]> err.no Git - sope/commitdiff
initial import of CVS snapshot 2004-08-20
authorznek <znek@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Fri, 20 Aug 2004 10:08:27 +0000 (10:08 +0000)
committerznek <znek@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Fri, 20 Aug 2004 10:08:27 +0000 (10:08 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

2150 files changed:
COPYRIGHT [new file with mode: 0644]
GNUmakefile [new file with mode: 0644]
PROJECTLEAD [new file with mode: 0644]
README [new file with mode: 0644]
Version [new file with mode: 0644]
mod_ngobjweb/.cvsignore [new file with mode: 0644]
mod_ngobjweb/CHANGES [new file with mode: 0644]
mod_ngobjweb/COPYRIGHT [new file with mode: 0644]
mod_ngobjweb/ChangeLog [new file with mode: 0644]
mod_ngobjweb/GNUmakefile [new file with mode: 0644]
mod_ngobjweb/NGBufferedDescriptor.c [new file with mode: 0644]
mod_ngobjweb/NGBufferedDescriptor.h [new file with mode: 0644]
mod_ngobjweb/README [new file with mode: 0644]
mod_ngobjweb/apversion.sh [new file with mode: 0755]
mod_ngobjweb/common.h [new file with mode: 0644]
mod_ngobjweb/config.c [new file with mode: 0644]
mod_ngobjweb/globals.c [new file with mode: 0644]
mod_ngobjweb/handler.c [new file with mode: 0644]
mod_ngobjweb/httpd.conf [new file with mode: 0644]
mod_ngobjweb/ngobjweb_module.c [new file with mode: 0644]
mod_ngobjweb/scanhttp.c [new file with mode: 0644]
mod_ngobjweb/skyrix.conf [new file with mode: 0644]
mod_ngobjweb/sns.c [new file with mode: 0644]
rules.mk [new file with mode: 0644]
skyrix-core/.cvsignore [new file with mode: 0644]
skyrix-core/COPYING [new file with mode: 0644]
skyrix-core/COPYRIGHT [new file with mode: 0644]
skyrix-core/ChangeLog [new file with mode: 0644]
skyrix-core/EOControl/.cvsignore [new file with mode: 0644]
skyrix-core/EOControl/COPYING [new file with mode: 0644]
skyrix-core/EOControl/COPYRIGHT [new file with mode: 0644]
skyrix-core/EOControl/ChangeLog [new file with mode: 0644]
skyrix-core/EOControl/EOAndQualifier.m [new file with mode: 0644]
skyrix-core/EOControl/EOArrayDataSource.h [new file with mode: 0644]
skyrix-core/EOControl/EOArrayDataSource.m [new file with mode: 0644]
skyrix-core/EOControl/EOClassDescription.h [new file with mode: 0644]
skyrix-core/EOControl/EOClassDescription.m [new file with mode: 0644]
skyrix-core/EOControl/EOControl-Info.plist [new file with mode: 0644]
skyrix-core/EOControl/EOControl.h [new file with mode: 0644]
skyrix-core/EOControl/EOControlDecls.h [new file with mode: 0644]
skyrix-core/EOControl/EODataSource.h [new file with mode: 0644]
skyrix-core/EOControl/EODataSource.m [new file with mode: 0644]
skyrix-core/EOControl/EODetailDataSource.h [new file with mode: 0644]
skyrix-core/EOControl/EODetailDataSource.m [new file with mode: 0644]
skyrix-core/EOControl/EOFetchSpecification.h [new file with mode: 0644]
skyrix-core/EOControl/EOFetchSpecification.m [new file with mode: 0644]
skyrix-core/EOControl/EOGenericRecord.h [new file with mode: 0644]
skyrix-core/EOControl/EOGenericRecord.m [new file with mode: 0644]
skyrix-core/EOControl/EOGlobalID.h [new file with mode: 0644]
skyrix-core/EOControl/EOGlobalID.m [new file with mode: 0644]
skyrix-core/EOControl/EOKeyComparisonQualifier.m [new file with mode: 0644]
skyrix-core/EOControl/EOKeyGlobalID.h [new file with mode: 0644]
skyrix-core/EOControl/EOKeyGlobalID.m [new file with mode: 0644]
skyrix-core/EOControl/EOKeyValueArchiver.h [new file with mode: 0644]
skyrix-core/EOControl/EOKeyValueArchiver.m [new file with mode: 0644]
skyrix-core/EOControl/EOKeyValueCoding.h [new file with mode: 0644]
skyrix-core/EOControl/EOKeyValueCoding.m [new file with mode: 0644]
skyrix-core/EOControl/EOKeyValueQualifier.m [new file with mode: 0644]
skyrix-core/EOControl/EONotQualifier.m [new file with mode: 0644]
skyrix-core/EOControl/EONull.h [new file with mode: 0644]
skyrix-core/EOControl/EONull.m [new file with mode: 0644]
skyrix-core/EOControl/EOObserver.h [new file with mode: 0644]
skyrix-core/EOControl/EOObserver.m [new file with mode: 0644]
skyrix-core/EOControl/EOOrQualifier.m [new file with mode: 0644]
skyrix-core/EOControl/EOQualifier.h [new file with mode: 0644]
skyrix-core/EOControl/EOQualifier.m [new file with mode: 0644]
skyrix-core/EOControl/EOQualifierParser.m [new file with mode: 0644]
skyrix-core/EOControl/EOQualifierVariable.m [new file with mode: 0644]
skyrix-core/EOControl/EOSQLParser.h [new file with mode: 0644]
skyrix-core/EOControl/EOSQLParser.m [new file with mode: 0644]
skyrix-core/EOControl/EOSortOrdering.h [new file with mode: 0644]
skyrix-core/EOControl/EOSortOrdering.m [new file with mode: 0644]
skyrix-core/EOControl/EOValidation.m [new file with mode: 0644]
skyrix-core/EOControl/GNUmakefile [new file with mode: 0644]
skyrix-core/EOControl/GNUmakefile.preamble [new file with mode: 0644]
skyrix-core/EOControl/NSArray+EOQualifier.m [new file with mode: 0644]
skyrix-core/EOControl/NSObject+EOQualifierOps.m [new file with mode: 0644]
skyrix-core/EOControl/NSObject+QualDesc.m [new file with mode: 0644]
skyrix-core/EOControl/README [new file with mode: 0644]
skyrix-core/EOControl/SxCore-EOControl.graffle [new file with mode: 0644]
skyrix-core/EOControl/TODO [new file with mode: 0644]
skyrix-core/EOControl/Version [new file with mode: 0644]
skyrix-core/EOControl/common.h [new file with mode: 0644]
skyrix-core/EOControl/libEOControl.def [new file with mode: 0644]
skyrix-core/GNUmakefile [new file with mode: 0644]
skyrix-core/NGExtensions/.cvsignore [new file with mode: 0644]
skyrix-core/NGExtensions/COPYING [new file with mode: 0644]
skyrix-core/NGExtensions/COPYRIGHT [new file with mode: 0644]
skyrix-core/NGExtensions/ChangeLog [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/.cvsignore [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOCacheDataSource.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOCompoundDataSource.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EODataSource+NGExtensions.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOFetchSpecification+plist.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOFilterDataSource.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOGrouping.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOGroupingSet.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOKeyGrouping.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOKeyMapDataSource.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOQualifier+CtxEval.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOQualifier+plist.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOQualifierGrouping.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOSortOrdering+plist.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/EOTrueQualifier.m [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/GNUmakefile [new file with mode: 0644]
skyrix-core/NGExtensions/EOExt.subproj/NSArray+EOGrouping.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/.cvsignore [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/GNUmakefile [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NGPropertyListParser.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSArray+enumerator.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSAutoreleasePool+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSCalendarDate+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSData+gzip.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSData+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSDictionary+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSEnumerator+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSException+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSFileManager+Extensions.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSMethodSignature+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSNull+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSObject+Logs.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSObject+Values.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSProcessInfo+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSRunLoop+FileObjects.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSSet+enumerator.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSString+Encoding.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSString+Ext.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSString+Formatting.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSString+German.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSString+HTMLEscaping.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSString+URLEscaping.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSString+XMLEscaping.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSString+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FdExt.subproj/NSURL+misc.m [new file with mode: 0644]
skyrix-core/NGExtensions/FileObjectHolder.m [new file with mode: 0644]
skyrix-core/NGExtensions/GNUmakefile [new file with mode: 0644]
skyrix-core/NGExtensions/GNUmakefile.preamble [new file with mode: 0644]
skyrix-core/NGExtensions/NGBase64Coding.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGBitSet.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGBundleManager.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGCString.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGCalendarDateRange.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGCustomFileManager.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGDirectoryEnumerator.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions-Info.plist [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/AutoDefines.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/DOMNode+EOQualifier.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOCacheDataSource.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOCompoundDataSource.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EODataSource+NGExtensions.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOFetchSpecification+plist.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOFilterDataSource.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOGrouping.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOGroupingSet.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOKeyGrouping.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOKeyMapDataSource.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOQualifier+CtxEval.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOQualifier+plist.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOQualifierGrouping.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOSortOrdering+plist.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/EOTrueQualifier.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/FileObjectHolder.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/IndexFunc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGBase64Coding.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGBaseTypes.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGBitSet.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGBundleManager.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGCString.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGCalendarDateRange.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGCharBuffers.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGCustomFileManager.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGDirectoryEnumerator.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGExtensions.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGExtensionsDecls.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGFileFolderInfoDataSource.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGFileManager.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGFileManagerURL.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGHashMap.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGMemoryAllocation.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGMerging.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGObjCRuntime.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGObjectMacros.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGPropertyListParser.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGQuotedPrintableCoding.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGRule.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGRuleAssignment.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGRuleContext.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGRuleEngine.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGRuleModel.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGStack.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NGStringScanEnumerator.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSArray+enumerator.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSAutoreleasePool+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSCalendarDate+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSData+gzip.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSData+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSDictionary+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSEnumerator+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSException+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSFileManager+Extensions.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSMethodSignature+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSNull+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSObject+Logs.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSObject+Values.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSProcessInfo+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSRunLoop+FileObjects.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSSet+enumerator.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSString+Encoding.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSString+Ext.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSString+Formatting.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSString+German.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSString+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGExtensions/NSURL+misc.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGFileFolderInfoDataSource.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGFileManager+JS.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGFileManager.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGFileManagerURL.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGHashMap.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGMerging.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGObjCRuntime.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGQuotedPrintableCoding.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGRuleEngine.subproj/.cvsignore [new file with mode: 0644]
skyrix-core/NGExtensions/NGRuleEngine.subproj/GNUmakefile [new file with mode: 0644]
skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRule.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleAssignment.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleContext.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleModel.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleParser.h [new file with mode: 0644]
skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleParser.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGRuleEngine.subproj/README [new file with mode: 0644]
skyrix-core/NGExtensions/NGStack.m [new file with mode: 0644]
skyrix-core/NGExtensions/NGStringScanEnumerator.m [new file with mode: 0644]
skyrix-core/NGExtensions/SxCore-NGExtensions.graffle [new file with mode: 0644]
skyrix-core/NGExtensions/TODO [new file with mode: 0644]
skyrix-core/NGExtensions/Version [new file with mode: 0644]
skyrix-core/NGExtensions/XmlExt.subproj/.cvsignore [new file with mode: 0644]
skyrix-core/NGExtensions/XmlExt.subproj/DOMNode+EOQualifier.m [new file with mode: 0644]
skyrix-core/NGExtensions/XmlExt.subproj/GNUmakefile [new file with mode: 0644]
skyrix-core/NGExtensions/common.h [new file with mode: 0644]
skyrix-core/NGExtensions/libNGExtensions.def [new file with mode: 0644]
skyrix-core/NGLdap/.cvsignore [new file with mode: 0644]
skyrix-core/NGLdap/COPYING [new file with mode: 0644]
skyrix-core/NGLdap/COPYRIGHT [new file with mode: 0644]
skyrix-core/NGLdap/ChangeLog [new file with mode: 0644]
skyrix-core/NGLdap/EOQualifier+LDAP.h [new file with mode: 0644]
skyrix-core/NGLdap/EOQualifier+LDAP.m [new file with mode: 0644]
skyrix-core/NGLdap/GNUmakefile [new file with mode: 0644]
skyrix-core/NGLdap/GNUmakefile.postamble [new file with mode: 0644]
skyrix-core/NGLdap/GNUmakefile.preamble [new file with mode: 0644]
skyrix-core/NGLdap/NGLdap-Info.plist [new file with mode: 0644]
skyrix-core/NGLdap/NGLdap.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapAttribute.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapAttribute.m [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapConnection+Private.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapConnection.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapConnection.m [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapDataSource.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapDataSource.m [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapEntry.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapEntry.m [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapFileManager.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapFileManager.m [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapGlobalID.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapGlobalID.m [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapModification.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapModification.m [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapSearchResultEnumerator.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapSearchResultEnumerator.m [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapURL.h [new file with mode: 0644]
skyrix-core/NGLdap/NGLdapURL.m [new file with mode: 0644]
skyrix-core/NGLdap/NSString+DN.h [new file with mode: 0644]
skyrix-core/NGLdap/NSString+DN.m [new file with mode: 0644]
skyrix-core/NGLdap/README [new file with mode: 0644]
skyrix-core/NGLdap/README.macosx [new file with mode: 0644]
skyrix-core/NGLdap/Version [new file with mode: 0644]
skyrix-core/NGLdap/common.h [new file with mode: 0644]
skyrix-core/NGMime/.cvsignore [new file with mode: 0644]
skyrix-core/NGMime/COPYING [new file with mode: 0644]
skyrix-core/NGMime/COPYRIGHT [new file with mode: 0644]
skyrix-core/NGMime/ChangeLog [new file with mode: 0644]
skyrix-core/NGMime/GNUmakefile [new file with mode: 0644]
skyrix-core/NGMime/GNUmakefile.preamble [new file with mode: 0644]
skyrix-core/NGMime/NGConcreteMimeType.h [new file with mode: 0644]
skyrix-core/NGMime/NGConcreteMimeType.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/.cvsignore [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/COPYING [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/ChangeLog [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/EOQualifier+IMAPAdditions.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/GNUmakefile [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4-Info.plist [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Client.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Client.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Context.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Context.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4DataSource.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4DataSource.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4FileManager.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4FileManager.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Folder.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Folder.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4FolderFlags.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4FolderFlags.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4FolderGlobalID.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4FolderGlobalID.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4FolderMailRegistry.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4FolderMailRegistry.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Functions.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Functions.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Message+BodyStructure.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Message.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Message.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4MessageGlobalID.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4MessageGlobalID.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4ResponseNormalizer.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4ResponseNormalizer.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4ResponseParser.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4ResponseParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4ServerGlobalID.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4ServerGlobalID.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4ServerRoot.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4ServerRoot.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Support.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGImap4Support.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGSieveClient.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NGSieveClient.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NSString+Imap4.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/NSString+Imap4.m [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/README [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/SxCore-NGImap4Flow.graffle [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/TODO [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/imCommon.h [new file with mode: 0644]
skyrix-core/NGMime/NGImap4/imTimeMacros.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/.cvsignore [new file with mode: 0644]
skyrix-core/NGMime/NGMail/COPYING [new file with mode: 0644]
skyrix-core/NGMime/NGMail/ChangeLog [new file with mode: 0644]
skyrix-core/NGMime/NGMail/GNUmakefile [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMBoxReader.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMBoxReader.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMail-Info.plist [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMail.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMail.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMailAddress.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMailAddress.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMailAddressList.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMailAddressList.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMailAddressParser.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMailAddressParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMailDecls.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMimeMessage.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMimeMessage.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMimeMessageBodyGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMimeMessageGenerator.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMimeMessageGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMimeMessageMultipartBodyGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMimeMessageParser.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMimeMessageParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMimeMessageRfc822BodyGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGMimeMessageTextBodyGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGPop3Client.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGPop3Client.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGPop3Support.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGPop3Support.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGSmtpClient.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGSmtpClient.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGSmtpReplyCodes.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGSmtpSupport.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/NGSmtpSupport.m [new file with mode: 0644]
skyrix-core/NGMime/NGMail/README [new file with mode: 0644]
skyrix-core/NGMime/NGMail/common.h [new file with mode: 0644]
skyrix-core/NGMime/NGMail/libNGMail.def [new file with mode: 0644]
skyrix-core/NGMime/NGMime-Info.plist [new file with mode: 0644]
skyrix-core/NGMime/NGMime.h [new file with mode: 0644]
skyrix-core/NGMime/NGMime.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeAddressHeaderFieldGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeBodyGenerator.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeBodyGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeBodyParser.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeBodyParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeBodyPart.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeBodyPart.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeBodyPartParser.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeBodyPartParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeContentDispositionHeaderFieldParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeContentLengthHeaderFieldGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeContentLengthHeaderFieldParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeContentTypeHeaderFieldGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeContentTypeHeaderFieldParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeDecls.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeExceptions.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeExceptions.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeFileData.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeFileData.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeGeneratorProtocols.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeHeaderFieldGenerator.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeHeaderFieldGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeHeaderFieldGeneratorSet.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeHeaderFieldParser.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeHeaderFieldParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeHeaderFieldParserSet.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeHeaderFields.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeHeaderFields.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeJoinedData.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeJoinedData.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeMultipartBody.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeMultipartBody.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeMultipartBodyParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimePartGenerator.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimePartGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimePartParser.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimePartParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeRFC822DateHeaderFieldGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeRFC822DateHeaderFieldParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeStringHeaderFieldGenerator.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeStringHeaderFieldParser.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeType.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeType.m [new file with mode: 0644]
skyrix-core/NGMime/NGMimeUtilities.h [new file with mode: 0644]
skyrix-core/NGMime/NGMimeUtilities.m [new file with mode: 0644]
skyrix-core/NGMime/NGPart.h [new file with mode: 0644]
skyrix-core/NGMime/NGPart.m [new file with mode: 0644]
skyrix-core/NGMime/NSCalendarDate+RFC822.m [new file with mode: 0644]
skyrix-core/NGMime/README [new file with mode: 0644]
skyrix-core/NGMime/SxCore-NGMime.graffle [new file with mode: 0644]
skyrix-core/NGMime/TODO [new file with mode: 0644]
skyrix-core/NGMime/Version [new file with mode: 0644]
skyrix-core/NGMime/common.h [new file with mode: 0644]
skyrix-core/NGMime/libNGMime.def [new file with mode: 0644]
skyrix-core/NGMime/timeMacros.h [new file with mode: 0644]
skyrix-core/NGStreams/.cvsignore [new file with mode: 0644]
skyrix-core/NGStreams/COPYING [new file with mode: 0644]
skyrix-core/NGStreams/COPYRIGHT [new file with mode: 0644]
skyrix-core/NGStreams/ChangeLog [new file with mode: 0644]
skyrix-core/NGStreams/DESIGN [new file with mode: 0644]
skyrix-core/NGStreams/GNUmakefile [new file with mode: 0644]
skyrix-core/NGStreams/GNUmakefile.postamble [new file with mode: 0644]
skyrix-core/NGStreams/GNUmakefile.preamble [new file with mode: 0644]
skyrix-core/NGStreams/NGActiveSSLSocket.m [new file with mode: 0644]
skyrix-core/NGStreams/NGActiveSocket+serialization.m [new file with mode: 0644]
skyrix-core/NGStreams/NGActiveSocket.m [new file with mode: 0644]
skyrix-core/NGStreams/NGBase64Stream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGBufferedStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGByteBuffer.m [new file with mode: 0644]
skyrix-core/NGStreams/NGByteCountStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGCTextStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGCharBuffer.m [new file with mode: 0644]
skyrix-core/NGStreams/NGConcreteStreamFileHandle.m [new file with mode: 0644]
skyrix-core/NGStreams/NGDataStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGDatagramPacket.m [new file with mode: 0644]
skyrix-core/NGStreams/NGDatagramSocket.m [new file with mode: 0644]
skyrix-core/NGStreams/NGDescriptorFunctions.m [new file with mode: 0644]
skyrix-core/NGStreams/NGFileStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGFilterStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGFilterTextStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGGZipStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGInternetSocketAddress.m [new file with mode: 0644]
skyrix-core/NGStreams/NGInternetSocketDomain.m [new file with mode: 0644]
skyrix-core/NGStreams/NGLocalSocketAddress.m [new file with mode: 0644]
skyrix-core/NGStreams/NGLocalSocketDomain.m [new file with mode: 0644]
skyrix-core/NGStreams/NGLockingStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGNetUtilities.m [new file with mode: 0644]
skyrix-core/NGStreams/NGPassiveSocket.m [new file with mode: 0644]
skyrix-core/NGStreams/NGSocket+private.h [new file with mode: 0644]
skyrix-core/NGStreams/NGSocket.m [new file with mode: 0644]
skyrix-core/NGStreams/NGSocketExceptions.m [new file with mode: 0644]
skyrix-core/NGStreams/NGStream+serialization.m [new file with mode: 0644]
skyrix-core/NGStreams/NGStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGStreamCoder.m [new file with mode: 0644]
skyrix-core/NGStreams/NGStreamExceptions.m [new file with mode: 0644]
skyrix-core/NGStreams/NGStreamPipe.m [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams-Info.plist [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams.m [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGActiveSSLSocket.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGActiveSocket+serialization.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGActiveSocket.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGBase64Stream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGBufferedStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGByteBuffer.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGByteCountStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGCTextStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGCharBuffer.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGConcreteStreamFileHandle.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGDataStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGDatagramPacket.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGDatagramSocket.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGDescriptorFunctions.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGFileStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGFilterStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGFilterTextStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGGZipStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGInternetSocketAddress.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGInternetSocketDomain.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGLocalSocketAddress.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGLocalSocketDomain.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGLockingStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGNet.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGNetDecls.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGNetUtilities.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGPassiveSocket.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGSocket.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGSocketExceptions.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGSocketProtocols.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGStream+serialization.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGStreamCoder.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGStreamExceptions.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGStreamPipe.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGStreamProtocols.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGStreams.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGStreamsDecls.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGStringTextStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGTaskStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGTerminalSupport.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGTextStream.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGTextStreamProtocols.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStreams/NGUrlChars.h [new file with mode: 0644]
skyrix-core/NGStreams/NGStringTextStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGTaskStream.m [new file with mode: 0644]
skyrix-core/NGStreams/NGTerminalSupport.m [new file with mode: 0644]
skyrix-core/NGStreams/NGTextStream.m [new file with mode: 0644]
skyrix-core/NGStreams/README [new file with mode: 0644]
skyrix-core/NGStreams/SxCore-NGStreams.graffle [new file with mode: 0644]
skyrix-core/NGStreams/TODO [new file with mode: 0644]
skyrix-core/NGStreams/Version [new file with mode: 0644]
skyrix-core/NGStreams/common.h [new file with mode: 0644]
skyrix-core/NGStreams/config.guess [new file with mode: 0755]
skyrix-core/NGStreams/config.h.in [new file with mode: 0644]
skyrix-core/NGStreams/config.sub [new file with mode: 0755]
skyrix-core/NGStreams/configure [new file with mode: 0755]
skyrix-core/NGStreams/configure.in [new file with mode: 0644]
skyrix-core/NGStreams/install-sh [new file with mode: 0755]
skyrix-core/NGStreams/libNGStreams.def [new file with mode: 0644]
skyrix-core/NGStreams/macosx/config.h [new file with mode: 0644]
skyrix-core/NGiCal/.cvsignore [new file with mode: 0644]
skyrix-core/NGiCal/COPYING [new file with mode: 0644]
skyrix-core/NGiCal/COPYRIGHT [new file with mode: 0644]
skyrix-core/NGiCal/ChangeLog [new file with mode: 0644]
skyrix-core/NGiCal/GNUmakefile [new file with mode: 0644]
skyrix-core/NGiCal/GNUmakefile.postamble [new file with mode: 0644]
skyrix-core/NGiCal/GNUmakefile.preamble [new file with mode: 0644]
skyrix-core/NGiCal/IcalElements.m [new file with mode: 0644]
skyrix-core/NGiCal/IcalResponse.h [new file with mode: 0644]
skyrix-core/NGiCal/IcalResponse.m [new file with mode: 0644]
skyrix-core/NGiCal/NGiCal-Info.plist [new file with mode: 0644]
skyrix-core/NGiCal/NGiCal.h [new file with mode: 0644]
skyrix-core/NGiCal/NGiCal.xmap [new file with mode: 0644]
skyrix-core/NGiCal/NSCalendarDate+ICal.h [new file with mode: 0644]
skyrix-core/NGiCal/NSCalendarDate+ICal.m [new file with mode: 0644]
skyrix-core/NGiCal/NSString+ICal.h [new file with mode: 0644]
skyrix-core/NGiCal/NSString+ICal.m [new file with mode: 0644]
skyrix-core/NGiCal/README [new file with mode: 0644]
skyrix-core/NGiCal/Version [new file with mode: 0644]
skyrix-core/NGiCal/common.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalAlarm.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalAlarm.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalAttachment.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalAttachment.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalCalendar.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalCalendar.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalDataSource.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalDataSource.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalDateHolder.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalDateHolder.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalDuration.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalDuration.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalEntityObject.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalEntityObject.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalEvent.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalEvent.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalFreeBusy.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalFreeBusy.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalJournal.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalJournal.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalObject.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalObject.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalPerson.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalPerson.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalToDo.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalToDo.m [new file with mode: 0644]
skyrix-core/NGiCal/iCalTrigger.h [new file with mode: 0644]
skyrix-core/NGiCal/iCalTrigger.m [new file with mode: 0644]
skyrix-core/PROJECTLEAD [new file with mode: 0644]
skyrix-core/README [new file with mode: 0644]
skyrix-core/README-OSX.txt [new file with mode: 0644]
skyrix-core/SxCore-Info.plist [new file with mode: 0644]
skyrix-core/SxCore.xcode/project.pbxproj [new file with mode: 0644]
skyrix-core/Version [new file with mode: 0644]
skyrix-core/common.make [new file with mode: 0644]
skyrix-core/dummy.c [new file with mode: 0644]
skyrix-core/samples/.cvsignore [new file with mode: 0644]
skyrix-core/samples/COPYING [new file with mode: 0644]
skyrix-core/samples/ChangeLog [new file with mode: 0644]
skyrix-core/samples/EOQualTool.h [new file with mode: 0644]
skyrix-core/samples/EOQualTool.m [new file with mode: 0644]
skyrix-core/samples/EncodingTool.h [new file with mode: 0644]
skyrix-core/samples/EncodingTool.m [new file with mode: 0644]
skyrix-core/samples/GNUmakefile [new file with mode: 0644]
skyrix-core/samples/GNUmakefile.preamble [new file with mode: 0644]
skyrix-core/samples/ImapListTool.h [new file with mode: 0644]
skyrix-core/samples/ImapListTool.m [new file with mode: 0644]
skyrix-core/samples/ImapQuotaTool.h [new file with mode: 0644]
skyrix-core/samples/ImapQuotaTool.m [new file with mode: 0644]
skyrix-core/samples/ImapTool.h [new file with mode: 0644]
skyrix-core/samples/ImapTool.m [new file with mode: 0644]
skyrix-core/samples/Mime2XmlTool.h [new file with mode: 0644]
skyrix-core/samples/Mime2XmlTool.m [new file with mode: 0644]
skyrix-core/samples/README [new file with mode: 0644]
skyrix-core/samples/bmlookup.m [new file with mode: 0644]
skyrix-core/samples/common.h [new file with mode: 0644]
skyrix-core/samples/encoding.m [new file with mode: 0644]
skyrix-core/samples/eoqual.m [new file with mode: 0644]
skyrix-core/samples/fmdls.m [new file with mode: 0644]
skyrix-core/samples/httpu_notify.m [new file with mode: 0644]
skyrix-core/samples/ical2.m [new file with mode: 0644]
skyrix-core/samples/ical3.m [new file with mode: 0644]
skyrix-core/samples/imap_tool.m [new file with mode: 0644]
skyrix-core/samples/imapls.m [new file with mode: 0644]
skyrix-core/samples/imapquota.m [new file with mode: 0644]
skyrix-core/samples/ldap2dsml.m [new file with mode: 0644]
skyrix-core/samples/ldapchkpwd.m [new file with mode: 0644]
skyrix-core/samples/ldapls.m [new file with mode: 0644]
skyrix-core/samples/mime2xml.m [new file with mode: 0644]
skyrix-core/samples/parserule.m [new file with mode: 0644]
skyrix-core/samples/pwd-check.m [new file with mode: 0644]
skyrix-core/samples/subclassing.m [new file with mode: 0644]
skyrix-core/samples/test_qpdecode.m [new file with mode: 0644]
skyrix-core/samples/testdirenum.m [new file with mode: 0644]
skyrix-core/samples/testsock.m [new file with mode: 0644]
skyrix-core/samples/testurl.m [new file with mode: 0644]
skyrix-sope/COPYING [new file with mode: 0644]
skyrix-sope/COPYRIGHT [new file with mode: 0644]
skyrix-sope/ChangeLog [new file with mode: 0644]
skyrix-sope/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGJavaScript/.cvsignore [new file with mode: 0644]
skyrix-sope/NGJavaScript/COPYING [new file with mode: 0644]
skyrix-sope/NGJavaScript/ChangeLog [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/.cvsignore [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/EODataSource+JS.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/EOJavaScriptGrouping.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/EOJavaScriptGrouping.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/EONull+JS.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/NGFileManager+JS.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/NSArray+JS.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/NSDate+JS.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/NSDictionary+JS.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/NSNumber+JS.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/NSObject+JS.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/NSObject+JS.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/NSString+JS.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/NSString+JS.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/Core+JS.subproj/NSUserDefaults+JS.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGJavaScript/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGJavaScript/JSObjectOps.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScript-Info.plist [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScript.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptArray.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptCallable.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptCallable.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptContext.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptContext.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptDecls.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptError.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptError.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptFunction.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptFunction.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptLanguage.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptObjCClassInfo.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptObjCClassInfo.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptObject.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptObject.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptObjectHandler.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptObjectHandler.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptObjectMappingContext.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptObjectMappingContext.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptRuntime.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptRuntime.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptShadow.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/NGJavaScriptShadow.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/README [new file with mode: 0644]
skyrix-sope/NGJavaScript/ScriptLanguages.plist [new file with mode: 0644]
skyrix-sope/NGJavaScript/TODO [new file with mode: 0644]
skyrix-sope/NGJavaScript/Version [new file with mode: 0644]
skyrix-sope/NGJavaScript/common.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/dummy.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/globals.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/globals.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/jsobjops.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/testjs.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/.cvsignore [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/Blah.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/Blah.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/Combined.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/Combined.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/JSArchivingTests.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/JSArchivingTests.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/JSBridgeTests.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/JSBridgeTests.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/JSTest.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/JSTest.m [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/MyNum.h [new file with mode: 0644]
skyrix-sope/NGJavaScript/tests/MyNum.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjDOM/COPYING [new file with mode: 0644]
skyrix-sope/NGObjDOM/COPYRIGHT [new file with mode: 0644]
skyrix-sope/NGObjDOM/ChangeLog [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/COPYING [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ChangeLog [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODBindNodeRenderFactory.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODBindNodeRenderFactory.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_checkbox.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_collapsible.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_datefield.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_fieldset.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_foreach.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_form.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_groupings.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_groupings.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_if.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_multiselection.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_nbsp.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_popupbutton.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_radiobutton.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_sortorderings.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_sortorderings.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_string.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_switch.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tablecell.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tablecell.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tabledata.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableheader.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableview+Private.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableview+Private.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableview.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tabview.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_viewertitle.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_with.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjDOM/GNUmakefile.postamble [new file with mode: 0644]
skyrix-sope/NGObjDOM/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjDOM/NGObjDOM-Info.plist [new file with mode: 0644]
skyrix-sope/NGObjDOM/NGObjDOM.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/NGObjDOMModule.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODNamespaces.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODNodeRenderer+attributes.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODNodeRenderer+attributes.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODNodeRenderer.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODNodeRenderer.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODNodeRendererFactory.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODNodeRendererFactory.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODNodeRendererFactorySet.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODNodeRendererFactorySet.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODREmbedComponent.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODREmbedComponent.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODRGenericTag.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODRGenericTag.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODRNodeText.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODRNodeText.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODRWebObject.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODRWebObject.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODR_bind_collapsible.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODR_bind_fieldset.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODR_bind_tableview.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODR_bind_tabview.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODR_bind_viewertitle.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODResourceManager.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODResourceManager.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/ODWONodeRenderFactory.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/README [new file with mode: 0644]
skyrix-sope/NGObjDOM/Version [new file with mode: 0644]
skyrix-sope/NGObjDOM/WOContext+Cursor.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/WORenderDOM.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/WORenderDOM.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/COPYING [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ChangeLog [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODRDynamicXHTMLTag.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODRDynamicXHTMLTag.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_a.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_button.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_form.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_img.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_input.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_option.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_select.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_textarea.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODXHTMLNodeRenderFactory.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/ODXHTMLNodeRenderFactory.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XHTML.subproj/bundle-info.plist [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/COPYING [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODRDynamicXULTag.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODRDynamicXULTag.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_box.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_box.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_button.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_column.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_columns.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_grid.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_image.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_spring.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_tab.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_text.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_textfield.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_title.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_titledbox.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_window.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODXULNodeRenderFactory.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/ODXULNodeRenderFactory.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/XUL.subproj/bundle-info.plist [new file with mode: 0644]
skyrix-sope/NGObjDOM/bundle-info.plist [new file with mode: 0644]
skyrix-sope/NGObjDOM/common.h [new file with mode: 0644]
skyrix-sope/NGObjDOM/dummy.m [new file with mode: 0644]
skyrix-sope/NGObjDOM/used_privates.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/NSUserDefaults+KVC.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOAssociation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOKeyPathAssociation.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOKeyPathAssociation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOKeyPathAssociationSystemKVC.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOLabelAssociation.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOLabelAssociation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOResourceURLAssociation.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOResourceURLAssociation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOScriptAssociation.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOScriptAssociation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOValueAssociation.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/Associations/WOValueAssociation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/COPYING [new file with mode: 0644]
skyrix-sope/NGObjWeb/COPYRIGHT [new file with mode: 0644]
skyrix-sope/NGObjWeb/ChangeLog [new file with mode: 0644]
skyrix-sope/NGObjWeb/DAVPropMap.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/Defaults.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/README [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOActionURL.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOActiveImage.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOBody.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOBrowser.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOCheckBox.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOCheckBoxList.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOComponentContent.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOComponentContent.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOComponentReference.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOComponentReference.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOCompoundElement.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOCompoundElement.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOConditional.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOEmbeddedObject.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOEntity.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOFileUpload.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOForm.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOForm.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOFrame.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOGenericContainer.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOGenericElement.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOGenericElement.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOHTMLDynamicElement.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOHTMLDynamicElement.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOHiddenField.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOHtml.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOHyperlink.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOHyperlink.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOHyperlinkInfo.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOHyperlinkInfo.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOIFrame.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOImage.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOImage.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOImageButton.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOInput.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOInput.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOJavaScript.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOMetaRefresh.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WONestedList.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOPasswordField.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOPopUpButton.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOQuickTime.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WORadioButton.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WORadioButtonList.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WORepetition.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOResetButton.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOResourceURL.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOSetCursor.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOString.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOSubmitButton.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOSwitchComponent.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOText.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOTextField.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOVBScript.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOxControlElemBuilder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOxHTMLElemBuilder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOxMiscElemBuilder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/WOxXULElemBuilder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/_WOCommonStaticDAHyperlink.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/_WOComplexHyperlink.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/_WOConstResourceImage.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/_WOResourceImage.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/_WOSimpleActionHyperlink.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/_WOTemporaryHyperlink.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/DynamicElements/common.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjWeb/GNUmakefile.postamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/Languages.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp+WO.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp+WO.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/ChangeLog [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttp-Info.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttp.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttp.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpBodyParser.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpBodyParser.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpCookie.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpCookie.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpDecls.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFieldParser.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFieldParser.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFields.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFields.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpMessage.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpMessage.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpMessageParser.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpMessageParser.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpRequest.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpRequest.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpResponse.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGHttpResponse.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGUrlFormCoder.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/NGUrlFormCoder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/README [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGHttp/common.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb-Info.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/NGObjWeb.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/NGObjWebDecls.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/OWResourceManager.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/OWResponder.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/OWViewRequestHandler.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WEClientCapabilities.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOActionResults.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOAdaptor.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOApplication.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOAssociation.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOComponent.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOComponentScript.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOContext.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOCookie.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOCoreApplication.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WODirectAction.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WODisplayGroup.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WODynamicElement.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOElement.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOElementTrackingContext.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOHTTPConnection.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOMailDelivery.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOMessage.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOPageGenerationContext.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOProxyRequestHandler.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WORequest.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WORequestHandler.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOResourceManager.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOResponse.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOSession.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOSessionStore.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOStatisticsStore.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOTemplate.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOTemplateBuilder.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGObjWeb/WOxElemBuilder.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/ChangeLog [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/EOFetchSpecification+XmlRpcCoding.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/EOKeyGlobalID+XmlRpcCoding.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/EONull+XmlRpcCoding.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/EOQualifier+XmlRpcCoding.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/EOSortOrdering+XmlRpcCoding.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGAsyncResultProxy.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGAsyncResultProxy.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpc-Info.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpc.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcAction+Registry.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcAction.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcAction.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcClient.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcClient.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcInvocation.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcInvocation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcMethodSignature.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcMethodSignature.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcRequestHandler.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcRequestHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NSObject+Reflection.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/NSObject+Reflection.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpc.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpc.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpcIntrospection.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpcIntrospection.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/WOMessage+XmlRpcCoding.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/WORequest+XmlRpcCoding.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/WOResponse+XmlRpcCoding.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodCall+WO.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodCall+WO.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodResponse+WO.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodResponse+WO.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/NSObject+WO.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/NSObject+WO.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/OWResourceManager.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/OWViewRequestHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/README [new file with mode: 0644]
skyrix-sope/NGObjWeb/SNSConnection.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SNSConnection.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoCoreProduct.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSBaseObject.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSBaseObject.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSChangeLog.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSChangeLog.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFactoryContext.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFactoryContext.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFactoryRegistry.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFactoryRegistry.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFile.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFile.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFileRenderer.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFileRenderer.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFolder+SoDAV.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFolder.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFolder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFolderClassDescription.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFolderClassDescription.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFolderDataSource.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSFolderDataSource.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSHttpPasswd.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSHttpPasswd.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSImage.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSImage.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSPropertyListObject.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSPropertyListObject.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSResourceManager.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSResourceManager.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSWebDocument.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSWebDocument.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSWebMethod.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSWebMethod.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSWebMethodRenderer.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSWebMethodRenderer.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSWebTemplate.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/OFSWebTemplate.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/README [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/SoOFS-Info.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/SoOFS-SXP-Info.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/SoOFS.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/TODO [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/common.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFS/product.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoOFSProduct.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/NOTES [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/NSException+HTTP.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/NSException+HTTP.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/README [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoApplication.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoApplication.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoClass.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoClass.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoClassRegistry.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoClassRegistry.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoClassSecurityInfo.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoClassSecurityInfo.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoComponent.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoComponent.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoControlPanel.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoControlPanel.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoCore-SXP-Info.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoDefaultRenderer.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoDefaultRenderer.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoHTTPAuthenticator.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoHTTPAuthenticator.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoLookupAssociation.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoLookupAssociation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjCClass.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjCClass.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObject+Traversal.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObject.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObject.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjectMethodDispatcher.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjectMethodDispatcher.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjectRequestHandler.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjectRequestHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjectSOAPDispatcher.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjectSOAPDispatcher.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjectXmlRpcDispatcher.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjectXmlRpcDispatcher.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoObjects.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoPageInvocation.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoPageInvocation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoPermissions.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoPermissions.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoProduct.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoProduct.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoProductClassInfo.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoProductClassInfo.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoProductRegistry.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoProductRegistry.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoProductResourceManager.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoProductResourceManager.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoSecurityException.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoSecurityException.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoSecurityManager.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoSecurityManager.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoSelectorInvocation.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoSelectorInvocation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoSubContext.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoSubContext.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoTemplateRenderer.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoTemplateRenderer.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoUser.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/SoUser.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/TODO [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/WOContext+SoObjects.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/WOContext+SoObjects.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/WODirectAction+SoObjects.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/WODirectActionRequestHandler+SoObjects.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/WORequest+So.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/WORequest+So.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/SoObjects/product.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/TODO [new file with mode: 0644]
skyrix-sope/NGObjWeb/TROUBLESHOOTING [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/README-Templates.txt [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOComponentScript.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOComponentScriptPart.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WODParser.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WODParser.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOHTMLParser.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOHTMLParser.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOSubcomponentInfo.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOTemplate.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOTemplateBuilder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOWrapperTemplateBuilder.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOWrapperTemplateBuilder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOxComponentElemBuilder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOxElemBuilder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOxTemplateBuilder.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/Templates/WOxTemplateBuilder.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/UnixSignalHandler.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/UnixSignalHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/Version [new file with mode: 0644]
skyrix-sope/NGObjWeb/WEClientCapabilities.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOAdaptor.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOApplication+defaults.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOApplication+private.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOApplication.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOApplicationMain.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOChildComponentReference.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOChildComponentReference.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOComponent+JS.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOComponent+Sync.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOComponent+private.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOComponent.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOComponentDefinition.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOComponentDefinition.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOComponentFault.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOComponentFault.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOComponentRequestHandler.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOComponentRequestHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOContext+private.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOContext.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOCookie.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOCoreApplication+Bundle.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOCoreApplication.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WODirectAction.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WODirectActionRequestHandler.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WODirectActionRequestHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WODisplayGroup.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WODynamicElement.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOElement+private.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOElement.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOElementID.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOElementID.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOFileSessionStore.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHTTPConnection.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHTTPURLHandle.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/WORecordRequestStream.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/WORecordRequestStream.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequest+Adaptor.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequest+Adaptor.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequestParser.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequestParser.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOMailDelivery.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOMessage+Validation.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOMessage+XML.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOMessage.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOPageRequestHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOProxyRequestHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WORequest.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WORequestHandler+private.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WORequestHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOResourceManager.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOResourceRequestHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOResponse+private.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOResponse.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WORunLoop.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WORunLoop.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOScriptedComponent.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOScriptedComponent.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOServerSessionStore.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOSession+JS.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOSession.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOSessionStore.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOSimpleHTTPParser.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOSimpleHTTPParser.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOStatisticsStore.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOStats.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WOWatchDogApplicationMain.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/.cvsignore [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/DAVFetchSpec.txt [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/EOFetchSpecification+SoDAV.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/EOFetchSpecification+SoDAV.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/README [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SaxDAVHandler.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SaxDAVHandler.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoDAV.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoDAVLockManager.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoDAVLockManager.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoDAVSQLParser.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoDAVSQLParser.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoObject+SoDAV.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoObject+SoDAV.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoObject+SoDAVQuery.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoObjectDataSource.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoObjectDataSource.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoObjectResultEntry.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoObjectResultEntry.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoObjectWebDAVDispatcher.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoObjectWebDAVDispatcher.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoSubscription.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoSubscription.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoSubscriptionManager.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoSubscriptionManager.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoWebDAVRenderer.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoWebDAVRenderer.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoWebDAVValue.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/SoWebDAVValue.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/TODO [new file with mode: 0644]
skyrix-sope/NGObjWeb/WebDAV/WebDAV-Info.plist [new file with mode: 0644]
skyrix-sope/NGObjWeb/_WOStringTable.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/_WOStringTable.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/common.h [new file with mode: 0644]
skyrix-sope/NGObjWeb/dummy.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/ngobjweb.make [new file with mode: 0644]
skyrix-sope/NGObjWeb/sope.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/woapp-gs.make [new file with mode: 0644]
skyrix-sope/NGObjWeb/woapp.make [new file with mode: 0644]
skyrix-sope/NGObjWeb/wobundle-gs.make [new file with mode: 0644]
skyrix-sope/NGObjWeb/wobundle.make [new file with mode: 0644]
skyrix-sope/NGObjWeb/wod.m [new file with mode: 0644]
skyrix-sope/NGObjWeb/xmlrpc_call.m [new file with mode: 0644]
skyrix-sope/NGScripting/.cvsignore [new file with mode: 0644]
skyrix-sope/NGScripting/COPYING [new file with mode: 0644]
skyrix-sope/NGScripting/ChangeLog [new file with mode: 0644]
skyrix-sope/NGScripting/GNUmakefile [new file with mode: 0644]
skyrix-sope/NGScripting/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/NGScripting/NGObjectMappingContext.h [new file with mode: 0644]
skyrix-sope/NGScripting/NGObjectMappingContext.m [new file with mode: 0644]
skyrix-sope/NGScripting/NGScriptLanguage.h [new file with mode: 0644]
skyrix-sope/NGScripting/NGScriptLanguage.m [new file with mode: 0644]
skyrix-sope/NGScripting/NGScripting-Info.plist [new file with mode: 0644]
skyrix-sope/NGScripting/NSObject+Scripting.h [new file with mode: 0644]
skyrix-sope/NGScripting/NSObject+Scripting.m [new file with mode: 0644]
skyrix-sope/NGScripting/Version [new file with mode: 0644]
skyrix-sope/NGScripting/common.h [new file with mode: 0644]
skyrix-sope/PROJECTLEAD [new file with mode: 0644]
skyrix-sope/README [new file with mode: 0644]
skyrix-sope/README-OSX.txt [new file with mode: 0644]
skyrix-sope/SOPE-Info.plist [new file with mode: 0644]
skyrix-sope/SOPE.xcode/project.pbxproj [new file with mode: 0644]
skyrix-sope/SxComponents/.cvsignore [new file with mode: 0644]
skyrix-sope/SxComponents/COPYING [new file with mode: 0644]
skyrix-sope/SxComponents/ChangeLog [new file with mode: 0644]
skyrix-sope/SxComponents/GNUmakefile [new file with mode: 0644]
skyrix-sope/SxComponents/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/SxComponents/NSObject+SxXmlRpcValue.m [new file with mode: 0644]
skyrix-sope/SxComponents/README [new file with mode: 0644]
skyrix-sope/SxComponents/SxBasicAuthCredentials.h [new file with mode: 0644]
skyrix-sope/SxComponents/SxBasicAuthCredentials.m [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponent.h [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponent.m [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponentException.h [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponentException.m [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponentInvocation.h [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponentInvocation.m [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponentMethodSignature.h [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponentMethodSignature.m [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponentRegistry.h [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponentRegistry.m [new file with mode: 0644]
skyrix-sope/SxComponents/SxComponents.h [new file with mode: 0644]
skyrix-sope/SxComponents/SxXmlRpcComponent.h [new file with mode: 0644]
skyrix-sope/SxComponents/SxXmlRpcComponent.m [new file with mode: 0644]
skyrix-sope/SxComponents/SxXmlRpcInvocation.h [new file with mode: 0644]
skyrix-sope/SxComponents/SxXmlRpcInvocation.m [new file with mode: 0644]
skyrix-sope/SxComponents/SxXmlRpcRegBackend.m [new file with mode: 0644]
skyrix-sope/SxComponents/Version [new file with mode: 0644]
skyrix-sope/SxComponents/common.h [new file with mode: 0644]
skyrix-sope/SxComponents/sxc_call.m [new file with mode: 0644]
skyrix-sope/SxComponents/sxc_ls.m [new file with mode: 0644]
skyrix-sope/Version [new file with mode: 0644]
skyrix-sope/WEExtensions/.cvsignore [new file with mode: 0644]
skyrix-sope/WEExtensions/COPYING [new file with mode: 0644]
skyrix-sope/WEExtensions/COPYRIGHT [new file with mode: 0644]
skyrix-sope/WEExtensions/ChangeLog [new file with mode: 0644]
skyrix-sope/WEExtensions/GNUmakefile [new file with mode: 0644]
skyrix-sope/WEExtensions/GNUmakefile.postamble [new file with mode: 0644]
skyrix-sope/WEExtensions/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/WEExtensions/JSClipboard.m [new file with mode: 0644]
skyrix-sope/WEExtensions/JSMenu.h [new file with mode: 0644]
skyrix-sope/WEExtensions/JSMenu.m [new file with mode: 0644]
skyrix-sope/WEExtensions/JSMenuItem.h [new file with mode: 0644]
skyrix-sope/WEExtensions/JSMenuItem.m [new file with mode: 0644]
skyrix-sope/WEExtensions/JSShiftClick.m [new file with mode: 0644]
skyrix-sope/WEExtensions/README [new file with mode: 0644]
skyrix-sope/WEExtensions/TODO [new file with mode: 0644]
skyrix-sope/WEExtensions/Version [new file with mode: 0644]
skyrix-sope/WEExtensions/WEBrowser.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WECalendarField.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WECalendarField.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEClientCapabilities.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WECollapsibleComponentContent.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEComponentValue.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEContextConditional.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WEContextConditional.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEContextKey.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEDateField.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEDragContainer.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEDropContainer.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEDropScript.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WEDropScript.js [new file with mode: 0644]
skyrix-sope/WEExtensions/WEDropScript.jsm [new file with mode: 0644]
skyrix-sope/WEExtensions/WEEpozEditor.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEExtensions-Info.plist [new file with mode: 0644]
skyrix-sope/WEExtensions/WEExtensionsBundle.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEMonthOverview.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEPageLink.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEPageView.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEQualifierConditional.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WERedirect.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WERichString.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WESwitch.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETabItem.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETabView.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETabView.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableCalcMatrix.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableCalcMatrix.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableMatrix.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableMatrixContent.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableMatrixLabel.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/.cvsignore [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/GNUmakefile [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/README [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableCell.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableCell.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableData.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableHeader.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableView+Grouping.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableView+Grouping.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableView.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableView.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewButtonMode.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewColorConfig.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewColorConfig.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewConfigObject.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewConfigObject.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewDefines.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewFooterMode.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewGroupMode.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewIconConfig.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewIconConfig.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewInfo.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewLabelConfig.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewLabelConfig.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewState.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewState.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETableView/WETableViewTitleMode.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETimeField.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETreeContextKeys.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETreeData.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETreeHeader.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETreeMatrixElement.h [new file with mode: 0644]
skyrix-sope/WEExtensions/WETreeMatrixElement.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WETreeView.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEWeekColumnView.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WEWeekOverview.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WExCalElemBuilder.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WExDnDElemBuilder.m [new file with mode: 0644]
skyrix-sope/WEExtensions/WExExtElemBuilder.m [new file with mode: 0644]
skyrix-sope/WEExtensions/bundle-info.plist [new file with mode: 0644]
skyrix-sope/WEExtensions/calendar.js [new file with mode: 0644]
skyrix-sope/WEExtensions/calendar.jsm [new file with mode: 0644]
skyrix-sope/WEExtensions/calendar.m [new file with mode: 0644]
skyrix-sope/WEExtensions/common.h [new file with mode: 0644]
skyrix-sope/WEExtensions/dummy.m [new file with mode: 0644]
skyrix-sope/WEExtensions/js2m.sh [new file with mode: 0755]
skyrix-sope/WOExtensions/.cvsignore [new file with mode: 0644]
skyrix-sope/WOExtensions/COPYING [new file with mode: 0644]
skyrix-sope/WOExtensions/COPYRIGHT [new file with mode: 0644]
skyrix-sope/WOExtensions/ChangeLog [new file with mode: 0644]
skyrix-sope/WOExtensions/GNUmakefile [new file with mode: 0644]
skyrix-sope/WOExtensions/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/WOExtensions/JSAlertPanel.m [new file with mode: 0644]
skyrix-sope/WOExtensions/JSConfirmPanel.m [new file with mode: 0644]
skyrix-sope/WOExtensions/JSImageFlyover.m [new file with mode: 0644]
skyrix-sope/WOExtensions/JSKeyHandler.m [new file with mode: 0644]
skyrix-sope/WOExtensions/JSModalWindow.m [new file with mode: 0644]
skyrix-sope/WOExtensions/JSTextFlyover.m [new file with mode: 0644]
skyrix-sope/WOExtensions/JSValidatedField.m [new file with mode: 0644]
skyrix-sope/WOExtensions/Version [new file with mode: 0644]
skyrix-sope/WOExtensions/WOCheckBoxMatrix.m [new file with mode: 0644]
skyrix-sope/WOExtensions/WOCollapsibleComponentContent.m [new file with mode: 0644]
skyrix-sope/WOExtensions/WODictionaryRepetition.m [new file with mode: 0644]
skyrix-sope/WOExtensions/WOExtensions-Info.plist [new file with mode: 0644]
skyrix-sope/WOExtensions/WOExtensions.h [new file with mode: 0644]
skyrix-sope/WOExtensions/WOKeyValueConditional.m [new file with mode: 0644]
skyrix-sope/WOExtensions/WORadioButtonMatrix.m [new file with mode: 0644]
skyrix-sope/WOExtensions/WORedirect.h [new file with mode: 0644]
skyrix-sope/WOExtensions/WORedirect.m [new file with mode: 0644]
skyrix-sope/WOExtensions/WOTabPanel.m [new file with mode: 0644]
skyrix-sope/WOExtensions/WOTable.m [new file with mode: 0644]
skyrix-sope/WOExtensions/WOThresholdColoredNumber.m [new file with mode: 0644]
skyrix-sope/WOExtensions/WOxExtElemBuilder.m [new file with mode: 0644]
skyrix-sope/WOExtensions/bundle-info.plist [new file with mode: 0644]
skyrix-sope/WOExtensions/common.h [new file with mode: 0644]
skyrix-sope/WOExtensions/compat.m [new file with mode: 0644]
skyrix-sope/WOExtensions/dummy.m [new file with mode: 0644]
skyrix-sope/WOXML/COPYING [new file with mode: 0644]
skyrix-sope/WOXML/COPYRIGHT [new file with mode: 0644]
skyrix-sope/WOXML/ChangeLog [new file with mode: 0644]
skyrix-sope/WOXML/GNUmakefile [new file with mode: 0644]
skyrix-sope/WOXML/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/WOXML/README [new file with mode: 0644]
skyrix-sope/WOXML/Version [new file with mode: 0644]
skyrix-sope/WOXML/WOXML-Info.plist [new file with mode: 0644]
skyrix-sope/WOXML/WOXML.h [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLDecoder.h [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLDecoder.m [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLMapDecoder.h [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLMapDecoder.m [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLMappingEntity.h [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLMappingEntity.m [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLMappingModel.h [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLMappingModel.m [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLMappingProperty.h [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLMappingProperty.m [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLSaxModelHandler.h [new file with mode: 0644]
skyrix-sope/WOXML/WOXMLSaxModelHandler.m [new file with mode: 0644]
skyrix-sope/WOXML/common.h [new file with mode: 0644]
skyrix-sope/WOXML/samples/slashdot/GNUmakefile [new file with mode: 0644]
skyrix-sope/WOXML/samples/slashdot/SlashDotStory.m [new file with mode: 0644]
skyrix-sope/WOXML/samples/slashdot/slashdot.xmlmodel [new file with mode: 0644]
skyrix-sope/WOXML/samples/slashdot/woslash.m [new file with mode: 0644]
skyrix-sope/common.make [new file with mode: 0644]
skyrix-sope/samples/.cvsignore [new file with mode: 0644]
skyrix-sope/samples/COPYING [new file with mode: 0644]
skyrix-sope/samples/ChangeLog [new file with mode: 0644]
skyrix-sope/samples/GNUmakefile [new file with mode: 0644]
skyrix-sope/samples/HelloWorld/ChangeLog [new file with mode: 0644]
skyrix-sope/samples/HelloWorld/GNUmakefile [new file with mode: 0644]
skyrix-sope/samples/HelloWorld/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/samples/HelloWorld/HelloWorld.m [new file with mode: 0644]
skyrix-sope/samples/HelloWorld/Main.m [new file with mode: 0644]
skyrix-sope/samples/HelloWorld/Main.wo/Main.html [new file with mode: 0644]
skyrix-sope/samples/HelloWorld/Main.wo/Main.wod [new file with mode: 0644]
skyrix-sope/samples/HelloWorld/common.h [new file with mode: 0644]
skyrix-sope/samples/TestPages/ChangeLog [new file with mode: 0644]
skyrix-sope/samples/TestPages/GNUmakefile [new file with mode: 0644]
skyrix-sope/samples/TestPages/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/samples/TestPages/Main.m [new file with mode: 0644]
skyrix-sope/samples/TestPages/Main.wo/Main.html [new file with mode: 0644]
skyrix-sope/samples/TestPages/Main.wo/Main.wod [new file with mode: 0644]
skyrix-sope/samples/TestPages/TestPages.m [new file with mode: 0644]
skyrix-sope/samples/TestPages/TwoForms.m [new file with mode: 0644]
skyrix-sope/samples/TestPages/TwoForms.wo/TwoForms.html [new file with mode: 0644]
skyrix-sope/samples/TestPages/TwoForms.wo/TwoForms.wod [new file with mode: 0644]
skyrix-sope/samples/TestPages/common.h [new file with mode: 0644]
skyrix-sope/samples/TestSite/.sope.plist [new file with mode: 0644]
skyrix-sope/samples/TestSite/ChangeLog [new file with mode: 0644]
skyrix-sope/samples/TestSite/Debug.xtmpl [new file with mode: 0644]
skyrix-sope/samples/TestSite/Main.xtmpl [new file with mode: 0644]
skyrix-sope/samples/TestSite/Projects/Main.xtmpl [new file with mode: 0644]
skyrix-sope/samples/TestSite/Projects/OGoLogo.gif [new file with mode: 0644]
skyrix-sope/samples/TestSite/Projects/blogstyle.css [new file with mode: 0644]
skyrix-sope/samples/TestSite/Projects/index.wox [new file with mode: 0644]
skyrix-sope/samples/TestSite/Projects/projectcard.wox [new file with mode: 0644]
skyrix-sope/samples/TestSite/Projects/stylesheet.css [new file with mode: 0644]
skyrix-sope/samples/TestSite/README [new file with mode: 0644]
skyrix-sope/samples/TestSite/accept.gif [new file with mode: 0644]
skyrix-sope/samples/TestSite/embed.wox [new file with mode: 0644]
skyrix-sope/samples/TestSite/favicon.ico [new file with mode: 0644]
skyrix-sope/samples/TestSite/htpasswd [new file with mode: 0644]
skyrix-sope/samples/TestSite/images/banner-new.gif [new file with mode: 0644]
skyrix-sope/samples/TestSite/images/banner.gif [new file with mode: 0644]
skyrix-sope/samples/TestSite/images/banner_back.gif [new file with mode: 0644]
skyrix-sope/samples/TestSite/images/banner_left.gif [new file with mode: 0644]
skyrix-sope/samples/TestSite/images/banner_right.gif [new file with mode: 0644]
skyrix-sope/samples/TestSite/index.html [new file with mode: 0644]
skyrix-sope/samples/TestSite/plisttest/Main.xtmpl [new file with mode: 0644]
skyrix-sope/samples/TestSite/plisttest/MyNews1.plist [new file with mode: 0644]
skyrix-sope/samples/TestSite/plisttest/MyNews2.plist [new file with mode: 0644]
skyrix-sope/samples/TestSite/plisttest/index.wox [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/Main.xtmpl [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/NOTES.txt [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/index.wox [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/linkOpaque.gif [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/linkTransparent.gif [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/loggedin.html [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/plone.css [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/ploneCustom.css [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/ploneNS4.css [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/plonePresentation.css [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/plonePrint.css [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/plone_formtooltip.js [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/plone_javascripts.js [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/required.gif [new file with mode: 0644]
skyrix-sope/samples/TestSite/plone/searchbox.wox [new file with mode: 0644]
skyrix-sope/samples/TestSite/stylesheet.css [new file with mode: 0644]
skyrix-sope/samples/TestSite/subdir/index.wox [new file with mode: 0644]
skyrix-sope/samples/TestSite/test.wox [new file with mode: 0644]
skyrix-sope/samples/TestSite/webfolders.xhtml [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/AlertPanel.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/AlertPanel.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Browser.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Browser.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/CalendarField.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/CalendarField.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ChangeLog [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/CheckBoxMatrix.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/CheckBoxMatrix.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/CollapsibleContent.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/CollapsibleContent.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/CollapsibleContentExt.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/CollapsibleContentExt.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ConfirmPanel.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ConfirmPanel.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/DateField.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/DateField.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/DictionaryRepetition.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/DictionaryRepetition.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/DirectAction.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/DnD.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/DnD.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Frame.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Frame.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/GNUmakefile [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ImageFlyover.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ImageFlyover.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/KeyValueConditional.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/KeyValueConditional.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Lori.icns [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Main.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Main.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ModalWindow.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ModalWindow.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/MonthOverview.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/MonthOverview.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/PageView.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/PageView.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/PanelContent.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/PanelContent.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/QualifierConditional.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/QualifierConditional.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/RadioButtonMatrix.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/RadioButtonMatrix.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Resources/Dictionary.plist [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Resources/TableView.plist [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Resources/TreeView.plist [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Resources/appointments.plist [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/RichString.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/RichString.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ShiftClick.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ShiftClick.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Switch.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Switch.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TabPanel.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TabPanel.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TabView.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TabView.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Table.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/Table.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TableMatrix.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TableMatrix.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TableView.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TableView.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TextFlyover.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TextFlyover.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ThresholdColoredNumber.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ThresholdColoredNumber.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TimeField.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TimeField.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TreeView.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/TreeView.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ValidatedField.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/ValidatedField.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/VarString.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WOxExtTest.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WOxExtTest.pbproj/project.pbxproj [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/OGoLogo.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/collapsed.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/corner_left.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/corner_right.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/downward_sorted.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/expanded.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/first.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/first_blind.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/folder_closed.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/folder_opened.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/last.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/last_blind.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/menu_email.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/menu_email_inactive.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/next.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/next_blind.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/non_sorted.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/previous.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/previous_blind.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_left.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news_left.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news_selected.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons_left.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons_selected.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects_left.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects_selected.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/tab_selected.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner_minus.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner_plus.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_junction.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_leaf.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_leaf_corner.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_line.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_minus.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_plus.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_space.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WebServerResources/upward_sorted.gif [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WeekColumnView.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WeekColumnView.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WeekOverview.m [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/WeekOverview.wox [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/common.h [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/favicon.ico [new file with mode: 0644]
skyrix-sope/samples/WOxExtTest/site.css [new file with mode: 0644]
skyrix-sope/samples/davpropget/GNUmakefile [new file with mode: 0644]
skyrix-sope/samples/davpropget/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/samples/davpropget/NOTES [new file with mode: 0644]
skyrix-sope/samples/davpropget/README [new file with mode: 0644]
skyrix-sope/samples/davpropget/davpropget.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/.cvsignore [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/COPYING [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/COPYRIGHT [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/ChangeLog [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/DirectAction.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/back.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/back_menu.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/back_menu2.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/back_seite.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/banner_a.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/banner_b.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/banner_c.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/banner_d.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/banner_deutsch.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/banner_e.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/favicon.ico [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/feedback.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/free_hosting.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/line.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/main.strings [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/pixel.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/powered_by_publisher.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/search.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/sidesmiley.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/site.css [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/small.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/submit.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/tab_.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/tab_left.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/tab_selected.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/wp_config.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/wp_create.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/wp_faq.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/wp_feedback.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/English.lproj/wp_info.gif [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/GNUmakefile [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/German.lproj/main.strings [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/.cvsignore [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/GNUmakefile [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalBaseFrame.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalBaseFrame.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalBox.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalBox.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalCalTabs.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalCalTabs.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalDayOverview.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalDayOverview.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalFeedbackPage.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalFeedbackPage.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalFrame.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalFrame.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalHomePage.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalHomePage.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalLeftMenu.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalLeftMenu.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalLicensePage.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalLicensePage.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalMonthView.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalMonthView.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalProfilePage.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalProfilePage.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalRegistrationPage.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalRegistrationPage.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalRightMenu.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalRightMenu.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalToDoView.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalToDoView.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalWeekOverview.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalWeekOverview.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalWelcomePage.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/Pages/iCalPortalWelcomePage.wox [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/README [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/.cvsignore [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/GNUmakefile [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalAction.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalAction.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalDeleteAction.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalDeleteAction.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalGetAction.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalGetAction.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalLockAction.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalLockAction.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalOptionsAction.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalOptionsAction.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalPublishAction.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalPublishAction.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalRequestHandler.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/WebDAV/iCalRequestHandler.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/common.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/db/account.tmpl [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/db/donald/.account.plist [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/db/donald/korg.ics [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/db/donald/mozcal-clean.ics [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/db/donald/mozcal.ics [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/db/donald/shire-cal1.ics [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/db/donald/skytest1.ics [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/db/donald/skytest2.ics [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalDayView.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalDayView.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalPortal.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalPortal.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalPortalCalendar.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalPortalCalendar.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalPortalDatabase.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalPortalDatabase.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalPortalPage.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalPortalPage.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalPortalUser.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalPortalUser.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalView.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalView.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalWeekView.h [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/iCalWeekView.m [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/icons.make [new file with mode: 0644]
skyrix-sope/samples/iCalPortal/mkpage.sh [new file with mode: 0755]
skyrix-sope/samples/parsedav/DAVParserTest.h [new file with mode: 0644]
skyrix-sope/samples/parsedav/DAVParserTest.m [new file with mode: 0644]
skyrix-sope/samples/parsedav/GNUmakefile [new file with mode: 0644]
skyrix-sope/samples/parsedav/GNUmakefile.preamble [new file with mode: 0644]
skyrix-sope/samples/parsedav/README [new file with mode: 0644]
skyrix-sope/samples/parsedav/common.h [new file with mode: 0644]
skyrix-sope/samples/parsedav/data/propupt1.xml [new file with mode: 0644]
skyrix-sope/samples/parsedav/parsedav.m [new file with mode: 0644]
skyrix-xml/CFXMLSaxDriver/CFXMLSaxDriver-Info.plist [new file with mode: 0644]
skyrix-xml/CFXMLSaxDriver/CFXMLSaxDriver.h [new file with mode: 0644]
skyrix-xml/CFXMLSaxDriver/CFXMLSaxDriver.m [new file with mode: 0644]
skyrix-xml/CFXMLSaxDriver/COPYING [new file with mode: 0644]
skyrix-xml/CFXMLSaxDriver/ChangeLog [new file with mode: 0644]
skyrix-xml/CFXMLSaxDriver/README [new file with mode: 0644]
skyrix-xml/CFXMLSaxDriver/bundle-info.plist [new file with mode: 0644]
skyrix-xml/COPYING [new file with mode: 0644]
skyrix-xml/COPYRIGHT [new file with mode: 0644]
skyrix-xml/ChangeLog [new file with mode: 0644]
skyrix-xml/DOM/.cvsignore [new file with mode: 0644]
skyrix-xml/DOM/COPYING [new file with mode: 0644]
skyrix-xml/DOM/COPYRIGHT [new file with mode: 0644]
skyrix-xml/DOM/ChangeLog [new file with mode: 0644]
skyrix-xml/DOM/DOM+JS.m [new file with mode: 0644]
skyrix-xml/DOM/DOM-Info.plist [new file with mode: 0644]
skyrix-xml/DOM/DOM.h [new file with mode: 0644]
skyrix-xml/DOM/DOMAttribute.h [new file with mode: 0644]
skyrix-xml/DOM/DOMAttribute.m [new file with mode: 0644]
skyrix-xml/DOM/DOMBuilder.h [new file with mode: 0644]
skyrix-xml/DOM/DOMBuilderFactory.h [new file with mode: 0644]
skyrix-xml/DOM/DOMBuilderFactory.m [new file with mode: 0644]
skyrix-xml/DOM/DOMCDATASection.h [new file with mode: 0644]
skyrix-xml/DOM/DOMCDATASection.m [new file with mode: 0644]
skyrix-xml/DOM/DOMCharacterData.h [new file with mode: 0644]
skyrix-xml/DOM/DOMCharacterData.m [new file with mode: 0644]
skyrix-xml/DOM/DOMComment.h [new file with mode: 0644]
skyrix-xml/DOM/DOMComment.m [new file with mode: 0644]
skyrix-xml/DOM/DOMDocument+factory.m [new file with mode: 0644]
skyrix-xml/DOM/DOMDocument.h [new file with mode: 0644]
skyrix-xml/DOM/DOMDocument.m [new file with mode: 0644]
skyrix-xml/DOM/DOMDocumentBuilder.h [new file with mode: 0644]
skyrix-xml/DOM/DOMDocumentFragment.h [new file with mode: 0644]
skyrix-xml/DOM/DOMDocumentFragment.m [new file with mode: 0644]
skyrix-xml/DOM/DOMDocumentType.h [new file with mode: 0644]
skyrix-xml/DOM/DOMDocumentType.m [new file with mode: 0644]
skyrix-xml/DOM/DOMElement.h [new file with mode: 0644]
skyrix-xml/DOM/DOMElement.m [new file with mode: 0644]
skyrix-xml/DOM/DOMEntity.h [new file with mode: 0644]
skyrix-xml/DOM/DOMEntity.m [new file with mode: 0644]
skyrix-xml/DOM/DOMEntityReference.h [new file with mode: 0644]
skyrix-xml/DOM/DOMEntityReference.m [new file with mode: 0644]
skyrix-xml/DOM/DOMImplementation.h [new file with mode: 0644]
skyrix-xml/DOM/DOMImplementation.m [new file with mode: 0644]
skyrix-xml/DOM/DOMNamedNodeMap.h [new file with mode: 0644]
skyrix-xml/DOM/DOMNode+Enum.h [new file with mode: 0644]
skyrix-xml/DOM/DOMNode+Enum.m [new file with mode: 0644]
skyrix-xml/DOM/DOMNode+QPEval.m [new file with mode: 0644]
skyrix-xml/DOM/DOMNode+QueryPath.h [new file with mode: 0644]
skyrix-xml/DOM/DOMNode+QueryPath.m [new file with mode: 0644]
skyrix-xml/DOM/DOMNode.h [new file with mode: 0644]
skyrix-xml/DOM/DOMNode.m [new file with mode: 0644]
skyrix-xml/DOM/DOMNodeFilter.h [new file with mode: 0644]
skyrix-xml/DOM/DOMNodeFilter.m [new file with mode: 0644]
skyrix-xml/DOM/DOMNodeIterator.h [new file with mode: 0644]
skyrix-xml/DOM/DOMNodeIterator.m [new file with mode: 0644]
skyrix-xml/DOM/DOMNodeWalker.h [new file with mode: 0644]
skyrix-xml/DOM/DOMNodeWalker.m [new file with mode: 0644]
skyrix-xml/DOM/DOMNodeWithChildren.m [new file with mode: 0644]
skyrix-xml/DOM/DOMNotation.h [new file with mode: 0644]
skyrix-xml/DOM/DOMNotation.m [new file with mode: 0644]
skyrix-xml/DOM/DOMPYXOutputter.h [new file with mode: 0644]
skyrix-xml/DOM/DOMPYXOutputter.m [new file with mode: 0644]
skyrix-xml/DOM/DOMProcessingInstruction.h [new file with mode: 0644]
skyrix-xml/DOM/DOMProcessingInstruction.m [new file with mode: 0644]
skyrix-xml/DOM/DOMProtocols.h [new file with mode: 0644]
skyrix-xml/DOM/DOMQueryPathExpression.h [new file with mode: 0644]
skyrix-xml/DOM/DOMQueryPathExpression.m [new file with mode: 0644]
skyrix-xml/DOM/DOMSaxBuilder.h [new file with mode: 0644]
skyrix-xml/DOM/DOMSaxBuilder.m [new file with mode: 0644]
skyrix-xml/DOM/DOMSaxHandler.h [new file with mode: 0644]
skyrix-xml/DOM/DOMSaxHandler.m [new file with mode: 0644]
skyrix-xml/DOM/DOMText.h [new file with mode: 0644]
skyrix-xml/DOM/DOMText.m [new file with mode: 0644]
skyrix-xml/DOM/DOMTreeWalker.h [new file with mode: 0644]
skyrix-xml/DOM/DOMTreeWalker.m [new file with mode: 0644]
skyrix-xml/DOM/DOMXMLOutputter.h [new file with mode: 0644]
skyrix-xml/DOM/DOMXMLOutputter.m [new file with mode: 0644]
skyrix-xml/DOM/EDOM.h [new file with mode: 0644]
skyrix-xml/DOM/GNUmakefile [new file with mode: 0644]
skyrix-xml/DOM/GNUmakefile.preamble [new file with mode: 0644]
skyrix-xml/DOM/NSObject+DOM.m [new file with mode: 0644]
skyrix-xml/DOM/NSObject+QPEval.h [new file with mode: 0644]
skyrix-xml/DOM/NSObject+QPEval.m [new file with mode: 0644]
skyrix-xml/DOM/NSObject+StringValue.h [new file with mode: 0644]
skyrix-xml/DOM/NSObject+StringValue.m [new file with mode: 0644]
skyrix-xml/DOM/README [new file with mode: 0644]
skyrix-xml/DOM/SxXML-DOM.graffle [new file with mode: 0644]
skyrix-xml/DOM/TODO [new file with mode: 0644]
skyrix-xml/DOM/Version [new file with mode: 0644]
skyrix-xml/DOM/common.h [new file with mode: 0644]
skyrix-xml/ExpatSaxDriver/COPYING [new file with mode: 0644]
skyrix-xml/ExpatSaxDriver/ExpatSaxDriver.m [new file with mode: 0644]
skyrix-xml/ExpatSaxDriver/GNUmakefile [new file with mode: 0644]
skyrix-xml/ExpatSaxDriver/README [new file with mode: 0644]
skyrix-xml/ExpatSaxDriver/bundle-info.plist [new file with mode: 0644]
skyrix-xml/ExpatSaxDriver/common.h [new file with mode: 0644]
skyrix-xml/ExpatSaxDriver/unicode.h [new file with mode: 0644]
skyrix-xml/GNUmakefile [new file with mode: 0644]
skyrix-xml/PROJECTLEAD [new file with mode: 0644]
skyrix-xml/PlistSaxDriver/GNUmakefile [new file with mode: 0644]
skyrix-xml/PlistSaxDriver/PlistSaxDriver.m [new file with mode: 0644]
skyrix-xml/PlistSaxDriver/README [new file with mode: 0644]
skyrix-xml/PlistSaxDriver/bundle-info.plist [new file with mode: 0644]
skyrix-xml/README [new file with mode: 0644]
skyrix-xml/README-OSX.txt [new file with mode: 0644]
skyrix-xml/STXSaxDriver/.cvsignore [new file with mode: 0644]
skyrix-xml/STXSaxDriver/COPYING.LIB [new file with mode: 0644]
skyrix-xml/STXSaxDriver/COPYRIGHT [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ChangeLog [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/.cvsignore [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/COPYRIGHT [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/GNUmakefile [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/NSString+STX.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/NSString+STX.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/README [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/StructuredLine.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/StructuredLine.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/StructuredStack.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/StructuredStack.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/StructuredTextRenderingDelegate.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText_XHTML.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText_XHTML.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/GNUmakefile [new file with mode: 0644]
skyrix-xml/STXSaxDriver/GNUmakefile.postamble [new file with mode: 0644]
skyrix-xml/STXSaxDriver/GNUmakefile.preamble [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/.cvsignore [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/COPYRIGHT [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/GNUmakefile [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/README [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextBodyElement.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextBodyElement.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextDocument.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextDocument.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextHeader.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextHeader.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextList.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextList.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextListItem.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextListItem.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextLiteralBlock.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextLiteralBlock.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextParagraph.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Model/StructuredTextParagraph.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/README [new file with mode: 0644]
skyrix-xml/STXSaxDriver/STXSaxDriver-Info.plist [new file with mode: 0644]
skyrix-xml/STXSaxDriver/STXSaxDriver.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/STXSaxDriver.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/StructuredTextBodyElement+SAX.m [new file with mode: 0644]
skyrix-xml/STXSaxDriver/TODO [new file with mode: 0644]
skyrix-xml/STXSaxDriver/Version [new file with mode: 0644]
skyrix-xml/STXSaxDriver/bundle-info.plist [new file with mode: 0644]
skyrix-xml/STXSaxDriver/common.h [new file with mode: 0644]
skyrix-xml/STXSaxDriver/data/extra_test1-expect.pyx [new file with mode: 0644]
skyrix-xml/STXSaxDriver/data/extra_test1.stx [new file with mode: 0644]
skyrix-xml/STXSaxDriver/data/extra_test2-expect.pyx [new file with mode: 0644]
skyrix-xml/STXSaxDriver/data/extra_test2.stx [new file with mode: 0644]
skyrix-xml/STXSaxDriver/data/hhtest1-expect.pyx [new file with mode: 0644]
skyrix-xml/STXSaxDriver/data/hhtest1.stx [new file with mode: 0644]
skyrix-xml/STXSaxDriver/data/hhtest2.stx [new file with mode: 0644]
skyrix-xml/STXSaxDriver/data/hhtest3-expect.pyx [new file with mode: 0644]
skyrix-xml/STXSaxDriver/data/hhtest3.stx [new file with mode: 0644]
skyrix-xml/SaxObjC/.cvsignore [new file with mode: 0644]
skyrix-xml/SaxObjC/COPYING [new file with mode: 0644]
skyrix-xml/SaxObjC/COPYRIGHT [new file with mode: 0644]
skyrix-xml/SaxObjC/ChangeLog [new file with mode: 0644]
skyrix-xml/SaxObjC/GNUmakefile [new file with mode: 0644]
skyrix-xml/SaxObjC/GNUmakefile.preamble [new file with mode: 0644]
skyrix-xml/SaxObjC/README [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxAttributeList.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxAttributeList.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxAttributes.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxAttributes.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxContentHandler.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxDTDHandler.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxDeclHandler.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxDefaultHandler+NSXML.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxDefaultHandler.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxDefaultHandler.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxDocumentHandler.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxEntityResolver.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxErrorHandler.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxException.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxException.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxHandlerBase.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxHandlerBase.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxLexicalHandler.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxLocator.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxLocator.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxMethodCallHandler.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxMethodCallHandler.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxNamespaceSupport.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxNamespaceSupport.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxObjC-Info.plist [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxObjC.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxObjectDecoder.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxObjectDecoder.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxObjectModel.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxObjectModel.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxXMLFilter.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxXMLFilter.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxXMLReader.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxXMLReaderFactory.h [new file with mode: 0644]
skyrix-xml/SaxObjC/SaxXMLReaderFactory.m [new file with mode: 0644]
skyrix-xml/SaxObjC/SxXML-SaxObjC.graffle [new file with mode: 0644]
skyrix-xml/SaxObjC/TODO [new file with mode: 0644]
skyrix-xml/SaxObjC/Version [new file with mode: 0644]
skyrix-xml/SaxObjC/XMLNamespaces.h [new file with mode: 0644]
skyrix-xml/SaxObjC/common.h [new file with mode: 0644]
skyrix-xml/SaxObjC/libSAXObjC.def [new file with mode: 0644]
skyrix-xml/SxXML-Info.plist [new file with mode: 0644]
skyrix-xml/SxXML.xcode/.cvsignore [new file with mode: 0644]
skyrix-xml/SxXML.xcode/project.pbxproj [new file with mode: 0644]
skyrix-xml/TODO [new file with mode: 0644]
skyrix-xml/Version [new file with mode: 0644]
skyrix-xml/XmlRpc/.cvsignore [new file with mode: 0644]
skyrix-xml/XmlRpc/COPYING [new file with mode: 0644]
skyrix-xml/XmlRpc/COPYRIGHT [new file with mode: 0644]
skyrix-xml/XmlRpc/ChangeLog [new file with mode: 0644]
skyrix-xml/XmlRpc/GNUmakefile [new file with mode: 0644]
skyrix-xml/XmlRpc/GNUmakefile.preamble [new file with mode: 0644]
skyrix-xml/XmlRpc/NSArray+XmlRpcCoding.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSData+XmlRpcCoding.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSDate+XmlRpcCoding.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSDictionary+XmlRpcCoding.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSException+XmlRpcCoding.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSHost+XmlRpcCoding.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSMutableString+XmlRpcDecoder.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSNotification+XmlRpcCoding.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSNumber+XmlRpcCoding.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSObject+XmlRpc.h [new file with mode: 0644]
skyrix-xml/XmlRpc/NSObject+XmlRpc.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSString+XmlRpcCoding.m [new file with mode: 0644]
skyrix-xml/XmlRpc/NSURL+XmlRpcCoding.m [new file with mode: 0644]
skyrix-xml/XmlRpc/SxXML-XmlRpc.graffle [new file with mode: 0644]
skyrix-xml/XmlRpc/Version [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpc-Info.plist [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpc.h [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcCoder.h [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcDecoder.m [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcEncoder.m [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcMethodCall.h [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcMethodCall.m [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcMethodResponse.h [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcMethodResponse.m [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcRequestDecoder.m [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcRequestEncoder.m [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcResponseDecoder.m [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcResponseEncoder.m [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcSaxHandler.h [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcSaxHandler.m [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcValue.h [new file with mode: 0644]
skyrix-xml/XmlRpc/XmlRpcValue.m [new file with mode: 0644]
skyrix-xml/XmlRpc/common.h [new file with mode: 0644]
skyrix-xml/common.make [new file with mode: 0644]
skyrix-xml/dummy.c [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/COPYING [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/COPYRIGHT [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/ChangeLog [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/GNUmakefile [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/GNUmakefile.postamble [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/GNUmakefile.preamble [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/ICalSaxParser.h [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/ICalSaxParser.m [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/NSCalendarDate+ICal.h [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/NSCalendarDate+ICal.m [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/NSString+ICal.h [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/NSString+ICal.m [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/README [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/TODO [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/Version [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/bundle-info.plist [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/common.h [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/iCalSaxDriver-Info.plist [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/test1.ics [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/test2.vfb [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/test3.ics [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/test4.ics [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/test5-entourage.ics [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/test6-appleical.ics [new file with mode: 0644]
skyrix-xml/iCalSaxDriver/unicode.h [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/.cvsignore [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/COPYING [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/COPYRIGHT [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/ChangeLog [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/GNUmakefile [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/GNUmakefile.preamble [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/README [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/TableCallbacks.h [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/TableCallbacks.m [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/Version [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/bundle-info.plist [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/common.h [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/libxmlDocSAXDriver.h [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/libxmlDocSAXDriver.m [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/libxmlSAXDriver-Info.plist [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/libxmlSAXDriver.h [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/libxmlSAXDriver.m [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/libxmlSAXLocator.h [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/libxmlSAXLocator.m [new file with mode: 0644]
skyrix-xml/libxmlSAXDriver/unicode.h [new file with mode: 0644]
skyrix-xml/pyxSAXDriver/COPYING [new file with mode: 0644]
skyrix-xml/pyxSAXDriver/ChangeLog [new file with mode: 0644]
skyrix-xml/pyxSAXDriver/GNUmakefile [new file with mode: 0644]
skyrix-xml/pyxSAXDriver/README [new file with mode: 0644]
skyrix-xml/pyxSAXDriver/bundle-info.plist [new file with mode: 0644]
skyrix-xml/pyxSAXDriver/pyxSAXDriver-Info.plist [new file with mode: 0644]
skyrix-xml/pyxSAXDriver/pyxSAXDriver.h [new file with mode: 0644]
skyrix-xml/pyxSAXDriver/pyxSAXDriver.m [new file with mode: 0644]
skyrix-xml/pyxSAXDriver/slashdot.pyx [new file with mode: 0644]
skyrix-xml/samples/.cvsignore [new file with mode: 0644]
skyrix-xml/samples/ChangeLog [new file with mode: 0644]
skyrix-xml/samples/GNUmakefile [new file with mode: 0644]
skyrix-xml/samples/README [new file with mode: 0644]
skyrix-xml/samples/common.h [new file with mode: 0644]
skyrix-xml/samples/data/Main.xtmpl [new file with mode: 0644]
skyrix-xml/samples/data/skyrix-xml.xml [new file with mode: 0644]
skyrix-xml/samples/data/slashdot.rss [new file with mode: 0644]
skyrix-xml/samples/domxml.m [new file with mode: 0644]
skyrix-xml/samples/rss2plist1.m [new file with mode: 0644]
skyrix-xml/samples/rss2plist2.m [new file with mode: 0644]
skyrix-xml/samples/rssparse.m [new file with mode: 0644]
skyrix-xml/samples/rssparse.xmap [new file with mode: 0644]
skyrix-xml/samples/saxxml.m [new file with mode: 0644]
skyrix-xml/samples/testqp.m [new file with mode: 0644]
skyrix-xml/samples/xmln.m [new file with mode: 0644]
svn-commit.tmp [new file with mode: 0644]

diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644 (file)
index 0000000..c684af4
--- /dev/null
@@ -0,0 +1,14 @@
+# $Id$
+
+# Note: could be that it doesn't fully compile 'inline'
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECTS += \
+       skyrix-xml      \
+       skyrix-core     \
+       skyrix-sope
+
+-include $(GNUSTEP_MAKEFILES)/GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/aggregate.make
+-include $(GNUSTEP_MAKEFILES)/GNUmakefile.postamble
diff --git a/PROJECTLEAD b/PROJECTLEAD
new file mode 100644 (file)
index 0000000..ab0c70a
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+PROJECTLEAD=helge.hess@opengroupware.org
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..f9b569d
--- /dev/null
+++ b/README
@@ -0,0 +1,54 @@
+# $Id$
+
+SKYRiX Object Publishing Environment
+====================================
+
+This directory contains SOPE, the application server hosting the
+OpenGroupware.org business logic and web interface.
+
+mod_ngobjweb
+============
+
+An Apache module for forwarding HTTP request from Apache to a SOPE
+application server. This is a non-streaming proxy so that the application
+server isn't blocked by IO of slow connections !
+(this eliminates the need for threading because of IO, the Apache server
+ pool runs the blocking IO operations)
+
+SKYRiX Libraries for XML Processing (skyrix-xml)
+================================================
+
+The package contains:
+- a SAX2 Implementation for Objective-C
+- SaxObjC driver bundles for: libxml2 (HTML, XML), libical (iCalendar, 
+  vCard), expat (XML), plists, pyx, CoreFoundation (XML)
+- DOM on top of SaxObjC
+- an XML-RPC implementation (without the transport layer)
+
+SKYRiX Core Libraries (skyrix-core)
+===================================
+
+The SKYRiX Core libraries (skyrix-core) contain:
+- various Foundation extensions
+- a java.io like stream and socket library
+- classes for processing MIME entities
+- a full IMAP4 implementation
+- prototypical POP3 and SMTP processors
+- an Objective-C wrapper for LDAP directory services
+- classes for iCalendar/vCard objects
+
+SKYRiX Application Server (SOPE)
+================================
+
+The SKYRiX SOPE package is a framework for developing web applications and 
+services. The name "SOPE" (SKYRiX Object Publishing Environment) is 
+inspired by ZOPE ;-)
+
+It provides
+- template rendering engine, lots of dynamic elements
+- HTTP client/server
+- XML-RPC client
+- WebDAV server framework
+- session management
+- scripting extensions for Foundation, JavaScript bridge
+- DOM tree rendering library
diff --git a/Version b/Version
new file mode 100644 (file)
index 0000000..ef15de7
--- /dev/null
+++ b/Version
@@ -0,0 +1,12 @@
+# $Id$
+#
+# This file is included by library makefiles to set the version information 
+# of the executable.
+
+# Note:
+#   These versions do not say anything about the OpenGroupware.org "release"
+#   version. It's just the "compatibility" version used for shared libraries.
+
+MAJOR_VERSION=5
+MINOR_VERSION=0
+SUBMINOR_VERSION=0
diff --git a/mod_ngobjweb/.cvsignore b/mod_ngobjweb/.cvsignore
new file mode 100644 (file)
index 0000000..e89ac98
--- /dev/null
@@ -0,0 +1 @@
+core.*
diff --git a/mod_ngobjweb/CHANGES b/mod_ngobjweb/CHANGES
new file mode 100644 (file)
index 0000000..89893e1
--- /dev/null
@@ -0,0 +1,16 @@
+Fri Jan 31 13:04:03 CET 2003  Helge Hess <hh@skyrix.com>
+-------------------------------------------------------------
+
+- fixed a small bug in the configuration of SNSAppPrefix
+  => not used in SkyrixGreen
+
+-------------------------------------------------------------
+Tue Dec 10 12:33:00 CET 2002  Helge Hess <hh@skyrix.com>
+
+- created CHANGES file to document changes on a higher level
+
+-------------------------------------------------------------
+Tue Jul  2 16:09:56 2002  Jan Reichmann  <jan@skyrix.com>
+
+- fixed SuSE Bug 13871 (improper handling of umlauts in HTTP
+  header fields - required for filenames in downloads)
diff --git a/mod_ngobjweb/COPYRIGHT b/mod_ngobjweb/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/mod_ngobjweb/ChangeLog b/mod_ngobjweb/ChangeLog
new file mode 100644 (file)
index 0000000..62971b8
--- /dev/null
@@ -0,0 +1,75 @@
+2004-04-02  Marcus Mueller <znek@mulle-kybernetik.com>
+
+       * README: Minor additions/changes for Apache 1.3.x
+
+2003-12-22  Frank Reppin  <frank@opengroupware.org>
+
+       * handler.c: ap_setup_client_block before ap_get_client_block
+         which fixes the issue reported in Bug #354.
+         Tested with 2.0.40/2.0.47/2.0.48
+
+       * thanks to Frank Wuebbeling <wuebbel@math dot uni-muenster dot de>
+         for pointing!
+
+2003-08-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * handler.c: if r->handler is NULL on Apache2, decline request - might
+         have been the cause for some crashes with Apache2
+
+2003-08-01  Bjoern Stierand  <bjoern@opengroupware.org>
+
+       * globals.c, common.h: added some missing headers to remove compilation
+          warnings on FreeBSD RELENG_4 (thanks to Frank Reppin <fr@skyrix.com>)
+
+2003-07-15  Thomas Woerner <twoerner@redhat.com>
+
+       * port to apache 2.x
+       
+       * thanks to Ricardo Cerqueira <ricardo@cerqueira.org> for testing
+       
+2003-02-05  Helge Hess  <helge.hess@skyrix.com>
+
+       * globals.c: disable HEAVY_LOG per default
+
+2003-01-31  Helge Hess  <helge.hess@skyrix.com>
+
+       * config.c: fixed a bug in the configuration of SNSAppPrefix
+
+2002-12-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * added CHANGES
+
+Tue Jul  2 16:09:56 2002  Jan Reichmann  <jan@skyrix.com>
+
+       * NGBufferedDescriptor.c: char -> unsigned char (fixes SuSE Bug 
+         13871),umlauts in HTTP were not correctly handled by the ngobjweb
+         proxy module
+
+Sat Mar 23 17:18:58 2002  Helge Hess  <helge.hess@skyrix.com>
+       
+       * removed "global" sns config (you need to specify the sns
+         explicitly using SetSNSPort
+       
+       * handler.c: major cleanups
+
+2001-11-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * sns.c (_sendSNSQuery): added fail-codes
+
+Tue Oct  9 15:42:07 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * sns.c: removed support for SNS over HTTP
+
+Wed Feb 28 16:03:14 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * sns.c (_sendSNSQuery): fixed bugs in HTTP support
+
+Fri Dec  1 16:08:00 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * added apxs support
+
+Tue Aug  3 16:35:38 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * sns.c (_sendSNSQuery): fixed bug, returned Unix-domain addresses 
+         were not null terminated (the SUN_LEN of an address is excluding 
+         the zero byte which is therefore not transferred by snsd)
diff --git a/mod_ngobjweb/GNUmakefile b/mod_ngobjweb/GNUmakefile
new file mode 100644 (file)
index 0000000..4f7cb84
--- /dev/null
@@ -0,0 +1,90 @@
+# $Id$
+
+-include $(GNUSTEP_MAKEFILES)/common.make
+
+# config
+
+APACHE = /usr
+APXS   = $(APACHE)/sbin/apxs
+HTTPD  = $(APACHE)/sbin/httpd
+
+ifneq ($(apxs),no)
+ifneq ($(apxs),yes)
+ifneq ($(apxs),)
+APXS=$(apxs)
+else
+APXS=$(shell which apxs)
+endif
+else
+APXS=$(shell which apxs)
+endif
+else
+APXS=
+endif
+
+APACHE_VERSION = $(shell ./apversion.sh -v ${HTTPD} | head -n 1)
+#APACHE_SSL     = $(shell ./apversion.sh -iseapi ${HTTPD})
+APACHE_SSL     =
+
+ifneq ($(APXS),)
+ifneq ($(shared),no)
+APXS_CFLAGS       = $(shell $(APXS) -q CFLAGS_SHLIB) $(shell $(APXS) -q CFLAGS)
+APXS_INCLUDE_DIRS = -I$(shell $(APXS) -q INCLUDEDIR)
+APXS_LIBS         = -l$(shell$ (APXS) -q LIBS_SHLIB)
+APXS_LDFLAGS      = $(shell $(APXS) -q LDFLAGS_SHLIB)
+else
+ifneq ($(APXS),)
+APXS_CFLAGS       = $(shell $(APXS) -q CFLAGS)
+APXS_INCLUDE_DIRS = -I$(shell $(APXS) -q INCLUDEDIR)
+else
+APXS_CFLAGS       = 
+APXS_INCLUDE_DIRS = 
+endif
+endif
+else # no apxs available
+
+APXS_CFLAGS="-DSHARED_MODULE -O2 -DEAPI_MM -fPIC -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHARD_SERVER_LIMIT=2048 -DDYNAMIC_MODULE_LIMIT=128 -DLINUX=22 -DMOD_SSL=208103 -DEAPI -DUSE_EXPAT"
+
+endif
+
+GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT)/Library/WOAdaptors/Apache
+
+CC            = gcc
+LD            = gcc
+SHARED_LIBEXT = .so
+
+CFLAGS  = -Wall -I. -fPIC $(APXS_CFLAGS) $(APXS_INCLUDE_DIRS)
+LDFLAGS = $(APXS_LDFLAGS) -shared -fPIC
+
+# adaptor
+
+OFILES = \
+       globals.o               \
+       handler.o               \
+       NGBufferedDescriptor.o  \
+       scanhttp.o              \
+       sns.o                   \
+       config.o                \
+       ngobjweb_module.o       \
+
+ifeq ($(APACHE_SSL),yes)
+APACHE_SSL=ssl
+else
+APACHE_SSL=
+endif
+
+product = ngobjweb$(APACHE_SSL)_$(APACHE_VERSION)$(SHARED_LIBEXT)
+
+all : $(product)
+
+clean : 
+       rm -f *.o $(product) *.so *~
+
+apache-dir :
+       $(MKDIRS) $(GNUSTEP_INSTALLATION_DIR)
+
+install : apache-dir all
+       $(INSTALL_PROGRAM) $(product) $(GNUSTEP_INSTALLATION_DIR)
+
+$(product) : $(OFILES)
+       $(LD) $(LDFLAGS) -o $@ $(OFILES) $(EXTRA_LDFLAGS)
diff --git a/mod_ngobjweb/NGBufferedDescriptor.c b/mod_ngobjweb/NGBufferedDescriptor.c
new file mode 100644 (file)
index 0000000..620ae40
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "NGBufferedDescriptor.h"
+
+// returns the number of bytes which where read from the buffer
+#define numberOfConsumedReadBufferBytes(self) \
+  ((self->readBufferSize == 0) ? 0 : (self->readBufferPos - self->readBuffer))
+
+// returns the number of bytes which can be read from buffer (without source access)
+#define numberOfAvailableReadBufferBytes(self) \
+  (self->readBufferFillSize - numberOfConsumedReadBufferBytes(self))
+
+// look whether all bytes in the buffer where consumed, if so, reset the buffer
+#define checkReadBufferFillState(self) \
+  if (numberOfAvailableReadBufferBytes(self) == 0) { \
+    self->readBufferPos = self->readBuffer; \
+    self->readBufferFillSize = 0;  \
+  }
+
+// implementation
+
+NGBufferedDescriptor *
+NGBufferedDescriptor_newWithDescriptorAndSize(int _fd, int _size)
+{
+  NGBufferedDescriptor *self = malloc(sizeof(NGBufferedDescriptor));
+  if (self) {
+    self->fd                  = _fd;
+    self->readBuffer          = malloc(_size);
+    self->writeBuffer         = malloc(_size);
+    self->readBufferPos       = self->readBuffer;
+    self->readBufferSize      = _size;
+    self->readBufferFillSize  = 0; // no bytes are read from source
+    self->writeBufferFillSize = 0;
+    self->writeBufferSize     = _size;
+    self->ownsFd              = 0;
+  }
+  return self;
+}
+
+NGBufferedDescriptor *NGBufferedDescriptor_newWithDescriptor(int _fd) {
+  return NGBufferedDescriptor_newWithDescriptorAndSize(_fd, 1024);
+}
+NGBufferedDescriptor *
+NGBufferedDescriptor_newWithOwnedDescriptorAndSize(int _fd, int _size) {
+  NGBufferedDescriptor *self = NULL;
+  
+  if ((self = NGBufferedDescriptor_newWithDescriptorAndSize(_fd, _size)))
+    self->ownsFd = 1;
+  else
+    close(_fd);
+  return self;
+}
+
+void NGBufferedDescriptor_free(NGBufferedDescriptor *self) {
+  if (self) {
+    NGBufferedDescriptor_flush(self);
+
+    if (self->ownsFd && self->fd != -1) {
+      close(self->fd);
+      self->fd = -1;
+    }
+
+    if (self->readBuffer) {
+      free(self->readBuffer);
+      self->readBuffer    = NULL;
+      self->readBufferPos = NULL;
+    }
+    self->readBufferFillSize = 0;
+    self->readBufferSize     = 0;
+
+    if (self->writeBuffer) {
+      free(self->writeBuffer);
+      self->writeBuffer = NULL;
+    }
+    self->writeBufferFillSize = 0;
+    self->writeBufferSize     = 0;
+    
+    free(self);
+  }
+}
+
+int NGBufferedDescriptor_getReadBufferSize(NGBufferedDescriptor *self) {
+  if (self == NULL) return 0;
+  return self->readBufferSize;
+}
+int NGBufferedDescriptor_getWriteBufferSize(NGBufferedDescriptor *self) {
+  if (self == NULL) return 0;
+  return self->writeBufferSize;
+}
+
+int NGBufferedDescriptor_read(NGBufferedDescriptor *self,
+                                   void *_buf, int _len) {
+  register int availBytes = numberOfAvailableReadBufferBytes(self);
+
+  if (self == NULL) return 0;
+  
+  if (self->readBufferSize == 0) { // no read buffering is done (buffersize==0)
+    return read(self->fd, _buf, _len);
+  }
+    
+  if (availBytes >= _len) {
+    // there are enough bytes in the buffer to fulfill the request
+    if (_len == 1) {
+      *(unsigned char *)_buf = *(unsigned char *)self->readBufferPos;
+      self->readBufferPos++;
+    }
+    else {
+      memcpy(_buf, self->readBufferPos, _len);
+      self->readBufferPos += _len;          // update read position (consumed-size)
+    }
+    checkReadBufferFillState(self); // check whether all bytes where consumed
+    return _len;
+  }
+  else if (availBytes > 0) {
+    // there are some bytes in the buffer, these are returned
+    
+    memcpy(_buf, self->readBufferPos, availBytes); // copy all bytes from buffer
+    self->readBufferPos      = self->readBuffer; // reset position
+    self->readBufferFillSize = 0;        // no bytes available in buffer anymore
+    return availBytes;
+  }
+  else if (_len > self->readBufferSize) {
+    // requested _len is bigger than the buffersize, so we can bypass the
+    // buffer (which is empty, as guaranteed by the previous 'ifs'
+    return read(self->fd, _buf, _len);
+  }
+  else {
+    // no bytes are available and the requested _len is smaller than the possible
+    // buffer size, we have to read the next block of input from the source
+
+    self->readBufferFillSize = read(self->fd,
+                                    self->readBuffer, self->readBufferSize);
+
+    // no comes a section which is roughly the same like the first to conditionals
+    // in this method
+    if (self->readBufferFillSize >= _len) {
+      // there are enough bytes in the buffer to fulfill the request
+    
+      memcpy(_buf, self->readBufferPos, _len);
+      self->readBufferPos += _len;          // update read position (consumed-size)
+      checkReadBufferFillState(self); // check whether all bytes where consumed
+      return _len;
+    }
+    else { // (readBufferFillSize > 0) (this is ensured by the above assert)
+      // there are some bytes in the buffer, these are returned
+
+      availBytes = self->readBufferFillSize;
+      memcpy(_buf, self->readBufferPos, self->readBufferFillSize); // copy all bytes from buffer
+      self->readBufferPos      = self->readBuffer; // reset position
+      self->readBufferFillSize = 0;          // no bytes available in buffer anymore
+      return availBytes;
+    }
+  }
+}
+
+int NGBufferedDescriptor_write(NGBufferedDescriptor *self,
+                               const void *_buf, int _len)
+{
+  register int  tmp       = 0;
+  register int  remaining = _len;
+  register void *track    = (void *)_buf;
+
+  if (self == NULL) return 0;
+  
+  while (remaining > 0) {
+    // how much bytes available in buffer ?
+    tmp = self->writeBufferSize - self->writeBufferFillSize; 
+    tmp = (tmp > remaining) ? remaining : tmp;
+  
+    memcpy((self->writeBuffer + self->writeBufferFillSize), track, tmp);
+    track += tmp;
+    remaining -= tmp;
+    self->writeBufferFillSize += tmp;
+
+    if (self->writeBufferFillSize == self->writeBufferSize) {
+      void *pos = self->writeBuffer;
+
+      while (self->writeBufferFillSize > 0) {
+        int result;
+        
+        result = write(self->fd, pos, self->writeBufferFillSize);
+        
+        if ((result == 0) || (result < 0)) { // socket closed || error
+          self->writeBufferFillSize = 0; // content is lost ..
+          return result;
+        }
+        self->writeBufferFillSize -= result;
+        pos += result;
+      }
+    }
+  }
+
+#if 0
+  if (self->flags._flushOnNewline == 1) {
+    // scan buffer for newlines, if one is found, flush buffer
+    
+    for (tmp = 0; tmp < _len; tmp++) {
+      if (tmp == '\n') {
+        NGBufferedDescriptor_flush(self);
+        break;
+      }
+    }
+  }
+#endif
+  
+  // clean up for GC
+  tmp       = 0;    
+  track     = NULL; // clean up for GC
+  remaining = 0;
+  
+  return _len;
+}
+
+char NGBufferedDescriptor_flush(NGBufferedDescriptor *self) {
+  if (self == NULL) return 0;
+  
+  if (self->writeBufferFillSize > 0) {
+    int  toGo = self->writeBufferFillSize;
+    void *pos = self->writeBuffer;
+
+    while (toGo > 0) {
+      int result = write(self->fd, pos, toGo);
+
+      if (result == 0) // socket was closed
+        return 0;
+      else if (result < 1) // socket error
+        return 0;
+
+      toGo -= result;
+      pos  += result;
+    }
+    self->writeBufferFillSize = 0;
+  }
+  return 1;
+}
+
+unsigned char NGBufferedDescriptor_safeRead(NGBufferedDescriptor *self,
+                                            void *_buffer, int _len) {
+  if (self == NULL) return 0;
+  
+  if (_len > 0) {
+    while (_len > 0) {
+      int result = NGBufferedDescriptor_read(self, _buffer, _len);
+
+      if (result == 0) // socket was closed
+        return 0;
+      else if (result < 1) // socket error
+        return 0;
+
+      _len    -= result;
+      _buffer += result;
+    }
+  }
+  return 1;
+}
+char NGBufferedDescriptor_safeWrite(NGBufferedDescriptor *self,
+                                    const void *_buffer, int _len) {
+  if (self == NULL) return 0;
+  
+  if (_len > 0) {
+    while (_len > 0) {
+      int result;
+      
+      result = NGBufferedDescriptor_write(self, _buffer, _len);
+      
+      if (result == 0) // socket was closed
+        return 0;
+      else if (result < 1) // socket error
+        return 0;
+
+      _len    -= result;
+      _buffer += result;
+    }
+  }
+  return 1;
+}
+
+int NGBufferedDescriptor_readChar(NGBufferedDescriptor *self) {
+  unsigned char c;
+  return (NGBufferedDescriptor_safeRead(self, &c, 1)) ? c : -1;
+}
+
+char NGBufferedDescriptor_writeHttpHeader(NGBufferedDescriptor *self,
+                                          const unsigned char *_key,
+                                          const unsigned char *_value)
+{
+  if (NGBufferedDescriptor_safeWrite(self, _key, strlen(_key))) {
+    if (NGBufferedDescriptor_safeWrite(self, ": ", 2)) {
+      if (NGBufferedDescriptor_safeWrite(self, _value, strlen(_value))) {
+        if (NGBufferedDescriptor_safeWrite(self, "\r\n", 2)) {
+          return 1;
+        }
+      }
+    }
+  }
+  return 0;
+}
diff --git a/mod_ngobjweb/NGBufferedDescriptor.h b/mod_ngobjweb/NGBufferedDescriptor.h
new file mode 100644 (file)
index 0000000..9e489f8
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGBufferedDescriptor_H__
+#define __NGBufferedDescriptor_H__
+
+typedef struct _NGBufferedDescriptor {
+  int  fd; // descriptor
+  void *readBuffer;
+  void *readBufferPos;     // current position (ptr) in buffer
+  int  readBufferFillSize; // number of 'read' bytes in the buffer
+  int  readBufferSize;     // maximum capacity in bytes
+  void *writeBuffer;
+  int  writeBufferFillSize;
+  int  writeBufferSize;
+  char ownsFd;
+} NGBufferedDescriptor;
+
+NGBufferedDescriptor *
+NGBufferedDescriptor_newWithOwnedDescriptorAndSize(int _fd, int _size);
+NGBufferedDescriptor *
+NGBufferedDescriptor_newWithDescriptorAndSize(int _fd, int _size);
+NGBufferedDescriptor *
+NGBufferedDescriptor_newWithDescriptor(int _fd);
+
+void NGBufferedDescriptor_free(NGBufferedDescriptor *self);
+
+// accessors
+
+int  NGBufferedDescriptor_getReadBufferSize(NGBufferedDescriptor *self);
+int  NGBufferedDescriptor_getWriteBufferSize(NGBufferedDescriptor *self);
+
+// primary read functions
+
+int  NGBufferedDescriptor_read(NGBufferedDescriptor *self,
+                               void *_buffer, int _len);
+int  NGBufferedDescriptor_write(NGBufferedDescriptor *self,
+                                const void *_buffer, int _len);
+
+// following functions return 1 on success and 0 and error/close
+
+char NGBufferedDescriptor_flush(NGBufferedDescriptor *self);
+
+unsigned char NGBufferedDescriptor_safeRead(NGBufferedDescriptor *self,
+                                   void *_buffer, int _len);
+char NGBufferedDescriptor_safeWrite(NGBufferedDescriptor *self,
+                                    const void *_buffer, int _len);
+
+int  NGBufferedDescriptor_readChar(NGBufferedDescriptor *self);
+
+char NGBufferedDescriptor_writeHttpHeader(NGBufferedDescriptor *self,
+                                          const unsigned char *_key,
+                                          const unsigned char *_value);
+
+#endif
diff --git a/mod_ngobjweb/README b/mod_ngobjweb/README
new file mode 100644 (file)
index 0000000..d33984c
--- /dev/null
@@ -0,0 +1,53 @@
+# $Id$
+
+mod_ngobjweb
+============
+
+This is an Apache module for forwarding HTTP requests to SOPE application
+server instances. It has the ability to ask the snsd load balancer to 
+distribute requests between processes and/or hosts.
+
+Apache Config Directives
+------------------------
+SetSNSPort
+SetAppPrefix
+SetAppPort
+SNSUseHTTP (experimental)
+
+Loading the Module with apache 1.3.x
+------------------------------------
+LoadModule ngobjweb_module modules/ngobjweb_1.3.x.so
+
+AddModule ngobjweb_module.c
+
+Loading the Module with apache 2.0.x
+------------------------------------
+LoadModule ngobjweb_module modules/ngobjweb_2.0.x.so
+
+Example Apache Config
+---------------------
+<LocationMatch "^/OpenGroupware/*">
+SetHandler ngobjweb-adaptor
+SetAppPort 20000
+</LocationMatch>
+
+Apache2 on SuSE 9.0
+===================
+
+Compilation for Apache2:
+
+  make \
+    apxs=/usr/sbin/apxs2   \
+    HTTPD=/usr/sbin/httpd2
+
+Just create a new config file in "/etc/apache2/conf.d/OGo.conf" and add the
+directives you need. Be sure to use "apache2" to restart instead of "apache"
+(which will restart Apache 1.3 ...).
+You should probably not use a threaded Apache 2 MPM, which may have issues
+with mod_ngobjweb but something like prefork.
+
+And finally: in the long run you should remove SuSE 9.0 from your machine and
+rather install a free distribution like Debian.
+
+Note: /etc/rc.d/apache2 stop does not work on SuSE 9.0 ... you need to killall
+the httpd-prefork processes manually, sigh.
diff --git a/mod_ngobjweb/apversion.sh b/mod_ngobjweb/apversion.sh
new file mode 100755 (executable)
index 0000000..037ffd7
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+# determines the Apache version number
+
+if test x"-v" = x"${1}"; then
+  if test x = x"${2}"; then
+    echo "usage: ${0} -v httpd"
+    exit 1
+  else
+    ${2} -v|grep 'ersion:*'|awk '{print $3}'|awk -F/ '{print $2}'
+  fi
+fi
+
+if test x"-iseapi" = x"${1}"; then
+  if test x = x"${2}"; then
+    echo "usage: ${0} -iseapi httpd"
+    exit 1
+  else
+    eapi=`${2} -V|grep -c EAPI`
+    if test x0 = x"${eapi}"; then
+      echo "no"
+      exit 0
+    else
+      echo "yes"
+      exit 0
+    fi
+  fi
+fi
+
+echo "usage: ${0} -iseapi|-v httpd"
+exit 1
diff --git a/mod_ngobjweb/common.h b/mod_ngobjweb/common.h
new file mode 100644 (file)
index 0000000..9640e09
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_Adaptors_apache_H__
+#define __NGObjWeb_Adaptors_apache_H__
+
+/* System includes */
+
+#include <strings.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+/* Apache includes */
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_config.h>
+#include <http_log.h>
+#include <http_protocol.h>
+
+#if MODULE_MAGIC_NUMBER_MAJOR >= 20010224
+/* apache ap version 2 */
+#include "apr.h"
+#include "apr_buckets.h"
+#include "apr_strings.h"
+#include "apr_portable.h"
+#include "apr_optional.h"
+#include "apr_lib.h"
+#include "ap_config.h"
+#include "ap_listen.h"
+#else
+/* for compatibility */
+#define AP_VERSION_1
+
+#define apr_array_header_t array_header
+#define apr_inet_addr      inet_addr
+#define apr_isalnum        isalnum
+#define apr_isspace        isspace
+#define apr_palloc         ap_palloc
+#define apr_pcalloc        ap_pcalloc
+#define apr_pool_t         pool
+#define apr_table_elts     ap_table_elts
+#define apr_table_entry_t  table_entry
+#define apr_table_get      ap_table_get
+#define apr_table_make     ap_make_table
+#define apr_table_set      ap_table_set
+#define apr_table_t        table
+#define apr_sleep          sleep
+#define apr_snprintf       snprintf
+
+#define ap_log_error(file, line, level, status, vars...) \
+       ap_log_error(file, line, level, ## vars)
+#endif
+
+#include "NGBufferedDescriptor.h"
+
+module ngobjweb_module;
+
+typedef struct {
+  char *snsPort;  /* the port of the SNS daemon                */
+  int  snsPortDomain;
+  
+  char *appPort; /* a single pass-through port of an instance */
+  int  appPortDomain;
+  
+  char *appPrefix;
+  int  useHTTP;
+} ngobjweb_dir_config;
+
+#define MAX_PORTNAME_SIZE   140
+#define MAX_SNS_PATH_SIZE   MAX_PORTNAME_SIZE
+#define MAX_APP_PREFIX_SIZE 256
+
+/* SNS */
+
+extern void *
+_sendSNSQuery(request_rec *_rq, const char *_line, const char *_cookie,
+              int *_domain, size_t *_len,
+              const char *_appName,
+              ngobjweb_dir_config *_cfg);
+
+/* HTTP */
+
+extern char
+NGScanResponseLine(NGBufferedDescriptor *_in,
+                   char *_version, int *_status, char *_text);
+extern apr_table_t *NGScanHeaders(apr_pool_t *_pool, NGBufferedDescriptor *_in);
+
+/* handlers */
+
+extern int ngobjweb_handler(request_rec *r);
+
+/* commands */
+
+extern const char *ngobjweb_set_sns_port(cmd_parms *cmd,
+                                         ngobjweb_dir_config *cfg,
+                                         char *arg);
+extern const char *ngobjweb_set_app_port(cmd_parms *cmd,
+                                         ngobjweb_dir_config *cfg,
+                                         char *arg);
+extern const char *ngobjweb_set_app_prefix(cmd_parms *cmd,
+                                           ngobjweb_dir_config *cfg,
+                                           char *arg);
+extern const char *ngobjweb_set_use_http(cmd_parms *cmd,
+                                         ngobjweb_dir_config *cfg);
+
+/* configuration */
+
+extern void *ngobjweb_create_dir_config(apr_pool_t *p, char *dummy);
+extern void *ngobjweb_merge_dir_configs(apr_pool_t *p, void *basev, void *addv);
+
+#endif /* __NGObjWeb_Adaptors_apache_H__ */
diff --git a/mod_ngobjweb/config.c b/mod_ngobjweb/config.c
new file mode 100644 (file)
index 0000000..6184c04
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+
+//#define LOG_CONFIG 1
+
+static char *_makeString(char *buf, char *str, int max) {
+  if (buf == NULL)
+    buf = calloc(max + 10, sizeof(char));
+  
+  strncpy(buf, str, max);
+  buf[max] = '\0';
+  return buf;
+}
+
+static char *_makePort(char *port, char *str) {
+  return _makeString(port, str, MAX_PORTNAME_SIZE);
+}
+
+static int _domainFromPort(char *port) {
+  if (port == NULL) return AF_INET;
+  return *port == '/' ? AF_UNIX : AF_INET;
+}
+
+const char *ngobjweb_set_sns_port(cmd_parms *cmd,
+                                  ngobjweb_dir_config *cfg,
+                                  char *arg)
+{
+  cfg->snsPort = _makePort(cfg->snsPort, arg);
+  cfg->snsPortDomain = _domainFromPort(cfg->snsPort);
+  
+#if LOG_CONFIG
+  fprintf(stderr, "%s: 0x%08X set snsport to %s, domain %i (http=%s)\n",
+          __PRETTY_FUNCTION__, (unsigned)cfg,
+          cfg->snsPort, cfg->snsPortDomain,
+          cfg->useHTTP ? "yes" : "no");
+#endif
+  return NULL;
+}
+
+const char *ngobjweb_set_app_port(cmd_parms *cmd,
+                                  ngobjweb_dir_config *cfg,
+                                  char *arg)
+{
+  cfg->appPort = _makePort(cfg->appPort, arg);
+  cfg->appPortDomain = _domainFromPort(cfg->appPort);
+  
+#if LOG_CONFIG
+  fprintf(stderr, "%s: 0x%08X set appPort to %s, domain %i (http=%s)\n",
+          __PRETTY_FUNCTION__, (unsigned)cfg,
+          cfg->appPort, cfg->snsPortDomain,
+          cfg->useHTTP ? "yes" : "no");
+#endif
+  return NULL;
+}
+
+const char *ngobjweb_set_app_prefix(cmd_parms *cmd,
+                                    ngobjweb_dir_config *cfg,
+                                    char *arg)
+{
+  cfg->appPrefix = _makeString(cfg->appPrefix, arg, MAX_APP_PREFIX_SIZE);
+  return NULL;
+}
+
+const char *ngobjweb_set_use_http(cmd_parms *cmd,
+                                  ngobjweb_dir_config *cfg)
+{
+#if LOG_CONFIG
+  fprintf(stderr, "%s: using HTTP.\n", __PRETTY_FUNCTION__);
+#endif
+  cfg->useHTTP = 1;
+  return NULL;
+}
+
+void *ngobjweb_create_dir_config(apr_pool_t *p, char *dummy) {
+  ngobjweb_dir_config *new;
+
+  new = apr_palloc(p, sizeof(ngobjweb_dir_config));
+  new->snsPort       = NULL;
+  new->snsPortDomain = AF_UNIX;
+  new->appPort       = NULL;
+  new->appPortDomain = AF_INET;
+  new->appPrefix     = NULL;
+  new->useHTTP       = 0;
+
+#if LOG_CONFIG
+  fprintf(stderr,"%s: created directory config 0x%08X ...\n",
+          __PRETTY_FUNCTION__, (unsigned)new);
+#endif
+
+  return new;
+}
+
+void *ngobjweb_merge_dir_configs(apr_pool_t *p, void *basev, void *addv) {
+  ngobjweb_dir_config *base;
+  ngobjweb_dir_config *add;
+  ngobjweb_dir_config *new;
+
+  base = (ngobjweb_dir_config *)basev;
+  add  = (ngobjweb_dir_config *)addv;
+  if (add == NULL) add = base;
+  
+  if ((new = apr_palloc(p, sizeof(ngobjweb_dir_config))) == NULL) {
+    fprintf(stderr, "%s: couldn't allocate memory of size %ld\n",
+            __PRETTY_FUNCTION__,
+            (long int) sizeof(ngobjweb_dir_config));
+    return NULL;
+  }
+  
+  new->snsPort       = NULL;
+  new->snsPortDomain = 0;
+  new->appPort       = NULL;
+  new->appPortDomain = 0;
+  new->appPrefix     = NULL;
+  new->useHTTP       = 0;
+  
+  if ((add == NULL) && (base == NULL))
+    goto finish;
+  
+  /* copy base stuff */
+  if (add) {
+    if (add->useHTTP)
+      new->useHTTP = 1;
+    
+    if (add->snsPortDomain)
+      new->snsPortDomain = add->snsPortDomain;
+    else
+      new->snsPortDomain = base ? base->snsPortDomain : 0;
+    
+    if (add->appPortDomain)
+      new->appPortDomain = add->appPortDomain;
+    else
+      new->appPortDomain = base ? base->appPortDomain : 0;
+  }
+  if (base) {
+    if (base->useHTTP)
+      new->useHTTP = 1;
+  }
+
+  /* copy SNS port */
+  if ((add != NULL) && (add->snsPort != NULL)) {
+    if ((new->snsPort = _makePort(NULL, add->snsPort)))
+      new->snsPortDomain = _domainFromPort(new->snsPort);
+  }
+  else if ((base != NULL) && (base->snsPort != NULL)) {
+    if ((new->snsPort = _makePort(NULL, base->snsPort)))
+      new->snsPortDomain = _domainFromPort(new->snsPort);
+  }
+
+  /* copy app port */
+  if ((add != NULL) && (add->appPort != NULL)) {
+    if ((new->appPort = _makePort(NULL, add->appPort)))
+      new->appPortDomain = _domainFromPort(new->appPort);
+  }
+  else if ((base != NULL) && (base->appPort != NULL)) {
+    if ((new->appPort = _makePort(NULL, base->appPort)))
+      new->appPortDomain = _domainFromPort(new->appPort);
+  }
+
+  /* copy app prefix */
+  if (add->appPrefix) {
+    new->appPrefix = _makeString(NULL, add->appPrefix, MAX_APP_PREFIX_SIZE);
+  }
+  else if (base->appPrefix) {
+    new->appPrefix = _makeString(NULL, base->appPrefix, MAX_APP_PREFIX_SIZE);
+  }
+  
+ finish:
+#if LOG_CONFIG
+  fprintf(stderr,
+          "MERGE: (base=0x%08X, add=0x%08X, new=0x%08X\n"
+          "  BASE: sns:'%s'%i app:'%s'%i prefix:'%s' http:%s\n"
+          "  ADD:  sns:'%s'%i app:'%s'%i prefix:'%s' http:%s\n"
+          "  NEW:  sns:'%s'%i app:'%s'%i prefix:'%s' http:%s\n",
+          (unsigned)base, (unsigned)add, (unsigned)new,
+          base->snsPort,   base->snsPortDomain, 
+          base->appPort,   base->appPortDomain,
+         base->appPrefix, base->useHTTP ? "on" : "off",
+          add->snsPort,   add->snsPortDomain, 
+          add->appPort,   add->appPortDomain,
+          add->appPrefix, add->useHTTP ? "on" : "off",
+          new->snsPort,   new->snsPortDomain, 
+          new->appPort,   new->appPortDomain,
+          new->appPrefix, new->useHTTP ? "on" : "off"
+         );
+#endif
+  return new;
+}
diff --git a/mod_ngobjweb/globals.c b/mod_ngobjweb/globals.c
new file mode 100644 (file)
index 0000000..00357b8
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int HEAVY_LOG = 0;
+//struct sockaddr *sns = 0;
diff --git a/mod_ngobjweb/handler.c b/mod_ngobjweb/handler.c
new file mode 100644 (file)
index 0000000..e906151
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+
+#define BUFSIZE   2048
+
+extern int HEAVY_LOG;
+
+#if WITH_LOGGING
+static void _logTable(const char *text, apr_table_t *table);
+#endif
+
+static ngobjweb_dir_config *_getConfig(request_rec *r) {
+  ngobjweb_dir_config *cfg;
+
+  if (r == NULL) {
+    fprintf(stderr, "%s: missing request !\n", __PRETTY_FUNCTION__);
+    return NULL;
+  }
+  if (r->per_dir_config == NULL) {
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                 "missing directory config in request ...");
+    return NULL;
+  }
+  
+  cfg = (ngobjweb_dir_config *)
+    ap_get_module_config(r->per_dir_config, &ngobjweb_module);
+  
+  return cfg;
+}
+
+static void _extractAppName(const char *uri, char *appName, int maxLen) {
+  char *tmp;
+  
+  /* extract name of application */
+  if ((tmp = index(uri + 1, '/'))) {
+    int len;
+    len = (tmp - (uri + 1));
+    strncpy(appName, (uri + 1), len);
+    appName[len] = '\0';
+  }
+  else {
+    strncpy(appName, (uri + 1), maxLen - 1);
+    appName[maxLen - 1] = '\0';
+  }
+  
+  /* cut off .woa extension from application name */
+  if ((tmp = strstr(appName, ".woa")))
+    *tmp = '\0';
+  
+  /* cut off .sky extension from application name */
+  if ((tmp = strstr(appName, ".sky")))
+    *tmp = '\0';
+}
+
+static void *_readRequestBody(request_rec *r, int *requestContentLength) {
+  const char *clen;
+  int  contentLength;
+  void *ptr;
+  int  readBytes, toBeRead;
+  void *requestBody;
+  
+  clen = apr_table_get(r->headers_in, "content-length");
+  contentLength = clen ? atoi(clen) : 0;
+  *requestContentLength = contentLength;
+  
+  /* no content to read ... */
+  if (contentLength == 0) return NULL;
+  
+  /* read content */
+  
+  if (HEAVY_LOG) {
+    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, 
+                 "going to read %i bytes from browser ...", contentLength);
+  }
+  
+  requestBody = apr_palloc(r->pool, contentLength + 2);
+
+  ptr = requestBody;
+  for (toBeRead = contentLength; toBeRead > 0;) {
+#ifdef AP_VERSION_1
+    readBytes = ap_bread(r->connection->client, ptr, toBeRead);
+#else
+               ap_setup_client_block(r,REQUEST_CHUNKED_DECHUNK);
+    readBytes = ap_get_client_block(r, ptr, toBeRead);
+#endif
+    toBeRead -= readBytes;
+    ptr += readBytes;
+    if (readBytes == 0) break;
+  }
+  ptr = NULL;
+      
+  if (toBeRead > 0) {
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                 "couldn't read complete HTTP req body from browser "
+                 "(read %i of %i bytes)",
+                 (contentLength - toBeRead), contentLength);
+    return NULL;
+  }
+  
+  return requestBody;
+}
+
+static void
+_copyHeadersToRequest(request_rec *r, apr_table_t *headers, int *contentLength)
+{
+  const apr_array_header_t *array;
+  apr_table_entry_t  *entries;
+  int          i;
+  const char   *value;
+  
+  if (headers == NULL) return;
+  
+  value = apr_table_get(headers, "content-type");
+  if (value) r->content_type = value;
+  value = apr_table_get(headers, "content-encoding");
+  if (value) r->content_encoding = value;
+  value = apr_table_get(headers, "content-length");
+  *contentLength = value ? atoi(value) : 0;
+  
+  array   = apr_table_elts(headers);
+  entries = (apr_table_entry_t *)array->elts;
+
+  for (i = 0; i < array->nelts; i++) {
+    apr_table_entry_t *entry = &(entries[i]);
+
+    apr_table_set(r->headers_out, entry->key, entry->val);
+  }
+  // _logTable("out", r->headers_out);
+}
+
+static void _logInstanceAddress(request_rec *r, struct sockaddr *address,
+                                size_t addressLen, int domain)
+{
+  char buf[1024];
+  
+  if (!HEAVY_LOG) return;
+  
+  apr_snprintf(buf, sizeof(buf), "  => address len=%li domain=%i<", (long int) addressLen, domain);
+  switch (domain) {
+    case AF_INET: strcat(buf, "inet"); break;
+    case AF_UNIX: strcat(buf, "unix"); break;
+    default: strcat(buf, "unknown"); break;
+  }
+  strcat(buf, ">");
+  
+  if (domain == AF_UNIX) {
+    strcat(buf, " path=\"");
+    strcat(buf, ((struct sockaddr_un *)address)->sun_path);
+    strcat(buf, "\"");
+  }
+  else if (domain == AF_INET) {
+    char         *ptr = NULL;
+    int  port;
+    char sport[256];
+    
+    ptr  = inet_ntoa(((struct sockaddr_in *)address)->sin_addr);
+    port = ntohs(((struct sockaddr_in *)address)->sin_port);
+    apr_snprintf(sport, sizeof(sport), "host=\"%s\" port=%i", ptr, port);
+    strcat(buf, sport);
+  }
+  
+  ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, buf);
+}
+
+static int _connectInstance(request_rec *r,
+                            int appFd, struct sockaddr *address,
+                            size_t addressLen)
+{
+  int  result;
+  int  tryCount = 0;
+  char isConnected = 0;
+  
+  result = connect(appFd, address, addressLen);
+  if (result >= 0) return result;
+  
+  while (tryCount < 3) {
+    char *pdelay = NULL; /* pblock_findval("delay", _paras) */
+    int delay    = pdelay ? atoi(pdelay) : 3; // default: 3s
+
+    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
+                 "sleeping %is ..", delay);
+    apr_sleep(delay);
+    
+    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
+                 "retry connect ..");
+    result = connect(appFd, address, addressLen);
+    
+    if (result >= 0) {
+      isConnected = 1;
+      break;
+    }
+    tryCount++;
+  }
+  
+  if (isConnected == 0) {
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                 "connect to application instance failed, tried %i times.",
+                 tryCount);
+    close(appFd);
+    return -1;
+  }
+  return result;
+}
+
+static int _writeInHeaders(NGBufferedDescriptor *toApp, request_rec *r) {
+  const apr_array_header_t *array;
+  apr_table_entry_t  *entries;
+  int          i;
+  
+  if (r->headers_in == NULL) return 1;
+
+  array   = apr_table_elts(r->headers_in);
+  entries = (apr_table_entry_t *)array->elts;
+
+  for (i = 0; i < array->nelts; i++) {
+    apr_table_entry_t *entry = &(entries[i]);
+        
+    if (!NGBufferedDescriptor_writeHttpHeader(toApp,
+                                              entry->key, entry->val)) {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+int ngobjweb_handler(request_rec *r) {
+  struct    sockaddr   *address = NULL;
+  size_t               addressLen;
+  int                  domain;
+  char                 appName[256];
+  NGBufferedDescriptor *toApp = NULL;
+  int                  appFd;
+  int                  result;
+  int                  writeError    = 0;
+  int                  contentLength = 0;
+  int                  statusCode    = 500;
+  ngobjweb_dir_config  *cfg;
+  const char           *uri;
+  unsigned             requestContentLength;
+  void                 *requestBody;
+  
+  uri = r->uri;
+  requestContentLength = 0;
+  requestBody = NULL;
+  
+#ifndef AP_VERSION_1
+  if (r->handler == NULL)
+    return DECLINED;
+  if (strcmp(r->handler, "ngobjweb-adaptor") != 0)
+    return DECLINED;
+#endif
+
+  if (uri == NULL)   return DECLINED;
+  if (uri[0] != '/') return DECLINED;
+  if (strstr(uri, "WebServerResources")) return DECLINED;
+
+  /* get directory configuration */
+  
+  if ((cfg = _getConfig(r))) {
+    if (cfg->appPrefix) {
+      if (HEAVY_LOG) {
+        ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
+                     "using prefix '%s'\n", cfg->appPrefix);
+      }
+      uri += strlen(cfg->appPrefix);
+    }
+  }
+  else {
+    return 500;
+  }
+
+  /* find app name in url */
+  _extractAppName(uri, appName, sizeof(appName));
+  
+  /* before continuing, read request body */
+  
+  requestBody = _readRequestBody(r, &contentLength);
+  requestContentLength = contentLength;
+  
+  if ((requestBody == NULL) && (contentLength > 0))
+    /* read failed, error is logged in function */
+    return 500;
+  
+  /* ask SNS for server address */
+
+  if (cfg->snsPort) {
+    address = _sendSNSQuery(r,
+                            r->the_request,
+                            apr_table_get(r->headers_in, "cookie"),
+                            &domain, &addressLen,
+                            appName,
+                            cfg);
+    if (address == NULL) {
+      /* did not find an appropriate application server */
+      ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                   "didn't find SKYRiXgreen server using SNS ...");
+      return DECLINED;
+    }
+  }
+  else if (cfg->appPort) {
+    domain = cfg->appPortDomain;
+    
+    if (cfg->appPortDomain == AF_UNIX) {
+      addressLen = sizeof(struct sockaddr_un);
+      address = apr_palloc(r->pool, sizeof(struct sockaddr_un)); 
+      memset(address, 0, sizeof(struct sockaddr_un)); 
+         
+      ((struct sockaddr_un *)address)->sun_family = AF_UNIX; 
+      strncpy(((struct sockaddr_un *)address)->sun_path, 
+              cfg->appPort, 
+              sizeof(((struct sockaddr_un *)address)->sun_path) - 1);
+    }
+    else {
+      struct sockaddr_in *snsi;
+      char *host;
+      int  port;
+      
+      host = "127.0.0.1";
+      port = atoi(cfg->appPort);
+
+      //ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
+      //             "appPort: '%s', cfg 0x%08X", cfg->appPort, cfg);
+      
+      addressLen = sizeof(struct sockaddr_in);
+      address = apr_palloc(r->pool, sizeof(struct sockaddr_in));
+      memset(address, 0, sizeof(struct sockaddr_in)); 
+      snsi = (struct sockaddr_in *)address; 
+         
+      snsi->sin_addr.s_addr = apr_inet_addr(host); 
+      
+      snsi->sin_family = AF_INET; 
+      snsi->sin_port   = htons((short)(port & 0xFFFF)); 
+      
+      if (snsi->sin_addr.s_addr == -1) { 
+       ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                    "couldn't convert snsd IP address: %s", host); 
+      } 
+      if (HEAVY_LOG && 0) { 
+        ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                     "connect IP address: %s", host); 
+      } 
+    }
+  }
+  else {
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                "neither SNS port nor app port are set for request ...");
+    return 500;
+  }
+
+  if (addressLen > 10000) {
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                "suspect instance port length (%li) ...", (long int) addressLen);
+    return 500;
+  }
+  
+  _logInstanceAddress(r, address, addressLen, domain);
+  
+  /* setup connection to application server */
+  
+  if ((appFd = socket(domain, SOCK_STREAM, 0)) < 0) {
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                 "could not create socket in domain %i.", domain);
+    return DECLINED;
+  }
+
+  if ((result = _connectInstance(r, appFd, address, addressLen)) < 0)
+    return 500;
+  
+  toApp = NGBufferedDescriptor_newWithOwnedDescriptorAndSize(appFd, 512);
+  if (toApp == NULL) {
+    close(appFd);
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                 "could not alloc socket buffer for "
+                 "application server connection");
+    return 500;
+  }
+  
+  /* write request to application server */
+  
+  if (HEAVY_LOG)
+    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "transfer reqline");
+
+  {
+    char *reqLine;
+    unsigned toGo;
+
+    reqLine = r->the_request;
+    toGo = reqLine ? strlen(reqLine) : 0;
+    
+    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
+                 "req is %s(len=%i)", reqLine, toGo);
+
+    if (!NGBufferedDescriptor_safeWrite(toApp, reqLine,
+                                        reqLine ? strlen(reqLine) : 0)) {
+      writeError = 1;
+      goto writeErrorHandler;
+    }
+    if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
+      writeError = 1;
+      goto writeErrorHandler;
+    }
+  }
+
+  /* transfer headers */
+  
+  if (writeError == 0) {
+    if (HEAVY_LOG)
+      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "transfer hdrs");
+    
+    /* extended adaptor headers */
+    {
+      char tmp[256];
+      const char *value;
+      
+      value = r->protocol;
+      value = value ? value : "http";
+      if (value) {
+        if (!NGBufferedDescriptor_writeHttpHeader(toApp,
+                                                  "x-webobjects-server-protocol",
+                                                  value)) {
+          writeError = 1;
+          goto writeErrorHandler;
+        }
+      }
+
+      if ((value = r->connection->remote_ip)) {
+        if (!NGBufferedDescriptor_writeHttpHeader(toApp,
+                                                  "x-webobjects-remote-addr",
+                                                  value)) {
+          writeError = 1;
+          goto writeErrorHandler;
+        }
+      }
+      
+      value = r->connection->remote_host;
+      if (value == NULL) value = r->connection->remote_ip;
+      if (value) {
+        if (!NGBufferedDescriptor_writeHttpHeader(toApp,
+                                                  "x-webobjects-remote-host",
+                                                  value)) {
+          writeError = 1;
+          goto writeErrorHandler;
+        }
+      }
+
+#ifdef AP_VERSION_1
+      if ((value = r->connection->ap_auth_type)) {
+#else
+      if ((value = r->ap_auth_type)) {
+#endif
+        if (!NGBufferedDescriptor_writeHttpHeader(toApp,
+                                                  "x-webobjects-auth-type",
+                                                  value)) {
+          writeError = 1;
+          goto writeErrorHandler;
+        }
+      }
+      
+#ifdef AP_VERSION_1
+      if ((value = r->connection->user)) {
+#else
+      if ((value = r->user)) {
+#endif
+        if (!NGBufferedDescriptor_writeHttpHeader(toApp,
+                                                  "x-webobjects-remote-user",
+                                                  value)) {
+          writeError = 1;
+          goto writeErrorHandler;
+        }
+      }
+
+      if (cfg) {
+        if (cfg->appPrefix) {
+          if (!NGBufferedDescriptor_writeHttpHeader(toApp,
+                "x-webobjects-adaptor-prefix", cfg->appPrefix)) {
+            writeError = 1;
+            goto writeErrorHandler;
+          }
+        }
+      }
+
+      if (!NGBufferedDescriptor_writeHttpHeader(toApp,
+                                                "x-webobjects-server-name",
+                                                r->server->server_hostname)) {
+        writeError = 1;
+        goto writeErrorHandler;
+      }
+
+      apr_snprintf(tmp, sizeof(tmp), "%i", r->server->port);
+      if (!NGBufferedDescriptor_writeHttpHeader(toApp,
+                                                "x-webobjects-server-port",
+                                                tmp)) {
+        writeError = 1;
+        goto writeErrorHandler;
+      }
+      
+      apr_snprintf(tmp, sizeof(tmp), "%s://%s:%i",
+              ap_http_method(r),
+              r->server->server_hostname,
+              r->server->port);
+      if (!NGBufferedDescriptor_writeHttpHeader(toApp,
+                                                "x-webobjects-server-url",
+                                                tmp)) {
+        writeError = 1;
+        goto writeErrorHandler;
+      }
+
+      /*
+        SSL stuff:
+        x-webobjects-clients-cert
+        x-webobjects-https-enabled
+        x-webobjects-https-keysize
+        x-webobjects-https-secret-keysize
+      */
+    }
+    
+    /* http headers */
+    if (!_writeInHeaders(toApp, r)) {
+      writeError = 1;
+      goto writeErrorHandler;
+    }
+    
+    if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
+      writeError = 1;
+      goto writeErrorHandler;
+    }
+    if (!NGBufferedDescriptor_flush(toApp))
+      writeError = 1;
+  }
+
+ writeErrorHandler:
+  if (writeError == 1) {
+    if (toApp) NGBufferedDescriptor_free(toApp);
+    
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                 "socket write error during transfer of HTTP header section");
+    return 500;
+  }
+  
+  /* transfer request body */
+  
+  if (requestContentLength > 0) {
+    if (!NGBufferedDescriptor_safeWrite(toApp,
+                                        requestBody,
+                                        requestContentLength)) {
+      if (toApp) NGBufferedDescriptor_free(toApp);
+      ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                   "couldn't transfer HTTP req body to app server (%i bytes)",
+                   contentLength);
+      return 500;
+    }
+    NGBufferedDescriptor_flush(toApp);
+  }
+  else {
+    if (HEAVY_LOG) {
+      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
+                   "no content in request to transfer");
+    }
+  }
+  
+  /* read response line */
+  
+  if (!NGScanResponseLine(toApp, NULL, &statusCode, NULL)) {
+    if (toApp) NGBufferedDescriptor_free(toApp);
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                 "error during reading of response line ..");
+    return 500;
+  }
+  r->status      = statusCode;
+  r->status_line = NULL;
+
+  /* process response headers */
+  {
+    apr_table_t *headers = NULL;
+    
+    if (HEAVY_LOG)
+      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "scan headers");
+
+    if ((headers = NGScanHeaders(r->pool, toApp)) == NULL) {
+      ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                   "error during parsing of response headers ..");
+    }
+    
+    _copyHeadersToRequest(r, headers, &contentLength);
+#ifdef AP_VERSION_1
+    ap_send_http_header(r);
+#endif
+  }
+  
+  /* send response content */
+  
+  if (!r->header_only) {
+    if (contentLength > 0) {
+      void *buffer = NULL;
+      
+      if ((buffer = apr_pcalloc(r->pool, contentLength + 1)) == NULL) {
+        ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
+                     "could not allocate response buffer (size=%i)",
+                     contentLength);
+      }
+
+      // read whole response
+      if (!NGBufferedDescriptor_safeRead(toApp, buffer, contentLength)) {
+        if (toApp) NGBufferedDescriptor_free(toApp);
+      }
+
+      // close connection to app
+      if (toApp) {
+        NGBufferedDescriptor_free(toApp);
+        toApp = NULL;
+      }
+
+      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
+                   "send response (size=%i)",
+                   contentLength);
+      // send response to client
+      ap_rwrite(buffer, contentLength, r);
+      ap_rflush(r);
+    }
+    else if (contentLength == 0) {
+      // no content length header, read until EOF
+      unsigned char buffer[4096];
+      int result = 0;
+      int writeCount = 0;
+
+      do {
+        result = NGBufferedDescriptor_read(toApp, buffer, sizeof(buffer));
+        if (result > 0) {
+          ap_rwrite(buffer, result, r);
+          ap_rflush(r);
+          writeCount += result;
+        }
+      }
+      while (result > 0);
+
+      if (HEAVY_LOG && (writeCount > 0)) {
+        ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
+                     "write %i bytes (without content-length header)",
+                     writeCount);
+      }
+    }
+  }
+  
+  return OK;
+}
+
+#if WITH_LOGGING
+static void test(void) {
+  fprintf(stderr,
+          "%s: called:\n"
+          "  app:      %s\n"
+          "  uri:      %s\n"
+          "  pathinfo: %s\n"
+          "  method:   %s\n"
+          "  protocol: %s\n"
+          "  1st:      %s\n"
+          "  host:     %s\n"
+          "  type:     %s\n"
+          "  handler:  %s\n",
+          __PRETTY_FUNCTION__,
+          appName,
+          r->uri,
+          r->path_info,
+          r->method,
+          r->protocol,
+          r->the_request,
+          apr_table_get(r->headers_in, "content-length"),
+          r->content_type,
+          r->handler
+          );
+
+  _logTable("  out", r->headers_out);
+  _logTable("  err", r->err_headers_out);
+  _logTable("  env", r->subprocess_env);
+  _logTable("  in",  r->headers_in);
+}
+
+static void _logTable(const char *text, apr_table_t *table) {
+  apr_array_header_t *array;
+  apr_table_entry_t  *entries;
+  int          i;
+
+  if (table == NULL) {
+    fprintf(stderr, "%s: log NULL table.\n", text);
+    return;
+  }
+
+  array   = apr_table_elts(table);
+  entries = (apr_table_entry_t *)array->elts;
+
+  if (array->nelts == 0) {
+    fprintf(stderr, "%s: empty\n", text);
+    return;
+  }
+
+  for (i = 0; i < array->nelts; i++) {
+    apr_table_entry_t *entry = &(entries[i]);
+    
+    fprintf(stderr, "%s: %s: %s\n", text, entry->key, entry->val);
+  }
+}
+#endif
diff --git a/mod_ngobjweb/httpd.conf b/mod_ngobjweb/httpd.conf
new file mode 100644 (file)
index 0000000..c04f152
--- /dev/null
@@ -0,0 +1,465 @@
+##
+## httpd.conf -- Apache HTTP server configuration file
+##
+
+### Section 1: Global Environment
+#
+# The directives in this section affect the overall operation of Apache,
+# such as the number of concurrent requests it can handle or where it
+# can find its configuration files.
+#
+
+#
+# ServerType is either inetd, or standalone.  Inetd mode is only supported on
+# Unix platforms.
+#
+ServerType standalone
+
+#
+# ServerRoot: The top of the directory tree under which the server's
+# configuration, error, and log files are kept.
+#
+# NOTE!  If you intend to place this on an NFS (or otherwise network)
+# mounted filesystem then please read the LockFile documentation
+# (available at <URL:http://www.apache.org/docs/mod/core.html#lockfile>);
+# you will save yourself a lot of trouble.
+#
+# Do NOT add a slash at the end of the directory path.
+#
+ServerRoot "/tmp/httpd-8888"
+
+#
+# The LockFile directive sets the path to the lockfile used when Apache
+# is compiled with either USE_FCNTL_SERIALIZED_ACCEPT or
+# USE_FLOCK_SERIALIZED_ACCEPT. This directive should normally be left at
+# its default value. The main reason for changing it is if the logs
+# directory is NFS mounted, since the lockfile MUST BE STORED ON A LOCAL
+# DISK. The PID of the main server process is automatically appended to
+# the filename. 
+#
+LockFile /tmp/httpd.accept.lock
+
+#
+# PidFile: The file in which the server should record its process
+# identification number when it starts.
+#
+PidFile /tmp/httpd.pid
+
+#
+# ScoreBoardFile: File used to store internal server process information.
+# Not all architectures require this.  But if yours does (you'll know because
+# this file will be  created when you run Apache) then you *must* ensure that
+# no two invocations of Apache share the same scoreboard file.
+#
+ScoreBoardFile /tmp/httpd.apache_runtime_status
+
+#
+# In the standard configuration, the server will process httpd.conf,
+# srm.conf, and access.conf in that order.  The latter two files are
+# now distributed empty, as it is recommended that all directives
+# be kept in a single file for simplicity.  The commented-out values
+# below are the built-in defaults.  You can have the server ignore
+# these files altogether by using "/dev/null" (for Unix) or
+# "nul" (for Win32) for the arguments to the directives.
+#
+#ResourceConfig conf/srm.conf
+#AccessConfig conf/access.conf
+ResourceConfig /dev/null
+AccessConfig   /dev/null
+
+#
+# Timeout: The number of seconds before receives and sends time out.
+#
+Timeout 300
+
+#
+# KeepAlive: Whether or not to allow persistent connections (more than
+# one request per connection). Set to "Off" to deactivate.
+#
+KeepAlive On
+
+#
+# MaxKeepAliveRequests: The maximum number of requests to allow
+# during a persistent connection. Set to 0 to allow an unlimited amount.
+# We recommend you leave this number high, for maximum performance.
+#
+MaxKeepAliveRequests 100
+
+#
+# KeepAliveTimeout: Number of seconds to wait for the next request from the
+# same client on the same connection.
+#
+KeepAliveTimeout 15
+
+#
+# Server-pool size regulation.  Rather than making you guess how many
+# server processes you need, Apache dynamically adapts to the load it
+# sees --- that is, it tries to maintain enough server processes to
+# handle the current load, plus a few spare servers to handle transient
+# load spikes (e.g., multiple simultaneous requests from a single
+# Netscape browser).
+#
+# It does this by periodically checking how many servers are waiting
+# for a request.  If there are fewer than MinSpareServers, it creates
+# a new spare.  If there are more than MaxSpareServers, some of the
+# spares die off.  The default values in httpd.conf-dist are probably OK
+# for most sites.
+#
+MinSpareServers 1
+MaxSpareServers 10
+
+#
+# Number of servers to start initially --- should be a reasonable ballpark
+# figure.
+#
+StartServers 1
+
+#
+# Limit on total number of servers running, i.e., limit on the number
+# of clients who can simultaneously connect --- if this limit is ever
+# reached, clients will be LOCKED OUT, so it should NOT BE SET TOO LOW.
+# It is intended mainly as a brake to keep a runaway server from taking
+# the system with it as it spirals down...
+#
+MaxClients 150
+
+#
+# MaxRequestsPerChild: the number of requests each child process is
+# allowed to process before the child dies.  The child will exit so
+# as to avoid problems after prolonged use when Apache (and maybe the
+# libraries it uses) leak memory or other resources.  On most systems, this
+# isn't really needed, but a few (such as Solaris) do have notable leaks
+# in the libraries.
+#
+MaxRequestsPerChild 30
+
+#
+# Dynamic Shared Object (DSO) Support
+#
+# To be able to use the functionality of a module which was built as a DSO you
+# have to place corresponding `LoadModule' lines at this location so the
+# directives contained in it are actually available _before_ they are used.
+# Please read the file README.DSO in the Apache 1.3 distribution for more
+# details about the DSO mechanism and run `httpd -l' for the list of already
+# built-in (statically linked and thus always available) modules in your httpd
+# binary.
+#
+# Note: The order is which modules are loaded is important.  Don't change
+# the order below without expert advice.
+#
+# Example:
+# LoadModule foo_module libexec/mod_foo.so
+LoadModule mmap_static_module /usr/lib/apache/mod_mmap_static.so
+LoadModule env_module         /usr/lib/apache/mod_env.so
+LoadModule config_log_module  /usr/lib/apache/mod_log_config.so
+LoadModule mime_module        /usr/lib/apache/mod_mime.so
+LoadModule includes_module    /usr/lib/apache/mod_include.so
+LoadModule alias_module       /usr/lib/apache/mod_alias.so
+LoadModule access_module      /usr/lib/apache/mod_access.so
+LoadModule auth_module        /usr/lib/apache/mod_auth.so
+LoadModule setenvif_module    /usr/lib/apache/mod_setenvif.so
+
+#  Reconstruction of the complete module list from all available modules
+#  (static and shared ones) to achieve correct module execution order.
+#  [WHENEVER YOU CHANGE THE LOADMODULE SECTION ABOVE UPDATE THIS, TOO]
+ClearModuleList
+AddModule mod_mmap_static.c
+AddModule mod_env.c
+AddModule mod_log_config.c
+AddModule mod_mime.c
+AddModule mod_include.c
+AddModule mod_alias.c
+AddModule mod_access.c
+AddModule mod_auth.c
+AddModule mod_so.c
+AddModule mod_setenvif.c
+
+#
+# ExtendedStatus controls whether Apache will generate "full" status
+# information (ExtendedStatus On) or just basic information (ExtendedStatus
+# Off) when the "server-status" handler is called. The default is Off.
+#
+#ExtendedStatus On
+
+### Section 2: 'Main' server configuration
+#
+# The directives in this section set up the values used by the 'main'
+# server, which responds to any requests that aren't handled by a
+# <VirtualHost> definition.  These values also provide defaults for
+# any <VirtualHost> containers you may define later in the file.
+#
+# All of these directives may appear inside <VirtualHost> containers,
+# in which case these default settings will be overridden for the
+# virtual host being defined.
+#
+
+#
+# If your ServerType directive (set earlier in the 'Global Environment'
+# section) is set to "inetd", the next few directives don't have any
+# effect since their settings are defined by the inetd configuration.
+# Skip ahead to the ServerAdmin directive.
+#
+
+#
+# Port: The port to which the standalone server listens. For
+# ports < 1023, you will need httpd to be run as root initially.
+#
+Port 8888
+
+#
+# If you wish httpd to run as a different user or group, you must run
+# httpd as root initially and it will switch.  
+#
+# User/Group: The name (or #number) of the user/group to run httpd as.
+#  . On SCO (ODT 3) use "User nouser" and "Group nogroup".
+#  . On HPUX you may not be able to use shared memory as nobody, and the
+#    suggested workaround is to create a user www and use that user.
+#  NOTE that some kernels refuse to setgid(Group) or semctl(IPC_SET)
+#  when the value of (unsigned)Group is above 60000; 
+#  don't use Group nogroup on these systems!
+#
+User  helge
+Group dev
+
+#
+# ServerAdmin: Your address, where problems with the server should be
+# e-mailed.  This address appears on some server-generated pages, such
+# as error documents.
+#
+ServerAdmin root@localhost
+
+#
+# ServerName allows you to set a host name which is sent back to clients for
+# your server if it's different than the one the program would get (i.e., use
+# "www" instead of the host's real name).
+#
+# Note: You cannot just invent host names and hope they work. The name you 
+# define here must be a valid DNS name for your host. If you don't understand
+# this, ask your network administrator.
+# If your host doesn't have a registered DNS name, enter its IP address here.
+# You will have to access it by its address (e.g., http://123.45.67.89/)
+# anyway, and this will make redirections work in a sensible way.
+#
+#ServerName Euklid.suse.de
+
+#
+# DocumentRoot: The directory out of which you will serve your
+# documents. By default, all requests are taken from this directory, but
+# symbolic links and aliases may be used to point to other locations.
+#
+DocumentRoot "/HOME/helge/mdev/LSOffice3/LSWebInterface/Skyrix"
+
+#
+# Each directory to which Apache has access, can be configured with respect
+# to which services and features are allowed and/or disabled in that
+# directory (and its subdirectories). 
+#
+# First, we configure the "default" to be a very restrictive set of 
+# permissions.  
+#
+<Directory />
+    Options FollowSymLinks
+    AllowOverride None
+</Directory>
+
+#
+# Note that from this point forward you must specifically allow
+# particular features to be enabled - so if something's not working as
+# you might expect, make sure that you have specifically enabled it
+# below.
+#
+
+#
+# This should be changed to whatever you set DocumentRoot to.
+#
+<Directory "/HOME/helge/mdev/LSOffice3/LSWebInterface/Skyrix">
+
+#
+# This may also be "None", "All", or any combination of "Indexes",
+# "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews".
+#
+# Note that "MultiViews" must be named *explicitly* --- "Options All"
+# doesn't give it to you.
+#
+    Options Indexes FollowSymLinks
+
+#
+# This controls which options the .htaccess files in directories can
+# override. Can also be "All", or any combination of "Options", "FileInfo", 
+# "AuthConfig", and "Limit"
+#
+    AllowOverride None
+
+#
+# Controls who can get stuff from this server.
+#
+    Order allow,deny
+    Allow from all
+</Directory>
+
+#
+# UseCanonicalName:  (new for 1.3)  With this setting turned on, whenever
+# Apache needs to construct a self-referencing URL (a URL that refers back
+# to the server the response is coming from) it will use ServerName and
+# Port to form a "canonical" name.  With this setting off, Apache will
+# use the hostname:port that the client supplied, when possible.  This
+# also affects SERVER_NAME and SERVER_PORT in CGI scripts.
+#
+UseCanonicalName On
+
+#
+# TypesConfig describes where the mime.types file (or equivalent) is
+# to be found.
+#
+TypesConfig /etc/httpd/mime.types
+
+#
+# DefaultType is the default MIME type the server will use for a document
+# if it cannot otherwise determine one, such as from filename extensions.
+# If your server contains mostly text or HTML documents, "text/plain" is
+# a good value.  If most of your content is binary, such as applications
+# or images, you may want to use "application/octet-stream" instead to
+# keep browsers from trying to display binary files as though they are
+# text.
+#
+DefaultType text/plain
+
+#
+# HostnameLookups: Log the names of clients or just their IP addresses
+# e.g., www.apache.org (on) or 204.62.129.132 (off).
+# The default is off because it'd be overall better for the net if people
+# had to knowingly turn this feature on, since enabling it means that
+# each client request will result in AT LEAST one lookup request to the
+# nameserver.
+#
+HostnameLookups Off
+
+#
+# ErrorLog: The location of the error log file.
+# If you do not specify an ErrorLog directive within a <VirtualHost>
+# container, error messages relating to that virtual host will be
+# logged here.  If you *do* define an error logfile for a <VirtualHost>
+# container, that host's errors will be logged there and not here.
+#
+ErrorLog /tmp/httpd-8888/httpd.error_log
+
+#
+# LogLevel: Control the number of messages logged to the error_log.
+# Possible values include: debug, info, notice, warn, error, crit,
+# alert, emerg.
+#
+LogLevel info
+
+#
+# The following directives define some format nicknames for use with
+# a CustomLog directive (see below).
+#
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%h %l %u %t \"%r\" %>s %b" common
+LogFormat "%{Referer}i -> %U" referer
+LogFormat "%{User-agent}i" agent
+
+#
+# The location and format of the access logfile (Common Logfile Format).
+# If you do not define any access logfiles within a <VirtualHost>
+# container, they will be logged here.  Contrariwise, if you *do*
+# define per-<VirtualHost> access logfiles, transactions will be
+# logged therein and *not* in this file.
+#
+CustomLog /tmp/httpd-8888/httpd.access_log common
+
+#
+# Optionally add a line containing the server version and virtual host
+# name to server-generated pages (error documents, FTP directory listings,
+# mod_status and mod_info output etc., but not CGI generated documents).
+# Set to "EMail" to also include a mailto: link to the ServerAdmin.
+# Set to one of:  On | Off | EMail
+#
+ServerSignature On
+
+#
+# SKYRIX configurations
+#
+Include skyrix.conf
+
+#
+# Redirect allows you to tell clients about documents which used to exist in
+# your server's namespace, but do not anymore. This allows you to tell the
+# clients where to look for the relocated document.
+# Format: Redirect old-URI new-URL
+#
+
+#
+# Directives controlling the display of server-generated directory listings.
+#
+
+#
+# AddEncoding allows you to have certain browsers (Mosaic/X 2.1+) uncompress
+# information on the fly. Note: Not all browsers support this.
+# Despite the name similarity, the following Add* directives have nothing
+# to do with the FancyIndexing customization directives above.
+#
+AddEncoding x-compress Z
+AddEncoding x-gzip gz
+
+#
+# Customizable error response (Apache style)
+#  these come in three flavors
+#
+#    1) plain text
+#ErrorDocument 500 "The server made a boo boo.
+#  n.b.  the (") marks it as text, it does not get output
+#
+#    2) local redirects
+#ErrorDocument 404 /missing.html
+#  to redirect to local URL /missing.html
+#ErrorDocument 404 /cgi-bin/missing_handler.pl
+#  N.B.: You can redirect to a script or a document using server-side-includes.
+#
+#    3) external redirects
+#ErrorDocument 402 http://some.other_server.com/subscription_info.html
+#  N.B.: Many of the environment variables associated with the original
+#  request will *not* be available to such a script.
+
+#
+# The following directives modify normal HTTP response behavior.
+# The first directive disables keepalive for Netscape 2.x and browsers that
+# spoof it. There are known problems with these browser implementations.
+# The second directive is for Microsoft Internet Explorer 4.0b2
+# which has a broken HTTP/1.1 implementation and does not properly
+# support keepalive when it is used on 301 or 302 (redirect) responses.
+#
+BrowserMatch "Mozilla/2" nokeepalive
+BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
+
+#
+# The following directive disables HTTP/1.1 responses to browsers which
+# are in violation of the HTTP/1.0 spec by not being able to grok a
+# basic 1.1 response.
+#
+BrowserMatch "RealPlayer 4\.0" force-response-1.0
+BrowserMatch "Java/1\.0" force-response-1.0
+BrowserMatch "JDK/1\.0" force-response-1.0
+
+#
+# Allow server status reports, with the URL of http://servername/server-status
+# Change the ".your_domain.com" to match your domain to enable.
+#
+<Location /server-status>
+    SetHandler server-status
+    Order deny,allow
+    Deny from all
+    Allow from localhost
+</Location>
+
+#
+# Allow remote server configuration reports, with the URL of
+#  http://servername/server-info (requires that mod_info.c be loaded).
+# Change the ".your_domain.com" to match your domain to enable.
+#
+#<Location /server-info>
+#    SetHandler server-info
+#    Order deny,allow
+#    Deny from all
+#    Allow from .your_domain.com
+#</Location>
diff --git a/mod_ngobjweb/ngobjweb_module.c b/mod_ngobjweb/ngobjweb_module.c
new file mode 100644 (file)
index 0000000..84291e4
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+
+static command_rec ngobjweb_cmds[] = {
+  {
+    "SetSNSPort",
+    ngobjweb_set_sns_port,
+    NULL,
+    OR_FILEINFO,
+    TAKE1,
+    "the path of the Unix domain address to use (eg /tmp/.snsd)"
+  },
+  {
+    "SetAppPort",
+    ngobjweb_set_app_port,
+    NULL,
+    OR_FILEINFO,
+    TAKE1,
+    "the path of the Unix domain address to use (eg /tmp/.snsd)"
+  },
+  {
+    "SetAppPrefix",
+    ngobjweb_set_app_prefix,
+    NULL,
+    OR_FILEINFO,
+    TAKE1,
+    "any prefix that is before the app name (eg /MyDir with /MyDir/MyApp.woa)"
+  },
+  {
+    "SNSUseHTTP",
+    ngobjweb_set_use_http,
+    NULL,
+    OR_FILEINFO,
+    0,
+    "use HTTP protocol to query snsd (on,off) ?"
+  },
+  { NULL }
+};
+
+#ifdef AP_VERSION_1
+static handler_rec ngobjweb_handlers[] = {
+  { "ngobjweb-adaptor", ngobjweb_handler },
+  { NULL }
+};
+
+static void ngobjweb_init(server_rec *_server, pool *_pool) {
+}
+
+module ngobjweb_module = {
+  STANDARD_MODULE_STUFF,
+  ngobjweb_init,              /* initializer */
+  ngobjweb_create_dir_config, /* dir config creater */
+  ngobjweb_merge_dir_configs, /* dir merger --- default is to override */
+  NULL,                       /* server config */
+  NULL,                       /* merge server config */
+  ngobjweb_cmds,              /* command table */
+  ngobjweb_handlers,          /* handlers */
+  NULL,                       /* filename translation */ 
+  NULL,                       /* check_user_id */
+  NULL,                       /* check auth */
+  NULL,                       /* check access */
+  NULL,                       /* type_checker */
+  NULL,                       /* fixups */
+  NULL,                       /* logger */
+  NULL                        /* header parser */
+};
+#else
+static void ngobjweb_register_hooks(apr_pool_t *p) {
+  ap_hook_handler(ngobjweb_handler, NULL, NULL, APR_HOOK_LAST);
+}
+
+module AP_MODULE_DECLARE_DATA ngobjweb_module = {
+  STANDARD20_MODULE_STUFF,
+  ngobjweb_create_dir_config,  /* create per-directory config structures */
+  ngobjweb_merge_dir_configs,  /* merge per-directory config structures  */
+  NULL,                        /* create per-server config structures    */
+  NULL,                        /* merge per-server config structures     */
+  ngobjweb_cmds,               /* command handlers */
+  ngobjweb_register_hooks      /* register hooks */
+};
+#endif
+
diff --git a/mod_ngobjweb/scanhttp.c b/mod_ngobjweb/scanhttp.c
new file mode 100644 (file)
index 0000000..8ff7928
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGBufferedDescriptor.h"
+
+char NGScanResponseLine(NGBufferedDescriptor *_in,
+                        char *_version, int *_status, char *_text) {
+  if (_in == NULL) return 0;
+
+  if (_version) *_version = '\0';
+  if (_text)    *_text    = '\0';
+  if (_status)  *_status  = '\0';
+  
+  {
+    int c;
+    int i;
+
+    // scan HTTP Version
+    {
+      c = NGBufferedDescriptor_readChar(_in);
+      i = 0;
+      while ((c > 0) && !apr_isspace(c) && (i < 16)) {
+        if (_version) _version[i] = c;
+        i++;
+        c = NGBufferedDescriptor_readChar(_in);
+      }
+      if (_version) _version[i] = '\0';
+      if (c < 1) return 0; // read error
+    }
+    
+    // skip spaces
+    while ((c > 0) && apr_isspace(c))
+      c = NGBufferedDescriptor_readChar(_in);
+    if (c < 1) return 0; // read error
+
+    // scan code
+    {
+      char buf[10];
+      i = 0;
+      while ((c > 0) && !apr_isspace(c) && (c != '\r') && (c != '\n') && (i < 6)) {
+        buf[i] = c;
+        i++;
+        c = NGBufferedDescriptor_readChar(_in);
+      }
+      buf[i] = '\0';
+      if (_status) *_status = atoi(buf);
+    }
+
+    // skip spaces
+    while ((c > 0) && apr_isspace(c))
+      c = NGBufferedDescriptor_readChar(_in);
+    if (c < 1) return 0; // read error
+
+    // check for EOL
+    if (c == '\n') return 1; // response without reason
+    if (c == '\r') { // response without reason
+      c = NGBufferedDescriptor_readChar(_in); // c=='\n'
+      return 1;
+    }
+
+    // scan reason
+    {
+      i = 0;
+      while ((c > 0) && !apr_isspace(c) && (c != '\r') && (c != '\n') && (i < 6)) {
+        if (_text) _text[i] = c;
+        i++;
+        c = NGBufferedDescriptor_readChar(_in);
+      }
+      if (_text) _text[i] = '\0';
+      if (c < 1) return 0; // read error
+    }
+
+    // scan until line end
+    while ((c > 0) && (c != '\n'))
+      c = NGBufferedDescriptor_readChar(_in);
+
+    if (c < 1) return 0; // read error
+  }
+  return 1;
+}
+
+apr_table_t *NGScanHeaders(apr_pool_t *_pool, NGBufferedDescriptor *_in) {
+  apr_table_t *headers = NULL;
+
+  if (_in == NULL) return NULL;
+
+  headers = apr_table_make(_pool, 64);
+  if (headers) {
+    unsigned char name[256];
+    unsigned char value[8000];
+    int c;
+
+    while (1) {
+      int i, j;
+      
+      c = NGBufferedDescriptor_readChar(_in);
+      if (c <= 0) // error
+        break;
+
+      // test for end of HTTP header
+      {
+        if (c == '\n') // end line '\n'
+          break;
+        if (c == '\r') { // end line '\r\n'
+          c = NGBufferedDescriptor_readChar(_in);
+          // c should be '\n'
+          break;
+        }
+      }
+
+      // scan name
+      {
+        i = 0;
+        while ((c > 0) && (c != ':') && (i < 255)) {
+          name[i] = c;
+          i++;
+          c = NGBufferedDescriptor_readChar(_in);
+        }
+        name[i] = '\0';
+        if (i < 1) break; // empty header name ?!
+      }
+      if (c != ':') break; // missing separator ?
+
+      // skip spaces following separator
+      c = NGBufferedDescriptor_readChar(_in);
+      while ((c > 0) && (apr_isspace(c)))
+        c = NGBufferedDescriptor_readChar(_in);
+
+      // scan value
+      {
+        j = 0;
+        while ((c > 0) && (c != '\r') && (j < 7999)) {
+          value[j] = c;
+          j++;
+          c = NGBufferedDescriptor_readChar(_in);
+        }
+        value[j] = '\0';
+        if (j < 1) break; // empty header value ?!
+      }
+
+      if (c == '\n') // '\n' header end
+        ;
+      else if (c == '\r') { // '\r\n' header end
+        c = NGBufferedDescriptor_readChar(_in);
+        if (c != '\n') break;
+      }
+      else // no valid header end
+        break;
+
+      // store value
+      apr_table_set(headers, name, value);
+    }
+  }
+  return headers;
+}
diff --git a/mod_ngobjweb/skyrix.conf b/mod_ngobjweb/skyrix.conf
new file mode 100644 (file)
index 0000000..a8cd0c8
--- /dev/null
@@ -0,0 +1,46 @@
+#
+# SKYRIX configurations
+#
+
+Alias /SNSMonitor.woa/WebServerResources/ /HOME/helge/mdev/MOF2/Web/sns/SNSMonitor.woa/WebServerResources/
+Alias /Skyrix.woa/WebServerResources/ /HOME/helge/mdev/LSOffice/LSWebInterface/Skyrix.woa/WebServerResources/
+Alias /MyApp2.woa/WebServerResources/ /HOME/helge/mdev/MOF2/Web/Examples/MyApp2/MyApp2.woa/
+Alias /ClassBrowser.woa/WebServerResources/ /HOME/helge/mdev/MOF2/Web/Examples/ClassBrowser/ClassBrowser.woa/
+Alias /LSCatalog.woa/WebServerResources/ /HOME/helge/mdev/LSCatalog/LSCatalog.woa/
+Alias /ArticleImages /tmp/skyrix-news
+
+LoadModule ngobjweb_module /HOME/helge/mdev/MOF2/Web/Adaptors/apache/ngobjweb_1.3.4.so
+
+<LocationMatch "^/Skyrix*">
+SetSNSPort /tmp/.helge.snsd
+SetHandler ngobjweb-adaptor
+</LocationMatch>
+
+<LocationMatch "^/OtherRoot/Skyrix*">
+SetSNSPort       /tmp/.helge.snsd
+SetAppPrefix     /OtherRoot
+SetHandler       ngobjweb-adaptor
+</LocationMatch>
+
+<LocationMatch "^/OtherRoot2/Skyrix*">
+SetSNSPort       /tmp/.helge.snsd2
+SetAppPrefix     /OtherRoot2
+SetHandler       ngobjweb-adaptor
+</LocationMatch>
+
+<LocationMatch "^/MyApp2*">
+SetSNSPort /tmp/.helge.snsd
+SetHandler ngobjweb-adaptor
+</LocationMatch>
+
+<LocationMatch "^/ClassBrowser*">
+SetHandler ngobjweb-adaptor
+</LocationMatch>
+
+<LocationMatch "^/LSCatalog*">
+SetHandler ngobjweb-adaptor
+</LocationMatch>
+
+<LocationMatch "^/SNSMonitor*">
+SetHandler ngobjweb-adaptor
+</LocationMatch>
diff --git a/mod_ngobjweb/sns.c b/mod_ngobjweb/sns.c
new file mode 100644 (file)
index 0000000..4b7e967
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGBufferedDescriptor.h"
+
+extern int HEAVY_LOG;
+
+//#define HTTP_DETAIL_LOG 1
+
+#define SNS_HTTP_METHOD "POST"
+#define SNS_LOOKUP_URL  "/snsd2/wa/lookupSession"
+#define SNS_REQLINE     "reqline"
+#define SNS_APPNAME     "appname"
+#define SNS_COOKIES     "cookies"
+
+static inline int _isPlistBreakChar(unsigned char c)
+{
+    if (!apr_isalnum(c)) return 1;
+    
+    switch (c) {
+        case '_': case '@': case '#': case '$':
+        case '.': case '=': case ';': case ',':
+        case '{': case '}': case '(': case ')':
+        case '<': case '>': case '/': case '\\':
+        case '"':
+            return 1;
+            
+        default:
+            return 0;
+    }
+}
+
+static void _getSNSAddressForRequest(request_rec *_rq, struct sockaddr **_sns,
+                                     ngobjweb_dir_config *_cfg)
+{
+  //extern struct sockaddr *sns;
+  struct sockaddr *result = NULL; //sns;
+  const char *socket;
+  
+  *_sns = NULL;
+  if (_rq == NULL) {
+    fprintf(stderr, "%s: missing request ...\n", __PRETTY_FUNCTION__);
+    return;
+  }
+  if (_cfg == NULL) {
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
+                 "SNS: missing directory config for request ..");
+    return;
+  }
+  
+    if ((socket = _cfg->snsPort)) {
+      long int port;
+      char     *end, *pos;
+      
+      if (_cfg->snsPortDomain == AF_UNIX) {
+        result = apr_palloc(_rq->pool, sizeof(struct sockaddr_un));
+        memset(result, 0, sizeof(struct sockaddr_un));
+        
+        ((struct sockaddr_un *)result)->sun_family = AF_UNIX;
+        strncpy(((struct sockaddr_un *)result)->sun_path,
+                socket,
+                sizeof(((struct sockaddr_un *)result)->sun_path) - 1);
+      }
+      else if (_cfg->snsPortDomain == AF_INET) {
+        /* the string contained a number - the port of an IP address */
+        struct sockaddr_in *snsi;
+        unsigned char *host;
+
+        /* try to convert port to number */
+        if ((pos = index(socket, ':'))) {
+          /* contains a ':' */
+          port = strtol((pos + 1), &end, 10);
+          
+          host = apr_palloc(_rq->pool, (pos - socket) + 3);
+          strncpy(host, socket, (pos - socket));
+          host[pos - socket] = '\0';
+        }
+        else {
+          host = "127.0.0.1";
+          port = strtol(socket, &end, 10);
+        }
+        
+        result = apr_palloc(_rq->pool, sizeof(struct sockaddr_in));
+        memset(result, 0, sizeof(struct sockaddr_in));
+        snsi = (struct sockaddr_in *)result;
+        
+        snsi->sin_addr.s_addr = apr_inet_addr(host);
+        
+        snsi->sin_family = AF_INET;
+        snsi->sin_port   = htons((short)(port & 0xFFFF));
+        
+        if (snsi->sin_addr.s_addr == -1) {
+          ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
+                       "SNS: couldn't convert snsd IP address: %s", host);
+        }
+        if (HEAVY_LOG && 0) {
+          ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
+                       "SNS: connect IP address: %s", host);
+        }
+      }
+      else {
+        ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
+                     "SNS: unknown socket domain %i for SNS server "
+                     "(address=%s) !!!",
+                     _cfg->snsPortDomain, _cfg->snsPort);
+      }
+    }
+  
+  *_sns = result;
+}
+
+static void _logSNSConnect(request_rec *_rq, struct sockaddr *sns) {
+  if (sns == NULL) {
+    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
+                 "found no SNS socket address ...");
+    return;
+  }
+  if (sns->sa_family == AF_INET) {
+    struct sockaddr_in *snsi = (struct sockaddr_in *)sns;
+      
+    if (HEAVY_LOG) {
+      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
+                   "SNS: connecting INET socket (family=%d, ip=%s:%i) ...",
+                   sns->sa_family,
+                   inet_ntoa(snsi->sin_addr),
+                   ntohs(snsi->sin_port));
+    }
+  }
+  else if (sns->sa_family == AF_UNIX) {
+    if (HEAVY_LOG) {
+      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
+                   "SNS: connect UNIX socket (family=%d) ...",
+                   sns->sa_family);
+    }
+  }
+  else {
+    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
+                 "SNS: unknown socket address family: %d.",
+                 sns->sa_family);
+  }
+}
+
+void *_sendSNSQuery(request_rec *_rq, const char *_line,
+                    const char *_cookie,
+                    int *_domain, size_t *_len,
+                    const char *_appName,
+                    ngobjweb_dir_config *_cfg)
+{
+  /*
+    Sends a query for the instance socket address to the session
+    name server.
+  */
+  NGBufferedDescriptor *toSNS = NULL;
+  int    fd;
+  struct sockaddr *sns;
+  int    failed = 0;
+  
+  _getSNSAddressForRequest(_rq, &sns, _cfg);
+  if (sns == NULL) {
+    return NULL;
+  }
+  
+  *_domain = 0;
+  *_len    = 0;
+  
+  if (_line   == NULL) _line   = "";
+  if (_cookie == NULL) _cookie = "";
+  
+  /* setup connection */
+  {
+    _logSNSConnect(_rq, sns);
+    
+    fd = socket(sns->sa_family, SOCK_STREAM, 0);
+    if (fd < 0) {
+      ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
+                   "SNS: could not setup socket to SNS: %s.",
+                   strerror(errno));
+      return NULL;
+    }
+    
+    if (connect(fd, sns,
+                (sns->sa_family == AF_INET)
+                ? sizeof(struct sockaddr_in)
+                : sizeof(struct sockaddr_un)) != 0) {
+      if (HEAVY_LOG) {
+        ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
+                     "could not connect sns daemon %s: %s.",
+                     sns->sa_family == AF_UNIX
+                     ? ((struct sockaddr_un *)sns)->sun_path
+                     : "via ip",
+                     strerror(errno));
+      }
+      close(fd);
+      return NULL;
+    }
+    
+    toSNS = NGBufferedDescriptor_newWithOwnedDescriptorAndSize(fd, 1024);
+    if (toSNS == NULL) {
+      ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
+                "could not allocate buffered descriptor.");
+      close(fd);
+      return NULL;
+    }
+  }
+  
+  /* send request */
+  {
+    char c   = 50; // SNSLookupSession
+    int  len = strlen(_line);
+    
+    if (HEAVY_LOG) {
+      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
+                   "SNS: line %s cookie '%s'", _line, _cookie);
+    }
+    
+    /* send message code */
+    if (!NGBufferedDescriptor_safeWrite(toSNS, &c, 1)) {
+      failed = 1;
+      goto finish;
+    }
+    
+    /* send request line + space + appname */
+    len = strlen(_line) + 1 + strlen(_appName);
+    if (!NGBufferedDescriptor_safeWrite(toSNS, &len, sizeof(len))) {
+      failed = 2;
+      goto finish;
+    }
+    
+    if ((len = strlen(_line)) > 0) {
+      if (!NGBufferedDescriptor_safeWrite(toSNS, _line, len)) {
+        failed = 3;
+        goto finish;
+      }
+    }
+    if (!NGBufferedDescriptor_safeWrite(toSNS, " ", 1)) {
+      failed = 4;
+      goto finish;
+    }
+    if ((len = strlen(_appName)) > 0) {
+      if (!NGBufferedDescriptor_safeWrite(toSNS, _appName, len)) {
+        failed = 5;
+        goto finish;
+      }
+    }
+    
+    // send cookie
+    len = strlen(_cookie);
+    if (len > 2000) {
+      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
+                   "WARNING: cookie length > 2000 bytes (%i bytes): %s",
+                   len, _cookie);
+    }
+    if (!NGBufferedDescriptor_safeWrite(toSNS, &len, sizeof(len))) {
+      failed = 6;
+      goto finish;
+    }
+    if (len > 0) {
+      if (!NGBufferedDescriptor_safeWrite(toSNS, _cookie, len)) {
+        failed = 7;
+        goto finish;
+      }
+    }
+
+    if (!NGBufferedDescriptor_flush(toSNS)) {
+      failed = 8;
+      goto finish;
+    }
+    
+    if (HEAVY_LOG) {
+      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
+                   "SNS: reading response ..");
+    }
+    
+    // recv response
+    {
+      char *buffer;
+      int  domain;
+      int  size;
+
+      buffer = apr_palloc(_rq->pool, 1000);
+      memset(buffer, 0, 1000);
+      
+      if (!NGBufferedDescriptor_safeRead(toSNS, &domain, sizeof(domain))) {
+        failed = 9;
+        goto finish;
+      }
+      if (HEAVY_LOG) {
+        ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
+                     "SNS:   domain: %i ..", domain);
+      }
+      
+      if (!NGBufferedDescriptor_safeRead(toSNS, &size, sizeof(size))) {
+        failed = 10;
+        goto finish;
+      }
+      if (HEAVY_LOG) {
+        ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
+                     "SNS:   size: %i ..", size);
+      }
+      
+      if (size > 1024) {
+        ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
+                     "SNS: size of returned address is too big (%i bytes) !",
+                     size);
+        goto finish;
+      }
+      
+      if (!NGBufferedDescriptor_safeRead(toSNS, buffer, size)) {
+        failed = 11;
+        goto finish;
+      }
+      
+      if (HEAVY_LOG) {
+        ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
+                     "SNS: got address in domain %i, size is %i bytes !",
+                     domain, size);
+      }
+
+      *_domain = domain;
+      *_len    = size;
+      
+      if (toSNS) {
+        NGBufferedDescriptor_free(toSNS);
+        toSNS = NULL;
+      }
+      return buffer;
+    }
+  finish:
+    if (failed) {
+      ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
+                   "SNS: lookup request failed (code=%i) !", failed);
+    }
+    if (toSNS) {
+      NGBufferedDescriptor_free(toSNS);
+      toSNS = NULL;
+    }
+  }
+  return NULL;
+}
diff --git a/rules.mk b/rules.mk
new file mode 100644 (file)
index 0000000..2bc8c17
--- /dev/null
+++ b/rules.mk
@@ -0,0 +1,55 @@
+# $Id: rules.mk,v 1.2 2003/07/30 09:30:08 helge Exp $
+
+# Why not use a gstep-make aggregate.make? Because xml must be installed
+# before core can be built and core must be installed before sope can be
+# built.
+
+SOPE-all : skyrixsope-install
+
+SOPE-install : skyrixsope-install
+
+SOPE-clean : skyrixxml-clean skyrixcore-clean skyrixsope-clean
+
+SOPE-distclean : skyrixxml-distclean skyrixcore-distclean skyrixsope-distclean
+
+# skyrix-xml
+
+skyrixxml-all :
+       (cd $(SOPEDIR)/skyrix-xml && $(MAKE) all)
+
+skyrixxml-install :
+       (cd $(SOPEDIR)/skyrix-xml && $(MAKE) install)
+
+skyrixxml-clean :
+       (cd $(SOPEDIR)/skyrix-xml && $(MAKE) clean)
+
+skyrixxml-distclean :
+       (cd $(SOPEDIR)/skyrix-xml && $(MAKE) distclean)
+
+# skyrix-core
+
+skyrixcore-all : skyrixxml-install
+       (cd $(SOPEDIR)/skyrix-core && $(MAKE) all)
+
+skyrixcore-install : skyrixxml-install
+       (cd $(SOPEDIR)/skyrix-core && $(MAKE) install)
+
+skyrixcore-clean :
+       (cd $(SOPEDIR)/skyrix-core && $(MAKE) clean)
+
+skyrixcore-distclean :
+       (cd $(SOPEDIR)/skyrix-core && $(MAKE) distclean)
+
+# skyrix-sope
+
+skyrixsope-all : skyrixcore-install
+       (cd $(SOPEDIR)/skyrix-sope && $(MAKE) all)
+
+skyrixsope-install : skyrixcore-install
+       (cd $(SOPEDIR)/skyrix-sope && $(MAKE) install)
+
+skyrixsope-clean :
+       (cd $(SOPEDIR)/skyrix-sope && $(MAKE) clean)
+
+skyrixsope-distclean :
+       (cd $(SOPEDIR)/skyrix-sope && $(MAKE) distclean)
diff --git a/skyrix-core/.cvsignore b/skyrix-core/.cvsignore
new file mode 100644 (file)
index 0000000..8d4bfcf
--- /dev/null
@@ -0,0 +1 @@
+nohup.out
diff --git a/skyrix-core/COPYING b/skyrix-core/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-core/COPYRIGHT b/skyrix-core/COPYRIGHT
new file mode 100644 (file)
index 0000000..8e76449
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2004 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-core/ChangeLog b/skyrix-core/ChangeLog
new file mode 100644 (file)
index 0000000..da09928
--- /dev/null
@@ -0,0 +1,64 @@
+2004-08-16  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SxCore.xcode: added NGCalendarDateRange.[hm]
+
+2004-07-21  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+        * SxCore.xcode: fixed incorrect framework search paths.
+
+2004-07-21  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * README-OSX.txt: Major overhaul for build description, especially the
+         Xcode section.
+
+2004-07-16  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SxCore.xcode: added 'Wrapper' build style and 'Wrapper Contents'
+         target. Use these to build the frameworks in an appropriate form to
+         have them embedded in an applications app wrapper's 'Frameworks'
+         folder.
+
+       * SxCore.xcode: LDAP related targets link against new LDAP system
+         framework now.
+
+2004-06-11  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SxCore.xcode: removed NGCString from NGExtensions (deprecated)
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * common.make: removed local ADDITIONAL_LIB_DIRS since those might not
+         yet be available during compilation, which in turn prints warnings
+         with Apple gcc
+
+2004-05-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SxCore.xcode: added subclassing test tool
+
+2004-03-24  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SxCore.xcode: added NSString+German.[hm] in NGExtensions.
+         Also, added -headerpad_max_install_names link option where
+         appropriate.
+
+2004-03-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SxCore.xcode: added new plist categories in NGExtensions to Xcode
+         project
+
+2004-03-08  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SxCore.xcode: added new source files in EOControl to Xcode project
+
+       * README-OSX.txt: added some build notes
+
+2004-02-10  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SxCore.xcode: Updated prebinding information according to
+         README-OSX.txt. Also, added Foundation.framework explicitly
+         to all subprojects.
+
+       * README-OSX.txt: New README currently describing prebinding
+         information for Mac OS X.
+
+       * ChangeLog: created.
diff --git a/skyrix-core/EOControl/.cvsignore b/skyrix-core/EOControl/.cvsignore
new file mode 100644 (file)
index 0000000..49a10b1
--- /dev/null
@@ -0,0 +1,2 @@
+shared_debug_obj
+shared_obj
diff --git a/skyrix-core/EOControl/COPYING b/skyrix-core/EOControl/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-core/EOControl/COPYRIGHT b/skyrix-core/EOControl/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-core/EOControl/ChangeLog b/skyrix-core/EOControl/ChangeLog
new file mode 100644 (file)
index 0000000..1531b66
--- /dev/null
@@ -0,0 +1,127 @@
+2004-07-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOKeyComparisonQualifier.m, EOKeyValueQualifier.m, 
+         EOKeyValueArchiver.m, EOFetchSpecification.m: fixed gcc 3.4 warnings
+         (v4.2.46)
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.45
+
+       * GNUmakefile.preamble: added prebinding
+
+       * GNUmakefile: minor cleanups
+
+2004-05-16  Helge Hess  <helge.hess@opengroupware.org>
+
+       * EOKeyComparisonQualifier.m, EOKeyValueQualifier.m, EOQualifier.m,
+         EOQualifierVariable.m: minor code cleanups, fixed some "== YES"
+         comparisons (v4.2.44)
+
+2004-04-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOQualifierParser.m: minor code cleanups (==YES) (v4.2.43)
+
+2004-03-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOFetchSpecification, EOQualifier, EOSortOrdering: moved property
+         list initializer methods to NGExtensions to improve GDL2 
+         compatibility (v4.2.42)
+
+2004-03-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOFetchSpecification, EOQualifier, EOSortOrdering: deprecated
+         -initWithPropertyList: method, added new -initWithPropertyList:owner:
+         method (like in EOPropertyListEncoding) (v4.2.41)
+
+2004-03-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * EOFetchSpecification.m: subminor improvement in -copyWithZone:
+         method (v4.2.40)
+
+2004-03-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOFetchSpecification.m: fixed a recursion introduced in v4.2.38
+         (v4.2.39)
+
+2004-03-02  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.38
+
+       * EOQualifier.m: added -qualifierByApplyingBindings: to improve GDL2
+         compatibility (should not be used)
+
+       * EOFetchSpecification.m: added -fetchSpecificationByApplyingBindings:
+         to improve GDL2 compatibility (should not be used)
+
+       * EOQualifier.m: moved EOQualifierVariable to separate file, moved
+         qualifier-description categories to separate files
+       
+       * EOFetchSpecification.m, EOSQLParser.m: improved GDL2/EOF 3 
+         compatibility (different -init method, deprecated old)
+
+2003-12-29  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * EOKeyValueCoding.m: do not invoke NSDictionary -objectForKey: with
+         'nil' key (v4.2.37)
+       
+2003-11-25  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed unused source files (v4.2.36) [what was v4.2.35?, missing]
+       
+2003-11-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOSortOrdering.m: added an assertion to prevent index overflows
+         (v4.2.34)
+
+Tue Nov 11 12:01:10 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * common.h: fixed Free marcro declaration (introduced in 4.2.33)  
+         (v4.2.34)
+
+2003-11-09  Helge Hess  <helge@groove.local>
+
+       * v4.2.33
+
+       * common.h: always use malloc/free for allocating instead of
+         objc_malloc/objc_free to clean up the code
+
+       * EOAndQualifier.m: some minor tweaks for Xcode
+
+       * EOFault.m: removed support for Boehm GC to clean up the code
+
+2003-09-06  Helge Hess  <helge.hess@skyrix.com>
+
+        * EOGenericRecord.m: fixed a warning on MacOSX (used return in
+          dealloc ...) (v4.2.32)
+
+        * v4.2.31
+
+        * EOSQLParser.m: do not use stringByReplacingString:withString:
+
+       * EOClassDescription.m: fixed some warning on OSX
+
+2003-09-06  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * EOFault.m/EOFaultHandler.m: ported to NeXT runtime (v4.2.30)
+
+2003-09-01  Helge Hess  <helge.hess@skyrix.com>
+
+       * changed not to require FoundationExt on MacOSX (v4.2.29)
+
+2003-08-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOQualifierParser.m: added facility to register own classes for
+         complex cast expressions (eg "cast(xxxx as myValue)"), required
+         for Evolution 1.4.4. Also less restrictive about whitespace between
+         "cast" and the "(" (v4.2.28)
+
+Fri Jul  4 17:00:54 2003  Helge Hess  <helge.hess@skyrix.com>
+
+       * added to OpenGroupware.org
+
+       * stripped out old ChangeLogs, unimportant for OGo
+
+Wed Dec  8 18:35:40 1999  Helge Hess  <helge.hess@mdlink.de>
+
+       * created ChangeLog
diff --git a/skyrix-core/EOControl/EOAndQualifier.m b/skyrix-core/EOControl/EOAndQualifier.m
new file mode 100644 (file)
index 0000000..86b8974
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EOQualifier.h>
+#include "common.h"
+
+@interface EOQualifier(EvalContext)
+- (BOOL)evaluateWithObject:(id)_object inEvalContext:(id)_ctx;
+@end
+
+@implementation EOAndQualifier
+
+static BOOL debugEval      = NO;
+static BOOL debugTransform = NO;
+
++ (void)initialize {
+  debugEval = [EOQualifier isEvaluationDebuggingEnabled];
+}
+
+- (id)initWithQualifierArray:(NSArray *)_qualifiers {
+  self->count      = [_qualifiers count];
+  self->qualifiers = [_qualifiers copyWithZone:[self zone]];
+  return self;
+}
+
+- (id)initWithQualifiers:(EOQualifier *)_qual1, ... {
+  va_list     va;
+  EOQualifier *q;
+  id       *qs;
+  unsigned c;
+  NSArray  *a;
+  
+  va_start(va, _qual1);
+  for (c = 0, q = _qual1; q != nil; q = va_arg(va, id), c++)
+    ;
+  va_end(va);
+
+  if (c == 0)
+    return [self initWithQualifierArray:nil];
+
+  qs = calloc(c, sizeof(id));
+  
+  va_start(va, _qual1);
+  for (c = 0, q = _qual1; q != nil; q = va_arg(va, id), c++) {
+    qs[c] = q;
+  }
+  va_end(va);
+
+  a = [NSArray arrayWithObjects:qs count:c];
+  if (qs) free(qs);
+
+  return [self initWithQualifierArray:a];
+}
+
+- (void)dealloc {
+  [self->qualifiers release];
+  [super dealloc];
+}
+
+- (NSArray *)qualifiers {
+  return self->qualifiers;
+}
+- (NSArray *)subqualifiers {
+  return [self qualifiers];
+}
+
+/* bindings */
+
+- (EOQualifier *)qualifierWithBindings:(NSDictionary *)_bindings
+  requiresAllVariables:(BOOL)_reqAll
+{
+  NSArray  *array;
+  id       objects[self->count + 1];
+  unsigned i;
+  id (*objAtIdx)(id,SEL,unsigned);
+  
+  objAtIdx = (void *)
+    [self->qualifiers methodForSelector:@selector(objectAtIndex:)];
+  
+  for (i = 0; i < self->count; i++) {
+    id q, newq;
+
+    q = objAtIdx(self->qualifiers, @selector(objectAtIndex:), i);
+    newq = [q qualifierWithBindings:_bindings requiresAllVariables:_reqAll];
+    if (newq == nil) newq = q;
+    
+    objects[i] = newq;
+  }
+
+  array = [NSArray arrayWithObjects:objects count:self->count];
+  return [[[[self class] alloc] initWithQualifierArray:array] autorelease];
+}
+
+- (NSArray *)bindingKeys {
+  NSMutableSet *keys = nil;
+  unsigned i;
+  IMP objAtIdx;
+
+  objAtIdx = [self->qualifiers methodForSelector:@selector(objectAtIndex:)];
+  
+  for (i = 0; i < self->count; i++) {
+    NSArray *qb;
+    id q;
+
+    q = objAtIdx(self->qualifiers, @selector(objectAtIndex:), i);
+    qb = [q bindingKeys];
+
+    if ([qb count] > 0) {
+      if (keys == nil) keys = [NSMutableSet setWithCapacity:16];
+      [keys addObjectsFromArray:qb];
+    }
+  }
+  
+  return keys ? [keys allObjects] : [NSArray array];
+}
+
+/* keys */
+
+- (void)addQualifierKeysToSet:(NSMutableSet *)_keys {
+  /* new in WO 4.5 */
+  [self->qualifiers makeObjectsPerformSelector:_cmd withObject:_keys];
+}
+
+/* evaluation */
+
+- (BOOL)evaluateWithObject:(id)_object inEvalContext:(id)_ctx {
+  unsigned i;
+  IMP objAtIdx;
+  
+  if ((_ctx == nil) && (self->count > 1))
+    _ctx = [NSMutableDictionary dictionaryWithCapacity:16];
+  
+  objAtIdx = [self->qualifiers methodForSelector:@selector(objectAtIndex:)];
+  
+  for (i = 0; i < self->count; i++) {
+    id q;
+    
+    q = objAtIdx(self->qualifiers, @selector(objectAtIndex:), i);
+    
+    if (![q evaluateWithObject:_object inEvalContext:_ctx]) {
+      if (debugEval) {
+        NSLog(@"Eval: EOAndQualifier '%@':\n  qualifier[%i]: '%@'\n"
+              @"  failed on object '%@'",
+              self, i+1, q, _object);
+      }
+      return NO;
+    }
+  }
+  if (debugEval) {
+    NSLog(@"Eval: EOAndQualifier '%@':\n  true on object '%@'",
+          self, _object);
+  }
+  return YES;
+}
+- (BOOL)evaluateWithObject:(id)_object {
+  return [self evaluateWithObject:_object inEvalContext:nil];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->qualifiers];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  self->qualifiers = [[_coder decodeObject] retain];
+  return self;
+}
+
+/* Comparing */
+
+- (BOOL)isEqualToQualifier:(EOQualifier *)_qual {
+  return [self->qualifiers isEqualToArray:[(EOAndQualifier *)_qual qualifiers]];
+}
+
+/* remapping keys */
+
+- (EOQualifier *)qualifierByApplyingTransformer:(id)_transformer
+  inContext:(id)_ctx
+{
+  if ([_transformer respondsToSelector:
+                      @selector(transformAndQualifier:inContext:)]) {
+    if (debugTransform)
+      NSLog(@"transformer: %@\n  transform: %@", _transformer, self);
+    return [_transformer transformAndQualifier:self inContext:_ctx];
+  }
+  else {
+    EOAndQualifier *aq;
+    NSArray  *a;
+    id       *qs;
+    unsigned i;
+    BOOL     didTransform = NO;
+    
+    if (debugTransform) {
+      NSLog(@"EOAndQualifier: transform %i using %@ ...", 
+            self->count, _transformer);
+    }
+    
+    qs = calloc(self->count + 1, sizeof(id));
+    for (i = 0; i < self->count; i++) {
+      EOQualifier *q;
+      
+      q     = [self->qualifiers objectAtIndex:i];
+      qs[i] = [q qualifierByApplyingTransformer:_transformer inContext:_ctx];
+      if (qs[i] == nil) 
+        qs[i] = q;
+      else if (qs[i] != q) {
+        if (debugTransform)
+          NSLog(@"EOAndQualifier:   subqualifier %i did transform", i);
+        didTransform = YES;
+      }
+      else if (debugTransform)
+        NSLog(@"EOAndQualifier:   subqualifier %i did not transform", i);
+    }
+    if (didTransform) {
+      a = [[NSArray alloc] initWithObjects:qs count:self->count];
+      if (qs) free(qs);
+      aq = [[EOAndQualifier alloc] initWithQualifierArray:a];
+      [a release];
+      return [aq autorelease];
+    }
+    else {
+      if (qs) free(qs);
+      return [[self retain] autorelease];
+    }
+  }
+}
+
+- (EOQualifier *)qualifierByApplyingKeyMap:(NSDictionary *)_map {
+  EOAndQualifier *aq;
+  NSArray  *a;
+  id       *qs;
+  unsigned i;
+  
+  qs = calloc(self->count + 1, sizeof(id));
+  for (i = 0; i < self->count; i++) {
+    EOQualifier *q;
+    
+    q     = [self->qualifiers objectAtIndex:i];
+    qs[i] = [q qualifierByApplyingKeyMap:_map];
+    if (qs[i] == nil) qs[i] = q;
+  }
+  a = [[NSArray alloc] initWithObjects:qs count:self->count];
+  if (qs) free(qs);
+  aq = [[EOAndQualifier alloc] initWithQualifierArray:a];
+  [a release];
+  return [aq autorelease];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  NSArray  *sd;
+  unsigned i, len;
+  
+  sd = [self->qualifiers valueForKey:@"qualifierDescription"];
+  if ((len = [sd count]) == 0)
+    return nil;
+  if (len == 1)
+    return [sd objectAtIndex:0];
+  
+  ms = [NSMutableString stringWithCapacity:(len * 16)];
+  [ms appendString:@"("];
+  for (i = 0; i < len; i++) {
+    if (i != 0) [ms appendString:@" AND "];
+    [ms appendString:[sd objectAtIndex:i]];
+  }
+  [ms appendString:@")"];
+  return ms;
+}
+
+@end /* EOAndQualifier */
diff --git a/skyrix-core/EOControl/EOArrayDataSource.h b/skyrix-core/EOControl/EOArrayDataSource.h
new file mode 100644 (file)
index 0000000..6054b26
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __EOArrayDataSource_H__
+#define __EOArrayDataSource_H__
+
+#include <EOControl/EODataSource.h>
+
+@class NSArray, NSMutableArray;
+@class EOFetchSpecification;
+
+@interface EOArrayDataSource : EODataSource
+{
+  NSMutableArray       *objects;
+  EOFetchSpecification *fetchSpecification;
+}
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec;
+- (EOFetchSpecification *)fetchSpecification;
+
+- (void)setArray:(NSArray *)_array;
+
+@end
+
+#endif /* __EOArrayDataSource_H__ */
diff --git a/skyrix-core/EOControl/EOArrayDataSource.m b/skyrix-core/EOControl/EOArrayDataSource.m
new file mode 100644 (file)
index 0000000..645b463
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EOArrayDataSource.h>
+#include <EOControl/EOFetchSpecification.h>
+#include <EOControl/EOSortOrdering.h>
+#include <EOControl/EOQualifier.h>
+#include "common.h"
+
+@interface EODataSource(PostChange)
+- (void)postDataSourceChangedNotification;
+@end
+
+@implementation EOArrayDataSource
+
+- (id)init {
+  if ((self = [super init])) {
+    self->objects = [[NSMutableArray alloc] init];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->fetchSpecification release];
+  [self->objects            release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec {
+  if ([self->fetchSpecification isEqual:_fspec])
+    return;
+  
+  [self->fetchSpecification autorelease];
+  self->fetchSpecification = [_fspec copy];
+  
+  [self postDataSourceChangedNotification];
+}
+- (EOFetchSpecification *)fetchSpecification {
+  return self->fetchSpecification;
+}
+
+- (void)setArray:(NSArray *)_array {
+  [self->objects removeAllObjects];
+  [self->objects addObjectsFromArray:_array];
+}
+
+/* fetching */
+
+- (NSArray *)fetchObjects {
+  NSArray *result;
+  
+  if (self->fetchSpecification == nil) {
+    result = [[self->objects copy] autorelease];
+  }
+  else {
+    EOQualifier *q;
+    NSArray     *sort;
+    
+    q    = [self->fetchSpecification qualifier];
+    sort = [self->fetchSpecification sortOrderings];
+    
+    if (q == nil) {
+      if (sort)
+        result = [self->objects sortedArrayUsingKeyOrderArray:sort];
+      else
+        result = [[self->objects copy] autorelease];
+    }
+    else {
+      result = [self->objects filteredArrayUsingQualifier:q];
+      if (sort) result = [result sortedArrayUsingKeyOrderArray:sort];
+    }
+  }
+  return result;
+}
+
+/* operations */
+
+- (void)deleteObject:(id)_object {
+  [self->objects removeObjectIdenticalTo:_object];
+  [self postDataSourceChangedNotification];
+}
+
+- (void)insertObject:(id)_object {
+  [self->objects addObject:_object];
+  [self postDataSourceChangedNotification];
+}
+
+- (id)createObject {
+  return [NSMutableDictionary dictionaryWithCapacity:16];
+}
+
+@end /* EOArrayDataSource */
diff --git a/skyrix-core/EOControl/EOClassDescription.h b/skyrix-core/EOControl/EOClassDescription.h
new file mode 100644 (file)
index 0000000..6617cb3
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_EOClassDescription_H__
+#define __EOControl_EOClassDescription_H__
+
+#import <Foundation/Foundation.h>
+#include <EOControl/EOGlobalID.h>
+
+@class NSException, NSString, NSFormatter;
+
+@interface EOClassDescription : NSClassDescription
+
+@end
+
+@interface NSClassDescription(EOClassDescription)
+
+/* model */
+
+- (NSString *)entityName;
+- (NSString *)inverseForRelationshipKey:(NSString *)_key;
+- (NSClassDescription *)classDescriptionForDestinationKey:(NSString *)_key;
+
+/* object initialization */
+
+- (id)createInstanceWithEditingContext:(id)_ec
+  globalID:(EOGlobalID *)_oid
+  zone:(NSZone *)_zone;
+
+- (void)awakeObject:(id)_object fromFetchInEditingContext:(id)_ec;
+- (void)awakeObject:(id)_object fromInsertionInEditingContext:(id)_ec;
+
+/* delete */
+
+- (void)propagateDeleteForObject:(id)_object editingContext:(id)_ec;
+
+/* entity names */
+
+#if 0
+// used by: EOGenericRecord.m
++ (NSClassDescription *)classDescriptionForEntityName:(NSString *)_entityName;
+#endif
+
+/* formatting */
+
+- (NSFormatter *)defaultFormatterForKey:(NSString *)_key;
+- (NSFormatter *)defaultFormatterForKeyPath:(NSString *)_keyPath;
+
+@end
+
+@interface NSClassDescription(EOValidation)
+
+- (NSException *)validateObjectForDelete:(id)_object;
+- (NSException *)validateObjectForSave:(id)_object;
+- (NSException *)validateValue:(id *)_value forKey:(NSString *)_key;
+
+@end
+
+@interface NSObject(EOClassDescriptionInit)
+
+/* object initialization */
+
+- (id)initWithEditingContext:(id)_ec
+  classDescription:(NSClassDescription *)_classDesc
+  globalID:(EOGlobalID *)_oid;
+
+- (void)awakeFromFetchInEditingContext:(id)_ec;
+- (void)awakeFromInsertionInEditingContext:(id)_ec;
+
+/* model */
+
+- (NSString *)entityName;
+- (NSString *)inverseForRelationshipKey:(NSString *)_key;
+- (NSArray *)attributeKeys;
+- (NSArray *)toManyRelationshipKeys;
+- (NSArray *)toOneRelationshipKeys;
+
+- (BOOL)isToManyKey:(NSString *)_key;
+- (NSArray *)allPropertyKeys;
+
+/* delete */
+
+- (void)propagateDeleteWithEditingContext:(id)_ec;
+
+@end
+
+/* validation */
+
+@interface NSObject(EOValidation)
+
+- (NSException *)validateForDelete;
+- (NSException *)validateForInsert;
+- (NSException *)validateForUpdate;
+- (NSException *)validateForSave;
+
+@end
+
+@interface NSException(EOValidation)
+
++ (NSException *)aggregateExceptionWithExceptions:(NSArray *)_exceptions;
+
+@end
+
+/* snapshots */
+
+@interface NSObject(EOSnapshots)
+
+- (NSDictionary *)snapshot;
+- (void)updateFromSnapshot:(NSDictionary *)_snapshot;
+- (NSDictionary *)changesFromSnapshot:(NSDictionary *)_snapshot;
+
+@end
+
+/* relationships */
+
+@interface NSObject(EORelationshipManipulation)
+
+- (void)addObject:(id)_o    toBothSidesOfRelationshipWithKey:(NSString *)_key;
+- (void)removeObject:(id)_o fromBothSidesOfRelationshipWithKey:(NSString *)_key;
+
+- (void)addObject:(id)_object    toPropertyWithKey:(NSString *)_key;
+- (void)removeObject:(id)_object fromPropertyWithKey:(NSString *)_key;
+
+@end
+
+/* shallow array copying */
+
+@interface NSArray(ShallowCopy)
+- (id)shallowCopy;
+@end
+
+#endif /* __EOControl_EOClassDescription_H__ */
diff --git a/skyrix-core/EOControl/EOClassDescription.m b/skyrix-core/EOControl/EOClassDescription.m
new file mode 100644 (file)
index 0000000..a76db6b
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOClassDescription.h"
+#include "EOKeyValueCoding.h"
+#include "EONull.h"
+#include "common.h"
+
+@implementation NSClassDescription(EOClassDescription)
+
+/* model */
+
+- (NSString *)entityName {
+  return nil;
+}
+- (NSString *)inverseForRelationshipKey:(NSString *)_key {
+  return nil;
+}
+
+- (NSClassDescription *)classDescriptionForDestinationKey:(NSString *)_key {
+  return nil;
+}
+
+/* object initialization */
+
+- (id)createInstanceWithEditingContext:(id)_ec
+  globalID:(EOGlobalID *)_oid
+  zone:(NSZone *)_zone
+{
+  return nil;
+}
+
+- (void)awakeObject:(id)_object
+  fromFetchInEditingContext:(id)_ec
+{
+}
+- (void)awakeObject:(id)_object
+  fromInsertionInEditingContext:(id)_ec
+{
+}
+
+/* formatting */
+
+- (NSFormatter *)defaultFormatterForKey:(NSString *)_key {
+  return nil;
+}
+- (NSFormatter *)defaultFormatterForKeyPath:(NSString *)_keyPath {
+  return nil;
+}
+
+/* delete */
+
+- (void)propagateDeleteForObject:(id)_object editingContext:(id)_ec {
+}
+
+@end /* NSClassDescription(EOClassDescription) */
+
+@implementation EOClassDescription
+
+// THREAD
+static NSMapTable *entityToDesc = NULL;
+static NSMapTable *classToDesc  = NULL;
+
++ (void)initialize {
+  if (entityToDesc == NULL) {
+    entityToDesc = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                    NSObjectMapValueCallBacks,
+                                    32);
+  }
+  if (classToDesc == NULL) {
+    classToDesc = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                   NSObjectMapValueCallBacks,
+                                   32);
+  }
+}
+
++ (NSClassDescription *)classDescriptionForClass:(Class)_class
+{
+  EOClassDescription *d;
+
+#if DEBUG
+  NSAssert(_class != [EOGlobalID class],
+           @"classDescriptionForClass:EOGlobalID ???");
+#endif
+  
+  if ((d = NSMapGet(classToDesc, _class)))
+    return d;
+  
+  [[NSNotificationCenter defaultCenter]
+                         postNotificationName:
+                           @"EOClassDescriptionNeededForClass"
+                         object:_class];
+  
+  return NSMapGet(classToDesc, _class);
+}
+
++ (NSClassDescription *)classDescriptionForEntityName:(NSString *)_entityName {
+  NSClassDescription *d;
+  
+  if ((d = NSMapGet(entityToDesc, _entityName)))
+    return d;
+
+  [[NSNotificationCenter defaultCenter]
+                         postNotificationName:
+                           @"EOClassDescriptionNeededForEntityName"
+                         object:_entityName];
+  
+  return NSMapGet(entityToDesc, _entityName);
+}
+
++ (void)invalidateClassDescriptionCache {
+  NSResetMapTable(entityToDesc);
+  NSResetMapTable(classToDesc);
+}
+
++ (void)registerClassDescription:(NSClassDescription *)_clazzDesc
+  forClass:(Class)_class
+{
+  NSString *entityName;
+  
+  if (_clazzDesc == nil)
+    return;
+  
+  if (_class)
+    NSMapInsert(classToDesc,  _class, _clazzDesc);
+  
+  if ((entityName = [_clazzDesc entityName]))
+    NSMapInsert(entityToDesc, entityName, _clazzDesc);
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: entity=%@>",
+                     NSStringFromClass([self class]), self,
+                     [self entityName]];
+}
+
+@end /* EOClassDescription */
+
+@implementation NSObject(EOClassDescription)
+
+- (NSClassDescription *)classDescriptionForDestinationKey:(NSString *)_key {
+  return [[self classDescription] classDescriptionForDestinationKey:_key];
+}
+
+/* object initialization */
+
+- (id)initWithEditingContext:(id)_ec
+  classDescription:(NSClassDescription *)_classDesc
+  globalID:(EOGlobalID *)_oid
+{
+  return [self init];
+}
+
+- (void)awakeFromFetchInEditingContext:(id)_ec {
+  [[self classDescription]
+         awakeObject:self fromFetchInEditingContext:_ec];
+}
+- (void)awakeFromInsertionInEditingContext:(id)_ec {
+  [[self classDescription]
+         awakeObject:self fromInsertionInEditingContext:_ec];
+}
+
+/* model */
+
+- (NSString *)entityName {
+  return [[self classDescription] entityName];
+}
+- (NSString *)inverseForRelationshipKey:(NSString *)_key {
+  return [[self classDescription] inverseForRelationshipKey:_key];
+}
+- (NSArray *)attributeKeys {
+  return [[self classDescription] attributeKeys];
+}
+
+- (BOOL)isToManyKey:(NSString *)_key {
+  return [[self toManyRelationshipKeys] containsObject:_key];
+}
+- (NSArray *)allPropertyKeys {
+  NSArray *attrs;
+
+  attrs = [self attributeKeys];
+  attrs = attrs
+    ? [attrs arrayByAddingObjectsFromArray:[self toOneRelationshipKeys]]
+    : [self toOneRelationshipKeys];
+  attrs = attrs
+    ? [attrs arrayByAddingObjectsFromArray:[self toManyRelationshipKeys]]
+    : [self toManyRelationshipKeys];
+
+  return attrs;
+}
+
+/* delete */
+
+- (void)propagateDeleteWithEditingContext:(id)_ec {
+  [[self classDescription] propagateDeleteForObject:self editingContext:_ec];
+}
+
+@end /* NSObject(EOClassDescription) */
+
+@implementation NSException(EOValidation)
+
++ (NSException *)aggregateExceptionWithExceptions:(NSArray *)_exceptions {
+  NSException *e;
+
+  e = [[self alloc] initWithName:@"EOAggregateException"
+                    reason:@"several exceptions occured"
+                    userInfo:
+                      [NSDictionary dictionaryWithObject:_exceptions
+                                    forKey:@"exceptions"]];
+  return [e autorelease];
+}
+
+@end /* NSException(EOValidation) */
+
+/* snapshots */
+
+@implementation NSObject(EOSnapshots)
+
+- (NSDictionary *)snapshot {
+  static NSNull *null = nil;
+  NSMutableDictionary *d;
+  NSDictionary *r;
+  NSEnumerator *e;
+  NSString *key;
+
+  if (null == nil) null = [NSNull null];
+  
+  d = [[NSMutableDictionary alloc] initWithCapacity:64];
+  
+  e = [[self attributeKeys] objectEnumerator];
+  while ((key = [e nextObject])) {
+    id value;
+
+    value = [self valueForKey:key];
+    value = (value == nil) ? (id)[null retain] : (id)[value copy];
+    [d setObject:value forKey:key];
+    [value release]; value = nil;
+  }
+  
+  e = [[self toOneRelationshipKeys] objectEnumerator];
+  while ((key = [e nextObject])) {
+    id value;
+
+    value = [self valueForKey:key];
+    if (value == nil) value = [NSNull null];
+
+    [d setObject:value forKey:key];
+  }
+  
+  e = [[self toManyRelationshipKeys] objectEnumerator];
+  while ((key = [e nextObject])) {
+    id value;
+
+    value = [self valueForKey:key];
+    if (value == nil) {
+      value = [[NSNull null] retain];
+    }
+    else {
+      value = [value shallowCopy];
+    }
+    [d setObject:value forKey:key];
+    [value release]; value = nil;
+  }
+  
+  r = [d copy];
+  [d release]; d = nil;
+  return [r autorelease];
+}
+
+- (void)updateFromSnapshot:(NSDictionary *)_snapshot {
+  [self takeValuesFromDictionary:_snapshot];
+}
+
+- (NSDictionary *)changesFromSnapshot:(NSDictionary *)_snapshot {
+  /* not really correct, need to work on relationships */
+  static NSNull *null = nil;
+  NSMutableDictionary *diff;
+  NSEnumerator *props;
+  NSString     *key;
+  
+  if (null == nil) null = [NSNull null];
+  
+  diff = [NSMutableDictionary dictionaryWithCapacity:32];
+  
+  props = [[self allPropertyKeys] objectEnumerator];
+  while ((key = [props nextObject])) {
+    id value;
+    id svalue;
+    
+    value  = [self valueForKey:key];
+    svalue = [_snapshot objectForKey:key];
+    if (value  == nil) value  = null;
+    if (svalue == nil) svalue = null;
+
+    if (svalue != value) {
+      /* difference */
+      if ([self isToManyKey:key]) {
+        id adiff[2];
+
+        adiff[0] = [NSArray array];
+        adiff[1] = [NSArray array];
+
+        /* to be completed: calc real diff */
+        
+        [diff setObject:[NSArray arrayWithObjects:adiff count:2] forKey:key];
+      }
+      else
+        [diff setObject:value forKey:key];
+    }
+  }
+  
+  return diff;
+}
+
+- (void)reapplyChangesFromDictionary:(NSDictionary *)_changes {
+  /* not really correct, need to work on relationships */
+  NSEnumerator *keys;
+  NSString *key;
+
+  keys = [_changes keyEnumerator];
+  while ((key = [keys nextObject])) {
+    id value;
+    
+    value = [_changes objectForKey:key];
+
+    if ([self isToManyKey:key]) {
+      NSArray        *added;
+      NSArray        *deleted;
+      NSMutableArray *current;
+
+      added   = [value objectAtIndex:0];
+      deleted = [value objectAtIndex:1];
+      current = [[self valueForKey:key] mutableCopy];
+      
+      if (added)   [current addObjectsFromArray:added];
+      if (deleted) [current removeObjectsInArray:deleted];
+      
+      [current release]; current = nil;
+    }
+    else
+      [self takeValue:value forKey:key];
+    
+    [self takeValuesFromDictionary:_changes];
+  }
+}
+
+@end /* NSObject(EOSnapshots) */
+
+/* relationships */
+
+@implementation NSObject(EORelationshipManipulation)
+
+- (void)addObject:(id)_o toBothSidesOfRelationshipWithKey:(NSString *)_key {
+  NSString *revKey;
+  BOOL     isToMany;
+  
+  revKey = [self inverseForRelationshipKey:_key];
+  isToMany = [self isToManyKey:_key];
+  
+  self = [[self retain] autorelease];
+  _o   = [[_o retain] autorelease];
+  
+  if (isToMany) {
+    /* watch out, likely to be buggy ! */
+    [self addObject:_o toPropertyWithKey:_key];
+  }
+  else
+    [self takeValue:_o forKey:_key];
+
+  if (revKey) {
+    /* add to the reverse object */
+    BOOL revIsToMany;
+
+    revIsToMany = [_o isToManyKey:revKey];
+    
+    if (revIsToMany)
+      [_o addObject:self toPropertyWithKey:revKey];
+    else
+      [_o takeValue:self forKey:revKey];
+  }
+}
+- (void)removeObject:(id)_o fromBothSidesOfRelationshipWithKey:(NSString *)_key {
+  NSString *revKey;
+  BOOL isToMany;
+
+  revKey   = [self inverseForRelationshipKey:_key];
+  isToMany = [self isToManyKey:_key];
+  
+  self = [[self retain] autorelease];
+  _o   = [[_o   retain] autorelease];
+
+  /* remove from this object */
+  
+  if (isToMany)
+    [self removeObject:_o fromPropertyWithKey:_key];
+  else
+    [self takeValue:nil forKey:_key];
+  
+  if (revKey) {
+    /* remove from reverse object */
+    BOOL revIsToMany;
+
+    revIsToMany = [_o isToManyKey:revKey];
+    
+    if (revIsToMany)
+      [_o removeObject:self fromPropertyWithKey:revKey];
+    else
+      [_o takeValue:nil forKey:revKey];
+  }
+}
+
+- (void)addObject:(id)_object toPropertyWithKey:(NSString *)_key {
+  NSString *selname;
+  SEL      sel;
+
+  selname = [@"addTo" stringByAppendingString:[_key capitalizedString]];
+  sel = NSSelectorFromString(selname);
+
+  if ([self respondsToSelector:sel])
+    [self performSelector:sel withObject:_object];
+  else {
+    id v;
+
+    v = [self valueForKey:_key];
+
+    if ([self isToManyKey:_key]) {
+      /* to-many relationship */
+      if (v == nil) {
+        [self takeValue:[NSArray arrayWithObject:_object] forKey:_key];
+      }
+      else if (![v containsObject:_object]) {
+        if ([v respondsToSelector:@selector(addObject:)])
+          [v addObject:_object];
+        else {
+          v = [v arrayByAddingObject:_object];
+          [self takeValue:v forKey:_key];
+        }
+      }
+    }
+    else {
+      /* to-one relationship */
+      if (v != _object)
+        [self takeValue:v forKey:_key];
+    }
+  }
+}
+- (void)removeObject:(id)_object fromPropertyWithKey:(NSString *)_key {
+  NSString *selname;
+  SEL      sel;
+
+  selname = [@"removeFrom" stringByAppendingString:[_key capitalizedString]];
+  sel = NSSelectorFromString(selname);
+  
+  if ([self respondsToSelector:sel])
+    [self performSelector:sel withObject:_object];
+  else {
+    id v;
+
+    v = [self valueForKey:_key];
+    
+    if ([self isToManyKey:_key]) {
+      /* to-many relationship */
+      if (v == nil) {
+        /* do nothing */
+      }
+      else if (![v containsObject:_object]) {
+        if ([v respondsToSelector:@selector(addObject:)])
+          [v removeObject:_object];
+        else {
+          v = [v mutableCopy];
+          [v removeObject:_object];
+          [self takeValue:v forKey:_key];
+          [v release]; v = nil;
+        }
+      }
+    }
+    else {
+      /* to-one relationship */
+      [self takeValue:nil forKey:_key];
+    }
+  }
+}
+
+@end /* NSObject(EORelationshipManipulation) */
+
+/* shallow array copying */
+
+@implementation NSArray(ShallowCopy)
+
+- (id)shallowCopy {
+  NSArray *a;
+  unsigned i, cc;
+  id *objects;
+
+  cc = [self count];
+  objects = calloc(cc + 1, sizeof(id));
+  
+  for (i = 0; i < cc; i++)
+    objects[i] = [self objectAtIndex:i];
+
+  a = [[NSArray alloc] initWithObjects:objects count:cc];
+  
+  if (objects) free(objects);
+  
+  return a;
+}
+
+@end /* NSArray(ShallowCopy) */
diff --git a/skyrix-core/EOControl/EOControl-Info.plist b/skyrix-core/EOControl/EOControl-Info.plist
new file mode 100644 (file)
index 0000000..c84c03f
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>EOControl</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.core.EOControl</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-core/EOControl/EOControl.h b/skyrix-core/EOControl/EOControl.h
new file mode 100644 (file)
index 0000000..3918a80
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_H__
+#define __EOControl_H__
+
+#include <EOControl/EOArrayDataSource.h>
+#include <EOControl/EOClassDescription.h>
+#include <EOControl/EODataSource.h>
+#include <EOControl/EODetailDataSource.h>
+#include <EOControl/EOFetchSpecification.h>
+#include <EOControl/EOGenericRecord.h>
+#include <EOControl/EOGlobalID.h>
+#include <EOControl/EOKeyGlobalID.h>
+#include <EOControl/EOKeyValueArchiver.h>
+#include <EOControl/EOKeyValueCoding.h>
+#include <EOControl/EONull.h>
+#include <EOControl/EOObserver.h>
+#include <EOControl/EOQualifier.h>
+#include <EOControl/EOSortOrdering.h>
+
+#endif /* __EOControl_H__ */
diff --git a/skyrix-core/EOControl/EOControlDecls.h b/skyrix-core/EOControl/EOControlDecls.h
new file mode 100644 (file)
index 0000000..fcb28cb
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_EOControlDecls_H__
+#define __EOControl_EOControlDecls_H__
+
+#if BUILD_libEOControl_DLL
+#  define EOControl_EXPORT  __declspec(dllexport)
+#  define EOControl_DECLARE __declspec(dllexport)
+#elif libEOControl_ISDLL
+#  define EOControl_EXPORT  extern __declspec(dllimport)
+#  define EOControl_DECLARE extern __declspec(dllimport)
+#else
+#  define EOControl_EXPORT  extern
+#  define EOControl_DECLARE 
+#endif
+
+#endif /* __EOControl_EOControlDecls_H__ */
diff --git a/skyrix-core/EOControl/EODataSource.h b/skyrix-core/EOControl/EODataSource.h
new file mode 100644 (file)
index 0000000..a8e4b54
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_EODataSource_H__
+#define __EOControl_EODataSource_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSArray, NSEnumerator;
+@class EOClassDescription;
+
+@interface EODataSource : NSObject
+
+/* reflection */
+
+- (EOClassDescription *)classDescriptionForObjects;
+
+/* master-detail */
+
+- (EODataSource *)dataSourceQualifiedByKey:(NSString *)_relKey;
+- (void)qualifyWithRelationshipKey:(NSString *)_relKey ofObject:(id)_object;
+
+/* operations */
+
+- (NSArray *)fetchObjects;
+- (void)deleteObject:(id)_object;
+- (void)insertObject:(id)_object;
+- (id)createObject;
+
+- (NSEnumerator *)fetchEnumerator;
+
+@end
+
+#endif /* __EOControl_EODataSource_H__ */
diff --git a/skyrix-core/EOControl/EODataSource.m b/skyrix-core/EOControl/EODataSource.m
new file mode 100644 (file)
index 0000000..fc50672
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EODataSource.h>
+#include <EOControl/EOClassDescription.h>
+#include "common.h"
+
+@implementation EODataSource
+
++ (int)version {
+  return 1;
+}
+
+/* reflection */
+
+- (EOClassDescription *)classDescriptionForObjects {
+  return nil;
+}
+
+/* master-detail */
+
+- (EODataSource *)dataSourceQualifiedByKey:(NSString *)_relKey {
+  [NSException raise:@"NSInvalidArgumentException"
+               format:@"datasource %@ can't return a ds qualified by key '%@'",
+                 self, _relKey];
+  return nil;
+}
+
+- (void)qualifyWithRelationshipKey:(NSString *)_relKey ofObject:(id)_object {
+  [NSException raise:@"NSInvalidArgumentException"
+               format:@"datasource %@ can't qualify by key '%@' of object %@",
+                 self, _relKey, _object];
+}
+
+/* operations */
+
+- (NSArray *)fetchObjects {
+  return nil;
+}
+- (NSEnumerator *)fetchEnumerator {
+  return [[self fetchObjects] objectEnumerator];
+}
+
+- (void)deleteObject:(id)_object {
+  [NSException raise:@"NSInvalidArgumentException"
+               format:@"datasource %@ can't delete object %@",
+                 self, _object];
+}
+
+- (void)insertObject:(id)_object {
+  [NSException raise:@"NSInvalidArgumentException"
+               format:@"datasource %@ can't insert object %@",
+                 self, _object];
+}
+
+- (id)createObject {
+  EOClassDescription *cd;
+  
+  if ((cd = [self classDescriptionForObjects]) == nil)
+    return nil;
+  
+  return [cd createInstanceWithEditingContext:nil globalID:nil zone:NULL];
+}
+
+@end /* EODataSource */
diff --git a/skyrix-core/EOControl/EODetailDataSource.h b/skyrix-core/EOControl/EODetailDataSource.h
new file mode 100644 (file)
index 0000000..d0c9523
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_EODetailDataSource_H__
+#define __EOControl_EODetailDataSource_H__
+
+#include <EOControl/EODataSource.h>
+
+@class EOClassDescription;
+
+@interface EODetailDataSource : EODataSource
+{
+  EOClassDescription *masterClassDescription;
+  EODataSource       *masterDataSource;
+  id                 masterObject;
+  NSString           *detailKey;
+}
+
+- (id)initWithMasterClassDescription:(EOClassDescription *)_cd
+  detailKey:(NSString *)_relKey; // designated initializer
+- (id)initWithMasterDataSource:(EODataSource *)_ds
+  detailKey:(NSString *)_relKey;
+
+/* reflection */
+
+- (void)setMasterClassDescription:(EOClassDescription *)_cd;
+- (EOClassDescription *)masterClassDescription;
+- (EODataSource *)masterDataSource;
+
+/* master-detail */
+
+- (id)masterObject;
+- (NSString *)detailKey;
+
+@end
+
+#endif /* __EOControl_EODetailDataSource_H__ */
diff --git a/skyrix-core/EOControl/EODetailDataSource.m b/skyrix-core/EOControl/EODetailDataSource.m
new file mode 100644 (file)
index 0000000..0541559
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EODetailDataSource.h>
+#include <EOControl/EOClassDescription.h>
+#include <EOControl/EOKeyValueCoding.h>
+#include "common.h"
+
+@implementation EODetailDataSource
+
+- (id)initWithMasterClassDescription:(EOClassDescription *)_cd
+  detailKey:(NSString *)_relKey
+{
+  if ((self = [super init])) {
+    self->masterClassDescription = [_cd retain];
+
+    [self qualifyWithRelationshipKey:_relKey ofObject:nil];
+  }
+  return self;
+}
+
+- (id)initWithMasterDataSource:(EODataSource *)_ds
+  detailKey:(NSString *)_relKey
+{
+  if ((self = [self initWithMasterClassDescription:nil detailKey:_relKey])) {
+    self->masterDataSource = [_ds retain];
+  }
+  return self;
+}
+
+- (id)init {
+  return [self initWithMasterClassDescription:nil detailKey:nil];
+}
+
+- (void)dealloc {
+  [self->detailKey              release];
+  [self->masterObject           release];
+  [self->masterClassDescription release];
+  [self->masterDataSource       release];
+  [super dealloc];
+}
+
+/* reflection */
+
+- (void)setMasterClassDescription:(EOClassDescription *)_cd {
+  ASSIGN(self->masterClassDescription, _cd);
+}
+- (EOClassDescription *)masterClassDescription {
+  return self->masterClassDescription;
+}
+
+- (EODataSource *)masterDataSource {
+  return self->masterDataSource;
+}
+
+/* editing context */
+
+- (id)editingContext {
+  return [[self masterObject] editingContext];
+}
+
+/* master-detail */
+
+- (id)masterObject {
+  return self->masterObject;
+}
+- (NSString *)detailKey {
+  return self->detailKey;
+}
+
+- (void)qualifyWithRelationshipKey:(NSString *)_relKey ofObject:(id)_object {
+  id tmp;
+
+  tmp = self->detailKey;
+  self->detailKey = [_relKey copy];
+  [tmp release];
+
+  ASSIGN(self->masterObject, _object);
+}
+
+/* operations */
+
+- (NSArray *)fetchObjects {
+  id       eo;
+  NSString *dk;
+  
+  if ((eo = [self masterObject]) == nil)
+    return [NSArray array];
+
+  if ((dk = [self detailKey]) == nil)
+    return [NSArray arrayWithObject:eo];
+
+  return [eo valueForKey:dk];
+}
+
+- (void)insertObject:(id)_object {
+  id       eo;
+  NSString *dk;
+  
+  if ((eo = [self masterObject]) == nil) {
+    [NSException raise:@"NSInternalInconsistencyException"
+                 format:
+                   @"detail datasource %@ has no master object set "
+                   @"for insertion of object %@",
+                   self, _object];
+  }
+  if ((dk = [self detailKey]) == nil) {
+    [NSException raise:@"NSInternalInconsistencyException"
+                 format:
+                   @"detail datasource %@ has no detail key set "
+                   @"for insertion of object %@ into master %@",
+                   self, _object, eo];
+  }
+  
+  [eo addObject:_object toBothSidesOfRelationshipWithKey:dk];
+}
+
+- (void)deleteObject:(id)_object {
+  id       eo;
+  NSString *dk;
+  
+  if ((eo = [self masterObject]) == nil) {
+    [NSException raise:@"NSInternalInconsistencyException"
+                 format:
+                   @"detail datasource %@ has no master object set "
+                   @"for deletion of object %@",
+                   self, _object];
+  }
+  if ((dk = [self detailKey]) == nil) {
+    [NSException raise:@"NSInternalInconsistencyException"
+                 format:
+                   @"detail datasource %@ has no detail key set "
+                   @"for deletion of object %@ from master %@",
+                   self, _object, eo];
+  }
+  
+  [eo removeObject:_object fromPropertyWithKey:dk];
+}
+
+@end /* EODetailDataSource */
diff --git a/skyrix-core/EOControl/EOFetchSpecification.h b/skyrix-core/EOControl/EOFetchSpecification.h
new file mode 100644 (file)
index 0000000..b25efe5
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOFetchSpecification_h__
+#define __EOFetchSpecification_h__
+
+#import <Foundation/NSObject.h>
+
+@class NSArray, NSString, NSDictionary;
+@class EOQualifier;
+
+@interface EOFetchSpecification : NSObject < NSCopying >
+{
+  NSString     *entityName;
+  EOQualifier  *qualifier;
+  NSArray      *sortOrderings;
+  unsigned     fetchLimit;
+  NSDictionary *hints;
+  struct {
+    int usesDistinct:1;
+    int locksObjects:1;
+    int deep:1;
+    int reserved:29;
+  } fsFlags;
+}
+
++ (EOFetchSpecification *)fetchSpecificationWithEntityName:(NSString *)_ename
+  qualifier:(EOQualifier *)_qualifier
+  sortOrderings:(NSArray *)sortOrderings;
+
+- (id)initWithEntityName:(NSString *)_name
+  qualifier:(EOQualifier *)_qualifier
+  sortOrderings:(NSArray *)_sortOrderings
+  usesDistinct:(BOOL)_dflag isDeep:(BOOL)_isDeep
+  hints:(NSDictionary *)_hints;
+
+/* accessors */
+
+- (void)setEntityName:(NSString *)_name;
+- (NSString *)entityName;
+
+- (void)setQualifier:(EOQualifier *)_qualifier;
+- (EOQualifier *)qualifier;
+
+- (void)setSortOrderings:(NSArray *)_orderings;
+- (NSArray *)sortOrderings;
+
+- (void)setUsesDistinct:(BOOL)_flag;
+- (BOOL)usesDistinct;
+
+- (void)setIsDeep:(BOOL)_flag;
+- (BOOL)isDeep;
+
+- (void)setLocksObjects:(BOOL)_flag;
+- (BOOL)locksObjects;
+
+- (void)setFetchLimit:(unsigned)_limit;
+- (unsigned)fetchLimit;
+
+- (void)setHints:(NSDictionary *)_hints;
+- (NSDictionary *)hints;
+
+/* bindings */
+
+- (EOFetchSpecification *)fetchSpecificationWithQualifierBindings:(NSDictionary *)_bindings;
+
+/* remapping keys */
+
+- (EOFetchSpecification *)fetchSpecificationByApplyingKeyMap:(NSDictionary *)_m;
+
+@end
+
+#endif /* __EOFetchSpecification_h__ */
diff --git a/skyrix-core/EOControl/EOFetchSpecification.m b/skyrix-core/EOControl/EOFetchSpecification.m
new file mode 100644 (file)
index 0000000..870ef93
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "EOFetchSpecification.h"
+#include "EOQualifier.h"
+#include "EOSortOrdering.h"
+#include "common.h"
+
+@implementation EOFetchSpecification
+
++ (EOFetchSpecification *)fetchSpecificationWithEntityName:(NSString *)_ename
+  qualifier:(EOQualifier *)_qualifier
+  sortOrderings:(NSArray *)_sortOrderings
+{
+  EOFetchSpecification *fs = nil;
+
+  fs = [[self alloc] initWithEntityName:_ename
+                     qualifier:_qualifier
+                     sortOrderings:_sortOrderings
+                     usesDistinct:NO isDeep:NO
+                    hints:nil];
+  return [fs autorelease];
+}
+
+- (id)initWithEntityName:(NSString *)_name
+  qualifier:(EOQualifier *)_qualifier
+  sortOrderings:(NSArray *)_sortOrderings
+  usesDistinct:(BOOL)_dflag isDeep:(BOOL)_isDeep
+  hints:(NSDictionary *)_hints
+{
+  if ((self = [super init])) {
+    self->entityName    = [_name copyWithZone:[self zone]];
+    self->qualifier     = [_qualifier     retain];
+    self->sortOrderings = [_sortOrderings retain];
+    self->fetchLimit    = 0;
+    self->hints         = [_hints retain];
+    
+    self->fsFlags.usesDistinct = _dflag  ? 1 : 0;
+    self->fsFlags.deep         = _isDeep ? 1 : 0;
+  }
+  return self;
+}
+- (id)initWithEntityName:(NSString *)_name
+  qualifier:(EOQualifier *)_qualifier
+  sortOrderings:(NSArray *)_sortOrderings
+  usesDistinct:(BOOL)_dflag
+{
+  // DEPRECATED
+  // Note: this does not work with GDL2! (and probably not with EOF 4)
+  return [self initWithEntityName:_name qualifier:_qualifier 
+              sortOrderings:_sortOrderings usesDistinct:_dflag
+               isDeep:NO hints:nil];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->hints         release];
+  [self->entityName    release];
+  [self->qualifier     release];
+  [self->sortOrderings release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setEntityName:(NSString *)_name {
+  if (_name != self->entityName) {
+#if !LIB_FOUNDATION_BOEHM_GC
+    id tmp = self->entityName;
+#endif
+    self->entityName = [_name copyWithZone:[self zone]];
+    [tmp release];
+  }
+}
+- (NSString *)entityName {
+  return self->entityName;
+}
+
+- (void)setQualifier:(EOQualifier *)_qualifier {
+  ASSIGN(self->qualifier, _qualifier);
+}
+- (EOQualifier *)qualifier {
+  return self->qualifier;
+}
+
+- (void)setSortOrderings:(NSArray *)_orderings {
+  ASSIGN(self->sortOrderings, _orderings);
+}
+- (NSArray *)sortOrderings {
+  return self->sortOrderings;
+}
+
+- (void)setUsesDistinct:(BOOL)_flag {
+  self->fsFlags.usesDistinct = _flag ? 1 : 0;
+}
+- (BOOL)usesDistinct {
+  return self->fsFlags.usesDistinct ? YES : NO;
+}
+
+- (void)setLocksObjects:(BOOL)_flag {
+  self->fsFlags.locksObjects = _flag ? 1 : 0;
+}
+- (BOOL)locksObjects {
+  return self->fsFlags.locksObjects ? YES : NO;
+}
+
+- (void)setIsDeep:(BOOL)_flag {
+  self->fsFlags.deep = _flag ? 1 : 0;
+}
+- (BOOL)isDeep {
+  return self->fsFlags.deep ? YES : NO;
+}
+
+- (void)setFetchLimit:(unsigned)_limit {
+  self->fetchLimit = _limit;
+}
+- (unsigned)fetchLimit {
+  return self->fetchLimit;
+}
+
+- (void)setHints:(NSDictionary *)_hints {
+  ASSIGN(self->hints, _hints);
+}
+- (NSDictionary *)hints {
+  return self->hints;
+}
+
+/* bindings */
+
+- (EOFetchSpecification *)
+  fetchSpecificationWithQualifierBindings:(NSDictionary *)_bindings
+{
+  EOQualifier          *q     = nil;
+  EOFetchSpecification *newfs = nil;
+
+  q     = [[self qualifier] qualifierWithBindings:_bindings
+                            requiresAllVariables:NO];
+  newfs = [[[self class] alloc]
+                  initWithEntityName:[self entityName]
+                  qualifier:q
+                  sortOrderings:[self sortOrderings]
+                  usesDistinct:[self usesDistinct]];
+  
+  [newfs setLocksObjects:[self locksObjects]];
+  [newfs setFetchLimit:[self fetchLimit]];
+  
+  return [newfs autorelease];
+}
+
+/* GDL2 compatibility */
+
+- (EOFetchSpecification *)
+  fetchSpecificationByApplyingBindings:(NSDictionary *)_bindings
+{
+  return [self fetchSpecificationWithQualifierBindings:_bindings];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  EOFetchSpecification *fspec;
+  NSDictionary *hdict;
+  
+  hdict = [[self hints] copy];
+  
+  fspec = [[[self class] alloc] initWithEntityName:[self entityName]
+                                qualifier:[self qualifier]
+                                sortOrderings:[self sortOrderings]
+                                usesDistinct:[self usesDistinct]
+                               isDeep:[self isDeep] hints:hdict];
+  [fspec setLocksObjects:[self locksObjects]];
+  [fspec setFetchLimit:[self fetchLimit]];
+  [hdict release];
+  
+  return fspec;
+}
+
+/* Equality */
+
+- (BOOL)isEqualToFetchSpecification:(EOFetchSpecification *)_fspec {
+  id t1, t2;
+  if (_fspec == self)
+    return YES;
+
+  t1 = [self entityName];
+  t2 = [_fspec entityName];
+  if (t1 != t2) {
+    if (![t1 isEqualToString:t2])
+      return NO;
+  }
+  
+  t1 = [self sortOrderings];
+  t2 = [_fspec sortOrderings];
+  if (t1 != t2) {
+    if (![t1 isEqual:t2])
+      return NO;
+  }
+
+  t1 = [self qualifier];
+  t2 = [_fspec qualifier];
+  if (t1 != t2) {
+    if (![t1 isEqual:t2])
+      return NO;
+  }
+  
+  if ([self usesDistinct] != [_fspec usesDistinct])
+    return NO;
+  if ([self locksObjects] != [_fspec locksObjects])
+    return NO;
+  if ([self fetchLimit] != [_fspec fetchLimit])
+    return NO;
+
+  t1 = [self hints];
+  t2 = [_fspec hints];
+  if (t1 != t2) {
+    if (![t1 isEqual:t2])
+      return NO;
+  }
+  
+  return YES;
+}
+- (BOOL)isEqual:(id)_other {
+  if ([_other isKindOfClass:[EOFetchSpecification class]])
+    return [self isEqualToFetchSpecification:_other];
+  
+  return NO;
+}
+
+/* remapping keys */
+
+- (EOFetchSpecification *)fetchSpecificationByApplyingKeyMap:(NSDictionary *)_m {
+  NSAutoreleasePool    *pool;
+  EOFetchSpecification *fs;
+  NSMutableDictionary  *lHints;
+  EOQualifier    *q = nil;
+  NSMutableArray *o = nil;
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  /* process qualifier */
+  
+  q = [self->qualifier qualifierByApplyingKeyMap:_m];
+  
+  /* process attributes */
+  
+  if (self->hints) {
+    NSArray  *a;
+    unsigned len;
+    
+    a = [self->hints objectForKey:@"attributes"];
+    if ((len = [a count]) > 0) {
+      NSMutableArray *ma;
+      unsigned i;
+      
+      ma = [[NSMutableArray alloc] initWithCapacity:(len + 1)];
+      for (i = 0; i < len; i++) {
+       NSString *key, *tkey;
+       
+       key  = [a objectAtIndex:i];
+       tkey = [_m objectForKey:key];
+       
+       [ma addObject:(tkey ? tkey : key)];
+      }
+      
+      lHints = [self->hints mutableCopy];
+      [lHints setObject:ma forKey:@"attributes"];
+      [ma release];
+    }
+    else
+      lHints = [self->hints retain];
+  }
+  else 
+    lHints = nil;
+  
+  /* process orderings */
+  
+  if (self->sortOrderings) {
+    unsigned i, len;
+    
+    len = [self->sortOrderings count];
+    o   = [[NSMutableArray alloc] initWithCapacity:len];
+    for (i = 0; i < len; i++) {
+      EOSortOrdering *so, *tso;
+      
+      so  = [self->sortOrderings objectAtIndex:i];
+      tso = [so sortOrderingByApplyingKeyMap:_m];
+      [o addObject:tso ? tso : so];
+    }
+  }
+  else
+    o = nil;
+  
+  /* construct result */
+  
+  fs = [[EOFetchSpecification alloc] initWithEntityName:self->entityName
+                                    qualifier:q
+                                    sortOrderings:o
+                                    usesDistinct:[self usesDistinct]
+                                    isDeep:[self isDeep]
+                                    hints:[self hints]];
+  [fs setLocksObjects:[self locksObjects]];
+  [fs setFetchLimit:self->fetchLimit];
+  if (lHints) {
+    [fs setHints:lHints];
+    [lHints release];
+  }
+  [o release];
+  [pool release];
+  return [fs autorelease];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  id tmp;
+  
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
+
+  if ((tmp = [self entityName]))
+    [ms appendFormat:@" entity=%@", tmp];
+  if ((tmp = [self qualifier]))
+    [ms appendFormat:@" qualifier=%@", tmp];
+  
+  if ((tmp = [self sortOrderings]))
+    [ms appendFormat:@" orderings=%@", tmp];
+  
+  if ([self locksObjects]) [ms appendString:@" locks"];
+  if ([self usesDistinct]) [ms appendString:@" distinct"];
+  
+  if ([self fetchLimit] > 0)
+    [ms appendFormat:@" limit=%i", [self fetchLimit]];
+
+  if ((tmp = [self hints])) {
+    NSEnumerator *e;
+    NSString *hint;
+    BOOL isFirst = YES;
+    
+    [ms appendString:@" hints:"];
+    e = [tmp keyEnumerator];
+    while ((hint = [e nextObject])) {
+      if (isFirst) isFirst = NO;
+      else [ms appendString:@","];
+      [ms appendString:hint];
+      [ms appendString:@"="];
+      [ms appendString:[[(NSDictionary *)tmp objectForKey:hint] stringValue]];
+    }
+  }
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* EOFetchSpecification */
diff --git a/skyrix-core/EOControl/EOGenericRecord.h b/skyrix-core/EOControl/EOGenericRecord.h
new file mode 100644 (file)
index 0000000..8baf443
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_EOGenericRecord_h__
+#define __EOControl_EOGenericRecord_h__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSMapTable.h>
+#include <EOControl/EOGlobalID.h>
+
+@class NSDictionary, NSArray, NSString, NSEnumerator;
+@class EOClassDescription;
+
+/*
+ * EOGeneric record class, used for enterprise objects
+ * that do not have special data handling
+ */
+
+@interface EOGenericRecord : NSObject < NSCopying >
+{
+  EOClassDescription *classDescription;
+  IMP                willChange;
+
+  /* hash-table */
+  struct _NSMapNode  **nodes;
+  unsigned int       hashSize;
+  unsigned int       itemsCount;
+}
+
+- (id)initWithEditingContext:(id)_ec
+  classDescription:(EOClassDescription *)_classDesc
+  globalID:(EOGlobalID *)_oid;
+
+// Key-value coding methods
+
+- (void)takeValuesFromDictionary:(NSDictionary *)dictionary;
+- (NSDictionary *)valuesForKeys:(NSArray *)keys;
+
+// Shortcuts to key-value coding methods
+
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (id)objectForKey:(id)aKey;
+- (void)removeObjectForKey:(id)aKey;
+
+@end /* EOGenericRecord */
+
+
+@class NSEnumerator;
+
+@interface EOGenericRecord(EOMOF2Extensions)
+- (NSEnumerator *)keyEnumerator;
+@end
+
+#endif /* __EOControl_EOGenericRecord_h__ */
diff --git a/skyrix-core/EOControl/EOGenericRecord.m b/skyrix-core/EOControl/EOGenericRecord.m
new file mode 100644 (file)
index 0000000..53b4975
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOGenericRecord.h"
+#include "EONull.h"
+#include "EOClassDescription.h"
+#include "EOObserver.h"
+#include "EOKeyValueCoding.h"
+#include "common.h"
+#include <math.h>
+
+@interface NSObject(MappedArray)
+- (NSArray *)mappedArrayUsingSelector:(SEL)_selector;
+@end
+
+@interface _EOConcreteEOGenericRecordKeyEnumerator : NSEnumerator
+{
+    EOGenericRecord   *dict;
+    struct _NSMapNode *node;
+    int                      bucket;
+}
++ (id)enumWithEO:(EOGenericRecord *)_eo;
+@end
+
+#if !LIB_FOUNDATION_LIBRARY
+struct _NSMapNode {
+    void *key;
+    void *value;
+    struct _NSMapNode *next;
+};
+#endif
+
+@implementation EOGenericRecord
+
+/* final methods */
+
+static __inline__ unsigned _getHashSize(EOGenericRecord *self);
+static __inline__ struct _NSMapNode *_getNodeAt(EOGenericRecord *self, int idx);
+static BOOL is_prime(unsigned n);
+static unsigned nextPrime(unsigned old_value);
+static void eoMapGrow(EOGenericRecord *table, unsigned newSize);
+static void eoCheckMapTableFull(EOGenericRecord *table);
+static __inline__ void eoInsert(EOGenericRecord *table, id key, id value);
+static __inline__ id eoGet(EOGenericRecord *table, id key);
+static __inline__ void eoRemove(EOGenericRecord *table, id key);
+
+static EONull *null = nil;
+
++ (int)version {
+  return 2;
+}
+
++ (void)initialize {
+  if (null == nil) null = [[EONull null] retain];
+}
+
+- (id)initWithEditingContext:(id)_ec
+  classDescription:(EOClassDescription *)_classDesc
+  globalID:(EOGlobalID *)_oid
+{
+  unsigned capacity;
+  
+#if DEBUG
+  NSAssert(_classDesc, @"did not find class description for EOGenericRecord !");
+#endif
+
+  capacity = 16 * 4 / 3;
+  capacity = capacity ? capacity : 13;
+  if (!is_prime(capacity))
+    capacity = nextPrime(capacity);
+
+  self->hashSize   = capacity;
+  self->nodes      = NSZoneCalloc([self zone], capacity, sizeof(void *));
+  self->itemsCount = 0;
+  
+  self->classDescription = [_classDesc retain];
+  self->willChange = [self methodForSelector:@selector(willChange)];
+  return self;
+}
+
+- (id)init {
+  EOClassDescription *c;
+  
+  c = (EOClassDescription *)
+    [EOClassDescription classDescriptionForClass:[self class]];
+  
+  return [self initWithEditingContext:nil classDescription:c globalID:nil];
+}
+
+- (void)dealloc {
+  if ([self respondsToSelector:@selector(_letDatabasesForget)])
+    [self performSelector:@selector(_letDatabasesForget)];
+  
+  if (self->itemsCount > 0) {
+    NSZone *z = [self zone];
+    unsigned i;
+        
+    for (i = 0; i < self->hashSize; i++) {
+      struct _NSMapNode *next, *node;
+            
+      node = self->nodes[i];
+      self->nodes[i] = NULL;           
+      while (node) {
+        [(id)node->key   release];
+        [(id)node->value release];
+        next = node->next;
+        NSZoneFree(z, node);
+        node = next;
+      }
+    }
+    self->itemsCount = 0;
+  }
+    
+  if (self->nodes)
+    NSZoneFree([self zone], self->nodes);
+
+  [self->classDescription release];
+  [super dealloc];
+}
+
+/* class description */
+
+- (NSClassDescription *)classDescription {
+  return self->classDescription;
+}
+
+static inline void _willChange(EOGenericRecord *self) {
+  if (self->willChange)
+    self->willChange(self, @selector(willChange:));
+  else
+    [self willChange];
+}
+
+- (void)takeValue:(id)_value forKey:(id)_key {
+  id value;
+  
+  if (_value == nil) _value = null;
+  
+#if DEBUG
+  NSAssert1(_key, @"called -takeValue:0x%08X forKey:nil !", _value);
+#endif
+  
+  value = eoGet(self, _key);
+  
+  if (value != _value) {
+    _willChange(self);
+    
+    if (_value == nil)
+      eoRemove(self, _key);
+    else
+      eoInsert(self, _key, _value);
+  }
+}
+- (id)valueForKey:(id)_key {
+  id v;
+  
+  if ((v = eoGet(self, _key)) == nil) {
+#if DEBUG && 0
+    if ([_key isEqualToString:@"description"]) {
+      NSLog(@"WARNING(%s): -valueForKey:%@ is nil, calling super",
+            __PRETTY_FUNCTION__, _key);
+    }
+#endif
+    
+    return [super valueForKey:_key];
+  }
+
+#if DEBUG
+  NSAssert(null != nil, @"missing null ..");
+#endif
+  
+  return v == null ? nil : v;
+}
+
+- (void)takeValuesFromDictionary:(NSDictionary *)dictionary {
+  _willChange(self);
+  {
+    NSEnumerator *e = [dictionary keyEnumerator];
+    NSString     *key;
+
+    while ((key = [e nextObject])) {
+      id value = [dictionary objectForKey:key];
+      NSAssert(value, @"tried to set <nil> value ..");
+      eoInsert(self, key, value);
+    }
+  }
+}
+
+- (NSDictionary *)valuesForKeys:(NSArray *)keys {
+  // OPT - cache IMP for objectAtIndex, objectForKey, setObject:forKey:
+  NSMutableDictionary *dict;
+  IMP objAtIdx, setObjForKey;
+  unsigned int i, n;
+
+  if (keys == nil) return nil;
+
+  n = [keys count];
+  dict = [NSMutableDictionary dictionaryWithCapacity:n];
+
+  objAtIdx     = [keys methodForSelector:@selector(objectAtIndex:)];
+  setObjForKey = [dict methodForSelector:@selector(setObject:forKey:)];
+    
+  for (i = 0; i < n; i++) {
+    NSString *key;
+    id       value;
+
+    key = objAtIdx(keys, @selector(objectAtIndex:), i);
+    NSAssert(key, @"invalid key <nil>");
+    
+    value = [self valueForKey:key];
+    if (value == nil) value = null;
+    
+#if DEBUG
+    NSAssert2(value, @"eo of type %@, missing value for attribute %@",
+              self->classDescription, key);
+#endif
+    
+    setObjForKey(dict, @selector(setObject:forKey:), value, key);
+  }
+  return dict;
+}
+
+- (void)takeStoredValue:(id)_value forKey:(NSString *)_key {
+  if (_value == nil) _value = null;
+  [self takeValue:_value forKey:_key];
+}
+- (id)storedValueForKey:(NSString *)_key {
+  id v;
+
+  v = [self valueForKey:_key];
+#if DEBUG && 0
+  NSAssert(v != null, @"valueForKey: return NSNull !");
+#endif
+  //if (v == nil) return [super storedValueForKey:_key];
+  return v;
+}
+
+- (void)setObject:(id)object forKey:(id)key {
+  if (object == nil) object = null;
+  
+  _willChange(self);
+  eoInsert(self, key, object);
+}
+
+- (id)objectForKey:(id)key {
+  return eoGet(self, key);
+}
+
+- (void)removeObjectForKey:(id)key {
+  _willChange(self);
+  eoRemove(self, key);
+}
+
+- (BOOL)kvcIsPreferredInKeyPath {
+  return YES;
+}
+
+- (NSEnumerator *)keyEnumerator {
+  return [_EOConcreteEOGenericRecordKeyEnumerator enumWithEO:self];
+}
+
+/* copying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<EOGenericRecord: description %@ attributes=%@>",
+                     [self entityName],
+                     [self valuesForKeys:[self attributeKeys]]];
+}
+
+/* final methods */
+
+static __inline__ unsigned _getHashSize(EOGenericRecord *self)
+{
+    return self->hashSize;
+}
+
+static __inline__ struct _NSMapNode *
+_getNodeAt(EOGenericRecord *self, int idx)
+{
+    return self->nodes[idx];
+}
+
+static BOOL is_prime(unsigned n) {
+  int i, n2 = sqrt(n);
+
+  for (i = 2; i <= n2; i++) {
+    if (n % i == 0)
+      return NO;
+  }
+  return YES;
+}
+static unsigned nextPrime(unsigned old_value) {
+  unsigned i, new_value = old_value | 1;
+
+  for (i = new_value; i >= new_value; i += 2) {
+    if (is_prime(i))
+      return i;
+  }
+  return old_value;
+}
+
+static void eoMapGrow(EOGenericRecord *table, unsigned newSize) {
+  unsigned i;
+  struct _NSMapNode **newNodeTable;
+    
+  newNodeTable =
+    NSZoneCalloc([table zone], newSize, sizeof(struct _NSMapNode*));
+    
+  for (i = 0; i < table->hashSize; i++) {
+    struct _NSMapNode *next, *node;
+    unsigned int h;
+    
+    node = table->nodes[i];
+    while (node) {
+      next = node->next;
+      h = [(id)node->key hash] % newSize;
+      node->next = newNodeTable[h];
+      newNodeTable[h] = node;
+      node = next;
+    }
+  }
+  NSZoneFree([table zone], table->nodes);
+  table->nodes    = newNodeTable;
+  table->hashSize = newSize;
+}
+
+static void eoCheckMapTableFull(EOGenericRecord *table) {
+  if( ++(table->itemsCount) >= ((table->hashSize * 3) / 4)) {
+    unsigned newSize;
+    
+    newSize = nextPrime((table->hashSize * 4) / 3);
+    if(newSize != table->hashSize)
+      eoMapGrow(table, newSize);
+  }
+}
+
+static __inline__ void eoInsert(EOGenericRecord *table, id key, id value) {
+  unsigned int h;
+  struct _NSMapNode *node;
+  
+  h = [key hash] % table->hashSize;
+  
+  for (node = table->nodes[h]; node; node = node->next) {
+    /* might cache the selector .. */
+    if ([key isEqual:node->key])
+      break;
+  }
+  
+  /* Check if an entry for key exist in nodeTable. */
+  if (node) {
+    /* key exist. Set for it new value and return the old value of it. */
+    if (key != node->key) {
+      key = [key retain];
+      [(id)node->key release];
+    }
+    if (value != node->value) {
+      value = [value retain];
+      [(id)node->value release];
+    }
+    node->key   = key;
+    node->value = value;
+    return;
+  }
+  
+  /* key not found. Allocate a new bucket and initialize it. */
+  node = NSZoneMalloc([table zone], sizeof(struct _NSMapNode));
+  key   = [key   retain];
+  value = [value retain];
+  node->key   = (void*)key;
+  node->value = (void*)value;
+  node->next  = table->nodes[h];
+  table->nodes[h] = node;
+  
+  eoCheckMapTableFull(table);
+}
+
+static __inline__ id eoGet(EOGenericRecord *table, id key) {
+    struct _NSMapNode *node;
+    
+    node = table->nodes[[key hash] % table->hashSize];
+    for (; node; node = node->next) {
+        /* could cache method .. */
+        if ([key isEqual:node->key])
+            return node->value;
+    }
+    return nil;
+}
+
+static __inline__ void eoRemove(EOGenericRecord *table, id key) {
+    unsigned int h;
+    struct _NSMapNode *node, *node1 = NULL;
+
+    if (key == nil)
+        return;
+
+    h = [key hash] % table->hashSize;
+    
+    // node point to current bucket, and node1 to previous bucket or to NULL
+    // if current node is the first node in the list 
+    
+    for (node = table->nodes[h]; node; node1 = node, node = node->next) {
+        /* could cache method .. */
+        if ([key isEqual:node->key]) {
+            [(id)node->key   release];
+            [(id)node->value release];
+            
+            if (!node1)
+                table->nodes[h] = node->next;
+            else
+                node1->next = node->next;
+           NSZoneFree([table zone], node);
+           (table->itemsCount)--;
+           return;
+        }
+    }
+}
+
+@end /* EOGenericRecord */
+
+@implementation _EOConcreteEOGenericRecordKeyEnumerator
+
+- (id)initWithEO:(EOGenericRecord *)_eo {
+  self->dict   = [_eo retain];
+  self->node   = NULL;
+  self->bucket = -1;
+  return self;
+}
+
+- (void)dealloc {
+  [self->dict release];
+  [super dealloc];
+}
+
++ (id)enumWithEO:(EOGenericRecord *)_eo {
+  return [[[self alloc] initWithEO:_eo] autorelease];
+}
+
+- (id)nextObject
+{
+    if (self->node)
+       self->node = self->node->next;
+    
+    if (self->node == NULL) {
+       for(self->bucket++;
+            ((unsigned)self->bucket) < _getHashSize(self->dict);
+            self->bucket++) {
+
+            if (_getNodeAt(self->dict, self->bucket)) {
+                self->node = _getNodeAt(self->dict, self->bucket);
+                break;
+           }
+        }
+       if (((unsigned)self->bucket) >= _getHashSize(self->dict)) {
+           self->node = NULL;
+           self->bucket = (_getHashSize(self->dict) - 1);
+           return nil;
+       }
+    }
+    return self->node->key;
+}
+
+@end /* _EOConcreteEOGenericRecordKeyEnumerator */
diff --git a/skyrix-core/EOControl/EOGlobalID.h b/skyrix-core/EOControl/EOGlobalID.h
new file mode 100644 (file)
index 0000000..e66a2d0
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_EOGlobalID_H__
+#define __EOControl_EOGlobalID_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSArray;
+@class EOFetchSpecification;
+
+#define EOUniqueBinaryKeyLength 12
+
+@interface EOGlobalID : NSObject < NSCopying >
+{
+}
+
+- (BOOL)isTemporary;
+
+@end
+
+@interface EOTemporaryGlobalID : EOGlobalID
+{
+  unsigned char idbuffer[EOUniqueBinaryKeyLength];
+}
+
++ (void)assignGloballyUniqueBytes:(unsigned char *)_buffer;
+
+@end
+
+#endif /* __EOControl_EOGlobalID_H__ */
diff --git a/skyrix-core/EOControl/EOGlobalID.m b/skyrix-core/EOControl/EOGlobalID.m
new file mode 100644 (file)
index 0000000..ae567d0
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOGlobalID.h"
+#include "common.h"
+#include <time.h>
+#include <unistd.h>
+#if !defined(__MINGW32__)
+#  include <netdb.h>
+#endif
+
+@implementation EOGlobalID
+
+- (BOOL)isTemporary {
+  return NO;
+}
+
+- (id)copyWithZone:(NSZone *)_zone {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+@end /* EOGlobalID */
+
+@implementation EOTemporaryGlobalID
+
+static unsigned short sequence = 0;
+static unsigned int   ip;
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    char buf[1024];
+    struct hostent *hostEntry;
+    
+    isInitialized = YES;
+    gethostname(buf, 1024);
+    // THREADING
+    if ((hostEntry = gethostbyname(buf))) {
+      char **ptr;
+
+      ptr = hostEntry->h_addr_list;
+      if (*ptr) {
+        NSAssert((unsigned)hostEntry->h_length >= sizeof(ip),
+                 @"invalid host address !");
+        memcpy(&ip, *ptr, sizeof(ip));
+      }
+      else {
+        NSLog(@"WARNING: set IP address for EO key generation to 0.0.0.0 !");
+        ip = 0;
+      }
+    }
+    else {
+      NSLog(@"WARNING: set IP address for EO key generation to 0.0.0.0 !");
+      ip = 0;
+    }
+  }
+}
+
++ (void)assignGloballyUniqueBytes:(unsigned char *)_buffer {
+  struct {
+    unsigned short sequence;
+    unsigned short pid;
+    unsigned int   time;
+    unsigned int   ip;
+  } *bufPtr;
+
+  bufPtr = (void *)_buffer;
+  bufPtr->sequence = sequence++;
+#if defined(__WIN32__)
+  bufPtr->pid      = (unsigned short)GetCurrentProcessId();
+#else
+  bufPtr->pid      = getpid();
+#endif
+  bufPtr->time     = time(NULL);
+  bufPtr->ip       = ip;
+}
+
+- (id)init {
+  [self->isa assignGloballyUniqueBytes:&(self->idbuffer[0])];
+  return self;
+}
+
+- (BOOL)isTemporary {
+  return YES;
+}
+
+- (BOOL)isEqual:(id)_other {
+  return _other == self ? YES : NO;
+#if 0
+  EOTemporaryGlobalID *otherKey;
+  
+  if (_other == nil)  return NO;
+  if (_other == self) return YES;
+  otherKey = _other;
+  if (otherKey->isa != self->isa) return NO;
+  // compare bytes
+  return NO;
+#endif
+}
+
+@end /* EOTemporaryGlobalID */
diff --git a/skyrix-core/EOControl/EOKeyComparisonQualifier.m b/skyrix-core/EOControl/EOKeyComparisonQualifier.m
new file mode 100644 (file)
index 0000000..23ff894
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <EOControl/EOQualifier.h>
+#include <EOControl/EONull.h>
+#include "common.h"
+
+@implementation EOKeyComparisonQualifier
+
+static EONull *null = nil;
+
++ (void)initialize {
+  if (null == nil)
+    null = [[EONull null] retain];
+}
+
+- (id)initWithLeftKey:(NSString *)_leftKey
+  operatorSelector:(SEL)_selector
+  rightKey:(NSString *)_rightKey;
+{
+  self->leftKey  = [_leftKey  copyWithZone:NULL];
+  self->rightKey = [_rightKey copyWithZone:NULL];
+  self->operator = _selector;
+  return self;
+}
+
+- (void)dealloc {
+  [self->leftKey  release];
+  [self->rightKey release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)leftKey {
+  return self->leftKey;
+}
+- (NSString *)rightKey {
+  return self->rightKey;
+}
+- (SEL)selector {
+  return self->operator;
+}
+
+/* bindings */
+
+- (EOQualifier *)qualifierWithBindings:(NSDictionary *)_bindings
+  requiresAllVariables:(BOOL)_reqAll
+{
+  static Class VarClass = Nil;
+  NSString *newLeftKey;
+  id       newRightKey;
+  BOOL     needNew;
+  
+  if (VarClass == Nil) VarClass = [EOQualifierVariable class];
+  needNew = NO;
+
+  if ([self->leftKey class] == VarClass) {
+    newLeftKey =
+      [_bindings objectForKey:[(EOQualifierVariable *)self->leftKey key]];
+    if (newLeftKey == nil) {
+      if (_reqAll)
+        // throw exception
+        ;
+      else
+        newLeftKey = self->leftKey;
+    }
+    else
+      needNew = YES;
+  }
+  else
+    newLeftKey = self->leftKey;
+
+  if ([self->rightKey class] == VarClass) {
+    newRightKey =
+      [_bindings objectForKey:[(EOQualifierVariable *)self->rightKey key]];
+    if (newRightKey == nil) {
+      if (_reqAll)
+        // throw exception
+        ;
+      else
+        newRightKey = self->rightKey;
+    }
+    else
+      needNew = YES;
+  }
+  else
+    newRightKey = self->rightKey;
+
+  if (!needNew)
+    return self;
+
+  return [[[[self class] alloc]
+                         initWithLeftKey:newLeftKey
+                         operatorSelector:self->operator
+                         rightKey:newRightKey]
+                         autorelease];
+}
+
+- (NSArray *)bindingKeys {
+  static Class VarClass = Nil;
+  Class lkClass, rkClass;
+  if (VarClass == Nil) VarClass = [EOQualifierVariable class];
+  
+  lkClass = [self->leftKey  class];
+  rkClass = [self->rightKey class];
+  
+  if ((lkClass == VarClass) && (rkClass == VarClass)) {
+    id o[2];
+    o[0] = [(EOQualifierVariable *)self->leftKey  key];
+    o[1] = [(EOQualifierVariable *)self->rightKey key];
+    return [NSArray arrayWithObjects:o count:2];
+  }
+  
+  if (lkClass == VarClass)
+    return [NSArray arrayWithObject:[(EOQualifierVariable *)self->leftKey key]];
+  if (rkClass == VarClass) {
+    return [NSArray arrayWithObject:
+                      [(EOQualifierVariable *)self->rightKey key]];
+  }
+  return [NSArray array];
+}
+
+/* keys */
+
+- (void)addQualifierKeysToSet:(NSMutableSet *)_keys {
+  /* new in WO 4.5 */
+  [_keys addObject:self->leftKey];
+  [_keys addObject:self->rightKey];
+}
+
+/* evaluation */
+
+- (BOOL)evaluateWithObject:(id)_object inEvalContext:(id)_ctx {
+  id   lv, rv;
+  BOOL (*m)(id, SEL, id);
+  
+  if (_ctx == nil)
+    _ctx = [NSMutableDictionary dictionaryWithCapacity:16];
+  
+  if ((lv = [(NSDictionary *)_ctx objectForKey:self->leftKey]) == nil) {
+    lv = [_object valueForKeyPath:self->leftKey];
+    if (lv == nil) lv = null;
+    [(NSMutableDictionary *)_ctx setObject:lv forKey:self->leftKey];
+  }
+  if ((rv = [(NSDictionary *)_ctx objectForKey:self->rightKey]) == nil) {
+    rv = [_object valueForKeyPath:self->rightKey];
+    if (rv == nil) rv = null;
+    [(NSMutableDictionary *)_ctx setObject:rv forKey:self->rightKey];
+  }
+  
+  if ((m = (void *)[lv methodForSelector:self->operator]) == NULL) {
+    /* no such operator method ! */
+    [lv doesNotRecognizeSelector:self->operator];
+    return NO;
+  }
+
+  return m(lv, self->operator, rv);
+}
+- (BOOL)evaluateWithObject:(id)_object {
+  return [self evaluateWithObject:_object inEvalContext:nil];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->leftKey];
+  [_coder encodeObject:self->rightKey];
+  [_coder encodeValueOfObjCType:@encode(SEL) at:&(self->operator)];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  self->leftKey  = [[_coder decodeObject] copyWithZone:[self zone]];
+  self->rightKey = [[_coder decodeObject] copyWithZone:[self zone]];
+  [_coder decodeValueOfObjCType:@encode(SEL) at:&(self->operator)];
+  return self;
+}
+
+/* Comparing */
+
+- (BOOL)isEqualToQualifier:(EOQualifier *)_qual {
+  if (![self->leftKey isEqual:[(EOKeyComparisonQualifier *)_qual leftKey]])
+    return NO;
+  if (![self->rightKey isEqual:[(EOKeyComparisonQualifier *)_qual rightKey]])
+    return NO;
+  if (sel_eq(self->operator, [(EOKeyComparisonQualifier *)_qual selector]))
+    return YES;
+  return NO;
+}
+
+/* remapping keys */
+
+- (EOQualifier *)qualifierByApplyingTransformer:(id)_transformer
+  inContext:(id)_ctx
+{
+  if ([_transformer respondsToSelector:
+                      @selector(transformKeyComparisonQualifier:inContext:)]) {
+    return [_transformer transformKeyComparisonQualifier:self inContext:_ctx];
+  }
+  else
+    return [[self retain] autorelease];
+}
+
+- (EOQualifier *)qualifierByApplyingKeyMap:(NSDictionary *)_map {
+  EOKeyComparisonQualifier *kcq;
+  NSString *l, *r;
+  
+  l = [_map objectForKey:self->leftKey];
+  if (l == nil) l = self->leftKey;
+  r = [_map objectForKey:self->rightKey];
+  if (r == nil) r = self->rightKey;
+  
+  kcq = [[EOKeyComparisonQualifier alloc] 
+         initWithLeftKey:l operatorSelector:self->operator rightKey:r];
+  return [kcq autorelease];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+  
+  s = [NSMutableString stringWithCapacity:64];
+  [s appendString:self->leftKey];
+  [s appendString:@" "];
+  [s appendString:[EOQualifier stringForOperatorSelector:self->operator]];
+  [s appendString:@" "];
+  [s appendString:self->rightKey];
+  return s;
+}
+
+@end /* EOKeyComparisonQualifier */
diff --git a/skyrix-core/EOControl/EOKeyGlobalID.h b/skyrix-core/EOControl/EOKeyGlobalID.h
new file mode 100644 (file)
index 0000000..88fdd35
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_EOKeyGlobalID_H__
+#define __EOControl_EOKeyGlobalID_H__
+
+#include <EOControl/EOGlobalID.h>
+
+@class NSArray;
+
+/*
+  An immutable global id based on primary key values. The values must
+  be passed in the alphabetical order of the attribute named.
+
+  This class cannot be subclassed !!!
+*/
+
+@interface EOKeyGlobalID : EOGlobalID < NSCoding >
+{
+@protected
+  NSString     *entityName;
+  unsigned int count;
+  id           values[1];
+}
+
++ (id)globalIDWithEntityName:(NSString *)_name
+  keys:(id *)_keyValues
+  keyCount:(unsigned int)_count
+  zone:(NSZone *)_zone;
+
+/* accessors */
+
+- (NSString *)entityName;
+- (unsigned int)keyCount;
+- (id *)keyValues;
+- (NSArray *)keyValuesArray;
+
+@end
+
+#endif /* __EOControl_EOKeyGlobalID_H__ */
diff --git a/skyrix-core/EOControl/EOKeyGlobalID.m b/skyrix-core/EOControl/EOKeyGlobalID.m
new file mode 100644 (file)
index 0000000..5e7ea9d
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOKeyGlobalID.h"
+#include "common.h"
+
+@implementation EOKeyGlobalID
+
++ (id)globalIDWithEntityName:(NSString *)_name
+  keys:(id *)_keyValues
+  keyCount:(unsigned int)_count
+  zone:(NSZone *)_zone
+{
+  EOKeyGlobalID *kid;
+
+  NSAssert1(_count > 0, @"missing key-values (count is 0, entity is %@", _name);
+  
+  if ((kid = (id)NSAllocateObject(self, sizeof(id) * _count, _zone))) {
+    unsigned int i;
+    kid->entityName = [_name copyWithZone:_zone];
+    kid->count      = _count;
+    
+    for (i = 0; i < _count; i++)
+      kid->values[i] = [_keyValues[i] retain];
+
+    return [kid autorelease];
+  }
+  else
+    return nil;
+}
+
+- (void)dealloc {
+  unsigned int i;
+  for (i = 0; i < self->count; i++) {
+    [self->values[i] release];
+    self->values[i] = nil;
+  }
+  [self->entityName release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)entityName {
+  return self->entityName;
+}
+
+- (unsigned int)keyCount {
+  return self->count;
+}
+- (id *)keyValues {
+  return &(self->values[0]);
+}
+
+- (NSArray *)keyValuesArray {
+  return [NSArray arrayWithObjects:&(self->values[0]) count:self->count];
+}
+
+/* Equality */
+
+- (unsigned)hash {
+  return [self->entityName hash] - [self->values[0] hash];
+}
+
+- (BOOL)isEqual:(id)_other {
+  EOKeyGlobalID *otherKey;
+  unsigned int i;
+
+  if (_other == nil)  return NO;
+  if (_other == self) return YES;
+  otherKey = _other;
+  if (otherKey->isa   != self->isa)   return NO;
+  if (otherKey->count != self->count) return NO;
+  if (![otherKey->entityName isEqualToString:self->entityName]) return NO;
+  
+  for (i = 0; i < self->count; i++) {
+    if (self->values[i] != otherKey->values[i]) {
+      if (![self->values[i] isEqual:otherKey->values[i]])
+        return NO;
+    }
+  }
+  
+  return YES;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [self doesNotRecognizeSelector:_cmd];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+#if 0
+  NSString     *entityName;
+  NSZone       *z;
+  unsigned int count;
+  
+  z = [self zone];
+  [self release];
+
+  entityName = [_coder decodeObject];
+  
+  self = [EOKeyGlobalID globalIDWithEntityName:entityName
+                        keys:NULL
+                        keyCount:0
+                        zone:z];
+  return [self retain];
+#endif
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+  NSString *d;
+  unsigned int i;
+  
+  s = [[NSMutableString alloc] init];
+  [s appendFormat:@"<0x%08X[%@]: %@",
+       self, NSStringFromClass([self class]),
+       [self entityName]];
+
+  for (i = 0; i < self->count; i++) {
+    if (i == 0) [s appendString:@" "];
+    else        [s appendString:@"/"];
+    [s appendString:[self->values[i] stringValue]];
+  }
+  
+  [s appendString:@">"];
+
+  d = [s copy];
+  [s release];
+  return [d autorelease];
+}
+
+@end /* EOKeyGlobalID */
diff --git a/skyrix-core/EOControl/EOKeyValueArchiver.h b/skyrix-core/EOControl/EOKeyValueArchiver.h
new file mode 100644 (file)
index 0000000..652d844
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_EOKeyValueArchiver_H__
+#define __EOControl_EOKeyValueArchiver_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSDictionary, NSMutableArray, NSMutableDictionary;
+@class NSMutableSet;
+
+@interface EOKeyValueArchiver : NSObject
+{
+  NSMutableDictionary *plist;
+  id delegate; // non-retained
+}
+
+/* coding */
+
+- (void)encodeObject:(id)_obj            forKey:(NSString *)_key;
+- (void)encodeReferenceToObject:(id)_obj forKey:(NSString *)_key;
+- (void)encodeBool:(BOOL)_flag           forKey:(NSString *)_key;
+- (void)encodeInt:(int)_value            forKey:(NSString *)_key;
+
+- (NSDictionary *)dictionary;
+
+/* delegate */
+
+- (void)setDelegate:(id)_delegate;
+- (id)delegate;
+
+@end
+
+@interface EOKeyValueUnarchiver : NSObject
+{
+  NSDictionary   *plist;
+  NSMutableArray *unarchivedObjects;
+  NSMutableSet   *awakeObjects;
+  id parent;
+  
+  id delegate; // non-retained
+}
+
+- (id)initWithDictionary:(NSDictionary *)_dict;
+
+/* decoding */
+
+- (id)decodeObjectForKey:(NSString *)_key;
+- (id)decodeObjectReferenceForKey:(NSString *)_key;
+- (BOOL)decodeBoolForKey:(NSString *)_key;
+- (int)decodeIntForKey:(NSString *)_key;
+
+/* operations */
+
+- (void)ensureObjectAwake:(id)_object;
+- (void)finishInitializationOfObjects;
+- (void)awakeObjects;
+- (id)parent;
+
+/* delegate */
+
+- (void)setDelegate:(id)_delegate;
+- (id)delegate;
+
+@end
+
+@protocol EOKeyValueArchiving
+
+- (id)initWithKeyValueUnarchiver:(EOKeyValueUnarchiver *)_unarchiver;
+- (void)encodeWithKeyValueArchiver:(EOKeyValueArchiver *)_archiver;
+
+@end
+
+@interface NSObject(EOKeyValueArchivingAwakeMethods)
+
+- (void)finishInitializationWithKeyValueUnarchiver:(EOKeyValueUnarchiver *)_una;
+- (void)awakeFromKeyValueUnarchiver:(EOKeyValueUnarchiver *)_unarchiver;
+
+@end
+
+/* delegates */
+
+@interface NSObject(KVCArchiverDelegates)
+
+- (id)archiver:(EOKeyValueArchiver *)_archiver
+  referenceToEncodeForObject:(id)_obj;
+
+@end
+
+@interface NSObject(KVCUnarchiverDelegates)
+
+- (id)unarchiver:(EOKeyValueUnarchiver *)_unarchiver
+  objectForReference:(id)_obj;
+
+@end
+
+#endif /* __EOControl_EOKeyValueArchiver_H__ */
diff --git a/skyrix-core/EOControl/EOKeyValueArchiver.m b/skyrix-core/EOControl/EOKeyValueArchiver.m
new file mode 100644 (file)
index 0000000..cc076fb
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOKeyValueArchiver.h"
+#include "common.h"
+
+@implementation EOKeyValueArchiver
+
+- (id)init {
+  if ((self = [super init])) {
+    self->plist = [[NSMutableDictionary alloc] init];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->plist release];
+  [super dealloc];
+}
+
+/* coding */
+
+static BOOL isPListObject(id _obj) {
+  if ([_obj isKindOfClass:[NSString class]])
+    return YES;
+  if ([_obj isKindOfClass:[NSData class]])
+    return YES;
+  if ([_obj isKindOfClass:[NSArray class]])
+    return YES;
+  return NO;
+}
+
+- (void)encodeObject:(id)_obj forKey:(NSString *)_key {
+  NSMutableDictionary *oldPlist;
+
+  if (isPListObject(_obj)) {
+    id c;
+    c = [_obj copy];
+    [self->plist setObject:c forKey:_key];
+    [c release];
+    return;
+  }
+  
+  oldPlist = self->plist;
+  self->plist = [[NSMutableDictionary alloc] init];
+  
+  if (_obj) {
+    /* store class name */
+    [self->plist setObject:NSStringFromClass([_obj class]) forKey:@"class"];
+
+    /* let object store itself */
+    [_obj encodeWithKeyValueArchiver:self];
+  }
+  else {
+    /* nil ??? */
+  }
+
+  [oldPlist setObject:self->plist forKey:_key];
+  [self->plist release];
+  self->plist = oldPlist;
+}
+
+- (void)encodeReferenceToObject:(id)_obj forKey:(NSString *)_key {
+  if ([self->delegate respondsToSelector:
+           @selector(archiver:referenceToEncodeForObject:)])
+    _obj = [self->delegate archiver:self referenceToEncodeForObject:_obj];
+
+  /* if _obj wasn't replaced by the delegate, encode the object in place .. */
+  [self encodeObject:_obj forKey:_key];
+}
+
+- (void)encodeBool:(BOOL)_flag forKey:(NSString *)_key {
+  /* NO values are not archived .. */
+  if (_flag) {
+    [self->plist setObject:@"YES" forKey:_key];
+  }
+}
+- (void)encodeInt:(int)_value forKey:(NSString *)_key {
+  [self->plist setObject:[NSString stringWithFormat:@"%i", _value] forKey:_key];
+}
+
+- (NSDictionary *)dictionary {
+  return [[self->plist copy] autorelease];
+}
+
+/* delegate */
+
+- (void)setDelegate:(id)_delegate {
+  self->delegate = _delegate;
+}
+- (id)delegate {
+  return self->delegate;
+}
+
+@end /* EOKeyValueArchiver */
+
+@implementation EOKeyValueUnarchiver
+
+- (id)initWithDictionary:(NSDictionary *)_dict {
+  self->plist = [_dict copy];
+  self->unarchivedObjects = [[NSMutableArray alloc] init];
+  self->awakeObjects      = [[NSMutableSet alloc] init]; // should be a hashtable
+  return self;
+}
+- (id)init {
+  [self release];
+  return nil;
+}
+
+- (void)dealloc {
+  [self->awakeObjects      release];
+  [self->unarchivedObjects release];
+  [self->plist             release];
+  [super dealloc];
+}
+
+/* decoding */
+
+- (id)decodeObjectForKey:(NSString *)_key {
+  NSString     *className;
+  NSDictionary *lastParent;
+  id obj;
+
+  lastParent   = self->parent;
+  self->parent = self->plist;
+  self->plist  = [(NSDictionary *)self->parent objectForKey:_key];
+
+  if (![self->plist isKindOfClass:[NSDictionary class]]) {
+    obj = [[self->plist copy] autorelease];
+  }
+  else if ((className = [self->plist objectForKey:@"class"]) != nil) {
+    obj = [NSClassFromString(className) alloc];
+    obj = [obj initWithKeyValueUnarchiver:self];
+    
+    [self->unarchivedObjects addObject:obj];
+    [obj release];
+  }
+  else {
+    obj = nil;
+  }
+  
+  self->plist  = self->parent;
+  self->parent = lastParent;
+  
+  return obj;
+}
+- (id)decodeObjectReferenceForKey:(NSString *)_key {
+  id refObj, obj;
+
+  refObj = [self decodeObjectForKey:_key];
+
+  if ([self->delegate respondsToSelector:
+           @selector(unarchiver:objectForReference:)]) {
+    obj = [self->delegate unarchiver:self objectForReference:refObj];
+    
+    [self->unarchivedObjects addObject:obj];
+  }
+  else {
+    /* if delegate does not dereference, pass back the reference object */
+    obj = refObj;
+  }
+  return obj;
+}
+
+- (BOOL)decodeBoolForKey:(NSString *)_key {
+  return [[self->plist objectForKey:_key] boolValue];
+}
+- (int)decodeIntForKey:(NSString *)_key {
+  return [[self->plist objectForKey:_key] intValue];
+}
+
+/* operations */
+
+- (void)ensureObjectAwake:(id)_object {
+  if (![self->awakeObjects containsObject:_object]) {
+    if ([_object respondsToSelector:@selector(awakeFromKeyValueUnarchiver:)]) {
+      [_object awakeFromKeyValueUnarchiver:self];
+    }
+    [self->awakeObjects addObject:_object];
+  }
+}
+- (void)awakeObjects {
+  NSEnumerator *e;
+  id obj;
+
+  e = [self->unarchivedObjects objectEnumerator];
+  while ((obj = [e nextObject]))
+    [self ensureObjectAwake:obj];
+}
+
+- (void)finishInitializationOfObjects {
+  NSEnumerator *e;
+  id obj;
+
+  e = [self->unarchivedObjects objectEnumerator];
+  while ((obj = [e nextObject])) {
+    if ([obj respondsToSelector:
+               @selector(finishInitializationWithKeyValueUnarchiver:)])
+      [obj finishInitializationWithKeyValueUnarchiver:self];
+  }
+}
+
+- (id)parent {
+  return self->parent;
+}
+
+/* delegate */
+
+- (void)setDelegate:(id)_delegate {
+  self->delegate = _delegate;
+}
+- (id)delegate {
+  return self->delegate;
+}
+
+@end /* EOKeyValueUnarchiver */
diff --git a/skyrix-core/EOControl/EOKeyValueCoding.h b/skyrix-core/EOControl/EOKeyValueCoding.h
new file mode 100644 (file)
index 0000000..8b4a902
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __EOControl_EOKeyValueCoding_H__
+#define __EOControl_EOKeyValueCoding_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSArray.h>
+
+#if NeXT_Foundation_LIBRARY
+
+#import <Foundation/NSKeyValueCoding.h>
+
+#else
+
+@interface NSObject(EOKeyValueCoding)
+
++ (BOOL)accessInstanceVariablesDirectly;
++ (void)flushAllKeyBindings;
+
+- (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key;
+- (id)handleQueryWithUnboundKey:(NSString *)_key;
+- (void)unableToSetNullForKey:(NSString *)_key;
+
+- (void)takeValuesFromDictionary:(NSDictionary *)_dictionary;
+- (NSDictionary *)valuesForKeys:(NSArray *)_keys;
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key;
+- (id)valueForKey:(NSString *)_key;
+
+/* stored values */
+
++ (BOOL)useStoredAccessor;
+- (void)takeStoredValue:(id)_value forKey:(NSString *)_key;
+- (id)storedValueForKey:(NSString *)_key;
+
+@end
+
+/* key-path stuff */
+
+@interface NSObject(EOKeyPathValueCoding)
+
+- (void)takeValue:(id)_value forKeyPath:(NSString *)_keyPath;
+- (id)valueForKeyPath:(NSString *)_keyPath;
+
+@end
+
+/* array stuff */
+
+@interface NSArray(EOKeyValueCoding)
+
+/*
+  Special functions for computed values. Computed keys start with
+  '@', seg '@sum'. Yoy can define own computed keys by following the
+  method naming 'compute' + Func + 'ForKey:'.
+*/
+- (id)computeSumForKey:(NSString *)_key;
+- (id)computeAvgForKey:(NSString *)_key;
+- (id)computeCountForKey:(NSString *)_key;
+- (id)computeMaxForKey:(NSString *)_key;
+- (id)computeMinForKey:(NSString *)_key;
+
+/*
+  Attention: NSArray's 'valueForKey:' is special in that it does not
+  return properties of the array but an array of the properties of it's
+  elements. That is, it is similiar to a map function.
+*/
+- (id)valueForKey:(NSString *)_key;
+
+@end
+
+#endif /* !NeXT_Foundation_LIBRARY */
+
+#endif /* __EOControl_EOKeyValueCoding_H__ */
diff --git a/skyrix-core/EOControl/EOKeyValueCoding.m b/skyrix-core/EOControl/EOKeyValueCoding.m
new file mode 100644 (file)
index 0000000..7cc47a0
--- /dev/null
@@ -0,0 +1,1560 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "EOKeyValueCoding.h"
+#include "EONull.h"
+#include "common.h"
+
+#if GNU_RUNTIME
+#  include <objc/objc-api.h>
+#  include <objc/encoding.h>
+#endif
+
+static EONull *null = nil;
+
+#if !NeXT_Foundation_LIBRARY
+
+static id idMethodGetFunc(void* info1, void* info2, id self);
+static id idIvarGetFunc(void* info1, void* info2, id self);
+static void idMethodSetFunc(void* info1, void* info2, id self, id val);
+static void idIvarSetFunc(void* info1, void* info2, id self, id val);
+static id charMethodGetFunc(void* info1, void* info2, id self);
+static id charIvarGetFunc(void* info1, void* info2, id self);
+static void charMethodSetFunc(void* info1, void* info2, id self, id val);
+static void charIvarSetFunc(void* info1, void* info2, id self, id val);
+static id unsignedCharMethodGetFunc(void* info1, void* info2, id self);
+static id unsignedCharIvarGetFunc(void* info1, void* info2, id self);
+static void unsignedCharMethodSetFunc(void* info1, void* info2, id self, id val);
+static void unsignedCharIvarSetFunc(void* info1, void* info2, id self, id val);
+static id shortMethodGetFunc(void* info1, void* info2, id self);
+static id shortIvarGetFunc(void* info1, void* info2, id self);
+static void shortMethodSetFunc(void* info1, void* info2, id self, id val);
+static void shortIvarSetFunc(void* info1, void* info2, id self, id val);
+static id unsignedShortMethodGetFunc(void* info1, void* info2, id self);
+static id unsignedShortIvarGetFunc(void* info1, void* info2, id self);
+static void unsignedShortMethodSetFunc(void* info1, void* info2, id self, id val);
+static void unsignedShortIvarSetFunc(void* info1, void* info2, id self, id val);
+static id intMethodGetFunc(void* info1, void* info2, id self);
+static id intIvarGetFunc(void* info1, void* info2, id self);
+static void intMethodSetFunc(void* info1, void* info2, id self, id val);
+static void intIvarSetFunc(void* info1, void* info2, id self, id val);
+static id unsignedIntMethodGetFunc(void* info1, void* info2, id self);
+static id unsignedIntIvarGetFunc(void* info1, void* info2, id self);
+static void unsignedIntMethodSetFunc(void* info1, void* info2, id self, id val);
+static void unsignedIntIvarSetFunc(void* info1, void* info2, id self, id val);
+static id longMethodGetFunc(void* info1, void* info2, id self);
+static id longIvarGetFunc(void* info1, void* info2, id self);
+static void longMethodSetFunc(void* info1, void* info2, id self, id val);
+static void longIvarSetFunc(void* info1, void* info2, id self, id val);
+static id unsignedLongMethodGetFunc(void* info1, void* info2, id self);
+static id unsignedLongIvarGetFunc(void* info1, void* info2, id self);
+static void unsignedLongMethodSetFunc(void* info1, void* info2, id self, id val);
+static void unsignedLongIvarSetFunc(void* info1, void* info2, id self, id val);
+static id longLongMethodGetFunc(void* info1, void* info2, id self);
+static id longLongIvarGetFunc(void* info1, void* info2, id self);
+static void longLongMethodSetFunc(void* info1, void* info2, id self, id val);
+static void longLongIvarSetFunc(void* info1, void* info2, id self, id val);
+static id unsignedLongLongMethodGetFunc(void* info1, void* info2, id self);
+static id unsignedLongLongIvarGetFunc(void* info1, void* info2, id self);
+static void unsignedLongLongMethodSetFunc(void* info1, void* info2, id self, id val);
+static void unsignedLongLongIvarSetFunc(void* info1, void* info2, id self, id val);
+static id floatMethodGetFunc(void* info1, void* info2, id self);
+static id floatIvarGetFunc(void* info1, void* info2, id self);
+static void floatMethodSetFunc(void* info1, void* info2, id self, id val);
+static void floatIvarSetFunc(void* info1, void* info2, id self, id val);
+static id doubleMethodGetFunc(void* info1, void* info2, id self);
+static id doubleIvarGetFunc(void* info1, void* info2, id self);
+static void doubleMethodSetFunc(void* info1, void* info2, id self, id val);
+static void doubleIvarSetFunc(void* info1, void* info2, id self, id val);
+
+static Class NumberClass = Nil;
+static Class StringClass = Nil;
+
+@implementation NSObject(EOKeyValueCoding)
+
+/*
+ *  Types
+ */
+
+typedef struct _KeyValueMethod {
+  NSString*   key;
+  Class       class;
+} KeyValueMethod;
+
+typedef struct _GetKeyValueBinding {
+  /* info1, info2, self */
+  id (*access)(void *, void *, id);
+  void *info1;
+  void *info2;
+} GetKeyValueBinding;
+
+typedef struct _SetKeyValueBinding {
+  /* info1, info2, self, val */
+  void (*access)(void *, void *, id, id);
+  void *info1;
+  void *info2;
+} SetKeyValueBinding;
+
+/*
+ * Globals
+ */
+
+static NSMapTable* getValueBindings = NULL;
+static NSMapTable* setValueBindings = NULL;
+static BOOL keyValueDebug = NO;
+static BOOL keyValueInit  = NO;
+
+/*
+ *  KeyValueMapping
+ */
+
+static GetKeyValueBinding* newGetBinding(NSString* key, id instance)
+{
+  GetKeyValueBinding *ret = NULL;
+  void *info1 = NULL;
+  void *info2 = NULL;
+  id (*fptr)(void*, void*, id) = NULL;
+
+  // Lookup method name [-(type)key]
+  {
+    Class      class = [instance class];
+    unsigned   clen  = [key cStringLength];
+    char       *cbuf;
+    const char *ckey;
+    SEL        sel;
+    struct objc_method* mth;
+    
+    cbuf = malloc(clen + 1);
+    [key getCString:cbuf]; cbuf[clen] = '\0';
+    ckey = cbuf;
+    sel = sel_get_any_uid(ckey);
+    
+    if (sel && (mth = class_get_instance_method(class, sel)) &&
+        method_get_number_of_arguments(mth) == 2) {
+      switch(*objc_skip_type_qualifiers(mth->method_types)) {
+        case _C_ID:
+          fptr = (id (*)(void*, void*, id))idMethodGetFunc;
+          break;
+        case _C_CHR:
+          fptr = (id (*)(void*, void*, id))charMethodGetFunc;
+          break;
+        case _C_UCHR:
+          fptr = (id (*)(void*, void*, id))unsignedCharMethodGetFunc;
+          break;
+        case _C_SHT:
+          fptr = (id (*)(void*, void*, id))shortMethodGetFunc;
+          break;
+        case _C_USHT:
+          fptr = (id (*)(void*, void*, id))unsignedShortMethodGetFunc;
+          break;
+        case _C_INT:
+          fptr = (id (*)(void*, void*, id))intMethodGetFunc;
+          break;
+        case _C_UINT:
+          fptr = (id (*)(void*, void*, id))unsignedIntMethodGetFunc;
+          break;
+        case _C_LNG:
+          fptr = (id (*)(void*, void*, id))longMethodGetFunc;
+          break;
+        case _C_ULNG:
+          fptr = (id (*)(void*, void*, id))unsignedLongMethodGetFunc;
+          break;
+        case 'q':
+          fptr = (id (*)(void*, void*, id))longLongMethodGetFunc;
+          break;
+        case 'Q':
+          fptr = (id (*)(void*, void*, id))unsignedLongLongMethodGetFunc;
+          break;
+        case _C_FLT:
+          fptr = (id (*)(void*, void*, id))floatMethodGetFunc;
+          break;
+        case _C_DBL:
+          fptr = (id (*)(void*, void*, id))doubleMethodGetFunc;
+          break;
+      }
+      if (fptr) {
+        info1 = (void*)(mth->method_imp);
+        info2 = (void*)(mth->method_name);
+      }
+    }
+    if (cbuf) free(cbuf);
+  }
+        
+  // Lookup ivar name
+  if (!fptr) {
+    Class class = [instance class];
+    unsigned   clen;
+    char       *cbuf;
+    const char *ckey;
+    int i;
+    
+    clen = [key cStringLength];
+    cbuf = malloc(clen + 1);
+    [key getCString:cbuf]; cbuf[clen] = '\0';
+    ckey = cbuf;
+    
+    while (class) {
+      for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) {
+        if (!Strcmp(ckey, class->ivars->ivar_list[i].ivar_name)) {
+          switch(*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) {
+            case _C_ID:
+              fptr = (id (*)(void*, void*, id))idIvarGetFunc;
+              break;
+            case _C_CHR:
+              fptr = (id (*)(void*, void*, id))charIvarGetFunc;
+              break;
+            case _C_UCHR:
+              fptr = (id (*)(void*, void*, id))unsignedCharIvarGetFunc;
+              break;
+            case _C_SHT:
+              fptr = (id (*)(void*, void*, id))shortIvarGetFunc;
+              break;
+            case _C_USHT:
+              fptr = (id (*)(void*, void*, id))unsignedShortIvarGetFunc;
+              break;
+            case _C_INT:
+              fptr = (id (*)(void*, void*, id))intIvarGetFunc;
+              break;
+            case _C_UINT:
+              fptr = (id (*)(void*, void*, id))unsignedIntIvarGetFunc;
+              break;
+            case _C_LNG:
+              fptr = (id (*)(void*, void*, id))longIvarGetFunc;
+              break;
+            case _C_ULNG:
+              fptr = (id (*)(void*, void*, id))unsignedLongIvarGetFunc;
+              break;
+            case 'q':
+              fptr = (id (*)(void*, void*, id))longLongIvarGetFunc;
+              break;
+            case 'Q':
+              fptr = (id (*)(void*, void*, id))unsignedLongLongIvarGetFunc;
+              break;
+            case _C_FLT:
+              fptr = (id (*)(void*, void*, id))floatIvarGetFunc;
+              break;
+            case _C_DBL:
+              fptr = (id (*)(void*, void*, id))doubleIvarGetFunc;
+              break;
+          }
+          if (fptr) {
+            info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
+            break;
+          }
+        }
+      }
+      class = class->super_class;
+    }
+    if (cbuf) free(cbuf);
+  }
+    
+  // Make binding and insert into map
+  if (fptr) {
+    KeyValueMethod     *mkey;
+    GetKeyValueBinding *bin;
+        
+    mkey = Malloc(sizeof(KeyValueMethod));
+    bin  = Malloc(sizeof(GetKeyValueBinding));
+    mkey->key   = [key copy];
+    mkey->class = [instance class];
+    
+    bin->access = fptr;
+    bin->info1 = info1;
+    bin->info2 = info2;
+        
+    NSMapInsert(getValueBindings, mkey, bin);
+    ret = bin;
+  }
+    
+  // If no way to access value warn
+  if (!ret && keyValueDebug)
+    NSLog(@"cannnot get key `%@' for instance of class `%@'",
+          key, NSStringFromClass([instance class]));
+    
+  return ret;
+}
+
+static SetKeyValueBinding* newSetBinding(NSString* key, id instance)
+{
+  SetKeyValueBinding *ret = NULL;
+  void *info1 = NULL;
+  void *info2 = NULL;
+  void (*fptr)(void*, void*, id, id) = NULL;
+    
+  // Lookup method name [-(void)setKey:(type)arg]
+  {
+    Class      class = [instance class];
+    unsigned   clen  = [key cStringLength];
+    char       *cbuf;
+    const char *ckey;
+    SEL        sel;
+    struct objc_method* mth;
+    char  sname[clen + 7];
+
+    cbuf = malloc(clen + 1);
+    [key getCString:cbuf]; cbuf[clen] = '\0';
+    ckey = cbuf;
+    
+    // Make sel from name
+    Strcpy(sname, "set");
+    Strcat(sname, ckey);
+    Strcat(sname, ":");
+    sname[3] = islower((int)sname[3]) ? toupper((int)sname[3]) : sname[3];
+    sel = sel_get_any_uid(sname);
+        
+    if (sel && (mth = class_get_instance_method(class, sel)) &&
+        method_get_number_of_arguments(mth) == 3 &&
+        *objc_skip_type_qualifiers(mth->method_types) == _C_VOID) {
+      char* argType = (char*)(mth->method_types);
+                
+      argType = (char*)objc_skip_argspec(argType);    // skip return
+      argType = (char*)objc_skip_argspec(argType);    // skip self
+      argType = (char*)objc_skip_argspec(argType);    // skip SEL
+                
+      switch(*objc_skip_type_qualifiers(argType)) {
+        case _C_ID:
+          fptr = (void (*)(void*, void*, id, id))idMethodSetFunc;
+          break;
+        case _C_CHR:
+          fptr = (void (*)(void*, void*, id, id))charMethodSetFunc;
+          break;
+        case _C_UCHR:
+          fptr = (void (*)(void*, void*, id, id))unsignedCharMethodSetFunc;
+          break;
+        case _C_SHT:
+          fptr = (void (*)(void*, void*, id, id))shortMethodSetFunc;
+          break;
+        case _C_USHT:
+          fptr = (void (*)(void*, void*, id, id))unsignedShortMethodSetFunc;
+          break;
+        case _C_INT:
+          fptr = (void (*)(void*, void*, id, id))intMethodSetFunc;
+          break;
+        case _C_UINT:
+          fptr = (void (*)(void*, void*, id, id))unsignedIntMethodSetFunc;
+          break;
+        case _C_LNG:
+          fptr = (void (*)(void*, void*, id, id))longMethodSetFunc;
+          break;
+        case _C_ULNG:
+          fptr = (void (*)(void*, void*, id, id))unsignedLongMethodSetFunc;
+          break;
+        case 'q':
+          fptr = (void (*)(void*, void*, id, id))longLongMethodSetFunc;
+          break;
+        case 'Q':
+          fptr = (void (*)(void*, void*, id, id))unsignedLongLongMethodSetFunc;
+          break;
+        case _C_FLT:
+          fptr = (void (*)(void*, void*, id, id))floatMethodSetFunc;
+          break;
+        case _C_DBL:
+          fptr = (void (*)(void*, void*, id, id))doubleMethodSetFunc;
+          break;
+      }
+      if (fptr) {
+        info1 = (void*)(mth->method_imp);
+        info2 = (void*)(mth->method_name);
+      }
+    }
+    if (cbuf) free(cbuf);
+  }    
+  // Lookup ivar name
+  if (!fptr) {
+    Class class = [instance class];
+    unsigned   clen  = [key cStringLength];
+    char       *cbuf;
+    const char *ckey;
+    int i;
+
+    cbuf = malloc(clen + 1);
+    [key getCString:cbuf]; cbuf[clen] = '\0';
+    ckey = cbuf;
+        
+    while (class) {
+      for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) {
+        if (!Strcmp(ckey, class->ivars->ivar_list[i].ivar_name)) {
+          switch(*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) {
+            case _C_ID:
+              fptr = (void (*)(void*, void*, id, id))idIvarSetFunc;
+              break;
+            case _C_CHR:
+              fptr = (void (*)(void*, void*, id, id))charIvarSetFunc;
+              break;
+            case _C_UCHR:
+              fptr = (void (*)(void*, void*, id, id))unsignedCharIvarSetFunc;
+              break;
+            case _C_SHT:
+              fptr = (void (*)(void*, void*, id, id))shortIvarSetFunc;
+              break;
+            case _C_USHT:
+              fptr = (void (*)(void*, void*, id, id))unsignedShortIvarSetFunc;
+              break;
+            case _C_INT:
+              fptr = (void (*)(void*, void*, id, id))intIvarSetFunc;
+              break;
+            case _C_UINT:
+              fptr = (void (*)(void*, void*, id, id))unsignedIntIvarSetFunc;
+              break;
+            case _C_LNG:
+              fptr = (void (*)(void*, void*, id, id))longIvarSetFunc;
+              break;
+            case _C_ULNG:
+              fptr = (void (*)(void*, void*, id, id))unsignedLongIvarSetFunc;
+              break;
+            case 'q':
+              fptr = (void (*)(void*, void*, id, id))longLongIvarSetFunc;
+              break;
+            case 'Q':
+              fptr = (void (*)(void*, void*, id, id))unsignedLongLongIvarSetFunc;
+              break;
+            case _C_FLT:
+              fptr = (void (*)(void*, void*, id, id))floatIvarSetFunc;
+              break;
+            case _C_DBL:
+              fptr = (void (*)(void*, void*, id, id))doubleIvarSetFunc;
+              break;
+          }
+          if (fptr) {
+            info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
+            break;
+          }
+        }
+      }
+      class = class->super_class;
+    }
+    if (cbuf) free(cbuf);
+  }
+    
+  // Make binding and insert into map
+  if (fptr) {
+    KeyValueMethod     *mkey;
+    SetKeyValueBinding *bin;
+        
+    mkey = Malloc(sizeof(KeyValueMethod));
+    bin  = Malloc(sizeof(SetKeyValueBinding));
+    mkey->key = [key copy];
+    mkey->class = [instance class];
+    
+    bin->access = fptr;
+    bin->info1 = info1;
+    bin->info2 = info2;
+        
+    NSMapInsert(setValueBindings, mkey, bin);
+    ret = bin;
+  }
+  // If no way to access value warn
+  if (!ret && keyValueDebug)
+    NSLog(@"cannnot set key `%@' for instance of class `%@'",
+          key, NSStringFromClass([instance class]));
+  
+  return ret;
+}
+
+/*
+ * MapTable initialization
+ */
+
+static unsigned keyValueMapHash(NSMapTable* table, KeyValueMethod* map) {
+  return [map->key hash] + (((int)(map->class)) >> 4);
+}
+
+static BOOL keyValueMapCompare(NSMapTable* table,
+                               KeyValueMethod* map1, KeyValueMethod* map2)
+{
+  return (map1->class == map2->class) && [map1->key isEqual:map2->key];
+}
+
+static void mapRetainNothing(NSMapTable* table, KeyValueMethod* map) {
+}
+
+static void keyValueMapKeyRelease(NSMapTable* table, KeyValueMethod* map) {
+  [map->key release];
+  Free(map);
+}
+
+static void keyValueMapValRelease(NSMapTable* table, void* map) {
+  Free(map);
+}
+
+static NSString* keyValueMapDescribe(NSMapTable* table, KeyValueMethod* map) {
+  if (StringClass == Nil) StringClass = [NSString class];
+  return [StringClass stringWithFormat:@"%@:%@",
+                   NSStringFromClass(map->class), map->key];
+}
+
+static NSString* describeBinding(NSMapTable* table, GetKeyValueBinding* bin) {
+  if (StringClass == Nil) StringClass = [NSString class];
+  return [StringClass stringWithFormat:@"%08x:%08x", bin->info1, bin->info2];
+}
+
+static NSMapTableKeyCallBacks keyValueKeyCallbacks = {
+  (unsigned(*)(NSMapTable *, const void *))keyValueMapHash,
+  (BOOL(*)(NSMapTable *, const void *, const void *))keyValueMapCompare,
+  (void (*)(NSMapTable *, const void *anObject))mapRetainNothing,
+  (void (*)(NSMapTable *, void *anObject))keyValueMapKeyRelease,
+  (NSString *(*)(NSMapTable *, const void *))keyValueMapDescribe,
+  (const void *)NULL
+}; 
+
+const NSMapTableValueCallBacks keyValueValueCallbacks = {
+  (void (*)(NSMapTable *, const void *))mapRetainNothing,
+  (void (*)(NSMapTable *, void *))keyValueMapValRelease,
+  (NSString *(*)(NSMapTable *, const void *))describeBinding
+}; 
+
+static void initKeyValueBindings(void)
+{
+  getValueBindings = NSCreateMapTable(keyValueKeyCallbacks, 
+                                      keyValueValueCallbacks, 31);
+  setValueBindings = NSCreateMapTable(keyValueKeyCallbacks, 
+                                      keyValueValueCallbacks, 31);
+  keyValueInit = YES;
+}
+
+/* 
+ * Access Methods 
+ */
+
+static inline void removeAllBindings(void) {
+  NSResetMapTable(getValueBindings);
+  NSResetMapTable(setValueBindings);
+}
+
+static inline id getValue(NSString* key, id instance) {
+  KeyValueMethod     mkey = { key, [instance class] };
+  GetKeyValueBinding *bin;
+  id value = nil;
+  
+  if (NumberClass == Nil)
+    NumberClass = [NSNumber class];
+  
+  // Check Init
+  if (!keyValueInit)
+    initKeyValueBindings();
+    
+  // Get existing binding
+  bin = (GetKeyValueBinding *)NSMapGet(getValueBindings, &mkey);
+    
+  // Create new binding
+  if (bin == NULL)
+    bin = newGetBinding(key, instance);
+    
+  // Get value if binding is ok
+  if (bin)
+    value = bin->access(bin->info1, bin->info2, instance);
+    
+  return value;
+}
+
+static inline BOOL setValue(NSString* key, id instance, id value)
+{
+  KeyValueMethod mkey = {key, [instance class]};
+  SetKeyValueBinding* bin;
+
+  if (NumberClass == Nil)
+    NumberClass = [NSNumber class];
+    
+  // Check Init
+  if (!keyValueInit)
+    initKeyValueBindings();
+    
+  // Get existing binding
+  bin = (SetKeyValueBinding *)NSMapGet(setValueBindings, &mkey);
+    
+  // Create new binding
+  if (bin == NULL)
+    bin = newSetBinding(key, instance);
+    
+  // Get value if binding is ok
+  if (bin)
+    bin->access(bin->info1, bin->info2, instance, value);
+    
+  return (bin != NULL);
+}
+
++ (BOOL)accessInstanceVariablesDirectly {
+  return NO;
+}
+
+- (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
+  NSDictionary *ui;
+
+  ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                      self, @"EOTargetObjectUserInfoKey",
+                      [self class],
+                      @"EOTargetObjectClassUserInfoKey",
+                      _key, @"EOUnknownUserInfoKey",
+                    nil];
+  [[NSException exceptionWithName:@"EOUnknownKeyException"
+               reason:@"called -takeValue:forKey: with unknown key"
+               userInfo:ui] raise];
+}
+
+- (id)handleQueryWithUnboundKey:(NSString *)_key {
+  NSDictionary *ui;
+
+  ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                      self, @"EOTargetObjectUserInfoKey",
+                      _key, @"EOUnknownUserInfoKey",
+                    nil];
+  [[NSException exceptionWithName:@"EOUnknownKeyException"
+               reason:@"called -valueForKey: with unknown key"
+               userInfo:ui] raise];
+  return nil;
+}
+
+- (void)unableToSetNullForKey:(NSString *)_key {
+  [NSException raise:@"NSInvalidArgumentException" 
+              format:
+                 @"EOKeyValueCoding cannot set EONull value for key %@,"
+                 @"in instance of %@ class.",
+                 _key, NSStringFromClass([self class])];
+}
+
++ (void)flushAllKeyBindings {
+  removeAllBindings();
+}
+- (void)flushKeyBindings {
+  // EOF 1.1 method
+  removeAllBindings();
+}
+
+- (void)setKeyValueCodingWarnings:(BOOL)aFlag {
+  keyValueDebug = aFlag;
+}
+
+- (void)takeValuesFromDictionary:(NSDictionary *)dictionary {
+  NSEnumerator *keyEnum;
+  id key;
+
+  if (null == nil) null = [EONull null];
+  keyEnum = [dictionary keyEnumerator];
+    
+  while ((key = [keyEnum nextObject])) {
+    id value;
+    
+    value = [dictionary objectForKey:key];
+
+    /* automagically convert EONull to nil */
+    if (value == null) value = nil;
+    
+    [self takeValue:value forKey:key];
+    
+#if 0 // this doesn't support overridden methods ...
+    if (!setValue(key, self, value)) {
+      [self handleTakeValue:value forUnboundKey:key];
+    }
+#endif
+  }
+}
+
+- (NSDictionary *)valuesForKeys:(NSArray *)keys {
+  static Class  NSDictionaryClass = Nil;
+  int n = [keys count];
+
+  if (NSDictionaryClass == Nil)
+    NSDictionaryClass = [NSDictionary class];
+  if (null == nil)
+    null = [EONull null];
+  
+  if (n == 0)
+    return [NSDictionaryClass dictionary];
+  else if (n == 1) {
+    NSString *key;
+    id value;
+    
+    key   = [keys objectAtIndex:0];
+    //value = getValue(key, self);
+    value = [self valueForKey:key];
+
+    /* automagically convert 'nil' to EONull */
+    if (value == nil) value = null;
+    
+    return [NSDictionaryClass dictionaryWithObject:value forKey:key];
+  }
+  else {
+    id newKeys[n];
+    id newVals[n];
+    int i;
+        
+    for (i = 0; i < n; i++) {
+      id key;
+      id val;
+      
+      key = [keys objectAtIndex:i];
+      //val = getValue(key, self);
+      val = [self valueForKey:key];
+
+      /* automagically convert 'nil' to EONull */
+      if (val == nil) val = null;
+      
+      newKeys[i] = key;
+      newVals[i] = val;
+    }
+    
+    return [NSDictionaryClass dictionaryWithObjects:newVals
+                              forKeys:newKeys
+                              count:n];
+  }
+}
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  if (!setValue(_key, self, _value)) {
+    //NSLog(@"ERROR(%s): couldn't take value for key %@", key);
+    [self handleTakeValue:_value forUnboundKey:_key];
+  }
+}
+
+- (id)valueForKey:(NSString *)key {
+  id val;
+  
+  if ((val = getValue(key, self)))
+    return val;
+  
+  return nil;
+}
+
+/* stored values */
+
++ (BOOL)useStoredAccessor {
+  return YES;
+}
+
+- (void)takeStoredValue:(id)_value forKey:(NSString *)_key {
+  if ([[self class] useStoredAccessor]) {
+    BOOL ok = YES;
+
+    /* this should be different */
+    
+    ok = setValue(_key, self, _value);
+    if (!ok) [self handleTakeValue:_value forUnboundKey:_key];
+  }
+  else
+    [self takeValue:_value forKey:_key];
+}
+
+- (id)storedValueForKey:(NSString *)_key {
+  if ([[self class] useStoredAccessor]) {
+    id val;
+
+    /* this should be different */
+    
+    if ((val = getValue(_key, self)))
+      return val;
+
+    /* val = [self handleQueryWithUnboundKey:_key] */
+    
+    return nil;
+  }
+  else
+    return [self valueForKey:_key];
+}
+
+@end /* NSObject(EOKeyValueCoding) */
+
+@implementation NSObject(EOKeyPathValueCoding)
+
+- (void)takeValue:(id)_value forKeyPath:(NSString *)_keyPath {
+  NSArray *keyPath;
+  unsigned i, count;
+  id target;
+
+  keyPath = [_keyPath componentsSeparatedByString:@"."];
+  count = [keyPath count];
+
+  if (count < 2)
+    [self takeValue:_value forKey:_keyPath];
+  else {
+
+    target = self;
+    for (i = 0; i < (count - 1) ; i++) {
+      if ((target = [target valueForKey:[keyPath objectAtIndex:i]]) == nil)
+        /* nil component */
+        return;
+    }
+  
+    [target takeValue:_value forKey:[keyPath lastObject]];
+  }
+}
+- (id)valueForKeyPath:(NSString *)_keyPath {
+#if 1
+  const unsigned char *buf;
+  unsigned int  i, start, len;
+  id value;
+
+  if ((len = [_keyPath cStringLength]) == 0)
+    return [self valueForKey:_keyPath];
+  
+  if (StringClass == Nil) StringClass = [NSString class];
+  value = self;
+  
+  buf = [_keyPath cString];
+  if (index(buf, '.') == NULL)
+    /* no point contained .. */
+    return [self valueForKey:_keyPath];
+  
+  for (i = start = 0; i < len; i++) {
+    if (buf[i] == '.') {
+      /* found a pt */
+      NSString *key;
+      
+      key = (start < i)
+        ? [StringClass stringWithCString:&(buf[start]) length:(i - start)]
+        : @"";
+      
+      if ((value = [value valueForKey:key]) == nil)
+        return nil;
+      
+      start = (i + 1); /* next part is after the pt */
+    }
+  }
+  /* check last part */
+  {
+    NSString *key;
+    
+    key = (start < i)
+      ? [StringClass stringWithCString:&(buf[start]) length:(i - start)]
+      : @"";
+    return [value valueForKey:key];
+  }
+#else
+  /* naive implementation */
+  NSEnumerator *keyPath;
+  NSString *key;
+  id value;
+  
+  value   = self;
+  keyPath = [[_keyPath componentsSeparatedByString:@"."] objectEnumerator];
+  while ((key = [keyPath nextObject]) && (value != nil))
+    value = [value valueForKey:key];
+  return value;
+#endif
+}
+
+@end /* NSObject(EOKeyPathValueCoding) */
+
+@implementation NSArray(EOKeyValueCoding)
+
+- (id)computeSumForKey:(NSString *)_key {
+  unsigned i, cc = [self count];
+  id (*objAtIdx)(id, SEL, unsigned int);
+  double sum;
+
+  if (cc == 0) return [NSNumber numberWithDouble:0.0];
+  
+  objAtIdx = (void*)[self methodForSelector:@selector(objectAtIndex:)];
+    
+  for (i = 0, sum = 0.0; i < cc; i++) {
+    register id o;
+      
+    o = objAtIdx(self, @selector(objectAtIndex:), i);
+    sum += [o doubleValue];
+  }
+  return [NSNumber numberWithDouble:sum];
+}
+
+- (id)computeAvgForKey:(NSString *)_key {
+  unsigned i, cc = [self count];
+  id (*objAtIdx)(id, SEL, unsigned int);
+  double sum;
+
+  if (cc == 0) return [NSNumber numberWithDouble:0.0];
+  
+  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
+    
+  for (i = 0, sum = 0.0; i < cc; i++) {
+    register id o;
+      
+    o = objAtIdx(self, @selector(objectAtIndex:), i);
+
+    sum += [o doubleValue];
+  }
+  return [NSNumber numberWithDouble:(sum / (double)cc)];
+}
+
+- (id)computeCountForKey:(NSString *)_key {
+  return [NSNumber numberWithUnsignedInt:[self count]];
+}
+
+- (id)computeMaxForKey:(NSString *)_key {
+  unsigned i, cc = [self count];
+  id (*objAtIdx)(id, SEL, unsigned int);
+  double max;
+
+  if (cc == 0) return nil;
+    
+  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
+
+  max = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
+  for (i = 1; i < cc; i++) {
+    register double ov;
+      
+    ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
+    if (ov > max) max = ov;
+  }
+  return [NSNumber numberWithDouble:max];
+}
+
+- (id)computeMinForKey:(NSString *)_key {
+  unsigned i, cc = [self count];
+  id (*objAtIdx)(id, SEL, unsigned int);
+  double min;
+
+  if (cc == 0) return nil;
+  
+  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
+    
+  min = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
+  for (i = 1; i < cc; i++) {
+    register double ov;
+      
+    ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
+    if (ov < min) min = ov;
+  }
+  return [NSNumber numberWithDouble:min];
+}
+
+- (id)valueForKey:(NSString *)_key {
+  if ([_key hasPrefix:@"@"]) {
+    /* process a computed function */
+    const char *keyStr;
+    char       *bufPtr;
+    unsigned   keyLen = [_key cStringLength];
+    char       *kbuf, *buf;
+    SEL        sel;
+
+    kbuf = malloc(keyLen + 4);
+    buf  = malloc(keyLen + 20);
+    [_key getCString:kbuf];
+    keyStr = kbuf;
+    bufPtr = buf;
+    strcpy(buf, "compute");       bufPtr += 7;
+    *bufPtr = toupper(keyStr[1]); bufPtr++;
+    strncpy(&(buf[8]), &(keyStr[2]), keyLen - 2); bufPtr += (keyLen - 2);
+    strcpy(bufPtr, "ForKey:");
+    if (kbuf) free(kbuf);
+    
+    sel = sel_get_any_uid(buf);
+    if (buf) free(buf);
+    
+    return sel != NULL ? [self performSelector:sel withObject:_key] : nil;
+  }
+  else {
+    /* process the _key in a map function */
+    unsigned i, cc = [self count];
+    id objects[cc];
+    id (*objAtIdx)(id, SEL, unsigned int);
+
+#if DEBUG
+    if ([_key isEqualToString:@"count"]) {
+      NSLog(@"WARNING(%s): USED -valueForKey(@\"count\") ON NSArray, YOU"
+            @"PROBABLY WANT TO USE @count INSTEAD !",
+            __PRETTY_FUNCTION__);
+      return [self valueForKey:@"@count"];
+    }
+#endif
+    
+    objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
+    
+    for (i = 0; i < cc; i++) {
+      register id o;
+      
+      o = [objAtIdx(self, @selector(objectAtIndex:), i) valueForKey:_key];
+      
+      if (o)
+        objects[i] = o;
+      else {
+        if (null == nil) null = [EONull null];
+        objects[i] = null;
+      }
+    }
+    
+    return [NSArray arrayWithObjects:objects count:cc];
+  }
+}
+
+@end /* NSArray(EOKeyValueCoding) */
+
+@implementation NSDictionary(EOKeyValueCoding)
+
+- (NSDictionary *)valuesForKeys:(NSArray *)keys {
+  int n = [keys count];
+
+  if (n == 0)
+    return [NSDictionary dictionary];
+  else if (n == 1) {
+    NSString *key = [keys objectAtIndex:0];
+
+    return [NSDictionary dictionaryWithObject:[self objectForKey:key]
+                         forKey:key];
+  }
+  else {
+    NSMutableArray *newKeys, *newVals;
+    int i;
+        
+    newKeys = [NSMutableArray arrayWithCapacity:n];
+    newVals = [NSMutableArray arrayWithCapacity:n];
+    
+    for (i = 0; i < n; i++) {
+      id key = [keys objectAtIndex:i];
+      id val = [self objectForKey:key];
+      
+      if (val) {
+        [newKeys addObject:key];
+        [newVals addObject:val];
+      }
+    }
+    
+    return [NSDictionary dictionaryWithObjects:newVals forKeys:newKeys];
+  }
+}
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  //#warning takeValue:forKey: is ignored in NSDictionaries !
+  // ignore
+  //[self handleTakeValue:_value forUnboundKey:_key];
+}
+
+- (id)valueForKey:(id)_key {
+  id obj;
+  
+  if (_key == nil) // TODO: warn about nil key?
+    return nil;
+  if ((obj = [self objectForKey:_key]) == nil)
+    return nil;
+  
+  if (null == nil) null = [[NSNull null] retain];
+  if (obj == null)
+    return nil;
+    
+  return obj;
+}
+
+@end /* NSDictionary(EOKeyValueCoding) */
+
+@implementation NSMutableDictionary(EOKeyValueCoding)
+
+- (void)takeValuesFromDictionary:(NSDictionary*)dictionary {
+  [self addEntriesFromDictionary:dictionary];
+}
+
+- (void)takeValue:(id)_value forKey:(id)_key {
+  if (_value == nil) _value = [NSNull null];
+  [self setObject:_value forKey:_key];
+}
+
+@end /* NSMutableDictionary(EOKeyValueCoding) */
+
+/*
+ *  Accessor functions
+ */
+
+/* ACCESS to keys of id type. */
+
+static id idMethodGetFunc(void* info1, void* info2, id self) {
+  id (*fptr)(id, SEL) = (id(*)(id, SEL))info1;
+  id val = fptr(self, (SEL)info2);
+  return val;
+}
+static id idIvarGetFunc(void* info1, void* info2, id self) {
+  id* ptr = (id*)((char*)self + (int)info2);
+  return *ptr;
+}
+
+static void idMethodSetFunc(void* info1, void* info2, id self, id val) {
+  void (*fptr)(id, SEL, id) = (void(*)(id, SEL, id))info1;
+  fptr(self, (SEL)info2, val);
+}
+
+static void idIvarSetFunc(void* info1, void* info2, id self, id val)
+{
+  id* ptr = (id*)((char*)self + (int)info2);
+  ASSIGN(*ptr, val);
+}
+
+/* ACCESS to keys of char type. */
+
+static id charMethodGetFunc(void* info1, void* info2, id self)
+{
+  char (*fptr)(id, SEL) = (char(*)(id, SEL))info1;
+  char val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithChar:val];
+}
+
+static id charIvarGetFunc(void* info1, void* info2, id self)
+{
+  char* ptr = (char*)((char*)self + (int)info2);
+  return [NumberClass numberWithChar:*ptr];
+}
+
+static void charMethodSetFunc(void* info1, void* info2, id self, id val)
+{
+  void (*fptr)(id, SEL, char) = (void(*)(id, SEL, char))info1;
+  fptr(self, (SEL)info2, [val charValue]);
+}
+
+static void charIvarSetFunc(void* info1, void* info2, id self, id val)
+{
+  char* ptr = (char*)((char*)self + (int)info2);
+  *ptr = [val charValue];
+}
+
+
+/* ACCESS to keys of unsigned char type. */
+
+static id unsignedCharMethodGetFunc(void* info1, void* info2, id self)
+{
+  unsigned char (*fptr)(id, SEL) = (unsigned char(*)(id, SEL))info1;
+  unsigned char val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithUnsignedChar:val];
+}
+
+static id unsignedCharIvarGetFunc(void* info1, void* info2, id self)
+{
+  unsigned char* ptr = (unsigned char*)((char*)self + (int)info2);
+  return [NumberClass numberWithUnsignedChar:*ptr];
+}
+
+static void unsignedCharMethodSetFunc(void* info1, void* info2, id self, id val)
+{
+  void (*fptr)(id, SEL, unsigned char) = (void(*)(id, SEL, unsigned char))info1;
+  fptr(self, (SEL)info2, [val unsignedCharValue]);
+}
+
+static void unsignedCharIvarSetFunc(void* info1, void* info2, id self, id val)
+{
+  unsigned char* ptr = (unsigned char*)((char*)self + (int)info2);
+  *ptr = [val unsignedCharValue];
+}
+
+
+/* ACCESS to keys of short type. */
+
+static id shortMethodGetFunc(void* info1, void* info2, id self)
+{
+  short (*fptr)(id, SEL) = (short(*)(id, SEL))info1;
+  short val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithShort:val];
+}
+
+static id shortIvarGetFunc(void* info1, void* info2, id self)
+{
+  short* ptr = (short*)((char*)self + (int)info2);
+  return [NumberClass numberWithShort:*ptr];
+}
+
+static void shortMethodSetFunc(void* info1, void* info2, id self, id val)
+{
+  void (*fptr)(id, SEL, short) = (void(*)(id, SEL, short))info1;
+  fptr(self, (SEL)info2, [val shortValue]);
+}
+
+static void shortIvarSetFunc(void* info1, void* info2, id self, id val)
+{
+  short* ptr = (short*)((char*)self + (int)info2);
+  *ptr = [val shortValue];
+}
+
+
+/* ACCESS to keys of unsigned short type. */
+
+static id unsignedShortMethodGetFunc(void* info1, void* info2, id self)
+{
+  unsigned short (*fptr)(id, SEL) = (unsigned short(*)(id, SEL))info1;
+  unsigned short val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithUnsignedShort:val];
+}
+
+static id unsignedShortIvarGetFunc(void* info1, void* info2, id self)
+{
+  unsigned short* ptr = (unsigned short*)((char*)self + (int)info2);
+  return [NumberClass numberWithUnsignedShort:*ptr];
+}
+
+static void unsignedShortMethodSetFunc(void* info1, void* info2, id self, id val)
+{
+  void (*fptr)(id, SEL, unsigned short) = (void(*)(id, SEL, unsigned short))info1;
+  fptr(self, (SEL)info2, [val unsignedShortValue]);
+}
+
+static void unsignedShortIvarSetFunc(void* info1, void* info2, id self, id val)
+{
+  unsigned short* ptr = (unsigned short*)((char*)self + (int)info2);
+  *ptr = [val unsignedShortValue];
+}
+
+
+/* ACCESS to keys of int type. */
+
+static id intMethodGetFunc(void* info1, void* info2, id self)
+{
+  int (*fptr)(id, SEL) = (int(*)(id, SEL))info1;
+  int val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithInt:val];
+}
+
+static id intIvarGetFunc(void* info1, void* info2, id self)
+{
+  int* ptr = (int*)((char*)self + (int)info2);
+  return [NumberClass numberWithInt:*ptr];
+}
+
+static void intMethodSetFunc(void* info1, void* info2, id self, id val)
+{
+  void (*fptr)(id, SEL, int) = (void(*)(id, SEL, int))info1;
+  fptr(self, (SEL)info2, [val intValue]);
+}
+
+static void intIvarSetFunc(void* info1, void* info2, id self, id val)
+{
+  int* ptr = (int*)((char*)self + (int)info2);
+  *ptr = [val intValue];
+}
+
+
+/* ACCESS to keys of unsigned int type. */
+
+static id unsignedIntMethodGetFunc(void* info1, void* info2, id self)
+{
+  unsigned int (*fptr)(id, SEL) = (unsigned int(*)(id, SEL))info1;
+  unsigned int val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithUnsignedInt:val];
+}
+
+static id unsignedIntIvarGetFunc(void* info1, void* info2, id self)
+{
+  unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
+  return [NumberClass numberWithUnsignedInt:*ptr];
+}
+
+static void unsignedIntMethodSetFunc(void* info1, void* info2, id self, id val)
+{
+  void (*fptr)(id, SEL, unsigned int) = (void(*)(id, SEL, unsigned int))info1;
+  fptr(self, (SEL)info2, [val unsignedIntValue]);
+}
+
+static void unsignedIntIvarSetFunc(void* info1, void* info2, id self, id val)
+{
+  unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
+  *ptr = [val unsignedIntValue];
+}
+
+
+/* ACCESS to keys of long type. */
+
+static id longMethodGetFunc(void* info1, void* info2, id self)
+{
+  long (*fptr)(id, SEL) = (long(*)(id, SEL))info1;
+  long val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithLong:val];
+}
+
+static id longIvarGetFunc(void* info1, void* info2, id self)
+{
+  long* ptr = (long*)((char*)self + (int)info2);
+  return [NumberClass numberWithLong:*ptr];
+}
+
+static void longMethodSetFunc(void* info1, void* info2, id self, id val)
+{
+  void (*fptr)(id, SEL, long) = (void(*)(id, SEL, long))info1;
+  fptr(self, (SEL)info2, [val longValue]);
+}
+
+static void longIvarSetFunc(void* info1, void* info2, id self, id val)
+{
+  long* ptr = (long*)((char*)self + (int)info2);
+  *ptr = [val longValue];
+}
+
+
+/* unsigned long type */
+
+static id unsignedLongMethodGetFunc(void* info1, void* info2, id self) {
+  unsigned long (*fptr)(id, SEL) = (unsigned long(*)(id, SEL))info1;
+  unsigned long val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithUnsignedLong:val];
+}
+
+static id unsignedLongIvarGetFunc(void* info1, void* info2, id self) {
+  unsigned long* ptr = (unsigned long*)((char*)self + (int)info2);
+  return [NumberClass numberWithUnsignedLong:*ptr];
+}
+
+static void unsignedLongMethodSetFunc(void* info1, void* info2, id self, id val) {
+  void (*fptr)(id, SEL, unsigned long) = (void(*)(id, SEL, unsigned long))info1;
+  fptr(self, (SEL)info2, [val unsignedLongValue]);
+}
+
+static void unsignedLongIvarSetFunc(void* info1, void* info2, id self, id val) {
+  unsigned long* ptr = (unsigned long*)((char*)self + (int)info2);
+  *ptr = [val unsignedLongValue];
+}
+
+
+/* long long type */
+
+static id longLongMethodGetFunc(void* info1, void* info2, id self) {
+  long long (*fptr)(id, SEL) = (long long(*)(id, SEL))info1;
+  long long val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithLongLong:val];
+}
+
+static id longLongIvarGetFunc(void* info1, void* info2, id self) {
+  long long* ptr = (long long*)((char*)self + (int)info2);
+  return [NumberClass numberWithLongLong:*ptr];
+}
+
+static void longLongMethodSetFunc(void* info1, void* info2, id self, id val) {
+  void (*fptr)(id, SEL, long long) = (void(*)(id, SEL, long long))info1;
+  fptr(self, (SEL)info2, [val longLongValue]);
+}
+
+static void longLongIvarSetFunc(void* info1, void* info2, id self, id val) {
+  long long* ptr = (long long*)((char*)self + (int)info2);
+  *ptr = [val longLongValue];
+}
+
+
+/* unsigned long long type */
+
+static id unsignedLongLongMethodGetFunc(void* info1, void* info2, id self) {
+  unsigned long long (*fptr)(id, SEL) = (unsigned long long(*)(id, SEL))info1;
+  unsigned long long val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithUnsignedLongLong:val];
+}
+
+static id unsignedLongLongIvarGetFunc(void* info1, void* info2, id self) {
+  unsigned long long* ptr = (unsigned long long*)((char*)self + (int)info2);
+  return [NumberClass numberWithUnsignedLongLong:*ptr];
+}
+
+static void unsignedLongLongMethodSetFunc(void* info1, void* info2, id self, id val) {
+  void (*fptr)(id, SEL, unsigned long long) = (void(*)(id, SEL, unsigned long long))info1;
+  fptr(self, (SEL)info2, [val unsignedLongLongValue]);
+}
+
+static void unsignedLongLongIvarSetFunc(void* info1, void* info2, id self, id val) {
+  unsigned long long* ptr = (unsigned long long*)((char*)self + (int)info2);
+  *ptr = [val unsignedLongLongValue];
+}
+
+
+/* float */
+
+static id floatMethodGetFunc(void* info1, void* info2, id self) {
+  float (*fptr)(id, SEL) = (float(*)(id, SEL))info1;
+  float val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithFloat:val];
+}
+
+static id floatIvarGetFunc(void* info1, void* info2, id self) {
+  float* ptr = (float*)((char*)self + (int)info2);
+  return [NumberClass numberWithFloat:*ptr];
+}
+
+static void floatMethodSetFunc(void* info1, void* info2, id self, id val) {
+  void (*fptr)(id, SEL, float) = (void(*)(id, SEL, float))info1;
+  fptr(self, (SEL)info2, [val floatValue]);
+}
+
+static void floatIvarSetFunc(void* info1, void* info2, id self, id val) {
+  float* ptr = (float*)((char*)self + (int)info2);
+  *ptr = [val floatValue];
+}
+
+
+/* double */
+
+static id doubleMethodGetFunc(void* info1, void* info2, id self) {
+  double (*fptr)(id, SEL) = (double(*)(id, SEL))info1;
+  double val = fptr(self, (SEL)info2);
+  return [NumberClass numberWithDouble:val];
+}
+
+static id doubleIvarGetFunc(void* info1, void* info2, id self) {
+  double* ptr = (double*)((char*)self + (int)info2);
+  return [NumberClass numberWithDouble:*ptr];
+}
+
+static void doubleMethodSetFunc(void* info1, void* info2, id self, id val) {
+  void (*fptr)(id, SEL, double) = (void(*)(id, SEL, double))info1;
+  fptr(self, (SEL)info2, [val doubleValue]);
+}
+
+static void doubleIvarSetFunc(void* info1, void* info2, id self, id val) {
+  double* ptr = (double*)((char*)self + (int)info2);
+  *ptr = [val doubleValue];
+}
+
+#else /* NeXT_Foundation_LIBRARY */
+
+@implementation NSArray(EOKeyValueCoding)
+
+- (id)computeSumForKey:(NSString *)_key {
+  unsigned i, cc = [self count];
+  id (*objAtIdx)(id, SEL, unsigned int);
+  double sum;
+
+  if (cc == 0) return [NSNumber numberWithDouble:0.0];
+  
+  objAtIdx = (void*)[self methodForSelector:@selector(objectAtIndex:)];
+    
+  for (i = 0, sum = 0.0; i < cc; i++) {
+    register id o;
+      
+    o = objAtIdx(self, @selector(objectAtIndex:), i);
+    sum += [o doubleValue];
+  }
+  return [NSNumber numberWithDouble:sum];
+}
+
+- (id)computeAvgForKey:(NSString *)_key {
+  unsigned i, cc = [self count];
+  id (*objAtIdx)(id, SEL, unsigned int);
+  double sum;
+
+  if (cc == 0) return [NSNumber numberWithDouble:0.0];
+  
+  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
+    
+  for (i = 0, sum = 0.0; i < cc; i++) {
+    register id o;
+      
+    o = objAtIdx(self, @selector(objectAtIndex:), i);
+
+    sum += [o doubleValue];
+  }
+  return [NSNumber numberWithDouble:(sum / (double)cc)];
+}
+
+- (id)computeCountForKey:(NSString *)_key {
+  return [NSNumber numberWithUnsignedInt:[self count]];
+}
+
+- (id)computeMaxForKey:(NSString *)_key {
+  unsigned i, cc = [self count];
+  id (*objAtIdx)(id, SEL, unsigned int);
+  double max;
+
+  if (cc == 0) return nil;
+    
+  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
+
+  max = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
+  for (i = 1; i < cc; i++) {
+    register double ov;
+      
+    ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
+    if (ov > max) max = ov;
+  }
+  return [NSNumber numberWithDouble:max];
+}
+
+- (id)computeMinForKey:(NSString *)_key {
+  unsigned i, cc = [self count];
+  id (*objAtIdx)(id, SEL, unsigned int);
+  double min;
+
+  if (cc == 0) return nil;
+  
+  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
+    
+  min = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
+  for (i = 1; i < cc; i++) {
+    register double ov;
+      
+    ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
+    if (ov < min) min = ov;
+  }
+  return [NSNumber numberWithDouble:min];
+}
+
+- (id)valueForKey:(NSString *)_key {
+  if (null == nil) null = [[EONull null] retain];
+  
+  if ([_key hasPrefix:@"@"]) {
+    /* process a computed function */
+    const char *keyStr;
+    char       *bufPtr;
+    unsigned   keyLen = [_key cStringLength];
+    char       *kbuf, *buf;
+    SEL        sel;
+
+    kbuf = malloc(keyLen + 1);
+    buf  = malloc(keyLen + 16);
+    [_key getCString:kbuf];
+    keyStr = kbuf;
+    bufPtr = buf;
+    strcpy(buf, "compute");       bufPtr += 7;
+    *bufPtr = toupper(keyStr[1]); bufPtr++;
+    strncpy(&(buf[8]), &(keyStr[2]), keyLen - 2); bufPtr += (keyLen - 2);
+    strcpy(bufPtr, "ForKey:");
+    if (kbuf) free(kbuf);
+
+#if NeXT_RUNTIME
+    sel = sel_getUid(buf);
+#else    
+    sel = sel_get_any_uid(buf);
+#endif
+    if (buf) free(buf);
+    
+    return sel != NULL ? [self performSelector:sel withObject:_key] : nil;
+  }
+  else {
+    /* process the _key in a map function */
+    unsigned i, cc = [self count];
+    NSArray  *result;
+    id *objects;
+    id (*objAtIdx)(id, SEL, unsigned int);
+
+#if DEBUG
+    if ([_key isEqualToString:@"count"]) {
+      NSLog(@"WARNING(%s): USED -valueForKey(@\"count\") ON NSArray, YOU"
+            @"PROBABLY WANT TO USE @count INSTEAD !",
+            __PRETTY_FUNCTION__);
+      return [self valueForKey:@"@count"];
+    }
+#endif
+    
+    if (cc == 0) return [NSArray array];
+    
+    objects = calloc(cc + 2, sizeof(id));
+    objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
+    
+    for (i = 0; i < cc; i++) {
+      register id o;
+      
+      o = [objAtIdx(self, @selector(objectAtIndex:), i) valueForKey:_key];
+      objects[i] = o ? o : null;
+    }
+    
+    result = [NSArray arrayWithObjects:objects count:cc];
+    if (objects) free(objects);
+    return result;
+  }
+}
+
+@end /* NSArray(EOKeyValueCoding) */
+
+#endif /* !NeXT_Foundation_LIBRARY */
diff --git a/skyrix-core/EOControl/EOKeyValueQualifier.m b/skyrix-core/EOControl/EOKeyValueQualifier.m
new file mode 100644 (file)
index 0000000..35ee01e
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <EOControl/EOQualifier.h>
+#include <EOControl/EONull.h>
+#include "common.h"
+
+@interface NSObject(QualifierDescription)
+- (NSString *)qualifierDescription;
+@end
+
+@implementation EOKeyValueQualifier
+
+static BOOL   debugEval      = NO;
+static BOOL   debugTransform = NO;
+static EONull *null = nil;
+
++ (void)initialize {
+  if (null == nil)
+    null = [[EONull null] retain];
+  debugEval = [EOQualifier isEvaluationDebuggingEnabled];
+}
+
+- (id)initWithKey:(NSString *)_key
+  operatorSelector:(SEL)_selector
+  value:(id)_value
+{
+  self->key      = [_key   copyWithZone:NULL];
+  self->value    = [_value retain];
+  self->operator = _selector;
+  return self;
+}
+
+- (void)dealloc {
+  [self->key   release];
+  [self->value release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)key {
+  return self->key;
+}
+- (SEL)selector {
+  return self->operator;
+}
+- (id)value {
+  return self->value;
+}
+
+/* bindings */
+
+- (EOQualifier *)qualifierWithBindings:(NSDictionary *)_bindings
+  requiresAllVariables:(BOOL)_reqAll
+{
+  static Class VarClass = Nil;
+  NSString *newKey;
+  id       newValue;
+  BOOL     needNew;
+  
+  if (VarClass == Nil) VarClass = [EOQualifierVariable class];
+  needNew = NO;
+
+  if ([self->key class] == VarClass) {
+    newKey = [_bindings objectForKey:[(EOQualifierVariable *)self->key key]];
+    if (newKey == nil) {
+      if (_reqAll)
+        // throw exception
+        ;
+      else
+        newKey = self->key;
+    }
+    else
+      needNew = YES;
+  }
+  else
+    newKey = self->key;
+
+  if ([self->value class] == VarClass) {
+    newValue = [_bindings objectForKey:[self->value key]];
+    if (newValue == nil) {
+      if (_reqAll)
+        // throw exception
+        ;
+      else
+        newValue = self->value;
+    }
+    else
+      needNew = YES;
+  }
+  else
+    newValue = self->value;
+
+  if (!needNew)
+    return self;
+
+  return [[[[self class] alloc]
+                         initWithKey:newKey
+                         operatorSelector:self->operator
+                         value:newValue] autorelease];
+}
+
+- (NSArray *)bindingKeys {
+  static Class VarClass = Nil;
+  Class keyClass, vClass;
+  if (VarClass == Nil) VarClass = [EOQualifierVariable class];
+  
+  keyClass = [self->key   class];
+  vClass   = [self->value class];
+  
+  if ((keyClass == VarClass) && (vClass == VarClass)) {
+    id o[2];
+    o[0] = [(EOQualifierVariable *)self->key   key];
+    o[1] = [(EOQualifierVariable *)self->value key];
+    return [NSArray arrayWithObjects:o count:2];
+  }
+  
+  if (keyClass == VarClass)
+    return [NSArray arrayWithObject:[(EOQualifierVariable *)self->key key]];
+  if (vClass == VarClass)
+    return [NSArray arrayWithObject:[(EOQualifierVariable *)self->value key]];
+  
+  return [NSArray array];
+}
+
+/* keys */
+
+- (void)addQualifierKeysToSet:(NSMutableSet *)_keys {
+  /* new in WO 4.5 */
+  [_keys addObject:self->key];
+}
+
+/* evaluation */
+
+- (BOOL)evaluateWithObject:(id)_object inEvalContext:(id)_ctx {
+  id   lv, rv;
+  BOOL (*m)(id, SEL, id);
+  BOOL result;
+  
+  if (_ctx == nil)
+    _ctx = [NSMutableDictionary dictionaryWithCapacity:16];
+  
+  if ((lv = [(NSDictionary *)_ctx objectForKey:self->key]) == nil) {
+    lv = [_object valueForKeyPath:self->key];
+    if (lv == nil) lv = null;
+    [(NSMutableDictionary *)_ctx setObject:lv forKey:self->key];
+  }
+  
+  rv = self->value ? self->value : null;
+  
+  if (debugEval) {
+    NSLog(@"Eval: EOKeyValueQualifier:(%@ %@)\n"
+          @"  compare %@<%@>\n  with %@<%@>",
+          self->key, NSStringFromSelector(self->operator),
+          lv, NSStringFromClass([lv class]),
+          rv, NSStringFromClass([rv class]));
+  }
+  
+  if ((m = (void *)[lv methodForSelector:self->operator]) == NULL) {
+    /* no such operator method ! */
+    [lv doesNotRecognizeSelector:self->operator];
+    return NO;
+  }
+  
+  result = m(lv, self->operator, rv);
+  if (debugEval)
+    NSLog(@"  %@", result ? @"MATCHES" : @"DOES NOT MATCH");
+  return result;
+}
+- (BOOL)evaluateWithObject:(id)_object {
+  return [self evaluateWithObject:_object inEvalContext:nil];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->key];
+  [_coder encodeObject:self->value];
+  [_coder encodeValueOfObjCType:@encode(SEL) at:&(self->operator)];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  self->key   = [[_coder decodeObject] copyWithZone:[self zone]];
+  self->value = [[_coder decodeObject] retain];
+  [_coder decodeValueOfObjCType:@encode(SEL) at:&(self->operator)];
+  return self;
+}
+
+/* Comparing */
+
+- (BOOL)isEqualToQualifier:(EOQualifier *)_qual {
+  if (![self->key isEqual:[(EOKeyValueQualifier *)_qual key]])
+    return NO;
+  if (![self->value isEqual:[(EOKeyValueQualifier *)_qual value]])
+    return NO;
+  if (sel_eq(self->operator, [(EOKeyValueQualifier *)_qual selector]))
+    return YES;
+  return NO;
+}
+
+/* remapping keys */
+
+- (EOQualifier *)qualifierByApplyingTransformer:(id)_transformer
+  inContext:(id)_ctx
+{
+  if ([_transformer respondsToSelector:
+                      @selector(transformKeyValueQualifier:inContext:)]) {
+    if (debugTransform)
+      NSLog(@"transformer: %@\n  transform: %@", _transformer, self);
+    return [_transformer transformKeyValueQualifier:self inContext:_ctx];
+  }
+  else {
+    if (debugTransform)
+      NSLog(@"EOKeyValueQualifier: not transforming using %@", _transformer);
+    return [[self retain] autorelease];
+  }
+}
+
+- (EOQualifier *)qualifierByApplyingKeyMap:(NSDictionary *)_map {
+  EOKeyValueQualifier *kvq;
+  NSString *k;
+  
+  k = [_map objectForKey:self->key];
+  if (k == nil) k = self->key;
+  
+  kvq = [[EOKeyValueQualifier alloc] 
+         initWithKey:k operatorSelector:self->operator value:self->value];
+  return [kvq autorelease];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+  
+  s = [NSMutableString stringWithCapacity:64];
+  [s appendString:self->key];
+  [s appendString:@" "];
+  [s appendString:[EOQualifier stringForOperatorSelector:self->operator]];
+  [s appendString:@" "];
+  [s appendString:[self->value qualifierDescription]];
+  return s;
+}
+
+@end /* EOKeyValueQualifier */
diff --git a/skyrix-core/EOControl/EONotQualifier.m b/skyrix-core/EOControl/EONotQualifier.m
new file mode 100644 (file)
index 0000000..5ec16fd
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EOQualifier.h>
+#include "common.h"
+
+@interface NSObject(QualifierDescription)
+- (NSString *)qualifierDescription;
+@end
+
+@interface EOQualifier(EvalContext)
+- (BOOL)evaluateWithObject:(id)_object inEvalContext:(id)_ctx;
+@end
+
+@implementation EONotQualifier
+
+- (id)initWithQualifier:(EOQualifier *)_qualifier {
+  self->qualifier = [_qualifier retain];
+  return self;
+}
+
+- (void)dealloc {
+  [self->qualifier release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (EOQualifier *)qualifier {
+  return self->qualifier;
+}
+
+- (unsigned int)count {
+  return self->qualifier ? 1 : 0;
+}
+- (NSArray *)subqualifiers {
+  return self->qualifier ? [NSArray arrayWithObject:self->qualifier] : nil;
+}
+
+/* bindings */
+
+- (EOQualifier *)qualifierWithBindings:(NSDictionary *)_bindings
+  requiresAllVariables:(BOOL)_reqAll
+{
+  EOQualifier *nq;
+
+  nq = [self->qualifier qualifierWithBindings:_bindings
+                        requiresAllVariables:_reqAll];
+  if (nq == nil)
+    return self;
+
+  if (nq == self->qualifier)
+    return self;
+  
+  return [[[[self class] alloc] initWithQualifier:nq] autorelease];
+}
+
+- (NSArray *)bindingKeys {
+  return [self->qualifier bindingKeys];
+}
+
+/* keys */
+
+- (void)addQualifierKeysToSet:(NSMutableSet *)_keys {
+  /* new in WO 4.5 */
+  [self->qualifier addQualifierKeysToSet:_keys];
+}
+
+/* evaluation */
+
+- (BOOL)evaluateWithObject:(id)_object inEvalContext:(id)_ctx {
+  return
+    [self->qualifier evaluateWithObject:_object inEvalContext:_ctx]
+    ? NO : YES;
+}
+- (BOOL)evaluateWithObject:(id)_object {
+  return [self evaluateWithObject:_object inEvalContext:nil];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->qualifier];
+}
+
+- (id)initWithCoder:(NSCoder *)_coder {
+  self->qualifier = [[_coder decodeObject] retain];
+  return self;
+}
+
+/* Comparing */
+
+- (BOOL)isEqualToQualifier:(EOQualifier *)_qual {
+  return [self->qualifier isEqual:[(EONotQualifier *)_qual qualifier]];
+}
+
+/* remapping keys */
+
+- (EOQualifier *)qualifierByApplyingTransformer:(id)_transformer
+  inContext:(id)_ctx
+{
+  if ([_transformer respondsToSelector:
+                      @selector(transformNotQualifier:inContext:)]) {
+    return [_transformer transformNotQualifier:self inContext:_ctx];
+  }
+  else {
+    EONotQualifier *nq;
+    EOQualifier *q;
+    
+    q = [self->qualifier
+             qualifierByApplyingTransformer:_transformer inContext:_ctx];
+    nq = [[EONotQualifier alloc] initWithQualifier:(q ? q : self->qualifier)];
+    return [nq autorelease];
+  }
+}
+
+- (EOQualifier *)qualifierByApplyingKeyMap:(NSDictionary *)_map {
+  EONotQualifier *nq;
+  EOQualifier *q;
+  
+  q = [self->qualifier qualifierByApplyingKeyMap:_map];
+  nq = [[EONotQualifier alloc] initWithQualifier:(q ? q : self->qualifier)];
+  return [nq autorelease];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSString *qd;
+  
+  qd = [self->qualifier qualifierDescription];
+  
+  return [[@"NOT (" stringByAppendingString:qd] stringByAppendingString:@")"];
+}
+
+@end /* EONotQualifier */
diff --git a/skyrix-core/EOControl/EONull.h b/skyrix-core/EOControl/EONull.h
new file mode 100644 (file)
index 0000000..731e42a
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_EONull_h__
+#define __EOControl_EONull_h__
+
+#import <Foundation/Foundation.h>
+
+#ifndef HAVE_NSNull
+#  define HAVE_NSNull 1
+#endif
+
+#if HAVE_NSNull
+
+#import <Foundation/NSNull.h>
+
+#define EONull NSNull
+
+#else /* !HAVE_NSNull | NeXT Foundation */
+
+#import <Foundation/NSObject.h>
+
+@interface EONull : NSObject <NSCopying>
+
++ (id)null;
+
+@end /* EONull */
+
+#endif /* !HAVE_NSNull */
+
+#endif /* __EOControl_EONull_h__ */
diff --git a/skyrix-core/EOControl/EONull.m b/skyrix-core/EOControl/EONull.m
new file mode 100644 (file)
index 0000000..fae0284
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EONull.h"
+#include "common.h"
+
+#ifdef EONull
+#  undef EONull
+#endif
+
+@interface EONull : NSNull
+@end
+
+@implementation EONull
+
++ (id)allocWithZone:(NSZone *)_zone {
+  return [NSNull allocWithZone:_zone];
+}
+
++ (id)null {
+  return [NSNull null];
+}
+
+- (id)self {
+  return [NSNull null];
+}
+
+@end
+
+@implementation NSNull(ExprValue)
+
+- (BOOL)boolValue {
+  return NO;
+}
+
+- (NSString *)expressionValueForContext:(id)context {
+  /* context is really EOExpressionArray .. */
+  return @"NULL";
+}
+
+@end /* EONull(ExprValue) */
diff --git a/skyrix-core/EOControl/EOObserver.h b/skyrix-core/EOControl/EOObserver.h
new file mode 100644 (file)
index 0000000..ae158bf
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __EOControl_EOObserver_H__
+#define __EOControl_EOObserver_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSArray;
+
+@protocol EOObserving < NSObject >
+
+- (void)objectWillChange:(id)_object;
+
+@end
+
+@interface NSObject(EOObserver)
+
+- (void)willChange;
+
+@end
+
+/*
+  Note that -addObserver/-removeObserver methods do *not* nest !
+  Suppression methods do nest.
+*/
+
+@interface EOObserverCenter : NSObject
+
++ (void)notifyObserversObjectWillChange:(id)_object;
+
++ (void)addObserver:(id<EOObserving>)_observer forObject:(id)_object;
++ (void)removeObserver:(id<EOObserving>)_observer forObject:(id)_object;
++ (void)addOmniscientObserver:(id<EOObserving>)_observer;
++ (void)removeOmniscientObserver:(id<EOObserving>)_observer;
+
++ (NSArray *)observersForObject:(id)_object;
++ (id)observerForObject:(id)_object ofClass:(Class)_targetClass;
+
+/* suppressing notifications */
+
++ (void)suppressObserverNotification;
++ (void)enableObserverNotification;
++ (unsigned)observerNotificationSuppressCount;
+
+@end
+
+/* asynchronous observing */
+
+typedef enum {
+  EOObserverPriorityImmediate,
+  EOObserverPriorityFirst,
+  EOObserverPrioritySecond,
+  EOObserverPriorityThird,
+  EOObserverPriorityFourth,
+  EOObserverPriorityFifth,
+  EOObserverPrioritySixth,
+  EOObserverPriorityLater
+} EOObserverPriority;
+
+@class EODelayedObserver;
+
+@interface EODelayedObserverQueue : NSObject
+{
+@protected
+  EODelayedObserver *queues[8];
+  NSArray           *runLoopModes;
+  BOOL              hasObservers;
+}
+
++ (EODelayedObserverQueue *)defaultObserverQueue;
+
+/* accessors */
+
+- (void)setRunLoopModes:(NSArray *)_modes;
+- (NSArray *)runLoopModes;
+
+/* managing queue */
+
+- (void)enqueueObserver:(EODelayedObserver *)_observer;
+- (void)dequeueObserver:(EODelayedObserver *)_observer;
+
+/* notification */
+
+- (void)notifyObserversUpToPriority:(EOObserverPriority)_lastPriority;
+
+@end
+
+@interface EODelayedObserver : NSObject < EOObserving >
+{
+@public
+  EODelayedObserver *next; /* for access by queue */
+}
+
+/* accessors */
+
+- (EOObserverPriority)priority;
+- (EODelayedObserverQueue *)observerQueue;
+
+/* notifications */
+
+- (void)subjectChanged;
+- (void)discardPendingNotification;
+
+@end
+
+@interface EOObserverProxy : EODelayedObserver
+{
+@protected
+  EOObserverPriority priority;
+  id  target;
+  SEL action;
+}
+
+- (id)initWithTarget:(id)_target action:(SEL)_action
+  priority:(EOObserverPriority)_priority;
+
+@end
+
+#endif /* __EOControl_EOObserver_H__ */
diff --git a/skyrix-core/EOControl/EOObserver.m b/skyrix-core/EOControl/EOObserver.m
new file mode 100644 (file)
index 0000000..b74769f
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "EOObserver.h"
+#include "common.h"
+
+// THREAD, MT
+
+typedef struct _EOObserverList {
+  struct _EOObserverList *next;
+  id<EOObserving>        observer;
+  void                   (*notify)(id, SEL, id);
+} EOObserverList;
+
+static void     mapValRetain(NSMapTable *self, const void *_value);
+static void     mapValRelease(NSMapTable *self, void *_value);
+static NSString *mapDescribe(NSMapTable *self, const void *_value);
+
+const NSMapTableValueCallBacks EOObserverListMapValueCallBacks = {
+  (void (*)(NSMapTable *, const void *))mapValRetain,
+  (void (*)(NSMapTable *, void *))mapValRelease,
+  (NSString *(*)(NSMapTable *, const void *))mapDescribe
+};
+
+@implementation NSObject(EOObserver)
+
+- (void)willChange {
+  static Class EOObserverCenterClass = Nil;
+  if (EOObserverCenterClass == Nil)
+    EOObserverCenterClass = [EOObserverCenter class];
+
+  [EOObserverCenterClass notifyObserversObjectWillChange:self];
+}
+
+@end /* NSObject(EOObserver) */
+
+@implementation EOObserverCenter
+
+static unsigned       observerNotificationSuppressCount = 0;
+static EOObserverList *omniscientObservers = NULL;
+static NSMapTable     *objectToObservers   = NULL;
+
++ (void)initialize {
+  if (objectToObservers == NULL) {
+    objectToObservers = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
+                                         EOObserverListMapValueCallBacks,
+                                         256);
+  }
+}
+
++ (void)notifyObserversObjectWillChange:(id)_object {
+  static id lastObject = nil;
+  register EOObserverList *l;
+
+  /* check if notifications are suppressed */
+  if (observerNotificationSuppressCount > 0)
+    return;
+  
+  /* compress notifications for the same object */
+  if (_object == lastObject)
+    return;
+
+  /* notify usual observers */
+
+  for (l = NSMapGet(objectToObservers, _object); l != NULL; l = l->next) {
+    if (l->notify)
+      l->notify(l->observer, @selector(objectWillChange:), _object);
+    else
+      [l->observer objectWillChange:_object];
+  }
+  
+  /* notify omniscient observers */
+  
+  for (l = omniscientObservers; l != NULL; l = l->next) {
+    if (l->notify)
+      l->notify(l->observer, @selector(objectWillChange:), _object);
+    else
+      [l->observer objectWillChange:_object];
+  }
+}
+
++ (void)addObserver:(id<EOObserving>)_observer forObject:(id)_object {
+  register EOObserverList *l, *nl;
+  
+  if ((l = NSMapGet(objectToObservers, _object))) {
+    /* check whether the observer is already registered */
+    
+    for (nl = l; nl != NULL; nl = nl->next) {
+      if (nl->observer == _object)
+        return;
+    }
+  }
+
+#if NeXT_RUNTIME
+  nl = malloc(sizeof(EOObserverList));
+#else  
+  nl = objc_malloc(sizeof(EOObserverList));
+#endif
+  nl->observer = [_observer retain];
+  nl->notify   = (void*)
+    [(id)_observer methodForSelector:@selector(objectWillChange:)];
+
+  if (l == NULL) {
+    /* this is the first observer defined */
+    nl->next = NULL;
+    NSMapInsert(objectToObservers, _object, nl);
+  }
+  else {
+    /*
+      insert at second position (so that we don't need to remove/add the new
+      entry in table or traverse the list to the end)
+    */
+    nl->next = l->next;
+    l->next = nl;
+  }
+}
+
++ (void)removeObserver:(id<EOObserving>)_observer forObject:(id)_object {
+  register EOObserverList *l, *ll, *first;
+
+  if ((first = NSMapGet(objectToObservers, _object)) == NULL)
+    /* no observers registered for object */
+    return;
+
+  l  = first;
+  ll = NULL;
+  while (l) {
+    if (l->observer == _observer) {
+      /* found matching list entry */
+      if (l != first) {
+        /* entry is not the first entry */
+        ll->next = l->next;
+        [l->observer release];
+#if NeXT_RUNTIME
+        free(l);
+#else    
+        objc_free(l);
+#endif
+        break;
+      }
+      else if (l->next) {
+        /*
+          entry is the first entry, but there are more than one entries.
+          In this case we copy the second to the first and remove the second,
+          this way we save removing/inserting in the hash table.
+        */
+        [l->observer release];
+        ll = l->next;
+        l->observer = ll->observer;
+        l->notify   = ll->notify;
+        l->next     = ll->next;
+#if NeXT_RUNTIME
+        free(ll);
+#else    
+        objc_free(ll);
+#endif
+        break;
+      }
+      else {
+        /* entry is the lone entry */
+        NSMapRemove(objectToObservers, _object);
+        [l->observer release];
+#if NeXT_RUNTIME
+        free(l);
+#else    
+        objc_free(l);
+#endif
+        break;
+      }
+    }
+    
+    ll = l;
+    l = ll->next;
+  }
+}
+
++ (NSArray *)observersForObject:(id)_object {
+  EOObserverList *observers;
+  NSMutableArray *result;
+  
+  if ((observers = NSMapGet(objectToObservers, _object)) == NULL)
+    return [NSArray array];
+  
+  result = [NSMutableArray arrayWithCapacity:16];
+  while ((observers)) {
+    if (observers->observer)
+      [result addObject:observers->observer];
+    observers = observers->next;
+  }
+  
+  return [[result copy] autorelease];
+}
+
++ (id)observerForObject:(id)_object ofClass:(Class)_targetClass {
+  register EOObserverList *observers;
+  
+  if ((observers = NSMapGet(objectToObservers, _object)) == NULL)
+    return nil;
+
+  while ((observers)) {
+    if ([observers->observer class] == _targetClass)
+      return observers->observer;
+    observers = observers->next;
+  }
+  return nil;
+}
+
++ (void)addOmniscientObserver:(id<EOObserving>)_observer {
+  EOObserverList *l;
+  
+  /* first check whether we already added this observer to the list */
+  
+  for (l = omniscientObservers; l != NULL; l = l->next) {
+    if (l->observer == _observer)
+      return;
+  }
+
+#if NeXT_RUNTIME
+  l = malloc(sizeof(EOObserverList));
+#else  
+  l = objc_malloc(sizeof(EOObserverList));
+#endif
+  l->next     = omniscientObservers;
+  l->observer = [_observer retain];
+  l->notify   = (void*)[(id)_observer methodForSelector:@selector(willChange:)];
+
+  omniscientObservers = l;
+}
++ (void)removeOmniscientObserver:(id<EOObserving>)_observer {
+  EOObserverList *l, *ll;
+  
+  /* first check whether we already added this observer to the list */
+  
+  for (l = omniscientObservers, ll = NULL; l != NULL; ) {
+    if (l->observer == _observer) {
+      /* matched */
+      if (ll == NULL)
+        omniscientObservers = l->next;
+      else
+        ll->next = l->next;
+
+      [l->observer release];
+      objc_free(l);
+      return;
+    }
+
+    ll = l;
+    l = ll->next;
+  }
+}
+
+/* suppressing notifications */
+
++ (void)suppressObserverNotification {
+  observerNotificationSuppressCount++;
+}
++ (void)enableObserverNotification {
+  observerNotificationSuppressCount--;
+}
+
++ (unsigned)observerNotificationSuppressCount {
+  return observerNotificationSuppressCount;
+}
+
+@end /* EOObserverCenter */
+
+@implementation EODelayedObserverQueue
+
+static EODelayedObserverQueue *defaultQueue = nil;
+
++ (EODelayedObserverQueue *)defaultObserverQueue {
+  if (defaultQueue == nil)
+    defaultQueue = [[EODelayedObserverQueue alloc] init];
+  return defaultQueue;
+}
+
+- (id)init {
+  [[NSNotificationCenter defaultCenter]
+                         addObserver:self selector:@selector(_notify:)
+                         name:@"EODelayedNotify" object:self];
+  return self;
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [self->runLoopModes release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setRunLoopModes:(NSArray *)_modes {
+  ASSIGN(self->runLoopModes, _modes);
+}
+- (NSArray *)runLoopModes {
+  return self->runLoopModes;
+}
+
+/* single queue */
+
+static inline void _enqueue(EODelayedObserverQueue *self,
+                            EODelayedObserver **list,
+                            EODelayedObserver *newEntry)
+{
+  if (*list == nil) {
+    /* first entry in this list */
+    *list = [newEntry retain];
+  }
+  else {
+    EODelayedObserver *e, *le;
+
+    for (e = *list, le = NULL; e != NULL; e = e->next) {
+      if (e == newEntry) {
+        /* already in queue */
+        return;
+      }
+      le = e;
+    }
+    le->next = [e retain];
+    e->next  = NULL;
+  }
+}
+static inline void _dequeue(EODelayedObserverQueue *self,
+                            EODelayedObserver **list,
+                            EODelayedObserver *entry)
+{
+  EODelayedObserver *e, *le;
+
+  for (e = *list, le = NULL; e != NULL; e = e->next) {
+    if (e == entry) {
+      /* found entry */
+      le->next = e->next;
+      [e release];
+      return;
+    }
+    le = e;
+  }
+}
+
+static inline void _notify(EODelayedObserverQueue *self, EODelayedObserver *list)
+{
+  while (list) {
+    [list subjectChanged];
+    list = list->next;
+  }
+}
+
+/* managing queue */
+
+- (void)enqueueObserver:(EODelayedObserver *)_observer {
+  if (_observer == nil) return;
+  
+  _enqueue(self, &(self->queues[[_observer priority]]), _observer);
+
+  if (!self->hasObservers) {
+    /* register for ASAP notification */
+    NSNotification *notification;
+    
+    notification = [NSNotification notificationWithName:@"EODelayedNotify"
+                                   object:self];
+    
+    [[NSNotificationQueue defaultQueue]
+                          enqueueNotification:notification
+                          postingStyle:NSPostASAP
+                          coalesceMask:NSNotificationCoalescingOnSender
+                          forModes:[self runLoopModes]];
+    
+    self->hasObservers = YES;
+  }
+}
+- (void)dequeueObserver:(EODelayedObserver *)_observer {
+  if (_observer == nil) return;
+  
+  _dequeue(self, &(self->queues[[_observer priority]]), _observer);
+}
+
+/* notification */
+
+- (void)notifyObserversUpToPriority:(EOObserverPriority)_lastPriority {
+  unsigned i;
+  
+  for (i = 0; i < _lastPriority; i++)
+    _notify(self, self->queues[i]);
+}
+
+- (void)_notify:(NSNotification *)_notification {
+  [self notifyObserversUpToPriority:EOObserverPrioritySixth];
+}
+
+@end /* EODelayedObserverQueue */
+
+@implementation EODelayedObserver
+
+/* accessors */
+
+- (EOObserverPriority)priority {
+  return EOObserverPriorityThird;
+}
+
+- (EODelayedObserverQueue *)observerQueue {
+  return [EODelayedObserverQueue defaultObserverQueue];
+}
+
+/* notifications */
+
+- (void)subjectChanged {
+  [self doesNotRecognizeSelector:_cmd];
+}
+
+- (void)objectWillChange:(id)_object {
+  [[self observerQueue] enqueueObserver:self];
+}
+
+- (void)discardPendingNotification {
+  [[self observerQueue] dequeueObserver:self];
+}
+
+@end /* EODelayedObserver */
+
+@implementation EOObserverProxy
+
+- (id)initWithTarget:(id)_target action:(SEL)_action
+  priority:(EOObserverPriority)_priority
+{
+  if ((self = [super init])) {
+    self->target   = [_target retain];
+    self->action   = _action;
+    self->priority = _priority;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithTarget:nil action:NULL priority:EOObserverPriorityThird];
+}
+
+- (void)dealloc {
+  [self->target release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (EOObserverPriority)priority {
+  return self->priority;
+}
+
+/* notifications */
+
+- (void)subjectChanged {
+  [self->target performSelector:self->action withObject:self];
+}
+
+@end /* EOObserverProxy */
+
+/* value functions for mapping table */
+
+static void mapValRetain(NSMapTable *self, const void *_value) {
+  /* do nothing */
+}
+static void mapValRelease(NSMapTable *self, void *_value) {
+  /* do nothing */
+}
+
+static NSString *mapDescribe(NSMapTable *self, const void *_value) {
+  return @"";
+}
diff --git a/skyrix-core/EOControl/EOOrQualifier.m b/skyrix-core/EOControl/EOOrQualifier.m
new file mode 100644 (file)
index 0000000..89e5117
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EOQualifier.h>
+#include "common.h"
+
+@interface EOQualifier(EvalContext)
+- (BOOL)evaluateWithObject:(id)_object inEvalContext:(id)_ctx;
+@end
+
+@implementation EOOrQualifier
+
+//static BOOL debugEval      = NO;
+static BOOL debugTransform = NO;
+
+- (id)initWithQualifierArray:(NSArray *)_qualifiers {
+  self->count      = [_qualifiers count];
+  self->qualifiers = [_qualifiers copyWithZone:[self zone]];
+  return self;
+}
+
+- (id)initWithQualifiers:(EOQualifier *)_qual1, ... {
+  va_list va;
+  EOQualifier *q;
+  id *qs;
+  unsigned c;
+  NSArray *a;
+  
+  va_start(va, _qual1);
+  for (c = 0, q = _qual1; q != nil; q = va_arg(va, id), c++)
+    ;
+  va_end(va);
+
+  if (c == 0)
+    return [self initWithQualifierArray:nil];
+
+  qs = objc_calloc(c, sizeof(id));
+  
+  va_start(va, _qual1);
+  for (c = 0, q = _qual1; q != nil; q = va_arg(va, id), c++) {
+    qs[c] = q;
+  }
+  va_end(va);
+
+  a = [NSArray arrayWithObjects:qs count:c];
+  objc_free(qs);
+  
+  return [self initWithQualifierArray:a];
+}
+
+- (void)dealloc {
+  [self->qualifiers release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSArray *)qualifiers {
+  return self->qualifiers;
+}
+- (NSArray *)subqualifiers {
+  return [self qualifiers];
+}
+
+/* bindings */
+
+- (EOQualifier *)qualifierWithBindings:(NSDictionary *)_bindings
+  requiresAllVariables:(BOOL)_reqAll
+{
+  NSArray  *array;
+  id       objects[self->count + 1];
+  unsigned i;
+
+  IMP objAtIdx;
+
+  objAtIdx = [self->qualifiers methodForSelector:@selector(objectAtIndex:)];
+  
+  for (i = 0; i < self->count; i++) {
+    id q, newq;
+
+    q = objAtIdx(self->qualifiers, @selector(objectAtIndex:), i);
+    newq = [q qualifierWithBindings:_bindings requiresAllVariables:_reqAll];
+    if (newq == nil) newq = q;
+    
+    objects[i] = newq;
+  }
+
+  array = [NSArray arrayWithObjects:objects count:self->count];
+  return [[[[self class] alloc] initWithQualifierArray:array] autorelease];
+}
+
+- (NSArray *)bindingKeys {
+  NSMutableSet *keys = nil;
+  unsigned i;
+  IMP objAtIdx;
+
+  objAtIdx = [self->qualifiers methodForSelector:@selector(objectAtIndex:)];
+  
+  for (i = 0; i < self->count; i++) {
+    NSArray *qb;
+    id q;
+
+    q = objAtIdx(self->qualifiers, @selector(objectAtIndex:), i);
+    qb = [q bindingKeys];
+
+    if ([qb count] > 0) {
+      if (keys == nil) keys = [NSMutableSet setWithCapacity:16];
+      [keys addObjectsFromArray:qb];
+    }
+  }
+  
+  return keys ? [keys allObjects] : [NSArray array];
+}
+
+/* keys */
+
+- (void)addQualifierKeysToSet:(NSMutableSet *)_keys {
+  /* new in WO 4.5 */
+  [self->qualifiers makeObjectsPerformSelector:_cmd withObject:_keys];
+}
+
+/* evaluation */
+
+- (BOOL)evaluateWithObject:(id)_object inEvalContext:(id)_ctx {
+  unsigned i;
+  IMP objAtIdx;
+  
+  if ((_ctx == nil) && (self->count > 1))
+    _ctx = [NSMutableDictionary dictionaryWithCapacity:16];
+  
+  objAtIdx = [self->qualifiers methodForSelector:@selector(objectAtIndex:)];
+  
+  for (i = 0; i < self->count; i++) {
+    id q;
+    
+    q = objAtIdx(self->qualifiers, @selector(objectAtIndex:), i);
+    if ([q evaluateWithObject:_object inEvalContext:_ctx])
+      return YES;
+  }
+  return NO;
+}
+- (BOOL)evaluateWithObject:(id)_object {
+  return [self evaluateWithObject:_object inEvalContext:nil];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->qualifiers];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  self->qualifiers = [[_coder decodeObject] retain];
+  return self;
+}
+
+/* Comparing */
+
+- (BOOL)isEqualToQualifier:(EOQualifier *)_qual {
+  return [self->qualifiers isEqualToArray:[(EOOrQualifier *)_qual qualifiers]];
+}
+
+/* remapping keys */
+
+- (EOQualifier *)qualifierByApplyingTransformer:(id)_transformer
+  inContext:(id)_ctx
+{
+  if ([_transformer respondsToSelector:
+                      @selector(transformOrQualifier:inContext:)]) {
+    if (debugTransform)
+      NSLog(@"transformer: %@\n  transform: %@", _transformer, self);
+    return [_transformer transformOrQualifier:self inContext:_ctx];
+  }
+  else {
+    EOOrQualifier *aq;
+    NSArray  *a;
+    id       *qs;
+    unsigned i;
+    BOOL     didTransform = NO;
+    
+    if (debugTransform) {
+      NSLog(@"EOOrQualifier: transform %i using %@ ...", 
+            self->count, _transformer);
+    }
+    
+    qs = calloc(self->count + 1, sizeof(id));
+    for (i = 0; i < self->count; i++) {
+      EOQualifier *q;
+      
+      q     = [self->qualifiers objectAtIndex:i];
+      qs[i] = [q qualifierByApplyingTransformer:_transformer inContext:_ctx];
+      if (qs[i] == nil) 
+        qs[i] = q;
+      else if (qs[i] != q) {
+        if (debugTransform)
+          NSLog(@"EOOrQualifier:   subqualifier %i did transform", i);
+        didTransform = YES;
+      }
+      else if (debugTransform)
+        NSLog(@"EOOrQualifier:   subqualifier %i did not transform", i);
+    }
+    if (didTransform) {
+      a = [[NSArray alloc] initWithObjects:qs count:self->count];
+      if (qs) free(qs);
+      aq = [[EOOrQualifier alloc] initWithQualifierArray:a];
+      [a release];
+      return [aq autorelease];
+    }
+    else {
+      if (qs) free(qs);
+      return [[self retain] autorelease];
+    }
+  }
+}
+
+- (EOQualifier *)qualifierByApplyingKeyMap:(NSDictionary *)_map {
+  EOOrQualifier *aq;
+  NSArray  *a;
+  id       *qs;
+  unsigned i;
+  
+  qs = calloc(self->count + 1, sizeof(id));
+  for (i = 0; i < self->count; i++) {
+    EOQualifier *q;
+    
+    q     = [self->qualifiers objectAtIndex:i];
+    qs[i] = [q qualifierByApplyingKeyMap:_map];
+    if (qs[i] == nil) qs[i] = q;
+  }
+  a = [[NSArray alloc] initWithObjects:qs count:self->count];
+  if (qs) free(qs);
+  aq = [[EOOrQualifier alloc] initWithQualifierArray:a];
+  [a release];
+  return [aq autorelease];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  NSArray  *sd;
+  unsigned i, len;
+  
+  sd = [self->qualifiers valueForKey:@"qualifierDescription"];
+  if ((len = [sd count]) == 0)
+    return nil;
+  if (len == 1)
+    return [sd objectAtIndex:0];
+  
+  ms = [NSMutableString stringWithCapacity:(len * 16)];
+  [ms appendString:@"("];
+  for (i = 0; i < len; i++) {
+    if (i != 0) [ms appendString:@" OR "];
+    [ms appendString:[sd objectAtIndex:i]];
+  }
+  [ms appendString:@")"];
+  return ms;
+}
+
+@end /* EOOrQualifier */
diff --git a/skyrix-core/EOControl/EOQualifier.h b/skyrix-core/EOControl/EOQualifier.h
new file mode 100644 (file)
index 0000000..f40313e
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __EOQualifier_h__
+#define __EOQualifier_h__
+
+#import <Foundation/NSObject.h> 
+
+/*
+  EOQualifier
+  
+  EOQualifier is the superclass of all the concrete qualifier classes which
+  are used to build up a qualification object hierarchy (aka a SQL where
+  statement).
+
+  Subclasses:
+    EOAndQualifier
+    EOOrQualifier
+    EONotQualifier
+    EOKeyValueQualifier
+    EOKeyComparisonQualifier
+
+  EOQualifierVariable
+
+  EOQualifierVariable defers the evaluation of some qualification value to
+  runtime. It's comparable to SQL late-binding variables (aka "a=$value").
+  
+  Also provided are some categories on NSObject and NSArray to filter an
+  in-memory object tree.
+*/
+
+@class NSDictionary, NSArray, NSSet, NSMutableSet;
+
+@protocol EOQualifierEvaluation
+- (BOOL)evaluateWithObject:(id)_object;
+@end
+
+@interface EOQualifier : NSObject
+
++ (EOQualifier *)qualifierToMatchAnyValue:(NSDictionary *)_values;
++ (EOQualifier *)qualifierToMatchAllValues:(NSDictionary *)_values;
+
++ (SEL)operatorSelectorForString:(NSString *)_str;
++ (NSString *)stringForOperatorSelector:(SEL)_sel;
+
+/* bindings */
+
+- (EOQualifier *)qualifierWithBindings:(NSDictionary *)_bindings
+  requiresAllVariables:(BOOL)_reqAll;
+- (NSArray *)bindingKeys;
+
+/* keys (new in WO 4.5) */
+
+- (NSSet *)allQualifierKeys;
+- (void)addQualifierKeysToSet:(NSMutableSet *)_keys;
+
+/* comparing */
+
+- (BOOL)isEqual:(id)_obj;
+- (BOOL)isEqualToQualifier:(EOQualifier *)_qual;
+
+/* remapping keys */
+
+- (EOQualifier *)qualifierByApplyingTransformer:(id)_t inContext:(id)_ctx;
+- (EOQualifier *)qualifierByApplyingKeyMap:(NSDictionary *)_map;
+
+/* BDControl additions */
+
+- (unsigned int)count;
+- (NSArray *)subqualifiers;
+
+/* debugging */
+
++ (BOOL)isEvaluationDebuggingEnabled;
+
+@end /* EOQualifier */
+
+@interface EOQualifier(Parsing)
+
++ (EOQualifier *)qualifierWithQualifierFormat:(NSString *)_qualifierFormat, ...;
++ (EOQualifier *)qualifierWithQualifierFormat:(NSString *)_qualifierFormat 
+  arguments:(NSArray *)_arguments;
+
+/* this is used in "cast (xxx as mytypename)" expressions */
++ (void)registerValueClass:(Class)_valueClass forTypeName:(NSString *)_type;
+
+@end
+
+@interface EOAndQualifier : EOQualifier < EOQualifierEvaluation, NSCoding >
+{
+  NSArray  *qualifiers;
+  unsigned count;
+}
+
+- (id)initWithQualifierArray:(NSArray *)_qualifiers;
+- (id)initWithQualifiers:(EOQualifier *)_qual1, ...;
+- (NSArray *)qualifiers;
+
+@end /* EOAndQualifier */
+
+@interface EOOrQualifier : EOQualifier < EOQualifierEvaluation, NSCoding >
+{
+  NSArray  *qualifiers;
+  unsigned count;
+}
+
+- (id)initWithQualifierArray:(NSArray *)_qualifiers; /* designated init */
+- (id)initWithQualifiers:(EOQualifier *)_qual1, ...;
+- (NSArray *)qualifiers;
+
+@end /* EOOrQualifier */
+
+@interface EONotQualifier : EOQualifier < EOQualifierEvaluation, NSCoding >
+{
+  EOQualifier *qualifier;
+}
+
+- (id)initWithQualifier:(EOQualifier *)_qualifier; /* designated init */
+- (EOQualifier *)qualifier;
+
+@end /* EONotQualifier */
+
+extern SEL EOQualifierOperatorEqual;
+extern SEL EOQualifierOperatorNotEqual;
+extern SEL EOQualifierOperatorLessThan;
+extern SEL EOQualifierOperatorGreaterThan;
+extern SEL EOQualifierOperatorLessThanOrEqualTo;
+extern SEL EOQualifierOperatorGreaterThanOrEqualTo;
+extern SEL EOQualifierOperatorContains;
+extern SEL EOQualifierOperatorLike;
+extern SEL EOQualifierOperatorCaseInsensitiveLike;
+
+@interface EOKeyValueQualifier : EOQualifier < EOQualifierEvaluation, NSCoding >
+{
+  /* this is a '%A selector %@' qualifier */
+  NSString *key;
+  id       value;
+  SEL      operator;
+}
+
+- (id)initWithKey:(NSString *)_key
+  operatorSelector:(SEL)_selector
+  value:(id)_value;
+
+- (NSString *)key;
+- (SEL)selector;
+- (id)value;
+
+@end
+
+@interface EOKeyComparisonQualifier : EOQualifier
+  < EOQualifierEvaluation, NSCoding >
+{
+  /* this is a '%A selector %A' qualifier */
+  NSString *leftKey;
+  NSString *rightKey;
+  SEL      operator;
+}
+
+- (id)initWithLeftKey:(NSString *)_leftKey
+  operatorSelector:(SEL)_selector
+  rightKey:(NSString *)_rightKey;
+
+- (NSString *)leftKey;
+- (NSString *)rightKey;
+- (SEL)selector;
+
+@end
+
+/* operators */
+
+#define EOQualifierOperatorEqual                @selector(isEqualTo:)
+#define EOQualifierOperatorNotEqual             @selector(isNotEqualTo:)
+#define EOQualifierOperatorLessThan             @selector(isLessThan:)
+#define EOQualifierOperatorGreaterThan          @selector(isGreaterThan:)
+#define EOQualifierOperatorLessThanOrEqualTo    @selector(isLessThanOrEqualTo:)
+#define EOQualifierOperatorGreaterThanOrEqualTo @selector(isGreaterThanOrEqualTo:)
+#define EOQualifierOperatorContains             @selector(doesContain:)
+#define EOQualifierOperatorLike                 @selector(isLike:)
+#define EOQualifierOperatorCaseInsensitiveLike  @selector(isCaseInsensitiveLike:)
+
+/* variable qualifier content */
+
+@interface EOQualifierVariable : NSObject < NSCoding >
+{
+  NSString *varKey;
+}
+
++ (id)variableWithKey:(NSString *)_key;
+- (id)initWithKey:(NSString *)_key;
+
+- (NSString *)key;
+
+/* Comparing */
+
+- (BOOL)isEqual:(id)_obj;
+- (BOOL)isEqualToQualifierVariable:(EOQualifierVariable *)_obj;
+
+@end
+
+/* define the appropriate selectors */
+
+@interface NSObject(QualifierComparisions)
+- (BOOL)isEqualTo:(id)_object;
+- (BOOL)isNotEqualTo:(id)_object;
+- (BOOL)isLessThan:(id)_object;
+- (BOOL)isGreaterThan:(id)_object;
+- (BOOL)isLessThanOrEqualTo:(id)_object;
+- (BOOL)isGreaterThanOrEqualTo:(id)_object;
+- (BOOL)doesContain:(id)_object;
+- (BOOL)isLike:(id)_object;
+- (BOOL)isCaseInsensitiveLike:(id)_object;
+@end
+
+@interface NSObject(EOQualifierTransformer)
+
+- (EOQualifier *)transformQualifier:(EOQualifier *)_q       inContext:(id)_ctx;
+- (EOQualifier *)transformAndQualifier:(EOAndQualifier *)_q inContext:(id)_ctx;
+- (EOQualifier *)transformOrQualifier:(EOOrQualifier *)_q   inContext:(id)_ctx;
+- (EOQualifier *)transformNotQualifier:(EONotQualifier *)_q inContext:(id)_ctx;
+
+- (EOQualifier *)transformKeyValueQualifier:(EOKeyValueQualifier *)_q 
+  inContext:(id)_ctx;
+- (EOQualifier *)transformKeyComparisonQualifier:(EOKeyComparisonQualifier *)q 
+  inContext:(id)_ctx;
+
+@end
+
+/* array qualification */
+
+#import <Foundation/NSArray.h>
+
+@interface NSArray(Qualification)
+- (NSArray *)filteredArrayUsingQualifier:(EOQualifier *)_qualifier;
+@end
+
+#endif /* __EOQualifier_h__ */
diff --git a/skyrix-core/EOControl/EOQualifier.m b/skyrix-core/EOControl/EOQualifier.m
new file mode 100644 (file)
index 0000000..8874bcd
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <stdio.h>
+#include "EOQualifier.h"
+#include "EOKeyValueCoding.h"
+#include "common.h"
+#include "EONull.h"
+#import <Foundation/NSException.h>
+
+@interface NSObject(QualifierDescription)
+- (NSString *)qualifierDescription;
+@end
+
+@implementation EOQualifier
+
+static NSMapTable *operatorToSelector = NULL;
+static NSMapTable *selectorToOperator = NULL;
+static EONull     *null = nil;
+
++ (void)initialize {
+  if (null == nil) null = [EONull null];
+  
+  if (operatorToSelector == NULL) {
+    operatorToSelector = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                          NSIntMapValueCallBacks,
+                                          10);
+    NSMapInsert(operatorToSelector, @"=",   EOQualifierOperatorEqual);
+    NSMapInsert(operatorToSelector, @"==",  EOQualifierOperatorEqual);
+    NSMapInsert(operatorToSelector, @"!=",  EOQualifierOperatorNotEqual);
+    NSMapInsert(operatorToSelector, @"<>",  EOQualifierOperatorNotEqual);        
+    NSMapInsert(operatorToSelector, @"<",   EOQualifierOperatorLessThan);
+    NSMapInsert(operatorToSelector, @">",   EOQualifierOperatorGreaterThan);
+    NSMapInsert(operatorToSelector, @"<=",  EOQualifierOperatorLessThanOrEqualTo);
+    NSMapInsert(operatorToSelector, @"like",EOQualifierOperatorLike);
+    NSMapInsert(operatorToSelector, @"LIKE",EOQualifierOperatorLike);
+    NSMapInsert(operatorToSelector, @">=",
+                EOQualifierOperatorGreaterThanOrEqualTo);
+    NSMapInsert(operatorToSelector, @"caseInsensitiveLike",
+                EOQualifierOperatorCaseInsensitiveLike);
+  }
+  if (selectorToOperator == NULL) {
+    selectorToOperator = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                          NSObjectMapValueCallBacks,
+                                          10);
+    NSMapInsert(selectorToOperator,
+                NSStringFromSelector(EOQualifierOperatorEqual),
+                @"=");
+    NSMapInsert(selectorToOperator,
+                NSStringFromSelector(EOQualifierOperatorNotEqual),
+                @"<>");
+    NSMapInsert(selectorToOperator,
+                NSStringFromSelector(EOQualifierOperatorLessThan),
+                @"<");
+    NSMapInsert(selectorToOperator,
+                NSStringFromSelector(EOQualifierOperatorGreaterThan),
+                @">");
+    NSMapInsert(selectorToOperator,
+                NSStringFromSelector(EOQualifierOperatorLessThanOrEqualTo),
+                @"<=");
+    NSMapInsert(selectorToOperator,
+                NSStringFromSelector(EOQualifierOperatorLike),
+                @"like");
+    NSMapInsert(selectorToOperator,
+                NSStringFromSelector(EOQualifierOperatorGreaterThanOrEqualTo),
+                @">=");
+    NSMapInsert(selectorToOperator,
+                NSStringFromSelector(EOQualifierOperatorCaseInsensitiveLike),
+                @"caseInsensitiveLike");
+  }
+}
+
++ (EOQualifier *)qualifierToMatchAnyValue:(NSDictionary *)_values {
+  /* OR qualifier */
+  NSEnumerator *keys;
+  NSString     *key;
+  NSArray      *array;
+  unsigned i;
+  id qualifiers[[_values count] + 1];
+  
+  keys = [_values keyEnumerator];
+  for (i = 0; (key = [keys nextObject]); i++) {
+    id value;
+    
+    value = [_values objectForKey:key];
+    qualifiers[i] =
+      [[EOKeyValueQualifier alloc]
+                            initWithKey:key
+                            operatorSelector:EOQualifierOperatorEqual
+                            value:value];
+    qualifiers[i] = [qualifiers[i] autorelease];
+  }
+  array = [NSArray arrayWithObjects:qualifiers count:i];
+  return [[[EOOrQualifier alloc] initWithQualifierArray:array] autorelease];
+}
+
++ (EOQualifier *)qualifierToMatchAllValues:(NSDictionary *)_values {
+  /* AND qualifier */
+  NSEnumerator *keys;
+  NSString     *key;
+  NSArray      *array;
+  unsigned i;
+  id qualifiers[[_values count] + 1];
+  
+  keys = [_values keyEnumerator];
+  for (i = 0; (key = [keys nextObject]); i++) {
+    id value;
+    
+    value = [_values objectForKey:key];
+    qualifiers[i] =
+      [[EOKeyValueQualifier alloc]
+                            initWithKey:key
+                            operatorSelector:EOQualifierOperatorEqual
+                            value:value];
+    qualifiers[i] = [qualifiers[i] autorelease];
+  }
+  array = [NSArray arrayWithObjects:qualifiers count:i];
+  return [[[EOAndQualifier alloc] initWithQualifierArray:array] autorelease];
+}
+
++ (SEL)operatorSelectorForString:(NSString *)_str {
+  SEL s;
+
+  if ((s = NSMapGet(operatorToSelector, _str)))
+    return s;
+  else
+    return NSSelectorFromString(_str);
+}
+
++ (NSString *)stringForOperatorSelector:(SEL)_sel {
+  NSString *s, *ss;
+  
+  if ((s = NSStringFromSelector(_sel)) == nil)
+    return nil;
+  
+  if ((ss = NSMapGet(selectorToOperator, s)))
+    return ss;
+  
+  return s;
+}
+
+/* bindings */
+
+- (EOQualifier *)qualifierWithBindings:(NSDictionary *)_bindings
+  requiresAllVariables:(BOOL)_reqAll
+{
+  return self;
+}
+
+- (NSArray *)bindingKeys {
+  return nil;
+}
+
+- (BOOL)requiresAllQualifierBindingVariables {
+  return YES;
+}
+
+/* keys */
+
+- (NSSet *)allQualifierKeys {
+  /* new in WO 4.5 */
+  id set;
+
+  set = [NSMutableSet setWithCapacity:64];
+  [self addQualifierKeysToSet:set];
+  return [[set copy] autorelease];
+}
+
+- (void)addQualifierKeysToSet:(NSMutableSet *)_keys {
+  /* new in WO 4.5 */
+}
+
+/* Comparing */
+
+- (BOOL)isEqual:(id)_obj {
+  if ([_obj isKindOfClass:[self class]])
+    return [self isEqualToQualifier:(EOQualifier *)_obj];
+  
+  return NO;
+}
+
+- (BOOL)isEqualToQualifier:(EOQualifier *)_qual {
+  [self doesNotRecognizeSelector:_cmd];
+  return NO;
+}
+
+/* remapping keys */
+
+- (EOQualifier *)qualifierByApplyingTransformer:(id)_t inContext:(id)_ctx {
+  if ([_t respondsToSelector:@selector(transformQualifier:inContext:)])
+    return [_t transformQualifier:self inContext:_ctx];
+  else
+    return [[self retain] autorelease];
+}
+- (EOQualifier *)qualifierByApplyingKeyMap:(NSDictionary *)_key {
+  return [[self copy] autorelease];
+}
+
+/* GDL2 compatibility */
+
+- (EOQualifier *)qualifierByApplyingBindings:(NSDictionary *)_bindings {
+  return [self qualifierWithBindings:_bindings 
+              requiresAllVariables:
+                [self requiresAllQualifierBindingVariables]];
+}
+
+/* BDControl additions */
+
+- (unsigned int)count {
+  return [[self subqualifiers] count];
+}
+- (NSArray *)subqualifiers {
+  return nil;
+}
+
+/* debugging */
+
++ (BOOL)isEvaluationDebuggingEnabled {
+  static int evalDebug = -1;
+  if (evalDebug == -1) {
+    evalDebug = [[NSUserDefaults standardUserDefaults] 
+                  boolForKey:@"EOQualifierDebugEvaluation"] ? 1 : 0;
+    if (evalDebug)
+      NSLog(@"WARNING: qualifier evaluation debugging is enabled !");
+  }
+  return evalDebug ? YES : NO;
+}
+
+@end /* EOQualifier */
+
+@implementation EOQualifier(QuickEval)
+
+- (BOOL)evaluateWithObject:(id)_object inEvalContext:(id)_ctx {
+  return [(id<EOQualifierEvaluation>)self evaluateWithObject:_object];
+}
+
+@end /* EOQualifier(QuickEval) */
diff --git a/skyrix-core/EOControl/EOQualifierParser.m b/skyrix-core/EOControl/EOQualifierParser.m
new file mode 100644 (file)
index 0000000..25a84aa
--- /dev/null
@@ -0,0 +1,1221 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <stdio.h>
+#include "EOQualifier.h"
+#include "EONull.h"
+#include "common.h"
+
+//#define USE_DESCRIPTION_FOR_AT 1
+
+static int qDebug = 0;
+static NSMutableDictionary *EOQualifierParserTypeMappings = nil;
+
+/* 
+   The literals understood by the value parser.
+   
+   NOTE: Any literal used here can never be used as a key ! So add as little
+   as possible.
+*/
+typedef struct {
+  const unsigned char *token;
+  id  value;
+  int scase;
+} EOQPTokEntry;
+
+static EOQPTokEntry toks[] = {
+  { "NULL",  nil, 0 },
+  { "nil",   nil, 1 },
+  { "YES",   nil, 0 },
+  { "NO",    nil, 0 },
+  { "TRUE",  nil, 0 },
+  { "FALSE", nil, 0 },
+  { NULL,    nil, 0 }
+};
+
+static inline void _setupLiterals(void) {
+  static BOOL didSetup = NO;
+  if (didSetup) return;
+  didSetup = YES;
+  toks[0].value = [[NSNull null] retain];
+  toks[1].value = toks[0].value;
+  toks[2].value = [[NSNumber numberWithBool:YES] retain];
+  toks[3].value = [[NSNumber numberWithBool:NO]  retain];
+  toks[4].value = toks[2].value;
+  toks[5].value = toks[3].value;
+}
+
+/* cache */
+static Class  StringClass = Nil;
+static Class  NumberClass = Nil;
+static EONull *null       = nil;
+
+/* parsing functions */
+
+static EOQualifier *_parseCompoundQualifier(id _ctx, const char *_buf,
+                                            unsigned _bufLen, unsigned *_qualLen);
+static EOQualifier *_testOperator(id _ctx, const char *_buf,
+                                  unsigned _bufLen, unsigned *_opLen,
+                                  BOOL *_testAnd);
+static EOQualifier *_parseQualifiers(id _ctx, const char *_buf,
+                                     unsigned _bufLen, unsigned *_qualLen);
+static EOQualifier *_parseParenthesisQualifier(id _ctx,
+                                               const char *_buf, unsigned _bufLen,
+                                               unsigned *_qualLen);
+static EOQualifier *_parseNotQualifier(id _ctx, const char *_buf,
+                                       unsigned _bufLen, unsigned *_qualLen);
+static EOQualifier *_parseKeyCompQualifier(id _ctx, const char *_buf,
+                                           unsigned _bufLen, unsigned *_qualLen);
+static NSString *_parseKey(id _ctx, const char *_buf, unsigned _bufLen,
+                           unsigned *_keyLen);
+static id _parseValue(id _ctx, const char *_buf, unsigned _bufLen,
+                      unsigned *_keyLen);
+static inline unsigned _countWhiteSpaces(const char *_buf, unsigned _bufLen);
+static NSString *_parseOp(const char *_buf, unsigned _bufLen,
+                          unsigned *_opLen);
+
+@interface EOQualifierParserContext : NSObject
+{
+  NSMapTable *qualifierCache;
+}
+- (NSDictionary *)resultForFunction:(NSString *)_fct atPos:(unsigned)_pos;
+- (void)setResult:(NSDictionary *)_dict forFunction:(NSString *)_fct
+            atPos:(unsigned)_pos;
+- (id)getObjectFromStackFor:(char)_c;
+
+/* factory */
+
+- (EOQualifier *)keyComparisonQualifierWithLeftKey:(NSString *)_leftKey
+  operatorSelector:(SEL)_sel
+  rightKey:(NSString *)_rightKey;
+- (EOQualifier *)keyValueQualifierWithKey:(NSString *)_key
+  operatorSelector:(SEL)_sel
+  value:(id)_value;
+- (EOQualifier *)andQualifierWithArray:(NSArray *)_qualifiers;
+- (EOQualifier *)orQualifierWithArray:(NSArray *)_qualifiers;
+- (EOQualifier *)notQualifierWithQualifier:(EOQualifier *)_qualifier;
+
+@end
+
+@interface EOQualifierVAParserContext : EOQualifierParserContext
+{
+  va_list    *va;  
+}
++ (id)contextWithVaList:(va_list *)_va;
+- (id)initWithVaList:(va_list *)_va;
+@end
+
+@interface EOQualifierEnumeratorParserContext : EOQualifierParserContext
+{
+  NSEnumerator *enumerator;
+}
++ (id)contextWithEnumerator:(NSEnumerator *)_enumerator;
+- (id)initWithEnumerator:(NSEnumerator  *)_enumerator;
+@end
+
+@implementation EOQualifierVAParserContext
+
++ (id)contextWithVaList:(va_list *)_va {
+  return [[[EOQualifierVAParserContext alloc] initWithVaList:_va] autorelease];
+}
+
+- (id)initWithVaList:(va_list *)_va {
+  if ((self = [super init])) {
+    self->va = _va;
+  }
+  return self;
+}
+
+- (id)getObjectFromStackFor:(char)_c {
+  id obj = nil;
+
+  if (StringClass == Nil) StringClass = [NSString class];
+  if (NumberClass == Nil) NumberClass = [NSNumber class];
+  if (null == nil)        null        = [EONull null];
+  
+  if (_c == 's') {
+    char *str = va_arg(*self->va, char*);
+    obj = [StringClass stringWithCString:str];
+  }
+  else if (_c == 'd') {
+    int i= va_arg(*self->va, int);
+    obj = [NumberClass numberWithInt:i];
+  }
+  else if (_c == 'f') {
+    double d = va_arg(*self->va, double);
+    obj = [NumberClass numberWithDouble:d];
+  }
+  else if (_c == '@') {
+    id o = va_arg(*self->va, id);
+#if USE_DESCRIPTION_FOR_AT
+    obj = (o == nil) ? (id)null : (id)[o description];
+#else
+    obj = (o == nil) ? (id)null : (id)o;
+#endif
+  }
+  else {
+    [NSException raise:@"NSInvalidArgumentException"
+                 format:@"unknown conversation char %c", _c];
+  }
+  return obj;
+}
+
+@end /* EOQualifierVAParserContext */
+
+@implementation EOQualifierEnumeratorParserContext
+
++ (id)contextWithEnumerator:(NSEnumerator *)_enumerator {
+  return [[[EOQualifierEnumeratorParserContext alloc]
+                                      initWithEnumerator:_enumerator] autorelease];
+}
+
+- (id)initWithEnumerator:(NSEnumerator *)_enumerator {
+  if ((self = [super init])) {
+    ASSIGN(self->enumerator, _enumerator);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->enumerator release];
+  [super dealloc];;
+}
+
+- (id)getObjectFromStackFor:(char)_c {
+  static Class NumberClass = Nil;
+  id o;
+
+  if (NumberClass == Nil) NumberClass = [NSNumber class];
+
+  o = [self->enumerator nextObject];
+  switch (_c) {
+    case '@':
+#if USE_DESCRIPTION_FOR_AT
+      return [o description];
+#else
+      return o;
+#endif
+    
+    case 'f':
+      return [NumberClass numberWithDouble:[o doubleValue]];
+      
+    case 'd':
+      return [NumberClass numberWithInt:[o intValue]];
+      
+    case 's':
+      // return [NSString stringWithCString:[o cString]];
+      return [[o copy] autorelease];
+      
+    default:
+      [NSException raise:@"NSInvalidArgumentException"
+                   format:@"unknown or not allowed conversation char %c", _c];
+  }
+  return nil;
+}
+
+@end /* EOQualifierEnumeratorParserContext */
+
+@implementation EOQualifierParserContext
+
+- (id)init {
+  if (StringClass == Nil) StringClass = [NSString class];
+  
+  if ((self = [super init])) {
+    self->qualifierCache = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                            NSObjectMapValueCallBacks,
+                                            200);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (self->qualifierCache) NSFreeMapTable(self->qualifierCache);
+  [super dealloc];
+}
+
+- (NSDictionary *)resultForFunction:(NSString *)_fct atPos:(unsigned)_pos
+{
+  return NSMapGet(self->qualifierCache,
+                  [StringClass stringWithFormat:@"%@_%d", _fct, _pos]);
+}
+
+- (void)setResult:(NSDictionary *)_dict forFunction:(NSString *)_fct
+  atPos:(unsigned)_pos
+{
+  NSMapInsert(self->qualifierCache,
+              [StringClass stringWithFormat:@"%@_%d", _fct, _pos],
+              _dict);
+}
+
+- (id)getObjectFromStackFor:(char)_c {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+/* factory */
+
+- (EOQualifier *)keyComparisonQualifierWithLeftKey:(NSString *)_leftKey
+  operatorSelector:(SEL)_sel
+  rightKey:(NSString *)_rightKey
+{
+  static Class clazz = Nil;
+  if (clazz == Nil) clazz = [EOKeyComparisonQualifier class];
+  
+  return [[[clazz alloc]
+                  initWithLeftKey:_leftKey
+                  operatorSelector:_sel
+                  rightKey:_rightKey]
+                  autorelease];
+}
+- (EOQualifier *)keyValueQualifierWithKey:(NSString *)_key
+  operatorSelector:(SEL)_sel
+  value:(id)_value
+{
+  static Class clazz = Nil;
+  if (clazz == Nil) clazz = [EOKeyValueQualifier class];
+  
+  return [[[clazz alloc]
+                  initWithKey:_key
+                  operatorSelector:_sel
+                  value:_value]
+                  autorelease];
+}
+- (EOQualifier *)andQualifierWithArray:(NSArray *)_qualifiers {
+  static Class clazz = Nil;
+  if (clazz == Nil) clazz = [EOAndQualifier class];
+  
+  return [[[clazz alloc] initWithQualifierArray:_qualifiers] autorelease];
+}
+- (EOQualifier *)orQualifierWithArray:(NSArray *)_qualifiers {
+  static Class clazz = Nil;
+  if (clazz == Nil) clazz = [EOOrQualifier class];
+  
+  return [[[clazz alloc] initWithQualifierArray:_qualifiers] autorelease];
+}
+
+- (EOQualifier *)notQualifierWithQualifier:(EOQualifier *)_qualifier {
+  static Class clazz = Nil;
+  if (clazz == Nil) clazz = [EONotQualifier class];
+  
+  return [[[clazz alloc] initWithQualifier:_qualifier] autorelease];
+}
+
+- (EOQualifierVariable *)variableWithKey:(NSString *)_key {
+  static Class clazz = Nil;
+  if (clazz == Nil) clazz = [EOQualifierVariable class];
+
+  return [clazz variableWithKey:_key];
+}
+
+@end /* EOQualifierParserContext */
+
+@implementation EOQualifier(Parsing)
+
++ (void)registerValueClass:(Class)_valueClass forTypeName:(NSString *)_type {
+  if (EOQualifierParserTypeMappings == nil)
+    EOQualifierParserTypeMappings = [[NSMutableDictionary alloc] init];
+  
+  if (_type == nil) {
+    NSLog(@"ERROR(%s): got passed no type name!", __PRETTY_FUNCTION__);
+    return;
+  }
+  if (_valueClass == nil) {
+    NSLog(@"ERROR(%s): got passed no value-class for type '%@'!",
+          __PRETTY_FUNCTION__, _type);
+    return;
+  }
+  
+  [EOQualifierParserTypeMappings setObject:_valueClass forKey:_type];
+}
+
++ (EOQualifier *)qualifierWithQualifierFormat:(NSString *)_qualifierFormat,... {
+  va_list     va;
+  EOQualifier *qualifier;
+  unsigned    length = 0;
+  const char  *buf;
+  unsigned    bufLen;
+  char        *cbuf;
+
+  _setupLiterals();
+  if (StringClass == Nil) StringClass = [NSString class];
+  
+  bufLen = [_qualifierFormat cStringLength];
+  cbuf   = malloc(bufLen + 1);
+  [_qualifierFormat getCString:cbuf]; cbuf[bufLen] = '\0';
+  buf = cbuf;
+  
+  va_start(va, _qualifierFormat);
+  qualifier =
+    _parseQualifiers([EOQualifierVAParserContext contextWithVaList:&va],
+                     buf, bufLen, &length);
+  va_end(va);
+  
+  if (qualifier != nil) { /* check whether the rest of the string is OK */
+    if (length < bufLen)
+      length += _countWhiteSpaces(buf + length, bufLen - length);
+    
+    if (length < bufLen) {
+      NSLog(@"WARNING(%s): unexpected chars at the end of the "
+            @"string(class=%@,len=%i) '%@'",
+            __PRETTY_FUNCTION__,
+            [_qualifierFormat class],
+            [_qualifierFormat length], _qualifierFormat);
+      NSLog(@"  buf-length: %i", bufLen);
+      NSLog(@"  length:     %i", length);
+      NSLog(@"  char[length]: '%c' (%i) '%s'", buf[length], buf[length],
+           (buf+length));
+      qualifier = nil;
+    }
+    else if (length > bufLen) {
+      NSLog(@"WARNING(%s): length should never be longer than bufLen ?, "
+           @"internal parsing error !",
+           __PRETTY_FUNCTION__);
+    }
+  }
+  free(cbuf);
+  return qualifier;
+}
+
++ (EOQualifier *)qualifierWithQualifierFormat:(NSString *)_qualifierFormat 
+  arguments:(NSArray *)_arguments
+{
+  EOQualifier *qual  = nil;
+  unsigned    length = 0;
+  const char  *buf   = NULL;
+  unsigned    bufLen = 0;
+  EOQualifierEnumeratorParserContext *ctx;
+
+  _setupLiterals();
+  if (StringClass == Nil) StringClass = [NSString class];
+  
+  ctx = [EOQualifierEnumeratorParserContext contextWithEnumerator:
+                                             [_arguments objectEnumerator]];
+  
+  //NSLog(@"qclass: %@", [_qualifierFormat class]);
+  buf    = [_qualifierFormat cString];
+  bufLen = [_qualifierFormat cStringLength];
+  qual   = _parseQualifiers(ctx, buf, bufLen, &length);
+  
+  if (qual != nil) { /* check whether the rest of the string is OK */
+    if (length < bufLen) {
+      length += _countWhiteSpaces(buf + length, bufLen - length);
+    }
+    if (length != bufLen) {
+      NSLog(@"WARNING(%s): unexpected chars at the end of the string '%@'",
+            __PRETTY_FUNCTION__, _qualifierFormat);
+      qual = nil;
+    }
+  }
+  return qual;
+}
+@end /* EOQualifier(Parsing) */
+
+static EOQualifier *_parseSingleQualifier(id _ctx, const char *_buf,
+                                            unsigned _bufLen,
+                                            unsigned *_qualLen)
+{
+  EOQualifier *res = nil;
+
+  if ((res = _parseParenthesisQualifier(_ctx, _buf, _bufLen, _qualLen))  != nil) {
+    if (qDebug)
+      NSLog(@"_parseSingleQualifier return <%@> for <%s> ", res, _buf);
+
+    return res;
+  }
+  if ((res = _parseNotQualifier(_ctx, _buf, _bufLen, _qualLen)) != nil) {
+    if (qDebug)
+      NSLog(@"_parseSingleQualifier return <%@> for <%s> ", res, _buf);
+
+    return res;
+  }
+  if ((res = _parseKeyCompQualifier(_ctx, _buf, _bufLen, _qualLen)) != nil) {
+    if (qDebug) {
+      NSLog(@"_parseSingleQualifier return <%@> for <%s> length %d", 
+           res, _buf, *_qualLen);
+    }
+    return res;
+  }
+  return nil;
+}
+
+static EOQualifier *_parseQualifiers(id _ctx, const char *_buf, unsigned _bufLen,
+                                     unsigned *_qualLen)
+{
+  EOQualifier *res = nil;
+
+
+  if ((res = _parseCompoundQualifier(_ctx, _buf, _bufLen, _qualLen))) {
+    if (qDebug)
+      NSLog(@"_parseQualifiers return <%@> for <%s> ", res, _buf);
+    return res;
+  }
+
+  if ((res = _parseSingleQualifier(_ctx, _buf, _bufLen, _qualLen))) {
+    if (qDebug)
+      NSLog(@"_parseQualifiers return <%@> for <%s> ", res, _buf);
+    return res;
+  }
+  
+  if (qDebug)
+    NSLog(@"_parseQualifiers return nil for <%s> ", _buf);
+
+  return nil;
+}
+
+static EOQualifier *_parseParenthesisQualifier(id _ctx, const char *_buf,
+                                               unsigned _bufLen,
+                                               unsigned *_qualLen)
+{
+  unsigned    pos     = 0;
+  unsigned    qualLen = 0;
+  EOQualifier *qual   = nil;
+
+  pos = _countWhiteSpaces(_buf, _bufLen);
+
+  if (_bufLen <= pos + 2) /* at least open and close parenthesis */ {
+    if (qDebug)
+      NSLog(@"1_parseParenthesisQualifier return nil for <%s> ", _buf);
+    return nil;
+  }
+  if (_buf[pos] != '(') {
+    if (qDebug)
+      NSLog(@"2_parseParenthesisQualifier return nil for <%s> ", _buf);
+    
+    return nil;
+  }
+  pos++;
+  if (!(qual = _parseQualifiers(_ctx, _buf + pos, _bufLen - pos,
+                                &qualLen))) {
+    if (qDebug)
+      NSLog(@"3_parseParenthesisQualifier return nil for <%s> ", _buf);
+    
+    return nil;
+  }
+  
+  pos += qualLen;
+  if (_bufLen <= pos) {
+    if (qDebug)
+      NSLog(@"4_parseParenthesisQualifier return nil for <%s> qual[%@] %@ bufLen %d "
+            @"pos %d", _buf, [qual class], qual, _bufLen, pos);
+
+    return nil;
+  }
+  pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
+  if (_buf[pos] != ')') {
+    if (qDebug)
+      NSLog(@"5_parseParenthesisQualifier return nil for <%s> [%s] ", _buf, _buf+pos);
+
+    return nil;
+  }
+  if (qDebug)
+    NSLog(@"6_parseParenthesisQualifier return <%@> for <%s> ", qual, _buf);
+  
+  *_qualLen = pos + 1; /* one step after the parenthesis */
+  return qual;
+}
+
+static EOQualifier *_parseNotQualifier(id _ctx, const char *_buf,
+                                       unsigned _bufLen, unsigned *_qualLen)
+{
+  unsigned    pos, len   = 0;
+  char        c0, c1, c2 = 0;
+  EOQualifier *qual      = nil;
+
+  pos = _countWhiteSpaces(_buf, _bufLen);
+
+  if (_bufLen - pos < 4) { /* at least 3 chars for 'NOT' */
+    if (qDebug)
+      NSLog(@"_parseNotQualifier return nil for <%s> ", _buf);
+    
+    return nil;
+  }
+  c0 = _buf[pos];
+  c1 = _buf[pos + 1];
+  c2 = _buf[pos + 2];
+  if (!(((c0 == 'n') || (c0 == 'N')) &&
+        ((c1 == 'o') || (c1 == 'O')) &&
+        ((c2 == 't') || (c2 == 'T')))) {
+    if (qDebug)
+      NSLog(@"_parseNotQualifier return nil for <%s> ", _buf);
+    return nil;
+  }
+  pos += 3;
+  qual = _parseSingleQualifier(_ctx, _buf + pos, _bufLen - pos, &len);
+  if (qual == nil) {
+    if (qDebug)
+      NSLog(@"_parseNotQualifier return nil for <%s> ", _buf);
+    
+    return nil;
+  }
+  *_qualLen = pos +len;
+  if (qDebug)
+    NSLog(@"_parseNotQualifier return %@ for <%s> ", qual, _buf);
+
+  return [_ctx notQualifierWithQualifier:qual];
+}
+
+static EOQualifier *_parseKeyCompQualifier(id _ctx, const char *_buf,
+                                           unsigned _bufLen, unsigned *_qualLen)
+{
+  NSString     *key       = nil;
+  NSString     *op        = nil;
+  NSString     *value     = nil;
+  EOQualifier  *qual      = nil;
+  NSDictionary *dict      = nil;
+  SEL          sel        = NULL;
+  unsigned     length     = 0;
+  unsigned     pos        = 0;
+  BOOL         valueIsKey = NO;
+
+  dict = [_ctx resultForFunction:@"parseKeyCompQualifier" atPos:(unsigned)_buf];
+  if (dict != nil) {
+    if (qDebug)
+      NSLog(@"_parseKeyCompQual return <%@> [cached] for <%s> ", dict, _buf);
+    
+    *_qualLen = [[dict objectForKey:@"length"] unsignedIntValue];
+    return [dict objectForKey:@"object"];
+  }
+  pos = _countWhiteSpaces(_buf, _bufLen);
+
+  if ((key = _parseKey(_ctx , _buf + pos, _bufLen - pos, &length)) == nil) {
+    if (qDebug)
+      NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
+    
+    return nil;
+  }
+  pos += length;
+  pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
+
+  if (!(op = _parseOp(_buf + pos, _bufLen - pos, &length))) {
+    if (qDebug)
+      NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
+    return nil;
+  }
+  sel = [EOQualifier operatorSelectorForString:op];
+  if (sel == NULL) {
+    NSLog(@"WARNING(%s): possible unknown operator <%@>", __PRETTY_FUNCTION__,
+          op);
+    if (qDebug)
+      NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
+    return nil;
+  }
+  pos       +=length;
+  pos       += _countWhiteSpaces(_buf + pos, _bufLen - pos);
+  valueIsKey = NO;  
+  
+  value = _parseValue(_ctx, _buf + pos, _bufLen - pos, &length);
+  if (value == nil) {
+    value = _parseKey(_ctx, _buf + pos, _bufLen - pos, &length);
+    if (value == nil) {
+      if (qDebug)
+       NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
+      return nil;
+    }
+    else
+      valueIsKey = YES;
+  }
+  pos      +=length;  
+  *_qualLen = pos;
+
+  qual = (valueIsKey)
+    ? [_ctx keyComparisonQualifierWithLeftKey:key
+            operatorSelector:sel
+            rightKey:value]
+    : [_ctx keyValueQualifierWithKey:key
+            operatorSelector:sel
+            value:value];
+  
+  if (qDebug)
+    NSLog(@"_parseKeyCompQualifier return <%@> for <%s> ", qual, _buf);
+
+  if (qual != nil) {
+    id keys[2], values[2];
+    keys[0] = @"length"; values[0] = [NSNumber numberWithUnsignedInt:pos];
+    keys[1] = @"object"; values[1] = qual;
+    [_ctx setResult:
+            [NSDictionary dictionaryWithObjects:values forKeys:keys count:2]
+          forFunction:@"parseKeyCompQualifier"
+          atPos:(unsigned)_buf];
+    *_qualLen = pos;
+  }
+  return qual;
+}
+
+static NSString *_parseOp(const char *_buf, unsigned _bufLen,
+                          unsigned *_opLen)
+{
+  unsigned pos = 0;
+  char     c0  = 0;
+  char     c1  = 0;  
+
+  if (_bufLen == 0) {
+    if (qDebug)
+      NSLog(@"_parseOp _bufLen == 0 --> return nil");
+    return nil;
+  }
+  pos = _countWhiteSpaces(_buf, _bufLen);
+  if (_bufLen - pos > 1) {/* at least an operation and a value */
+    c0 = _buf[pos];
+    c1 = _buf[pos+1];  
+
+    if (((c0 >= '<') && (c0 <= '>')) || (c0 == '!')) {
+      NSString *result;
+      
+      if ((c1 >= '<') && (c1 <= '>')) {
+        *_opLen = 2;
+        result = [StringClass stringWithCString:_buf + pos length:2];
+       if (qDebug)
+         NSLog(@"_parseOp return <%@> for <%s> ", result, _buf);
+      }
+      else {
+        *_opLen = 1;
+        result = [StringClass stringWithCString:&c0 length:1];
+       if (qDebug)
+         NSLog(@"_parseOp return <%@> for <%s> ", result, _buf);
+      }
+      return result;
+    }
+    else { /* string designator operator */
+      unsigned opStart = pos;
+      while (pos < _bufLen) {
+        if (_buf[pos] == ' ')
+          break;
+        pos++;
+      }
+      if (pos >= _bufLen) {
+        NSLog(@"WARNING(%s): found end of string during operator parsing",
+              __PRETTY_FUNCTION__);
+      }
+
+      if (qDebug) {
+       NSLog(@"%s: _parseOp return <%@> for <%s> ", __PRETTY_FUNCTION__,
+             [StringClass stringWithCString:_buf + opStart
+                          length:pos - opStart], _buf);
+      }
+      
+      *_opLen = pos;
+      return [StringClass stringWithCString:_buf + opStart length:pos - opStart];
+    }
+  }
+  if (qDebug)
+    NSLog(@"_parseOp return nil for <%s> ", _buf);
+  return nil;
+}
+
+static NSString *_parseKey(id _ctx, const char *_buf, unsigned _bufLen,
+                           unsigned *_keyLen)
+{ 
+  id           result   = nil;
+  NSDictionary *dict    = nil;
+  unsigned     pos      = 0;
+  unsigned     startKey = 0;
+  char         c        = 0;
+
+  if (_bufLen == 0) {
+    if (qDebug) NSLog(@"%s: _bufLen == 0 --> return nil", __PRETTY_FUNCTION__);
+    return nil;
+  }
+  dict = [_ctx resultForFunction:@"parseKey" atPos:(unsigned)_buf];
+  if (dict != nil) {
+    if (qDebug) {
+      NSLog(@"%s: return <%@> [cached] for <%s> ", __PRETTY_FUNCTION__,
+           dict, _buf);
+    }
+    *_keyLen = [[dict objectForKey:@"length"] unsignedIntValue];
+    return [dict objectForKey:@"object"];
+  }
+  pos      = _countWhiteSpaces(_buf, _bufLen);
+  startKey = pos;
+  c        = _buf[pos];
+
+  if (c == '%') {
+    if (_bufLen - pos < 2) {
+      if (qDebug) {
+       NSLog(@"%s: [c==%%,bufLen-pos<2]: _parseValue return nil for <%s> ", 
+             __PRETTY_FUNCTION__, _buf);
+      }
+      return nil;
+    }
+    pos++;
+    result = [_ctx getObjectFromStackFor:_buf[pos]];
+    pos++;
+  }
+  else {
+    /* '{' for namspaces */
+    register BOOL isQuotedKey = NO;
+
+    if (c == '"')
+      isQuotedKey = YES;
+    else if (!(((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
+             c == '{')) {
+      if (qDebug) {
+       NSLog(@"%s: [c!=AZaz{]: _parseKey return nil for <%s> ", 
+             __PRETTY_FUNCTION__, _buf);
+      }
+      return nil;
+    }
+    
+    pos++;
+    while (pos < _bufLen) {
+      c = _buf[pos];
+      if (isQuotedKey && c == '"')
+       break;
+      else if
+       ((c == ' ') || (c == '<') || (c == '>') || (c == '=') || (c == '!') ||
+         c == ')' || c == '(')
+        break;
+      pos++;    
+    }
+    if (isQuotedKey) {
+      pos++; // skip quote
+      result = [StringClass stringWithCString:(_buf + startKey + 1) 
+                           length:(pos - startKey - 2)];
+    }
+    else {
+      result = [StringClass stringWithCString:(_buf + startKey) 
+                           length:(pos - startKey)];
+    }
+  }
+  *_keyLen = pos;  
+  if (qDebug)
+    NSLog(@"%s: return <%@> for <%s> ", __PRETTY_FUNCTION__, result, _buf);
+  
+  if (result != nil) {
+    id keys[2], values[2];
+    
+    keys[0] = @"length"; values[0] = [NSNumber numberWithUnsignedInt:pos];
+    keys[1] = @"object"; values[1] = result;
+    
+    [_ctx setResult:
+            [NSDictionary dictionaryWithObjects:values forKeys:keys count:2]
+          forFunction:@"parseKey"
+          atPos:(unsigned)_buf];
+    *_keyLen = pos;
+  }
+  return result;
+}
+
+static id _parseValue(id _ctx, const char *_buf, unsigned _bufLen,
+                      unsigned *_keyLen)
+{
+  NSString     *cast = nil;
+  NSDictionary *dict = nil;
+  id           obj   = nil;
+  unsigned     pos   = 0;
+  char         c     = 0;
+  
+  if (NumberClass == Nil) NumberClass = [NSNumber class];
+  if (null == nil) null = [[NSNull null] retain];
+  
+  if (_bufLen == 0) {
+    if (qDebug) NSLog(@"_parseValue _bufLen == 0 --> return nil");
+    return nil;
+  }
+  
+  dict = [_ctx resultForFunction:@"parseValue" atPos:(unsigned)_buf];
+  if (dict != nil) {
+    if (qDebug) {
+      NSLog(@"_parseKeyCompQualifier return <%@> [cached] for <%s> ",
+           dict, _buf);
+    }
+    *_keyLen = [[dict objectForKey:@"length"] unsignedIntValue];
+    return [dict objectForKey:@"object"];
+  }
+  
+  pos = _countWhiteSpaces(_buf, _bufLen);
+  c   = _buf[pos];
+  
+  if (c == '$') { /* found EOQualifierVariable */
+    unsigned startVar = 0;
+    NSString *varKey;
+    
+    pos++;
+    startVar = pos;
+    while (pos < _bufLen) {
+      if ((_buf[pos] == ' ') || (_buf[pos] == ')'))
+        break;
+      pos++;
+    }
+
+    varKey = [StringClass stringWithCString:(_buf + startVar)
+                          length:pos - startVar];
+    obj = [_ctx variableWithKey:varKey];
+  }
+  else {
+    /* first, check for CAST */
+    BOOL parseComplexCast = NO;
+    
+    if (c == 'c' && _bufLen > 14) {
+      if (strstr(_buf, "cast") == _buf && (isspace(_buf[4]) || _buf[4]=='(')) {
+       /* for example: cast("1970-01-01T00:00:00Z" as 'dateTime') [min 15 #]*/
+       pos += 4; /* skip 'cast' */
+        while (isspace(_buf[pos])) /* skip spaces */
+          pos++;
+        if (_buf[pos] != '(') {
+          NSLog(@"WARNING(%s): got unexpected cast string: '%s'",
+                __PRETTY_FUNCTION__, _buf);
+        }
+        else
+          pos++; /* skip opening bracket '(' */
+        
+       parseComplexCast = YES;
+       c = _buf[pos];
+      }
+    }
+    else if (c == '(') { /* starting with a cast */
+      /* for example: (NSCalendarDate)"1999-12-12" [min 5 chars] */
+      unsigned startCast = 0;
+      
+      pos++;
+      startCast = pos;
+      while (pos < _bufLen) {
+        if (_buf[pos] == ')')
+          break;
+        pos++;
+      }
+      pos++;
+      if (pos >= _bufLen) {
+        NSLog(@"WARNING(%s): found end of string while reading a cast",
+              __PRETTY_FUNCTION__);
+        return nil;
+      }
+      c    = _buf[pos];
+      cast = [StringClass stringWithCString:(_buf + startCast)
+                          length:(pos - 1 - startCast)];
+      if (qDebug)
+       NSLog(@"%s: got cast %@", __PRETTY_FUNCTION__, cast);
+    }
+    
+    /* next, check for FORMAT SPECIFIER */
+    if (c == '%') {
+      if (_bufLen - pos < 2) {
+       if (qDebug)
+         NSLog(@"_parseValue return nil for <%s> ", _buf);
+       
+        return nil;
+      }
+      pos++;
+      obj = [_ctx getObjectFromStackFor:_buf[pos]];
+      pos++;
+    }
+    
+    /* next, check for A NUMBER */
+    else if (((c >= '0') && (c <= '9')) || (c == '-')) { /* got a number */
+      unsigned startNumber;
+
+      startNumber = pos;
+      pos++;
+      while (pos < _bufLen) {
+        c = _buf[pos];
+        if (!((c >= '0') && (c <= '9')))
+          break;
+        pos++;
+      }
+      obj = [NumberClass numberWithInt:atoi(_buf + startNumber)];
+    }
+
+    /* check for some text literals */
+    if ((obj == nil) && ((_bufLen - pos) > 1)) {
+      unsigned char i;
+      
+      for (i = 0; i < 20 && (toks[i].token != NULL) && (obj == nil); i++) {
+       const unsigned char *tok;
+       unsigned char toklen;
+       int rc;
+       
+       tok = toks[i].token;
+       toklen = strlen(tok);
+       if ((_bufLen - pos) < toklen)
+         /* remaining string not long enough */
+         continue;
+       
+       rc = toks[i].scase 
+         ? strncmp(&(_buf[pos]),     tok, toklen)
+         : strncasecmp(&(_buf[pos]), tok, toklen);
+       if (rc != 0)
+         /* does not match */
+         continue;
+       if (!(_buf[pos + toklen] == '\0' || isspace(_buf[pos + toklen])))
+         /* not at the string end or folloed by a space */
+         continue;
+
+       /* wow, found the token */
+       pos += toklen; /* skip it */
+       obj = toks[i].value;
+      }
+    }
+    
+    /* next, check for STRING */
+    if (obj == nil) {
+      if ((c == '\'') || (c == '"')) {
+       NSString *res                  = nil;
+       char     string[_bufLen - pos];
+       unsigned cnt                   = 0;
+      
+       pos++;
+       while (pos < _bufLen) {
+         char ch = _buf[pos];
+         if (ch == c)
+           break;
+         if ((ch == '\\') && (_bufLen > (pos + 1))) {
+           if (_buf[pos + 1] == c) {
+             pos += 1;
+             ch = c;
+           }
+         }
+         string[cnt++] = ch;
+         pos++;
+       }
+       if (pos >= _bufLen) {
+         NSLog(@"WARNING(%s): found end of string before end of quoted text",
+               __PRETTY_FUNCTION__);
+         return nil;
+       }
+       res = [StringClass stringWithCString:string length:cnt];
+       pos++; /* don`t forget quotations */
+       if (qDebug) NSLog(@"_parseValue return <%@> for <%s> ", res, _buf);
+       obj = res;
+      }
+    }
+    
+    /* complete parsing of cast */
+    if (parseComplexCast && (pos + 6) < _bufLen) {
+      /* now we need " as 'dateTime'" [min 7 #] */
+      
+      /* skip spaces */
+      while (isspace(_buf[pos]) && pos < _bufLen) pos++;
+      
+      //printf("POS: '%s'\n", &(_buf[pos]));
+      /* parse 'as' */
+      if (_buf[pos] != 'a' && _buf[pos] != 'A')
+       NSLog(@"%s: expecting 'AS' of complex cast ...", __PRETTY_FUNCTION__);
+      else if (_buf[pos + 1] != 's' && _buf[pos + 1] != 'S')
+       NSLog(@"%s: expecting 'AS' of complex cast ...", __PRETTY_FUNCTION__);
+      else {
+       /* skip AS */
+       pos += 2;
+       
+       /* skip spaces */
+       while (isspace(_buf[pos]) && pos < _bufLen) pos++;
+       
+       /* read cast type */
+       if (_buf[pos] != '\'') {
+         NSLog(@"%s: expected type of complex cast ...", __PRETTY_FUNCTION__);
+       }
+       else {
+         const unsigned char *cs, *ce;
+         
+         //printf("POS: '%s'\n", &(_buf[pos]));
+         pos++;
+         cs = &(_buf[pos]);
+         ce = index(cs, '\'');
+         cast = [NSString stringWithCString:cs length:(ce - cs)];
+         if (qDebug) {
+           NSLog(@"%s: parsed complex cast: '%@' to '%@'", __PRETTY_FUNCTION__,
+                 obj, cast);
+         }
+         pos += (ce - cs);
+         pos++; // skip '
+         pos++; // skip )
+         //printf("POS: '%s'\n", &(_buf[pos]));
+       }
+      }
+    }
+  }
+  
+  if (cast != nil && obj != nil) {
+    Class class = Nil;
+    id orig = obj;
+    
+    if ((class = [EOQualifierParserTypeMappings objectForKey:cast]) == nil) {
+      /* no value explicitly mapped to class, try to construct class name... */
+      NSString *className;
+
+      className = cast;
+      if ((class = NSClassFromString(className)) == Nil) {
+        /* check some default cast types ... */
+        className = [cast lowercaseString];
+        
+        if ([className isEqualToString:@"datetime"])
+          class = [NSCalendarDate class];
+        else if ([className isEqualToString:@"datetime.tz"])
+          class = [NSCalendarDate class];
+      }
+    }
+    if (class) {
+      obj = [[[class alloc] initWithString:[orig description]] autorelease];
+      
+      if (obj == nil) {
+       NSLog(@"%s: could not init object '%@' of cast class %@(%@) !",
+             __PRETTY_FUNCTION__, orig, class, cast);
+       obj = null;
+      }
+    }
+    else {
+      NSLog(@"WARNING(%s): could not map cast '%@' to a class "
+           @"(returning null) !", 
+           __PRETTY_FUNCTION__, cast);
+      obj = null;
+    }
+  }
+  
+  if (qDebug) {
+    NSLog(@"%s: return <%@> for <%s> ", __PRETTY_FUNCTION__, 
+         obj?obj:@"<nil>", _buf);
+  }
+  
+  if (obj != nil) {
+    id keys[2], values[2];
+    
+    keys[0] = @"length"; values[0] = [NSNumber numberWithUnsignedInt:pos];
+    keys[1] = @"object"; values[1] = obj;
+    
+    [_ctx setResult:
+            [NSDictionary dictionaryWithObjects:values forKeys:keys count:2]
+          forFunction:@"parseValue" atPos:(unsigned)_buf];
+    *_keyLen = pos;
+  }
+  return obj;
+}
+
+static EOQualifier *_testOperator(id _ctx, const char *_buf,
+                                  unsigned _bufLen, unsigned *_opLen,
+                                  BOOL *isAnd)
+{
+  EOQualifier *qual       = nil;
+  char        c0, c1, c2  = 0;
+  unsigned    pos, len    = 0;
+
+  pos = _countWhiteSpaces(_buf, _bufLen);  
+  
+  if (_bufLen < 4) {/* at least OR or AND and somethink more */   
+    if (qDebug)
+      NSLog(@"_testOperator return nil for <%s> ", _buf);
+    return nil;
+  }
+  c0 = _buf[pos + 0];
+  c1 = _buf[pos + 1];
+  c2 = _buf[pos + 2];
+  
+  if (((c0 == 'a') || (c0  == 'A')) &&
+        ((c1 == 'n') || (c1  == 'N')) &&
+        ((c2 == 'd') || (c2  == 'D'))) {
+      pos    += 3;
+      *isAnd  = YES;
+  }
+  else if (((c0 == 'o') || (c0  == 'O')) && ((c1 == 'r') || (c1  == 'R'))) {
+      pos    += 2;
+      *isAnd  = NO;
+  }
+  pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
+  qual = _parseSingleQualifier(_ctx, _buf + pos, _bufLen - pos, &len);
+  *_opLen = pos + len;
+  if (qDebug)
+    NSLog(@"_testOperator return %@ for <%s> ", qual, _buf);
+  
+  return qual;
+}
+
+static EOQualifier *_parseCompoundQualifier(id _ctx, const char *_buf,
+                                            unsigned _bufLen, unsigned *_qualLen)
+{
+  EOQualifier    *q0, *q1 = nil;
+  NSMutableArray *array   = nil;
+  unsigned       pos, len = 0;
+  EOQualifier    *result;
+  BOOL           isAnd;
+
+  isAnd = YES;
+
+  if ((q0 = _parseSingleQualifier(_ctx, _buf, _bufLen, &len)) == nil) {
+    if (qDebug)
+      NSLog(@"_parseAndOrQualifier return nil for <%s> ", _buf);
+    
+    return nil;
+  }
+  pos = len;
+
+  if (!(q1 = _testOperator(_ctx, _buf + pos, _bufLen - pos, &len, &isAnd))) {
+    if (qDebug)
+      NSLog(@"_parseAndOrQualifier return nil for <%s> ", _buf);
+    return nil;
+  }
+  pos  += len;
+  array = [NSMutableArray arrayWithObjects:q0, q1, nil];
+  
+  while (YES) {
+    BOOL newIsAnd;
+
+    newIsAnd = YES;
+    q0       = _testOperator(_ctx,  _buf + pos, _bufLen - pos, &len, &newIsAnd);
+
+    if (!q0)
+      break;
+    
+    if (newIsAnd != isAnd) {
+      NSArray *a;
+
+      a = [[array copy] autorelease];
+      
+      q1 = (isAnd)
+        ? [_ctx andQualifierWithArray:a]
+        : [_ctx orQualifierWithArray:a];
+
+      [array removeAllObjects];
+      [array addObject:q1];
+      isAnd = newIsAnd;
+    }
+    [array addObject:q0];
+
+    pos += len;
+  }
+
+  *_qualLen = pos;
+  result = (isAnd)
+    ? [_ctx andQualifierWithArray:array]
+    : [_ctx orQualifierWithArray:array];
+  
+  if (qDebug)
+    NSLog(@"_parseAndOrQualifier return <%@> for <%s> ", result, _buf);
+
+  return result;
+}
+
+static inline unsigned _countWhiteSpaces(const char *_buf, unsigned _bufLen) {
+  unsigned cnt = 0;
+  
+  if (_bufLen == 0) {
+    if (qDebug)
+      NSLog(@"_parseString _bufLen == 0 --> return nil");
+    return 0;
+  }
+  
+  while (_buf[cnt] == ' ' || _buf[cnt] == '\t' || 
+        _buf[cnt] == '\n' || _buf[cnt] == '\r') {
+    cnt++;
+    if (cnt == _bufLen)
+      break;
+  }
+  return cnt;
+}
diff --git a/skyrix-core/EOControl/EOQualifierVariable.m b/skyrix-core/EOControl/EOQualifierVariable.m
new file mode 100644 (file)
index 0000000..7264247
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "EOQualifier.h"
+#include "common.h"
+
+@implementation EOQualifierVariable
+
++ (id)variableWithKey:(NSString *)_key {
+  return [[[self alloc] initWithKey:_key] autorelease];
+}
+
+- (id)initWithKey:(NSString *)_key {
+  self->varKey = [_key copyWithZone:[self zone]];
+  return self;
+}
+- (id)init {
+  return [self initWithKey:nil];
+}
+
+- (void)dealloc {
+  [self->varKey release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)key {
+  return self->varKey;
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->varKey];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  self->varKey = [[_coder decodeObject] copyWithZone:[self zone]];
+  return self;
+}
+
+/* Comparing */
+
+- (BOOL)isEqual:(id)_obj {
+  if ([_obj isKindOfClass:[self class]])
+    return [self isEqualToQualifierVariable:(EOQualifierVariable *)_obj];
+  
+  return NO;
+}
+
+- (BOOL)isEqualToQualifierVariable:(EOQualifierVariable *)_obj {
+  return [self->varKey isEqual:[_obj key]];
+}
+
+/* description */
+
+- (NSString *)qualifierDescription {
+  return [@"$" stringByAppendingString:[self key]];
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: variable=%@>",
+                     NSStringFromClass([self class]), self,
+                     [self key]];
+}
+
+@end /* EOQualifierVariable */
diff --git a/skyrix-core/EOControl/EOSQLParser.h b/skyrix-core/EOControl/EOSQLParser.h
new file mode 100644 (file)
index 0000000..a527b86
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_EOSQLParser_H__
+#define __EOControl_EOSQLParser_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+
+/*
+  This is parser can be used to parse simple SQL statements. It's not a full
+  SQL implementation, but should be sufficient for simple applications.
+
+  Additional hints:
+  - the selected attributes are added to the 'attributes' hint, if a
+    wildcard select is used (*), the hint is not set
+  - the depth of WebDAV scope from-queries are set in the depth-hint, valid
+    values are "deep", "flat", "flat+self", "self"
+  - if multiple entities are queried in the FROM, they are joined using ","
+    and set as the entityName of the fetch spec
+*/
+
+@class EOFetchSpecification, EOQualifier;
+
+@interface EOSQLParser : NSObject
+{
+}
+
++ (id)sharedSQLParser;
+
+/* top level parser entry points */
+
+- (EOFetchSpecification *)parseSQLSelectStatement:(NSString *)_sql;
+- (EOQualifier *)parseSQLWhereExpression:(NSString *)_sql;
+
+/* parsing parts (exported for overloading in subclasses) */
+
+- (BOOL)parseSQL:(id *)result
+  from:(unichar **)pos length:(unsigned *)len
+  strict:(BOOL)beStrict;
+- (BOOL)parseToken:(const unsigned char *)tk
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume;
+- (BOOL)parseIdentifier:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume;
+- (BOOL)parseQualifier:(EOQualifier **)result
+  from:(unichar **)pos length:(unsigned *)len;
+- (BOOL)parseScope:(NSString **)_scope:(NSString **)_entity
+  from:(unichar **)pos length:(unsigned *)len;
+
+- (BOOL)parseColumnName:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume;
+- (BOOL)parseTableName:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume;
+- (BOOL)parseIdentifierList:(NSArray **)result
+  from:(unichar **)pos length:(unsigned *)len
+  selector:(SEL)_sel;
+
+@end
+
+#endif /* __EOControl_EOSQLParser_H__ */
diff --git a/skyrix-core/EOControl/EOSQLParser.m b/skyrix-core/EOControl/EOSQLParser.m
new file mode 100644 (file)
index 0000000..2d8b7a6
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOSQLParser.h"
+#include "EOQualifier.h"
+#include "EOFetchSpecification.h"
+#include "EOSortOrdering.h"
+#include "EOClassDescription.h"
+#include "common.h"
+
+// TODO: better error output
+
+@interface EOSQLParser(Logging) /* this is available in NGExtensions */
+- (void)logWithFormat:(NSString *)_fmt,...;
+@end
+
+@implementation EOSQLParser
+
++ (id)sharedSQLParser {
+  static EOSQLParser *sharedParser = nil; // THREAD
+  if (sharedParser == nil)
+    sharedParser = [[EOSQLParser alloc] init];
+  return sharedParser;
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* top level parsers */
+
+- (EOFetchSpecification *)parseSQLSelectStatement:(NSString *)_sql {
+  EOFetchSpecification *fs;
+  unichar  *us, *pos;
+  unsigned len, remainingLen;
+  
+  if ((len = [_sql length]) == 0) return nil;
+
+  us  = calloc(len + 10, sizeof(unichar));
+  [_sql getCharacters:us];
+  us[len] = 0;
+  pos = us;
+  remainingLen = len;
+  
+  if (![self parseSQL:&fs from:&pos length:&remainingLen strict:NO])
+    [self logWithFormat:@"parsing of SQL failed."];
+  
+  free(us);
+  
+  return [fs autorelease];
+}
+
+- (EOQualifier *)parseSQLWhereExpression:(NSString *)_sql {
+  // TODO: process %=>* and %%, and $
+  unichar  *buf;
+  unsigned i, len;
+  BOOL     didReplace;
+  if ((len = [_sql length]) == 0) return nil;
+  
+  // TODO: improve, real parsing in qualifier parser !
+  
+  buf = calloc(len + 3, sizeof(unichar));
+  NSAssert(buf, @"could not allocate char buffer");
+  
+  [_sql getCharacters:buf];
+  for (i = 0, didReplace = NO; i < len; i++) {
+    if (buf[i] != '%') {
+      if (buf[i] == '*') {
+        NSLog(@"WARNING(%s): SQL string contains a '*': %@",
+              __PRETTY_FUNCTION__, _sql);
+      }
+      continue;
+    }
+    buf[i] = '%';    
+    didReplace = YES;
+  }
+  if (didReplace)
+    _sql = [NSString stringWithCharacters:buf length:len];
+  if (buf) free(buf);
+  
+  return [EOQualifier qualifierWithQualifierFormat:_sql];
+}
+
+/* parsing parts (exported for overloading in subclasses) */
+
+static inline BOOL
+uniIsCEq(unichar *haystack, const unsigned char *needle, unsigned len) 
+{
+  register unsigned idx;
+  for (idx = 0; idx < len; idx++) {
+    if (*needle == '\0')               return YES;
+    if (toupper(haystack[idx]) != needle[idx]) return NO;
+  }
+  return YES;
+}
+static inline void skipSpaces(unichar **pos, unsigned *len) {
+  while (*len > 0) {
+    if (!isspace(*pos[0])) return;
+    (*len)--;
+    (*pos)++;
+  }
+}
+static void printUniStr(unichar *pos, unsigned len) __attribute__((unused));
+static void printUniStr(unichar *pos, unsigned len) {
+  unsigned i;
+  for (i = 0; i < len && i < 80; i++)
+    putchar(pos[i]);
+  putchar('\n');
+}
+
+static inline BOOL isTokStopChar(unichar c) {
+  switch (c) {
+  case 0:
+  case ')': case '(': case '"': case '\'':
+    return YES;
+  default:
+    if (isspace(c)) return YES;
+    return NO;
+  }
+}
+
+- (BOOL)parseToken:(const unsigned char *)tk
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume
+{
+  /* ...[space] (strlen(tk)+1 chars) */
+  unichar  *scur;
+  unsigned slen, tlen;
+  
+  tlen = strlen(tk);
+  scur=*pos; slen=*len; // begin transaction
+  skipSpaces(&scur, &slen);
+  
+  if (slen < tlen)
+    return NO;
+  if (toupper(scur[0]) != tk[0])
+    return NO;
+  if (tlen < slen) { /* if tok is not at the end */
+    if (!isTokStopChar(scur[tlen]))
+      return NO; /* not followed by a token stopper */
+  }
+  if (!uniIsCEq(scur, tk, tlen)) 
+    return NO;
+  
+  scur+=tlen; slen-=tlen;
+  
+  if (consume) { *pos = scur; *len = slen; } // end tx
+  return YES;
+}
+
+- (BOOL)parseIdentifier:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume
+{
+  /* "attr" or attr (at least 1 char or 2 for ") */
+  unichar  *scur;
+  unsigned slen;
+  
+  if (result) *result = nil;
+  scur=*pos; slen=*len; // begin transaction
+  skipSpaces(&scur, &slen);
+  
+  if (*scur == '"') {
+    /* quoted attr */
+    unichar *start;
+    
+    //printf("try quoted attr\n");
+    if (slen < 2) return NO;
+    scur++; slen--; /* skip quote */
+    if (*scur == '"') {
+      /* empty name */
+      scur++; slen--;
+      if (consume) { *pos = scur; *len = slen; } // end transaction
+      *result = @"";
+      //printf("is empty quoted\n");
+      return YES;
+    }
+    if (slen < 2) return NO;
+    
+    start = scur;
+    while ((slen > 0) && (*scur != '"')) {
+      if (*scur == '\\' && (slen > 1)) {
+       /* quoted char */
+       scur++; slen--; // skip one more (still needs to be filtered in result
+      }
+      scur++; slen--;
+    }
+    if (slen > 0) { scur++; slen--; } /* skip quote */
+    
+    // TODO: xhandle contained quoted chars ?
+    *result = 
+      [[NSString alloc] initWithCharacters:start length:(scur-start-1)];
+    //NSLog(@"found qattr: %@", *result);
+  }
+  else {
+    /* non-quoted attr */
+    unichar *start;
+    
+    if (slen < 1) return NO;
+    
+    if ([self parseToken:"FROM" from:&scur length:&slen consume:NO]) {
+      /* not an attribute, the from starts ... */
+      // printf("rejected unquoted attr, is a FROM\n");
+      return NO;
+    }
+    if ([self parseToken:"WHERE" from:&scur length:&slen consume:NO]) {
+      /* not an attribute, the where starts ... */
+      // printf("rejected unquoted attr, is a WHERE\n");
+      return NO;
+    }
+    
+    start = scur;
+    while ((slen > 0) && !isspace(*scur) && (*scur != ',')) {
+      slen--;
+      scur++;
+    }
+    *result = [[NSString alloc] initWithCharacters:start length:(scur-start)];
+    //NSLog(@"found attr: %@ (len=%i)", *result, (scur-start));
+  }
+  if (consume && result) { *pos = scur; *len = slen; } // end transaction
+  return *result ? YES : NO;
+}
+- (BOOL)parseColumnName:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume
+{
+  return [self parseIdentifier:result from:pos length:len consume:consume];
+}
+- (BOOL)parseTableName:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume
+{
+  return [self parseIdentifier:result from:pos length:len consume:consume];
+}
+
+- (BOOL)parseIdentifierList:(NSArray **)result
+  from:(unichar **)pos length:(unsigned *)len
+  selector:(SEL)_sel
+{
+  /* attr[,attr] */
+  NSMutableArray *attrs = nil;
+  unichar  *scur;
+  unsigned slen;
+  id       attr;
+  BOOL (*parser)(id, SEL, NSString **, unichar **, unsigned *, BOOL);
+  
+  if (result) *result = nil;
+  scur=*pos; slen=*len; // begin transaction
+  skipSpaces(&scur, &slen);
+  parser = (void *)[self methodForSelector:_sel];
+  
+  if (slen < 1) return NO; // not enough chars
+  
+  if (*scur == '*') {
+    /* a wildcard list, return 'nil' as result */
+    //printf("try wildcard\n");
+    scur++; slen--; // skip '*'
+    if (!(slen == 0 || isspace(*scur))) {
+      /* not followed by space or at end */
+      return NO;
+    }
+    *pos = scur; *len = slen; // end transaction
+    *result = nil;
+    return YES;
+  }
+  
+  if (!parser(self, _sel, &attr,&scur,&slen,YES))
+    /* well, we need at least one attribute to make it a list */
+    return NO;
+  
+  attrs = [[NSMutableArray alloc] initWithCapacity:32];
+  [attrs addObject:attr]; [attr release];
+  
+  /* all the remaining attributes must be prefixed with a "," */
+  while (slen > 1) {
+    //printf("try next list attr comma\n");
+    skipSpaces(&scur, &slen);
+    if (slen < 2) break;
+    if (*scur != ',') break;
+    scur++; slen--; // skip ','
+    
+    //printf("try next list attr\n");
+    if (!parser(self, _sel, &attr,&scur,&slen,YES))
+      break;
+    
+    [attrs addObject:attr]; [attr release];
+  }
+  
+  *pos = scur; *len = slen; // end transaction
+  *result = attrs;
+  return YES;
+}
+
+- (BOOL)parseContainsQualifier:(EOQualifier **)q_
+  from:(unichar **)pos length:(unsigned *)len
+{
+  /* contains('"hh@"') [12+ chars] */
+  unichar  *scur;
+  unsigned slen;
+  NSString *s;
+  if (q_) *q_ = nil;
+  skipSpaces(&scur, &slen);
+  
+  if (slen < 12) return NO; // not enough chars
+  
+  if (![self parseToken:"CONTAINS" from:pos length:len consume:YES])
+    return NO;
+  skipSpaces(&scur, &slen);
+  [self parseToken:"('" from:&scur length:&slen consume:YES];
+  
+  if (![self parseIdentifier:&s from:&scur length:&slen consume:YES])
+    return NO;
+  
+  skipSpaces(&scur, &slen);
+  [self parseToken:"')" from:&scur length:&slen consume:YES];
+  
+  *q_ = [[EOQualifier qualifierWithQualifierFormat:
+                       @"contentAsString doesContain: %@", s] retain];
+  if (*q_) {
+    *pos = scur; *len = slen; // end transaction
+    return YES;
+  }
+  else
+    return NO;
+}
+
+- (BOOL)parseQualifier:(EOQualifier **)result
+  from:(unichar **)pos length:(unsigned *)len
+{
+  unichar  *scur;
+  unsigned slen;
+  
+  if (result) *result = nil;
+  scur=*pos; slen=*len; // begin transaction
+  skipSpaces(&scur, &slen);
+  
+  if (slen < 3) return NO; // not enough chars
+  
+  // for now should scan till we find either ORDER BY order GROUP BY
+  {
+    unichar *start = scur;
+    
+    while (slen > 0) {
+      if (*scur == 'O' || *scur == 'o') {
+       if ([self parseToken:"ORDER" from:&scur length:&slen consume:NO]) {
+         //printf("FOUND ORDER TOKEN ...\n");
+         break;
+       }
+      }
+      else if (*scur == 'G' || *scur == 'g') {
+       if ([self parseToken:"GROUP" from:&scur length:&slen consume:NO]) {
+         //printf("FOUND GROUP TOKEN ...\n");
+         break;
+       }
+      }
+      
+      scur++; slen--;
+    }
+
+    {
+      EOQualifier *q;
+      NSString *s;
+      
+      s = [[NSString alloc] initWithCharacters:start length:(scur-start)];
+      if ([s length] == 0) {
+       [s release];
+       return NO;
+      }
+      if ((q = [self parseSQLWhereExpression:s]) == nil) {
+       [s release];
+       return NO;
+      }
+      *result = [q retain];
+      [s release];
+    }
+  }
+  
+  *pos = scur; *len = slen; // end transaction
+  return YES;
+}
+
+- (BOOL)parseScope:(NSString **)_scope:(NSString **)_entity
+  from:(unichar **)pos length:(unsigned *)len
+{
+  /* 
+    "('shallow traversal of "..."')"
+    "('hierarchical traversal of "..."')"
+  */
+  unichar  *scur;
+  unsigned slen;
+  NSString *entityName;
+  BOOL isShallow = NO;
+  BOOL isDeep    = NO;
+  
+  if (_scope)  *_scope  = nil;
+  if (_entity) *_entity = nil;
+  scur=*pos; slen=*len; // begin transaction
+  skipSpaces(&scur, &slen);
+  if (slen < 14) return NO; // not enough chars
+  
+  if (*scur != '(') return NO; // does not start with '('
+  scur++; slen--; // skip '('
+  skipSpaces(&scur, &slen);
+  
+  if (*scur != '\'') return NO; // does not start with '(''
+  scur++; slen--; // skip single quote
+  
+  /* next the depth */
+  
+  if ([self parseToken:"SHALLOW" from:&scur length:&slen consume:YES])
+    isShallow = YES;
+  else if ([self parseToken:"HIERARCHICAL" from:&scur length:&slen consume:YES])
+    isDeep = YES;
+  else if ([self parseToken:"DEEP" from:&scur length:&slen consume:YES])
+    isDeep = YES;
+  else
+    /* unknown traveral key */
+    return NO;
+  
+  /* some syntactic sugar (not strict about that ...) */
+  [self parseToken:"TRAVERSAL" from:&scur length:&slen consume:YES];
+  [self parseToken:"OF"        from:&scur length:&slen consume:YES];
+  if (slen < 1) return NO; // not enough chars
+  
+  /* now the entity */
+  skipSpaces(&scur, &slen);
+  if (![self parseTableName:&entityName from:&scur length:&slen consume:YES])
+    return NO; // failed to parse entity from scope
+
+  /* trailer */
+  skipSpaces(&scur, &slen);
+  if (slen > 0 && *scur == '\'') {
+    scur++; slen--; // skip single quote
+  }
+  skipSpaces(&scur, &slen);
+  if (slen > 0 && *scur == ')') {
+    scur++; slen--; // skip ')'
+  }
+  
+  if (_scope)  *_scope  = isShallow ? @"flat" : @"deep";
+  if (_entity) *_entity = entityName;
+  *pos = scur; *len = slen; // end transaction
+  return YES;
+}
+
+- (BOOL)parseSELECT:(EOFetchSpecification **)result
+  from:(unichar **)pos length:(unsigned *)len
+  strict:(BOOL)beStrict
+{
+  EOFetchSpecification *fs;
+  NSMutableDictionary *lHints;
+  NSString *scope     = nil;
+  NSArray  *attrs     = nil;
+  NSArray  *fromList  = nil;
+  NSArray  *orderList = nil;
+  NSArray  *lSortOrderings = nil;
+  EOQualifier *q = nil;
+  BOOL hasSelect = NO;
+  BOOL hasFrom   = NO;
+  BOOL missingByOfOrder = NO;
+  BOOL missingByOfGroup = NO;
+  
+  *result = nil;
+  
+  if (![self parseToken:"SELECT" from:pos length:len consume:YES]) {
+    /* must begin with SELECT */
+    if (beStrict) return NO;
+  }
+  else
+    hasSelect = YES;
+  
+  if (![self parseIdentifierList:&attrs from:pos length:len
+            selector:@selector(parseColumnName:from:length:consume:)]) {
+    [self logWithFormat:@"missing ID list .."];
+    return NO;
+  }
+  //[self debugWithFormat:@"parsed attrs (%i): %@", [attrs count], attrs];
+  
+  /* now a from is expected */
+  if ([self parseToken:"FROM" from:pos length:len consume:YES])
+    hasFrom = YES;
+  else {
+    if (beStrict) return NO;
+  }
+  
+  /* check whether it's followed by a scope */
+  if ([self parseToken:"SCOPE" from:pos length:len consume:YES]) {
+    NSString *scopeEntity = nil;
+    
+    if (![self parseScope:&scope:&scopeEntity from:pos length:len]) {
+      if (beStrict) return NO;
+    }
+#if DEBUG_PARSING
+    else
+      [self logWithFormat:@"FOUND SCOPE: '%@'", scope];
+#endif
+    
+    if (scopeEntity)
+      fromList = [[NSArray alloc] initWithObjects:scopeEntity, nil];
+    [scopeEntity release];
+  }
+  else {
+    if (![self parseIdentifierList:&fromList from:pos length:len
+              selector:@selector(parseTableName:from:length:consume:)]) {
+      [self logWithFormat:@"missing from list .."];
+      return NO;
+    }
+#if DEBUG_PARSING
+    [self logWithFormat:@"parsed FROM list (%i): %@",
+         [fromList count], fromList];
+#endif
+  }
+  
+  /* check where */
+  if ([self parseToken:"WHERE" from:pos length:len consume:YES]) {
+    /* parse qualifier ... */
+    
+    if ([self parseToken:"CONTAINS" from:pos length:len consume:NO]) {
+      if (![self parseContainsQualifier:&q from:pos length:len]) {
+       if (beStrict) return NO;
+      }
+    }
+    else if (![self parseQualifier:&q from:pos length:len]) {
+      if (beStrict) return NO;
+    }
+#if DEBUG_PARSING
+    [self logWithFormat:@"FOUND Qualifier: '%@'", q];
+#endif
+  }
+  
+  /* check order-by */
+  if ([self parseToken:"ORDER" from:pos length:len consume:YES]) {
+    if (![self parseToken:"BY" from:pos length:len consume:YES]) {
+      if (beStrict) return NO;
+      missingByOfOrder = YES;
+    }
+    
+    if (![self parseIdentifierList:&orderList from:pos length:len
+              selector:@selector(parseColumnName:from:length:consume:)])
+      return NO;
+#if DEBUG_PARSING
+    [self logWithFormat:@"parsed ORDER list (%i): %@", 
+           [orderList count], orderList];
+#endif
+  }
+  
+  /* check group-by */
+  if ([self parseToken:"GROUP" from:pos length:len consume:YES]) {
+    if (![self parseToken:"BY" from:pos length:len consume:YES]) {
+      if (beStrict) return NO;
+      missingByOfGroup = YES;
+    }
+  }
+  
+  //printUniStr(*pos, *len); // DEBUG
+  
+  if (!hasSelect) [self logWithFormat:@"missing SELECT !"];
+  if (!hasFrom)   [self logWithFormat:@"missing FROM !"];
+  if (missingByOfOrder) [self logWithFormat:@"missing BY in ORDER BY !"];
+
+  /* build fetchspec */
+
+  lHints = [[NSMutableDictionary alloc] initWithCapacity:16];
+  
+  if (scope) {
+    [lHints setObject:scope forKey:@"scope"];
+    [scope release]; scope = nil;
+  }
+  if (attrs) {
+    [lHints setObject:attrs forKey:@"attributes"];
+    [attrs release]; attrs = nil;
+  }
+  if (orderList) {
+    NSMutableArray *ma;
+    unsigned i, len;
+    
+    len = [orderList count];
+    ma = [[NSMutableArray alloc] initWithCapacity:len];
+    for (i = 0; i < len; i++) {
+      EOSortOrdering *so;
+      
+      so = [EOSortOrdering sortOrderingWithKey:[orderList objectAtIndex:i]
+                          selector:EOCompareAscending];
+    }
+    lSortOrderings = [ma shallowCopy];
+    [ma release];
+    [orderList release]; orderList = nil;
+  }
+  
+  fs = [[EOFetchSpecification alloc]
+        initWithEntityName:[fromList componentsJoinedByString:@","]
+        qualifier:q
+        sortOrderings:lSortOrderings
+        usesDistinct:NO isDeep:NO hints:lHints];
+  [lHints release];
+  [q release];
+  [fromList release];
+  
+  *result = fs;
+  return fs ? YES : NO;
+}
+
+- (BOOL)parseSQL:(id *)result
+  from:(unichar **)pos length:(unsigned *)len
+  strict:(BOOL)beStrict
+{
+  if (*len < 1) return NO;
+  
+  if ([self parseToken:"SELECT" from:pos length:len consume:NO])
+    return [self parseSELECT:result from:pos length:len strict:beStrict];
+  
+  //if ([self parseToken:"UPDATE" from:pos length:len consume:NO])
+  //if ([self parseToken:"INSERT" from:pos length:len consume:NO])
+  //if ([self parseToken:"DELETE" from:pos length:len consume:NO])
+  
+  [self logWithFormat:@"tried to parse an unsupported SQL statement."];
+  return NO;
+}
+
+@end /* EOSQLParser */
+
+@implementation EOSQLParser(Tests)
+
++ (void)testDAVQuery {
+  EOFetchSpecification *fs;
+  NSString *sql;
+  
+  NSLog(@"testing: %@ --------------------", self);
+
+  sql = @"\n"
+  @"select \n"
+  @"  \"http://schemas.microsoft.com/mapi/proptag/x0e230003\",        \n"
+  @"  \"urn:schemas:mailheader:subject\",        \n"
+  @"  \"urn:schemas:mailheader:from\",\n"
+  @"  \"urn:schemas:mailheader:to\",        \n"
+  @"  \"urn:schemas:mailheader:cc\",        \n"
+  @"  \"urn:schemas:httpmail:read\",        \n"
+  @"  \"urn:schemas:httpmail:hasattachment\",        \n"
+  @"  \"DAV:getcontentlength\",        \n"
+  @"  \"urn:schemas:mailheader:date\",        \n"
+  @"  \"urn:schemas:httpmail:date\",      \n"
+  @"  \"urn:schemas:mailheader:received\",        \n"
+  @"  \"urn:schemas:mailheader:message-id\",        \n"
+  @"  \"urn:schemas:mailheader:in-reply-to\",        \n"
+  @"  \"urn:schemas:mailheader:references\"      \n"
+  @"from \n"
+  @"  scope('shallow traversal of \"http://127.0.0.1:9000/o/ol/helge/INBOX\"')\n"
+  @"where \n"
+  @"  \"DAV:iscollection\" = False \n"
+  @"  and \n"
+  @"  \"http://schemas.microsoft.com/mapi/proptag/x0c1e001f\" != 'SMTP'\n"
+  @"  and \n"
+  @"  \"http://schemas.microsoft.com/mapi/proptag/x0e230003\" > 0  \n"
+  @"  \n";
+  fs = [[self sharedSQLParser] parseSQLSelectStatement:sql];
+  
+  NSLog(@"  FS: %@", fs);
+  if (fs == nil) {
+    NSLog(@"  ERROR: could not parse SQL: %@", sql);
+  }
+  else {
+    EOQualifier *q;
+    NSString *scope;
+    NSArray  *props;
+    
+    if ((scope = [[fs hints] objectForKey:@"scope"]) == nil)
+      NSLog(@"  INVALID: got no scope !");
+    if (![scope isEqualToString:@"flat"])
+      NSLog(@"  INVALID: got scope %@, expected flat !", scope);
+
+#if 0    
+    if ([fs queryWebDAVPropertyNamesOnly])
+      NSLog(@"  INVALID: name query only, but queried several attrs !");
+#endif
+    
+    /* check qualifier */
+    if ((q = [fs qualifier]) == nil)
+      NSLog(@"  INVALID: got not qualifier (expected one) !");
+    else if (![q isKindOfClass:[EOAndQualifier class]]) {
+      NSLog(@"  INVALID: expected AND qualifier, got %@ !",
+           NSStringFromClass([q class]));
+    }
+    else if ([[(EOAndQualifier *)q qualifiers] count] != 3) {
+      NSLog(@"  INVALID: expected 3 subqualifiers, got %i !",
+           [[(EOAndQualifier *)q qualifiers] count]);
+    }
+
+    /* check sortordering */
+    if ([fs sortOrderings] != nil) {
+      NSLog(@"  INVALID: got sort orderings, specified none: %@ !",
+           [fs sortOrderings]);
+    }
+    
+    /* attributes */
+    if ((props = [[fs hints] objectForKey:@"attributes"]) == nil)
+      NSLog(@"  INVALID: got not attributes (expected some) !");
+    else if (![props isKindOfClass:[NSArray class]]) {
+      NSLog(@"  INVALID: attributes not delivered as array ?: %@",
+           NSStringFromClass([props class]));
+    }
+    else if ([props count] != 14) {
+      NSLog(@"  INVALID: invalid attribute count, expected 14, got %i.",
+           [props count]);
+    }
+  }
+  
+  NSLog(@"done test: %@ ------------------", self);
+}
+
+@end /* EOSQLParser(Tests) */
diff --git a/skyrix-core/EOControl/EOSortOrdering.h b/skyrix-core/EOControl/EOSortOrdering.h
new file mode 100644 (file)
index 0000000..7e16889
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __EOControl_EOSortOrdering_H__
+#define __EOControl_EOSortOrdering_H__
+
+#import <Foundation/NSObject.h>
+#include <EOControl/EOControlDecls.h>
+
+@class NSDictionary, NSString;
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+#define EOCompareAscending  @selector(compareAscending:)
+#define EOCompareDescending @selector(compareDescending:)
+#define EOCompareCaseInsensitiveAscending  @selector(compareCaseInsensitiveAscending:)
+#define EOCompareCaseInsensitiveDescending @selector(compareCaseInsensitiveDescending:)
+#else
+#  ifdef __APPLE__
+#    warning did you define the proper runtime ? (eg APPLE_RUNTIME)
+#  endif
+EOControl_EXPORT SEL EOCompareAscending;
+EOControl_EXPORT SEL EOCompareDescending;
+EOControl_EXPORT SEL EOCompareCaseInsensitiveAscending;
+EOControl_EXPORT SEL EOCompareCaseInsensitiveDescending;
+#endif
+
+@interface EOSortOrdering : NSObject
+{
+  NSString *key;
+  SEL      selector;
+}
+
++ (EOSortOrdering *)sortOrderingWithKey:(NSString *)_key 
+  selector:(SEL)_selector;
+- (id)initWithKey:(NSString *)_key selector:(SEL)_selector;
+
+/* accessors */
+
+- (NSString *)key;
+- (SEL)selector;
+
+/* remapping keys */
+
+- (EOSortOrdering *)sortOrderingByApplyingKeyMap:(NSDictionary *)_map;
+
+@end
+
+#import <Foundation/NSArray.h>
+
+@interface NSArray(EOSortOrdering)
+
+- (NSArray *)sortedArrayUsingKeyOrderArray:(NSArray *)_orderings;
+
+@end
+
+@interface NSMutableArray(EOSortOrdering)
+
+- (void)sortUsingKeyOrderArray:(NSArray *)_orderings;
+
+@end
+
+#import <Foundation/NSString.h>
+
+@interface NSString(EOSortOrdering)
+- (int)compareAscending:(id)_object;
+- (int)compareDescending:(id)_object;
+- (int)compareCaseInsensitiveAscending:(id)_object;
+- (int)compareCaseInsensitiveDescending:(id)_object;
+@end
+
+#endif /* __EOControl_EOSortOrdering_H__ */
diff --git a/skyrix-core/EOControl/EOSortOrdering.m b/skyrix-core/EOControl/EOSortOrdering.m
new file mode 100644 (file)
index 0000000..5bb9baa
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "EOSortOrdering.h"
+#include "EOKeyValueCoding.h"
+#include <EOControl/EONull.h>
+#include "common.h"
+
+#if GNU_RUNTIME
+#  include <objc/objc.h>
+#endif
+
+#ifndef SEL_EQ
+#  if GNU_RUNTIME
+#    define SEL_EQ(sel1,sel2) sel_eq(sel1,sel2)
+#  else
+#    define SEL_EQ(sel1,sel2) (sel1 == sel2)
+#  endif
+#endif
+
+#if !NeXT_RUNTIME
+EOControl_DECLARE SEL EOCompareAscending                 = 
+  @selector(compareAscending:);
+EOControl_DECLARE SEL EOCompareDescending                = 
+  @selector(compareDescending:);
+EOControl_DECLARE SEL EOCompareCaseInsensitiveAscending  =
+  @selector(compareCaseInsensitiveAscending:);
+EOControl_DECLARE SEL EOCompareCaseInsensitiveDescending = 
+  @selector(compareCaseInsensitiveDescending:);
+#endif
+
+@implementation EOSortOrdering
+/*"
+  This class specifies a sort-ordering as used with
+  EOFetchSpecification. It takes a key and a sort
+  selector which is used for comparision.
+"*/
+
+/*" Create a sort-ordering object with the specified key and sort selector "*/
++ (EOSortOrdering *)sortOrderingWithKey:(NSString *)_key selector:(SEL)_sel {
+  return [[[self alloc] initWithKey:_key selector:_sel] autorelease];
+}
+
+/*" 
+  Initialize a sort-ordering object with the specified key and sort selector
+"*/
+- (id)initWithKey:(NSString *)_key selector:(SEL)_selector {
+  if ((self = [super init])) {
+    self->key      = [_key copyWithZone:[self zone]];
+    self->selector = _selector;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->key release];
+  [super dealloc];
+}
+
+/* accessors */
+
+/*"
+  Returns the key the ordering sorts with.
+"*/
+- (NSString *)key {
+  return self->key;
+}
+
+/*"
+  Returns the selector the ordering sorts with.
+"*/
+- (SEL)selector {
+  return self->selector;
+}
+
+/* equality */
+
+- (BOOL)isEqualToSortOrdering:(EOSortOrdering *)_sortOrdering {
+  if (!SEL_EQ([_sortOrdering selector], [self selector]))
+    return NO;
+  if (![[_sortOrdering key] isEqualToString:[self key]])
+    return NO;
+  return YES;
+}
+- (BOOL)isEqual:(id)_other {
+  if ([_other isKindOfClass:[EOSortOrdering class]])
+    return [self isEqualToSortOrdering:_other];
+
+  return NO;
+}
+
+/* remapping keys */
+
+- (EOSortOrdering *)sortOrderingByApplyingKeyMap:(NSDictionary *)_map {
+  NSString *k;
+  
+  k = [_map objectForKey:self->key];
+  return [EOSortOrdering sortOrderingWithKey:(k ? k : self->key)
+                        selector:self->selector];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<0x%08X[%@]: key=%@ selector=%@>",
+                     self, NSStringFromClass([self class]),
+                     [self key], NSStringFromSelector([self selector])];
+}
+
+@end /* EOSortOrdering */
+
+@implementation NSArray(EOSortOrdering)
+
+/*" 
+  Sort the array using the sort-orderings contained in the argument. If no
+  orderings are given, a copy of self is returned.
+"*/
+- (NSArray *)sortedArrayUsingKeyOrderArray:(NSArray *)_orderings {
+  NSMutableArray *m      = nil;
+  NSArray        *result = nil;
+  
+  if ([_orderings count] == 0)
+    return [[self copy] autorelease];
+  
+  m = [self mutableCopy];
+  [m sortUsingKeyOrderArray:_orderings];
+  result = [m copy];
+  [m release]; m = nil;
+  return [result autorelease];
+}
+
+@end /* NSArray(EOSortOrdering) */
+
+@implementation NSMutableArray(EOSortOrdering)
+
+typedef struct {
+  EOSortOrdering *orderings[10]; /* max depth 10 */
+  short          count;
+} EOSortOrderingContext;
+
+static EONull *null = nil;
+
+static int keyOrderComparator(id o1, id o2, EOSortOrderingContext *context) {
+  short i;
+
+  for (i = 0; i < context->count; i++) {
+    NSString *key;
+    SEL      sel;
+    id       v1, v2;
+    int      (*ccmp)(id, SEL, id);
+    int      result;
+
+    key = [context->orderings[i] key];
+    sel = [context->orderings[i] selector];
+    
+    v1 = [o1 valueForKey:key];
+    v2 = [o2 valueForKey:key];
+
+    if (v1 == v2)
+      result = NSOrderedSame;
+    else if ((v1 == nil) || (v1 == null))
+      result = (sel == EOCompareAscending)
+        ? NSOrderedAscending : NSOrderedDescending;
+    else if ((v2 == nil) || (v2 == null))
+      result = (sel == EOCompareAscending)
+        ? NSOrderedDescending : NSOrderedAscending;
+    else if ((ccmp = (void *)[v1 methodForSelector:sel]))
+      result = ccmp(v1, sel, v2);
+    else
+      result = (int)[v1 performSelector:sel withObject:v2];
+
+    if (result != NSOrderedSame)
+      return result;
+  }
+  return NSOrderedSame;
+}
+
+/*" 
+  Sort the array using the sort-orderings contained in the argument.
+"*/
+- (void)sortUsingKeyOrderArray:(NSArray *)_orderings {
+  NSEnumerator          *e        = nil;
+  EOSortOrdering        *ordering = nil;
+  EOSortOrderingContext ctx;
+  int                   i;
+  
+  NSAssert([_orderings count] < 10, @"max sort descriptor count is 10!");
+  
+  e = [_orderings objectEnumerator];
+  for (i = 0; (ordering = [e nextObject]) && (i < 10); i++)
+    ctx.orderings[i] = ordering;
+
+  ctx.count = i;
+
+  if (null == nil) null = [EONull null];
+  [self sortUsingFunction:(void *)keyOrderComparator context:&ctx];
+}
+
+@end /* NSMutableArray(EOSortOrdering) */
+
+@implementation EONull(EOSortOrdering)
+
+/*" 
+  Compares the null object, "nil" and "self" are considered of the same order,
+  otherwise null is considered of lower order.
+"*/
+- (int)compareAscending:(id)_object {
+  if (_object == self) return NSOrderedSame;
+  if (_object == nil)  return NSOrderedSame;
+  return NSOrderedDescending;
+}
+
+/*" 
+  Compares the null object, "nil" and "self" are considered of the same order,
+  otherwise null is considered of higher order.
+"*/
+- (int)compareDescending:(id)_object {
+  if (_object == self) return NSOrderedSame;
+  if (_object == nil)  return NSOrderedSame;
+  return NSOrderedAscending;
+}
+
+@end /* EONull(EOSortOrdering) */
+
+@implementation NSNumber(EOSortOrdering)
+
+static Class NumClass = Nil;
+
+- (int)compareAscending:(id)_object {
+  if (_object == self) return NSOrderedSame;
+  if (NumClass == Nil) NumClass = [NSNumber class];
+  
+  if ([_object isKindOfClass:NumClass])
+    return [self compare:_object];
+  else
+    return [_object compareDescending:self];
+}
+
+- (int)compareDescending:(id)_object {
+  int result;
+  
+  result = [self compareAscending:_object];
+  
+  if (result == NSOrderedAscending)
+    return NSOrderedDescending;
+  else if (result == NSOrderedDescending)
+    return NSOrderedAscending;
+  else
+    return NSOrderedSame;
+}
+
+@end /* NSNumber(EOSortOrdering) */
+
+@implementation NSString(EOSortOrdering)
+
+- (int)compareAscending:(id)_object {
+  if (_object == self) return NSOrderedSame;
+  return [self compare:[_object stringValue]];
+}
+- (int)compareCaseInsensitiveAscending:(id)_object {
+  if (_object == self) return NSOrderedSame;
+  return [self caseInsensitiveCompare:[_object stringValue]];
+}
+
+- (int)compareDescending:(id)_object {
+  int result;
+  
+  if (_object == self) return NSOrderedSame;
+  
+  result = [self compareAscending:_object];
+  
+  if (result == NSOrderedAscending)
+    return NSOrderedDescending;
+  else if (result == NSOrderedDescending)
+    return NSOrderedAscending;
+  else
+    return NSOrderedSame;
+}
+
+- (int)compareCaseInsensitiveDescending:(id)_object {
+  int result;
+  
+  if (_object == self) return NSOrderedSame;
+  result = [self compareCaseInsensitiveAscending:_object];
+  
+  if (result == NSOrderedAscending)
+    return NSOrderedDescending;
+  else if (result == NSOrderedDescending)
+    return NSOrderedAscending;
+  else
+    return NSOrderedSame;
+}
+
+@end /* NSString(EOSortOrdering) */
+
+@implementation NSDate(EOSortOrdering)
+
+static Class DateClass = Nil;
+
+- (int)compareAscending:(id)_object {
+  if (_object == self) return NSOrderedSame;
+  if (DateClass == Nil) DateClass = [NSDate class];
+  if (![_object isKindOfClass:DateClass]) return NSOrderedAscending;
+  return [self compare:_object];
+}
+- (int)compareDescending:(id)_object {
+  int result;
+
+  if (_object == self) return NSOrderedSame;
+
+  if (DateClass == Nil) DateClass = [NSDate class];
+  if (![_object isKindOfClass:DateClass]) return NSOrderedDescending;
+  
+  result = [self compare:_object];
+  
+  if (result == NSOrderedAscending)
+    return NSOrderedDescending;
+  else if (result == NSOrderedDescending)
+    return NSOrderedAscending;
+  else
+    return NSOrderedSame;
+}
+
+@end /* NSDate(EOSortOrdering) */
diff --git a/skyrix-core/EOControl/EOValidation.m b/skyrix-core/EOControl/EOValidation.m
new file mode 100644 (file)
index 0000000..2a39d91
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOClassDescription.h"
+#include "EOKeyValueCoding.h"
+#include "EONull.h"
+#include "common.h"
+
+#if !LIB_FOUNDATION_LIBRARY
+
+@interface NSException(UsedSetUI) /* does Jaguar allow -setUserInfo: ? */
+- (void)setUserInfo:(NSDictionary *)_ui;
+@end
+
+#endif
+
+@implementation NSClassDescription(EOValidation)
+
+- (NSException *)validateObjectForDelete:(id)_object {
+  return nil;
+}
+- (NSException *)validateObjectForSave:(id)_object {
+  return nil;
+}
+- (NSException *)validateValue:(id *)_value forKey:(NSString *)_key {
+  return nil;
+}
+
+@end /* NSClassDescription(EOValidation) */
+
+@implementation NSObject(EOValidation)
+
+- (NSException *)validateForDelete {
+  return [[self classDescription] validateObjectForDelete:self];
+}
+
+- (NSException *)validateForInsert {
+  return [self validateForSave];
+}
+- (NSException *)validateForUpdate {
+  return [self validateForSave];
+}
+
+- (NSException *)validateForSave {
+  NSException    *e;
+  NSMutableArray *exceptions;
+  NSArray        *properties;
+  unsigned int i, count;
+  id (*validate)(id, SEL, id *, NSString *);
+  id (*objAtIdx)(id, SEL, unsigned int idx);
+  id (*valForKey)(id, SEL, NSString *);
+  
+  exceptions = nil;
+
+  /* first ask class description to validate object */
+  
+  if ((e = [[self classDescription] validateObjectForSave:self])) {
+    if (exceptions == nil) exceptions = [NSMutableArray array];
+    [exceptions addObject:e];
+  }
+  
+  /* then process all properties */
+  
+  if ((properties = [self allPropertyKeys]) == nil)
+    properties = [NSArray array];
+  
+  validate  = (void *)[self methodForSelector:@selector(validateValue:forKey:)];
+  valForKey = (void *)[self methodForSelector:@selector(valueForKey:)];
+  objAtIdx  = (void *)[properties methodForSelector:@selector(objectAtIndex:)];
+  
+  for (i = 0, count = [properties count]; i < count; i++) {
+    NSString *key;
+    id value, orgValue;
+    
+    key      = objAtIdx(properties, @selector(objectAtIndex:), i);
+    orgValue = value = valForKey(self, @selector(valueForKey:), key);
+    
+    if ((e = validate(self, @selector(validateValue:forKey:), &value, key))) {
+      /* validation of property failed */
+      if (exceptions == nil) exceptions = [NSMutableArray array];
+      [exceptions addObject:e];
+    }
+    else if (orgValue != value) {
+      /* the value was changed during validation */
+      [self takeValue:value forKey:key];
+    }
+  }
+  
+  if ((count = [exceptions count]) == 0) {
+    return nil;
+  }
+  else if (count == 1) {
+    return [exceptions objectAtIndex:0];
+  }
+  else {
+    NSException *master;
+    NSMutableDictionary *ui;
+
+    master = [exceptions objectAtIndex:0];
+    [exceptions removeObjectAtIndex:0];
+    ui = [[master userInfo] mutableCopy];
+    if (ui == nil) ui = [[NSMutableDictionary alloc] init];
+    [ui setObject:exceptions forKey:@"EOAdditionalExceptions"];
+    [master setUserInfo:ui];
+    [ui release]; ui = nil;
+    return master;
+  }
+}
+
+- (NSException *)validateValue:(id *)_value forKey:(NSString *)_key {
+  NSException *e;
+  
+  if ((e = [[self classDescription] validateValue:_value forKey:_key]))
+    return e;
+  
+  /* should invoke key-specific methods, eg -validateBlah: */
+  
+  {
+    /* construct 'validate'(8) + key + ':'(1) */
+    unsigned len;
+    char *buf;
+    SEL  sel;
+
+    len = [_key cStringLength];
+    buf = malloc(len + 14);
+    strcpy(buf, "validate");
+    [_key getCString:&buf[8]];
+    strcat(buf, ":");
+    buf[8] = toupper(buf[8]);
+    
+#if NeXT_RUNTIME
+    sel = sel_getUid(buf);
+#else
+    sel = sel_get_any_uid(buf);
+#endif
+    if (sel) {
+      if ([self respondsToSelector:sel]) {
+        if (buf) free(buf);
+        return [self performSelector:sel withObject:*_value];
+      }
+    }
+    if (buf) free(buf);
+  }
+  return nil;
+}
+
+@end /* NSObject(EOValidation) */
diff --git a/skyrix-core/EOControl/GNUmakefile b/skyrix-core/EOControl/GNUmakefile
new file mode 100644 (file)
index 0000000..0fd72a3
--- /dev/null
@@ -0,0 +1,62 @@
+# $Id$
+
+include ../common.make
+
+LIBRARY_NAME = libEOControl
+
+libEOControl_DLL_DEF = libEOControl.def
+libEOControl_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libEOControl_HEADER_FILES_DIR         = .
+libEOControl_HEADER_FILES_INSTALL_DIR = /EOControl
+
+libEOControl_HEADER_FILES = \
+       EOArrayDataSource.h             \
+       EOClassDescription.h            \
+       EOControl.h                     \
+       EOControlDecls.h                \
+       EODataSource.h                  \
+       EODetailDataSource.h            \
+       EOFetchSpecification.h          \
+       EOGenericRecord.h               \
+       EOGlobalID.h                    \
+       EOKeyGlobalID.h                 \
+       EOKeyValueArchiver.h            \
+       EOKeyValueCoding.h              \
+       EONull.h                        \
+       EOObserver.h                    \
+       EOQualifier.h                   \
+       EOSortOrdering.h                \
+       EOSQLParser.h                   \
+
+libEOControl_OBJC_FILES = \
+       EOAndQualifier.m                \
+       EOArrayDataSource.m             \
+       EOClassDescription.m            \
+       EODataSource.m                  \
+       EODetailDataSource.m            \
+       EOFetchSpecification.m          \
+       EOGenericRecord.m               \
+       EOGlobalID.m                    \
+       EOKeyComparisonQualifier.m      \
+       EOKeyGlobalID.m                 \
+       EOKeyValueArchiver.m            \
+       EOKeyValueCoding.m              \
+       EOKeyValueQualifier.m           \
+       EONotQualifier.m                \
+       EONull.m                        \
+       EOObserver.m                    \
+       EOOrQualifier.m                 \
+       EOQualifier.m                   \
+       EOQualifierParser.m             \
+       EOSortOrdering.m                \
+       EOValidation.m                  \
+       NSArray+EOQualifier.m           \
+       NSObject+EOQualifierOps.m       \
+       EOSQLParser.m                   \
+       EOQualifierVariable.m           \
+       NSObject+QualDesc.m             \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/EOControl/GNUmakefile.preamble b/skyrix-core/EOControl/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..b969716
--- /dev/null
@@ -0,0 +1,31 @@
+# $Id$
+
+libEOControl_INCLUDE_DIRS += -I..
+
+ADDITIONAL_CPPFLAGS += -Wall
+
+# libFoundation, gstep-base
+
+ifeq ($(FOUNDATION_LIB),fd)
+libEOControl_LIBRARIES_DEPEND_UPON += -lFoundation
+endif
+
+ifeq ($(FOUNDATION_LIB),gnu)
+libEOControl_LIBRARIES_DEPEND_UPON += -lgnustep-base
+endif
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libEOControl_PREBIND_ADDR="0xC1000000"
+libEOControl_LDFLAGS += -seg1addr $(libEOControl_PREBIND_ADDR)
+endif
+
+# Windows
+
+ifeq ($(GNUSTEP_TARGET_OS),mingw32)
+libEOControl_LIBRARIES_DEPEND_UPON += -lobjc
+endif
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+libEOControl_LIBRARIES_DEPEND_UPON += -lobjc
+endif
diff --git a/skyrix-core/EOControl/NSArray+EOQualifier.m b/skyrix-core/EOControl/NSArray+EOQualifier.m
new file mode 100644 (file)
index 0000000..7414293
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EOQualifier.h>
+#include "common.h"
+
+@implementation NSArray(EOQualifier)
+
+- (NSArray *)filteredArrayUsingQualifier:(EOQualifier *)_qualifier {
+  NSAutoreleasePool *pool;
+  NSMutableArray *array = nil;
+  NSArray  *result;
+  unsigned i, count;
+
+  pool = [[NSAutoreleasePool alloc] init];
+  result = nil;
+  
+  count = [self count];
+  array = [NSMutableArray arrayWithCapacity:count];
+  for (i = 0, count; i < count; i++) {
+    id o;
+    
+    o = [self objectAtIndex:i];
+    
+    if ([(id<EOQualifierEvaluation>)_qualifier evaluateWithObject:o])
+      [array addObject:o];
+  }
+  result = [array copy];
+  [pool release];
+  return [result autorelease];
+}
+
+@end /* NSArray(EOQualifier) */
diff --git a/skyrix-core/EOControl/NSObject+EOQualifierOps.m b/skyrix-core/EOControl/NSObject+EOQualifierOps.m
new file mode 100644 (file)
index 0000000..cea6703
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOQualifier.h"
+#include "EONull.h"
+#include "common.h"
+
+static EONull *null = nil;
+
+/* values */
+
+@interface NSObject(CompareIFace)
+- (NSComparisonResult)compare:(id)_object;
+@end
+
+@implementation NSObject(ImplementedQualifierComparisons)
+
+- (BOOL)isEqualTo:(id)_object {
+  return [self isEqual:_object];
+}
+- (BOOL)isNotEqualTo:(id)_object {
+  return ![self isEqualTo:_object];
+}
+
+- (BOOL)isLessThan:(id)_object {
+  return [self compare:_object] < 0 ? YES : NO;
+}
+- (BOOL)isGreaterThan:(id)_object {
+  return [self compare:_object] > 0 ? YES : NO;
+}
+- (BOOL)isLessThanOrEqualTo:(id)_object {
+  return [self compare:_object] <= 0 ? YES : NO;
+}
+- (BOOL)isGreaterThanOrEqualTo:(id)_object {
+  return [self compare:_object] >= 0 ? YES : NO;
+}
+
+- (BOOL)doesContain:(id)_object {
+  return NO;
+}
+
+- (BOOL)isLike:(NSString *)_object {
+  return NO;
+}
+- (BOOL)isCaseInsensitiveLike:(NSString *)_object {
+  return NO;
+}
+
+@end /* NSObject(ImplementedQualifierComparisons) */
+
+@implementation NSArray(ImplementedQualifierComparisons)
+
+- (BOOL)doesContain:(id)_object {
+  return [self containsObject:_object];
+}
+
+@end /* NSArray(ImplementedQualifierComparisons) */
+
+@implementation NSString(ImplementedQualifierComparisons)
+
+- (BOOL)isLike:(NSString *)_pattern {
+  NSArray  *cs;
+  unsigned count;
+#if 0  
+  NSString *first, *last;
+#endif  
+  
+  if (null == nil) null = [[EONull null] retain];
+
+  if ((id)_pattern == (id)null)
+    return NO;
+  
+  if ([_pattern isEqual:@"*"])
+    /* all match */
+    return YES;
+  
+  cs    = [_pattern componentsSeparatedByString:@"*"];
+  count = [cs count];
+
+  if (count == 0)
+    return [self isEqual:_pattern];
+  
+  if (count == 1)
+    return [self isEqual:_pattern];
+  
+  if (count == 2) {
+    if ([_pattern hasPrefix:@"*"])
+      return [self hasSuffix:[cs objectAtIndex:1]];
+    if ([_pattern hasSuffix:@"*"])
+      return [self hasPrefix:[cs objectAtIndex:0]];
+  }
+  if (count == 3) {
+    if ([_pattern hasPrefix:@"*"] && [_pattern hasSuffix:@"*"])
+      return [self rangeOfString:[cs objectAtIndex:1]].length == 0
+        ? NO : YES;
+  }
+#if 1
+  {
+    NSEnumerator *enumerator;
+    int          idx;
+    int          len;
+    NSString     *str;
+
+    idx        = 0;
+    len        = [self length];
+    enumerator = [cs objectEnumerator];
+    
+    while ((str = [enumerator nextObject]) && idx < len) {
+      NSRange r;
+      
+      if ([str length] == 0)
+        continue;
+      
+      r = NSMakeRange(idx, ([self length] - idx));
+      r = [self rangeOfString:str options:0 range:r];
+      if (r.length == 0)
+        return NO;
+      
+      idx += r.length;
+    }
+    return [enumerator nextObject] ? NO : YES;
+  }
+#else
+  first = [cs objectAtIndex:0];
+  last  = [cs lastObject];
+
+  if (![self hasPrefix:first])
+    return NO;
+  if (![self hasSuffix:last])
+    return NO;
+
+  /* to be completed (match interior stuff, match '?') */
+  
+  return YES;
+#endif
+  return NO;
+}
+
+- (BOOL)isCaseInsensitiveLike:(NSString *)_pattern {
+  return [[self lowercaseString] isLike:[_pattern lowercaseString]];
+}
+
+@end /* NSString(ImplementedQualifierComparisons) */
+
+@implementation NSNumber(ImplementedQualifierComparisons)
+
+- (BOOL)isEqualTo:(id)_object {
+  if (_object == nil) return NO;
+  if (_object == self) return YES;
+  return [self isEqual:_object];
+}
+- (BOOL)isNotEqualTo:(id)_object {
+  if (_object == nil) return YES;
+  return ![self isEqualTo:_object];
+}
+
+- (BOOL)isLessThan:(id)_object {
+  if (_object == nil)  return YES;
+  if (_object == self) return NO;
+  return [self compare:_object] < 0 ? YES : NO;
+}
+- (BOOL)isGreaterThan:(id)_object {
+  if (_object == nil) return NO;
+  if (_object == self) return NO;
+  return [self compare:_object] > 0 ? YES : NO;
+}
+- (BOOL)isLessThanOrEqualTo:(id)_object {
+  if (_object == nil)  return YES;
+  if (_object == self) return YES;
+  return [self compare:_object] <= 0 ? YES : NO;
+}
+- (BOOL)isGreaterThanOrEqualTo:(id)_object {
+  if (_object == nil)  return NO;
+  if (_object == self) return YES;
+  return [self compare:_object] >= 0 ? YES : NO;
+}
+
+@end /* NSNumber(ImplementedQualifierComparisons) */
+
+@implementation NSDate(ImplementedQualifierComparisons)
+
+#define CHECK_NULL(__VAL__, __RES__) \
+  {if (null == nil) null = [[EONull null] retain];} \
+  if (__VAL__ == nil || __VAL__ == null) return __RES__
+
+- (BOOL)isLessThan:(id)_object {
+  CHECK_NULL(_object, NO);
+  return [self compare:_object] < 0 ? YES : NO;
+}
+- (BOOL)isGreaterThan:(id)_object {
+  CHECK_NULL(_object, YES);
+  return [self compare:_object] > 0 ? YES : NO;
+}
+
+- (BOOL)isLessThanOrEqualTo:(id)_object {
+  CHECK_NULL(_object, NO);
+  return [self compare:_object] <= 0 ? YES : NO;
+}
+- (BOOL)isGreaterThanOrEqualTo:(id)_object {
+  CHECK_NULL(_object, YES);
+  return [self compare:_object] >= 0 ? YES : NO;
+}
+
+@end /* NSDate(ImplementedQualifierComparisons) */
diff --git a/skyrix-core/EOControl/NSObject+QualDesc.m b/skyrix-core/EOControl/NSObject+QualDesc.m
new file mode 100644 (file)
index 0000000..3f5b726
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "EONull.h"
+#include "common.h"
+
+@implementation NSObject(QualifierDescription)
+
+- (NSString *)qualifierDescription {
+  return [self description];
+}
+
+@end /* NSObject(QualifierDescription) */
+
+@implementation NSString(QualifierDescription)
+
+- (NSString *)qualifierDescription {
+  return [NSString stringWithFormat:@"'%@'", self];
+}
+
+@end /* NSString(QualifierDescription) */
+
+@implementation EONull(QualifierDescription)
+
+- (NSString *)qualifierDescription {
+  return @"nil";
+}
+
+@end /* EONull(QualifierDescription) */
diff --git a/skyrix-core/EOControl/README b/skyrix-core/EOControl/README
new file mode 100644 (file)
index 0000000..8b577a4
--- /dev/null
@@ -0,0 +1,21 @@
+# $Id$
+
+EOControl
+=========
+
+TODO: Intro
+
+Qualifiers / Sorting / Fetch-Spec
+=================================
+
+TODO: explain
+
+Datasources
+===========
+
+TODO: explain
+
+Primary Keys
+============
+
+TODO: explain
diff --git a/skyrix-core/EOControl/SxCore-EOControl.graffle b/skyrix-core/EOControl/SxCore-EOControl.graffle
new file mode 100644 (file)
index 0000000..d3f4957
--- /dev/null
@@ -0,0 +1,1474 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+       <key>CanvasColor</key>
+       <dict>
+               <key>w</key>
+               <real>1.000000e+00</real>
+       </dict>
+       <key>ColumnAlign</key>
+       <integer>0</integer>
+       <key>ColumnSpacing</key>
+       <real>5.400000e+01</real>
+       <key>GraphDocumentVersion</key>
+       <integer>2</integer>
+       <key>GraphicsList</key>
+       <array>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 414}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2788</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOQualifierVariable}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 351}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2787</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOGenericRecord.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOGenericRecord}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{243, 270}, {135, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2782</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOKeyGlobalID.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOKeyGlobalID}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{387, 270}, {135, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2783</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOGlobalID.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOTemporaryGlobalID}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{315, 234}, {135, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2784</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOGlobalID.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOGlobalID}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2782</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2785</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{364.5, 252}</string>
+                                               <string>{328.5, 270}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2784</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2783</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2786</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{400.5, 252}</string>
+                                               <string>{436.5, 270}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2784</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>2781</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 315}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2780</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOSortOrdering.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOSortOrdering}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 162}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2779</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOObserver.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOObserverCenter}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{99, 585}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2762</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EONotQualifier}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{297, 630}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2763</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOAndQualifier}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{315, 594}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2764</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOKeyValueQualifier}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{333, 558}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2765</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOOrQualifier}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{99, 504}, {135, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2766</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 EOQualifierEvaluation}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{279, 504}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2767</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOQualifier}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{99, 630}, {171, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2768</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOKeyComparisonQualifier}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2762</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2769</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{166, 522}</string>
+                                               <string>{162.5, 585}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2766</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2762</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2770</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{322, 522}</string>
+                                               <string>{182, 585}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2767</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2763</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2771</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{180.321, 522}</string>
+                                               <string>{346.179, 630}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2766</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2763</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2772</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{343.286, 522}</string>
+                                               <string>{358.714, 630}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2767</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2764</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2773</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{187.65, 522}</string>
+                                               <string>{356.85, 594}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2766</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2764</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2774</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{345.6, 522}</string>
+                                               <string>{374.4, 594}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2767</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2765</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2775</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{204.75, 522}</string>
+                                               <string>{357.75, 558}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2766</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2765</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2776</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{351, 522}</string>
+                                               <string>{387, 558}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2767</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2768</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2777</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{167.786, 522}</string>
+                                               <string>{183.214, 630}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2766</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2768</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2778</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{330.75, 522}</string>
+                                               <string>{195.75, 630}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2767</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>2761</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{243, 342}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2759</integer>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSClassDescription}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{243, 378}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2760</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOClassDescription.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOClassDescription}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>2758</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{387, 342}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2755</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOObserver.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 EOObserving}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{387, 378}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2756</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOObserver.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EODelayedObserver}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{387, 414}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2757</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOObserver.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOObserverProxy}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>2754</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{252, 153}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2749</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EODetailDataSource.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EODetailDataSource}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{387, 153}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2750</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOArrayDataSource.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOArrayDataSource}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{324, 117}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>2751</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EODataSource.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EODataSource}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2749</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2752</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{369, 135}</string>
+                                               <string>{333, 153}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2751</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2750</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>2753</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{402.75, 135}</string>
+                                               <string>{434.25, 153}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>2751</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>2748</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 126}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2747</integer>
+                       <key>Link</key>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 }</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 99}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2746</integer>
+                       <key>Link</key>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 }</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 288}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2745</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOFetchSpecification.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOFetchSpecification}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 189}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2744</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOObserver.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EODelayedObserverQueue}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 378}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2743</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EONull.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EONull}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 252}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2742</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOKeyValueArchiver.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOKeyValueUnarchiver}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 225}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2741</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOKeyValueArchiver.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOKeyValueArchiver}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2760</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2740</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{306, 360}</string>
+                               <string>{306, 378}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2759</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2756</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2739</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{450, 360}</string>
+                               <string>{450, 378}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2755</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2757</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2738</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{450, 396}</string>
+                               <string>{450, 414}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2756</integer>
+                       </dict>
+               </dict>
+       </array>
+       <key>GridInfo</key>
+       <dict/>
+       <key>HPages</key>
+       <integer>1</integer>
+       <key>ImageCounter</key>
+       <integer>1</integer>
+       <key>IsPalette</key>
+       <string>NO</string>
+       <key>Layers</key>
+       <array>
+               <dict>
+                       <key>Lock</key>
+                       <string>NO</string>
+                       <key>Name</key>
+                       <string>Layer 1</string>
+                       <key>Print</key>
+                       <string>YES</string>
+                       <key>View</key>
+                       <string>YES</string>
+               </dict>
+       </array>
+       <key>LayoutInfo</key>
+       <dict>
+               <key>AutoAdjust</key>
+               <string>YES</string>
+               <key>HierarchicalOrientation</key>
+               <integer>0</integer>
+               <key>MagneticFieldCenter</key>
+               <string>{0, 0}</string>
+       </dict>
+       <key>MagnetsEnabled</key>
+       <string>YES</string>
+       <key>PageBreakColor</key>
+       <dict>
+               <key>w</key>
+               <real>3.333333e-01</real>
+       </dict>
+       <key>PageBreaks</key>
+       <string>YES</string>
+       <key>PageSetup</key>
+       <data>
+       BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE
+       hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpEpKEhIQITlNT
+       dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE
+       mZkOTlNCb3R0b21NYXJnaW6GkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVlAJSEASqEhAFm
+       nSSGkoSZmQtOU1BhcGVyTmFtZYaShJmZBkxldHRlcoaShJmZD05TUHJpbnRBbGxQYWdl
+       c4aShJ2chIQBc54AhpKEmZkNTlNSaWdodE1hcmdpboaShJ2cn50khpKEmZkITlNDb3Bp
+       ZXOGkoSdnISEAVOfAYaShJmZD05TU2NhbGluZ0ZhY3RvcoaShJ2chIQBZKABhpKEmZkL
+       TlNGaXJzdFBhZ2WGkoSdnKmfAYaShJmZFE5TVmVydGljYWxQYWdpbmF0aW9uhpKEnZyk
+       ngCGkoSZmRVOU0hvcml6b25hbFBhZ2luYXRpb26GkoSdnKSeAIaShJmZFk5TSG9yaXpv
+       bnRhbGx5Q2VudGVyZWSGkoSdnKSeAYaShJmZDE5TTGVmdE1hcmdpboaShJ2cn50khpKE
+       mZkNTlNPcmllbnRhdGlvboaShJ2cpJ4AhpKEmZkZTlNQcmludFJldmVyc2VPcmllbnRh
+       dGlvboaSo5KEmZkKTlNMYXN0UGFnZYaShJ2chJeXgn////+GkoSZmQtOU1RvcE1hcmdp
+       boaShJ2cn50khpKEmZkUTlNWZXJ0aWNhbGx5Q2VudGVyZWSGkrSShJmZC05TUGFwZXJT
+       aXplhpKEnpyEhAx7X05TU2l6ZT1mZn2hgQJkgQMYhoaG
+       </data>
+       <key>RowAlign</key>
+       <integer>0</integer>
+       <key>RowSpacing</key>
+       <real>8.999991e+00</real>
+       <key>VPages</key>
+       <integer>1</integer>
+       <key>WindowInfo</key>
+       <dict>
+               <key>Frame</key>
+               <string>{{67, 21}, {821, 897}}</string>
+               <key>VisibleRegion</key>
+               <string>{{-133, -50}, {806, 820}}</string>
+               <key>Zoom</key>
+               <string>1</string>
+       </dict>
+</dict>
+</plist>
diff --git a/skyrix-core/EOControl/TODO b/skyrix-core/EOControl/TODO
new file mode 100644 (file)
index 0000000..8de3631
--- /dev/null
@@ -0,0 +1,6 @@
+# $Id: TODO,v 1.1 2003/09/01 17:16:19 helge Exp $
+
+TODOs:
+
+EOSQLParser.m
+- remove usage of stringByReplacingString: which is not available on MacOSX
diff --git a/skyrix-core/EOControl/Version b/skyrix-core/EOControl/Version
new file mode 100644 (file)
index 0000000..5cae3ac
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=46
diff --git a/skyrix-core/EOControl/common.h b/skyrix-core/EOControl/common.h
new file mode 100644 (file)
index 0000000..69c3bb4
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOControl_COMMON_H__
+#define __EOControl_COMMON_H__
+
+#include <stdlib.h>
+#include <objc/Protocol.h>
+
+#import <Foundation/Foundation.h>
+#import <Foundation/NSObjCRuntime.h>
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+#  define objc_free(__mem__)    free(__mem__)
+#  define objc_malloc(__size__) malloc(__size__)
+#  define objc_calloc(__cnt__, __size__) calloc(__cnt__, __size__)
+#  define objc_realloc(__ptr__, __size__) realloc(__ptr__, __size__)
+#  ifndef sel_eq
+#    define sel_eq(sela,selb) (sela==selb?YES:NO)
+#  endif
+#endif
+
+#ifndef ASSIGN
+#  define ASSIGN(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) [__value retain]; \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+#ifndef ASSIGNCOPY
+#  define ASSIGNCOPY(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) __value = [__value copy];   \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+
+// ******************** common functions ********************
+
+static inline char* Strdup(const char*) __attribute__((unused));
+static inline char* Strcpy (char*, const char*) __attribute__((unused));
+static inline char* Strncpy (char*, const char*, unsigned)
+    __attribute__((unused));
+static inline char* Strcat (char*, const char*) __attribute__((unused));
+static inline char* Strncat (char*, const char*, unsigned)
+    __attribute__((unused));
+static inline int Strcmp(const char*, const char*) __attribute__((unused));
+static inline int Strncmp(const char*, const char*, unsigned)
+    __attribute__((unused));
+static inline int Atoi(const char*) __attribute__((unused));
+static inline long Atol(const char*) __attribute__((unused));
+
+#define Malloc  malloc
+#define Calloc  calloc
+#define Realloc realloc
+#define Free(__p__)  if(__p__) { free(__p__); __p__ = NULL; }
+
+#define Strlen(__s__) (__s__?strlen(__s__):0)
+
+static inline char *Strdup(const char *s) {
+  return s ? strcpy(Malloc(strlen(s) + 1), s) : NULL;
+}
+static inline char* Strcpy (char *d, const char *s) {
+  return s && d ? strcpy(d, s) : d;
+}
+static inline char* Strncpy (char* d, const char* s, unsigned size) {
+  return s && d ? strncpy(d, s, size) : d;
+}
+static inline char* Strcat (char* d, const char* s) {
+  return s && d ? strcat(d, s) : d;
+}
+static inline char* Strncat (char* d, const char* s , unsigned size) {
+  return s && d ? strncat(d, s , size) : d;
+}
+
+static inline int Strcmp(const char* p, const char* q) {
+  if(p == NULL) {
+    if(!q)
+      return 0;
+    else return -1;
+  }
+  else {
+    if(!q)
+      return 1;
+    else return strcmp(p, q);
+  }
+}
+
+static inline int Strncmp(const char* p, const char* q, unsigned size) {
+  if(!p) {
+      if(!q)
+          return 0;
+      else return -1;
+  }
+  else {
+      if(!q)
+          return 1;
+      else return strncmp(p, q, size);
+  }
+}
+
+static inline int Atoi(const char* str) {
+  return str ? atoi(str) : 0;
+}
+static inline long Atol(const char *str) {
+  return str ? atol(str) : 0;
+}
+
+#ifndef MAX
+#define MAX(a, b) \
+    ({typedef _ta = (a), _tb = (b);   \
+       _ta _a = (a); _tb _b = (b);     \
+       _a > _b ? _a : _b; })
+#endif
+
+#ifndef MIN
+#define MIN(a, b) \
+    ({typedef _ta = (a), _tb = (b);   \
+       _ta _a = (a); _tb _b = (b);     \
+       _a < _b ? _a : _b; })
+#endif
+
+static inline char *Ltoa(long nr, char *str, int base) {
+  char buff[34], rest, is_negative;
+  int ptr;
+
+  ptr = 32;
+  buff[33] = '\0';
+  if (nr < 0) {
+    is_negative = 1;
+    nr = -nr;
+  }
+  else
+    is_negative = 0;
+
+  while (nr != 0) {
+    rest = nr % base;
+    if (rest > 9)
+      rest += 'A' - 10;
+    else
+      rest += '0';
+    buff[ptr--] = rest;
+    nr /= base;
+  }
+  if (ptr == 32)
+    buff[ptr--] = '0';
+  if (is_negative)
+    buff[ptr--] = '-';
+
+  Strcpy(str, &buff[ptr+1]);
+
+  return(str);
+}
+
+#endif /* __EOControl_COMMON_H__ */
diff --git a/skyrix-core/EOControl/libEOControl.def b/skyrix-core/EOControl/libEOControl.def
new file mode 100644 (file)
index 0000000..5180d59
--- /dev/null
@@ -0,0 +1,5 @@
+EXPORTS
+       EOCompareAscending;
+       EOCompareDescending;
+       EOCompareCaseInsensitiveAscending;
+       EOCompareCaseInsensitiveDescending;
diff --git a/skyrix-core/GNUmakefile b/skyrix-core/GNUmakefile
new file mode 100644 (file)
index 0000000..2de4288
--- /dev/null
@@ -0,0 +1,23 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+PACKAGE_NAME=skyrix-core
+VERSION=4.2.0
+
+SUBPROJECTS = \
+       EOControl       \
+       NGExtensions    \
+       NGStreams       \
+       NGMime          \
+       NGLdap          \
+       NGiCal          \
+
+include $(GNUSTEP_MAKEFILES)/aggregate.make
+
+autodoc :
+       (cd EOControl;    $(MAKE) autodoc)
+       (cd NGExtensions; $(MAKE) autodoc)
+       (cd NGStreams;    $(MAKE) autodoc)
+       (cd NGMime;       $(MAKE) autodoc)
+       (cd NGLdap;       $(MAKE) autodoc)
diff --git a/skyrix-core/NGExtensions/.cvsignore b/skyrix-core/NGExtensions/.cvsignore
new file mode 100644 (file)
index 0000000..53fe1e1
--- /dev/null
@@ -0,0 +1,3 @@
+shared_debug_obj
+shared_obj
+.gdb_history
diff --git a/skyrix-core/NGExtensions/COPYING b/skyrix-core/NGExtensions/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-core/NGExtensions/COPYRIGHT b/skyrix-core/NGExtensions/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-core/NGExtensions/ChangeLog b/skyrix-core/NGExtensions/ChangeLog
new file mode 100644 (file)
index 0000000..8496314
--- /dev/null
@@ -0,0 +1,1114 @@
+2004-08-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGCalendarDateRange.m: added range category on NSArray, added some
+         methods to daterange (v4.2.102)
+
+2004-08-16  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * added NGCalendarDateRange class (v4.2.101)
+
+2004-07-26  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSObject+Values.m([NSString -unsignedCharValue]): added
+         a specific implementation for NSString to support KVC bool operations
+         (because BOOL values are represented as 'unsigned char' values at
+         runtime, [self takeValue:@"YES" ...] coercion did fail for bool
+         methods) (v4.2.100)
+
+2004-07-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOExt.subproj/EOKeyMapDataSource.m: fixed a gcc 3.4 warning (v4.2.99)
+
+2004-07-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSString+Encoding.m: improved error logs in case an
+         iconv buffer is too small (v4.2.98)
+
+2004-06-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGExtensions/FdExt.subproj/NGPropertyListParser.m: minor cleanups to
+         log messages (v4.2.97)
+
+2004-06-22  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.96
+
+       * FdExt.subproj/NSArray+enumerator.m: fixed a bug with array capacity
+         initialization (used an uninitialized variable leading to a virtual
+         memory exhausted on gstep-base)
+
+       * FdExt.subproj/NGPropertyListParser.m (_makeException): be more
+         tolerant about nil results in NSString creation (fixes an exception
+         with gstep-base)
+
+2004-06-17  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSURL+misc.m: add a hack to work around a bug in NSURL
+         on Cocoa Foundation, added a lot of debug logs (v4.2.95)
+
+2004-06-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGObjCRuntime.m: fixed hack for dynamic class loading with gcc 3.4
+         (type signature of the privates changed or is more strictly checked)
+         (v4.2.94)
+
+       * v4.2.93
+
+       * GNUmakefile: removed NGCString from compilation
+
+       * NGExtensions/NGExtensions.h: do not include NGCString.h
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGExtensions/GNUmakefile.preamble: added prebinding (v4.2.92)
+
+2004-06-08  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj: include NGPropertyListParser categories when compiling
+         for libFoundation (v4.2.91)
+
+       * v4.2.90
+
+       * GNUmakefile.preamble: fixed path to DOM library, added explicit 
+         dependency to SaxObjC for MacOSX
+
+       * NGBundleManager.m: logging can now be enabled using the 
+         NGBundleManagerDebugEnabled default, some code cleanups
+
+2004-06-07  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * NGExtensions/NSString+misc.[hm]: improved, now works with any object
+         which supports KVC (v4.2.89)
+       
+2004-06-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGBundleManager.m: fixed gcc 3.4 warnings (v4.2.88)
+
+2004-06-05  Stephane Corthesy  <stephane@sente.ch>
+
+       * NGBundleManager.m(-bundleForClass:): added basic support for classes
+         defined in frameworks (v4.2.87)
+
+2004-06-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGObjCRuntime.m: added a hack to make NGObjCRuntime.m compile with
+         gcc 3.4.0 (v4.2.86)
+
+2004-06-01  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * NGExtensions/NSCalendarDate+misc.h,
+         FdExt.subproj/NSCalendarDate+misc.m: new method -(BOOL)isInLeapYear,
+         utilized by rewritten -(int)numberOfDaysInMonth. 
+         -(NSCalendarDate *)lastDayOfMonth uses -(int)numberOfDaysInMonth now
+         instead of the other way round as before. -lastDayOfMonth turned
+         out to be non-portable to gnustep-base, the new implementation works
+         with all foundation and is far more time/memory efficient. (v4.2.85)
+
+2004-05-17  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSNull+misc.m: added 'NSNullAbortOnMessage' default to
+         enable abort()'s if a message is sent to NSNull (useful for debugging
+         NSNull issues on MacOSX (v4.2.84)
+
+2004-05-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGObjCRuntime.m: fixed a bug in GNU runtime method addition, added
+         a class enumerator for the GNU runtime (v4.2.83)
+
+       * NGObjCRuntime.m: added an implementation of +addMethods for the
+         Apple runtime (v4.2.82)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.81)
+
+2004-05-04  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * EOExt.subproj/EOSortOrdering+plist.m: fixed wrong mappings for
+         case insensitive sortOrderings (v4.2.80)
+
+2004-05-01  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * v4.2.79
+
+       * EOExt.subproj/EOSortOrdering+plist.m: fixed wrong key argument to
+         initWithKey:selector: in initWithDictionary:.
+
+       * EOExt.subproj/EOFetchSpecification+plist.m: testing for
+         respondsToSelector(objectEnumerator) matches dictionaries as well,
+         resulting in improper behavior. Narrowed to testing for kind of
+         NSArray now.
+
+2004-05-01  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * NGObjCRuntime.m: improved support for Apple runtime (v4.2.78)
+       
+2004-04-07  Jean-Alexis Montignies  <ja@sente.ch>
+       
+       * NGHashMap: added because used in NGObjWeb
+         -asDictionaryWithArraysForValues (v4.2.77)
+       
+2004-04-07  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGExtensions/NSString+Encoding.h: exported 
+         +stringEncodingForEncodingNamed: on Cocoa (v4.2.76)
+
+2004-04-01  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * NGHashMap: some code cleanups, made the code a bit more fault
+         tolerant (check for some NULL references, as suggest by Jean-Alexis 
+         Montignies), fixed missing class in header file (v4.2.75)
+       
+2004-03-24  Helge Hess  <helge.hess@skyrix.com>
+
+       * FdExt: added NSString+German category which contains some methods to
+         deal with ASCII representations of German umlauts (useful for some
+         searches) (v4.2.74)
+
+2004-03-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.73
+
+       * FdExt.subproj/NSString+HTMLEscaping.m: added escaping for some
+         missing umlauts
+
+       * FdExt.subproj/NSObject+Values.m: minor speed optimization to NSString
+         -boolValue
+
+2004-03-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOExt: moved in property list initializer methods from EOControl (to
+         make them available for GDL2)
+
+2004-03-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGBundleManager.m: print an error log if we were unable to get the 
+         system NSUserDefaults object, as it currently happens with 
+         gstep-base, added a hack not to create the NGBundleManager if the
+         NSUserDefaults object could not be retrieved (v4.2.71)
+
+2004-03-13  Helge Hess  <helge.hess@opengroupware.org>
+
+       * EOFilterDataSource: code cleanups, added -description method 
+         (v4.2.70)
+
+2004-03-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGBundleManager.m: disabled a debug log (v4.2.69)
+
+2004-03-10  Donald Duck  <helge.hess@opengroupware.org>
+
+       * NGBundleManager.m: print a warning if the NGBundlePath default is not
+         configured (v4.2.68)
+
+2004-03-08  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSException+misc.m: added a -copyWithZone: method,
+         as used by the XML-RPC client (v4.2.67)
+
+2004-03-01  Helge Hess  <helge.hess@skyrix.com>
+
+       * FdExt.subproj/NSException+misc.m: added a -setReason: implementation
+         for gnustep-base - thanks to chunsj for pointing that out (v4.2.66)
+
+2004-02-24  Helge Hess  <helge@mac.in.skyrix.com>
+
+       * FdExt.subproj/NSNull+misc.m: added -descriptionWithLocale: on MacOSX
+         (v4.2.65)
+
+2004-02-23  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSNull+misc.m: added -descriptionWithLocale: for
+         Cocoa Foundation (v4.2.65)
+
+       * FdExt.subproj/NSNull+misc.m: added various "ignore that" methods for 
+         MacOSX: -isEqualToString:, -characterAtIndex:, 
+         -descriptionWithLocale:indent:, added -respondsToSelector: (always
+         returns YES on MacOSX) - Note: this is to be considered a workaround,
+         we need to find out, why OGo calls such methods on NSString with
+         Cocoa Foundation (v4.2.64)
+
+2004-02-19  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSCalendarDate+misc.m, NSString+Ext.m: added KVC 
+         default handlers for Cocoa Foundation (avoids some exceptions, 
+         libFoundation is much more tolerant regarding missing KVC keys than 
+         Cocoa) (v4.2.63)
+
+2004-02-13  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.62
+
+       * NGBundleManager.m: do not report missing resources on MacOSX (reduced
+         debug level)
+
+       * FdExt.subproj/NSArray+enumerator.m: added implementation of 
+         -map:... (to be considered deprecated ...) for the MacOSX port
+
+2004-02-12  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGBundleManager.m: disabled class-hook debugging on OSX (v4.2.61)
+
+2004-02-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGStack.m: fixed minor compilation warning on OSX (v4.2.60)
+
+2004-02-08  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSString+Encoding.m: cleanups, use ucs-2-internal
+         instead of ucs-2 on non-Linux platforms and detect platform byte
+         ordering and use ucs-2le or ucs-2be depending on that - should fix
+         OGo bugs #580 (does not fix #145) (v4.2.59)
+
+2004-01-23  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSFileManager+Extensions.m: renamed category to
+         ExtendedFileManagerImp to avoid gcc warnings (v4.2.58)
+
+2003-12-28  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGBundleManager.m: minor cleanups (v4.2.57)
+
+2003-11-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSString+misc.m, 
+         FdExt.subproj/NSMethodSignature+misc.m: applied some minor patches
+         for gstep-base provided by chunsj@embian.com (v4.2.56)
+
+2003-11-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSString+URLEscaping.m: added UTF-8 URL escaping
+         (v4.2.55)
+
+       * v4.2.54
+       
+       * NSString+URLEscaping.m: added default 'NGUseUTF8AsURLEncoding' to
+         unescape URL strings as UTF-8 entities. This is usually the right
+         thing to do for WebDAV servers like ZideStore. Note that encoding
+         is still always done in ISO-Latin-1 (to be fixed)
+       
+       * FdExt.subproj/NSString+misc.m: moved the various string escaping
+         implementations (URL, HTML and XML) into separate NSString categories
+
+2003-11-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * FdExt.subproj/NSString+Formatting.m: minor speed and MacOSX
+         compatibility improvements (v4.2.53)
+
+2003-10-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGBase64Coding.m: bad day, fixed the new -dataByDecodingBase64
+         (v4.2.52)
+
+       * NGBase64Coding.m: added -dataByDecodingBase64 to NSString, since
+         a base64 string can (of course!) contain zero bytes. 
+         -stringByDecodingBase64 now returns nil if it encounteres such a 
+         situation (v4.2.51)
+
+       * NGBase64Coding.m: fixed a major bug in the base64 encoding (which did
+         not handle empty values properly!) (v4.2.50)
+
+2003-10-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.49
+
+       * FdExt.subproj/NSException+misc.m: fixed ZNeK's setReason:
+         implementation for gstep-make
+
+       * moved NGPropertyListParser.h to NGExtensions and made it a
+         public header
+
+2003-10-13  Helge Hess  <helge@opengroupware.org>
+
+       * compile and link NGPropertyListParser in case we are not on
+         libFoundation, compile and link FileObjectHolder on Cocoa
+         (v4.2.48)
+
+2003-10-11  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * FdExt.subproj/NSException+misc.m: Provided implementation for
+         setReason: (as needed with COCOA_Foundation_LIBRARY) and provided
+         interface declaration in case of GNUSTEP_BASE_LIBRARY. (v4.2.47)
+
+2003-09-07  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * v4.2.46
+
+       * NGBundleManager.m, NGHashMap.m, NGObjCRuntime.m, NGStack.m,
+         EOExt.subproj/EOQualifier+CtxEval.m, FdExt.subproj/NSNull+misc.m,
+         FdExt.subproj/NSProcessInfo+misc.m, FdExt.subproj/NSString+misc.m:
+         Fixed outdated references to FoundationExt and pointed to
+         NGExtensions where appropriate.
+         Also, added defines for NeXT_RUNTIME.
+       * EOExt.subproj/EOKeyMapDataSource.m: Fixed problem with method
+         not returning value when not void.
+
+2003-09-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.45
+
+       * NGExtensions.h: do not include FoundationExt but NGObjectMacros.h
+          instead
+
+        * added NGObjectMacros.h which contains the RC macros 
+
+       * FdExt.subproj/NSString+Formatting.m: cache the NSString class
+          object, use less autorelease, fixed a nil-parameter bug on MacOSX,
+          added some hacks to implement unicode format scanning (v4.2.44)
+
+2003-09-06  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * v4.2.43
+
+       * GNUmakefile.preamble: added iconv to the list of necessary
+         libraries on FreeBSD (4.x/5.x)
+
+       * FdExt.subproj/NSString+Encoding.m: do not use iconv on Apple,
+         instead use CoreFoundation's
+         CFStringConvertIANACharSetNameToEncoding()
+
+2003-07-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.42
+
+       * FdExt.subproj/NSData+gzip.m: removed dependency on zutil.h,
+         patch provided by Filip Van Raemdonck
+
+       * NGHashMap.m, NSNull+misc.m: fixed gstep-base compilation problems, 
+         patch provided by Filip Van Raemdonck
+
+Wed Jul 16 16:03:47 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * FdExt.subproj/NSString+Formatting.m: use ISERIES/USE_VA_LIST_PTR 
+        defines to handle va_list structures (v4.2.41)
+
+Wed Jul 16 15:00:16 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * FdExt.subproj/NSString+Formatting.m: fixed a bug regarding iSeries 
+         port, copy va_list structure before give it to a function and read 
+         one argument from the original va_list (v4.2.40)
+
+Tue Jul 15 21:09:26 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * FdExt.subproj/NSString+Formatting.m: replace *va_list function 
+         arguments with va_list (iSeries port) (v4.2.39)
+
+Mon Jul 14 18:21:55 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGBundleManager.m: cache bundle using name.extension instead of name 
+         only (v4.2.38)
+
+2003-06-23  Helge Hess  <helge.hess@skyrix.com>
+       
+       * NGFileManager.m: ignore empty strings during path standardization
+         (reason for publisher bug 1778) (v4.2.37)
+       
+2003-06-06  Jan Reichmann <jr@skyrix.com>
+       
+       * NSString+Encoding.m: added a category to encode/decode string from
+         arbitary encoding formats using libiconv (v4.2.36)
+
+2003-05-26  Helge Hess  <helge.hess@skyrix.com>
+
+       * updated MacOSX port, some smaller modification to compile without 
+         FoundationExt (exceptions, memory allocation, plist parsing) 
+         (v4.2.35)
+
+2003-05-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.34
+
+       * NGRuleEngine.subproj/NGRuleContext.m: added a flag to enable 
+         debugging on a per-context base, added some logging
+
+       * NGRuleEngine.subproj/NGRuleModel.m: during sorting of rules also 
+         consider how specific a qualifier is (by calling -count on the 
+         qualifier)
+
+       * v4.2.33
+
+       * NGRuleEngine: fixed default priorities
+       
+       * NGRuleEngine/NGRuleParser: fixed bug in rule-model parsing, added
+         a "reset" method to reset stored variables
+
+       * NGRuleContext: added some constructors (v4.2.32)
+
+2003-05-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGRuleEngine: added parsing of rule-models (v4.2.31)
+
+       * v4.2.30
+       
+       * EOExt.subproj/NSArray+EOGrouping.m: fixed a bug introduced by
+         clean ups in v4.2.26
+
+       * EOExt: added EOTrueQualifier (used in rule system for *true*)
+
+       * added simple NGRule parser
+
+2003-05-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * FdExt.subproj/NSString+misc.m: added a new scanning method,
+         -rangeOfString:skipQuotes:escapedByChar: for easier parsing of
+         common quoted languages (v4.2.29)
+
+2003-05-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved headers to "NGExtensions" subdirectory (v4.2.28)
+
+       * started to add NGRuleEngine, a KVC/EOQualifier based evaluation 
+         system (v4.2.27)
+
+       * cleaned up source organization, created three subprojects,
+         FdExt, EOExt and XmlExt for Foundation, EOControl and skyrix-xml
+         additions (v4.2.26)
+
+2003-04-09  GNUstep User  <helge.hess@skyrix.com>
+
+       * fixed unsigned/signed warnings for gcc 3.3 (v4.2.25)
+
+       * NSProcessInfo+misc.m: small fix for gstep-base (use 
+         -stringByTrimmingSpaces instead of ..WhiteSpaces..) (v4.2.24)
+
+2003-04-01  GNUstep User  <helge.hess@skyrix.com>
+
+       * NGObjCRuntime.m: added a hack for GNUstep Base with the incomplete
+         FoundationExt library (v4.2.23)
+
+2003-04-01  Helge Hess  <helge.hess@skyrix.com>
+
+       * added compilation support for GNUstep base (v4.2.22)
+
+2003-03-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSString+misc.m: do not encode umlaut entities in XML output 
+         (v4.2.21)
+
+2003-03-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGBase64Coding.m: added -stringByEncodingBase64 and 
+         -stringByDecodingBase64 to NSData (v4.2.20)
+
+Tue Mar  4 13:53:40 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * GNUmakefile, NGFileManager+JS.m: add JS functions 
+         (copied from NGJavaScript/Core+JS/NGFileManager+JS.m) (bug 712) 
+          (v4.2.19)
+
+Tue Feb  4 11:56:34 2003    <jan@skyrix.com>
+
+       * NGHashMap.m: disable throwing exception in objectForKey: if 
+         more than one object exsist, print out a warning only (bug 981) 
+         (v4.2.18)
+
+Fri Jan 17 16:43:13 2003  Martin Hoerning  <mh@skyrix.com>
+
+       * NSCalendarDate+misc.m 
+       ([NSCalendarDate -dateByAddingYears:months:days:]): 
+         fixed month overflow (bug 871) (v4.2.17)
+
+2003-01-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGBundleManager.m: do not print a warning if the principal class of a
+         bundle could not be found (since the bundle might have none ...) and
+         use the NGBundle class as the default handler (v4.2.16)
+
+2003-01-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.15
+
+       * changes for improved compilation on MacOSX, replaced RETAIN macros
+         with methods
+       
+       * common.h: does not include anything from FoundationExt (required
+         includes were moved to the .m files)
+
+Fri Dec 27 10:42:11 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * fixed Copyright headers in most files (v4.2.14)
+
+Mon Dec 23 15:34:51 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSObject+Logs.m: print a warning if DEBUG is disabled (v4.2.13)
+
+       * NSFileManager+Extensions.m: correctly implement NGFileManager (some
+         trash related fixes)
+
+2002-11-25  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSString+misc.m: added some methods for processing fully qualified
+         XML names (v4.2.12)
+       
+2002-11-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOKeyMapDataSource.m: finished EOKeyMapDataSource (v4.2.11)
+       
+       * EOKeyMapDataSource.m: started EOKeyMapDataSource (v4.2.10)
+
+       * EOCacheDataSource.m: tiny code cleanups
+
+2002-11-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSURL+misc.m: fixed an index bug in URL string processing (v4.2.9)
+
+2002-10-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSDictionary+misc: added a method 
+         -dictionaryByExchangingKeysAndValues to reverse the mapping of a
+         dictionary (v4.2.8)
+
+2002-10-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGStringScanEnumerator.m: properly clear data when being passed an
+         empty NSData (v4.2.7)
+
+Thu Oct 17 16:18:49 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added Bjoern's excellent NGStringScanEnumerator for scanning binaries
+         for printable strings (useful for extracting version information of
+         executables that have no --version support ..) (v4.2.6)
+
+2002-09-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSEnumerator+misc.m, NSProcessInfo+misc.m: removed some compilation
+         warnings (v4.2.5)
+
+Fri Aug 30 11:40:59 2002  Jan Reichmann  <jan@skyrix.com>
+
+       * NGQuotedPrintableCoding.m: (Suse Bug 18600) fixed 
+         'Soft line Breaks'-Bug (v4.2.4)
+
+2002-08-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSFileManager+Extensions.m: added support for GlobalIDs, make
+         relative pathes absolute before calling standarizePath (v4.2.3)
+
+2002-07-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved tools/tests to skyrix-core/samples
+
+2002-05-31  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGBundleManager.m: changed to work with gstep-base library
+
+2002-05-23 Helge Hess  <helge.hess@skyrix.com>
+
+       * moved from Skyrix-dev-42 repository to skyrix-core (v4.2.2)
+
+Fri May 17 14:51:13 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NSData+gzip category from NGZlib
+
+Thu May  2 15:21:00 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NSURL+misc for handling relative NSURLs
+
+Thu May  2 13:38:11 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * made some modifications to support gstep-base
+
+Mon Apr 29 11:35:31 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSProcessInfo+misc.m: added convenience methods: 
+         -argumentsWithoutDefaults
+
+Tue Apr 16 13:13:05 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSString+misc.m: fixed bug with HTML escaping \n \r etc
+
+Tue Feb 12 21:04:16 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSObject+Values.m: the -stringValue of NSMutableString now returns an
+         immutable copy
+       
+       * added DOM extensions
+
+Sat Feb  9 12:25:57 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added object logging methods
+
+Wed Feb  6 11:54:04 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSProcessInfo+misc.m: added -temporaryFileName
+
+Mon Jan  7 15:33:41 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGBundleManager.m: use a set for resource lookup to avoid duplicates
+
+Mon Dec 17 15:19:23 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGFileManager.m: added -trashFileAtPath:handler: method
+
+Tue Nov 27 19:30:29 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGBundleManager: made NGBundle class public
+
+       * NSProcessInfo+misc.m: speed optimized /proc processing ...
+
+Thu Nov 22 10:48:29 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSCalendarDate+misc.m: added method for calculation of
+         easter
+
+Tue Nov  6 12:06:49 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed NGFileManager*Tools from Sascha, too many dependencies on
+         SkyProject ...
+
+Tue Nov  6 12:00:11 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NGFileManager*Tools from Sascha
+
+Thu Oct 18 15:34:13 2001  Helge Hess  <helge.hess@skyrix.com>
+       
+       * NSNull+misc.m: added forwarding code to catch unknown selectors
+       
+Tue Oct 16 16:34:25 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOQualifier+CtxEval.m ([NSArray -filteredArrayUsingQualifier:context:]): 
+         return empty array instead of nil if no object matches
+
+Mon Oct 15 15:59:42 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSNull+misc.m: implemented KVC for NSNull ...
+
+Mon Oct 15 15:33:52 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSNull+misc.m: added -count,-length implementations
+         to improve stability against typing bugs (calls get
+         logged using NSLog)
+
+Tue Aug 28 11:32:06 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSString+misc.m: added Unicode support to HTML escaping
+
+       * NSString+misc.h: added methods to do HTML escaping
+
+Mon Aug 20 17:59:49 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOCompoundDataSource.m: fixed bug: remove from notification center
+         in -dealloc
+         
+       * EOFilterDataSource.m ([NSDictionary -flattenedArrayWithHint:andKeys:]): 
+         fixed allocation bug (missing -autorelease)
+
+Fri Aug 17 12:47:07 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NSProcessInfo+misc for querying the /proc filesystem
+
+Fri Aug 10 13:31:28 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NGFileManager class
+
+Thu Aug  9 13:49:30 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSString+misc.m (NGUnescapeUrlBuffer): added URL escaping/unescaping
+
+Tue Jul 31 11:27:46 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * EOFilterDataSource.m: can handle groupings now
+
+Tue Jul 10 11:56:18 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSCalendarDate+misc.m(firstMondayAndLastWeekInYear:): do not dump
+         core if passed NULL
+
+2001-06-26  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed NGNil, NGArchiver
+
+       * moved to SkyDev41
+
+Wed May 30 14:47:11 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOFilterDataSource.m: completed
+
+Thu May 10 11:23:57 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGBundleManager.m: improved error handling
+
+Mon Apr 30 10:44:02 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOCacheDataSource.m: added -description
+
+Thu Apr 19 11:58:57 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * EOCompoundDataSource.m: insert mh bugfix (return empty array instead 
+       of nil); fixed sources notification bug
+       
+Tue Apr 10 13:15:38 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGFileManager.h: completed NGFileManager protocol
+
+Mon Mar 26 12:29:14 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * added NSNull+misc with -isNotNull
+
+Thu Mar  8 16:51:31 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * EOKeyGrouping.m: fixed bug with 'nil' in -addObject:
+
+Tue Feb 13 10:51:03 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * EOGrouping.m: added -setGroupings/-groupings to EOFetchSpecification
+
+Tue Feb 13 10:31:29 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * fixed bugs in grouping stuff
+
+Tue Feb  6 18:18:48 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * NSArray+Grouping.[hm], EO*Grouping.[hm]: added
+
+Mon Jan 29 15:36:07 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSFileManager+Extensions.m: added trash-folder support
+
+Wed Jan 24 19:35:43 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NSString+misc.[mh]: add FilePathVersioningMethods
+
+Wed Jan 24 19:35:00 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NSFileManager+Extensions.h: add fileAttributesAtPath:traverseLink:
+       version:
+
+Tue Jan 23 18:04:35 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * EOQualifier+CtxEval.m: fixed bug in parameter countin
+
+Thu Jan 18 17:04:07 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSFileManager+Extensions: changed feature-check methods
+
+Tue Jan 16 11:28:38 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * EOCacheDataSource.m: fixed timeout bug
+
+Mon Jan 15 14:24:45 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSFileManager+Extensions.h: added locking protocol
+
+Mon Jan 15 12:54:54 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSFileManager+Extensions.h: added methods for versioning
+
+Sun Jan 14 19:27:23 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * EOCacheDataSource.[mh]: improved timeout
+
+Fri Jan 12 18:29:33 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * EOCacheDataSource.[hm]: timeout
+
+Wed Jan 10 15:56:40 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * EODataSource+NGExtensions.m: added EONoFetchWithEmptyQualifierHint
+
+Wed Jan  3 15:36:40 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * EOCacheDataSource.m: fixed dealloc bug
+
+Thu Oct 26 20:00:41 2000  Jan Reichmann  <jan@skyrix.com>
+
+       * EOQualifier+CtxEval.m: fixed log bug
+
+Thu Oct 19 14:31:48 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSString+misc.m: added changes of Jan
+
+Mon Oct 16 19:30:30 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * EODataSource+NGExtensions.m: added
+
+Mon Oct  2 18:04:28 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSString+Formatting.m: added %ll specifier for long-long types
+
+Thu Aug 31 17:54:59 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSEnumerator+misc: added this new category/classes
+
+Fri Aug 18 15:09:14 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGBundleManager.m: cache bundle manager object
+
+Thu Aug 17 13:43:06 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGBundleManager.m: always search in $GSROOT/Library/Bundles
+
+Wed Jul  5 20:32:24 2000  Martin Hoerning  <mh@mdlink.de>
+
+       * NSCalendarDate+misc.m: fixed -numberOfWeeksInYear
+
+Wed Jun 28 15:24:46 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSCalendarDate+misc.m: added -numberOfWeeksInYear
+
+Tue Jun 13 18:34:04 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGObjCRuntime.m, NSString+Formatting.m: doesn't use stack allocated
+         buffers anymore
+
+Fri Jun  9 17:37:09 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGQuotedPrintableCoding.m: changed 'char' type to 'signed char'
+
+Wed May 31 16:33:53 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSCalendarDate+misc.h: added -firstDayOfMonth and -weekOfMonth
+
+Wed May 17 11:54:20 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSCalendarDate+misc.m: added -isForenoon and -isAfternoon
+
+Wed May  3 17:45:19 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSCalendarDate+misc.m: fixed mondays-of-year calculation to respect
+         the DST timezones
+
+Wed May  3 17:14:32 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSCalendarDate+misc.m: added week-calculation methods
+
+Tue May  2 17:24:09 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGBundleManager.m ([NGBundleManager -providedResourcesOfType:inBundle:]): 
+         fixed bug, didn't qualify based on type
+
+Tue May  2 14:00:45 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NSString+misc.m: fixed possible buffer overflow bug
+
+Tue May  2 13:24:40 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGHashMap.m: fixed RC-Bug in allObjects and _NGHashMapObjectEnumerator 
+       -nextObject
+
+Tue May  2 13:12:11 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHashMap.m: added NSAssert's to check for a valid 'table'
+
+Fri Apr 28 19:00:52 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSString+misc.m: added placeholder replacement stuff, removed string
+         debugging stuff
+
+Wed Apr 12 19:33:26 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSCalendarDate+misc.m: added -isToday method
+
+Tue Feb 29 17:12:15 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * MOF3 import
+
+Mon Feb 21 13:49:40 2000  Helge Hess  <helge.hess@mdlink.de>
+       
+       * removed -cString calls
+
+2000-02-17    <helge.hess@mdlink.de>
+
+       * NSString+Formatting.m, NSBase64Coding.m, NGBundleManager.m, NSString+misc:
+         removed a lot of 'cString' usage
+
+Thu Jan 20 18:44:27 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * added NGObjCRuntime category. Contains ObjC runtime manipulation stuff
+
+Mon Jan 10 12:44:10 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSCalendarDate+misc.m: added Y2K support method
+
+Mon Dec  6 19:15:27 1999  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGBundleManager.m: added support for EOQualifier queries
+
+Thu Sep 16 18:14:39 1999  Helge Hess  <helge.hess@mdlink.de>
+
+       * removed NGTool.[hm], NGProxy.[hm], NGMainMacros.h
+
+Mon Jul 26 12:21:44 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGBundleManager.m: added -principalObject method
+
+Thu Jul 22 14:31:36 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * NGQuotedPrintableCoding.m: fixed NGEncodeQuotedPrintable
+
+Thu Jul  8 10:23:52 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGBundleManager.m: send notification if bundle did load
+
+Wed Jun 30 15:20:05 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * added NGBundleManager
+
+Fri Jun 25 19:58:14 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSString+Formatting.m: fixed bug (formatter looks for empty format)
+
+Tue Jun 15 10:38:05 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * added NGQuotedPrintableCoding categories
+
+Fri May 21 16:13:52 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * make it compile with gstep-base
+
+Fri May 21 13:19:10 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * changed OPENSTEP macro to WITH_OPENSTEP
+
+Tue Mar 16 12:43:03 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * common.h: added support for mingw32
+
+Tue Jan 12 13:19:36 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHashMap.m: added -asDictionary method
+
+Fri Jan  8 14:42:31 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSSet+enumerator.m: implemented mapping methods
+
+Thu Jan  7 16:14:55 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGBase64Coding.m: use +stringWithCStringNoCopy:...
+
+Wed Jan  6 18:54:50 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSString+Formatting.m: use Objective-C allocation functions
+
+       * NGMemoryAllocation.h: use Objective-C allocation functions
+
+       * NSAutoreleasePool+misc.m: content is ignored if Boehm GC is used
+
+Wed Dec 30 09:54:51 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * fixed exception creation, cleanups in NSAttributedString
+
+Mon Dec 28 09:51:24 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * replaced THROW with -raise
+
+       * replaced TRY with NS_DURING
+
+       * removed GNU regex library because of license issues
+
+Wed Dec 23 12:13:07 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSArray+enumerator.m: added methods to create sets using selector
+         mapping
+
+Wed Dec 16 12:23:24 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSArray+enumerator.m: added methods to create arrays using selector
+         mapping
+
+Fri Dec 11 18:58:35 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSCalendarDate+misc.m: added -hour:minute:second:, -hour:minute:
+
+Tue Dec  8 19:23:23 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSCalendarDate+misc.m: fixed -tomorrow, -yesterday which was broken
+
+       * NSCalendarDate+misc.m: added various methods: 
+         -isDateOnSameDay, -isDateInSameWeek, -yesterday, -tomorrow
+
+       * added NSCalendarDate+misc category
+
+Fri Nov 27 15:53:48 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGExtensions.h: added 'index()' function for WIN32
+
+Thu Nov 26 13:48:35 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSException+misc.h: removed FINALLY from SYNCHRONIZED macros
+
+       * GNUmakefile: added install capability
+
+Tue Nov 24 11:51:08 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSAutoreleasePool+misc.m: added category linking function
+
+       * NGStack.m: fixed RC bug (elements were not released on dealloc)
+
+Mon Nov 23 10:37:55 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSString+misc.m: added string debugging methods (init replacements)
+         which were in libFoundation-mof2 before
+
+       * added NSAutoreleasePool+misc.[hm]
+
+Mon Nov 16 18:41:15 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGCharBuffers.h: fixed bug in initialization
+
+Fri Nov 13 10:44:03 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGExtensions.h: made NoZone a libFoundation specific
+
+       * Makefile.preamble: added -Wno-protocol switch
+
+       * NGTool.m: getpid() replaced for WIN32
+
+Tue Nov 10 17:01:20 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGTool.m: signal handler sets itself again after signal is executed
+
+Fri Nov  6 11:07:03 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGArchiver.m: added proper Copyright information
+
+Thu Nov  5 08:28:07 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGArchiver.m: reformatted for inclusion in libFoundation
+
+Wed Oct 28 14:57:40 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHashMap.m: added -initWithDictionary:, +hashMapWithDictionary: methods
+
+Thu Oct 22 14:07:32 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * added NSDictionary+misc category
+
+Tue Oct 20 19:34:33 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * added xor digests in MD5 generator
+
+1998-10-19  Helge Hess  <helge@trex.mdlink.de>
+
+       * NSObject+Values.m: modified values method to use only intValue,
+         floatValue and doubleValue.
+
+       * NSException+misc.h: added synchronized macros
+       
+       * removed property list parser (now in libFoundation)
+
+1998-10-15  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGStack.m: made category on NSMutableArray to make it conform to
+         stack protocol
+
+       * added NSString+misc category. Contains a method to return a
+         string escaped using C rules (newline becomes '\n', ..)
+
+1998-10-11  Helge Hess  <helge@trex.mdlink.de>
+
+       * started Rhapsody support
+
+1998-10-10  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGBase64Coding.m: removed generation of newline at end of encoding,
+                           cleaned up, removed MAXLINE constant
+
+1998-10-09  Helge Hess  <helge@trex.mdlink.de>
+
+       * reformatted NGArchiver.m
+
+       * created ChangeLog
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/.cvsignore b/skyrix-core/NGExtensions/EOExt.subproj/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOCacheDataSource.m b/skyrix-core/NGExtensions/EOExt.subproj/EOCacheDataSource.m
new file mode 100644 (file)
index 0000000..7c20334
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+  Copyright (C) 2000-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$
+
+//#define PROFILE 1
+
+#include "EOCacheDataSource.h"
+#import <EOControl/EOControl.h>
+#import "EODataSource+NGExtensions.h"
+#import "common.h"
+#include <sys/time.h>
+
+@interface EOCacheDataSource(Private)
+- (void)_registerForSource:(id)_source;
+- (void)_removeObserverForSource:(id)_source;
+- (void)_clearCache;
+@end
+
+@implementation EOCacheDataSource
+
+- (id)initWithDataSource:(EODataSource *)_ds {
+  if ((self = [super init])) {
+    self->source  = [_ds retain];
+    self->timeout = 0;
+    self->timer   = nil;
+    self->time    = 0;
+    [self _registerForSource:self->source];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self _removeObserverForSource:self->source];
+  [self->timer invalidate];
+  [self->timer  release];
+  [self->source release];
+  [self->cache  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setSource:(EODataSource *)_source {
+  [self _removeObserverForSource:self->source];
+  ASSIGN(self->source, _source);
+  [self _registerForSource:self->source];
+  [self _clearCache];
+}
+
+- (EODataSource *)source {
+  return self->source;
+}
+
+- (void)setTimeout:(NSTimeInterval)_timeout {
+  self->timeout = _timeout;
+}
+- (NSTimeInterval)timeout {
+  return self->timeout;
+}
+
+/* operations */
+
+- (NSArray *)fetchObjects {
+  BEGIN_PROFILE;
+
+  self->_isFetching = YES;
+  
+  if (self->time > 0) {
+    if (self->time < [[NSDate date] timeIntervalSinceReferenceDate]) {
+      [self->cache release]; self->cache = nil;
+    }
+  }
+  if (self->cache == nil) {
+    self->time = 0;
+    if (self->timer != nil) {
+      [self->timer invalidate];
+      [self->timer release]; self->timer = nil;
+    }
+    
+    self->cache = [[self->source fetchObjects] retain];
+    
+    if (self->timeout > 0) {
+      self->time =
+        [[NSDate date] timeIntervalSinceReferenceDate] + self->timeout;
+      
+      self->timer = [NSTimer scheduledTimerWithTimeInterval:self->timeout
+                             target:self
+                             selector:@selector(clear)
+                             userInfo:nil repeats:NO];
+      self->timer = [self->timer retain];
+    }
+    PROFILE_CHECKPOINT("cache miss");
+  }
+  else {
+    PROFILE_CHECKPOINT("cache hit");
+  }
+  
+  self->_isFetching = NO;
+  END_PROFILE;
+  return self->cache;
+}
+
+- (EOFetchSpecification *)fetchSpecification {
+  return [self->source fetchSpecification];
+}
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fetchSpec {
+  [self->source setFetchSpecification:_fetchSpec];
+}
+
+- (void)insertObject:(id)_obj {
+  [self _clearCache];
+  [self->source insertObject:_obj];
+}
+
+- (void)deleteObject:(id)_obj {
+  [self _clearCache];
+  [self->source deleteObject:_obj];
+}
+
+- (id)createObject {
+  return [self->source createObject];
+}
+
+- (void)updateObject:(id)_obj {
+  [self->source updateObject:_obj];
+  [self _clearCache];  
+}
+
+- (EOClassDescription *)classDescriptionForObjects {
+  return [[self source] classDescriptionForObjects];
+}
+
+- (void)clear {
+  [self _clearCache];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSString *fmt;
+
+  fmt = [NSString stringWithFormat:@"<%@[0x%08X]: source=%@>",
+                    NSStringFromClass([self class]), self,
+                    self->source];
+  return fmt;
+}
+
+@end /* EOCacheDataSource */
+
+@implementation EOCacheDataSource(Private)
+
+- (void)_registerForSource:(id)_source {
+  static NSNotificationCenter *nc = nil;
+
+  if (_source != nil) {
+    if (nc == nil)
+      nc = [[NSNotificationCenter defaultCenter] retain];
+    
+    [nc addObserver:self selector:@selector(_clearCache)
+        name:EODataSourceDidChangeNotification object:_source];
+  }
+}
+
+- (void)_removeObserverForSource:(id)_source {
+  static NSNotificationCenter *nc = nil;
+
+  if (_source != nil) {
+    if (nc == nil)
+      nc = [NSNotificationCenter defaultCenter];
+    [nc removeObserver:self name:EODataSourceDidChangeNotification
+        object:_source];
+  }
+}
+
+- (void)_clearCache {
+#if DEBUG && 0
+  NSLog(@"clearing cache (%s)...", self->_isFetching?"fetching":"");
+  if (fgetc(stdin) == 'a')
+    abort();
+#endif
+  
+  self->time = 0;
+  
+  if (self->timer) {
+    [self->timer invalidate];
+    [self->timer release]; self->timer = nil;
+  }
+  
+  if (self->cache) {
+    [self->cache release]; self->cache = nil;
+    [self postDataSourceChangedNotification];
+  }
+}
+
+@end /* EOCacheDataSource(Private) */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOCompoundDataSource.m b/skyrix-core/NGExtensions/EOExt.subproj/EOCompoundDataSource.m
new file mode 100644 (file)
index 0000000..6490867
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOCompoundDataSource.h"
+#import <EOControl/EOControl.h>
+#import "EODataSource+NGExtensions.h"
+#import "common.h"
+
+@implementation EOCompoundDataSource
+
+- (id)initWithDataSources:(NSArray *)_ds {
+  if ((self = [super init])) {
+    self->sources = [_ds shallowCopy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [self->sortOrderings      release];
+  [self->auxiliaryQualifier release];
+  [self->sources            release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setSources:(NSArray *)_sources {
+  if (self->sources != _sources) {
+    _sources = [_sources shallowCopy];
+    [self->sources release];
+    self->sources = _sources;
+    {
+      NSNotificationCenter *nc;
+      NSEnumerator         *enumerator;
+      id                   obj;
+      
+      nc         = [NSNotificationCenter defaultCenter];
+      enumerator = [self->sources objectEnumerator];
+      
+      while ((obj = [enumerator nextObject])) {
+        [nc addObserver:self
+            selector:@selector(postDataSourceChangedNotification)
+            name:EODataSourceDidChangeNotification object:obj];
+      }
+    }
+  }
+  [self postDataSourceChangedNotification];
+}
+- (NSArray *)sources {
+  return self->sources;
+}
+
+- (void)setAuxiliaryQualifier:(EOQualifier *)_q {
+  ASSIGN(self->auxiliaryQualifier, _q);
+  [self postDataSourceChangedNotification];
+}
+- (EOQualifier *)auxiliaryQualifier {
+  return self->auxiliaryQualifier;
+}
+
+- (void)setSortOrderings:(NSArray *)_so {
+  if (self->sortOrderings != _so) {
+    _so = [_so shallowCopy];
+    [self->sortOrderings release];
+    self->sortOrderings = _so;
+  }
+  [self postDataSourceChangedNotification];
+}
+- (NSArray *)sortOrderings {
+  return self->sortOrderings;
+}
+
+/* operations */
+
+- (NSArray *)fetchObjects {
+  NSArray  *objs;
+  unsigned count;
+
+  if ((count = [[self sources] count]) == 0) {
+    objs = nil;
+  }
+  else if (count == 1)
+    objs = [[[self sources] objectAtIndex:0] fetchObjects];
+  else {
+    NSMutableArray *a;
+    NSEnumerator   *e;
+    EODataSource   *ds;
+    
+    a = nil;
+    e = [[self sources] objectEnumerator];
+    while ((ds = [e nextObject])) {
+      NSArray *o;
+
+      o = [ds fetchObjects];
+      if ([o count] > 0) {
+        if (a == nil)
+          a = [NSMutableArray arrayWithCapacity:[o count]];
+        [a addObjectsFromArray:o];
+      }
+    }
+
+    objs = [[a shallowCopy] autorelease];
+  }
+
+  if (objs == nil)
+    return [NSArray array];
+  
+  if ([self auxiliaryQualifier])
+    objs = [objs filteredArrayUsingQualifier:[self auxiliaryQualifier]];
+  
+  if ([self sortOrderings])
+    objs = [objs sortedArrayUsingKeyOrderArray:[self sortOrderings]];
+  
+  return objs;
+}
+
+- (void)insertObject:(id)_obj {
+  unsigned count;
+
+  if ((count = [[self sources] count]) == 0)
+    [super insertObject:_obj];
+  else if (count == 1)
+    [[[self sources] objectAtIndex:0] insertObject:_obj];
+  else {
+    NSEnumerator *e;
+    EODataSource *ds;
+
+    e = [[self sources] objectEnumerator];
+    while ((ds = [e nextObject])) {
+      BOOL didFail = NO;
+      
+      NS_DURING
+        [ds insertObject:_obj];
+      NS_HANDLER
+        didFail = YES;
+      NS_ENDHANDLER;
+      
+      if (!didFail)
+        return;
+    }
+    /* all datasources failed to insert .. */
+    [super insertObject:_obj];
+  }
+  [self postDataSourceChangedNotification];
+}
+
+- (void)deleteObject:(id)_obj {
+  unsigned count;
+
+  if ((count = [[self sources] count]) == 0)
+    [super deleteObject:_obj];
+  else if (count == 1)
+    [[[self sources] objectAtIndex:0] deleteObject:_obj];
+  else {
+    NSEnumerator *e;
+    EODataSource *ds;
+
+    e = [[self sources] objectEnumerator];
+    while ((ds = [e nextObject])) {
+      BOOL didFail = NO;
+      
+      NS_DURING
+        [ds deleteObject:_obj];
+      NS_HANDLER
+        didFail = YES;
+      NS_ENDHANDLER;
+      
+      if (!didFail)
+        return;
+    }
+    /* all datasources failed to delete .. */
+    [super deleteObject:_obj];
+  }
+  [self postDataSourceChangedNotification];  
+}
+
+- (id)createObject {
+  unsigned count;
+  
+  if ((count = [[self sources] count]) == 0)
+    return [super createObject];
+  else if (count == 1)
+    return [[[self sources] objectAtIndex:0] createObject];
+  else {
+    NSEnumerator *e;
+    EODataSource *ds;
+    
+    e = [[self sources] objectEnumerator];
+    while ((ds = [e nextObject])) {
+      id obj;
+
+      if ((obj = [ds createObject]))
+        return obj;
+    }
+    /* all datasources failed to create .. */
+    return [super createObject];
+  }
+  [self postDataSourceChangedNotification];  
+}
+
+- (void)updateObject:(id)_obj {
+  unsigned count;
+
+  if ((count = [[self sources] count]) == 0)
+    [super updateObject:_obj];
+  else if (count == 1)
+    [[[self sources] objectAtIndex:0] updateObject:_obj];
+  else {
+    NSEnumerator *e;
+    EODataSource *ds;
+
+    e = [[self sources] objectEnumerator];
+    while ((ds = [e nextObject])) {
+      BOOL didFail = NO;
+      
+      NS_DURING
+        [ds updateObject:_obj];
+      NS_HANDLER
+        didFail = YES;
+      NS_ENDHANDLER;
+      
+      if (!didFail)
+        return;
+    }
+    /* all datasources failed to update .. */
+    [super updateObject:_obj];
+  }
+  [self postDataSourceChangedNotification];  
+}
+
+- (EOClassDescription *)classDescriptionForObjects {
+  unsigned count;
+  NSEnumerator *e;
+  EODataSource *ds;
+  
+  if ((count = [[self sources] count]) == 0)
+    return [super classDescriptionForObjects];
+
+  if (count == 1)
+    return [[[self sources] objectAtIndex:0] classDescriptionForObjects];
+    
+  e = [[self sources] objectEnumerator];
+  while ((ds = [e nextObject])) {
+    EOClassDescription *cd;
+
+    if ((cd = [ds classDescriptionForObjects]))
+      return cd;
+  }
+  /* all datasources failed to create .. */
+  return [super classDescriptionForObjects];
+}
+
+@end /* EOCompoundDataSource */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EODataSource+NGExtensions.m b/skyrix-core/NGExtensions/EOExt.subproj/EODataSource+NGExtensions.m
new file mode 100644 (file)
index 0000000..63c9dd7
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EODataSource+NGExtensions.h"
+#include <EOControl/EOFetchSpecification.h>
+#include "common.h"
+
+NGExtensions_DECLARE NSString *EODataSourceDidChangeNotification =
+  @"EODataSourceDidChangeNotification";
+NGExtensions_DECLARE NSString *EONoFetchWithEmptyQualifierHint =
+  @"EONoFetchWithEmptyQualifierHint";
+
+@implementation EODataSource(NGExtensions)
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fetchSpec {
+  [self doesNotRecognizeSelector:_cmd];
+}
+
+- (EOFetchSpecification *)fetchSpecification {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+- (void)updateObject:(id)_obj {
+  [self doesNotRecognizeSelector:_cmd];
+}
+
+- (void)postDataSourceChangedNotification {
+  static NSNotificationCenter *nc = nil;
+  
+  if (nc == nil)
+    nc = [[NSNotificationCenter defaultCenter] retain];
+  
+  [nc postNotificationName:EODataSourceDidChangeNotification object:self];
+}
+
+
+@end /* EODataSource(NGExtensions) */
+
+/* static linking */
+
+void __link_EODataSource_NGExtensions(void) {
+  __link_EODataSource_NGExtensions();
+}
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOFetchSpecification+plist.m b/skyrix-core/NGExtensions/EOExt.subproj/EOFetchSpecification+plist.m
new file mode 100644 (file)
index 0000000..20f1a21
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGExtensions/EOFetchSpecification+plist.h>
+#include <EOControl/EOControl.h>
+#include "common.h"
+
+@implementation EOFetchSpecification(plist)
+
+- (id)initWithDictionary:(NSDictionary *)_dictionary {
+  if ((self = [self init])) {
+    id tmp;
+    
+    if ((tmp = [_dictionary objectForKey:@"qualifier"])) {
+      if ([tmp isKindOfClass:[NSDictionary class]])
+        tmp = [EOQualifier qualifierToMatchAllValues:tmp];
+      else
+        tmp = [EOQualifier qualifierWithQualifierFormat:tmp];
+      
+      [self setQualifier:tmp];
+    }
+    
+    if ((tmp = [_dictionary objectForKey:@"sortOrderings"])) {
+      NSArray        *sos = nil;
+      EOSortOrdering *so;
+      
+      if ([tmp isKindOfClass:[NSArray class]]) {
+        NSMutableArray *result  = nil;
+        NSEnumerator   *objEnum;
+        id             obj;
+        
+        objEnum = [tmp objectEnumerator];
+        result = [NSMutableArray arrayWithCapacity:8];
+        while ((obj = [objEnum nextObject])) {
+          so = [[EOSortOrdering alloc] initWithPropertyList:obj owner:nil];
+          [so autorelease];
+          if (so)
+            [result addObject:so];
+        }
+        sos = [NSArray arrayWithArray:result];
+      }
+      else {
+        so = [[[EOSortOrdering alloc] initWithPropertyList:tmp owner:nil] 
+                               autorelease];
+          
+        if (so)
+          sos = [NSArray arrayWithObject:so];
+      }
+      [self setSortOrderings:sos];
+    }
+    
+    if ((tmp = [_dictionary objectForKey:@"fetchLimit"])) {
+      if ([tmp respondsToSelector:@selector(intValue)])
+        [self setFetchLimit:[tmp intValue]];
+      else
+        NSLog(@"%s: invalid fetchLimit key !", __PRETTY_FUNCTION__);
+    }
+    
+    if ((tmp = [_dictionary objectForKey:@"hints"])) {
+      if ([tmp isKindOfClass:[NSDictionary class]])
+        [self setHints:tmp];
+      else
+        NSLog(@"%s: invalid hints key !", __PRETTY_FUNCTION__);
+    }
+    
+    if ([self->hints objectForKey:@"addDocumentsAsObserver"] == nil) {
+      NSMutableDictionary *hnts;
+
+      hnts = [[NSMutableDictionary alloc] initWithDictionary:self->hints];
+      [hnts setObject:[NSNumber numberWithBool:NO]
+            forKey:@"addDocumentsAsObserver"];
+      [self setHints:hnts];
+      [hnts release];
+    }
+  }
+  return self;
+}
+- (id)initWithString:(NSString *)_string {
+  EOQualifier *q;
+  
+  q = [EOQualifier qualifierWithQualifierFormat:_string];
+  
+  return [self initWithEntityName:nil
+               qualifier:q
+               sortOrderings:nil
+               usesDistinct:NO isDeep:NO hints:nil];
+}
+
+- (id)initWithPropertyList:(id)_plist owner:(id)_owner {
+  if ([_plist isKindOfClass:[NSDictionary class]])
+    return [self initWithDictionary:_plist];
+  
+  if ([_plist isKindOfClass:[NSString class]])
+    return [self initWithString:_plist];
+  
+  if ([_plist isKindOfClass:[self class]]) {
+    [self release];
+    return [_plist copy];
+  }
+
+  [self release];
+  return nil;
+}
+- (id)initWithPropertyList:(id)_plist {
+  return [self initWithPropertyList:_plist owner:nil];
+}
+
+@end /* EOFetchSpecification(plist) */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOFilterDataSource.m b/skyrix-core/NGExtensions/EOExt.subproj/EOFilterDataSource.m
new file mode 100644 (file)
index 0000000..1dae5cc
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "EOFilterDataSource.h"
+#include "EODataSource+NGExtensions.h"
+#include "EOGrouping.h"
+#include <EOControl/EOControl.h>
+#include "common.h"
+
+@interface NSDictionary(EOFilterDataSource)
+
+- (NSArray *)flattenedArrayWithHint:(unsigned int)_hint
+  andKeys:(NSArray *)_keys;
+
+@end
+
+@implementation EOFilterDataSource
+
+- (id)initWithDataSource:(EODataSource *)_ds {
+  if ((self = [super init])) {
+    [self setSource:_ds];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithDataSource:nil];
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [self->sortOrderings      release];
+  [self->groupings          release];
+  [self->auxiliaryQualifier release];
+  [self->source             release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setSource:(EODataSource *)_source {
+  NSNotificationCenter *nc;
+  
+  if (self->source == _source)
+    return;
+    
+  nc = [NSNotificationCenter defaultCenter];
+
+  if (self->source) {
+      [nc removeObserver:self
+          name:EODataSourceDidChangeNotification object:self->source];
+  }
+    
+  ASSIGN(self->source, _source);
+    
+  if (self->source) {
+      [nc addObserver:self selector:@selector(_sourceDidChange:)
+          name:EODataSourceDidChangeNotification object:self->source];
+  }
+    
+  [self postDataSourceChangedNotification];
+}
+- (EODataSource *)source {
+  return self->source;
+}
+
+- (void)setAuxiliaryQualifier:(EOQualifier *)_q {
+  if ([_q isEqual:self->auxiliaryQualifier])
+    return;
+
+  ASSIGN(self->auxiliaryQualifier, _q);
+  [self postDataSourceChangedNotification];
+}
+- (EOQualifier *)auxiliaryQualifier {
+  return self->auxiliaryQualifier;
+}
+
+- (void)setSortOrderings:(NSArray *)_so {
+  if (self->sortOrderings == _so)
+    return;
+  
+  _so = [_so shallowCopy];
+  [self->sortOrderings release];
+  self->sortOrderings = _so;
+  [self postDataSourceChangedNotification];
+}
+- (NSArray *)sortOrderings {
+  return self->sortOrderings;
+}
+
+- (void)setGroupings:(NSArray *)_groupings {
+  if (self->groupings == _groupings)
+    return;
+  
+  _groupings = [_groupings shallowCopy];
+  [self->groupings release];
+  self->groupings = _groupings;
+  [self postDataSourceChangedNotification];  
+}
+- (NSArray *)groupings {
+  return self->groupings;
+}
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec {
+  [[self source] setFetchSpecification:_fspec];
+}
+- (EOFetchSpecification *)fetchSpecification {
+  return [[self source] fetchSpecification];
+}
+
+/* notifications */
+
+- (void)_sourceDidChange:(NSNotification *)_notification {
+  [self postDataSourceChangedNotification];
+}
+
+/* operations */
+
+- (NSArray *)fetchObjects {
+  NSAutoreleasePool *pool;
+  NSArray *objs;
+  NSArray *groups;
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  objs = [[self source] fetchObjects];
+  
+  if ([self auxiliaryQualifier])
+    objs = [objs filteredArrayUsingQualifier:[self auxiliaryQualifier]];
+
+  if ((groups = [self groupings]) != nil) {
+    unsigned int cnt;
+    EOGrouping   *grouping;
+    NSArray      *allKeys;
+    NSArray      *sos;
+    NSDictionary *groupDict;
+
+    cnt = [objs count];
+
+    grouping = [groups lastObject];
+    
+    if ((sos = [self sortOrderings]) != nil) {
+      [grouping setSortOrderings:sos];
+    }
+    groupDict = [objs arrayGroupedBy:grouping];
+
+    allKeys = [groupDict allKeys];
+    allKeys = [allKeys sortedArrayUsingSelector:@selector(compare:)];
+    objs    = [groupDict flattenedArrayWithHint:cnt andKeys:allKeys];
+  }
+  else if ([self sortOrderings])
+    objs = [objs sortedArrayUsingKeyOrderArray:[self sortOrderings]];
+  
+  objs = [objs copy];
+  [pool release];
+  
+  return [objs autorelease];
+}
+
+- (void)insertObject:(id)_obj {
+  [[self source] insertObject:_obj];
+}
+
+- (void)deleteObject:(id)_obj {
+  [[self source] deleteObject:_obj];
+}
+
+- (void)updateObject:(id)_obj {
+  [self->source updateObject:_obj];
+}
+
+- (id)createObject {
+  return [[self source] createObject];
+}
+
+- (EOClassDescription *)classDescriptionForObjects {
+  return [[self source] classDescriptionForObjects];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->source) [ms appendFormat:@" source=%@", self->source];
+  if (self->auxiliaryQualifier) 
+    [ms appendFormat:@" qualifier=%@", self->auxiliaryQualifier];
+  if (self->sortOrderings)
+    [ms appendFormat:@" orderings=%@", self->sortOrderings];
+  if (self->groupings)
+    [ms appendFormat:@" groupings=%@", self->sortOrderings];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* EOFilterDataSource */
+
+@implementation NSDictionary(EOFilterDataSource)
+
+- (NSArray *)flattenedArrayWithHint:(unsigned int)_hint
+  andKeys:(NSArray *)_keys
+{
+  NSMutableArray *result = nil;
+  unsigned int   i, cnt;
+  
+  result =
+    [[NSMutableArray alloc] initWithCapacity:_hint]; // should be improved
+  
+  for (i = 0, cnt = [_keys count]; i < cnt; i++) {
+    NSString *key;
+    NSArray  *tmp;
+    
+    key = [_keys objectAtIndex:i];
+    tmp = [self objectForKey:key];
+    [result addObjectsFromArray:tmp];
+  }
+  
+  return [result autorelease];
+}
+
+@end /* NSDictionary(EOFilterDataSource) */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOGrouping.m b/skyrix-core/NGExtensions/EOExt.subproj/EOGrouping.m
new file mode 100644 (file)
index 0000000..0c0d69a
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOGrouping.h"
+#include "common.h"
+
+@implementation EOGrouping
+
+- (id)initWithDefaultName:(NSString *)_defaultName {
+  if ((self = [super init])) {
+    self->defaultName = [_defaultName copy];
+  }
+  return self;
+}
+
+- (id)init {
+  return [self initWithDefaultName:nil];
+}
+
+- (void)dealloc {
+  [self->defaultName   release];
+  [self->sortOrderings release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setDefaultName:(NSString *)_defaultName {
+  ASSIGN(self->defaultName, _defaultName);
+}
+- (NSString *)defaultName {
+  return self->defaultName;
+}
+
+- (void)setSortOrderings:(NSArray *)_sortOrderings {
+  ASSIGN(self->sortOrderings, _sortOrderings);
+}
+
+- (NSArray *)sortOrderings {
+  return self->sortOrderings;
+}
+
+/* operations */
+
+- (NSString *)groupNameForObject:(id)_object {
+  [self doesNotRecognizeSelector:_cmd]; // subclass
+  return nil;
+}
+
+- (NSArray *)orderedGroupNames {
+  [self doesNotRecognizeSelector:_cmd]; // subclass
+  return nil;
+}
+
+- (NSString *)description {
+  return @"EOGrouping";
+}
+
+@end /* EOGrouping */
+
+
+NSString *EOGroupingHint = @"EOGroupingHint";
+
+@implementation EOFetchSpecification(Groupings)
+
+- (void)setGroupings:(NSArray *)_groupings {
+  NSDictionary        *lhints;
+  NSMutableDictionary *md;
+  
+  lhints = [self hints];
+  md = lhints ? [lhints mutableCopy] : [[NSMutableDictionary alloc] init];
+  if (_groupings)
+    [md setObject:_groupings forKey:EOGroupingHint];
+  else
+    [md removeObjectForKey:EOGroupingHint];
+  lhints = [md copy];
+  [md release];
+  [self setHints:lhints];
+  [lhints release];
+}
+- (NSArray *)groupings {
+  return [[self hints] objectForKey:EOGroupingHint];
+}
+
+@end /* EOFetchSpecification(Groupings) */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOGroupingSet.m b/skyrix-core/NGExtensions/EOExt.subproj/EOGroupingSet.m
new file mode 100644 (file)
index 0000000..4a77e3a
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOGrouping.h"
+#include "common.h"
+
+@interface EOGroupingSet(PrivateMethodes)
+- (void)_updateDefaultNames;
+@end
+
+
+@implementation EOGroupingSet
+
+- (void)dealloc {
+  [self->groupings release];
+  [super dealloc];
+}
+
+- (void)setGroupings:(NSArray *)_groupings {
+  ASSIGN(self->groupings, _groupings);
+  [self _updateDefaultNames];
+}
+- (NSArray *)groupings {
+  return self->groupings;
+}
+
+- (void)setDefaultName:(NSString *)_defaultName {
+  [super setDefaultName:_defaultName];
+  [self _updateDefaultNames];
+}
+
+- (NSString *)groupNameForObject:(id)_object {
+  NSString *result;
+  int      i, cnt;
+
+  for (i = 0, cnt = [self->groupings count]; i < cnt; i++) {
+    EOGrouping *group;
+
+    group = [self->groupings objectAtIndex:i];
+    if ((result = [group groupNameForObject:_object]))
+      return result;
+  }
+  return self->defaultName;
+}
+
+- (NSArray *)orderedGroupNames {
+  NSMutableArray *result;
+  unsigned int   i, cnt;
+
+  result = [NSMutableArray arrayWithCapacity:8];
+  
+  for (i = 0, cnt = [self->groupings count]; i < cnt; i++) {
+    EOGrouping *group;
+
+    group = [self->groupings objectAtIndex:i];
+    [result addObjectsFromArray:[group orderedGroupNames]];
+  }
+  
+  return result;
+}
+
+/* PrivateMethodes */
+
+- (void)_updateDefaultNames {
+  unsigned int i, cnt;
+
+  for (i = 0, cnt = [self->groupings count]; i < cnt; i++) {
+    EOGrouping *group;
+
+    group = [self->groupings objectAtIndex:i];
+    [group setDefaultName:nil];
+  }
+}
+
+@end /* EOGroupingSet */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOKeyGrouping.m b/skyrix-core/NGExtensions/EOExt.subproj/EOKeyGrouping.m
new file mode 100644 (file)
index 0000000..dd5c619
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOGrouping.h"
+#include "common.h"
+
+@implementation EOKeyGrouping
+
+- (id)initWithKey:(NSString *)_key {
+  if ((self = [super initWithDefaultName:nil])) {
+    self->key        = [_key copy];
+    self->groupNames = [[NSMutableArray alloc] initWithCapacity:32];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->key        release];
+  [self->groupNames release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)key {
+  return self->key;
+}
+- (void)setKey:(NSString *)_key {
+  NSAssert1(_key != nil, @"%s: nil _key parameter", __PRETTY_FUNCTION__);
+  ASSIGNCOPY(self->key, _key);
+}
+
+/* operations */
+
+- (NSString *)groupNameForObject:(id)_object {
+  NSString *result = nil;
+
+  if ([self->key length] == 0)
+    return @"";
+  
+  result = [[_object valueForKey:self->key] stringValue];
+  result = (result != nil) ? result : self->defaultName;
+  
+  if (result == nil)
+    return nil;
+  
+  if (![self->groupNames containsObject:result])
+    [self->groupNames addObject:result];
+  
+  return result;
+}
+
+- (NSArray *)orderedGroupNames {
+  if ([self->key length] == 0)
+    return [NSArray arrayWithObject:@""];
+  
+  return self->groupNames;
+}
+
+@end /* EOKeyGrouping */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOKeyMapDataSource.m b/skyrix-core/NGExtensions/EOExt.subproj/EOKeyMapDataSource.m
new file mode 100644 (file)
index 0000000..91590fa
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "EOKeyMapDataSource.h"
+#include "NSArray+enumerator.h"
+#include "EODataSource+NGExtensions.h"
+#include "NSNull+misc.h"
+#import <EOControl/EOControl.h>
+#include "common.h"
+#include <sys/time.h>
+
+@interface EOKeyMapDataSource(Private)
+- (void)_registerForSource:(id)_source;
+- (void)_removeObserverForSource:(id)_source;
+- (void)_sourceChanged;
+@end
+
+@implementation EOKeyMapDataSource
+
+- (id)initWithDataSource:(EODataSource *)_ds map:(id)_map {
+  if ((self = [super init])) {
+    self->source  = [_ds  retain];
+    self->map     = [_map retain];
+    [self _registerForSource:self->source];
+  }
+  return self;
+}
+- (id)initWithDataSource:(EODataSource *)_ds {
+  return [self initWithDataSource:_ds map:nil];
+}
+- (id)init {
+  return [self initWithDataSource:nil map:nil];
+}
+
+- (void)dealloc {
+  [self _removeObserverForSource:self->source];
+  [self->classDescription release];
+  [self->entityKeys release];
+  [self->mappedKeys release];
+  [self->map    release];
+  [self->fspec  release];
+  [self->source release];
+  [super dealloc];
+}
+
+/* mapping */
+
+- (EOFetchSpecification *)mapFetchSpecification:(EOFetchSpecification *)_fs {
+  return [_fs fetchSpecificationByApplyingKeyMap:self->map];
+}
+
+- (id)mapFromSourceObject:(id)_object {
+  id values;
+  if (_object == nil) return nil;
+  
+  if (self->mappedKeys == nil) {
+    /* no need to rewrite keys, only taking a subset */
+    values = [_object valuesForKeys:self->entityKeys];
+  }
+  else {
+    unsigned i, count;
+    
+    count  = [self->entityKeys count];
+    values = [NSMutableDictionary dictionaryWithCapacity:count];
+    
+    for (i = 0; i < count; i++) {
+      NSString *key, *newKey;
+      id value;
+      
+      key    = [self->mappedKeys objectAtIndex:i];
+      newKey = [self->entityKeys objectAtIndex:i];
+      
+      value = [_object valueForKey:key];
+      if (value) [(NSMutableDictionary *)values setObject:value forKey:newKey];
+    }
+  }
+  
+  return [[[EOMappedObject alloc] 
+           initWithObject:_object values:values] autorelease];
+}
+
+- (id)mapToSourceObject:(id)_object {
+  // TODO
+  if (_object == nil) return nil;
+
+  if ([_object isKindOfClass:[EOMappedObject class]]) {
+    id obj;
+    
+    if ((obj = [_object mappedObject]) == nil) {
+      NSLog(@"don't know how to back-map objects: %@", _object);
+      return nil;
+    }
+    
+    if ([obj isModified]) {
+      if (self->map) {
+       NSLog(@"%s: don't know how to back-map modified object: %@", 
+             _object);
+#if NeXT_Foundation_LIBRARY
+    [self doesNotRecognizeSelector:_cmd];
+    return nil; // keep compiler happy
+#else
+    return [self notImplemented:_cmd];
+#endif
+      }
+      
+      [obj applyChangesOnObject];
+    }    
+    return obj;
+  }
+  else {
+    NSLog(@"don't know how to back-map objects of class %@", [_object class]);
+#if NeXT_Foundation_LIBRARY
+    [self doesNotRecognizeSelector:_cmd];
+#else
+    return [self notImplemented:_cmd];
+#endif
+  }
+  return nil; // keep compiler happy
+}
+
+- (id)mapCreatedObject:(id)_object {
+  return [self mapFromSourceObject:_object];
+}
+
+- (id)mapObjectForUpdate:(id)_object {
+  return [self mapToSourceObject:_object];
+}
+- (id)mapObjectForInsert:(id)_object {
+  return [self mapToSourceObject:_object];
+}
+- (id)mapObjectForDelete:(id)_object {
+  return [self mapToSourceObject:_object];
+}
+
+- (id)mapFetchedObject:(id)_object {
+  return [self mapFromSourceObject:_object];
+}
+
+- (void)setClassDescriptionForObjects:(NSClassDescription *)_cd {
+  ASSIGN(self->classDescription, _cd);
+  
+  /* setup array of keys to map */
+  
+  [self->entityKeys release]; self->entityKeys = nil;
+  [self->mappedKeys release]; self->mappedKeys = nil;
+  
+  if (_cd) {
+    NSMutableArray *ma;
+    NSArray  *tmp;
+    unsigned i, count;
+    
+    ma = [[NSMutableArray alloc] initWithCapacity:16];
+    
+    /* first, collect keys we need */
+    
+    if ((tmp = [_cd attributeKeys]))
+      [ma addObjectsFromArray:tmp];
+    if ((tmp = [_cd toOneRelationshipKeys]))
+      [ma addObjectsFromArray:tmp];
+    if ((tmp = [_cd toManyRelationshipKeys]))
+      [ma addObjectsFromArray:tmp];
+    
+    self->entityKeys = [ma copy];
+
+    /* next, map those keys to the source-schema */
+    
+    if (self->map) {
+      [ma removeAllObjects];
+      for (i = 0, count = [entityKeys count]; i < count; i++) {
+       NSString *mappedKey, *key;
+       
+       key       = [entityKeys objectAtIndex:i];
+       mappedKey = [self->map valueForKey:key];
+       [ma addObject:mappedKey ? mappedKey : key];
+      }
+      
+      self->mappedKeys = [ma copy];
+    }
+    
+    [ma release];
+  }
+}
+- (NSClassDescription *)classDescriptionForObjects {
+  return self->classDescription;
+}
+
+/* accessors */
+
+- (void)setSource:(EODataSource *)_source {
+  NSAssert(self->fspec == nil, @"only allowed as long as no spec is set !");
+  
+  [self _removeObserverForSource:self->source];
+  ASSIGN(self->source, _source);
+  [self _registerForSource:self->source];
+  
+  [self postDataSourceChangedNotification];
+}
+- (EODataSource *)source {
+  return self->source;
+}
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fetchSpec {
+  if (![_fetchSpec isEqual:self->fspec]) {
+    /*
+      This saves the spec in the datasource and saves a mapped spec
+      in the source datasource.
+    */
+    EOFetchSpecification *mappedSpec;
+    
+    ASSIGN(self->fspec, _fetchSpec);
+    mappedSpec = [self mapFetchSpecification:self->fspec];
+    [self->source setFetchSpecification:mappedSpec];
+    
+    [self postDataSourceChangedNotification];
+  }
+}
+- (EOFetchSpecification *)fetchSpecification {
+  return self->fspec;
+}
+
+- (NSException *)lastException {
+  if ([self->source respondsToSelector:@selector(lastException)])
+    return [(id)self->source lastException];
+  return nil;
+}
+
+/* fetch operations */
+
+- (Class)fetchEnumeratorClass {
+  return [EOKeyMapDataSourceEnumerator class];
+}
+
+- (NSEnumerator *)fetchEnumerator {
+  NSEnumerator *e;
+  
+  if ((e = [self->source fetchEnumerator]) == nil)
+    return nil;
+  
+  e = [[[self fetchEnumeratorClass] alloc] initWithKeyMapDataSource:self
+                                          fetchEnumerator:e];
+  return [e autorelease];
+}
+
+- (NSArray *)fetchObjects {
+  NSAutoreleasePool *pool;
+  NSArray *a;
+  
+  pool = [[NSArray alloc] init];
+  a = [[NSArray alloc] initWithObjectsFromEnumerator:[self fetchEnumerator]];
+  [pool release];
+  return [a autorelease];
+}
+
+/* modifications */
+
+- (void)insertObject:(id)_obj {
+  [self->source insertObject:[self mapObjectForInsert:_obj]];
+}
+
+- (void)deleteObject:(id)_obj {
+  [self->source deleteObject:[self mapObjectForDelete:_obj]];
+}
+
+- (id)createObject {
+  return [self mapCreatedObject:[self->source createObject]];
+}
+- (void)updateObject:(id)_obj {
+  [self->source updateObject:[self mapObjectForUpdate:_obj]];
+}
+
+- (void)clear {
+  if ([self->source respondsToSelector:@selector(clear)])
+    [(id)self->source clear];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSString *fmt;
+
+  fmt = [NSString stringWithFormat:@"<%@[0x%08X]: source=%@ map=%@>",
+                    NSStringFromClass([self class]), self,
+                    self->source, self->map];
+  return fmt;
+}
+
+@end /* EOKeyMapDataSource */
+
+@implementation EOKeyMapDataSource(Private)
+
+- (void)_registerForSource:(id)_source {
+  static NSNotificationCenter *nc = nil;
+
+  if (_source != nil) {
+    if (nc == nil)
+      nc = [[NSNotificationCenter defaultCenter] retain];
+    
+    [nc addObserver:self selector:@selector(_sourceChanged)
+        name:EODataSourceDidChangeNotification object:_source];
+  }
+}
+
+- (void)_removeObserverForSource:(id)_source {
+  static NSNotificationCenter *nc = nil;
+
+  if (_source != nil) {
+    if (nc == nil)
+      nc = [NSNotificationCenter defaultCenter];
+    [nc removeObserver:self name:EODataSourceDidChangeNotification
+        object:_source];
+  }
+}
+
+ - (void)_sourceChanged {
+  [self postDataSourceChangedNotification];
+}
+
+@end /* EOKeyMapDataSource(Private) */
+
+@implementation EOKeyMapDataSourceEnumerator
+
+- (id)initWithKeyMapDataSource:(EOKeyMapDataSource *)_ds
+  fetchEnumerator:(NSEnumerator *)_enum
+{
+  if ((self = [super init])) {
+    self->ds     = [_ds retain];
+    self->source = [_enum retain];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->ds     release];
+  [self->source release];
+  [super dealloc];
+}
+
+/* fetching */
+
+- (void)fetchDone {
+}
+
+- (id)nextObject {
+  id object;
+  
+  if ((object = [self->source nextObject]) == nil) {
+    [self fetchDone];
+    return nil;
+  }
+  
+  return [self->ds mapFetchedObject:object];
+}
+
+@end /* EOKeyMapDataSourceEnumerator */
+
+@implementation EOMappedObject
+
+- (id)initWithObject:(id)_object values:(NSDictionary *)_values {
+  if ((self = [super init])) {
+    self->original = [_object retain];
+    self->values   = [_values mutableCopy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->original release];
+  [self->globalID release];
+  [self->values   release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id)mappedObject {
+  return self->original;
+}
+- (EOGlobalID *)globalID {
+  if (self->globalID == nil) {
+    if ([self->original respondsToSelector:@selector(globalID)])
+      self->globalID = [[self->original globalID] retain];
+  }
+  return self->globalID;
+}
+
+- (BOOL)isModified {
+  return self->flags.didChange ? YES : NO;
+}
+- (void)willChange {
+  self->flags.didChange = 1;
+}
+
+- (void)applyChangesOnObject {
+  if (!self->flags.didChange)
+    [self->original takeValuesFromDictionary:self->values];
+}
+
+/* mimic dictionary */
+
+- (void)setObject:(id)_obj forKey:(id)_key {
+  [self willChange];
+  [self->values setObject:_obj forKey:_key];
+}
+- (id)objectForKey:(id)_key {
+  return [self->values objectForKey:_key];
+}
+
+- (void)removeObjectForKey:(id)_key {
+  [self willChange];
+  [self->values removeObjectForKey:_key];
+}
+
+- (NSEnumerator *)keyEnumerator {
+  return [self->values keyEnumerator];
+}
+- (NSEnumerator *)objectEnumerator {
+  return [self->values objectEnumerator];
+}
+
+- (NSDictionary *)asDictionary {
+  return self->values;
+}
+
+/* KVC */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  [self willChange];
+  if ([_value isNotNull])
+    [self->values setObject:_value forKey:_key];
+  else
+    [self->values removeObjectForKey:_key];
+}
+
+- (id)valueForKey:(NSString *)_key {
+  return [self->values objectForKey:_key];
+}
+
+@end /* EOMappedObject */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOQualifier+CtxEval.m b/skyrix-core/NGExtensions/EOExt.subproj/EOQualifier+CtxEval.m
new file mode 100644 (file)
index 0000000..fa16877
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOQualifier+CtxEval.h"
+#import <EOControl/EOKeyValueCoding.h>
+#import <EOControl/EONull.h>
+#include "common.h"
+
+#if LIB_FOUNDATION_LIBRARY
+#  import <objc/objc-api.h>
+#  import <objc/objc.h>
+#  import <extensions/objc-runtime.h>
+#elif GNUSTEP_BASE_LIBRARY
+#  import <objc/objc-api.h>
+#else
+#  import <objc/objc.h>
+#  define sel_get_name sel_getName
+#endif
+
+static inline int countSelArgs(SEL _sel) {
+  register const char *selName;
+
+  if ((selName = sel_get_name(_sel))) {
+    register int count;
+    
+    for (count = 0; *selName; selName++) {
+      if (*selName == ':')
+        count++;
+    }
+    return count + 2;
+  }
+  else
+    return -1;
+}
+
+@implementation EOQualifier(ContextEvaluation)
+
+- (BOOL)evaluateWithObject:(id)_object context:(id)_context {
+  [self doesNotRecognizeSelector:_cmd]; /* subclass */
+  return NO;
+}
+
+@end /* EOQualifier(ContextEvaluation) */
+
+@implementation NSArray(ContextEvaluation)
+
+- (NSArray *)filteredArrayUsingQualifier:(EOQualifier *)_qualifier
+  context:(id)_context
+{
+  NSMutableArray *a = nil;
+  unsigned i, count;
+
+  for (i = 0, count = [self count]; i < count; i++) {
+    id o;
+
+    o = [self objectAtIndex:i];
+    
+    if ([_qualifier evaluateWithObject:o context:_context]) {
+      if (a == nil) a = [NSMutableArray arrayWithCapacity:count];
+      [a addObject:o];
+    }
+  }
+  return a ? [[a copy] autorelease] : [NSArray array];
+}
+
+@end /* NSArray(ContextEvaluation) */
+
+@implementation EOAndQualifier(ContextEvaluation)
+
+- (BOOL)evaluateWithObject:(id)_object context:(id)_context {
+  unsigned i;
+  IMP objAtIdx;
+  NSArray *qs;
+
+  qs       = [self qualifiers];
+  objAtIdx = [qs methodForSelector:@selector(objectAtIndex:)];
+  
+  for (i = 0; i < [qs count]; i++) {
+    EOQualifier *q;
+
+    q = objAtIdx(qs, @selector(objectAtIndex:), i);
+
+    if (![q evaluateWithObject:_object context:_context])
+      return NO;
+  }
+  return YES;
+}
+
+@end /* EOAndQualifier(ContextEvaluation) */
+
+@implementation EOOrQualifier(ContextEvaluation)
+
+- (BOOL)evaluateWithObject:(id)_object context:(id)_context {
+  unsigned i;
+  IMP objAtIdx;
+  NSArray *qs;
+
+  qs       = [self qualifiers];
+  objAtIdx = [qs methodForSelector:@selector(objectAtIndex:)];
+  
+  for (i = 0; i < [qs count]; i++) {
+    EOQualifier *q;
+    
+    q = objAtIdx(qs, @selector(objectAtIndex:), i);
+    
+    if ([q evaluateWithObject:_object context:_context])
+      return YES;
+  }
+  return NO;
+}
+
+@end /* EOOrQualifier(ContextEvaluation) */
+
+@implementation EONotQualifier(ContextEvaluation)
+
+- (BOOL)evaluateWithObject:(id)_object context:(id)_context {
+  return
+    [[self qualifier] evaluateWithObject:_object context:_context]
+    ? NO : YES;
+}
+
+@end /* EONotQualifier(ContextEvaluation) */
+
+@implementation EOKeyValueQualifier(ContextEvaluation)
+
+- (BOOL)evaluateWithObject:(id)_object context:(id)_context {
+  static EONull *null = nil;
+  id lv, rv;
+  union {
+    IMP  m;
+    BOOL (*unary)(id, SEL);
+    BOOL (*binary)(id, SEL, id);
+    BOOL (*ctx)(id, SEL, id, id);
+  } m;
+  SEL op;
+  
+  op = [self selector];
+  lv = [_object valueForKeyPath:[self key]];
+  rv = [self value];
+
+  if (null == nil) null = [EONull null];
+  if (lv == nil) lv = null;
+  if (rv == nil) rv = null;
+  
+  if ((m.m = [lv methodForSelector:op]) == NULL) {
+    /* no such operator method ! */
+    [lv doesNotRecognizeSelector:op];
+    return NO;
+  }
+  switch (countSelArgs(op)) {
+    case 0:
+    case 1:
+      NSLog(@"%s: called with invalid selector %@", __PRETTY_FUNCTION__,
+            NSStringFromSelector(op));
+      return NO;
+      
+    case 2:
+      return m.unary(lv, op);
+    case 3:
+      return m.binary(lv, op, rv);
+    default:
+      return m.ctx(lv, op, rv, _context);
+  }
+}
+
+@end /* EOKeyValueQualifier(ContextEvaluation) */
+
+@implementation EOKeyComparisonQualifier(ContextEvaluation)
+
+- (BOOL)evaluateWithObject:(id)_object context:(id)_context {
+  static EONull *null = nil;
+  id lv, rv;
+  union {
+    IMP  m;
+    BOOL (*unary)(id, SEL);
+    BOOL (*binary)(id, SEL, id);
+    BOOL (*ctx)(id, SEL, id, id);
+  } m;
+  SEL op;
+  
+  lv = [_object valueForKeyPath:[self leftKey]];
+  rv = [_object valueForKeyPath:[self rightKey]];
+  if (null == nil) null = [EONull null];
+  if (lv == nil) lv = null;
+  if (rv == nil) rv = null;
+
+  op = [self selector];
+  
+  if ((m.m = (void *)[lv methodForSelector:op]) == NULL) {
+    /* no such operator method ! */
+    [lv doesNotRecognizeSelector:op];
+    return NO;
+  }
+  switch (countSelArgs(op)) {
+    case 0:
+    case 1:
+      NSLog(@"%s: called with invalid selector %@", __PRETTY_FUNCTION__,
+            NSStringFromSelector(op));
+      return NO;
+      
+    case 2:
+      return m.unary(lv, op);
+    case 3:
+      return m.binary(lv, op, rv);
+    default:
+      return m.ctx(lv, op, rv, _context);
+  }
+}
+
+@end /* EOKeyComparisonQualifier(ContextEvaluation) */
+
+@implementation NSObject(ImplementedQualifierComparisons2)
+
+- (BOOL)isEqualTo:(id)_object inContext:(id)_context {
+  return [self isEqualTo:_object];
+}
+- (BOOL)isNotEqualTo:(id)_object inContext:(id)_context {
+  return [self isNotEqualTo:_object];
+}
+
+- (BOOL)isLessThan:(id)_object inContext:(id)_context {
+  return [self isLessThan:_object];
+}
+- (BOOL)isGreaterThan:(id)_object inContext:(id)_context {
+  return [self isGreaterThan:_object];
+}
+- (BOOL)isLessThanOrEqualTo:(id)_object inContext:(id)_context {
+  return [self isLessThanOrEqualTo:_object];
+}
+- (BOOL)isGreaterThanOrEqualTo:(id)_object inContext:(id)_context {
+  return [self isGreaterThanOrEqualTo:_object];
+}
+
+- (BOOL)doesContain:(id)_object inContext:(id)_context {
+  return [self doesContain:_object];
+}
+
+- (BOOL)isLike:(NSString *)_object inContext:(id)_context {
+  return [self isLike:_object];
+}
+- (BOOL)isCaseInsensitiveLike:(NSString *)_object inContext:(id)_context {
+  return [self isCaseInsensitiveLike:_object];
+}
+
+@end
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOQualifier+plist.m b/skyrix-core/NGExtensions/EOExt.subproj/EOQualifier+plist.m
new file mode 100644 (file)
index 0000000..51b9faf
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGExtensions/EOQualifier+plist.h>
+#include "common.h"
+
+@implementation EOQualifier(plist)
+
+- (id)initWithDictionary:(NSDictionary *)_dict {
+  [self release];
+  return [[EOQualifier qualifierToMatchAllValues:_dict] retain];
+}
+
+- (id)initWithArray:(NSArray *)_array {
+  unsigned count;
+  NSString *fmt;
+  NSArray  *args;
+  
+  [self release];
+
+  if ((count = [_array count]) == 0) {
+    NSLog(@"%s: invalid array for qualifier: %@", __PRETTY_FUNCTION__, _array);
+    return nil;
+  }
+  
+  fmt = [_array objectAtIndex:0];
+  if (count == 1)
+    args = nil;
+  else
+    args = [_array subarrayWithRange:NSMakeRange(1, (count - 1))];
+  
+  return [[EOQualifier qualifierWithQualifierFormat:fmt arguments:args]
+                       retain];
+}
+
+- (id)initWithString:(NSString *)_string {
+  [self release];
+  return [[EOQualifier qualifierWithQualifierFormat:_string] retain];
+}
+
+- (id)initWithPropertyList:(id)_plist owner:(id)_owner {
+  if ([_plist isKindOfClass:[NSDictionary class]])
+    return [self initWithDictionary:_plist];
+  
+  if ([_plist isKindOfClass:[NSString class]])
+    return [self initWithString:_plist];
+  
+  if ([_plist isKindOfClass:[NSArray class]])
+    return [self initWithArray:_plist];
+  
+  if ([_plist isKindOfClass:[self class]]) {
+    [self release];
+    return [_plist copy];
+  }
+
+  [self release];
+  return nil;
+}
+- (id)initWithPropertyList:(id)_plist {
+  return [self initWithPropertyList:_plist owner:nil];
+}
+
+@end /* EOQualifier(plist) */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOQualifierGrouping.m b/skyrix-core/NGExtensions/EOExt.subproj/EOQualifierGrouping.m
new file mode 100644 (file)
index 0000000..1a354b1
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOGrouping.h"
+#include <EOControl/EOQualifier.h>
+#include "common.h"
+
+@implementation EOQualifierGrouping
+
+- (id)initWithQualifier:(EOQualifier *)_qualifier name:(NSString *)_name {
+  if ((self = [super initWithDefaultName:nil])) {
+    self->name      = [_name copy];
+    self->qualifier = [_qualifier retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->qualifier release];
+  [self->name      release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setName:(NSString *)_name {
+  NSAssert1(_name != nil, @"%s: name is nil", __PRETTY_FUNCTION__);
+  ASSIGNCOPY(self->name, _name);
+}
+- (NSString *)name {
+  return self->name;
+}
+
+- (void)setQualifier:(EOQualifier *)_qualifier {
+  ASSIGN(self->qualifier, _qualifier);
+}
+- (EOQualifier *)qualifier {
+  return self->qualifier;
+}
+
+/* operations */
+
+- (NSString *)groupNameForObject:(id)_object {
+  if (self->qualifier == nil)
+    return self->name;
+  
+  if ([(id<EOQualifierEvaluation>)self->qualifier evaluateWithObject:_object])
+    return self->name;
+  
+  return self->defaultName;
+}
+
+- (NSArray *)orderedGroupNames {
+  return [NSArray arrayWithObjects:[self name], [self defaultName], nil];
+}
+
+@end /* EOQualifierGrouping */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOSortOrdering+plist.m b/skyrix-core/NGExtensions/EOExt.subproj/EOSortOrdering+plist.m
new file mode 100644 (file)
index 0000000..c11f3fd
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGExtensions/EOSortOrdering+plist.h>
+#include "common.h"
+
+@implementation EOSortOrdering(plist)
+
+/*"
+  Initialize a sort-ordering with information contained in the dictionary.
+  The following keys are recognized: "key" is required and specifies the
+  key to be sorted on, "selector" is optional and specifies the sort
+  selector as a string. The default for "selector" is EOCompareAscending
+  and the following "special" values are recognized: "compareAscending",
+  "compareDescending", "compareCaseInsensitiveAscending", 
+  "compareCaseInsensitiveDescending".
+"*/
+- (id)initWithDictionary:(NSDictionary *)_dict {
+  NSString *k  = nil;
+  SEL      sel = EOCompareAscending;
+  NSString *tmp;
+
+  if (_dict == nil) {
+    [self release];
+    return nil;
+  }
+  
+  k = [_dict objectForKey:@"key"];
+  if ([k length] == 0) {
+    NSLog(@"%s: invalid key %@ (dict=%@)", __PRETTY_FUNCTION__, k, _dict);
+    [self release];
+    return nil;
+  }
+  
+  if ((tmp = [[_dict objectForKey:@"selector"] stringValue])) {
+    if ([tmp isEqualToString:@"compareAscending"])
+      sel = EOCompareAscending;
+    else if ([tmp isEqualToString:@"compareDescending"])
+      sel = EOCompareDescending;
+    else if ([tmp isEqualToString:@"compareCaseInsensitiveAscending"])
+      sel = EOCompareCaseInsensitiveAscending;
+    else if ([tmp isEqualToString:@"compareCaseInsensitiveDescending"])
+      sel = EOCompareCaseInsensitiveDescending;
+    else
+      sel = NSSelectorFromString(tmp);
+  }
+  return [self initWithKey:k selector:sel];
+}
+
+/*"
+  Initialize/parse a sort-ordering from a string. Usually the string is
+  taken as the key of the ordering and the sorting EOCompareAscending. This
+  can be modified by adding ".reverse" to the key, eg "name.reverse" sorts
+  on the "name" key using EOCompareDescending.
+"*/
+- (id)initWithString:(NSString *)_string {
+  SEL      sel;
+  NSString *k;
+  NSRange  r;
+  
+  if ([_string length] == 0) {
+    [self release];
+    return nil;
+  }
+  
+  r = [_string rangeOfString:@".reverse"];
+  if (r.length == 0) {
+    k    = _string;
+    sel = EOCompareAscending;
+  }
+  else {
+    k   = [_string substringToIndex:r.location];
+    sel = EOCompareDescending;
+  }
+  
+  return [self initWithKey:k selector:sel];
+}
+
+- (id)initWithPropertyList:(id)_plist owner:(id)_owner {
+  if (_plist == nil) {
+    [self release];
+    return nil;
+  }
+  
+  if ([_plist isKindOfClass:[NSDictionary class]])
+    return [self initWithDictionary:_plist];
+  if ([_plist isKindOfClass:[NSString class]])
+    return [self initWithString:_plist];
+  
+  if ([_plist isKindOfClass:[self class]]) {
+    [self release];
+    return [_plist copy];
+  }
+  
+  [self release];
+  return nil;
+}
+- (id)initWithPropertyList:(id)_plist {
+  return [self initWithPropertyList:_plist owner:nil];
+}
+
+@end /* EOSortOrdering(plist) */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/EOTrueQualifier.m b/skyrix-core/NGExtensions/EOExt.subproj/EOTrueQualifier.m
new file mode 100644 (file)
index 0000000..c6fb9cf
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOTrueQualifier.h"
+#include "common.h"
+
+@implementation EOTrueQualifier
+
+static EOTrueQualifier *tq = nil;
+
+- (id)init {
+  if (tq == nil) {
+    tq = [[super init] retain];
+    return tq;
+  }
+  else {
+    [self release];
+    return [tq retain];
+  }
+}
+
+- (BOOL)evaluateWithObject:(id)_object {
+  /* we always evaluate to "true" ... */
+  return YES;
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  return @"*true*";
+}
+
+- (NSString *)description {
+  return [self stringValue];
+}
+
+@end /* EOTrueQualifier */
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/GNUmakefile b/skyrix-core/NGExtensions/EOExt.subproj/GNUmakefile
new file mode 100644 (file)
index 0000000..7564fdd
--- /dev/null
@@ -0,0 +1,30 @@
+# $Id$
+
+include ../../common.make
+
+SUBPROJECT_NAME = EOExt
+
+EOExt_OBJC_FILES = \
+       EOCacheDataSource.m             \
+       EOCompoundDataSource.m          \
+       EODataSource+NGExtensions.m     \
+       EOFetchSpecification+plist.m    \
+       EOFilterDataSource.m            \
+       EOGrouping.m                    \
+       EOGroupingSet.m                 \
+       EOKeyGrouping.m                 \
+       EOKeyMapDataSource.m            \
+       EOQualifier+CtxEval.m           \
+       EOQualifier+plist.m             \
+       EOQualifierGrouping.m           \
+       EOSortOrdering+plist.m          \
+       EOTrueQualifier.m               \
+       NSArray+EOGrouping.m            \
+
+ADDITIONAL_INCLUDE_DIRS += -I. -I.. -I../NGExtensions/ \
+       -I../FdExt.subproj/     \
+       -I../..
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/NGExtensions/EOExt.subproj/NSArray+EOGrouping.m b/skyrix-core/NGExtensions/EOExt.subproj/NSArray+EOGrouping.m
new file mode 100644 (file)
index 0000000..1053c38
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOGrouping.h"
+#include <EOControl/EOSortOrdering.h>
+#include "common.h"
+
+@implementation NSArray(EOGrouping)
+
+static BOOL ProfileComponents = NO;
+
+- (NSDictionary *)arrayGroupedBy:(EOGrouping *)_grouping {
+  NSMutableDictionary *result;
+  NSEnumerator        *keyEnum;
+  NSString            *key;
+  NSArray             *sortings;
+  int                 i, cnt;
+  IMP                 objAtIndex;
+  IMP                 groupForObj;
+  NSTimeInterval      st = 0.0;
+  
+  if (ProfileComponents)
+    st = [[NSDate date] timeIntervalSince1970];
+  
+  cnt    = [self count];
+  result = [NSMutableDictionary dictionaryWithCapacity:cnt];
+
+  objAtIndex  = [self methodForSelector:@selector(objectAtIndex:)];
+  groupForObj = [_grouping methodForSelector:@selector(groupNameForObject:)];
+  
+  for (i = 0; i < cnt; i++) {
+    NSString       *gName = nil; // groupName
+    NSMutableArray *tmp   = nil;
+    id   obj              = nil;
+
+    obj   = objAtIndex(self, @selector(objectAtIndex:), i);
+    gName = groupForObj(_grouping, @selector(groupNameForObject:), obj);
+
+    if (gName == nil) continue;
+
+    if (!(tmp = [result objectForKey:gName])) {
+      tmp = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
+      [result setObject:tmp forKey:gName];
+    }
+    [tmp addObject:obj];
+  }
+  
+  sortings = [_grouping sortOrderings];
+
+  if ([sortings count] > 0) {
+    // sort each group
+    keyEnum = [result keyEnumerator];
+    while ((key = [keyEnum nextObject])) {
+      NSArray *tmp;
+    
+      tmp = [result objectForKey:key];
+      tmp = [tmp  sortedArrayUsingKeyOrderArray:sortings];
+      [result setObject:tmp forKey:key];
+    }
+  }
+  
+  if (ProfileComponents) {
+    NSTimeInterval diff;
+    diff = [[NSDate date] timeIntervalSince1970] - st;
+    
+    printf("NSArray+Grouping: %0.4fs\n", diff);
+  }
+  
+  return result;
+}
+
+@end /* NSArray(EOGrouping) */
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/.cvsignore b/skyrix-core/NGExtensions/FdExt.subproj/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/GNUmakefile b/skyrix-core/NGExtensions/FdExt.subproj/GNUmakefile
new file mode 100644 (file)
index 0000000..bcaeb87
--- /dev/null
@@ -0,0 +1,43 @@
+# $Id$
+
+include ../../common.make
+
+SUBPROJECT_NAME = FdExt
+
+FdExt_OBJC_FILES = \
+       NSArray+enumerator.m            \
+       NSAutoreleasePool+misc.m        \
+       NSCalendarDate+misc.m           \
+       NSData+gzip.m                   \
+       NSData+misc.m                   \
+       NSDictionary+misc.m             \
+       NSEnumerator+misc.m             \
+       NSException+misc.m              \
+       NSFileManager+Extensions.m      \
+       NSMethodSignature+misc.m        \
+       NSNull+misc.m                   \
+       NSObject+Logs.m                 \
+       NSObject+Values.m               \
+       NSProcessInfo+misc.m            \
+       NSRunLoop+FileObjects.m         \
+       NSSet+enumerator.m              \
+       NSString+Ext.m                  \
+       NSString+Encoding.m             \
+       NSString+Formatting.m           \
+       NSString+misc.m                 \
+       NSString+HTMLEscaping.m         \
+       NSString+XMLEscaping.m          \
+       NSString+URLEscaping.m          \
+       NSString+German.m               \
+       NSURL+misc.m                    \
+       NGPropertyListParser.m          \
+
+ADDITIONAL_INCLUDE_DIRS += -I. -I../NGExtensions/ -I.. -I../..
+
+ifeq ($(iseries),yes)
+ADDITIONAL_CPPFLAGS += -DISERIES=1
+endif
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NGPropertyListParser.m b/skyrix-core/NGExtensions/FdExt.subproj/NGPropertyListParser.m
new file mode 100644 (file)
index 0000000..cba5634
--- /dev/null
@@ -0,0 +1,1249 @@
+/*
+  Copyright (C) 2000-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$
+
+#if !LIB_FOUNDATION_LIBRARY
+
+//#define HAVE_MMAP
+
+#ifdef HAVE_MMAP
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#endif
+#include <ctype.h>
+
+#import "common.h"
+#import "NGPropertyListParser.h"
+#import "NGMemoryAllocation.h"
+//#import "NSObjectMacros.h"
+//#import "NSException.h"
+#import <Foundation/NSData.h>
+
+#define NoZone NULL
+
+@interface NSException(UsedPrivates) /* may break on Panther? */
+- (void)setUserInfo:(NSDictionary *)_ui;
+- (void)setReason:(NSString *)_reason;
+@end
+
+static NSString     *_parseString (NSZone *_zone, const char *_buffer,
+                                   unsigned *_idx, unsigned _len,
+                                   NSException **_exception);
+static NSDictionary *_parseDict   (NSZone *_zone, const char *_buffer,
+                                   unsigned *_idx, unsigned _len,
+                                   NSException **_exception);
+static NSArray      *_parseArray  (NSZone *_zone, const char *_buffer,
+                                   unsigned *_idx, unsigned _len,
+                                   NSException **_exception);
+static NSData       *_parseData   (NSZone *_zone, const char *_buffer,
+                                   unsigned *_idx, unsigned _len,
+                                   NSException **_exception);
+static id           _parseProperty(NSZone *_zone, const char *_buffer,
+                                   unsigned *_idx, unsigned _len,
+                                   NSException **_exception);
+static NSDictionary *_parseStrings(NSZone *_zone, const char *_buffer,
+                                   unsigned *_idx, unsigned _len,
+                                   NSException **_exception);
+
+// public functions
+
+NSString *NGParseStringFromBuffer(const unsigned char *_buffer, unsigned _len)
+{
+    NSString    *result    = nil;
+    NSException *exception = nil;
+    unsigned    idx        = 0;
+
+    if (_len >= 2) {
+        if (_buffer[0] == 0xFE && _buffer[1] == 0xFF) {
+            NSLog(@"WARNING(%s): tried to parse Unicode string (FE/FF) ...",
+                  __PRETTY_FUNCTION__);
+            return nil;
+        }
+        else if (_buffer[0] == 0xFF && _buffer[1] == 0xFE) {
+            NSLog(@"WARNING(%s): tried to parse Unicode string (FF/FE) ...",
+                  __PRETTY_FUNCTION__);
+            return nil;
+        }
+    }
+    
+    result = [_parseString(NoZone, _buffer, &idx, _len, &exception) autorelease];
+    [exception raise];
+    return result;
+}
+
+NSArray *NGParseArrayFromBuffer(const unsigned char *_buffer, unsigned _len)
+{
+    NSArray     *result    = nil;
+    NSException *exception = nil;
+    unsigned    idx        = 0;
+
+    if (_len >= 2) {
+        if (_buffer[0] == 0xFE && _buffer[1] == 0xFF) {
+            NSLog(@"WARNING(%s): tried to parse Unicode array (FE/FF) ...",
+                  __PRETTY_FUNCTION__);
+            return nil;
+        }
+        else if (_buffer[0] == 0xFF && _buffer[1] == 0xFE) {
+            NSLog(@"WARNING(%s): tried to parse Unicode array (FF/FE) ...",
+                  __PRETTY_FUNCTION__);
+            return nil;
+        }
+    }
+    
+    result = [_parseArray(NoZone, _buffer, &idx, _len, &exception) autorelease];
+    [exception raise];
+    return result;
+}
+
+NSDictionary *NGParseDictionaryFromBuffer(const unsigned char *_buffer, unsigned _len)
+{
+    NSDictionary *result    = nil;
+    NSException  *exception = nil;
+    unsigned     idx        = 0;
+
+    if (_len >= 2) {
+        if (_buffer[0] == 0xFE && _buffer[1] == 0xFF) {
+            NSLog(@"WARNING(%s): tried to parse Unicode dict (FE/FF) ...",
+                  __PRETTY_FUNCTION__);
+            return nil;
+        }
+        else if (_buffer[0] == 0xFF && _buffer[1] == 0xFE) {
+            NSLog(@"WARNING(%s): tried to parse Unicode dict (FF/FE) ...",
+                  __PRETTY_FUNCTION__);
+            return nil;
+        }
+    }
+    
+    result = [_parseDict(NoZone, _buffer, &idx, _len, &exception) autorelease];
+    [exception raise];
+    return result;
+}
+
+NSString *NGParseStringFromData(NSData *_data)
+{
+    return NGParseStringFromBuffer([_data bytes], [_data length]);
+}
+
+NSArray *NGParseArrayFromData(NSData *_data)
+{
+    return NGParseArrayFromBuffer([_data bytes], [_data length]);
+}
+
+NSDictionary *NGParseDictionaryFromData(NSData *_data)
+{
+    return NGParseDictionaryFromBuffer([_data bytes], [_data length]);
+}
+
+NSString *NGParseStringFromString(NSString *_str)
+{
+    return NGParseStringFromBuffer([_str cString], [_str cStringLength]);
+}
+
+NSArray *NGParseArrayFromString(NSString *_str)
+{
+    return NGParseArrayFromBuffer([_str cString], [_str cStringLength]);
+}
+
+NSDictionary *NGParseDictionaryFromString(NSString *_str)
+{
+    return NGParseDictionaryFromBuffer([_str cString], [_str cStringLength]);
+}
+
+id NGParsePropertyListFromBuffer(const unsigned char *_buffer, unsigned _len)
+{
+    id          result = nil;
+    NSException *exception = nil;
+    unsigned    idx = 0;
+    
+    if (_len >= 2) {
+        if (_buffer[0] == 0xFE && _buffer[1] == 0xFF) {
+            NSLog(@"WARNING(%s): tried to parse Unicode plist (FE/FF) ...",
+                  __PRETTY_FUNCTION__);
+            return nil;
+        }
+        else if (_buffer[0] == 0xFF && _buffer[1] == 0xFE) {
+            NSLog(@"WARNING(%s): tried to parse Unicode plist (FF/FE) ...",
+                  __PRETTY_FUNCTION__);
+            return nil;
+        }
+    }
+    
+    result = [_parseProperty(NoZone, _buffer, &idx, _len, &exception) 
+                           autorelease];
+    [exception raise];
+    return result;
+}
+
+id NGParsePropertyListFromData(NSData *_data)
+{
+    return NGParsePropertyListFromBuffer([_data bytes], [_data length]);
+}
+
+id NGParsePropertyListFromString(NSString *_string)
+{
+    return NGParsePropertyListFromBuffer([_string cString], [_string cStringLength]);
+}
+
+id NGParsePropertyListFromFile(NSString *_path)
+{
+#ifdef HAVE_MMAP
+    NSException *exception = nil;
+    int         fd         = 0;
+    id          result     = nil;
+
+    fd = open([_path cString], O_RDONLY);
+    if (fd != -1) {
+        struct stat statInfo;
+        if (fstat(fd, &statInfo) == 0) {
+            void *mem = NULL;
+
+            mem = mmap(0, statInfo.st_size, PROT_READ, MAP_SHARED, fd, 0);
+            if ((mem != MAP_FAILED) || (mem == NULL)) {
+                NS_DURING {
+                    unsigned idx = 0;
+                    result = _parseProperty(nil, mem, &idx, statInfo.st_size,
+                                            &exception);
+                }
+                NS_HANDLER {
+                    result = nil;
+                    exception = [localException retain];
+                }
+                NS_ENDHANDLER;
+
+                munmap(mem, statInfo.st_size);
+                mem = NULL;
+            }
+            else {
+                NSLog(@"Could not map file %@ into virtual memory !", _path);
+            }
+        }
+        else {
+            NSLog(@"File %@ could not be mapped !", _path);
+        }
+        close(fd);
+    }
+    else {
+        NSLog(@"File %@ does not exist !", _path);
+    }
+
+    [result autorelease];
+    if (exception)
+        [exception raise];
+  
+    return result;
+#else
+    NSData *data = [NSData dataWithContentsOfFile:_path];
+    
+    if (data) {
+        return NGParsePropertyListFromData(data);
+    }
+    else {
+        NSLog(@"%s: Could not parse plist file %@ !", __PRETTY_FUNCTION__,
+              _path);
+        return nil;
+    }
+#endif
+}
+
+NSDictionary *NGParseStringsFromBuffer(const char *_buffer, unsigned _len)
+{
+    NSDictionary *result    = nil;
+    NSException  *exception = nil;
+    unsigned     idx        = 0;
+    
+    result = [_parseStrings(NoZone, _buffer, &idx, _len, &exception) autorelease];
+    [exception raise];
+    return result;
+}
+
+NSDictionary *NGParseStringsFromData(NSData *_data)
+{
+    return NGParseStringsFromBuffer([_data bytes], [_data length]);
+}
+
+NSDictionary *NGParseStringsFromString(NSString *_string)
+{
+    return NGParseStringsFromBuffer([_string cString], [_string cStringLength]);
+}
+
+NSDictionary *NGParseStringsFromFile(NSString *_path)
+{
+#ifdef HAVE_MMAP
+    struct stat statInfo;
+    NSException *exception = nil;
+    int         fd = 0;
+    id          result = nil;
+
+    fd = open([_path cString], O_RDONLY);
+    if (fd != -1) {
+        if (fstat(fd, &statInfo) == 0) {
+            void *mem = NULL;
+
+            mem = mmap(0, statInfo.st_size, PROT_READ, MAP_SHARED, fd, 0);
+            if (mem != MAP_FAILED) {
+                NS_DURING {
+                    unsigned idx = 0;
+                    result = _parseStrings(nil, mem, &idx, statInfo.st_size,
+                                           &exception);
+                }
+                NS_HANDLER {
+                    exception = [localException retain];
+                    result = nil;
+                }
+                NS_ENDHANDLER;
+
+                munmap(mem, statInfo.st_size);
+                mem = NULL;
+            }
+            else
+                NSLog(@"Could not map file %@ into virtual memory !", _path);
+        }
+        else {
+            NSLog(@"File %@ could not be mapped !", _path);
+        }
+        close(fd);
+    }
+    else {
+        NSLog(@"File %@ does not exist !", _path);
+    }
+
+    [result autorelease];
+    [exception raise];
+  
+    return result;
+#else
+    NSData *data = [NSData dataWithContentsOfFile:_path];
+
+    if (data)
+        return NGParseStringsFromData(data);
+    else {
+        NSLog(@"%s: Could not parse strings file %@ !",
+              __PRETTY_FUNCTION__, _path);
+        return nil;
+    }
+#endif
+}
+
+/* ******************* implementation ******************** */
+
+static inline BOOL _isBreakChar(char _c)
+{
+    switch (_c) {
+        case ' ': case '\t': case '\n': case '\r':
+        case '/': case '=':  case ';':  case ',':
+        case '{': case '(':  case '"':  case '<':
+        case '}': case ')': case '>':
+            return YES;
+
+        default:
+            return NO;
+    }
+}
+
+static inline int _valueOfHexChar(char _c)
+{
+    switch (_c) {
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+            return (_c - 48); // 0-9 (ascii-char)'0' - 48 => (int)0
+      
+        case 'A': case 'B': case 'C':
+        case 'D': case 'E': case 'F':
+            return (_c - 55); // A-F, A=10..F=15, 'A'=65..'F'=70
+      
+        case 'a': case 'b': case 'c':
+        case 'd': case 'e': case 'f':
+            return (_c - 87); // a-f, a=10..F=15, 'a'=97..'f'=102
+
+        default:
+            return -1;
+    }
+}
+static inline BOOL _isHexDigit(char _c)
+{
+    switch (_c) {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+    case 'A': case 'B': case 'C':
+    case 'D': case 'E': case 'F':
+    case 'a': case 'b': case 'c':
+    case 'd': case 'e': case 'f':
+        return YES;
+
+    default:
+        return NO;
+    }
+}
+
+static inline int _numberOfLines(const char *_buffer, unsigned _lastIdx)
+{
+    register int pos, lineCount = 1;
+
+    for (pos = 0; (pos < _lastIdx) && (_buffer[pos] != '\0'); pos++) {
+        if (_buffer[pos] == '\n')
+            lineCount++;
+    }
+    return lineCount;
+}
+
+static NSException *_makeException(NSException *_exception,
+                                   const char *_buffer, unsigned _idx,
+                                   unsigned _len, NSString *_text)
+{
+    NSMutableDictionary *ui = nil;
+    NSException *exception = nil;
+    int         numLines   = _numberOfLines(_buffer, _idx);
+    BOOL        atEof      = (_idx >= _len) ? YES : NO;
+
+    if (_exception) // error resulted from a previous error (exception already set)
+        return _exception;
+
+    exception = [NSException exceptionWithName:@"SyntaxErrorException"
+                             reason:nil
+                             userInfo:nil];
+
+    _text = atEof
+        ? [NSString stringWithFormat:@"Unexpected end: %@", _text]
+        : [NSString stringWithFormat:@"Syntax error in line %i: %@", numLines,_text];
+  
+    [exception setReason:_text];
+
+    // user info
+    {
+        ui = [[exception userInfo] mutableCopy];
+        if (ui == nil)
+            ui = [[NSMutableDictionary alloc] initWithCapacity:8];
+
+        [ui setObject:[NSNumber numberWithInt:numLines] forKey:@"line"];
+        [ui setObject:[NSNumber numberWithInt:_len]     forKey:@"size"];
+        [ui setObject:[NSNumber numberWithInt:_idx]     forKey:@"position"];
+
+        /*
+          if (_len > 0)
+          [ui setObject:[NSString stringWithCString:_buffer length:_len]
+              forKey:@"text"];
+    
+          if (!atEof && (_idx > 0)) {
+          [ui setObject:[NSString stringWithCString:_buffer length:_idx]
+          forKey:@"consumedText"];
+          }
+        */
+        if (!atEof && (_idx > 0)) {
+            register unsigned pos;
+            const char *startPos, *endPos;
+
+            for (pos = _idx; (pos >= 0) && (_buffer[pos] != '\n'); pos--)
+                ;
+            startPos = &(_buffer[pos + 1]);
+
+            for (pos = _idx; ((pos < _len) && (_buffer[pos] != '\n')); pos++)
+                ;
+            endPos = &(_buffer[pos - 1]);
+
+            if (startPos < endPos) {
+               NSString *s;
+               
+               s = [[NSString alloc] initWithCString:startPos 
+                                     length:(endPos - startPos)];
+               if (s != nil) {
+                   [ui setObject:s forKey:@"lastLine"];
+                   [s release];
+               }
+               else {
+                   NSLog(@"ERROR(%s): could not get last-line!",
+                         __PRETTY_FUNCTION__);
+               }
+            }
+            else
+                NSLog(@"startPos=0x%08X endPos=0x%08X", startPos, endPos);
+        }
+    
+        [exception setUserInfo:ui];
+    
+        [ui release]; ui = nil;
+    }
+
+    return exception;
+}
+
+static BOOL _skipComments(const char *_buffer, unsigned *_idx, unsigned _len,
+                          BOOL _skipSpaces, NSException **_exception)
+{
+    register unsigned pos = *_idx;
+    BOOL lookAgain;
+
+    if (pos >= _len)
+        return NO;
+  
+    do { // until all comments are filtered ..
+        lookAgain = NO;
+    
+        if ((_buffer[pos] == '/') && (pos + 1 < _len)) {
+            if (_buffer[pos + 1] == '/') { // single line comments
+                pos += 2; // skip '//'
+
+                // search for '\n' ..
+                while ((pos < _len) && (_buffer[pos] != '\n'))
+                    pos++;
+
+                if ((pos < _len) && (_buffer[pos] == '\n')) {
+                    pos++; // skip newline, otherwise EOF was reached
+                    lookAgain = YES;
+                }
+            }
+            else if (_buffer[pos + 1] == '*') { /* multiline comments */
+                BOOL commentIsClosed = NO;
+      
+                pos += 2; // skip '/*'
+
+                do { // search for '*/'
+                    while ((pos < _len) && (_buffer[pos] != '*'))
+                        pos++;
+
+                    if (pos < _len) { // found '*'
+                        if ((pos + 1) < _len) {
+                            if (_buffer[pos + 1] == '/') { // found '*/'
+                                commentIsClosed = YES;
+                                pos += 2; // skip '*/'
+                                lookAgain = YES;
+                                break; // leave loop
+                            }
+                        }
+                    }
+                }
+                while (pos < _len);
+
+                if (!commentIsClosed) {
+                    // EOF found, comment was not closed
+                    *_exception =
+                        _makeException(*_exception, _buffer, *_idx, _len,
+                                       @"comment was not closed (expected '*/')");
+                    return NO;
+                }
+            }
+        }
+        else if (_skipSpaces && isspace((int)_buffer[pos])) {
+            pos++;
+            lookAgain = YES;
+        }
+    }
+    while (lookAgain && (pos < _len));
+
+    // store position ..
+    *_idx = pos;
+    //NSLog(@"skipped comments, now at '%s'", &(_buffer[*_idx]));
+
+    return (pos < _len);
+}
+
+static NSString *_parseString(NSZone *_zone, const char *_buffer, unsigned *_idx,
+                              unsigned _len, NSException **_exception)
+{
+
+    // skip comments and spaces
+    if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+        // EOF reached during comment-skipping
+        *_exception =
+            _makeException(*_exception, _buffer, *_idx, _len,
+                           @"did not find a string !");
+        return nil;
+    }
+
+    if (_buffer[*_idx] == '"') { // a quoted string
+        register unsigned pos = *_idx;
+        register unsigned len = 0;
+        unsigned startPos = pos + 1;
+        BOOL     containsEscaped = NO;
+    
+        pos++; // skip starting quote
+
+        // loop until closing quote
+        while ((_buffer[pos] != '"') && (pos < _len)) {
+            if (_buffer[pos] == '\\') {
+                containsEscaped = YES;
+                pos++; // skip following char
+                if (pos == _len) {
+                    *_exception =
+                        _makeException(*_exception, _buffer, *_idx, _len,
+                                       @"escape in quoted string not finished !");
+                    return nil;
+                }
+            }
+            pos++;
+            len++;
+        }
+
+        if (pos == _len) { // syntax error, quote not closed
+            *_idx = pos;
+            *_exception =
+                _makeException(*_exception, _buffer, *_idx, _len,
+                               @"quoted string not closed (expected '\"')");
+            return nil;
+        }
+
+        pos++;       // skip closing quote
+        *_idx = pos; // store pointer
+        pos = 0;
+    
+        if (len == 0) { // empty string
+            return @"";
+        }
+        else if (containsEscaped) {
+            register unsigned pos2;
+            char *str = NGMallocAtomic(len + 1);
+            id   ostr = nil;
+
+            NSCAssert(len > 0, @"invalid length ..");
+
+            for (pos = startPos, pos2 = 0; _buffer[pos] != '"'; pos++, pos2++) {
+                //NSLog(@"char=%c pos=%i pos2=%i", _buffer[pos], pos2);
+                if (_buffer[pos] == '\\') {
+                    pos++;
+                    switch (_buffer[pos]) {
+                    case 'a':  str[pos2] = '\a'; break;
+                    case 'b':  str[pos2] = '\b'; break;
+                    case 'f':  str[pos2] = '\f'; break;
+                    case 'n':  str[pos2] = '\n'; break;
+                    case 't':  str[pos2] = '\t'; break;
+                    case 'v':  str[pos2] = '\v'; break;
+                    case '\\': str[pos2] = '\\'; break;
+            
+                    default:
+                        str[pos2] = _buffer[pos];
+                        break;
+                    }
+                }
+                else {
+                    str[pos2] = _buffer[pos];
+                }
+            }
+            str[pos2] = '\0';
+            NSCAssert(pos2 == len, @"invalid unescape ..");
+
+            ostr = [[NSString allocWithZone:_zone]
+                              initWithCString:str length:len];
+            NGFree(str); str = NULL;
+
+            return ostr;
+        }
+        else {
+            NSCAssert(len > 0, @"invalid length ..");
+      
+            return [[NSString allocWithZone:_zone]
+                              initWithCString:&(_buffer[startPos]) length:len];
+        }
+    }
+    else { // an unquoted string, may not be zero chars long !
+        register unsigned pos = *_idx;
+        register unsigned len = 0;
+        unsigned startPos = pos;
+
+        // loop until break char
+        while (!_isBreakChar(_buffer[pos]) && (pos < _len)) {
+            pos++;
+            len++;
+        }
+
+        if (len == 0) { // was not a string ..
+            *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                         @"did not find a string !");
+            return nil;
+        }
+        else {
+            *_idx = pos;
+            return [[NSString allocWithZone:_zone]
+                              initWithCString:&(_buffer[startPos]) length:len];
+        }
+    }
+}
+
+static NSData *_parseData(NSZone *_zone, const char *_buffer,
+                          unsigned *_idx, unsigned _len, NSException **_exception)
+{
+    if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+        // EOF reached during comment-skipping
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"did not find a data (expected '<') !");
+        return nil;
+    }
+
+    if (_buffer[*_idx] != '<') { // it's not a data that's follows
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"did not find a data (expected '<') !");
+        return nil;
+    }
+    else {
+        register      unsigned pos = *_idx + 1;
+        register      unsigned len = 0;
+        unsigned      endPos = 0;
+        NSMutableData *data  = nil;
+    
+        *_idx += 1; // skip '<'
+
+        if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+            *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                         @"data was not closed (expected '>') ..");
+            return nil; // EOF
+        }
+
+        if (_buffer[*_idx] == '>') { // empty data
+            *_idx += 1; // skip '>'
+            return [[NSData allocWithZone:_zone] init];
+        }
+
+        // count significant chars
+        while ((_buffer[pos] != '>') && (pos < _len)) {
+            if ((_buffer[pos] == ' ') || (_buffer[pos] == '\t'))
+                ;
+            else if (_isHexDigit(_buffer[pos]))
+                len++;
+            else {
+                *_idx = pos;
+                *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                             @"invalid char in data property");
+                return nil; // abort
+            }
+            pos++;
+        }
+        if (pos == _len) {
+            *_idx = pos;
+            *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                         @"data was not closed (expected '>')");
+            return nil; // EOF
+        }
+        endPos = pos; // store position of closing '>'
+
+        // if odd, then add one byte for trailing nibble
+        len = (len % 2 == 1) ? len / 2 + 1 : len / 2;
+        data = [[NSMutableData allocWithZone:_zone] initWithLength:len];
+
+        // now copy bytes ..
+        {
+            register unsigned i;
+            register unsigned pending = -1;
+            char *buf = [data mutableBytes];
+      
+            for (pos = *_idx, i = 0; (pos < endPos) && (i < len); pos++) {
+                int value = _valueOfHexChar(_buffer[pos]);
+
+                if (value != -1) {
+                    if (pending == -1)
+                        pending = value;
+                    else {
+                        value = value * 16 + pending;
+                        pending = -1;
+
+                        buf[i] = value;
+                        i++;
+                    }
+                }
+            }
+            if (pending != -1) { // was odd, now add the trailer ..
+                NSCAssert(i < len, @"invalid length ..");
+                buf[i] = pending * 16;
+            }
+        }
+    
+        // update global position
+        *_idx = endPos + 1; // endPos + 1 (*endPos == '>', 1 => skips '>')
+
+        return data;
+    }
+}
+
+static NSDictionary *_parseDict(NSZone *_zone, const char *_buffer, unsigned *_idx,
+                                unsigned _len, NSException **_exception)
+{
+    if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+        // EOF reached during comment-skipping
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"did not find dictionary (expected '{')");
+        return nil;
+    }
+  
+    if (_buffer[*_idx] != '{') { // it's not a dict that's follows
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"did not find dictionary (expected '{')");
+        return nil;
+    }
+    else {
+        NSMutableDictionary *result = nil;
+        id   key     = nil;
+        id   value   = nil;
+        BOOL didFail = NO;
+    
+        *_idx += 1; // skip '{'
+
+        if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+            *_exception =
+                _makeException(*_exception, _buffer, *_idx, _len,
+                               @"dictionary was not closed (expected '}')");
+            return nil; // EOF
+        }
+
+        if (_buffer[*_idx] == '}') { // an empty dictionary
+            *_idx += 1; // skip the '}'
+            return [[NSDictionary allocWithZone:_zone] init];
+        }
+
+        result = [[NSMutableDictionary allocWithZone:_zone] init];
+        do {
+            key   = nil;
+            value = nil;
+      
+            if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+                *_exception =
+                    _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"dictionary was not closed (expected '}')");
+                didFail = YES;
+                break; // unexpected EOF
+            }
+
+            if (_buffer[*_idx] == '}') { // dictionary closed
+                *_idx += 1; // skip the '}'
+                break;
+            }
+      
+            // read key property
+            key = _parseProperty(_zone, _buffer, _idx, _len, _exception);
+            if (key == nil) { // syntax error
+                if (*_exception == nil) {
+                    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                                 @"got nil-key in dictionary ..");
+                }
+                didFail = YES;
+                break;
+            }
+
+            /* The following parses:  (comment|space)* '=' (comment|space)* */
+            if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+                *_exception =
+                    _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"expected '=' after key in dictionary");
+                didFail = YES;
+                break; // unexpected EOF
+            }
+            // no we need a '=' assignment
+            if (_buffer[*_idx] != '=') {
+                *_exception =
+                    _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"expected '=' after key in dictionary");
+                didFail = YES;
+                break;
+            }
+            *_idx += 1; // skip '='
+            if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+                *_exception =
+                    _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"expected value after key '=' in dictionary");
+                didFail = YES;
+                break; // unexpected EOF
+            }
+
+            // read value property
+            value = _parseProperty(_zone, _buffer, _idx, _len, _exception);
+            if (value == nil) { // syntax error
+                if (*_exception == nil) {
+                    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                                 @"got nil-value in dictionary");
+                }
+                didFail = YES;
+                break;
+            }
+
+            NSCAssert(key,   @"invalid key ..");
+            NSCAssert(value, @"invalid value ..");
+
+            [result setObject:value forKey:key];
+
+            // release key and value
+            [key   release]; key   = nil;
+            [value release]; value = nil;
+
+            // read trailing ';' if available
+            if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+                *_exception =
+                    _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"dictionary was not closed (expected '}')");
+                didFail = YES;
+                break; // unexpected EOF
+            }
+            if (_buffer[*_idx] == ';') {
+                *_idx += 1; // skip ';'
+            }
+            else { // no ';' at end of pair, only allowed at end of dictionary
+                if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+                    *_exception =
+                        _makeException(*_exception, _buffer, *_idx, _len,
+                                       @"dictionary was not closed (expected '}')");
+                    didFail = YES;
+                    break; // unexpected EOF
+                }
+
+                if (_buffer[*_idx] != '}') { // dictionary was not closed
+                    *_exception =
+                        _makeException(*_exception, _buffer, *_idx, _len,
+                                       @"key-value pair without ';' at the end");
+                    didFail = YES;
+                    break;
+                }
+            }
+        }
+        while ((*_idx < _len) && (result != nil) && !didFail);
+
+        if (didFail) {
+            [key    release]; key    = nil;
+            [value  release]; value  = nil;
+            [result release]; result = nil;
+            return nil;
+        }
+        else
+            return result;
+    }
+}
+
+static NSArray *_parseArray(NSZone *_zone, const char *_buffer, unsigned *_idx,
+                            unsigned _len, NSException **_exception)
+{
+    if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+        // EOF reached during comment-skipping
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"did not find array (expected '(')");
+        return nil;
+    }
+
+    if (_buffer[*_idx] != '(') { // it's not an array that's follows
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"did not find array (expected '(')");
+        return nil;
+    }
+    else {
+        NSMutableArray *result = nil;
+        id element = nil;
+
+        *_idx += 1; // skip '('
+
+        if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+            *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                         @"array was not closed (expected ')')");
+            return nil; // EOF
+        }
+
+        if (_buffer[*_idx] == ')') { // an empty array
+            *_idx += 1; // skip the ')'
+            return [[NSArray allocWithZone:_zone] init];
+        }
+
+        result = [[NSMutableArray allocWithZone:_zone] init];
+        do {
+            element = _parseProperty(_zone, _buffer, _idx, _len, _exception);
+            if (element == nil) {
+                *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                             @"expected element in array");
+                [result release]; result = nil;
+                break;
+            }
+            [result addObject:element];
+            [element release]; element = nil;
+
+            if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+                *_exception =
+                    _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"array was not closed (expected ')' or ',')");
+                [result release]; result = nil;
+                break;
+            }
+
+            if (_buffer[*_idx] == ')') { // closed array
+                *_idx += 1; // skip ')'
+                break;
+            }
+            else if (_buffer[*_idx] == ',') { // next element
+                *_idx += 1; // skip ','
+
+                if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+                    *_exception =
+                        _makeException(*_exception, _buffer, *_idx, _len,
+                                       @"array was not closed (expected ')')");
+                    [result release]; result = nil;
+                    break;
+                }
+                if (_buffer[*_idx] == ')') { // closed array, like this '(1,2,)'
+                    *_idx += 1; // skip ')'
+                    break;
+                }
+            }
+            else { // syntax error
+                *_exception =
+                    _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"expected ')' or ',' after array element");
+                [result release]; result = nil;
+                break;
+            }
+        }
+        while ((*_idx < _len) && (result != nil));
+
+        return result;
+    }
+}
+
+static id _parseProperty(NSZone *_zone, const char *_buffer, unsigned *_idx,
+                         unsigned _len, NSException **_exception)
+{
+    id result = nil;
+    
+    if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+        // no property found
+        return nil; // EOF
+    }
+
+    switch (_buffer[*_idx]) {
+    case '"': // quoted string
+        result = _parseString(_zone, _buffer, _idx, _len, _exception);
+        break;
+    case '{': // dictionary
+        result = _parseDict(_zone, _buffer, _idx, _len, _exception);
+        break;
+    case '(': // array
+        result = _parseArray(_zone, _buffer, _idx, _len, _exception);
+        break;
+    case '<': // data
+        result = _parseData(_zone, _buffer, _idx, _len, _exception);
+        break;
+    default: // an unquoted string
+        result = _parseString(_zone, _buffer, _idx, _len, _exception);
+        break;
+    }
+
+    return result;
+}
+
+static NSDictionary *_parseStrings(NSZone *_zone, const char *_buffer,
+                                   unsigned *_idx, unsigned _len,
+                                   NSException **_exception)
+{
+    NSMutableDictionary *result = nil;
+    id   key     = nil;
+    id   value   = nil;
+    BOOL didFail = NO;
+  
+    result = [[NSMutableDictionary allocWithZone:_zone] init];
+    while ((*_idx < _len) && (result != nil) && !didFail) {
+        key   = nil;
+        value = nil;
+      
+        if (!_skipComments(_buffer, _idx, _len, YES, _exception))
+            break; // expected EOF
+
+        // read key string
+        key = _parseString(_zone, _buffer, _idx, _len, _exception);
+        if (key == nil) { // syntax error
+            if (*_exception == nil) {
+                *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                             @"got nil-key in string table ..");
+            }
+            didFail = YES;
+            break;
+        }
+
+        /* The following parses:  (comment|space)* '=' (comment|space)* */
+        if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+            *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                         @"expected '=' after key in string table");
+            didFail = YES;
+            break; // unexpected EOF
+        }
+        // no we need a '=' assignment
+        if (_buffer[*_idx] != '=') {
+            *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                         @"expected '=' after key in string table");
+            didFail = YES;
+            break;
+        }
+        *_idx += 1; // skip '='
+        if (!_skipComments(_buffer, _idx, _len, YES, _exception)) {
+            *_exception =
+                _makeException(*_exception, _buffer, *_idx, _len,
+                               @"expected value after key in string table");
+            didFail = YES;
+            break; // unexpected EOF
+        }
+
+        // read value string
+        value = _parseString(_zone, _buffer, _idx, _len, _exception);
+        if (value == nil) { // syntax error
+            if (*_exception == nil) {
+                *_exception =
+                    _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"got nil-value after key in string table");
+            }
+            didFail = YES;
+            break;
+        }
+
+        NSCAssert(key,   @"invalid key ..");
+        NSCAssert(value, @"invalid value ..");
+
+        [result setObject:value forKey:key];
+
+        // release key and value
+        [key   release]; key   = nil;
+        [value release]; value = nil;
+
+        // read trailing ';' if available
+        if (!_skipComments(_buffer, _idx, _len, YES, _exception))
+            break; // expected EOF
+
+        if (_buffer[*_idx] == ';') {
+            *_idx += 1; // skip ';'
+        }
+    }
+
+    if (didFail) {
+        [key    release]; key    = nil;
+        [value  release]; value  = nil;
+        [result release]; result = nil;
+        return nil;
+    }
+    else
+        return result;
+}
+
+// ******************** categories ********************
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSException.h>
+
+@implementation NSArray(NGPropertyListParser)
+
++ (id)skyArrayWithContentsOfFile:(NSString *)_path {
+    volatile id plist = nil;
+    
+    NSString *format = @"%@: Caught exception %@ with reason %@ ";
+    
+    NS_DURING {
+        plist = NGParsePropertyListFromFile(_path);
+    
+        if (![plist isKindOfClass:[NSArray class]])
+            plist = nil;
+    }
+    NS_HANDLER {
+        NSLog(format, self, [localException name], [localException reason]);
+        plist = nil;
+    }
+    NS_ENDHANDLER;
+
+    return plist;
+}
+
+- (id)skyInitWithContentsOfFile:(NSString *)_path {
+    NSArray *plist = [NSArray arrayWithContentsOfFile:_path];
+
+    if (plist)
+        return [self initWithArray:plist];
+    else {
+        [self autorelease];
+        return nil;
+    }
+}
+
+@end /* NSArray(NGPropertyListParser) */
+
+@implementation NSDictionary(NGPropertyListParser)
+
++ (id)skyDictionaryWithContentsOfFile:(NSString *)_path {
+    volatile id plist = nil;
+
+    NSString *format = @"%@: Caught exception %@ with reason %@ ";
+    
+    NS_DURING {
+        plist = NGParsePropertyListFromFile(_path);
+    
+        if (![plist isKindOfClass:[NSDictionary class]])
+            plist = nil;
+    }
+    NS_HANDLER {
+        NSLog(format, self, [localException name], [localException reason]);
+        plist = nil;
+    }
+    NS_ENDHANDLER;
+
+    return plist;
+}
+
+- (id)skyInitWithContentsOfFile:(NSString *)_path {
+    NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:_path];
+
+    if (plist)
+        return [self initWithDictionary:plist];
+    else {
+        [self autorelease];
+        return nil;
+    }
+}
+
+@end /* NSDictionary(NGPropertyListParser) */
+
+#else /* LIB_FOUNDATION_LIBRARY */
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSException.h>
+
+@implementation NSArray(NGPropertyListParser)
+
++ (id)skyArrayWithContentsOfFile:(NSString *)_path {
+    return [self arrayWithContentsOfFile:_path];
+}
+
+- (id)skyInitWithContentsOfFile:(NSString *)_path {
+    [self release];
+    return [[[self class] skyArrayWithContentsOfFile:_path] retain];
+}
+
+@end /* NSArray(NGPropertyListParser) */
+
+@implementation NSDictionary(NGPropertyListParser)
+
++ (id)skyDictionaryWithContentsOfFile:(NSString *)_path {
+    return [self dictionaryWithContentsOfFile:_path];
+}
+
+- (id)skyInitWithContentsOfFile:(NSString *)_path {
+    [self release];
+    return [[[self class] skyDictionaryWithContentsOfFile:_path] retain];
+}
+
+@end /* NSDictionary(NGPropertyListParser) */
+
+#endif /* LIB_FOUNDATION_LIBRARY */
+
+/*
+  Local Variables:
+  c-basic-offset: 4
+  tab-width: 8
+  End:
+*/
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSArray+enumerator.m b/skyrix-core/NGExtensions/FdExt.subproj/NSArray+enumerator.m
new file mode 100644 (file)
index 0000000..75971a4
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSArray+enumerator.h"
+#include "common.h"
+
+@implementation NSArray(enumerator)
+
+- (id)initWithObjectsFromEnumerator:(NSEnumerator *)_enumerator {
+  NSMutableArray *array = nil;
+  
+  array = [[NSMutableArray alloc]
+                           initWithObjectsFromEnumerator:_enumerator];
+  self = [self initWithArray:array];
+  [array release]; array = nil;
+  return self;
+}
+
+/* mapping */
+
+- (NSArray *)mappedArrayUsingSelector:(SEL)_selector {
+  int i, count = [self count];
+  id  objects[count];
+  IMP objAtIndex;
+  
+  if (_selector == NULL) return self;
+
+  objAtIndex = [self methodForSelector:@selector(objectAtIndex:)];
+
+  for (i = 0; i < count; i++) {
+    objects[i] = objAtIndex(self, @selector(objectAtIndex:), i);
+    objects[i] = [objects[i] performSelector:_selector];
+    if (objects[i] == nil)
+      objects[i] = [NSNull null];
+  }
+
+  return [NSArray arrayWithObjects:objects count:count];
+}
+- (NSArray *)mappedArrayUsingSelector:(SEL)_selector withObject:(id)_object {
+  int i, count = [self count];
+  id  objects[count];
+  IMP objAtIndex;
+  
+  if (_selector == NULL) return self;
+
+  objAtIndex = [self methodForSelector:@selector(objectAtIndex:)];
+
+  for (i = 0; i < count; i++) {
+    objects[i] = [objAtIndex(self, @selector(objectAtIndex:), i)
+                            performSelector:_selector withObject:_object];
+
+    if (objects[i] == nil)
+      objects[i] = [NSNull null];
+  }
+
+  return [NSArray arrayWithObjects:objects count:count];
+}
+
+- (NSSet *)mappedSetUsingSelector:(SEL)_selector {
+  return [NSSet setWithArray:[self mappedArrayUsingSelector:_selector]];
+}
+- (NSSet *)mappedSetUsingSelector:(SEL)_selector withObject:(id)_object {
+  return [NSSet setWithArray:[self mappedArrayUsingSelector:_selector
+                                   withObject:_object]];
+}
+
+#if !LIB_FOUNDATION_LIBRARY
+
+- (NSArray *)map:(SEL)_sel {
+  unsigned int index, count;
+  id array;
+  
+  count = [self count];
+  array = [NSMutableArray arrayWithCapacity:count];
+  for (index = 0; index < count; index++) {
+    [array insertObject:[[self objectAtIndex:index] performSelector:_sel]
+          atIndex:index];
+  }
+  return array;
+}
+
+- (NSArray *)map:(SEL)_sel with:(id)_arg {
+  unsigned int index, count;
+  id array;
+  
+  count = [self count];
+  array = [NSMutableArray arrayWithCapacity:count];
+  for (index = 0; index < count; index++) {
+    [array insertObject:[[self objectAtIndex:index]
+                              performSelector:_sel withObject:_arg]
+          atIndex:index];
+  }
+  return array;
+}
+
+#endif
+
+@end /* NSArray(enumerator) */
+
+@implementation NSMutableArray(enumerator) 
+
+- (id)initWithObjectsFromEnumerator:(NSEnumerator *)_enumerator {
+  if ((self = [self init])) {
+    id obj = nil;
+     
+    while ((obj = [_enumerator nextObject]))
+      [self addObject:obj];
+  }
+  return self;
+}
+
+@end /* NSMutableArray(enumerator)  */
+
+void __link_NGExtensions_NSArrayEnumerator() {
+  __link_NGExtensions_NSArrayEnumerator();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSAutoreleasePool+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSAutoreleasePool+misc.m
new file mode 100644 (file)
index 0000000..e90d555
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NSAutoreleasePool+misc.h"
+
+#if defined(LIB_FOUNDATION_LIBRARY)
+
+BOOL __autoreleaseEnableRetainRemove = NO;
+
+#if !LIB_FOUNDATION_BOEHM_GC
+
+@implementation NSAutoreleasePool(misc)
+
+// retain/remove check
+
++ (void)enableRetainRemove:(BOOL)enable {
+    __autoreleaseEnableRetainRemove = enable;
+}
+
++ (NSAutoreleasePool *)findReleasingPoolForObject:(id)_obj {
+    NSAutoreleasePool *pool = nil;
+    
+    for (pool = [self defaultPool]; pool; pool = pool->parentPool) {
+        NSAutoreleasePoolChunk *ch;
+        int i;
+
+        for (ch = pool->firstChunk; ch; ch = ch->next) {
+            for (i = 0; i < ch->used; i++) {
+                if (ch->objects[i] == _obj)
+                    return pool;
+            }
+        }
+        //if ([pool doesReleaseObject:_obj])
+        //    return pool;
+    }
+    return nil;
+}
+
++ (BOOL)retainAutoreleasedObject:(id)_obj {
+    register NSAutoreleasePool *pool = nil;
+    
+    for (pool = [self defaultPool]; pool; pool = pool->parentPool) {
+        register NSAutoreleasePoolChunk *ch;
+        register int i;
+
+        for (ch = pool->firstChunk; ch; ch = ch->next) {
+            for (i = 0; i < ch->used; i++) {
+                if (ch->objects[i] == _obj) {
+                    ch->objects[i] = nil;
+                    return YES;
+                }
+            }
+        }
+        //if ([pool doesReleaseObject:_obj])
+        //    return pool;
+    }
+    return NO;
+}
+
+- (BOOL)retainAutoreleasedObject:(id)_obj {
+    NSAutoreleasePoolChunk *ch;
+    int i;
+
+    for (ch = firstChunk; ch; ch = ch->next) {
+       for (i = 0; i < ch->used; i++) {
+           if (ch->objects[i] == _obj) {
+                ch->objects[i] = nil;
+                return YES;
+            }
+        }
+    }
+    return NO;
+}
+
+@end
+
+@implementation NSObject(RC)
+
+- (oneway void)release
+{
+#if BUILD_libFoundation_DLL && defined(__WIN32__)
+    extern __declspec(dllimport) BOOL __autoreleaseEnableCheck;
+#else
+    extern BOOL __autoreleaseEnableCheck;
+#endif
+
+    // check if retainCount is Ok
+    if (__autoreleaseEnableCheck) {
+       unsigned int toCome = [NSAutoreleasePool autoreleaseCountForObject:self];
+       if (toCome+1 > [self retainCount]) {
+           NSLog(@"Release[0x%08X<%@>] release check for object %@ "
+                  @"has %d references "
+                 @"and %d pending calls to release in autorelease pools\n", 
+                 (unsigned)self, NSStringFromClass([self class]),
+                  self,
+                  [self retainCount], toCome);
+            NSLog(@"  description='%@'", [self description]);
+            abort(); // core dump for debugging
+           return;
+       }
+    }
+    if (NSExtraRefCount(self) == 1)
+       [self dealloc];
+    else
+       NSDecrementExtraRefCountWasZero(self);
+}
+
+- (id)retain
+{
+    extern BOOL __autoreleaseEnableRetainRemove;
+
+    if (__autoreleaseEnableRetainRemove) {
+        if ([NSAutoreleasePool retainAutoreleasedObject:self]) {
+            NSLog(@"retained autoreleased object ..");
+            return self;
+        }
+    }
+    
+    NSIncrementExtraRefCount(self);
+    return self;
+}
+
+@end
+
+#endif // !LIB_FOUNDATION_BOEHM_GC
+
+#endif // defined(LIB_FOUNDATION_LIBRARY)
+
+void __link_NSAutoreleasePool_misc(void) {
+  __link_NSAutoreleasePool_misc();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSCalendarDate+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSCalendarDate+misc.m
new file mode 100644 (file)
index 0000000..752c8ae
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+  Copyright (C) 2000-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$
+
+#import "common.h"
+#import "NSCalendarDate+misc.h"
+
+#define NUMBER_OF_SECONDS_IN_DAY (24 * 60 * 60)
+
+@implementation NSCalendarDate(misc)
+
++ (NSCalendarDate *)mondayOfWeek:(int)_weekNumber inYear:(int)_year
+  timeZone:(NSTimeZone *)_tz
+{
+  NSCalendarDate *janFirst;
+  
+  janFirst  = [NSCalendarDate dateWithYear:_year month:1 day:1 
+                            hour:0 minute:0 second:0
+                            timeZone:_tz];
+  return [janFirst mondayOfWeek:_weekNumber];
+}
+
+- (NSCalendarDate *)mondayOfWeek:(int)_weekNumber {
+  NSCalendarDate *mondayOfWeek;
+  short          lastWeek;
+  
+  mondayOfWeek = [self firstMondayAndLastWeekInYear:&lastWeek];
+  
+  if (_weekNumber == 1)
+    return mondayOfWeek;
+  
+  return [mondayOfWeek dateByAddingYears:0
+                       months:0
+                       days:(7 * (_weekNumber - 1))];
+}
+
++ (NSArray *)mondaysOfYear:(int)_year timeZone:(NSTimeZone *)_tz {
+  NSCalendarDate *janFirst;
+  
+  janFirst  = [NSCalendarDate dateWithYear:_year month:1 day:1 
+                            hour:0 minute:0 second:0
+                            timeZone:_tz];
+  return [janFirst mondaysOfYear];
+}
+
+- (NSArray *)mondaysOfYear {
+  NSArray        *array;
+  NSMutableArray *mondays;
+  NSCalendarDate *mondayOfWeek;
+  short          lastWeek;
+  int            i;
+  
+  mondayOfWeek = [self firstMondayAndLastWeekInYear:&lastWeek];
+  mondays = [[NSMutableArray alloc] initWithCapacity:55];
+  
+  for (i = 0; i < lastWeek; i++) {
+#if 0 // hh: can someone explain this ?!
+    if (i > 0) {
+      mondayOfWeek =
+        [mondayOfWeek addYear:0 month:0 day:7 hour:0 minute:0 second:0];
+    }
+    mondayOfWeek = [[mondayOfWeek copy] autorelease];
+    [mondays addObject:mondayOfWeek];
+#else
+    NSCalendarDate *tmp;
+    tmp = [mondayOfWeek dateByAddingYears:0 months:0 days:(i * 7)];
+    [mondays addObject:tmp];
+#endif
+  }
+  
+  array = [mondays copy];
+  [mondays release];
+  return [array autorelease];
+}
+
+- (NSCalendarDate *)firstMondayAndLastWeekInYear:(short *)_lastWeek {
+  NSTimeZone     *tz;
+  int            currentYear;
+  short          lastWeek;
+  NSCalendarDate *janFirst;
+  NSCalendarDate *silvester;
+  NSCalendarDate *mondayOfWeek;
+  
+  tz          = [self timeZone];
+  currentYear = [self yearOfCommonEra];
+  
+  if ([self weekOfYear] == 53) {
+    NSCalendarDate *nextJanFirst = nil;
+
+    nextJanFirst = [NSCalendarDate dateWithYear:(currentYear + 1)
+                                 month:1 day:1
+                                 hour:0 minute:0 second:0
+                                 timeZone:tz];
+
+    if ([nextJanFirst weekOfYear] == 1)
+      currentYear++;
+  }
+  
+  janFirst  = [NSCalendarDate dateWithYear:currentYear
+                            month:1 day:1
+                            hour:0 minute:0 second:0
+                            timeZone:tz];
+  silvester = [NSCalendarDate dateWithYear:currentYear
+                            month:12 day:31
+                            hour:23 minute:59 second:59
+                            timeZone:tz];
+
+  lastWeek = [silvester weekOfYear];
+
+  if (lastWeek == 53) {
+    NSCalendarDate *nextJanFirst = nil;
+    
+    nextJanFirst = [NSCalendarDate dateWithYear:currentYear+1
+                                 month:1 day:1
+                                 hour:0 minute:0 second:0
+                                 timeZone:tz];
+    
+    if ([nextJanFirst weekOfYear] == 1)
+      lastWeek = 52;
+  }
+  
+  if ([janFirst weekOfYear] != 1) {
+    mondayOfWeek = [janFirst mondayOfWeek];
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+    mondayOfWeek =
+      [mondayOfWeek dateByAddingYears:0 months:0 days:7 
+                   hours:0 minutes:0 seconds:0];
+#else
+    mondayOfWeek =
+      [mondayOfWeek addYear:0 month:0 day:7 hour:0 minute:0 second:0];
+#endif
+  }
+  else {
+    mondayOfWeek = [janFirst mondayOfWeek];
+  }
+
+  if (_lastWeek) *_lastWeek = lastWeek;
+  return mondayOfWeek;
+}
+
+- (NSCalendarDate *)firstDayOfMonth {
+  NSTimeInterval tv;
+  NSCalendarDate *first;
+  int            dayOfMonth;
+  NSTimeZone     *tz;
+  
+  dayOfMonth = [self dayOfMonth];
+  tz = [self timeZone];
+  
+  tv = (1 - dayOfMonth) * NUMBER_OF_SECONDS_IN_DAY;
+  tv = [self timeIntervalSince1970] + tv;
+  first = [NSCalendarDate dateWithTimeIntervalSince1970:tv];
+  [first setTimeZone:tz];
+  return first;
+}
+
+- (NSCalendarDate *)lastDayOfMonth {
+  int offset = [self numberOfDaysInMonth] - [self dayOfMonth];
+  return [self dateByAddingYears:0 months:0 days:offset];
+}
+
+- (int)numberOfDaysInMonth {
+  static int leapYearMonths[12] = {31,29,31,30,31,30,31,31,30,31,30,31};
+  static int nonLeapYearMonths[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
+  int *numberOfDaysInMonth = [self isInLeapYear] ? leapYearMonths :
+                                                   nonLeapYearMonths;
+  return numberOfDaysInMonth[[self monthOfYear] - 1];
+}
+
+- (BOOL)isInLeapYear
+{
+  unsigned year = [self yearOfCommonEra];
+  return (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0);
+}
+
+- (int)weekOfMonth {
+  /* returns 1-6 */
+  int dayOfMonth;
+  int weekOfYear;
+  int firstWeekOfYear;
+  
+  dayOfMonth = [self dayOfMonth]; /* 1-31 */
+  if (dayOfMonth == 1)
+    return 1;
+
+  /* could be done smarter (by calculating on dayOfWeek) */
+  weekOfYear      = [self weekOfYear];
+  firstWeekOfYear = [[self firstDayOfMonth] weekOfYear];
+  
+  return (weekOfYear - firstWeekOfYear + 1);
+}
+
+- (int)weekOfYear {
+  static int whereToStart[] = { 6, 7, 8, 9, 10, 4, 5 };
+  NSCalendarDate *janFirst;
+  int            year, day, weekOfYear;
+  NSTimeZone     *tz;
+  
+  year = [self yearOfCommonEra];
+  day  = [self dayOfYear] - 1; 
+  
+  tz = [self timeZone];
+
+  janFirst  = [NSCalendarDate dateWithYear:year month:1 day:1 
+                            hour:0 minute:0 second:0
+                            timeZone:tz];
+  
+  weekOfYear = (day + whereToStart[[janFirst dayOfWeek]]) / 7;
+
+  if (weekOfYear == 0) {
+    NSCalendarDate *silvesterLastYear;
+
+    silvesterLastYear = [NSCalendarDate dateWithYear:(year - 1)
+                                      month:12 day:31 
+                                      hour:0 minute:0 second:0
+                                      timeZone:tz];
+    return [silvesterLastYear weekOfYear];
+  }
+  
+#if 0  
+  if (weekOfYear == 53) {
+    NSCalendarDate *nextJanFirst = nil;
+    int            janYear       = year + 1;
+    int            janDay;
+    int            week;
+
+    nextJanFirst = [NSCalendarDate dateWithYear:janYear
+                                 month:1 day:1
+                                 hour:0 minute:0 second:0
+                                 timeZone:[self timeZone]];
+
+    janDay = [nextJanFirst dayOfYear];
+    week   = (janDay + whereToStart[[nextJanFirst dayOfWeek]]) / 7;
+
+    if (week == 1)
+      return 52;
+  }
+#endif  
+  return weekOfYear;
+}
+
+- (short)numberOfWeeksInYear {
+  NSCalendarDate *silvester;
+  NSCalendarDate *dayOfLastWeek;
+  NSTimeZone     *tz;
+  short currentYear;
+
+  currentYear = [self yearOfCommonEra];
+  tz          = [self timeZone];
+
+  silvester = [NSCalendarDate dateWithYear:currentYear
+                              month:12 day:31
+                              hour:23 minute:59 second:59
+                              timeZone:tz];
+  dayOfLastWeek = [silvester dateByAddingYears:0 months:0 days:-3 hours:0
+                             minutes:0 seconds:0];
+
+  return [dayOfLastWeek weekOfYear];
+}
+
+- (NSCalendarDate *)mondayOfWeek {
+  NSTimeInterval tv;
+  NSCalendarDate *monday;
+  int            dayOfWeek;
+  NSTimeZone     *tz;
+  
+  dayOfWeek = [self dayOfWeek];
+  tz = [self timeZone];
+  
+  if (dayOfWeek == 0) dayOfWeek = 7; // readjust Sunday
+  
+  tv = (1 - dayOfWeek) * NUMBER_OF_SECONDS_IN_DAY;
+  tv = [self timeIntervalSince1970] + tv;
+  monday = [NSCalendarDate dateWithTimeIntervalSince1970:tv];
+  [monday setTimeZone:tz];
+  return monday;
+}
+
+- (NSCalendarDate *)beginOfDay {
+  NSTimeZone     *tz;
+
+  tz = [self timeZone];
+  
+  return [NSCalendarDate dateWithYear:[self yearOfCommonEra]
+                         month:       [self monthOfYear]
+                         day:         [self dayOfMonth]
+                         hour:0 minute:0 second:0
+                         timeZone:    tz];
+}
+
+- (NSCalendarDate *)endOfDay {
+  NSTimeZone     *tz;
+
+  tz = [self timeZone];
+  
+  return [NSCalendarDate dateWithYear:[self yearOfCommonEra]
+                         month:       [self monthOfYear]
+                         day:         [self dayOfMonth]
+                         hour:23 minute:59 second:59
+                         timeZone:    tz];
+}
+
+- (BOOL)isDateOnSameDay:(NSCalendarDate *)_date {
+  if ([self dayOfYear]       != [_date dayOfYear])       return NO;
+  if ([self yearOfCommonEra] != [_date yearOfCommonEra]) return NO;
+  return YES;
+}
+- (BOOL)isDateInSameWeek:(NSCalendarDate *)_date {
+  if ([self weekOfYear]      != [_date weekOfYear])      return NO;
+  if ([self yearOfCommonEra] != [_date yearOfCommonEra]) return NO;
+  return YES;
+}
+
+- (BOOL)isToday {
+  NSCalendarDate *d;
+  BOOL result;
+  
+  d = [[NSCalendarDate alloc] init];
+  [d setTimeZone:[self timeZone]];
+  result = [self isDateOnSameDay:d];
+  [d release];
+  return result;
+}
+
+- (BOOL)isForenoon {
+  return [self hourOfDay] >= 12 ? NO : YES;
+}
+- (BOOL)isAfternoon {
+  return [self hourOfDay] >= 12 ? NO : YES;
+}
+
+- (NSCalendarDate *)yesterday {
+  return [self dateByAddingYears:0 months:0 days:-1 
+              hours:0 minutes:0 seconds:0];
+}
+- (NSCalendarDate *)tomorrow {
+  return [self dateByAddingYears:0 months:0 days:1 
+              hours:0 minutes:0 seconds:0];
+}
+
+- (NSCalendarDate *)lastYear {
+  return [self dateByAddingYears:-1 months:0 days:0 
+              hours:0 minutes:0 seconds:0];
+}
+- (NSCalendarDate *)nextYear {
+  return [self dateByAddingYears:1 months:0 days:0 
+              hours:0 minutes:0 seconds:0];
+}
+
+- (NSCalendarDate *)hour:(int)_hour minute:(int)_minute second:(int)_second {
+  NSTimeZone *tz;
+
+  tz = [self timeZone];
+  
+  return [NSCalendarDate dateWithYear:[self yearOfCommonEra]
+                         month:       [self monthOfYear]
+                         day:         [self dayOfMonth]
+                         hour:_hour minute:_minute second:_second
+                         timeZone:    tz];
+}
+- (NSCalendarDate *)hour:(int)_hour minute:(int)_minute {
+  return [self hour:_hour minute:_minute second:0];
+}
+
+/* Y2K support */
+
+- (NSCalendarDate *)y2kDate {
+  NSCalendarDate *newDate;
+  int year;
+  
+  year = [self yearOfCommonEra];
+  if (year >= 70 && year < 135) {
+    newDate = [[NSCalendarDate
+                      alloc]
+                      initWithYear:(year + 1900)
+                      month:[self monthOfYear]
+                      day:[self dayOfMonth]
+                      hour:[self hourOfDay]
+                      minute:[self minuteOfHour]
+                      second:[self secondOfMinute]
+                      timeZone:[self timeZone]];
+  }
+  else if (year >= 0 && year < 70) {
+    newDate = [[NSCalendarDate
+                      alloc]
+                      initWithYear:(year + 2000)
+                      month:[self monthOfYear]
+                      day:[self dayOfMonth]
+                      hour:[self hourOfDay]
+                      minute:[self minuteOfHour]
+                      second:[self secondOfMinute]
+                      timeZone:[self timeZone]];
+  }
+  else
+    newDate = [self retain];
+    
+  return [newDate autorelease];
+}
+
+- (NSCalendarDate *)dateByAddingYears:(int)_years
+  months:(int)_months
+  days:(int)_days
+{
+#if 0
+  /* this expects that NSCalendarDate accepts invalid days, like
+     2000-02-31 */
+  int newYear, newMonth, newDay;
+  
+  newYear  = [self yearOfCommonEra] + _years;
+  newMonth = [self monthOfYear]     + _months;
+  newDay   = [self dayOfMonth]      + _days;
+
+  // this doesn't check month overflow !!
+  return [NSCalendarDate dateWithYear:newYear month:newMonth day:newDay
+                         hour:[self hourOfDay]
+                         minute:[self minuteOfHour]
+                         second:[self secondOfMinute]
+                         timeZone:[self timeZone]];
+#else
+  // but this does it 
+  return [self dateByAddingYears:_years months:_months days:_days
+               hours:0 minutes:0 seconds:0];
+#endif
+}
+
+/* calculate easter ... */
+
+- (NSCalendarDate *)easterOfYear {
+  /*
+    algorithm taken from:
+      http://www.uni-bamberg.de/~ba1lw1/fkal.html#Algorithmus
+  */
+  int      y;
+  unsigned m, n;
+  int      a, b, c, d, e;
+  unsigned easterMonth, easterDay;
+  
+  y = [self yearOfCommonEra];
+
+  if ((y > 1699) && (y < 1800)) {
+    m = 23;
+    n = 3;
+  }
+  else if ((y > 1799) && (y < 1900)) {
+    m = 23;
+    n = 4;
+  }
+  else if ((y > 1899) && (y < 2100)) {
+    m = 24;
+    n = 5;
+  }
+  else if ((y > 2099) && (y < 2200)) {
+    m = 24;
+    n = 6;
+  }
+  else
+    return nil;
+    
+  a = y % 19;
+  b = y % 4;
+  c = y % 7;
+  d = (19 * a + m) % 30;
+  e = (2 * b + 4 * c + 6 * d + n) % 7;
+  
+  easterMonth = 3;
+  easterDay   = 22 + d + e;
+  if (easterDay > 31) {
+    easterDay  -= 31;
+    easterMonth = 4;
+    if (easterDay == 26)
+      easterDay = 19;
+    if ((easterDay == 25) && (d == 28) && (a > 10))
+      easterDay = 18;
+  }
+  
+  return [NSCalendarDate dateWithYear:y
+                         month:easterMonth
+                         day:easterDay
+                         hour:0 minute:0 second:0
+                         timeZone:[self timeZone]];
+}
+
+#if !LIB_FOUNDATION_LIBRARY
+- (id)valueForUndefinedKey:(NSString *)_key {
+  NSLog(@"WARNING: tried to access undefined KVC key '%@' on date object: %@",
+       _key, self);
+  return nil;
+}
+#endif
+
+@end /* NSCalendarDate(misc) */
+
+/* static linking */
+
+void __link_NSCalendarDate_misc(void) {
+  __link_NSCalendarDate_misc();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSData+gzip.m b/skyrix-core/NGExtensions/FdExt.subproj/NSData+gzip.m
new file mode 100644 (file)
index 0000000..e1e35f3
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSData+gzip.h"
+#include "common.h"
+
+#ifdef Assert
+#  undef Assert
+#endif
+
+#include <zlib.h>
+#ifndef DEF_MEM_LEVEL /* zutil.h */
+#  if MAX_MEM_LEVEL >= 8
+#    define DEF_MEM_LEVEL 8
+#  else
+#    define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#  endif
+#  define OS_CODE  0x07 /* TODO: probably need to adjust that ... */
+#endif
+
+#undef Assert
+
+@implementation NSData(gzip)
+
+- (NSData *)gzip {
+  return [self gzipWithLevel:Z_DEFAULT_COMPRESSION];
+}
+
+static inline void putLong(uLong x, NSMutableData *data, IMP addBytes) {
+  int n;
+  for (n = 0; n < 4; n++) {
+    unsigned char c = (int)(x & 0xff);
+    addBytes(data, @selector(appendBytes:length:), &c, 1);
+    x >>= 8;
+  }
+}
+
+- (NSData *)gzipWithLevel:(int)_level {
+  NSMutableData *data     = nil;
+  int           errorCode = 0;
+  unsigned      len       = [self length];
+  void          *src      = (void *)[self bytes];
+  IMP           addBytes  = NULL;
+  char          outBuf[4096];
+  z_stream      out;
+  uLong         crc;
+
+  NSAssert1((_level >= NGGZipMinimalCompression &&
+             _level <= NGGZipMaximalCompression)
+            || (_level == Z_DEFAULT_COMPRESSION),
+            @"invalid compression level %i (0-9)", _level);
+
+  data = [NSMutableData dataWithCapacity:
+                          (len / 10 < 128) ? len : len / 10];
+  addBytes = [data methodForSelector:@selector(appendBytes:length:)];
+
+  out.zalloc    = (alloc_func)NULL;
+  out.zfree     = (free_func)NULL;
+  out.opaque    = (voidpf)NULL;
+  out.next_out  = (Byte*)&outBuf;
+  out.avail_out = sizeof(outBuf);
+  out.next_in   = Z_NULL;
+  out.avail_in  = 0;
+  errorCode     = Z_OK;
+  crc           = crc32(0L, Z_NULL, 0);
+
+  errorCode = deflateInit2(&out, _level, Z_DEFLATED, -MAX_WBITS,
+                           DEF_MEM_LEVEL,
+                           0); // windowBits is passed <0 to suppress zlib header
+  if (errorCode != Z_OK) {
+    NSLog(@"ERROR: could not init deflate !");
+    return nil;
+  }
+
+  { // add gzip header
+    char buf[10] = {
+      0x1f, 0x8b,    // magic
+      Z_DEFLATED, 0, // flags
+      0, 0, 0, 0,    // time
+      0, OS_CODE     // flags
+    };
+    addBytes(data, @selector(appendBytes:length:), &buf, 10);
+  }
+  
+  { // gz_write
+    out.next_in  = src;
+    out.avail_in = len;
+    
+    while (out.avail_in > 0) {
+      if (out.avail_out == 0) {
+        out.next_out = (void *)&outBuf; // reset buffer position
+        addBytes(data, @selector(appendBytes:length:), &outBuf, sizeof(outBuf));
+        out.avail_out = sizeof(outBuf);
+      }
+      errorCode = deflate(&out, Z_NO_FLUSH);
+      if (errorCode != Z_OK) {
+        NSLog(@"ERROR: could not deflate chunk !");
+        if (out.state) deflateEnd(&out);
+        return nil;
+      }
+    }
+    crc = crc32(crc, src, len);
+  }
+
+  { // gz_flush
+    BOOL done = NO;
+    
+    out.next_in  = NULL;
+    out.avail_in = 0; // should be zero already anyway
+    
+    for (;;) {
+      len = sizeof(outBuf) - out.avail_out;
+
+      if (len > 0) {
+        addBytes(data, @selector(appendBytes:length:), &outBuf, len);
+        out.next_out  = (void *)&outBuf;
+        out.avail_out = sizeof(outBuf);
+      }
+      if (done)
+        break;
+      errorCode = deflate(&out, Z_FINISH);
+
+      // deflate has finished flushing only when it hasn't used up
+      // all the available space in the output buffer: 
+      done = (out.avail_out != 0 || errorCode == Z_STREAM_END);
+
+      if (errorCode != Z_OK && errorCode != Z_STREAM_END)
+        break;
+    }
+    if (errorCode != Z_STREAM_END) {
+      NSLog(@"ERROR: flush failed.");
+      if (out.state) deflateEnd(&out);
+      return nil;
+    }
+  }
+  { // write trailer (checksum and filesize)
+    putLong(crc, data, addBytes);
+    putLong(out.total_in, data, addBytes);
+  }
+  if (out.state) deflateEnd(&out);
+
+  return data;
+}
+
+@end
+
+void __link_NSData_gzip(void) {
+  __link_NSData_gzip();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSData+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSData+misc.m
new file mode 100644 (file)
index 0000000..286570a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NSData+misc.h"
+
+@implementation NSData(misc)
+
+- (BOOL)hasPrefix:(NSData *)_data {
+  return [self hasPrefixBytes:[_data bytes] length:[_data length]];
+}
+
+- (BOOL)hasPrefixBytes:(const void *)_bytes length:(unsigned)_len {
+  if (_len > [self length])
+    return NO;
+  else {
+    const unsigned char *ownBytes = [self bytes];
+    register unsigned i;
+
+    for (i = 0; i < _len; i++) {
+      if (((unsigned char *)_bytes)[i] != ownBytes[i])
+        return NO;
+    }
+    return YES;
+  }
+}
+
+@end /* NSData(misc) */
+
+void __link_NSData_misc() {
+  __link_NSData_misc();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSDictionary+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSDictionary+misc.m
new file mode 100644 (file)
index 0000000..cbe6767
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NSDictionary+misc.h"
+
+@implementation NSDictionary(misc)
+
+- (NSDictionary *)dictionaryByExchangingKeysAndValues {
+  NSDictionary *reverse;
+  NSArray  *oKeys;
+  unsigned i, len;
+  id *keys, *values;
+  
+  oKeys = [self allKeys];
+  if ((len = [oKeys count]) == 0)
+    return [[self copy] autorelease];
+  
+  keys   = calloc(len + 10, sizeof(id));
+  values = calloc(len + 10, sizeof(id));
+  for (i = 0; i < len; i++) {
+    values[i] = [oKeys objectAtIndex:i];
+    keys[i]   = [self objectForKey:values[i]];
+  }
+  
+  reverse =
+    [[NSDictionary alloc] initWithObjects:values forKeys:keys count:len];
+  free(keys);
+  free(values);
+  return [reverse autorelease];
+}
+
+@end /* NSDictionary(misc) */
+
+@implementation NSMutableDictionary(misc)
+
+- (void)removeObjectsForKeysV:(id)_firstKey, ... {
+  va_list ap;
+
+  va_start(ap, _firstKey);
+  while (_firstKey) {
+    [self removeObjectForKey:_firstKey];
+    _firstKey = va_arg(ap, id);
+  }
+  va_end(ap);
+}
+
+@end /* NSMutableDictionary(misc) */
+
+void __link_NSDictionary_misc() {
+  __link_NSDictionary_misc();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSEnumerator+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSEnumerator+misc.m
new file mode 100644 (file)
index 0000000..3db9e36
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "NSEnumerator+misc.h"
+#import <Foundation/Foundation.h>
+#import <EOControl/EOQualifier.h>
+#include "common.h"
+
+@interface _NGFilterEnumerator : NSEnumerator
+{
+  NSEnumerator *source;
+}
+
++ (NSEnumerator *)filterEnumeratorWithSource:(NSEnumerator *)_e;
+
+- (NSEnumerator *)source;
+
+@end
+
+@interface _NGQualifierFilterEnumerator : _NGFilterEnumerator
+{
+  EOQualifier *q;
+}
+- (void)setQualifier:(EOQualifier *)_q;
+- (EOQualifier *)qualifier;
+@end
+
+@interface _NGSelFilterEnumerator : _NGFilterEnumerator
+{
+  SEL  sel;
+  id   arg;
+}
+- (void)setSelector:(SEL)_s;
+- (SEL)selector;
+- (void)setArgument:(id)_arg;
+- (id)argument;
+@end
+
+@implementation NSEnumerator(misc)
+
+- (NSEnumerator *)filterWithQualifier:(EOQualifier *)_qualifier {
+  id e;
+  
+  e = [_NGQualifierFilterEnumerator filterEnumeratorWithSource:self];
+  [e setQualifier:_qualifier];
+  return e;
+}
+- (NSEnumerator *)filterWithQualifierString:(NSString *)_s {
+  EOQualifier *q;
+  
+  q = [EOQualifier qualifierWithQualifierFormat:_s];
+  return [self filterWithQualifier:q];
+}
+
+- (NSEnumerator *)filterWithSelector:(SEL)_selector withObject:(id)_argument {
+  id e;
+  
+  e = [_NGSelFilterEnumerator filterEnumeratorWithSource:self];
+  [e setSelector:_selector];
+  [e setArgument:_argument];
+  return e;
+}
+
+@end /* NSEnumerator(misc) */
+
+@implementation _NGFilterEnumerator
+
+- (id)initWithSource:(NSEnumerator *)_e {
+  self->source = [_e retain];
+  return self;
+}
+- (void)dealloc {
+  [self->source release];
+  [super dealloc];
+}
+
++ (NSEnumerator *)filterEnumeratorWithSource:(NSEnumerator *)_e {
+  return [[(_NGFilterEnumerator *)[self alloc] initWithSource:_e] autorelease];
+}
+
+- (NSEnumerator *)source {
+  return self->source;
+}
+
+- (id)nextObject {
+  return [self->source nextObject];
+}
+
+@end /* _NGFilterEnumerator */
+
+@implementation _NGQualifierFilterEnumerator
+
+- (void)dealloc {
+  [self->q release];
+  [super dealloc];
+}
+
+- (void)setQualifier:(EOQualifier *)_q {
+  ASSIGN(self->q, _q);
+}
+- (EOQualifier *)qualifier {
+  return self->q;
+}
+
+- (id)nextObject {
+  while (YES) {
+    id obj;
+    
+    if ((obj = [self->source nextObject]) == nil)
+      return nil;
+    if (self->q == nil)
+      return obj;
+
+    if ([(id<EOQualifierEvaluation>)self->q evaluateWithObject:obj])
+      return obj;
+  }
+}
+
+@end /* _NGQualifierFilterEnumerator */
+
+@implementation _NGSelFilterEnumerator
+
+- (void)dealloc {
+  [self->arg release];
+  [super dealloc];
+}
+
+- (void)setSelector:(SEL)_s {
+  self->sel = _s;
+}
+- (SEL)selector {
+  return self->sel;
+}
+
+- (void)setArgument:(id)_arg {
+  ASSIGN(self->arg, _arg);
+}
+- (id)argument {
+  return self->arg;
+}
+
+- (id)nextObject {
+  while (YES) {
+    id obj;
+    BOOL (*m)(id,SEL,id);
+    
+    if ((obj = [self->source nextObject]) == nil)
+      return nil;
+    
+    if ((m = (void *)[obj methodForSelector:self->sel]) == NULL)
+      continue;
+
+    if (m(obj, self->sel, self->arg))
+      return obj;
+  }
+}
+
+@end /* _NGSelFilterEnumerator */
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSException+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSException+misc.m
new file mode 100644 (file)
index 0000000..c3d78fc
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSException+misc.h"
+#include "common.h"
+
+@implementation NSException(NGMiscellaneous)
+
+- (id)initWithReason:(NSString *)_reason {
+  return [self initWithReason:_reason userInfo:nil];
+}
+- (id)initWithReason:(NSString *)_reason userInfo:(id)_userInfo {
+  return [self initWithName:NSStringFromClass([self class])
+               reason:_reason
+               userInfo:_userInfo];
+}
+
+- (id)initWithFormat:(NSString *)_format,... {
+  NSString *tmp = nil;
+  va_list  ap;
+  
+  va_start(ap, _format);
+  tmp = [[NSString allocWithZone:[self zone]]
+                   initWithFormat:_format arguments:ap];
+  va_end(ap);
+
+  self = [self initWithReason:tmp userInfo:nil];
+  [tmp release]; tmp = nil;
+  return self;
+}
+
+- (id)copyWithZone:(NSZone *)_zone {
+  // TODO: should make a real copy?
+  return [self retain];
+}
+
+@end /* NSException(NGMiscellaneous) */
+
+#if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+
+@implementation NSException (NGLibFoundationCompatibility)
+- (void)setReason:(NSString *)_reason {
+  [_reason retain];
+  [self->reason release];
+  self->reason = _reason;
+}
+@end
+
+#elif GNUSTEP_BASE_LIBRARY
+
+@implementation NSException (NGLibFoundationCompatibility)
+- (void)setReason:(NSString *)_reason {
+  [_reason retain];
+  [self->_e_reason release];
+  self->_e_reason = _reason;
+}
+@end
+
+#endif
+
+void __link_NGExtensions_NSExceptionMisc() {
+  __link_NGExtensions_NSExceptionMisc();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSFileManager+Extensions.m b/skyrix-core/NGExtensions/FdExt.subproj/NSFileManager+Extensions.m
new file mode 100644 (file)
index 0000000..0e1e5e7
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSFileManager+Extensions.h"
+#include "NGFileFolderInfoDataSource.h"
+#include <EOControl/EOGlobalID.h>
+#include "common.h"
+
+@interface NSFileManagerGlobalID : EOGlobalID < NSCopying >
+{
+@public
+  NSString *path;
+}
+@end
+
+// TODO: support -lastException
+// TODO: add stuff like -dictionaryAtPath:, -arrayAtPath:, -propertyListAtPath:
+
+@implementation NSFileManager(ExtendedFileManagerImp)
+
+/* path modifications */
+
+- (NSString *)standardizePath:(NSString *)_path {
+  if (![_path isAbsolutePath])
+    _path = [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
+  
+  return [_path stringByStandardizingPath];
+}
+- (NSString *)resolveSymlinksInPath:(NSString *)_path {
+  return [_path stringByResolvingSymlinksInPath];
+}
+- (NSString *)expandTildeInPath:(NSString *)_path {
+  return [_path stringByExpandingTildeInPath];
+}
+
+/* feature check */
+
+- (BOOL)supportsVersioningAtPath:(NSString *)_path {
+  return NO;
+}
+- (BOOL)supportsLockingAtPath:(NSString *)_path {
+  return NO;
+}
+- (BOOL)supportsFolderDataSourceAtPath:(NSString *)_path {
+  return YES;
+}
+
+- (BOOL)supportsFeature:(NSString *)_featureURI atPath:(NSString *)_path {
+  if ([_featureURI isEqualToString:NGFileManagerFeature_DataSources])
+    return YES;
+  
+  return NO;
+}
+
+/* writing */
+
+- (BOOL)writeContents:(NSData *)_content atPath:(NSString *)_path {
+  return [_content writeToFile:_path atomically:YES];
+}
+
+/* global-IDs */
+
+- (EOGlobalID *)globalIDForPath:(NSString *)_path {
+  NSFileManagerGlobalID *gid;
+  
+  _path = [self standardizePath:_path];
+  
+  gid = [[NSFileManagerGlobalID alloc] init];
+  gid->path = [_path copy];
+  return [gid autorelease];
+}
+- (NSString *)pathForGlobalID:(EOGlobalID *)_gid {
+  NSFileManagerGlobalID *gid;
+  
+  if (![_gid isKindOfClass:[NSFileManagerGlobalID class]])
+    /* not a gid we can handle ... */
+    return nil;
+  
+  gid = (NSFileManagerGlobalID *)_gid;
+  return gid->path;
+}
+
+/* datasources (work on folders) */
+
+- (EODataSource *)dataSourceAtPath:(NSString *)_path {
+  return
+    [[[NGFileFolderInfoDataSource alloc] initWithFolderPath:_path] autorelease];
+}
+
+- (EODataSource *)dataSource {
+  return [self dataSourceAtPath:[self currentDirectoryPath]];
+}
+
+/* trash */
+
+- (BOOL)supportsTrashFolderAtPath:(NSString *)_path {
+  return NO;
+}
+- (NSString *)trashFolderForPath:(NSString *)_path {
+  return nil;
+}
+
+- (BOOL)trashFileAtPath:(NSString *)_path handler:(id)_handler {
+  // TODO: support trashfolder on MacOSX ?
+  return NO;
+}
+
+@end /* NSFileManager(ExtendedFileManagerImp) */
+
+@implementation NSFileManagerGlobalID
+
+- (void)dealloc {
+  [self->path release];
+  [super dealloc];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  /* global IDs are immutable, so we can return an retained object ... */
+  return [self retain];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms = [NSMutableString stringWithCapacity:32];
+  
+  [ms appendFormat:@"<0x%08X[%@]", self, NSStringFromClass([self class])];
+  [ms appendFormat:@" path=%@", self->path];
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* NSFileManagerGlobalID */
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSMethodSignature+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSMethodSignature+misc.m
new file mode 100644 (file)
index 0000000..a63394d
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NSMethodSignature+misc.h"
+
+@implementation NSMethodSignature(misc)
+
+#if NeXT_Foundation_LIBRARY
+- (NSString *)objCTypes {
+  return [NSString stringWithCString:self->_types];
+}
+#else
+- (NSString *)objCTypes {
+  char buf[256], *bufPos = buf;
+  int  argCount = [self numberOfArguments];
+  char *pos1    = NULL, *pos2 = NULL;
+  
+  // return type
+#if GNUSTEP_BASE_LIBRARY
+  pos1 = (char *)[self methodType];
+#else
+  pos1 = (char *)[self types];
+#endif
+  pos2 = (char *)objc_skip_typespec(pos1);
+  strncpy(bufPos, pos1, pos2 - pos1);
+  bufPos += pos2 - pos1;
+  //*bufPos = '\0';
+  pos1 = (char *)objc_skip_offset(pos2);
+
+  // arguments
+  {
+    register int i;
+
+    for (i = 0; i < argCount; i++) {
+      pos2 = (char *)objc_skip_typespec(pos1); // forward to offset
+      strncpy(bufPos, pos1, pos2 - pos1);
+      bufPos += pos2 - pos1;
+      //*bufPos = '\0';
+      pos1 = (char *)objc_skip_offset(pos2);   // forward to next type
+    }
+  }
+  *bufPos = '\0';
+
+  return [NSString stringWithCString:buf];
+}
+#endif
+
+@end /* NSMethodSignature(misc) */
+
+void __link_NSMethodSignature_misc() {
+  __link_NSMethodSignature_misc();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSNull+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSNull+misc.m
new file mode 100644 (file)
index 0000000..bcec398
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSNull+misc.h"
+#include "common.h"
+
+#if LIB_FOUNDATION_LIBRARY || GNUSTEP_BASE_LIBRARY
+#  include <objc/objc-api.h>
+#  include <objc/objc.h>
+#  include <objc/encoding.h>
+#  ifndef GNUSTEP
+#    import <extensions/objc-runtime.h>
+#  endif
+#else
+#  import <objc/objc-class.h>
+#endif
+
+@implementation NSNull(misc)
+
+static int _doAbort = -1;
+static inline BOOL doAbort(void) {
+  if (_doAbort == -1) {
+    _doAbort = [[NSUserDefaults standardUserDefaults]
+                               boolForKey:@"NSNullAbortOnMessage"] ? 1 : 0;
+  }
+  return _doAbort ? YES : NO;
+}
+
+- (BOOL)isNotNull {
+  return NO;
+}
+- (BOOL)isNull {
+#if DEBUG
+  NSLog(@"WARNING(%s): called deprecated -isNull on NSNull (use -isNotNull) !",
+        __PRETTY_FUNCTION__);
+  if (doAbort()) abort();
+#endif
+  return YES;
+}
+
+- (NSString *)stringValue {
+#if DEBUG && 0
+  NSLog(@"WARNING(%s): "
+        @"NSNull -stringValue returns empty string.",
+        __PRETTY_FUNCTION__);
+  if (doAbort()) abort();
+#endif
+  return @"";
+}
+- (double)doubleValue {
+#if DEBUG && 0
+  NSLog(@"WARNING(%s): "
+        @"NSNull -doubleValue returns 0.0.",
+        __PRETTY_FUNCTION__);
+  if (doAbort()) abort();
+#endif
+  return 0.0;
+}
+
+- (unsigned int)length {
+#if DEBUG
+  NSLog(@"WARNING(%s): "
+        @"called NSNull -length (returns 0) !!!",
+        __PRETTY_FUNCTION__);
+  if (doAbort()) abort();
+#endif
+  return 0;
+}
+- (unsigned int)count {
+#if DEBUG
+  NSLog(@"WARNING(%s): "
+        @"called NSNull -count (returns 0) !!!",
+        __PRETTY_FUNCTION__);
+  if (doAbort()) abort();
+#endif
+  return 0;
+}
+
+- (BOOL)isEqualToString:(NSString *)_s {
+#if DEBUG
+  NSLog(@"WARNING(%s): "
+        @"called NSNull -isEqualToString:!!!",
+        __PRETTY_FUNCTION__);
+  if (doAbort()) abort();
+#endif
+  return _s == (id)self || _s == nil ? YES : NO;
+}
+
+- (unichar)characterAtIndex:(unsigned int)_idx {
+#if DEBUG
+  NSLog(@"WARNING(%s): "
+        @"called NSNull -characterAtIndex:%d - returning 0!",
+        __PRETTY_FUNCTION__, _idx);
+  if (doAbort()) abort();
+#endif
+  return 0;
+}
+
+/* key-value coding */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  /* do nothing */
+}
+- (id)valueForKey:(NSString *)_key {
+  if ([_key isEqualToString:@"isNotNull"]) {
+    static NSNumber *noNum  = nil;
+    
+    if (noNum == nil)
+      noNum = [NSNumber numberWithBool:NO];
+    
+    return noNum;
+  }
+  if ([_key isEqualToString:@"isNull"]) {
+    static NSNumber *yesNum = nil;
+    
+    if (yesNum == nil)
+      yesNum = [NSNumber numberWithBool:YES];
+    return yesNum;
+  }
+  
+  /* do nothing */
+  return nil;
+}
+
+/* forwarding ... */
+
+#if !GNU_RUNTIME
+- (BOOL)respondsToSelector:(SEL)_sel {
+  /* fake that we have a selector */
+  return YES;
+}
+
+- (NSString *)descriptionWithLocale:(id)_locale indent:(int)_indent {
+  return @"<null>";
+}
+- (NSString *)descriptionWithLocale:(id)_locale {
+  return @"<null>";
+}
+
+#endif
+
+- (void)forwardInvocation:(NSInvocation *)_invocation {
+  NSMethodSignature *sig;
+  
+  NSLog(@"ERROR(%s): called selector %@ on NSNull !",
+        __PRETTY_FUNCTION__,
+        NSStringFromSelector([_invocation selector]));
+  if (doAbort()) abort();
+  
+  if ((sig = [_invocation methodSignature])) {
+    const unsigned char *ret;
+    
+    if ((ret = [sig methodReturnType])) {
+      switch (*ret) {
+        case _C_INT: {
+          int v = 0;
+          [_invocation setReturnValue:&v];
+          break;
+        }
+        case _C_UINT: {
+          unsigned int v = 0;
+          [_invocation setReturnValue:&v];
+          break;
+        }
+          
+        case _C_ID:
+        case _C_CLASS: {
+          id v = nil;
+          [_invocation setReturnValue:&v];
+          break;
+        }
+        
+        default:
+          NSLog(@"  didn't set return value for type '%s'", ret);
+          break;
+      }
+    }
+    else
+      NSLog(@"  no method return type in signature %@", sig);
+  }
+  else
+    NSLog(@"  no method signature in invocation %@", _invocation);
+}
+
+@end /* NSNull(misc) */
+
+@implementation NSObject(NSNullMisc)
+
+- (BOOL)isNotNull {
+  return YES;
+}
+
+- (BOOL)isNull {
+#if DEBUG
+  NSLog(@"%s: WARNING, called -isNull on NSObject (use -isNotNull) !",
+        __PRETTY_FUNCTION__);
+#endif
+  return NO;
+}
+
+@end /* NSObject(NSNullMisc) */
+
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSObject+Logs.m b/skyrix-core/NGExtensions/FdExt.subproj/NSObject+Logs.m
new file mode 100644 (file)
index 0000000..792bce3
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSObject+Logs.h"
+#include "common.h"
+
+@implementation NSObject(NGLogs)
+
+static Class StringClass = Nil;
+
+static inline Class NSStringClass(void) {
+  if (StringClass == Nil) StringClass = [NSString class];
+  return StringClass;
+}
+
+- (BOOL)isDebuggingEnabled {
+#if DEBUG
+  return YES;
+#else
+  return NO;
+#endif
+}
+- (NSString *)loggingPrefix {
+  /* improve perf ... */
+  return [NSStringClass() stringWithFormat:@"<0x%08X[%@]>",
+                       self, NSStringFromClass([self class])];
+}
+
+- (void)logWithFormat:(NSString *)_format arguments:(va_list)ap {
+  NSString *value = nil;
+  
+  value = [[NSStringClass() alloc] initWithFormat:_format arguments:ap];
+  NSLog(@"%@ %@", [self loggingPrefix], value);
+  [value release];
+}
+
+- (void)debugWithFormat:(NSString *)_format arguments:(va_list)ap {
+#if DEBUG
+  NSString *value = nil;
+  
+  if (![self isDebuggingEnabled]) return;
+  
+  value = [[NSStringClass() alloc] initWithFormat:_format arguments:ap];
+  NSLog(@"<%@>D %@", [self loggingPrefix], value);
+  [value release];
+#else
+#  warning debug is disabled, debugWithFormat wont print anything ..
+#endif
+}
+
+- (void)logWithFormat:(NSString *)_format, ... {
+  va_list ap;
+  
+  va_start(ap, _format);
+  [self logWithFormat:_format arguments:ap];
+  va_end(ap);
+}
+- (void)debugWithFormat:(NSString *)_format, ... {
+  va_list ap;
+  
+  va_start(ap, _format);
+  [self debugWithFormat:_format arguments:ap];
+  va_end(ap);
+}
+
+@end /* NSObject(NGLogs) */
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSObject+Values.m b/skyrix-core/NGExtensions/FdExt.subproj/NSObject+Values.m
new file mode 100644 (file)
index 0000000..159b06a
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSObject+Values.h"
+#include "common.h"
+
+@implementation NSObject(NGValues)
+
+- (BOOL)boolValue {
+  // this returns always YES (the id != nil)
+  return YES;
+}
+
+- (char)charValue {
+  return (char)[self intValue];
+}
+- (unsigned char)unsignedCharValue {
+  return (unsigned char)[self intValue];
+}
+- (short)shortValue {
+  return (short)[self intValue];
+}
+- (unsigned short)unsignedShortValue {
+  return (unsigned short)[self unsignedIntValue];
+}
+
+- (int)intValue {
+  return [[self stringValue] intValue];
+}
+- (unsigned int)unsignedIntValue {
+  return (unsigned int)[self intValue];
+}
+
+- (long)longValue {
+  return (long)[self intValue];
+}
+- (unsigned long)unsignedLongValue {
+  return (unsigned long)[self unsignedIntValue];
+}
+
+- (long long)longLongValue {
+  return [[self stringValue] longLongValue];
+}
+- (unsigned long long)unsignedLongLongValue {
+  return [[self stringValue] unsignedLongLongValue];
+}
+
+- (float)floatValue {
+  return [[self stringValue] floatValue];
+}
+- (double)doubleValue {
+  return [[self stringValue] doubleValue];
+}
+
+- (NSString *)stringValue {
+  return [self description];
+}
+
+@end /* NSObject(Values) */
+
+@implementation NSString(NGValues)
+
+- (BOOL)boolValue {
+  unsigned len;
+  unichar  c1;
+
+  if ((len = [self length]) == 0)
+    return NO;
+
+  switch (len) {
+  case 1:
+    c1 = [self characterAtIndex:0];
+    if (c1 == '1') return YES;
+    return NO;
+    
+  case 2:
+    // NO, no (this is false in any case ;-)
+    return NO;
+    
+  case 3:
+    c1 = [self characterAtIndex:0];
+    if (c1 != 'Y' && c1 != 'y')
+      return NO;
+    
+    if ([@"YES" isEqualToString:self]) return YES;
+    if ([@"yes" isEqualToString:self]) return YES;
+    break;
+    
+  case 4:
+    c1 = [self characterAtIndex:0];
+    if (c1 != 'T' && c1 != 't')
+      return NO;
+    
+    if ([@"TRUE" isEqualToString:self]) return YES;
+    if ([@"true" isEqualToString:self]) return YES;
+    break;
+    
+  case 5:
+    // FALSE, false (this is false in any case ;-)
+    return NO;
+  }
+  
+  return NO;
+}
+
+- (NSString *)stringValue {
+  return self;
+}
+
+- (unsigned char)unsignedCharValue {
+  /*
+    Note: this is a hack to support bool values with KVC operations. Problem 
+          is, that bools in Objective-C have no own type code and the runtime 
+          will use uchar to represent a bool.
+         
+    Note: there are platforms where int as used as the BOOL base type?
+  */
+  register unsigned len;
+  register unichar  c1;
+  
+  if ((len = [self length]) == 0)
+    return 0;
+  
+  c1 = [self characterAtIndex:0];
+  if (!isdigit(c1)) {
+    switch (len) {
+    case 2:
+      // NO, no (this is false in any case ;-)
+      break;
+    case 3:
+      c1 = [self characterAtIndex:0];
+      if (c1 != 'Y' && c1 != 'y')
+       return NO;
+    
+      if ([@"YES" isEqualToString:self]) return YES;
+      if ([@"yes" isEqualToString:self]) return YES;
+      break;
+    case 4:
+      c1 = [self characterAtIndex:0];
+      if (c1 != 'T' && c1 != 't')
+       return NO;
+    
+      if ([@"TRUE" isEqualToString:self]) return YES;
+      if ([@"true" isEqualToString:self]) return YES;
+      break;
+    }
+  }
+  
+  return [self intValue];
+}
+
+@end /* NSString(Values) */
+
+@implementation NSMutableString(NGValues)
+
+- (NSString *)stringValue {
+  return [[self copy] autorelease];
+}
+
+@end /* NSMutableString(Values) */
+
+void __link_NGExtensions_NSObjectValues(void) {
+  /* required for static linking */
+  __link_NGExtensions_NSObjectValues();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSProcessInfo+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSProcessInfo+misc.m
new file mode 100644 (file)
index 0000000..e8d7ed5
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSProcessInfo+misc.h"
+#include "common.h"
+#include <time.h>
+
+#if !LIB_FOUNDATION_LIBRARY && !GNUSTEP_BASE_LIBRARY
+#  import <NGExtensions/NSString+Ext.h>
+#endif
+
+@implementation NSProcessInfo(misc)
+
+/* arguments */
+
+- (NSArray *)argumentsWithoutDefaults {
+  NSMutableArray *ma;
+  NSArray  *a;
+  unsigned count, i;
+  BOOL     foundDefault;
+  
+  a = [self arguments];
+  if ((count = [a count]) == 0) return nil;
+  if (count == 1) return a;
+  
+  ma = [NSMutableArray arrayWithCapacity:count];
+  [ma addObject:[a objectAtIndex:0]]; // tool name
+  
+  for (i = 1, foundDefault = NO; i < count; i++) {
+    NSString *arg;
+    
+    arg = [a objectAtIndex:i];
+    if ([arg hasPrefix:@"-"] && ([arg length] > 1)) {
+      /* a default .. */
+      i++; /* consume value */
+      foundDefault = YES;
+      continue;
+    }
+    
+    [ma addObject:arg];
+  }
+  
+  return foundDefault ? (id)ma : a;
+}
+
+/* create temp file name */
+
+- (NSString *)temporaryFileName:(NSString *)_prefix {
+  static int cnt = 0;
+  NSString *s;
+  cnt++;
+  s = [NSString stringWithFormat:
+                  @"%04X%X%02X.tmp", getpid(), time(NULL),
+                  cnt];
+  return [_prefix stringByAppendingString:s];
+}
+- (NSString *)temporaryFileName {
+  NSString *prefix;
+  
+  prefix = [@"/tmp/" stringByAppendingPathComponent:[self processName]];
+  return [self temporaryFileName:prefix];
+}
+
+/* return process-id (pid on Unix) */
+
+- (id)processId {
+  int pid;
+#if defined(__MINGW32__)
+  pid = (int)GetCurrentProcessId();
+#else                     
+  pid = (int)getpid();
+#endif
+  return [NSNumber numberWithInt:pid];
+}
+
+- (NSString *)procDirectoryPathForProcess {
+  NSString *p;
+  BOOL isDir;
+  
+  p = [@"/proc/" stringByAppendingString:[[self processId] stringValue]];
+  if (![[NSFileManager defaultManager] fileExistsAtPath:p isDirectory:&isDir])
+    return nil;
+  
+  return isDir ? p : nil;
+}
+
+- (NSDictionary *)procStatusDictionary {
+  NSMutableDictionary *dict;
+  NSString     *procStatusPath;
+  NSString     *s;
+  NSEnumerator *lines;
+  NSString     *line;
+  
+  procStatusPath =
+    [[self procDirectoryPathForProcess]
+           stringByAppendingPathComponent:@"status"];
+  
+  s = [[NSString alloc] initWithContentsOfFile:procStatusPath];
+  if (s == nil) return nil;
+  
+  dict = [NSMutableDictionary dictionaryWithCapacity:32];
+  
+  lines = [[s componentsSeparatedByString:@"\n"] objectEnumerator];
+  while ((line = [lines nextObject])) {
+    NSString *key;
+    NSRange  r;
+    id value;
+    
+    r = [line rangeOfString:@":"];
+    if (r.length == 0) continue;
+    
+    key   = [line substringToIndex:r.location];
+    value = [[line substringFromIndex:(r.location + r.length)] 
+                  stringByTrimmingSpaces];
+    
+    if (value == nil)
+      value = [NSNull null];
+    
+    [dict setObject:value forKey:key];
+  }
+  
+  return [[dict copy] autorelease];
+}
+
+static NSNumber *_int(int i) __attribute__((unused));
+static NSNumber *_uint(unsigned int i) __attribute__((unused));
+
+static NSNumber *_int(int i) {
+  return [NSNumber numberWithInt:i];
+}
+static NSNumber *_uint(unsigned int i) {
+  return [NSNumber numberWithUnsignedInt:i];
+}
+
+#define NG_GET_PROC_INFO \
+    FILE          *fh;\
+    char          pp[256];\
+    int           res;\
+    int           pid, ppid, pgrp, session, tty, tpgid;\
+    unsigned int  flags, minflt, cminflt, majflt, cmajflt;\
+    int           utime, stime, cutime, cstime, counter;\
+    unsigned char comm[256];\
+    char          state = 0;\
+    int           priority, starttime;\
+    unsigned int  timeout, itrealvalue, vsize, rss, rlim, startcode, endcode;\
+    unsigned int  startstack, kstkesp, kstkeip;\
+    int           signal, blocked, sigignore, sigcatch;\
+    unsigned int  wchan;\
+    \
+    pid = getpid();\
+    snprintf(pp, 255, "/proc/%i/stat", pid);\
+    fh = fopen(pp, "r");\
+    if (fh == NULL)\
+      res = -1;\
+    else\
+      res = fscanf(fh,\
+                 "%d %255s %c %d %d %d %d %d "\
+                 "%u %u %u %u %u "\
+                 "%d %d %d %d %d "\
+                 "%d %u %u %d "\
+                 "%u %u %u %u %u"\
+                 "%u %u %u "\
+                 "%d %d %d %d "\
+                 "%u"\
+                 ,\
+                 &pid, &(comm[0]), &state, &ppid, &pgrp, &session, &tty, \
+                 &tpgid,\
+                 &flags, &minflt, &cminflt, &majflt, &cmajflt,\
+                 &utime, &stime, &cutime, &cstime, &counter,\
+                 &priority, &timeout, &itrealvalue, &starttime,\
+                 &vsize, &rss, &rlim, &startcode, &endcode,\
+                 &startstack, &kstkesp, &kstkeip,\
+                 &signal, &blocked, &sigignore, &sigcatch,\
+                 &wchan\
+                 );\
+    fclose(fh); fh = NULL;
+
+- (unsigned int)virtualMemorySize {
+#ifdef __linux__
+  NG_GET_PROC_INFO;
+  return vsize;
+#else
+  return 0;
+#endif
+}
+- (unsigned int)residentSetSize {
+#ifdef __linux__
+  NG_GET_PROC_INFO;
+  return rss;
+#else
+  return 0;
+#endif
+}
+- (unsigned int)residentSetSizeLimit {
+#ifdef __linux__
+  NG_GET_PROC_INFO;
+  return rlim;
+#else
+  return 0;
+#endif
+}
+
+- (NSDictionary *)procStatDictionary {
+#ifdef __linux__
+  /* see 'man 5 proc' */
+  NSMutableDictionary *dict;
+  NG_GET_PROC_INFO;
+  
+  if (res > 0) {
+    dict = [NSMutableDictionary dictionaryWithCapacity:res];
+    
+    if (res >  0) [dict setObject:_int(pid)          forKey:@"pid"];
+    if (res >  1) [dict setObject:[NSString stringWithCString:comm]
+                        forKey:@"comm"];
+    if (res >  2) [dict setObject:[NSString stringWithCString:&state length:1]
+                        forKey:@"state"];
+    if (res >  3) [dict setObject:_int(ppid)         forKey:@"ppid"];
+    if (res >  4) [dict setObject:_int(pgrp)         forKey:@"pgrp"];
+    if (res >  5) [dict setObject:_int(session)      forKey:@"session"];
+    if (res >  6) [dict setObject:_int(tty)          forKey:@"tty"];
+    if (res >  7) [dict setObject:_int(tpgid)        forKey:@"tpgid"];
+    if (res >  8) [dict setObject:_uint(flags)       forKey:@"flags"];
+    if (res >  9) [dict setObject:_uint(minflt)      forKey:@"minflt"];
+    if (res > 10) [dict setObject:_uint(cminflt)     forKey:@"cminflt"];
+    if (res > 11) [dict setObject:_uint(majflt)      forKey:@"majflt"];
+    if (res > 12) [dict setObject:_uint(cmajflt)     forKey:@"cmajflt"];
+    if (res > 13) [dict setObject:_int(utime)        forKey:@"utime"];
+    if (res > 14) [dict setObject:_int(stime)        forKey:@"stime"];
+    if (res > 15) [dict setObject:_int(cutime)       forKey:@"cutime"];
+    if (res > 16) [dict setObject:_int(cstime)       forKey:@"cstime"];
+    if (res > 17) [dict setObject:_int(counter)      forKey:@"counter"];
+    if (res > 18) [dict setObject:_int(priority)     forKey:@"priority"];
+    if (res > 19) [dict setObject:_uint(timeout)     forKey:@"timeout"];
+    if (res > 20) [dict setObject:_uint(itrealvalue) forKey:@"itrealvalue"];
+    if (res > 21) [dict setObject:_int(starttime)    forKey:@"starttime"];
+    if (res > 22) [dict setObject:_uint(vsize)       forKey:@"vsize"];
+    if (res > 23) [dict setObject:_uint(rss)         forKey:@"rss"];
+    if (res > 24) [dict setObject:_uint(rlim)        forKey:@"rlim"];
+    if (res > 25) [dict setObject:_uint(startcode)   forKey:@"startcode"];
+    if (res > 26) [dict setObject:_uint(endcode)     forKey:@"endcode"];
+    if (res > 27) [dict setObject:_uint(startstack)  forKey:@"startstack"];
+    if (res > 28) [dict setObject:_uint(kstkesp)     forKey:@"kstkesp"];
+    if (res > 29) [dict setObject:_uint(kstkeip)     forKey:@"kstkeip"];
+    if (res > 30) [dict setObject:_int(signal)       forKey:@"signal"];
+    if (res > 31) [dict setObject:_int(blocked)      forKey:@"blocked"];
+    if (res > 32) [dict setObject:_int(sigignore)    forKey:@"sigignore"];
+    if (res > 33) [dict setObject:_int(sigcatch)     forKey:@"sigcatch"];
+    if (res > 34) [dict setObject:_uint(wchan)       forKey:@"wchan"];
+    
+    return dict;
+  }
+  else {
+    NSLog(@"%s: couldn't scan /proc-info ...", __PRETTY_FUNCTION__);
+    dict = nil;
+  }
+  
+  return [[dict copy] autorelease];
+#else
+  return nil;
+#endif
+}
+
+@end /* NSProcessInfo(misc) */
+
+// linking
+
+void __link_NSProcessInfo_misc(void) {
+  __link_NSProcessInfo_misc();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSRunLoop+FileObjects.m b/skyrix-core/NGExtensions/FdExt.subproj/NSRunLoop+FileObjects.m
new file mode 100644 (file)
index 0000000..d9526c8
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+// Created by Helge Hess on Mon Mar 11 2002.
+
+#if !LIB_FOUNDATION_LIBRARY
+
+#include <stdlib.h>
+#include "NSRunLoop+FileObjects.h"
+#include "FileObjectHolder.h"
+#import <Foundation/NSMapTable.h>
+#import <Foundation/NSNotification.h>
+#include "common.h"
+
+NSString *NSFileObjectBecameActiveNotificationName =
+  @"NSFileObjectBecameActiveNotification";
+
+#if GNUSTEP_BASE_LIBRARY
+
+@interface NSObject(FileObjectWatcher) < RunLoopEvents >
+@end
+
+@implementation NSObject(FileObjectWatcher)
+
+- (NSDate *)timedOutEvent:(void *)_fdData
+  type: (RunLoopEventType)_type
+  forMode: (NSString *)_mode
+{
+  NSLog(@"%s: timed out ...", __PRETTY_FUNCTION__);
+  return nil;
+}
+
+- (void)receivedEvent:(void *)_fdData
+  type:(RunLoopEventType)_type
+  extra:(void *)_extra
+  forMode:(NSString *)_mode
+{
+  NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+  
+  [nc postNotificationName:NSFileObjectBecameActiveNotificationName
+      object:self];
+}
+
+@end /* NSObject(FileObjectWatcher) */
+
+#endif
+
+@implementation NSRunLoop(FileObjects)
+
+#if GNUSTEP_BASE_LIBRARY
+
+/* implement using -addEvent:type:watcher:forMode: */
+
+- (void)addFileObject:(id)_fileObject
+  activities:(unsigned int)_activities
+  forMode:(NSString *)_mode
+{
+  int evType = 0;
+  
+  _fileObject = RETAIN(_fileObject);
+  
+  [self addEvent:(void *)[_fileObject fileDescriptor]
+        type:evType
+        watcher:_fileObject
+        forMode:_mode];
+}
+- (void)removeFileObject:(id)_fileObject
+  forMode:(NSString *)_mode
+{
+  int evType = 0;
+  
+  _fileObject = AUTORELEASE(_fileObject);
+  [self removeEvent:(void *)[_fileObject fileDescriptor]
+        type:evType
+        forMode:_mode
+        all:NO];
+}
+
+#else /* eg MacOSX Foundation ... */
+
+static NSMutableArray *activeHandles = nil;
+
+- (void)addFileObject:(id)_fileObject
+  activities:(unsigned int)_activities
+  forMode:(NSString *)_mode
+{
+  FileObjectHolder *fo;
+  
+  if (activeHandles == nil)
+    activeHandles = [[NSMutableArray alloc] init];
+  
+  fo = [[FileObjectHolder alloc] initWithFileObject:_fileObject
+                                 activities:_activities
+                                 mode:_mode];
+  [activeHandles addObject:fo];
+  [fo wait];
+  [fo release];
+}
+
+- (FileObjectHolder *)_findHolderForObject:(id)_fileObject {
+  NSEnumerator *e;
+  FileObjectHolder *fo;
+  
+  if (activeHandles == nil) return NULL;
+  e = [activeHandles objectEnumerator];
+  while ((fo = [e nextObject])) {
+    if ([fo fileObject] == _fileObject)
+      break;
+  }
+  return fo;
+}
+  
+- (void)removeFileObject:(id)_fileObject
+  forMode:(NSString *)_mode
+{
+  FileObjectHolder *fo;
+
+  if ((fo = [self _findHolderForObject:_fileObject]) == nil) {
+    NSLog(@"found no holder for fileobject %@ ...", _fileObject);
+    return;
+  }
+  
+  [fo retain];
+  [activeHandles removeObject:fo];
+  [fo stopWaiting];
+  [fo release];
+}
+
+#endif /* !GNUSTEP_BASE_LIBRARY */
+
+@end /* NSRunLoop(FileObjects) */
+
+#endif /* !LIB_FOUNDATION_LIBRARY */
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSSet+enumerator.m b/skyrix-core/NGExtensions/FdExt.subproj/NSSet+enumerator.m
new file mode 100644 (file)
index 0000000..e9f0fbe
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NSSet+enumerator.h"
+
+@implementation NSSet(enumerator)
+
+- (id)initWithObjectsFromEnumerator:(NSEnumerator *)_enumerator {
+  NSMutableSet *set = nil;
+
+  set = [[NSMutableSet alloc] initWithObjectsFromEnumerator:_enumerator];
+  self = [self initWithSet:set];
+  [set release]; set = nil;
+  return self;
+}
+
+// mapping
+
+- (NSArray *)mappedArrayUsingSelector:(SEL)_selector {
+  NSArray *array = nil;
+  NSSet   *set   = nil;
+
+  set = [self mappedSetUsingSelector:_selector];
+  if (set) {
+    array = [[NSArray allocWithZone:[self zone]]
+                      initWithObjectsFromEnumerator:[set objectEnumerator]];
+  }
+  set = nil;
+  return [array autorelease];
+}
+- (NSArray *)mappedArrayUsingSelector:(SEL)_selector withObject:(id)_object {
+  NSArray *array = nil;
+  NSSet   *set   = nil;
+
+  set = [self mappedSetUsingSelector:_selector withObject:_object];
+  if (set) {
+    array = [[NSArray allocWithZone:[self zone]]
+                      initWithObjectsFromEnumerator:[set objectEnumerator]];
+  }
+  set = nil;
+  return [array autorelease];
+}
+
+- (NSSet *)mappedSetUsingSelector:(SEL)_selector {
+  NSMutableSet *set   = [NSMutableSet setWithCapacity:[self count]];
+  NSEnumerator *e     = [self objectEnumerator];
+  id           object = nil;
+
+  while ((object = [e nextObject])) {
+    object = [object performSelector:_selector];
+
+    [set addObject:object ? object : [NSNull null]];
+  }
+  return set;
+}
+- (NSSet *)mappedSetUsingSelector:(SEL)_selector withObject:(id)_object {
+  NSMutableSet *set = [NSMutableSet setWithCapacity:[self count]];
+  NSEnumerator *e     = [self objectEnumerator];
+  id           object = nil;
+
+  while ((object = [e nextObject])) {
+    object = [object performSelector:_selector withObject:_object];
+
+    [set addObject:object ? object : [NSNull null]];
+  }
+  return set;
+}
+
+@end
+
+@implementation NSMutableSet(enumerator) 
+
+- (id)initWithObjectsFromEnumerator:(NSEnumerator *)_enumerator {
+  if ((self = [self init])) {
+    id obj = nil;
+     
+    while ((obj = [_enumerator nextObject]))
+      [self addObject:obj];
+  }
+  return self;
+}
+
+@end
+
+void __link_NGExtensions_NSSetEnumerator() {
+  __link_NGExtensions_NSSetEnumerator();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSString+Encoding.m b/skyrix-core/NGExtensions/FdExt.subproj/NSString+Encoding.m
new file mode 100644 (file)
index 0000000..d02ac2e
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGExtensions/NSString+Encoding.h>
+#include <NGExtensions/NSObject+Logs.h>
+#include "common.h"
+
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+#  import <CoreFoundation/CoreFoundation.h>
+#else
+#  include <iconv.h>
+#  import <Foundation/NSByteOrder.h>
+#endif
+
+// TODO: should move different implementations to different files ...
+
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+
+@interface NSString(Encoding_PrivateAPI)
++ (NSStringEncoding)stringEncodingForEncodingNamed:(NSString *)encoding;
+@end
+
+@implementation NSString(Encoding)
+
++ (NSStringEncoding)stringEncodingForEncodingNamed:(NSString *)_encoding
+{
+  CFStringEncoding cfEncoding;
+
+  if(_encoding == nil)
+    return 0;
+
+  _encoding = [_encoding lowercaseString];
+  cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)_encoding);
+  if(cfEncoding == kCFStringEncodingInvalidId)
+    return 0;
+  return CFStringConvertEncodingToNSStringEncoding(cfEncoding);
+}
+
++ (NSString *)stringWithData:(NSData *)_data
+  usingEncodingNamed:(NSString *)_encoding
+{
+  NSStringEncoding encoding;
+
+  encoding = [NSString stringEncodingForEncodingNamed:_encoding];
+  return [[[NSString alloc] initWithData:_data encoding:encoding] autorelease];
+}
+
+- (NSData *)dataUsingEncodingNamed:(NSString *)_encoding {
+  NSStringEncoding encoding;
+
+  encoding = [NSString stringEncodingForEncodingNamed:_encoding];
+  return [self dataUsingEncoding:encoding];
+}
+
+@end /* NSString(Encoding) */
+
+#else /* ! NeXT_Foundation_LIBRARY */
+
+@implementation NSString(Encoding)
+
+#ifdef __linux__
+static NSString *unicharEncoding = @"UCS-2LE";
+#else
+static NSString *unicharEncoding = @"UCS-2-INTERNAL";
+#endif
+static int IconvLogEnabled = -1;
+
+static void checkDefaults(void) {
+  NSUserDefaults *ud;
+  
+  if (IconvLogEnabled != -1) 
+    return;
+  ud = [NSUserDefaults standardUserDefaults];
+  IconvLogEnabled = [ud boolForKey:@"IconvLogEnabled"]?1:0;
+
+#ifdef __linux__
+  if (NSHostByteOrder() == NS_BigEndian) {
+    NSLog(@"Note: using UCS-2 big endian on Linux.");
+    unicharEncoding = @"UCS-2BE";
+  }
+  else {
+    NSLog(@"Note: using UCS-2 little endian on Linux.");
+    unicharEncoding = @"UCS-2LE";
+  }
+#endif
+}
+
+static char *iconv_wrapper(id self, char *_src, unsigned _srcLen,
+                           NSString *_fromEncode, NSString *_toEncode,
+                           unsigned *outLen_)
+{
+  iconv_t    type;
+  size_t     inbytesleft, outbytesleft, write, outlen;
+  const char *fromEncode, *toEncode;
+  char       *inbuf, *outbuf, *tm;
+  NSString   *result;
+
+  checkDefaults();
+
+  if (IconvLogEnabled) {
+    [self logWithFormat:@"FromEncode: %@; ToEncode: %@", _fromEncode,
+          _toEncode];
+  }
+
+  _fromEncode = [_fromEncode uppercaseString];
+  _toEncode   = [_toEncode   uppercaseString];
+
+  if (0 && [_fromEncode isEqualToString:_toEncode]) {
+    outlen = _srcLen;
+    outbuf = calloc(sizeof(char), outlen+1);
+
+    memcpy(outbuf, _src, _srcLen);
+    *outLen_ = outlen;
+    
+    return outbuf;
+  }
+  result     = nil;
+  fromEncode = [_fromEncode cString];
+  toEncode   = [_toEncode   cString];
+  
+  type       = iconv_open(toEncode, fromEncode);
+  inbuf      = NULL;
+  outbuf     = NULL;
+  
+  if ((type == (iconv_t)-1)) {
+    [self logWithFormat:@"%s: Could not handle iconv encoding. FromEncoding:%@"
+          @" to encoding:%@", __PRETTY_FUNCTION__, _fromEncode, _toEncode];
+    goto CLEAR_AND_RETURN;
+  }
+  inbytesleft  = _srcLen;
+  inbuf        = _src;
+  outlen       = inbytesleft * 3;
+  outbuf       = calloc(outlen + 1, sizeof(char));;
+  tm           = outbuf;
+  outbytesleft = outlen;
+
+  write = iconv(type, &inbuf, &inbytesleft, &tm, &outbytesleft);
+
+  if (write == (size_t)-1) {
+    if (errno == EILSEQ) {
+      [self logWithFormat:@"Got invalid multibyte sequence. ToEncode: %@"
+            @" FromEncode: %@.", _toEncode, _fromEncode];
+      if (IconvLogEnabled) {
+        [self logWithFormat:@"ByteSequence:\n%s\n", _src];
+      }
+      goto CLEAR_AND_RETURN;
+    }
+    else if (errno == EINVAL) {
+      [self logWithFormat:@"Got incomplete multibyte sequence. ToEncode: %@"
+       @" FromEncode: %@", _toEncode, _fromEncode];
+      if (IconvLogEnabled)
+        [self logWithFormat:@"ByteSequence:\n%s\n", _src];
+      
+    }
+    else if (errno == E2BIG) {
+      [self logWithFormat:
+             @"Got to small outputbuffer (inbytesleft=%d, outbytesleft=%d, "
+             @"outlen=%d). ToEncode: %@ FromEncode: %@", 
+             inbytesleft, outbytesleft, outlen,
+             _toEncode, _fromEncode];
+      if (IconvLogEnabled)
+        [self logWithFormat:@"ByteSequence:\n%s\n", _src];
+      
+      goto CLEAR_AND_RETURN;
+    }
+    else {
+      [self logWithFormat:@"Got unexpected error. ToEncode: %@"
+       @" FromEncode: %@", _toEncode, _fromEncode];
+      goto CLEAR_AND_RETURN;
+    }
+  }
+#if DEBUG_ICONV
+  NSLogL(@"outlen %d outbytesleft %d", outlen, outbytesleft);
+#endif
+  if (type)
+    iconv_close(type);
+  
+  *outLen_ = outlen - outbytesleft;
+  
+  return outbuf;
+  
+ CLEAR_AND_RETURN:
+  if (type)
+    iconv_close(type);
+  
+  if (outbuf) {
+    free(outbuf); outbuf = NULL;
+  }
+  return NULL;
+}
+
++ (NSString *)stringWithData:(NSData *)_data
+  usingEncodingNamed:(NSString *)_encoding
+{
+  void      *inbuf, *res;
+  unsigned  len, inbufLen;
+  NSString  *result;
+
+  if (![_encoding length])
+    return nil;
+  
+  inbufLen = [_data length];
+  inbuf    = calloc(sizeof(char), inbufLen + 4);
+  [_data getBytes:inbuf];
+  
+  result = nil;
+  res    = iconv_wrapper(self, inbuf, inbufLen, _encoding, unicharEncoding, &len);
+  if (res) {
+    result = [[NSString alloc] initWithCharacters:res length:(len / 2)];
+    free(res); res = NULL;
+  }
+  if (inbuf) free(inbuf); inbuf = NULL;
+  return [result autorelease];
+}
+
+- (NSData *)dataUsingEncodingNamed:(NSString *)_encoding {
+  unichar  *chars;
+  char     *res;
+  unsigned inputLen, resLen;
+  NSData   *data;
+  
+  if (![_encoding length])
+    return nil;
+
+  data     = nil;
+  inputLen = [self length];
+  chars    = calloc(sizeof(unichar), inputLen + 4);
+  [self getCharacters:chars];
+  
+  res = iconv_wrapper(self, (char *)chars, inputLen*2, 
+                     unicharEncoding, _encoding,
+                      &resLen);
+  if (res) data = [NSData dataWithBytes:res length:resLen];
+  
+  if (chars) free(chars); chars = NULL;
+  return data;
+}
+
+@end /* NSString(Encoding) */
+
+#endif /* ! NeXT_Foundation_LIBRARY */
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSString+Ext.m b/skyrix-core/NGExtensions/FdExt.subproj/NSString+Ext.m
new file mode 100644 (file)
index 0000000..d949884
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSString+Ext.h"
+#include "common.h"
+#include <ctype.h>
+
+@implementation NSString(GSAdditions)
+
+- (NSString *)stringWithoutPrefix:(NSString *)_prefix
+{
+    return ([self hasPrefix:_prefix])
+        ? [self substringFromIndex:[_prefix length]]
+        : [[self copy] autorelease];
+}
+
+- (NSString *)stringWithoutSuffix:(NSString *)_suffix
+{
+    return ([self hasSuffix:_suffix])
+        ? [self substringToIndex:([self length] - [_suffix length])]
+        : [[self copy] autorelease];
+}
+
+- (NSString *)stringByReplacingString:(NSString *)_orignal
+  withString:(NSString *)_replacement
+{
+    /* very slow solution .. */
+    
+    if ([self rangeOfString:_orignal].length == 0)
+        return [[self copy] autorelease];
+    
+    return [[self componentsSeparatedByString:_orignal]
+                  componentsJoinedByString:_replacement];
+}
+
+- (NSString *)stringByTrimmingLeadWhiteSpaces
+{
+    // should check 'whitespaceAndNewlineCharacterSet' ..
+    unsigned len;
+    
+    if ((len = [self length]) > 0) {
+        unichar  *buf;
+        unsigned idx;
+        
+        buf = calloc(len + 1, sizeof(unichar));
+        [self getCharacters:buf];
+        
+        for (idx = 0; (idx < len) && (buf[idx] == 32); idx++)
+            ;
+        
+        self = [NSString stringWithCharacters:&(buf[idx]) length:(len - idx)];
+        free(buf);
+        return self;
+    }
+    else
+        return [[self copy] autorelease];
+}
+- (NSString *)stringByTrimmingTailWhiteSpaces
+{
+    // should check 'whitespaceAndNewlineCharacterSet' ..
+    unsigned len;
+    
+    if ((len = [self length]) > 0) {
+        unichar  *buf;
+        unsigned idx;
+        
+        buf = calloc(len + 1, sizeof(unichar));
+        [self getCharacters:buf];
+
+        for (idx = (len - 1); (idx >= 0) && (buf[idx] == 32); idx--)
+            ;
+        
+        self = [NSString stringWithCharacters:buf length:(idx + 1)];
+        free(buf);
+        return self;
+    }
+    else
+        return [[self copy] autorelease];
+}
+
+- (NSString *)stringByTrimmingLeadSpaces
+{
+    unsigned len;
+    
+    if ((len = [self length]) > 0) {
+        unichar  *buf;
+        unsigned idx;
+        
+        buf = calloc(len + 1, sizeof(unichar));
+        [self getCharacters:buf];
+        
+        for (idx = 0; (idx < len) && isspace(buf[idx]); idx++)
+            ;
+        
+        self = [NSString stringWithCharacters:&(buf[idx]) length:(len - idx)];
+        free(buf);
+        return self;
+    }
+    else
+        return [[self copy] autorelease];
+}
+- (NSString *)stringByTrimmingTailSpaces
+{
+    unsigned len;
+    
+    if ((len = [self length]) > 0) {
+        unichar  *buf;
+        unsigned idx;
+        
+        buf = calloc(len + 1, sizeof(unichar));
+        [self getCharacters:buf];
+        
+        for (idx = (len - 1); (idx >= 0) && isspace(buf[idx]); idx--)
+            ;
+        
+        self = [NSString stringWithCharacters:buf length:(idx + 1)];
+        free(buf);
+        return self;
+    }
+    else
+        return [[self copy] autorelease];
+}
+
+- (NSString *)stringByTrimmingWhiteSpaces
+{
+    return [[self stringByTrimmingTailWhiteSpaces]
+                  stringByTrimmingLeadWhiteSpaces];
+}
+- (NSString *)stringByTrimmingSpaces
+{
+    return [[self stringByTrimmingTailSpaces]
+                  stringByTrimmingLeadSpaces];
+}
+
+@end /* NSString(GSAdditions) */
+
+@implementation NSMutableString(GNUstepCompatibility)
+
+- (void)trimLeadSpaces
+{
+    [self setString:[self stringByTrimmingLeadSpaces]];
+}
+- (void)trimTailSpaces
+{
+    [self setString:[self stringByTrimmingTailSpaces]];
+}
+- (void)trimSpaces
+{
+    [self setString:[self stringByTrimmingSpaces]];
+}
+
+@end /* NSMutableString(GNUstepCompatibility) */
+
+@implementation NSString(lfNSURLUtilities)
+
+- (BOOL)isAbsoluteURL
+{
+    NSRange r;
+    unsigned i;
+    
+    if ([self hasPrefix:@"mailto:"])
+        return YES;
+    if ([self hasPrefix:@"javascript:"])
+        return YES;
+    
+    r = [self rangeOfString:@"://"];
+    if (r.length == 0) {
+        if ([self hasPrefix:@"file:"])
+            return YES;
+        return NO;
+    }
+    
+    if ([self hasPrefix:@"/"])
+        return NO;
+
+    for (i = 0; i < r.location; i++) {
+        if (!isalpha([self characterAtIndex:i]))
+            return NO;
+    }
+    return YES;
+}
+
+- (NSString *)urlScheme
+{
+    unsigned i, count;
+    unichar c = 0;
+    
+    if ((count = [self length]) == 0)
+        return nil;
+    
+    for (i = 0; i < count; i++) {
+        c = [self characterAtIndex:i];
+        
+        if (!isalpha(c))
+            break;
+    }
+    if ((c != ':') || (i < 1))
+        return nil;
+    
+    return [self substringToIndex:i];
+}
+
+@end /* NSString(lfNSURLUtilities) */
+
+#if !LIB_FOUNDATION_LIBRARY
+
+@implementation NSString(KVCCompatibility)
+
+- (id)valueForUndefinedKey:(NSString *)_key {
+  NSLog(@"WARNING: tried to access undefined KVC key '%@' on str object: %@",
+       _key, self);
+  return nil;
+}
+
+@end
+
+#endif
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSString+Formatting.m b/skyrix-core/NGExtensions/FdExt.subproj/NSString+Formatting.m
new file mode 100644 (file)
index 0000000..d244eb6
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "common.h"
+#include "NSString+Formatting.h"
+#include "NGMemoryAllocation.h"
+
+#if 0
+
+#if !ISERIES
+#  ifndef USE_VA_LIST_PTR
+#    define USE_VA_LIST_PTR 1
+#  endif
+#else
+#  define USE_VA_LIST_PTR 0
+#endif
+
+
+// format
+//   %|[justification]|[fieldwidth]|[precision]|formatChar
+//   %[-]{digit}*[.{digit}*]conv
+
+static const char *formatChars =
+  "diouxX" // integers
+  "feEgG"  // double
+  "c"      // int arg -> uchar
+  "s"      // string
+  "@"      // object
+  "$"      // string object
+;
+static const char *formatAttrs = "#0- +,";
+static const char *formatConv  = "hlLqZ";
+static Class StrClass = Nil;
+
+typedef enum {
+  DEFAULT_TYPE = 0,
+  SHORT_TYPE,
+  LONG_TYPE,
+  VERY_LONG_TYPE
+} NGFormatType;
+
+// implementation
+
+static inline NSString *
+wideString(const char *str, int width, char fillChar, BOOL isRightAligned)
+{
+  unsigned char *tmp;
+  register int cnt;
+  int len;
+  
+  if (StrClass == Nil) StrClass = [NSString class];
+  
+  if (width <= 0)
+    return str ? [StrClass stringWithCString:str] : nil;
+
+  if ((len = strlen(str)) >= width)
+    return str ? [StrClass stringWithCString:str] : nil;
+
+  tmp = malloc(width + 2);
+  if (isRightAligned) { // right aligned
+    for (cnt = 0; cnt < (width - len); cnt++)
+      tmp[cnt] = fillChar;
+    strncpy(tmp + (width - len), str, len);
+    tmp[width] = '\0';
+  }
+  else { // left aligned
+    for (cnt = len; cnt < width; cnt++)
+      tmp[cnt] = fillChar;
+    strncpy(tmp, str, len);
+    tmp[cnt] = '\0';
+  }
+  
+  return [[[StrClass alloc]
+                     initWithCStringNoCopy:tmp length:strlen(tmp)
+                     freeWhenDone:YES] autorelease];
+}
+
+static inline NSString *xsSimpleFormatObject(char *fmt, id _value, NSString *_ds) {
+  /*
+    formats an object value in an simple format
+    (this is only the '%{mods}{type}' part of a real
+    format string !)
+    The method to get the value of the object is
+    determined by the {type} of the Format,
+    eg: i becomes intValue, @ becomes description ..
+
+    the decimal point in float-strings can be replaced by the _ds
+    String. To do this, the result of the Format is scanned for
+    '.' and _ds is expanded for this.
+  */
+  int  fmtLen  = strlen(fmt);
+  char fmtChar = fmt[fmtLen - 1];
+  NGFormatType typeMode = DEFAULT_TYPE;
+  int  width      = -1;
+  int  prec       = -1;
+  BOOL alignRight = YES;
+  char *pos = fmt + 1;
+  char *tmp;
+  
+  if (StrClass == Nil) StrClass = [NSString class];
+  
+  while (index(formatAttrs, *pos)) {
+    if (*pos == '-')
+      alignRight = NO;
+    pos++;
+  }
+  
+  /* width */
+  tmp = pos;
+  while (isdigit((int)*pos)) pos++;
+  if (tmp != pos) {
+    char old = *pos;
+    *pos = '\0';
+    width = atoi(tmp);
+    *pos = old;
+  }
+
+  /* prec */
+  if (*pos == '.') {
+    pos++;
+    tmp = pos;
+    while (isdigit((int)*pos)) pos++;
+    if (tmp != pos) {
+      char old = *pos;
+      *pos = '\0';
+      prec = atoi(tmp);
+      *pos = old;
+    }
+  }
+
+  /* conversion */
+  if (index(formatConv, *pos)) {
+    switch (*pos) {
+      case 'h':
+        typeMode = SHORT_TYPE;
+        pos++;
+        break;
+      case 'l':
+        typeMode = LONG_TYPE;
+        pos++;
+        if (*pos == 'l') { // long-long
+          typeMode = VERY_LONG_TYPE;
+          pos++;
+        }
+        break;
+      case 'L':
+      case 'q':
+        typeMode = VERY_LONG_TYPE;
+        pos++;
+        break;
+    }
+  }
+
+  if (index("diouxX", fmtChar)) {
+    char buf[128];
+    int  len = -1;
+
+    switch (typeMode) {
+      case SHORT_TYPE: {
+        unsigned short int i = [(NSNumber *)_value unsignedShortValue];
+        len = sprintf(buf, fmt, i);
+        break;
+      }
+      case LONG_TYPE: {
+        unsigned long int i = [(NSNumber *)_value unsignedLongValue];
+        len = sprintf(buf, fmt, i);
+        break;
+      }
+      case VERY_LONG_TYPE: {
+        long long i = [(NSNumber *)_value unsignedLongLongValue];
+        len = sprintf(buf, fmt, i);
+        break;
+      }
+      default: {
+        unsigned int i = [(NSNumber *)_value unsignedIntValue];
+        len = sprintf(buf, fmt, i);
+        break;
+      }
+    }
+
+    return (len >= 0) ? [StrClass stringWithCString:buf length:len] : nil;
+  }
+  
+  if (fmtChar == 'c') {
+    char buf[64];
+    int  i = [(NSNumber *)_value unsignedCharValue];
+    int  len;
+
+    len = sprintf(buf, fmt, (unsigned char)i);
+
+    return (len > 0) ? [StrClass stringWithCString:buf length:len] : nil;
+  }
+  if (fmtChar == 'C') {
+    // TODO: implement correctly
+    /* 16bit unichar value */
+    char buf[64];
+    int  i, len;
+    
+    /* TODO: evil hack */
+    fmt[fmtLen - 1] = 'c';
+    i = [(NSNumber *)_value unsignedCharValue];
+    len = sprintf(buf, fmt, (unsigned char)i);
+    
+    return (len > 0) ? [StrClass stringWithCString:buf length:len] : nil;
+  }
+  
+  if (index("feEgG", fmtChar)) {
+    unsigned char buf[256];
+    unsigned len;
+
+    if (typeMode == VERY_LONG_TYPE) {
+      long double i = [(NSNumber *)_value doubleValue];
+      len = sprintf(buf, fmt, i);
+    }
+    else {
+      double i = [(NSNumber *)_value doubleValue];
+      len = sprintf(buf, fmt, i);
+    }
+
+    if (len >= 0) {
+      NSMutableString *result;
+      unsigned int cnt;
+      char         *ptr = buf;
+      unsigned int bufCount = 0;
+      
+      if (_ds == nil)
+        return [StrClass stringWithCString:buf length:len];
+
+      result = 
+        [NSMutableString stringWithCapacity:len + [_ds cStringLength]];
+
+      for (cnt = 0; cnt < len; cnt++) {
+        if (buf[cnt] == '.') {
+          if (bufCount > 0) {
+            NSString *s;
+            
+            // TODO: cache selector
+            s = [[StrClass alloc] initWithCString:ptr length:bufCount];
+            if (s) [result appendString:s];
+            [s release];
+          }
+
+          if (_ds) [result appendString:_ds];
+          
+          ptr = &(buf[cnt + 1]);
+          bufCount = 0;
+        }
+        else {
+          bufCount++;
+        }
+        
+        if (bufCount > 0) {
+          NSString *s;
+          
+          // TODO: cache selector
+          s = [[StrClass alloc] initWithCString:ptr length:bufCount];
+          if (s) [result appendString:s];
+          [s release];
+        }
+        return result;
+      }
+    }
+    else 
+      return nil;
+  }
+  else {
+    switch (fmtChar) {
+      case 's': case 'S': {
+        /* TODO: implement 'S', current mech is evil hack */
+       unsigned len;
+       char *buffer = NULL;
+       id result;
+
+       if (_value == nil)
+         return wideString("<null>", width, ' ', alignRight);
+       
+       len    = [(NSString *)_value cStringLength];
+       buffer = malloc(len + 10);
+       [_value getCString:buffer];
+       buffer[len] = '\0';
+       
+        result = wideString(buffer, width, ' ', alignRight);
+       free(buffer);
+       return result;
+      }
+      
+      case '@': {
+        id       obj   = _value;
+        NSString *dstr = obj ? [obj description] : @"<nil>";
+       char     *buffer = NULL;
+       unsigned len;
+
+       if (dstr == nil)
+         return wideString("<null>", width, ' ', alignRight);
+       
+       len    = [dstr cStringLength];
+       buffer = malloc(len + 10);
+       [dstr getCString:buffer];
+       buffer[len] = '\0';
+       
+       dstr = wideString(buffer, width, ' ', alignRight);
+       free(buffer);
+       return dstr;
+      }
+      
+      case '$': {
+        id       obj   = _value;
+        NSString *dstr;
+        char     *cstr;
+
+        dstr = obj ? [obj stringValue] : @"<nil>";
+        cstr = (char *)[dstr cString];
+        if (cstr == NULL) cstr = "<null>";
+        
+        return wideString(cstr, width, ' ', alignRight);
+      }
+        
+      default:
+        fprintf(stderr, "WARNING(%s): unknown printf format used: '%s'\n", 
+                __PRETTY_FUNCTION__, fmt);
+        break;
+    }
+  }
+  return nil;
+}
+
+#if USE_VA_LIST_PTR
+static inline NSString *handleFormat(char *fmt, int fmtLen, va_list *_ap) {
+#else
+static inline NSString *handleFormat(char *fmt, int fmtLen, va_list _ap) {
+#endif
+  char fmtChar;
+  char typeMode   = DEFAULT_TYPE;
+  int  width      = -1;
+  int  prec       = -1;
+  BOOL alignRight = YES;
+  char *pos = fmt + 1;
+  char *tmp;
+  if (StrClass == Nil) StrClass = [NSString class];
+
+  if (fmtLen == 0)
+    return @"";
+
+  fmtChar = fmt[fmtLen - 1];
+  
+  while (index(formatAttrs, *pos)) {
+    if (*pos == '-')
+      alignRight = NO;
+    pos++;
+  }
+  
+  /* width */
+  tmp = pos;
+  while (isdigit((int)*pos)) pos++;
+  if (tmp != pos) {
+    char old = *pos;
+    *pos = '\0';
+    width = atoi(tmp);
+    *pos = old;
+  }
+
+  /* prec */
+  if (*pos == '-') {
+    pos++;
+    tmp = pos;
+    while (isdigit((int)*pos)) pos++;
+    if (tmp != pos) {
+      char old = *pos;
+      *pos = '\0';
+      prec = atoi(tmp);
+      *pos = old;
+    }
+  }
+
+  /* conversion */
+  if (index(formatConv, *pos)) {
+    switch (*pos) {
+      case 'h':
+        typeMode = SHORT_TYPE;
+        pos++;
+        break;
+      case 'l':
+        typeMode = LONG_TYPE;
+        pos++;
+        if (*pos == 'l') { // long-long
+          typeMode = VERY_LONG_TYPE;
+          pos++;
+        }
+        break;
+      case 'L':
+      case 'q':
+        typeMode = VERY_LONG_TYPE;
+        pos++;
+        break;
+    }
+  }
+
+#if HEAVY_DEBUG && 0
+  printf("  width=%i prec=%i\n", width, prec); fflush(stdout);
+#endif
+    
+  if (index("diouxX", fmtChar)) {
+    char buf[128];
+    int  len = -1;
+
+    switch (typeMode) {
+      case SHORT_TYPE: {
+#if USE_VA_LIST_PTR
+        unsigned short int i = va_arg(*_ap, int);
+#else
+        unsigned short int i = va_arg(_ap, int);
+#endif
+        len = sprintf(buf, fmt, i);
+        break;
+      }
+      case LONG_TYPE: {
+#if USE_VA_LIST_PTR        
+        unsigned long int i = va_arg(*_ap, unsigned long int);
+#else
+        unsigned long int i = va_arg(_ap, unsigned long int);
+#endif
+        len = sprintf(buf, fmt, i);
+        break;
+      }
+      case VERY_LONG_TYPE: {
+#if USE_VA_LIST_PTR        
+        long long i = va_arg(*_ap, long long);
+#else
+        long long i = va_arg(_ap, long long);
+#endif
+        len = sprintf(buf, fmt, i);
+        break;
+      }
+      default: {
+#if USE_VA_LIST_PTR        
+        unsigned int i = va_arg(*_ap, unsigned int);
+#else
+        unsigned int i = va_arg(_ap, unsigned int);
+#endif
+        len = sprintf(buf, fmt, i);
+        break;
+      }
+    }
+
+    return (len >= 0) ? [StrClass stringWithCString:buf length:len] : nil;
+  }
+  
+  if (fmtChar == 'c') {
+    char buf[64];
+#if USE_VA_LIST_PTR        
+    int  i = va_arg(*_ap, int);
+#else
+    int  i = va_arg(_ap, int);
+#endif
+    int  len;
+
+    if (i == 0)
+      return @"<'\\0'-char>";
+
+    len = sprintf(buf, fmt, (unsigned char)i);
+
+#if HEAVY_DEBUG && 0
+    xsprintf("got format %s char %i made %s len %i\n",
+             fmt, i, buf, len);
+#endif
+    
+    if (len == 0) return nil;
+    return [StrClass stringWithCString:buf length:len];
+  }
+  if (fmtChar == 'C') {
+    /* 16bit unichar */
+    char buf[64];
+#if USE_VA_LIST_PTR        
+    int  i = va_arg(*_ap, int);
+#else
+    int  i = va_arg(_ap, int);
+#endif
+    int  len;
+
+    if (i == 0)
+      return @"<'\\0'-unichar>";
+    
+    /* TODO: implement properly, evil hack */
+    fmt[fmtLen - 1] = 'c';
+    len = sprintf(buf, fmt, (unsigned char)i);
+
+#if HEAVY_DEBUG && 0
+    xsprintf("got format %s unichar %i made %s len %i\n",
+             fmt, i, buf, len);
+#endif
+    
+    if (len == 0) return nil;
+    return [StrClass stringWithCString:buf length:len];
+  }
+  
+  if (index("feEgG", fmtChar)) {
+    char buf[256];
+    int  len;
+
+    if (typeMode == VERY_LONG_TYPE) {
+#if USE_VA_LIST_PTR        
+      long double i = va_arg(*_ap, long double);
+#else
+      long double i = va_arg(_ap, long double);
+#endif
+      len = sprintf(buf, fmt, i);
+    }
+    else {
+#if USE_VA_LIST_PTR        
+      double i = va_arg(*_ap, double);
+#else
+      double i = va_arg(_ap, double);
+#endif
+      len = sprintf(buf, fmt, i);
+    }
+
+    return (len >= 0) ? [StrClass stringWithCString:buf length:len] : nil;
+  }
+  
+  {
+    id result = nil;
+    
+    switch (fmtChar) {
+      case 's':
+      case 'S': /* unicode char array */
+      case '@':
+      case '$': {
+        char *cstr = NULL;
+       BOOL owned = NO;
+
+        if (fmtChar == 's') {
+#if USE_VA_LIST_PTR        
+          cstr = va_arg(*_ap, char *);
+#else
+          cstr = va_arg(_ap, char *);
+#endif
+        }
+        else {
+#if USE_VA_LIST_PTR        
+          id obj = va_arg(*_ap, id);
+#else
+          id obj = va_arg(_ap, id);
+#endif
+          if (obj == nil)
+            cstr = "<nil>";
+          else {
+           NSString *d;
+           
+            if ((d = (fmtChar == '@') ?[obj description]:[obj stringValue])) {
+             unsigned len = [d cStringLength];
+
+             cstr = NGMalloc(len + 1);
+             [d getCString:cstr];
+             cstr[len] = '\0';
+             owned = YES;
+           }
+          }
+        }
+
+        if (cstr == NULL) cstr = "<null>";
+
+        result = wideString(cstr, width, ' ', alignRight);
+       if (owned) NGFree(cstr);
+        break;
+      }
+
+      default:
+        fprintf(stderr, "WARNING(%s): unknown printf format used: '%s'\n", 
+                __PRETTY_FUNCTION__, fmt);
+        break;
+    }
+    return result;
+  }
+  return nil;
+}
+
+static inline NSString *_stringWithCFormat(const char *_format, va_list _ap) {
+  const char *firstPercent;
+  NSMutableString *result;
+  
+  if (StrClass == Nil) StrClass = [NSString class];
+  firstPercent = index(_format, '%');
+#if 0
+  fprintf(stderr, "OWN: format='%s'\n", _format);
+  fflush(stderr);
+#endif
+  
+  // first check whether there are any '%' in the format ..
+  if (firstPercent == NULL) {
+    // no formatting contained in _format
+    return [StrClass stringWithCString:_format];
+  }
+  
+  result = [NSMutableString stringWithCapacity:256];
+
+  if ((firstPercent - _format) > 0) {
+    NSString *s;
+    s = [[StrClass alloc] initWithCString:_format 
+                          length:(firstPercent - _format)];
+    if (s) [result appendString:s];
+    [s release];
+    _format = firstPercent;
+  }
+
+  while (*_format != '\0') { // until end of format string
+    if (*_format == '%') { // found formatting character
+      _format++; // skip '%'
+
+      if (*_format == '%') { // was a quoted '%'
+        [result appendString:@"%"];
+        _format++;
+      }
+      else { // check format
+        char extFmt[16];
+        char *pos  = extFmt;
+
+        extFmt[0] = '%';
+        pos++;
+      
+        while ((*_format != '\0') &&
+                (index(formatChars, *_format) == NULL)) {
+          *pos = *_format;
+          _format++;
+          pos++;
+        }
+        *pos = *_format;
+        _format++;
+        pos++;
+        *pos = '\0';
+
+        // printf("handling ext format '%s'\n", extFmt); fflush(stdout);
+        /* hack for iSeries port, ix86 seems to copy va_list iSeries
+            don`t like pointers to va_list
+        */
+        {
+          NSString *s;
+#if USE_VA_LIST_PTR
+          s = handleFormat(extFmt, strlen(extFmt), &_ap);
+#else
+          s = handleFormat(extFmt, strlen(extFmt), _ap);
+#endif
+          if (s) [result appendString:s];
+        }
+      }
+    }
+    else { // normal char
+      const char *start = _format; // remember start
+      NSString *s;
+      _format++; // skip found char
+
+      // further increase format until '\0' or '%'
+      while ((*_format != '\0') && (*_format != '%'))
+        _format++;
+      
+      s = [[StrClass alloc] initWithCString:start
+                            length:(_format - start)];
+      if (s) [result appendString:s];
+      [s release];
+    }
+  }
+  return result;
+}
+
+@implementation NSString(XSFormatting)
+
++ (id)stringWithCFormat:(const char *)_format arguments:(va_list)_ap {
+  return [self stringWithString:_stringWithCFormat(_format, _ap)];
+}
+
++ (id)stringWithFormat:(NSString *)_format arguments:(va_list)_ap {
+  unsigned len;
+  char     *cfmt;
+  id s;
+
+  len = [_format cStringLength] + 1;
+  cfmt = malloc(len + 1);
+  [_format getCString:cfmt]; cfmt[len] = '\0';
+  s = [self stringWithString:_stringWithCFormat(cfmt, _ap)];
+  free(cfmt);
+  return s;
+}
+
++ (id)stringWithCFormat:(const char *)_format, ... {
+  id      result = nil;
+  va_list ap;
+  
+  va_start(ap, _format);
+  result = [self stringWithString:_stringWithCFormat(_format, ap)];
+  va_end(ap);
+  return result;
+}
+
++ (id)stringWithFormat:(NSString *)_format, ... {
+  id       result = nil;
+  unsigned len;
+  char     *cfmt;
+  va_list  ap;
+  
+  len = [_format cStringLength];
+  cfmt = malloc(len + 1);
+  [_format getCString:cfmt]; cfmt[len] = '\0';
+  va_start(ap, _format);
+  result = [self stringWithString:_stringWithCFormat(cfmt, ap)];
+  va_end(ap);
+  free(cfmt);
+  return result;
+}
+
+- (id)initWithFormat:(NSString *)_format arguments:(va_list)_ap {
+  unsigned len;
+  char *cfmt;
+
+  len = [_format cStringLength];
+  cfmt = malloc(len + 1);
+  [_format getCString:cfmt]; cfmt[len] = '\0';
+  self = [self initWithString:_stringWithCFormat(cfmt, _ap)];
+  free(cfmt);
+  return self;
+}
+
+@end /* NSString(XSFormatting) */
+
+@implementation NSMutableString(XSFormatting)
+
+- (void)appendFormat:(NSString *)_format arguments:(va_list)_ap {
+  unsigned len;
+  NSString *s;
+  char     *cfmt;
+  
+  len = [_format cStringLength];
+  cfmt = malloc(len + 4);
+  
+  [_format getCString:cfmt]; cfmt[len] = '\0';
+  s = _stringWithCFormat(cfmt, _ap);
+  if (cfmt) free(cfmt);
+  if (s) [self appendString:s];
+}
+- (void)appendFormat:(NSString *)_format, ... {
+  unsigned len;
+  char     *cfmt;
+  NSString *s;
+  va_list  ap;
+  
+  len = [_format cStringLength];
+  cfmt = malloc(len + 4);
+  [_format getCString:cfmt]; cfmt[len] = '\0';
+  va_start(ap, _format);
+  s = _stringWithCFormat(cfmt, ap);
+  va_end(ap);
+  if (cfmt) free(cfmt);
+  if (s) [self appendString:s];
+}
+
+@end /* NSMutableString(XSFormatting) */
+
+#endif
+
+// var args wrappers
+
+int xs_sprintf(char *str, const char *format, ...) {
+  va_list ap;
+  int result;
+  va_start(ap, format);
+  result = xs_vsprintf(str, format, ap);
+  va_end(ap);
+  return result;
+}
+int xs_snprintf(char *str, size_t size, const char *format, ...) {
+  va_list ap;
+  int result;
+  va_start(ap, format);
+  result = xs_vsnprintf(str, size, format, ap);
+  va_end(ap);
+  return result;
+}
+
+/* static linking */
+
+void __link_NSString_Formatting(void) {
+  __link_NSString_Formatting();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSString+German.m b/skyrix-core/NGExtensions/FdExt.subproj/NSString+German.m
new file mode 100644 (file)
index 0000000..39922ba
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSString+German.h"
+#include "common.h"
+
+@implementation NSString(German)
+
+- (BOOL)doesContainGermanUmlauts {
+  register unsigned i, len;
+  
+  if ((len = [self length]) == 0)
+    return NO;
+  
+  for (i = 0; i < len; i++) {
+    switch ([self characterAtIndex:i]) {
+      case 252: /* &uuml; */
+      case 220: /* &Uuml; */
+      case 228: /* &auml; */
+      case 196: /* &Auml; */
+      case 246: /* &ouml; */
+      case 214: /* &Ouml; */
+      case 223: /* &szlig; */
+        return YES;
+    }
+  }
+  return NO;
+}
+
+- (NSString *)stringByReplacingGermanUmlautsWithTwoCharsAndSzWith:(unichar)_c {
+  /*
+    a^ => ae, o^ => oe, u^ => ue, A^ => Ae, O^ => Oe, O^ => Ue
+    s^ => sz or ss (_sz arg)
+  */
+  unsigned i, len, rlen;
+  unichar  *buf;
+  NSString *s;
+  
+  if ((len = [self length]) == 0)
+    return @"";
+  
+  buf = calloc((len * 2) + 3, sizeof(unichar));
+  
+  for (i = 0, rlen = 0; i < len; i++) {
+    // TODO
+    register unichar c;
+    
+    c = [self characterAtIndex:i];
+    switch (c) {
+      case 252: /* ue */
+        buf[rlen] = 'u'; rlen++;
+        buf[rlen] = 'e'; rlen++;
+        break;
+      case 220: /* Ue */
+        buf[rlen] = 'U'; rlen++;
+        buf[rlen] = 'e'; rlen++;
+        break;
+      case 228: /* ae */
+        buf[rlen] = 'a'; rlen++;
+        buf[rlen] = 'e'; rlen++;
+        break;
+      case 196: /* Ae */
+        buf[rlen] = 'A'; rlen++;
+        buf[rlen] = 'e'; rlen++;
+        break;
+      case 246: /* oe */
+        buf[rlen] = 'o'; rlen++;
+        buf[rlen] = 'e'; rlen++;
+        break;
+      case 214: /* Oe */
+        buf[rlen] = 'O'; rlen++;
+        buf[rlen] = 'e'; rlen++;
+        break;
+      case 223: /* ss or sz */
+        // TODO
+        buf[rlen] = 's'; rlen++;
+        buf[rlen] = _c;  rlen++;
+        break;
+        
+    default: /* copy char and continue */
+      buf[rlen] = c;
+      rlen++;
+      break;
+    }
+  }
+  
+  s = (rlen > len)
+    ? [[NSString alloc] initWithCharacters:buf length:rlen]
+    : [self copy];
+  if (buf) free(buf);
+  return [s autorelease];
+}
+- (NSString *)stringByReplacingGermanUmlautsWithTwoChars {
+  // default sz mapping is "ss" (like Hess ;-)
+  return [self stringByReplacingGermanUmlautsWithTwoCharsAndSzWith:'s'];
+}
+
+- (NSString *)stringByReplacingTwoCharEncodingsOfGermanUmlauts {
+  /*
+    ae => a^, oe => o^, ue => u^, Ae => A^, Oe => O^, Ue => U^
+    sz => s^
+    ss => s^
+  */
+  unsigned i, len, rlen;
+  NSString *s;
+  unichar  *buf;
+  BOOL     didReplace;
+  
+  if ((len = [self length]) == 0)
+    return @"";
+  if (len == 1)
+    return [[self copy] autorelease];
+  
+  buf = calloc(len + 3, sizeof(unichar));
+  [self getCharacters:buf]; // Note: we can reuse that buffer!
+  
+  for (i = 0, rlen = 0, didReplace = NO; i < len; i++) {
+    register unichar c, cn;
+    
+    c = buf[i];
+
+    if ((i + 1) >= len) {
+      buf[rlen] = c;
+      rlen++;
+      break; // end, found last char (so can't be a sequence)
+    }
+
+    cn = buf[i + 1];
+    
+    if ((c=='a' || c=='A' || c=='u' || c=='U' || c=='o' || c=='O')&&cn=='e') {
+      /* an umlaut sequence */
+      switch (c) {
+      case 'a': buf[rlen] = 228; break;
+      case 'A': buf[rlen] = 196; break;
+      case 'o': buf[rlen] = 246; break;
+      case 'O': buf[rlen] = 214; break;
+      case 'u': buf[rlen] = 252; break;
+      case 'U': buf[rlen] = 220; break;
+      }
+      rlen++;
+      i++; // skip sequence char
+      didReplace = YES;
+    }
+    else if (c == 's' && (cn == 's' || cn == 'z')) {
+      /* a sz sequence */
+      buf[rlen] = 223;
+      rlen++;
+      i++; // skip sequence char
+      didReplace = YES;
+    }
+    else {
+      /* regular char, copy */
+      buf[rlen] = c;
+      rlen++;
+    }
+  }
+  
+  s = didReplace
+    ? [[NSString alloc] initWithCharacters:buf length:rlen]
+    : [self copy];
+  if (buf) free(buf);
+  return [s autorelease];
+}
+
+- (NSArray *)germanUmlautVariantsOfString {
+  /*
+    The ^ is used to signal the single character umlaut to avoid non-ASCII
+    source code.
+    
+    Note: we can only do a limited set of transformations! Eg you can only
+          mix umlauts *OR* the "ue", "oe" variants!
+    
+    Q: what about names which contain encoded umlauts *and* the same sequence
+       as a regular part of the name! For example "Neuendoerf".
+    
+    string with umlauts (two variants, ss and sz):
+      a^ => ae
+      o^ => oe
+      u^ => ue
+      A^ => Ae
+      O^ => Oe
+      O^ => Ue
+      s^ => sz & ss
+    
+    string with umlaut workaround (three variants due to sz/ss):
+      ae => a^
+      oe => o^
+      ue => u^
+      Ae => A^
+      Oe => O^
+      Ue => U^
+      sz => s^ & sz // ?
+      ss => s^ & ss // ?
+  */
+  NSString *s1, *s2;
+  unsigned len;
+  
+  if ((len = [self length]) == 0)
+    return [NSArray arrayWithObjects:@"", nil];
+  
+  if ([self doesContainGermanUmlauts]) {
+    s1 = [self stringByReplacingGermanUmlautsWithTwoCharsAndSzWith:'s'];
+    s2 = [self stringByReplacingGermanUmlautsWithTwoCharsAndSzWith:'z'];
+    
+    if ([s2 isEqualToString:s1] || [s2 isEqualToString:self])
+      s2 = nil;
+    if ([s1 isEqualToString:self])
+      s1 = s2;
+    
+    return [NSArray arrayWithObjects:self, s1, s2, nil];
+  }
+  
+  if (len < 2) // a sequence would have at least 2 chars
+    return [NSArray arrayWithObjects:self, nil];
+  
+  s1 = [self stringByReplacingTwoCharEncodingsOfGermanUmlauts];
+  
+  if ([self isEqualToString:s1])
+    /* nothing was replaced */
+    return [NSArray arrayWithObjects:self, nil];
+  
+  return [NSArray arrayWithObjects:self, s1, nil];
+}
+
+@end /* NSString(German) */
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSString+HTMLEscaping.m b/skyrix-core/NGExtensions/FdExt.subproj/NSString+HTMLEscaping.m
new file mode 100644 (file)
index 0000000..be4864e
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSString+misc.h"
+#include "common.h"
+
+@implementation NSString(HTMLEscaping)
+
+- (NSString *)stringByEscapingHTMLStringUsingCharacters {
+  register unsigned i, len, j;
+  register unichar  *chars, *buf;
+  unsigned escapeCount;
+  
+  if ((len = [self length]) == 0) return @"";
+  
+  chars = malloc((len + 3) * sizeof(unichar));
+  [self getCharacters:chars];
+  
+  /* check for characters to escape ... */
+  for (i = 0, escapeCount = 0; i < len; i++) {
+    switch (chars[i]) {
+      case '&': case '"': case '<': case '>':
+        escapeCount++;
+        break;
+      default:
+        if (chars[i] > 127)
+          escapeCount++;
+        break;
+    }
+  }
+  if (escapeCount == 0 ) {
+    /* nothing to escape ... */
+    if (chars) free(chars);
+    return [[self copy] autorelease];
+  }
+  
+  buf = calloc((len + 5) + (escapeCount * 8), sizeof(unichar));
+  for (i = 0, j = 0; i < len; i++) {
+    switch (chars[i]) {
+      /* escape special chars */
+      case '&':
+        buf[j] = '&'; j++; buf[j] = 'a'; j++; buf[j] = 'm'; j++;
+        buf[j] = 'p'; j++; buf[j] = ';'; j++;
+        break;
+      case '"':
+        buf[j] = '&'; j++; buf[j] = 'q'; j++; buf[j] = 'u'; j++;
+        buf[j] = 'o'; j++; buf[j] = 't'; j++; buf[j] = ';'; j++;
+        break;
+      case '<':
+        buf[j] = '&'; j++; buf[j] = 'l'; j++; buf[j] = 't'; j++;
+        buf[j] = ';'; j++;
+        break;
+      case '>':
+        buf[j] = '&'; j++; buf[j] = 'g'; j++; buf[j] = 't'; j++;
+        buf[j] = ';'; j++;
+        break;
+      case 223: /* &szlig; */
+        buf[j] = '&'; j++; buf[j] = 's'; j++; buf[j] = 'z'; j++;
+        buf[j] = 'l'; j++; buf[j] = 'i'; j++; buf[j] = 'g'; j++;
+        buf[j] = ';'; j++;
+        break;
+        // TODO: this is missing a LOT?
+      case 252: /* &uuml; */
+        buf[j] = '&'; j++; buf[j] = 'u'; j++; buf[j] = 'u'; j++;
+        buf[j] = 'm'; j++; buf[j] = 'l'; j++; buf[j] = ';'; j++;
+        break;
+      case 220: /* &Uuml; */
+        buf[j] = '&'; j++; buf[j] = 'U'; j++; buf[j] = 'u'; j++;
+        buf[j] = 'm'; j++; buf[j] = 'l'; j++; buf[j] = ';'; j++;
+        break;
+      case 228: /* &auml; */
+        buf[j] = '&'; j++; buf[j] = 'a'; j++; buf[j] = 'u'; j++;
+        buf[j] = 'm'; j++; buf[j] = 'l'; j++; buf[j] = ';'; j++;
+        break;
+      case 196: /* &Auml; */
+        buf[j] = '&'; j++; buf[j] = 'A'; j++; buf[j] = 'u'; j++;
+        buf[j] = 'm'; j++; buf[j] = 'l'; j++; buf[j] = ';'; j++;
+        break;
+      case 246: /* &ouml; */
+        buf[j] = '&'; j++; buf[j] = 'o'; j++; buf[j] = 'u'; j++;
+        buf[j] = 'm'; j++; buf[j] = 'l'; j++; buf[j] = ';'; j++;
+        break;
+      case 214: /* &Ouml; */
+        buf[j] = '&'; j++; buf[j] = 'O'; j++; buf[j] = 'u'; j++;
+        buf[j] = 'm'; j++; buf[j] = 'l'; j++; buf[j] = ';'; j++;
+        break;
+        
+      default:
+        /* escape big chars */
+        if (chars[i] > 127) {
+          unsigned char nbuf[16];
+          unsigned int k;
+          
+          sprintf(nbuf, "&#%i;", (int)chars[i]);
+          for (k = 0; nbuf[k] != '\0'; k++) {
+            buf[j] = nbuf[k];
+            j++;
+          }
+        }
+        else {
+          /* nothing to escape */
+          buf[j] = chars[i];
+          j++;
+        }
+        break;
+    }
+  }
+  
+  self = [NSString stringWithCharacters:buf length:j];
+  
+  if (chars) free(chars);
+  if (buf)   free(buf);
+  return self;
+}
+
+- (NSString *)stringByEscapingHTMLAttributeValueUsingCharacters {
+  register unsigned i, len, j;
+  register unichar  *chars, *buf;
+  unsigned escapeCount;
+  
+  if ((len = [self length]) == 0) return @"";
+  
+  chars = malloc((len + 3) * sizeof(unichar));
+  [self getCharacters:chars];
+  
+  /* check for characters to escape ... */
+  for (i = 0, escapeCount = 0; i < len; i++) {
+    switch (chars[i]) {
+      case '&':
+      case '"':
+      case '<':
+      case '>':
+      case '\t':
+      case '\n':
+      case '\r':
+        escapeCount++;
+        break;
+      default:
+        if (chars[i] > 127)
+          escapeCount++;
+        break;
+    }
+  }
+  if (escapeCount == 0 ) {
+    /* nothing to escape ... */
+    if (chars) free(chars);
+    return [[self copy] autorelease];
+  }
+  
+  buf = calloc((len + 3) + (escapeCount * 8), sizeof(unichar));
+  for (i = 0, j = 0; i < len; i++) {
+    switch (chars[i]) {
+      /* escape special chars */
+      case '&':
+        buf[j] = '&'; j++; buf[j] = 'a'; j++; buf[j] = 'm'; j++;
+        buf[j] = 'p'; j++; buf[j] = ';'; j++;
+        break;
+      case '"':
+        buf[j] = '&'; j++; buf[j] = 'q'; j++; buf[j] = 'u'; j++;
+        buf[j] = 'o'; j++; buf[j] = 't'; j++; buf[j] = ';'; j++;
+        break;
+      case '<':
+        buf[j] = '&'; j++; buf[j] = 'l'; j++; buf[j] = 't'; j++;
+        buf[j] = ';'; j++;
+        break;
+      case '>':
+        buf[j] = '&'; j++; buf[j] = 'g'; j++; buf[j] = 't'; j++;
+        buf[j] = ';'; j++;
+        break;
+        
+      case '\t':
+        buf[j] = '&'; j++; buf[j] = '#'; j++; buf[j] = '9'; j++;
+        buf[j] = ';'; j++;
+        break;
+      case '\n':
+        buf[j] = '&'; j++; buf[j] = '#'; j++; buf[j] = '1'; j++;
+        buf[j] = '0'; j++; buf[j] = ';'; j++;
+        break;
+      case '\r':
+        buf[j] = '&'; j++; buf[j] = '#'; j++; buf[j] = '1'; j++;
+        buf[j] = '3'; j++; buf[j] = ';'; j++;
+        break;
+        
+      default:
+        /* escape big chars */
+        if (chars[i] > 127) {
+          unsigned char nbuf[16];
+          unsigned int k;
+          
+          sprintf(nbuf, "&#%i;", (int)chars[i]);
+          for (k = 0; nbuf[k] != '\0'; k++) {
+            buf[j] = nbuf[k];
+            j++;
+          }
+        }
+        else {
+          /* nothing to escape */
+          buf[j] = chars[i]; j++;
+        }
+        break;
+    }
+  }
+  
+  self = [NSString stringWithCharacters:buf length:j];
+  
+  if (chars) free(chars);
+  if (buf)   free(buf);
+  return self;
+}
+
+- (NSString *)stringByEscapingHTMLString {
+  return [self stringByEscapingHTMLStringUsingCharacters];
+}
+- (NSString *)stringByEscapingHTMLAttributeValue {
+  return [self stringByEscapingHTMLAttributeValueUsingCharacters];
+}
+
+@end /* NSString(HTMLEscaping) */
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSString+URLEscaping.m b/skyrix-core/NGExtensions/FdExt.subproj/NSString+URLEscaping.m
new file mode 100644 (file)
index 0000000..f6d30d7
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSString+misc.h"
+#include "common.h"
+
+@implementation NSString(URLEscaping)
+
+static int useUTF8Encoding = -1;
+
+static inline BOOL doUseUTF8Encoding(void) {
+  if (useUTF8Encoding == -1) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    
+    useUTF8Encoding = [ud boolForKey:@"NGUseUTF8AsURLEncoding"] ? 1 : 0;
+    if (useUTF8Encoding)
+      NSLog(@"Note: Using UTF-8 as URL encoding in NGExtensions.");
+  }
+  return useUTF8Encoding ? YES : NO;
+}
+
+static inline BOOL isUrlAlpha(unsigned char _c) {
+  return
+    (((_c >= 'a') && (_c <= 'z')) ||
+     ((_c >= 'A') && (_c <= 'Z')))
+    ? YES : NO;
+}
+static inline BOOL isUrlDigit(unsigned char _c) {
+  return ((_c >= '0') && (_c <= '9')) ? YES : NO;
+}
+static inline BOOL isUrlSafeChar(unsigned char _c) {
+  switch (_c) {
+    case '$': case '-': case '_': case '@':
+    case '.': case '&': case '+':
+      return YES;
+
+    default:
+      return NO;
+  }
+}
+static inline BOOL isUrlExtraChar(unsigned char _c) {
+  switch (_c) {
+    case '!': case '*': case '"': case '\'':
+    case '|': case ',':
+      return YES;
+  }
+  return NO;
+}
+static inline BOOL isUrlEscapeChar(unsigned char _c) {
+  return (_c == '%') ? YES : NO;
+}
+static inline BOOL isUrlReservedChar(unsigned char _c) {
+  switch (_c) {
+    case '=': case ';': case '/':
+    case '#': case '?': case ':':
+    case ' ':
+      return YES;
+  }
+  return NO;
+}
+
+static inline BOOL isUrlXalpha(unsigned char _c) {
+  if (isUrlAlpha(_c))      return YES;
+  if (isUrlDigit(_c))      return YES;
+  if (isUrlSafeChar(_c))   return YES;
+  if (isUrlExtraChar(_c))  return YES;
+  if (isUrlEscapeChar(_c)) return YES;
+  return NO;
+}
+
+static inline BOOL isUrlHexChar(unsigned char _c) {
+  if (isUrlDigit(_c))
+    return YES;
+  if ((_c >= 'a') && (_c <= 'f'))
+    return YES;
+  if ((_c >= 'A') && (_c <= 'F'))
+    return YES;
+  return NO;
+}
+
+static inline BOOL isUrlAlphaNum(unsigned char _c) {
+  return (isUrlAlpha(_c) || isUrlDigit(_c)) ? YES : NO;
+}
+
+static inline BOOL isToBeEscaped(unsigned char _c) {
+  return (isUrlAlphaNum(_c) || (_c == '_')) ? NO : YES;
+}
+
+static void
+NGEscapeUrlBuffer(const unsigned char *_source, unsigned char *_dest,
+                 unsigned srclen)
+{
+  register const unsigned char *src = (void*)_source;
+  register unsigned i;
+  for (i = 0; i < srclen; i++, src++) {
+#if 0 // explain!
+    if (*src == ' ') { // a ' ' becomes a '+'
+      *_dest = '+'; _dest++;
+    }
+#endif
+    if (!isToBeEscaped(*src)) {
+      *_dest = *src;
+      _dest++;
+    } 
+    else { // any other char is escaped ..
+      *_dest = '%'; _dest++;
+      sprintf(_dest, "%02X", (unsigned)*src);
+      _dest += 2;
+    }
+  }
+  *_dest = '\0';
+}
+
+static inline int _valueOfHexChar(register unichar _c) {
+  switch (_c) {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      return (_c - 48); // 0-9 (ascii-char)'0' - 48 => (int)0
+      
+    case 'A': case 'B': case 'C':
+    case 'D': case 'E': case 'F':
+      return (_c - 55); // A-F, A=10..F=15, 'A'=65..'F'=70
+      
+    case 'a': case 'b': case 'c':
+    case 'd': case 'e': case 'f':
+      return (_c - 87); // a-f, a=10..F=15, 'a'=97..'f'=102
+
+    default:
+      return -1;
+  }
+}
+static inline BOOL _isHexDigit(register unichar _c) {
+  switch (_c) {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+    case 'A': case 'B': case 'C':
+    case 'D': case 'E': case 'F':
+    case 'a': case 'b': case 'c':
+    case 'd': case 'e': case 'f':
+      return YES;
+
+    default:
+      return NO;
+  }
+}
+
+static void
+NGUnescapeUrlBuffer(const unsigned char *_source, unsigned char *_dest)
+{
+  BOOL done = NO;
+
+  while (!done && (*_source != '\0')) {
+    char c = *_source;
+
+    //if (c == '+') // '+' stands for a space
+    //  *_dest = ' ';
+    if (c == '%') {
+      _source++; c = *_source;
+      
+      if (c == '\0') {
+        *_dest = '%';
+        done = YES;
+      }
+      else if (_isHexDigit(c)) { // hex-escaped char, like '%F3'
+        int decChar = _valueOfHexChar(c);
+        _source++;
+        c = *_source;
+        decChar = decChar * 16 + _valueOfHexChar(c);
+        *_dest = (unsigned char)decChar;
+      }
+      else // escaped char, like '%%' -> '%'
+        *_dest = c;
+    }
+    else // char passed through
+      *_dest = c;
+
+    _dest++;
+    _source++;
+  }
+  *_dest = '\0';
+}
+
+- (BOOL)containsURLEscapeCharacters {
+  register unsigned i, len;
+  register unichar (*charAtIdx)(id,SEL,unsigned);
+  
+  if ((len = [self length]) == 0) return NO;
+  
+  charAtIdx = (void*)[self methodForSelector:@selector(characterAtIndex:)];
+  for (i = 0; i < len; i++) {
+    if (charAtIdx(self, @selector(characterAtIndex:), i) == '%')
+      return YES;
+  }
+  return NO;
+}
+- (BOOL)containsURLInvalidCharacters {
+  register unsigned i, len;
+  register unichar (*charAtIdx)(id,SEL,unsigned);
+  
+  if ((len = [self length]) == 0) return NO;
+  
+  charAtIdx = (void*)[self methodForSelector:@selector(characterAtIndex:)];
+  for (i = 0; i < len; i++) {
+    if (isToBeEscaped(charAtIdx(self, @selector(characterAtIndex:), i)))
+      return YES;
+  }
+  return NO;
+}
+
+- (NSString *)stringByUnescapingURL {
+  /* 
+     input is a URL string - per definition ASCII(?!), like "hello%98%88.txt"
+     output is a unicode string (never longer than the input)
+     
+     Note that the input itself is in some encoding! That is, the input is
+     turned into a buffer eg containing UTF-8 and needs to be converted into
+     a unicode string.
+  */
+  unsigned len;
+  char     *cstr;
+  char     *buffer = NULL;
+  NSString *s;
+  
+  if (![self containsURLEscapeCharacters]) /* scan for '%' */
+    return [[self copy] autorelease];
+  
+  if ((len = [self cStringLength]) == 0) return @"";
+  
+  cstr = malloc(len + 10);
+  [self getCString:cstr]; /* this is OK, a URL is always in ASCII! */
+  cstr[len] = '\0';
+  
+  buffer = malloc(len + 4);
+  NGUnescapeUrlBuffer(cstr, buffer);
+  
+  if (doUseUTF8Encoding()) {
+    /* OK, the input is considered UTF-8 encoded in a string */
+    s = [[NSString alloc] initWithUTF8String:buffer];
+    if (buffer) free(buffer);
+  }
+  else {
+    s = [[NSString alloc]
+         initWithCStringNoCopy:buffer
+         length:strlen(buffer)
+         freeWhenDone:YES];
+  }
+  if (cstr) free(cstr);
+  return [s autorelease];
+}
+
+- (NSString *)stringByEscapingURL {
+  unsigned len;
+  NSString *s;
+  char     *buffer = NULL;
+  
+  if ((len = [self length]) == 0) return @"";
+  
+  if (![self containsURLInvalidCharacters]) // needs to be escaped ?
+    return [[self copy] autorelease];
+  
+  if (doUseUTF8Encoding()) {
+    // steps:
+    // a) encode into a data buffer! (eg UTF8 or ISO)
+    // b) encode that buffer into URL encoding
+    // c) create an ASCII string from that
+    NSData *data;
+    
+    if ((data = [self dataUsingEncoding:NSUTF8StringEncoding]) == nil)
+      return nil;
+    if ((len = [data length]) == 0)
+      return @"";
+    
+    buffer = malloc(len * 3 + 2);
+    NGEscapeUrlBuffer([data bytes], buffer, len);
+  }
+  else {
+    unsigned char *cstr;
+    
+    len  = [self cStringLength];
+    cstr = malloc(len + 4);
+    [self getCString:cstr]; // Unicode!
+    cstr[len] = '\0';
+    
+    buffer = malloc(len * 3 + 2);
+    NGEscapeUrlBuffer(cstr, buffer, len);
+    if (cstr) free(cstr);
+  
+  }
+  /* the following assumes that the default-encoding is ASCII compatible */
+  s = [[NSString alloc]
+                initWithCStringNoCopy:buffer
+                length:strlen(buffer)
+                freeWhenDone:YES];
+  return [s autorelease];
+}
+
+@end /* NSString(URLEscaping) */
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSString+XMLEscaping.m b/skyrix-core/NGExtensions/FdExt.subproj/NSString+XMLEscaping.m
new file mode 100644 (file)
index 0000000..1e9fccf
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSString+misc.h"
+#include "common.h"
+
+@implementation NSString(XMLEscaping)
+
+- (NSString *)stringByEscapingXMLStringUsingCharacters {
+  register unsigned i, len, j;
+  register unichar  *chars, *buf;
+  unsigned escapeCount;
+  
+  if ((len = [self length]) == 0) return @"";
+  
+  chars = malloc((len + 3) * sizeof(unichar));
+  [self getCharacters:chars];
+  
+  /* check for characters to escape ... */
+  for (i = 0, escapeCount = 0; i < len; i++) {
+    switch (chars[i]) {
+      case '&': case '"': case '<': case '>':
+        escapeCount++;
+        break;
+      default:
+        if (chars[i] > 127)
+          escapeCount++;
+        break;
+    }
+  }
+  if (escapeCount == 0 ) {
+    /* nothing to escape ... */
+    if (chars) free(chars);
+    return [[self copy] autorelease];
+  }
+  
+  buf = malloc(((len + 3) * sizeof(unichar)) +
+              (escapeCount * 8 * sizeof(unichar)));
+  for (i = 0, j = 0; i < len; i++) {
+    switch (chars[i]) {
+      /* escape special chars */
+      case '&':
+        buf[j] = '&'; j++; buf[j] = 'a'; j++; buf[j] = 'm'; j++;
+        buf[j] = 'p'; j++; buf[j] = ';'; j++;
+        break;
+      case '"':
+        buf[j] = '&'; j++; buf[j] = 'q'; j++; buf[j] = 'u'; j++;
+        buf[j] = 'o'; j++; buf[j] = 't'; j++; buf[j] = ';'; j++;
+        break;
+      case '<':
+        buf[j] = '&'; j++; buf[j] = 'l'; j++; buf[j] = 't'; j++;
+        buf[j] = ';'; j++;
+        break;
+      case '>':
+        buf[j] = '&'; j++; buf[j] = 'g'; j++; buf[j] = 't'; j++;
+        buf[j] = ';'; j++;
+        break;
+        
+      default:
+        /* escape big chars */
+        if (chars[i] > 127) {
+          unsigned char nbuf[16];
+          unsigned int k;
+          
+          sprintf(nbuf, "&#%i;", (int)chars[i]);
+          for (k = 0; nbuf[k] != '\0'; k++) {
+            buf[j] = nbuf[k];
+            j++;
+          }
+        }
+        else {
+          /* nothing to escape */
+          buf[j] = chars[i];
+          j++;
+        }
+        break;
+    }
+  }
+  
+  self = [NSString stringWithCharacters:buf length:j];
+  
+  if (chars) free(chars);
+  if (buf)   free(buf);
+  return self;
+}
+
+- (NSString *)stringByEscapingXMLString {
+  return [self stringByEscapingXMLStringUsingCharacters];
+}
+
+- (NSString *)stringByEscapingXMLAttributeValue {
+  return [self stringByEscapingHTMLAttributeValue];
+}
+
+/* XML FQNs */
+
+- (BOOL)xmlIsFQN {
+  if ([self length] == 0) return NO;
+  return [self characterAtIndex:0] == '{' ? YES : NO;
+}
+
+- (NSString *)xmlNamespaceURI {
+  NSRange r;
+  
+  r = [self rangeOfString:@"}" options:(NSLiteralSearch | NSBackwardsSearch)];
+  if (r.length == 0) return nil;
+  if ([self characterAtIndex:0] != '{') return nil;
+  
+  r.length   = (r.location - 1);
+  r.location = 1;
+  return [self substringWithRange:r];
+}
+
+- (NSString *)xmlLocalName {
+  NSRange r;
+  
+  r = [self rangeOfString:@"}" options:(NSLiteralSearch | NSBackwardsSearch)];
+  if (r.length == 0) return nil;
+  if ([self characterAtIndex:0] != '{') return nil;
+  
+  return [self substringFromIndex:(r.location + r.length)];
+}
+
+@end /* NSString(XMLEscaping) */
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSString+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSString+misc.m
new file mode 100644 (file)
index 0000000..0954939
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSString+misc.h"
+#include "common.h"
+
+@interface NSStringVariableBindingException : NSException
+@end
+
+@implementation NSStringVariableBindingException
+@end
+
+@implementation NSObject(StringBindings)
+
+- (NSString *)valueForStringBinding:(NSString *)_key {
+  if (_key == nil) return nil;
+  return [[self valueForKey:_key] stringValue];
+}
+
+@end /* NSObject(StringBindings) */
+
+@implementation NSDictionary(StringBindings)
+
+- (NSString *)valueForStringBinding:(NSString *)_key {
+  if (_key == nil) return nil;
+  return [[self objectForKey:_key] stringValue];
+}
+
+@end /* NSDictionary(StringBindings) */
+
+@implementation NSString(misc)
+
+- (NSString *)stringByApplyingCEscaping {
+  // Unicode!
+  const char   *cstr;
+  char         *buffer;
+  register int pos = 0;
+  
+  cstr = [self cString];
+  buffer = malloc([self cStringLength] * 2 + 1);
+    
+  while (*cstr) {
+    switch (*cstr) {
+      case '\n':
+        buffer[pos] = '\\'; pos++;
+        buffer[pos] = 'n';
+        break;
+      case '\r':
+        buffer[pos] = '\\'; pos++;
+        buffer[pos] = 'r';
+        break;
+      case '\t':
+        buffer[pos] = '\\'; pos++;
+        buffer[pos] = 't';
+        break;
+
+      default:
+        buffer[pos] = *cstr;
+        break;
+    }
+    cstr++;
+    pos++;
+  }
+  buffer[pos] = '\0';
+  
+#if NeXT_Foundation_LIBRARY || GNUSTEP_BASE_LIBRARY
+  {
+    NSString *s;
+    
+    s = buffer ? [NSString stringWithCString:buffer] : nil;
+    if (buffer) free(buffer);
+    return s;
+  }
+#else
+  return [NSString stringWithCStringNoCopy:buffer freeWhenDone:YES];
+#endif
+}
+- (NSSet *)bindingVariables
+{
+  unsigned        len, pos = 0;
+  const char      *buf     = NULL;
+  NSMutableSet    *result  = nil;
+
+  result = [NSMutableSet set];
+  len    = [self cStringLength];  
+  buf    = [self cString];
+  
+  while (pos < len) {
+    unsigned startPos;
+    
+    if (pos + 1 == len) { /* last entry */
+      if (buf[pos] == '$') { /* found $ without end-char */
+        [[[NSStringVariableBindingException alloc]
+          initWithFormat:@"did not find end of variable for string %@", self]
+          raise];
+      }
+      break;
+    }
+    if (buf[pos] != '$') {
+      pos++;
+      continue;
+    }
+    
+    if (buf[pos + 1] == '$') { /* found $$ --> ignore*/
+      pos += 2;
+      continue;
+    }
+
+    /* process binding */
+    
+    startPos = pos;
+    
+    pos += 2; /* buf[pos + 1] != '$' */
+    while (pos < len) {
+      if (buf[pos] != '$')
+       pos++;
+      else
+       break;
+    }
+    if (pos == len) { /* end of string was reached */
+      [[[NSStringVariableBindingException alloc]
+                                          initWithFormat:@"didn`t find end of "
+                                            @"variable for string %@", self]
+                                          raise];
+    }
+    else {
+      NSString *key   = nil;
+
+      key = [[NSString alloc]
+                       initWithCStringNoCopy:(char*)buf + startPos + 1
+                       length:pos - startPos - 1
+                       freeWhenDone:NO];
+      [result addObject:key];
+      [key release];
+    }
+    pos++;
+  }
+  return [[result copy] autorelease];
+}
+
+- (NSString *)stringByReplacingVariablesWithBindings:(id)_bindings
+  stringForUnknownBindings:(NSString *)_unknown
+{
+  unsigned        len, pos = 0;
+  const char      *buf     = NULL;
+  NSMutableString *str     = nil;
+  
+  str = [self mutableCopy];
+  len = [str cStringLength];  
+  buf = [str cString];
+  
+  while (pos < len) {
+    if (pos + 1 == len) { /* last entry */
+      if (buf[pos] == '$') { /* found $ without end-char */
+        [[[NSStringVariableBindingException alloc]
+          initWithFormat:@"did not find end of variable for string %@", self]
+         raise];
+      }
+      break;
+    }
+    if (buf[pos] == '$') {
+      if (buf[pos + 1] == '$') { /* found $$ --> $ */
+        [str deleteCharactersInRange:NSMakeRange(pos, 1)];
+        buf = [str cString];
+        len = [str cStringLength];
+      }
+      else {
+        unsigned startPos = pos;
+
+        pos += 2; /* buf[pos + 1] != '$' */
+        while (pos < len) {
+          if (buf[pos] != '$')
+            pos++;
+          else
+            break;
+        }
+        if (pos == len) { /* end of string was reached */
+          [[[NSStringVariableBindingException alloc]
+            initWithFormat:@"did not find end of variable for string %@", 
+            self] raise];
+       }
+        else {
+          NSString *key;
+          NSString *value;
+
+          key = [[NSString alloc]
+                           initWithCStringNoCopy:(char*)buf + startPos + 1
+                           length:pos - startPos - 1
+                           freeWhenDone:NO];
+         
+          if ((value = [_bindings valueForStringBinding:key]) == nil) {
+            if (_unknown == nil) {
+              [[[NSStringVariableBindingException alloc]
+                          initWithFormat:@"did not find binding for "
+                                         @"name %@ in binding-dictionary %@",
+                                         [key autorelease], _bindings] raise];
+            }
+            else
+              value = _unknown;
+          }
+          [key release]; key = nil;
+          [str replaceCharactersInRange:
+                NSMakeRange(startPos, pos - startPos + 1)
+               withString:value];
+          buf = [str cString];
+          len = [str cStringLength];
+          pos = startPos - 1 + [value length];
+        }
+      }
+    }
+    pos++;
+  }
+  {
+    id tmp = str;
+    str = [str copy];
+    [tmp release]; tmp = nil;
+  }
+  return [str autorelease];
+}
+
+- (NSString *)stringByReplacingVariablesWithBindings:(id)_bindings {
+  return [self stringByReplacingVariablesWithBindings:_bindings
+               stringForUnknownBindings:nil];
+}
+
+@end /* NSString(misc) */
+
+
+@implementation NSString(FilePathVersioningMethods)
+
+/*
+  "/path/file.txt;1"
+*/
+- (NSString *)pathVersion {
+  NSRange r;
+
+  r = [self rangeOfString:@";"];
+  if (r.length > 0) {
+    return ([self length] > r.location)
+      ? [self substringFromIndex:(r.location + r.length)]
+      : @"";
+  }
+  return nil;
+}
+
+- (NSString *)stringByDeletingPathVersion {
+  NSRange r;
+
+  r = [self rangeOfString:@";"];
+  return (r.length > 0)
+    ? [self substringToIndex:r.location]
+    : self;
+}
+
+- (NSString *)stringByAppendingPathVersion:(NSString *)_version {
+  return [[self stringByAppendingString:@";"] 
+               stringByAppendingString:_version];
+}
+
+@end /* NSString(FilePathMethodsVersioning) */
+
+@implementation NSString(NGScanning)
+
+- (NSRange)rangeOfString:(NSString *)_s 
+  skipQuotes:(NSString *)_quotes
+  escapedByChar:(unichar)_escape
+{
+  // TODO: speed ...
+  // TODO: check correctness with invalid input !
+  static NSRange notFound = { 0, 0 };
+  NSCharacterSet *quotes;
+  unsigned i, len, slen;
+  unichar sc;
+  
+  if ((slen = [_s length]) == 0)
+    return notFound;
+  if ((len = [self length]) < slen) /* to short */
+    return notFound;
+  
+  if ([_quotes length] == 0)
+    _quotes = @"'\"";
+  quotes = [NSCharacterSet characterSetWithCharactersInString:_quotes];
+  
+  sc = [_s characterAtIndex:0];
+  
+  for (i = 0; i < len; i++) {
+    unichar c;
+    
+    c = [self characterAtIndex:i];
+    
+    if (c == sc) {
+      /* start search section */
+      if (slen == 1)
+        return NSMakeRange(i, 1);
+      
+      if ([[self substringFromIndex:i] hasPrefix:_s])
+        return NSMakeRange(i, slen);
+    }
+    else if ([quotes characterIsMember:c]) {
+      /* skip quotes */
+      for (i++; i < len && ![quotes characterIsMember:c]; i++) {
+        if (c == _escape) {
+          i++; /* skip next char (eg \') */
+          continue;
+        }
+      }
+    }
+  }
+  
+  return notFound;
+}
+
+- (NSRange)rangeOfString:(NSString *)_s skipQuotes:(NSString *)_quotes {
+  return [self rangeOfString:_s skipQuotes:_quotes escapedByChar:'\\'];
+}
+
+@end /* NSString(NGScanning) */
+
+// linking
+
+void __link_NSString_misc(void) {
+  __link_NSString_misc();
+}
diff --git a/skyrix-core/NGExtensions/FdExt.subproj/NSURL+misc.m b/skyrix-core/NGExtensions/FdExt.subproj/NSURL+misc.m
new file mode 100644 (file)
index 0000000..fca96e8
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSURL+misc.h"
+#include "common.h"
+
+static BOOL debugURLProcessing = NO;
+
+@implementation NSURL(misc)
+
+- (NSString *)pathWithCorrectTrailingSlash {
+#if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+  /*
+    At least on OSX 10.3 the -path method missing the trailing slash, eg:
+      http://localhost:20000/dbd.woa/so/localhost/
+    gives:
+      /dbd.woa/so/localhost
+  */
+  NSString *p;
+  
+  if ((p = [self path]) == nil)
+    return nil;
+  
+  if ([p hasSuffix:@"/"])
+    return p;
+
+  if (![[self absoluteString] hasSuffix:@"/"])
+    return p;
+  
+  /* so we are running into the bug ... */
+  return [p stringByAppendingString:@"/"];
+#else
+  return [self path];
+#endif
+}
+
+- (NSString *)stringByAddingFragmentAndQueryToPath:(NSString *)_path {
+  NSString *lFrag, *lQuery;
+  
+  if ([self isFileURL])
+    return _path;
+  
+  lFrag   = [self fragment];
+  lQuery  = [self query];
+  
+  if ((lFrag != nil) || (lQuery != nil)) {
+    NSMutableString *ms;
+    
+    ms = [NSMutableString stringWithCapacity:([_path length] + 32)];
+    
+    [ms appendString:_path];
+    
+    if (lFrag) {
+      [ms appendString:@"#"];
+      [ms appendString:lFrag];
+    }
+    if (lQuery) {
+      [ms appendString:@"?"];
+      [ms appendString:lQuery];
+    }
+    return ms;
+  }
+  else
+    return _path;
+}
+
+- (NSString *)stringValueRelativeToURL:(NSURL *)_base {
+  /*
+    Sample:
+      base: http://localhost:20000/dbd.woa/so/localhost/
+      self: http://localhost:20000/dbd.woa/so/localhost/Databases/A
+         => Databases/A
+    
+    Note: on Panther Foundation the -path misses the trailing slash!
+  */
+  NSString *relPath;
+  
+  if (_base == self || _base == nil) {
+    relPath = [[self pathWithCorrectTrailingSlash] urlPathRelativeToSelf];
+    relPath = [self stringByAddingFragmentAndQueryToPath:relPath];
+    if (debugURLProcessing) {
+      NSLog(@"%s: no base or base is self => '%@'", 
+           __PRETTY_FUNCTION__, relPath);
+    }
+    return relPath;
+  }
+  
+  /* check whether we are already marked relative to _base .. */
+  if ([self baseURL] == _base) {
+    NSString *p;
+    
+    p = [self relativePath];
+#if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+    /* see -pathWithCorrectTrailingSlash for bug description ... */
+    if (![p hasSuffix:@"/"]) {
+      if ([[self absoluteString] hasSuffix:@"/"])
+       p = [p stringByAppendingString:@"/"];
+    }
+#endif
+    p = [self stringByAddingFragmentAndQueryToPath:p];
+    if (debugURLProcessing) {
+      NSLog(@"%s: url base and _base match => '%@'", 
+           __PRETTY_FUNCTION__, p);
+    }
+    return p;
+  }
+  
+  /* check whether we are in the same path namespace ... */
+  if (![self isInSameNamespaceWithURL:_base]) {
+    /* need to return full URL */
+    relPath = [self absoluteString];
+    if (debugURLProcessing) {
+      NSLog(@"%s: url is in different namespace from base => '%@'", 
+           __PRETTY_FUNCTION__, relPath);
+    }
+    return relPath;
+  }
+  
+  relPath = [[self pathWithCorrectTrailingSlash] 
+                   urlPathRelativeToPath:[_base pathWithCorrectTrailingSlash]];
+  if (debugURLProcessing) {
+    NSLog(@"%s: path '%@', base-path '%@' => rel '%@'", __PRETTY_FUNCTION__,
+         [self path], [_base path], relPath);
+  }
+  relPath = [self stringByAddingFragmentAndQueryToPath:relPath];
+  
+  if (debugURLProcessing) {
+    NSLog(@"%s: same namespace, but no direct relative (%@, base %@) => '%@'", 
+         __PRETTY_FUNCTION__, self, _base, relPath);
+  }
+  return relPath;
+}
+
+static BOOL isEqual(id o1, id o2) {
+  if (o1 == o2) return YES;
+  if (o1 == nil || o2 == nil) return NO;
+  return [o1 isEqual:o2];
+}
+
+- (BOOL)isInSameNamespaceWithURL:(NSURL *)_url {
+  if (_url == nil)  return NO;
+  if (_url == self) return YES;
+  if ([self isFileURL] && [_url isFileURL]) return YES;
+  if ([self baseURL] == _url) return YES;
+  if ([_url baseURL] == self) return YES;
+  
+  if (![[self scheme] isEqualToString:[_url scheme]])
+    return NO;
+  
+  if (!isEqual([self host], [_url host]))
+    return NO;
+  if (!isEqual([self port], [_url port]))
+    return NO;
+  if (!isEqual([self user], [_url user]))
+    return NO;
+  
+  return YES;
+}
+
+@end /* NSURL */
+
+@implementation NSString(URLPathProcessing)
+
+- (NSString *)urlPathRelativeToSelf {
+  /*
+    eg:                "/a/b/c.html"
+    should resolve to: "c.html"
+    
+    Directories are a bit more difficult, eg:
+      "/a/b/c/"
+    is resolved to
+      "../c/"
+  */
+  NSString *p;
+  NSString *lp;
+  
+  p  = self;
+  lp = [p lastPathComponent];
+  
+  p = ([p hasSuffix:@"/"])
+    ? [NSString stringWithFormat:@"../%@/", p]
+    : lp;
+  return p;
+}
+
+- (NSString *)urlPathRelativeToRoot {
+  NSString *p;
+  
+  p = self;
+  
+  if ([p isEqualToString:@"/"])
+    /* don't know better ... what is root-relative-to-root ? */
+    return @"/";
+  
+  if ([p length] == 0) {
+    NSLog(@"%s: invalid path (length 0), using /: %@",
+          __PRETTY_FUNCTION__, self);
+    return @"/";
+  }
+  
+  /* this is the same like the absoltute path, only without a leading "/" .. */
+  return [p substringFromIndex:1];
+}
+
+- (NSString *)urlPathRelativeToPath:(NSString *)_base {
+  /*
+    This can be used for URLs in the same namespace. It should
+    never return an absolute path (it only does in error conditions).
+  */
+  
+  if (_base == nil || [_base length] == 0) {
+    NSLog(@"%s: invalid base (nil or length 0), using absolute path '%@' ...",
+          __PRETTY_FUNCTION__, self);
+    return self;
+  }
+  
+  if ([_base isEqualToString:@"/"])
+    return [self urlPathRelativeToRoot];
+  if ([_base isEqualToString:self])
+    return [self urlPathRelativeToSelf];
+  
+  if (debugURLProcessing)
+    NSLog(@"%s: %@ relative to %@ ...", __PRETTY_FUNCTION__, self, _base);
+  
+  if ([self hasPrefix:_base]) {
+    /*
+      the whole base URI is prefix of our URI:
+        case a)
+          b: "/a/b/c"
+          s: "/a/b/c/d"
+          >: "c/d"
+        case b)
+          b: "/a/b/c/"
+          s: "/a/b/c/d"
+          >: "d"
+        case c)
+          b: "/a/b/c"
+          s: "/a/b/ccc/d"
+          >: "ccc/d"
+        
+      b=s is already catched above and s is guaranteed to be
+      longer than b.
+    */
+    unsigned blen;
+    NSString *result;
+    
+    if (debugURLProcessing)
+      NSLog(@"%s:   has base as prefix ...", __PRETTY_FUNCTION__);
+    blen = [_base length];
+    
+    if ([_base characterAtIndex:(blen - 1)] == '/') {
+      /* last char of 'b' is '/' => case b) */
+      result = [self substringFromIndex:blen];
+    }
+    else {
+      /*
+        last char of 'b' is not a slash (either case a) or case c)),
+        both are handled in the same way (search last / ...)
+      */
+      NSRange  r;
+        
+      r = [_base rangeOfString:@"/" options:NSBackwardsSearch];
+      if (r.length == 0) {
+        NSLog(@"%s: invalid base, found no '/': '%@' !",
+              __PRETTY_FUNCTION__, _base);
+        result = self;
+      }
+      else {
+        /* no we have case b) ... */
+        result = [self substringFromIndex:(r.location + 1)];
+      }
+    }
+    return result;
+  }
+  else {
+    NSString *prefix;
+    unsigned plen;
+    
+    prefix = [self commonPrefixWithString:_base options:0];
+    plen = [prefix length];
+    
+    if (plen == 0) {
+      NSLog(@"%s: invalid strings, no common prefix ...: '%@' and '%@' !",
+              __PRETTY_FUNCTION__, self, _base);
+      return self;
+    }
+    
+    if (plen == 1) {
+      /*
+        common prefix is root. That is, nothing in common:
+          b: "/a/b"
+          s: "/l"
+          >: "../l"
+          
+          b: "/a/b/"
+          s: "/l"
+          >: "../../l"
+      */
+      
+      if ([prefix characterAtIndex:0] != '/') {
+        NSLog(@"%s: invalid strings, common prefix '%@' is not '/': "
+              @"'%@' and '%@' !",
+              __PRETTY_FUNCTION__, self, _base, prefix);
+      }
+      
+      /* TODO: to be completed ... */
+      return self;
+    }
+    
+    /* TODO: to be completed ... */
+  }
+  
+  return self;
+}
+
+@end /* NSString(URLPathProcessing) */
diff --git a/skyrix-core/NGExtensions/FileObjectHolder.m b/skyrix-core/NGExtensions/FileObjectHolder.m
new file mode 100644 (file)
index 0000000..46056ff
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+// Created by Helge Hess on Wed Apr 17 2002.
+
+#include "FileObjectHolder.h"
+#include "NSRunLoop+FileObjects.h"
+#import <Foundation/NSException.h>
+#import <Foundation/NSNotification.h>
+#import <Foundation/NSFileHandle.h>
+#include "common.h"
+
+@implementation FileObjectHolder
+
+- (id)initWithFileObject:(id)_object
+  activities:(int)_activities
+  mode:(NSString *)_mode 
+{
+  if (_object == nil) {
+    [self release];
+    return nil;
+  }
+  self->fileObject = [_object retain];
+  self->fd         = [_object fileDescriptor];
+  self->activities = _activities;
+  self->mode       = [_mode copy];
+  self->fileHandle =
+    [[NSFileHandle alloc] initWithFileDescriptor:self->fd closeOnDealloc:NO];
+  NSAssert(self->fileHandle, @"couldn't create filehandle ...");
+
+  [[self notificationCenter]
+         addObserver:self selector:@selector(_dataAvailable:)
+         name:NSFileHandleDataAvailableNotification 
+         object:self->fileHandle];
+  [[self notificationCenter]
+         addObserver:self selector:@selector(_acceptAvailable:)
+         name:NSFileHandleConnectionAcceptedNotification
+         object:self->fileHandle];
+  
+  return self;
+}
+
+- (void)dealloc {
+  if (self->waitActive)
+    [[self notificationCenter] removeObserver:self];
+  [self->mode       release];
+  [self->fileHandle release];
+  [self->fileObject release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (int)fileDescriptor {
+  return self->fd;
+}
+- (NSFileHandle *)fileHandle {
+  return self->fileHandle;
+}
+- (id)fileObject {
+  return self->fileObject;
+}
+- (int)activities {
+  return self->activities;
+}
+- (NSString *)mode {
+  return self->mode;
+}
+
+- (NSArray *)modes {
+  return [NSArray arrayWithObject:[self mode]];
+}
+
+/* notifications */
+
+- (NSNotificationCenter *)notificationCenter {
+  return [NSNotificationCenter defaultCenter];
+}
+
+- (void)handleException:(NSException *)_exception {
+  NSLog(@"%s: catched: %@", __PRETTY_FUNCTION__, _exception);
+}
+
+- (void)_dataAvailable:(NSNotification *)_notification {
+  if ([_notification object] != self->fileHandle) {
+    NSLog(@"%s: notification object %@ does not match file handle %@",
+          __PRETTY_FUNCTION__, [_notification object], self->fileHandle);
+    return;
+  }
+  
+  if (![self->fileObject isOpen]) {
+    //NSLog(@"file object is closed ...");
+    return;
+  }
+  
+  NS_DURING {
+    self->waitActive = NO;
+    [self wait];
+    [[self notificationCenter]
+           postNotificationName:NSFileObjectBecameActiveNotificationName
+           object:self->fileObject];
+  }
+  NS_HANDLER
+    [self handleException:localException];
+  NS_ENDHANDLER;
+}
+
+- (void)_acceptAvailable:(NSNotification *)_notification {
+  NSLog(@"accept available ...");
+  if ([_notification object] != self->fileHandle) {
+    NSLog(@"%s: notification object %@ does not match file handle %@",
+          __PRETTY_FUNCTION__, [_notification object], self->fileHandle);
+    return;
+  }
+  [[self notificationCenter]
+         postNotificationName:NSFileObjectBecameActiveNotificationName
+         object:self->fileObject];
+}
+
+/* operations */
+
+- (void)wait {
+  if (self->waitActive) return;
+  
+  if (![self->fileObject isOpen]) return;
+  
+  self->waitActive = YES;
+  
+#if 0
+  /* use accept for passive fileobjects ?, wait seems to work too ... :-) */
+  if ([self->fileObject isPassive]) {
+    NSLog(@"add passive %@ ..", self->fileObject);
+// => this also accepts the connection :-(
+    [self->fileHandle acceptConnectionInBackgroundAndNotifyForModes:
+                        [self modes]];
+  }
+  else
+#endif
+    [self->fileHandle waitForDataInBackgroundAndNotifyForModes:[self modes]];
+}
+- (void)stopWaiting {
+}
+
+/* equality */
+
+- (BOOL)isEqualToFileObjectHolder:(FileObjectHolder *)_other {
+  if (self->fd != _other->fd) return NO;
+  if (![self->mode isEqualToString:_other->mode]) return NO;
+  if (![self->fileObject isEqual:_other->fileObject]) return NO;
+  return YES;
+}
+- (BOOL)isEqual:(id)_other {
+  if (_other == self) return YES;
+  if (_other == nil)  return NO;
+  if ([_other class] != [self class]) return NO;
+  return [self isEqualToFileObjectHolder:_other];
+}
+
+/* description */
+
+@end /* FileObject */
diff --git a/skyrix-core/NGExtensions/GNUmakefile b/skyrix-core/NGExtensions/GNUmakefile
new file mode 100644 (file)
index 0000000..beb6bb5
--- /dev/null
@@ -0,0 +1,134 @@
+#
+#   GNUmakefile
+#
+# $Id$
+
+include ../common.make
+
+LIBRARY_NAME = libNGExtensions
+
+libNGExtensions_DLL_DEF = libNGExtensions.def
+libNGExtensions_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libNGExtensions_HEADER_FILES_DIR        = ./NGExtensions
+libNGExtensions_HEADER_FILES_INSTALL_DIR = /NGExtensions
+
+libNGExtensions_HEADER_FILES = \
+       NGExtensionsDecls.h                     \
+       NGExtensions.h                          \
+       AutoDefines.h                           \
+       IndexFunc.h                             \
+       NGBase64Coding.h                        \
+       NGBaseTypes.h                           \
+       NGBitSet.h                              \
+       NGBundleManager.h                       \
+       NGCharBuffers.h                         \
+       NGCustomFileManager.h                   \
+       NGDirectoryEnumerator.h                 \
+       NGFileFolderInfoDataSource.h            \
+       NGFileManager.h                         \
+       NGFileManagerURL.h                      \
+       NGHashMap.h                             \
+       NGMemoryAllocation.h                    \
+       NGMerging.h                             \
+       NGObjCRuntime.h                         \
+       NGQuotedPrintableCoding.h               \
+       NGStack.h                               \
+       NGObjectMacros.h                        \
+       NGCalendarDateRange.h                   \
+
+libNGExtensions_OBJC_FILES = \
+       NGExtensions.m                          \
+       NGBase64Coding.m                        \
+       NGBitSet.m                              \
+       NGBundleManager.m                       \
+       NGCustomFileManager.m                   \
+       NGDirectoryEnumerator.m                 \
+       NGFileFolderInfoDataSource.m            \
+       NGFileManager.m                         \
+       NGFileManager+JS.m                      \
+       NGFileManagerURL.m                      \
+       NGHashMap.m                             \
+       NGMerging.m                             \
+       NGObjCRuntime.m                         \
+       NGQuotedPrintableCoding.m               \
+       NGStack.m                               \
+       NGCalendarDateRange.m                   \
+
+ifeq ($(FOUNDATION_LIB), apple)
+libNGExtensions_OBJC_FILES += FileObjectHolder.m
+endif
+
+libNGExtensions_SUBPROJECTS = \
+       FdExt.subproj           \
+       EOExt.subproj           \
+       XmlExt.subproj          \
+       NGRuleEngine.subproj    \
+
+EOExt_HEADER_FILES = \
+       EOCacheDataSource.h             \
+       EOCompoundDataSource.h          \
+       EODataSource+NGExtensions.h     \
+       EOFilterDataSource.h            \
+       EOGrouping.h                    \
+       EOGroupingSet.h                 \
+       EOKeyGrouping.h                 \
+       EOKeyMapDataSource.h            \
+       EOQualifier+CtxEval.h           \
+       EOQualifierGrouping.h           \
+       EOTrueQualifier.h               \
+       EOQualifier+plist.h             \
+       EOSortOrdering+plist.h          \
+       EOFetchSpecification+plist.h    \
+
+FdExt_HEADER_FILES = \
+       NSArray+enumerator.h            \
+       NSAutoreleasePool+misc.h        \
+       NSCalendarDate+misc.h           \
+       NSData+gzip.h                   \
+       NSData+misc.h                   \
+       NSDictionary+misc.h             \
+       NSEnumerator+misc.h             \
+       NSException+misc.h              \
+       NSFileManager+Extensions.h      \
+       NSMethodSignature+misc.h        \
+       NSNull+misc.h                   \
+       NSObject+Logs.h                 \
+       NSObject+Values.h               \
+       NSProcessInfo+misc.h            \
+       NSRunLoop+FileObjects.h         \
+       NSSet+enumerator.h              \
+       NSString+Ext.h                  \
+       NSString+German.h               \
+       NSString+Formatting.h           \
+       NSString+Encoding.h             \
+       NSString+misc.h                 \
+       NSURL+misc.h                    \
+       NGPropertyListParser.h          \
+
+XmlExt_HEADER_FILES = \
+       DOMNode+EOQualifier.h
+
+NGRuleEngine_HEADER_FILES = \
+       NGRuleEngine.h          \
+       NGRule.h                \
+       NGRuleAssignment.h      \
+       NGRuleContext.h         \
+       NGRuleModel.h           \
+
+libNGExtensions_HEADER_FILES += \
+       $(FdExt_HEADER_FILES)   \
+       $(EOExt_HEADER_FILES)   \
+       $(XmlExt_HEADER_FILES)  \
+       $(NGRuleEngine_HEADER_FILES)
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I./NGExtensions/       \
+       -I./FdExt.subproj/ -I./EOExt.subproj/
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+-include GNUmakefile.postamble
+
+autodoc :
+       autodoc $(AUTODOC_FLAGS) -dest ../Documentation/NGExtensions/ -proj .
diff --git a/skyrix-core/NGExtensions/GNUmakefile.preamble b/skyrix-core/NGExtensions/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..a76cdf5
--- /dev/null
@@ -0,0 +1,50 @@
+# $Id$
+
+ADDITIONAL_CPP_FLAGS     += -Wall -Wno-import -Wno-protocol -O2
+libNGExtensions_INCLUDE_DIRS += -I..
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+libNGExtensions_LIB_DIRS += \
+       -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)
+else
+libNGExtensions_LIB_DIRS += \
+       -L../EOControl/$(GNUSTEP_OBJ_DIR) \
+       -L../../skyrix-xml/DOM/$(GNUSTEP_OBJ_DIR)
+endif
+
+libNGExtensions_LIBRARIES_DEPEND_UPON += -lEOControl -lDOM -lSaxObjC -lz
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libNGExtensions_PREBIND_ADDR="0xC1200000"
+libNGExtensions_LDFLAGS += -seg1addr $(libNGExtensions_PREBIND_ADDR)
+endif
+
+# platform specific settings
+
+ifeq ($(GNUSTEP_TARGET_OS),mingw32)
+libNGExtensions_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+libNGExtensions_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
+
+ifeq ($(GNUSTEP_HOST_OS),rhapsody5.5)
+#libNGExtensions_LIBRARIES_DEPEND_UPON += -lFoundationExt
+endif
+
+ifeq ($(GNUSTEP_TARGET_OS),freebsd)
+libNGExtensions_LIB_DIRS += -L/usr/local/lib
+libNGExtensions_LIBRARIES_DEPEND_UPON += -liconv
+endif
+
+# Foundation specific settings
+
+ifeq ($(FOUNDATION_LIB),nx)
+ADDITIONAL_LDFLAGS += -framework Foundation
+endif
diff --git a/skyrix-core/NGExtensions/NGBase64Coding.m b/skyrix-core/NGExtensions/NGBase64Coding.m
new file mode 100644 (file)
index 0000000..37f0f3d
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGBase64Coding.h"
+#include "common.h"
+#import <Foundation/NSString.h>
+#import <Foundation/NSException.h>
+
+static inline BOOL isbase64(char a) {
+  if (('A' <= a) && (a <= 'Z'))
+    return YES;
+  if (('a' <= a) && (a <= 'z'))
+    return YES;
+  if (('0' <= a) && (a <= '9'))
+    return YES;
+  if ((a == '+') || (a == '/'))
+    return YES;
+  return NO;
+}
+
+static inline int encode_base64(const char *_src, size_t _srcLen, char *_dest,
+                                size_t _destSize, size_t *_destLen,
+                                int _maxLineWidth);
+static inline int decode_base64(const char *_src, size_t _srcLen, char *_dest,
+                                size_t _destSize, size_t *_destLen);
+
+@implementation NSString(Base64Coding)
+
+static Class StringClass = Nil;
+static int NSStringMaxLineWidth = 1024;
+  
+- (NSString *)stringByEncodingBase64 {
+  unsigned len;
+  size_t destSize;
+  size_t destLength = -1;
+  char   *dest, *src;
+  
+  if ((len = [self cStringLength]) == 0)
+    return @"";
+  
+  destSize = (len + 2) / 3 * 4; // 3:4 conversion ratio
+  destSize += destSize / NSStringMaxLineWidth + 2; // space for newlines and '\0'
+  destSize += 64;
+  dest = malloc(destSize + 4);
+  if (dest == NULL) return nil;
+
+  NSAssert(destSize > 0, @"invalid buffer size ..");
+  NSAssert(dest,         @"invalid buffer ..");
+
+  src = malloc(len + 4);
+  [self getCString:src];
+  src[len] = '\0';
+  
+  if (encode_base64(src, len,
+                    dest, destSize, &destLength, NSStringMaxLineWidth) == 0) {
+    if (src) free(src);
+    return [[[NSString alloc]
+                       initWithCStringNoCopy:dest
+                       length:destLength
+                       freeWhenDone:YES] autorelease];
+  }
+
+  if (src) free(src);
+  if (dest) free((void *)dest); dest = NULL;
+  return nil;
+}
+
+- (NSString *)stringByDecodingBase64 {
+  unsigned len;
+  size_t destSize;
+  size_t destLength = -1;
+  char   *dest, *src;
+
+  if (StringClass == Nil) StringClass = [NSString class];
+  
+  if ((len = [self cStringLength]) == 0)
+    return @"";
+  
+  destSize = (len / 4 + 1) * 3 + 1;
+  dest = malloc(destSize + 1);
+
+  NSAssert(destSize > 0, @"invalid buffer size ..");
+  NSAssert(dest,         @"invalid buffer ..");
+
+  src = malloc(len + 4);
+  [self getCString:src];
+  src[len] = '\0';
+  
+  if (decode_base64(src, len, dest, destSize, &destLength) == 0) {
+    if (src) free(src);
+    
+    if (*dest == '\0' && destLength > 0) {
+      NSLog(@"ERROR(%s): could not decode %@ as string (contains \\0 bytes)!", 
+            __PRETTY_FUNCTION__, self);
+      abort();
+      if (dest) free(dest);
+      return nil;
+    }
+    
+    return [[[StringClass alloc]
+              initWithCStringNoCopy:dest
+              length:destLength
+              freeWhenDone:YES] autorelease];
+  }
+  else {
+    if (src) free(src);
+    if (dest) free(dest);
+    return nil;
+  }
+}
+
+- (NSData *)dataByDecodingBase64 {
+  unsigned len;
+  size_t destSize;
+  size_t destLength = -1;
+  char   *dest, *src;
+
+  if (StringClass == Nil) StringClass = [NSString class];
+  
+  if ((len = [self cStringLength]) == 0)
+    return [NSData data];
+  
+  destSize = (len / 4 + 1) * 3 + 1;
+  dest = malloc(destSize + 1);
+
+  NSAssert(destSize > 0, @"invalid buffer size ..");
+  NSAssert(dest,         @"invalid buffer ..");
+
+  src = malloc(len + 4);
+  [self getCString:src];
+  src[len] = '\0';
+  
+  if (decode_base64(src, len, dest, destSize, &destLength) == 0) {
+    if (src) free(src);
+    return [NSData dataWithBytesNoCopy:dest length:destLength];
+  }
+  
+  if (src)  free(src);
+  if (dest) free(dest);
+  return nil;
+}
+
+@end /* NSString(Base64Coding) */
+
+@implementation NSData(Base64Coding)
+
+static int NSDataMaxLineWidth = 72;
+
+- (NSData *)dataByEncodingBase64 {
+  unsigned len;
+  size_t destSize;
+  size_t destLength = -1;
+  char   *dest;
+  
+  if ((len = [self length]) == 0)
+    return [NSData data];
+  
+  destSize   = (len + 2) / 3 * 4; // 3:4 conversion ratio
+  destSize += destSize / NSDataMaxLineWidth + 2; // space for newlines and '\0'
+  destSize += 64;
+
+  dest = malloc(destSize + 4);
+
+  NSAssert(destSize > 0, @"invalid buffer size ..");
+  NSAssert(dest,         @"invalid buffer ..");
+  
+  if (encode_base64([self bytes], len,
+                    dest, destSize, &destLength, NSDataMaxLineWidth) == 0) {
+    return [NSData dataWithBytesNoCopy:dest length:destLength];
+  }
+  else {
+    if (dest) free((void *)dest);
+    return nil;
+  }
+}
+
+- (NSData *)dataByDecodingBase64 {
+  unsigned len;
+  size_t destSize;
+  size_t destLength = -1;
+  char   *dest;
+
+  if ((len = [self length]) == 0)
+    return [NSData data];
+  
+  destSize = (len / 4 + 1) * 3 + 1;
+  dest = malloc(destSize + 4);
+
+  NSAssert(destSize > 0, @"invalid buffer size ..");
+  NSAssert(dest,         @"invalid buffer ..");
+  
+  if (decode_base64([self bytes], len, dest, destSize, &destLength) == 0)
+    return [NSData dataWithBytesNoCopy:dest length:destLength];
+
+  if (dest) free(dest);
+  return nil;
+}
+
+- (NSString *)stringByEncodingBase64 {
+  NSData   *data;
+  NSString *s;
+  
+  if ((data = [self dataByEncodingBase64]) == nil)
+    return nil;
+  s = [[NSString alloc] initWithData:data 
+                        encoding:[NSString defaultCStringEncoding]];
+  return [s autorelease];
+}
+- (NSString *)stringByDecodingBase64 {
+  NSData   *data;
+  NSString *s;
+  
+  if ((data = [self dataByDecodingBase64]) == nil)
+    return nil;
+  s = [[NSString alloc] initWithData:data
+                        encoding:[NSString defaultCStringEncoding]];
+  return [s autorelease];
+}
+
+@end /* NSData(Base64Coding) */
+
+// functions
+
+int NGEncodeBase64(const void *_source, unsigned _len,
+                   void *_buffer, unsigned _bufferCapacity,
+                   int _maxLineWidth) {
+  size_t len;
+
+  if ((_source == NULL) || (_buffer == NULL) || (_bufferCapacity == 0))
+    return -1;
+  
+  { // check whether buffer is big enough
+    size_t outSize;
+    outSize =  (_len + 2) / 3 * 4;            // 3:4 conversion ratio
+    outSize += (outSize / _maxLineWidth) + 2; // Space for newlines and NUL
+
+    if (_bufferCapacity < outSize)
+      return -1;
+  }
+  
+  if (encode_base64(_source, _len,
+                    _buffer, _bufferCapacity, &len, _maxLineWidth) == 0) {
+    return len;
+  }
+  else
+    return -1;
+}
+
+int NGDecodeBase64(const void *_source, unsigned _len,
+                   void *_buffer, unsigned _bufferCapacity) {
+  size_t len;
+  
+  if ((_source == NULL) || (_buffer == NULL) || (_bufferCapacity == 0))
+    return -1;
+  
+  if (((_len / 4 + 1) * 3 + 1) > _bufferCapacity)
+    return -1;
+  
+  if (decode_base64(_source, _len, _buffer, _bufferCapacity, &len) == 0)
+    return len;
+  else
+    return -1;
+}
+
+// private implementation
+
+static char base64tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "abcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static char base64idx[128] = {
+    '\377','\377','\377','\377','\377','\377','\377','\377',
+    '\377','\377','\377','\377','\377','\377','\377','\377',
+    '\377','\377','\377','\377','\377','\377','\377','\377',
+    '\377','\377','\377','\377','\377','\377','\377','\377',
+    '\377','\377','\377','\377','\377','\377','\377','\377',
+    '\377','\377','\377',    62,'\377','\377','\377',    63,
+        52,    53,    54,    55,    56,    57,    58,    59,
+        60,    61,'\377','\377','\377','\377','\377','\377',
+    '\377',     0,     1,     2,     3,     4,     5,     6,
+         7,     8,     9,    10,    11,    12,    13,    14,
+        15,    16,    17,    18,    19,    20,    21,    22,
+        23,    24,    25,'\377','\377','\377','\377','\377',
+    '\377',    26,    27,    28,    29,    30,    31,    32,
+        33,    34,    35,    36,    37,    38,    39,    40,
+        41,    42,    43,    44,    45,    46,    47,    48,
+        49,    50,    51,'\377','\377','\377','\377','\377'
+};
+
+static inline int encode_base64(const char *_src, size_t _srcLen, char *_dest,
+                                size_t _destSize, size_t *_destLen,
+                                int _maxLineWidth) {
+  size_t inLen  = _srcLen;
+  char   *out   = _dest;
+  size_t inPos  = 0;
+  size_t outPos = 0;
+  int    c1, c2, c3;
+  unsigned i;
+  
+  // Get three characters at a time and encode them.
+  for (i = 0; i < inLen / 3; ++i) {
+    c1 = _src[inPos++] & 0xFF;
+    c2 = _src[inPos++] & 0xFF;
+    c3 = _src[inPos++] & 0xFF;
+    out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
+    out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
+    out[outPos++] = base64tab[((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6)];
+    out[outPos++] = base64tab[c3 & 0x3F];
+
+    if ((outPos + 1) % (_maxLineWidth + 1) == 0)
+      out[outPos++] = '\n';
+  }
+  
+  // Encode the remaining one or two characters.
+  switch (inLen % 3) {
+    case 0:
+      //out[outPos++] = '\n';
+      break;
+    case 1:
+      c1 = _src[inPos] & 0xFF;
+      out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
+      out[outPos++] = base64tab[((c1 & 0x03) << 4)];
+      out[outPos++] = '=';
+      out[outPos++] = '=';
+      //out[outPos++] = '\n';
+      break;
+    case 2:
+      c1 = _src[inPos++] & 0xFF;
+      c2 = _src[inPos] & 0xFF;
+      out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
+      out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
+      out[outPos++] = base64tab[((c2 & 0x0F) << 2)];
+      out[outPos++] = '=';
+      //out[outPos++] = '\n';
+      break;
+  }
+  out[outPos] = 0;
+  *_destLen = outPos;
+  return 0;
+}
+
+static inline int decode_base64(const char *_src, size_t inLen, char *out,
+                                size_t _destSize, size_t *_destLen) 
+{
+  BOOL   isErr     = NO;
+  BOOL   isEndSeen = NO;
+  register int    b1, b2, b3;
+  register int    a1, a2, a3, a4;
+  register size_t inPos  = 0;
+  register size_t outPos = 0;
+  
+  /* Get four input chars at a time and decode them. Ignore white space
+   * chars (CR, LF, SP, HT). If '=' is encountered, terminate input. If
+   * a char other than white space, base64 char, or '=' is encountered,
+   * flag an input error, but otherwise ignore the char.
+   */
+  while (inPos < inLen) {
+    a1 = a2 = a3 = a4 = 0;
+
+    // get byte 1
+    while (inPos < inLen) {
+      a1 = _src[inPos++] & 0xFF;
+      
+      if (isbase64(a1))
+        break;
+      else if (a1 == '=') {
+        isEndSeen = YES;
+        break;
+      }
+      else if (a1 != '\r' && a1 != '\n' && a1 != ' ' && a1 != '\t') {
+        isErr = YES;
+      }
+    }
+    
+    // get byte 2
+    while (inPos < inLen) {
+      a2 = _src[inPos++] & 0xFF;
+
+      if (isbase64(a2))
+        break;
+      else if (a2 == '=') {
+        isEndSeen = YES;
+        break;
+      }
+      else if (a2 != '\r' && a2 != '\n' && a2 != ' ' && a2 != '\t') {
+        isErr = YES;
+      }
+    }
+    
+    // get byte 3
+    while (inPos < inLen) {
+      a3 = _src[inPos++] & 0xFF;
+
+      if (isbase64(a3))
+        break;
+      else if (a3 == '=') {
+        isEndSeen = YES;
+        break;
+      }
+      else if (a3 != '\r' && a3 != '\n' && a3 != ' ' && a3 != '\t') {
+        isErr = YES;
+      }
+    }
+
+    // get byte 4
+    while (inPos < inLen) {
+      a4 = _src[inPos++] & 0xFF;
+
+      if (isbase64(a4))
+        break;
+      else if (a4 == '=') {
+        isEndSeen = YES;
+        break;
+      }
+      else if (a4 != '\r' && a4 != '\n' && a4 != ' ' && a4 != '\t') {
+        isErr = YES;
+      }
+    }
+
+    // complete chunk
+    if (isbase64(a1) && isbase64(a2) && isbase64(a3) && isbase64(a4)) {
+      a1 = base64idx[a1] & 0xFF;
+      a2 = base64idx[a2] & 0xFF;
+      a3 = base64idx[a3] & 0xFF;
+      a4 = base64idx[a4] & 0xFF;
+      b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
+      b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
+      b3 = ((a3 << 6) & 0xC0) | ( a4       & 0x3F);
+      out[outPos++] = (char)b1;
+      out[outPos++] = (char)b2;
+      out[outPos++] = (char)b3;
+    }
+    // 3-chunk
+    else if (isbase64(a1) && isbase64(a2) && isbase64(a3) && a4 == '=') {
+      a1 = base64idx[a1] & 0xFF;
+      a2 = base64idx[a2] & 0xFF;
+      a3 = base64idx[a3] & 0xFF;
+      b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
+      b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
+      out[outPos++] = (char)b1;
+      out[outPos++] = (char)b2;
+      break;
+    }
+    // 2-chunk
+    else if (isbase64(a1) && isbase64(a2) && a3 == '=' && a4 == '=') {
+      a1 = base64idx[a1] & 0xFF;
+      a2 = base64idx[a2] & 0xFF;
+      b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
+      out[outPos++] = (char)b1;
+      break;
+    }
+    // invalid state
+    else {
+      break;
+    }
+    
+    if (isEndSeen)
+      break;
+  }
+  *_destLen = outPos;
+  return (isErr) ? -1 : 0;
+}
+
+// for static linking
+
+void __link_NGBase64Coding(void) {
+  __link_NGBase64Coding();
+}
diff --git a/skyrix-core/NGExtensions/NGBitSet.m b/skyrix-core/NGExtensions/NGBitSet.m
new file mode 100644 (file)
index 0000000..152b78a
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NGMemoryAllocation.h"
+#import "NGBitSet.h"
+
+#define NGStorageSize   sizeof(NGBitSetStorage)
+#define NGBitsPerEntry  (NGStorageSize * 8)
+#define NGByteSize      (universe / 8)
+
+#define NGTestBit(_x)   (((storage[ _x / NGBitsPerEntry ] & \
+                         (1 << (_x % NGBitsPerEntry))) == 0) ? NO : YES)
+
+@interface NGConcreteBitSetEnumerator : NSEnumerator
+{
+@public
+  unsigned int    universe;
+  unsigned int    count;
+  NGBitSetStorage *storage;
+
+  unsigned int position;
+  unsigned int found;
+}
+
+- (id)nextObject;
+
+@end
+
+@implementation NGBitSet
+
++ (id)bitSet {
+  return [[[self alloc] init] autorelease];
+}
++ (id)bitSetWithCapacity:(unsigned)_capacity {
+  return [[[self alloc] initWithCapacity:_capacity] autorelease];
+}
++ (id)bitSetWithBitSet:(NGBitSet *)_set {
+  return [[[self alloc] initWithBitSet:_set] autorelease];
+}
+
+- (id)initWithCapacity:(unsigned)_capacity {
+  if ((self = [super init])) {
+    self->universe = (_capacity / NGBitsPerEntry + 1) * NGBitsPerEntry;
+    storage  = NGMallocAtomic(NGByteSize);
+    memset(storage, 0, NGByteSize);
+    count = 0;
+  }
+  return self;
+}
+
+- (id)initWithBitSet:(NGBitSet *)_set {
+  if ((self = [self initWithCapacity:NGBitsPerEntry])) {
+    NSEnumerator *enumerator = [_set objectEnumerator];
+    id obj = nil;
+
+    while ((obj = [enumerator nextObject]))
+      [self addMember:[obj unsignedIntValue]];
+
+    enumerator = nil;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithCapacity:NGBitsPerEntry];
+}
+- (id)initWithNullTerminatedArray:(unsigned int *)_array {
+  if ((self = [self initWithCapacity:NGBitsPerEntry])) {
+    while (*_array) {
+      [self addMember:*_array];
+      _array++;
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (self->storage) {
+    NGFree(self->storage);
+    self->storage = NULL;
+  }
+  [super dealloc];
+}
+
+/* storage */
+
+- (void)_expandToInclude:(unsigned int)_element {
+  unsigned int nu = (_element / NGBitsPerEntry + 1) * NGBitsPerEntry;
+  if (nu > self->universe) {
+    void *old = storage;
+    storage = (NGBitSetStorage *)NGMallocAtomic(nu / 8);
+    memset(storage, 0, nu / 8);
+    if (old) {
+      memcpy(storage, old, NGByteSize);
+      NGFree(old);
+      old = NULL;
+    }
+    self->universe = nu;
+  }
+}
+
+/* accessors */
+
+- (unsigned int)capacity {
+  return self->universe;
+}
+- (unsigned int)count {
+  return count;
+}
+
+/* membership */
+
+- (BOOL)isMember:(unsigned int)_element {
+  return (_element >= self->universe) ? NO : NGTestBit(_element);
+}
+
+- (void)addMember:(unsigned int)_element {
+  register unsigned int subIdxPattern = 1 << (_element % NGBitsPerEntry);
+
+  if (_element >= self->universe)
+    [self _expandToInclude:_element];
+
+  if ((storage[ _element / NGBitsPerEntry ] & subIdxPattern) == 0) {
+    storage[ _element / NGBitsPerEntry ] |= subIdxPattern;
+    count++;
+  }
+}
+- (void)addMembersInRange:(NSRange)_range {
+  register unsigned int from = _range.location;
+  register unsigned int to   = from + _range.length - 1;
+
+  if (to >= self->universe)
+    [self _expandToInclude:to];
+
+  for (; from <= to; from++) {
+    register unsigned int subIdxPattern = 1 << (from % NGBitsPerEntry);
+
+    if ((storage[ from / NGBitsPerEntry ] & subIdxPattern) == 0) {
+      storage[ from / NGBitsPerEntry ] |= subIdxPattern;
+      count++;
+    }
+  }
+}
+
+- (void)addMembersFromBitSet:(NGBitSet *)_set {
+  unsigned i;
+
+  if ([_set capacity] > self->universe)
+    [self _expandToInclude:[_set capacity]];
+
+  for (i = 0; i < [_set capacity]; i++) {
+    if ([_set isMember:i]) {
+      register unsigned int subIdxPattern = 1 << (i % NGBitsPerEntry);
+      
+      if ((storage[ i / NGBitsPerEntry ] & subIdxPattern) == 0) {
+        storage[ i / NGBitsPerEntry ] |= subIdxPattern;
+        count++;
+      }
+    }
+  }
+}
+
+- (void)removeMember:(unsigned int)_element {
+  register unsigned int subIdxPattern = 1 << (_element % NGBitsPerEntry);
+
+  if (_element >= self->universe)
+    return;
+
+  if ((storage[ _element / NGBitsPerEntry ] & subIdxPattern) != 0) {
+    storage[ _element / NGBitsPerEntry ] -= subIdxPattern;
+    count--;
+  }
+}
+- (void)removeMembersInRange:(NSRange)_range {
+  register unsigned int from = _range.location;
+  register unsigned int to   = from + _range.length - 1;
+
+  if (from >= self->universe)
+    return;
+  if (to >= self->universe) to = self->universe - 1;
+  
+  for (; from <= to; from++) {
+    register unsigned int subIdxPattern = 1 << (from % NGBitsPerEntry);
+
+    if ((storage[ from / NGBitsPerEntry ] & subIdxPattern) != 0) {
+      storage[ from / NGBitsPerEntry ] -= subIdxPattern;
+      count--;
+    }
+  }
+}
+- (void)removeAllMembers {
+  memset(storage, 0, NGByteSize);
+  count = 0;
+}
+
+- (unsigned int)firstMember {
+  register unsigned int element;
+
+  for (element = 0; element < self->universe; element++) {
+    if (NGTestBit(element))
+      return element;
+  }
+  return NSNotFound;
+}
+
+- (unsigned int)lastMember {
+  register unsigned int element;
+
+  for (element = (self->universe - 1); element >= 0; element--) {
+    if (NGTestBit(element))
+      return element;
+  }
+  return NSNotFound;
+}
+
+/* equality */
+
+- (BOOL)isEqual:(id)_object {
+  if (self == _object) return YES;
+  if ([self class] != [_object class]) return NO;
+  return [self isEqualToSet:_object];
+}
+- (BOOL)isEqualToSet:(NGBitSet *)_set {
+  if (self == _set) return YES;
+  if (count != [_set count]) return NO;
+
+  {
+    register unsigned int element;
+
+    for (element = 0; element < self->universe; element++) {
+      if (NGTestBit(element)) {
+        if (![_set isMember:element])
+          return NO;
+      }
+    }
+    return YES;
+  }
+}
+
+/* enumerator */
+
+- (NSEnumerator *)objectEnumerator {
+  if (self->count == 0) 
+    return nil;
+  else {
+    NGConcreteBitSetEnumerator *en = [[NGConcreteBitSetEnumerator alloc] init];
+    en->universe = self->universe;
+    en->count    = self->count;
+    en->storage  = self->storage;
+    return [en autorelease];
+  }
+}
+
+/* NSCopying */
+
+- (id)copy {
+  return [self copyWithZone:[self zone]];
+}
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[NGBitSet alloc] initWithBitSet:self];
+}
+
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  unsigned int element;
+  register unsigned int found;
+
+  [_coder encodeValueOfObjCType:@encode(unsigned int) at:&count];
+
+  for (element = 0, found = 0; (element < self->universe) && (found < count); element++) {
+    if (NGTestBit(element)) {
+      [_coder encodeValueOfObjCType:@encode(unsigned int) at:&element];
+      found++;
+    }
+  }
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  if ((self = [super init])) {
+    unsigned int nc;
+    register unsigned int cnt;
+
+    self->universe = NGBitsPerEntry;
+    storage  = NGMallocAtomic(NGByteSize);
+    memset(storage, 0, NGByteSize);
+
+    [_coder decodeValueOfObjCType:@encode(unsigned int) at:&nc];
+
+    for (cnt = 0; cnt < nc; cnt++) {
+      unsigned int member;
+      [_coder decodeValueOfObjCType:@encode(unsigned int) at:&member];
+      [self addMember:member];
+    }
+  }
+  return self;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<NGBitSet[0x%08X]: capacity=%u count=%u content=%@>",
+                     (unsigned)self, self->universe, self->count,
+                     [[self toArray] description]];
+}
+
+- (NSArray *)toArray {
+  NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:count + 1];
+  register unsigned int element, found;
+
+  for (element = 0, found = 0;
+       (element < self->universe) && (found < self->count); element++) {
+    
+    if (NGTestBit(element)) {
+      [result addObject:[NSNumber numberWithUnsignedInt:element]];
+      found++;
+    }
+  }
+  return [[[result autorelease] copy] autorelease];
+}
+
+@end /* NGBitSet */
+
+@implementation NGConcreteBitSetEnumerator
+
+- (id)nextObject {
+  if (self->found == self->count)
+    return nil;
+  if (self->position >= self->universe)
+    return nil;
+
+  while (!NGTestBit(self->position))
+    self->position++;
+
+  self->found++;
+  self->position++;
+
+  return [NSNumber numberWithUnsignedInt:(self->position - 1)];
+}
+
+@end /* NGConcreteBitSetEnumerator */
+
+NSString *stringValueForBitset(unsigned int _set, char _setC, char _unsetC,
+                               short _wide) {
+  char           buf[_wide + 1];
+  register short pos;
+
+  for (pos = 0; pos < _wide; pos++) {
+    register unsigned int v = (1 << pos);
+    buf[(int)pos] = ((v & _set) == v) ? _setC : _unsetC;
+  }
+  
+  buf[_wide] = '\0';
+  return [NSString stringWithCString:buf];
+}
+
+void __link_NGExtensions_NGBitSet() {
+  __link_NGExtensions_NGBitSet();
+}
diff --git a/skyrix-core/NGExtensions/NGBundleManager.m b/skyrix-core/NGExtensions/NGBundleManager.m
new file mode 100644 (file)
index 0000000..7abeb2f
--- /dev/null
@@ -0,0 +1,1861 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGBundleManager.h"
+#include "common.h"
+#import <Foundation/NSFileManager.h>
+#import <EOControl/EOQualifier.h>
+#include <ctype.h>
+
+#if 0 && GNUSTEP_BASE_LIBRARY /* supported in repository since 19990916-2254-MET */
+/* hack until GNUstep provides the necessary callbacks */
+#  define NSNonRetainedObjectMapValueCallBacks NSObjectMapValueCallBacks
+#endif
+
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+#  include <NGExtensions/NGPropertyListParser.h>
+#endif
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+
+#include <objc/objc-runtime.h>
+
+//OBJC_EXPORT void objc_setClassHandler(int (*)(const char *));
+
+static BOOL debugClassHook = NO;
+
+static int _getClassHook(const char *className) {
+  if (className == NULL) return 0;
+  
+  if (debugClassHook)
+    printf("lookup class '%s'.\n", className);
+  
+  if (objc_lookUpClass(className))
+    return 1;
+  
+  {
+    static NGBundleManager *manager = nil;
+    NSBundle *bundle;
+    
+    if (debugClassHook)
+      NSLog(@"%s: look for class %s", __PRETTY_FUNCTION__, className);
+    if (manager == nil)
+      manager = [NGBundleManager defaultBundleManager];
+    
+    bundle  = [manager bundleForClassNamed:
+                        [NSString stringWithCString:className]];
+    if (bundle) {
+      if (debugClassHook) {
+       NSLog(@"%s: found bundle %@", __PRETTY_FUNCTION__, 
+             [bundle bundlePath]);
+      }
+      
+      if (![manager loadBundle:bundle]) {
+       fprintf(stderr,
+               "bundleManager couldn't load bundle for class '%s'.\n", 
+                className);
+      }
+#if 0
+      else {
+        Class c = objc_lookUpClass(className);
+        NSLog(@"%s: loaded bundle %@ for className %s class %@", 
+             __PRETTY_FUNCTION__,
+              bundle, className, c);
+      }
+#endif
+    }
+  }
+  
+  return 1;
+}
+
+#endif
+
+#if GNU_RUNTIME
+#include <objc/objc-api.h>
+
+static Class (*oldClassLoadHook)(const char *_name) = NULL;
+
+static inline BOOL _isValidClassName(const char *_name) {
+  register int len;
+
+  if (_name == NULL) return NO;
+
+  for (len = 0; (len < 256) && (*_name != '\0'); len++, _name++) {
+    if (*_name != '_') {
+      if (!isalnum((int)*_name))
+        return NO;
+    }
+  }
+  return (len == 256) ? NO : YES;
+}
+
+static Class _classLoadHook(const char *_name) {
+  if (_isValidClassName(_name)) {
+    static NGBundleManager *manager = nil;
+    NSBundle *bundle;
+    
+    //NSLog(@"%s: look for class %s", __PRETTY_FUNCTION__, _name);
+    if (manager == nil)
+      manager = [NGBundleManager defaultBundleManager];
+    
+    bundle  = [manager bundleForClassNamed:[NSString stringWithCString:_name]];
+    if (bundle) {
+      //NSLog(@"%s: found bundle %@", __PRETTY_FUNCTION__, [bundle bundlePath]);
+      
+      if ([manager loadBundle:bundle]) {
+        Class clazz;
+        void *hook;
+
+        hook = _objc_lookup_class;
+        _objc_lookup_class = NULL;
+        clazz = objc_lookup_class(_name);
+        _objc_lookup_class = hook;
+
+        if (clazz) return clazz;
+      }
+    }
+  }
+  return (oldClassLoadHook != NULL) ? oldClassLoadHook(_name) : Nil;
+}
+#endif // GNU_RUNTIME
+
+NSString *NGBundleWasLoadedNotificationName = @"NGBundleWasLoadedNotification";
+
+@interface NSBundle(NGBundleManagerPrivate)
+- (BOOL)_loadForBundleManager:(NGBundleManager *)_manager;
+@end
+
+@interface NGBundleManager(PrivateMethods)
+
+- (void)registerBundle:(NSBundle *)_bundle
+  classes:(NSArray *)_classes
+  categories:(NSArray *)_categories;
+
+- (NSString *)pathForBundleProvidingResource:(NSString *)_resourceName
+  ofType:(NSString *)_type
+  resourceSelector:(NGBundleResourceSelector)_selector
+  context:(void *)_ctx;
+  
+- (NSString *)makeBundleInfoPath:(NSString *)_path;
+
+@end
+
+static BOOL _selectClassByVersion(NSString        *_resourceName,
+                                  NSString        *_resourceType,
+                                  NSString        *_path,
+                                  NSDictionary    *_resourceConfig,
+                                  NGBundleManager *_bundleManager,
+                                  void            *_version)
+{
+  id  tmp;
+  int classVersion;
+  
+  if (![_resourceType isEqualToString:@"classes"])
+    return NO;
+
+  if (_version == NULL)
+    return YES;
+  if ([(id)_version intValue] == -1)
+    return YES;
+
+  if ((tmp = [_resourceConfig objectForKey:@"version"])) {
+    classVersion = [tmp intValue];
+
+    if (classVersion < [(id)_version intValue]) {
+      NSLog(@"WARNING: class version mismatch for class %@: "
+            @"requested at least version %i, got version %i",
+            _resourceName, [(id)_version intValue], classVersion);
+    }
+  }
+  if ((tmp = [_resourceConfig objectForKey:@"exact-version"])) {
+    classVersion = [tmp intValue];
+
+    if (classVersion != [(id)_version intValue]) {
+      NSLog(@"WARNING: class version mismatch for class %@: "
+            @"requested exact version %i, got version %i",
+            _resourceName, [(id)_version intValue], classVersion);
+    }
+  }
+  return YES;
+}
+
+@implementation NGBundleManager
+
+// THREAD
+static NGBundleManager *defaultManager = nil;
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  debugOn = [ud boolForKey:@"NGBundleManagerDebugEnabled"];
+}
+
+#if GNU_RUNTIME && 0
++ (void)load {
+  if (_objc_lookup_class != _classLoadHook) {
+    oldClassLoadHook = _objc_lookup_class;
+    _objc_lookup_class = _classLoadHook;
+  }
+}
+#endif
+
++ (id)defaultBundleManager {
+  if (defaultManager == nil) {
+    defaultManager = [[NGBundleManager alloc] init];
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+    {
+      static BOOL didRegisterCallback = NO;
+      
+      if (!didRegisterCallback) {
+       didRegisterCallback = YES;
+       objc_setClassHandler(_getClassHook);
+      }
+    }
+#endif
+
+#if GNU_RUNTIME
+    if (_objc_lookup_class != _classLoadHook) {
+      oldClassLoadHook = _objc_lookup_class;
+      _objc_lookup_class = _classLoadHook;
+    }
+#endif
+  }
+  return defaultManager;
+}
+
+- (void)_setupBundleSearchPathes {
+  NSProcessInfo  *pi;
+  NSUserDefaults *ud;
+  id       paths;
+  NSString *path;
+
+  pi = [NSProcessInfo processInfo];
+  
+  /* setup bundle search path */
+
+  self->bundleSearchPaths = [[NSMutableArray alloc] init];
+    
+  // first add main-bundle path
+  
+  path = [[[pi arguments] objectAtIndex:0] stringByDeletingLastPathComponent];
+  if ([path isEqual:@""])
+        path = @".";
+#if WITH_GNUSTEP
+  else {
+        /* The path is the complete path to the executable, including the
+           processor, the OS and the library combo. Strip these directories
+           from the main bundle's path. */
+        path = [[[path stringByDeletingLastPathComponent]
+                       stringByDeletingLastPathComponent]
+                       stringByDeletingLastPathComponent];
+  }
+#endif
+  [self->bundleSearchPaths addObject:path];
+    
+  // look into NGBundlePath default
+      
+  if ((ud = [NSUserDefaults standardUserDefaults]) == nil) {
+       // got this with gstep-base during the port, apparently it happens
+       // if the bundle manager is created inside the setup process of
+       // gstep-base (for whatever reason)
+       NSLog(@"ERROR(NGBundleManager): got no system userdefaults object!");
+#if DEBUG
+       abort();
+#endif
+  }
+      
+  paths = [ud arrayForKey:@"NGBundlePath"];
+  if (paths == nil) {
+        paths = [ud stringForKey:@"NGBundlePath"];
+        if (paths) {
+#if defined(__MINGW32__)
+          paths = [paths componentsSeparatedByString:@";"];
+#else
+          paths = [paths componentsSeparatedByString:@":"];
+#endif
+        }
+  }
+  if (paths) 
+    [self->bundleSearchPaths addObjectsFromArray:paths];
+  else
+    NSLog(@"Note: NGBundlePath default is not configured.");
+
+  // look into environment
+
+  paths = [[pi environment] objectForKey:@"NGBundlePath"];
+  if (paths) {
+#if defined(__MINGW32__)
+        paths = [paths componentsSeparatedByString:@";"];
+#else
+        paths = [paths componentsSeparatedByString:@":"];
+#endif
+  }
+  if (paths) [self->bundleSearchPaths addObjectsFromArray:paths];
+
+  /* add standard bundle paths */
+  {
+#if !GNUSTEP
+#else
+    // TODO: whats that supposed to do?
+    // TODO: replace with proper path locator function!
+    NSDictionary *env;
+    NSString *p;
+      
+    env = [[NSProcessInfo processInfo] environment];
+    p = [[[env objectForKey:@"GNUSTEP_USER_ROOT"]
+                 stringByAppendingPathComponent:@"Library"]
+                 stringByAppendingPathComponent:@"Bundles"];
+    if (p) [self->bundleSearchPaths addObject:p];
+    p = [[[env objectForKey:@"GNUSTEP_LOCAL_ROOT"]
+                 stringByAppendingPathComponent:@"Library"]
+                 stringByAppendingPathComponent:@"Bundles"];
+    if (p) [self->bundleSearchPaths addObject:p];
+    p = [[[env objectForKey:@"GNUSTEP_NETWORK_ROOT"]
+                 stringByAppendingPathComponent:@"Library"]
+                 stringByAppendingPathComponent:@"Bundles"];
+    if (p) [self->bundleSearchPaths addObject:p];
+    p = [[[env objectForKey:@"GNUSTEP_SYSTEM_ROOT"]
+                 stringByAppendingPathComponent:@"Library"]
+                 stringByAppendingPathComponent:@"Bundles"];
+    if (p) [self->bundleSearchPaths addObject:p];
+#endif
+  }
+  
+#if DEBUG && NeXT_Foundation_LIBRARY && 0
+  NSLog(@"%s: bundle search pathes:\n%@", __PRETTY_FUNCTION__, 
+       self->bundleSearchPaths);
+#endif
+}
+
+- (void)_registerLoadedBundles {
+  NSEnumerator *currentBundles;
+  NSBundle     *loadedBundle;
+  
+  currentBundles = [[NSBundle allBundles] objectEnumerator];
+  while ((loadedBundle = [currentBundles nextObject]))
+    [self registerBundle:loadedBundle classes:nil categories:nil];
+}
+
+- (void)_registerForBundleLoadNotification {
+  [[NSNotificationCenter defaultCenter]
+                         addObserver:self
+                         selector:@selector(_bundleDidLoadNotifcation:)
+                         name:@"NSBundleDidLoadNotification"
+                         object:nil];
+}
+
+- (id)init {
+#if GNUSTEP_BASE_LIBRARY
+  if ([NSUserDefaults standardUserDefaults] == nil) {
+    /* called inside setup process, deny creation (HACK) */
+    [self release];
+    return nil;
+  }
+#endif
+  
+  if ((self = [super init])) {
+    self->classToBundle =
+      NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
+                       NSNonRetainedObjectMapValueCallBacks,
+                       32);
+    self->classNameToBundle =
+      NSCreateMapTable(NSObjectMapKeyCallBacks,
+                       NSNonRetainedObjectMapValueCallBacks,
+                       32);
+    self->categoryNameToBundle =
+      NSCreateMapTable(NSObjectMapKeyCallBacks,
+                       NSNonRetainedObjectMapValueCallBacks,
+                       32);
+    self->pathToBundle =
+      NSCreateMapTable(NSObjectMapKeyCallBacks,
+                       NSNonRetainedObjectMapValueCallBacks,
+                       32);
+    self->pathToBundleInfo =
+      NSCreateMapTable(NSObjectMapKeyCallBacks,
+                       NSObjectMapValueCallBacks,
+                       32);
+    self->nameToBundle =
+      NSCreateMapTable(NSObjectMapKeyCallBacks,
+                       NSNonRetainedObjectMapValueCallBacks,
+                       32);
+    self->loadedBundles = 
+      NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks,
+                       NSObjectMapValueCallBacks,
+                       32);
+    
+    [self _setupBundleSearchPathes];
+    [self _registerLoadedBundles];
+    [self _registerForBundleLoadNotification];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->loadingBundles release];
+  if (self->loadedBundles)        NSFreeMapTable(self->loadedBundles);
+  if (self->classToBundle)        NSFreeMapTable(self->classToBundle);
+  if (self->classNameToBundle)    NSFreeMapTable(self->classNameToBundle);
+  if (self->categoryNameToBundle) NSFreeMapTable(self->categoryNameToBundle);
+  if (self->pathToBundle)         NSFreeMapTable(self->pathToBundle);
+  if (self->pathToBundleInfo)     NSFreeMapTable(self->pathToBundleInfo);
+  if (self->nameToBundle)         NSFreeMapTable(self->nameToBundle);
+  [self->bundleSearchPaths release];
+  [super dealloc];
+}
+
+/* registering bundles */
+
+- (void)registerBundle:(NSBundle *)_bundle
+  classes:(NSArray *)_classes
+  categories:(NSArray *)_categories
+{
+  NSEnumerator *e;
+  id v;
+
+  //NSLog(@"NGBundleManager: register loaded bundle %@", [_bundle bundlePath]);
+
+  e = [_classes objectEnumerator];
+  while ((v = [e nextObject])) {
+    NSMapInsert(self->classToBundle, NSClassFromString(v), _bundle);
+    NSMapInsert(self->classNameToBundle, v, _bundle);
+  }
+
+  e = [_categories objectEnumerator];
+  while ((v = [e nextObject]))
+    NSMapInsert(self->categoryNameToBundle, v, _bundle);
+}
+
+/* bundle locator */
+
+- (NSString *)pathForBundleWithName:(NSString *)_name type:(NSString *)_type {
+  NSFileManager *fm = [NSFileManager defaultManager];
+  NSEnumerator  *e;
+  NSString      *path;
+  NSString      *bundlePath;
+  NSBundle      *bundle;
+  
+  /* first check in table */
+    
+
+  bundlePath = [_name stringByAppendingPathExtension:_type];
+  
+  if ((bundle = NSMapGet(self->nameToBundle, bundlePath)))
+    return [bundle bundlePath];
+  
+  e = [self->bundleSearchPaths objectEnumerator];
+  while ((path = [e nextObject])) {
+    BOOL isDir = NO;
+    
+    if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
+      if (!isDir) continue;
+
+      if ([[path lastPathComponent] isEqualToString:bundlePath]) {
+        // direct match (a bundle was specified in the path)
+        return path;
+      }
+      else {
+        NSString *tmp;
+        
+        tmp = [path stringByAppendingPathComponent:bundlePath];
+        if ([fm fileExistsAtPath:tmp isDirectory:&isDir]) {
+          if (isDir)
+            // found bundle
+            return tmp;
+        }
+      }
+    }
+  }
+  return nil;
+}
+/* getting bundles */
+
+- (NSBundle *)bundleForClass:(Class)aClass {
+  /* this method never loads a dynamic bundle (since the class is set up) */
+  NSBundle *bundle;
+
+  bundle = NSMapGet(self->classToBundle, aClass);
+
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+  if (bundle == nil){
+    bundle = [NSBundle bundleForClass:aClass];
+    if (bundle == [NSBundle mainBundle])
+      bundle = nil;
+  }
+#endif
+  if (bundle == nil) {
+    /*
+      if the class wasn't loaded from a bundle, it's *either* the main bundle
+      or a bundle loaded before NGExtension was loaded !!!
+    */
+
+#if !LIB_FOUNDATION_LIBRARY && !GNUSTEP_BASE_LIBRARY
+#  warning incorrect behaviour if NGExtensions is dynamically loaded !
+    // TODO: can we do anything about this? Can we detect the situation and
+    //       print a log instead of the compile warning?
+#endif
+    bundle = [NSBundle mainBundle];
+    NSMapInsert(self->classToBundle,     aClass, bundle);
+    NSMapInsert(self->classNameToBundle, NSStringFromClass(aClass), bundle);
+  }
+  return bundle;
+}
+- (NSBundle *)bundleWithPath:(NSString *)path {
+  NSBundle *bundle = nil;
+  NSString *bn;
+  
+  path = [path stringByResolvingSymlinksInPath];
+  if (path == nil)
+    return nil;
+  
+  if (debugOn) NSLog(@"find bundle for path: '%@'", path);
+  bundle = NSMapGet(self->pathToBundle, path);
+  
+  if (bundle) {
+    if (debugOn) NSLog(@"  found: %@", bundle);
+    return bundle;
+  }
+  
+  if ((bundle = [(NGBundle *)[NGBundle alloc] initWithPath:path]) == nil) {
+    NSLog(@"ERROR(%s): could not create bundle for path: '%@'", 
+         __PRETTY_FUNCTION__, path);
+    return nil;
+  }
+  
+  bn = [[bundle bundleName]
+                stringByAppendingPathExtension:[bundle bundleType]],
+    
+  NSMapInsert(self->pathToBundle, path, bundle);
+  NSMapInsert(self->nameToBundle, bn,   bundle);
+  return bundle;
+}
+
+- (NSBundle *)bundleWithName:(NSString *)_name type:(NSString *)_type {
+  NSBundle *bundle;
+  NSString *bn;
+
+  bn     = [_name stringByAppendingPathExtension:_type];
+  bundle = NSMapGet(self->nameToBundle, bn);
+  
+  if (bundle == nil)
+    bundle = [self bundleWithPath:[self pathForBundleWithName:_name type:_type]];
+
+  if (![[bundle bundleType] isEqualToString:_type])
+    bundle = nil;
+
+  return bundle;
+}
+- (NSBundle *)bundleWithName:(NSString *)_name {
+  return [self bundleWithName:_name type:@"bundle"];
+}
+
+- (NSBundle *)bundleForClassNamed:(NSString *)_className {
+  NSString *path   = nil;
+  NSBundle *bundle = nil;
+  
+  if (_className == nil)
+    return nil;
+
+  /* first check in table */
+  
+  if ((bundle = NSMapGet(self->classNameToBundle, _className)))
+    return bundle;
+  
+#if GNU_RUNTIME
+  /* then look in runtime, reset load callback to avoid recursion */
+  {
+    // THREAD
+    void  *loadCallback;
+    Class clazz;
+    
+    
+    loadCallback = _objc_lookup_class;
+    _objc_lookup_class = NULL;
+    clazz = NSClassFromString(_className);
+    _objc_lookup_class = loadCallback;
+
+    if (clazz) {
+      /* the class is already loaded */
+      bundle = [self bundleForClass:clazz];
+      NSMapInsert(self->classNameToBundle, _className, bundle);
+      return bundle;
+    }
+  }
+#endif
+  
+  path = [self pathForBundleProvidingResource:_className
+               ofType:@"classes"
+               resourceSelector:_selectClassByVersion
+               context:NULL /* version */];
+  if (path) {
+    path = [path stringByResolvingSymlinksInPath];
+    NSAssert(path, @"couldn't resolve symlinks in path ..");
+  }
+
+  if (path == nil)
+    return nil;
+  
+  if ((bundle = [self bundleWithPath:path]))
+    NSMapInsert(self->classNameToBundle, _className, bundle);
+
+  return bundle;
+}
+
+// dependencies
+
++ (int)version {
+  return 2;
+}
+
+- (NSArray *)bundlesRequiredByBundle:(NSBundle *)_bundle {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (NSArray *)classesProvidedByBundle:(NSBundle *)_bundle {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+- (NSArray *)classesRequiredByBundle:(NSBundle *)_bundle {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+// initialization
+
+- (NSString *)makeBundleInfoPath:(NSString *)_path {
+#if (NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY) && !defined(GSWARN)
+  return [[[_path stringByAppendingPathComponent:@"Contents"]
+                  stringByAppendingPathComponent:@"Resources"]
+                  stringByAppendingPathComponent:@"bundle-info.plist"];
+#else
+  return [_path stringByAppendingPathComponent:@"bundle-info.plist"];
+#endif
+}
+
+- (id)_initializeLoadedBundle:(NSBundle *)_bundle
+  info:(NSDictionary *)_bundleInfo
+{
+  id handler = nil;
+  
+  /* check whether a handler was specified */
+
+  if ((handler = [_bundleInfo objectForKey:@"bundleHandler"])) {
+    if ((handler = NSClassFromString(handler)) == nil) {
+      NSLog(@"ERROR: did not find handler class %@ of bundle %@.",
+            [_bundleInfo objectForKey:@"bundleHandler"], [_bundle bundlePath]);
+      handler = [_bundle principalClass];
+    }
+
+    handler = [handler alloc];
+    
+    if ([handler respondsToSelector:@selector(initForBundle:bundleManager:)])
+      handler = [handler initForBundle:_bundle bundleManager:self];
+    else
+      handler = [handler init];
+    handler = [handler autorelease];
+    
+    if (handler == nil) {
+      NSLog(@"ERROR: could not instantiate handler class %@ of bundle %@.",
+            [_bundleInfo objectForKey:@"bundleHandler"], [_bundle bundlePath]);
+      handler = [_bundle principalClass];
+    }
+  }
+  else {
+    if ((handler = [_bundle principalClass]) == nil)
+      /* use NGBundle class as default bundle handler */
+      handler = [NGBundle class];
+  }
+  
+  return handler;
+}
+
+/* loading */
+
+- (NSDictionary *)_loadBundleInfoAtExistingPath:(NSString *)_path {
+  NSDictionary *bundleInfo;
+  id info;
+
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+  bundleInfo = NGParsePropertyListFromFile(_path);
+#else
+  bundleInfo = [NSDictionary dictionaryWithContentsOfFile:_path];
+#endif
+  if (bundleInfo == nil) {
+    NSLog(@"couldn't load bundle-info at path '%@' !", _path);
+    return nil;
+  }
+  
+  /* check required bundle manager version */
+  info = [bundleInfo objectForKey:@"requires"];
+  if ((info = [(NSDictionary *)info objectForKey:@"bundleManagerVersion"])) {
+    if ([info intValue] > [[self class] version]) {
+      /* bundle manager version does not match ... */
+      return nil;
+    }
+  }
+  NSMapInsert(self->pathToBundleInfo, _path, bundleInfo);
+  return bundleInfo;
+}
+
+- (NSBundle *)_locateBundleForClassInfo:(NSDictionary *)_classInfo {
+  NSString *className;
+  NSBundle *bundle;
+  
+  if (_classInfo == nil)
+    return nil;
+  if ((className = [_classInfo objectForKey:@"name"]) == nil) {
+    NSLog(@"ERROR: missing classname in bundle-info.plist class section !");
+    return nil;
+  }
+  
+  if ((bundle = [self bundleForClassNamed:className]) == nil) {
+#if 0 // class might be already loaded
+    NSLog(@"ERROR: did not find class %@ required by bundle %@.",
+          className, [_bundle bundlePath]);
+#endif
+  }
+  
+  return bundle;
+}
+- (NSArray *)_locateBundlesForClassInfos:(NSEnumerator *)_classInfos {
+  NSMutableArray *requiredBundles;
+  NSDictionary   *i;
+  
+  requiredBundles = [NSMutableArray arrayWithCapacity:16];
+  while ((i = [_classInfos nextObject])) {
+    NSBundle *bundle;
+    
+    if ((bundle = [self _locateBundleForClassInfo:i]) == nil)
+      continue;
+    
+    [requiredBundles addObject:bundle];
+  }
+  return requiredBundles;
+}
+
+- (BOOL)_preLoadBundle:(NSBundle *)_bundle info:(NSDictionary *)_bundleInfo {
+  /* TODO: split up this huge method */
+  NSDictionary   *requires      = nil;
+  NSMutableArray *requiredBundles = nil;
+  NSBundle       *requiredBundle  = nil;
+
+  requires = [_bundleInfo objectForKey:@"requires"];
+  
+  if (requires == nil)
+    /* invalid bundle info specified */
+    return YES;
+
+  /* load required bundles */
+  {
+    NSEnumerator *e;
+    NSDictionary *i;
+
+    /* locate required bundles */
+    
+    e = [[requires objectForKey:@"bundles"] objectEnumerator];
+    while ((i = [e nextObject])) {
+      NSString *bundleName;
+      
+      if (![i respondsToSelector:@selector(objectForKey:)]) {
+        NSLog(@"ERROR(%s): invalid bundle-info of bundle %@ !!!\n"
+              @"  requires-entry is not a dictionary: %@",
+              __PRETTY_FUNCTION__, _bundle, i);
+        continue;
+      }
+      
+      if ((bundleName = [i objectForKey:@"name"])) {
+        NSString *type;
+        
+        type = [i objectForKey:@"type"];
+        if (type == nil) type = @"bundle";
+
+        if ((requiredBundle = [self bundleWithName:bundleName type:type])) {
+          if (requiredBundles == nil)
+            requiredBundles = [NSMutableArray arrayWithCapacity:16];
+          
+          [requiredBundles addObject:requiredBundle];
+        }
+        else {
+          NSLog(@"ERROR(NGBundleManager): did not find bundle '%@' (type=%@) "
+               @"required by bundle %@.",
+                bundleName, type, [_bundle bundlePath]);
+         continue;
+        }
+      }
+      else
+        NSLog(@"ERROR: error in bundle-info.plist of bundle %@", _bundle);
+    }
+  }
+
+  /* load located bundles */
+  {
+    NSEnumerator *e;
+    
+    e = [requiredBundles objectEnumerator];
+    while ((requiredBundle = [e nextObject])) {
+      Class bundleMaster;
+      
+      if ((bundleMaster = [self loadBundle:requiredBundle]) == Nil) {
+        NSLog(@"ERROR: could not load bundle %@ (%@) required by bundle %@.",
+              [requiredBundle bundlePath], requiredBundle, [_bundle bundlePath]);
+       continue;
+      }
+    }
+  }
+
+  /* load required classes */
+  {
+    NSArray *bundles;
+    NSArray *reqClasses;
+    
+    reqClasses = [requires objectForKey:@"classes"];
+    bundles = [self _locateBundlesForClassInfos:[reqClasses objectEnumerator]];
+    if (requiredBundles == nil)
+      requiredBundles = [NSMutableArray arrayWithCapacity:16];
+    [requiredBundles addObjectsFromArray:bundles];
+  }
+  
+  /* load located bundles */
+  {
+    NSEnumerator *e;
+    
+    e = [requiredBundles objectEnumerator];
+    while ((requiredBundle = [e nextObject])) {
+      Class bundleMaster;
+      
+      if ((bundleMaster = [self loadBundle:requiredBundle]) == Nil) {
+        NSLog(@"ERROR: could not load bundle %@ (%@) required by bundle %@.",
+              [requiredBundle bundlePath], requiredBundle, [_bundle bundlePath]);
+       continue;
+      }
+    }
+  }
+
+  /* check whether versions of classes match */
+  {
+    NSEnumerator *e;
+    NSDictionary *i;
+
+    e = [[requires objectForKey:@"classes"] objectEnumerator];
+    while ((i = [e nextObject])) {
+      NSString *className;
+      Class clazz;
+
+      if ((className = [i objectForKey:@"name"]) == nil)
+        continue;
+
+      if ((clazz = NSClassFromString(className)) == Nil)
+        continue;
+      
+      if ([i objectForKey:@"exact-version"]) {
+        int v;
+
+        v = [[i objectForKey:@"exact-version"] intValue];
+       
+        if (v != [clazz version]) {
+          NSLog(@"ERROR: required exact class match failed:\n"
+                @"  class:            %@\n"
+                @"  required version: %i\n"
+                @"  loaded version:   %i\n"
+                @"  bundle:           %@",
+                className,
+                v, [clazz version],
+                [_bundle bundlePath]);
+        }
+      }
+      else if ([i objectForKey:@"version"]) {
+        int v;
+        
+        v = [[i objectForKey:@"version"] intValue];
+        
+        if (v > [clazz version]) {
+          NSLog(@"ERROR: provided class does not match required version:\n"
+                @"  class:                  %@\n"
+                @"  least required version: %i\n"
+                @"  loaded version:         %i\n"
+                @"  bundle:                 %@",
+                className,
+                v, [clazz version],
+                [_bundle bundlePath]);
+        }
+      }
+    }
+  }
+  
+  return YES;
+}
+- (BOOL)_postLoadBundle:(NSBundle *)_bundle info:(NSDictionary *)_bundleInfo {
+  return YES;
+}
+
+- (id)loadBundle:(NSBundle *)_bundle {
+  NSString     *path       = nil;
+  NSDictionary *bundleInfo = nil;
+  id bundleManager = nil;
+
+#if DEBUG
+  NSAssert(self->loadedBundles, @"missing loadedBundles hashmap ..");
+#endif
+  
+  if ((bundleManager = NSMapGet(self->loadedBundles, _bundle)))
+    return bundleManager;
+  
+  if (_bundle == [NSBundle mainBundle])
+    return [NSBundle mainBundle];
+  
+  if ([self->loadingBundles containsObject:_bundle])
+    // recursive call
+    return nil;
+  
+  if (self->loadingBundles == nil)
+    self->loadingBundles = [[NSMutableSet allocWithZone:[self zone]] init];
+  [self->loadingBundles addObject:_bundle];
+
+  path = [_bundle bundlePath];
+  path = [self makeBundleInfoPath:path];
+
+  if ((bundleInfo = NSMapGet(self->pathToBundleInfo, path)) == nil) {
+    if ([[NSFileManager defaultManager] fileExistsAtPath:path])
+      bundleInfo = [self _loadBundleInfoAtExistingPath:path];
+  }
+  
+  if (![self _preLoadBundle:_bundle info:bundleInfo])
+    goto done;
+  
+  if (![_bundle _loadForBundleManager:self])
+    goto done;
+  
+  if (![self _postLoadBundle:_bundle info:bundleInfo])
+    goto done;
+  
+  if ((bundleManager = 
+       [self _initializeLoadedBundle:_bundle info:bundleInfo])) {
+    NSMapInsert(self->loadedBundles, _bundle, bundleManager);
+    
+    if ([bundleManager respondsToSelector:
+                         @selector(bundleManager:didLoadBundle:)])
+      [bundleManager bundleManager:self didLoadBundle:_bundle];
+  }
+#if 0
+  else {
+    NSLog(@"ERROR(%s): couldn't initialize loaded bundle '%@'",
+          __PRETTY_FUNCTION__, [_bundle bundlePath]);
+  }
+#endif
+ done:
+  [self->loadingBundles removeObject:_bundle];
+
+  if (bundleManager) {
+    if (bundleInfo == nil)
+      bundleInfo = [NSDictionary dictionary];
+    
+    [[NSNotificationCenter defaultCenter]
+                           postNotificationName:
+                             NGBundleWasLoadedNotificationName
+                           object:_bundle
+                           userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+                             self,          @"NGBundleManager",
+                             bundleManager, @"NGBundleHandler",
+                             bundleInfo,    @"NGBundleInfo",
+                             nil]];
+  }
+  return bundleManager;
+}
+
+// manager
+
+- (id)principalObjectOfBundle:(NSBundle *)_bundle {
+  return (id)NSMapGet(self->loadedBundles, _bundle);
+}
+
+// resources
+
+static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info)
+{
+  int i, count;
+
+  for (i = 0, count = [keys count]; i < count; i++) {
+    NSString *key;
+    id kv, vv;
+
+    key = [keys objectAtIndex:i];
+    vv  = [info objectForKey:key];
+
+    if (vv == nil) {
+      /* info has no matching key */
+      return NO;
+    }
+
+    kv = [dict objectForKey:key];
+    if (![kv isEqual:vv])
+      return NO;
+  }
+  return YES;
+}
+
+- (NSDictionary *)configForResource:(id)_resource ofType:(NSString *)_type
+  providedByBundle:(NSBundle *)_bundle
+{
+  NSDictionary *bundleInfo = nil;
+  NSString     *infoPath;
+  NSEnumerator *providedResources;
+  NSArray      *rnKeys = nil;
+  int          rnKeyCount = 0;
+  id           info;
+
+  if ([_resource respondsToSelector:@selector(objectForKey:)]) {
+    rnKeys     = [_resource allKeys];
+    rnKeyCount = [rnKeys count];
+  }
+  
+  infoPath = [self makeBundleInfoPath:[_bundle bundlePath]];
+
+  /* check whether info is in cache */
+  if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
+    if (![[NSFileManager defaultManager] fileExistsAtPath:infoPath])
+      /* no bundle-info.plist available .. */
+      return nil;
+
+    /* load info */
+    bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
+  }
+
+  /* get provided resources config */
+  
+  providedResources =
+    [[(NSDictionary *)[bundleInfo objectForKey:@"provides"] objectForKey:_type]
+                  objectEnumerator];
+  if (providedResources == nil) return nil;
+
+  /* scan provided resources */
+  
+  while ((info = [providedResources nextObject])) {
+    if (rnKeys) {
+      if (!_doesInfoMatch(rnKeys, _resource, info))
+        continue;
+    }
+    else {
+      NSString *name;
+      
+      name = [[(NSDictionary *)info objectForKey:@"name"] stringValue];
+      if (name == nil) continue;
+      if (![name isEqualToString:_resource]) continue;
+    }
+    return info;
+  }
+  return nil;
+}
+
+- (void)_processInfoForProvidedResources:(NSDictionary *)info 
+  ofType:(NSString *)_type path:(NSString *)path
+  resourceName:(NSString *)_resourceName
+  resourceSelector:(NGBundleResourceSelector)_selector
+  context:(void *)_context
+  andAddToResultArray:(NSMutableArray *)result
+{
+  NSEnumerator *providedResources = nil;
+  if (info == nil) return;
+  
+  /* direct match (a bundle was specified in the path) */
+
+  providedResources = [[(NSDictionary *)[info objectForKey:@"provides"]
+                              objectForKey:_type]
+                              objectEnumerator];
+  info = nil;
+  if (providedResources == nil) return;
+
+  /* scan provide array */
+  while ((info = [providedResources nextObject])) {
+    NSString *name;
+          
+    if ((name = [[info objectForKey:@"name"] stringValue]) == nil)
+      continue;
+
+    if (_resourceName) {
+      if (![name isEqualToString:_resourceName])
+       continue;
+    }
+    if (_selector) {
+      if (!_selector(_resourceName, _type, path, info, self, _context))
+       continue;
+    }
+    
+    [result addObject:path];
+  }
+}
+
+- (NSArray *)pathsForBundlesProvidingResource:(NSString *)_resourceName
+  ofType:(NSString *)_type
+  resourceSelector:(NGBundleResourceSelector)_selector
+  context:(void *)_context
+{
+  /* TODO: split up method */
+  NSMutableArray *result = nil;
+  NSFileManager  *fm;
+  NSEnumerator   *e;
+  NSString       *path;
+  
+  fm     = [NSFileManager defaultManager];
+  result = [NSMutableArray arrayWithCapacity:64];
+  
+  e = [self->bundleSearchPaths objectEnumerator];
+  while ((path = [e nextObject])) {
+    BOOL isDir = NO;
+    
+    if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
+      NSString *tmp;
+      id info = nil;
+      if (!isDir) continue;
+
+      /* check whether an appropriate bundle is contained in 'path' */
+      {
+        NSEnumerator *dir;
+
+        dir = [[fm directoryContentsAtPath:path] objectEnumerator];
+        while ((tmp = [dir nextObject])) {
+          NSDictionary *bundleInfo      = nil;
+          NSEnumerator *providedResources = nil;
+          NSString *infoPath;
+          id info;
+          
+          tmp = [path stringByAppendingPathComponent:tmp];
+          infoPath = [self makeBundleInfoPath:tmp];
+
+          if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
+            if (![fm fileExistsAtPath:infoPath])
+              continue;
+
+            bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
+          }
+
+          providedResources = 
+            [[(NSDictionary *)[bundleInfo objectForKey:@"provides"]
+                                          objectForKey:_type]
+                                          objectEnumerator];
+          if (providedResources == nil) continue;
+
+          // scan provide array
+          while ((info = [providedResources nextObject])) {
+            NSString *name;
+            
+            name = [[(NSDictionary *)info objectForKey:@"name"] stringValue];
+            if (name == nil) continue;
+
+            if (_resourceName) {
+              if (![name isEqualToString:_resourceName])
+                continue;
+            }
+            if (_selector) {
+              if (!_selector(name, _type, tmp, info, self, _context))
+                continue;
+            }
+
+            [result addObject:tmp];
+            break;
+          }
+        }
+      }
+
+      /* check for direct match */
+
+      tmp = [self makeBundleInfoPath:path];
+
+      if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) {
+        if ([fm fileExistsAtPath:tmp])
+          info = [self _loadBundleInfoAtExistingPath:tmp];
+      }
+      
+      [self _processInfoForProvidedResources:info ofType:_type path:path
+           resourceName:_resourceName resourceSelector:_selector
+           context:_context
+           andAddToResultArray:result];
+    }
+  }
+  return [[result copy] autorelease];
+}
+
+- (NSString *)pathForBundleProvidingResource:(id)_resourceName
+  ofType:(NSString *)_type
+  resourceSelector:(NGBundleResourceSelector)_selector
+  context:(void *)_context
+{
+  NSFileManager *fm = [NSFileManager defaultManager];
+  NSEnumerator  *e;
+  NSString      *path;
+  NSArray       *rnKeys = nil;
+  int           rnKeyCount = 0;
+
+  if ([_resourceName respondsToSelector:@selector(objectForKey:)]) {
+    rnKeys     = [_resourceName allKeys];
+    rnKeyCount = [rnKeys count];
+  }
+  
+  e = [self->bundleSearchPaths objectEnumerator];
+  while ((path = [e nextObject])) {
+    BOOL isDir = NO;
+    
+    if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
+      NSString *tmp;
+      id info = nil;
+      
+      if (!isDir) continue;
+      
+      /* check whether an appropriate bundle is contained in 'path' */
+      {
+        NSEnumerator *dir;
+       
+        dir = [[fm directoryContentsAtPath:path] objectEnumerator];
+        while ((tmp = [dir nextObject])) {
+          NSDictionary *bundleInfo      = nil;
+          NSEnumerator *providedResources = nil;
+          NSString *infoPath;
+          id info;
+          
+          tmp = [path stringByAppendingPathComponent:tmp];
+          infoPath = [self makeBundleInfoPath:tmp];
+
+         if (debugOn)
+           NSLog(@"check path path=%@ info=%@", tmp, infoPath);
+         
+          if ((bundleInfo=NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
+            if (![fm fileExistsAtPath:infoPath])
+              continue;
+
+            bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
+          }
+         if (debugOn) {
+           NSLog(@"found info for path=%@ info=%@: %@", 
+                 tmp, infoPath, bundleInfo);
+         }
+         
+          providedResources = 
+            [[(NSDictionary *)[bundleInfo objectForKey:@"provides"]
+                                          objectForKey:_type]
+                                          objectEnumerator];
+          if (providedResources == nil) continue;
+
+          // scan provide array
+          while ((info = [providedResources nextObject])) {
+            if (rnKeys) {
+              if (!_doesInfoMatch(rnKeys, _resourceName, info))
+                continue;
+            }
+            else {
+              NSString *name;
+
+              name = [[(NSDictionary *)info objectForKey:@"name"] stringValue];
+              if (name == nil) continue;
+              if (![name isEqualToString:_resourceName]) continue;
+            }
+
+            if (_selector) {
+              if (!_selector(_resourceName, _type, tmp, info, self, _context))
+                continue;
+            }
+            /* all conditions applied */
+            return tmp;
+          }
+        }
+      }
+
+      /* check for direct match */
+      
+      tmp = [self makeBundleInfoPath:path];
+
+      if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) {
+        if ([fm fileExistsAtPath:tmp])
+          info = [self _loadBundleInfoAtExistingPath:tmp];
+        else if (debugOn) {
+          NSLog(@"WARNING(%s): did not find direct path '%@'",
+                __PRETTY_FUNCTION__, tmp);
+        }
+      }
+      
+      if (info) {
+        // direct match (a bundle was specified in the path)
+        NSEnumerator *providedResources;
+        NSDictionary *provides;
+        
+        provides          = [(NSDictionary *)info objectForKey:@"provides"];
+        providedResources = [[provides objectForKey:_type] objectEnumerator];
+        info              = nil;
+        if (providedResources == nil) continue;
+        
+        // scan provide array
+        while ((info = [providedResources nextObject])) {
+          if (rnKeys) {
+            if (!_doesInfoMatch(rnKeys, _resourceName, info))
+              continue;
+          }
+          else {
+            NSString *name;
+
+            name = [[(NSDictionary *)info objectForKey:@"name"] stringValue];
+            if (name == nil) continue;
+            if (![name isEqualToString:_resourceName]) continue;
+          }
+
+          if (_selector) {
+            if (!_selector(_resourceName, _type, tmp, info, self, _context))
+              continue;
+          }
+          /* all conditions applied */
+          return tmp;
+        }
+      }
+    }
+  }
+  return nil;
+}
+
+- (NSBundle *)bundleProvidingResource:(id)_resourceName
+  ofType:(NSString *)_resourceType
+{
+  NSString *bp;
+  
+  bp = [self pathForBundleProvidingResource:_resourceName
+             ofType:_resourceType
+             resourceSelector:NULL context:nil];
+  if ([bp length] == 0) {
+#if (NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY) && HEAVY_DEBUG
+    NSLog(@"%s: found no resource '%@' of type '%@' ...",
+          __PRETTY_FUNCTION__, _resourceName, _resourceType);
+#endif
+    return nil;
+  }
+  
+  return [self bundleWithPath:bp];
+}
+
+- (NSArray *)bundlesProvidingResource:(id)_resourceName
+  ofType:(NSString *)_type
+{
+  NSArray        *paths;
+  NSMutableArray *bundles;
+  int i, count;
+
+  paths = [self pathsForBundlesProvidingResource:_resourceName
+                ofType:_type
+                resourceSelector:NULL context:nil];
+  
+  count = [paths count];
+  if (paths == nil) return nil;
+  if (count == 0)   return paths;
+
+  bundles = [NSMutableArray arrayWithCapacity:count];
+  for (i = 0; i < count; i++) {
+    NSBundle *bundle;
+
+    if ((bundle = [self bundleWithPath:[paths objectAtIndex:i]]))
+      [bundles addObject:bundle];
+  }
+  return [[bundles copy] autorelease];
+}
+
+- (NSArray *)providedResourcesOfType:(NSString *)_resourceType
+  inBundle:(NSBundle *)_bundle
+{
+  NSString     *path;
+  NSDictionary *bundleInfo;
+  
+  path = [self makeBundleInfoPath:[_bundle bundlePath]];
+  if (path == nil) return nil;
+  
+  /* retrieve bundle info dictionary */
+  if ((bundleInfo = NSMapGet(self->pathToBundleInfo, path)) == nil)
+    bundleInfo = [self _loadBundleInfoAtExistingPath:path];
+  
+  return [(NSDictionary *)[bundleInfo objectForKey:@"provides"] 
+                                      objectForKey:_resourceType];
+}
+
+- (NSArray *)providedResourcesOfType:(NSString *)_resourceType {
+  NSMutableSet  *result = nil;
+  NSFileManager *fm = [NSFileManager defaultManager];
+  NSEnumerator  *e;
+  NSString      *path;
+  
+  result = [NSMutableSet setWithCapacity:128];
+  
+  e = [self->bundleSearchPaths objectEnumerator];
+  while ((path = [e nextObject])) {
+    BOOL isDir = NO;
+
+    if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
+      NSString *tmp;
+      id info = nil;
+      if (!isDir) continue;
+
+      /* check whether an appropriate bundle is contained in 'path' */
+      {
+        NSEnumerator *dir;
+
+        dir = [[fm directoryContentsAtPath:path] objectEnumerator];
+        while ((tmp = [dir nextObject])) {
+          NSDictionary *bundleInfo      = nil;
+          NSArray      *providedResources = nil;
+          NSString     *infoPath;
+          
+          tmp = [path stringByAppendingPathComponent:tmp];
+          infoPath = [self makeBundleInfoPath:tmp];
+
+         //NSLog(@"  info path: %@", tmp);
+
+          if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
+            if (![fm fileExistsAtPath:infoPath])
+              continue;
+
+            bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
+          }
+
+          providedResources = 
+            [(NSDictionary *)[bundleInfo objectForKey:@"provides"]
+                                         objectForKey:_resourceType];
+          if (providedResources == nil) continue;
+
+          [result addObjectsFromArray:providedResources];
+        }
+      }
+
+      /* check for direct match */
+      
+      tmp = [self makeBundleInfoPath:path];
+
+      if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) {
+        if ([fm fileExistsAtPath:tmp])
+          info = [self _loadBundleInfoAtExistingPath:tmp];
+      }
+      
+      if (info) {
+        // direct match (a bundle was specified in the path)
+        NSArray      *providedResources;
+        NSDictionary *provides;
+
+        provides          = [(NSDictionary *)info objectForKey:@"provides"];
+        providedResources = [provides objectForKey:_resourceType];
+        info = nil;
+        if (providedResources == nil) continue;
+
+        [result addObjectsFromArray:providedResources];
+      }
+    }
+  }
+  return [result allObjects];
+}
+
+- (NSBundle *)bundleProvidingResourceOfType:(NSString *)_resourceType
+  matchingQualifier:(EOQualifier *)_qual
+{
+  NSFileManager  *fm = [NSFileManager defaultManager];
+  NSEnumerator   *e;
+  NSString       *path;
+
+  /* foreach search path entry */
+  
+  e = [self->bundleSearchPaths objectEnumerator];
+  while ((path = [e nextObject])) {
+    BOOL isDir = NO;
+    
+    if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
+      NSString *tmp;
+      id info = nil;
+      if (!isDir) continue;
+
+      /* check whether an appropriate bundle is contained in 'path' */
+      {
+        NSEnumerator *dir;
+
+        dir = [[fm directoryContentsAtPath:path] objectEnumerator];
+        while ((tmp = [dir nextObject])) {
+          NSDictionary *bundleInfo;
+          NSArray      *providedResources;
+          NSString     *infoPath;
+          
+          tmp      = [path stringByAppendingPathComponent:tmp];
+          infoPath = [self makeBundleInfoPath:tmp];
+          
+          if ((bundleInfo=NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
+            if (![fm fileExistsAtPath:infoPath])
+              continue;
+
+            bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
+          }
+          
+          bundleInfo        = [bundleInfo objectForKey:@"provides"];
+          providedResources = [bundleInfo objectForKey:_resourceType];
+          bundleInfo        = nil;
+          if (providedResources == nil) continue;
+
+          providedResources =
+            [providedResources filteredArrayUsingQualifier:_qual];
+
+          if ([providedResources count] > 0)
+            return [self bundleWithPath:tmp];
+        }
+      }
+
+      /* check for direct match */
+      
+      tmp = [self makeBundleInfoPath:path];
+
+      if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) {
+        if ([fm fileExistsAtPath:tmp])
+          info = [self _loadBundleInfoAtExistingPath:tmp];
+      }
+      
+      if (info) {
+        // direct match (a bundle was specified in the path)
+        NSArray      *providedResources;
+        NSDictionary *provides;
+        
+        provides          = [(NSDictionary *)info objectForKey:@"provides"];
+        providedResources = [provides objectForKey:_resourceType];
+        info = nil;
+        if (providedResources == nil) continue;
+
+        providedResources =
+          [providedResources filteredArrayUsingQualifier:_qual];
+
+        if ([providedResources count] > 0)
+          return [self bundleWithPath:path];
+      }
+    }
+  }
+  return nil;
+}
+
+- (NSBundle *)bundlesProvidingResourcesOfType:(NSString *)_resourceType
+  matchingQualifier:(EOQualifier *)_qual
+{
+  NSMutableArray *bundles = nil;
+  NSFileManager  *fm = [NSFileManager defaultManager];
+  NSEnumerator   *e;
+  NSString       *path;
+
+  bundles = [NSMutableArray arrayWithCapacity:128];
+
+  /* foreach search path entry */
+  
+  e = [self->bundleSearchPaths objectEnumerator];
+  while ((path = [e nextObject])) {
+    BOOL isDir = NO;
+    
+    if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
+      NSString *tmp;
+      id info = nil;
+      if (!isDir) continue;
+
+      /* check whether an appropriate bundle is contained in 'path' */
+      {
+        NSEnumerator *dir;
+
+        dir = [[fm directoryContentsAtPath:path] objectEnumerator];
+        while ((tmp = [dir nextObject])) {
+          NSDictionary *bundleInfo      = nil;
+          NSArray      *providedResources = nil;
+          NSString     *infoPath;
+          
+          tmp = [path stringByAppendingPathComponent:tmp];
+          infoPath = [self makeBundleInfoPath:tmp];
+          
+          if ((bundleInfo=NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
+            if (![fm fileExistsAtPath:infoPath])
+              continue;
+
+            bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
+          }
+          
+          bundleInfo        = [bundleInfo objectForKey:@"provides"];
+          providedResources = [bundleInfo objectForKey:_resourceType];
+          bundleInfo        = nil;
+          if (providedResources == nil) continue;
+
+          providedResources =
+            [providedResources filteredArrayUsingQualifier:_qual];
+
+          if ([providedResources count] > 0)
+            [bundles addObject:[self bundleWithPath:tmp]];
+        }
+      }
+
+      /* check for direct match */
+      
+      tmp = [self makeBundleInfoPath:path];
+
+      if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) {
+        if ([fm fileExistsAtPath:tmp])
+          info = [self _loadBundleInfoAtExistingPath:tmp];
+      }
+      
+      if (info) {
+        // direct match (a bundle was specified in the path)
+        NSArray      *providedResources;
+        NSDictionary *provides;
+        
+        provides          = [(NSDictionary *)info objectForKey:@"provides"];
+        providedResources = [provides objectForKey:_resourceType];
+        info = nil;
+        if (providedResources == nil) continue;
+
+        providedResources =
+          [providedResources filteredArrayUsingQualifier:_qual];
+
+        if ([providedResources count] > 0)
+          [bundles addObject:[self bundleWithPath:path]];
+      }
+    }
+  }
+  return [[bundles copy] autorelease];
+}
+
+// notifications
+
+- (void)_bundleDidLoadNotifcation:(NSNotification *)_notification {
+  NSDictionary *ui = [_notification userInfo];
+
+#if 0
+  NSLog(@"bundle %@ did load with classes %@",
+        [[_notification object] bundlePath],
+        [ui objectForKey:@"NSLoadedClasses"]);
+#endif
+  
+  [self registerBundle:[_notification object]
+        classes:[ui objectForKey:@"NSLoadedClasses"]
+        categories:[ui objectForKey:@"NSLoadedCategories"]];
+}
+
+@end /* NGBundleManager */
+
+@implementation NSBundle(BundleManagerSupport)
+
++ (id)alloc {
+  return [NGBundle alloc];
+}
++ (id)allocWithZone:(NSZone *)zone {
+  return [NGBundle allocWithZone:zone];
+}
+
+#if !(NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY)
+//#warning remember, bundleForClass is not overridden !
+#if 0
++ (NSBundle *)bundleForClass:(Class)aClass {
+  return [[NGBundleManager defaultBundleManager] bundleForClass:aClass];
+}
+#endif
++ (NSBundle *)bundleWithPath:(NSString*)path {
+  return [[NGBundleManager defaultBundleManager] bundleWithPath:path];
+}
+#endif
+
+@end /* NSBundle(BundleManagerSupport) */
+
+@implementation NSBundle(NGBundleManagerExtensions)
+
+- (id)principalObject {
+  return [[NGBundleManager defaultBundleManager]
+                           principalObjectOfBundle:self];
+}
+
+- (NSArray *)providedResourcesOfType:(NSString *)_resourceType {
+  return [[NGBundleManager defaultBundleManager]
+                           providedResourcesOfType:_resourceType
+                           inBundle:self];
+}
+
+- (NSString *)bundleName {
+  return [[[self bundlePath] lastPathComponent] stringByDeletingPathExtension];
+}
+
+- (NSString *)bundleType {
+  return [[self bundlePath] pathExtension];
+}
+
+- (NSArray *)providedClasses {
+  return [[NGBundleManager defaultBundleManager] classesProvidedByBundle:self];
+}
+
+- (NSArray *)requiredClasses {
+  return [[NGBundleManager defaultBundleManager] classesRequiredByBundle:self];
+}
+
+- (NSArray *)requiredBundles {
+  return [[NGBundleManager defaultBundleManager] bundlesRequiredByBundle:self];
+}
+
+- (NSDictionary *)configForResource:(id)_resource ofType:(NSString *)_type {
+  return [[NGBundleManager defaultBundleManager]
+                           configForResource:_resource ofType:_type
+                           providedByBundle:self];
+}
+
+// loading
+
+- (BOOL)_loadForBundleManager:(NGBundleManager *)_manager {
+  return [self load];
+}
+
+@end /* NSBundle(NGBundleManagerExtensions) */
+
+@implementation NSBundle(NGLanguageResourceExtensions)
+
+// locating resources
+
+- (NSString *)pathForResource:(NSString *)_name ofType:(NSString *)_ext
+  inDirectory:(NSString *)_directory
+  languages:(NSArray *)_languages
+{
+  NSFileManager *fm   = [NSFileManager defaultManager];
+  NSString      *path = nil;
+  int i, langCount;
+  id (*objAtIdx)(id,SEL,int);
+
+  path = _directory
+    ? [[self bundlePath] stringByAppendingPathComponent:_directory]
+    : [self bundlePath];
+
+  if (![fm fileExistsAtPath:path])
+    return nil;
+  
+  if (_ext) _name = [_name stringByAppendingPathExtension:_ext];
+  
+  langCount = [_languages count];
+  objAtIdx = (langCount > 0)
+    ? (void*)[_languages methodForSelector:@selector(objectAtIndex:)]
+    : NULL;
+
+  for (i = 0; i < langCount; i++) {
+    NSString *language;
+    NSString *lpath;
+
+    language = objAtIdx
+      ? objAtIdx(_languages, @selector(objectAtIndex:), i)
+      : [_languages objectAtIndex:i];
+
+    language = [language stringByAppendingPathExtension:@"lproj"];
+    lpath = [path stringByAppendingPathComponent:language];
+    lpath = [lpath stringByAppendingPathComponent:_name];
+
+    if ([fm fileExistsAtPath:lpath])
+      return lpath;
+  }
+
+  /* now look into x.bundle/Resources/name.type */
+  if ([fm fileExistsAtPath:[path stringByAppendingPathComponent:_name]])
+    return [path stringByAppendingPathComponent:_name];
+
+  return nil;
+}
+
+- (NSString *)pathForResource:(NSString *)_name ofType:(NSString *)_ext
+  languages:(NSArray *)_languages
+{
+  NSString *path;
+
+  path = [self pathForResource:_name ofType:_ext
+               inDirectory:@"Resources"
+               languages:_languages];
+  if (path) return path;
+
+  path = [self pathForResource:_name ofType:_ext
+               inDirectory:nil
+               languages:_languages];
+  return path;
+}
+
+@end /* NSBundle(NGLanguageResourceExtensions) */
+
+@implementation NGBundle
+
++ (id)alloc {
+  return [self allocWithZone:NULL];
+}
++ (id)allocWithZone:(NSZone*)zone {
+  return NSAllocateObject(self, 0, zone);
+}
+
+- (id)initWithPath:(NSString *)__path {
+  return [super initWithPath:__path];
+}
+
+/* loading */
+
+- (BOOL)_loadForBundleManager:(NGBundleManager *)_manager {
+  return [super load];
+}
+
+- (BOOL)load {
+  NGBundleManager *bm;
+
+  bm = [NGBundleManager defaultBundleManager];
+  
+  return [bm loadBundle:self] ? YES : NO;
+}
+
++ (NSBundle *)bundleForClass:(Class)aClass {
+  return [[NGBundleManager defaultBundleManager] bundleForClass:aClass];
+}
++ (NSBundle *)bundleWithPath:(NSString*)path {
+  return [[NGBundleManager defaultBundleManager] bundleWithPath:path];
+}
+
+#if GNUSTEP_BASE_LIBRARY
+
+- (Class)principalClass {
+  Class c;
+  NSString *cname;
+  
+  if ((c = [super principalClass]))
+    return c;
+  
+  if ((cname = [[self infoDictionary] objectForKey:@"NSPrincipalClass"]) ==nil)
+    return Nil;
+  
+  if ((c = NSClassFromString(cname)))
+    return c;
+  
+  NSLog(@"%s: did not find principal class named '%@' of bundle %@",
+       __PRETTY_FUNCTION__, cname, self);
+  return Nil;
+}
+
+/* description */
+
+- (NSString *)description {
+  char buffer[1024];
+    
+  sprintf (buffer,
+          "<%s %p fullPath: %s infoDictionary: %p loaded=%s>",
+          (char*)object_get_class_name(self),
+          self,
+          [[self bundlePath] cString],
+          [self infoDictionary], 
+          self->_codeLoaded ? "yes" : "no");
+  
+  return [NSString stringWithCString:buffer];
+}
+#endif
+
+@end /* NGBundle */
diff --git a/skyrix-core/NGExtensions/NGCString.m b/skyrix-core/NGExtensions/NGCString.m
new file mode 100644 (file)
index 0000000..1c84b69
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NGCString.h"
+#import "NGMemoryAllocation.h"
+
+@implementation NGCString
+
++ (id)stringWithCString:(const char *)_value length:(unsigned)_len {
+  return [[[self alloc] initWithCString:_value length:_len] autorelease];
+}
++ (id)stringWithCString:(const char *)_value {
+  return [[[self alloc] initWithCString:_value] autorelease];
+}
+
+- (id)initWithCString:(const char *)_value length:(unsigned)_len {
+  if ((self = [super init])) {
+    value = NGMallocAtomic(_len + 1);
+    memcpy(value, _value, _len);
+    value[_len] = '\0';
+    len = _len;
+  }
+  return self;
+}
+- (id)initWithCString:(const char *)_value {
+  return [self initWithCString:_value length:strlen(_value)];
+}
+
+- (void)dealloc {
+  NGFree(self->value); self->value = NULL;
+  len = 0;
+  [super dealloc];
+}
+
+// unicode
+
+- (unsigned int)length {
+  return [self cStringLength];
+}
+
+- (unichar)characterAtIndex:(unsigned int)_idx {
+  return [self charAtIndex:_idx];
+}
+
+// comparing
+
+- (BOOL)isEqual:(id)_object {
+  if ([_object isKindOfClass:[NGCString class]])
+    return [self isEqualToCString:_object];
+  else if ([_object isKindOfClass:[NSString class]])
+    return [self isEqualToString:_object];
+  else
+    return NO;
+}
+- (BOOL)isEqualToCString:(NGCString *)_cstr {
+  return (strcmp([_cstr cString], value) == 0);
+}
+- (BOOL)isEqualToString:(NSString *)_str {
+  return (strcmp([_str cString], value) == 0);
+}
+
+- (unsigned)hash {
+  unsigned hash = 0, hash2;
+  unsigned i;
+
+  for(i = 0; i < len; i++) {
+    hash <<= 4;
+    hash += value[i];
+    if((hash2 = hash & 0xf0000000))
+      hash ^= (hash2 >> 24) ^ hash2;
+  }
+  return hash;
+}
+
+/* copying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[NGCString alloc] initWithCString:value length:len];
+}
+- (id)mutableCopyWithZone:(NSZone *)_zone {
+  return [[NGMutableCString alloc] initWithCString:value length:len];
+}
+
+/* coding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeValueOfObjCType:@encode(unsigned int) at:&len];
+  [_coder encodeArrayOfObjCType:@encode(char) count:len at:value];
+}
+
+- (id)initWithCoder:(NSCoder *)_decoder {
+  char         *buffer = NULL;
+  unsigned int length;
+  id           cstr = nil;
+
+  [_decoder decodeValueOfObjCType:@encode(unsigned int) at:&length];
+  buffer = NGMallocAtomic(sizeof(unsigned char) * length);
+  [_decoder decodeArrayOfObjCType:@encode(char) count:length at:buffer];
+
+  cstr = [self initWithCString:buffer length:length];
+  
+  NGFree(buffer); buffer = NULL;
+  return cstr;
+}
+
+/* getting C strings */
+
+- (const char *)cString {
+  return value;
+}
+- (unsigned int)cStringLength {
+  return len;
+}
+
+- (void)getCString:(char *)_buffer {
+  strcpy(_buffer, value);
+}
+- (void)getCString:(char *)_buffer maxLength:(unsigned int)_maxLength {
+  unsigned int size = (_maxLength > len) ? len : _maxLength;
+
+  strncpy(_buffer, value, size);
+  _buffer[size] = '\0';
+}
+
+- (char)charAtIndex:(unsigned int)_idx {
+  if (_idx >= len) {
+#if LIB_FOUNDATION_LIBRARY
+    NSException *exc =
+      [[IndexOutOfRangeException alloc]
+          initWithFormat:@"index %d out of range in string %x of length %d",
+            _idx, self, len];
+    [exc raise];
+#else
+    [NSException raise:NSRangeException
+                 format:@"index %d out of range in string %x of length %d",
+                   _idx, self, len];
+#endif
+  }
+  return value[_idx];
+}
+
+// getting numeric values
+
+- (double)doubleValue {
+  if (len == 0)
+    return 0.0;
+  else
+    return atof(value);
+}
+- (float)floatValue {
+  return [self doubleValue];
+}
+- (int)intValue {
+  if (len == 0)
+    return 0;
+  else
+    return atoi(value);
+}
+
+- (NSString *)stringValue {
+  return (len > 0) ? [NSString stringWithCString:value] : @"";
+}
+
+// description
+
+- (NSString *)description {
+  return [self stringValue];
+}
+
+@end
+
+@implementation NGMutableCString
+
+static inline void _checkCapacity(NGMutableCString *self, unsigned int _add) {
+  if (self->capacity < (self->len + _add)) {
+    char         *old        = self->value;
+    unsigned int newCapacity = self->capacity * 2;
+
+    if (newCapacity < (self->len + _add))
+      newCapacity = self->len + _add;
+
+    self->value = NGMallocAtomic(newCapacity + 1);
+    if (old) {
+      memcpy(self->value, old, self->len);
+      NGFree(old);
+      old = NULL;
+    }
+    self->value[self->len] = '\0';
+  }
+}
+
+// init
+
+- (id)initWithCString:(const char *)_value length:(unsigned)_len {
+  if ((self = [super initWithCString:_value length:_len])) {
+    capacity = _len;
+  }
+  return self;
+}
+
+// appending
+
+- (void)appendString:(id)_str {
+  _checkCapacity(self, [_str cStringLength]);
+  strcat(value, [_str cString]);
+}
+
+- (void)appendCString:(const char *)_cstr {
+  int l = strlen(_cstr);
+  _checkCapacity(self, l);
+  strcat(value, _cstr);
+}
+
+- (void)appendCString:(const char *)_cstr length:(unsigned)_len {
+  _checkCapacity(self, _len);
+  memcpy(&(value[len]), _cstr, _len);
+  len += _len;
+  value[len] = '\0';
+}
+
+// removing
+
+- (void)removeAllContents {
+  len = 0;
+  value[len] = '\0';
+}
+
+@end
diff --git a/skyrix-core/NGExtensions/NGCalendarDateRange.m b/skyrix-core/NGExtensions/NGCalendarDateRange.m
new file mode 100644 (file)
index 0000000..74e5ce7
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+  Copyright (C) 2004 Marcus Mueller
+
+  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.
+*/
+
+#include "NGCalendarDateRange.h"
+#include <NGExtensions/NSCalendarDate+misc.h>
+#include <NGExtensions/NSNull+misc.h>
+#include "common.h"
+
+@implementation NGCalendarDateRange
+
++ (id)calendarDateRangeWithStartDate:(NSCalendarDate *)start
+  endDate:(NSCalendarDate *)end
+{
+    return [[[self alloc] initWithStartDate:start endDate:end] autorelease];
+}
+
+- (id)initWithStartDate:(NSCalendarDate *)start endDate:(NSCalendarDate *)end {
+  NSAssert(start != nil, @"startDate MUST NOT be nil!");
+  NSAssert(end   != nil, @"endDate MUST NOT be nil!");
+  
+  if ((self = [super init])) {
+    if ([start compare:end] == NSOrderedAscending) {
+      self->startDate = [start copy];
+      self->endDate   = [end   copy];
+    }
+    else {
+      self->startDate = [end   copy];
+      self->endDate   = [start copy];
+    }
+  }
+  return self;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)zone {
+  /* object is immutable */
+  return [self retain];
+}
+
+/* accessors */
+
+- (NSCalendarDate *)startDate {
+  return self->startDate;
+}
+
+- (NSCalendarDate *)endDate {
+  return self->endDate;
+}
+
+- (NGCalendarDateRange *)intersectionDateRange:(NGCalendarDateRange *)other {
+  NSCalendarDate *a, *b, *c, *d;
+    
+  if ([self compare:other] == NSOrderedAscending) {
+    a = self->startDate;
+    b = self->endDate;
+    c = [other startDate];
+    d = [other endDate];
+  }
+  else {
+    a = [other startDate];
+    b = [other endDate];
+    c = self->startDate;
+    d = self->endDate;
+  }
+  if ([b compare:c] == NSOrderedAscending)
+    return nil; // no intersection
+  if ([b compare:d] == NSOrderedAscending)
+    return [NGCalendarDateRange calendarDateRangeWithStartDate:c endDate:b];
+  
+  return [NGCalendarDateRange calendarDateRangeWithStartDate:c endDate:d];
+}
+
+- (BOOL)doesIntersectWithDateRange:(NGCalendarDateRange *)_other {
+  // TODO: improve
+  if (_other == nil) return NO;
+  return [self intersectionDateRange:_other] != nil ? YES : NO;
+}
+
+- (NGCalendarDateRange *)unionDateRange:(NGCalendarDateRange *)other {
+  NSCalendarDate *a, *b, *c, *d;
+    
+  if ([self compare:other] == NSOrderedAscending) {
+    a = self->startDate;
+    b = self->endDate;
+    c = [other startDate];
+    d = [other endDate];
+  }
+  else {
+    a = [other startDate];
+    b = [other endDate];
+    c = self->startDate;
+    d = self->endDate;
+  }
+  if ([b compare:d] == NSOrderedAscending)
+    return [NGCalendarDateRange calendarDateRangeWithStartDate:a endDate:d];
+  
+  return [NGCalendarDateRange calendarDateRangeWithStartDate:a endDate:b];
+}
+
+- (BOOL)containsDate:(NSCalendarDate *)date {
+  return ([self->startDate earlierDate:date] == self->startDate && 
+         [self->endDate laterDate:date] == self->endDate) ? YES : NO;
+}
+
+/* comparison */
+
+- (BOOL)isEqual:(id)other {
+  if (other == nil)
+    return NO;
+  if (other == self)
+    return YES;
+  
+  if ([other isKindOfClass:self->isa] == NO)
+    return NO;
+  
+  return ([self->startDate isEqual:[other startDate]] && 
+         [self->endDate isEqual:[other endDate]]) ? YES : NO;
+}
+
+- (unsigned)hash {
+  return [self->startDate hash] ^ [self->endDate hash];
+}
+
+- (NSComparisonResult)compare:(NGCalendarDateRange *)other {
+  return [self->startDate compare:[other startDate]];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *description;
+    
+  description = [NSMutableString stringWithCapacity:64];
+
+  [description appendFormat:@"<%@[0x%x]: startDate:%@ endDate: ", 
+                NSStringFromClass(self->isa), self, self->startDate];
+  
+  if ([self->startDate isEqual:self->endDate])
+    [description appendString:@"== startDate"];
+  else
+    [description appendFormat:@"%@", self->endDate];
+  [description appendString:@">"];
+  return description;
+}
+
+@end /* NGCalendarDateRange */
+
+@implementation NSArray(NGCalendarDateRanges)
+
+- (NSArray *)arrayByCreatingDateRangesFromObjectsWithStartDateKey:(NSString *)s
+  andEndDateKey:(NSString *)e
+{
+  NSMutableArray *ma;
+  unsigned i, count;
+  
+  count = [self count];
+  ma    = [NSMutableArray arrayWithCapacity:count];
+  for (i = 0; i < count; i++) {
+    NGCalendarDateRange *daterange;
+    NSCalendarDate *start, *end;
+    id object;
+    
+    object = [self objectAtIndex:i];
+    start  = [object valueForKey:s];
+    end    = [object valueForKey:e];
+    
+    /* skip invalid data */
+    if (![start isNotNull]) continue;
+    if (![end   isNotNull]) continue;
+    
+    daterange =
+      [[NGCalendarDateRange alloc] initWithStartDate:start endDate:end];
+    if (daterange) [ma addObject:daterange];
+    [daterange release];
+  }
+  return ma;
+}
+
+- (BOOL)dateRangeArrayContainsDate:(NSCalendarDate *)_date {
+  unsigned i, count;
+  
+  if (_date == nil) 
+    return NO;
+  if ((count = [self count]) == 0)
+    return NO;
+
+  for (i = 0; i < count; i++) {
+    if ([[self objectAtIndex:i] containsDate:_date])
+      return YES;
+  }
+  return NO;
+}
+- (unsigned)indexOfFirstIntersectingDateRange:(NGCalendarDateRange *)_range {
+  unsigned i, count;
+  
+  if (_range == nil)
+    return NO;
+  
+  if ((count = [self count]) == 0)
+    return NSNotFound;
+
+  for (i = 0; i < count; i++) {
+    if ([[self objectAtIndex:i] doesIntersectWithDateRange:_range])
+      return i;
+  }
+  return NSNotFound;
+}
+
+- (NSArray *)arrayByCompactingContainedDateRanges {
+  // TODO: this is a candidate for unit testing ...
+  // TODO: pretty "slow" algorithm, improve
+  NSMutableArray *ma;
+  unsigned i, count;
+  
+  count = [self count];
+  if (count < 2)
+    return [[self copy] autorelease];
+  
+  ma = [NSMutableArray arrayWithCapacity:count];
+  [ma addObject:[self objectAtIndex:0]]; /* add first range */
+  
+  for (i = 1; i < count; i++) {
+    NGCalendarDateRange *rangeToAdd;
+    NGCalendarDateRange *availRange;
+    NGCalendarDateRange *newRange;
+    unsigned idx;
+    
+    rangeToAdd = [self objectAtIndex:i];
+    idx = [ma indexOfFirstIntersectingDateRange:rangeToAdd];
+    
+    if (idx == NSNotFound) {
+      /* range not yet covered in array */
+      [ma addObject:rangeToAdd];
+      continue;
+    }
+    
+    /* union old range and replace the entry */
+    
+    availRange = [ma objectAtIndex:idx];
+    newRange   = [availRange unionDateRange:rangeToAdd];
+    
+    [ma replaceObjectAtIndex:idx withObject:newRange];
+  }
+  /* Note: we might want to join ranges up to some "closeness" (eg 1s)? */
+  return [ma sortedArrayUsingSelector:@selector(compare:)];
+}
+
+@end /* NSArray(NGCalendarDateRanges) */
diff --git a/skyrix-core/NGExtensions/NGCustomFileManager.m b/skyrix-core/NGExtensions/NGCustomFileManager.m
new file mode 100644 (file)
index 0000000..2a0cb17
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGExtensions/NGCustomFileManager.h>
+#include "common.h"
+
+typedef struct {
+  NSString                *sourcePath;
+  NSString                *absolutePath;
+  NSString                *path;
+  NGCustomFileManagerInfo *info;
+  id                      fileManager;
+} NGCustomFMPath;
+
+@interface NGCustomFileManager(Helpers)
+- (NGCustomFMPath)_resolvePath:(NSString *)_path;
+- (BOOL)_boolDo:(SEL)_sel onPath:(NSString *)_path;
+- (BOOL)_boolDo:(SEL)_sel onPath:(NSString *)_path handler:(id)_handler;
+- (id)_do:(SEL)_sel onPath:(NSString *)_path;
+@end
+
+@implementation NGCustomFileManager
+
++ (int)version {
+  return [super version] + 0 /* v0 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 0,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+/* customization */
+
+- (NSString *)makeAbsolutePath:(NSString *)_path {
+  if ([_path isAbsolutePath])
+    return _path;
+  
+  return [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
+}
+
+- (NGCustomFileManagerInfo *)fileManagerInfoForPath:(NSString *)_path {
+  return nil;
+}
+
+/* common ops */
+
+- (NGCustomFMPath)_resolvePath:(NSString *)_path {
+  NGCustomFMPath p;
+  
+  p.sourcePath   = _path;
+  p.absolutePath = [self makeAbsolutePath:_path];
+  p.info         = [self fileManagerInfoForPath:_path];
+  p.path         = [p.info rewriteAbsolutePath:p.absolutePath];
+  p.fileManager  = [p.info fileManager];
+  return p;
+}
+
+- (BOOL)_boolDo:(SEL)_sel onPath:(NSString *)_path {
+  NGCustomFMPath p;
+  BOOL (*op)(id,SEL,NSString *);
+  
+  if (_sel == NULL) return NO;
+  p = [self _resolvePath:_path];
+  if ((_path = p.path) == nil) return NO;
+  if ((op = (void *)[p.fileManager methodForSelector:_sel]) == NULL) return NO;
+  
+  return op(p.fileManager, _sel, _path);
+}
+- (BOOL)_boolDo:(SEL)_sel onPath:(NSString *)_path handler:(id)_handler {
+  NGCustomFMPath p;
+  BOOL (*op)(id,SEL,NSString *,id);
+  
+  if (_sel == NULL) return NO;
+  p = [self _resolvePath:_path];
+  if ((_path = p.path) == nil) return NO;
+  if ((op = (void *)[p.fileManager methodForSelector:_sel]) == NULL) return NO;
+  
+  return op(p.fileManager, _sel, _path, _handler);
+}
+- (id)_do:(SEL)_sel onPath:(NSString *)_path {
+  NGCustomFMPath p;
+  id (*op)(id,SEL,NSString *);
+  
+  if (_sel == NULL) return NO;
+  p = [self _resolvePath:_path];
+  if ((_path = p.path) == nil) return NO;
+  if ((op = (void *)[p.fileManager methodForSelector:_sel]) == NULL) return NO;
+  
+  return op(p.fileManager, _sel, _path);
+}
+
+/* directory operations */
+
+- (BOOL)changeCurrentDirectoryPath:(NSString *)_path {
+  BOOL isDir = NO;
+  if ((_path = [self makeAbsolutePath:_path]) == nil) return NO;
+  
+  if (![self fileExistsAtPath:_path isDirectory:&isDir]) return NO;
+  if (!isDir) return NO;
+  
+  ASSIGNCOPY(self->cwd, _path);
+  return YES;
+}
+- (NSString *)currentDirectoryPath {
+  return self->cwd;
+}
+
+- (BOOL)createDirectoryAtPath:(NSString *)_path
+  attributes:(NSDictionary *)_ats
+{
+  NGCustomFMPath p;
+  p = [self _resolvePath:_path];
+  if (p.path == nil) return NO;
+  
+  return [p.fileManager createDirectoryAtPath:p.path attributes:_ats];
+}
+
+/* file operations */
+
+- (BOOL)copyPath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler {
+  NGCustomFileManagerInfo *sinfo, *dinfo;
+  
+  if ((_s = [self makeAbsolutePath:_s]) == nil) return NO;
+  if ((_d = [self makeAbsolutePath:_d]) == nil) return NO;
+  if ((sinfo = [self fileManagerInfoForPath:_s]) == nil) return NO;
+  if ((dinfo = [self fileManagerInfoForPath:_d]) == nil) return NO;
+  _s = [sinfo rewriteAbsolutePath:_s];
+  _d = [dinfo rewriteAbsolutePath:_d];
+  
+  if ([sinfo isEqual:dinfo]) /* same filemanager */
+    return [[sinfo fileManager] copyPath:_s toPath:_d handler:_handler];
+  
+  /* operation between different filemanagers ... */
+  return NO;
+}
+
+- (BOOL)movePath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler {
+  NGCustomFileManagerInfo *sinfo, *dinfo;
+  
+  if ((_s = [self makeAbsolutePath:_s]) == nil) return NO;
+  if ((_d = [self makeAbsolutePath:_d]) == nil) return NO;
+  if ((sinfo = [self fileManagerInfoForPath:_s]) == nil) return NO;
+  if ((dinfo = [self fileManagerInfoForPath:_d]) == nil) return NO;
+  _s = [sinfo rewriteAbsolutePath:_s];
+  _d = [dinfo rewriteAbsolutePath:_d];
+  
+  if ([sinfo isEqual:dinfo]) /* same filemanager */
+    return [[sinfo fileManager] movePath:_s toPath:_d handler:_handler];
+    
+  /* operation between different filemanagers ... */
+  return NO;
+}
+
+- (BOOL)linkPath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler {
+  NGCustomFileManagerInfo *sinfo, *dinfo;
+  
+  if ((_s = [self makeAbsolutePath:_s]) == nil) return NO;
+  if ((_d = [self makeAbsolutePath:_d]) == nil) return NO;
+  if ((sinfo = [self fileManagerInfoForPath:_s]) == nil) return NO;
+  if ((dinfo = [self fileManagerInfoForPath:_d]) == nil) return NO;
+  _s = [sinfo rewriteAbsolutePath:_s];
+  _d = [dinfo rewriteAbsolutePath:_d];
+  
+  if ([sinfo isEqual:dinfo]) /* same filemanager */
+    return [[sinfo fileManager] linkPath:_s toPath:_d handler:_handler];
+    
+  /* operation between different filemanagers ... */
+  return NO;
+}
+
+- (BOOL)removeFileAtPath:(NSString *)_path handler:(id)_handler {
+  return [self _boolDo:_cmd onPath:_path handler:_handler];
+}
+
+- (BOOL)createFileAtPath:(NSString *)_path contents:(NSData *)_contents
+  attributes:(NSDictionary *)_attributes
+{
+  NGCustomFMPath p;
+  p = [self _resolvePath:_path];
+  if (p.path == nil) return NO;
+  
+  return [p.fileManager
+                createFileAtPath:p.path
+                contents:_contents
+                attributes:_attributes];
+}
+
+/* getting and comparing file contents */
+
+- (NSData *)contentsAtPath:(NSString *)_path {
+  return [self _do:_cmd onPath:_path];
+}
+
+- (BOOL)contentsEqualAtPath:(NSString *)_path1 andPath:(NSString *)_path2 {
+  NGCustomFileManagerInfo *info1, *info2;
+  
+  if ((_path1 = [self makeAbsolutePath:_path1]) == nil) return NO;
+  if ((_path2 = [self makeAbsolutePath:_path2]) == nil) return NO;
+  if ((info1 = [self fileManagerInfoForPath:_path1]) == nil) return NO;
+  if ((info2 = [self fileManagerInfoForPath:_path2]) == nil) return NO;
+  _path1 = [info1 rewriteAbsolutePath:_path1];
+  _path2 = [info2 rewriteAbsolutePath:_path2];
+  
+  if ([info1 isEqual:info2]) /* same filemanager */
+    return [[info1 fileManager] contentsEqualAtPath:_path1 andPath:_path2];
+  
+  /* operation between different filemanagers ... */
+  return NO;
+}
+
+/* determining access to files */
+
+- (BOOL)fileExistsAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+- (BOOL)fileExistsAtPath:(NSString *)_path isDirectory:(BOOL *)_isDirectory {
+  NGCustomFMPath p;
+  p = [self _resolvePath:_path];
+  if (p.path == nil) return NO;
+  
+  return [p.fileManager fileExistsAtPath:p.path isDirectory:_isDirectory];
+}
+- (BOOL)isReadableFileAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+- (BOOL)isWritableFileAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+- (BOOL)isExecutableFileAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+- (BOOL)isDeletableFileAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+
+/* Getting and setting attributes */
+
+- (NSDictionary *)fileAttributesAtPath:(NSString *)_p traverseLink:(BOOL)_flag{
+  NGCustomFMPath p;
+  p = [self _resolvePath:_p];
+  if (p.path == nil) return NO;
+  
+  /* special link handling required ??? */
+  return [p.fileManager fileAttributesAtPath:p.path traverseLink:_flag];
+}
+
+- (NSDictionary *)fileSystemAttributesAtPath:(NSString *)_p {
+  return [self _do:_cmd onPath:_p];
+}
+
+- (BOOL)changeFileAttributes:(NSDictionary *)_attributes atPath:(NSString *)_p{
+  NGCustomFMPath p;
+  p = [self _resolvePath:_p];
+  if (p.path == nil) return NO;
+  
+  return [p.fileManager changeFileAttributes:_attributes atPath:p.path];
+}
+
+/* discovering directory contents */
+
+- (NSArray *)directoryContentsAtPath:(NSString *)_path {
+  /* this returns relative path's, can be passed back */
+  return [self _do:_cmd onPath:_path];
+}
+
+- (NSDirectoryEnumerator *)enumeratorAtPath:(NSString *)_path {
+  /* this needs to be wrapped ! */
+  return nil;
+}
+
+- (NSArray *)subpathsAtPath:(NSString *)_path {
+  /* this returns relative path's, can be passed back */
+  return [self _do:_cmd onPath:_path];
+}
+
+/* symbolic-link operations */
+
+- (BOOL)createSymbolicLinkAtPath:(NSString *)_p pathContent:(NSString *)_dpath{
+  /* should that process the link-path somehow ??? */
+  NGCustomFMPath p;
+  p = [self _resolvePath:_p];
+  if (p.path == nil) return NO;
+  
+  return [p.fileManager createSymbolicLinkAtPath:p.path pathContent:_dpath];
+}
+- (NSString *)pathContentOfSymbolicLinkAtPath:(NSString *)_path {
+  /* should that process the link-path somehow ??? */
+  return [self _do:_cmd onPath:_path];
+}
+
+/* feature check */
+
+- (BOOL)supportsVersioningAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+- (BOOL)supportsLockingAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+- (BOOL)supportsFolderDataSourceAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+
+- (BOOL)supportsFeature:(NSString *)_featureURI atPath:(NSString *)_path {
+  NGCustomFMPath p;
+  p = [self _resolvePath:_path];
+  if (p.path == nil) return NO;
+  
+  return [p.fileManager supportsFeature:_featureURI atPath:p.path];
+}
+
+/* writing */
+
+- (BOOL)writeContents:(NSData *)_content atPath:(NSString *)_path {
+  NGCustomFMPath p;
+  p = [self _resolvePath:_path];
+  if (p.path == nil) return NO;
+  
+  return [p.fileManager writeContents:_content atPath:p.path];
+}
+
+/* global-IDs */
+
+- (EOGlobalID *)globalIDForPath:(NSString *)_path {
+  NGCustomFileManagerInfo *info;
+  if ((_path = [self makeAbsolutePath:_path])      == nil) return NO;
+  if ((info = [self fileManagerInfoForPath:_path]) == nil) return NO;
+
+  if (![info supportsGlobalIDs])
+    return nil;
+  
+  if ((_path = [info rewriteAbsolutePath:_path]) == nil)
+    return NO;
+  
+  return [[info fileManager] globalIDForPath:_path];
+}
+
+- (NSString *)pathForGlobalID:(EOGlobalID *)_gid {
+  return nil;
+}
+
+/* trash */
+
+- (BOOL)supportsTrashFolderAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+- (NSString *)trashFolderForPath:(NSString *)_path {
+  return NO;
+}
+
+@end /* NGCustomFileManager */
+
+@implementation NGCustomFileManager(NGFileManagerVersioning)
+
+/* versioning */
+
+- (BOOL)checkoutFileAtPath:(NSString *)_path handler:(id)_handler {
+  return [self _boolDo:_cmd onPath:_path handler:_handler];
+}
+- (BOOL)releaseFileAtPath:(NSString *)_path handler:(id)_handler {
+  return [self _boolDo:_cmd onPath:_path handler:_handler];
+}
+- (BOOL)rejectFileAtPath:(NSString *)_path handler:(id)_handler {
+  return [self _boolDo:_cmd onPath:_path handler:_handler];
+}
+- (BOOL)checkoutFileAtPath:(NSString *)_path version:(NSString *)_version
+  handler:(id)_handler
+{
+  NGCustomFMPath p;
+  p = [self _resolvePath:_path];
+  if (p.path == nil) return NO;
+  
+  return [p.fileManager
+           checkoutFileAtPath:p.path version:_version handler:_handler];
+}
+
+/* versioning data */
+
+- (NSString *)lastVersionAtPath:(NSString *)_path {
+  return [self _do:_cmd onPath:_path];
+}
+- (NSArray *)versionsAtPath:(NSString *)_path {
+  return [self _do:_cmd onPath:_path];
+}
+
+- (NSData *)contentsAtPath:(NSString *)_path version:(NSString *)_version {
+  NGCustomFMPath p;
+  p = [self _resolvePath:_path];
+  if (p.path == nil) return NO;
+  
+  return [p.fileManager contentsAtPath:p.path version:_version];
+}
+
+- (NSDictionary *)fileAttributesAtPath:(NSString *)_path
+  traverseLink:(BOOL)_followLink
+  version:(NSString *)_version
+{
+  NGCustomFMPath p;
+  p = [self _resolvePath:_path];
+  if (p.path == nil) return NO;
+  
+  /* do something special to symlink ??? */
+  
+  return [p.fileManager
+           fileAttributesAtPath:p.path
+           traverseLink:_followLink
+           version:_version];
+}
+
+@end /* NGCustomFileManager(NGFileManagerVersioning) */
+
+@implementation NGCustomFileManager(NGFileManagerLocking)
+
+- (BOOL)lockFileAtPath:(NSString *)_path handler:(id)_handler {
+  return [self _boolDo:_cmd onPath:_path handler:_handler];
+}
+- (BOOL)unlockFileAtPath:(NSString *)_path handler:(id)_handler {
+  return [self _boolDo:_cmd onPath:_path handler:_handler];
+}
+- (BOOL)isFileLockedAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+
+/* access rights */
+
+- (BOOL)isLockableFileAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+- (BOOL)isUnlockableFileAtPath:(NSString *)_path {
+  return [self _boolDo:_cmd onPath:_path];
+}
+
+@end /* NGCustomFileManager(NGFileManagerLocking) */
+
+@implementation NGCustomFileManager(NGFileManagerDataSources)
+
+/* datasources (work on folders) */
+
+- (EODataSource *)dataSourceAtPath:(NSString *)_path {
+  return [self _do:_cmd onPath:_path];
+}
+
+- (EODataSource *)dataSource {
+  return [self dataSourceAtPath:[self currentDirectoryPath]];
+}
+
+@end /* NGCustomFileManager(NGFileManagerDataSources) */
+
+@implementation NGCustomFileManagerInfo
+
+- (id)initWithCustomFileManager:(NGCustomFileManager *)_master
+  fileManager:(id<NGFileManager,NSObject>)_fm
+{
+  self->master      = _master;
+  self->fileManager = [_fm retain];
+  return self;
+}
+- (id)init {
+  return [self initWithCustomFileManager:nil fileManager:nil];
+}
+
+- (void)dealloc {
+  [self->fileManager release];
+  [super dealloc];
+}
+
+- (void)resetMaster {
+  self->master = nil;
+}
+
+/* accessors */
+
+- (NGCustomFileManager *)master {
+  return self->master;
+}
+- (id<NGFileManager,NSObject>)fileManager {
+  return self->fileManager;
+}
+
+/* operations */
+
+- (NSString *)rewriteAbsolutePath:(NSString *)_path {
+  return _path;
+}
+
+/* capabilities */
+
+- (BOOL)supportsGlobalIDs {
+  return [self->fileManager respondsToSelector:@selector(globalIDForPath:)];
+}
+
+@end /* NGCustomFileManagerInfo */
diff --git a/skyrix-core/NGExtensions/NGDirectoryEnumerator.m b/skyrix-core/NGExtensions/NGDirectoryEnumerator.m
new file mode 100644 (file)
index 0000000..ee0d280
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGDirectoryEnumerator.h"
+#import <Foundation/NSFileManager.h>
+#include "common.h"
+
+@interface NGDirectoryEnumerator(PrivateMethods)
+- (void)recurseIntoDirectory:(NSString *)_path relativeName:(NSString *)_name;
+- (void)backtrack;
+- (void)findNextFile;
+@end
+
+@interface NGDirEntry : NSObject
+{
+@public
+  id           fileManager;
+  NSString     *path;
+  NSEnumerator *e;
+}
+
+- (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
+  path:(NSString *)_path;
+
+- (NSString *)readdir;
+
+@end
+
+@implementation NGDirectoryEnumerator
+
+- (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
+  directoryPath:(NSString *)_path 
+  recurseIntoSubdirectories:(BOOL)_recurse
+  followSymlinks:(BOOL)_follow
+  prefixFiles:(BOOL)_prefix
+{
+  self->fileManager = _fm
+    ? [_fm retain]
+    : [[NSFileManager defaultManager] retain];
+
+  self->pathStack = [[NSMutableArray alloc] init];
+  self->enumStack = [[NSMutableArray alloc] init];
+  self->flags.isRecursive = _recurse;
+  self->flags.isFollowing = _follow;
+  
+  self->topPath = [_path copy];
+  
+  [self recurseIntoDirectory:_path relativeName:@""];
+  
+  return self;
+}
+
+- (id)initWithDirectoryPath:(NSString *)_path 
+  recurseIntoSubdirectories:(BOOL)_recurse
+  followSymlinks:(BOOL)_follow
+  prefixFiles:(BOOL)_prefix
+{
+  return [self initWithFileManager:nil
+               directoryPath:_path
+               recurseIntoSubdirectories:_recurse
+               followSymlinks:_follow
+               prefixFiles:_prefix];
+}
+
+- (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm {
+  return [self initWithFileManager:_fm
+               directoryPath:@"/"
+               recurseIntoSubdirectories:YES
+               followSymlinks:NO
+               prefixFiles:YES];
+}
+- (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
+  directoryPath:(NSString *)_path
+{
+  return [self initWithFileManager:_fm
+               directoryPath:_path
+               recurseIntoSubdirectories:YES
+               followSymlinks:NO
+               prefixFiles:YES];
+}
+
+- (void)dealloc {
+  while ([self->pathStack count])
+    [self backtrack];
+  
+  [self->pathStack release];
+  [self->enumStack release];
+  [self->currentFileName release];
+  [self->currentFilePath release];
+  [self->topPath release];
+
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id<NSObject,NGFileManager>)fileManager {
+  return self->fileManager;
+}
+
+/* operations */
+
+- (NSDictionary *)directoryAttributes {
+  return [self->fileManager
+              fileAttributesAtPath:self->topPath
+              traverseLink:self->flags.isFollowing];
+}
+
+- (NSDictionary *)fileAttributes {
+  return [self->fileManager
+              fileAttributesAtPath:self->currentFilePath
+              traverseLink:self->flags.isFollowing];
+}
+
+- (void)skipDescendents {
+  if ([self->pathStack count])
+    [self backtrack];
+}
+
+/* enumerator */
+
+- (id)nextObject {
+  [self findNextFile];
+  return self->currentFileName;
+}
+
+/* internals */
+
+- (void)recurseIntoDirectory:(NSString *)_path relativeName:(NSString *)name {
+  /* 
+     recurses into directory `path' 
+     - pushes relative path (relative to root of search) on pathStack
+     - pushes system dir enumerator on enumPath 
+  */
+  NGDirEntry *dir;
+
+  //NSLog(@"RECURSE INTO: %@", _path);
+  
+  dir = [[NGDirEntry alloc] initWithFileManager:self->fileManager path:_path];
+  
+  if (dir) {
+    [pathStack addObject:name];
+    [enumStack addObject:dir];
+  }
+}
+
+- (void)backtrack {
+  /*
+    backtracks enumeration to the previous dir
+    - pops current dir relative path from pathStack
+    - pops system dir enumerator from enumStack
+    - sets currentFile* to nil
+  */
+  //NSLog(@"BACKTRACK: %@", [self->pathStack lastObject]);
+  [self->enumStack removeLastObject];
+  [self->pathStack removeLastObject];
+  [self->currentFileName release]; self->currentFileName = nil;
+  [self->currentFilePath release]; self->currentFilePath = nil;
+}
+
+- (void)findNextFile {
+  /*
+    finds the next file according to the top enumerator
+    - if there is a next file it is put in currentFile
+    - if the current file is a directory and if isRecursive calls 
+    recurseIntoDirectory:currentFile
+    - if the current file is a symlink to a directory and if isRecursive 
+    and isFollowing calls recurseIntoDirectory:currentFile
+    - if at end of current directory pops stack and attempts to
+    find the next entry in the parent
+    - sets currentFile to nil if there are no more files to enumerate
+  */
+  NGDirEntry *dir;
+  
+  [self->currentFileName release]; self->currentFileName = nil;
+  [self->currentFilePath release]; self->currentFilePath = nil;
+    
+  while ([self->pathStack count]) {
+    NSString     *dname;
+    NSString     *dtype;
+    
+    dir = [enumStack lastObject];
+    
+    if ((dname = [dir readdir]) == nil) {
+      /* If we reached the end of this directory, go back to the upper one */
+      [self backtrack];
+      continue;
+    }
+    
+    /* Skip "." and ".." directory entries */
+    
+    if ([dname isEqualToString:@"."]) continue;
+    if ([dname isEqualToString:@".."]) continue;
+    
+    /* Name of current file */
+    
+    self->currentFileName =
+      [[[pathStack lastObject]
+                   stringByAppendingPathComponent:dname]
+                   copy];
+    
+    /* Full path of current file */
+    
+    self->currentFilePath =
+      [[self->topPath stringByAppendingPathComponent:self->currentFileName]
+                      copy];
+    
+    dtype = [[self->fileManager
+                  fileAttributesAtPath:self->currentFilePath
+                  traverseLink:self->flags.isFollowing]
+                  objectForKey:NSFileType];
+    
+    // do not follow links
+    
+    if (!flags.isFollowing) {
+      if ([dtype isEqualToString:NSFileTypeSymbolicLink])
+        /* if link then return it as link */
+        break;
+    }
+    
+    /* Follow links - check for directory */
+
+    if ([dtype isEqualToString:NSFileTypeDirectory] &&
+        self->flags.isRecursive) {
+      [self recurseIntoDirectory:self->currentFilePath 
+            relativeName:self->currentFileName];
+    }
+    
+    break;
+  }
+}
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:128];
+
+  [ms appendFormat:@"<%@[0x%08X]: ", NSStringFromClass([self class]), self];
+
+  [ms appendFormat:@" dir='%@'", self->topPath];
+  [ms appendFormat:@" cname='%@'", self->currentFileName];
+  [ms appendFormat:@" cpath='%@'", self->currentFilePath];
+  [ms appendString:@">"];
+  
+  return ms;
+}
+
+@end /* NGDirectoryEnumerator */
+
+@implementation NGDirEntry
+
+- (id)initWithFileManager:(id)_fm path:(NSString *)_path {
+  self->fileManager = [_fm retain];
+  self->path        = [_path copy];
+  return self;
+}
+
+- (void)dealloc {
+  [self->e    release];
+  [self->path release];
+  [self->fileManager release];
+  [super dealloc];
+}
+
+- (NSString *)readdir {
+  NSString *s;
+  
+  if (self->e == nil) {
+    self->e = [[[self->fileManager directoryContentsAtPath:self->path]
+                                   sortedArrayUsingSelector:
+                                     @selector(compare:)]
+                                   objectEnumerator];
+    self->e = [self->e retain];
+  }
+  
+  s = [self->e nextObject];
+  //NSLog(@"readdir: %@", s);
+  
+  return s;
+}
+
+@end /* NGDirEntry */
diff --git a/skyrix-core/NGExtensions/NGExtensions-Info.plist b/skyrix-core/NGExtensions/NGExtensions-Info.plist
new file mode 100644 (file)
index 0000000..ad6ca31
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGExtensions</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.core.NGExtensions</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-core/NGExtensions/NGExtensions.m b/skyrix-core/NGExtensions/NGExtensions.m
new file mode 100644 (file)
index 0000000..42409eb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGExtensions.h"
+#include "NGBase64Coding.h"
+#include "NGBaseTypes.h"
+#include "NGBitSet.h"
+#include "NGHashMap.h"
+#include "NGMemoryAllocation.h"
+#include "NGStack.h"
+#include "NGBundleManager.h"
+#include "NGQuotedPrintableCoding.h"
+#include "NSArray+enumerator.h"
+#include "NSData+misc.h"
+#include "NSException+misc.h"
+#include "NSMethodSignature+misc.h"
+#include "NSObject+Values.h"
+#include "NSSet+enumerator.h"
+#include "NSString+Formatting.h"
+#include "NSString+misc.h"
+#include "NSDictionary+misc.h"
+#include "NSCalendarDate+misc.h"
+
+@implementation NGExtensions
+
+/* statically link Objective-C categories */
+
+extern void __link_NSProcessInfo_misc(void);
+extern void __link_NSCalendarDate_misc(void);
+extern void __link_EODataSource_NGExtensions(void);
+extern void __link_NSString_Formatting(void);
+extern void __link_NGBase64Coding(void);
+extern void __link_NGExtensions_NSObjectValues(void);
+
+- (void)_staticLinkClasses {
+   __link_NSProcessInfo_misc();
+   __link_NSCalendarDate_misc();
+   __link_EODataSource_NGExtensions();
+   __link_NSString_Formatting();
+   __link_NGBase64Coding();
+   __link_NGExtensions_NSObjectValues();
+}
+
+@end /* NGExtensions */
diff --git a/skyrix-core/NGExtensions/NGExtensions/AutoDefines.h b/skyrix-core/NGExtensions/NGExtensions/AutoDefines.h
new file mode 100644 (file)
index 0000000..745a45b
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_AutoDefines_H__
+#define __NGExtensions_AutoDefines_H__
+
+#if defined(__MINGW32__)
+#  define WITH_OPENSTEP 0
+#  define GNUSTEP  1
+#elif defined(__CYGWIN32__)
+#  define WITH_OPENSTEP 0
+#  ifndef GNUSTEP
+#    define GNUSTEP 1
+#  endif
+#elif defined(NeXT) || defined(WIN32)
+#  define WITH_OPENSTEP 1
+#  define GNUSTEP  0
+#  ifndef NeXT_RUNTIME
+#    define NeXT_RUNTIME 1
+#  endif
+#else
+#  define WITH_OPENSTEP 0
+#  define GNUSTEP  1
+#endif
+
+#endif /* __NGExtensions_AutoDefines_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/DOMNode+EOQualifier.h b/skyrix-core/NGExtensions/NGExtensions/DOMNode+EOQualifier.h
new file mode 100644 (file)
index 0000000..2d94e3b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOM_DOMNode_EOQualifier_H__
+#define __DOM_DOMNode_EOQualifier_H__
+
+#include <DOM/DOMNode.h>
+
+@class NSArray;
+@class EOQualifier;
+
+@interface DOMNode(EOQualifier)
+
+- (NSArray *)childrenMatchingQualifier:(EOQualifier *)_qualifier;
+- (NSArray *)descendantsMatchingQualifier:(EOQualifier *)_qualifier;
+
+@end
+
+#endif /* __DOM_DOMNode_EOQualifier_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOCacheDataSource.h b/skyrix-core/NGExtensions/NGExtensions/EOCacheDataSource.h
new file mode 100644 (file)
index 0000000..fd687fb
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_EOCacheDataSource_H__
+#define __NGExtensions_EOCacheDataSource_H__
+
+#import <EOControl/EODataSource.h>
+#import <Foundation/NSDate.h>
+
+@class NSTimer;
+
+@interface EOCacheDataSource : EODataSource
+{
+  EODataSource   *source;
+  id             cache;
+  NSTimeInterval timeout;
+  NSTimeInterval time;
+  NSTimer        *timer;
+
+  BOOL _isFetching;
+}
+
+- (id)initWithDataSource:(EODataSource *)_ds;
+
+/* accessors */
+
+- (void)setSource:(EODataSource *)_source;
+- (EODataSource *)source;
+
+- (void)setTimeout:(NSTimeInterval)_timeout;
+- (NSTimeInterval)timeout;
+
+- (void)clear;
+
+@end
+
+#endif /* __NGExtensions_EOCacheDataSource_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOCompoundDataSource.h b/skyrix-core/NGExtensions/NGExtensions/EOCompoundDataSource.h
new file mode 100644 (file)
index 0000000..7adf5bb
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_EOCompoundDataSource_H__
+#define __NGExtensions_EOCompoundDataSource_H__
+
+#import <EOControl/EODataSource.h>
+
+@class NSArray;
+@class EOQualifier;
+
+@interface EOCompoundDataSource : EODataSource
+{
+  NSArray     *sources;
+  EOQualifier *auxiliaryQualifier;
+  NSArray     *sortOrderings;
+}
+
+- (id)initWithDataSources:(NSArray *)_ds;
+
+/* accessors */
+
+- (void)setSources:(NSArray *)_sources;
+- (NSArray *)sources;
+
+- (void)setAuxiliaryQualifier:(EOQualifier *)_q;
+- (EOQualifier *)auxiliaryQualifier;
+- (void)setSortOrderings:(NSArray *)_o;
+- (NSArray *)sortOrderings;
+
+@end
+
+#endif /* __NGExtensions_EOCompoundDataSource_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EODataSource+NGExtensions.h b/skyrix-core/NGExtensions/NGExtensions/EODataSource+NGExtensions.h
new file mode 100644 (file)
index 0000000..ffe0f3d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_EODataSource_NGExtensions_H__
+#define __NGExtensions_EODataSource_NGExtensions_H__
+
+#import <EOControl/EODataSource.h>
+#include <NGExtensions/NGExtensionsDecls.h>
+
+@class EOFetchSpecification;
+
+NGExtensions_EXPORT NSString *EODataSourceDidChangeNotification;
+
+/*
+  If a fetchspecification without a qualifier is passed, the
+  datasource should fetch all objects by default. If the
+  EONoFetchWithEmptyQualifierHint value in the fspec hints-dictionary
+  is YES, an emtpy array should be returned.
+*/
+NGExtensions_EXPORT NSString *EONoFetchWithEmptyQualifierHint;
+
+@interface EODataSource(NGExtensions)
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fetchSpec;
+- (EOFetchSpecification *)fetchSpecification;
+
+- (void)postDataSourceChangedNotification;
+
+- (void)updateObject:(id)_obj;
+
+@end
+
+#endif /* __NGExtensions_EODataSource_NGExtensions_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOFetchSpecification+plist.h b/skyrix-core/NGExtensions/NGExtensions/EOFetchSpecification+plist.h
new file mode 100644 (file)
index 0000000..b751c27
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __EOFetchSpecification_plist_h__
+#define __EOFetchSpecification_plist_h__
+
+#include <EOControl/EOFetchSpecification.h>
+
+@class NSDictionary, NSString;
+
+@interface EOFetchSpecification(plist)
+
+- (id)initWithDictionary:(NSDictionary *)_dictionary;
+- (id)initWithString:(NSString *)_string;
+- (id)initWithPropertyList:(id)_plist owner:(id)_owner;
+
+@end
+
+#endif
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOFilterDataSource.h b/skyrix-core/NGExtensions/NGExtensions/EOFilterDataSource.h
new file mode 100644 (file)
index 0000000..3dbc6ba
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_EOFilterDataSource_H__
+#define __NGExtensions_EOFilterDataSource_H__
+
+#import <EOControl/EODataSource.h>
+
+@class NSArray;
+@class EOQualifier;
+
+@interface EOFilterDataSource : EODataSource
+{
+  EODataSource *source;
+  EOQualifier *auxiliaryQualifier;
+  NSArray     *sortOrderings;
+  NSArray     *groupings;
+}
+
+- (id)initWithDataSource:(EODataSource *)_ds;
+
+/* accessors */
+
+- (void)setSource:(EODataSource *)_source;
+- (EODataSource *)source;
+
+- (void)setAuxiliaryQualifier:(EOQualifier *)_q;
+- (EOQualifier *)auxiliaryQualifier;
+- (void)setSortOrderings:(NSArray *)_o;
+- (NSArray *)sortOrderings;
+- (void)setGroupings:(NSArray *)_groupings;
+- (NSArray *)groupings;
+
+@end
+
+#endif /* __NGExtensions_EOFilterDataSource_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOGrouping.h b/skyrix-core/NGExtensions/NGExtensions/EOGrouping.h
new file mode 100644 (file)
index 0000000..4b3abd7
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef _EOGrouping_h__
+#define _EOGrouping_h__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSArray, NSMutableArray;
+@class EOQualifier;
+
+@interface EOGrouping : NSObject
+{
+  NSString *defaultName;
+  NSArray  *sortOrderings;
+}
+
+- (id)initWithDefaultName:(NSString *)_defaultName;
+
+- (NSString *)defaultName;
+- (void)setDefaultName:(NSString *)_defaultName;
+
+- (NSArray *)sortOrderings;
+- (void)setSortOrderings:(NSArray *)_sortOrderings;
+
+- (NSString *)groupNameForObject:(id)object;
+- (NSArray *)orderedGroupNames;
+
+@end
+
+@interface EOGroupingSet : EOGrouping
+{
+  NSArray *groupings;
+}
+
+- (NSArray *)groupings;
+- (void)setGroupings:(NSArray *)_groupings;
+
+@end
+
+@interface EOKeyGrouping : EOGrouping
+{
+  NSString       *key;
+  NSMutableArray *groupNames; /* ??? to be fixed */
+}
+
+- (id)initWithKey:(NSString *)_key;
+
+- (NSString *)key;
+- (void)setKey:(NSString *)_key;
+
+@end
+
+@interface EOQualifierGrouping : EOGrouping
+{
+  EOQualifier *qualifier;
+  NSString    *name;
+}
+
+- (id)initWithQualifier:(EOQualifier *)_qualifier name:(NSString *)_name;
+
+- (void)setName:(NSString *)_name;
+- (NSString *)name;
+
+- (void)setQualifier:(EOQualifier *)_qualifier;
+- (EOQualifier *)qualifier;
+
+@end
+
+#import <Foundation/NSArray.h>
+
+@class NSDictionary;
+
+@interface NSArray(EOGrouping)
+- (NSDictionary *)arrayGroupedBy:(EOGrouping *)_grouping;
+@end
+
+#import <EOControl/EOFetchSpecification.h>
+
+extern NSString *EOGroupingHint;
+
+@interface EOFetchSpecification(Groupings)
+- (void)setGroupings:(NSArray *)_groupings;
+- (NSArray *)groupings;
+@end
+
+#endif /* _EOGrouping_h__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOGroupingSet.h b/skyrix-core/NGExtensions/NGExtensions/EOGroupingSet.h
new file mode 100644 (file)
index 0000000..edc0872
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef _EOGroupingSet_h__
+#define _EOGroupingSet_h__
+
+#include <NGExtensions/EOGrouping.h>
+
+#endif /* _EOGroupingSet_h__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOKeyGrouping.h b/skyrix-core/NGExtensions/NGExtensions/EOKeyGrouping.h
new file mode 100644 (file)
index 0000000..10a421f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef _EOKeyGrouping_h__
+#define _EOKeyGrouping_h__
+
+#include <NGExtensions/EOGrouping.h>
+
+#endif /* _EOKeyGrouping_h__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOKeyMapDataSource.h b/skyrix-core/NGExtensions/NGExtensions/EOKeyMapDataSource.h
new file mode 100644 (file)
index 0000000..0e84f8a
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_EOKeyMapDataSource_H__
+#define __NGExtensions_EOKeyMapDataSource_H__
+
+#import <EOControl/EODataSource.h>
+
+/*
+  EOKeyMapDataSource
+  
+  This class allows you to remap the keys of a source datasource on the fly. It
+  fully supports fetch enumerators.
+  
+  The class description of the datasource describes what keys the resulting
+  objects should have (note that the fetchspec isn't checked for validaty on
+  that).
+*/
+
+@class NSException, NSEnumerator, NSArray, NSClassDescription;
+@class NSMutableDictionary, NSDictionary;
+@class EOFetchSpecification, EOGlobalID;
+
+@interface EOKeyMapDataSource : EODataSource
+{
+  EOFetchSpecification *fspec;
+  EODataSource         *source;
+  NSClassDescription   *classDescription;
+  NSArray *entityKeys;
+  NSArray *mappedKeys;
+  id      map;
+}
+
+- (id)initWithDataSource:(EODataSource *)_ds map:(id)_map;
+
+/* accessors */
+
+- (void)setSource:(EODataSource *)_source;
+- (EODataSource *)source;
+- (void)setFetchSpecification:(EOFetchSpecification *)_fetchSpec;
+- (EOFetchSpecification *)fetchSpecification;
+
+- (NSException *)lastException;
+
+/* mappings (default implementations use the map) */
+
+- (EOFetchSpecification *)mapFetchSpecification:(EOFetchSpecification *)_fs;
+
+- (void)setClassDescriptionForObjects:(NSClassDescription *)_cd;
+- (NSClassDescription *)classDescriptionForObjects;
+
+- (id)mapCreatedObject:(id)_object;
+- (id)mapObjectForUpdate:(id)_object;
+- (id)mapObjectForInsert:(id)_object;
+- (id)mapObjectForDelete:(id)_object;
+- (id)mapFetchedObject:(id)_object;
+
+- (id)mapFromSourceObject:(id)_object;
+- (id)mapToSourceObject:(id)_object;
+
+/* fetching */
+
+- (Class)fetchEnumeratorClass;
+- (NSEnumerator *)fetchEnumerator;
+- (NSArray *)fetchObjects;
+
+- (void)clear;
+
+/* operations */
+
+- (void)updateObject:(id)_obj;
+- (void)insertObject:(id)_obj;
+- (void)deleteObject:(id)_obj;
+- (id)createObject;
+
+@end
+
+#import <Foundation/NSEnumerator.h>
+
+@interface EOKeyMapDataSourceEnumerator : NSEnumerator
+{
+  EOKeyMapDataSource *ds;
+  NSEnumerator       *source;
+}
+
+- (id)initWithKeyMapDataSource:(EOKeyMapDataSource *)_ds
+  fetchEnumerator:(NSEnumerator *)_enum;
+
+@end
+
+@interface EOMappedObject : NSObject
+{
+  id         original;
+  EOGlobalID *globalID;
+  NSMutableDictionary *values;
+  struct {
+    BOOL didChange:1;
+    int  reserved:31;
+  } flags;
+}
+
+- (id)initWithObject:(id)_object values:(NSDictionary *)_values;
+
+/* accessors */
+
+- (id)mappedObject;
+- (EOGlobalID *)globalID;
+
+- (BOOL)isModified;
+- (void)willChange;
+- (void)applyChangesOnObject;
+
+/* mimic dictionary */
+
+- (void)setObject:(id)_obj forKey:(id)_key;
+- (id)objectForKey:(id)_key;
+- (void)removeObjectForKey:(id)_key;
+
+- (NSEnumerator *)keyEnumerator;
+- (NSEnumerator *)objectEnumerator;
+
+/* KVC */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key;
+- (id)valueForKey:(NSString *)_key;
+
+@end
+
+#endif /* __NGExtensions_EOKeyMapDataSource_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOQualifier+CtxEval.h b/skyrix-core/NGExtensions/NGExtensions/EOQualifier+CtxEval.h
new file mode 100644 (file)
index 0000000..311cbd8
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_EOQualifier_ContextEvaluation_H__
+#define __NGExtensions_EOQualifier_ContextEvaluation_H__
+
+#import <EOControl/EOQualifier.h>
+#import <Foundation/NSArray.h>
+
+@interface EOQualifier(ContextEvaluation)
+
+- (BOOL)evaluateWithObject:(id)_object context:(id)_context;
+
+@end
+
+@interface NSArray(ContextEvaluation)
+
+- (NSArray *)filteredArrayUsingQualifier:(EOQualifier *)_qualifier
+  context:(id)_context;
+
+@end
+
+@interface NSObject(ContextQualifierComparisons)
+
+- (BOOL)isEqualTo:(id)_object inContext:(id)_context;
+- (BOOL)isNotEqualTo:(id)_object inContext:(id)_context;
+
+- (BOOL)isLessThan:(id)_object inContext:(id)_context;
+- (BOOL)isGreaterThan:(id)_object inContext:(id)_context;
+- (BOOL)isLessThanOrEqualTo:(id)_object inContext:(id)_context;
+- (BOOL)isGreaterThanOrEqualTo:(id)_object inContext:(id)_context;
+
+- (BOOL)doesContain:(id)_object inContext:(id)_context;
+
+- (BOOL)isLike:(NSString *)_object inContext:(id)_context;
+- (BOOL)isCaseInsensitiveLike:(NSString *)_object inContext:(id)_context;
+
+@end
+
+#endif /* __NGExtensions_EOQualifier_ContextEvaluation_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOQualifier+plist.h b/skyrix-core/NGExtensions/NGExtensions/EOQualifier+plist.h
new file mode 100644 (file)
index 0000000..bc6f11b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __EOQualifier_plist_h__
+#define __EOQualifier_plist_h__
+
+#include <EOControl/EOQualifier.h>
+
+@class NSDictionary, NSString;
+
+@interface EOQualifier(plist)
+
+- (id)initWithDictionary:(NSDictionary *)_dictionary;
+- (id)initWithString:(NSString *)_string;
+- (id)initWithPropertyList:(id)_plist owner:(id)_owner;
+
+@end
+
+#endif
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOQualifierGrouping.h b/skyrix-core/NGExtensions/NGExtensions/EOQualifierGrouping.h
new file mode 100644 (file)
index 0000000..2eb1f58
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef _EOQualifierGrouping_h__
+#define _EOQualifierGrouping_h__
+
+#include <NGExtensions/EOGrouping.h>
+
+#endif /* _EOQualifierGrouping_h__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOSortOrdering+plist.h b/skyrix-core/NGExtensions/NGExtensions/EOSortOrdering+plist.h
new file mode 100644 (file)
index 0000000..6e68c00
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __EOSortOrdering_plist_h__
+#define __EOSortOrdering_plist_h__
+
+#include <EOControl/EOSortOrdering.h>
+
+@class NSDictionary, NSString;
+
+@interface EOSortOrdering(plist)
+
+- (id)initWithDictionary:(NSDictionary *)_dictionary;
+- (id)initWithString:(NSString *)_string;
+- (id)initWithPropertyList:(id)_plist owner:(id)_owner;
+
+@end
+
+#endif
diff --git a/skyrix-core/NGExtensions/NGExtensions/EOTrueQualifier.h b/skyrix-core/NGExtensions/NGExtensions/EOTrueQualifier.h
new file mode 100644 (file)
index 0000000..a841ec3
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __EOExt_EOTrueQualifier_H__
+#define __EOExt_EOTrueQualifier_H__
+
+#include <EOControl/EOQualifier.h>
+
+/*
+  EOTrueQualifier
+  
+  This is an extremly simple qualifier which always evaluates to true ...
+  (eg used in the rule-system)
+  
+  Note: the EOTrueQualifier may not map properly to a storage based qualifier,
+  so you probably need to find a workaround to represent a generic 'true' in
+  your database.
+*/
+
+@interface EOTrueQualifier : EOQualifier < EOQualifierEvaluation >
+{
+}
+
+@end
+
+#endif /* __EOExt_EOTrueQualifier_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/FileObjectHolder.h b/skyrix-core/NGExtensions/NGExtensions/FileObjectHolder.h
new file mode 100644 (file)
index 0000000..41c2d5e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+// Created by Helge Hess on Wed Apr 17 2002.
+
+#ifndef __testrunloop_FileObject__
+#define __testrunloop_FileObject__
+
+#import <Foundation/NSObject.h>
+
+@class NSFileHandle, NSNotificationCenter;
+
+/*
+  This class is used to implement Unix filedescriptor notification
+  on the MacOSX Foundation library.
+*/
+
+@interface FileObjectHolder : NSObject 
+{
+  NSFileHandle *fileHandle;
+  NSString     *mode;
+  id   fileObject;
+  int  fd;
+  int  activities;
+  BOOL waitActive;
+}
+
+- (id)initWithFileObject:(id)_obj activities:(int)_act mode:(NSString *)_mode;
+
+/* accessors */
+
+- (NSFileHandle *)fileHandle;
+- (id)fileObject;
+- (int)fileDescriptor;
+- (int)activities;
+- (NSString *)mode;
+
+- (NSNotificationCenter *)notificationCenter;
+
+/* operations */
+
+- (void)wait;
+- (void)stopWaiting;
+
+@end
+
+#endif /* __testrunloop_FileObject__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/IndexFunc.h b/skyrix-core/NGExtensions/NGExtensions/IndexFunc.h
new file mode 100644 (file)
index 0000000..9deb371
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_IndexFunc_H__
+#define __NGExtensions_IndexFunc_H__
+
+#if defined(WIN32) && !defined(__CYGWIN32__)
+
+static inline const char *index(register const char *_str, register unsigned char _c) {
+  if (_str == NULL) return NULL;
+  while ((*_str != '\0') && (*_str != _c)) _str++;
+  if (*_str == _c) return _str;
+  return NULL;
+}
+
+#endif
+
+#endif /* __NGExtensions_IndexFunc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGBase64Coding.h b/skyrix-core/NGExtensions/NGExtensions/NGBase64Coding.h
new file mode 100644 (file)
index 0000000..17841d0
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGBase64Encoding_H__
+#define __NGExtensions_NGBase64Encoding_H__
+
+#import <Foundation/NSString.h>
+#import <Foundation/NSData.h>
+
+/*
+  Base64 encoder/decoder
+
+  Attention: these methods/function do _not_ generate a '\n' at the end of
+             the end of encoding (after the '=' signs).
+
+  The NSString and NSData have their own maximum line length, for strings
+  it is currently 1024 bytes and for data's 72 chars.
+*/
+
+@interface NSString(Base64Coding)
+
+- (NSString *)stringByEncodingBase64;
+- (NSString *)stringByDecodingBase64;
+- (NSData *)dataByDecodingBase64;
+
+@end
+
+@interface NSData(Base64Coding)
+
+- (NSData *)dataByEncodingBase64;
+- (NSData *)dataByDecodingBase64;
+- (NSString *)stringByEncodingBase64;
+- (NSString *)stringByDecodingBase64;
+
+@end
+
+/*
+  These function return the length of the resulting buffer or -1 on error
+*/
+int NGEncodeBase64(const void *_source, unsigned _len,
+                   void *_buffer, unsigned _bufferCapacity,
+                   int _maxLineWidth);
+int NGDecodeBase64(const void *_source, unsigned _len,
+                   void *_buffer, unsigned _bufferCapacity);
+
+#endif /* __NGExtensions_NGBase64Encoding_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGBaseTypes.h b/skyrix-core/NGExtensions/NGExtensions/NGBaseTypes.h
new file mode 100644 (file)
index 0000000..e87a49b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGBaseTypes_H__
+#define __NGExtensions_NGBaseTypes_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSValue.h>
+
+static inline NSNumber *shortObj(short _s) {
+  return [NSNumber numberWithShort:_s];
+}
+
+static inline NSNumber *intObj(int _i) {
+  return [NSNumber numberWithInt:_i];
+}
+
+static inline NSNumber *floatObj(float _f) {
+  return [NSNumber numberWithFloat:_f];
+}
+
+static inline NSNumber *doubleObj(double _d) {
+  return [NSNumber numberWithDouble:_d];
+}
+
+static inline NSString *cstrObj(const char *_c) {
+  return [NSString stringWithCString:_c];
+}
+
+#endif /* __NGExtensions_NGBaseTypes_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGBitSet.h b/skyrix-core/NGExtensions/NGExtensions/NGBitSet.h
new file mode 100644 (file)
index 0000000..f2bd7af
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGBitSet_H__
+#define __NGExtensions_NGBitSet_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSRange.h>
+
+@class NSArray, NSEnumerator;
+
+typedef unsigned int NGBitSetStorage;
+
+@protocol NGBitSet < NSObject >
+
+// state
+
+- (unsigned int)count;
+
+// membership
+
+- (BOOL)isMember:(unsigned int)_element;
+- (void)addMember:(unsigned int)_element;
+- (void)addMembersInRange:(NSRange)_range;
+- (void)removeMember:(unsigned int)_element;
+- (void)removeMembersInRange:(NSRange)_range;
+- (void)removeAllMembers;
+
+@end
+
+@interface NGBitSet : NSObject < NGBitSet, NSCopying, NSCoding >
+{
+@protected
+  unsigned int    universe;
+  unsigned int    count;
+  NGBitSetStorage *storage;
+}
+
++ (id)bitSet;
++ (id)bitSetWithCapacity:(unsigned)_capacity;
++ (id)bitSetWithBitSet:(NGBitSet *)_set;
+- (id)init;
+- (id)initWithCapacity:(unsigned)_capacity; // designated initializer
+- (id)initWithBitSet:(NGBitSet *)_set;
+- (id)initWithNullTerminatedArray:(unsigned int *)_array;
+
+// state
+
+- (unsigned int)capacity;
+
+// membership
+
+- (unsigned int)firstMember;
+- (unsigned int)lastMember;
+- (void)addMembersFromBitSet:(NGBitSet *)_set;
+
+// equality
+
+- (BOOL)isEqual:(id)_object;
+- (BOOL)isEqualToSet:(NGBitSet *)_set;
+
+// enumerator
+
+- (NSEnumerator *)objectEnumerator;
+
+// NSCopying
+
+- (id)copy;
+- (id)copyWithZone:(NSZone *)_zone;
+
+// NSCoding
+
+- (void)encodeWithCoder:(NSCoder *)_coder;
+- (id)initWithCoder:(NSCoder *)_coder;
+
+// description
+
+- (NSString *)description;
+- (NSArray *)toArray;
+
+@end
+
+NSString *stringValueForBitset(unsigned int _set, char _setC, char _unsetC,
+                               short _wide);
+
+#endif /* __NGExtensions_NGBitSet_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGBundleManager.h b/skyrix-core/NGExtensions/NGExtensions/NGBundleManager.h
new file mode 100644 (file)
index 0000000..8077be0
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NGBundleManager_H__
+#define __NGExtensions_NGBundleManager_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSBundle.h>
+#import <Foundation/NSMapTable.h>
+#include <NGExtensions/NGExtensionsDecls.h>
+
+@class NSString, NSArray, NSMutableArray, NSDictionary, NSMutableSet;
+@class EOQualifier;
+
+/*
+  NGBundleManager
+
+  NGBundleManager is a class similiar to a Java class loader. It searches
+  for dynamically loadable bundles in a specified path set.
+
+  The default bundle search path is:
+
+    1. bundles contained in the main-bundle
+    2. pathes specified by the 'NGBundlePath' user default
+    3. pathes specified by the 'NGBundlePath' environment variable
+
+  Bundles managed by NGBundleManager can specify load-requirements, this
+  is done via the 'bundle-info.plist' file contained at the root of the
+  bundle directory. The file is a property list file and can specify required
+  and provided classes.
+  
+  Example bundle-info.plist:
+    {
+      bundleHandler = "MyBundleManager";
+      
+      provides = {
+        classes = ( { name = MyClass; } );
+      };
+      requires = {
+        bundleManagerVersion = 1;
+        bundles = ( { name = Foundation; type = framework; } );
+        classes = ( { name = NSObject; exact-version = 1; } );
+      };
+    }
+*/
+
+NGExtensions_EXPORT NSString *NGBundleWasLoadedNotificationName;
+
+@class NGBundleManager;
+
+typedef BOOL (*NGBundleResourceSelector)(NSString        *_resourceName,
+                                         NSString        *_resourceType,
+                                         NSString        *_path,
+                                         NSDictionary    *_resourceConfig,
+                                         NGBundleManager *_bundleManager,
+                                         void            *_context);
+
+@interface NGBundleManager : NSObject
+{
+@private
+  NSMutableArray *bundleSearchPaths;
+  NSMapTable     *pathToBundle;
+  NSMapTable     *pathToBundleInfo;
+  NSMapTable     *nameToBundle;
+
+  /* bundles loaded by the manager (NSBundle->BundleManager) */
+  NSMapTable     *loadedBundles;
+
+  /* the following are maintained using NSBundleDidLoadNotification .. */
+  NSMapTable     *classToBundle;
+  NSMapTable     *classNameToBundle;
+  NSMapTable     *categoryNameToBundle;
+
+  // transient
+  NSMutableSet *loadingBundles;
+}
+
++ (id)defaultBundleManager;
+
+/*
+ * bundle access
+ */
+
+- (NSBundle *)bundleWithName:(NSString *)name type:(NSString *)_type;
+- (NSBundle *)bundleWithName:(NSString *)name; // type=='bundle'
+- (NSBundle *)bundleForClassNamed:(NSString *)aClassName;
+- (NSBundle *)bundleForClass:(Class)aClass;
+- (NSBundle *)bundleWithPath:(NSString *)path;
+
+/*
+ * dependencies
+ */
+
+/* returns the names of the bundles required by the bundle */
+- (NSArray *)bundlesRequiredByBundle:(NSBundle *)_bundle;
+
+/* returns the names of the classes provided by the bundle */
+- (NSArray *)classesProvidedByBundle:(NSBundle *)_bundle;
+
+/* returns the names of the classes required by the bundle */
+- (NSArray *)classesRequiredByBundle:(NSBundle *)_bundle;
+
+/*
+ * loading
+ */
+
+- (id)loadBundle:(NSBundle *)_bundle;
+
+/*
+ * bundle manager object
+ */
+
+- (id)principalObjectOfBundle:(NSBundle *)_bundle;
+
+/*
+ * resources
+ */
+
+- (NSDictionary *)configForResource:(id)_resource ofType:(NSString *)_type
+  providedByBundle:(NSBundle *)_bundle;
+
+- (NSBundle *)bundleProvidingResource:(id)_resourceName
+  ofType:(NSString *)_resourceType;
+
+- (NSArray *)bundlesProvidingResource:(id)_resourceName
+  ofType:(NSString *)_resourceType;
+
+- (NSBundle *)bundleProvidingResourceOfType:(NSString *)_resourceType
+  matchingQualifier:(EOQualifier *)_qual;
+- (NSBundle *)bundlesProvidingResourcesOfType:(NSString *)_resourceType
+  matchingQualifier:(EOQualifier *)_qual;
+
+/*
+  This returns an array of NSDictionaries describing the provided
+  resources.
+*/
+- (NSArray *)providedResourcesOfType:(NSString *)_resourceType;
+
+- (NSString *)pathForBundleProvidingResource:(id)_resourceName
+  ofType:(NSString *)_type
+  resourceSelector:(NGBundleResourceSelector)_selector
+  context:(void *)_context;
+
+@end /* NGBundleManager */
+
+@interface NSBundle(NGLanguageResourceExtensions)
+
+- (NSString *)pathForResource:(NSString *)_name ofType:(NSString *)_ext
+  inDirectory:(NSString *)_directory
+  languages:(NSArray *)_languages;
+
+- (NSString *)pathForResource:(NSString *)_name ofType:(NSString *)_ext
+  languages:(NSArray *)_languages;
+
+@end /* NSBundle(NGLanguageResourceExtensions) */
+
+@interface NSBundle(NGBundleManagerExtensions)
+
+/* Returns the object managing the bundle (might be the principal class) */
+- (id)principalObject;
+
+- (NSArray *)providedResourcesOfType:(NSString *)_resourceType;
+
+/* Returns the name of the bundle */
+- (NSString *)bundleName;
+
+/* Returns the type of the bundle */
+- (NSString *)bundleType;
+
+/* Returns the names of the classes provided by the bundle */
+- (NSArray *)providedClasses;
+
+/* Returns the names of the classes required by the bundle */
+- (NSArray *)requiredClasses;
+
+/* Returns the names of other bundles required for loading this bundle */
+- (NSArray *)requiredBundles;
+
+/* Return a NSDictionary with bundle-info configuration of the specified rsrc */
+- (NSDictionary *)configForResource:(id)_resource ofType:(NSString *)_type;
+
+@end /* NSBundle(NGBundleManagerExtensions) */
+
+@interface NSObject(BundleManager)
+
+- (id)initForBundle:(NSBundle *)_bundle bundleManager:(NGBundleManager *)_mng;
+
+/*
+  This method is invoked if the bundle was successfully loaded.
+*/
+- (void)bundleManager:(NGBundleManager *)_manager
+  didLoadBundle:(NSBundle *)_bundle;
+
+@end /* NSObject(BundleManager) */
+
+@interface NGBundle : NSBundle
+@end
+
+#endif
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGCString.h b/skyrix-core/NGExtensions/NGExtensions/NGCString.h
new file mode 100644 (file)
index 0000000..c3f3e53
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NGCString_H__
+#define __NGExtensions_NGCString_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+
+@interface NGCString : NSObject < NSCopying, NSMutableCopying, NSCoding >
+{
+  char         *value;
+  unsigned int len;
+}
+
++ (id)stringWithCString:(const char *)_value length:(unsigned)_len;
++ (id)stringWithCString:(const char *)_value;
+- (id)initWithCString:(const char *)_value length:(unsigned)_len;
+- (id)initWithCString:(const char *)_value;
+
+// unicode
+
+- (unsigned int)length;
+- (unichar)characterAtIndex:(unsigned int)_idx;
+
+// comparing
+
+- (BOOL)isEqual:(id)_object;
+- (BOOL)isEqualToCString:(NGCString *)_cstr;
+- (BOOL)isEqualToString:(NSString *)_str;
+- (unsigned)hash;
+
+// copying
+
+- (id)copyWithZone:(NSZone *)_zone;
+- (id)mutableCopyWithZone:(NSZone *)_zone;
+
+// archiving
+
+- (void)encodeWithCoder:(NSCoder *)_coder;
+- (id)initWithCoder:(NSCoder *)_decoder;
+
+// getting C strings
+
+- (const char *)cString;
+- (unsigned int)cStringLength;
+- (void)getCString:(char *)_buffer;
+- (void)getCString:(char *)_buffer maxLength:(unsigned int)_maxLength;
+- (char)charAtIndex:(unsigned int)_idx;
+
+// getting numeric values
+
+- (double)doubleValue;
+- (float)floatValue;
+- (int)intValue;
+- (NSString *)stringValue;
+
+// description
+
+- (NSString *)description;
+
+@end
+
+@interface NGMutableCString : NGCString
+{
+  unsigned int capacity;
+}
+
+// appending
+
+- (void)appendString:(id)_str; // either NSString or NGCString
+- (void)appendCString:(const char *)_cstr;
+- (void)appendCString:(const char *)_cstr length:(unsigned)_len;
+
+// removing
+
+- (void)removeAllContents;
+
+@end
+
+#endif /* __NGExtensions_NGCString_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGCalendarDateRange.h b/skyrix-core/NGExtensions/NGExtensions/NGCalendarDateRange.h
new file mode 100644 (file)
index 0000000..3760064
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2004 Marcus Mueller
+
+  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$
+
+#ifndef        __NGExtensions_NGCalendarDateRange_H_
+#define        __NGExtensions_NGCalendarDateRange_H_
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSArray.h>
+
+@class NSString, NSCalendarDate;
+
+@interface NGCalendarDateRange : NSObject <NSCopying>
+{
+  NSCalendarDate *startDate;
+  NSCalendarDate *endDate;
+}
+
++ (id)calendarDateRangeWithStartDate:(NSCalendarDate *)_start
+  endDate:(NSCalendarDate *)_end;
+- (id)initWithStartDate:(NSCalendarDate *)_start
+  endDate:(NSCalendarDate *)_end;
+
+/* accessors */
+
+- (NSCalendarDate *)startDate;
+- (NSCalendarDate *)endDate;
+
+/* comparison */
+
+- (NSComparisonResult)compare:(NGCalendarDateRange *)other;
+
+/* operations */
+
+- (NGCalendarDateRange *)intersectionDateRange:(NGCalendarDateRange *)other;
+- (NGCalendarDateRange *)unionDateRange:(NGCalendarDateRange *)other;
+
+- (BOOL)doesIntersectWithDateRange:(NGCalendarDateRange *)_other;
+
+- (BOOL)containsDate:(NSCalendarDate *)date;
+
+@end
+
+@interface NSArray(NGCalendarDateRanges)
+
+- (NSArray *)arrayByCreatingDateRangesFromObjectsWithStartDateKey:(NSString *)s
+  andEndDateKey:(NSString *)e;
+
+- (unsigned)indexOfFirstIntersectingDateRange:(NGCalendarDateRange *)_range;
+- (BOOL)dateRangeArrayContainsDate:(NSCalendarDate *)_date;
+
+- (NSArray *)arrayByCompactingContainedDateRanges;
+
+@end
+
+#endif /* __NGExtensions_NGCalendarDateRange_H_ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGCharBuffers.h b/skyrix-core/NGExtensions/NGExtensions/NGCharBuffers.h
new file mode 100644 (file)
index 0000000..9315a33
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGCharBuffers_H__
+#define __NGExtensions_NGCharBuffers_H__
+
+#include <string.h>
+#include <ctype.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSException.h>
+#import <NGExtensions/NGMemoryAllocation.h>
+
+typedef struct {
+  unsigned      capacity;
+  unsigned      length;
+  unsigned char increaseRatio;
+  unsigned char *buffer; // zero terminated buffer
+} NGCharBuffer8Struct;
+
+typedef NGCharBuffer8Struct *NGCharBuffer8;
+
+static inline NGCharBuffer8 NGCharBuffer8_init(NGCharBuffer8 _str,
+                                               unsigned _capacity) {
+  _str->capacity      = _capacity;
+  _str->length        = 0;
+  _str->increaseRatio = 2;
+  _str->buffer        = NGMallocAtomic(_capacity);
+  _str->buffer[0]     = '\0';
+  return _str;
+}
+static inline void NGCharBuffer8_reset(NGCharBuffer8 _str) {
+  if (_str) {
+    _str->capacity = 0;
+    _str->length   = 0;
+    _str->increaseRatio = 0;
+    NGFree(_str->buffer);
+    _str->buffer = NULL;
+  }
+}
+
+static inline NGCharBuffer8 NGCharBuffer8_new(unsigned _capacity) {
+  NGCharBuffer8 str = NULL;
+  str = NGMalloc(sizeof(NGCharBuffer8Struct));
+  return NGCharBuffer8_init(str, _capacity);
+}
+
+static inline NGCharBuffer8 NGCharBuffer8_newWithCString(const char *_cstr) {
+  NGCharBuffer8 str = NULL;
+  str = NGMalloc(sizeof(NGCharBuffer8Struct));
+  str = NGCharBuffer8_init(str, strlen(_cstr) + 2);
+  strcpy(str->buffer, _cstr);
+  return str;
+}
+
+static inline void NGCharBuffer8_dealloc(NGCharBuffer8 _str) {
+  if (_str) {
+    NGCharBuffer8_reset(_str);
+    NGFree(_str);
+    _str = NULL;
+  }
+}
+
+static inline void NGCharBuffer8_checkCapacity(NGCharBuffer8 _str,
+                                               unsigned _needed) {
+  if (_str->capacity < (_str->length + _needed + 1)) {
+    // increase size
+    unsigned char *oldBuffer = _str->buffer;
+
+    _str->capacity *= _str->increaseRatio;
+    if (_str->capacity < (_str->length + _needed + 1))
+      _str->capacity += _needed + 1;
+    
+    _str->buffer   = NGMallocAtomic(_str->capacity + 2);
+    memcpy(_str->buffer, oldBuffer, (_str->length + 1));
+    NGFree(oldBuffer);
+    oldBuffer = NULL;
+  }
+}
+
+static inline void NGCharBuffer8_addChar(NGCharBuffer8 _str, unsigned char _c) {
+  NGCharBuffer8_checkCapacity(_str, 1);
+
+  _str->buffer[_str->length] = _c;
+  (_str->length)++;
+  _str->buffer[_str->length] = '\0';
+}
+
+static inline void NGCharBuffer8_addCString(NGCharBuffer8 _str, char *_cstr) {
+  unsigned len;
+  
+  if (_cstr == NULL)
+    return;
+
+  len = strlen(_cstr);
+  NGCharBuffer8_checkCapacity(_str, len);
+  strcat(_str->buffer, _cstr);
+  _str->length += len;
+}
+
+static inline void NGCharBuffer8_removeContents(NGCharBuffer8 _str) {
+  _str->length = 0;
+  _str->buffer[0] = '\0';
+}
+
+static inline NSString *NGCharBuffer8_makeStringAndDealloc(NGCharBuffer8 _str) {
+  if (_str == NULL) {
+    return nil;
+  }
+  else {
+    NSString *str = [NSString stringWithCString:_str->buffer length:_str->length];
+
+    NSCAssert3(strlen(_str->buffer) == _str->length,
+               @"length of cstring(%s) and the buffer do not match (%i vs %i)",
+               _str->buffer, strlen(_str->buffer), _str->length);
+
+    NGCharBuffer8_dealloc(_str); _str = NULL;
+    return str;
+  }
+}
+
+static inline void NGCharBuffer8_stripTrailingSpaces(NGCharBuffer8 _str) {
+  if (_str == NULL)
+    return;
+  else if (_str->length == 0)
+    return;
+  else {
+    while (_str->length > 0) {
+      unsigned char c = _str->buffer[_str->length - 1];
+
+      if (isspace((int)c) || (c == '\n') || (c == '\r')) {
+        (_str->length)--;
+      }
+      else {
+        break;
+      }
+    }
+    _str->buffer[_str->length] = '\0';
+  }
+}
+
+#endif /* __NGExtensions_NGCharBuffers_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGCustomFileManager.h b/skyrix-core/NGExtensions/NGExtensions/NGCustomFileManager.h
new file mode 100644 (file)
index 0000000..5e76f3c
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGCustomFileManager_H__
+#define __NGCustomFileManager_H__
+
+#include <NGExtensions/NGFileManager.h>
+
+/*
+  An abstract baseclass for developing custom filemanagers which are ideally
+  based on other filemanager classes.
+*/
+
+@class NGCustomFileManagerInfo;
+
+@interface NGCustomFileManager : NGFileManager
+{
+}
+
+/* customization */
+
+- (NSString *)makeAbsolutePath:(NSString *)_path;
+- (NGCustomFileManagerInfo *)fileManagerInfoForPath:(NSString *)_path;
+
+@end
+
+@interface NGCustomFileManager(NGFileManagerVersioning)
+
+/* versioning */
+
+- (BOOL)checkoutFileAtPath:(NSString *)_path handler:(id)_handler;
+- (BOOL)releaseFileAtPath:(NSString *)_path  handler:(id)_handler;
+- (BOOL)rejectFileAtPath:(NSString *)_path   handler:(id)_handler;
+- (BOOL)checkoutFileAtPath:(NSString *)_path version:(NSString *)_version
+  handler:(id)_handler;
+
+/* versioning data */
+
+- (NSString *)lastVersionAtPath:(NSString *)_path;
+- (NSArray *)versionsAtPath:(NSString *)_path;
+- (NSData *)contentsAtPath:(NSString *)_path version:(NSString *)_version;
+- (NSDictionary *)fileAttributesAtPath:(NSString *)_path
+  traverseLink:(BOOL)_followLink
+  version:(NSString *)_version;
+
+@end
+
+@interface NGCustomFileManager(NGFileManagerDataSources)
+
+/* datasources (work on folders) */
+
+- (EODataSource *)dataSourceAtPath:(NSString *)_path;
+- (EODataSource *)dataSource; // works on current-directory-path
+
+@end
+
+@interface NGCustomFileManager(NGFileManagerLocking)
+
+- (BOOL)lockFileAtPath:(NSString *)_path handler:(id)_handler;
+- (BOOL)unlockFileAtPath:(NSString *)_path handler:(id)_handler;
+- (BOOL)isFileLockedAtPath:(NSString *)_path;
+
+/* access rights */
+- (BOOL)isLockableFileAtPath:(NSString *)_path;
+- (BOOL)isUnlockableFileAtPath:(NSString *)_path;
+
+@end
+
+@interface NGCustomFileManagerInfo : NSObject
+{
+@private
+  NGCustomFileManager        *master;      /* non retained */
+  id<NGFileManager,NSObject> fileManager;
+}
+
+- (id)initWithCustomFileManager:(NGCustomFileManager *)_master
+  fileManager:(id<NGFileManager,NSObject>)_fm;
+
+- (void)resetMaster;
+
+/* accessors */
+
+- (NGCustomFileManager *)master;
+- (id<NGFileManager,NSObject>)fileManager;
+
+/* operations */
+
+- (NSString *)rewriteAbsolutePath:(NSString *)_path;
+
+/* capabilities */
+
+- (BOOL)supportsGlobalIDs;
+
+@end
+
+#endif /* __NGCustomFileManager_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGDirectoryEnumerator.h b/skyrix-core/NGExtensions/NGExtensions/NGDirectoryEnumerator.h
new file mode 100644 (file)
index 0000000..118d2ff
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGDirectoryEnumerator_H__
+#define __NGDirectoryEnumerator_H__
+
+#import <Foundation/NSEnumerator.h>
+#include <NGExtensions/NGFileManager.h>
+
+/*
+  A class which is compatible to NSDirectoryEnumerator, but works with any
+  object conforming to the filemanager interface.
+*/
+
+@class NSString, NSMutableArray, NSFileManager, NSDictionary;
+
+@interface NGDirectoryEnumerator : NSEnumerator
+{
+  id<NSObject,NGFileManager> fileManager;
+
+  NSMutableArray *enumStack;
+  NSMutableArray *pathStack;
+  NSString       *currentFileName;
+  NSString       *currentFilePath;
+  NSString       *topPath;
+  struct {
+    BOOL isRecursive:1;
+    BOOL isFollowing:1;
+  } flags;
+}
+
+- (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
+  directoryPath:(NSString *)path 
+  recurseIntoSubdirectories:(BOOL)recurse
+  followSymlinks:(BOOL)follow
+  prefixFiles:(BOOL)prefix;
+- (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm;
+- (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
+  directoryPath:(NSString *)_path;
+
+- (id<NSObject,NGFileManager>)fileManager;
+
+- (NSDictionary *)directoryAttributes;
+- (NSDictionary *)fileAttributes;
+
+- (void)skipDescendents;
+
+@end
+
+#endif /* __NGDirectoryEnumerator_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGExtensions.h b/skyrix-core/NGExtensions/NGExtensions/NGExtensions.h
new file mode 100644 (file)
index 0000000..52839d4
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_H__
+#define __NGExtensions_H__
+
+#include <NGExtensions/AutoDefines.h>
+
+#if defined(LIB_FOUNDATION_LIBRARY)
+#  define NoZone nil
+#else
+#  define NoZone NULL
+#endif
+
+#include <NGExtensions/EODataSource+NGExtensions.h>
+#include <NGExtensions/EOGrouping.h>
+#include <NGExtensions/EOGroupingSet.h>
+#include <NGExtensions/EOKeyGrouping.h>
+#include <NGExtensions/EOQualifierGrouping.h>
+#include <NGExtensions/NGBase64Coding.h>
+#include <NGExtensions/NGBaseTypes.h>
+#include <NGExtensions/NGBitSet.h>
+#include <NGExtensions/NGBundleManager.h>
+#include <NGExtensions/NGFileManager.h>
+#include <NGExtensions/NGHashMap.h>
+#include <NGExtensions/NGMemoryAllocation.h>
+#include <NGExtensions/NGMerging.h>
+#include <NGExtensions/NGQuotedPrintableCoding.h>
+#include <NGExtensions/NGStack.h>
+#include <NGExtensions/NSArray+enumerator.h>
+#include <NGExtensions/NSCalendarDate+misc.h>
+#include <NGExtensions/NSData+misc.h>
+#include <NGExtensions/NSDictionary+misc.h>
+#include <NGExtensions/NSURL+misc.h>
+#include <NGExtensions/NSEnumerator+misc.h>
+#include <NGExtensions/NSException+misc.h>
+#include <NGExtensions/NSMethodSignature+misc.h>
+#include <NGExtensions/NSNull+misc.h>
+#include <NGExtensions/NSObject+Logs.h>
+#include <NGExtensions/NSObject+Values.h>
+#include <NGExtensions/NSProcessInfo+misc.h>
+#include <NGExtensions/NSSet+enumerator.h>
+#include <NGExtensions/NSString+Formatting.h>
+#include <NGExtensions/NSString+Encoding.h>
+#include <NGExtensions/NSString+misc.h>
+#include <NGExtensions/NGObjectMacros.h>
+
+#include <NGExtensions/EOQualifier+plist.h>
+#include <NGExtensions/EOSortOrdering+plist.h>
+#include <NGExtensions/EOFetchSpecification+plist.h>
+
+#include <NGExtensions/IndexFunc.h>
+
+// kit class
+
+@interface NGExtensions : NSObject
+@end
+
+// linking ..
+
+#define LINK_NGExtensions \
+  void __link_NGExtensions(void) { \
+    [NGExtensions self];   \
+    __link_NGExtensions(); \
+  }
+
+#endif /* __NGExtensions_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGExtensionsDecls.h b/skyrix-core/NGExtensions/NGExtensions/NGExtensionsDecls.h
new file mode 100644 (file)
index 0000000..74d0830
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGExtensionsDecls_H__
+#define __NGExtensions_NGExtensionsDecls_H__
+
+#if BUILD_libNGExtensions_DLL
+#  define NGExtensions_EXPORT  __declspec(dllexport)
+#  define NGExtensions_DECLARE __declspec(dllexport)
+#elif libNGExtensions_ISDLL
+#  define NGExtensions_EXPORT  extern __declspec(dllimport)
+#  define NGExtensions_DECLARE extern __declspec(dllimport)
+#else
+#  define NGExtensions_EXPORT  extern
+#  define NGExtensions_DECLARE 
+#endif
+
+#endif /* __NGExtensions_NGExtensionsDecls_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGFileFolderInfoDataSource.h b/skyrix-core/NGExtensions/NGExtensions/NGFileFolderInfoDataSource.h
new file mode 100644 (file)
index 0000000..efb056c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGFileInfoDataSource_H__
+#define __NGFileInfoDataSource_H__
+
+#import <Foundation/NSFileManager.h>
+#import <EOControl/EODataSource.h>
+#include <NGExtensions/NGExtensionsDecls.h>
+
+@class NSString;
+@class EOFetchSpecification;
+
+/*
+  supported keys:
+
+    NSFileName
+    NSFilePath
+    NSParentPath
+    + all NSFileManager attributes returned by -fileAttributesAtPath:...
+    
+  supported fetch hints:
+  
+    NSTraverseLinks - bool
+*/
+
+NGExtensions_EXPORT NSString *NSFileName;
+NGExtensions_EXPORT NSString *NSFilePath;
+NGExtensions_EXPORT NSString *NSParentPath;
+NGExtensions_EXPORT NSString *NSTraverseLinks;
+
+@interface NGFileFolderInfoDataSource : EODataSource
+{
+  NSString             *folderPath;
+  EOFetchSpecification *fspec;
+}
+
+- (id)initWithFolderPath:(NSString *)_path;
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec;
+- (EOFetchSpecification *)fetchSpecification;
+
+/* operations */
+
+- (NSArray *)fetchObjects;
+
+@end
+
+#endif /* __NGFileInfoDataSource_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGFileManager.h b/skyrix-core/NGExtensions/NGExtensions/NGFileManager.h
new file mode 100644 (file)
index 0000000..e04947f
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+  Copyright (C) 2000-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
+
+#ifndef __NGFileManager_H__
+#define __NGFileManager_H__
+
+#import <Foundation/NSFileManager.h>
+
+@class NSString, NSData;
+@class EODataSource, EOGlobalID;
+
+@protocol NGFileManager
+
+/* path operations */
+
+- (NSString *)standardizePath:(NSString *)_path;
+- (NSString *)resolveSymlinksInPath:(NSString *)_path;
+- (NSString *)expandTildeInPath:(NSString *)_path;
+
+/* directory operations */
+
+- (BOOL)changeCurrentDirectoryPath:(NSString *)_path;
+- (BOOL)createDirectoryAtPath:(NSString *)_path attributes:(NSDictionary *)_ats;
+- (NSString *)currentDirectoryPath;
+
+/* file operations */
+
+- (BOOL)copyPath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler;
+- (BOOL)movePath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler;
+- (BOOL)linkPath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler;
+
+- (BOOL)removeFileAtPath:(NSString *)_path handler:(id)_handler;
+
+- (BOOL)createFileAtPath:(NSString *)_path contents:(NSData *)_contents
+  attributes:(NSDictionary *)_attributes;
+
+/* getting and comparing file contents */
+
+- (NSData *)contentsAtPath:(NSString *)_path;
+- (BOOL)contentsEqualAtPath:(NSString *)_path1 andPath:(NSString *)_path2;
+
+/* determining access to files */
+
+- (BOOL)fileExistsAtPath:(NSString *)_path;
+- (BOOL)fileExistsAtPath:(NSString *)_path isDirectory:(BOOL*)_isDirectory;
+- (BOOL)isReadableFileAtPath:(NSString *)_path;
+- (BOOL)isWritableFileAtPath:(NSString *)_path;
+- (BOOL)isExecutableFileAtPath:(NSString *)_path;
+- (BOOL)isDeletableFileAtPath:(NSString *)_path;
+
+/* Getting and setting attributes */
+
+- (NSDictionary *)fileAttributesAtPath:(NSString *)_p traverseLink:(BOOL)_flag;
+- (NSDictionary *)fileSystemAttributesAtPath:(NSString *)_p;
+- (BOOL)changeFileAttributes:(NSDictionary *)_attributes atPath:(NSString *)_p;
+
+/* discovering directory contents */
+
+- (NSArray *)directoryContentsAtPath:(NSString *)_path;
+- (NSDirectoryEnumerator *)enumeratorAtPath:(NSString *)_path;
+- (NSArray *)subpathsAtPath:(NSString *)_path;
+
+/* symbolic-link operations */
+
+- (BOOL)createSymbolicLinkAtPath:(NSString *)_p pathContent:(NSString *)_dpath;
+- (NSString *)pathContentOfSymbolicLinkAtPath:(NSString *)_path;
+
+/* feature check */
+
+- (BOOL)supportsVersioningAtPath:(NSString *)_path;
+- (BOOL)supportsLockingAtPath:(NSString *)_path;
+- (BOOL)supportsFolderDataSourceAtPath:(NSString *)_path;
+- (BOOL)supportsFeature:(NSString *)_featureURI atPath:(NSString *)_path;
+
+/* writing */
+
+- (BOOL)writeContents:(NSData *)_content atPath:(NSString *)_path;
+
+/* global-IDs */
+
+- (EOGlobalID *)globalIDForPath:(NSString *)_path;
+- (NSString *)pathForGlobalID:(EOGlobalID *)_gid;
+
+/* trash */
+
+- (BOOL)supportsTrashFolderAtPath:(NSString *)_path;
+- (NSString *)trashFolderForPath:(NSString *)_path;
+
+- (BOOL)trashFileAtPath:(NSString *)_path handler:(id)_handler;
+
+@end
+
+@protocol NGFileManagerVersioning < NGFileManager >
+
+/* versioning */
+
+- (BOOL)checkoutFileAtPath:(NSString *)_path handler:(id)_handler;
+- (BOOL)releaseFileAtPath:(NSString *)_path  handler:(id)_handler;
+- (BOOL)rejectFileAtPath:(NSString *)_path   handler:(id)_handler;
+- (BOOL)checkoutFileAtPath:(NSString *)_path version:(NSString *)_version
+  handler:(id)_handler;
+
+/* versioning data */
+
+- (NSString *)lastVersionAtPath:(NSString *)_path;
+- (NSArray *)versionsAtPath:(NSString *)_path;
+- (NSData *)contentsAtPath:(NSString *)_path version:(NSString *)_version;
+- (NSDictionary *)fileAttributesAtPath:(NSString *)_path
+  traverseLink:(BOOL)_followLink
+  version:(NSString *)_version;
+
+@end
+
+@protocol NGFileManagerLocking < NGFileManager >
+
+- (BOOL)lockFileAtPath:(NSString *)_path handler:(id)_handler;
+- (BOOL)unlockFileAtPath:(NSString *)_path handler:(id)_handler;
+- (BOOL)isFileLockedAtPath:(NSString *)_path;
+
+/* access rights */
+- (BOOL)isLockableFileAtPath:(NSString *)_path;
+- (BOOL)isUnlockableFileAtPath:(NSString *)_path;
+
+@end
+
+@protocol NGFileManagerDataSources < NGFileManager >
+
+/* datasources (work on folders) */
+
+- (EODataSource *)dataSourceAtPath:(NSString *)_path;
+- (EODataSource *)dataSource; // works on current-directory-path
+
+@end
+
+/* features */
+
+#define NGFileManagerFeature_DataSources \
+  @"http://www.skyrix.com/filemanager/datasources"
+#define NGFileManagerFeature_Locking \
+  @"http://www.skyrix.com/filemanager/locking"
+#define NGFileManagerFeature_Versioning \
+  @"http://www.skyrix.com/filemanager/versioning"
+
+/* abstract superclass for filemanagers ... */
+
+@class NSString, NSURL;
+
+@interface NGFileManager : NSObject < NGFileManager >
+{
+@protected
+  NSString *cwd;
+}
+
+/* paths */
+
+/*
+  This method removes all 'special' things:
+    '.'
+    '//'
+    '..'
+*/
+- (NSString *)standardizePath:(NSString *)_path;
+
+/* this does return _path in NGFileManager ... */
+- (NSString *)resolveSymlinksInPath:(NSString *)_path;
+
+/* this does return _path in NGFileManager ... */
+- (NSString *)expandTildeInPath:(NSString *)_path;
+
+/* URLs */
+
+- (NSURL *)urlForPath:(NSString *)_path;
+
+@end
+
+#endif /* __NGFileManager_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGFileManagerURL.h b/skyrix-core/NGExtensions/NGExtensions/NGFileManagerURL.h
new file mode 100644 (file)
index 0000000..a498d12
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGFileManagerURL_H__
+#define __NGFileManagerURL_H__
+
+#if GNUSTEP_BASE_LIBRARY
+#  import <Foundation/NSObjCRuntime.h> /* add GS_EXPORT .. */
+#  import <Foundation/NSObject.h>      /* add NSObject .. */
+#endif
+
+#import <Foundation/NSURL.h>
+#include <NGExtensions/NGFileManager.h>
+
+/*
+  A URL which works on NGFileManager's.
+  
+  The NSURLHandle should work, but the URL can't be serialized.
+*/
+
+@interface NGFileManagerURL : NSURL
+{
+  /* do *NOT* cache in filemanager - retain cycle !!! */
+  id<NSObject,NGFileManager> fileManager;
+  NSString *path;
+}
+
+- (id)initWithPath:(NSString *)_path
+  fileManager:(id<NSObject,NGFileManager>)_fm;
+
+/* accessors */
+
+- (id<NSObject,NGFileManager>)fileManager;
+
+@end
+
+#endif /* __NGFileManagerURL_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGHashMap.h b/skyrix-core/NGExtensions/NGExtensions/NGHashMap.h
new file mode 100644 (file)
index 0000000..2741fef
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NGHashMap_H__
+#define __NGExtensions_NGHashMap_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSMapTable.h>
+
+@class NSArray, NSDictionary;
+
+@interface NGHashMap : NSObject < NSCopying, NSMutableCopying, NSCoding >
+{
+@protected
+  NSMapTable *table;  
+}
+
++ (id)hashMap;
++ (id)hashMapWithHashMap:(NGHashMap *)_hashMap;
++ (id)hashMapWithObjects:(NSArray *)_objects forKey:(id)_key;
++ (id)hashMapWithDictionary:(NSDictionary *)_dict;
+
+- (id)init;
+- (id)initWithCapacity:(unsigned int)_size;
+- (id)initWithObjects:(NSArray *)_objects forKey:(id)_key;
+- (id)initWithHashMap:(NGHashMap *)_hashMap;
+- (id)initWithDictionary:(NSDictionary *)_dictionary;
+
+- (BOOL)isEqual:(id)anObject;
+- (BOOL)isEqualToHashMap:(NGHashMap *)_other;
+
+- (id)objectForKey:(id)_key;
+- (NSArray *)objectsForKey:(id)_key;
+- (id)objectAtIndex:(unsigned int)_index forKey:(id)_key;
+
+- (NSArray *)allKeys;
+- (NSArray *)allObjects;
+
+- (NSEnumerator *)keyEnumerator;
+- (NSEnumerator *)objectEnumerator;
+- (NSEnumerator *)objectEnumeratorForKey:(id)_key;
+
+- (id)propertyList;
+- (NSString *)description;
+- (NSDictionary *)asDictionary;
+- (NSDictionary *)asDictionaryWithArraysForValues;
+
+- (unsigned int)hash;
+- (unsigned int)count; // returns the number of keys
+- (unsigned int)countObjectsForKey:(id)_key;
+
+@end
+
+@interface NGMutableHashMap : NGHashMap
+{
+}
+
++ (id)hashMapWithCapacity:(unsigned int)_numItems;
+
+- (id)init;
+- (void)insertObject:(id)_object atIndex:(unsigned int)_index forKey:(id)_key;
+- (void)insertObjects:(NSArray *)_object
+  atIndex:(unsigned int)_index forKey:(id)_key;
+- (void)insertObjects:(id*)_objects count:(unsigned int)_count
+  atIndex:(unsigned int)_index forKey:(id)_key;
+
+- (void)addObject:(id)_object forKey:(id)_key;
+- (void)addObjects:(NSArray *)_objects forKey:(id)_key;
+- (void)addObjects:(id*)_objects count:(unsigned int)_count
+  forKey:(id)_key;
+
+- (void)setObject:(id)_object forKey:(id)_key;
+- (void)setObjects:(NSArray *)_objects forKey:(id)_key;
+
+- (void)removeAllObjects;
+- (void)removeAllObjects:(id)_object forKey:(id)_key;
+- (void)removeAllObjectsForKey:(id)_key;
+- (void)removeAllObjectsForKeys:(NSArray *)_keyArray;
+
+@end
+
+#endif /* __NGExtensions_NGHashMap_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGMemoryAllocation.h b/skyrix-core/NGExtensions/NGExtensions/NGMemoryAllocation.h
new file mode 100644 (file)
index 0000000..d32ce81
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGMemoryAllocation_H__
+#define __NGExtensions_NGMemoryAllocation_H__
+
+#include <objc/objc-api.h>
+#include <stdlib.h>
+
+#if LIB_FOUNDATION_BOEHM_GC
+#  define NGMalloc       objc_malloc
+#  define NGMallocAtomic objc_atomic_malloc
+#  define NGFree         objc_free
+#  define NGRealloc      objc_realloc
+#else
+#  define NGMalloc       malloc
+#  define NGMallocAtomic malloc
+#  define NGFree         free
+#  define NGRealloc      realloc
+#endif
+
+#endif /* __NGExtensions_NGMemoryAllocation_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGMerging.h b/skyrix-core/NGExtensions/NGExtensions/NGMerging.h
new file mode 100644 (file)
index 0000000..b4a8d7c
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGMerging_H__
+#define __NGExtensions_NGMerging_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSZone.h>
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSArray.h>
+
+@interface NSObject(NGMerging)
+
+- (BOOL)canMergeWithObject:(id)_object;
+- (id)mergeWithObject:(id)_object zone:(NSZone *)_zone;
+- (id)mergeWithObject:(id)_object;
+
+@end
+
+/*
+  dictionaries merge only with other dictionaries
+*/
+@interface NSDictionary(NGMerging)
+
+- (id)mergeWithDictionary:(NSDictionary *)_object zone:(NSZone *)_zone;
+
+@end
+
+/*
+  arrays merge with any objects responding to -objectEnumerator
+*/
+@interface NSArray(NGMerging)
+
+- (id)mergeWithArray:(NSArray *)_object zone:(NSZone *)_zone;
+- (id)mergeWithEnumeration:(NSEnumerator *)_object zone:(NSZone *)_zone;
+
+@end
+
+#endif /* __NGExtensions_NGMerging_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGObjCRuntime.h b/skyrix-core/NGExtensions/NGExtensions/NGObjCRuntime.h
new file mode 100644 (file)
index 0000000..2409c67
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NGObjCRuntime_H__
+#define __NGExtensions_NGObjCRuntime_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSArray, NSEnumerator;
+
+@interface NSObject(NGObjCRuntime)
+
+/* retrieving additional class info */
+
++ (unsigned)instanceSize;
+
+/* adding methods to a class */
+
++ (void)addMethods:(SEL)_selector, ...;
++ (void)addClassMethods:(SEL)_selector, ...;
+
++ (NSEnumerator *)methodNameEnumerator;
++ (NSEnumerator *)hierachyMethodNameEnumerator;
+
+/* making a subclass of a class */
+
++ (Class)subclass:(NSString *)_className ivars:(NSString *)_name1,...;
+
+/* instance variables */
+
++ (NSArray *)instanceVariableNames;
++ (NSArray *)allInstanceVariableNames;
++ (BOOL)hasInstanceVariableWithName:(NSString *)_ivarName;
++ (NSString *)signatureOfInstanceVariableWithName:(NSString *)_ivarName;
++ (unsigned)offsetOfInstanceVariableWithName:(NSString *)_ivarName;
+
+@end
+
+#endif /* __NGExtensions_NGObjCRuntime_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGObjectMacros.h b/skyrix-core/NGExtensions/NGExtensions/NGObjectMacros.h
new file mode 100644 (file)
index 0000000..93c62fa
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGObjectMacros_H__
+#define __NGExtensions_NGObjectMacros_H__
+
+#ifndef ASSIGN
+#  define ASSIGN(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) [__value retain]; \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+#ifndef ASSIGNCOPY
+#  define ASSIGNCOPY(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) __value = [__value copy];   \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+#ifndef RETAIN
+#  define RETAIN(__XXX__) [__XXX__ retain]
+#endif
+#ifndef RELEASE
+#  define RELEASE(__XXX__) [__XXX__ release]
+#endif
+#ifndef AUTORELEASE
+#  define AUTORELEASE(__XXX__) [__XXX__ autorelease]
+#endif
+
+#endif /* __NGExtensions_NGObjectMacros_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGPropertyListParser.h b/skyrix-core/NGExtensions/NGExtensions/NGPropertyListParser.h
new file mode 100644 (file)
index 0000000..07fbdba
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NGPropertyListParser_H__
+#define __NGExtensions_NGPropertyListParser_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSArray, NSDictionary, NSData;
+
+/*
+  The property list format is:
+
+    Strings: char's without specials:  'hello', but not 'hel  lo'
+             or quoted string:         '"hello world !"
+
+    Arrays:  '(' ')'
+             or '(' element ( ',' element )* ')'
+
+    Dicts:   '{' ( dictEntry )* '}'
+             dictEntry = property '=' property ';' ;
+
+    Data:    '<' data '>', eg: '< AABB 88CC 77a7 11 >'
+ */
+
+NSString     *NGParseStringFromBuffer(const unsigned char *_buffer, unsigned _len);
+NSArray      *NGParseArrayFromBuffer(const unsigned char *_buffer, unsigned _len);
+NSDictionary *NGParseDictionaryFromBuffer(const unsigned char *_buffer, unsigned _len);
+
+NSString     *NGParseStringFromData(NSData *_data);
+NSArray      *NGParseArrayFromData(NSData *_data);
+NSDictionary *NGParseDictionaryFromData(NSData *_data);
+NSString     *NGParseStringFromString(NSString *_str);
+NSArray      *NGParseArrayFromString(NSString *_str);
+NSDictionary *NGParseDictionaryFromString(NSString *_str);
+
+id NGParsePropertyListFromBuffer(const unsigned char *_buffer, unsigned _len);
+id NGParsePropertyListFromData(NSData *_data);
+id NGParsePropertyListFromString(NSString *_string);
+id NGParsePropertyListFromFile(NSString *_path);
+
+NSDictionary *NGParseStringsFromBuffer(const char *_buffer, unsigned _len);
+NSDictionary *NGParseStringsFromData(NSData *_data);
+NSDictionary *NGParseStringsFromString(NSString *_string);
+NSDictionary *NGParseStringsFromFile(NSString *_path);
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSDictionary.h>
+
+@interface NSArray(NGPropertyListParser)
+
++ (id)skyArrayWithContentsOfFile:(NSString *)_path;
+- (id)skyInitWithContentsOfFile:(NSString *)_path;
+
+@end
+
+@interface NSDictionary(NGPropertyListParser)
+
++ (id)skyDictionaryWithContentsOfFile:(NSString *)_path;
+- (id)skyInitWithContentsOfFile:(NSString *)_path;
+
+@end
+
+#endif /* __NGExtensions_NGPropertyListParser_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGQuotedPrintableCoding.h b/skyrix-core/NGExtensions/NGExtensions/NGQuotedPrintableCoding.h
new file mode 100644 (file)
index 0000000..a69e449
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGQuotedPrintableCoding_H__
+#define __NGExtensions_NGQuotedPrintableCoding_H__
+
+#import <Foundation/NSString.h>
+#import <Foundation/NSData.h>
+#include <NGExtensions/NGExtensionsDecls.h>
+
+/*
+  Quoted Printable encoder/decoder
+
+  As specified in RFC 822
+*/
+
+@interface NSString(QuotedPrintableCoding)
+
+- (NSString *)stringByDecodingQuotedPrintable;
+- (NSString *)stringByEncodingQuotedPrintable;
+
+@end
+
+@interface NSData(QuotedPrintableCoding)
+
+/*
+  Decode a quoted printable encoded data. Returns nil if decoding failed.
+*/
+- (NSData *)dataByDecodingQuotedPrintable;
+
+/*
+  Decode data in quoted printable encoding. Returns nil if encoding failed.
+*/
+- (NSData *)dataByEncodingQuotedPrintable;
+
+@end
+
+NGExtensions_EXPORT int
+NGEncodeQuotedPrintable(const char *_src, unsigned _srcLen,
+                        char *_dest, unsigned _destLen);
+NGExtensions_EXPORT int
+NGDecodeQuotedPrintable(const char *_src, unsigned _srcLen,
+                        char *_dest, unsigned _destLen);
+
+#endif /* __NGExtensions_NGQuotedPrintableCoding_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGRule.h b/skyrix-core/NGExtensions/NGExtensions/NGRule.h
new file mode 100644 (file)
index 0000000..5647fda
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGRuleEngine_NGRule_H__
+#define __NGRuleEngine_NGRule_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  NGRule
+
+  This class represents a rule inside the rule-model. A rule conceptually has:
+  - a qualifier - aka lhs (the condition which must be true for the rule)
+  - an action   - aka rhs (the "thing" which is performed when the rule is
+                           triggered)
+  - a priority  - to select a rule if multiple ones match
+  
+  String Representation:
+    qualifer => action [; priority]
+    *true*   => action
+  
+  Example:
+    "(request.isXmlRpcRequest = YES) => dispatcher = XmlRpc ;0"
+*/
+
+@class EOQualifier;
+
+@interface NGRule : NSObject
+{
+  EOQualifier *qualifier;
+  id          action;
+  int         priority;
+}
+
++ (id)ruleWithQualifier:(EOQualifier *)_q action:(id)_action priority:(int)_p;
++ (id)ruleWithQualifier:(EOQualifier *)_q action:(id)_action;
+- (id)initWithQualifier:(EOQualifier *)_q action:(id)_action priority:(int)_p;
+
+- (id)initWithPropertyList:(id)_plist;
+- (id)initWithString:(NSString *)_s;
+
+/* accessors */
+
+- (void)setQualifier:(EOQualifier *)_q;
+- (EOQualifier *)qualifier;
+
+- (void)setAction:(id)_action;
+- (id)action;
+
+- (void)setPriority:(int)_pri;
+- (int)priority;
+
+/* operations */
+
+- (BOOL)isCandidateForKey:(NSString *)_key;
+- (id)fireInContext:(id)_ctx;
+
+/* representations */
+
+- (NSString *)stringValue;
+
+@end
+
+@interface NSObject(RuleAction)
+- (id)fireInContext:(id)_ctx;
+@end
+
+#endif /* __NGRuleEngine_NGRule_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGRuleAssignment.h b/skyrix-core/NGExtensions/NGExtensions/NGRuleAssignment.h
new file mode 100644 (file)
index 0000000..86d6536
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGRuleEngine_NGRuleAssignment_H__
+#define __NGRuleEngine_NGRuleAssignment_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  NGRuleAssignment
+  
+  Assignments are the right-hand side of a rule in the rule system, if a rule
+  is selected by qualifier and priority the assignment is the "thing" which 
+  is executed.
+  
+  NGRuleKeyAssignment
+  
+  Special case of NGRuleAssignment which evaluates the "value" as a keypath
+  relative to the context.
+*/
+
+@class NSString;
+
+@interface NGRuleAssignment : NSObject
+{
+  NSString *keyPath;
+  id value;
+}
+
++ (id)assignmentWithKeyPath:(NSString *)_kp value:(id)_value;
+- (id)initWithKeyPath:(NSString *)_kp value:(id)_value;
+
+/* accessors */
+
+- (void)setKeyPath:(NSString *)_kp;
+- (NSString *)keyPath;
+
+- (void)setValue:(id)_value;
+- (id)value;
+
+/* operations */
+
+- (BOOL)isCandidateForKey:(NSString *)_key;
+- (id)fireInContext:(id)_ctx;
+
+@end
+
+@interface NGRuleKeyAssignment : NGRuleAssignment
+{
+}
+
+@end
+
+#endif /* __NGRuleEngine_NGRuleAssignment_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGRuleContext.h b/skyrix-core/NGExtensions/NGExtensions/NGRuleContext.h
new file mode 100644 (file)
index 0000000..7cc57b6
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGRuleEngine_NGRuleContext_H__
+#define __NGRuleEngine_NGRuleContext_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  NGRuleContext
+  
+  This is a specialized rule evaluation object for key based (assignment)
+  rules. It exports evaluated rule values using key-value coding, thereby
+  giving a very simple access somewhat similiar to CSS.
+*/
+
+@class NSString, NSArray, NSMutableDictionary;
+@class NGRuleModel;
+
+@interface NGRuleContext : NSObject
+{
+  NSMutableDictionary *storedValues;
+  NGRuleModel *model;
+  BOOL        debugOn;
+}
+
++ (id)ruleContextWithModelInUserDefault:(NSString *)_defName;
++ (id)ruleContextWithModel:(NGRuleModel *)_model;
+- (id)initWithModel:(NGRuleModel *)_model;
+
+/* accessors */
+
+- (void)setModel:(NGRuleModel *)_model;
+- (NGRuleModel *)model;
+
+- (void)setDebugEnabled:(BOOL)_flag;
+- (BOOL)isDebuggingEnabled;
+
+/* values */
+
+- (void)takeStoredValue:(id)_value forKey:(NSString *)_key;
+- (id)storedValueForKey:(NSString *)_key;
+- (void)reset;
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key;
+
+/* processing */
+
+- (id)valueForKey:(NSString *)_key;
+
+- (id)inferredValueForKey:(NSString *)_key;
+
+- (NSArray *)valuesForKeyPath:(NSString *)_kp
+  takingSuccessiveValues:(NSArray *)_values
+  forKeyPath:(NSString *)_valkp;
+
+@end
+
+#endif /* __NGRuleEngine_NGRuleContext_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGRuleEngine.h b/skyrix-core/NGExtensions/NGExtensions/NGRuleEngine.h
new file mode 100644 (file)
index 0000000..a562e2a
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGExtensions/NGRule.h>
+#include <NGExtensions/NGRuleAssignment.h>
+#include <NGExtensions/NGRuleContext.h>
+#include <NGExtensions/NGRuleModel.h>
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGRuleModel.h b/skyrix-core/NGExtensions/NGExtensions/NGRuleModel.h
new file mode 100644 (file)
index 0000000..f4c7a53
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGRuleEngine_NGRuleModel_H__
+#define __NGRuleEngine_NGRuleModel_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  NGRuleModel
+  
+  A rule model is a specialized sequence of rules.
+*/
+
+@class NSArray, NSMutableArray;
+@class NGRule;
+
+@interface NGRuleModel : NSObject
+{
+  NSMutableArray *rules;
+}
+
++ (id)ruleModelWithPropertyList:(id)_plist;
++ (id)ruleModelWithContentsOfUserDefault:(NSString *)_defName;
+
+- (id)init;
+- (id)initWithRules:(NSArray *)_rules;
+- (id)initWithPropertyList:(id)_plist;
+- (id)initWithContentsOfFile:(NSString *)_path;
+- (id)initWithContentsOfUserDefault:(NSString *)_defaultName;
+
+/* accessors */
+
+- (void)setRules:(NSArray *)_rules;
+- (NSArray *)rules;
+- (void)addRule:(NGRule *)_rule;
+- (void)removeRule:(NGRule *)_rule;
+
+/* operations */
+
+- (NSArray *)candidateRulesForKey:(NSString *)_key;
+
+@end
+
+#endif /* __NGRuleEngine_NGRuleModel_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGStack.h b/skyrix-core/NGExtensions/NGExtensions/NGStack.h
new file mode 100644 (file)
index 0000000..a36b93f
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGStack_H__
+#define __NGExtensions_NGStack_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSException.h>
+#import <Foundation/NSArray.h>
+
+@class NSArray;
+
+@protocol NGStack < NSObject >
+
+// state
+
+- (unsigned int)stackPointer;
+- (unsigned int)count;
+- (BOOL)isEmpty;
+
+// operations
+
+- (void)push:(id)_obj;
+- (id)pop;
+- (void)clear;
+
+// elements
+
+- (id)elementAtTop;
+- (NSEnumerator *)topDownEnumerator;
+- (NSEnumerator *)bottomUpEnumerator;
+
+@end
+
+@interface NGStack : NSObject < NGStack, NSCoding, NSCopying >
+{
+@protected
+  unsigned int stackPointer;
+  unsigned int capacity;
+  id           *stack;
+}
+
++ (id)stackWithCapacity:(unsigned int)_capacity;
++ (id)stack;
++ (id)stackWithArray:(NSArray *)_array;
+- (id)init;
+- (id)initWithCapacity:(unsigned int)_capacity; // designated initializer
+- (id)initWithArray:(NSArray *)_array;
+
+// state
+
+- (unsigned int)capacity;
+
+- (unsigned int)stackPointer;
+- (unsigned int)count;
+- (BOOL)isEmpty;
+
+// elements
+
+- (id)elementAtTop;
+- (id)elementAtBottom;
+- (NSEnumerator *)topDownEnumerator;
+- (NSEnumerator *)bottomUpEnumerator;
+
+// operations
+
+- (void)push:(id)_obj;
+- (id)pop;
+- (void)clear;
+
+// description
+
+- (NSArray *)toArray; // array representation, bottom element first
+
+@end
+
+@interface NGStackException : NSException
+@end
+
+@interface NSMutableArray(Stack) < NGStack >
+@end
+
+#endif /* __NGExtensions_NGStack_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NGStringScanEnumerator.h b/skyrix-core/NGExtensions/NGExtensions/NGStringScanEnumerator.h
new file mode 100644 (file)
index 0000000..753bcb0
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NGStringScanEnumerator_H__
+#define __NGExtensions_NGStringScanEnumerator_H__
+
+#import <Foundation/NSEnumerator.h>
+#import <Foundation/NSData.h>
+
+/*
+  NGStringScanEnumerator
+
+  This class is used to scan (binary) NSData objects for printable strings,
+  pretty much like the "strings" Unix program.
+  
+  Example:
+  
+    NSData *data = [NSData dataWithContentsOfMappedFile:@"/bin/ls"];
+    NSEnumerator *e;
+    NSString *s;
+    
+    e = [data stringScanEnumerator];
+    while ((s = [e nextObject])) {
+      if ([s hasPrefix:@"4"] && [s length] > 5) {
+        NSLog(@"ls version: %@", s);
+        break;
+      }
+    }
+*/
+
+@interface NGStringScanEnumerator : NSEnumerator
+{
+  unsigned int curPos;
+  NSData       *data;
+  unsigned int maxLength;
+}
+
++ (id)enumeratorWithData:(NSData *)_data maxLength:(unsigned int)_maxLength;
+
+@end /* StringEnumerator */
+
+@interface NSData(NGStringScanEnumerator)
+
+/* scan strings with up to 256 chars length */
+- (NSEnumerator *)stringScanEnumerator;
+
+- (NSEnumerator *)stringScanEnumeratorWithMaxStringLength:(unsigned int)_max;
+
+@end
+
+#endif /* __NGExtensions_NGStringScanEnumerator_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSArray+enumerator.h b/skyrix-core/NGExtensions/NGExtensions/NSArray+enumerator.h
new file mode 100644 (file)
index 0000000..4da271a
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NSArray_enumerator_H__
+#define __NGExtensions_NSArray_enumerator_H__
+
+#import <Foundation/NSArray.h>
+
+@class NSSet;
+
+@interface NSArray(enumerator)
+
+- (id)initWithObjectsFromEnumerator:(NSEnumerator *)_enumerator;
+
+/*
+  Returns an array contructed using this algorithm:
+
+    for (i = 0; i < [self count]; i++)
+      newArray[i] = [array[i] performSelector:_selector];
+
+  If the selector returns nil, NSNull is placed in the resulting array.
+*/
+- (NSArray *)mappedArrayUsingSelector:(SEL)_selector;
+- (NSArray *)mappedArrayUsingSelector:(SEL)_selector withObject:(id)_object;
+- (NSSet *)mappedSetUsingSelector:(SEL)_selector;
+- (NSSet *)mappedSetUsingSelector:(SEL)_selector withObject:(id)_object;
+
+#if !LIB_FOUNDATION_LIBRARY
+- (NSArray *)map:(SEL)_sel;
+- (NSArray *)map:(SEL)_sel with:(id)_arg;
+#endif
+
+@end
+
+@interface NSMutableArray(enumerator);
+
+- (id)initWithObjectsFromEnumerator:(NSEnumerator *)_enumerator;
+
+@end
+
+#endif /* __NGExtensions_NSArray_enumerator_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSAutoreleasePool+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSAutoreleasePool+misc.h
new file mode 100644 (file)
index 0000000..28e0660
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSAutoreleasePool_misc_H__
+#define __NGExtensions_NSAutoreleasePool_misc_H__
+
+#import <Foundation/NSAutoreleasePool.h>
+
+#if defined(LIB_FOUNDATION_LIBRARY)
+
+@interface NSAutoreleasePool(misc)
+
++ (void)enableRetainRemove:(BOOL)enable;
++ (NSAutoreleasePool *)findReleasingPoolForObject:(id)_obj;
++ (BOOL)retainAutoreleasedObject:(id)_obj;
+- (BOOL)retainAutoreleasedObject:(id)_obj;
+
+@end
+
+#endif /* !LIB_FOUNDATION_LIBRARY */
+
+#endif /* __NGExtensions_NSAutoreleasePool_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSCalendarDate+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSCalendarDate+misc.h
new file mode 100644 (file)
index 0000000..05ca8c9
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NSCalendarDate_misc_H__
+#define __NGExtensions_NSCalendarDate_misc_H__
+
+#import <Foundation/NSDate.h>
+
+#if NeXT_Foundation_LIBRARY || GNUSTEP_BASE_LIBRARY
+#  import <Foundation/NSCalendarDate.h>
+#endif
+
+@interface NSCalendarDate(misc)
+
+- (int)weekOfMonth;
+- (int)weekOfYear;
+- (short)numberOfWeeksInYear;
++ (NSArray *)mondaysOfYear:(int)_year timeZone:(NSTimeZone *)_tz;
+- (NSArray *)mondaysOfYear;
+- (NSCalendarDate *)firstMondayAndLastWeekInYear:(short *)_lastWeek;
++ (NSCalendarDate *)mondayOfWeek:(int)_weekNumber inYear:(int)_year
+  timeZone:(NSTimeZone *)_tz;
+- (NSCalendarDate *)mondayOfWeek:(int)_weekNumber;
+
+- (NSCalendarDate *)firstDayOfMonth;
+- (NSCalendarDate *)lastDayOfMonth;
+- (NSCalendarDate *)mondayOfWeek;
+- (NSCalendarDate *)beginOfDay;
+- (NSCalendarDate *)endOfDay;
+- (int)numberOfDaysInMonth;
+
+- (BOOL)isDateOnSameDay:(NSCalendarDate *)_date;
+- (BOOL)isDateInSameWeek:(NSCalendarDate *)_date;
+- (BOOL)isInLeapYear;
+
+- (BOOL)isToday;
+- (NSCalendarDate *)yesterday;
+- (NSCalendarDate *)tomorrow;
+- (BOOL)isForenoon;
+- (BOOL)isAfternoon;
+
+- (NSCalendarDate *)nextYear;
+- (NSCalendarDate *)lastYear;
+
+/* returns a date on the same day with the specified time */
+- (NSCalendarDate *)hour:(int)_hour minute:(int)_minute second:(int)_second;
+- (NSCalendarDate *)hour:(int)_hour minute:(int)_minute;
+
+/*
+  applies the following modifications:
+    if year >= 70 && year < 135
+      year = 1900 + year
+    elif year >= 0 && year < 70
+      year = 2000 + year
+*/
+      
+- (NSCalendarDate *)y2kDate;
+
+/*
+  adding years, months and days while *keeping* the clock time, eg:
+
+    d1 = [NSCalendarDate dateWithYear:2000 month:2 day:15
+                         hour:12 minute:0 second:0
+                         timeZone:@"MET"];
+    d2 = [d1 dateByAddingYear:0 month:3 day:0];
+
+    [d2 hourOfDay] will be '15' though the timezone changed from
+    MET to MET-DST.
+
+    -dateByAddingYears:months:days:hours:minutes:seconds: which can
+    be found in NSCalendarDate will not keep the clock time (the time
+    will be adjusted in the new DST timezone
+*/
+
+- (NSCalendarDate *)dateByAddingYears:(int)_years
+  months:(int)_months
+  days:(int)_days;
+
+/* calculate easter ... */
+
+- (NSCalendarDate *)easterOfYear;
+
+@end
+
+#endif /* __NGExtensions_NSCalendarDate_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSData+gzip.h b/skyrix-core/NGExtensions/NGExtensions/NSData+gzip.h
new file mode 100644 (file)
index 0000000..1aedaff
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGZlib_NSData_gzip_H__
+#define __NGZlib_NSData_gzip_H__
+
+#import <Foundation/NSData.h>
+
+#define NGGZipMinimalCompression 0
+#define NGGZipMaximalCompression 9
+
+@interface NSData(gzip)
+
+- (NSData *)gzipWithLevel:(int)_compressionLevel;
+- (NSData *)gzip;
+
+@end
+
+#endif /* __NGZlib_NSData_gzip_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSData+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSData+misc.h
new file mode 100644 (file)
index 0000000..f259dc1
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSData_misc_H__
+#define __NGExtensions_NSData_misc_H__
+
+#import <Foundation/NSData.h>
+
+@interface NSData(misc)
+
+- (BOOL)hasPrefix:(NSData *)_data;
+- (BOOL)hasPrefixBytes:(const void *)_bytes length:(unsigned)_len;
+
+@end
+
+#endif /* __NGExtensions_NSData_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSDictionary+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSDictionary+misc.h
new file mode 100644 (file)
index 0000000..569c16d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSDictionary_misc_H__
+#define __NGExtensions_NSDictionary_misc_H__
+
+#import <Foundation/NSDictionary.h>
+
+@interface NSDictionary(misc)
+
+- (NSDictionary *)dictionaryByExchangingKeysAndValues;
+
+@end
+
+@interface NSMutableDictionary(misc)
+
+- (void)removeObjectsForKeysV:(id)_firstKey, ...;
+
+@end
+
+#endif /* __NGExtensions_NSDictionary_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSEnumerator+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSEnumerator+misc.h
new file mode 100644 (file)
index 0000000..c0c815d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSEnumerator_misc_H__
+#define __NGExtensions_NSEnumerator_misc_H__
+
+#import <Foundation/NSEnumerator.h>
+
+@class NSEnumerator, EOQualifier;
+
+@interface NSEnumerator(misc)
+
+- (NSEnumerator *)filterWithQualifier:(EOQualifier *)_qualifier;
+- (NSEnumerator *)filterWithQualifierString:(NSString *)_q;
+
+- (NSEnumerator *)filterWithSelector:(SEL)_selector withObject:(id)_argument;
+
+@end
+
+#endif /* __NGExtensions_NSEnumerator_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSException+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSException+misc.h
new file mode 100644 (file)
index 0000000..c99a050
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSException_misc_H__
+#define __NGExtensions_NSException_misc_H__
+
+#import <Foundation/NSException.h>
+#import <Foundation/NSLock.h>
+
+/*
+  Miscellaneous method additions to NSException
+
+  the additions make it easier using exceptions in the Java way. In OpenStep
+  exceptions are identified by their name, subclasses are mainly used when
+  additional information needs to be stored. This works well as long as you do
+  not use exceptions very much (as in the Foundation Kit) - if you do you
+  soon wish to have a 'hierachy' of exceptions. This can be modelled - like in
+  Java - using a subclass for each different kind of exception and then using
+  the type of the exception for it's identification. This is supported by
+  libFoundation using the TRY and CATCH macros.
+
+  The methods below always use the class name as the exception name if the name
+  isn't specified explicitly.
+*/
+
+@interface NSException(NGMiscellaneous)
+
+- (id)initWithReason:(NSString *)_reason;
+- (id)initWithReason:(NSString *)_reason userInfo:(id)_userInfo;
+- (id)initWithFormat:(NSString *)_format,...;
+
+@end
+
+
+#if COCOA_Foundation_LIBRARY || GNUSTEP_BASE_LIBRARY
+@interface NSException (NGLibFoundationCompatibility)
+- (void)setReason:(NSString *)_reason;
+@end
+#endif
+
+
+/*
+  The following macros are for use of locks together with exception handling.
+  A synchronized block is properly 'unlocked' even if an exception occures.
+  It is used this way:
+
+    SYNCHRONIZED(MyObject) {
+      THROW(MyException..);
+    }
+    END_SYNCHRONIZED;
+
+  Where MyObject must be an object that conforms to the NSObject and NSLocking
+  protocol.
+  This is much different to
+
+    [MyObject lock];
+    {
+      THROW(MyException..);
+    }
+    [MyObject unlock];
+
+  which leaves the lock locked when an exception happens.
+*/
+
+#if defined(DEBUG_SYNCHRONIZED)
+
+#define SYNCHRONIZED(__lock__) \
+  { \
+    id<NSObject,NSLocking> __syncLock__ = [__lock__ retain]; \
+    [__syncLock__ lock]; \
+    fprintf(stderr, "0x%08X locked in %s.\n", \
+            (unsigned)__syncLock__, __PRETTY_FUNCTION__); \
+    NS_DURING {
+
+#define END_SYNCHRONIZED \
+    } \
+    NS_HANDLER { \
+      fprintf(stderr, "0x%08X exceptional unlock in %s exception %s.\n", \
+              (unsigned)__syncLock__, __PRETTY_FUNCTION__,\
+              [[localException description] cString]); \
+      [__syncLock__ unlock]; \
+      [__syncLock__ release]; __syncLock__ = nil; \
+      [localException raise]; \
+    } \
+    NS_ENDHANDLER; \
+    fprintf(stderr, "0x%08X unlock in %s.\n", \
+            (unsigned)__syncLock__, __PRETTY_FUNCTION__); \
+    [__syncLock__ unlock]; \
+    [__syncLock__ release];  __syncLock__ = nil; \
+  }
+
+#else
+
+#define SYNCHRONIZED(__lock__) \
+  { \
+    id<NSObject,NSLocking> __syncLock__ = [__lock__ retain]; \
+    [__syncLock__ lock]; \
+    NS_DURING {
+
+#define END_SYNCHRONIZED \
+    } \
+    NS_HANDLER { \
+      [__syncLock__ unlock]; \
+      [__syncLock__ release]; \
+      [localException raise]; \
+    } \
+    NS_ENDHANDLER; \
+    [__syncLock__ unlock]; \
+    [__syncLock__ release]; \
+  }
+
+#endif
+
+#endif /* __NGExtensions_NSException_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSFileManager+Extensions.h b/skyrix-core/NGExtensions/NGExtensions/NSFileManager+Extensions.h
new file mode 100644 (file)
index 0000000..6743cb6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NSFileManager_Extensions_H__
+#define __NSFileManager_Extensions_H__
+
+#import <Foundation/NSFileManager.h>
+#include <NGExtensions/NGFileManager.h>
+
+@interface NSFileManager(ExtendedFileManager) < NGFileManagerDataSources >
+@end
+
+#endif /* __NSFileManager_Extensions_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSMethodSignature+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSMethodSignature+misc.h
new file mode 100644 (file)
index 0000000..e2ffaeb
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSMethodSignature_misc_H__
+#define __NGExtensions_NSMethodSignature_misc_H__
+
+#import <Foundation/NSMethodSignature.h>
+
+@class NSString;
+
+@interface NSMethodSignature(misc)
+
+- (NSString *)objCTypes;
+
+@end
+
+#endif /* __NGExtensions_NSMethodSignature_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSNull+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSNull+misc.h
new file mode 100644 (file)
index 0000000..eb6b3ee
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NSNull_misc_H__
+#define __NSNull_misc_H__
+
+#import <Foundation/NSNull.h>
+
+@interface NSNull(misc)
+
+- (BOOL)isNotNull;
+
+- (double)doubleValue;
+- (NSString *)stringValue;
+
+@end
+
+@interface NSObject(NSNullMisc)
+
+- (BOOL)isNotNull;
+
+@end
+
+#endif /* __NSNull_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSObject+Logs.h b/skyrix-core/NGExtensions/NGExtensions/NSObject+Logs.h
new file mode 100644 (file)
index 0000000..4900f38
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSObject_Logs_H__
+#define __NGExtensions_NSObject_Logs_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+
+@interface NSObject(NGLogs)
+
+/* "end user" methods, variable argument logging methods .. */
+- (void)logWithFormat:(NSString *)_format, ...;
+- (void)debugWithFormat:(NSString *)_format, ...;
+
+/* prefix, override that, to make a special logging prefix */
+- (NSString *)loggingPrefix;
+
+/* says whether debugging is enabled for object ... */
+- (BOOL)isDebuggingEnabled;
+
+/*"designated" logging methods */
+- (void)logWithFormat:(NSString *)format   arguments:(va_list)argList;
+- (void)debugWithFormat:(NSString *)format arguments:(va_list)argList;
+
+@end
+
+#endif /* __NGExtensions_NSObject_Logs_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSObject+Values.h b/skyrix-core/NGExtensions/NGExtensions/NSObject+Values.h
new file mode 100644 (file)
index 0000000..9324cb2
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSObject_Values_H__
+#define __NGExtensions_NSObject_Values_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+
+@interface NSObject(NGValues)
+
+- (BOOL)boolValue; // this returns always YES (the id != nil)
+
+// these methods perform their operation on the string-representation of the object
+- (char)charValue;
+- (unsigned char)unsignedCharValue;
+- (short)shortValue;
+- (unsigned short)unsignedShortValue;
+- (int)intValue;
+- (unsigned int)unsignedIntValue;
+- (long)longValue;
+- (unsigned long)unsignedLongValue;
+- (long long)longLongValue;
+- (unsigned long long)unsignedLongLongValue;
+- (float)floatValue;
+- (double)doubleValue;
+
+- (NSString *)stringValue;
+
+@end
+
+@interface NSString(NGValues)
+
+- (BOOL)boolValue;
+- (NSString *)stringValue;
+
+@end
+
+#endif /* __NGExtensions_NSObject_Values_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSProcessInfo+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSProcessInfo+misc.h
new file mode 100644 (file)
index 0000000..06dbe24
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NSProcessInfo_misc_H__
+#define __NSProcessInfo_misc_H__
+
+#import <Foundation/NSProcessInfo.h>
+
+@interface NSProcessInfo(misc)
+
+/* arguments */
+
+- (NSArray *)argumentsWithoutDefaults;
+
+/* create temp file name */
+
+- (NSString *)temporaryFileName:(NSString *)_prefix;
+- (NSString *)temporaryFileName;
+
+/* return process-id (pid on Unix) */
+- (id)processId;
+
+/* return path to proc directory for this process */
+- (NSString *)procDirectoryPathForProcess;
+
+/* returns contents of /proc/pid/status */
+- (NSDictionary *)procStatusDictionary;
+
+/* returns contents of /proc/pid/stat mapped as in 'man 5 proc' */
+- (NSDictionary *)procStatDictionary;
+
+/* wrappers */
+- (unsigned int)virtualMemorySize;
+- (unsigned int)residentSetSize;
+- (unsigned int)residentSetSizeLimit;
+
+@end
+
+#endif /* __NSProcessInfo_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSRunLoop+FileObjects.h b/skyrix-core/NGExtensions/NGExtensions/NSRunLoop+FileObjects.h
new file mode 100644 (file)
index 0000000..007cf42
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+// Created by Helge Hess on Mon Mar 11 2002.
+
+#ifndef __FoundationExt_NSRunLoop_FileObjects__
+#define __FoundationExt_NSRunLoop_FileObjects__
+
+#if !LIB_FOUNDATION_LIBRARY
+
+#import <Foundation/NSRunLoop.h>
+
+typedef enum {
+    NSPosixNoActivity = 0,
+    NSPosixReadableActivity = 1,
+    NSPosixWritableActivity = 2,
+    NSPosixExceptionalActivity = 4
+} NSPosixFileActivities;
+
+extern NSString *NSFileObjectBecameActiveNotificationName;
+
+@interface NSRunLoop(FileObjects)
+
+/* Monitoring file objects */
+
+- (void)addFileObject:(id)_fileObject
+  activities:(unsigned int)_activities
+  forMode:(NSString *)_mode;
+  
+- (void)removeFileObject:(id)_fileObject
+  forMode:(NSString *)_mode;
+
+@end
+
+@interface NSObject(RunloopFileObject)
+
+- (BOOL)isOpen;
+- (int)fileDescriptor;
+
+@end
+
+#endif /* !LIB_FOUNDATION_LIBRARY */
+
+#endif /* __FoundationExt_NSRunLoop_FileObjects__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSSet+enumerator.h b/skyrix-core/NGExtensions/NGExtensions/NSSet+enumerator.h
new file mode 100644 (file)
index 0000000..6aa4ad9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSSet_enumerator_H__
+#define __NGExtensions_NSSet_enumerator_H__
+
+#import <Foundation/NSSet.h>
+
+@interface NSSet(enumerator)
+
+- (id)initWithObjectsFromEnumerator:(NSEnumerator *)_enumerator;
+
+- (NSArray *)mappedArrayUsingSelector:(SEL)_selector;
+- (NSArray *)mappedArrayUsingSelector:(SEL)_selector withObject:(id)_object;
+- (NSSet *)mappedSetUsingSelector:(SEL)_selector;
+- (NSSet *)mappedSetUsingSelector:(SEL)_selector withObject:(id)_object;
+
+@end
+
+@interface NSMutableSet(enumerator);
+
+- (id)initWithObjectsFromEnumerator:(NSEnumerator *)_enumerator;
+
+@end
+
+#endif /* __NGExtensions_NSSet_enumerator_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSString+Encoding.h b/skyrix-core/NGExtensions/NGExtensions/NSString+Encoding.h
new file mode 100644 (file)
index 0000000..38b7c15
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSString_Encoding_H__
+#define __NGExtensions_NSString_Encoding_H__
+
+#import <Foundation/NSString.h>
+
+/*
+  NSString(Encoding)
+  
+  TODO: handler is currently fixed to iconv, should allow a registry of
+        handlers
+*/
+
+@interface NSString(Encoding)
+
++ (NSString *)stringWithData:(NSData *)_da usingEncodingNamed:(NSString *)_enc;
+- (NSData *)dataUsingEncodingNamed:(NSString *)_encoding;
+
+// TODO: fix this, do not use a define, implement a selector on all platforms!
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
++ (NSStringEncoding)stringEncodingForEncodingNamed:(NSString *)encoding;
+#endif
+
+@end
+
+#endif /* __NGExtensions_NSString_Encoding_H__ */
+
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSString+Ext.h b/skyrix-core/NGExtensions/NGExtensions/NSString+Ext.h
new file mode 100644 (file)
index 0000000..f2b877a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NSString_Ext_H__
+#define __NGExtensions_NSString_Ext_H__
+
+#import <Foundation/NSString.h>
+
+/* specific to gstep-base, supported in libFoundation */
+
+#if !LIB_FOUNDATION_LIBRARY && !GNUSTEP_BASE_LIBRARY
+
+@interface NSString(GSAdditions)
+
+- (NSString *)stringWithoutPrefix:(NSString *)_prefix;
+- (NSString *)stringWithoutSuffix:(NSString *)_suffix;
+
+- (NSString *)stringByReplacingString:(NSString *)_orignal
+  withString:(NSString *)_replacement;
+
+- (NSString *)stringByTrimmingLeadSpaces;
+- (NSString *)stringByTrimmingTailSpaces;
+- (NSString *)stringByTrimmingSpaces;
+
+/* the following are not available in gstep-base 1.6 ? */
+- (NSString *)stringByTrimmingLeadWhiteSpaces;
+- (NSString *)stringByTrimmingTailWhiteSpaces;
+- (NSString *)stringByTrimmingWhiteSpaces;
+
+@end /* NSString(GSAdditions) */
+
+@interface NSMutableString(GNUstepCompatibility)
+
+- (void)trimLeadSpaces;
+- (void)trimTailSpaces;
+- (void)trimSpaces;
+
+@end /* NSMutableString(GNUstepCompatibility) */
+
+#endif
+
+/* specific to libFoundation */
+
+#if !LIB_FOUNDATION_LIBRARY
+
+@interface NSString(lfNSURLUtilities)
+
+- (BOOL)isAbsoluteURL;
+- (NSString *)urlScheme;
+
+@end
+
+#endif
+
+#endif /* __NGExtensions_NSString_Ext_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSString+Formatting.h b/skyrix-core/NGExtensions/NGExtensions/NSString+Formatting.h
new file mode 100644 (file)
index 0000000..19a3045
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NSString_Formatting_H__
+#define __NGExtensions_NSString_Formatting_H__
+
+#import <Foundation/NSString.h>
+
+// category
+
+@interface NSString(XSFormatting)
+
++ (id)stringWithCFormat:(const char *)_format arguments:(va_list)_ap;
++ (id)stringWithCFormat:(const char *)_format, ...;
+
+@end
+
+@interface NSMutableString(XSFormatting)
+
+- (void)appendFormat:(NSString *)_format arguments:(va_list)_ap;
+- (void)appendFormat:(NSString *)_format, ...;
+
+@end
+
+// C support functions
+
+static inline int 
+xs_vsnprintf(char *str, size_t max, const char *fmt, va_list _ap) 
+{
+  NSString *obj = [NSString stringWithCFormat:str arguments:_ap];
+  [obj getCString:str maxLength:(max - 1)];
+  return [obj cStringLength]; // return the len the string would have consumed
+}
+
+static inline int xs_vsprintf (char *_str, const char *_fmt, va_list _ap) {
+  NSString *obj = [NSString stringWithCFormat:_str arguments:_ap];
+  [obj getCString:_str];
+  return [obj cStringLength]; // return the length of the string
+}
+
+/*
+  Could use formats ..
+     //     __attribute__ ((format (printf, 2, 3)));
+     //     __attribute__ ((format (printf, 3, 4)));
+*/
+int xs_sprintf (char *str, const char *format, ...);
+int xs_snprintf(char *str, size_t size, const char *format, ...);
+
+#endif /* __NGExtensions_NSString_Formatting_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSString+German.h b/skyrix-core/NGExtensions/NGExtensions/NSString+German.h
new file mode 100644 (file)
index 0000000..fe84dec
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NSString_German_H__
+#define __NGExtensions_NSString_German_H__
+
+#import <Foundation/NSString.h>
+
+@class NSArray;
+
+@interface NSString(German)
+
+- (BOOL)doesContainGermanUmlauts;
+- (NSString *)stringByReplacingGermanUmlautsWithTwoCharsAndSzWith:(unichar)_c;
+- (NSString *)stringByReplacingGermanUmlautsWithTwoChars;
+
+- (NSArray *)germanUmlautVariantsOfString;
+
+@end
+
+#endif /* __NGExtensions_NSString_German_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSString+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSString+misc.h
new file mode 100644 (file)
index 0000000..0515ec7
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGExtensions_NSString_misc_H__
+#define __NGExtensions_NSString_misc_H__
+
+#import <Foundation/NSString.h>
+
+@class NSSet, NSDictionary, NSString;
+
+@interface NSObject(StringBindings)
+- (NSString *)valueForStringBinding:(NSString *)_key;
+@end
+
+@interface NSString(misc)
+
+- (NSString *)stringByApplyingCEscaping;
+
+/*
+  Replaces keys, which enclosed in '$', with values from _bindings. The values
+  are retrieved using the '-valueForStringBinding:' method which per default
+  use -valueForKey: and -objectForKey: for NSDictionary objects.
+  For using of $ escape it with $$.
+  
+  Example:
+    source: @"du da blah $var$ doof"
+
+    dest = [source stringByReplacingVariablesWithBindings:
+                     @{ var = @"dummy"; }];
+    =>
+    dest:   @"du da blah dummy doof"
+*/
+- (NSString *)stringByReplacingVariablesWithBindings:(id)_bindings;
+
+/*
+  If there are variables with no binding, _unkown is used instead.
+  If _unkown is nil and there are unknown bindings, an exception will be thrown.
+*/
+- (NSString *)stringByReplacingVariablesWithBindings:(id)_bindings
+  stringForUnknownBindings:(NSString *)_unknown;
+
+/*
+  Returns all binding variables. ('aaa $doof$ $bla$' --> (doof, bla) )
+*/
+- (NSSet *)bindingVariables;
+
+@end
+
+@interface NSString(FilePathVersioningMethods)
+
+/*
+  "/PATH/file.txt;1"
+*/
+
+- (NSString *)pathVersion;
+- (NSString *)stringByDeletingPathVersion;
+- (NSString *)stringByAppendingPathVersion:(NSString *)_version;
+
+@end /* NSString(FilePathMethodsVersioning) */
+
+@interface NSString(URLEscaping)
+
+/*
+  These functions encode/decode HTTP style URL paths, which can escape
+  spaces and special chars.
+  Chars are escaped using the '%' hex-notation:
+
+  Encode:
+      'Hello World' => 'Hello%20World'
+      '& ?' => '%26%20%3F'
+*/
+
+- (BOOL)containsURLEscapeCharacters;
+- (NSString *)stringByUnescapingURL;
+- (NSString *)stringByEscapingURL;
+
+@end
+
+@interface NSString(HTMLEscaping)
+- (NSString *)stringByEscapingHTMLString;
+- (NSString *)stringByEscapingHTMLAttributeValue;
+@end
+
+@interface NSString(XMLEscaping)
+
+- (NSString *)stringByEscapingXMLString;
+- (NSString *)stringByEscapingXMLAttributeValue;
+
+/*
+  The following methods work in "fully-qualified XML names", in this
+  format:
+    '{namespace}name'
+*/
+- (BOOL)xmlIsFQN;
+- (NSString *)xmlNamespaceURI;
+- (NSString *)xmlLocalName;
+
+@end
+
+@interface NSString(NGScanning)
+
+/* 
+   this methods search for a string, while skipping quotes, eg:
+   
+     [@"abc '++' hello" rangeOfString:@"++" skipQuotes:@"\"'"];
+   
+   would not return a result !
+*/
+- (NSRange)rangeOfString:(NSString *)_s 
+  skipQuotes:(NSString *)_quotes
+  escapedByChar:(unichar)_escape;
+- (NSRange)rangeOfString:(NSString *)_s skipQuotes:(NSString *)_quotes;
+
+@end
+
+#endif /* __NGExtensions_NSString_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGExtensions/NSURL+misc.h b/skyrix-core/NGExtensions/NGExtensions/NSURL+misc.h
new file mode 100644 (file)
index 0000000..3e751b2
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_NSURL_misc_H__
+#define __NGExtensions_NSURL_misc_H__
+
+#import <Foundation/NSObject.h> // required by gstep-base
+#import <Foundation/NSURL.h>
+#import <Foundation/NSString.h>
+
+@interface NSURL(misc)
+
+/*
+  This method tries to construct the "shortest" path
+  between the two URLs. If the URLs are not in the same
+  namespace, -absoluteString is returned ...
+*/
+- (NSString *)stringValueRelativeToURL:(NSURL *)_base;
+
+/*
+  This checks whether protocol, host, login match. That is,
+  checks whether it's possible to build a relative URL to
+  _url (whether self is in the same path namespace).
+*/
+- (BOOL)isInSameNamespaceWithURL:(NSURL *)_url;
+
+/* adding fragments and queries to a string ... */
+- (NSString *)stringByAddingFragmentAndQueryToPath:(NSString *)_path;
+
+@end
+
+@interface NSString(URLPathProcessing)
+
+/* relative path processing (should never return an absolute path) */
+
+- (NSString *)urlPathRelativeToSelf;
+- (NSString *)urlPathRelativeToRoot;
+- (NSString *)urlPathRelativeToPath:(NSString *)_base;
+
+@end
+
+#endif /* __NGExtensions_NSURL_misc_H__ */
diff --git a/skyrix-core/NGExtensions/NGFileFolderInfoDataSource.m b/skyrix-core/NGExtensions/NGFileFolderInfoDataSource.m
new file mode 100644 (file)
index 0000000..04244fd
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGExtensions/NGFileFolderInfoDataSource.h>
+#import <EOControl/EOFetchSpecification.h>
+#import <EOControl/EOQualifier.h>
+#import <EOControl/EOSortOrdering.h>
+#include "common.h"
+
+NGExtensions_DECLARE NSString *NSFileName      = @"NSFileName";
+NGExtensions_DECLARE NSString *NSFilePath      = @"NSFilePath";
+NGExtensions_DECLARE NSString *NSParentPath    = @"NSParentPath";
+NGExtensions_DECLARE NSString *NSTraverseLinks = @"NSTraverseLinks";
+
+@implementation NGFileFolderInfoDataSource
+
+- (id)initWithFolderPath:(NSString *)_path {
+  if ((self = [self init])) {
+    self->folderPath = [_path copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->fspec      release];
+  [self->folderPath release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec {
+  ASSIGN(self->fspec, _fspec);
+}
+- (EOFetchSpecification *)fetchSpecification {
+  return self->fspec;
+}
+
+/* operations */
+
+- (NSArray *)_attributesForPaths:(NSEnumerator *)_paths
+  filterUsingQualifier:(EOQualifier *)_q
+  fileManager:(NSFileManager *)_fm
+{
+  NSMutableArray      *ma;
+  NSMutableDictionary *workArea;
+  NSArray             *result;
+  NSString            *path;
+  BOOL                tlinks;
+  
+  ma       = [NSMutableArray arrayWithCapacity:256];
+  workArea = [NSMutableDictionary dictionaryWithCapacity:32];
+  
+  tlinks = [[[self->fspec hints] objectForKey:@"NSTraverseLinks"] boolValue];
+  
+  while ((path = [_paths nextObject])) {
+    NSDictionary *record;
+    NSString     *fullPath;
+    
+    fullPath = [self->folderPath stringByAppendingPathComponent:path];
+    
+    [workArea setDictionary:
+                [_fm fileAttributesAtPath:fullPath traverseLink:tlinks]];
+    [workArea setObject:path             forKey:@"NSFileName"];
+    [workArea setObject:fullPath         forKey:@"NSFilePath"];
+    [workArea setObject:self->folderPath forKey:@"NSParentPath"];
+    
+    record = [[workArea copy] autorelease];
+    
+    if (_q) {
+      if (![(id<EOQualifierEvaluation>)_q evaluateWithObject:record])
+        /* filter out */
+        continue;
+    }
+
+    /* add to result set */
+    [ma addObject:record];
+  }
+  
+  result = [[ma copy] autorelease];
+  return result;
+}
+
+- (NSArray *)_fetchObjectsFromFileManager:(NSFileManager *)_fm {
+  NSAutoreleasePool *pool;
+  BOOL        isDir;
+  NSArray     *array;
+  NSArray     *sortOrderings;
+
+  if (![_fm fileExistsAtPath:self->folderPath isDirectory:&isDir])
+    /* path does not exist */
+    return nil;
+  if (!isDir)
+    /* path is not a directory */
+    return nil;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  array = [_fm directoryContentsAtPath:self->folderPath];
+  
+  if ([array count] == 0) {
+    /* no directory contents */
+    array = [array retain];
+    [pool release];
+    return [array autorelease];
+  }
+
+  array = [self _attributesForPaths:[array objectEnumerator]
+                filterUsingQualifier:[self->fspec qualifier]
+                fileManager:_fm];
+  
+  if ((sortOrderings = [self->fspec sortOrderings]))
+    /* sort set */
+    array = [array sortedArrayUsingKeyOrderArray:sortOrderings];
+  
+  array = [array retain];
+  [pool release];
+  
+  return [array autorelease];
+}
+
+- (NSArray *)fetchObjects {
+  NSFileManager *fm;
+  
+  fm = [NSFileManager defaultManager];
+  return [self _fetchObjectsFromFileManager:fm];
+}
+
+@end /* NGFileInfoDataSource */
diff --git a/skyrix-core/NGExtensions/NGFileManager+JS.m b/skyrix-core/NGExtensions/NGFileManager+JS.m
new file mode 100644 (file)
index 0000000..11016fc
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGFileManager.h"
+#include "NSFileManager+Extensions.h"
+#include "EOCacheDataSource.h"
+
+/*
+  JavaScript
+  
+    Properties
+    
+      cwd - readonly - current working directory, string
+    
+    Methods
+    
+      bool   cd(path)
+      Object ls([path|paths])
+      bool   mkdir(path[,path..])
+      bool   rmdir(path[,path..])
+      bool   rm(path[,path..])
+      bool   trash(path[,path..])
+      bool   cp(frompath[,frompath..], topath)
+      bool   mv(frompath[,frompath..], topath)
+      bool   ln(frompath, topath)
+      
+      bool   exists(path[,path..])
+      bool   isdir(path[,path..])
+      bool   islink(path[,path..])
+      
+      Object getDataSource([String path, [bool cache]])
+*/
+
+@implementation NGFileManager(JSSupport)
+
+static NSNumber *boolYes = nil;
+static NSNumber *boolNo  = nil;
+
+static void _ensureBools(void) {
+  if (boolYes == nil) boolYes = [[NSNumber numberWithBool:YES] retain];
+  if (boolNo  == nil) boolNo  = [[NSNumber numberWithBool:NO]  retain];
+}
+
+/* properties */
+
+- (id)_jsprop_cwd {
+  return [self currentDirectoryPath];
+}
+
+/* methods */
+
+- (id)_jsfunc_cd:(NSArray *)_args {
+  _ensureBools();
+  return [self changeCurrentDirectoryPath:[_args objectAtIndex:0]]
+    ? boolYes
+    : boolNo;
+}
+
+- (id)_jsfunc_ls:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) {
+    return [self directoryContentsAtPath:@"."];
+  }
+  else if (count == 1) {
+    return [self directoryContentsAtPath:
+                   [[_args objectAtIndex:0] stringValue]];
+  }
+  else {
+    NSMutableDictionary *md;
+    unsigned i;
+    
+    md = [NSMutableDictionary dictionaryWithCapacity:count];
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      NSArray  *contents;
+
+      path     = [_args objectAtIndex:i];
+      contents = [self directoryContentsAtPath:path];
+
+      if (contents)
+        [md setObject:contents forKey:path];
+    }
+    
+    return md;
+  }
+}
+
+- (id)_jsfunc_mkdir:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+
+  if ((count = [_args count]) == 0) {
+    return boolNo;
+  }
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      
+      path = [_args objectAtIndex:i];
+      
+      if (![self createDirectoryAtPath:path attributes:nil])
+        return boolNo;
+    }
+    
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_rmdir:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+
+  if ((count = [_args count]) == 0) {
+    return boolNo;
+  }
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      BOOL isDir;
+      
+      path = [_args objectAtIndex:i];
+      
+      if (![self fileExistsAtPath:path isDirectory:&isDir])
+        return boolNo;
+      
+      if (!isDir)
+        /* not a directory ! */
+        return boolNo;
+      
+      if ([[self directoryContentsAtPath:path] count] > 0)
+        /* directory has contents */
+        return boolNo;
+
+      if (![self removeFileAtPath:path handler:nil])
+        /* remove failed */
+        return boolNo;
+    }
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_rm:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0) {
+    return boolNo;
+  }
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      BOOL isDir;
+      
+      path = [_args objectAtIndex:i];
+      
+      if (![self fileExistsAtPath:path isDirectory:&isDir])
+        return boolNo;
+
+      if (isDir) {
+        if ([[self directoryContentsAtPath:path] count] > 0)
+          /* directory has contents */
+          return boolNo;
+      }
+      
+      if (![self removeFileAtPath:path handler:nil])
+        /* remove failed */
+        return boolNo;
+    }
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_trash:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+
+  if ((count = [_args count]) == 0) {
+    return boolNo;
+  }
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      BOOL isDir;
+      
+      path = [_args objectAtIndex:i];
+      if (![self supportsTrashFolderAtPath:path])
+        return boolNo;
+      
+      if (![self fileExistsAtPath:path isDirectory:&isDir])
+        return boolNo;
+      
+      if (![self trashFileAtPath:path handler:nil])
+        /* remove failed */
+        return boolNo;
+    }
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_mv:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0)
+    return boolNo;
+  else if (count == 1)
+    /* missing target path */
+    return boolNo;
+  else {
+    NSString *destpath;
+    unsigned i;
+    BOOL isDir;
+    
+    destpath = [_args objectAtIndex:(count - 1)];
+
+    if (![self fileExistsAtPath:destpath isDirectory:&isDir])
+      isDir = NO;
+    
+    for (i = 0; i < (count - 1); i++) {
+      NSString *path, *dpath = nil;
+      
+      path = [_args objectAtIndex:i];
+      
+      dpath = isDir
+        ? [dpath stringByAppendingPathComponent:[path lastPathComponent]]
+        : destpath;
+      
+      if (![self movePath:path toPath:dpath handler:nil])
+        /* move failed */
+        return boolNo;
+    }
+    
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_cp:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+   
+  if ((count = [_args count]) == 0)
+    return boolNo;
+  else if (count == 1)
+    /* missing target path */
+    return boolNo;
+  else {
+    NSString *destpath;
+    unsigned i;
+    BOOL isDir;
+    
+    destpath = [_args objectAtIndex:(count - 1)];
+
+    if (![self fileExistsAtPath:destpath isDirectory:&isDir])
+      isDir = NO;
+    
+    for (i = 0; i < (count - 1); i++) {
+      NSString *path, *dpath = nil;
+      
+      path = [_args objectAtIndex:i];
+
+      dpath = isDir
+        ? [dpath stringByAppendingPathComponent:[path lastPathComponent]]
+        : destpath;
+      
+      if (![self copyPath:path toPath:dpath handler:nil])
+        /* copy failed */
+        return boolNo;
+    }
+    
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_ln:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0)
+    return boolNo;
+  else if (count == 1)
+    /* missing target path */
+    return boolNo;
+  else {
+    NSString *srcpath;
+    NSString *destpath;
+    
+    srcpath  = [_args objectAtIndex:0];
+    destpath = [_args objectAtIndex:1];
+    
+    if (![self createSymbolicLinkAtPath:destpath pathContent:srcpath])
+      return boolNo;
+    
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_exists:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0)
+    return boolYes;
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      
+      path = [_args objectAtIndex:i];
+      
+      if (![self fileExistsAtPath:path])
+        return boolNo;
+    }
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_isdir:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0) {
+    return boolYes;
+  }
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      BOOL isDir;
+      
+      path = [_args objectAtIndex:i];
+
+#if 0
+      NSLog(@"CHECK PATH: %@", path);
+#endif
+      
+      if (![self fileExistsAtPath:path isDirectory:&isDir]) {
+#if 0
+        NSLog(@"  does not exist ..");
+#endif
+        return boolNo;
+      }
+
+      if (!isDir) {
+#if 0
+        NSLog(@"  not a directory ..");
+#endif
+        return boolNo;
+      }
+    }
+
+#if 0
+    NSLog(@"%s: returning yes, %@ are directories",
+          __PRETTY_FUNCTION__, _args);
+#endif
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_islink:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0)
+    return boolYes;
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString     *path;
+      BOOL         isDir;
+      NSDictionary *attrs;
+      
+      path = [_args objectAtIndex:i];
+      
+      if (![self fileExistsAtPath:path isDirectory:&isDir])
+        return boolNo;
+      
+      if (isDir)
+        return boolNo;
+
+      if ((attrs = [self fileAttributesAtPath:path traverseLink:NO])==nil)
+        return boolNo;
+
+      if (![[attrs objectForKey:NSFileType]
+                   isEqualToString:NSFileTypeSymbolicLink])
+        return boolNo;
+    }
+    return boolYes;
+  }
+}
+
+/* datasource */
+
+- (id)_jsfunc_getDataSource:(NSArray *)_args {
+  unsigned count;
+  NSString *path = nil;
+  BOOL     lcache;
+  id       ds;
+  _ensureBools();
+  
+  lcache = NO;
+  
+  if ((count = [_args count]) == 0) {
+    path = @".";
+  }
+  else if (count == 1) {
+    path = [[_args objectAtIndex:0] stringValue];
+  }
+  else if (count == 2) {
+    path  = [[_args objectAtIndex:0] stringValue];
+    lcache = [[_args objectAtIndex:1] boolValue];
+  }
+  
+  if (![self supportsFolderDataSourceAtPath:path])
+    return nil;
+  
+  if ((ds = [(id<NGFileManagerDataSources>)self dataSourceAtPath:path])==nil)
+    return nil;
+  
+  if (lcache) 
+    ds = [[[EOCacheDataSource alloc] initWithDataSource:ds] autorelease];
+  
+  return ds;
+}
+
+@end /* NGFileManager(JSSupport) */
diff --git a/skyrix-core/NGExtensions/NGFileManager.m b/skyrix-core/NGExtensions/NGFileManager.m
new file mode 100644 (file)
index 0000000..6d5a42d
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGFileManager.h"
+#include "NGFileManagerURL.h"
+#include "NSObject+Logs.h"
+#include "common.h"
+
+@implementation NGFileManager
+
+static BOOL logPathOps = NO;
+
++ (int)version {
+  return 0;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->cwd = @"/";
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->cwd release];
+  [super dealloc];
+}
+
+/* path modifications */
+
+- (NSString *)standardizePath:(NSString *)_path {
+  NSMutableArray *rpc;
+  NSArray        *pc;
+  unsigned       i, pcn;
+  NSString       *result;
+
+  if (logPathOps) [self logWithFormat:@"standardize: %@", _path];
+  
+  pc = [_path pathComponents];
+  if ((pcn = [pc count]) == 0) return _path;
+
+  if (logPathOps) {
+    [self logWithFormat:@"  components: %@", 
+            [pc componentsJoinedByString:@" => "]];
+  }
+  
+  rpc = [NSMutableArray arrayWithCapacity:pcn];
+  
+  for (i = 0; i < pcn; i++) {
+    NSString *p;
+    
+    p = [pc objectAtIndex:i];
+    
+    if ([p isEqualToString:@"/"]) {
+      /* found root */
+      [rpc removeAllObjects];
+      [rpc addObject:@"/"];
+    }
+    else if ([p isEqualToString:@"."]) {
+      /* found current directory */
+      /* '.' can always be removed, right ??? ... */
+    }
+    else if ([p isEqualToString:@".."]) {
+      /* found parent directory */
+      if (i == 0)
+        /* relative path starting with '..' */
+        [rpc addObject:p];
+      else {
+        /* remove last path component .. */
+        unsigned count;
+        
+        if ((count = [rpc count]) > 0)
+          [rpc removeObjectAtIndex:(count - 1)];
+      }
+    }
+    else if ([p isEqualToString:@""]) {
+      /* ignore empty strings */
+    }
+    else {
+      /* usual path */
+      [rpc addObject:p];
+    }
+  }
+  
+  if (logPathOps) {
+    [self logWithFormat:@"  new components: %@", 
+            [rpc componentsJoinedByString:@" => "]];
+  }
+  result = [NSString pathWithComponents:rpc];
+  if ([result length] == 0)
+    return _path;
+  
+  if (logPathOps) [self logWithFormat:@"  standardized: %@", result];
+  return result;
+}
+
+- (NSString *)resolveSymlinksInPath:(NSString *)_path {
+  return _path;
+}
+
+- (NSString *)expandTildeInPath:(NSString *)_path {
+  return _path;
+}
+
+/* directory operations */
+
+- (BOOL)changeCurrentDirectoryPath:(NSString *)_path {
+  BOOL isDir;
+
+  if (![self fileExistsAtPath:_path isDirectory:&isDir])
+    return NO;
+  if (!isDir)
+    return NO;
+  ASSIGNCOPY(self->cwd, _path);
+  return YES;
+}
+- (NSString *)currentDirectoryPath {
+  return self->cwd;
+}
+
+- (BOOL)createDirectoryAtPath:(NSString *)_path
+  attributes:(NSDictionary *)_ats
+{
+  return NO;
+}
+
+/* file operations */
+
+- (BOOL)copyPath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler {
+  return NO;
+}
+- (BOOL)movePath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler {
+  return NO;
+}
+- (BOOL)linkPath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler {
+  return NO;
+}
+
+- (BOOL)removeFileAtPath:(NSString *)_path handler:(id)_handler {
+  return NO;
+}
+
+- (BOOL)createFileAtPath:(NSString *)_path contents:(NSData *)_contents
+  attributes:(NSDictionary *)_attributes
+{
+  return NO;
+}
+
+/* getting and comparing file contents */
+
+- (NSData *)contentsAtPath:(NSString *)_path {
+  return nil;
+}
+- (BOOL)contentsEqualAtPath:(NSString *)_path1 andPath:(NSString *)_path2 {
+  NSData *data1, *data2;
+  
+  data1 = [self contentsAtPath:_path1];
+  data2 = [self contentsAtPath:_path2];
+  
+  if (data1 == data2) return YES;
+  if (data1 == nil || data2 == nil) return NO;
+  
+  return [data1 isEqual:data2];
+}
+
+/* determining access to files */
+
+- (BOOL)fileExistsAtPath:(NSString *)_path {
+  BOOL dummy = NO;
+  return [self fileExistsAtPath:_path isDirectory:&dummy];
+}
+- (BOOL)fileExistsAtPath:(NSString *)_path isDirectory:(BOOL*)_isDirectory {
+  return NO;
+}
+- (BOOL)isReadableFileAtPath:(NSString *)_path {
+  return NO;
+}
+- (BOOL)isWritableFileAtPath:(NSString *)_path {
+  return NO;
+}
+- (BOOL)isExecutableFileAtPath:(NSString *)_path {
+  return NO;
+}
+- (BOOL)isDeletableFileAtPath:(NSString *)_path {
+  return NO;
+}
+
+/* Getting and setting attributes */
+
+- (NSDictionary *)fileAttributesAtPath:(NSString *)_p traverseLink:(BOOL)_flag{
+  return nil;
+}
+- (NSDictionary *)fileSystemAttributesAtPath:(NSString *)_p {
+  return nil;
+}
+- (BOOL)changeFileAttributes:(NSDictionary *)_attributes atPath:(NSString *)_p{
+  return NO;
+}
+
+/* discovering directory contents */
+
+- (NSArray *)directoryContentsAtPath:(NSString *)_path {
+  return nil;
+}
+- (NSDirectoryEnumerator *)enumeratorAtPath:(NSString *)_path {
+  return nil;
+}
+- (NSArray *)subpathsAtPath:(NSString *)_path {
+  return nil;
+}
+
+/* symbolic-link operations */
+
+- (BOOL)createSymbolicLinkAtPath:(NSString *)_p pathContent:(NSString *)_dpath{
+  return NO;
+}
+- (NSString *)pathContentOfSymbolicLinkAtPath:(NSString *)_path {
+  return nil;
+}
+
+/* feature check */
+
+- (BOOL)supportsVersioningAtPath:(NSString *)_path {
+  return [self supportsFeature:NGFileManagerFeature_Versioning atPath:_path];
+}
+- (BOOL)supportsLockingAtPath:(NSString *)_path {
+  return [self supportsFeature:NGFileManagerFeature_Locking atPath:_path];
+}
+- (BOOL)supportsFolderDataSourceAtPath:(NSString *)_path {
+  return [self supportsFeature:NGFileManagerFeature_DataSources atPath:_path];
+}
+- (BOOL)supportsFeature:(NSString *)_featureURI atPath:(NSString *)_path {
+  return NO;
+}
+
+/* writing */
+
+- (BOOL)writeContents:(NSData *)_content atPath:(NSString *)_path {
+  return NO;
+}
+
+/* global-IDs */
+
+- (EOGlobalID *)globalIDForPath:(NSString *)_path; {
+  return nil;
+}
+- (NSString *)pathForGlobalID:(EOGlobalID *)_gid {
+  return nil;
+}
+
+/* trash */
+
+- (BOOL)supportsTrashFolderAtPath:(NSString *)_path {
+  return NO;
+}
+- (NSString *)trashFolderForPath:(NSString *)_path {
+  return nil;
+}
+
+- (BOOL)trashFileAtPath:(NSString *)_path handler:(id)_handler {
+  NSString *trash, *destPath;
+  BOOL     isDir;
+  unsigned i;
+  NSString *tmp;
+  
+  if (![self supportsTrashFolderAtPath:_path])
+    return NO;
+  if ([(trash = [self trashFolderForPath:_path]) length] == 0)
+    return NO;
+  
+  if ([_path hasPrefix:trash])
+    /* path already is in trash ... */
+    return YES;
+  
+  /* ensure that the trash folder is existent */
+
+  if ([self fileExistsAtPath:trash isDirectory:&isDir]) {
+    if (!isDir) {
+      NSLog(@"%s: '%@' exists, but isn't a folder !", __PRETTY_FUNCTION__,
+            trash);
+      return NO;
+    }
+  }
+  else { /* trash doesn't exist yet */
+    if (![self createDirectoryAtPath:trash attributes:nil]) {
+      NSLog(@"%s: couldn't create trash folder '%@' !", __PRETTY_FUNCTION__,
+            trash);
+      return NO;
+    }
+  }
+
+  /* construct trash path for target ... */
+
+  destPath = [trash stringByAppendingPathComponent:
+                      [_path lastPathComponent]];
+  tmp = destPath;
+  i = 0;
+  while ([self fileExistsAtPath:tmp]) {
+    i++;
+    tmp = [destPath stringByAppendingFormat:@"%d", i];
+    if (i > 40) {
+      NSLog(@"%s: too many files named similiar to '%@' in trash folder '%@'",
+            __PRETTY_FUNCTION__, destPath, trash);
+      return NO;
+    }
+  }
+  destPath = tmp;
+  
+  /* move to trash */
+  if (![self movePath:_path toPath:destPath handler:_handler])
+    return NO;
+  
+  return YES;
+}
+
+/* URLs */
+
+- (NSURL *)urlForPath:(NSString *)_path {
+  return [[[NGFileManagerURL alloc]
+                             initWithPath:_path fileManager:self]
+                             autorelease];
+}
+
+@end /* NGFileManager */
diff --git a/skyrix-core/NGExtensions/NGFileManagerURL.m b/skyrix-core/NGExtensions/NGFileManagerURL.m
new file mode 100644 (file)
index 0000000..127b3aa
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGFileManagerURL.h"
+#include "common.h"
+
+@interface NGFileManagerURLHandle : NSURLHandle
+{
+  id<NSObject,NGFileManager> fileManager;
+  NSString          *path;
+  BOOL              shallCache;
+  NSURLHandleStatus status;
+  NSData            *cachedData;
+  NSDictionary      *cachedProperties;
+}
+@end
+
+@implementation NGFileManagerURL
+
+- (id)initWithPath:(NSString *)_path
+  fileManager:(id<NSObject,NGFileManager>)_fm
+{
+  static BOOL didRegisterHandleClass = NO;
+  if (!didRegisterHandleClass) {
+    [NSURLHandle registerURLHandleClass:[NGFileManagerURLHandle class]];
+    didRegisterHandleClass = YES;
+  }
+  
+  self->path        = [[_fm standardizePath:_path] copy];
+  self->fileManager = [_fm retain];
+  return self;
+}
+
+- (void)dealloc {
+  [self->path        release];
+  [self->fileManager release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id<NSObject,NGFileManager>)fileManager {
+  return self->fileManager;
+}
+
+- (NSString *)fragment {
+  return nil;
+}
+- (NSString *)host {
+  return nil;
+}
+- (NSString *)path {
+  return self->path;
+}
+- (NSString *)scheme {
+  return nil;
+}
+- (NSString *)user {
+  return nil;
+}
+- (NSString *)password {
+  return nil;
+}
+- (NSNumber *)port {
+  return nil;
+}
+- (NSString *)query {
+  return nil;
+}
+
+- (BOOL)isFileURL {
+  return NO;
+}
+
+@end /* NGFileManagerURL */
+
+@implementation NGFileManagerURLHandle
+
++ (BOOL)canInitWithURL:(NSURL *)_url {
+  return [_url isKindOfClass:[NGFileManagerURL class]] ? YES : NO;
+}
+
+- (id)initWithURL:(NSURL *)_url cached:(BOOL)_flag {
+  if (![[self class] canInitWithURL:_url]) {
+    [self release];
+    return nil;
+  }
+
+  self->fileManager = [[(NGFileManagerURL *)_url fileManager] retain];
+  self->path        = [[_url path] copy];
+  self->shallCache  = _flag;
+  self->status      = NSURLHandleNotLoaded;
+  return self;
+}
+- (void)dealloc {
+  [self->cachedData  release];
+  [self->cachedProperties release];
+  [self->path        release];
+  [self->fileManager release];
+  [super dealloc];
+}
+
+- (NSData *)loadInForeground {
+  [self->cachedProperties release]; self->cachedProperties = nil;
+  [self->cachedData       release]; self->cachedData       = nil;
+  
+  self->cachedData = [[self->fileManager contentsAtPath:self->path] retain];
+  self->cachedProperties =
+    [[self->fileManager fileAttributesAtPath:self->path traverseLink:YES]
+                        copy];
+  
+  return self->cachedData;
+}
+- (void)loadInBackground {
+  [self loadInBackground];
+}
+
+- (void)flushCachedData {
+  [self->cachedData       release]; self->cachedData       = nil;
+  [self->cachedProperties release]; self->cachedProperties = nil;
+}
+
+- (NSData *)resourceData {
+  NSData *data;
+  
+  if (self->cachedData)
+    return [[self->cachedData copy] autorelease];
+  
+  data = [self loadInForeground];
+  data = [data copy];
+  
+  if (!self->shallCache)
+    [self flushCachedData];
+  
+  return [data autorelease];
+}
+
+- (NSData *)availableResourceData {
+  return [[self->cachedData copy] autorelease];
+}
+
+- (NSURLHandleStatus)status {
+  return self->status;
+}
+- (NSString *)failureReason {
+  if (self->status != NSURLHandleLoadFailed)
+    return nil;
+  
+  return @"loading of URL failed";
+}
+
+/* properties */
+
+- (id)propertyForKey:(NSString *)_key {
+  if (self->cachedProperties)
+    return [self->cachedProperties objectForKey:_key];
+  
+  if ([self loadInForeground]) {
+    id value;
+    
+    value = [self->cachedProperties objectForKey:_key];
+    value = [value retain];
+    
+    if (!self->shallCache)
+      [self flushCachedData];
+
+    return [value autorelease];
+  }
+  else {
+    [self flushCachedData];
+    return nil;
+  }
+}
+- (id)propertyForKeyIfAvailable:(NSString *)_key {
+  return [self->cachedProperties objectForKey:_key];
+}
+
+/* writing */
+
+- (BOOL)writeData:(NSData *)_data {
+  [self flushCachedData];
+
+  return NO;
+}
+
+@end /* NGFileManagerURLHandle */
diff --git a/skyrix-core/NGExtensions/NGHashMap.m b/skyrix-core/NGExtensions/NGHashMap.m
new file mode 100644 (file)
index 0000000..c6394a2
--- /dev/null
@@ -0,0 +1,996 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGHashMap.h"
+#include "common.h"
+
+#if LIB_FOUNDATION_LIBRARY
+#  import <extensions/exceptions/GeneralExceptions.h>
+#endif
+
+#if !LIB_FOUNDATION_LIBRARY
+@interface NSException(SetUI) /* allowed on Jaguar ? */
+- (void)setUserInfo:(NSDictionary *)_ui;
+@end
+#endif
+
+typedef struct _LList {
+  struct _LList *next;
+  id            object;
+  unsigned int  count;
+} LList;
+
+static inline void *initLListElement(id _object, LList* _next) {
+  LList *element  = malloc(sizeof(LList));
+  _object = [_object retain];
+  element->object = _object;
+  element->next   = _next;
+  element->count  = 0;
+  return element;
+}
+
+static inline void checkForAddErrorMessage(id _self, id _object, id _key) {
+  NSException  *exc;
+  NSDictionary *ui;
+  NSString     *r;
+  
+  if (_key == nil) {
+    r = [NSString stringWithFormat:@"nil key to be added in HashMap with object %@",
+           _object ? _object : @"<nil>"];
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                                     _self, @"map",
+                                     _key ? _key : @"<nil>",
+                                     @"key",
+                                     _object ? _object : @"<nil>",
+                                     @"object",
+                                     nil];
+    exc = [NSException exceptionWithName:NSInvalidArgumentException
+                       reason:r userInfo:ui];
+    [exc raise];
+  }
+  if (_object == nil) {
+    r = [NSString stringWithFormat:
+                   @"nil object to be added in HashMap for key %@",
+                   _key ? _key : @"<nil>"];
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                                     _self, @"map",
+                                     _key ? _key : @"<nil>",
+                                     @"key",
+                                     _object ? _object : @"<nil>",
+                                     @"object",
+                                     nil];
+    exc = [NSException exceptionWithName:NSInvalidArgumentException
+                       reason:r userInfo:ui];
+    [exc raise];
+  }
+}
+
+static inline void checkForRemoveErrorMessage(id _self, id _object, id _key) {
+  NSException  *exc;
+  NSDictionary *ui;
+  NSString     *r;
+  
+  if (_object != nil && _key != nil)
+    return;
+  
+  r = [NSString stringWithFormat:
+                 @"nil object to be removed in HashMap for key %@",
+                 _key ? _key : @"<nil>"];
+  ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                                     _self, @"map",
+                                     _key ? _key : @"<nil>",
+                                     @"key",
+                                     _object ? _object : @"<nil>",
+                                     @"object",
+                                     nil];
+  exc = [NSException exceptionWithName:NSInvalidArgumentException
+                     reason:r userInfo:ui];
+  [exc raise];
+}
+
+static inline void raiseInvalidArgumentExceptionForNilKey(id _self) {
+  NSException *exc = nil;
+  exc = [NSException exceptionWithName:NSInvalidArgumentException
+                     reason:@"key is nil"
+                     userInfo:[NSDictionary dictionaryWithObject:_self forKey:@"map"]];
+  [exc raise];
+}
+
+@interface _NGHashMapObjectEnumerator : NSEnumerator
+{
+  NSEnumerator *keys;
+  NSEnumerator *elements;
+  NGHashMap    *hashMap;
+}
+- (id)initWithHashMap:(NGHashMap *)_hashMap;
+- (id)nextObject;
+@end
+
+@interface _NGHashMapObjectForKeyEnumerator : NSEnumerator
+{
+  LList *element;
+  NGHashMap    *map;
+}
+- (id)initWithHashMap:(NGHashMap *)_hashMap andKey:(id)_key;
+- (id)nextObject;
+@end
+
+@interface _NGHashMapKeyEnumerator : NSEnumerator
+{
+  NSMapEnumerator enumerator;
+  NGHashMap *map;
+}
+- (id)initWithHashMap:(NGHashMap *)_hashMap;
+- (id)nextObject;
+@end
+
+// ************************* NGHashMap *************************
+
+@interface NGHashMap(private)
+- (LList *)__structForKey:(id)_key;
+- (NSMapEnumerator)__keyEnumerator;
+- (void)__removeAllObjectsForKey:(id)_key;
+- (void)__removeAllObjects;
+@end
+
+static Class NSArrayClass = Nil;
+
+@implementation NGHashMap
+
++ (void)initialize {
+  NSArrayClass = [NSArray class];
+}
+
+/* final methods */
+
+static inline void _removeAllObjectsInList(LList *list) {
+  while (list) {
+    register LList *element;
+    
+    [list->object release];
+    element = list;
+    list    = list->next;
+    if (element) free(element);
+  }
+}
+
+static inline LList *__structForKey(NGHashMap *self, id _key) {
+  if (_key == nil) raiseInvalidArgumentExceptionForNilKey(self);
+#if DEBUG
+  NSCAssert(self->table, @"missing table ..");
+#endif
+  return (LList *)NSMapGet(self->table, (void *)_key);
+}
+
+static inline unsigned __countObjectsForKey(NGHashMap *self, id _key) {
+  LList *list = NULL;
+  return (list = __structForKey(self, _key)) ? list->count : 0;
+}
+
+/* methods */
+
++ (id)hashMap {
+  return [[[self alloc] init] autorelease];
+}
++ (id)hashMapWithHashMap:(NGHashMap *)_hashMap {
+  return [[[self alloc] initWithHashMap:_hashMap] autorelease];
+}
++ (id)hashMapWithObjects:(NSArray *)_objects forKey:(id)_key {
+  return [[[self alloc] initWithObjects:_objects forKey:_key] autorelease];
+}
++ (id)hashMapWithDictionary:(NSDictionary *)_dict {
+  return [[[self alloc] initWithDictionary:_dict] autorelease];
+}
+
+- (id)init {
+  return [self initWithCapacity:0];
+}
+
+- (id)initWithCapacity:(unsigned int)_size {
+  if ((self = [super init])) {
+    self->table = NSCreateMapTableWithZone(NSObjectMapKeyCallBacks,
+                                           NSNonOwnedPointerMapValueCallBacks, 
+                                           _size * 4/3 ,NULL);
+    NSAssert1(self->table, @"missing table for hashmap of size %d ..", _size);
+  }
+  return self;
+}
+
+- (id)initWithHashMap:(NGHashMap *)_hashMap {
+  NSEnumerator *keys    = nil;
+  id            key     = nil;
+  LList *list    = NULL;
+  LList *newList = NULL;
+  LList *oldList = NULL;
+
+  if ((self = [self initWithCapacity:[_hashMap count]])) {
+    keys  = [_hashMap keyEnumerator];
+    while ((key = [keys nextObject])) {
+      list           = [_hashMap __structForKey:key];
+      newList        = initLListElement(list->object,NULL);
+      newList->count = list->count;
+      NSMapInsert(self->table,key,newList);
+      while (list->next) {
+        oldList       = newList;
+        list          = list->next;
+        newList       = initLListElement(list->object,NULL);
+        oldList->next = newList;
+      }
+    }
+  }
+  return self;
+}
+
+- (id)initWithObjects:(NSArray *)_objects forKey:(id)_key {
+  LList *root    = NULL;
+  LList *element = NULL;
+  LList *pred    = NULL;  
+  int           count   = 0;
+  int           i       = 0; 
+
+  if (( self = [self initWithCapacity:1])) {
+    count = [_objects count];
+    if (count == 0) 
+      return self;
+
+    root = initLListElement([_objects objectAtIndex:0], NULL);
+    pred = root;
+    for (i = 1; i < count; i++) {
+      element    = initLListElement([_objects objectAtIndex:i], NULL);
+      pred->next = element;
+      pred       = element;
+    }
+    root->count = i;
+    NSMapInsert(self->table,_key, root);
+  }
+  NSAssert(self->table, @"missing table for hashmap ..");
+  return self;
+}
+
+- (id)initWithDictionary:(NSDictionary *)_dictionary {
+  if (![self isKindOfClass:[NGMutableHashMap class]]) {
+    self = [self autorelease];
+    self = [[NGMutableHashMap allocWithZone:[self zone]]
+                              initWithCapacity:[_dictionary count]];
+  }
+  else
+    self = [self initWithCapacity:[_dictionary count]];
+  
+  if (self) {
+    NSEnumerator *keys;
+    id key;
+    
+    keys = [_dictionary keyEnumerator];
+    while ((key = [keys nextObject])) {
+      [(NGMutableHashMap *)self
+                          setObject:[_dictionary objectForKey:key] 
+                          forKey:key];
+    }
+  }
+  NSAssert(self->table, @"missing table for hashmap ..");
+  return self;
+}
+
+- (void)dealloc {
+  if (self->table) {
+    NSMapEnumerator mapenum;
+    id key = nil, value = nil;
+
+    mapenum = [self __keyEnumerator];
+
+    while (NSNextMapEnumeratorPair(&mapenum, (void **)&key, (void **)&value))
+      _removeAllObjectsInList((LList *)value);
+
+    NSFreeMapTable(self->table);
+    self->table = NULL;
+  }
+  [super dealloc];
+}
+
+/* removing */
+
+- (void)__removeAllObjectsForKey:(id)_key {
+  _removeAllObjectsInList(__structForKey(self, _key));
+  NSMapRemove(self->table, _key);
+}
+
+- (void)__removeAllObjects {
+  NSEnumerator *keys = nil;
+  id           key  = nil;
+
+  keys = [self keyEnumerator];
+  while ((key = [keys nextObject]))
+    _removeAllObjectsInList(__structForKey(self, key));
+
+  NSResetMapTable(self->table);
+}
+
+/* equality */
+
+- (unsigned int)hash {
+  return [self count];
+}
+
+- (BOOL)isEqual:(id)anObject {
+  if (self == anObject)
+    return YES;
+  
+  if (![anObject isKindOfClass:[NGHashMap class]])
+    return NO;
+  
+  return [self isEqualToHashMap:anObject];
+}
+
+- (BOOL)isEqualToHashMap:(NGHashMap *)_other {
+  NSEnumerator *keyEnumerator = nil;
+  id            key           = nil;
+  LList *selfList      = NULL;
+  LList *otherList     = NULL;
+
+  if (_other == self) 
+    return YES;
+
+  if ([self count] != [_other count])
+    return NO;
+
+  keyEnumerator = [self keyEnumerator];
+  while ((key = [keyEnumerator nextObject])) {
+    if (__countObjectsForKey(self, key) != [_other countObjectsForKey:key])
+      return NO;
+
+    selfList  = __structForKey(self, key);
+    otherList = [_other __structForKey:key];
+    while (selfList) {
+      if (![selfList->object isEqual:otherList->object]) 
+        return NO;
+
+      selfList = selfList->next;
+      otherList = otherList->next;      
+    }
+  }
+  return YES;
+}
+
+
+- (id)objectForKey:(id)_key {
+  LList *list;
+  
+  if (!(list = __structForKey(self, _key))) 
+    return nil;
+
+  if (list->next) {
+    NSLog(@"WARNING[%s] more than one element for key %@ objects: %@, "
+          @"return first object", __PRETTY_FUNCTION__, _key,
+          [self objectsForKey:_key]);
+  }
+  return list->object;
+}
+
+- (NSArray *)objectsForKey:(id)_key {
+  NSArray         *array      = nil;
+  NSEnumerator    *objectEnum = nil;
+  id              object      = nil;
+  id              *objects    = NULL;
+  unsigned int    i           = 0;
+
+  if ((objectEnum = [self objectEnumeratorForKey:_key]) == nil)
+    return nil;
+  
+  objects = calloc(__countObjectsForKey(self, _key) + 1, sizeof(id));
+  for (i = 0; (object = [objectEnum nextObject]); i++)
+    objects[i] = object;
+  
+  array = [NSArrayClass arrayWithObjects:objects count:i];
+  if (objects) free(objects);
+  return array;
+}
+
+- (id)objectAtIndex:(unsigned int)_index forKey:(id)_key {
+  LList *list = NULL;
+  
+  if (!(list = __structForKey(self, _key)))
+    return nil;
+  
+  if ((_index < list->count) == 0) {
+#if LIB_FOUNDATION_LIBRARY
+    NSException *exc = [[IndexOutOfRangeException alloc]
+      initForSize:list->count index:_index];
+    [exc setUserInfo:
+          [NSDictionary dictionaryWithObject:self forKey:@"object"]];
+    [exc raise];
+#else
+    [NSException raise:NSRangeException
+                 format:@"index %d out of range for key %@ of length %d",
+                   _index, _key, list->count];
+#endif
+  }
+
+  while (_index--)
+    list = list->next;
+
+  return list->object;
+}
+
+- (NSArray *)allKeys {
+  NSArray      *array   = nil;
+  NSEnumerator *keys;  
+  id           *objects;
+  id           object;
+  int          i;
+  
+  objects = calloc([self count] + 1, sizeof(id));
+  keys    = [self keyEnumerator];
+  for(i = 0; (object = [keys nextObject]); i++)
+    objects[i] = object;
+  
+  array = [[NSArrayClass alloc] initWithObjects:objects count:i];
+  if (objects) free (objects);
+  return [array autorelease];
+}
+
+- (NSArray *)allObjects {
+  NSEnumerator   *keys   = nil;
+  id             object  = nil;
+  NSMutableArray *mArray = nil;
+  NSArray        *result = nil;
+  
+  mArray = [[NSMutableArray alloc] init];
+  keys   = [self keyEnumerator];
+  while ((object = [keys nextObject])) 
+    [mArray addObjectsFromArray:[self objectsForKey:object]];
+
+  result = [mArray copy];
+  [mArray release]; mArray = nil;
+  return [result autorelease];
+}
+
+- (unsigned int)countObjectsForKey:(id)_key {
+  return __countObjectsForKey(self, _key);
+}
+
+- (NSEnumerator *)keyEnumerator {
+  return [[[_NGHashMapKeyEnumerator alloc] initWithHashMap:self] autorelease];
+}
+
+- (NSEnumerator *)objectEnumerator {
+  return [[[_NGHashMapObjectEnumerator alloc] 
+           initWithHashMap:self] autorelease];
+}
+
+- (NSEnumerator *)objectEnumeratorForKey:(id)_key {
+  if (_key == nil)
+    raiseInvalidArgumentExceptionForNilKey(self);
+  
+  return [[[_NGHashMapObjectForKeyEnumerator alloc]
+              initWithHashMap:self andKey:_key] autorelease];
+}
+
+- (NSDictionary *)asDictionaryWithArraysForValues:(BOOL)arraysOnly {
+  NSDictionary  *dict    = nil;
+  NSEnumerator  *keys;
+  id            key;
+  id            *dicObj;
+  id            *dicKeys;
+  int           cntKey;
+  
+  keys    = [self keyEnumerator];
+  cntKey  = [self count];
+  dicObj  = calloc(cntKey + 1, sizeof(id));
+  dicKeys = calloc(cntKey + 1, sizeof(id));  
+  
+  for (cntKey = 0; (key = [keys nextObject]); ) {
+    id     object   = nil;    
+    LList  *list;
+    
+    if ((list = __structForKey(self, key)) == NULL) {
+      NSLog(@"ERROR(%s): did not find key '%@' in hashmap: %@", 
+           __PRETTY_FUNCTION__, key, self);
+      continue;
+    }
+    
+    if (list->next) {
+      id   *objects = NULL;
+      int  cntObj   = 0;      
+      
+      objects = calloc(list->count + 1, sizeof(id));
+      {
+        cntObj  = 0;
+        while (list) {
+          objects[cntObj++] = list->object;
+          list = list->next;
+        }
+        
+               object = [NSArray arrayWithObjects:objects count:cntObj];
+      }
+      if (objects) free(objects); objects = NULL;
+    }
+    else {
+               if (arraysOnly) {
+          object = [NSArray arrayWithObject:list->object ];
+               } else {
+                 object = list->object;
+               }
+       }
+       
+    dicObj[cntKey]    = object;
+    dicKeys[cntKey++] = key;
+  }
+  
+  dict = [[NSDictionary alloc]
+                        initWithObjects:dicObj forKeys:dicKeys count:cntKey];
+  
+  if (dicObj)  free(dicObj);  dicObj  = NULL;
+  if (dicKeys) free(dicKeys); dicKeys = NULL;
+  return [dict autorelease];
+}
+
+- (NSDictionary *)asDictionary {
+       return [ self asDictionaryWithArraysForValues: NO ];
+}
+
+- (NSDictionary *)asDictionaryWithArraysForValues {
+       return [ self asDictionaryWithArraysForValues: YES ];
+}
+
+
+- (id)propertyList {
+  NSDictionary  *dict    = nil;
+  NSEnumerator  *keys    = nil;
+  id            key;
+  id            *dicObj  = NULL;
+  id            *dicKeys = NULL;
+  int           cntKey   = 0;
+
+  keys    = [self keyEnumerator];
+  cntKey  = [self count];
+  dicObj  = calloc(cntKey + 1, sizeof(id));
+  dicKeys = calloc(cntKey + 1, sizeof(id));
+  
+  for (cntKey = 0; (key = [keys nextObject]); ) {
+    id            object   = nil;    
+    LList  *list    = NULL;
+    
+    list = __structForKey(self, key);
+    if (list->next) {
+      id   *objects = NULL;
+      int  cntObj   = 0;      
+      
+      objects = calloc(list->count + 1, sizeof(id));
+      {
+        cntObj  = 0;
+        while (list) {
+          objects[cntObj++] = list->object;
+          list = list->next;
+        }
+        object = [NSArrayClass arrayWithObjects:objects count:cntObj];
+      }
+      if (objects) free(objects); objects = NULL;
+    }
+    else 
+      object = list->object;
+    
+    dicObj[cntKey]  = object;
+    dicKeys[cntKey] = key;
+    cntKey++;
+  }
+  dict = [[[NSDictionary alloc] initWithObjects:dicObj forKeys:dicKeys
+                                count:cntKey] autorelease];
+  if (dicObj)  free(dicObj);  dicObj  = NULL;
+  if (dicKeys) free(dicKeys); dicKeys = NULL;
+  return dict;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [[self propertyList] description];
+}
+
+- (unsigned int)count {
+  return self->table ? NSCountMapTable(table) : 0;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[NGHashMap allocWithZone:_zone] initWithHashMap:self];    
+}
+
+- (id)mutableCopyWithZone:(NSZone *)_zone {
+  return [[NGMutableHashMap allocWithZone:_zone] initWithHashMap:self];  
+}
+
+/* */
+
+- (NSMapEnumerator)__keyEnumerator {
+  return NSEnumerateMapTable(table);
+}
+
+- (LList *)__structForKey:(id)_key {
+  return __structForKey(self, _key);
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_encoder {
+  unsigned        keyCount = [self count];
+  NSMapEnumerator mapenum  = [self __keyEnumerator];
+  id              key      = nil;
+  LList           *value   = NULL;
+  
+  [_encoder encodeValueOfObjCType:@encode(unsigned) at:&keyCount];
+
+  while (NSNextMapEnumeratorPair(&mapenum, (void **)&key, (void **)&value)) {
+    unsigned valueCount = value ? value->count : 0;
+    unsigned outCount   = 0; // debugging
+
+    [_encoder encodeObject:key];
+    [_encoder encodeValueOfObjCType:@encode(unsigned) at:&valueCount];
+
+    while (value) {
+      [_encoder encodeObject:value->object];
+      value = value->next;
+      outCount++;
+    }
+
+    NSAssert(valueCount == outCount, @"didn't encode enough value objects");
+  }
+}
+
+- (id)initWithCoder:(NSCoder *)_decoder {
+  NGMutableHashMap *map = [[NGMutableHashMap alloc] init];
+  unsigned keyCount;
+  unsigned cnt;
+
+  [_decoder decodeValueOfObjCType:@encode(unsigned) at:&keyCount];
+  for (cnt = 0; cnt < keyCount; cnt++) {
+    unsigned valueCount = 0, cnt2 = 0;
+    id       key        = nil;
+
+    key = [_decoder decodeObject];
+    [_decoder decodeValueOfObjCType:@encode(unsigned) at:&valueCount];
+
+    for (cnt2 = 0; cnt2 < valueCount; cnt2++) {
+      id value = [_decoder decodeObject];
+      [map addObject:value forKey:key];
+    }
+  }
+
+  self = [self initWithHashMap:map];
+  [map release]; map = nil;
+
+  return self;
+}
+
+@end /* NGHashMap */
+
+// ************************* NGMutableHashMap ******************
+
+@implementation NGMutableHashMap
+
++ (id)hashMapWithCapacity:(unsigned int)_numItems {
+  return [[[self alloc] initWithCapacity:_numItems] autorelease];
+}
+
+- (id)init {
+  return [self initWithCapacity:0];
+}
+
+/* inserting objects */
+
+- (void)insertObject:(id)_object atIndex:(unsigned int)_index forKey:(id)_key {
+  [self insertObjects:&_object count:1 atIndex:_index forKey:_key];
+}
+
+- (void)insertObjects:(NSArray *)_objects atIndex:(unsigned int)_index
+  forKey:(id)_key 
+{
+  id  *objects = NULL;
+  int i        = 0;
+  int cntI     = 0;
+  
+  cntI    = [_objects count];
+  objects = calloc(cntI + 1, sizeof(id));
+  for (i = 0 ; i < cntI; i++) 
+    objects[i] = [_objects objectAtIndex:i];
+
+  [self insertObjects:objects count:cntI atIndex:_index forKey:_key];
+  if (objects) free(objects);
+}
+
+- (void)insertObjects:(id*)_objects count:(unsigned int)_count
+  atIndex:(unsigned int)_index forKey:(id)_key 
+{
+  id            object  = nil;
+  LList *root    = NULL;
+  LList *element = NULL;
+  unsigned i = 0;
+  
+  if (_count == 0)
+    return;
+
+  checkForAddErrorMessage(self, _objects[0],_key);
+  if ((root = [self __structForKey:_key]) == NULL) {
+    if (_index > 0) {
+#if LIB_FOUNDATION_LIBRARY
+      NSException *exc = [[IndexOutOfRangeException alloc]
+        initForSize:0 index:_index];
+      [exc setUserInfo:[NSDictionary dictionaryWithObject:self forKey:@"map"]];
+      [exc raise];
+#else
+      [NSException raise:NSRangeException
+                   format:@"index %d out of range in map 0x%08X", 
+                    _index, self];
+#endif
+    }
+
+    root        = initLListElement(_objects[0], NULL);
+    root->count = _count;
+    NSMapInsert(self->table, _key, root);
+  }
+  else {
+    if (!(_index < root->count)) {
+#if LIB_FOUNDATION_LIBRARY
+      NSException *exc = [[IndexOutOfRangeException alloc]
+        initForSize:root->count index:_index];
+      [exc setUserInfo:[NSDictionary dictionaryWithObject:self forKey:@"map"]];
+      [exc raise];
+#else
+      [NSException raise:NSRangeException
+                   format:@"index %d out of range in map 0x%08X length %d", 
+                    _index, self, root->count];
+#endif
+    }
+    
+    root->count += _count;
+    if (_index == 0) {
+      element         = initLListElement(_objects[0],NULL);
+      object          = element->object;
+      element->next   = root->next;
+      element->object = root->object;      
+      root->object    = object;
+      root->next      = element;
+    }
+    else {
+      while (--_index)
+        root = root->next;
+
+      element       = initLListElement(_objects[0], NULL);
+      element->next = root->next;
+      root->next    = element;
+      root          = root->next;
+    }
+  }
+  for (i = 1; i < _count; i++) {
+    checkForAddErrorMessage(self, _objects[i], _key);
+    element       = initLListElement(_objects[i], NULL);
+    element->next = root->next;
+    root->next    = element;
+    root          = element;
+  }
+}
+
+/* adding objects */
+
+- (void)addObjects:(id*)_objects count:(unsigned int)_count forKey:(id)_key {
+  LList *root     = NULL;
+  LList *element  = NULL;
+  unsigned i      = 0;
+
+  if (_count == 0)
+    return;
+
+  checkForAddErrorMessage(self, _objects[0],_key);
+  if ((root = [self __structForKey:_key]) == NULL) {
+    root        = initLListElement(_objects[0], NULL);
+    root->count = _count;
+    NSMapInsert(self->table, _key, root);
+  }
+  else {
+    root->count += _count;
+    while (root->next)
+      root = root->next;
+    
+    element    = initLListElement(_objects[0], NULL);
+    root->next = element;
+    root       = root->next;
+  }
+  for (i = 1; i < _count; i++) {
+    checkForAddErrorMessage(self, _objects[i], _key);
+    element    = initLListElement(_objects[i], NULL);
+    root->next = element;
+    root       = element;
+  }
+}
+
+- (void)addObject:(id)_object forKey:(id)_key {
+  checkForAddErrorMessage(self, _object,_key);
+  [self addObjects:&_object count:1 forKey:_key];  
+}
+
+- (void)addObjects:(NSArray *)_objects forKey:(id)_key {
+  id  *objects = NULL;
+  int i        = 0;
+  int cntI     = 0;
+  
+  cntI    = [_objects count];
+  objects = calloc(cntI + 1, sizeof(id));
+  for (i = 0 ; i < cntI; i++) 
+    objects[i] = [_objects objectAtIndex:i];
+
+  [self addObjects:objects count:cntI forKey:_key];
+  if (objects) free(objects);
+}
+
+/* setting objects */
+
+- (void)setObject:(id)_object forKey:(id)_key {
+  checkForAddErrorMessage(self, _object, _key);
+  [self removeAllObjectsForKey:_key];
+  [self addObjects:&_object count:1 forKey:_key];
+}
+
+- (void)setObjects:(NSArray *)_objects forKey:(id)_key {
+  checkForAddErrorMessage(self, _objects, _key);  
+  [self removeAllObjectsForKey:_key];
+  [self addObjects:_objects forKey:_key];
+}
+
+/* removing objects */
+
+- (void)removeAllObjects {
+  [self __removeAllObjects];
+}
+
+- (void)removeAllObjectsForKey:(id)_key {
+  [self __removeAllObjectsForKey:_key];
+}
+
+- (void)removeAllObjects:(id)_object forKey:(id)_key {
+  LList  *list    = NULL;
+  LList  *root    = NULL;
+  LList  *oldList = NULL;  
+  unsigned int  cnt      = 0;
+
+  checkForRemoveErrorMessage(self, _object, _key);
+  if (!(root = [self __structForKey:_key])) 
+    return;
+
+  while ([root->object isEqual:_object]) {
+    [root->object release];
+    if (root->next == NULL) {
+      if (root) free(root);
+      root = NULL;
+      NSMapRemove(self->table,_key);
+      break;
+    }
+    else {
+      list         = root->next;
+      root->next   = list->next;
+      root->object = list->object;
+      root->count--;
+      if (list) free(list);
+      list = NULL;
+    }
+  }
+  if (root) {
+    list = root;
+    while (list->next) {
+      oldList = list;    
+      list    = list->next;
+      if ([list->object isEqual:_object]) {
+        cnt++;
+        oldList->next = list->next;
+        if (list) free(list);
+        list = oldList;
+      }
+    }
+    root->count -= cnt;
+  }
+}
+
+- (void)removeAllObjectsForKeys:(NSArray *)_keyArray {
+  register int index  = 0;
+  for (index = [_keyArray count]; index > 0;)
+    [self removeAllObjectsForKey:[_keyArray objectAtIndex:--index]];
+}
+
+@end /* NGMutableHashMap */
+
+// ************************* Enumerators ******************
+
+@implementation _NGHashMapKeyEnumerator
+
+- (id)initWithHashMap:(NGHashMap *)_hashMap {
+  self->map        = [_hashMap retain];
+  self->enumerator = [_hashMap __keyEnumerator];
+  return self;
+}
+- (void)dealloc {
+  [self->map release];
+  [super dealloc];
+}
+
+- (id)nextObject {
+  id key, value;
+  return NSNextMapEnumeratorPair(&self->enumerator,(void**)&key, (void**)&value) ?
+         key : nil;
+}
+
+@end /* _NGHashMapKeyEnumerator */
+
+@implementation _NGHashMapObjectEnumerator
+
+- (id)initWithHashMap:(NGHashMap *)_hashMap {
+  self->keys     = [[_hashMap keyEnumerator] retain];
+  self->hashMap  = [_hashMap retain];
+  self->elements = nil;
+  return self;
+}
+
+- (void)dealloc {
+  [self->keys     release];
+  [self->hashMap  release];
+  [self->elements release];
+  [super dealloc];
+}
+
+- (id)nextObject {
+  id object;
+  id key;
+  
+  if ((object = [self->elements nextObject]))
+    return object;
+  
+  if ((key = [self->keys nextObject])) {
+    ASSIGN(self->elements, [self->hashMap objectEnumeratorForKey:key]);
+    object = [self->elements nextObject];
+  }
+  return object;
+}
+
+@end /* _NGHashMapObjectEnumerator */
+
+@implementation _NGHashMapObjectForKeyEnumerator
+
+- (id)initWithHashMap:(NGHashMap *)_hashMap andKey:(id)_key {
+  element = [_hashMap __structForKey:_key];
+  self->map = [_hashMap retain];
+  return self;
+}
+- (void)dealloc {
+  [self->map release];
+  [super dealloc];
+}
+
+- (id)nextObject {
+  id object;
+  
+  if (element == NULL) 
+    return nil;
+  
+  object  = element->object;
+  element = element->next;
+  return object;
+}
+
+@end /* _NGHashMapObjectForKeyEnumerator */
diff --git a/skyrix-core/NGExtensions/NGMerging.m b/skyrix-core/NGExtensions/NGMerging.m
new file mode 100644 (file)
index 0000000..ec39532
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMerging.h"
+#include "common.h"
+#import <Foundation/Foundation.h>
+#import <Foundation/NSObject.h>
+
+static NSString *NGCannotMergeWithObjectException =
+  @"NGCannotMergeWithObjectException";
+
+@implementation NSObject(NGMerging)
+
+- (BOOL)canMergeWithObject:(id)_object {
+  return ((_object == nil) || (_object == self)) ? YES : NO;
+}
+
+- (id)_makeMergeCopyWithZone:(NSZone *)_zone {
+  return [(id<NSCopying>)self copyWithZone:_zone];
+}
+
+- (id)mergeWithObject:(id)_object zone:(NSZone *)_zone {
+  if ((_object == nil) || (_object == self))
+    return [self _makeMergeCopyWithZone:_zone];
+  
+  [NSException raise:NGCannotMergeWithObjectException
+               format:@"cannot merge objects of class %@ and %@",
+                 NSStringFromClass([self class]),
+                 NSStringFromClass([_object class])];
+  return nil;
+}
+
+- (id)mergeWithObject:(id)_object {
+  return [self mergeWithObject:_object zone:NULL];
+}
+
+@end
+
+@implementation NSDictionary(NGMerging)
+
+- (BOOL)canMergeWithObject:(id)_object {
+  if ((self == _object) || (_object == nil))
+    return YES;
+
+  if ([_object isKindOfClass:[NSDictionary class]])
+    return YES;
+
+  return NO;
+}
+
+- (id)_makeMergeCopyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+- (id)mergeWithDictionary:(NSDictionary *)_object zone:(NSZone *)_zone {
+  NSMutableDictionary *result;
+  NSArray *aKeys, *bKeys;
+  int i, count;
+  
+  if ((self == _object) || (_object == nil))
+    return [self _makeMergeCopyWithZone:_zone];
+
+  aKeys = [self allKeys];
+  bKeys = [_object allKeys];
+  result = [NSMutableDictionary dictionary];
+
+  /* merge all keys of a */
+  for (i = 0, count = [aKeys count]; i < count; i++) {
+    id key;
+    id av, bv;
+
+    key = [aKeys objectAtIndex:i];
+    av = [self    objectForKey:key];
+    bv = [_object objectForKey:key];
+
+    if (bv == nil) {
+      /* key is only in a */
+      [result setObject:av forKey:key];
+    }
+    else {
+      /* key is in both - need to merge */
+      if ([av canMergeWithObject:bv]) {
+        av = [av mergeWithObject:bv zone:_zone];
+        [result setObject:av forKey:key];
+      }
+      else
+        // if objects cannot be merged, av wins
+        [result setObject:av forKey:key];
+    }
+  }
+
+  /* add remaining keys in b */
+  for (i = 0, count = [bKeys count]; i < count; i++) {
+    id key;
+
+    key = [bKeys objectAtIndex:i];
+    if ([result objectForKey:key])
+      // already merged key ..
+      continue;
+
+    [result setObject:[_object objectForKey:key] forKey:key];
+  }
+
+  return result;
+}
+
+- (id)mergeWithObject:(id)_object zone:(NSZone *)_zone {
+  if ((self == _object) || (_object == nil))
+    return [self _makeMergeCopyWithZone:_zone];
+  
+  if ([_object isKindOfClass:[NSDictionary class]])
+    return [self mergeWithDictionary:_object zone:_zone];
+
+  [NSException raise:NGCannotMergeWithObjectException
+               format:@"cannot merge %@ with %@",
+                 NSStringFromClass([self class]),
+                 NSStringFromClass([_object class])];
+  return nil;
+}
+
+@end
+
+@implementation NSMutableDictionary(NGMerging)
+
+- (id)_makeMergeCopyWithZone:(NSZone *)_zone {
+  return [self copyWithZone:_zone];
+}
+
+@end
+
+@implementation NSArray(NGMerging)
+
+- (BOOL)canMergeWithObject:(id)_object {
+  if ((self == _object) || (_object == nil))
+    return YES;
+
+  if ([_object respondsToSelector:@selector(objectEnumerator)])
+    return YES;
+  
+  return NO;
+}
+
+- (id)_makeMergeCopyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+- (id)mergeWithEnumeration:(NSEnumerator *)_object zone:(NSZone *)_zone {
+  NSMutableArray *result;
+  id value;
+
+  if (_object == nil)
+    return [self _makeMergeCopyWithZone:_zone];
+
+  /* make copy of self */
+  result = [[self mutableCopyWithZone:_zone] autorelease];
+
+  /* add other elements */
+  while ((value = [_object nextObject]))
+    [result addObject:value];
+
+  return result;
+}
+
+- (id)mergeWithArray:(NSArray *)_object zone:(NSZone *)_zone {
+  if (_object == nil)
+    return [self _makeMergeCopyWithZone:_zone];
+  
+  return [self arrayByAddingObjectsFromArray:_object];
+}
+
+- (id)mergeWithObject:(id)_object zone:(NSZone *)_zone {
+  if (_object == nil)
+    return [self _makeMergeCopyWithZone:_zone];
+  
+  if ([_object respondsToSelector:@selector(objectEnumerator)])
+    return [self mergeWithEnumeration:[_object objectEnumerator] zone:_zone];
+
+  [NSException raise:NGCannotMergeWithObjectException
+               format:@"cannot merge %@ with %@",
+                 NSStringFromClass([self class]),
+                 NSStringFromClass([_object class])];
+  return nil;
+}
+
+@end
+
+@implementation NSMutableArray(NGMerging)
+
+- (id)_makeMergeCopyWithZone:(NSZone *)_zone {
+  return [self copyWithZone:_zone];
+}
+
+@end
+
+// for static linking
+
+void __link_NGExtensions_NGMerging(void) {
+  __link_NGExtensions_NGMerging();
+}
diff --git a/skyrix-core/NGExtensions/NGObjCRuntime.m b/skyrix-core/NGExtensions/NGObjCRuntime.m
new file mode 100644 (file)
index 0000000..3003fb6
--- /dev/null
@@ -0,0 +1,827 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGObjCRuntime.h"
+#include "NGMemoryAllocation.h"
+#include <objc/objc.h>
+#include <objc/objc-api.h>
+#include <stdlib.h>
+#include "common.h"
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+#  include <objc/objc-class.h>
+#  include <objc/objc-runtime.h>
+typedef struct objc_method_list *MethodList_t;
+typedef struct objc_ivar_list   *IvarList_t;
+typedef struct objc_method      *Method_t;
+#else
+#  include <objc/encoding.h>
+#endif
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSException.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSSet.h>
+#import <Foundation/NSEnumerator.h>
+
+#define GCC_VERSION (__GNUC__ * 10000 \
+                     + __GNUC_MINOR__ * 100 \
+                     + __GNUC_PATCHLEVEL__)
+
+#if GNUSTEP_BASE_LIBRARY
+/* this is a hack for the extensions 0.8.6 library */
+
+void class_add_behavior(Class class, Class behavior) {
+  extern void behavior_class_add_class (Class class, Class behavior);
+  behavior_class_add_class(class, behavior);
+}
+
+#endif
+
+@interface _NGMethodNameEnumerator : NSEnumerator
+{
+  Class        clazz;
+  BOOL         includeSuperclassMethods;
+  NSMutableSet *names;
+
+  struct objc_method_list *methods; // current method list
+  unsigned i; // current index in current method list
+#if APPLE_RUNTIME || NeXT_RUNTIME
+  void     *iter; // runtime iterator
+#endif
+}
+
+- (id)initWithClass:(Class)_clazz includeSuperclassMethods:(BOOL)_flag;
+- (id)nextObject;
+
+@end
+
+@implementation NSObject(NGObjCRuntime)
+
+static NSArray *emptyArray = nil;
+
+static unsigned countMethodSpecs(SEL _selector, va_list *va)
+     __attribute__((unused));
+
+static unsigned countMethodSpecs(SEL _selector, va_list *va) {
+  SEL      selector;
+  NSString *signature;
+  IMP      imp;
+  unsigned count;
+  
+  selector  = _selector;
+  signature = nil;
+  imp       = NULL;
+  if (selector)  signature = va_arg(*va, id);
+  if (signature) imp       = va_arg(*va, IMP);
+  
+  count = 0;
+  while ((selector != NULL) && (signature != nil) && (imp != NULL)) {
+    count++;
+    
+    if ((selector  = va_arg(*va, SEL))            == NULL) break;
+    if ((signature = (id)va_arg(*va, NSString *)) == nil)  break;
+    if ((imp       = (IMP)va_arg(*va, IMP))       == NULL) break;
+  }
+  return count;
+}
+
+static void
+fillMethodListWithSpecs(MethodList_t methods, SEL _selector, va_list *va)
+{
+  /* takes triple: SEL, signature, IMP */
+  SEL      selector;
+  NSString *signature;
+  IMP      imp;
+  unsigned count;
+  
+  selector  = _selector;
+  signature = selector  ? va_arg(*va, NSString *) : nil;
+  imp       = signature ? va_arg(*va, IMP) : NULL;
+  count     = 0;
+  while ((selector != NULL) && (signature != nil) && (imp != NULL)) {
+    unsigned   len;
+    char       *types;
+#if GNU_RUNTIME
+    const char *selname;
+#endif
+    
+    /* allocate signature buffer */
+    len = [signature cStringLength];
+    types = malloc(len + 4);
+    [signature getCString:types];
+    types[len] = 0;
+    
+#if APPLE_RUNTIME || NeXT_RUNTIME
+    count = methods->method_count;
+    methods->method_list[count].method_name  = selector;
+    methods->method_list[count].method_types = types;
+    methods->method_list[count].method_imp   = imp;
+    methods->method_count++;
+#else
+    /* determine selector name */
+    selname  = sel_get_name(selector);
+
+    /* fill structure */
+    methods->method_list[count].method_name  = (SEL)selname;
+    methods->method_list[count].method_types = types;
+    methods->method_list[count].method_imp   = imp;
+    count++;
+#endif
+    
+    /* go to next method spec */
+    if ((selector  = va_arg(*va, SEL))        == NULL) break;
+    if ((signature = va_arg(*va, NSString *)) == nil)  break;
+    if ((imp       = va_arg(*va, IMP))        == NULL) break;
+  }
+#if GNU_RUNTIME
+  methods->method_count = count;
+  methods->method_next  = NULL;
+#endif
+}
+
++ (unsigned)instanceSize {
+  return ((Class)self)->instance_size;
+}
+
+/* adding methods */
+
++ (void)addMethodList:(MethodList_t)_methods {
+  if (_methods == NULL)            return;
+  if (_methods->method_count == 0) return;
+
+#if NeXT_RUNTIME
+  class_addMethods(self, _methods);
+#else
+  {
+    extern void class_add_method_list (Class class, MethodList_t list);
+    class_add_method_list(self, _methods);
+  }
+#endif
+}
+
++ (void)addClassMethodList:(MethodList_t)_methods {
+  if (_methods == NULL)            return;
+  if (_methods->method_count == 0) return;
+#if NeXT_RUNTIME
+  class_addMethods(((Class)self)->isa, _methods);
+#else
+  {
+    extern void class_add_method_list (Class class, MethodList_t list);
+    class_add_method_list(((Class)self)->class_pointer, _methods);
+  }
+#endif
+}
+
++ (void)addMethods:(SEL)_selector, ... {
+  /* takes triples (sel, type, imp) finished by nil */
+  MethodList_t methods;
+  va_list      va;
+  unsigned     count;
+  
+  va_start(va, _selector);
+  count = countMethodSpecs(_selector, &va);
+  va_end(va);
+  if (count == 0) return;
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+  methods = malloc(sizeof(struct objc_method_list) +
+                   ((count + 1) * sizeof(struct objc_method)));
+  methods->method_count = 0;
+
+  va_start(va, _selector);
+  fillMethodListWithSpecs(methods, _selector, &va);
+  va_end(va);
+  
+  [self addMethodList:methods];
+#else
+  methods = malloc(sizeof(MethodList) + (count + 2) * sizeof(Method));
+  NSAssert(methods, @"could not allocate methodlist");
+  
+  va_start(va, _selector);
+  fillMethodListWithSpecs(methods, _selector, &va);
+  va_end(va);
+  
+  [self addMethodList:methods];
+#endif
+}
+
++ (void)addClassMethods:(SEL)_selector, ... {
+  /* takes triples finished by nil */
+  MethodList_t methods;
+  va_list      va;
+  unsigned     count;
+  
+  va_start(va, _selector);
+  count = countMethodSpecs(_selector, &va);
+  va_end(va);
+  if (count == 0) return;
+  
+#if NeXT_RUNTIME
+  methods = malloc(sizeof(struct objc_method_list) +
+                   ((count + 1) * sizeof(struct objc_method)));
+  methods->method_count = 0;
+
+  va_start(va, _selector);
+  fillMethodListWithSpecs(methods, _selector, &va);
+  va_end(va);
+  
+  [self addClassMethodList:methods];
+#else
+  methods = malloc(sizeof(MethodList) + count * sizeof(Method));
+  NSAssert(methods, @"couldn't allocate methodlist");
+  
+  va_start(va, _selector);
+  fillMethodListWithSpecs(methods, _selector, &va);
+  va_end(va);
+  
+  [self addClassMethodList:methods];
+#endif
+}
+
++ (NSEnumerator *)methodNameEnumerator {
+  return [[[_NGMethodNameEnumerator alloc]
+                                    initWithClass:self
+                                    includeSuperclassMethods:NO]
+                                    autorelease];
+}
++ (NSEnumerator *)hierachyMethodNameEnumerator {
+  return [[[_NGMethodNameEnumerator alloc]
+                                    initWithClass:self
+                                    includeSuperclassMethods:YES]
+                                    autorelease];
+}
+
+/* subclassing */
+
++ (Class)subclass:(NSString *)_className
+  ivarsList:(IvarList_t)_ivars
+{
+#if NeXT_RUNTIME
+  [(NSObject *)self doesNotRecognizeSelector:_cmd];
+  return Nil;
+#else
+  // TODO: do we really need a symtab? PyObjC does not seem to require that
+  Module_t module;
+  Class    newMetaClass, newClass;
+  unsigned nameLen;
+  char     *name, *moduleName, *metaName;
+  int      instanceSize, i;
+  
+  /* define names */
+  
+  nameLen = [_className cStringLength];
+  name    = malloc(nameLen + 3);
+  [_className getCString:name];
+  
+  moduleName = name;
+  metaName   = name;
+
+  /* calc instance size */
+
+  // printf("calc isize ..\n");
+
+  for (i = 0, instanceSize = ((Class)self)->instance_size;
+       i < _ivars->ivar_count; i++) {
+    unsigned typeAlign, typeLen;
+    
+    // printf("ivar %s\n", _ivars->ivar_list[i].ivar_name);
+    // printf("  type %s\n", _ivars->ivar_list[i].ivar_type);
+    
+    typeAlign = objc_alignof_type(_ivars->ivar_list[i].ivar_type);
+    typeLen   = objc_sizeof_type(_ivars->ivar_list[i].ivar_type);
+    
+    /* check if offset is aligned */
+    if ((instanceSize % typeAlign) != 0) {
+      /* add alignment size */
+      instanceSize += (typeAlign - (instanceSize % typeAlign));
+    }
+    instanceSize += typeLen;
+  }
+  
+  /* allocate structures */
+  
+  newMetaClass = malloc(sizeof(struct objc_class));
+  newClass     = malloc(sizeof(struct objc_class));
+  NSCAssert(newMetaClass, @"could not allocate new meta class structure");
+  NSCAssert(newClass,     @"could not allocate new class structure");
+  
+  // printf("setup meta ..\n");
+  
+  /* init meta class */
+  newMetaClass->super_class    = (Class)((Class)self)->class_pointer->name;
+  newMetaClass->class_pointer  = newMetaClass->super_class->class_pointer;
+  newMetaClass->name           = metaName;
+  newMetaClass->version        = 0;
+  newMetaClass->info           = _CLS_META;
+  newMetaClass->instance_size  = newMetaClass->super_class->instance_size;
+  newMetaClass->methods        = NULL;
+  newMetaClass->dtable         = NULL;
+  newMetaClass->subclass_list  = NULL;
+  newMetaClass->sibling_class  = NULL;
+  newMetaClass->protocols      = NULL;
+  newMetaClass->gc_object_type = NULL;
+  
+  // printf("setup class ..\n");
+  /* init class */
+  newClass->super_class    = (Class)((Class)self)->name;
+  newClass->class_pointer  = newMetaClass;
+  newClass->name           = name;
+  newClass->version        = 0;
+  newClass->info           = _CLS_CLASS;
+  newClass->instance_size  = instanceSize;
+  newClass->methods        = NULL;
+  newClass->dtable         = NULL;
+  newClass->subclass_list  = NULL;
+  newClass->sibling_class  = NULL;
+  newClass->protocols      = NULL;
+  newClass->gc_object_type = NULL;
+  newClass->ivars          = _ivars;
+  
+  /* allocate module */
+  
+  module = malloc(sizeof(Module));
+  NSCAssert(module, @"could not allocate module !");
+  memset(module, 0, sizeof(Module));
+  module->version = 8;
+  module->size    = sizeof(Module);
+  module->name    = moduleName;
+
+  /* allocate symtab with one entry */
+  module->symtab = malloc(sizeof(Symtab) + (2 * sizeof(void *)));
+  module->symtab->sel_ref_cnt = 0;
+  module->symtab->refs        = 0; // ptr to array of 'struct objc_selector'
+  module->symtab->cls_def_cnt = 1;
+  module->symtab->cat_def_cnt = 0;
+  module->symtab->defs[0] = newClass;
+  module->symtab->defs[1] = NULL;
+
+  /* execute module */
+  {
+#if GCC_VERSION < 30400
+    extern void __objc_exec_class(Module_t module); // is thread-safe
+    extern void __objc_resolve_class_links();
+#else
+    void __objc_exec_class(void* module);
+    void __objc_resolve_class_links();
+#endif
+    
+    //printf("execute class\n");
+    __objc_exec_class(module);
+    //printf("resolve links\n");
+    __objc_resolve_class_links();
+  }
+  
+  return NSClassFromString(_className);
+#endif
+}
+
++ (Class)subclass:(NSString *)_className
+  ivars:(NSString *)_name1,...
+{
+  va_list    va;
+  unsigned   ivarCount, currentSize;
+  NSString   *n, *t;
+  
+  currentSize = ((Class)self)->instance_size;
+  
+  va_start(va, _name1);
+  for (n = _name1, t = va_arg(va, NSString *), ivarCount = 0;
+       (n != nil && t != nil);
+       n = va_arg(va, NSString *), t = va_arg(va, NSString *))
+    ivarCount++;
+  va_end(va);
+  
+#if NeXT_RUNTIME || APPLE_RUNTIME
+  {
+    /* some tricks for Apple inspired by PyObjC, long live OpenSource ;-) */
+    IvarList_t        ivars;
+    struct objc_class *clazz;
+    struct objc_class *metaClazz;
+    struct objc_class *rootClazz;
+    
+    /* build ivars */
+    
+    ivars = NULL;
+    if (ivarCount > 0) {
+      ivars = calloc(sizeof(struct objc_ivar_list) +
+                    (ivarCount) * sizeof(struct objc_ivar), sizeof(char));
+      
+      va_start(va, _name1);
+      for (n = _name1, t = va_arg(va, NSString *), ivarCount = 0;
+          (n != nil && t != nil);
+          n = va_arg(va, NSString *), t=va_arg(va, NSString *), ivarCount++) {
+       Ivar     var;
+       char     *ivarName, *ivarType;
+       int      ivarOffset;
+       unsigned len, typeAlign, typeLen;
+       
+       len = [n cStringLength];
+       ivarName = malloc(len + 2);
+       [n getCString:ivarName];
+       ivarName[len] = '\0';
+       
+       len = [t cStringLength];
+       ivarType = malloc(len + 2);
+       [t getCString:ivarType];
+       ivarType[len] = '\0';
+       
+       /* calc ivarOffset */
+       typeAlign = 0; // TODO: alignment?!
+       // TODO: add more types ...
+       switch (*ivarType) { 
+         /* the Apple runtime has no func to calc a type size ?! */
+       case '@': typeLen = sizeof(id);    break;
+       case ':': typeLen = sizeof(SEL);   break;
+       case 'c': typeLen = sizeof(signed char);  break;
+       case 's': typeLen = sizeof(signed short); break;
+       case 'i': typeLen = sizeof(signed int);   break;
+       case 'C': typeLen = sizeof(unsigned char);  break;
+       case 'S': typeLen = sizeof(unsigned short); break;
+       case 'I': typeLen = sizeof(unsigned int);   break;
+       default:
+         NSAssert1(NO, @"does not support ivars of type '%s'", ivarType);
+         break;
+       }
+       ivarOffset = currentSize;
+
+       var = ivars->ivar_list + ivars->ivar_count;
+       ivars->ivar_count++;
+       
+       var->ivar_name   = ivarName;
+       var->ivar_offset = ivarOffset;
+       var->ivar_type   = ivarType;
+       
+       /* adjust current size */
+       currentSize = ivarOffset + typeLen;
+      }
+      va_end(va);
+    }
+    
+    // TODO: move the following to a subclass method
+    
+    /* determine root class */
+    
+    for (rootClazz = self; rootClazz->super_class != NULL; )
+      rootClazz = rootClazz->super_class;
+
+    /* setup meta class */
+    
+    metaClazz = calloc(1, sizeof(struct objc_class));
+    metaClazz->isa           = rootClazz->isa; // root-meta is the metameta
+    metaClazz->name          = strdup([_className cString]);
+    metaClazz->info          = CLS_META;
+    metaClazz->super_class   = ((struct objc_class *)self)->isa;
+    metaClazz->instance_size = ((struct objc_class *)self)->isa->instance_size;
+    metaClazz->ivars         = NULL;
+    metaClazz->protocols     = NULL;
+    
+    /* setup class */
+    
+    clazz = calloc(1, sizeof(struct objc_class));
+    clazz->isa           = metaClazz; /* hook up meta class */
+    clazz->name          = strdup([_className cString]);
+    clazz->info          = CLS_CLASS;
+    clazz->super_class   = self;
+    clazz->instance_size = currentSize;
+    clazz->ivars         = ivars;
+    clazz->protocols     = NULL;
+
+#if 0
+    NSLog(@"instance size: %d, ivar-count: %d",
+         currentSize, ivars->ivar_count);
+#endif
+    
+    /* setup method lists */
+    
+    metaClazz->methodLists = calloc(1, sizeof(struct objc_method_list *));
+    clazz->methodLists     = calloc(1, sizeof(struct objc_method_list *));
+    
+    /* Note: MacOSX specific, Radar #3317376, hint taken from PyObjC */
+    metaClazz->methodLists[0] = (struct objc_method_list *)-1;
+    clazz->methodLists[0]     = (struct objc_method_list *)-1;
+    
+    /* add to runtime (according to PyObjC not reversible?) */
+    objc_addClass(clazz);
+    return NSClassFromString(_className);
+  }
+#else
+  {
+  IvarList_t ivars;
+  
+  ivars = malloc(sizeof(IvarList) + (sizeof(struct objc_ivar) * ivarCount));
+  ivars->ivar_count = ivarCount;
+  
+  va_start(va, _name1);
+  for (n = _name1, t = va_arg(va, NSString *), ivarCount = 0;
+       (n != nil && t != nil);
+       n = va_arg(va, NSString *), t = va_arg(va, NSString *), ivarCount++) {
+    char     *ivarName, *ivarType;
+    int      ivarOffset;
+    unsigned len, typeAlign, typeLen;
+    
+    len = [n cStringLength];
+    ivarName = malloc(len + 2);
+    [n getCString:ivarName];
+    ivarName[len] = '\0';
+    
+    len = [t cStringLength];
+    ivarType = malloc(len + 2);
+    [t getCString:ivarType];
+    ivarType[len] = '\0';
+    
+    /* calc ivarOffset */
+    typeAlign  = objc_alignof_type(ivarType);
+    typeLen    = objc_sizeof_type(ivarType);
+    ivarOffset = currentSize;
+    
+    /* check if offset is aligned */
+    if ((ivarOffset % typeAlign) != 0) {
+      /* align offset */
+      len = (typeAlign - (ivarOffset % typeAlign));
+      ivarOffset += len;
+    }
+
+    /* adjust current size */
+    currentSize = ivarOffset + typeLen;
+    
+    ivars->ivar_list[ivarCount].ivar_name   = ivarName;
+    ivars->ivar_list[ivarCount].ivar_type   = ivarType;
+    ivars->ivar_list[ivarCount].ivar_offset = ivarOffset;
+  }
+  va_end(va);
+  
+  return [self subclass:_className ivarsList:ivars];
+  }
+#endif
+}
+
+/* instance variables */
+
++ (NSArray *)instanceVariableNames {
+  NSArray  *result;
+  NSString **names;
+  int i;
+  
+  if (((Class)self)->ivars == NULL || ((Class)self)->ivars->ivar_count == 0) {
+    if (emptyArray == nil) emptyArray = [[NSArray alloc] init];
+    return emptyArray;
+  }
+
+  names = calloc(((Class)self)->ivars->ivar_count + 2, sizeof(NSString *));
+  
+  for (i = 0; i < ((Class)self)->ivars->ivar_count; i++) {
+    register unsigned char *ivarName;
+    
+    ivarName = (void *)(((Class)self)->ivars->ivar_list[i].ivar_name);
+    if (ivarName == NULL) {
+      NSLog(@"WARNING(%s): ivar without name! (idx=%d)", 
+           __PRETTY_FUNCTION__, i);
+      continue;
+    }
+    
+#if !LIB_FOUNDATION_LIBRARY
+    names[i] = [NSString stringWithCString:ivarName];
+#else
+    names[i] = [NSString stringWithCStringNoCopy:ivarName freeWhenDone:NO];
+#endif
+  }
+  
+  result = [NSArray arrayWithObjects:names
+                   count:((Class)self)->ivars->ivar_count];
+  if (names) free(names);
+  return result;
+}
++ (NSArray *)allInstanceVariableNames {
+  NSMutableArray *varNames;
+  Class c;
+
+  varNames = [NSMutableArray arrayWithCapacity:32];
+  for (c = self; c != Nil; c = [c superclass])
+    [varNames addObjectsFromArray:[c instanceVariableNames]];
+
+  return [[varNames copy] autorelease];
+}
+
++ (BOOL)hasInstanceVariableWithName:(NSString *)_ivarName {
+  Class    c;
+  unsigned len = [_ivarName cStringLength];
+  char     *ivarName;
+  
+  if (len == 0)
+    return NO;
+  
+  ivarName = malloc(len + 1);
+  [_ivarName getCString:ivarName]; ivarName[len] = '\0';
+  
+  for (c = self; c != Nil; c = [c superclass]) {
+    int i;
+    
+    for (i = 0; i < c->ivars->ivar_count; i++) {
+      if (strcmp(ivarName, c->ivars->ivar_list[i].ivar_name) == 0) {
+        free(ivarName);
+        return YES;
+      }
+    }
+  }
+  free(ivarName);
+  return NO;
+}
+
++ (NSString *)signatureOfInstanceVariableWithName:(NSString *)_ivarName {
+  Class    c;
+  unsigned len = [_ivarName cStringLength];
+  char     *ivarName;
+  
+  if (len == 0)
+    return nil;
+
+  ivarName = malloc(len + 1);
+  [_ivarName getCString:ivarName]; ivarName[len] = '\0';
+  
+  for (c = self; c != Nil; c = [c superclass]) {
+    int i;
+
+    for (i = 0; i < c->ivars->ivar_count; i++) {
+      if (strcmp(ivarName, c->ivars->ivar_list[i].ivar_name) == 0) {
+        /* found matching ivar name */
+        if (ivarName) free(ivarName);
+#if !LIB_FOUNDATION_LIBRARY
+        return [NSString stringWithCString:
+                           (char *)(c->ivars->ivar_list[i].ivar_type)];
+#else
+        return [NSString stringWithCStringNoCopy:
+                           (char *)(c->ivars->ivar_list[i].ivar_type)
+                         freeWhenDone:NO];
+#endif
+      }
+    }
+  }
+  if (ivarName) free(ivarName);
+  return nil;
+}
+
+
++ (unsigned)offsetOfInstanceVariableWithName:(NSString *)_ivarName {
+  Class    c;
+  unsigned len = [_ivarName cStringLength];
+  char     *ivarName;
+  
+  if (len == 0)
+    return NSNotFound;
+
+  ivarName = malloc(len + 3);
+  [_ivarName getCString:ivarName]; ivarName[len] = '\0';
+  
+  for (c = self; c != Nil; c = [c superclass]) {
+    int i;
+
+    for (i = 0; i < c->ivars->ivar_count; i++) {
+      if (strcmp(ivarName, c->ivars->ivar_list[i].ivar_name) == 0) {
+        /* found matching ivar name */
+        free(ivarName);
+        return c->ivars->ivar_list[i].ivar_offset;
+      }
+    }
+  }
+  free(ivarName);
+  return NSNotFound;
+}
+
+@end /* NSObject(NGObjCRuntime) */
+
+@implementation _NGMethodNameEnumerator
+
+- (id)initWithClass:(Class)_clazz includeSuperclassMethods:(BOOL)_flag {
+  if (_clazz == Nil) {
+    [self release];
+    return nil;
+  }
+
+  self->names = [[NSMutableSet alloc] initWithCapacity:200];
+  self->clazz                    = _clazz;
+  self->includeSuperclassMethods = _flag;
+
+#if NeXT_RUNTIME
+  self->iter    = 0;
+  self->methods = class_nextMethodList(self->clazz, &(self->iter));
+#else
+  self->methods = _clazz->methods;
+  self->i       = 0;
+#endif
+  return self;
+}
+
+- (void)dealloc {
+  [self->names release];
+  [super dealloc];
+}
+
+- (id)nextObject {
+  if (self->clazz == nil)
+    return nil;
+
+  if (self->methods == NULL) {
+    /* methods of current class are done .. */
+    if (!self->includeSuperclassMethods)
+      return nil;
+
+    /* loop, maybe there are classes without a method-list ? */
+    while (self->methods == NULL) {
+      if ((self->clazz = [self->clazz superclass]) == Nil)
+        /* no more superclasses */
+        return nil;
+      
+#if NeXT_RUNTIME
+      self->iter = 0;
+      self->methods = class_nextMethodList(self->clazz, &(self->iter));
+#else
+      self->methods = self->clazz->methods;
+#endif
+    }
+    self->i = 0;
+  }
+  
+#if DEBUG
+  NSAssert(self->methods, @"missing method-list !");
+#endif
+  
+  while (self->i >= (unsigned)self->methods->method_count) {
+#if NeXT_RUNTIME || APPLE_RUNTIME
+    self->methods = class_nextMethodList(self->clazz, &(self->iter));
+#else
+    self->methods = self->methods->method_next;
+#endif
+    if (self->methods == NULL)
+      break;
+    self->i = 0;
+  }
+  
+  if (self->methods == NULL) {
+    /* recurse to next super class */
+    return self->includeSuperclassMethods
+      ? [self nextObject]
+      : nil;
+  }
+
+  /* get name .. */
+  {
+    Method_t m;
+    NSString *name;
+
+    m = &(self->methods->method_list[self->i]);
+    self->i++;
+    
+    NSAssert(m, @"missing method structure !");
+    name = NSStringFromSelector(m->method_name);
+    NSAssert(name, @"couldn't get method name !");
+    
+    if ([self->names containsObject:name]) {
+      /* this name was already delivered from a subclass, take next */
+      return [self nextObject];
+    }
+
+    [self->names addObject:name];
+    
+    return name;
+  }
+}
+
+@end /* _NGMethodNameEnumerator */
+
+#if GNU_RUNTIME
+
+@interface NGObjCClassEnumerator : NSEnumerator
+{
+  void *state;
+}
+@end
+
+@implementation NGObjCClassEnumerator
+
+- (id)nextObject {
+  return objc_next_class(&(self->state));
+}
+
+@end /* NGObjCClassEnumerator */
+
+#endif /* GNU_RUNTIME */
diff --git a/skyrix-core/NGExtensions/NGQuotedPrintableCoding.m b/skyrix-core/NGExtensions/NGQuotedPrintableCoding.m
new file mode 100644 (file)
index 0000000..23c0845
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGQuotedPrintableCoding.h"
+#include "NGMemoryAllocation.h"
+
+@implementation NSString(QuotedPrintableCoding)
+
+- (NSString *)stringByDecodingQuotedPrintable {
+  NSData   *data;
+  unsigned len;
+  
+  if ((len = [self cStringLength])) {
+    void *buf;
+    buf = malloc(len + 10);
+    [self getCString:buf];
+    data = [NSData dataWithBytes:buf length:len];
+    free(buf);
+  }
+  else
+    data = [NSData data];
+  
+  data = [data dataByDecodingQuotedPrintable];
+  return [NSString stringWithCString:[data bytes] length:[data length]];
+}
+- (NSString *)stringByEncodingQuotedPrintable {
+  NSData *data;
+  unsigned len;
+  
+  if ((len = [self cStringLength])) {
+    void *buf;
+    buf = malloc(len + 10);
+    [self getCString:buf];
+    data = [NSData dataWithBytes:buf length:len];
+    free(buf);
+  }
+  else
+    data = [NSData data];
+  
+  data = [data dataByEncodingQuotedPrintable];
+  return [NSString stringWithCString:[data bytes] length:[data length]];
+}
+
+@end
+
+@implementation NSData(QuotedPrintableCoding)
+
+- (NSData *)dataByDecodingQuotedPrintable {
+  char   *dest    = NULL;
+  size_t destSize = 0;
+  size_t resSize  = 0;
+  
+  destSize = [self length];
+  dest     = NGMallocAtomic(destSize * sizeof(char));
+
+  resSize = NGDecodeQuotedPrintable([self bytes],[self length],dest,destSize);
+  
+  return ((int)resSize != -1)
+    ? [NSData dataWithBytesNoCopy:dest length:resSize]
+    : nil;
+}
+
+- (NSData *)dataByEncodingQuotedPrintable {
+  const char   *bytes  = [self bytes];
+  unsigned int length  = [self length];
+  char         *des    = NULL;
+  unsigned int desLen  = 0;
+
+  desLen = length *3;
+  des = NGMallocAtomic(sizeof(char) * desLen);
+
+  desLen = NGEncodeQuotedPrintable(bytes, length, des, desLen);
+  
+  return (int)desLen != -1
+    ? [NSData dataWithBytesNoCopy:des length:desLen]
+    : nil;
+}
+
+@end
+
+// implementation
+
+static inline char __hexToChar(char c) {
+  if ((c > 47) && (c < 58)) // '0' .. '9'
+    return c - 48;
+  if ((c > 64) && (c < 71)) // 'A' .. 'F'
+    return c - 55;
+  if ((c > 96) && (c < 103)) // 'a' .. 'f'
+    return c - 87;
+  return -1;
+}
+
+int NGDecodeQuotedPrintable(const char *_src, unsigned _srcLen,
+                            char *_dest, unsigned _destLen) {
+  unsigned cnt     = 0;
+  unsigned destCnt = 0;
+
+  if (_srcLen < _destLen)
+    return -1;
+
+  for (cnt = 0; ((cnt < _srcLen) && (destCnt < _destLen)); cnt++) {
+    if (_src[cnt] != '=') {
+      _dest[destCnt++] = _src[cnt];
+    }
+    else {
+      if ((_srcLen - cnt) > 1) {
+        signed char c1, c2;
+
+        c1 = _src[++cnt];
+
+        if (c1 == '\r' || c1 == '\n') {
+          if (_src[cnt+1] == '\r' || _src[cnt+1] == '\n' )
+            cnt++;
+          continue;
+        }
+        c1 = __hexToChar(c1);
+        c2 = __hexToChar(_src[++cnt]);
+        
+        if ((c1 == -1) || (c2 == -1)) {
+          if ((_destLen - destCnt) > 1) {
+            _dest[destCnt++] = _src[cnt - 1];
+            _dest[destCnt++] = _src[cnt];
+          }
+          else
+            break;
+        }
+        else {
+          char c = ((c1 << 4) | c2);
+          _dest[destCnt++] = c;
+        }
+      }
+      else 
+        break;
+    }
+  }
+  if (cnt < _srcLen)
+    return -1;
+  return destCnt;
+}
+
+/*
+  From RFC 2045 Multipurpose Internet Mail Extensions
+
+  6.7. Quoted-Printable Content-Transfer-Encoding
+
+  ...
+
+  In this encoding, octets are to be represented as determined by the
+  following rules: 
+
+
+    (1)   (General 8bit representation) Any octet, except a CR or
+          LF that is part of a CRLF line break of the canonical
+          (standard) form of the data being encoded, may be
+          represented by an "=" followed by a two digit
+          hexadecimal representation of the octet's value.  The
+          digits of the hexadecimal alphabet, for this purpose,
+          are "0123456789ABCDEF".  Uppercase letters must be
+          used; lowercase letters are not allowed.  Thus, for
+          example, the decimal value 12 (US-ASCII form feed) can
+          be represented by "=0C", and the decimal value 61 (US-
+          ASCII EQUAL SIGN) can be represented by "=3D".  This
+          rule must be followed except when the following rules
+          allow an alternative encoding.
+
+    (2)   (Literal representation) Octets with decimal values of
+          33 through 60 inclusive, and 62 through 126, inclusive,
+          MAY be represented as the US-ASCII characters which
+          correspond to those octets (EXCLAMATION POINT through
+          LESS THAN, and GREATER THAN through TILDE,
+          respectively).
+
+    (3)   (White Space) Octets with values of 9 and 32 MAY be
+          represented as US-ASCII TAB (HT) and SPACE characters,
+          respectively, but MUST NOT be so represented at the end
+          of an encoded line. Any TAB (HT) or SPACE characters on an
+          encoded line MUST thus be followed on that line by a printable
+          character. In particular, an "=" at the end of an encoded line,
+          indicating a soft line break (see rule #5) may follow one or
+          more TAB (HT) or SPACE characters. It follows that an octet
+          with decimal value 9 or 32 appearing at the end of an encoded line
+          must be represented according to Rule #1. This rule is necessary
+          because some MTAs (Message Transport Agents, programs which transport
+          messages from one user to another, or perform a portion of such
+          transfers) are known to pad lines of text with SPACEs, and others
+          are known to remove "white space" characters from the end of a line.
+          Therefore, when decoding a Quoted-Printable body, any trailing white
+          space on a line must be deleted, as it will necessarily have been
+          added by intermediate transport agents. 
+
+
+    (4)   (Line Breaks) A line break in a text body, represented
+          as a CRLF sequence in the text canonical form, must be
+          represented by a (RFC 822) line break, which is also a
+          CRLF sequence, in the Quoted-Printable encoding.  Since
+          the canonical representation of media types other than
+          text do not generally include the representation of
+          line breaks as CRLF sequences, no hard line breaks
+          (i.e. line breaks that are intended to be meaningful
+          and to be displayed to the user) can occur in the
+          quoted-printable encoding of such types.  Sequences
+          like "=0D", "=0A", "=0A=0D" and "=0D=0A" will routinely
+          appear in non-text data represented in quoted-
+          printable, of course.
+
+    (5)   (Soft Line Breaks) The Quoted-Printable encoding
+          REQUIRES that encoded lines be no more than 76
+          characters long.  If longer lines are to be encoded
+          with the Quoted-Printable encoding, "soft" line breaks
+          must be used.  An equal sign as the last character on a
+          encoded line indicates such a non-significant ("soft")
+          line break in the encoded text.
+
+*/          
+
+int NGEncodeQuotedPrintable(const char *_src, unsigned _srcLen,
+                            char *_dest, unsigned _destLen) {
+  unsigned cnt      = 0;
+  unsigned destCnt  = 0;
+  char     hexT[16] = {'0','1','2','3','4','5','6','7','8',
+                       '9','A','B','C','D','E','F'};
+  
+  if (_srcLen > _destLen)
+    return -1;
+  
+  for (cnt = 0; (cnt < _srcLen) && (destCnt < _destLen); cnt++) {
+    char c = _src[cnt];
+    if ((c == 9)  ||
+        (c == 10) ||
+        (c == 13) ||
+        ((c > 31) && (c < 61)) ||
+        ((c > 61) && (c < 127))) { // no quoting
+      _dest[destCnt++] = c;
+    }
+    else { // need to be quoted
+      if (_destLen - destCnt > 2) {
+        _dest[destCnt++] = '=';
+        _dest[destCnt++] = hexT[(c >> 4) & 15];
+        _dest[destCnt++] = hexT[c & 15];
+      }
+      else 
+        break;
+    }
+  }
+  if (cnt < _srcLen)
+    return -1;
+  return destCnt;
+}
+
+// static linking
+
+void __link_NGQuotedPrintableCoding(void) {
+  __link_NGQuotedPrintableCoding();
+}
diff --git a/skyrix-core/NGExtensions/NGRuleEngine.subproj/.cvsignore b/skyrix-core/NGExtensions/NGRuleEngine.subproj/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-core/NGExtensions/NGRuleEngine.subproj/GNUmakefile b/skyrix-core/NGExtensions/NGRuleEngine.subproj/GNUmakefile
new file mode 100644 (file)
index 0000000..5f466ec
--- /dev/null
@@ -0,0 +1,18 @@
+# $Id$
+
+include ../../common.make
+
+SUBPROJECT_NAME = NGRuleEngine
+
+NGRuleEngine_OBJC_FILES = \
+       NGRule.m                \
+       NGRuleAssignment.m      \
+       NGRuleContext.m         \
+       NGRuleModel.m           \
+       NGRuleParser.m          \
+
+ADDITIONAL_INCLUDE_DIRS += -I. -I.. -I../NGExtensions/ -I../..
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRule.m b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRule.m
new file mode 100644 (file)
index 0000000..6c30acb
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGRule.h"
+#include "NGRuleAssignment.h"
+#include "NGRuleParser.h"
+#include "common.h"
+#include <EOControl/EOQualifier.h>
+
+@implementation NGRule
+
++ (id)ruleWithQualifier:(EOQualifier *)_q action:(id)_action priority:(int)_p {
+  return [[[self alloc] initWithQualifier:_q action:_action priority:_p] 
+                 autorelease];
+}
++ (id)ruleWithQualifier:(EOQualifier *)_q action:(id)_action {
+  return [self ruleWithQualifier:_q action:_action priority:0];
+}
+
+- (id)initWithString:(NSString *)_s {
+  [self release];
+  return [[[NGRuleParser sharedRuleParser] parseRuleFromString:_s] retain];
+}
+- (id)initWithPropertyList:(id)_plist {
+  [self release];
+  return [[[NGRuleParser sharedRuleParser] 
+                         parseRuleFromPropertyList:_plist] retain];
+}
+
+- (id)initWithQualifier:(EOQualifier *)_q action:(id)_action priority:(int)_p {
+  if ((self = [super init])) {
+    self->qualifier = [_q      retain];
+    self->action    = [_action retain];
+    self->priority  = _p;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithQualifier:nil action:nil priority:0];
+}
+
+- (void)dealloc {
+  [self->qualifier release];
+  [self->action    release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setQualifier:(EOQualifier *)_q {
+  ASSIGN(self->qualifier, _q);
+}
+- (EOQualifier *)qualifier {
+  return self->qualifier;
+}
+
+- (void)setAction:(id)_action {
+  ASSIGN(self->action, _action);
+}
+- (id)action {
+  return self->action;
+}
+
+- (void)setPriority:(int)_pri {
+  self->priority = _pri;
+}
+- (int)priority {
+  return self->priority;
+}
+
+/* operations */
+
+- (BOOL)isCandidateForKey:(NSString *)_key {
+  id o;
+  if (_key == nil) return YES;
+  
+  o = [self action];
+  if ([o respondsToSelector:@selector(isCandidateForKey:)])
+    return [o isCandidateForKey:_key];
+  
+  return NO; /* action is not an assignment ! */
+}
+
+- (id)fireInContext:(id)_ctx {
+  return [self->action fireInContext:_ctx];
+}
+
+/* representations */
+
+- (NSString *)stringValue {
+  NSString *sq, *sa;
+  
+  sq = [[self qualifier] description];
+  sa = [[self action]    description];
+  return [NSString stringWithFormat:@"%@ => %@ ; %i",
+                     sq, sa, [self priority]];
+}
+
+- (NSString *)description {
+  return [self stringValue];
+}
+
+@end /* NGRule(Parsing) */
diff --git a/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleAssignment.m b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleAssignment.m
new file mode 100644 (file)
index 0000000..549d7d7
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGRuleAssignment.h"
+#include "common.h"
+
+@implementation NGRuleAssignment
+
++ (id)assignmentWithKeyPath:(NSString *)_kp value:(id)_value {
+  return [[[self alloc] initWithKeyPath:_kp value:_value] autorelease];
+}
+- (id)initWithKeyPath:(NSString *)_kp value:(id)_value {
+  if ((self = [super init])) {
+    self->keyPath = [_kp copy];
+    self->value   = [_value retain];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithKeyPath:nil value:nil];
+}
+
+- (void)dealloc {
+  [self->keyPath release];
+  [self->value   release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setKeyPath:(NSString *)_kp {
+  ASSIGNCOPY(self->keyPath, _kp);
+}
+- (NSString *)keyPath {
+  return self->keyPath;
+}
+
+- (void)setValue:(id)_value {
+  ASSIGN(self->value, _value);
+}
+- (id)value {
+  return self->value;
+}
+
+/* operations */
+
+- (BOOL)isCandidateForKey:(NSString *)_key {
+  if (_key == nil) return YES;
+  
+  // TODO: perform a real keypath check
+  return [self->keyPath isEqualToString:_key];
+}
+
+- (id)fireInContext:(id)_ctx {
+  // TODO: shouldn't we apply the value on ctx ?
+  return self->value;
+}
+
+/* description */
+
+- (NSString *)valueStringValue {
+  return [self->value isKindOfClass:[NSNumber class]]
+    ? [self->value stringValue]
+    : [NSString stringWithFormat:@"\"%@\"", self->value];
+}
+
+- (NSString *)stringValue {
+  return [NSString stringWithFormat:@"%@ = %@",
+                     [self keyPath],
+                     [self valueStringValue]];
+}
+
+- (NSString *)description {
+  return [self stringValue];
+}
+
+@end /* NGRuleAssignment */
+
+@implementation NGRuleKeyAssignment
+
+/* operations */
+
+- (id)fireInContext:(id)_ctx {
+  // TODO: shouldn't we apply the value on ctx ?
+  return [_ctx valueForKeyPath:[[self value] stringValue]];
+}
+
+/* description */
+
+- (NSString *)valueStringValue {
+  return [self->value stringValue];
+}
+
+@end /* NGRuleKeyAssignment */
diff --git a/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleContext.m b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleContext.m
new file mode 100644 (file)
index 0000000..d33db7c
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGRuleContext.h"
+#include "NGRule.h"
+#include "NGRuleModel.h"
+#include "NSObject+Logs.h"
+#include "common.h"
+#include <EOControl/EOQualifier.h>
+
+@implementation NGRuleContext
+
++ (id)ruleContextWithModelInUserDefault:(NSString *)_defName {
+  NGRuleModel *mod;
+  
+  if ((mod = [NGRuleModel ruleModelWithContentsOfUserDefault:_defName]) == nil)
+    return nil;
+  
+  return [self ruleContextWithModel:mod];
+}
+
++ (id)ruleContextWithModel:(NGRuleModel *)_model {
+  return [[[self alloc] initWithModel:_model] autorelease];
+}
+
+- (id)initWithModel:(NGRuleModel *)_model {
+  if ((self = [super init])) {
+    [self setModel:_model];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithModel:nil];
+}
+
+- (void)dealloc {
+  [self->model        release];
+  [self->storedValues release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setModel:(NGRuleModel *)_model {
+  ASSIGN(self->model, _model);
+}
+- (NGRuleModel *)model {
+  return self->model;
+}
+
+/* values */
+
+- (void)takeStoredValue:(id)_value forKey:(NSString *)_key {
+  if (_value) {
+    if (self->storedValues == nil)
+      self->storedValues = [[NSMutableDictionary alloc] initWithCapacity:32];
+    [self->storedValues setObject:_value forKey:_key];
+  }
+  else
+    [self->storedValues removeObjectForKey:_key];
+}
+- (id)storedValueForKey:(NSString *)_key {
+  return [self->storedValues objectForKey:_key];
+}
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  [self takeStoredValue:_value forKey:_key];
+}
+
+- (void)reset {
+  [self->storedValues removeAllObjects];
+}
+
+/* processing */
+
+- (id)inferredValueForKey:(NSString *)_key {
+  NSArray *rules;
+  unsigned i, count;
+  
+  if (self->debugOn)
+    [self debugWithFormat:@"calculate value for key: '%@'", _key];
+  
+  /* select candidates */
+  rules = [[self model] candidateRulesForKey:_key];
+  if (self->debugOn)
+    [self debugWithFormat:@"  candidate rules: %@", rules];
+  
+  /* check qualifiers */
+  for (i = 0, count = [rules count]; i < count; i++) {
+    NGRule *rule;
+    
+    rule = [rules objectAtIndex:i];
+    if ([(id<EOQualifierEvaluation>)[rule qualifier] evaluateWithObject:self]){
+      if (self->debugOn)
+        [self debugWithFormat:@"  rule %i matches: %@", i, rule];
+      return [[rule action] fireInContext:self];
+    }
+  }
+  if (self->debugOn)
+    [self debugWithFormat:@"  no rule matched !"];
+  return nil;
+}
+
+- (id)valueForKey:(NSString *)_key {
+  id v;
+  
+  /* look for constants */
+  if ((v = [self->storedValues objectForKey:_key]))
+    return v;
+  
+  /* look into rule system */
+  if ((v = [self inferredValueForKey:_key]))
+    return v;
+  
+  return nil;
+}
+
+- (NSArray *)valuesForKeyPath:(NSString *)_kp
+  takingSuccessiveValues:(NSArray *)_values
+  forKeyPath:(NSString *)_valkp
+{
+  NSMutableArray *results;
+  unsigned i, count;
+  
+  count   = [_values count];
+  results = [NSMutableArray arrayWithCapacity:count];
+  
+  for (i = 0; i < count; i++) {
+    id ruleValue;
+    
+    /* take the value */
+    [self takeValue:[_values objectAtIndex:i] forKeyPath:_valkp];
+
+    /* calculate the rule value */
+    ruleValue = [self valueForKey:_kp];
+    [results addObject:ruleValue ? ruleValue : [NSNull null]];
+  }
+  return results;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return self->debugOn;
+}
+- (void)setDebugEnabled:(BOOL)_flag {
+  self->debugOn = _flag;
+}
+
+@end /* NGRuleContext */
diff --git a/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleModel.m b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleModel.m
new file mode 100644 (file)
index 0000000..1ab441e
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGRuleModel.h"
+#include "NGRule.h"
+#include "NGRuleParser.h"
+#include "EOTrueQualifier.h"
+#include <EOControl/EOControl.h>
+#include "common.h"
+
+// TODO: add a candidate cache
+
+@implementation NGRuleModel
+
++ (id)ruleModelWithPropertyList:(id)_plist {
+  static NGRuleParser *ruleParser = nil; // THREAD
+
+  if (ruleParser == nil)
+    ruleParser = [[NGRuleParser sharedRuleParser] retain];
+  
+  return [ruleParser parseRuleModelFromPropertyList:_plist];
+}
++ (id)ruleModelWithContentsOfUserDefault:(NSString *)_defName {
+  id plist;
+  
+  plist = [[NSUserDefaults standardUserDefaults] objectForKey:_defName];
+  if (plist == nil) return nil;
+  
+  return [self ruleModelWithPropertyList:plist];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->rules = [[NSMutableArray alloc] initWithCapacity:16];
+  }
+  return self;
+}
+- (id)initWithRules:(NSArray *)_rules {
+  if ((self = [self init])) {
+    [self->rules addObjectsFromArray:_rules];
+  }
+  return self;
+}
+
+- (id)initWithPropertyList:(id)_plist {
+  [self autorelease];
+  return [[[self class] ruleModelWithPropertyList:_plist] retain];
+}
+
+- (id)initWithContentsOfFile:(NSString *)_path {
+  NSString *s;
+  id plist;
+  
+  if ((s = [[NSString alloc] initWithContentsOfFile:_path])) {
+    [self release];
+    return nil;
+  }
+  plist = [s propertyList];
+  [s release];
+  return [self initWithPropertyList:plist];
+}
+
+- (id)initWithContentsOfUserDefault:(NSString *)_defName {
+  [self autorelease];
+  return [[[self class] ruleModelWithContentsOfUserDefault:_defName] retain];
+}
+
+- (void)dealloc {
+  [self->rules release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setRules:(NSArray *)_rules {
+  [self->rules removeAllObjects];
+  [self->rules addObjectsFromArray:_rules];
+}
+- (NSArray *)rules {
+  return [[self->rules shallowCopy] autorelease];
+}
+
+- (void)addRule:(NGRule *)_rule {
+  [self->rules addObject:_rule];
+}
+- (void)removeRule:(NGRule *)_rule {
+  [self->rules removeObject:_rule];
+}
+
+/* operations */
+
+static int candidateSort(NGRule *rule1, NGRule *rule2, NGRuleModel *model) {
+  static Class TrueQualClass = Nil;
+  EOQualifier *q1, *q2;
+  register int pri1, pri2;
+  
+  pri1 = [rule1 priority];
+  pri2 = [rule2 priority];
+  if (pri1 != pri2)
+    return pri1 > pri2 ? NSOrderedAscending : NSOrderedDescending;
+  
+  /* check number of qualifiers (order on how specific the qualifier is) */
+
+  if (TrueQualClass == Nil) TrueQualClass = [EOTrueQualifier class];
+  q1 = [rule1 qualifier];
+  q2 = [rule2 qualifier];
+  
+  pri1 = [q1 isKindOfClass:TrueQualClass]
+    ? - 1
+    : ([q1 respondsToSelector:@selector(count)] ? [q1 count] : 0);
+  pri2 = [q2 isKindOfClass:TrueQualClass]
+    ? -1
+    : ([q2 respondsToSelector:@selector(count)] ? [q2 count] : 0);
+  
+  if (pri1 != pri2)
+    return pri1 > pri2 ? NSOrderedAscending : NSOrderedDescending;
+  
+  return NSOrderedSame;
+}
+
+- (NSArray *)candidateRulesForKey:(NSString *)_key {
+  NSMutableArray *candidates;
+  unsigned i, cnt;
+  
+  /* first, find all candidates */
+  candidates = nil;
+  cnt = [self->rules count];
+  for (i = 0; i < cnt; i++) {
+    NGRule *rule;
+    
+    rule = [self->rules objectAtIndex:i];
+    if ([rule isCandidateForKey:_key]) {
+      if (candidates == nil)
+        candidates = [[NSMutableArray alloc] initWithCapacity:cnt];
+      [candidates addObject:rule];
+    }
+  }
+
+  /* sort candidates */
+  [candidates sortUsingFunction:(void *)candidateSort context:self];
+  
+  return candidates;
+}
+
+/* representations */
+
+@end /* NGRuleModel */
diff --git a/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleParser.h b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleParser.h
new file mode 100644 (file)
index 0000000..bf8d9f5
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGRuleEngine_NGRuleParser_H__
+#define __NGRuleEngine_NGRuleParser_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+
+/*
+  NGRuleParser
+  
+  This class parses NGRule objects. The serialization format is:
+  
+     qualifier => assignment [; priority]
+     
+  The qualifier is either the special '*true*' or a serialized EOQualifier
+  and the assignment is a key/value statement, eg "value=blue".
+
+  We map some special priority "keys":
+    "important" => 1000
+    "very high" => 200
+    "high"      => 150
+    "default"   => 100
+    "normal"    => 100
+    "low"       => 50
+    "very low"  => 5
+    "fallback"  => 0
+*/
+
+@class NSException, NSString, NSDictionary;
+@class EOQualifier;
+@class NGRule, NGRuleModel;
+
+@interface NGRuleParser : NSObject
+{
+  NSString     *ruleQuotes;
+  unichar      ruleEscape;
+  NSException  *lastException;
+  NSDictionary *priorityMapping; /* maps strings to ints (eg high => 10)  */
+  NSDictionary *boolMapping;     /* maps strings to bool (eg false => NO) */
+}
+
++ (id)sharedRuleParser;
+
+/* accessors */
+
+- (NSException *)lastException;
+
+/* parsing */
+
+- (NGRule *)parseRuleFromPropertyList:(id)_plist;
+- (NGRule *)parseRuleFromString:(NSString *)_plist;
+- (NGRuleModel *)parseRuleModelFromPropertyList:(id)_plist;
+
+/* parsing of the individual parts */
+
+- (EOQualifier *)parseQualifierFromString:(NSString *)_s;
+- (id)parseActionFromString:(NSString *)_s;
+- (int)parsePriorityFromString:(NSString *)_s;
+
+- (BOOL)splitString:(NSString *)_s 
+  intoQualifierString:(NSString **)_qs
+  actionString:(NSString **)_as
+  andPriorityString:(NSString **)_ps;
+
+@end
+
+#endif /* __NGRuleEngine_NGRuleParser_H__ */
diff --git a/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleParser.m b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleParser.m
new file mode 100644 (file)
index 0000000..21bd4ea
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGRuleParser.h"
+#include "NGRule.h"
+#include "NGRuleModel.h"
+#include "NGRuleAssignment.h"
+#include "NSObject+Logs.h"
+#include "NSString+misc.h"
+#include "NSString+Ext.h"
+#include "EOTrueQualifier.h"
+#include <EOControl/EOQualifier.h>
+#include "common.h"
+
+// TODO: proper reports errors in last-exception !
+// TODO: improve performance
+
+#define RULE_PRIORITY_NORMAL 100
+
+@implementation NGRuleParser
+
+static BOOL parseDebugOn = YES;
+
++ (void)initialize {
+  parseDebugOn = [[NSUserDefaults standardUserDefaults] 
+                                  boolForKey:@"NGRuleParserDebugEnabled"];
+}
+
++ (id)sharedRuleParser {
+  static NGRuleParser *parser = nil; // THREAD
+  if (parser == nil)
+    parser = [[NGRuleParser alloc] init];
+  return parser;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->ruleQuotes = @"'\"";
+    self->ruleEscape = '\\';
+    self->priorityMapping =
+      [[NSDictionary alloc] initWithObjectsAndKeys:
+                              [NSNumber numberWithInt:1000], @"important",
+                              [NSNumber numberWithInt:200],  @"very high",
+                              [NSNumber numberWithInt:150],  @"high",
+                              [NSNumber numberWithInt:RULE_PRIORITY_NORMAL], 
+                              @"normal",
+                              [NSNumber numberWithInt:RULE_PRIORITY_NORMAL],
+                              @"default",
+                              [NSNumber numberWithInt:50],   @"low",
+                              [NSNumber numberWithInt:5],    @"very low",
+                              [NSNumber numberWithInt:0],    @"fallback",
+                            nil];
+    self->boolMapping =
+      [[NSDictionary alloc] initWithObjectsAndKeys:
+                              [NSNumber numberWithBool:YES], @"yes",
+                              [NSNumber numberWithBool:NO],  @"no",
+                              [NSNumber numberWithBool:YES], @"true",
+                              [NSNumber numberWithBool:NO],  @"false",
+                            nil];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->priorityMapping release];
+  [self->boolMapping   release];
+  [self->ruleQuotes    release];
+  [self->lastException release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSException *)lastException {
+  return self->lastException;
+}
+
+/* parsing */
+
+- (NGRule *)parseRuleFromPropertyList:(id)_plist {
+  if (_plist == nil)
+    return nil;
+  
+  if ([_plist isKindOfClass:[NSString class]])
+    return [self parseRuleFromString:_plist];
+  
+  [self debugWithFormat:
+          @"cannot deal with plist rule of class '%@': %@",
+          NSStringFromClass([_plist class]), _plist];
+  return nil;
+}
+
+- (NGRule *)parseRuleFromArray:(NSArray *)_a {
+  /* eg: ( "a>2", "a='3'", 5 ) */
+  unsigned count;
+  id qpart, apart, ppart;
+  EOQualifier *q;
+  id   action;
+  int  priority;
+  
+  if (_a == nil) 
+    return nil;
+  if ((count = [_a count]) < 2) {
+    [self debugWithFormat:@"invalid rule array: %@", _a];
+    return nil;
+  }
+
+  /* extract parts */
+  
+  qpart = [_a objectAtIndex:0];
+  apart = [_a objectAtIndex:1];
+  ppart = count > 2 ? [_a objectAtIndex:2] : nil;
+  
+  /* parse separate strings */
+  
+  // TODO: handle plists !
+  q        = [self parseQualifierFromString:[qpart stringValue]];
+  action   = [self parseActionFromString:[apart stringValue]];
+  priority = [self parsePriorityFromString:[ppart stringValue]];
+  
+  /* create rule */
+  return [NGRule ruleWithQualifier:q action:action priority:priority];
+}
+
+- (NGRule *)parseRuleFromString:(NSString *)_s {
+  /* "qualifier => assignment [; prio]" */
+  NSString    *qs, *as, *ps;
+  EOQualifier *q;
+  id   action;
+  int  priority;
+  BOOL ok;
+
+  if (_s == nil)
+    return nil;
+  
+  [self debugWithFormat:@"should parse rule: '%@'", _s];
+
+  /* split string */
+  
+  ok = [self splitString:_s 
+             intoQualifierString:&qs
+             actionString:&as
+             andPriorityString:&ps];
+  if (!ok) return nil;
+  
+  [self debugWithFormat:@"  splitted: q='%@', as='%@', pri=%@", qs, as, ps];
+  
+  /* parse separate strings */
+  
+  q        = [self parseQualifierFromString:qs];
+  action   = [self parseActionFromString:as];
+  priority = [self parsePriorityFromString:ps];
+  
+  /* create rule */
+  return [NGRule ruleWithQualifier:q action:action priority:priority];
+}
+
+- (NGRuleModel *)parseRuleModelFromPropertyList:(id)_plist {
+  if (_plist == nil)
+    return nil;
+  
+  if ([_plist isKindOfClass:[NSString class]]) {
+    NGRule *rule;
+    
+    if ((rule = [self parseRuleFromString:_plist]) == nil)
+      return nil;
+    
+    return [[[NGRuleModel alloc]
+                          initWithRules:[NSArray arrayWithObject:rule]]
+                          autorelease];
+  }
+  else if ([_plist isKindOfClass:[NSArray class]]) {
+    NSMutableArray *rules;
+    unsigned i, count;
+    
+    if ((count = [(NSArray *)_plist count]) == 0)
+      return [[[NGRuleModel alloc] init] autorelease];
+    
+    rules = [NSMutableArray arrayWithCapacity:(count + 1)];
+    for (i = 0; i < count; i++) {
+      NGRule *rule;
+      
+      rule = [self parseRuleFromPropertyList:[_plist objectAtIndex:i]];
+      if (rule == nil) {
+        [self debugWithFormat:@"could not parse rule %i in model !", (i + 1)];
+        return nil;
+      }
+      [rules addObject:rule];
+    }
+    
+    return [[[NGRuleModel alloc] initWithRules:rules] autorelease];
+  }
+  else {
+    [self debugWithFormat:
+            @"cannot deal with plist rule-model of class '%@': %@",
+            NSStringFromClass([_plist class]), _plist];
+    return nil;
+  }
+}
+
+/* parsing of parts */
+
+- (BOOL)splitString:(NSString *)_s 
+  intoQualifierString:(NSString **)_qs
+  actionString:(NSString **)_as
+  andPriorityString:(NSString **)_ps
+{
+  unsigned len;
+  NSRange  r;
+  NSString *qs, *as, *ps;
+
+  if (_qs) *_qs = nil;
+  if (_as) *_as = nil;
+  if (_ps) *_ps = nil;
+  
+  if ((len = [_s length]) == 0)
+    return NO;
+  
+  /* split into qualifier and assignment/prio */
+  
+  r = [_s rangeOfString:@"=>" 
+          skipQuotes:self->ruleQuotes 
+          escapedByChar:self->ruleEscape];
+  if (r.length == 0) {
+    [self debugWithFormat:@"ERROR: missing => in rule '%@'", _s];
+    return NO;
+  }
+  
+  qs = [[_s substringToIndex:r.location] stringByTrimmingSpaces];
+  as = [_s substringFromIndex:(r.location + r.length)];
+  
+  /* split assignment and prio */
+  
+  r = [as rangeOfString:@";" 
+          skipQuotes:self->ruleQuotes 
+          escapedByChar:self->ruleEscape];
+  if (r.length == 0) {
+    /* no priority */
+    ps = nil;
+    as = [as stringByTrimmingSpaces];
+  }
+  else {
+    ps = [[as substringFromIndex:(r.location + r.length)] 
+              stringByTrimmingSpaces];
+    as = [[as substringToIndex:r.location] stringByTrimmingSpaces];
+  }
+  
+  /* return results */
+  *_qs = qs;
+  *_as = as;
+  *_ps = ps;
+  return YES;
+}
+
+- (EOQualifier *)parseQualifierFromString:(NSString *)_s {
+  if ([_s length] == 0)
+    return nil;
+  
+  _s = [_s stringByTrimmingSpaces];
+  
+  if ([_s isEqualToString:@"*true*"]) {
+    static EOTrueQualifier *tq = nil;
+    if (tq == nil) tq = [[EOTrueQualifier alloc] init];
+    return tq;
+  }
+  
+  return [EOQualifier qualifierWithQualifierFormat:_s arguments:nil];
+}
+
+- (id)parseActionFromString:(NSString *)_s {
+  NSRange  r;
+  NSString *key;
+  NSString *valstr;
+  Class    AssignmentClass;
+  id       value;
+  
+  _s = [_s stringByTrimmingSpaces];
+  
+  /* split assignment */
+  
+  r = [_s rangeOfString:@"="
+          skipQuotes:self->ruleQuotes 
+          escapedByChar:self->ruleEscape];
+  if (r.length == 0) {
+    [self debugWithFormat:@"cannot parse rule action: '%@'", _s];
+    return nil;
+  }
+  
+  key    = [[_s substringToIndex:r.location] stringByTrimmingSpaces];
+  valstr = [[_s substringFromIndex:(r.location + r.length)] 
+                stringByTrimmingSpaces];
+
+  /* setup defaults */
+  
+  AssignmentClass = [NGRuleKeyAssignment class];
+  value = valstr;
+  
+  /* parse value */
+  
+  if ([valstr length] > 0) {
+    unichar c1 = [valstr characterAtIndex:0];
+    id tmp;
+    
+    if (c1 == '"' || c1 == '\'') {
+      /* a quoted, constant string */
+      NSString *s, *qs;
+      NSRange  r;
+      
+      AssignmentClass = [NGRuleAssignment class];
+      
+      qs = [NSString stringWithCharacters:&c1 length:1];
+      s  = [valstr substringFromIndex:1]; // TODO: perf
+      r  = [s rangeOfString:qs];
+      if (r.length == 0) {
+        [self debugWithFormat:
+                @"quoting of assignment string-value is not closed !"];
+        value = valstr;
+      }
+      else
+        value = [s substringToIndex:r.location];
+    }
+    else if (isdigit(c1) || c1 == '-') {
+      AssignmentClass = [NGRuleAssignment class];
+      value = [NSNumber numberWithInt:[valstr intValue]];
+    }
+    else if ((tmp=[self->boolMapping objectForKey:[valstr lowercaseString]])) {
+      AssignmentClass = [NGRuleAssignment class];
+      value = tmp;
+    }
+    else if ([valstr isEqualToString:@"nil"] || 
+             [valstr isEqualToString:@"null"]) {
+      AssignmentClass = [NGRuleAssignment class];
+      value = [NSNull null];
+    }
+  }
+  
+  return [AssignmentClass assignmentWithKeyPath:key value:value];
+}
+
+- (int)parsePriorityFromString:(NSString *)_s {
+  unichar c1;
+  id num;
+  
+  _s = [_s stringByTrimmingSpaces];
+  // [self debugWithFormat:@"parse priority: '%@'", _s];
+  
+  if ([_s length] == 0)
+    return RULE_PRIORITY_NORMAL;
+  c1 = [_s characterAtIndex:0];
+  
+  if (isdigit(c1) || c1 == '-')
+    return [_s intValue];
+  
+  if ((num = [self->priorityMapping objectForKey:_s]))
+    return [num intValue];
+  
+  [self debugWithFormat:@"cannot parse rule priority: '%@'", _s];
+  return RULE_PRIORITY_NORMAL;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return parseDebugOn;
+}
+
+@end /* NGRuleParser */
diff --git a/skyrix-core/NGExtensions/NGRuleEngine.subproj/README b/skyrix-core/NGExtensions/NGRuleEngine.subproj/README
new file mode 100644 (file)
index 0000000..906bc08
--- /dev/null
@@ -0,0 +1,32 @@
+# $Id$
+
+NGRuleEngine
+============
+
+This is a rule engine inspired by the "BDRuleEngine" available from 
+bDistributed.com (www.bdistributed.com).
+We have choosen different class names, so that NGExtensions can be used
+together with the BDRuleEngine framework.
+
+It's a nice application of EOControl qualifiers and key-value coding to
+implement a simple rule evaluation system. It consists of just five small
+classes:
+  NGRuleAssignment
+  NGRuleKeyAssignment
+  NGRule
+  NGRuleContext
+  NSRuleModel
+
+Priorities
+==========
+
+You should normally use one of the predefined priorities:
+  - important (override)
+  - very high
+  - high
+  - normal/default
+  - low
+  - very low
+  - fallback
+If you need fine-grained control, you can use priority numbers which should
+be between 50 (low) and 150 (high).
diff --git a/skyrix-core/NGExtensions/NGStack.m b/skyrix-core/NGExtensions/NGStack.m
new file mode 100644 (file)
index 0000000..9eb9d24
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGStack.h"
+#include "NGMemoryAllocation.h"
+
+@interface _NGConcreteStackEnumerator : NSEnumerator
+{
+  NGStack  *stack; // for retain
+  id       *trace;
+  unsigned toGo;
+  BOOL     downWard; // top=>down
+}
+
+- (id)initWithStack:(NGStack *)_stack trace:(id *)_ptr count:(int)_size
+  topDown:(BOOL)_downWard;
+
+- (id)nextObject;
+
+@end
+
+@implementation NGStack
+
++ (id)stackWithCapacity:(unsigned int)_capacity {
+  return [[[self alloc] initWithCapacity:_capacity] autorelease];
+}
++ (id)stack {
+  return [[[self alloc] init] autorelease];
+}
++ (id)stackWithArray:(NSArray *)_array {
+  return [[[self alloc] initWithArray:_array] autorelease];
+}
+
+- (id)init {
+  return [self initWithCapacity:256];
+}
+- (id)initWithCapacity:(unsigned int)_capacity {
+  if ((self = [super init])) {
+    stackPointer = 0;
+    capacity     = (_capacity > 0) ? _capacity : 16;
+
+    stack = NGMalloc(sizeof(id) * capacity);
+  }
+  return self;
+}
+- (id)initWithArray:(NSArray *)_array {
+  register unsigned int count = [_array count];
+
+  if ((self = [self initWithCapacity:(count + 1)])) {
+    unsigned cnt;
+
+    for (cnt = 0; cnt < count; cnt++)
+      [self push:[_array objectAtIndex:cnt]];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (self->stack) {
+    [self clear];
+    NGFree(self->stack);
+  }
+  [super dealloc];
+}
+
+/* sizing */
+
+- (void)_increaseStack {
+  if (capacity > 256) capacity += 256;
+  else capacity *= 2;
+
+  stack = NGRealloc(stack, sizeof(id) * capacity);
+}
+
+/* state */
+
+- (unsigned int)capacity {
+  return capacity;
+}
+- (unsigned int)stackPointer {
+  return stackPointer;
+}
+- (unsigned int)count {
+  return stackPointer;
+}
+- (BOOL)isEmpty {
+  return (stackPointer == 0);
+}
+
+/* operations */
+
+- (void)push:(id)_obj {
+  stackPointer++;
+  if (stackPointer >= capacity) [self _increaseStack];
+  stack[stackPointer] = [_obj retain];
+}
+
+- (id)pop {
+  id obj = stack[stackPointer];
+  if (stackPointer <= 0) {
+    [[[NGStackException alloc] initWithName:@"StackException"
+      reason:@"tried to pop an object from an empty stack !"
+      userInfo:nil] raise];
+  }
+  stack[stackPointer] = nil;
+  stackPointer--;
+  return [obj autorelease];
+}
+
+- (void)clear {
+  unsigned cnt;
+  for (cnt = 1; cnt <= stackPointer; cnt++) {
+#if !LIB_FOUNDATION_BOEHM_GC
+    [stack[cnt] release];
+#endif
+    stack[cnt] = nil;
+  }
+  stackPointer = 0;
+}
+
+/* elements */
+
+- (id)elementAtTop {
+  return (stackPointer == 0) ? nil : stack[stackPointer];
+}
+- (id)elementAtBottom {
+  return (stackPointer == 0) ? nil : stack[1];
+}
+
+- (NSEnumerator *)topDownEnumerator {
+  if (stackPointer == 0)
+    return nil;
+
+  return [[[_NGConcreteStackEnumerator alloc]
+                        initWithStack:self trace:&(stack[stackPointer])
+                        count:stackPointer topDown:YES] autorelease];
+}
+- (NSEnumerator *)bottomUpEnumerator {
+  if (stackPointer == 0)
+    return nil;
+
+  return [[[_NGConcreteStackEnumerator alloc]
+                        initWithStack:self trace:&(stack[1])
+                        count:stackPointer topDown:NO] autorelease];
+}
+
+/* NSCoding */
+
+- (Class)classForCoder {
+  return [NGStack class];
+}
+
+- (void)encodeWithCoder:(NSCoder *)_encoder {
+  unsigned cnt;
+  
+  [_encoder encodeValueOfObjCType:@encode(unsigned int) at:&capacity];
+  [_encoder encodeValueOfObjCType:@encode(unsigned int) at:&stackPointer];
+
+  for (cnt = 1; cnt <= stackPointer; cnt++) {
+    id obj = stack[cnt];
+    [_encoder encodeObject:obj];
+  }
+}
+
+- (id)initWithCoder:(NSCoder *)_decoder {
+  int tmpCapacity;
+  int tmpStackPointer;
+
+  [_decoder decodeValueOfObjCType:@encode(unsigned int) at:&tmpCapacity];
+  [_decoder decodeValueOfObjCType:@encode(unsigned int) at:&tmpStackPointer];
+
+  self = [self initWithCapacity:tmpCapacity];
+  {
+    register int cnt;
+
+    for (cnt = 1; cnt <= tmpStackPointer; cnt++) {
+      id obj = [_decoder decodeObject];
+      stack[cnt] = [obj retain];
+    }
+    stackPointer = tmpStackPointer;
+  }
+  return self;
+}
+
+/* copying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  register NGStack *newStack = nil;
+  register unsigned cnt;
+
+  newStack = [[NGStack allocWithZone:(_zone ? _zone : NSDefaultMallocZone())]
+                       initWithCapacity:[self stackPointer]];
+
+  for (cnt = 1; cnt <= stackPointer; cnt++)
+    [newStack push:stack[cnt]];
+
+  return newStack;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<%@[0x%08X] capacity=%u SP=%u count=%u content=%s>",
+                     NSStringFromClass([self class]), (unsigned)self,
+                     [self capacity], [self stackPointer], [self count],
+                     [[[self toArray] description] cString]];
+}
+
+- (NSArray *)toArray {
+  register NSMutableArray *array = nil;
+  register unsigned cnt;
+
+  array = [[NSMutableArray alloc] initWithCapacity:stackPointer];
+
+  for (cnt = 1; cnt <= stackPointer; cnt++)
+    [array addObject:stack[cnt]];
+
+  return [array autorelease];
+}
+
+@end /* NGStack */
+
+@implementation _NGConcreteStackEnumerator
+
+- (id)initWithStack:(NGStack *)_stack trace:(id *)_ptr count:(int)_size
+  topDown:(BOOL)_downWard {
+
+  stack    = [_stack retain];
+  trace    = _ptr;
+  toGo     = _size;
+  downWard = _downWard;
+
+  return self;
+}
+
+- (void)dealloc {
+  [self->stack release];
+  trace = NULL;
+  [super dealloc];
+}
+
+- (id)nextObject {
+  id result = nil;
+  
+  if (toGo == 0)
+    return nil;
+
+  toGo--;
+
+  result = *trace;
+  
+  if (downWard) trace--; // top=>bottom (downward)
+  else          trace++; // bottom=>top (upward)
+
+  return result;
+}
+
+@end /* NGStack */
+
+@implementation NGStackException
+@end /* NGStackException */
+
+@implementation NSMutableArray(StackImp)
+
+/* state */
+
+- (unsigned int)stackPointer {
+  return ([self count] - 1);
+}
+
+- (BOOL)isEmpty {
+  return ([self count] == 0) ? YES : NO;
+}
+
+/* operations */
+
+- (void)push:(id)_obj {
+  [self addObject:_obj];
+}
+- (id)pop {
+  unsigned lastIdx = ([self count] - 1);
+
+  if (lastIdx >= 0) {
+    id element = [self objectAtIndex:lastIdx];
+    [self removeObjectAtIndex:lastIdx];
+    return element;
+  }
+  else {
+    [[[NGStackException alloc] initWithName:@"StackException"
+        reason:@"tried to pop an object from an empty stack !"
+        userInfo:nil] raise];
+    return nil;
+  }
+}
+
+- (void)clear {
+  [self removeAllObjects];
+}
+
+/* elements */
+
+- (id)elementAtTop {
+  return [self lastObject];
+}
+
+- (NSEnumerator *)topDownEnumerator {
+  return [self reverseObjectEnumerator];
+}
+- (NSEnumerator *)bottomUpEnumerator {
+  return [self objectEnumerator];
+}
+
+@end /* NSMutableArray(NGStack) */
+
+void __link_NGExtensions_NGStack() {
+  __link_NGExtensions_NGStack();
+}
diff --git a/skyrix-core/NGExtensions/NGStringScanEnumerator.m b/skyrix-core/NGExtensions/NGStringScanEnumerator.m
new file mode 100644 (file)
index 0000000..c9d6b1a
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGStringScanEnumerator.h"
+#include "common.h"
+#include <ctype.h>
+
+@implementation NGStringScanEnumerator
+
+- (id)initWithData:(NSData *)_data maxLength:(unsigned int)_length {
+  if (_data == nil) {
+    [self release];
+    return nil;
+  }
+  
+  if ((self = [super init])) {
+    self->data      = [_data retain];
+    self->curPos    = 0;
+    self->maxLength = _length;
+  }
+  return self;
+}
+
++ (id)enumeratorWithData:(NSData *)_data maxLength:(unsigned int)_length {
+  return [[[self alloc] initWithData:_data maxLength:_length] autorelease];
+}
+
+- (void)dealloc {
+  [self->data release];
+  [super dealloc];
+}
+
+- (NSString *)nextObject {
+  register int i;
+  const unsigned char *bytes;
+  unsigned int length;
+  register int startPos = -1;
+  
+  bytes  = [self->data bytes];
+  length = [self->data length];
+
+  if (length == 0) {
+    [self->data release]; self->data = nil;
+    return nil;
+  }
+  
+  for (i = self->curPos; i < length; i++) {
+
+    if (isprint(bytes[i])) {
+      if (startPos == -1)
+        startPos = i;
+    }
+    else {
+      if (startPos != -1) {
+        if ((i - startPos) >= self->maxLength) {
+          self->curPos = i;
+          
+          return [NSString stringWithCString:(bytes + startPos)
+                           length:(i - startPos)];
+        }
+        startPos = -1;
+      }
+    }
+  }
+  /* end reached (can release data) */
+  [self->data release]; self->data = nil;
+  return nil;
+}
+
+@end /* NGStringScanEnumerator */
+
+@implementation NSData(NGStringScanEnumerator)
+
+- (NSEnumerator *)stringScanEnumeratorWithMaxStringLength:(unsigned int)_max {
+  return [NGStringScanEnumerator enumeratorWithData:self maxLength:_length];
+}
+
+- (NSEnumerator *)stringScanEnumerator {
+  return [self stringScanEnumeratorWithMaxStringLength:256];
+}
+
+@end /* NSData(Strings) */
diff --git a/skyrix-core/NGExtensions/SxCore-NGExtensions.graffle b/skyrix-core/NGExtensions/SxCore-NGExtensions.graffle
new file mode 100644 (file)
index 0000000..87801c6
--- /dev/null
@@ -0,0 +1,1616 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+       <key>CanvasColor</key>
+       <dict>
+               <key>w</key>
+               <real>1.000000e+00</real>
+       </dict>
+       <key>ColumnAlign</key>
+       <integer>0</integer>
+       <key>ColumnSpacing</key>
+       <real>5.400000e+01</real>
+       <key>GraphDocumentVersion</key>
+       <integer>2</integer>
+       <key>GraphicsList</key>
+       <array>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{5.66667, 9.66667}, {176, 36}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>1681</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\b\fs48 \cf0 NGExtensions}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>Group</string>
+                                       <key>Graphics</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{531, 72}, {135, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1677</integer>
+                                                       <key>Shape</key>
+                                                       <string>RoundedRectangle</string>
+                                                       <key>Style</key>
+                                                       <dict>
+                                                               <key>fill</key>
+                                                               <dict>
+                                                                       <key>Color</key>
+                                                                       <dict>
+                                                                               <key>b</key>
+                                                                               <real>5.000000e-01</real>
+                                                                               <key>g</key>
+                                                                               <real>1.000000e+00</real>
+                                                                               <key>r</key>
+                                                                               <real>1.000000e+00</real>
+                                                                       </dict>
+                                                               </dict>
+                                                       </dict>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSBundle}</string>
+                                                       </dict>
+                                               </dict>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{531, 108}, {135, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1678</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGBundleManager.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>RoundedRectangle</string>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGBundle}</string>
+                                                       </dict>
+                                               </dict>
+                                               <dict>
+                                                       <key>Class</key>
+                                                       <string>LineGraphic</string>
+                                                       <key>Head</key>
+                                                       <dict>
+                                                               <key>ID</key>
+                                                               <integer>1678</integer>
+                                                       </dict>
+                                                       <key>ID</key>
+                                                       <integer>1679</integer>
+                                                       <key>Points</key>
+                                                       <array>
+                                                               <string>{598.5, 90}</string>
+                                                               <string>{598.5, 108}</string>
+                                                       </array>
+                                                       <key>Style</key>
+                                                       <dict>
+                                                               <key>stroke</key>
+                                                               <dict>
+                                                                       <key>HeadArrow</key>
+                                                                       <string>FilledArrow</string>
+                                                                       <key>TailArrow</key>
+                                                                       <string>0</string>
+                                                               </dict>
+                                                       </dict>
+                                                       <key>Tail</key>
+                                                       <dict>
+                                                               <key>ID</key>
+                                                               <integer>1677</integer>
+                                                       </dict>
+                                               </dict>
+                                       </array>
+                                       <key>ID</key>
+                                       <integer>1676</integer>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{531, 36}, {135, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1680</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGBundleManager.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGBundleManager}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1675</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{603, 504}, {63, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1669</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGBitSet.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGBitSet}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{522, 504}, {63, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1670</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGBitSet.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGBitSet}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{603, 468}, {63, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1671</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGStack.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGStack}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{522, 468}, {63, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1672</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGStack.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStack}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1670</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1673</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{603, 513}</string>
+                                               <string>{585, 513}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1669</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1672</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1674</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{603, 477}</string>
+                                               <string>{585, 477}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1671</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1668</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{198, 279}, {144, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1667</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGFileManager}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{36, 324}, {144, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1666</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGCustomFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCustomFileManager}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{36, 279}, {144, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1665</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGFileManager}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1665</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1664</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{198, 288}</string>
+                               <string>{180, 288}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1667</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1666</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1663</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{108, 297}</string>
+                               <string>{108, 324}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1665</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{198, 243}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1661</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManagerURL.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGFileManagerURL}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{198, 207}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1662</integer>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSURL}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1660</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{531, 180}, {135, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1659</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGByteBuffer.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGByteBuffer}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{99, 495}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1652</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOGroupingSet.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOGroupingSet}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{27, 468}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1653</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOQualifierGrouping.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOQualifierGrouping}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{99, 432}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1654</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOGrouping.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOGrouping}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{171, 468}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1655</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOKeyGrouping.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOKeyGrouping}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1652</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1656</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{162, 450}</string>
+                                               <string>{162, 495}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1654</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1653</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1657</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{144, 450}</string>
+                                               <string>{108, 468}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1654</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1655</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1658</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{180, 450}</string>
+                                               <string>{216, 468}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1654</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1651</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{531, 153}, {135, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1650</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGCharBuffer.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCharBuffer}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{36, 243}, {144, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1648</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGDirectoryEnumerator.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGDirectoryEnumerator}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{36, 207}, {144, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1649</integer>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSEnumerator}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1647</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{27, 99}, {171, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1646</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOCompoundDataSource.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOCompoundDataSource}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{117, 135}, {171, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1645</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOCacheDataSource.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOCacheDataSource}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{234, 99}, {171, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1644</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOFilterDataSource.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EOFilterDataSource}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{126, 54}, {171, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1643</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EODataSource.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>5.000000e-01</real>
+                                               <key>g</key>
+                                               <real>1.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EODataSource}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1646</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1642</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{191.7, 72}</string>
+                               <string>{132.3, 99}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1643</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1645</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1641</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{210.5, 72}</string>
+                               <string>{203.5, 135}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1643</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1644</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1640</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{233.1, 72}</string>
+                               <string>{297.9, 99}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1643</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{198, 324}, {171, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1639</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileFolderInfoDataSource.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGFileFolderInfoDataSource}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1639</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1638</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{213.9, 72}</string>
+                               <string>{281.1, 324}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1643</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{531, 207}, {135, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1637</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGMD5Generator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMD5Generator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{522, 441}, {144, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1636</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGStack.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStackException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{540, 315}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1634</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGCString.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMutableCString}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{540, 279}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1635</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGCString.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCString}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1633</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{315, 441}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1632</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGCustomFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCustomFileManagerInfo}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{522, 360}, {144, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1630</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGHashMap.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGHashMap}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{522, 396}, {144, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1631</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGHashMap.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMutableHashMap}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1629</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1661</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1628</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{261, 225}</string>
+                               <string>{261, 243}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1662</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1648</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1627</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{108, 225}</string>
+                               <string>{108, 243}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1649</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1634</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1626</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{603, 297}</string>
+                               <string>{603, 315}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1635</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1631</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1625</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{594, 378}</string>
+                               <string>{594, 396}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1630</integer>
+                       </dict>
+               </dict>
+       </array>
+       <key>GridInfo</key>
+       <dict/>
+       <key>HPages</key>
+       <integer>1</integer>
+       <key>ImageCounter</key>
+       <integer>1</integer>
+       <key>IsPalette</key>
+       <string>NO</string>
+       <key>Layers</key>
+       <array>
+               <dict>
+                       <key>Lock</key>
+                       <string>NO</string>
+                       <key>Name</key>
+                       <string>Layer 1</string>
+                       <key>Print</key>
+                       <string>YES</string>
+                       <key>View</key>
+                       <string>YES</string>
+               </dict>
+       </array>
+       <key>LayoutInfo</key>
+       <dict>
+               <key>AutoAdjust</key>
+               <string>YES</string>
+               <key>HierarchicalOrientation</key>
+               <integer>0</integer>
+               <key>MagneticFieldCenter</key>
+               <string>{0, 0}</string>
+       </dict>
+       <key>MagnetsEnabled</key>
+       <string>YES</string>
+       <key>PageBreakColor</key>
+       <dict>
+               <key>w</key>
+               <real>3.333333e-01</real>
+       </dict>
+       <key>PageBreaks</key>
+       <string>YES</string>
+       <key>PageSetup</key>
+       <data>
+       BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE
+       hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpEpKEhIQITlNT
+       dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE
+       mZkOTlNCb3R0b21NYXJnaW6GkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVlAJSEASqEhAFm
+       nSSGkoSZmQtOU1BhcGVyTmFtZYaShJmZBkxldHRlcoaShJmZD05TUHJpbnRBbGxQYWdl
+       c4aShJ2chIQBc54AhpKEmZkNTlNSaWdodE1hcmdpboaShJ2cn50khpKEmZkITlNDb3Bp
+       ZXOGkoSdnISEAVOfAYaShJmZD05TU2NhbGluZ0ZhY3RvcoaShJ2chIQBZKABhpKEmZkL
+       TlNGaXJzdFBhZ2WGkoSdnKmfAYaShJmZFE5TVmVydGljYWxQYWdpbmF0aW9uhpKEnZyk
+       ngCGkoSZmRVOU0hvcml6b25hbFBhZ2luYXRpb26GkoSdnKSeAIaShJmZFk5TSG9yaXpv
+       bnRhbGx5Q2VudGVyZWSGkoSdnKSeAYaShJmZDE5TTGVmdE1hcmdpboaShJ2cn50khpKE
+       mZkNTlNPcmllbnRhdGlvboaShJ2cpJ4BhpKEmZkZTlNQcmludFJldmVyc2VPcmllbnRh
+       dGlvboaSo5KEmZkKTlNMYXN0UGFnZYaShJ2chJeXgn////+GkoSZmQtOU1RvcE1hcmdp
+       boaShJ2cn50khpKEmZkUTlNWZXJ0aWNhbGx5Q2VudGVyZWSGkrSShJmZC05TUGFwZXJT
+       aXplhpKEnpyEhAx7X05TU2l6ZT1mZn2hgQMYgQJkhoaG
+       </data>
+       <key>RowAlign</key>
+       <integer>0</integer>
+       <key>RowSpacing</key>
+       <real>9.000000e+00</real>
+       <key>VPages</key>
+       <integer>1</integer>
+       <key>WindowInfo</key>
+       <dict>
+               <key>Frame</key>
+               <string>{{104, 118}, {794, 751}}</string>
+               <key>VisibleRegion</key>
+               <string>{{-159, -179}, {1038.67, 898.667}}</string>
+               <key>Zoom</key>
+               <string>0.75</string>
+       </dict>
+</dict>
+</plist>
diff --git a/skyrix-core/NGExtensions/TODO b/skyrix-core/NGExtensions/TODO
new file mode 100644 (file)
index 0000000..dcc1b19
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id: TODO,v 1.1.1.1 2003/07/09 22:57:26 cvs Exp $
+
+- remove dependency on FoundationExt on GNUstep Base and Cocoa
+  - added source of FileObjectHolder, NSRunLoop+FileObjects
+
+NSString+Encoding.m:
+- encoding support for MacOSX and other non-iconv platforms
+- add a "charset" encoding registry
+- improve error handling
+- improve buffer size handling
diff --git a/skyrix-core/NGExtensions/Version b/skyrix-core/NGExtensions/Version
new file mode 100644 (file)
index 0000000..e8b125e
--- /dev/null
@@ -0,0 +1,5 @@
+# $Id$
+
+SUBMINOR_VERSION:=102
+
+# v4.2.72 requires libEOControl v4.2.39
diff --git a/skyrix-core/NGExtensions/XmlExt.subproj/.cvsignore b/skyrix-core/NGExtensions/XmlExt.subproj/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-core/NGExtensions/XmlExt.subproj/DOMNode+EOQualifier.m b/skyrix-core/NGExtensions/XmlExt.subproj/DOMNode+EOQualifier.m
new file mode 100644 (file)
index 0000000..639e0f6
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMNode+EOQualifier.h"
+#include <EOControl/EOQualifier.h>
+#include "common.h"
+
+@interface NSObject(DOMNodeEOQualifier)
+- (NSArray *)_domChildrenMatchingQualifier:(EOQualifier *)_qualifier;
+- (NSArray *)_domDescendantsMatchingQualifier:(EOQualifier *)_qualifier
+  includeSelf:(BOOL)_includeSelf;
+@end
+
+@implementation NSObject(DOMNodeEOQualifier)
+/* this category is used to support DOM ops on any object */
+
+static NSArray *emptyArray = nil;
+
+- (NSArray *)_domChildrenMatchingQualifier:(EOQualifier *)_qualifier {
+  id       children;
+  unsigned count;
+  
+  if (![(DOMNode *)self hasChildNodes])
+    return nil;
+
+  if ((children = [(DOMNode *)self childNodes]) == nil)
+    return nil;
+
+  if ((count = [children count]) == 0) {
+    if (emptyArray == nil) emptyArray = [[NSArray alloc] init];
+    return emptyArray;
+  }
+  else {
+    NSMutableArray *marray;
+    unsigned i;
+    
+    marray = [NSMutableArray arrayWithCapacity:(count + 1)];
+    
+    for (i = 0; i < count; i++) {
+      id childNode;
+      
+      if ((childNode = [children objectAtIndex:i])) {
+        if ((_qualifier == nil) ||
+            [(id<EOQualifierEvaluation>)_qualifier evaluateWithObject:childNode])
+          [marray addObject:childNode];
+      }
+    }
+    
+    return [[marray copy] autorelease];
+  }
+}
+
+- (void)_addDOMDescendantsMatchingQualifier:(EOQualifier *)_qualifier
+  toMutableArray:(NSMutableArray *)_array
+  includeSelf:(BOOL)_includeSelf
+{
+  id       children;
+  unsigned i, count;
+
+  if (_includeSelf) {
+    if ([(id<EOQualifierEvaluation>)_qualifier evaluateWithObject:self])
+      [_array addObject:self];
+  }
+  
+  if (![(DOMNode *)self hasChildNodes])
+    return;
+
+  children = [(DOMNode *)self childNodes];
+  for (i = 0, count = [children count]; i < count; i++) {
+    [[children objectAtIndex:i]
+               _addDOMDescendantsMatchingQualifier:_qualifier
+               toMutableArray:_array
+               includeSelf:YES];
+  }
+}
+- (NSArray *)_domDescendantsMatchingQualifier:(EOQualifier *)_qualifier
+  includeSelf:(BOOL)_includeSelf
+{
+  NSMutableArray *marray;
+  
+  marray = [NSMutableArray arrayWithCapacity:16];
+  
+  [self _addDOMDescendantsMatchingQualifier:_qualifier
+        toMutableArray:marray
+        includeSelf:_includeSelf];
+  
+  return [[marray copy] autorelease];
+}
+
+@end /* NSObject(DOMNodeEOQualifier) */
+
+@implementation DOMNode(EOQualifier)
+
+- (NSArray *)childrenMatchingQualifier:(EOQualifier *)_qualifier {
+  return [self _domChildrenMatchingQualifier:_qualifier];
+}
+
+- (NSArray *)descendantsMatchingQualifier:(EOQualifier *)_qualifier {
+  return [self _domDescendantsMatchingQualifier:_qualifier
+               includeSelf:NO];
+}
+
+@end /* DOMNode(EOQualifier) */
diff --git a/skyrix-core/NGExtensions/XmlExt.subproj/GNUmakefile b/skyrix-core/NGExtensions/XmlExt.subproj/GNUmakefile
new file mode 100644 (file)
index 0000000..223777f
--- /dev/null
@@ -0,0 +1,14 @@
+# $Id$
+
+include ../../common.make
+
+SUBPROJECT_NAME = XmlExt
+
+XmlExt_OBJC_FILES = \
+       DOMNode+EOQualifier.m
+
+ADDITIONAL_INCLUDE_DIRS += -I. -I.. -I../NGExtensions/ -I../..
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/NGExtensions/common.h b/skyrix-core/NGExtensions/common.h
new file mode 100644 (file)
index 0000000..01d1a0d
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGExtensions_common_h__
+#define __NGExtensions_common_h__
+
+#import <Foundation/Foundation.h>
+#import <Foundation/NSMapTable.h>
+
+#if defined(WIN32)
+#  include <windows.h>
+#elif defined(NeXT) || NeXT_Foundation_LIBRARY
+#  include <netinet/in.h>
+#else
+#  include <arpa/inet.h>
+#endif
+
+#if !defined(WIN32)
+#include <unistd.h>
+#endif
+
+#if defined(__MINGW32__)
+#  define WITH_OPENSTEP 0
+#  define GNUSTEP  1
+#elif defined(NeXT) || defined(WIN32)
+#  define WITH_OPENSTEP 1
+#  define GNUSTEP  0
+#  ifndef NeXT_RUNTIME
+#    define NeXT_RUNTIME 1
+#  endif
+#else
+#  define WITH_OPENSTEP 0
+#  define GNUSTEP  1
+#endif
+
+#if LIB_FOUNDATION_LIBRARY
+#  include <time.h>
+#  import <objc/objc-api.h>
+#  import <objc/objc.h>
+#  import <objc/encoding.h>
+#  import <extensions/objc-runtime.h>
+#  import <extensions/exceptions/GeneralExceptions.h>
+#endif
+
+#ifndef ASSIGN
+#  define ASSIGN(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) [__value retain]; \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+#ifndef ASSIGNCOPY
+#  define ASSIGNCOPY(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) __value = [__value copy];   \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+
+#if defined(LIB_FOUNDATION_LIBRARY)
+#  define NoZone nil
+#else
+#  define NoZone NULL
+#endif
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __MINGW32__
+#include <strings.h>
+#endif
+
+#if defined(WIN32)
+static inline const char *index(const char *str, char c) __attribute__((unused));
+
+static const char *index(const char *str, char c) {
+  while ((*str != '\0') && (*str != c)) str++;
+  if (*str == '\0') return NULL;
+  else return str;
+}
+#endif
+
+#if PROFILE
+#  define BEGIN_PROFILE \
+     { NSTimeInterval __ti = [[NSDate date] timeIntervalSince1970];
+
+#  define END_PROFILE \
+     __ti = [[NSDate date] timeIntervalSince1970] - __ti;\
+     if (__ti > 0.05) \
+       printf("***PROF[%s]: %0.3fs\n", __PRETTY_FUNCTION__, __ti);\
+     else if (__ti > 0.005) \
+       printf("PROF[%s]: %0.3fs\n", __PRETTY_FUNCTION__, __ti);\
+     }
+
+#  define PROFILE_CHECKPOINT(__key__) \
+       printf("---PROF[%s] CP %s: %0.3fs\n", __PRETTY_FUNCTION__, __key__,\
+              [[NSDate date] timeIntervalSince1970] - __ti)
+
+#else
+#  define BEGIN_PROFILE {
+#  define END_PROFILE   }
+#  define PROFILE_CHECKPOINT(__key__)
+#endif
+
+#endif
diff --git a/skyrix-core/NGExtensions/libNGExtensions.def b/skyrix-core/NGExtensions/libNGExtensions.def
new file mode 100644 (file)
index 0000000..aeefc7e
--- /dev/null
@@ -0,0 +1,21 @@
+EXPORTS
+       __objc_class_name_NGBitSet;
+       __objc_class_name_NGConcreteBitSetEnumerator;
+       __objc_class_name_NGBundleManager;
+       __objc_class_name_NGBundle;
+       __objc_class_name_NGCString;
+       __objc_class_name_NGMutableCString;
+       __objc_class_name_NGExtensions;
+       __objc_class_name_NGHashMap;
+       __objc_class_name_NGMutableHashMap;
+       __objc_class_name__NGHashMapKeyEnumerator;
+       __objc_class_name__NGHashMapObjectEnumerator;
+       __objc_class_name__NGHashMapObjectForKeyEnumerator;
+       __objc_class_name_NGMD5Generator;
+       __objc_class_name_NGStack;
+       __objc_class_name__NGConcreteStackEnumerator;
+       __objc_class_name_NGStackException;
+       NGBundleWasLoadedNotificationName;
+       NGEncodeQuotedPrintable;
+       NGDecodeQuotedPrintable;
+    EODataSourceDidChangeNotification;
diff --git a/skyrix-core/NGLdap/.cvsignore b/skyrix-core/NGLdap/.cvsignore
new file mode 100644 (file)
index 0000000..49a10b1
--- /dev/null
@@ -0,0 +1,2 @@
+shared_debug_obj
+shared_obj
diff --git a/skyrix-core/NGLdap/COPYING b/skyrix-core/NGLdap/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-core/NGLdap/COPYRIGHT b/skyrix-core/NGLdap/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-core/NGLdap/ChangeLog b/skyrix-core/NGLdap/ChangeLog
new file mode 100644 (file)
index 0000000..baaf9db
--- /dev/null
@@ -0,0 +1,173 @@
+2004-06-20  Florian G. Pflug  <fgp@phlo.org>
+
+       * NGLdapConnection.m: added support for MS Active Directory, introduced
+         three new defaults: LDAPInitialBindSpecific - YES means not to do 
+         anonymous binds, but instead use LDAPInitialBindDN, LDAPInitialBindPW
+         for the initial bind. Two LDAP options are set (protocol version to
+         LDAPv3 and disabled referrals). Finally "LDAP_PARTIAL_RESULTS" is
+         accepted as a valid return code for successful searches. (v4.2.17)
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile.preamble: added prebinding (v4.2.16)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.15)
+
+2004-01-19  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGLdapConnection.m: fixed various compile warnings with OpenLDAP v2
+         (v4.2.14)
+
+2003-09-07  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * v4.2.13
+
+       * EOQualifier+LDAP.m: define sel_eq for NeXT_RUNTIME
+
+       * common.h: remove obsolete FoundationExt references
+
+2003-07-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile.preamble: do not link against SASL library by default,
+         you can still use the "sasl=yes" makefile parameter to enable
+         compilation against the SASL library (required for some older
+         LDAP libraries which do not link against SASL)
+
+2003-07-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGLdapConnection.m: replaced an indexOfString with rangeOfString
+         (v4.2.12)
+
+Wed Apr 16 17:00:06 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGLdapConnection.m: move DN for login code in seperate method 
+         (v4.2.11)
+
+2003-04-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGLdapURL.m: small cleanups (v4.2.10)
+
+2003-04-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile.preamble: added "nosasl" and "nossl" configuration
+         parameters
+
+2003-04-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile.preamble: added setting to compile against reentrant
+         LDAP libraries
+
+       * NGLdapConnection.m: added new LDAPLoginAttributeName default and
+         a lot more debugging messages if LDAPDebugEnabled is on (v4.2.9)
+       
+2003-04-01  GNUstep User  <helge.hess@skyrix.com>
+
+       * v4.2.8
+
+       * common.h: compiles with GNUstep Base
+
+       * NGLdapDataSource.m, NGLdapFileManager.m: do not use NSFileIdentifier
+         constant (uses a string instead)
+
+       * NGLdapAttribute.m, NSString+DN.m: replaced -indexOfString: calls
+         with -rangeOfString
+
+2003-01-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGLdapFileManager.m: replaced a RETAIN macro (v4.2.7)
+
+2003-01-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * changes for improved compilation on MacOSX, replaced RETAIN macros
+         with methods (v4.2.6)
+
+Fri Dec 27 10:55:32 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGLdapAttribute.m: moved UTF8/Latin1 string to NSString conversion to
+         a centralized method (stringFromData) (v4.2.5)
+
+2002-11-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGLdapFileManager.m: made -dnForPath:, -pathForDn: and 
+         -ldapConnection public methods (v4.2.4)
+       
+       * NGLdapFileManager.m: added -initWithURL: to init filemanager using
+         an NSURL object (v4.2.3)
+
+       * moved ldapls, ldap2dsml tools to ../samples/
+
+2002-09-26  Helge Hess  <helge.hess@skyrix.com>
+
+        * removed all OpenLDAP v1 things not available in v2 anymore ... 
+         (v4.2.2)
+
+2002-05-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved from Skyrix-dev-42 repository to skyrix-core (v4.2.1)
+
+Thu Apr 25 15:37:57 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGLdapConnection.m: pass credentials as ISO-Latin-1 ..
+
+Wed Mar  6 13:29:28 CET 2002 Jan41 Reichmann  <jan@skyrix.com>
+
+       * merge with SkyrixGreen
+
+Mon Jan 21 16:29:30 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGLdapAttribute.m: 
+       * NGLdapSearchResultEnumerator.m: Fixed UTF8 handling
+
+Wed Oct 24 12:46:58 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * changed various places to use UTF-8 instead of cString
+
+       * updated to SKYRiXgreen
+
+Mon Aug 13 18:01:48 2001  Martin Hoerning  <mh@skyrix.com>
+
+       * NGLdapSearchResultEnumerator.m: fixed RETAIN-BUG
+
+       * NGLdapAttribute.m: fixed performance/BUGS
+
+       * NGLdapConnection.m: repeared RETAIN-BUG, 
+                             updated changes from SKYRiXgreen
+
+       * NSString+DN.m: repaired free - BUG
+
+       * NGLdapSearchResultEnumerator.m: repaired RETAIN bugs
+
+       * NGLdapConnection.m/NSString+DN.m repaired RETAIN bugs
+
+Fri Aug 10 13:52:30 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGLdapFileManager.m: inherit from NGFileManager
+
+Mon Feb 26 17:03:38 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGLdapConnection.m: use port 389 if none is specified
+
+Mon Jan 29 15:38:23 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGLdapFileManager.m: added (non-)support for trash-folder
+
+Fri Jan 19 16:15:57 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGLdapFileManager.m: added support for global-ids
+
+Thu Jan 18 17:08:50 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGLdapFileManager.m: use new FileManager protocols in NGExtensions
+
+Mon Dec 18 13:02:10 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGLdapEntry.m: added -valueForKey:
+
+Wed Nov 29 18:06:03 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * created ChangeLog
+
diff --git a/skyrix-core/NGLdap/EOQualifier+LDAP.h b/skyrix-core/NGLdap/EOQualifier+LDAP.h
new file mode 100644 (file)
index 0000000..ec0b91e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __EOQualifier_LDAP_H__
+#define __EOQualifier_LDAP_H__
+
+#include <EOControl/EOQualifier.h>
+
+@class NSString;
+
+@interface EOQualifier(LDAP)
+
+- (id)initWithLDAPFilterString:(NSString *)_filter;
+- (NSString *)ldapFilterString;
+
+@end /* EOQualifier(LDAP) */
+
+#endif /* __EOQualifier_LDAP_H__ */
diff --git a/skyrix-core/NGLdap/EOQualifier+LDAP.m b/skyrix-core/NGLdap/EOQualifier+LDAP.m
new file mode 100644 (file)
index 0000000..3b4ade0
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOQualifier+LDAP.h"
+#include "common.h"
+
+#if NeXT_RUNTIME
+#define sel_eq(sel1, sel2) ((sel1)) == ((sel2))
+#endif
+
+@interface EOQualifier(LDAPPrivates)
+
+- (void)addToLDAPFilterString:(NSMutableString *)_s inContext:(id)_ctx;
+
+@end
+
+@implementation EOQualifier(LDAP)
+
+- (id)initWithLDAPFilterString:(NSString *)_filter {
+  return nil;
+}
+
+- (void)addToLDAPFilterString:(NSMutableString *)_s inContext:(id)_ctx {
+  [self doesNotRecognizeSelector:_cmd]; // subclass
+}
+
+- (NSString *)ldapFilterString {
+  NSMutableString *s;
+  NSString *is;
+
+  s = [[NSMutableString alloc] initWithCapacity:100];
+  [self addToLDAPFilterString:s inContext:nil];
+  is = [s copy];
+  [s release];
+  return [is autorelease];
+}
+
+@end /* EOQualifier(LDAP) */
+
+@implementation EOAndQualifier(LDAP)
+
+- (void)addToLDAPFilterString:(NSMutableString *)_s inContext:(id)_ctx {
+  unsigned i, cnt;
+  NSArray  *array;
+
+  array = [self qualifiers];
+  cnt   = [array count];
+  
+  [_s appendString:@"(&"];
+  
+  for (i = 0; i < cnt; i++) {
+    EOQualifier *sq;
+
+    sq = [array objectAtIndex:i];
+    [sq addToLDAPFilterString:_s inContext:_ctx];
+  }
+  
+  [_s appendString:@")"];
+}
+
+@end /* EOAndQualifier(LDAP) */
+
+@implementation EOOrQualifier(LDAP)
+
+- (void)addToLDAPFilterString:(NSMutableString *)_s inContext:(id)_ctx {
+  unsigned i, cnt;
+  NSArray  *array;
+
+  array = [self qualifiers];
+  cnt   = [array count];
+  
+  [_s appendString:@"(|"];
+  
+  for (i = 0; i < cnt; i++) {
+    EOQualifier *sq;
+
+    sq = [array objectAtIndex:i];
+    [sq addToLDAPFilterString:_s inContext:_ctx];
+  }
+  
+  [_s appendString:@")"];
+}
+
+@end /* EOOrQualifier(LDAP) */
+
+@implementation EONotQualifier(LDAP)
+
+- (void)addToLDAPFilterString:(NSMutableString *)_s inContext:(id)_ctx {
+  [_s appendString:@"(!"];
+  [[self qualifier] addToLDAPFilterString:_s inContext:_ctx];
+  [_s appendString:@")"];
+}
+
+@end /* EONotQualifier(LDAP) */
+
+@implementation EOKeyValueQualifier(LDAP)
+
+- (void)addToLDAPFilterString:(NSMutableString *)_s inContext:(id)_ctx {
+  // TODO: patterns are treated like regular strings or the reverse?
+  SEL sel;
+
+  sel = [self selector];
+
+  if (sel_eq(sel,  EOQualifierOperatorNotEqual))
+    [_s appendString:@"(!"];
+  
+  [_s appendString:@"("];
+  [_s appendString:[self key]];
+
+  if (sel_eq(sel,  EOQualifierOperatorEqual))
+    [_s appendString:@"="];
+  else if (sel_eq(sel,  EOQualifierOperatorNotEqual))
+    [_s appendString:@"="];
+  else if (sel_eq(sel,  EOQualifierOperatorLessThan))
+    [_s appendString:@"<"];
+  else if (sel_eq(sel,  EOQualifierOperatorGreaterThan))
+    [_s appendString:@">"];
+  else if (sel_eq(sel,  EOQualifierOperatorLessThanOrEqualTo))
+    [_s appendString:@"<="];
+  else if (sel_eq(sel,  EOQualifierOperatorGreaterThanOrEqualTo))
+    [_s appendString:@">="];
+  else if (sel_eq(sel,  EOQualifierOperatorContains))
+    [_s appendString:@"=*"];
+  else if (sel_eq(sel,  EOQualifierOperatorLike))
+    [_s appendString:@"="];
+  else if (sel_eq(sel,  EOQualifierOperatorCaseInsensitiveLike))
+    [_s appendString:@"="];
+  else {
+    NSLog(@"UNKNOWN operator: %@", NSStringFromSelector([self selector]));
+    [_s appendString:@"="];
+  }
+
+  [_s appendString:[[self value] description]];
+  [_s appendString:@")"];
+  
+  if (sel_eq(sel,  EOQualifierOperatorNotEqual))
+    [_s appendString:@")"];
+}
+
+@end /* EOKeyValueQualifier(LDAP) */
+
+@implementation EOKeyComparisonQualifier(LDAP)
+
+- (void)addToLDAPFilterString:(NSMutableString *)_s inContext:(id)_ctx {
+  /* ldap supports no comparison operations on keys */
+  SEL sel;
+
+  sel = [self selector];
+
+  if (sel_eq(sel,  EOQualifierOperatorNotEqual))
+    [_s appendString:@"(!"];
+  
+  [_s appendString:@"("];
+  [_s appendString:[self leftKey]];
+
+  if (sel_eq(sel,  EOQualifierOperatorEqual))
+    [_s appendString:@"="];
+  else if (sel_eq(sel,  EOQualifierOperatorNotEqual))
+    [_s appendString:@"="];
+  else if (sel_eq(sel,  EOQualifierOperatorLessThan))
+    [_s appendString:@"<"];
+  else if (sel_eq(sel,  EOQualifierOperatorGreaterThan))
+    [_s appendString:@">"];
+  else if (sel_eq(sel,  EOQualifierOperatorLessThanOrEqualTo))
+    [_s appendString:@"<="];
+  else if (sel_eq(sel,  EOQualifierOperatorGreaterThanOrEqualTo))
+    [_s appendString:@">="];
+  else if (sel_eq(sel,  EOQualifierOperatorContains))
+    [_s appendString:@"=*"];
+  else if (sel_eq(sel,  EOQualifierOperatorLike))
+    [_s appendString:@"="];
+  else if (sel_eq(sel,  EOQualifierOperatorCaseInsensitiveLike))
+    [_s appendString:@"="];
+  else {
+    NSLog(@"UNKNOWN operator: %@", NSStringFromSelector([self selector]));
+    [_s appendString:@"="];
+  }
+
+  [_s appendString:[self rightKey]];
+  [_s appendString:@")"];
+  
+  if (sel_eq(sel,  EOQualifierOperatorNotEqual))
+    [_s appendString:@")"];
+}
+
+@end /* EOKeyComparisonQualifier(LDAP) */
diff --git a/skyrix-core/NGLdap/GNUmakefile b/skyrix-core/NGLdap/GNUmakefile
new file mode 100644 (file)
index 0000000..d50d139
--- /dev/null
@@ -0,0 +1,51 @@
+# $Id$
+
+include ../common.make
+
+GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT)
+
+LIBRARY_NAME = libNGLdap
+
+libNGLdap_HEADER_FILES_DIR         = .
+libNGLdap_HEADER_FILES_INSTALL_DIR = /NGLdap
+
+libNGLdap_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libNGLdap_HEADER_FILES = \
+       NGLdap.h                \
+       \
+       EOQualifier+LDAP.h      \
+       NSString+DN.h           \
+       NGLdapEntry.h           \
+       NGLdapConnection.h      \
+       NGLdapAttribute.h       \
+       NGLdapModification.h    \
+       NGLdapSearchResultEnumerator.h  \
+       \
+       NGLdapURL.h             \
+       NGLdapGlobalID.h        \
+       NGLdapFileManager.h     \
+       NGLdapDataSource.h      \
+
+libNGLdap_CORE_OBJC_FILES = \
+       EOQualifier+LDAP.m              \
+       NSString+DN.m                   \
+       NGLdapAttribute.m               \
+       NGLdapEntry.m                   \
+       NGLdapSearchResultEnumerator.m  \
+       NGLdapModification.m            \
+       NGLdapConnection.m              \
+       NGLdapDataSource.m              \
+
+libNGLdap_OBJC_FILES = \
+       $(libNGLdap_CORE_OBJC_FILES)    \
+       NGLdapURL.m                     \
+       NGLdapGlobalID.m                \
+       NGLdapFileManager.m             \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+-include GNUmakefile.postamble
+
+autodoc :
+       autodoc $(AUTODOC_FLAGS) -dest ../Documentation/NGLdap/ -proj .
diff --git a/skyrix-core/NGLdap/GNUmakefile.postamble b/skyrix-core/NGLdap/GNUmakefile.postamble
new file mode 100644 (file)
index 0000000..2bd83b9
--- /dev/null
@@ -0,0 +1,8 @@
+# $Id$
+
+ifeq ($(GNUSTEP_TARGET_OS),mingw32)
+libNGLdap_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+libNGLdap_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
diff --git a/skyrix-core/NGLdap/GNUmakefile.preamble b/skyrix-core/NGLdap/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..914d90b
--- /dev/null
@@ -0,0 +1,74 @@
+# $Id$
+
+libNGLdap_LIBRARIES_DEPEND_UPON += \
+       -lNGExtensions -lEOControl      \
+       -lDOM -lSaxObjC
+
+ifeq ($(reentrant),yes)
+ADDITIONAL_CPPFLAGS += -D_REENTRANT=1
+libNGLdap_LIBRARIES_DEPEND_UPON += -lldap_r -llber -lpthread
+else
+libNGLdap_LIBRARIES_DEPEND_UPON += -lldap -llber
+endif
+
+ifneq ($(FOUNDATION_LIB),nx)
+
+ifeq ($(sasl),yes)
+libNGLdap_LIBRARIES_DEPEND_UPON += -lsasl
+endif
+ifneq ($(nossl),yes)
+libNGLdap_LIBRARIES_DEPEND_UPON += -lssl
+endif
+
+else
+
+libNGLdap_LIBRARIES_DEPEND_UPON += -lFoundationExt
+ADDITIONAL_LDFLAGS += -framework Foundation
+ADDITIONAL_TOOL_LIBS += -lFoundationExt
+
+endif
+
+ldap2dsml_TOOL_LIBS  += -lSaxObjC
+
+ADDITIONAL_TOOL_LIBS += -lNGLdap -lNGExtensions -lEOControl
+#ADDITIONAL_TOOL_LIBS = $(libNGLdap_LIBRARIES_DEPEND_UPON)
+
+ADDITIONAL_CPPFLAGS     += -Wall -Wno-protocol
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..                            \
+       -I../NGStreams                  \
+       -I../NGExtensions               \
+       -I/usr/local/include            \
+       -I/usr/local/openldap/include
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                                            \
+       -L$(RELBUILD_DIR_SxCore)/NGStreams/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+       -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)             \
+       -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += \
+       -L./$(GNUSTEP_OBJ_DIR)                  \
+       -L../NGStreams/$(GNUSTEP_OBJ_DIR)       \
+       -L../NGExtensions/$(GNUSTEP_OBJ_DIR)    \
+       -L../../skyrix-xml/SaxObjC/$(GNUSTEP_OBJ_DIR)   \
+       -L../EOControl/$(GNUSTEP_OBJ_DIR)
+endif
+
+ADDITIONAL_LIB_DIRS += \
+       -L/usr/local/lib                        \
+       -L/usr/local/openldap/lib
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libNGLdap_PREBIND_ADDR="0xC1C00000"
+libNGLdap_LDFLAGS += -seg1addr $(libNGLdap_PREBIND_ADDR)
+endif
diff --git a/skyrix-core/NGLdap/NGLdap-Info.plist b/skyrix-core/NGLdap/NGLdap-Info.plist
new file mode 100644 (file)
index 0000000..b3a579d
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGLdap</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.core.NGLdap</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-core/NGLdap/NGLdap.h b/skyrix-core/NGLdap/NGLdap.h
new file mode 100644 (file)
index 0000000..f3e92de
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdap_H__
+#define __NGLdap_H__
+
+#include <NGLdap/EOQualifier+LDAP.h>
+#include <NGLdap/NGLdap.h>
+#include <NGLdap/NGLdapAttribute.h>
+#include <NGLdap/NGLdapConnection.h>
+#include <NGLdap/NGLdapDataSource.h>
+#include <NGLdap/NGLdapEntry.h>
+#include <NGLdap/NGLdapFileManager.h>
+#include <NGLdap/NGLdapModification.h>
+#include <NGLdap/NGLdapSearchResultEnumerator.h>
+#include <NGLdap/NGLdapURL.h>
+#include <NGLdap/NSString+DN.h>
+
+#endif /* __NGLdap_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapAttribute.h b/skyrix-core/NGLdap/NGLdapAttribute.h
new file mode 100644 (file)
index 0000000..3f85944
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGLdapAttribute_H__
+#define __NGLdapAttribute_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSArray, NSData, NSEnumerator;
+
+@interface NGLdapAttribute : NSObject < NSCopying >
+{
+  NSString *name;
+  NSArray  *values;
+  BOOL     didChange;
+}
+
+- (id)initWithAttributeName:(NSString *)_name;
+- (id)initWithAttributeName:(NSString *)_name values:(NSArray *)_values;
+
+/* attribute name operations */
+
+- (NSString *)attributeName;
+
++ (NSString *)baseNameOfAttributeName:(NSString *)_attrName;
+- (NSString *)attributeBaseName;
+
++ (NSArray *)subtypesOfAttributeName:(NSString *)_attrName;
+- (NSArray *)subtypes;
+- (BOOL)hasSubtype:(NSString *)_subtype;
+- (NSString *)langSubtype;
+
+/* values */
+
+- (unsigned)count;
+
+- (void)addValue:(NSData *)_value;
+- (NSArray *)allValues;
+- (NSEnumerator *)valueEnumerator;
+
+- (void)addStringValue:(NSString *)_value;
+- (NSArray *)allStringValues;
+- (NSEnumerator *)stringValueEnumerator;
+- (NSString *)stringValueAtIndex:(unsigned)_idx;
+
+@end
+
+#endif /* __NGLdapAttribute_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapAttribute.m b/skyrix-core/NGLdap/NGLdapAttribute.m
new file mode 100644 (file)
index 0000000..48db9ba
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGLdapAttribute.h"
+#include "common.h"
+
+@implementation NGLdapAttribute
+
+- (id)initWithAttributeName:(NSString *)_name values:(NSArray *)_values {
+  self->name   = [_name   copy];
+  self->values = [_values copy];
+  return self;
+}
+- (id)initWithAttributeName:(NSString *)_name {
+  return [self initWithAttributeName:_name values:nil];
+}
+
+- (void)dealloc {
+  [self->name   release];
+  [self->values release];
+  [super dealloc];
+}
+
+/* attribute name operations */
+
+- (NSString *)attributeName {
+  return self->name;
+}
+
++ (NSString *)baseNameOfAttributeName:(NSString *)_attrName {
+  NSRange r;
+  
+  r = [_attrName rangeOfString:@";"];
+  if (r.length == 0) return _attrName;
+  return [_attrName substringToIndex:r.location];
+}
+- (NSString *)attributeBaseName {
+  return [[self class] baseNameOfAttributeName:[self attributeName]];
+}
+
++ (NSArray *)subtypesOfAttributeName:(NSString *)_attrName {
+  NSArray *parts;
+  
+  parts = [_attrName componentsSeparatedByString:@";"];
+
+  return [parts count] > 1
+    ? [parts subarrayWithRange:NSMakeRange(1, [parts count] - 1)]
+    : [NSArray array];
+}
+
+- (NSArray *)subtypes {
+  return [[self class] subtypesOfAttributeName:[self attributeName]];
+}
+
+- (BOOL)hasSubtype:(NSString *)_subtype {
+  NSString *attrName;
+  
+  if (_subtype == nil)
+    return NO;
+  
+  attrName = [self attributeName];
+  _subtype = [NSString stringWithFormat:@";%@;", _subtype];
+  
+  return [attrName rangeOfString:_subtype].length > 0 ? YES : NO;
+}
+
+- (NSString *)langSubtype {
+  NSString *attrName;
+  NSRange  r;
+  
+  attrName = [self attributeName];
+  r = [attrName rangeOfString:@";lang-"];
+  if (r.length == 0) return nil;
+  
+  attrName = [attrName substringFromIndex:(r.location + 1)];
+  
+  r = [attrName rangeOfString:@";"];
+  if (r.length > 0) attrName = [attrName substringToIndex:r.location];
+  
+  return attrName;
+}
+
+/* values */
+
+- (unsigned)count {
+  return [self->values count];
+}
+
+- (void)addValue:(id)_value {
+  self->didChange = YES;
+  
+  if (self->values == nil)
+    self->values = [[NSArray alloc] initWithObjects:&_value count:1];
+  else {
+    NSArray *tmp;
+
+    tmp = self->values;
+    self->values = [[tmp arrayByAddingObject:_value] retain];
+    [tmp release];
+  }
+}
+
+- (NSArray *)allValues {
+  return self->values;
+}
+- (NSEnumerator *)valueEnumerator {
+  return [self->values objectEnumerator];
+}
+
+- (void)addStringValue:(NSString *)_value {
+  NSData *d;
+
+  d = [_value dataUsingEncoding:NSUTF8StringEncoding];
+  
+  [self addValue:d];
+}
+
+- (void)catchedDecodeException:(NSException *)_exception {
+  fprintf(stderr, "Got exception %s decoding NSUTF8StringEncoding, "
+          "use defaultCStringEncoding", [[_exception description] cString]);
+}
+- (NSString *)stringFromData:(NSData *)_data {
+  static NSStringEncoding enc = 0;
+  NSString *s;
+  
+  if (enc == 0) enc = [NSString defaultCStringEncoding];
+  
+  if (_data == nil) return nil;
+  *(&s) = nil;
+  NS_DURING
+    s = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding];
+  NS_HANDLER {
+    [self catchedDecodeException:localException];
+    s = nil;
+  }
+  NS_ENDHANDLER;
+  if (s == nil)
+    s = [[NSString alloc] initWithData:_data encoding:enc];
+  return s;
+}
+
+- (NSString *)stringValueAtIndex:(unsigned)_idx {
+  NSData *data;
+  
+  data = [[self allValues] objectAtIndex:_idx];
+  if (![data isNotNull])
+    return nil;
+  
+  return [[self stringFromData:data] autorelease];
+}
+
+- (NSArray *)allStringValues {
+  unsigned cnt;
+
+  if ((cnt = [self count]) == 0) {
+    return [NSArray array];
+  }
+  else if (cnt == 1) {
+    NSString *s;
+    NSData   *data;
+    NSArray  *a;
+
+    data = [[self allValues] objectAtIndex:0];
+    
+    if (![data isNotNull])
+      return nil;
+    
+    s = [self stringFromData:data];
+    a = [[NSArray alloc] initWithObjects:&s count:1];
+    [s release];
+    return [a autorelease];
+  }
+  else {
+    id       *objs;
+    unsigned i;
+    NSArray  *vals, *a;
+    
+    vals = [self allValues];
+    
+    objs = calloc(cnt, sizeof(id));
+    for (i = 0; i < cnt; i++) {
+      NSData *data;
+
+      if ((data = [vals objectAtIndex:i]) == nil) {
+        NSLog(@"missing data for value at index %i", i);
+        objs[i] = [[NSString alloc] initWithString:@""];
+      }
+      else {
+        objs[i] = (![data isNotNull]) ? (id)@"" : [self stringFromData:data];
+      }
+    }
+    
+    a = [[NSArray alloc] initWithObjects:objs count:cnt];
+
+    for (i = 0; i < cnt; i++)
+      [objs[i] release];
+    
+    free(objs); objs = NULL;
+
+    return [a autorelease];
+  }
+}
+- (NSEnumerator *)stringValueEnumerator {
+  return [[self allStringValues] objectEnumerator];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[[self class] alloc] initWithAttributeName:self->name
+                               values:self->values];
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  NSMutableString *ms;
+  NSString     *s;
+  NSEnumerator *e;
+  id           value;
+  BOOL         isFirst;
+
+  ms = [[NSMutableString alloc] initWithCapacity:100];
+  
+  e = [self stringValueEnumerator];
+  isFirst = YES;
+  while ((value = [e nextObject])) {
+    if (isFirst) isFirst = NO;
+    else [ms appendString:@","];
+    [ms appendString:[value description]];
+  }
+  
+  s = [ms copy];
+  [ms release];
+  return [s autorelease];
+}
+
+- (NSString *)description {
+  NSMutableString *s;
+  
+  s = [NSMutableString stringWithCapacity:100];
+  [s appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  [s appendFormat:@" name='%@'", [self attributeName]];
+  [s appendString:@" values="];
+  [s appendString:[self stringValue]];
+  [s appendString:@">"];
+
+  return s;
+}
+
+@end /* NGLdapAttribute */
diff --git a/skyrix-core/NGLdap/NGLdapConnection+Private.h b/skyrix-core/NGLdap/NGLdapConnection+Private.h
new file mode 100644 (file)
index 0000000..991f8ac
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdapConnection_Private_H__
+#define __NGLdapConnection_Private_H__
+
+#include "NGLdapConnection.h"
+
+@class NSException, NSString, NSDictionary;
+
+@interface NGLdapConnection(Privates)
+
+- (void *)ldapHandle;
+
+- (NSException *)_exceptionForErrorCode:(int)_err
+  operation:(NSString *)_operation
+  userInfo:(NSDictionary *)_ui;
+
+@end /* NGLdapConnection(Privates) */
+
+#endif /* __NGLdapConnection_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapConnection.h b/skyrix-core/NGLdap/NGLdapConnection.h
new file mode 100644 (file)
index 0000000..a187e00
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdapConnection_H__
+#define __NGLdapConnection_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSDate.h>
+
+@class NSString, NSArray, NSEnumerator;
+@class EOQualifier;
+@class NGLdapEntry;
+
+@interface NGLdapConnection : NSObject
+{
+  void           *handle;
+  NSString       *hostName;
+  int            port;
+  
+  NSTimeInterval cacheTimeout;
+  long           cacheMaxMemory; /* in bytes */
+  BOOL           isCacheEnabled;
+
+  struct {
+    BOOL isBound:1;
+  } flags;
+}
+
+- (id)initWithHostName:(NSString *)_hostName port:(int)_port; // designated init
+- (id)initWithHostName:(NSString *)_hostName;
+
+/* settings */
+
+- (NSString *)hostName;
+- (int)port;
+
+/* binding */
+
+- (BOOL)isBound;
+- (void)unbind;
+
+- (BOOL)bindWithMethod:(NSString *)_method
+  binddn:(NSString *)_login credentials:(NSString *)_cred;
+
+/* running queries */
+
+- (NSEnumerator *)flatSearchAtBaseDN:(NSString *)_base
+  qualifier:(EOQualifier *)_q
+  attributes:(NSArray *)_attributes;
+- (NSEnumerator *)deepSearchAtBaseDN:(NSString *)_base
+  qualifier:(EOQualifier *)_q
+  attributes:(NSArray *)_attributes;
+- (NSEnumerator *)baseSearchAtBaseDN:(NSString *)_base
+  qualifier:(EOQualifier *)_q
+  attributes:(NSArray *)_attributes;
+
+- (NGLdapEntry *)entryAtDN:(NSString *)_dn attributes:(NSArray *)_attrs;
+
+/* cache */
+
+- (void)setCacheTimeout:(NSTimeInterval)_to;
+- (NSTimeInterval)cacheTimeout;
+
+- (void)setCacheMaxMemoryUsage:(long)_maxMem;
+- (long)cacheMaxMemoryUsage;
+
+- (void)setUseCache:(BOOL)_flag;
+- (BOOL)doesUseCache;
+
+- (void)flushCache;
+- (void)destroyCache;
+
+- (void)cacheForgetEntryWithDN:(NSString *)_dn;
+
+/* modifications */
+
+- (BOOL)addEntry:(NGLdapEntry *)_entry;
+- (BOOL)removeEntryWithDN:(NSString *)_dn;
+- (BOOL)modifyEntryWithDN:(NSString *)_dn changes:(NSArray *)_mods;
+
+/* root DSE */
+
+- (NGLdapEntry *)schemaEntry;
+- (NGLdapEntry *)rootDSE;
+- (NGLdapEntry *)configEntry;
+- (NSArray *)namingContexts;
+
+@end
+
+@interface NGLdapConnection(PlainPasswordCheck)
+
+/* specialized password check routine */
+
+- (NSString *)dnForLogin:(NSString *)_login baseDN:(NSString *)_baseDN;
+
++ (BOOL)checkPassword:(NSString *)_pwd ofLogin:(NSString *)_login
+  atBaseDN:(NSString *)_baseDN
+  onHost:(NSString *)_hostName port:(int)_port;
+
+@end
+
+#endif /* __NGLdapConnection_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapConnection.m b/skyrix-core/NGLdap/NGLdapConnection.m
new file mode 100644 (file)
index 0000000..1ec2c34
--- /dev/null
@@ -0,0 +1,1016 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGLdapConnection.h"
+#include "NGLdapSearchResultEnumerator.h"
+#include "NGLdapEntry.h"
+#include "NGLdapAttribute.h"
+#include "NGLdapModification.h"
+#include "EOQualifier+LDAP.h"
+#include "common.h"
+#include <ldap.h>
+
+static BOOL     LDAPDebugEnabled        = NO;
+static BOOL     LDAPInitialBindSpecific = NO;
+static NSString *LDAPInitialBindDN = @"" ;
+static NSString *LDAPInitialBindPW = @"" ;
+
+/* this is required by SuSE EMail Server III */
+#define ISOLATIN1_CREDENTIALS 1
+
+@interface NGLdapConnection(Privates)
+- (BOOL)_reinit;
+@end
+
+@implementation NGLdapConnection
+
+static void freeMods(LDAPMod **mods) {
+  LDAPMod  *buf;
+  unsigned i;
+  
+  if (mods == NULL)
+    return;
+
+  buf = mods[0];
+  for (i = 0; mods[i] != NULL; i++) {
+    struct berval **values;
+    char *type;
+
+    if ((values = buf[i].mod_bvalues) != NULL) {
+      unsigned j;
+      
+      for (j = 0; values[j] != NULL; j++)
+       free(values[j]);
+      
+      free(values);
+    }
+    
+    if ((type = buf[i].mod_type) != NULL)
+      free(type);
+  }
+  
+  if (buf)  free(buf);
+  if (mods) free(mods);
+}
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  LDAPDebugEnabled        = [ud boolForKey:@"LDAPDebugEnabled"];
+  LDAPInitialBindSpecific = [ud boolForKey:@"LDAPInitialBindSpecific"];
+  LDAPInitialBindDN       = [[ud stringForKey:@"LDAPInitialBindDN"] copy];
+  LDAPInitialBindPW       = [[ud stringForKey:@"LDAPInitialBindPW"] copy];
+}
+
+- (BOOL)_reinit {
+  if (self->handle) {
+    ldap_unbind(self->handle);
+    self->handle = NULL;
+  }
+  
+  self->handle = ldap_init((char *)[self->hostName cString], self->port);
+
+  if (self->handle == NULL)
+    return NO;
+
+  return YES;
+}
+
+- (id)initWithHostName:(NSString *)_hostName port:(int)_port {
+  self->hostName = [_hostName copy];
+  self->port     = (_port != 0) ? _port : 389;
+
+  if (![self _reinit]) {
+    [self release];
+    return nil;
+  }
+  
+  [self setCacheTimeout:120.0];
+  [self setCacheMaxMemoryUsage:16000];
+  
+  return self;
+}
+- (id)initWithHostName:(NSString *)_hostName {
+  return [self initWithHostName:_hostName port:0];
+}
+
+- (void)dealloc {
+  if (self->handle) {
+    if ([self isBound])
+      [self unbind];
+    else {
+      // call unbind to free resources
+      int err;
+      err = ldap_unbind(self->handle);
+      self->handle = NULL;
+    }
+
+    // free handle
+  }
+  [self->hostName release];
+  [super dealloc];
+}
+
+/* settings */
+
+- (NSString *)hostName {
+  return self->hostName;
+}
+- (int)port {
+  return self->port;
+}
+
+/* internals */
+
+- (void *)ldapHandle {
+  return self->handle;
+}
+
+/* errors */
+
+- (NSException *)_exceptionForErrorCode:(int)_err
+  operation:(NSString *)_operation
+  userInfo:(NSDictionary *)_ui
+{
+  NSException *e;
+  NSString *name, *reason;
+
+  name = @"LDAPException";
+
+  switch (_err) {
+    case LDAP_SUCCESS:
+      return nil;
+
+    case LDAP_INAPPROPRIATE_AUTH:
+      reason = @"inappropriate authorization";
+      break;
+
+    case LDAP_INVALID_CREDENTIALS:
+      reason = @"invalid credentials";
+      break;
+      
+    case LDAP_INSUFFICIENT_ACCESS:
+      reason = @"insufficient access";
+      break;
+
+    case LDAP_SERVER_DOWN:
+      reason = @"the server is down";
+      break;
+
+    case LDAP_TIMEOUT:
+      reason = @"the operation timed out";
+      break;
+
+    case LDAP_AUTH_UNKNOWN:
+      reason = @"authorization unknown";
+      break;
+      
+    case LDAP_NOT_ALLOWED_ON_NONLEAF:
+      reason = @"operation not allowed on non-leaf record";
+      break;
+      
+    default:
+      reason = [NSString stringWithFormat:
+                           @"operation %@ failed with code 0x%X",
+                           _operation, _err];
+      break;
+  }
+
+  e = [NSException exceptionWithName:name
+                   reason:reason
+                   userInfo:_ui];
+  
+  return e;
+}
+
+/* binding */
+
+- (BOOL)isBound {
+  return self->flags.isBound ? YES : NO;
+}
+
+- (void)unbind {
+  if (self->flags.isBound) {
+    int err;
+    
+    err = ldap_unbind(self->handle);
+    self->flags.isBound = 0;
+    self->handle = NULL;
+  }
+}
+
+- (BOOL)bindWithMethod:(NSString *)_method
+  binddn:(NSString *)_login credentials:(NSString *)_cred
+{
+  int ldap_version3 = LDAP_VERSION3 ;
+  int method, err;
+  const char *l, *p;
+
+  if (self->handle == NULL)
+    [self _reinit];
+  
+  if ((_method == nil) || ([_method isEqualToString:@"simple"])) {
+    method = LDAP_AUTH_SIMPLE;
+  }
+  else if ([_method isEqualToString:@"krbv41"]) {
+    method = LDAP_AUTH_KRBV41;
+  }
+  else if ([_method isEqualToString:@"krbv42"]) {
+    method = LDAP_AUTH_KRBV42;
+  }
+  else
+    /* unknown method */
+    return NO;
+
+  l = (char *)[_login UTF8String];
+#if ISOLATIN1_CREDENTIALS
+  p = (char *)[_cred  cString];
+#else
+  p = (char *)[_cred  UTF8String];
+#endif
+  err = (method == LDAP_AUTH_SIMPLE)
+    ? ldap_simple_bind_s(self->handle, l, p)
+    : ldap_bind_s(self->handle, l, p, method);
+  
+  if (err == LDAP_SUCCESS) {
+    ldap_set_option(self->handle, LDAP_OPT_PROTOCOL_VERSION, &ldap_version3) ;
+    ldap_set_option(self->handle, LDAP_OPT_REFERRALS, LDAP_OPT_OFF) ;
+    self->flags.isBound = YES;
+    return YES;
+  }
+
+  [[self _exceptionForErrorCode:err
+         operation:@"bind"
+         userInfo:[NSDictionary dictionaryWithObject:_login ? _login : @"<nil>"
+                                forKey:@"login"]]
+         raise];
+  
+  return NO;
+}
+
+/* running queries */
+
+- (NSEnumerator *)_searchAtBaseDN:(NSString *)_base
+  qualifier:(EOQualifier *)_q
+  attributes:(NSArray *)_attributes
+  scope:(int)_scope
+{
+  NSString *filter;
+  int      msgid;
+  char     **attrs;
+  NGLdapSearchResultEnumerator *e;
+
+  if (self->handle == NULL)
+    [self _reinit];
+
+  if ((filter = [_q ldapFilterString]) == nil)
+    filter = @"(objectclass=*)";
+
+  if (_attributes) {
+    unsigned i, acount;
+
+    acount = [_attributes count];
+    attrs = calloc(acount + 1, sizeof(char *));
+    
+    for (i = 0; i < acount; i++)
+      attrs[i] = (char *)[[_attributes objectAtIndex:i] UTF8String];
+  }
+  else
+    attrs = NULL;
+
+  if (LDAPDebugEnabled) 
+    printf("%s: search with at base %s filter %s for attrs %s\n",
+           __PRETTY_FUNCTION__, [_base cString], [filter cString],
+           [[_attributes description] cString]);
+
+  msgid = ldap_search(self->handle,
+                      (char *)[_base UTF8String],
+                      _scope,
+                      (char *)[filter UTF8String],                      
+                      attrs,
+                      0);
+
+  /* free attributes */
+  if (attrs) {
+    free(attrs); attrs = NULL;
+  }
+  
+  if (msgid == -1) {
+    /* trouble */
+    return nil;
+  }
+  
+  e = [[NGLdapSearchResultEnumerator alloc]
+                                     initWithConnection:self messageID:msgid];
+
+  return [e autorelease];
+}
+
+- (NSEnumerator *)flatSearchAtBaseDN:(NSString *)_base
+  qualifier:(EOQualifier *)_q
+  attributes:(NSArray *)_attributes
+{
+  return [self _searchAtBaseDN:_base
+               qualifier:_q
+               attributes:_attributes
+               scope:LDAP_SCOPE_ONELEVEL];
+}
+
+- (NSEnumerator *)deepSearchAtBaseDN:(NSString *)_base
+  qualifier:(EOQualifier *)_q
+  attributes:(NSArray *)_attributes
+{
+  return [self _searchAtBaseDN:_base
+               qualifier:_q
+               attributes:_attributes
+               scope:LDAP_SCOPE_SUBTREE];
+}
+
+- (NSEnumerator *)baseSearchAtBaseDN:(NSString *)_base
+  qualifier:(EOQualifier *)_q
+  attributes:(NSArray *)_attributes
+{
+  return [self _searchAtBaseDN:_base
+               qualifier:_q
+               attributes:_attributes
+               scope:LDAP_SCOPE_BASE];
+}
+
+- (NGLdapEntry *)entryAtDN:(NSString *)_dn attributes:(NSArray *)_attrs {
+  NSEnumerator *e;
+  NGLdapEntry  *entry;
+  
+  e = [self _searchAtBaseDN:_dn
+            qualifier:nil
+            attributes:_attrs
+            scope:LDAP_SCOPE_BASE];
+  
+  entry = [e nextObject];
+  
+  if ([e nextObject]) {
+    NSLog(@"more than one search results in base search !!!");
+    /* consume all entries */
+    while ([e nextObject])
+      ;
+  }
+  
+  return entry;
+}
+
+/* cache */
+
+- (void)setCacheTimeout:(NSTimeInterval)_to {
+  if (self->cacheTimeout != _to) {
+    self->cacheTimeout = _to;
+
+    if (self->isCacheEnabled) {
+#if LDAP_API_VERSION > 2000
+      NSLog(@"WARNING(%s): setting cache-timeout unsupported on the client "
+           @"library version!", __PRETTY_FUNCTION__);
+#else
+      ldap_disable_cache(self->handle);
+      ldap_enable_cache(self->handle, _to, [self cacheMaxMemoryUsage]);
+#endif
+    }
+  }
+}
+- (NSTimeInterval)cacheTimeout {
+  return self->cacheTimeout;
+}
+
+- (void)setCacheMaxMemoryUsage:(long)_maxMem {
+  if (self->cacheMaxMemory != _maxMem) {
+    self->cacheMaxMemory = _maxMem;
+
+    if (self->isCacheEnabled) {
+#if LDAP_API_VERSION > 2000
+      NSLog(@"WARNING(%s): setting maxmem usage unsupported on the client "
+           @"library version!", __PRETTY_FUNCTION__);
+#else
+      ldap_disable_cache(self->handle);
+      ldap_enable_cache(self->handle, [self cacheTimeout], _maxMem);
+#endif
+    }
+  }
+}
+- (long)cacheMaxMemoryUsage {
+  return self->cacheMaxMemory;
+}
+
+- (void)setUseCache:(BOOL)_flag {
+  if (_flag) {
+#if LDAP_API_VERSION > 2000
+      NSLog(@"WARNING(%s): setting cache-usage unsupported on the client "
+           @"library version!", __PRETTY_FUNCTION__);
+#else
+    ldap_enable_cache(self->handle,
+                      [self cacheTimeout], [self cacheMaxMemoryUsage]);
+#endif
+    self->isCacheEnabled = YES;
+  }
+  else {
+#if LDAP_API_VERSION > 2000
+      NSLog(@"WARNING(%s): setting cache-usage unsupported on the client "
+           @"library version!", __PRETTY_FUNCTION__);
+#else
+    ldap_disable_cache(self->handle);
+#endif
+    self->isCacheEnabled = NO;
+  }
+}
+- (BOOL)doesUseCache {
+  return self->isCacheEnabled;
+}
+
+- (void)flushCache {
+#if !(LDAP_API_VERSION > 2000)
+  ldap_flush_cache(self->handle);
+#endif
+}
+- (void)destroyCache {
+#if !(LDAP_API_VERSION > 2000)
+  ldap_destroy_cache(self->handle);
+#endif
+  self->isCacheEnabled = NO;
+}
+
+- (void)cacheForgetEntryWithDN:(NSString *)_dn {
+  if (_dn == nil) return;
+#if !(LDAP_API_VERSION > 2000)
+  ldap_uncache_entry(self->handle, (char *)[_dn UTF8String]);
+#endif
+}
+
+/* modifications */
+
+- (BOOL)addEntry:(NGLdapEntry *)_entry {
+  int         msgid, res;
+  LDAPMod     **attrs;
+  LDAPMessage *msg;
+  LDAPMod     *attrBuf;
+  unsigned    count;
+  
+  attrs   = NULL;
+  attrBuf = NULL;
+  
+  /* construct attributes */
+  {
+    unsigned        i;
+    NSEnumerator    *e;
+    NGLdapAttribute *attribute;
+    
+    count = [_entry count];
+    
+    attrBuf = calloc(count, sizeof(LDAPMod));
+    NSAssert(attrBuf, @"couldn't allocate attribute buffer");
+
+    attrs = calloc(count + 1, sizeof(LDAPMod *));
+    NSAssert(attrs, @"couldn't allocate attribute ptr buffer");
+
+    e = [[[_entry attributes] allValues] objectEnumerator];
+    for (i = 0; (attribute = [e nextObject]) && (i < count); i++) {
+      unsigned      valCount, j;
+      struct berval **values;
+      NSEnumerator  *ve;
+      NSData        *v;
+      char          *attrName;
+      NSString      *key;
+
+      key = [attribute attributeName];
+      
+      valCount = [attribute count];
+      values = calloc(valCount + 1, sizeof(struct berval *));
+
+      ve = [attribute valueEnumerator];
+      for (j = 0; (v = [ve nextObject]) && (j < valCount); j++) {
+        struct berval *bv;
+
+        bv = malloc(sizeof(struct berval));
+        
+        bv->bv_len = [v length];
+        bv->bv_val = (void *)[v bytes];
+        values[j] = bv;
+      }
+      values[valCount] = NULL;
+
+      /* TODO: use UTF-8, UNICODE */
+      attrName = malloc([key cStringLength] + 1);
+      [key getCString:attrName];
+      
+      attrBuf[i].mod_op      = LDAP_MOD_BVALUES;
+      attrBuf[i].mod_type    = attrName;
+      attrBuf[i].mod_bvalues = values;
+      attrs[i] = &(attrBuf[i]);
+    }
+    attrs[count] = NULL;
+  }
+  
+  /* start operation */
+
+  msgid = ldap_add(self->handle, (char *)[[_entry dn] UTF8String], attrs);
+
+  /* deconstruct attributes */
+
+  freeMods(attrs);
+  attrs   = NULL;
+  attrBuf = NULL;
+
+  /* check operation return value */
+  
+  if (msgid == -1) {
+    [[self _exceptionForErrorCode:
+            0 /* was in v1: ((LDAP *)self->handle)->ld_errno */
+           operation:@"add"
+           userInfo:[NSDictionary dictionaryWithObject:_entry forKey:@"entry"]]
+           raise];
+    return NO;
+  }
+  
+  /* process result */
+  
+  msg = NULL;
+  res = ldap_result(self->handle, msgid, 0, NULL /* timeout */, &msg);
+
+  if (res == -1) {
+    /* error */
+    int err;
+
+    err = ldap_result2error(self->handle, msg, 1 /* free msg */);
+    [[self _exceptionForErrorCode:err
+           operation:@"add"
+           userInfo:[NSDictionary dictionaryWithObject:_entry forKey:@"entry"]]
+           raise];
+    
+    return NO;
+  }
+  
+  if (msg) ldap_msgfree(msg);
+  
+  return YES;
+}
+
+/* comparing */
+
+- (BOOL)compareAttribute:(NSString *)_attr ofEntryWithDN:(NSString *)_dn
+  withValue:(id)_value
+{
+  int res;
+  
+  if (_dn == nil)
+    return NO;
+
+  res = ldap_compare_s(self->handle,
+                       (char *)[_dn UTF8String],
+                       (char *)[_attr UTF8String],
+                       (char *)[[_value stringValue] UTF8String]);
+  
+  if (res == LDAP_COMPARE_TRUE)
+    return YES;
+  if (res == LDAP_COMPARE_FALSE)
+    return NO;
+
+  [[self _exceptionForErrorCode:res
+         operation:@"compare"
+         userInfo:[NSDictionary dictionaryWithObject:_dn forKey:@"dn"]]
+         raise];
+  
+  return NO;
+}
+
+- (BOOL)removeEntryWithDN:(NSString *)_dn {
+  int res;
+
+  if (_dn == nil)
+    return YES;
+
+  res = ldap_delete_s(self->handle, (char *)[_dn UTF8String]);
+
+  if (res == LDAP_SUCCESS)
+    return YES;
+
+  [[self _exceptionForErrorCode:res
+         operation:@"delete"
+         userInfo:[NSDictionary dictionaryWithObject:_dn forKey:@"dn"]]
+         raise];
+  
+  return NO;
+}
+
+- (BOOL)modifyEntryWithDN:(NSString *)_dn changes:(NSArray *)_mods {
+  int      res;
+  LDAPMod  **mods;
+  LDAPMod  *modBuf;
+  unsigned i, count;
+
+  if (_dn == nil)
+    return NO;
+
+  if ((count = [_mods count]) == 0)
+    return YES;
+
+  /* construct mods */
+
+  mods   = calloc(count + 1, sizeof(LDAPMod *));
+  modBuf = calloc(count, sizeof(LDAPMod));
+  NSAssert(mods,   @"couldn't allocate modification array");
+  NSAssert(modBuf, @"couldn't allocate modification buffer");
+
+  for (i = 0; i < count; i++) {
+    NGLdapModification *mod;
+    NGLdapAttribute    *attr;
+    NSString           *attrName;
+    unsigned           attrLen;
+    unsigned           valCount;
+    NSEnumerator       *e;
+    NSData             *value;
+    struct berval      **values;
+    unsigned           j;
+
+    mod = [_mods objectAtIndex:i];
+    mods[i] = &(modBuf[i]);
+
+    switch ([mod operation]) {
+      case NGLdapAddAttribute:
+        modBuf[i].mod_op = LDAP_MOD_ADD;
+        break;
+      case NGLdapDeleteAttribute:
+        modBuf[i].mod_op = LDAP_MOD_DELETE;
+        break;
+      case NGLdapReplaceAttribute:
+        modBuf[i].mod_op = LDAP_MOD_REPLACE;
+        break;
+    }
+    modBuf[i].mod_op |= LDAP_MOD_BVALUES;
+
+    attr     = [mod      attribute];
+    attrName = [attr     attributeName];
+    /* TODO: use UTF-8, UNICODE */
+    attrLen  = [attrName cStringLength];
+
+    modBuf[i].mod_type = malloc(attrLen + 1);
+    [attrName getCString:modBuf[i].mod_type];
+
+    valCount = [attr count];
+    values = calloc(valCount + 1, sizeof(struct berval *));
+    
+    e = [attr valueEnumerator];
+    for (j = 0; (value = [e nextObject]) && (j < valCount); j++) {
+      struct berval *bv;
+
+      bv = malloc(sizeof(struct berval));
+      bv->bv_len = [value length];
+      bv->bv_val = (void *)[value bytes];
+      values[j] = bv;
+    }
+    values[valCount] = NULL;
+
+    modBuf[i].mod_bvalues = values;
+  }
+  mods[count] = NULL;
+
+  /* run modify */
+
+  res = ldap_modify_s(self->handle, (char *)[_dn UTF8String], mods);
+
+  /* free structures */
+
+  freeMods(mods);
+  mods   = NULL;
+  modBuf = NULL;
+
+  /* check result */
+  
+  if (res == -1) {
+    [[self _exceptionForErrorCode:
+            0 /* was in v1: ((LDAP *)self->handle)->ld_errno */
+           operation:@"modify"
+           userInfo:[NSDictionary dictionaryWithObject:_dn forKey:@"dn"]]
+           raise];
+    return NO;
+  }
+  return YES;
+}
+
+/* root DSE */
+
+- (NGLdapEntry *)schemaEntry {
+  NGLdapEntry *e;
+  
+  if ((e = [self entryAtDN:@"cn=schema" attributes:nil]))
+    return e;
+  
+  return nil;
+}
+
+- (NGLdapEntry *)rootDSE {
+  NGLdapEntry *e;
+  
+  if ((e = [self entryAtDN:@"" attributes:nil]))
+    return e;
+  
+  return nil;
+}
+
+- (NGLdapEntry *)configEntry {
+  NGLdapEntry *e;
+  
+  if ((e = [self entryAtDN:@"cn=config" attributes:nil]))
+    return e;
+  
+  return nil;
+}
+
+- (NSArray *)namingContexts {
+  NGLdapEntry    *e;
+  NSEnumerator   *values;
+  NSString       *value;
+  NSMutableArray *ma;
+  
+  if ((e = [self rootDSE])) {
+    /* LDAP v3 */
+    return [[e attributeWithName:@"namingcontexts"] allStringValues];
+  }
+  
+  if ((e = [self configEntry]) == nil)
+    return nil;
+  
+  /* OpenLDAP */
+    
+  values = [[e attributeWithName:@"database"] stringValueEnumerator];
+  ma     = [NSMutableArray arrayWithCapacity:4];
+
+  while ((value = [values nextObject])) {
+    NSRange r;
+      
+    r = [value rangeOfString:@":"];
+    if (r.length == 0)
+      /* couldn't parse value */
+      continue;
+      
+    value = [value substringFromIndex:(r.location + r.length)];
+    [ma addObject:value];
+  }
+  return ma;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+
+  s = [NSMutableString stringWithCapacity:100];
+  [s appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if ([self isBound])
+    [s appendString:@" bound"];
+  
+  if ([self doesUseCache]) {
+    [s appendFormat:@" cache[to=%.2fs,mem=%i]",
+         [self cacheTimeout], [self cacheMaxMemoryUsage]];
+  }
+  
+  [s appendString:@">"];
+
+  return s;
+}
+
+@end /* NGLdapConnection */
+
+@implementation NGLdapConnection(PlainPasswordCheck)
+
++ (NSString *)uidAttributeName {
+  static NSString *uidAttr = nil;
+  if (uidAttr == nil) {
+    uidAttr = [[[NSUserDefaults standardUserDefaults] 
+                 stringForKey:@"LDAPLoginAttributeName"] copy];
+    if ([uidAttr length] == 0) uidAttr = @"uid";
+  }
+  return uidAttr;
+}
+
+- (NSString *)dnForLogin:(NSString *)_login baseDN:(NSString *)_baseDN {
+  NSString    *filter;
+  char        *attrs[2];
+  LDAPMessage *result;
+  LDAPMessage *entry;
+  char        *dn;
+  BOOL        didBind = NO;
+  int         matchCount;
+  NSString    *strDN;
+  int         ldap_search_result ;
+
+  if (LDAPDebugEnabled)
+    [self logWithFormat:@"dn for login '%@' on %@", _login, _baseDN];
+  
+  if (self->handle == NULL) {
+    if (![self _reinit]) {
+      NSLog(@"%s: _reinit failed...:", __PRETTY_FUNCTION__);
+      return nil;
+    }
+  }
+  if (![self isBound]) {
+    didBind = NO;
+    if (LDAPDebugEnabled)
+      [self logWithFormat:@"  attempt to do a simple, anonymous bind .."];
+    
+    NS_DURING
+      if (LDAPInitialBindSpecific)
+        didBind = [self bindWithMethod:@"simple" binddn:LDAPInitialBindDN credentials:LDAPInitialBindPW];
+      else
+        didBind = [self bindWithMethod:@"simple" binddn:@"" credentials:@""];
+    NS_HANDLER
+      didBind = NO;
+    NS_ENDHANDLER;
+
+    if (!didBind) {
+      /* couldn't bind */
+      if (LDAPDebugEnabled) [self logWithFormat:@"  bind failed !"];
+      return nil;
+    }
+    didBind = YES;
+    if (LDAPDebugEnabled) [self logWithFormat:@"  bound."];
+  }
+  filter = [NSString stringWithFormat:@"(%@=%@)",
+                       [[self class] uidAttributeName],
+                       _login];
+  if (LDAPDebugEnabled) [self logWithFormat:@"  search: '%@'", filter];
+  
+  /* we only check the DN anyway .. */
+  attrs[0] = "objectclass";
+  attrs[1] = NULL;
+  
+  ldap_search_result = ldap_search_s(self->handle,
+                    (char *)[_baseDN UTF8String],
+                    LDAP_SCOPE_SUBTREE,
+                    (char *)[filter UTF8String],
+                    attrs, 1,
+                    &result) ;
+  if ((ldap_search_result != LDAP_SUCCESS) && (ldap_search_result != LDAP_PARTIAL_RESULTS)) {
+    /* search failed */
+    if (didBind)
+      [self unbind];
+
+    if (LDAPDebugEnabled) {
+      [self logWithFormat:@"  search failed"];
+    }
+    return nil;
+  }
+
+  /*
+    If the entry count is not equal to one, either the UID was not unique or
+    there was no match
+  */
+  if (((matchCount = ldap_count_entries(self->handle, result))) != 1) {
+    if (didBind) [self unbind];
+    if (LDAPDebugEnabled)
+      [self logWithFormat:@"  failed: %i matches", matchCount];
+    return nil;
+  }
+  
+  /* get first entry */
+  if ((entry = ldap_first_entry(self->handle, result)) == NULL) {
+    if (didBind) [self unbind];
+    if (LDAPDebugEnabled) 
+      [self logWithFormat:@"  could not retrieve first entry !"];
+    return nil;
+  }
+
+  /* get DN of first entry */
+  if ((dn = ldap_get_dn(self->handle, entry)) == NULL) {
+    /* couldn't get DN */
+    if (didBind) [self unbind];
+    if (LDAPDebugEnabled) [self logWithFormat:@"  got no DN for entry !"];
+    return nil;
+  }
+  strDN = nil;
+  NS_DURING {
+    strDN = [[[NSString alloc] initWithUTF8String:dn] autorelease];
+  }
+  NS_HANDLER {
+    fprintf(stderr, "Got exception %s while NSUTF8StringEncoding, "
+            "use defaultCStringEncoding",
+            [[localException description] cString]);
+    strDN = nil;
+  }
+  NS_ENDHANDLER;
+
+  if (strDN == nil) {
+    if (LDAPDebugEnabled) {
+      [self debugWithFormat:
+            @"could not convert DN to UTF-8 string, try cString .."];
+    }
+    strDN = [[[NSString alloc] initWithCString:dn] autorelease];
+  }
+  free(dn); dn = NULL;
+
+  if (result) {
+    ldap_msgfree(result);
+  }
+  [self unbind];
+  if (LDAPDebugEnabled) {
+    [self logWithFormat:@"   return DN %@", strDN];
+  }
+  return strDN;
+}
+
+- (BOOL)checkPassword:(NSString *)_pwd ofLogin:(NSString *)_login
+  atBaseDN:(NSString *)_baseDN
+{
+  BOOL        didBind;
+  NSString    *strDN; 
+
+  if (LDAPDebugEnabled)
+    [self logWithFormat:@"check pwd of login '%@' on %@", _login, _baseDN];
+  
+  if (self->handle == NULL) {
+    if (![self _reinit]) {
+      NSLog(@"%s: _reinit failed...:", __PRETTY_FUNCTION__);
+    }
+  }
+  strDN = [self dnForLogin:_login baseDN:_baseDN];
+
+  if (LDAPDebugEnabled) {
+    [self logWithFormat:@"  attempting to bind login %@ DN: %@ %s!",
+          _login, strDN,
+          [_pwd length] > 0 ? "(with password) " : "(empty password) "];
+  }
+  
+  if (!strDN) {
+    if (LDAPDebugEnabled) {
+      [self logWithFormat:@"  missing dn for login %@ atBaseDN %@",
+            _login, _baseDN];
+    }
+    return NO;
+  }
+  /*
+    Now bind as the DN with the password supplied earlier...
+    Successful bind means the password was correct, otherwise the
+    password is invalid.
+  */
+
+  didBind = NO;
+  NS_DURING
+    didBind = [self bindWithMethod:@"simple" binddn:strDN credentials:_pwd];
+  NS_HANDLER
+    didBind = NO;
+  NS_ENDHANDLER;
+  
+  if (!didBind) {
+    /* invalid login or password */
+    if (LDAPDebugEnabled) 
+      [self logWithFormat:@"  could not simple bind DN '%@' !", strDN];
+    
+    [self unbind];
+    return NO;
+  }
+  [self unbind];
+  if (LDAPDebugEnabled) [self logWithFormat:@"  bound successfully !"];
+  return YES;
+}
+
++ (BOOL)checkPassword:(NSString *)_pwd ofLogin:(NSString *)_login
+  atBaseDN:(NSString *)_baseDN
+  onHost:(NSString *)_hostName port:(int)_port
+{
+  NGLdapConnection *ldap;
+  
+  if (LDAPDebugEnabled) {
+    NSLog(@"LDAP: check pwd of login '%@' on %@,%i,%@ ...",
+          _login, _hostName, _port, _baseDN);
+  }
+  
+  if ((ldap = [[self alloc] initWithHostName:_hostName port:_port]) == nil) {
+    if (LDAPDebugEnabled)
+      NSLog(@"LDAP:   got no connection to %@,%i ...", _hostName, _port);
+    return NO;
+  }
+  ldap = [ldap autorelease];
+  if (LDAPDebugEnabled)
+    NSLog(@"LDAP:   use connection: %@", ldap);
+  
+  return [ldap checkPassword:_pwd ofLogin:_login atBaseDN:_baseDN];
+}
+
+@end /* NGLdapConnection(PlainPasswordCheck) */
diff --git a/skyrix-core/NGLdap/NGLdapDataSource.h b/skyrix-core/NGLdap/NGLdapDataSource.h
new file mode 100644 (file)
index 0000000..c43434b
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdapDataSource_H__
+#define __NGLdapDataSource_H__
+
+#import <EOControl/EODataSource.h>
+
+@class EOFetchSpecification;
+@class NGLdapConnection;
+
+/*
+  supported keys:
+    
+    any LDAP attribute name
+    
+  supported fetch hints:
+
+    NSFetchKeys  - array of NSString's denoting the keys to fetch
+    NSFetchScope - [NSFetchScopeBase|NSFetchScopeOneLevel|NSFetchScopeSubTree]
+*/
+
+@interface NGLdapDataSource : EODataSource
+{
+  NGLdapConnection     *ldap;
+  EOFetchSpecification *fspec;
+  NSString             *searchBase;
+}
+
+- (id)initWithLdapConnection:(NGLdapConnection *)_con searchBase:(NSString *)_dn;
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec;
+- (EOFetchSpecification *)fetchSpecification;
+
+/* operations */
+
+- (NSArray *)fetchObjects;
+
+- (NSString *)searchBase;
+
+@end /* NGLdapDataSource */
+
+#endif /* __NGLdapDataSource_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapDataSource.m b/skyrix-core/NGLdap/NGLdapDataSource.m
new file mode 100644 (file)
index 0000000..c5ee333
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGLdapDataSource.h"
+#include "NGLdapEntry.h"
+#include "NGLdapAttribute.h"
+#include "NGLdapConnection.h"
+#import <NGExtensions/NGFileFolderInfoDataSource.h>
+#import <EOControl/EOControl.h>
+#include "common.h"
+
+@implementation NGLdapDataSource
+
+- (id)initWithLdapConnection:(NGLdapConnection *)_con searchBase:(NSString *)_dn{
+  if (_con == nil) {
+    [self release];
+    return nil;
+  }
+  if ((self = [super init])) {
+    self->ldap       = [_con retain];
+    self->searchBase = [_dn copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->searchBase release];
+  [self->fspec      release];
+  [self->ldap       release];
+  [super dealloc];
+}
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec {
+  /* should invalidate ds chain */
+  ASSIGN(self->fspec, _fspec);
+}
+- (EOFetchSpecification *)fetchSpecification {
+  return self->fspec;
+}
+
+/* transformation */
+
+- (NSDictionary *)_recordFromEntry:(NGLdapEntry *)_entry {
+  NSMutableDictionary *md;
+  NSEnumerator        *keys;
+  NSString            *key;
+  id tmp;
+  
+  if (_entry == nil)
+    return nil;
+  
+  md = [NSMutableDictionary dictionaryWithCapacity:[_entry count]];
+  
+  if ((tmp = [_entry dn])) {
+    [md setObject:tmp forKey:@"NSFileIdentifier"];
+    [md setObject:tmp forKey:NSFilePath];
+  }
+  if ((tmp = [_entry rdn]))
+    [md setObject:tmp forKey:NSFileName];
+  
+  keys = [[_entry attributeNames] objectEnumerator];
+  
+  while ((key = [keys nextObject])) {
+    NGLdapAttribute *attribute;
+    unsigned count;
+    id value;
+    
+    attribute = [_entry attributeWithName:key];
+    count     = [attribute count];
+    
+    if (count == 0)
+      value = [EONull null];
+    else if (count == 1)
+      value = [attribute stringValueAtIndex:0];
+    else
+      value = [attribute allStringValues];
+
+    [md setObject:value forKey:key];
+  }
+
+  return [[md copy] autorelease];
+}
+
+/* operations */
+
+- (NSArray *)fetchObjects { // TODO: use the new fetch-enumerator
+  NSAutoreleasePool *pool;
+  NSString       *scope;
+  EOQualifier    *qualifier;
+  NSArray        *sortOrderings;
+  NSEnumerator   *e;
+  NSString       *baseDN;
+  NSMutableArray *results;
+  NGLdapEntry    *entry;
+  NSArray        *array;
+  NSArray        *attrs;
+
+  pool = [NSAutoreleasePool new];
+  
+  scope         = nil;
+  qualifier     = nil;
+  sortOrderings = nil;
+  baseDN        = nil;
+  attrs         = nil;
+  
+  if (self->fspec) {
+    NSString *entityName;
+    
+    qualifier     = [self->fspec qualifier];
+    sortOrderings = [self->fspec sortOrderings];
+    scope         = [[self->fspec hints] objectForKey:@"NSFetchScope"];
+    attrs         = [[self->fspec hints] objectForKey:@"NSFetchKeys"];
+
+    if ((entityName = [self->fspec entityName])) {
+      EOQualifier *oq;
+
+      oq = [[EOKeyValueQualifier alloc]
+                                 initWithKey:@"objectclass"
+                                 operatorSelector:EOQualifierOperatorEqual
+                                 value:entityName];
+      if (qualifier) {
+        NSArray *qa;
+        
+        qa = [NSArray arrayWithObjects:oq, qualifier, nil];
+        qualifier = [[EOAndQualifier alloc] initWithQualifierArray:qa];
+        qualifier = [qualifier autorelease];
+        [oq release]; oq = nil;
+      }
+      else {
+        qualifier = [oq autorelease];
+        oq = nil;
+      }
+    }
+  }
+  else {
+    static NSArray *so = nil;
+    if (so == nil) {
+      EOSortOrdering *o;
+      o = [EOSortOrdering sortOrderingWithKey:@"NSFileIdentifier"
+                         selector:EOCompareAscending];
+      so = [[NSArray alloc] initWithObjects:&o count:1];
+    }
+    sortOrderings = so;
+  }
+  
+  if (scope == nil)
+    scope = @"NSFetchScopeOneLevel";
+  if (baseDN == nil)
+    baseDN = self->searchBase;
+
+  if ([scope isEqualToString:@"NSFetchScopeOneLevel"]) {
+    e = [self->ldap flatSearchAtBaseDN:baseDN
+                    qualifier:qualifier
+                    attributes:attrs];
+  }
+  else if ([scope isEqualToString:@"NSFetchScopeSubTree"]) {
+    e = [self->ldap deepSearchAtBaseDN:baseDN
+                    qualifier:qualifier
+                    attributes:attrs];
+  }
+  else {
+    [NSException raise:@"NGLdapDataSourceException"
+                 format:@"unsupported fetch-scope: '%@' !", scope];
+    e = nil;
+  }
+  
+  if (e == nil) {
+    /* no results */
+    [pool release];
+    return nil;
+  }
+
+  /* transform results into records */
+  
+  results = [NSMutableArray arrayWithCapacity:64];
+  while ((entry = [e nextObject])) {
+    NSDictionary *record;
+
+    if ((record = [self _recordFromEntry:entry]) == nil) {
+      NSLog(@"WARNING: couldn't transform entry %@ into record !", entry);
+      continue;
+    }
+    
+    [results addObject:record];
+  }
+  array = [[results copy] autorelease];
+  
+  /* apply sort-orderings in-memory */
+  if (sortOrderings)
+    array = [array sortedArrayUsingKeyOrderArray:sortOrderings];
+
+  array = [array retain];
+  [pool release];
+  
+  return [array autorelease];
+}
+
+- (NSString *)searchBase {
+  return self->searchBase;
+}
+
+
+@end /* NGLdapDataSource */
diff --git a/skyrix-core/NGLdap/NGLdapEntry.h b/skyrix-core/NGLdap/NGLdapEntry.h
new file mode 100644 (file)
index 0000000..01828e9
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdapEntry_H__
+#define __NGLdapEntry_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSDictionary, NSArray;
+@class NGLdapAttribute;
+
+@interface NGLdapEntry : NSObject < NSCopying >
+{
+  NSString *dn;
+  NSArray  *attributes;
+}
+
+- (id)initWithDN:(NSString *)_dn attributes:(NSArray *)_attrs;
+
+/* distinguished name */
+
+- (NSString *)dn;
+- (NSString *)rdn; /* relative dn */
+
+/* class */
+
+- (NSArray *)objectClasses;
+
+/* attributes */
+
+- (NGLdapAttribute *)attributeWithName:(NSString *)_name;
+- (NGLdapAttribute *)attributeWithName:(NSString *)_name
+  language:(NSString *)_language;
+
+- (NSArray *)attributeNames;
+- (NSDictionary *)attributes;
+- (unsigned)count;
+
+/* LDIF */
+
+- (NSString *)ldif;
+
+@end
+
+#endif /* __NGLdapEntry_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapEntry.m b/skyrix-core/NGLdap/NGLdapEntry.m
new file mode 100644 (file)
index 0000000..acbdcdc
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGLdapEntry.h"
+#include "NGLdapAttribute.h"
+#include "NSString+DN.h"
+#import <EOControl/EOControl.h>
+#include "common.h"
+
+@implementation NGLdapEntry
+
+- (id)initWithDN:(NSString *)_dn attributes:(NSArray *)_attrs {
+  _dn = [_dn lowercaseString];
+  self->dn         = [[[_dn dnComponents] componentsJoinedByString:@","] copy];
+  self->attributes = [_attrs copy];
+  return self;
+}
+- (id)init {
+  [self release];
+  return nil;
+}
+
+- (void)dealloc {
+  [self->attributes release];
+  [self->dn         release];
+  [super dealloc];
+}
+
+/* distinguished name */
+
+- (NSString *)dn {
+  return self->dn;
+}
+- (NSString *)rdn {
+  return [self->dn lastDNComponent];
+}
+
+/* class */
+
+- (NSArray *)objectClasses {
+  NGLdapAttribute *a;
+
+  a = [self attributeWithName:@"objectclass"];
+  
+  return [[a allStringValues] sortedArrayUsingSelector:@selector(compare:)];
+}
+
+/* attributes */
+
+- (unsigned)count {
+  return [self->attributes count];
+}
+
+- (NSArray *)attributeNames {
+  NSMutableArray  *ma;
+  NSArray         *a;
+  NSEnumerator    *e;
+  NGLdapAttribute *attr;
+
+  ma = [[NSMutableArray alloc] initWithCapacity:[self->attributes count]];
+
+  e = [self->attributes objectEnumerator];
+  while ((attr = [e nextObject]))
+    [ma addObject:[attr attributeName]];
+  
+  a = [ma copy];
+  [ma release];
+  return [a autorelease];
+}
+- (NSDictionary *)attributes {
+  NSMutableDictionary *md;
+  NSDictionary    *d;
+  NSEnumerator    *e;
+  NGLdapAttribute *a;
+  
+  md = [[NSMutableDictionary alloc] initWithCapacity:[self->attributes count]];
+
+  e = [self->attributes objectEnumerator];
+  while ((a = [e nextObject]))
+    [md setObject:a forKey:[a attributeName]];
+  
+  d = [md copy];
+  [md release];
+  return [d autorelease];
+}
+
+- (NGLdapAttribute *)attributeWithName:(NSString *)_name {
+  NSEnumerator    *e;
+  NGLdapAttribute *a;
+  
+  if (_name == nil)
+    return nil;
+
+  e = [self->attributes objectEnumerator];
+
+  while ((a = [e nextObject])) {
+    if ([[a attributeName] isEqualToString:_name])
+      return a;
+  }
+  return nil;
+}
+
+- (NGLdapAttribute *)attributeWithName:(NSString *)_name
+  language:(NSString *)_language
+{
+  NSEnumerator    *e;
+  NGLdapAttribute *a;
+  NGLdapAttribute *awl, *al;
+
+  if (_language == nil)
+    return [self attributeWithName:_name];
+
+  awl = al = nil;
+  e = [self->attributes objectEnumerator];
+  while ((a = [e nextObject])) {
+    if ([[a attributeBaseName] isEqualToString:_name]) {
+      NSString *lang;
+      
+      if (al == nil) al = a;
+
+      if ((lang = [a langSubtype])) {
+        if ([lang isEqualToString:_language])
+          return a;
+      }
+      else {
+        awl = a;
+      }
+    }
+  }
+  if (awl) return awl;
+  if (al)  return al;
+  return nil;
+}
+
+/* LDIF */
+
+- (NSString *)ldif {
+  NSMutableString *ms;
+  NSEnumerator    *names;
+  NSString        *cname;
+  
+  ms = [NSMutableString stringWithCapacity:256];
+
+  /* add DN to LDIF */
+  [ms appendString:@"DN: "];
+  [ms appendString:[self dn]];
+  [ms appendString:@"\n"];
+  
+  /* add attributes */
+  names = [[self attributeNames] objectEnumerator];
+  while ((cname = [names nextObject])) {
+    NGLdapAttribute *attr;
+    
+    if ((attr = [self attributeWithName:cname])) {
+      NSEnumerator *values;
+      NSString *value;
+
+      values = [attr stringValueEnumerator];
+      while ((value = [values nextObject])) {
+        [ms appendString:cname];
+        [ms appendString:@": "];
+        [ms appendString:value];
+        [ms appendString:@"\n"];
+      }
+    }
+  }
+  
+  return ms;
+}
+
+/* key-value coding */
+
+- (id)valueForKey:(NSString *)_key {
+  return [self attributeWithName:_key];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[[self class] alloc] initWithDN:self->dn attributes:self->attributes];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+  
+  s = [NSMutableString stringWithCapacity:100];
+  [s appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  [s appendFormat:@" dn='%@'", [self dn]];
+  
+  [s appendString:@" attrs="];
+  [s appendString:[[self attributes] description]];
+
+  [s appendString:@">"];
+
+  return s;
+}
+
+@end /* NGLdapEntry */
diff --git a/skyrix-core/NGLdap/NGLdapFileManager.h b/skyrix-core/NGLdap/NGLdapFileManager.h
new file mode 100644 (file)
index 0000000..1e5bacc
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdapFileManager_H__
+#define __NGLdapFileManager_H__
+
+#import <Foundation/NSObject.h>
+#import <NGExtensions/NGFileManager.h>
+#import <NGExtensions/NSFileManager+Extensions.h>
+
+@class NSString, NSDictionary, NSData, NSArray, NSURL;
+@class NGLdapConnection;
+
+@interface NGLdapFileManager : NGFileManager
+{
+  NGLdapConnection *connection;
+  NSString *rootDN;
+  NSString *currentDN;
+  NSString *currentPath;
+}
+
+- (id)initWithURLString:(NSString *)_url;
+- (id)initWithURL:(id)_url;
+
+- (id)initWithHostName:(NSString *)_host port:(int)_port
+  bindDN:(NSString *)_login credentials:(NSString *)_pwd
+  rootDN:(NSString *)_rootDN;
+
+/* operations */
+
+- (BOOL)changeCurrentDirectoryPath:(NSString *)_path;
+- (NSString *)currentDirectoryPath;
+
+- (NSArray *)directoryContentsAtPath:(NSString *)_path;
+- (NSArray *)subpathsAtPath:(NSString *)_path;
+
+- (NSDictionary *)fileAttributesAtPath:(NSString *)_path traverseLink:(BOOL)_fl;
+
+/* determine access */
+
+- (BOOL)fileExistsAtPath:(NSString *)_path isDirectory:(BOOL *)_isDir;
+- (BOOL)fileExistsAtPath:(NSString *)_path;
+- (BOOL)isReadableFileAtPath:(NSString *)_path;
+- (BOOL)isWritableFileAtPath:(NSString *)_path;
+- (BOOL)isExecutableFileAtPath:(NSString *)_path;
+- (BOOL)isDeletableFileAtPath:(NSString *)_path;
+
+/* reading contents */
+
+- (BOOL)contentsEqualAtPath:(NSString *)_path1 andPath:(NSString *)_path2;
+- (NSData *)contentsAtPath:(NSString *)_path;
+
+/* modifications */
+
+- (BOOL)removeFileAtPath:(NSString *)_path handler:(id)handler;
+
+- (BOOL)copyPath:(NSString *)_source toPath:(NSString *)_destination
+  handler:(id)_handler;
+- (BOOL)movePath:(NSString *)_source toPath:(NSString *)_destination 
+  handler:(id)_handler;
+- (BOOL)linkPath:(NSString *)_source toPath:(NSString *)_destination 
+  handler:(id)_handler;
+
+- (BOOL)createFileAtPath:(NSString *)path
+  contents:(NSData *)contents
+  attributes:(NSDictionary *)attributes;
+
+/* internals */
+
+- (NGLdapConnection *)ldapConnection;
+- (NSString *)dnForPath:(NSString *)_path;
+- (NSString *)pathForDN:(NSString *)_dn;
+
+@end
+
+@class EODataSource;
+
+@interface NGLdapFileManager(ExtendedFileManager) < NGFileManagerDataSources >
+
+/* feature check */
+
+- (BOOL)supportsVersioningAtPath:(NSString *)_path;
+- (BOOL)supportsLockingAtPath:(NSString *)_path;
+- (BOOL)supportsFolderDataSourceAtPath:(NSString *)_path;
+
+/* writing */
+
+- (BOOL)writeContents:(NSData *)_content atPath:(NSString *)_path;
+
+@end
+
+#endif /* __NGLdapFileManager_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapFileManager.m b/skyrix-core/NGLdap/NGLdapFileManager.m
new file mode 100644 (file)
index 0000000..93457e9
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGLdapFileManager.h"
+#include "NGLdapConnection.h"
+#include "NGLdapEntry.h"
+#include "NGLdapAttribute.h"
+#include "NGLdapURL.h"
+#include "NSString+DN.h"
+#import <NGExtensions/NGFileFolderInfoDataSource.h>
+#include "common.h"
+
+@implementation NGLdapFileManager
+
++ (int)version {
+  return [super version] + 0 /* v0 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 0,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+static NSString *LDAPObjectClassKey = @"objectclass";
+static NSArray  *objectClassAttrs = nil;
+static NSArray  *fileInfoAttrs    = nil;
+
++ (void)_initCache {
+  if (objectClassAttrs == nil) {
+    objectClassAttrs =
+      [[NSArray alloc] initWithObjects:&LDAPObjectClassKey count:1];
+  }
+  if (fileInfoAttrs == nil) {
+    fileInfoAttrs =
+      [[NSArray alloc] initWithObjects:
+                         @"objectclass",
+                         @"createTimestamp",
+                         @"modifyTimestamp",
+                         @"creatorsName",
+                         @"modifiersName",
+                         nil];
+  }
+}
+
+- (id)initWithLdapConnection:(NGLdapConnection *)_con { // designated initializer
+  if (_con == nil) {
+    [self release];
+    return nil;
+  }
+  
+  [[self class] _initCache];
+  
+  if ((self = [super init])) {
+    self->connection = [_con retain];
+  }
+  return self;
+}
+
+- (id)initWithHostName:(NSString *)_host port:(int)_port
+  bindDN:(NSString *)_login credentials:(NSString *)_pwd
+  rootDN:(NSString *)_rootDN
+{
+  NGLdapConnection *ldap;
+  
+  ldap = [[NGLdapConnection alloc] initWithHostName:_host port:_port?_port:389];
+  if (ldap == nil) {
+    [self release];
+    return nil;
+  }
+  ldap = [ldap autorelease];
+  
+  if (![ldap bindWithMethod:@"simple" binddn:_login credentials:_pwd]) {
+    NSLog(@"couldn't bind as DN '%@' with %@", _login, ldap);
+    [self release];
+    return nil;
+  }
+  
+  if ((self = [self initWithLdapConnection:ldap])) {
+    if (_rootDN == nil) {
+      /* check cn=config as available in OpenLDAP */
+      NSArray *nctxs;
+      
+      if ((nctxs = [self->connection namingContexts])) {
+        if ([nctxs count] > 1)
+          NSLog(@"WARNING: more than one naming context handled by server !");
+        if ([nctxs count] > 0)
+          _rootDN = [[nctxs objectAtIndex:0] lowercaseString];
+      }
+    }
+    
+    if (_rootDN) {
+      ASSIGNCOPY(self->rootDN,    _rootDN);
+      ASSIGNCOPY(self->currentDN, _rootDN);
+      self->currentPath = @"/";
+    }
+  }
+  return self;
+}
+
+- (id)initWithURLString:(NSString *)_url {
+  NGLdapURL *url;
+
+  if ((url = [NGLdapURL ldapURLWithString:_url]) == nil) {
+    /* couldn't parse URL */
+    [self release];
+    return nil;
+  }
+  
+  return [self initWithHostName:[url hostName] port:[url port]
+               bindDN:nil credentials:nil
+               rootDN:[url baseDN]];
+}
+- (id)initWithURL:(id)_url {
+  return (![_url isKindOfClass:[NSURL class]])
+    ? [self initWithURLString:[_url stringValue]]
+    : [self initWithURLString:[_url absoluteString]];
+}
+
+- (void)dealloc {
+  [self->connection  release];
+  [self->rootDN      release];
+  [self->currentDN   release];
+  [self->currentPath release];
+  [super dealloc];
+}
+
+/* internals */
+
+- (NSString *)_rdnForPathComponent:(NSString *)_pathComponent {
+  return _pathComponent;
+}
+- (NSString *)_pathComponentForRDN:(NSString *)_rdn {
+  return _rdn;
+}
+
+- (NSString *)pathForDN:(NSString *)_dn {
+  NSEnumerator *dnComponents;
+  NSString     *path;
+  NSString     *rdn;
+  
+  if (_dn == nil) return nil;
+  _dn = [_dn lowercaseString];
+  
+  if (![_dn hasSuffix:self->rootDN]) {
+    /* DN is not rooted in this hierachy */
+    return nil;
+  }
+
+  /* cut of root */
+  _dn = [_dn substringToIndex:([_dn length] - [self->rootDN length])];
+  
+  path = @"/";
+  dnComponents = [[_dn dnComponents] reverseObjectEnumerator];
+  while ((rdn = [dnComponents nextObject])) {
+    NSString *pathComponent;
+    
+    pathComponent = [self _pathComponentForRDN:rdn];
+    
+    path = [path stringByAppendingPathComponent:pathComponent];
+  }
+  return path;
+}
+
+- (NGLdapConnection *)ldapConnection {
+  return self->connection;
+}
+- (NSString *)dnForPath:(NSString *)_path {
+  NSString *dn = nil;
+  NSArray  *pathComponents;
+  unsigned i, count;
+
+  if (![_path isAbsolutePath])
+    _path = [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
+  
+  if ([_path length] == 0) return nil;
+  
+  NSAssert1([_path isAbsolutePath],
+           @"path %@ is not an absolute path (after append to cwd) !", _path);
+  NSAssert(self->rootDN, @"missing root DN !");
+  
+  pathComponents = [_path pathComponents];
+  for (i = 0, count = [pathComponents count]; i < count; i++) {
+    NSString *pathComponent;
+    NSString *rdn;
+    
+    pathComponent = [pathComponents objectAtIndex:i];
+
+    if ([pathComponent isEqualToString:@"."])
+      continue;
+    if ([pathComponent length] == 0)
+      continue;
+
+    if ([pathComponent isEqualToString:@"/"]) {
+      dn = self->rootDN;
+      continue;
+    }
+    
+    if ([pathComponent isEqualToString:@".."]) {
+      dn = [dn stringByDeletingLastDNComponent];
+      continue;
+    }
+    
+    rdn = [self _rdnForPathComponent:pathComponent];
+    dn  = [dn stringByAppendingDNComponent:rdn];
+  }
+  
+  return [dn lowercaseString];
+}
+
+/* accessors */
+
+- (BOOL)changeCurrentDirectoryPath:(NSString *)_path {
+  NSString *dn;
+  NSString *path;
+
+  if ([_path length] == 0)
+    return NO;
+  
+  if ((dn = [self dnForPath:_path]) == nil)
+    return NO;
+  
+  if ((path = [self pathForDN:dn]) == nil)
+    return NO;
+  
+  ASSIGNCOPY(self->currentDN,   dn);
+  ASSIGNCOPY(self->currentPath, path);
+  return YES;
+}
+
+- (NSString *)currentDirectoryPath {
+  return self->currentPath;
+}
+
+
+- (NSArray *)directoryContentsAtPath:(NSString *)_path {
+  NSString       *dn;
+  NSEnumerator   *e;
+  NSMutableArray *rdns;
+  NGLdapEntry    *entry;
+  
+  if ((dn = [self dnForPath:_path]) == nil)
+    return nil;
+  
+  e = [self->connection flatSearchAtBaseDN:dn
+                        qualifier:nil
+                        attributes:objectClassAttrs];
+  if (e == nil)
+    return nil;
+
+  rdns = nil;
+  while ((entry = [e nextObject])) {
+    if (rdns == nil)
+      rdns = [NSMutableArray arrayWithCapacity:128];
+    
+    [rdns addObject:[entry rdn]];
+  }
+
+  return [[rdns copy] autorelease];
+}
+
+- (NSArray *)subpathsAtPath:(NSString *)_path {
+  NSString       *dn;
+  NSEnumerator   *e;
+  NSMutableArray *paths;
+  NGLdapEntry    *entry;
+  
+  if ((dn = [self dnForPath:_path]) == nil)
+    return nil;
+  
+  _path = [self pathForDN:dn];
+  
+  e = [self->connection deepSearchAtBaseDN:dn
+                        qualifier:nil
+                        attributes:objectClassAttrs];
+  if (e == nil)
+    return nil;
+  
+  paths = nil;
+  while ((entry = [e nextObject])) {
+    NSString *path;
+    NSString *sdn;
+    
+    sdn = [entry dn];
+    
+    if ((path = [self pathForDN:sdn]) == nil) {
+      NSLog(@"got no path for dn '%@' ..", sdn);
+      continue;
+    }
+
+    if ([path hasPrefix:_path])
+      path = [path substringFromIndex:[_path length]];
+
+    if (paths == nil)
+      paths = [NSMutableArray arrayWithCapacity:128];
+    
+    [paths addObject:path];
+  }
+  
+  return [[paths copy] autorelease];
+}
+
+- (NSDictionary *)fileAttributesAtPath:(NSString *)_path traverseLink:(BOOL)_fl {
+  NSString        *dn;
+  NGLdapEntry     *entry;
+  NGLdapAttribute *attr;
+  id    keys[10];
+  id    vals[10];
+  short count;
+  
+  if ((dn = [self dnForPath:_path]) == nil)
+    return NO;
+  
+  entry = [self->connection entryAtDN:dn attributes:fileInfoAttrs];
+  if (entry == nil)
+    return nil;
+  
+  count = 0;
+  if ((attr = [entry attributeWithName:@"modifytimestamp"])) {
+    keys[count] = NSFileModificationDate;
+    vals[count] = [[attr stringValueAtIndex:0] ldapTimestamp];
+    count++;
+  }
+  if ((attr = [entry attributeWithName:@"modifiersname"])) {
+    keys[count] = NSFileOwnerAccountName;
+    vals[count] = [[attr allStringValues] componentsJoinedByString:@","];
+    count++;
+  }
+  if ((attr = [entry attributeWithName:@"creatorsname"])) {
+    keys[count] = @"NSFileCreatorAccountName";
+    vals[count] = [[attr allStringValues] componentsJoinedByString:@","];
+    count++;
+  }
+  if ((attr = [entry attributeWithName:@"createtimestamp"])) {
+    keys[count] = @"NSFileCreationDate";
+    vals[count] = [[attr stringValueAtIndex:0] ldapTimestamp];
+    count++;
+  }
+  if ((attr = [entry attributeWithName:@"objectclass"])) {
+    keys[count] = @"LDAPObjectClasses";
+    vals[count] = [attr allStringValues];
+    count++;
+  }
+
+  keys[count] = @"NSFileIdentifier";
+  if ((vals[count] = [entry dn]))
+    count++;
+  
+  keys[count] = NSFilePath;
+  if ((vals[count] = _path))
+    count++;
+  
+  keys[count] = NSFileName;
+  if ((vals[count] = [self _pathComponentForRDN:[dn lastDNComponent]]))
+    count++;
+  
+  return [NSDictionary dictionaryWithObjects:vals forKeys:keys count:count];
+}
+
+/* determine access */
+
+- (BOOL)fileExistsAtPath:(NSString *)_path {
+  return [self fileExistsAtPath:_path isDirectory:NULL];
+}
+- (BOOL)fileExistsAtPath:(NSString *)_path isDirectory:(BOOL *)_isDir {
+  NSString    *dn;
+  NGLdapEntry *entry;
+  
+  if ((dn = [self dnForPath:_path]) == nil)
+    return NO;
+  
+  entry = [self->connection entryAtDN:dn attributes:objectClassAttrs];
+  if (entry == nil)
+    return NO;
+
+  if (_isDir) {
+    NSEnumerator *e;
+
+    /* is-dir based on child-availablitiy */
+    e = [self->connection flatSearchAtBaseDN:dn
+                          qualifier:nil
+                          attributes:objectClassAttrs];
+    *_isDir = [e nextObject] ? YES : NO;
+  }
+  return YES;
+}
+
+- (BOOL)isReadableFileAtPath:(NSString *)_path {
+  return [self fileExistsAtPath:_path];
+}
+- (BOOL)isWritableFileAtPath:(NSString *)_path {
+  return [self fileExistsAtPath:_path];
+}
+- (BOOL)isExecutableFileAtPath:(NSString *)_path {
+  return NO;
+}
+- (BOOL)isDeletableFileAtPath:(NSString *)_path {
+  return [self fileExistsAtPath:_path];
+}
+
+/* reading contents */
+
+- (BOOL)contentsEqualAtPath:(NSString *)_path1 andPath:(NSString *)_path2 {
+  NSString    *dn1, *dn2;
+  NGLdapEntry *e1, *e2;
+
+  if ((dn1 = [self dnForPath:_path1]) == nil)
+    return NO;
+  if ((dn2 = [self dnForPath:_path2]) == nil)
+    return NO;
+  
+  if ([dn1 isEqualToString:dn2])
+    /* same DN */
+    return YES;
+
+  e1 = [self->connection entryAtDN:dn1 attributes:nil];
+  e2 = [self->connection entryAtDN:dn2 attributes:nil];
+  
+  return [e1 isEqual:e2];
+}
+- (NSData *)contentsAtPath:(NSString *)_path {
+  /* generate LDIF for record */
+  NSString        *dn;
+  NGLdapEntry     *entry;
+  
+  if ((dn = [self dnForPath:_path]) == nil)
+    return NO;
+  
+  entry = [self->connection entryAtDN:dn attributes:nil];
+  if (entry == nil)
+    return nil;
+  
+  return [[entry ldif] dataUsingEncoding:NSUTF8StringEncoding];
+}
+
+/* modifications */
+
+- (NSDictionary *)_errDictForPath:(NSString *)_path toPath:(NSString *)_dest
+  dn:(NSString *)_dn reason:(NSString *)_reason
+{
+  id    keys[6];
+  id    values[6];
+  short count;
+
+  count = 0;
+  
+  if (_path) {
+    keys[count]   = @"Path";
+    values[count] = _path;
+    count++;
+  }
+  if (_dest) {
+    keys[count]   = @"ToPath";
+    values[count] = _dest;
+    count++;
+  }
+  if (_reason) {
+    keys[count]   = @"Error";
+    values[count] = _reason;
+    count++;
+  }
+  if (_dn) {
+    keys[count]   = @"dn";
+    values[count] = _dn;
+    count++;
+    keys[count]   = @"ldap";
+    values[count] = self->connection;
+    count++;
+  }
+  
+  return [NSDictionary dictionaryWithObjects:values forKeys:keys count:count];
+}
+
+- (BOOL)removeFileAtPath:(NSString *)_path handler:(id)_fhandler {
+  NSString *dn;
+  
+  [_fhandler fileManager:(id)self willProcessPath:_path];
+  
+  if ((dn = [self dnForPath:_path]) == nil) {
+    if (_fhandler) {
+      NSDictionary *errDict;
+      
+      errDict = [self _errDictForPath:_path toPath:nil dn:nil
+                      reason:@"couldn't map path to LDAP dn"];
+      
+      if ([_fhandler fileManager:(id)self shouldProceedAfterError:errDict])
+        return YES;
+    }
+    return NO;
+  }
+  
+  /* should delete sub-entries first ... */
+  
+  /* delete entry */
+  
+  if (![self->connection removeEntryWithDN:dn]) {
+    if (_fhandler) {
+      NSDictionary *errDict;
+      
+      errDict = [self _errDictForPath:_path toPath:nil dn:dn
+                      reason:@"couldn't remove LDAP entry"];
+      
+      if ([_fhandler fileManager:(id)self shouldProceedAfterError:errDict])
+        return YES;
+    }
+    return NO;
+  }
+  
+  return YES;
+}
+
+- (BOOL)copyPath:(NSString *)_path toPath:(NSString *)_destination
+  handler:(id)_fhandler
+{
+  NGLdapEntry *e;
+  NSString    *fromDN, *toDN, *toRDN;
+  
+  [_fhandler fileManager:(id)self willProcessPath:_path];
+  
+  if ((fromDN = [self dnForPath:_path]) == nil) {
+    if (_fhandler) {
+      NSDictionary *errDict;
+      
+      errDict = [self _errDictForPath:_path toPath:_destination dn:nil
+                      reason:@"couldn't map source path to LDAP dn"];
+      
+      if ([_fhandler fileManager:(id)self shouldProceedAfterError:errDict])
+        return YES;
+    }
+    return NO;
+  }
+
+  /*
+    split destination. 'toDN' is the target 'directory', 'toRDN' the name of
+    the target 'file'
+  */
+  toDN  = [self dnForPath:_destination];
+  toRDN = [toDN lastDNComponent];
+  toDN  = [toDN stringByDeletingLastDNComponent];
+  
+  if ((toDN == nil) || (toRDN == nil)) {
+    if (_fhandler) {
+      NSDictionary *errDict;
+      
+      errDict = [self _errDictForPath:_path toPath:_destination dn:fromDN
+                      reason:@"couldn't map destination path to LDAP dn"];
+      
+      if ([_fhandler fileManager:(id)self shouldProceedAfterError:errDict])
+        return YES;
+    }
+    return NO;
+  }
+
+  /* process record */
+  
+  if ((e = [self->connection entryAtDN:fromDN attributes:nil]) == nil) {
+    if (_fhandler) {
+      NSDictionary *errDict;
+      
+      errDict = [self _errDictForPath:_path toPath:_destination dn:fromDN
+                      reason:@"couldn't load source LDAP record"];
+      
+      if ([_fhandler fileManager:(id)self shouldProceedAfterError:errDict])
+        return YES;
+    }
+    return NO;
+  }
+  else {
+    /* create new record with the attributes of the old one */
+    NGLdapEntry *newe;
+    NSArray     *attrs;
+    
+    attrs = [[e attributes] allValues];
+    newe  = [[NGLdapEntry alloc] initWithDN:toDN attributes:attrs];
+    newe  = [newe autorelease];
+    
+    /* insert record in target space */
+    if (![self->connection addEntry:newe]) {
+      /* insert failed */
+
+      if (_fhandler) {
+        NSDictionary *errDict;
+        
+        errDict = [self _errDictForPath:_path toPath:_destination dn:toDN
+                        reason:@"couldn't insert LDAP record in target dn"];
+        
+        if ([_fhandler fileManager:(id)self shouldProceedAfterError:errDict])
+          return YES;
+      }
+      return NO;
+    }
+  }
+  
+  /* should process children ? */
+  
+  return YES;
+}
+
+- (BOOL)movePath:(NSString *)_path toPath:(NSString *)_destination 
+  handler:(id)_fhandler
+{
+  /* needs to invoke a modrdn operation */
+  [_fhandler fileManager:(id)self willProcessPath:_path];
+  
+  return NO;
+}
+
+- (BOOL)linkPath:(NSString *)_path toPath:(NSString *)_destination 
+  handler:(id)_fhandler
+{
+  /* LDAP doesn't support links .. */
+  [_fhandler fileManager:(id)self willProcessPath:_path];
+  
+  return NO;
+}
+
+- (BOOL)createFileAtPath:(NSString *)path
+  contents:(NSData *)contents
+  attributes:(NSDictionary *)attributes
+{
+  return NO;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->rootDN)
+    [ms appendFormat:@" root=%@", self->rootDN];
+  if (self->currentDN && ![self->currentDN isEqualToString:self->rootDN])
+    [ms appendFormat:@" cwd=%@", self->currentDN];
+  
+  if (self->connection)
+    [ms appendFormat:@" ldap=%@", self->connection];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* NGLdapFileManager */
+
+#include <NGLdap/NGLdapDataSource.h>
+#include <NGLdap/NGLdapGlobalID.h>
+
+@implementation NGLdapFileManager(ExtendedFileManager)
+
+/* feature check */
+
+- (BOOL)supportsVersioningAtPath:(NSString *)_path {
+  return NO;
+}
+- (BOOL)supportsLockingAtPath:(NSString *)_path {
+  return NO;
+}
+- (BOOL)supportsFolderDataSourceAtPath:(NSString *)_path {
+  return YES;
+}
+
+/* writing */
+
+- (BOOL)writeContents:(NSData *)_content atPath:(NSString *)_path {
+  /* should decode LDIF and store at path .. */
+  return NO;
+}
+
+/* datasources (work on folders) */
+
+- (EODataSource *)dataSourceAtPath:(NSString *)_path {
+  NGLdapDataSource *ds;
+  NSString *dn;
+  
+  if ((dn = [self dnForPath:_path]) == nil)
+    /* couldn't get DN for specified path .. */
+    return nil;
+  
+  ds = [[NGLdapDataSource alloc]
+                          initWithLdapConnection:self->connection
+                          searchBase:dn];
+  return [ds autorelease];
+}
+- (EODataSource *)dataSource {
+  return [self dataSourceAtPath:[self currentDirectoryPath]];
+}
+
+/* global-IDs */
+
+- (EOGlobalID *)globalIDForPath:(NSString *)_path {
+  NSString       *dn;
+  NGLdapGlobalID *gid;
+  
+  if ((dn = [self dnForPath:_path]) == nil)
+    return nil;
+  
+  gid = [[NGLdapGlobalID alloc]
+                         initWithHost:[self->connection hostName]
+                         port:[self->connection port]
+                         dn:dn];
+  return [gid autorelease];
+}
+
+- (NSString *)pathForGlobalID:(EOGlobalID *)_gid {
+  NGLdapGlobalID *gid;
+  
+  if (![_gid isKindOfClass:[NGLdapGlobalID class]])
+    return nil;
+
+  gid = (NGLdapGlobalID *)_gid;
+  
+  /* check whether host&port is correct */
+  if (![[self->connection hostName] isEqualToString:[gid host]])
+    return nil;
+  if (![self->connection port] == [gid port])
+    return nil;
+  
+  return [self pathForDN:[gid dn]];
+}
+
+/* trash */
+
+- (BOOL)supportsTrashFolderAtPath:(NSString *)_path {
+  return NO;
+}
+- (NSString *)trashFolderForPath:(NSString *)_path {
+  return nil;
+}
+
+@end /* NGLdapFileManager(ExtendedFileManager) */
diff --git a/skyrix-core/NGLdap/NGLdapGlobalID.h b/skyrix-core/NGLdap/NGLdapGlobalID.h
new file mode 100644 (file)
index 0000000..f972247
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdapGlobalID_H__
+#define __NGLdapGlobalID_H__
+
+#import <EOControl/EOGlobalID.h>
+
+@interface NGLdapGlobalID : EOGlobalID
+{
+  NSString *host;
+  int      port;
+  NSString *dn;
+}
+
+- (id)initWithHost:(NSString *)_host port:(int)_port dn:(NSString *)_dn;
+
+/* accessors */
+
+- (NSString *)host;
+- (NSString *)dn;
+- (int)port;
+
+@end
+
+#endif /* __NGLdapGlobalID_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapGlobalID.m b/skyrix-core/NGLdap/NGLdapGlobalID.m
new file mode 100644 (file)
index 0000000..fd730cb
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGLdapGlobalID.h"
+#include "NSString+DN.h"
+#import <EOControl/EOControl.h>
+#include "common.h"
+
+@implementation NGLdapGlobalID
+
+- (id)initWithHost:(NSString *)_host port:(int)_port dn:(NSString *)_dn {
+  self->host = [_host copy];
+  self->port = _port;
+  self->dn   = [[[_dn dnComponents] componentsJoinedByString:@","] copy];
+  return self;
+}
+
+- (void)dealloc {
+  [self->host release];
+  [self->dn   release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)host {
+  return self->host;
+}
+- (NSString *)dn {
+  return self->dn;
+}
+- (int)port {
+  return self->port;
+}
+
+/* equality */
+
+- (unsigned)hash {
+  return [self->dn hash] + [self->host hash];
+}
+
+- (BOOL)isEqual:(id)_other {
+  NGLdapGlobalID *ooid;
+  
+  if ([_other class] != [self class])
+    return NO;
+
+  ooid = _other;
+
+  if ((ooid->dn == self->dn) &&
+      (ooid->host == self->host) &&
+      (ooid->port == self->port))
+    return YES;
+
+  if (![ooid->dn isEqualToString:self->dn])
+    return NO;
+  if (ooid->port != self->port)
+    return NO;
+  if (![ooid->host isEqualToString:self->host])
+    return NO;
+
+  return YES;
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  return [NSString stringWithFormat:@"%@:%i/%@",
+                     self->host, self->port, self->dn];
+}
+
+- (NSString *)description {
+  NSMutableString *s;
+  NSString *d;
+  
+  s = [[NSMutableString alloc] init];
+  [s appendFormat:@"<0x%08X[%@]: ", self, NSStringFromClass([self class])];
+  [s appendFormat:@" host=%@", self->host];
+  [s appendFormat:@" port=%i", self->port];
+  [s appendFormat:@" dn=%@", self->dn];
+  [s appendString:@">"];
+
+  d = [s copy];
+  [s release];
+  return [d autorelease];
+}
+
+@end /* NGLdapGlobalID */
diff --git a/skyrix-core/NGLdap/NGLdapModification.h b/skyrix-core/NGLdap/NGLdapModification.h
new file mode 100644 (file)
index 0000000..2799855
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdapModification_H__
+#define __NGLdapModification_H__
+
+#import <Foundation/NSObject.h>
+
+@class NGLdapAttribute;
+
+#define NGLdapAddAttribute     1
+#define NGLdapDeleteAttribute  2
+#define NGLdapReplaceAttribute 3
+
+@interface NGLdapModification : NSObject
+{
+  int             operation;
+  NGLdapAttribute *attribute;
+}
+
++ (id)addModification:(NGLdapAttribute *)_attribute;
++ (id)replaceModification:(NGLdapAttribute *)_attribute;
++ (id)deleteModification:(NGLdapAttribute *)_attribute;
+- (id)initWithOperation:(int)_op attribute:(NGLdapAttribute *)_attribute;
+
+- (int)operation;
+- (NGLdapAttribute *)attribute;
+
+@end
+
+#endif /* __NGLdapModification_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapModification.m b/skyrix-core/NGLdap/NGLdapModification.m
new file mode 100644 (file)
index 0000000..a604cb4
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGLdapModification.h"
+#include "NGLdapAttribute.h"
+#include "common.h"
+
+@implementation NGLdapModification
+
++ (id)addModification:(NGLdapAttribute *)_attribute {
+  return [[[self alloc] initWithOperation:NGLdapAddAttribute
+                        attribute:_attribute] autorelease];
+}
++ (id)replaceModification:(NGLdapAttribute *)_attribute {
+  return [[[self alloc] initWithOperation:NGLdapReplaceAttribute
+                        attribute:_attribute] autorelease];
+}
++ (id)deleteModification:(NGLdapAttribute *)_attribute {
+  return [[[self alloc] initWithOperation:NGLdapDeleteAttribute
+                        attribute:_attribute] autorelease];
+}
+
+- (id)initWithOperation:(int)_op attribute:(NGLdapAttribute *)_attribute {
+  self->operation = _op;
+  self->attribute = [_attribute retain];
+  return self;
+}
+
+- (void)dealloc {
+  [self->attribute release];
+  [super dealloc];
+}
+
+- (int)operation {
+  return self->operation;
+}
+
+- (NGLdapAttribute *)attribute {
+  return self->attribute;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"%@ : self->attribute %@ operation %d",
+                   [super description], self->attribute, self->operation];
+}
+
+@end /* NGLdapModification */
diff --git a/skyrix-core/NGLdap/NGLdapSearchResultEnumerator.h b/skyrix-core/NGLdap/NGLdapSearchResultEnumerator.h
new file mode 100644 (file)
index 0000000..614b8ee
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdapSearchResultEnumerator_H__
+#define __NGLdapSearchResultEnumerator_H__
+
+#import <Foundation/NSEnumerator.h>
+#import <Foundation/NSDate.h>
+
+@class NGLdapConnection;
+
+@interface NGLdapSearchResultEnumerator : NSEnumerator
+{
+@public
+  NGLdapConnection *connection;
+  void             *handle;
+  int              msgid;
+  NSTimeInterval   timeout;
+  NSTimeInterval   startTime;
+  unsigned         index;
+}
+
+- (id)initWithConnection:(NGLdapConnection *)_con messageID:(int)_mid;
+
+- (int)messageID;
+- (NSTimeInterval)duration;
+- (unsigned)index;
+
+- (void)cancel;
+
+@end
+
+#endif /* __NGLdapSearchResultEnumerator_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapSearchResultEnumerator.m b/skyrix-core/NGLdap/NGLdapSearchResultEnumerator.m
new file mode 100644 (file)
index 0000000..fcc6046
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGLdapSearchResultEnumerator.h"
+#include "NGLdapConnection+Private.h"
+#include "NGLdapAttribute.h"
+#include "NGLdapEntry.h"
+#include "common.h"
+
+#include <sys/time.h>
+
+@implementation NGLdapSearchResultEnumerator
+
+- (id)initWithConnection:(NGLdapConnection *)_con messageID:(int)_mid {
+  self->connection = [_con retain];
+  self->handle     = [_con ldapHandle];
+  self->msgid      = _mid;
+  self->startTime  = [[NSDate date] timeIntervalSince1970];
+  return self;
+}
+
+- (void)dealloc {
+  [self->connection release];
+  [super dealloc];
+}
+
+/* state */
+
+- (int)messageID {
+  return self->msgid;
+}
+
+- (NSTimeInterval)duration {
+  return [[NSDate date] timeIntervalSince1970] - self->startTime;
+}
+
+- (unsigned)index {
+  return self->index;
+}
+
+/* enumerator */
+
+- (void)cancel {
+  if (self->handle) {
+    int res;
+    
+    res = ldap_abandon(self->handle, self->msgid);
+    
+    self->handle = NULL;
+    [self->connection release]; self->connection = nil;
+  }
+}
+
+- (NSArray *)_attributesFromResult:(LDAPMessage *)result {
+  NSMutableArray *attributes;
+  char           *attr;
+  BerElement     *ber;
+
+  attributes = [[NSMutableArray alloc] initWithCapacity:32];
+      
+  for (attr = ldap_first_attribute(self->handle, result, &ber);
+       attr != NULL;
+       free(attr), attr = ldap_next_attribute(self->handle, result, ber)) {
+    NSString        *key;
+    NGLdapAttribute *attribute;
+    struct berval   **values;
+    unsigned        valueCount;
+    NSArray         *ovalues;
+
+    if (!(key = [[NSString alloc] initWithCString:attr]))
+      /* missing attribute name */
+      continue;
+
+    /* process values */
+        
+    if ((values = ldap_get_values_len(self->handle, result, attr)) == NULL) {
+      ovalues = [[NSArray alloc] init];
+    }
+    else if ((valueCount = ldap_count_values_len(values)) == 1) {
+      NSData *value;
+          
+      value = [[NSData alloc] initWithBytes:values[0]->bv_val
+                              length:values[0]->bv_len];
+          
+      ovalues = [[NSArray alloc] initWithObjects:&value count:1];
+          
+      [value release];
+    }
+    else {
+      NSMutableArray *a;
+      int j;
+          
+      a = [[NSMutableArray alloc] initWithCapacity:valueCount];
+          
+      for (j = 0; values[j]; j++) {
+        NSData *data;
+
+        data = [[NSData alloc] initWithBytes:values[j]->bv_val
+                               length:values[j]->bv_len];
+        [a addObject:data];
+        [data release];
+      }
+      ovalues = [a copy];
+      [a release];
+    }
+
+    if (values) {
+      ldap_value_free_len(values);
+      values = NULL;
+    }
+        
+    /* create attribute */
+        
+    attribute =
+      [[NGLdapAttribute alloc] initWithAttributeName:key values:ovalues];
+        
+    [key     release]; key    = nil;
+    [ovalues release]; ovalues = nil;
+
+    [attributes addObject:attribute];
+    [attribute release];
+  }
+#if 0
+  if (first) {
+    ldap_memfree(first);
+  }
+#endif
+  if (ber) {
+    ber_free(ber, 0);
+  }
+  return attributes;
+}
+
+- (id)nextObject {
+  int            res;
+  struct timeval to;
+  struct timeval *top;
+  LDAPMessage *msg;
+  id          record;
+
+  if (self->handle == NULL)
+    return nil;
+
+  msg = NULL;
+  record = nil;
+
+  top = NULL;
+  if (self->timeout > 0) {
+    to.tv_sec = self->timeout;
+    to.tv_sec = (long)(self->timeout * 1000.0) - (to.tv_sec * 1000);
+    top = &to;
+  }
+
+  res = ldap_result(self->handle, self->msgid, 0, top, &msg);
+  
+  if (msg) {
+    switch(res) {
+#if defined(LDAP_RES_SEARCH_REFERENCE)
+      case LDAP_RES_SEARCH_REFERENCE: {
+        int         rres;
+        char        **rptr;
+        LDAPControl **ctrl;
+
+        rres = ldap_parse_reference(self->handle, msg, &rptr, &ctrl,
+                                    0 /* don't free msg */);
+        if (rres == LDAP_SUCCESS) {
+        }
+        else {
+          /* error */
+          NSLog(@"%s: couldn't parse result reference ..", __PRETTY_FUNCTION__);
+        }
+
+        NSLog(@"WARNING: doesn't support result references yet ..");
+        
+        if (rptr) ldap_value_free(rptr);
+        if (ctrl) ldap_controls_free(ctrl);
+        
+        break;
+      }
+#endif
+      
+      case LDAP_RES_SEARCH_ENTRY: {
+        int resultCount;
+        
+        if ((resultCount = ldap_count_entries(self->handle, msg)) == -1) {
+          /* failed */
+          int err;
+    
+          err = ldap_result2error(self->handle, msg, 1 /* free msg */);
+          
+          [[self->connection _exceptionForErrorCode:err
+                             operation:@"count-fetch"
+                             userInfo:nil]
+                             raise];
+          return nil;
+        }
+        else if (resultCount == 1) {
+          LDAPMessage *result;
+          NSString    *dn = nil;
+          char        *tmp;
+          NSArray     *attributes;
+          
+          if ((result = ldap_first_entry(self->handle, msg)) == NULL) {
+            /* could not get entry */
+            int err;
+            
+            err = ldap_result2error(self->handle, msg, 1 /* free msg */);
+            
+            [[self->connection _exceptionForErrorCode:resultCount
+                               operation:@"fetch"
+                               userInfo:nil]
+                               raise];
+            
+            return nil;
+          }
+    
+          /* get distinguished name */
+          
+          if ((tmp = ldap_get_dn(self->handle, result))) {
+            NS_DURING {
+              dn = [[[NSString alloc] initWithUTF8String:tmp] autorelease];
+            }
+            NS_HANDLER {
+              fprintf(stderr, "Got exception %s while NSUTF8StringEncoding, "
+                      "use defaultCStringEncoding",
+                      [[localException description] cString]);
+              dn = nil;
+            }
+            NS_ENDHANDLER;
+
+            if (dn == nil)
+              dn = [[[NSString alloc] initWithCString:tmp] autorelease];
+
+            free(tmp);
+          }
+          /* get all attributes */
+          
+          attributes = [self _attributesFromResult:result];
+
+          if (result) {
+            // TODO: ldap_msgfree(result); // do not release result-msg ???
+            result = NULL;
+          }
+          
+          record = [[NGLdapEntry alloc] initWithDN:dn attributes:attributes];
+          
+          [attributes release]; attributes = nil;
+        }
+        else if (resultCount == 0) {
+          /* no more results */
+          record = nil;
+        }
+        break;
+      }
+
+      case LDAP_RES_SEARCH_RESULT:
+        self->handle = NULL;
+        [self->connection release]; self->connection = nil;
+        break;
+
+      default:
+        NSLog(@"unexpected msg-code: %X", res);
+        break;
+    }
+    if (msg)
+      ldap_msgfree(msg);
+  }
+  
+  if (record)
+    self->index++;
+
+  return [record autorelease];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+
+  s = [NSMutableString stringWithCapacity:100];
+  [s appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  [s appendFormat:@" msgid=%i", [self messageID]];
+  [s appendFormat:@" duration=%.2fs", [self duration]];
+  [s appendFormat:@" index=%i", [self index]];
+  
+  [s appendString:@">"];
+
+  return s;
+}
+
+@end /* LDAPResultEnumerator */
diff --git a/skyrix-core/NGLdap/NGLdapURL.h b/skyrix-core/NGLdap/NGLdapURL.h
new file mode 100644 (file)
index 0000000..8072c6d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdapURL_H__
+#define __NGLdapURL_H__
+
+#import <Foundation/NSObject.h> // required by gstep-base
+#import <Foundation/NSURL.h>
+
+@class NSString, NSArray, NSHost, NSEnumerator;
+@class NGLdapConnection, NGLdapEntry;
+
+// ldap://hostport/dn[?attributes[?scope[?filter]]]
+
+@interface NGLdapURL : NSURL < NSCopying >
+{
+  NSString *host;
+  int      port;
+  NSString *base;
+  int      scope;
+  NSString *filter;
+  NSArray  *attributes;
+}
+
++ (id)ldapURLWithString:(NSString *)_url;
+- (id)initWithString:(NSString *)_url; // designated initializer
+
+/* accessors */
+
+- (NSString *)hostName;
+- (NSHost *)host;
+
+- (int)port;
+- (NSString *)baseDN;
+- (int)scope;
+- (NSString *)searchFilter;
+- (NSArray *)attributes;
+
+/* query */
+
+- (NGLdapConnection *)openConnection;
+- (NSEnumerator *)fetchEntries;
+- (NGLdapEntry *)fetchEntry;
+
+/* url */
+
+- (NSString *)urlString;
+
+@end
+
+#endif /* __NGLdapURL_H__ */
diff --git a/skyrix-core/NGLdap/NGLdapURL.m b/skyrix-core/NGLdap/NGLdapURL.m
new file mode 100644 (file)
index 0000000..4652110
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGLdapURL.h"
+#include "NGLdapConnection.h"
+#include "NGLdapEntry.h"
+#include "EOQualifier+LDAP.h"
+#include "common.h"
+
+static inline BOOL isUrlAlpha(unsigned char _c) {
+  return
+    (((_c >= 'a') && (_c <= 'z')) ||
+     ((_c >= 'A') && (_c <= 'Z')))
+    ? YES : NO;
+}
+static inline BOOL isUrlDigit(unsigned char _c) {
+  return ((_c >= '0') && (_c <= '9')) ? YES : NO;
+}
+static inline BOOL isUrlSafeChar(unsigned char _c) {
+  switch (_c) {
+    case '$': case '-': case '_': case '@':
+    case '.': case '&': case '+':
+      return YES;
+
+    default:
+      return NO;
+  }
+}
+static inline BOOL isUrlExtraChar(unsigned char _c) {
+  switch (_c) {
+    case '!': case '*': case '"': case '\'':
+    case '|': case ',':
+      return YES;
+  }
+  return NO;
+}
+static inline BOOL isUrlEscapeChar(unsigned char _c) {
+  return (_c == '%') ? YES : NO;
+}
+static inline BOOL isUrlReservedChar(unsigned char _c) {
+  switch (_c) {
+    case '=': case ';': case '/':
+    case '#': case '?': case ':':
+    case ' ':
+      return YES;
+  }
+  return NO;
+}
+
+static inline BOOL isUrlXalpha(unsigned char _c) {
+  if (isUrlAlpha(_c))      return YES;
+  if (isUrlDigit(_c))      return YES;
+  if (isUrlSafeChar(_c))   return YES;
+  if (isUrlExtraChar(_c))  return YES;
+  if (isUrlEscapeChar(_c)) return YES;
+  return NO;
+}
+
+static inline BOOL isUrlHexChar(unsigned char _c) {
+  if (isUrlDigit(_c))
+    return YES;
+  if ((_c >= 'a') && (_c <= 'f'))
+    return YES;
+  if ((_c >= 'A') && (_c <= 'F'))
+    return YES;
+  return NO;
+}
+
+static inline BOOL isUrlAlphaNum(unsigned char _c) {
+  return (isUrlAlpha(_c) || isUrlDigit(_c)) ? YES : NO;
+}
+
+static inline BOOL isToBeEscaped(unsigned char _c) {
+  return (isUrlAlphaNum(_c) || (_c == '_')) ? NO : YES;
+}
+
+static BOOL NGContainsUrlInvalidCharacters(const unsigned char *_buffer) {
+  while (*_buffer) {
+    if (isToBeEscaped(*_buffer))
+      return YES;
+    _buffer++;
+  }
+  return NO;
+}
+static void NGEscapeUrlBuffer
+(const unsigned char *_source, unsigned char *_dest) {
+  register const unsigned char *src = (void*)_source;
+  while (*src) {
+    //if (*src == ' ') { // a ' ' becomes a '+'
+    //  *_dest = '+'; _dest++;
+    //}
+    if (!isToBeEscaped(*src)) {
+      *_dest = *src;
+      _dest++;
+    } 
+    else { // any other char is escaped ..
+      *_dest = '%'; _dest++;
+      sprintf(_dest, "%02X", (unsigned)*src);
+      _dest += 2;
+    }
+    src++;
+  }
+  *_dest = '\0';
+}
+static NSString *NGEscapeUrlString(NSString *_source) {
+  unsigned len;
+  char     *cstr;
+  NSString *s;
+
+  if ((len = [_source cStringLength]) == 0)
+    return _source;
+
+  cstr = malloc(len + 1);
+  [_source getCString:cstr];
+  cstr[len] = '\0';
+  
+  if (NGContainsUrlInvalidCharacters(cstr)) { // needs to be escaped ?
+    char *buffer = NULL;
+    
+    buffer = NGMallocAtomic([_source cStringLength] * 3 + 2);
+    NGEscapeUrlBuffer(cstr, buffer);
+    
+    s = [[[NSString alloc]
+                    initWithCStringNoCopy:buffer
+                    length:strlen(buffer)
+                    freeWhenDone:YES] autorelease];
+  }
+  else
+    s = [[_source copy] autorelease];
+  
+  free(cstr);
+  return s;
+}
+
+@implementation NGLdapURL
+
++ (id)ldapURLWithString:(NSString *)_url {
+  if (!ldap_is_ldap_url((char *)[_url UTF8String]))
+    return nil;
+
+  return [[[self alloc] initWithString:_url] autorelease];
+}
+
+- (id)initWithString:(NSString *)_url {
+  LDAPURLDesc *urld = NULL;
+  unsigned attrCount, i;
+  int err;
+
+  self->scope = -1;
+
+  if ((err = ldap_url_parse((char *)[_url UTF8String], &urld)) != 0) {
+    [self release];
+    return nil;
+  }
+  if (urld == NULL) {
+    [self release];
+    return nil;
+  }
+    
+  self->host   = [[NSString alloc] initWithCString:urld->lud_host];
+  self->port   = urld->lud_port;
+  self->base   = [[NSString alloc] initWithCString:urld->lud_dn];
+  self->scope  = urld->lud_scope;
+  self->filter = [[NSString alloc] initWithCString:urld->lud_filter];
+  
+  if (urld != NULL && urld->lud_attrs != NULL) {
+    register char *tmp, **a;
+    a = urld->lud_attrs;
+    for (i = 0; (tmp = a[i]); i++)
+      ;
+    attrCount = i;
+  }
+  else
+    attrCount = 0;
+    
+  if (attrCount > 0) {
+    id *attrs;
+
+    attrs = calloc(attrCount+1, sizeof(id));
+    
+    for (i = 0; i < attrCount; i++)
+      attrs[i] = [[NSString alloc] initWithCString:urld->lud_attrs[i]];
+      
+    self->attributes = [[NSArray alloc] initWithObjects:attrs count:attrCount];
+
+    for (i = 0; i < attrCount; i++)
+      [attrs[i] release];
+    if (attrs) free(attrs);
+  }
+  
+  if (urld) ldap_free_urldesc(urld);
+  
+  return self;
+}
+
+- (id)init {
+  return [self initWithString:nil];
+}
+
+- (void)dealloc {
+  [self->host       release];
+  [self->base       release];
+  [self->filter     release];
+  [self->attributes release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)hostName {
+  return self->host;
+}
+- (NSHost *)host {
+  return [NSHost hostWithName:[self hostName]];
+}
+
+- (int)port {
+  return self->port;
+}
+- (NSString *)baseDN {
+  return self->base;
+}
+- (int)scope {
+  return self->scope;
+}
+
+- (NSString *)searchFilter {
+  return self->filter;
+}
+- (EOQualifier *)searchFilterQualifier {
+  EOQualifier *q;
+  
+  if (self->filter == nil)
+    return nil;
+
+  q = nil;
+  q = [[EOQualifier alloc] initWithLDAPFilterString:self->filter];
+
+  return [q autorelease];
+}
+
+- (NSArray *)attributes {
+  return self->attributes;
+}
+
+/* perform fetches */
+
+- (NGLdapConnection *)openConnection {
+  NGLdapConnection *con;
+
+  con = [[NGLdapConnection alloc] initWithHostName:[self hostName]
+                                  port:[self port] ? [self port] : 389];
+  return [con autorelease];
+}
+
+- (NSEnumerator *)fetchEntries {
+  NGLdapConnection *con;
+
+  if ((con = [self openConnection]) == nil)
+    return nil;
+  
+  switch (self->scope) {
+    case LDAP_SCOPE_ONELEVEL:
+      return [con flatSearchAtBaseDN:[self baseDN]
+                  qualifier:[self searchFilterQualifier]
+                  attributes:[self attributes]];
+      
+    case LDAP_SCOPE_SUBTREE:
+      return [con deepSearchAtBaseDN:[self baseDN]
+                  qualifier:[self searchFilterQualifier]
+                  attributes:[self attributes]];
+      
+    case LDAP_SCOPE_BASE:
+      return [con baseSearchAtBaseDN:[self baseDN]
+                  qualifier:[self searchFilterQualifier]
+                  attributes:[self attributes]];
+  }
+
+  return nil;
+}
+- (NGLdapEntry *)fetchEntry {
+  return [[self fetchEntries] nextObject];
+}
+
+/* url */
+
+- (NSString *)urlString {
+  NSMutableString *s;
+  NSString *is;
+
+  s = [[NSMutableString alloc] initWithCapacity:200];
+
+  [s appendString:@"ldap://"];
+  [s appendString:self->host ? self->host : @"localhost"];
+  if (self->port > 0) [s appendFormat:@":%i", self->port];
+
+  [s appendString:@"/"];
+  is = self->base;
+  is = NGEscapeUrlString(is);
+  [s appendString:is];
+  
+  if ((self->attributes != nil) || (self->scope != -1) || (self->filter != nil)){
+    [s appendString:@"?"];
+    is = [self->attributes componentsJoinedByString:@","];
+    is = NGEscapeUrlString(is);
+    [s appendString:is];
+  }
+  if ((self->scope != -1) || (self->filter != nil)) {
+    [s appendString:@"?"];
+    switch (self->scope) {
+      case LDAP_SCOPE_ONELEVEL:
+        [s appendString:@"one"];
+        break;
+      case LDAP_SCOPE_SUBTREE:
+        [s appendString:@"sub"];
+        break;
+      case LDAP_SCOPE_BASE:
+      default:
+        [s appendString:@"base"];
+        break;
+    }
+  }
+  if (self->filter) {
+    [s appendString:@"?"];
+    is = self->filter;
+    is = NGEscapeUrlString(is);
+    [s appendString:is];
+  }
+
+  is = [s copy];
+  [s release];
+  return [is autorelease];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[[self class] allocWithZone:_zone] initWithString:[self urlString]];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [self urlString];
+}
+
+@end /* NGLdapURL */
diff --git a/skyrix-core/NGLdap/NSString+DN.h b/skyrix-core/NGLdap/NSString+DN.h
new file mode 100644 (file)
index 0000000..8a16fd2
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NSString_DN_H__
+#define __NSString_DN_H__
+
+#import <Foundation/NSString.h>
+
+@class NSArray, NSDate;
+
+@interface NSString(DNSupport)
+
++ (NSString *)dnWithComponents:(NSArray *)_components;
+
+- (NSArray *)dnComponents;
+
+- (NSString *)stringByAppendingDNComponent:(NSString *)_component;
+- (NSString *)stringByDeletingLastDNComponent;
+- (NSString *)lastDNComponent;
+
+- (const char *)ldapRepresentation;
+
+- (NSDate *)ldapTimestamp;
+
+@end
+
+#endif /* __NSString_DN_H__ */
diff --git a/skyrix-core/NGLdap/NSString+DN.m b/skyrix-core/NGLdap/NSString+DN.m
new file mode 100644 (file)
index 0000000..516c922
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSString+DN.h"
+#include "common.h"
+
+static NSString *dnSeparator = @",";
+
+static NSString *_stripSpaces(NSString *s) {
+  NSString *result = nil;
+  char     *cstr, *tmp;
+  unsigned len, clen;
+  
+  if ([s rangeOfString:@" "].length == 0)
+    return s;
+  
+  len = [s cStringLength];
+  cstr = malloc(len + 1);
+  [s getCString:cstr];
+
+  tmp  = cstr;
+  clen = len;
+
+  /* strip leading spaces */
+  while ((*tmp == ' ') && (*tmp != '\0')) {
+    tmp++;
+    clen--;
+  }
+
+  /* strip trailing spaces */
+  while (clen > 0) {
+    if (tmp[clen - 1] != ' ')
+      break;
+    clen--;
+  }
+  tmp[clen] = '\0';
+  
+  result = [NSString stringWithCString:tmp length:clen];
+  if (cstr)
+    free(cstr);
+  return result;
+}
+
+static NSArray *cleanDNComponents(NSArray *_components) {
+  unsigned i, count;
+  id *cs;
+  
+  count = [_components count];
+  
+  if (count == 0)
+    return nil;
+  
+  cs = calloc(count, sizeof(id));
+  for (i = 0; i < count; i++) {
+    NSString *rdn;
+    
+    rdn = [_components objectAtIndex:i];
+    cs[i] = _stripSpaces(rdn);
+  }
+  _components = [NSArray arrayWithObjects:cs count:count];
+  if (cs) free(cs);
+
+  return _components;
+}
+
+@implementation NSString(DNSupport)
+
++ (NSString *)dnWithComponents:(NSArray *)_components {
+  return [cleanDNComponents(_components) componentsJoinedByString:dnSeparator];
+}
+
+- (NSArray *)dnComponents {
+  return cleanDNComponents([self componentsSeparatedByString:dnSeparator]);
+}
+
+- (NSString *)stringByAppendingDNComponent:(NSString *)_component {
+  NSString *s;
+
+  s = _stripSpaces(self);
+  if ([s length] == 0)
+    return _component;
+
+  s = [dnSeparator stringByAppendingString:self];
+  return [_component stringByAppendingString:s];
+}
+
+- (NSString *)stringByDeletingLastDNComponent {
+  NSRange r;
+  
+  r = [self rangeOfString:dnSeparator];
+  if (r.length == 0) return nil;
+  
+  return _stripSpaces([self substringFromIndex:(r.location + r.length)]);
+}
+
+- (NSString *)lastDNComponent {
+  NSRange r;
+  
+  r = [self rangeOfString:dnSeparator];
+  if (r.length == 0) return nil;
+  
+  return _stripSpaces([self substringToIndex:r.location]);
+}
+
+- (const char *)ldapRepresentation {
+  return [self UTF8String];
+}
+
+- (NSDate *)ldapTimestamp {
+  /* eg: '20000403055250Z' */
+  unsigned   len;
+  short      year, month, day, hour, minute, second;
+  NSString   *tzname;
+  NSTimeZone *tz;
+  
+  if ((len = [self length]) == 0)
+    return nil;
+
+  if (len < 14)
+    return nil;
+  
+  year   = [[self substringWithRange:NSMakeRange(0,  4)] intValue];
+  month  = [[self substringWithRange:NSMakeRange(4,  2)] intValue];
+  day    = [[self substringWithRange:NSMakeRange(6,  2)] intValue];
+  hour   = [[self substringWithRange:NSMakeRange(8,  2)] intValue];
+  minute = [[self substringWithRange:NSMakeRange(10, 2)] intValue];
+  second = [[self substringWithRange:NSMakeRange(12, 2)] intValue];
+
+  /* timezone ??? */
+  tzname = @"GMT";
+  tz = [NSTimeZone timeZoneWithAbbreviation:tzname];
+
+  return [NSCalendarDate dateWithYear:year month:month
+                         day:day hour:hour minute:minute second:second
+                         timeZone:tz];
+}
+
+@end /* NSString(DNSupport) */
diff --git a/skyrix-core/NGLdap/README b/skyrix-core/NGLdap/README
new file mode 100644 (file)
index 0000000..3c08dde
--- /dev/null
@@ -0,0 +1,21 @@
+# $Id$
+
+NGLdap
+======
+
+NGLdap is a thin wrapper library around the libldap C client library for
+LDAP directory servers.
+
+Examples
+========
+
+  ldapls
+  ldap2dsml
+
+Defaults
+========
+
+  LDAPDebugEnabled       - debug mode, log operations
+  LDAPLoginAttributeName - the name of the attribute which stores login
+                           names for password checks (default: uid)
+
diff --git a/skyrix-core/NGLdap/README.macosx b/skyrix-core/NGLdap/README.macosx
new file mode 100644 (file)
index 0000000..87ad6ed
--- /dev/null
@@ -0,0 +1,28 @@
+# $Id$
+
+NOTE: Jaguar (MacOSX 10.2) comes with OpenLDAP client libraries :-), so
+      the instructions below are deprecated
+
+OpenLDAP 2.1 --without-slurpd --without-slapd funkt ohne Probleme ...
+
+==========================
+- get openldap
+
+---snip---
+ld: common symbols not allowed with MH_DYLIB output format
+ld: common symbols not allowed with MH_DYLIB output format
+/usr/local/openldap/lib/libldap.a(open.o) definition of common _ldap_debug (size 4)
+/usr/local/openldap/lib/libldap.a(init.o) definition of common _openldap_ldap_global_options (size 24)
+/usr/local/openldap/lib/liblber.a(decode.o) definition of common _lber_debug (size 4)
+/usr/bin/libtool: internal link edit command failed
+---snap---
+
+openldap 2.0.7
+CC=cc -traditional-cpp
+
+./configure --prefix=/usr/local --disable-slapd --disable-slurpd --disable-threads --disable-tls --disable-readline --disable-kerberos --disable-sasl
+make depend
+
+... delete .._r stuff ...
+
+make install
diff --git a/skyrix-core/NGLdap/Version b/skyrix-core/NGLdap/Version
new file mode 100644 (file)
index 0000000..33dfbe1
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=17
diff --git a/skyrix-core/NGLdap/common.h b/skyrix-core/NGLdap/common.h
new file mode 100644 (file)
index 0000000..64c72c4
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGLdap_common_H__
+#define __NGLdap_common_H__
+
+#if USE_OWN_LIBLDAP
+#  include <sys/types.h>
+#  include <ldap/lber.h>
+#  include <ldap/ldap.h>
+#else
+#  include <lber.h>
+#  include <ldap.h>
+#endif
+
+#import <Foundation/Foundation.h>
+
+#include <NGExtensions/NGExtensions.h>
+#include <NGExtensions/NGFileFolderInfoDataSource.h>
+
+#endif /* __NGLdap_common_H__ */
diff --git a/skyrix-core/NGMime/.cvsignore b/skyrix-core/NGMime/.cvsignore
new file mode 100644 (file)
index 0000000..49a10b1
--- /dev/null
@@ -0,0 +1,2 @@
+shared_debug_obj
+shared_obj
diff --git a/skyrix-core/NGMime/COPYING b/skyrix-core/NGMime/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-core/NGMime/COPYRIGHT b/skyrix-core/NGMime/COPYRIGHT
new file mode 100644 (file)
index 0000000..8e76449
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2004 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-core/NGMime/ChangeLog b/skyrix-core/NGMime/ChangeLog
new file mode 100644 (file)
index 0000000..0fb3251
--- /dev/null
@@ -0,0 +1,1244 @@
+2004-08-02  Frank Reppin  <frank@opengroupware.org>
+
+       * NGMimeRFC822DateHeaderFieldParser.m: fixed OGo Bug #861 (August 
+         mails were reported as April mails) (v4.2.171)
+
+2004-07-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.170
+
+       * NGMimeHeaderFieldParser.h: fixed prototypes of 
+         NGMimeHeaderFieldParser protocol
+
+       * NGMimeFileData.m, NGMail: fixed a gcc 3.4 warning
+
+2004-07-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4: fixed OGo bug #840 (introduced in v4.2.166), code cleanups,
+         fixed some gcc 3.4 warnings (v4.2.169)
+
+2004-07-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4: fixed some compilation issue with older gcc's (v4.2.168)
+
+       * NGImap4: minor improvements to exception handling (v4.2.167)
+
+       * NGImap4: some changes to body response parser which might fix OGo
+         bug 800, some speed improvements in the fetch response normalizer
+         (v4.2.166)
+
+       * NGImap4: added more logging output (v4.2.165)
+
+2004-06-21  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4: fixed a gstep-base warning (v4.2.164)
+
+2004-06-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.163
+
+       * NGImap4/NGImap4Message.m: minor optimization
+
+       * NGMimeAddressHeaderFieldGenerator.m, NGMimeBodyParser.m, 
+         NGMimeHeaderFields.m, NGMimeMultipartBodyParser.m,
+         NGMimePartParser.m, NGMimeUtilities.m: minor cleanups to default
+         processing
+
+       * NGMimeFileData.m, NGMimeBodyGenerator.m: per default generate 
+         temporary files in /tmp/OGo/ instead of /tmp/Skyrix/
+
+2004-06-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4: fixed some gcc 3.4 warnings (v4.2.162)
+
+2004-06-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMail: fixed some gcc 3.4 warnings (v4.2.161)
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGMail: minor tweaks (v4.2.160)
+
+       * GNUmakefile.preamble: added prebinding (v4.2.159)
+
+2004-05-16  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4: various cleanups (v4.2.158)
+
+       * NGMimeAddressHeaderFieldGenerator.m, NGMimeBodyGenerator.m, 
+         NGMimeContentDispositionHeaderFieldGenerator.m,
+         NGMimeContentTypeHeaderFieldGenerator.m, NGMimeMultipartBodyParser.m,
+         NGMimePartParser.m: various code cleanups (v4.2.157)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.156)
+
+2004-04-19  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * NGMimeRFC822DateHeaderFieldParser.m: ported RFC822 timezone parser
+         to gnustep-base and Apple's Foundation. Using abbreviations for
+         timezone names turned out to be non-portable across foundations.
+         Also enhanced the range of GMT timezones understood - this is now
+         from GMT-1400 until GMT+1200 (v4.2.155)
+
+2004-04-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4: some code cleanups, fixed OGo bug #660 (premature dealloc)
+         (v4.2.154)
+
+2004-03-19  Helge Hess  <helge.hess@skyrix.com>
+       
+       * v4.2.153
+       
+       * NGMimeRFC822DateHeaderFieldParser.m: improved RFC822 timezone parser
+         to deal with timezone strings as submitted by MultiMail (-05-500)
+       
+       * NGConcreteMimeType.m: detect x-avg-checked MIME type parameter
+
+2004-02-17  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4: fixed OGo bug #582 (mail searching was broken) (v4.2.152)
+
+2004-02-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4, NGMail: fixed compilation warnings on OSX (v4.2.151)
+
+2004-02-08  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.150
+
+       * NGMail/NGMimeMessageGenerator.m: expose _base64Encoding function
+
+       * NGMail/GNUmakefile, NGMail/NGMimeMessageGenerator.m: moved body 
+         generator subclass to separate source files
+       
+       * GNUmakefile, NGMimeHeaderFieldGenerator.m: moved out field generator
+         subclasses to own source files
+       
+       * NGMimeHeaderFieldGenerator.h: export NGEncodeQuotedPrintableMime
+         function (should be a NSString category?!)
+
+2004-01-24  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * NGImap4: various improvements, parsing optimization (v4.2.149)
+
+       * NGMimeRFC822DateHeaderFieldParser.m: improved performance, see
+         NGImap4 ChangeLog for details (v4.2.146)
+       
+2004-01-22  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4: cleanups, fixed OGo bug #537 (v4.2.145)
+
+2004-01-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4: cleanups, cleanups, cleanups (v4.2.144)
+
+2004-01-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4: cleaned up API (v4.2.143)
+
+2004-01-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4Message: optimization (v4.2.142)
+
+2004-01-19  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4: various optimizations and cleanups (see NGImap4 ChangeLog
+         for details) (v4.2.141)
+
+2004-01-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * added global-id classes in NGImap4 (v4.2.140)
+
+2004-01-12  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.139
+       
+       * NGMimeRFC822DateHeaderFieldParser.m: optimized date parsing - 
+         additional optimizations lined out
+       
+       * NGMimeHeaderFieldParser.m: moved the various parser classes to 
+         separate files (maybe should be moved to a subproject in the long 
+         run), minor code cleanups
+       
+       * NGMimePartParser.m: cache defaultRfc822HeaderFieldParserSet for speed
+       
+       * NGImap4: major cleanups, see NGImap4/ChangeLog for details
+
+2004-01-11  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.138
+
+       * NGImap4: major cleanups
+
+       * NGImap4: renamed common.h to imCommon.h, fixed other files to include
+         that (v4.2.137)
+
+Tue Nov 11 15:04:18 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4ResponseParser.m: add parsing of capability entries without 
+         value (v4.2.136)
+
+2003-11-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.135
+
+       * NGMime.m: use some defaults for the NGMime version in case we are
+         not compiling using gstep-make
+
+       * NGImap4ResponseParser.m: explicitly marked the lastChar variable as
+         being a signed char to avoid compiler errors
+
+Thu Nov  6 16:41:13 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.134
+
+       * NGSieveClient: fixed a bug in normalizeResponse, return 
+         NSMutableDictionary
+
+       * NGImap4ResponseParser.m: remove CYRUS_2_0 constant, don`t now
+         what it should be :(
+
+Mon Nov  3 15:42:37 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Context: temporary set selected folder befor the select action
+         to prevent notification confusions (v4.2.133)
+
+2003-10-17  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4: small code cleanups to Sieve client (v4.2.132)
+
+2003-10-12  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile.preamble: added libEOControl as a dependency
+         (required on MacOSX) (v4.2.131)
+
+2003-09-06  Helge Hess  <helge.hess@skyrix.com>
+       
+       * removed various dependencies to FoundationExt (v4.2.130)
+
+       * various fixes to remove warnings on MacOSX (v4.2.129)
+
+Tue Jul 22 15:19:34 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4ResponseParser.m: check for empty quota reponses 
+         (v4.2.128)
+
+2003-07-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4: fixed some gstep-base issues, patch provided by 
+         Filip Van Raemdonck and cleaned up a bit (v4.2.127)
+
+Thu Jul 17 10:37:22 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4ServerRoot: add a missing method 
+         (bulkFetchHeadersFor:inRange:withAllUnread:) (v4.2.126)
+
+Fri Jun 27 18:08:49 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4Message.m: improve flag handling (v4.2.124)
+
+       * NGImap4Message.m: code cleanups (v4.2.123)
+
+Thu Jun 26 13:23:30 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * v.4.2.122
+       
+       * NGImap4Message.m: add messageWithURL: methods
+
+       * NGImap4Context.m: execute select-command before setting selectet folder
+
+       * NGImap4Folder: add a struct do store failed select, status, getQuota 
+         responses, set selectet folder after successfully select response
+
+Fri Jun 20 18:51:24 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * v4.2.121
+
+       * NGImap4Client.m: cleanups
+
+       * NGImap4ServerRoot, NGImap4Folder.m, NGImap4Functions: 
+         fetch status (new/unseen) of subfolders on demand only if Default: 
+         FetchNewUnseenMessagesInSubFoldersOnDemand = 'YES'
+
+       * NGImap4ServerRoot, NGImap4Folder.m: improve folder-flag analysing, 
+         nonexistent folders will be ignored (Default: ShowNonExistentFolder), 
+          no 'list' request for folder  with hasnochildren flag 
+         (Default: IgnoreHasNoChildrenFlag) (v4.2.120)
+
+       * 4.2.119
+       
+       * NGImap4Functions: cleanups
+
+       * NGImap4Context.m: cleanups
+
+       * NGImap4Folder.m: only reset subfolders if -resetSubFolders called 
+         (prev. behavior: -resetFolder called -resetSubFolders), cleanups
+
+Tue Jun 17 11:53:46 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap/NGImap4Message+BodyStructure.h: check whether parsing of 
+         date headerfield failed (v4.2.118)
+
+Fri Jun 13 17:37:37 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeType.m: add charset 'unknown' (use us-ascii) (v4.2.117)
+
+Wed Jun 11 14:49:05 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * v4.2.116
+       
+       * NGMimeMultipartBodyParser.m: improve multipart-body parsing behavior 
+         (parse bodies with no content)
+       
+       * NGMimeType.m: use ASCII string encoding for "x-unknown" encoding type
+       
+       * NGMimePartParser: add unknown-8bit content-transfer encoding
+
+       * v4.2.115
+       
+       * NGMimePartParser.m, NGMimeMultipartBodyParser.m: code cleanups
+       
+       * NGConcreteMimeType: added "x-unix-mode" as a known text mime-type 
+         parameter
+
+       * NGMimePartParser: add 'binary' content transfer encoding (v4.2.114)
+       
+       * v4.2.113
+       
+       * NGMail/NGMimeMessageParser: use unicode, use named encoding to 
+         encode header fields (if default 
+         'UseFoundationStringEncodingForMimeHeader' = YES, libFoundation 
+         string encoding will be used)
+       
+       * NGMimeUtilities: add parseParameters() (parse the same kind of 
+         parameter for NGMimeType and NGMimeContentDispositionType), use 
+         unicode
+       
+       * NGMimeType.m: use unicode, parse parameters in NGMimeUtilities
+       
+       * NGMimeHeaderFields.m: use unicode, parse parameters in 
+         NGMimeUtilities 
+       
+       * NGMimeHeaderFieldParser.m: code cleanups, add default whether to 
+         strip leading spaces or not (StripLeadingSpaces), use unicode for
+         content-type, content-disposition and string type header-fields,
+         wrap some comments with MimeLogEnabled, some speed optimization, 
+       
+       * NGMimePartParser.m: ignore leading white spaces for header values 
+         (speed optimization)
+       
+       * NGMimeHeaderFieldParser.m: use unicode to remove comments, improve 
+         comment parsing behavior, strip leading spaces only if 
+         default 'StripLeadingSpaces' is set (currently be done during 
+         header-field parsing for speed optimization)
+       
+       * NGMimeBodyParser.m: use named encoding (currently iconv) to encode
+         text bodies, (if default 'UseFoundationStringEncodingForMimeText' 
+         is set, libFoundation string encoding will be used)
+
+2003-06-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGConcreteMimeType.m: added support for 'delsp' attribute (delete
+         space ?) on text/... mime-types (v4.2.113)
+
+Mo Jun 02 15:55:20 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4Folder, NGImap4Functions: add notification for 
+         subfolder-resets (v4.2.112)
+
+2003-05-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * fixed a linking bug in NGImap4 (due to a ignored warning ...)
+         (v4.2.111)
+
+Tue May 27 17:39:20 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4Folder.m: check for quota only if folder is selectable 
+         (v4.2.110)
+
+Tue May 20 18:03:12 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4Context; add accessor to set edit default values (v4.2.108)
+
+Wed May 14 12:54:08 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * v4.2.107
+       
+       * NGMimeType.m: code cleanups, hide some logs behind 'MimeLogEnabled'
+       
+       * NGMimeMessageParser.m: code cleanups, fix a decode quoted printable 
+         bug (sometimes last char was ignored) 
+
+       * v4.2.106
+       
+       * NGImap4ResponseParser.m: use lowercase string to determine whether
+         fetch body reponse is 'text' or 'message' (courier imap use lowercase
+         letters for the body description) (bug 1611)
+       
+       * Info: move rfc, drafts and other information files to 'Info'
+
+Thu May 13 17:59:25 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4Folder.m: add notification for folder reset, if more than one
+         folder for the same folderpath exist (v4.2.105) (bug 1612)
+
+Fri May  9 10:35:42 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * media-types: add (v4.2.104)
+
+Mon May  5 17:59:25 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4Folder.m: improve error log, fix a bug regarding multiple 
+         mail copy from and to the same folder (v4.2.103)
+
+Wed Apr 30 15:24:26 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * v4.2.102
+       
+       * NGMimeHeaderFieldParser.m: add some time zone format fields (bug 943)
+       
+       * NGImap4ServerRoot: noinferiors depends on serverkind (bug 932)
+       
+       * NGImap4ResponseParser.m: improve parsing of server greeting 
+       
+       * NGImap4Folder, NGImap4ServerRoot: take ShowOnlySubscribedIn* 
+         from context
+       
+       * NGImap4Context.m: set ShowOnlySubscribedIn* Defaults 
+         (depends on server)
+       
+       * NGImap4Client.m: detect washington imap server
+
+       * v4.2.101
+       
+       * NGImap4ServerRoot: fixed retain bug
+       
+       * NGImap4Folder.m: NSLog -> logWithFormat, fixed release (bug 1559),
+       
+       * NGImap4Context: accessors for server defaults
+       
+       * NGImap4Client.m: code cleanups, some logs depends LogDefault,
+         try to get server name (cyrus, courier) - set some server-depending
+         Defaults, fixed special folder subscribe/create behavior (bug 1540)
+
+Thu Apr 17 11:13:44 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeFileData.m: fixed bug which occurs during hh cleanups 
+         (self->path = [path copy] --> self->path = [_path copy] (v4.2.100)
+
+Fri Apr 11 10:59:45 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * v4.2.99
+       
+       * NGImap4Functions.m: add ImapLogEnabled' default
+         bind some logs to ImapLogEnabled'
+       
+       * NGMimeType.m: create MimeLogEnabled'
+         'WARNING(%s): expected end of string or' - occurs only if 
+         MimeLogEnabled (bug 1430)
+
+2003-04-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.98
+
+       * various fixed of new gcc 3.3 warnings in all modules
+       
+       * NGMimeType.m: fixed gcc 3.3 signed/unsigned warnings
+
+       * NGMimeFileData.m: small cleanups, signed-warnings
+
+       * NGMail: fixed more gcc 3.3 signed/unsigned warnings (v4.2.97)
+       
+       * v4.2.96
+
+       * NGMail: some gcc 3.3 signed/unsigned warnings fixed
+
+       * NGMimeUtilities.h: some gcc 3.3 signed/unsigned warnings fixed
+
+       * NGImap4: small speed improvements
+
+Mon Apr  7 20:02:29 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * v4.2.95
+       
+       * NGImap4Message.m: check whether encoding was set -> set encoding 
+         during body-structure fetch
+       
+       * NGImap4Message+BodyStructure.h: body-structuree component is no 
+         rfc822 or multipart --> body url got  'part=1'
+
+2003-04-01  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4: added compilation support for GNUstep base (v4.2.94)
+
+Fri Feb 28 18:32:53 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4/NGImap4Functions.m: add support for Washington Imap Server, 
+         (delete folders in server root) (v4.2.93)
+
+Wed Feb 26 17:47:53 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * v4.2.92
+       
+       * NGImap/NGImap4ServerRoot.m: read also inbox folder if it
+         is not subscribed
+       
+       * NGImap/NGImap4Client.m: check whether no sequence contains 'ALERT', 
+         reconnect also if the server repsonse an unexpecte 'bye' sequence
+
+       * (Changes for Washington Imap Server support)
+       
+       * NGImap/NGImap4Client.m: remove NXConstStr in Excep. Handler (v4.2.91)
+
+       * NGMimePartParser.h: add headers (v4.2.90)
+
+Wed Feb 26 11:37:18 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap/NGImap4Client.m: check whether so key exist, 
+         use DATE as default sort key (v4.2.89)
+
+Tue Feb 25 11:21:52 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap/NGImap4Client.m: fixed a reconnect bug (try only one time, 
+         before return with exception) (bug 1108) (v4.2.88)
+
+Mon Feb 24 15:48:07 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4/NGImap4Message.m: select folder befor fetch 
+          body structure (bug 1094) (v4.2.87)
+
+Mon Feb 17 18:19:06 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * v4.2.86 (fixed bug 1064)
+       
+       * NGMimeBodyParser: remove NGMimeRfc822BodyParser
+       
+       * NGMimePartParser.m: remove call to NGMimeRfc822BodyParser
+       
+       * NGMimeMessageParser: add NGMimeRfc822BodyParser, 
+         add delegate method bodyParserForPart: to call the 
+         NGMimeRfc822BodyParser 
+
+Fri Feb 14 16:16:47 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4Context.m: code cleanups (v4.2.85)
+
+Wed Feb  5 14:43:22 2003    <jan@skyrix.com>
+
+       * NGMimePartParser.m: check whether la (called to buffer data) 
+         failed with EndOfStream (bug 993) (v4.2.84)
+
+Fri Jan 31 17:05:55 2003    <jan@skyrix.com>
+
+       * NGImap4Context.m: add defaults for imap special folders, 
+         fix folder create bug (v4.2.83)
+
+       * NGImap4Folder.m: fetch all messages if no sort failed or no 
+         sortordering was given (v4.2.82)
+
+       * NGImap4: fix parsing structure bug, code cleanups (v4.2.81)
+
+Wed Jan 29 22:12:08 2003    <jan@skyrix.com>
+
+       * NGImap4*: code cleanups (replace macros with method calls),
+         catch all exceptions, now they are stored in [context lastException]
+         remove connection retry (v4.2.80)
+       
+2003-01-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeFileData.m: fixed required includes (v4.2.79)
+
+Tue Jan 28 15:39:25 2003    <jan@skyrix.com>
+
+       * NGImap4: courier support (v4.2.78)
+
+       * NGImap4: remove abort() (v4.2.77)
+
+       * v4.2.76
+       
+       * NGMimePartGenerator: generator handles now tmp-file creation
+       
+       * NGMimeGeneratorProtocols.h: add missing methods
+       
+       * NGMimeFileData.m: add Data init methods, use default to generate 
+         file-data (NGMimeBuildMimeTempDirectory)
+
+       * v4.2.75
+       
+       * NGMimeJoinedData: code cleanups, write file with 0600
+       
+       * NGMimeFileData: code cleanups
+
+       * NGMimeFileData: code cleanup (v4.2.74)
+
+Mon Jan 27 19:08:28 2003    <jan@skyrix.com>
+
+       * v4.2.73
+       
+       * NGMimeJoinedData: a mutable date wrapper to join date objects 
+         without merging them in memory
+       
+       * NGMimeFileData: a data object to store the date content on disk
+       
+       * NGMime*Generator: build mime parts on disk
+
+Wed Jan 22 17:26:17 2003    <jan@skyrix.com>
+
+       * NGMimeBodyGenerator.m: add configurable boundary prefix
+
+2003-01-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeMultipartBodyParser.m: use incremental version (v4.2.72)
+
+Tue Jan 21 19:05:30 2003    <jan@skyrix.com>
+       
+       * NGImap4: add additional Courier imapd support (v4.2.71)
+       
+       * v4.2.70
+       
+       * NGImap4: increase class version number of NGMimeMessageParser
+       
+       * NGMimePartParser: if parsePartFromData got immutable data, 
+         parsing will be based on data bytes, increase version, 
+         add instance vars
+       
+       * NGMimeMultipartBodyParser.m: code cleanups 
+       
+Mon Jan 20 19:00:14 2003    <jan@skyrix.com>
+       
+       * NGMimePartGenerator.m: fixed wrong release handling (v4.2.69)
+       
+2003-01-20  Helge Hess  <helge.hess@skyrix.com>
+       
+       * NGConcreteMimeType.m: added support for vCalendar "method" parameters
+         in text/* MIME types, replaced some RELEASE macros (v4.2.68)
+       
+       * replaced some RETAIN macros (v4.2.67)
+       
+Fri Jan 17 13:49:17 2003    <jan@skyrix.com>
+       
+       * NGImap4: fix variable placing (v4.2.66)
+
+Thu Jan 16 18:36:54 2003    <jan@skyrix.com>
+
+       * v4.2.65
+
+       * NGImap4: decode headers values fur bodystructures
+
+       * NGMimePartParser: add +defaultHeaderFieldEncoding
+
+Tue Jan 14 16:57:28 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4: improve body structure parsing
+       
+       * NGMimeType.m: allow all chars for parameter-values,
+         use constant strings for some types, subtypes, parameternames
+         (v4.2.64)
+
+2003-01-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeType.m: added "koi-r" as an unsupported, but known encoding
+         (v4.2.62)
+       
+Tue Jan 14 12:24:44 2003    <jan@skyrix.com>
+
+       * NGImap4: improve error handling, handle unexpected BYE response
+         (v4.2.61)
+       
+       * NGImap: fix parsing of cyrus version bug (skyrix bug 845) (v4.2.60)
+
+Mon Jan 13 19:42:47 2003    <jan@skyrix.com>
+
+       * v4.2.59
+       
+       * NGMimePartParser: add fix header field names
+
+       * NGImap4, NGPart.m, NGMimeHeaderFieldParser.m,
+         NGMimeHeaderFieldGenerator.m, NGMimeBodyPart.m: use header field 
+         name constants
+
+2003-01-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGPart.h: added some docu to header
+
+Fri Jan 10 09:54:14 2003    <jan@skyrix.com>
+
+       * NGImap4: fixed skyrix bug 822, improve error handling (v4.2.58)
+
+Wed Jan  9 15:26:00 2003    <jan@skyrix.com>
+
+       * NGImap4: improve parsing to handle over quota warnings
+         fix skyrix bug 777 (v4.2.57)
+
+Wed Jan  8 16:26:00 2003    <jan@skyrix.com>
+
+       * NGImap4: fix skyrix bug 835 (fix quota bugs) (v4.2.56)
+
+Tue Jan  7 16:47:36 2003    <jan@skyrix.com>
+
+       * NGImap4: fix skyrix bug 821 (add -usedSpace and -maxQuota to 
+         NGImap4Folder protocol and NGImap4ServerRoot) (v4.2.55)
+
+2003-01-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * changes for improved compilation on MacOSX, replaced RETAIN macros
+         with methods (v4.2.54)
+
+Fri Dec 27 10:53:50 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * smaller clean ups (v4.2.53)
+
+Mon Dec 23 15:39:33 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4: small cleanups (v4.2.52)
+
+2002-12-17  Helge Hess  <helge.hess@skyrix.com>
+
+       * cosmetic change, replaced 'THROW' with 'raise'
+
+       * NGMimeType.m: added big5, 'iso-2022-jp' and 'gb2312' as unsupported,
+         but known encodings (SuSE Bug 16780) (v4.2.51)
+
+Tue Dec 10 19:12:45 2002    <jan@skyrix.com>
+
+       * NGImap4: add quota support
+
+2002-12-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4: fixed a compilation warning (v4.2.49)
+       
+       * fixed Jan's version numbers
+
+Tue Dec 10 19:12:45 2002    <jan@skyrix.com>
+
+       * NGImap4ResponseParser.m: throw concrete exception  (Bug 651)
+       
+       * NGImap4Folder.m, NGImap4ServerRoot: Default for display sub-folders 
+       
+       * NGImap4Client.m: fixed debug release-bug (v4.2.48)
+
+       * NGImap4ResponseParser.m: fix parse bug
+       
+       * NGImap4Message+BodyStructure.h: fix header handling (v4.2.47)
+       
+Mon Dec  9 13:55:52 2002    <jan@skyrix.com>
+
+       * NGImap4Context.m, NGImap4Client.*, NGImap4ResponseParser: add 
+         capability support (v4.2.46)
+
+Fri Dec  6 17:08:28 2002    <jan@skyrix.com>
+
+       * NGImap4Folder (v4.2.45)
+       
+       * NGImap4Message: add some ss-sorting improvements
+       
+Tue Dec  3 16:45:14 2002    <jan@skyrix.com>
+
+       * NGImap4ResponseParser.m: parse empty string if message does 
+         'no longer exists' (v4.2.44)
+
+Mon Dec  2 19:22:13 2002  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4Context.m: performance improvements (v4.2.43)
+       * NGImap4Folder.m: -(BUG 17379) clear msn->uid cache after delete
+                          -performance
+
+Mon Dec  2 11:18:51 2002    <jan@skyrix.com>
+
+       * NGImap4Folder.m: only reset subfolder if they are already loaded (v4.2.42)
+
+Fri Nov 29 18:12:32 2002    <jan@skyrix.com>
+
+       * NGMimePartParser.m: improve error log (v4.2.41)
+       * NGMail/NGMimeMessageParser.m: fixed quoted printable parsing bug
+
+Fri Nov 29 12:27:25 2002    <jan@skyrix.com>
+
+       * NGImap4ResponseParser.m: check tagged responses before parsing 
+         it(v4.2.40)
+       
+Mon Nov 25 16:29:40 2002  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4Context.m, NGImap4Folder: add msn-uid cache (v4.2.39)
+       * NGImap4Folder.m: if no next mail, return nil (v4.2.38)
+* NGImap4Client.m: check whether sort keys are valid (v4.2.36)
+       * NGImap4ResponseParser.m: fixed content parsing
+
+Fri Nov 22 15:04:18 2002    <jan@skyrix.com>
+
+       * NGImap4Message*: add support for body-structure content(v4.2.35)
+
+Fri Nov 22 11:13:40 2002    <jan@skyrix.com>
+
+       * NGImap4ResponseParser.m: add Imap4MMDataBoundary Default to 
+       modify MM-Data-Use boundary (v4.2.34)
+
+Tue Nov 21 18:13:38 2002    <jan@skyrix.com>
+       
+       * NGImap4*: memory mapped data (v4.2.33)
+       * NGImap4*: add fetch bodystructure/single part bodies (v4.2.32)
+
+2002-11-20  Helge Hess  <helge.hess@skyrix.com>
+       
+       * NGImap4: can query headers using KVC (4.2.31)
+       
+       * NGImap4: smaller changes in URL initialization (v4.2.30)
+
+Tue Nov 19 18:13:38 2002    <jan@skyrix.com>
+
+       * NGImap4*: add commands (thread, fetch body) (v4.2.29)
+
+Mon Nov 11 10:24:14 2002  Jan Reichmann  <jan@skyrix.com>
+
+       * NGImap4Client.m: improve greetings parse behavior (v4.2.29)
+
+2002-11-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4: initialize objects with URL and SSL support (v4.2.28)
+
+Wed Oct 30 16:26:46 2002  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimePartParser.m retain/autorelease values to prevent 
+       RELEASE Exceptions (v4.2.27)
+
+2002-09-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.25
+
+       * NGMimeHeaderFieldGenerator.m: fixed some compilation warnings
+
+2002-08-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeHeaderFieldGenerator.m: small fix for Jaguar compilation
+
+Tue Aug 20 18:33:00 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMimeHeaderFieldGenerator.m: add default for LF seperated address 
+       entries (v4.2.22) (BUG 17551)
+
+2002-08-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeType.m: added windows-1252, iso-8859-2 as known charset strings
+         (v4.2.20)
+
+- 2002-07-23 v4.2.19 (hh)
+- 2002-07-17 v4.2.18 (jr)
+- 2002-07-17 v4.2.17 (hh)
+- 2002-07-10 v4.2.16 (hh)
+- 2002-07-09 v4.2.15 (hh)
+- 2002-07-09 v4.2.14 (hh)
+- 2002-07-08 v4.2.13 (hh)
+- 2002-07-08 v4.2.12 (hh)
+
+2002-07-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeType.m: added some charset encoding strings (8859-1, 
+         ks_c_5601-1987, euc-kr)
+
+       * NGConcreteMimeType.m: do not print a warning if a "x-mac-" MIME type
+         parameter was found ...
+
+Tue Jul  9 12:39:12 2002  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMime.m: add libraryVersion method
+
+2002-07-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed fix for -valueOfHeaderField:data:, since this breaks
+         SKYRiXgreen => later
+
+2002-07-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimePartParser.m: immediatly close the datastream after parsing,
+         so that the NSData object associated with the stream is guaranteed
+         to be released (this lessens the possibility for a new variant of
+         "The Big Master Bug")
+
+       * NGMimeUtilities.h (_rfc2047Decoding): small optimization, if the
+         data is base64 encoded, immediatly release the temporary NSData
+         object used to call -dataByDecodingBase64:
+
+       * NGMimeType.m: added a class method to turn charset strings into
+         a Foundation NSStringEncoding constants 
+         (eg utf-8 => NSUTF8StringEncoding)
+
+       * NGMimePartParser.m: cache the mutable data object used during parsing
+         to avoid memory fragmentation and to improve speed
+
+       * NGMimeBodyParser.m: moved multipart body parser to it's own file
+
+       * NGMimePartParser.m ([NGMimePartParser -valueOfHeaderField:data:):
+         fixed behaviour of method when a delegate is set. Previously if
+         the delegate returned nil, the parser would invoke it's own
+         header field parsing (while the doc says, that if the delegate
+         implements the method, it's *completly* responsible ...)
+         SEE ABOVE, fix removed
+       
+       * major source code cleanup to support hunting the bug known as
+         "The Big Master Bug" (BMB, SuSE bug 16845)
+
+Fri Jun 28 17:27:16 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMimeBodyGenerator.m: remove log
+       * NGMimeHeaderFieldParser.m: add DateFormat
+
+Fri Jun 28 16:58:15 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMimeBodyParser.m: compares charset caseInsensitive now
+
+Fri Jun 26 10:40:05 2002  Helge Hess <hh@skyrix.com>
+
+       * various fixes for MacOSX
+
+- 2002-06-13 v4.2.11 (jr) [extracted from CVS]
+- 2002-06-11 v4.2.10 (jr) [extracted from CVS]
+- 2002-06-10 v4.2.9  (jr) [extracted from CVS]
+- 2002-06-10 v4.2.8  (jr) [extracted from CVS]
+- 2002-06-09 v4.2.7  (jr) [extracted from CVS]
+- 2002-06-09 v4.2.6  (jr) [extracted from CVS]
+- 2002-06-07 v4.2.5  (jr) [extracted from CVS]
+
+Fri Jun  7 17:11:05 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMime*: add better encoding handling
+
+- 2002-06-04 v4.2.4  (jr) [extracted from CVS]
+
+Tue Jun  4 17:47:30 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMimeHeaderFieldParser.m: fixed euro handling
+
+Fri May 31 16:13:56 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMimeHeaderFieldGenerator.m: add NGMimeAddressHeaderFieldGenerator,
+         encoding of filenames
+
+- 2002-05-22 v4.2.3  (jr) [extracted from CVS]
+
+Wed May 15 13:23:03 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NGMail, NGImap4 subprojects
+
+Mon May  6 22:28:21 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeHeaderFieldGenerator.m: fixed a problem with GroupWise (a space
+         was generated before a MIME-type parameter value)
+
+Thu Mar  7 12:24:41 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMimeBodyGenerator.m: fixed assertion bug
+
+Thu Feb 21 13:03:52 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimePartParser.m: changed to support -lastException
+
+Thu Feb 14 11:27:06 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMimeHeaderFields.m: supports now ill microsoft content-disposition type
+
+Tue Dec 18 16:58:11 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGConcreteMimeType.m ([NGConcreteTextMimeType -initWithType:subType:parameters:]): 
+         parse "q" quality parameter
+
+Tue Dec 18 11:37:15 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeBodyParser.m: added iso-8859-1 as a known charset
+
+Tue Dec 11 09:53:03 2001  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMimeHeaderFieldGenerator.m: fixed string value bug
+       * NGMimeHeaderFieldParser.m: add date format
+
+Fri Dec  7 15:17:54 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeBodyGenerator.m: fixed bug with content-type
+
+Mon Oct 22 19:00:59 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimePartParser.m ([NGMimePartParser -parserForBodyOfPart:data:]): 
+         use TextParser only for text/plain bodies
+
+Mon Oct 22 10:12:45 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeHeaderFieldGenerator.m: changed to deal with string-header
+         fields and replaced various -cString calls with -dataUsingEncoding:
+
+Tue Oct 16 19:21:15 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeType.m: check for empty mime-type strings ...
+
+Tue Oct 16 18:59:39 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeHeaderFieldGenerator.m: fixed static-var init bug
+
+Fri Oct 12 10:36:53 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimePartParser.m ([NGMimePartParser -parserForBodyOfPart:data:]):
+         trim spaces of header-field values ...
+
+Thu Aug  9 14:21:45 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed java.mail related stuff
+
+Thu Aug  9 13:22:35 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeFileDataSource.m: use -initWithPath:, no use of NGFileUrl
+
+Fri Jul 20 15:48:36 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGConcreteMimeType.m: allow parameters in wildcard MIME type
+
+Fri Apr  6 14:51:41 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimePartGenerator.m: fixed Autorelease/Release bug
+
+Wed Mar 28 17:55:21 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeHeaderFieldParser.m: add new date formats
+
+Tue Feb  6 17:08:04 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimePartParser.m: fixed delegate message bug
+
+Mon Jan 29 16:27:23 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeBodyParser.m, NGMimePartGenerator.m, NGMimePartParser.m: fixed 
+       header encoding bug
+
+Mon Dec  4 12:19:19 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGMimePartParser.m: changed to support empty HTTP headers (might break
+         some email parsing ??)
+
+       * NGMimePartParser.m: dynamically allocate parse buffer, added class
+         caching
+
+Fri Jun 23 14:24:36 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * reverted changes from Jun-21
+
+Fri Jun 23 12:21:32 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGMimeHeaderFieldParser.m: fixed stmt ordering bug
+
+Wed Jun 21 23:39:23 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * removed stack-buffer allocations in various methods
+
+Tue Jun 13 19:33:31 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGMimeHeaderFields.m: do not use stack-allocated buffers
+
+Fri Jun  9 17:50:00 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * GNUmakefile (ADDITIONAL_CPPFLAGS): added -Wall
+
+Tue Feb 29 18:24:39 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * MOF3 import
+
+2000-02-17    <helge.hess@mdlink.de>
+
+       * NGMimeHeaderFieldGenerator.m, NGMimeType, NGMimePartParser, NGMimeHeaderFields:
+         removed cString stuff
+
+Wed Jan 26 11:11:23 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeHeaderFieldParser.m: NGMimeRFC822DateHeaderFieldParser returns now
+       a y2k date
+
+Mon Oct 25 15:07:36 1999  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGConcreteMimeType.m: fixed bug in NGConcreteTextMimeType, fixed bugs
+         in -stringValue of multipart-types
+
+Wed Oct  6 14:19:57 1999  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGConcreteMimeType.m: added support for 'format' parameter in 
+         text/* types
+
+Mon Oct  4 10:23:32 1999  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGMimePartParser.m: lowercase content-transfer-encoding, to catch both,
+         7bit and 7BIT and 7Bit ...
+
+Fri Oct  1 18:53:43 1999  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGMimeHeaderFieldParser.m: added various date formats to Rfc822 date
+         header scanner
+
+       * NGMimePartParser.m: added '8bit' as a known content-transfer-encoding
+
+Thu Sep  2 21:04:32 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * added class versions and superclass version checks
+
+Mon Jul 12 22:36:45 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGMimePartGenerator.m: fixed bug (collection was modified while an
+         enumerator was in use ..)
+
+Fri Jun 18 19:28:52 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGMimePartParser.m: filter out and apply content-transfer-encoding
+
+Tue Jun 15 11:22:29 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * removed quoted printable encoding from string header field parser
+
+       * NGMimePartParser.m: lowercase MIME header field names on-the-fly
+
+Tue Jun 15 07:57:20 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeHeaderFieldGenerator.m: insert parsing of date-field and 
+         quoted-printable encoding 
+       * NGMimeHeaderFieldParser.m : insert generating from NSDate date-field
+
+Tue Jun  1 16:48:38 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeBodyGenerator.m: fixed bug (add generated boundary to multipart)
+
+Wed May 26 11:01:48 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeBodyGenerator.m fixed nil-body bug
+
+Fri May  7 20:42:53 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * add -stringValue to NGMimeHeaderFields
+
+Tue May  4 16:16:47 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * added MIME generator classes
+
+Tue May  4 11:43:39 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeBodyPartParser.m: fixed remove-comments bug
+
+Tue May  4 11:30:53 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGMimeBodyParser.m: added NGMimeRfc822BodyParser class
+
+       * NGMimePartParser.m: added new delegate method to apply content
+         transfer encoding like stuff on MIME bodies.
+
+Thu Apr 22 18:58:02 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * renamed NGMimeParser to NGMimePartParser
+
+Tue Apr 20 18:27:44 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeParser.m: fixed content-length LA-bug
+
+Tue Apr 20 11:01:27 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeBodyParser.m: end-of-line chars needn`t to be on end of 
+       boundary
+       
+       body can be less than 2 * boundary (remove assert)
+       if start- or end-boundary wasn`t found the left over data were append 
+       to the multipart
+
+       * NGMimeParser.m : check whether content-type, content-length, 
+       subject are already in headers
+
+       * NGMimeType.m : fixed len bug
+
+Mon Apr 19 08:55:42 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeParser.m: add delegate for use of content-length-field
+       fixed read content-length bug
+
+Fri Apr 16 19:52:46 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGMimeParser.m: improved content-length parsing
+
+Fri Apr 16 18:48:35 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGMimeParser.m: rewritten to support MIME mails
+
+Fri Apr 16 12:33:46 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGMimeType.m, NGConcreteMimeType.[hm]: added 'name' parameter to
+         text type and added x-vcard type
+
+       * NGMimeType.m: make MIME type names and parameters lowercase
+
+       * NGMimeBodyParser.m: added support for different EOL sequences
+
+       * NGMimeParser.m: added delegates to parse a body of a part or to
+         select a body parser for a body of a part.
+
+       * NGConcreteMimeType.m: fixed bug, message/rfc822 is not a composite
+         type
+
+Mon Apr 12 16:28:47 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * use #include instead of #import, made headers #include safe
+
+Mon Mar 29 11:39:45 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * added kit class NGMime
+
+       * separate MIME parsers for messages and general MIME.
+
+Mon Jan 18 20:17:19 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGConcreteMimeType.m: fixed bug in NSConcreteTextMimeType
+         -parametersAsDictionary method
+
+Sat Jan  9 21:09:29 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGMimeParser.m: new 'foundEOF' variable
+
+Tue Dec 15 17:56:40 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGConcreteMimeType.m: fixed -isEqual: of NGConcreteGenericMimeType
+
+Fri Nov 27 14:50:03 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * started WIN32 support
+
+Thu Nov  5 12:25:22 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * added NGMimeHeaderFields.[hm] with NGMimeContentDispositionHeaderField
+       class in it.
+
+       * NGMimeHeaderFieldParser.m: added NGMimeContentDispositionHeaderFieldParser
+       class
+
+       * added NGMimeBodyPart for parts contained in multiparts
+
+       * made NSData/NSMutableData a NGMimePart
+
+       * added NGMimeMultipartBody class
+
+Wed Nov  4 21:07:48 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGMimeType.m: bugfix in wildcard-type creation
+
+       * NGConcreteMimeType.m: bugfix in wildcard matching
+
+       * NGMimeBodyParser.m: added NGMimeMultipartBodyParser for parsing
+       multipart bodies.
+
+Wed Nov  4 18:49:22 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * added NGMimeBodyPartParser for parsing the entities in multipart-bodies.
+
+       * NGConcreteMimeType.m: added fast concrete implementations of
+       comparison methods
+
+       * NGMimeType.m: added advanced type-comparison/matching methods
+
+       * Added new protocol and class NGMimeBodyParser responsible for parsing
+       raw body data provided by the NGMimeParser.
+
+1998-10-09  Helge Hess  <helge@trex.mdlink.de>
+
+       * created ChangeLog
+
diff --git a/skyrix-core/NGMime/GNUmakefile b/skyrix-core/NGMime/GNUmakefile
new file mode 100644 (file)
index 0000000..523290d
--- /dev/null
@@ -0,0 +1,88 @@
+# $Id$
+
+include ../common.make
+
+GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT)
+
+LIBRARY_NAME = libNGMime
+
+libNGMime_DLL_DEF                  = libNGMime.def
+libNGMime_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+libNGMime_HEADER_FILES_DIR         = .
+libNGMime_HEADER_FILES_INSTALL_DIR = /NGMime
+
+libNGMime_HEADER_FILES = \
+       NGMimeDecls.h                   \
+       NGMime.h                        \
+       \
+       NGConcreteMimeType.h            \
+       NGMimeBodyGenerator.h           \
+       NGMimeBodyParser.h              \
+       NGMimeBodyPart.h                \
+       NGMimeBodyPartParser.h          \
+       NGMimeExceptions.h              \
+       NGMimeGeneratorProtocols.h      \
+       NGMimeHeaderFieldGenerator.h    \
+       NGMimeHeaderFieldParser.h       \
+       NGMimeHeaderFields.h            \
+       NGMimeMultipartBody.h           \
+       NGMimePartGenerator.h           \
+       NGMimePartParser.h              \
+       NGMimeType.h                    \
+       NGMimeUtilities.h               \
+       NGPart.h                        \
+       NGMimeFileData.h                \
+       NGMimeJoinedData.h              \
+
+libNGMime_OBJC_FILES = \
+       NGMime.m                        \
+       \
+       NGConcreteMimeType.m            \
+       NGMimeBodyGenerator.m           \
+       NGMimeBodyParser.m              \
+       NGMimeBodyPart.m                \
+       NGMimeBodyPartParser.m          \
+       NGMimeExceptions.m              \
+       NGMimeHeaderFieldGenerator.m    \
+       NGMimeHeaderFieldParser.m       \
+       NGMimeHeaderFields.m            \
+       NGMimeMultipartBody.m           \
+       NGMimeMultipartBodyParser.m     \
+       NGMimePartGenerator.m           \
+       NGMimePartParser.m              \
+       NGMimeType.m                    \
+       NGPart.m                        \
+       NGMimeFileData.m                \
+       NGMimeJoinedData.m              \
+       NGMimeUtilities.m               \
+       \
+       NGMimeContentDispositionHeaderFieldParser.m     \
+       NGMimeContentLengthHeaderFieldParser.m          \
+       NGMimeContentTypeHeaderFieldParser.m            \
+       NGMimeHeaderFieldParserSet.m                    \
+       NGMimeRFC822DateHeaderFieldParser.m             \
+       NGMimeStringHeaderFieldParser.m                 \
+       NSCalendarDate+RFC822.m                         \
+       \
+       NGMimeAddressHeaderFieldGenerator.m             \
+       NGMimeContentDispositionHeaderFieldGenerator.m  \
+       NGMimeContentLengthHeaderFieldGenerator.m       \
+       NGMimeContentTypeHeaderFieldGenerator.m         \
+       NGMimeHeaderFieldGeneratorSet.m                 \
+       NGMimeRFC822DateHeaderFieldGenerator.m          \
+       NGMimeStringHeaderFieldGenerator.m              \
+
+libNGMime_SUBPROJECTS = NGMail NGImap4
+
+ADDITIONAL_CPPFLAGS += -DLIBRARY_MAJOR_VERSION=${MAJOR_VERSION} \
+                      -DLIBRARY_MINOR_VERSION=${MINOR_VERSION} \
+                      -DLIBRARY_SUBMINOR_VERSION=${SUBMINOR_VERSION} \
+
+autodoc :
+       autodoc $(AUTODOC_FLAGS) -dest ../Documentation/NGMime/ -proj .
+       autodoc $(AUTODOC_FLAGS) -dest ../Documentation/NGMail/ -proj ./NGMail/
+       autodoc $(AUTODOC_FLAGS) -dest ../Documentation/NGImap4/ -proj ./NGImap4/
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/NGMime/GNUmakefile.preamble b/skyrix-core/NGMime/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..9efd299
--- /dev/null
@@ -0,0 +1,45 @@
+# $Id$
+
+ADDITIONAL_CPPFLAGS += -Wall
+
+libNGMime_LIBRARIES_DEPEND_UPON += \
+       -lNGStreams -lNGExtensions -lEOControl  \
+       -lDOM -lSaxObjC
+
+libNGMime_INCLUDE_DIRS += \
+       -I.. -I../NGStreams -I../NGExtensions
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+libNGMime_LIB_DIRS += \
+       -L$(RELBUILD_DIR_SxCore)/NGStreams/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+       -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)             \
+       -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+libNGMime_LIB_DIRS += \
+       -L../NGStreams/$(GNUSTEP_OBJ_DIR)       \
+       -L../NGExtensions/$(GNUSTEP_OBJ_DIR)    \
+       -L../EOControl/$(GNUSTEP_OBJ_DIR)
+endif
+
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libNGMime_PREBIND_ADDR="0xC1A00000"
+libNGMime_LDFLAGS += -seg1addr $(libNGMime_PREBIND_ADDR)
+endif
+
+# Windows
+
+ifeq ($(GNUSTEP_TARGET_OS),mingw32)
+libNGMime_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
+
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+libNGMime_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
diff --git a/skyrix-core/NGMime/NGConcreteMimeType.h b/skyrix-core/NGMime/NGConcreteMimeType.h
new file mode 100644 (file)
index 0000000..cc28347
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGConcreteMimeType_H__
+#define __NGMime_NGConcreteMimeType_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMime/NGMimeType.h>
+
+@class NSString, NSDictionary;
+
+@interface NGParameterMimeType : NGMimeType
+{
+@protected
+  NSString     *subType;
+  NSDictionary *parameters;
+}
+
+- (id)initWithType:(NSString *)_type subType:(NSString *)_subType
+  parameters:(NSDictionary *)_parameters;
+
+@end
+
+/*
+  The "text" media type is intended for sending material which is principally
+  textual in form. A "charset" parameter may be used to indicate the character
+  set of the body text for "text" subtypes, notably including the subtype
+  "text/plain", which is a generic subtype for plain text. Plain text does not
+  provide for or allow formatting commands, font attribute specifications,
+  processing instructions, interpretation directives, or content markup. Plain
+  text is seen simply as a linear sequence of characters, possibly interrupted by
+  line breaks or page breaks. Plain text may allow the stacking of several
+  characters in the same position in the text. Plain text in scripts like Arabic
+  and Hebrew may also include facilitites that allow the arbitrary mixing of text
+  segments with opposite writing directions. 
+
+  Beyond plain text, there are many formats for representing what might be known
+  as "rich text". An interesting characteristic of many such representations is
+  that they are to some extent readable even without the software that interprets
+  them. It is useful, then, to distinguish them, at the highest level, from such
+  unreadable data as images, audio, or text represented in an unreadable form. In
+  the absence of appropriate interpretation software, it is reasonable to show
+  subtypes of "text" to the user, while it is not reasonable to do so with most
+  nontextual data. Such formatted textual data should be represented using
+  subtypes of "text".
+
+
+  The format parameter is described in:
+
+    http://www.ietf.org/internet-drafts/draft-gellens-format-06.txt
+*/
+@interface NGConcreteTextMimeType : NGMimeType
+{
+@protected
+  NSString *subType;
+  NSString *charset;
+  NSString *name;   // used in vcards
+  NSString *format;
+  NSString *method; // used in iCalendars (method=REQUEST)
+  BOOL     delsp;
+  float    quality;
+}
+
+@end
+
+@interface NGConcreteTextVcardMimeType : NGConcreteTextMimeType
+@end
+
+/*
+ The "application" media type is to be used for discrete data which do not fit in
+ any of the other categories, and particularly for data to be processed by some
+ type of application program.
+ This is information which must be processed by an application before it is
+ viewable or usable by a user. Expected uses for the "application" media type
+ include file transfer, spreadsheets, data for mail-based scheduling systems, and
+ languages for "active" (computational) material. (The latter, in particular, can
+ pose security problems which must be understood by implementors, and are
+ considered in detail in the discussion of the "application/PostScript" media type.)
+*/
+@interface NGConcreteApplicationMimeType : NGParameterMimeType
+@end
+
+/*
+  The "octet-stream" subtype is used to indicate that a body contains arbitrary
+  binary data. The set of currently defined parameters is:
+
+   1. TYPE -- the general type or category of binary data. This is intended as
+      information for the human recipient rather than for any automatic processing. 
+
+   2. PADDING -- the number of bits of padding that were appended to the bit-stream
+      comprising the actual contents to produce the enclosed 8bit byte-oriented
+      data. This is useful for enclosing a bit-stream in a body when the total
+      number of bits is not a multiple of 8. 
+
+   Both of these parameters are optional. 
+
+   An additional parameter, "CONVERSIONS", was defined in RFC 1341 but has since
+   been removed. RFC 1341 also defined the use of a "NAME" parameter which gave a
+   suggested file name to be used if the data were to be written to a file. This
+   has been deprecated in anticipation of a separate Content-Disposition header
+   field, to be defined in a subsequent RFC. 
+*/
+@interface NGConcreteAppOctetMimeType : NGMimeType
+{
+@protected
+  NSString *type;         // the general type or category of binary data
+  unsigned padding;       // the number of bits of padding that were appended
+  NSString *conversions;
+  NSString *name;
+}
+
+@end
+
+@interface NGConcreteMultipartMimeType : NGParameterMimeType
+@end
+
+@interface NGConcreteMessageMimeType : NGParameterMimeType
+@end
+
+
+@interface NGConcreteImageMimeType : NGParameterMimeType
+@end
+
+@interface NGConcreteAudioMimeType : NGParameterMimeType
+@end
+
+@interface NGConcreteVideoMimeType : NGParameterMimeType
+@end
+
+
+@interface NGConcreteGenericMimeType : NGMimeType
+{
+@protected
+  NSString     *type;
+  NSString     *subType;
+  NSDictionary *parameters;
+}
+
+@end
+
+@interface NGConcreteWildcardType : NGMimeType
+{
+@protected
+  NSString     *type;    // nil means wildcard
+  NSString     *subType; // nil means wildcard
+  NSDictionary *parameters;
+}
+
+@end
+
+#endif /* __NGMime_NGConcreteMimeType_H__ */
diff --git a/skyrix-core/NGMime/NGConcreteMimeType.m b/skyrix-core/NGMime/NGConcreteMimeType.m
new file mode 100644 (file)
index 0000000..6f1b0b2
--- /dev/null
@@ -0,0 +1,811 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGConcreteMimeType.h"
+#include "common.h"
+
+@implementation NGParameterMimeType
+
+- (id)initWithType:(NSString *)_type subType:(NSString *)_subType
+  parameters:(NSDictionary *)_parameters
+{
+  self->subType    = [_subType    copy];
+  self->parameters = [_parameters copy];
+  return self;
+}
+
+- (void)dealloc {
+  [self->subType    release];
+  [self->parameters release];
+  [super dealloc];
+}
+
+/* types */
+
+- (NSString *)type {
+  [self subclassResponsibility:_cmd];
+  return nil;
+}
+- (NSString *)subType {
+  return self->subType;
+}
+- (BOOL)isCompositeType {
+  return NO;
+}
+
+/* parameters */
+
+- (NSEnumerator *)parameterNames {
+  return [self->parameters keyEnumerator];
+}
+
+- (id)valueOfParameter:(NSString *)_parameterName {
+  return [self->parameters objectForKey:_parameterName];
+}
+
+/* representations */
+
+- (NSDictionary *)parametersAsDictionary {
+  return self->parameters;
+}
+
+- (NSString *)stringValue {
+  NSMutableString *str = [NSMutableString stringWithCapacity:20];
+  NSString *paras;
+  
+  [str appendString:[self type]];
+  [str appendString:@"/"];
+  [str appendString:[self subType]];
+
+  paras = [self parametersAsString];
+  if (paras) [str appendString:paras];
+
+  return str;
+}
+
+@end /* NGParameterMimeType */
+
+@implementation NGConcreteTextMimeType
+
+static NGConcreteTextMimeType *textPlainNoCharset = nil;
+
++ (void)initialize {
+  BOOL isInitialized = NO;
+  if (isInitialized) return;
+  isInitialized = YES;
+  textPlainNoCharset =
+    [[NGConcreteTextMimeType alloc] initWithType:NGMimeTypeText
+                                    subType:@"plain"
+                                    parameters:nil];
+}
+
+- (id)initWithType:(NSString *)_type subType:(NSString *)_subType
+  parameters:(NSDictionary *)_parameters
+{
+  NSAssert([_type isEqualToString:NGMimeTypeText],
+           @"invalid use of concrete subclass ..");
+
+  if (textPlainNoCharset) {
+    if (_parameters == nil) {
+      if ([_subType isEqualToString:@"plain"]) {
+        [self release];
+        return [textPlainNoCharset retain]; // init returns retained objects !
+      }
+    }
+  }
+  delsp   = NO;
+  subType = [_subType copy];
+  NSAssert(subType, @"subtype may not be nil");
+  {
+    NSEnumerator *keys = [_parameters keyEnumerator];
+    NSString     *key  = nil;
+    
+    while ((key = [keys nextObject])) {
+      NSAssert([key isKindOfClass:[NSString class]],
+               @"parameter name has to be a NSString");
+      
+      if ([key isEqualToString:NGMimeParameterTextCharset]) {
+        id tc = [[_parameters objectForKey:key] lowercaseString];
+        ASSIGN(self->charset, tc);
+        tc = nil;
+      }
+      else if ([key isEqualToString:@"name"]) {
+        [self->name release]; self->name = nil;
+        self->name = [[_parameters objectForKey:key] copy];
+      }
+      else if ([key isEqualToString:@"q"]) {
+        id v;
+        if ((v = [_parameters objectForKey:key]))
+          self->quality = [v floatValue];
+        else
+          self->quality = 1.0;
+      }
+      else if ([key isEqualToString:@"format"]) {
+        [self->format release]; self->format = nil;
+        self->format = [[_parameters objectForKey:key] copy];
+      }
+      else if ([key isEqualToString:@"method"]) {
+        [self->method release]; self->method = nil;
+        self->method = [[_parameters objectForKey:key] copy];
+      }
+      else if ([key isEqualToString:@"delsp"]) {
+        self->delsp = [[_parameters objectForKey:key] boolValue];
+      }
+      else {
+        // TODO: how do we want to deal with extra parameters?
+        BOOL printWarn = YES;
+        
+        if ([key hasPrefix:@"x-"]) {
+          if ([key hasPrefix:@"x-mac"])
+            printWarn = NO;
+          else if ([key hasPrefix:@"x-unix-mode"])
+            printWarn = NO;
+          else if ([key hasPrefix:@"x-avg-checked"])
+            // eg: 'x-avg-checked: avg-ok-12CD4A13'
+            printWarn = NO;
+        }
+        
+        if (printWarn) {
+          NSLog(@"MimeType 'text/*' does not support a parameter named "
+                @"'%@' with value '%@'", key, [_parameters objectForKey:key]);
+        }
+      }
+    }
+  }
+  NSAssert(self, @"self is nil !");
+  return self;
+}
+
+- (void)dealloc {
+  [self->method  release];
+  [self->format  release];
+  [self->name    release];
+  [self->subType release];
+  [self->charset release];
+  [super dealloc];
+}
+
+/* type */
+
+- (NSString *)type {
+  return NGMimeTypeText;
+}
+- (NSString *)subType {
+  return self->subType;
+}
+- (BOOL)isCompositeType {
+  return NO;
+}
+
+/* comparing types */
+
+- (BOOL)isEqualToMimeType:(NGMimeType *)_type {
+  NSDictionary *paras = nil;
+    
+  if (_type == nil)  return NO;
+  if (_type == self) return YES;
+
+  if (![self hasSameType:_type])
+    return NO;
+
+  paras = [_type parametersAsDictionary];
+  switch ([paras count]) {
+    case 0:
+      if (self->charset) return NO;
+      break;
+
+    case 1: {
+      id ocs = nil;
+      if (self->charset == nil) return NO;
+      ocs = [paras objectForKey:NGMimeParameterTextCharset];
+      if (ocs == nil) return NO;
+      if (![ocs isEqual:self->charset]) return NO;
+      break;
+    }
+
+    case 2: {
+      id ocs = nil;
+      if (self->charset == nil) return NO;
+      if (self->name    == nil) return NO;
+      
+      ocs = [paras objectForKey:NGMimeParameterTextCharset];
+      if (ocs == nil) return NO;
+      if (![ocs isEqual:self->charset]) return NO;
+
+      ocs = [paras objectForKey:@"name"];
+      if (ocs == nil) return NO;
+      if (![ocs isEqual:self->name]) return NO;
+      break;
+    }
+
+    case 3: {
+      id ocs = nil;
+      if (self->charset == nil) return NO;
+      if (self->name    == nil) return NO;
+      if (self->format  == nil) return NO;
+      
+      ocs = [paras objectForKey:NGMimeParameterTextCharset];
+      if (ocs == nil) return NO;
+      if (![ocs isEqual:self->charset]) return NO;
+
+      ocs = [paras objectForKey:@"name"];
+      if (ocs == nil) return NO;
+      if (![ocs isEqual:self->name]) return NO;
+
+      ocs = [paras objectForKey:@"format"];
+      if (ocs == nil) return NO;
+      if (![ocs isEqual:self->format]) return NO;
+      break;
+    }
+
+    default:
+      return NO;
+  }
+
+  return YES;
+}
+
+- (BOOL)hasSameGeneralType:(NGMimeType *)_other { // only the 'type' must match
+  if (_other == nil)            return NO;
+  if (_other == self)           return YES;
+  if ([_other isCompositeType]) return NO;
+  if (![[_other type] isEqualToString:NGMimeTypeText]) return NO;
+  return YES;
+}
+- (BOOL)hasSameType:(NGMimeType *)_other { // parameters need not match
+  if (_other == nil)            return NO;
+  if (_other == self)           return YES;
+  if ([_other isCompositeType]) return NO;
+  if (![[_other type]    isEqualToString:NGMimeTypeText]) return NO;
+  if (![[_other subType] isEqualToString:self->subType])  return NO;
+  return YES;
+}
+
+- (BOOL)doesMatchType:(NGMimeType *)_other { // interpretes wildcards
+  NSString *ot  = [_other type];
+  NSString *ost = [_other subType];
+
+  if ([ot  isEqualToString:@"*"]) ot = NGMimeTypeText;
+  if (![NGMimeTypeText isEqualToString:ot]) return NO;
+  
+  if ([ost isEqualToString:@"*"]) ost = self->subType;
+  if (![self->subType isEqualToString:ost]) return NO;
+
+  return YES;
+}
+
+/* parameters */
+
+- (NSString *)characterSet {
+  return self->charset;
+}
+- (NSString *)name {
+  return self->name;
+}
+- (NSString *)format {
+  return self->format;
+}
+- (NSString *)method {
+  return self->method;
+}
+- (float)quality {
+  return self->quality;
+}
+- (BOOL)delsp {
+  return self->delsp;
+}
+
+- (NSEnumerator *)parameterNames {
+  id  args[5];
+  int argCount = 0;
+
+  if (self->charset) {
+    args[argCount] = NGMimeParameterTextCharset;
+    argCount++;
+  }
+  if (self->name) {
+    args[argCount] = @"name";
+    argCount++;
+  }
+  if (self->format) {
+    args[argCount] = @"format";
+    argCount++;
+  }
+  if (self->method) {
+    args[argCount] = @"method";
+    argCount++;
+  }
+
+  if (argCount == 0)
+    return nil;
+
+  return [[NSArray arrayWithObjects:args count:argCount] objectEnumerator];
+}
+- (id)valueOfParameter:(NSString *)_parameterName {
+  if ([_parameterName isEqualToString:NGMimeParameterTextCharset])
+    return self->charset;
+  else if ([_parameterName isEqualToString:@"name"])
+    return self->name;
+  else if ([_parameterName isEqualToString:@"format"])
+    return self->format;
+  else if ([_parameterName isEqualToString:@"method"])
+    return self->method;
+  else
+    return nil;
+}
+
+/* representations */
+
+- (NSDictionary *)parametersAsDictionary {
+  NSMutableDictionary *d;
+
+  d = [NSMutableDictionary dictionaryWithCapacity:4];
+  if (self->charset)
+    [d setObject:self->charset forKey:NGMimeParameterTextCharset];
+  if (self->name)
+    [d setObject:self->name forKey:@"name"];
+  if (self->format)
+    [d setObject:self->format forKey:@"format"];
+  if (self->method)
+    [d setObject:self->method forKey:@"method"];
+
+  return d;
+}
+
+- (NSString *)stringValue {
+  NSMutableString *str = [NSMutableString stringWithCapacity:20];
+  [str appendString:NGMimeTypeText];
+  [str appendString:@"/"];
+  [str appendString:self->subType];
+  if (self->charset) {
+    [str appendString:@"; "];
+    [str appendString:NGMimeParameterTextCharset];
+    [str appendString:@"="];
+    [str appendString:self->charset];
+  }
+  if (self->name) {
+    [str appendString:@"; name="];
+    [str appendString:self->name];
+  }
+  if (self->format) {
+    [str appendString:@"; format="];
+    [str appendString:self->format];
+  }
+  if (self->method) {
+    [str appendString:@"; method="];
+    [str appendString:self->method];
+  }
+  return str;
+}
+
+@end /* NGConcreteTextMimeType */
+
+@implementation NGConcreteTextVcardMimeType
+@end /* NGConcreteTextVcardMimeType */
+
+// application type
+
+@implementation NGConcreteApplicationMimeType
+
+- (NSString *)type {
+  return NGMimeTypeApplication;
+}
+- (BOOL)isCompositeType {
+  return NO;
+}
+
+@end /* NGConcreteApplicationMimeType */
+
+@implementation NGConcreteAppOctetMimeType
+
+- (id)initWithType:(NSString *)_type subType:(NSString *)_subType
+  parameters:(NSDictionary *)_parameters {
+
+  NSEnumerator *keys = [_parameters keyEnumerator];
+  NSString     *key  = nil;
+
+  while ((key = [keys nextObject])) {
+    NSAssert([key isKindOfClass:[NSString class]],
+             @"parameter name has to be a NSString");
+
+    if ([key isEqualToString:@"type"])
+      self->type = [[_parameters objectForKey:@"type"] retain];
+    else if ([key isEqualToString:@"padding"])
+      self->padding = [[_parameters objectForKey:@"padding"] unsignedIntValue];
+    else if ([key isEqualToString:@"conversions"])
+      self->conversions = [[_parameters objectForKey:@"conversions"] retain];
+    else if ([key isEqualToString:@"name"])
+      self->name = [[_parameters objectForKey:@"name"] copy];
+    else {
+      if (![key hasPrefix:@"x-mac"]) {
+       NSLog(@"MimeType 'application/*' does not support a parameter"
+              @" named '%@'", key);
+      }
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->type        release];
+  [self->conversions release];
+  [self->name        release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)type {
+  return NGMimeTypeApplication;
+}
+- (NSString *)subType {
+  return @"octet";
+}
+- (BOOL)isCompositeType {
+  return NO;
+}
+
+/* parameters */
+
+- (NSString *)typeDescription {
+  return self->type;
+}
+
+- (NSEnumerator *)parameterNames {
+  NSMutableArray *array = [NSMutableArray arrayWithCapacity:5];
+  if (self->type)        [array addObject:@"type"];
+  if (self->padding)     [array addObject:@"padding"];
+  if (self->conversions) [array addObject:@"conversions"];
+  if (self->name)        [array addObject:@"name"];
+  return ([array count] > 0) ? [array objectEnumerator] : nil;
+}
+
+- (id)valueOfParameter:(NSString *)_parameterName {
+  if ([_parameterName isEqualToString:@"type"])
+    return self->type;
+  else if ([_parameterName isEqualToString:@"padding"])
+    return [NSNumber numberWithUnsignedInt:self->padding];
+  else if ([_parameterName isEqualToString:@"conversions"])
+    return self->conversions;
+  else if ([_parameterName isEqualToString:@"name"])
+    return self->name;
+  else
+    return nil;
+}
+
+- (NSString *)stringValue {
+  NSMutableString *str = [NSMutableString stringWithCapacity:20];
+  NSString *paras;
+  
+  [str appendString:NGMimeTypeApplication];
+  [str appendString:@"/"];
+  [str appendString:@"octet"];
+
+  paras = [self parametersAsString];
+  if (paras) [str appendString:paras];
+
+  return str;
+}
+
+@end /* NGConcreteAppOctetMimeType */
+
+// other types
+
+@implementation NGConcreteImageMimeType
+
+- (NSString *)type {
+  return NGMimeTypeImage;
+}
+
+// description
+
+- (NSString *)stringValue {
+  return [@"image/" stringByAppendingString:[self subType]];
+}
+
+@end /* NGConcreteImageMimeType */
+
+@implementation NGConcreteAudioMimeType
+
+- (NSString *)type {
+  return NGMimeTypeAudio;
+}
+
+// description
+
+- (NSString *)stringValue {
+  return [@"audio/" stringByAppendingString:[self subType]];
+}
+
+@end /* NGConcreteAudioMimeType */
+
+@implementation NGConcreteVideoMimeType
+
+- (NSString *)type {
+  return NGMimeTypeVideo;
+}
+
+// description
+
+- (NSString *)stringValue {
+  return [@"video/" stringByAppendingString:[self subType]];
+}
+
+@end /* NGConcreteVideoMimeType */
+
+@implementation NGConcreteMultipartMimeType
+
+- (NSString *)type {
+  return NGMimeTypeMultipart;
+}
+- (BOOL)isCompositeType {
+  return YES;
+}
+
+@end /* NGConcreteMultipartMimeType */
+
+@implementation NGConcreteMessageMimeType
+
+- (NSString *)type {
+  return NGMimeTypeMessage;
+}
+- (BOOL)isCompositeType {
+  return NO;
+}
+
+@end /* NGConcreteMessageMimeType */
+
+// generic mime type
+
+@implementation NGConcreteGenericMimeType
+
+- (id)initWithType:(NSString *)_type subType:(NSString *)_subType
+  parameters:(NSDictionary *)_parameters {
+
+  self->type       = [_type       retain];
+  self->subType    = [_subType    copy];
+  self->parameters = [_parameters retain];
+  return self;
+}
+
+- (void)dealloc {
+  [self->type       release];
+  [self->subType    release];
+  [self->parameters release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)type {
+  return self->type;
+}
+- (NSString *)subType {
+  return self->subType;
+}
+- (BOOL)isCompositeType {
+  return NO;
+}
+
+/* comparing types */
+
+- (BOOL)isEqualToMimeType:(NGMimeType *)_type {
+  id p;
+  
+  if (_type == nil)  return NO;
+  if (_type == self) return YES;
+
+  if (![self hasSameType:_type])
+    return NO;
+
+  p = [_type parametersAsDictionary];
+  if ((p == nil) && (self->parameters == nil))
+    return YES;
+
+  if (([p count] == 0) && ([self->parameters count] == 0))
+    return YES;
+  
+  if ((p == nil) || (self->parameters == nil))
+    return NO;
+
+  if (![p isEqual:self->parameters])
+    return NO;
+
+  return YES;
+}
+
+- (BOOL)hasSameGeneralType:(NGMimeType *)_other { // only the 'type' must match
+  if (_other == nil)            return NO;
+  if (_other == self)           return YES;
+  if ([_other isCompositeType]) return NO;
+  if (![[_other type]    isEqualToString:self->type]) return NO;
+  return YES;
+}
+- (BOOL)hasSameType:(NGMimeType *)_other { // parameters need not match
+  if (_other == nil)            return NO;
+  if (_other == self)           return YES;
+  if ([_other isCompositeType]) return NO;
+  if (![[_other type]    isEqualToString:self->type])    return NO;
+  if (![[_other subType] isEqualToString:self->subType]) return NO;
+  return YES;
+}
+
+- (BOOL)doesMatchType:(NGMimeType *)_other { // interpretes wildcards
+  NSString *ot  = [_other type];
+  NSString *ost = [_other subType];
+
+  if ([ot  isEqualToString:@"*"]) ot  = self->type;
+  if (![self->type isEqualToString:ot]) return NO;
+  
+  if ([ost isEqualToString:@"*"]) ost = self->subType;
+  if (![self->subType isEqualToString:ost]) return NO;
+
+  return YES;
+}
+
+// parameters
+
+- (NSEnumerator *)parameterNames {
+  return [self->parameters keyEnumerator];
+}
+
+- (id)valueOfParameter:(NSString *)_parameterName {
+  return [self->parameters objectForKey:_parameterName];
+}
+
+- (NSDictionary *)parametersAsDictionary {
+  return self->parameters;
+}
+
+// description
+
+- (NSString *)stringValue {
+  NSMutableString *str = [NSMutableString stringWithCapacity:128];
+
+  [str appendString:self->type];
+  [str appendString:@"/"];
+  [str appendString:self->subType];
+
+  if ([self->parameters count] > 0) {
+    NSEnumerator *keys = [self->parameters keyEnumerator];
+    id           key   = nil;
+    
+    while ((key = [keys nextObject])) {
+      [str appendString:@"; "];
+      [str appendString:key];
+      [str appendString:@"=\""];
+      [str appendString:[self->parameters objectForKey:key]];
+      [str appendString:@"\""];
+    }
+  }
+  return str;
+}
+
+@end /* NGConcreteGenericMimeType */
+
+@implementation NGConcreteWildcardType 
+
+- (id)initWithType:(NSString *)_type subType:(NSString *)_subType
+  parameters:(NSDictionary *)_parameters
+{
+  self->parameters = [_parameters copy];
+  self->type    = [_type    isEqualToString:@"*"] ? nil : [_type    copy];
+  self->subType = [_subType isEqualToString:@"*"] ? nil : [_subType copy];
+  return self;
+}
+
+- (void)dealloc {
+  [self->parameters release];
+  [self->type       release];
+  [self->subType    release];
+  [super dealloc];
+}
+
+// accessors
+
+- (NSString *)type {
+  return self->type ? self->type : @"*";
+}
+- (NSString *)subType {
+  return self->subType ? self->subType : @"*";
+}
+- (BOOL)isCompositeType {
+  return NO;
+}
+
+/* parameters */
+
+- (NSEnumerator *)parameterNames {
+  return [self->parameters keyEnumerator];
+}
+
+- (id)valueOfParameter:(NSString *)_parameterName {
+  return [self->parameters objectForKey:_parameterName];
+}
+
+/* representations */
+
+- (NSDictionary *)parametersAsDictionary {
+  return self->parameters;
+}
+
+/* comparing types */
+
+- (BOOL)isEqualToMimeType:(NGMimeType *)_type {
+  if (_type == nil)  return NO;
+  if (_type == self) return YES;
+
+  if (![self hasSameType:_type])
+    return NO;
+
+  if (![[_type parametersAsDictionary] isEqual:[self parametersAsDictionary]])
+    return NO;
+
+  return YES;
+}
+
+- (BOOL)hasSameGeneralType:(NGMimeType *)_other { // only the 'type' must match
+  if (_other == nil)  return NO;
+  if (_other == self) return YES;
+  if (![[_other type] isEqualToString:[self type]]) return NO;
+  return YES;
+}
+- (BOOL)hasSameType:(NGMimeType *)_other { // parameters need not match
+  if (_other == nil)            return NO;
+  if (_other == self)           return YES;
+  if (![[_other type]    isEqualToString:[self type]])    return NO;
+  if (![[_other subType] isEqualToString:[self subType]]) return NO;
+  return YES;
+}
+
+- (BOOL)doesMatchType:(NGMimeType *)_other { // interpretes wildcards
+  if (self->type) {
+    NSString *ot  = [_other type];
+    if ([ot  isEqualToString:@"*"]) ot  = self->type;
+    if (![self->type isEqualToString:ot]) return NO;
+  }
+  if (self->subType) {
+    NSString *ost = [_other subType];
+    if ([ost isEqualToString:@"*"]) ost = self->subType;
+    if (![self->subType isEqualToString:ost]) return NO;
+  }
+
+  return YES;
+}
+
+// description
+
+- (NSString *)stringValue {
+  NSMutableString *str = [NSMutableString stringWithCapacity:128];
+  NSString *paras;
+  
+  [str appendString:[self type]];
+  [str appendString:@"/"];
+  [str appendString:[self subType]];
+  
+  paras = [self parametersAsString];
+  if (paras) [str appendString:paras];
+  
+  return str;
+}
+
+@end /* NGConcreteWildcardType */
diff --git a/skyrix-core/NGMime/NGImap4/.cvsignore b/skyrix-core/NGMime/NGImap4/.cvsignore
new file mode 100644 (file)
index 0000000..23b4528
--- /dev/null
@@ -0,0 +1,3 @@
+Resources
+shared_debug_obj
+*.log
diff --git a/skyrix-core/NGMime/NGImap4/COPYING b/skyrix-core/NGMime/NGImap4/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-core/NGMime/NGImap4/ChangeLog b/skyrix-core/NGMime/NGImap4/ChangeLog
new file mode 100644 (file)
index 0000000..1c29d8c
--- /dev/null
@@ -0,0 +1,1062 @@
+2004-07-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.169
+
+       * NGImap4Client.m, NGImap4Context.m, NGImap4DataSource.m,
+         NGImap4FileManager.m, NGImap4Message.m, NGImap4ResponseParser.m:
+         fixed gcc 3.x warnings
+
+       * NGImap4ResponseNormalizer.m: fixed some gcc 3.x warnings, fixed
+         normalization (OGo bug #840), bug introduced in v4.2.166
+
+       * NGImap4Folder.m: major code cleanups, fixed some gcc 3.x warnings,
+         added debug output if ImapDebugEnabled is on
+
+2004-07-13  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4Client.m: fixed some compilation issue with older gcc's
+         (v4.2.168)
+
+       * NGImap4Client.m: minor improvements to exception handling (v4.2.167)
+
+       * v4.2.166
+
+       * NGImap4Message.m(-generateBodyStructure): scan for the response
+         containing the body structure if multiple responses were submitted
+         by the IMAP server (eg Courier), this might fix OGo bug #800
+
+       * NGImap4ResponseNormalizer.m: various code cleanups, minor speed
+         improvements in fetch-response normalization
+
+       * NGImap4Message.m: added more logging to find OGo bug #800 (v4.2.165)
+
+2004-06-21  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4FolderMailRegistry.m: fixed a warning with gstep-base 
+         (v4.2.164)
+
+2004-06-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4/NGImap4Message.m: minor optimization (v4.2.163)
+
+2004-06-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4Client.m, NGImap4ResponseParser.m, NSString+Imap4.m: fixed
+         gcc 3.4 warnings (v4.2.162)
+
+2004-05-16  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4Context.m, NGImap4FileManager.m, NGImap4Folder.m, 
+         NGImap4Message.m, NGImap4ServerRoot.m, NGSieveClient.m: replaced 
+         "==YES" comparisons (v4.2.158)
+
+2004-04-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.154
+
+       * NGImap4Message.m: remember mail registry in an ivar (increased the
+         class version), this should fix OGo bug #660
+
+       * NGImap4Folder.m: some code cleanups
+
+2004-02-17  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.152
+
+       * EOQualifier+IMAPAdditions.m, NGImap4Client.m: minor cleanups
+
+       * imCommon.h: only define sel_eq on NeXT or APPLE runtime, fixes OGo
+         bug #582
+
+2004-02-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4Client.m, NGImap4FolderMailRegistry.m, NGImap4Functions.m,
+         NGImap4ResponseParser.m, NGSieveClient.m: fixed compilation warnings
+         on OSX (v4.2.151)
+
+2004-01-25  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * NGImap4Folder.m: use new NGDataStream API to allow additional
+         optimizations (open data parsing streams in read-only mode) 
+         (v4.2.149)
+
+2004-01-24  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.148
+
+       * NGImap4Client.m: cleanups, moved "response normalization" methods to
+         a separate NGImap4ResponseNormalizer object
+       
+       * NGImap4ResponseParser.m (_parseUntaggedResponse): optimized parsing
+         of untagged responses, cache NSNumber class, improved autorelease
+         behaviour (v4.2.147)
+       
+       * NGMimeRFC822DateHeaderFieldParser.m: replaced (expensive) usage of 
+         the NSCalendarDate parser with a hackish, but much faster hand
+         written parser. Should give a good performance benefit on large mail
+         folders (looks like ~50ms for 30 mails ) (v4.2.146)
+
+2004-01-22  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.145
+
+       * NGImap4FolderMailRegistry.m: implemented new "flat-array" 
+         notification center for mail flag coordination. Quite fast with
+         observer inserts/removes. Hopefully this doesn't break anything,
+         but apparently it works just fine.
+
+       * added NGImap4FolderFlags class to manage folder flags
+
+2004-01-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.144
+
+       * EOQualifier+IMAPAdditions.m: fixed unseen qualifier processing
+
+       * NGImap4Client.m, EOQualifier+IMAPAdditions.m: moved IMAP4 search
+         string generation out of NGImap4Client.m to 
+         EOQualifier+IMAPAdditions.m
+
+2004-01-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.143
+
+       * NGImap4Message.m: deprecated URL based factory methods - you should
+         always use the context or folder "constructors", removed 
+         +messageWithUid:.. methods (used nowhere and messages should be
+         constructed using their folder!)
+
+       * NGImap4Folder.m: added -messageWithUid: factory method - you should
+         always use that instead of allocating an NGImap4Message on your own,
+         removed +imap4FolderWithContext: (used nowhere and folders should be
+         constructed using their parent folder or context)
+
+       * NGImap4Context.m: added URL based factory for messages and folders
+
+2004-01-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4Message.m: added various attempts for optimizations (v4.2.142)
+
+2004-01-19  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.141
+
+       * NGImap4Context.m: added globalID method, various cleanups
+       
+       * NGImap4Folder.m: added -globalID method, major cleanups
+       
+       * NGImap4Client.m: added -serverGlobalID method, moved password 
+         escaping code to NSString+Imap4.m
+       
+       * added global-id classes in NGImap4 (v4.2.140)
+
+2004-01-16  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.139
+
+       * NGImap4Functions.m: started a new object to wrap all the old function
+         junk
+
+       * NGImap4Client.m, NGImap4Message.m: major cleanups
+
+       * NGImap4DataSource.m: moved EOQualifier additions to separate source
+         file, various cleanups
+
+       * v4.2.138
+
+       * NGImap4ServerRoot.m: some cleanups, replaced NSZoneMalloc with
+         calloc()
+
+       * NGImap4Client.m: major cleanups, better handling of -lastException
+
+Tue Nov 11 15:04:18 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4ResponseParser.m: add parsing of capability entries without 
+         value (v4.2.136)
+
+2003-11-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGImap4ResponseParser.m: explicitly marked the lastChar variable as
+         being a signed char to avoid compiler errors (v4.2.135)
+
+Thu Nov  6 16:41:13 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.134
+
+       * NGSieveClient: fixed a bug in normalizeResponse, return 
+         NSMutableDictionary
+
+       * NGImap4ResponseParser.m: remove CYRUS_2_0 constant, don`t now
+         what it should be :(
+
+Mon Nov  3 15:42:37 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Context: temporary set selected folder befor the select action
+         to prevent notification confusions (v4.2.133)
+
+2003-10-17  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGSieveClient.m: small code cleanups
+
+Fri Jul 25 13:27:26 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4DataSource.h: fixed #define
+
+Tue Jul 22 15:19:34 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4ResponseParser.m: check for empty quota reponses 
+         (v4.2.128)
+
+2003-07-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4Client.m: fixed some gstep-base issues, patch provided by 
+         Filip Van Raemdonck and cleaned up a bit (v4.2.127)
+
+Thu Jul 17 10:37:22 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4ServerRoot: add a missing method 
+         (bulkFetchHeadersFor:inRange:withAllUnread:) (v4.2.126)
+
+Mon Jun 30 17:45:12 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.125
+       
+       * NGImap4Client: code cleanups
+
+       * NGImap4Message: improve cache behavior (store the read-flag without
+         fetching all flags)
+
+       * NGImap4Folder: add a new method to fetch headers in range + set all
+         read flags
+
+Fri Jun 27 18:08:49 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Message.m: improve flag handling (v4.2.124)
+
+       * NGImap4Message.m: code cleanups (v4.2.123)
+
+Thu Jun 26 13:23:30 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v.4.2.122
+       
+       * NGImap4Message.m: add messageWithURL: methods
+
+       * NGImap4Context.m: execute select-command before setting selectet 
+         folder
+
+       * NGImap4Folder: add a struct do store failed select, status, getQuota 
+         responses, set selectet folder after successfully select response
+
+Fri Jun 20 18:51:24 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.121
+
+       * NGImap4Client.m: cleanups
+
+       * NGImap4ServerRoot, NGImap4Folder.m, NGImap4Functions: 
+         fetch status (new/unseen) of subfolders on demand only if Default: 
+         FetchNewUnseenMessagesInSubFoldersOnDemand = 'YES'
+
+       * NGImap4ServerRoot, NGImap4Folder.m: improve folder-flag analysing, 
+         nonexistent folders will be ignored (Default: ShowNonExistentFolder), 
+          no 'list' request for folder  with hasnochildren flag 
+         (Default: IgnoreHasNoChildrenFlag) (v4.2.120)
+
+       * v4.2.119
+       
+       * NGImap4Functions: cleanups
+
+       * NGImap4Context.m: cleanups
+
+       * NGImap4Folder.m: only reset subfolders if -resetSubFolders called 
+         (prev. behavior: -resetFolder called -resetSubFolders), cleanups
+
+Tue Jun 17 11:53:46 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.118
+       
+       * NGImap4Message+BodyStructure.h: check parsing of date failed 
+
+       * NGImap4Folder: cleanups
+
+Mo Jun 02 15:55:20 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder, NGImap4Functions: add notification for 
+         subfolder-resets (v4.2.112)
+       
+2003-05-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4Folder.m: fixed NSLogL=>NSLog removed a NSLog (v4.2.111)
+
+Tue May 27 17:39:20 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder.m: check for quota only if folder is selectable 
+         (v4.2.110)
+
+Tue May 20 18:03:12 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Context; add accessor to edit default values (v4.2.108)
+
+Wed May 14 10:57:51 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.106
+       * NGImap4ResponseParser.m: use lowercase string to determine whether
+         fetch body reponse is 'text' or 'message' (courier imap use lowercase
+         letters for the body description) (bug 1611)
+       * Info: move rfc, drafts and other information files to 'Info'
+
+Thu May 13 17:59:25 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder.m: add notification for folder reset, if more than one
+         folder for the same folderpath exist (v4.2.105) (bug 1612)
+
+Mon May  5 17:59:25 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder.m: improve error log, fix a bug regarding multiple 
+         mail copy from and to the same folder (v4.2.103)
+
+Wed Apr 30 15:24:26 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.102
+       
+       * NGImap4ServerRoot: noinferiors depends on serverkind (bug 932)
+       
+       * NGImap4ResponseParser.m: improve parsing of server greeting 
+       
+       * NGImap4Folder, NGImap4ServerRoot: take ShowOnlySubscribedIn* 
+         from context
+       
+       * NGImap4Context.m: set ShowOnlySubscribedIn* Defaults 
+         (depends on server)
+       
+       * NGImap4Client.m: detect washington imap server
+
+Wed Apr 30 12:34:38 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.101
+       
+       * NGImap4ServerRoot: fixed retain bug
+       
+       * NGImap4Folder.m: NSLog -> logWithFormat, fixed release (bug 1559),
+       
+       * NGImap4Context: accessors for server defaults
+       
+       * NGImap4Client.m: code cleanups, some logs depends LogDefault,
+         try to get server name (cyrus, courier) - set some server-depending
+         Defaults, fixed special folder subscribe/create behavior (bug 1540)
+         
+
+Fri Apr 11 11:17:25 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Functions.m: add ImapLogEnabled' default
+         bind some logs to 'LogImapEnabled' (v4.2.99)
+
+2003-04-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.98
+
+       * NSString+Imap4.m: fixed a gcc signed/unsigned warning
+
+       * NGSieveClient.m: fixed a warning
+
+       * NGImap4FileManager.m: fixed some warnings
+
+       * NGImap4Folder.m: fixed a warning
+
+       * NGImap4Client.m: small cleanups
+
+       * NGImap4ResponseParser.m: some smaller cleanups and small performance
+         improvements (less autorelease, use NSStringClass) (v4.2.96)
+       
+Mon Apr  7 20:02:29 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.95
+       
+       * NGImap4Message.m: check whether encoding was set -> set encoding 
+         during body-structure fetch
+       
+       * NGImap4Message+BodyStructure.h: if body-structure component is no 
+         rfc822 or multipart --> body url got  'part=1' (bug 1385)
+
+Fri Feb 28 18:32:53 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Functions.m: add support for Washington Imap Server, 
+         (delete folders in server root) (v4.2.93)
+
+Wed Feb 26 17:47:53 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.92
+       
+       * NGImap4ServerRoot.m: read also inbox folder if it
+         is not subscribed
+       
+       * NGImap4Client.m: check whether no sequence contains 'ALERT', 
+         reconnect also if the server repsonse an unexpecte 'bye' sequence
+
+       * (Changes for Washington Imap Server support)
+       
+Wed Feb 26 14:26:30 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m: remove NXConstStr in Excep. Handler (v4.2.91)
+
+Wed Feb 26 11:37:18 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m: check whether so key exist, 
+         use DATE as default sort key (v4.2.89)
+
+Tue Feb 25 11:21:52 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m: fixed a reconnect bug (try only one time, 
+         before return with exception) (bug 1108) (v4.2.88)
+
+Mon Feb 24 15:48:07 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Message.m: select folder befor fetch body structure (bug 1094)
+         (v4.2.87)
+
+Fri Feb 14 16:16:47 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Context.m: code cleanups (v4.2.85)
+
+Fri Jan 31 17:05:55 2003    <jr@skyrix.com>
+
+       * NGImap4Context.m: add defaults for imap special folders, 
+         fix folder create bug (v4.2.83)
+
+Fri Jan 31 14:39:12 2003    <jr@skyrix.com>
+
+       * NGImap4Folder.m: fetch all messages if no sort failed or no 
+         sortordering was given (v4.2.82)
+
+Fri Jan 31 12:28:09 2003    <jr@skyrix.com>
+
+       * v4.2.81
+       
+       * NGImap4Message.m: code cleanups
+       
+       * NGImap4Message+BodyStructure.h: fix parsing structure bug
+
+Wed Jan 29 22:12:08 2003    <jr@skyrix.com>
+
+       * NGImap4*: code cleanups (replace macros with method calls),
+         catch all exceptions, now they are stored in [context lastException]
+         remove connection retry (v4.2.80)
+       
+Tue Jan 28 16:24:37 2003    <jr@skyrix.com>
+
+       * NGImap4Functions.m: fix courier imap bug (couldn`t delete subfoder 
+         which are selected) (v4.2.78)
+
+Tue Jan 28 15:54:21 2003    <jr@skyrix.com>
+
+       * NGImap4Client.m: remove unnecessary abort() (v4.2.77)
+
+Tue Jan 21 19:05:30 2003    <jr@skyrix.com>
+
+       * NGImap4Client.m: add sort encoding default 
+         (ImapSortEncoding default: UTF-8) (v4.2.71)
+
+Tue Jan 21 18:38:09 2003    <jr@skyrix.com>
+
+       * NGMimeMessageParser: increase version number cause changing of 
+         instance vars of super-class (v4.2.70)
+
+Fri Jan 17 13:49:17 2003    <jr@skyrix.com>
+
+       * NGImap4ResponseParser: fix variable placing (v4.2.66)
+
+Thu Jan 16 18:40:47 2003    <jr@skyrix.com>
+
+       * NGImap4ResponseParser.m: decode header values fur bodystructures
+       (v4.2.65)
+
+Tue Jan 14 18:17:55 2003    <jr@skyrix.com>
+
+       * v4.2.64
+       
+       * NGImap4Message+BodyStructure.h: lowercase content-transfer-encoding
+
+Tue Jan 14 12:24:44 2003    <jr@skyrix.com>
+
+       * v4.2.61
+
+       * NGImap4Functions.m: build exception after delete failed
+       
+       * NGImap4Folder.m: reset subfolders after rename
+       
+       * NGImap4Client.m: handle unexpectet 'bye' - response (occured with 
+         broken courier-imap server) 
+
+Tue Jan 14 10:20:29 2003    <jr@skyrix.com>
+
+       * v4.2.60
+       
+       * NGImap4Client.m: fix parsing of cyrus version bug (skyrix bug 845)
+
+Tue Jan 14 09:22:47 2003    <jr@skyrix.com>
+
+       * NGImap4Message+BodyStructure.h: fixed wong instance var
+
+Mon Jan 13 19:44:55 2003    <jr@skyrix.com>
+
+       * NGImap4Message.m, NGImap4Message+BodyStructure.h,
+         NGImap4FileManager.m: use NGMime header field name contants (v4.2.59)
+
+Fri Jan 10 09:54:14 2003    <jr@skyrix.com>
+
+       * v4.2.58
+       
+       * NGImap4Support.h: add -isOverQuota method to protocol
+       
+       * NGImap4ServerRoot.m: add missed methods from protocol
+       
+       * NGImap4ResponseParser.m: parse also quotaroot respones without 
+         given quota-root (skyrix bug 822)
+       
+       * NGImap4Folder.m: improve error handling (needed by quota errors)
+
+Thu Jan  9 14:31:12 2003    <jr@skyrix.com>
+
+       * v4.2.57
+       
+       * NGImap4Context.m: add private method to set lastExceptions 
+         from folder
+       
+       * NGImap4Client.m: handle ALERT responses
+       
+       * NGImap4Folder: check for quota warning, check whether copy failed 
+         during move (SKYRiX Bug #777)
+       
+       * NGImap4ResponseParser.m: improve 'no' response parsing
+       
+Wed Jan  8 16:26:00 2003    <jr@skyrix.com>
+       
+       * v4.2.56
+
+       * NGImap4ResponseParser.m: fix quoted quota response parsing behavior
+
+       * NGImap4Folder, NGImap4Client.m: use absolute names for 
+         quota response (bug 835)
+
+Tue Jan  7 16:47:36 2003    <jr@skyrix.com>
+
+       * v4.2.55
+
+       * NGImap4ServerRoot.m: add -usedSpace und -maxQuota methods (bug 821)
+
+       * NGImap4Support.h: complete NGImap4Folder protocol 
+         (add -usedSpace, -maxQuota)
+
+Fri Dec 27 10:52:44 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.53
+
+       * NSString+Imap4.m: fixed ordering of arguments to calloc() call
+         (count,size) not (size,count)
+       
+       * NGSieveClient.m: removed some gcc 3.2 warnings
+
+       * NGImap4ResponseParser.h: added -parseSieveResponse to interface
+         declaration (removes a warning)
+
+Mon Dec 23 15:38:30 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.52
+
+       * NGImap4Message.m: removed some unneeded code in -dealloc
+
+       * NGImap4Message.h: NSMutableDictionary declaration was missing in the
+         header file
+
+       * NGImap4FileManager.m: -messageAtPath: is now typed to returned an
+         NGImap4Message
+
+2002-12-17  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4Client.m: replaced THROW with raise (4.2.51)
+
+Tue Dec 17 14:46:58 2002    <jr@skyrix.com>
+
+       * v4.2.50
+
+       * NGImap4ResponseParser.m: parse quota responses
+       
+       * NGImap4Folder.*: add maxQuota/usedQuota methods
+       
+       * NGImap4Context.*: add -canQuota method
+       
+       * NGImap4Client.*: add 'quota' command
+
+2002-12-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4Folder.m: added -isComplete prototype to NGImap4Message
+         Privates (removes a compilation warning) (v4.2.49)
+
+Tue Dec 10 19:12:45 2002    <jr@skyrix.com>
+
+       * v4.2.48
+
+       * NGImap4ResponseParser.m: throw exception "No response exception" 
+         if server is down (SKYRiX Bug #651)
+       
+       * NGImap4Folder.m, NGImap4ServerRoot: Default for display 
+         subscribed-folders (ShowOnlySubscribedInSubFolders and
+         ShowOnlySubscribedInRoot)
+       
+       * NGImap4Client.m: release exceptions after description output now 
+
+Tue Dec 10 12:47:08 2002    <jr@skyrix.com>
+
+       * v4.2.47
+
+       * NGImap4ResponseParser.m: fixing 'fetch body' response bug (check for
+         empty bodies) (SX Bug #756)
+       
+       * NGImap4Message+BodyStructure.h: build messages only for rfc822 
+         subtype, fixed header handling message/rfc822 bodies
+       
+       * NGImap4Folder.m: remove logs
+       
+       * NGImap4ServerRoot.m: add fake methods (SX Bug #756)
+       
+Mon Dec  9 13:55:52 2002    <jr@skyrix.com>
+
+       * v4.2.46
+
+       * NGImap4Context.m: add capability support
+       
+       * NGImap4Client.*, NGImap4ResponseParser: add capability command
+
+Fri Dec  6 17:08:28 2002    <jr@skyrix.com>
+
+       * v4.2.45
+       
+       * NGImap4Folder*: add some ss-sorting improvements, bulk-fetch 
+         messages in range
+       
+       * NGImap4Message.m: description do not initialize headers anymore,
+         add -_setHeaders: private function for bulk-fetching
+
+Tue Dec  3 16:45:14 2002    <jr@skyrix.com>
+
+       * NGImap4ResponseParser.m: parse empty string if message does 
+         'no longer exists'(v4.2.44)
+
+Mon Dec  2 19:22:13 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * v4.2.43
+
+       * NGImap4Context.m: add -setSelectedFolder for performance 
+         improvements
+       
+       * NGImap4Folder.m: (Bug #17379) clear msn->uid cache after delete,
+         performance (remove double 'select' call) 
+
+Mon Dec  2 11:18:51 2002    <jr@skyrix.com>
+
+       * NGImap4Folder.m: only reset subfolder if they are already loaded 
+         (v4.2.42)
+
+Fri Nov 29 12:27:25 2002    <jr@skyrix.com>
+
+       * v4.2.40
+
+       * NGImap4ResponseParser.m: check tagged responses before parsing 
+         it
+       
+       * code cleanups
+
+Wed Nov 27 16:42:07 2002    <jr@skyrix.com>
+
+       * NGImap4Context.m, NGImap4Folder: add msn-uid cache (v4.2.39)
+
+Mon Nov 25 16:29:40 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder.m: if no next mail, return nil (v4.2.38)
+       
+       * NGImap4Client.m: check whether sort keys are valid (v4.2.36)
+       
+       * NGImap4ResponseParser.m: fix 'idle to long' bug
+
+Fri Nov 22 15:04:18 2002    <jr@skyrix.com>
+
+       * NGImap4ResponseParser.m: fixed content parsing (v4.2.36)
+       
+       * NGImap4Message*: add support for body-structure content(v4.2.35)
+
+Fri Nov 22 11:13:40 2002    <jr@skyrix.com>
+
+       * NGImap4ResponseParser.m: add Imap4MMDataBoundary Default to 
+         modify MM-Data-Use boundary (v4.2.34)
+
+Thu Nov 21 20:02:48 2002    <jr@skyrix.com>
+
+       * NGImap4ResponseParser.m: add file mapped data for fetching imap data 
+         (to restore previous behavior -NoMemoryMappedDataForImapBlobs YES) 
+         (v4.2.33)
+
+Wed Nov 21 18:07:37 2002    <jr@skyrix.com>
+
+       * add fetch body structure with content-urls
+       
+       * add fetch content of single parts (v4.2.32)
+
+Wed Nov 20 18:07:37 2002    <jr@skyrix.com>
+
+       * GNUmakefile: remove tool-make
+
+2002-11-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4Message.m: added ability to query headers using KVC (v4.2.31)
+
+       * v4.2.30
+
+       * NGImap4FileManager.m: do not create if no URL is given, better
+         error handling with URL initialization
+
+       * NGImap4Context.m: do not create context if an empty URL is given
+
+Tue Nov 19 18:13:38 2002    <jr@skyrix.com>
+
+       * NGImap4*: add commands (thread, fetch body)
+
+Mon Nov 11 10:24:14 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m: improve greetings parse behaviour
+
+2002-11-10  Helge Hess  <helge.hess@skyrix.com>
+       
+       * NGImap4Client, NGImap4FileManager: can init with URL (v4.2.27)
+
+2002-09-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4Client.m: prepared for SSL support
+
+       * NGImap4Context.m: do not alloc with zone (v4.2.25)
+
+Tue Aug 22 14:57:38 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * (from 4.1) use cyrus 2.0, sieve, fixes (v4.2.23)
+
+Tue Aug 20 14:57:38 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder.m: (BUG 17379) if there is no prev-message,
+         take last message (v4.2.22)
+
+Tue Jul 23 10:17:23 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder.m: (BUG 17129) remove debug abort (v4.2.19)
+
+- 2002-07-17 v4.2.17 (hh) [extracted from CVS]
+
+Wed Jul 17 12:58:01 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder.m: added better logs (v4.2.18)
+
+       * NGImap4Folder.m: (BUG 16784) if no sort ordering is given,
+         sort on "date" field of the message
+       
+Thu Jul 11 16:04:39 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder, NGImap4Client, NGImap4ResponseParser: add 
+         sortedMessagesInRange Method
+
+- 2002-07-10 v4.2.16 (hh) [extracted from CVS]
+
+2002-07-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4DataSource.m: place -fetchObjects in an autorelease-pool
+         (v4.2.15)
+
+       * NGImap4Message.m: now supports file-info keys, cleaned up 
+         -description (v4.2.14)
+
+- 2002-07-08 v4.2.13 (hh) [extracted from CVS]
+- 2002-07-08 v4.2.12 (hh) [extracted from CVS]
+
+Thu Jun 13 19:36:33 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Context: add folderWithName:caseInsensitive: (v4.2.11)
+
+Tue Jun 11 16:17:06 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m: (bug 11939) add quote support for special 
+         chars in passwd (v4.2.10)
+
+Mon Jun 10 18:58:55 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Context.m, NGImap4Folder.m: add support for case sensitve 
+         folder handling (v4.2.9)
+
+       * NGImap4Context.m, NGImap4Folder.m: reduce logs (v4.2.8)
+
+Sun Jun  9 02:56:55 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m: (bug 16482) double encoding bug (v4.2.7)
+
+       * NGImap4ServerRoot.m: (bug 16050) show also not subscribed folders
+         (v4.2.6)
+
+- 2002-06-07 v4.2.5  (jr) [extracted from CVS]
+- 2002-06-04 v4.2.4  (jr) [extracted from CVS]
+
+2002-06-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * fixed to compile with gstep-base
+
+- 2002-05-22 v4.2.3  (jr) [extracted from CVS]
+
+Wed Mar  6 13:29:28 CET 2002 Jan Reichmann  <jr@skyrix.com>
+
+       * merge with SkyrixGreen
+
+Mon Jan  7 16:57:07 2002  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4ResponseParser.m: improved error messages
+
+Fri Dec  7 14:14:33 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m ([NGImap -fetchFrom:to:parts:]): add profiling
+
+Tue Dec  4 19:14:43 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m ([NGImap -fetchFrom:to:parts:]): passwd with spaces
+
+Wed Nov 28 18:17:06 2001  Gerrit Albrecht  <ga@skyrix.com>
+
+       * NGImap4Context.m, NGImap4FileManager.m: Added knowledge
+         about drafts folder.
+
+Wed Oct 24 13:18:29 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4Client.m: moved Folder-Name encoding/decoding to NSString
+         category - needs to be corrected to NSData !!!
+
+       * updated to SKYRiXgreen version (lots of fixes & changes)
+
+Tue Oct  2 05:41:32 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Context.m: Fixed __RELEASE__ bug ;(
+
+Fri Aug 10 13:48:29 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4FileManager.m: inherit from NGFileManager
+
+Fri Aug 10 07:28:10 2001  Martin Hoerning  <mh@skyrix.com>
+
+       * NGImap4Client, NGImap4FileManager, NGImap4Context:
+         RETAIN-BUGS fixed
+
+Fri Jun 22 15:46:23 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m: fixed search uid bug
+
+Thu Jun 21 16:50:13 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4FileManager.m: add -imapContext
+
+Wed May 16 17:59:00 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m, NGImap4Context.m, NGImap4ResponseParser.m: 
+         washington imap server
+
+Tue May 15 18:10:33 2001  Jan Reichmann  <jr@skyrix.com>
+
+
+       * NGImap4ResponseParser.m: ignore now empty fetchentries with no 
+       header length field
+
+Tue May  8 16:26:13 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4FileManager.m: add edit possibility for syncMode
+
+Mon Apr  17 11:17:47 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder.m: fixed error log bug
+       
+Mon Apr  2 13:47:47 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4FileManager.m: fixed private interface
+
+Fri Mar 30 14:17:25 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m: try only 10 times to reconnect before raising an 
+       exception
+
+       * NGImap4Client.m: fixed error log
+
+Fri Mar 30 10:54:08 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGImap4DataSource.m: major cleanups
+
+Fri Mar 16 16:05:27 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Message.m: fixed parse message bug 
+
+Wed Mar 14 13:16:24 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4FileManager.m: add datasource at path
+
+Tue Feb  6 19:47:03 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder.m: fixed bug for wrong MSN
+
+Tue Feb  6 19:47:03 2001  Joerg Grimm  <joerg@trex2>
+
+       * NGImap4Client.m: check open connection response without
+                          servername (Cyrus IMAP4 v)
+
+Wed Jan  3 13:14:43 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m: fixed flag bug
+
+Tue Jan  2 16:58:46 2001  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m: hide password in log
+
+       * NGImap4Client.m: sleep before reconnect
+
+Mon Dec 18 14:48:18 2000  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Folder.m: fixed 'lookup only' folder bug
+
+Fri Dec 15 19:26:09 2000  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Client.m, NGImap4Context.m: automatically subscribe to inbox
+
+       * NGImap4Context.m: format text
+
+Mon Nov 13 14:51:13 2000  Jan Reichmann  <jr@skyrix.com>
+
+       * Python/: insert python module
+       * NGImapClient.m: enable append of messages with more than 15kB
+
+Fri Sep 29 15:15:29 2000  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4: add sync mode (synchronize selects for folder)
+
+Thu Sep 14 13:33:49 2000  Jan Reichmann  <jr@skyrix.com>
+
+       * search.txt: use '=' instead of '=='
+
+       * NGImap4Context.[hm]: insert - newMessages
+
+       * NGImap4Client.m: remove compiler warning
+
+Wed Sep 13 14:47:23 2000  Jan Reichmann  <jr@skyrix.com>
+
+       * NGImap4Context.m: at first ask inbox in method hasNewMessages
+
+Tue Sep  5 14:04:37 2000  Joerg Grimm  <joerg@trex2>
+
+       * NGImap4Folder.m: log removed
+
+Fri Sep  1 13:15:22 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Client.m: remove logs
+
+Wed Aug 30 21:22:31 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Context.[hm], NGImap4Client.m: store server data
+
+Tue Aug 29 18:56:38 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Context.m, NGImap4Folder.h, NGImap4Folder.m,NGImap4Functions.m:
+       actions for no-select folders
+
+Mon Aug 28 18:43:11 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Folder.m: fixed bug for read-only folder
+
+Tue Aug  8 11:21:16 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGImap4Message.m: added -globalID method
+
+       * NGImap4Context.m: added -login method
+
+Thu Jul 27 14:48:26 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Folder.m: fixed bug (unseen was not updated) 
+
+Fri Jun 23 10:32:00 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4ResponseParser.m: remove category for NSData
+
+Wed Jun  7 16:07:03 2000  Jan Reichmann  <jan@mdlink.de>
+
+       *  NGImap4Folder.[hm], NGImap4ServerRoot.[hm]: maxResults for search 
+
+Mon May 29 17:56:46 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Functions.m: remove recursive copy bug
+
+Sat May 27 18:27:48 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Message.m: add flagged methods
+
+Tue May 23 12:33:25 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Context.[hm]: improvements ( add -folderWithName)
+
+Fri May 19 11:52:25 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Client.m: replace 0 with 1 in range-commands
+
+Thu May 18 15:20:19 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4*: enabled mailboxes with more than one rootfolder
+
+Tue May 16 12:35:46 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Client.m: fixed RC bug
+
+Mon May 15 16:26:19 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Context.m, NGImap4Folder.[hm]: evaluate noinferiors flag 
+
+Wed May 10 19:30:37 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Folder.m: fixed RC-bug (raised during moveFolder)
+
+Wed May  3 22:15:10 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Folder.m: improvements
+
+Mon May  1 21:24:21 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Folder.m: fixed RC-bug
+
+Wed Apr 26 10:26:54 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Context.m: bugfix in hasNewMessages
+
+Thu Apr 13 16:19:56 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4Message.m: insert isEqual: and hash methods
+
+Mon Apr 10 14:34:49 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGImap4Folder.m: added autorelease-pools, added immutable containers
+
+       * NGImap4Client.m: added autorelease-pools
+
+       * NGImap4Client.m(-normalizeFetchResponse:): created immutable, 
+         not-autoreleased NSDictionary entry objects
+
+       * NGImap4Client.m: replaced abort() with NSCAssert
+
+Thu Apr  6 16:32:09 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGImap4 build lib-internal Trash/Sent Folder managment
+
+Tue Feb 29 19:18:09 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * MOF3 import
+
+Tue Feb 22 19:16:11 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * GNUmakefile (GNUSTEP_INSTALLATION_DIR): changed to GNUSTEP_LOCAL_ROOT
+
+Thu Jan 13 17:24:40 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * created ChangeLog
diff --git a/skyrix-core/NGMime/NGImap4/EOQualifier+IMAPAdditions.m b/skyrix-core/NGMime/NGImap4/EOQualifier+IMAPAdditions.m
new file mode 100644 (file)
index 0000000..57c9eae
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "imCommon.h"
+
+@interface EOQualifier(PrivateMethodes)
+
+- (NSString *)qualifierDescription;
+
+- (NSException *)invalidImap4SearchQualifier:(NSString *)_reason;
+
+- (NSException *)appendToImap4SearchString:(NSMutableString *)_search 
+  insertNot:(BOOL)_insertNot;
+
+@end
+
+@implementation EOQualifier(IMAPAdditions)
+
+- (BOOL)isImap4UnseenQualifier {
+  return NO;
+}
+
+/* building search qualifiers */
+
+static NSArray *FlagKeyWords = nil;
+static NSArray *OtherKeyWords = nil;
+static BOOL    debugOn = NO;
+
+- (void)_initImap4SearchCategory {
+  NSUserDefaults *ud;
+  
+  if (FlagKeyWords) return;
+
+  ud = [NSUserDefaults standardUserDefaults];
+  FlagKeyWords = [[NSArray alloc] initWithObjects: @"answered", @"deleted",
+                            @"draft", @"flagged", @"new", @"old", @"recent",
+                            @"seen", @"unanswered", @"undeleted", @"undraft",
+                            @"unflagged", @"unseen", nil];
+  OtherKeyWords = [[NSArray alloc] initWithObjects:
+                             @"bcc", @"body", @"cc", @"from", @"subject",
+                             @"text", @"to", @"keyword", @"unkeyword", nil];
+  
+  debugOn = [ud boolForKey:@"ImapDebugQualifierGeneration"];
+}
+
+- (NSException *)invalidImap4SearchQualifier:(NSString *)_reason {
+  if (_reason == nil) _reason = @"unknown reason";
+  return [NSException exceptionWithName:@"NGImap4SearchQualifierException"
+                      reason:_reason
+                      userInfo:nil];
+}
+
+- (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
+  return nil;
+}
+- (BOOL)isImap4NotQualifier {
+  return NO;
+}
+- (BOOL)isImap4KeyValueQualifier {
+  return NO;
+}
+
+- (NSException *)appendToImap4SearchString:(NSMutableString *)_search 
+  insertNot:(BOOL)_insertNot
+{
+  return [self invalidImap4SearchQualifier:@"expected key/value qualifier"];
+}
+- (NSException *)appendToImap4SearchString:(NSMutableString *)_search { 
+  return [self appendToImap4SearchString:_search insertNot:NO];
+}
+
+- (id)imap4SearchString { /* returns exception on fail */
+  // TODO: split up method
+  BOOL            disjunction = NO; /* OR */
+  NSEnumerator    *quals;
+  id              qualifier;
+  NSMutableString *search;
+  
+  [self _initImap4SearchCategory];
+  
+  if ([self isImap4UnseenQualifier]) {
+    if (debugOn)
+      [self logWithFormat:@"is unseen: %@ (%@)", self, [self class]];
+    return @" unseen";
+  }
+  
+  if (debugOn)
+    [self logWithFormat:@"generate IMAP4 expression for qualifier: %@", self];
+  
+  search = [NSMutableString stringWithCapacity:256];
+  quals  = nil;
+  
+  if ((quals = [self subqualifiersForImap4SearchString:&disjunction]) == nil) {
+    if (debugOn)
+      [self logWithFormat:@"  got no subqualifiers .."];
+    
+    return (id)[self invalidImap4SearchQualifier:@"unexpected qualifier 1"];
+  }
+  
+  if (disjunction)
+    [search appendString:@" or"];
+  
+  while ((qualifier = [quals nextObject])) {
+    NSException *error;
+
+    if (debugOn)
+      [self logWithFormat:@"  append subqualifier: %@", qualifier];
+    
+    if ((error = [qualifier appendToImap4SearchString:search]))
+      return error;
+  }
+  
+  if (debugOn)
+    [self logWithFormat:@"  generated: '%@'", search];
+
+  return search;
+}
+
+@end /* EOQualifier(IMAPAdditions) */
+
+@implementation EOAndQualifier(IMAPAdditions)
+
+- (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
+  if (_isDisjunction) *_isDisjunction = NO;
+  return [[self qualifiers] objectEnumerator];
+}
+
+@end /* EOAndQualifier(IMAPAdditions) */
+
+@implementation EOOrQualifier(IMAPAdditions)
+
+- (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
+  if (_isDisjunction) *_isDisjunction = YES;
+  return [[self qualifiers] objectEnumerator];
+}
+
+@end /* EOOrQualifier(IMAPAdditions) */
+
+@implementation EOKeyValueQualifier(IMAPAdditions)
+
+- (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
+  if (_isDisjunction) *_isDisjunction = NO;
+  return [[NSArray arrayWithObject:self] objectEnumerator];
+}
+
+- (BOOL)isImap4KeyValueQualifier {
+  return YES;
+}
+
+- (BOOL)isImap4UnseenQualifier {
+  // TODO: this is rather weird: flags suggests an array value!
+  if (![[self key] isEqualToString:@"flags"]) 
+    return NO;
+  return [[self value] isEqualToString:@"unseen"];
+}
+
+- (NSException *)appendFlagsCheckToImap4SearchString:(NSMutableString *)search 
+  insertNot:(BOOL)insertNot
+{
+  NSEnumerator *enumerator = nil;
+  id       lvalue;
+  SEL      lselector;
+  
+  lvalue    = [self value];
+  lselector = [self selector];
+      
+      if (sel_eq(lselector, EOQualifierOperatorEqual)) {
+        lvalue = [NSArray arrayWithObject:lvalue];
+      }
+      else if (!sel_eq(lselector, EOQualifierOperatorContains)) {
+        return [self invalidImap4SearchQualifier:
+                       @"unexpected EOKeyValueQualifier selector"];
+      }
+      if (![lvalue isKindOfClass:[NSArray class]]) {
+        return [self invalidImap4SearchQualifier:
+                       @"expected an array in contains-qualifier"];
+      }
+      enumerator = [lvalue objectEnumerator];
+      while ((lvalue = [enumerator nextObject])) {
+        lvalue = [lvalue lowercaseString];
+        
+        if ([FlagKeyWords containsObject:lvalue]) {
+         [search appendString:insertNot ? @" not " : @" "];
+          [search appendString:lvalue];
+        }
+        else {
+          return [self invalidImap4SearchQualifier:
+                         @"unexpected keyword for EOKeyValueQualifier"];
+       }
+      }
+      return nil;
+}
+
+- (NSString *)imap4OperatorForDateComparisonSelector:(SEL)lselector {
+  if (sel_eq(lselector, EOQualifierOperatorEqual))
+    return @" senton ";
+  if (sel_eq(lselector, EOQualifierOperatorGreaterThan))
+    return @" sentsince ";
+  if (sel_eq(lselector, EOQualifierOperatorLessThan))
+    return @" sentbefore ";
+  
+  return nil;
+}
+
+- (NSException *)appendToImap4SearchString:(NSMutableString *)search 
+  insertNot:(BOOL)insertNot
+{
+  /* returns exception on fail */
+  NSString *lkey;
+  id       lvalue;
+  SEL      lselector;
+  
+  lkey      = [[self key] lowercaseString];
+  lvalue    = [self value];
+  lselector = [self selector];
+    
+  if ([lkey isEqualToString:@"flags"]) {
+    return [self appendFlagsCheckToImap4SearchString:search 
+                 insertNot:insertNot];
+  }
+  
+  /* not a flag */
+  if (insertNot) 
+    [search appendString:@" not"];
+  
+  if ([lkey isEqualToString:@"date"]) {
+    NSString *s;
+    
+    if (![lvalue isKindOfClass:[NSCalendarDate class]]) {
+      return [self invalidImap4SearchQualifier:
+                    @"expected a NSDate as value"];
+    }
+    
+    if ((s = [self imap4OperatorForDateComparisonSelector:lselector]) == nil)
+      return [self invalidImap4SearchQualifier:@"unexpected selector"];
+    
+    // TODO: much faster without descriptionWithCalendarFormat:?!
+    s = [lvalue descriptionWithCalendarFormat:@"%d-%b-%Y"];
+    [search appendString:s];
+  }
+  else if ([lkey isEqualToString:@"uid"]) {
+    if (!sel_eq(lselector, EOQualifierOperatorEqual))
+      return [self invalidImap4SearchQualifier:@"unexpected qualifier 2"];
+    
+    [search appendString:@" uid "];
+    [search appendString:[lvalue stringValue]];
+  }
+  else if ([lkey isEqualToString:@"size"]) {
+    if (sel_eq(lselector, EOQualifierOperatorGreaterThan))
+      [search appendString:@" larger "];
+    else if (sel_eq(lselector, EOQualifierOperatorLessThan))
+      [search appendString:@" smaller "];
+    else
+      return [self invalidImap4SearchQualifier:@"unexpected qualifier 3"];
+        
+    [search appendString:[lvalue stringValue]];
+  }
+  else if ([OtherKeyWords containsObject:lkey]) {
+    if (!sel_eq(lselector, EOQualifierOperatorEqual)) {
+      [self logWithFormat:@"SELECTOR: got: %@, allowed: %@", 
+           NSStringFromSelector(lselector),
+           NSStringFromSelector(EOQualifierOperatorEqual)];
+      return [self invalidImap4SearchQualifier:
+                    @"unexpected qualifier, disallowed comparison on "
+                    @"OtherKeyWords)"];
+    }
+    
+    [search appendString:@" "];
+    [search appendString:lkey];
+    [search appendString:@" \""];
+    [search appendString:[lvalue stringValue]];
+    [search appendString:@"\""];
+  }
+  else {
+    if (!sel_eq(lselector, EOQualifierOperatorEqual))
+      return [self invalidImap4SearchQualifier:@"unexpected qualifier 5"];
+    
+    [search appendString:@" header "];
+    [search appendString:lkey];
+    [search appendString:@" \""];
+    [search appendString:[lvalue stringValue]];
+    [search appendString:@"\""];
+  }
+  return nil;
+}
+
+@end /* EOKeyValueQualifier(IMAPAdditions) */
+
+@implementation EONotQualifier(IMAPAdditions)
+
+- (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
+  if (_isDisjunction) *_isDisjunction = NO;
+  return [[NSArray arrayWithObject:self] objectEnumerator];
+}
+
+- (BOOL)isImap4NotQualifier {
+  return YES;
+}
+
+- (NSException *)appendToImap4SearchString:(NSMutableString *)_search { 
+  return [[self qualifier] appendToImap4SearchString:_search insertNot:YES];
+}
+
+@end /* EONotQualifier(IMAPAdditions) */
diff --git a/skyrix-core/NGMime/NGImap4/GNUmakefile b/skyrix-core/NGMime/NGImap4/GNUmakefile
new file mode 100644 (file)
index 0000000..2506b3e
--- /dev/null
@@ -0,0 +1,60 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = NGImap4
+
+NGImap4_HEADER_FILES_DIR         = .
+NGImap4_HEADER_FILES_INSTALL_DIR = /NGImap4
+
+NGImap4_HEADER_FILES = \
+       NGImap4ResponseParser.h \
+       NGImap4Client.h         \
+       NGImap4Support.h        \
+       NGImap4Folder.h         \
+       NGImap4Context.h        \
+       NGImap4Message.h        \
+       NGImap4ServerRoot.h     \
+       NGImap4FileManager.h    \
+       NGImap4.h               \
+       NGImap4DataSource.h     \
+       NSString+Imap4.h        \
+       NGSieveClient.h         \
+
+NGImap4_OBJC_FILES = \
+       NGImap4ResponseParser.m         \
+       NGImap4Client.m                 \
+       NGImap4Support.m                \
+       NGImap4.m                       \
+       NGImap4Folder.m                 \
+       NGImap4Context.m                \
+       NGImap4Message.m                \
+       NGImap4ServerRoot.m             \
+       NGImap4Functions.m              \
+       NGImap4FileManager.m            \
+       NGImap4DataSource.m             \
+       NSString+Imap4.m                \
+       NGSieveClient.m                 \
+       EOQualifier+IMAPAdditions.m     \
+       \
+       NGImap4MessageGlobalID.m        \
+       NGImap4FolderGlobalID.m         \
+       NGImap4ServerGlobalID.m         \
+       NGImap4FolderMailRegistry.m     \
+       NGImap4FolderFlags.m            \
+       NGImap4ResponseNormalizer.m     \
+
+#TOOL_NAME = imap_tool
+
+#imap_tool_OBJC_FILES = imap_tool.m #$(NGImap4_OBJC_FILES)
+ADDITIONAL_TOOL_LIBS += -lNGMime
+
+NGImap4_INCLUDE_DIRS += \
+       -I.. -I../..            \
+       -I../../NGStreams/      \
+       -I../../NGExtensions/
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+include $(GNUSTEP_MAKEFILES)/tool.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4-Info.plist b/skyrix-core/NGMime/NGImap4/NGImap4-Info.plist
new file mode 100644 (file)
index 0000000..b97e78b
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGImap4</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.core.NGImap4</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4.h b/skyrix-core/NGMime/NGImap4/NGImap4.h
new file mode 100644 (file)
index 0000000..b9d3745
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGImap4_NGImap4_H__
+#define __NGImap4_NGImap4_H__
+
+#include <NGImap4/NGImap4Client.h>
+#include <NGImap4/NGImap4Context.h>
+#include <NGImap4/NGImap4Folder.h>
+#include <NGImap4/NGImap4Message.h>
+#include <NGImap4/NGImap4ResponseParser.h>
+
+// kit class
+
+@interface NGImap4 : NSObject
+@end
+
+#define LINK_NGImap4 \
+  static void __link_NGImap4(void) { \
+    [NGImap4 self]; \
+    __link_NGImap4(); \
+  }
+
+#endif /* __NGImap4_NGImap4_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4.m b/skyrix-core/NGMime/NGImap4/NGImap4.m
new file mode 100644 (file)
index 0000000..b41899e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+// 6313727
+// $Id$
+
+#include "NGImap4.h"
+#include "NGImap4Client.h"
+#include "NGImap4ResponseParser.h"
+#include "NGImap4Folder.h"
+#include "NGImap4Message.h"
+#include "NGImap4Context.h"
+#import <NGStreams/NGStreams.h>
+
+@implementation NGImap4
+
+- (void)_staticLinkClasses {
+  [NGImap4Client         class];
+  [NGImap4ResponseParser class];
+  [NGImap4Folder         class];
+  [NGImap4Message        class];
+  [NGImap4Context        class];
+}
+
+- (void)_staticLinkModules {
+  [NGImap4 class];
+}
+
+@end
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Client.h b/skyrix-core/NGMime/NGImap4/NGImap4Client.h
new file mode 100644 (file)
index 0000000..4cff2b4
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __OGo_NGImap4_NGImap4Client_H__
+#define __OGo_NGImap4_NGImap4Client_H__
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGStreams.h>
+#include <NGStreams/NGSocketProtocols.h>
+#include <NGImap4/NGImap4Support.h>
+
+/*
+  NGImap4Client
+  
+  An IMAP4 client object.
+*/
+
+@class NSMutableArray, NSString, NSNumber, NSDictionary, NSArray, NSURL;
+@class EOGlobalID, EOQualifier;
+@class NGHashMap;
+@class NGImap4ResponseParser, NGImap4Client, NGImap4ResponseNormalizer;
+
+typedef enum {
+  UnConnected_NGImap4State = 1,
+  NonAuthenticated_NGImap4State,
+  Authenticated_NGImap4State,
+  Selected_NGImap4State,
+} NGImap4State;
+
+@interface NGImap4Client : NSObject
+{
+  id<NGActiveSocket>        socket;
+  id<NGExtendedTextStream>  text;
+  id<NGSocketAddress>       address;
+  NGImap4ResponseParser     *parser;
+  NGImap4ResponseNormalizer *normer;
+  NSMutableArray            *responseReceiver;  
+
+  BOOL     isLogin;
+  unsigned tagId;
+
+  NSString *delimiter;
+  NSString *selectedFolder;
+  NSString *login;
+  NSString *password;
+
+  BOOL debug;
+  BOOL useSSL;
+
+  NGImap4Context *context; /* not retained, used to store exceptions */
+  EOGlobalID *serverGID;
+}
+
++ (id)clientWithURL:(NSURL *)_url;
++ (id)clientWithAddress:(id<NGSocketAddress>)_address;
++ (id)clientWithHost:(id)_host;
+
+- (id)initWithURL:(NSURL *)_url;
+- (id)initWithHost:(id)_host;
+- (id)initWithAddress:(id<NGSocketAddress>)_address;
+
+/* equality */
+
+- (BOOL)isEqualToClient:(NGImap4Client *)_obj;
+
+/* accessors */
+
+- (id<NGActiveSocket>)socket;
+- (id<NGSocketAddress>)address;
+- (NSString *)delimiter;
+- (EOGlobalID *)serverGlobalID;
+
+/* notifications */
+
+- (void)registerForResponseNotification:(id<NGImap4ResponseReceiver>)_obj;
+- (void)removeFromResponseNotification:(id<NGImap4ResponseReceiver>)_obj;
+
+/* connection */
+
+- (NSDictionary *)openConnection;
+- (void)closeConnection;
+- (NSNumber *)isConnected;
+- (void)reconnect;
+
+/* commands */
+
+- (NSDictionary *)login:(NSString *)_login password:(NSString *)_passwd;
+- (NSDictionary *)logout;
+- (NSDictionary *)noop;
+  
+- (NSDictionary *)capability;
+- (NSDictionary *)list:(NSString *)_folder pattern:(NSString *)_pattern;
+- (NSDictionary *)lsub:(NSString *)_folder pattern:(NSString *)_pattern;
+- (NSDictionary *)select:(NSString *)_folder;
+- (NSDictionary *)status:(NSString *)_folder flags:(NSArray *)_flags;
+- (NSDictionary *)rename:(NSString *)_folder to:(NSString *)_newName;
+- (NSDictionary *)delete:(NSString *)_folder;
+- (NSDictionary *)create:(NSString *)_name;
+- (NSDictionary *)subscribe:(NSString *)_name;
+- (NSDictionary *)unsubscribe:(NSString *)_name;
+- (NSDictionary *)expunge;
+  
+- (NSDictionary *)sort:(NSArray *)_sortOrderings
+  qualifier:(EOQualifier *)_qual;
+- (NSDictionary *)fetchUids:(NSArray *)_uids parts:(NSArray *)_parts;
+- (NSDictionary *)fetchUid:(unsigned)_uid parts:(NSArray *)_parts;
+- (NSDictionary *)fetchFrom:(unsigned)_from to:(unsigned)_to
+  parts:(NSArray *)_parts;
+- (NSDictionary *)storeUid:(unsigned)_uid add:(NSNumber *)_add
+  flags:(NSArray *)_flags;
+- (NSDictionary *)storeFrom:(unsigned)_from to:(unsigned)_to
+  add:(NSNumber *)_add flags:(NSArray *)_flags;
+- (NSDictionary *)copyUid:(unsigned)_uid toFolder:(NSString *)_folder;
+- (NSDictionary *)copyFrom:(unsigned)_from to:(unsigned)_to
+  toFolder:(NSString *)_folder;
+- (NSDictionary *)append:(NSData *)_message toFolder:(NSString *)_folder
+  withFlags:(NSArray *)_flags;
+- (NSDictionary *)threadBySubject:(BOOL)_bySubject
+  charset:(NSString *)_charSet;
+- (NSDictionary *)getQuotaRoot:(NSString *)_folder;
+
+- (NSDictionary *)searchWithQualifier:(EOQualifier *)_qualifier;
+
+- (void)setContext:(NGImap4Context *)_ctx;
+- (NGImap4Context *)context;
+
+@end
+
+#endif /* __OGo_NGImap4_NGImap4Client_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Client.m b/skyrix-core/NGMime/NGImap4/NGImap4Client.m
new file mode 100644 (file)
index 0000000..879ac19
--- /dev/null
@@ -0,0 +1,1312 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <unistd.h>
+
+#include "NGImap4Client.h"
+#include "NGImap4Context.h"
+#include "NGImap4Support.h"
+#include "NGImap4Functions.h"
+#include "NGImap4ResponseParser.h"
+#include "NGImap4ResponseNormalizer.h"
+#include "NGImap4ServerGlobalID.h"
+#include "NSString+Imap4.h"
+#include "imCommon.h"
+#include <sys/time.h>
+#include "imTimeMacros.h"
+
+@interface EOQualifier(IMAPAdditions)
+- (NSString *)imap4SearchString;
+@end
+
+@interface NGImap4Client(ConnectionRegistration)
+
+- (void)removeFromConnectionRegister;
+- (void)registerConnection;
+- (NGCTextStream *)textStream;
+
+@end /* NGImap4Client(ConnectionRegistration); */
+
+#if GNUSTEP_BASE_LIBRARY
+/* FIXME: TODO: move someplace better (hh: NGExtensions...) */
+@implementation NSException(setUserInfo)
+
+- (id)setUserInfo:(NSDictionary *)_userInfo {
+  ASSIGN(self->_e_info, _userInfo);
+  return self;
+}
+
+@end /* NSException(setUserInfo) */
+#endif
+
+@interface NGImap4Client(Private)
+
+- (NSString *)_folder2ImapFolder:(NSString *)_folder;
+
+- (NGHashMap *)processCommand:(NSString *)_command;
+- (NGHashMap *)processCommand:(NSString *)_command withTag:(BOOL)_tag;
+- (NGHashMap *)processCommand:(NSString *)_command withTag:(BOOL)_tag
+  withNotification:(BOOL)_notification;
+- (NGHashMap *)processCommand:(NSString *)_command logText:(NSString *)_txt;
+
+- (void)sendCommand:(NSString *)_command;
+- (void)sendCommand:(NSString *)_command withTag:(BOOL)_tag;
+- (void)sendCommand:(NSString *)_command withTag:(BOOL)_tag
+        logText:(NSString *)_txt;
+
+- (void)sendResponseNotification:(NGHashMap *)map;
+
+- (NSDictionary *)login;
+
+@end
+
+/*
+  An implementation of an Imap4 client
+  
+  A folder name always looks like an absolute filename (/inbox/doof) 
+*/
+
+@implementation NGImap4Client
+
+// TODO: replace?
+static inline NSArray *_flags2ImapFlags(NGImap4Client *, NSArray *);
+
+static NSNumber *YesNumber     = nil;
+static NSNumber *NoNumber      = nil;
+
+static id           *ImapClients       = NULL;
+static unsigned int CountClient        = 0;
+static unsigned int MaxImapClients     = 0;
+static int          ProfileImapEnabled = -1;
+static int          LogImapEnabled     = -1;
+static int          PreventExceptions  = -1;
+static NSArray      *AllowedSortKeys   = nil;
+static BOOL         fetchDebug         = NO;
+static BOOL         ImapDebugEnabled   = NO;
+
+- (BOOL)useSSL {
+  return self->useSSL;
+}
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  PreventExceptions  = [ud boolForKey:@"ImapPreventConnectionExceptions"]?1:0;
+  LogImapEnabled     = [ud boolForKey:@"ImapLogEnabled"]?1:0;
+  ProfileImapEnabled = [ud boolForKey:@"ProfileImapEnabled"]?1:0;
+  ImapDebugEnabled   = [ud boolForKey:@"ImapDebugEnabled"];
+  
+  YesNumber = [[NSNumber numberWithBool:YES] retain];
+  NoNumber  = [[NSNumber numberWithBool:NO]  retain];
+  
+  if (MaxImapClients < 1) {
+    MaxImapClients = [ud integerForKey:@"NGImapMaxConnectionCount"];
+    if (MaxImapClients < 1) MaxImapClients = 50;
+  }
+  if (ImapClients == NULL)
+    ImapClients = calloc(MaxImapClients + 2, sizeof(id));
+
+  AllowedSortKeys = [[NSArray alloc] initWithObjects:
+                                         @"ARRIVAL", @"CC", @"DATE", @"FROM",
+                                         @"SIZE", @"SUBJECT", @"TO", nil];
+}
+
+/* constructors */
+
++ (id)clientWithURL:(NSURL *)_url {
+  return [[(NGImap4Client *)[self alloc] initWithURL:_url] autorelease];
+}
++ (id)clientWithAddress:(id<NGSocketAddress>)_address {
+  return
+    [[(NGImap4Client *)[self alloc] initWithAddress:_address] autorelease];
+}
+
++ (id)clientWithHost:(id)_host {
+  return [[[self alloc] initWithHost:_host] autorelease];
+}
+
+- (id)initWithHost:(id)_host {
+  NGInternetSocketAddress *a;
+  
+  a = [NGInternetSocketAddress addressWithPort:143 onHost:_host];
+  return [self initWithAddress:a];
+}
+- (id)initWithURL:(NSURL *)_url {
+  NGInternetSocketAddress *a;
+  int port;
+  id  tmp;
+  
+  if ((self->useSSL = [[_url scheme] isEqualToString:@"imaps"])) {
+    if (NSClassFromString(@"NGActiveSSLSocket") == nil) {
+      [self logWithFormat:
+            @"no SSL support available, cannot connect: %@", _url];
+      [self release];
+      return nil;
+    }
+  }
+  if ((tmp = [_url port])) {
+    port = [tmp intValue];
+    if (port <= 0) port = self->useSSL ? 993 : 143;
+  }
+  else
+    port = self->useSSL ? 993 : 143;
+  
+  self->login    = [[_url user]     copy];
+  self->password = [[_url password] copy];
+  
+  a = [NGInternetSocketAddress addressWithPort:port onHost:[_url host]];
+  return [self initWithAddress:a];
+}
+
+- (id)initWithAddress:(id<NGSocketAddress>)_address { /* designated init */
+  if ((self = [super init])) {
+    self->address          = [_address retain];
+    self->debug            = ImapDebugEnabled;
+    self->responseReceiver = [[NSMutableArray alloc] initWithCapacity:128];
+    self->normer = [[NGImap4ResponseNormalizer alloc] initWithClient:self];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self removeFromConnectionRegister];
+  [self->normer           release];
+  [self->text             release];
+  [self->address          release];
+  [self->socket           release];
+  [self->parser           release];
+  [self->responseReceiver release];
+  [self->login            release];
+  [self->password         release];
+  [self->selectedFolder   release];
+  [self->delimiter        release];
+  [self->serverGID        release];
+  
+  self->context = nil; /* not retained */
+  [super dealloc];
+}
+
+/* equality (required for adding clients to Foundation sets) */
+
+- (BOOL)isEqual:(id)_obj {
+  if (_obj == self)
+    return YES;
+  
+  if ([_obj isKindOfClass:[NGImap4Client class]])
+    return [self isEqualToClient:_obj];
+  
+  return NO;
+}
+
+- (BOOL)isEqualToClient:(NGImap4Client *)_obj {
+  if (_obj == self) return YES;
+  if (_obj == nil)  return NO;
+  
+  return [[_obj address] isEqual:self->address];
+}
+
+/* accessors */
+
+- (id<NGActiveSocket>)socket {
+  return self->socket;
+}
+
+- (id<NGSocketAddress>)address {
+  return self->address;
+}
+
+- (NSString *)delimiter {
+  return self->delimiter;
+}
+
+- (EOGlobalID *)serverGlobalID {
+  NGInternetSocketAddress *is;
+  
+  if (self->serverGID)
+    return self->serverGID;
+  
+  is = (id)[self address];
+  
+  self->serverGID = [[NGImap4ServerGlobalID alloc]
+                     initWithHostname:[is hostName]
+                     port:[is port]
+                     login:self->login];
+  return self->serverGID;
+}
+
+/* connection */
+
+- (id)_openSocket {
+  Class socketClass = Nil;
+  id sock;
+
+  socketClass = [self useSSL] 
+    ? NSClassFromString(@"NGActiveSSLSocket")
+    : [NGActiveSocket class];
+  
+  NS_DURING {
+    sock = [socketClass socketConnectedToAddress:self->address];
+  }
+  NS_HANDLER {
+    [self->context setLastException:localException];
+    sock = nil;
+  }
+  NS_ENDHANDLER;
+  
+  return sock;
+}
+
+- (NSDictionary *)_receiveServerGreetingWithoutTagId {
+  NSDictionary *res = nil;
+  
+  NS_DURING {
+    NSException *e;
+    NGHashMap *hm;
+    
+    hm = [self->parser parseResponseForTagId:-1 exception:&e];
+    [e raise];
+    res = [self->normer normalizeOpenConnectionResponse:hm];
+  }
+  NS_HANDLER
+    [self->context setLastException:localException];
+  NS_ENDHANDLER;
+  
+  if (!_checkResult(self->context, res, __PRETTY_FUNCTION__))
+    return nil;
+  
+  return res;
+}
+
+- (NSDictionary *)_openConnection {
+  /* open connection as configured */
+  NGBufferedStream *buffer;
+  struct timeval tv;
+  double         ti = 0.0;
+  
+  if (ProfileImapEnabled == 1) {
+    gettimeofday(&tv, NULL);
+    ti =  (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0);
+  }
+  [self->socket release]; self->socket = nil;
+  [self->parser release]; self->parser = nil;
+  [self->text   release]; self->text   = nil;
+  
+  [self->context resetLastException];
+
+  if ((self->socket = [[self _openSocket] retain]) == nil)
+    return nil;
+  if ([self->context lastException])
+    return nil;
+  
+  buffer     = 
+    [(NGBufferedStream *)[NGBufferedStream alloc] initWithSource:self->socket];
+  self->text = [(NGCTextStream *)[NGCTextStream alloc] initWithSource:buffer];
+  [buffer release]; buffer = nil;
+  
+  self->parser = [[NGImap4ResponseParser alloc] initWithStream:self->socket];
+  self->tagId  = 0;
+  
+  if (ProfileImapEnabled == 1) {
+    gettimeofday(&tv, NULL);
+    ti = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0) - ti;
+    fprintf(stderr, "[%s] <openConnection> : time needed: %4.4fs\n",
+           __PRETTY_FUNCTION__, ti < 0.0 ? -1.0 : ti);    
+  }
+  [self registerConnection];
+  [self->context resetLastException];
+  
+  return [self _receiveServerGreetingWithoutTagId];
+}
+
+- (NSDictionary *)openConnection {
+  return [self _openConnection];
+}
+
+- (NSNumber *)isConnected {
+  /* 
+     Check whether stream is already open (could be closed because 
+     server-timeout) 
+  */
+  return (self->socket == nil)
+    ? NoNumber 
+    : ([(NGActiveSocket *)self->socket isAlive] ? YesNumber : NoNumber);
+}
+
+- (NSException *)_handleTextReleaseException:(NSException *)_ex {
+  [self logWithFormat:@"got exception during stream dealloc: %@", _ex];
+  return nil;
+}
+- (NSException *)_handleSocketCloseException:(NSException *)_ex {
+  [self logWithFormat:@"got exception during socket close: %@", _ex];
+  return nil;
+}
+- (NSException *)_handleSocketReleaseException:(NSException *)_ex {
+  [self logWithFormat:@"got exception during socket deallocation: %@", _ex];
+  return nil;
+}
+- (void)closeConnection {
+  /* close a connection */
+  
+  // TODO: this is a bit weird, probably because of the flush
+  //       maybe just call -close on the text stream?
+  NS_DURING
+    [self->text release]; 
+  NS_HANDLER
+    [[self _handleTextReleaseException:localException] raise];
+  NS_ENDHANDLER;
+  self->text = nil;
+  
+  NS_DURING
+    [self->socket close];
+  NS_HANDLER
+    [[self _handleSocketCloseException:localException] raise];
+  NS_ENDHANDLER;
+  
+  NS_DURING
+    [self->socket release];
+  NS_HANDLER
+    [[self _handleSocketReleaseException:localException] raise];
+  NS_ENDHANDLER;
+  self->socket = nil;
+  
+  [self->parser    release]; self->parser    = nil;
+  [self->delimiter release]; self->delimiter = nil;
+  [self removeFromConnectionRegister];
+}
+
+// ResponseNotifications
+
+- (void)registerForResponseNotification:(id<NGImap4ResponseReceiver>)_obj {
+  [self->responseReceiver addObject:[NSValue valueWithNonretainedObject:_obj]];
+}
+
+- (void)removeFromResponseNotification:(id<NGImap4ResponseReceiver>)_obj {
+  [self->responseReceiver removeObject:
+       [NSValue valueWithNonretainedObject:_obj]];
+}
+
+- (void)sendResponseNotification:(NGHashMap *)_map {
+  NSValue                     *val;
+  id<NGImap4ResponseReceiver> obj;
+  NSEnumerator                *enumerator;
+  NSDictionary                *resp;
+
+  resp       = [self->normer normalizeResponse:_map];
+  enumerator = [self->responseReceiver objectEnumerator];
+
+  while ((val = [enumerator nextObject])) {
+    obj = [val nonretainedObjectValue];
+    [obj responseNotificationFrom:self response:resp];
+  }
+}
+
+/* commands */
+
+- (NSDictionary *)login:(NSString *)_login password:(NSString *)_passwd {
+  /* login with plaintext password authenticating */
+
+  if ((_login == nil) || (_passwd == nil))
+    return nil;
+
+  [self->login     release]; self->login    = nil;
+  [self->password  release]; self->password = nil;
+  [self->serverGID release]; self->serverGID = nil;
+  
+  self->login    = [_login copy];
+  self->password = [[_passwd stringByEscapingImap4Password] copy];
+  
+  return [self login];
+}
+
+- (void)reconnect {
+  if ([self->context lastException] != nil)
+    return;
+    
+  [self closeConnection];  
+  self->tagId = 0;
+  [self openConnection];
+
+  if ([self->context lastException] != nil)
+    return;
+  
+  [self login];
+}
+
+- (NSDictionary *)login {
+  NGHashMap *map;
+  NSString  *s, *log;
+
+  if (self->isLogin )
+    return nil;
+  
+  self->isLogin = YES;
+
+  s = [NSString stringWithFormat:@"login \"%@\" \"%@\"",
+                 self->login, self->password];
+  log = [NSString stringWithFormat:@"login %@ <%@>",
+                   self->login,
+                   (self->password != nil) ? @"PASSWORD" : @"NO PASSWORD"];
+  map = [self processCommand:s logText:log];
+  
+  if (self->selectedFolder)
+    [self select:self->selectedFolder];
+  
+  self->isLogin = NO;
+  
+  return [self->normer normalizeResponse:map];
+}
+
+- (NSDictionary *)logout {
+  /* logout from the connected host and close the connection */
+  NGHashMap *map;
+
+  map = [self processCommand:@"logout"];
+  [self closeConnection];
+  
+  return [self->normer normalizeResponse:map];
+}
+
+/* Authenticated State */
+
+- (NSDictionary *)list:(NSString *)_folder pattern:(NSString *)_pattern {
+  /*
+    The method build statements like 'LIST "_folder" "_pattern"'.
+    The Cyrus IMAP4 v1.5.14 server ignores the given folder.
+    Instead of you should use the pattern to get the expected result.
+    If folder is NIL it would be set to empty string ''.
+    If pattern is NIL it would be set to ''.
+  */
+  NSAutoreleasePool *pool;
+  NGHashMap         *map;
+  NSDictionary      *result;
+  NSString *s;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  if (_folder  == nil) _folder  = @"";
+  if (_pattern == nil) _pattern = @"";
+  
+  if ([_folder length] > 0) {
+    if ((_folder = [self _folder2ImapFolder:_folder]) == nil)
+      return nil;
+  }
+  
+
+  if ([_pattern length] > 0)
+    if (!(_pattern = [self _folder2ImapFolder:_pattern]))
+      return nil;
+  
+  s = [NSString stringWithFormat:@"list \"%@\" \"%@\"", _folder, _pattern];
+  map = [self processCommand:s];
+  
+  if (self->delimiter == nil) {
+    NSDictionary *rdel;
+    
+    rdel = [[map objectEnumeratorForKey:@"list"] nextObject];
+    self->delimiter = [[rdel objectForKey:@"delimiter"] copy];
+  }
+  
+  result = [[self->normer normalizeListResponse:map] copy];
+  [pool release];
+  return [result autorelease];
+}
+
+- (NSDictionary *)capability {
+  id capres;
+  capres = [self processCommand:@"capability"];
+  return [self->normer normalizeCapabilityRespone:capres];
+}
+
+- (NSDictionary *)lsub:(NSString *)_folder pattern:(NSString *)_pattern {
+  /*
+    The method build statements like 'LSUB "_folder" "_pattern"'.
+    The returnvalue is the same like the list:pattern: method
+  */
+  NGHashMap *map;
+  NSString  *s;
+
+  if (_folder == nil)
+    _folder = @"";
+
+  if ([_folder length] > 0) {
+    if ((_folder = [self _folder2ImapFolder:_folder]) == nil)
+      return nil;
+  }
+  if (_pattern == nil)
+    _pattern = @"";
+
+  if ([_pattern length] > 0) {
+    if ((_pattern = [self _folder2ImapFolder:_pattern]) == nil)
+      return nil;
+  }
+  
+  s = [NSString stringWithFormat:@"lsub \"%@\" \"%@\"", _folder, _pattern];
+  map = [self processCommand:s];
+
+  if (self->delimiter == nil) {
+    NSDictionary *rdel;
+    
+    rdel = [[map objectEnumeratorForKey:@"LIST"] nextObject];
+    self->delimiter = [[rdel objectForKey:@"delimiter"] copy];
+  }
+  return [self->normer normalizeListResponse:map];
+}
+
+- (NSDictionary *)select:(NSString *)_folder {
+  NSString *s;
+  id tmp;
+
+  tmp = self->selectedFolder;
+
+  if ([_folder length] == 0)
+    return nil;
+  if ((_folder = [self _folder2ImapFolder:_folder]) == nil)
+    return nil;
+
+  self->selectedFolder = [_folder copy];
+  
+  [tmp release]; tmp = nil;
+
+  s = [NSString stringWithFormat:@"select \"%@\"", self->selectedFolder];
+  return [self->normer normalizeSelectResponse:[self processCommand:s]];
+}
+
+- (NSDictionary *)status:(NSString *)_folder flags:(NSArray *)_flags {
+  NSString *cmd;
+  
+  if (_folder == nil)
+    return nil;
+  if ((_flags == nil) || ([_flags count] == 0))
+    return nil;
+  if ((_folder = [self _folder2ImapFolder:_folder]) == nil)
+    return nil;
+  
+  cmd     = [NSString stringWithFormat:@"status \"%@\" (%@)",
+                      _folder, [_flags componentsJoinedByString:@" "]];
+  return [self->normer normalizeStatusResponse:[self processCommand:cmd]];
+}
+
+- (NSDictionary *)noop {
+  // at any state
+  return [self->normer normalizeResponse:[self processCommand:@"noop"]];
+}
+
+- (NSDictionary *)rename:(NSString *)_folder to:(NSString *)_newName {
+  NSString *cmd;
+  
+  if ((_folder = [self _folder2ImapFolder:_folder]) == nil)
+    return nil;
+  if ((_newName = [self _folder2ImapFolder:_newName]) == nil)
+    return nil;
+  
+  cmd = [NSString stringWithFormat:@"rename \"%@\" \"%@\"", _folder, _newName];
+  
+  return [self->normer normalizeResponse:[self processCommand:cmd]];
+}
+
+- (NSDictionary *)_performCommand:(NSString *)_op onFolder:(NSString *)_fname {
+  NSString *command;
+  
+  if ((_fname = [self _folder2ImapFolder:_fname]) == nil)
+    return nil;
+  
+  // eg: 'delete "blah"'
+  command = [NSString stringWithFormat:@"%@ \"%@\"", _op, _fname];
+  
+  return [self->normer normalizeResponse:[self processCommand:command]];
+}
+
+- (NSDictionary *)delete:(NSString *)_name {
+  return [self _performCommand:@"delete" onFolder:_name];
+}
+- (NSDictionary *)create:(NSString *)_name {
+  return [self _performCommand:@"create" onFolder:_name];
+}
+- (NSDictionary *)subscribe:(NSString *)_name {
+  return [self _performCommand:@"subscribe" onFolder:_name];
+}
+- (NSDictionary *)unsubscribe:(NSString *)_name {
+  return [self _performCommand:@"unsubscribe" onFolder:_name];
+}
+
+- (NSDictionary *)expunge {
+  return [self->normer normalizeResponse:[self processCommand:@"expunge"]];
+}
+
+- (NSString *)_uidsJoinedForFetchCmd:(NSArray *)_uids {
+  return [_uids componentsJoinedByString:@","];
+}
+- (NSString *)_partsJoinedForFetchCmd:(NSArray *)_parts {
+  return [_parts componentsJoinedByString:@" "];
+}
+
+- (NSDictionary *)fetchUids:(NSArray *)_uids parts:(NSArray *)_parts {
+  NSAutoreleasePool *pool;
+  NSString          *cmd;
+  NSDictionary      *result;
+  id fetchres;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  cmd  = [NSString stringWithFormat:@"uid fetch %@ (%@)",
+                  [self _uidsJoinedForFetchCmd:_uids],
+                  [self _partsJoinedForFetchCmd:_parts]];
+  
+  fetchres = [self processCommand:cmd];
+  result   = [[self->normer normalizeFetchResponse:fetchres] retain];
+  [pool release];
+  
+  return [result autorelease];
+}
+
+- (NSDictionary *)fetchUid:(unsigned)_uid parts:(NSArray *)_parts {
+  // TODO: describe what exactly this can return!
+  NSAutoreleasePool *pool;
+  NSString          *cmd;
+  NSDictionary      *result;
+  id fetchres;
+  
+  pool   = [[NSAutoreleasePool alloc] init];
+  cmd    = [NSString stringWithFormat:@"uid fetch %d (%@)", _uid,
+                     [self _partsJoinedForFetchCmd:_parts]];
+  fetchres = [self processCommand:cmd];
+  result   = [[self->normer normalizeFetchResponse:fetchres] retain];
+  
+  [pool release];
+  return [result autorelease];
+}
+
+- (NSDictionary *)fetchFrom:(unsigned)_from to:(unsigned)_to
+  parts:(NSArray *)_parts
+{
+  // TODO: optimize
+  NSAutoreleasePool *pool;
+  NSMutableString   *cmd;
+  NSDictionary      *result; 
+  NGHashMap         *rawResult;
+  if (_to == 0)
+    return [self noop];
+  
+  if (_from == 0)
+    _from = 1;
+
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    unsigned i, count;
+    
+    cmd = [NSMutableString stringWithCapacity:256];
+    [cmd appendString:@"fetch "];
+    [cmd appendFormat:@"%d:%d (", _from, _to];
+    for (i = 0, count = [_parts count]; i < count; i++) {
+      if (i != 0) [cmd appendString:@" "];
+      [cmd appendString:[_parts objectAtIndex:i]];
+    }
+    [cmd appendString:@")"];
+    
+    if (fetchDebug) NSLog(@"%s: process: %@", __PRETTY_FUNCTION__, cmd);
+    rawResult = [self processCommand:cmd];
+    /*
+      RawResult is a dict containing keys:
+        ResponseResult: dict    eg: {descripted=Completed;result=ok;tagId=8;}
+       fetch:          array of record dicts (eg "rfc822.header" key)
+    */
+    
+    if (fetchDebug) NSLog(@"%s: normalize: %@", __PRETTY_FUNCTION__,rawResult);
+    result = [[self->normer normalizeFetchResponse:rawResult] retain];
+    if (fetchDebug) NSLog(@"%s: normalized: %@", __PRETTY_FUNCTION__, result);
+  }
+  [pool release];
+  if (fetchDebug) NSLog(@"%s: pool done.", __PRETTY_FUNCTION__);
+  return [result autorelease];
+}
+
+- (NSDictionary *)storeUid:(unsigned)_uid add:(NSNumber *)_add
+  flags:(NSArray *)_flags
+{
+  NSString *icmd, *iflags;
+  
+  iflags = [_flags2ImapFlags(self, _flags) componentsJoinedByString:@" "];
+  icmd   = [NSString stringWithFormat:@"uid store %d %cFLAGS (%@)",
+                     _uid, [_add boolValue] ? '+' : '-',
+                     iflags];
+  return [self->normer normalizeResponse:[self processCommand:icmd]];
+}
+
+- (NSDictionary *)storeFrom:(unsigned)_from to:(unsigned)_to
+  add:(NSNumber *)_add
+  flags:(NSArray *)_flags
+{
+  NSString *cmd;
+  NSString *flagstr;
+
+  if (_to == 0)
+    return [self noop];
+  if (_from == 0)
+    _from = 1;
+
+  flagstr = [_flags2ImapFlags(self, _flags) componentsJoinedByString:@" "];
+  cmd = [NSString stringWithFormat:@"store %d:%d %cFLAGS (%@)",
+                   _from, _to, [_add boolValue] ? '+' : '-', flagstr];
+  
+  return [self->normer normalizeResponse:[self processCommand:cmd]];
+}
+
+- (NSDictionary *)copyFrom:(unsigned)_from to:(unsigned)_to
+  toFolder:(NSString *)_folder
+{
+  NSString *cmd;
+
+  if (_to == 0)
+    return [self noop];
+  if (_from == 0)
+    _from = 1;
+  if ((_folder = [self _folder2ImapFolder:_folder]) == nil)
+    return nil;
+  
+  cmd = [NSString stringWithFormat:@"copy %d:%d \"%@\"", _from, _to, _folder];
+  return [self->normer normalizeResponse:[self processCommand:cmd]];
+}
+
+- (NSDictionary *)copyUid:(unsigned)_uid toFolder:(NSString *)_folder {
+  NSString *cmd;
+  
+  if ((_folder = [self _folder2ImapFolder:_folder]) == nil)
+    return nil;
+  
+  cmd = [NSString stringWithFormat:@"uid copy %d \"%@\"", _uid, _folder];
+  
+  return [self->normer normalizeResponse:[self processCommand:cmd]];
+}
+
+- (NSDictionary *)getQuotaRoot:(NSString *)_folder {
+  NSString *cmd;
+
+  if ((_folder = [self _folder2ImapFolder:_folder]) == nil)
+    return nil;
+  
+  cmd = [NSString stringWithFormat:@"getquotaroot \"%@\"", _folder];
+  return [self->normer normalizeQuotaResponse:[self processCommand:cmd]];
+}
+
+- (NSDictionary *)append:(NSData *)_message toFolder:(NSString *)_folder
+  withFlags:(NSArray *)_flags
+{
+  NSArray   *flags;
+  NGHashMap *result;
+  NSString  *message, *icmd;
+
+  flags   = _flags2ImapFlags(self, _flags);
+  if ((_folder = [self _folder2ImapFolder:_folder]) == nil)
+    return nil;
+  
+
+  /* Remove bare newlines */
+  {
+    char       *new;
+    const char *old;
+    int         cntOld   = 0;
+    int         cntNew   = 0;
+    int         len      = 0;
+    
+    old = [_message bytes];
+    len = [_message length];
+    
+    new = calloc(len * 2 + 4, sizeof(char));
+    
+    while (cntOld < (len - 1)) {
+      if (old[cntOld] == '\n') {
+        new[cntNew++] = '\r';
+        new[cntNew++] = '\n';
+      }
+      else if (old[cntOld] != '\r') {
+        new[cntNew++] = old[cntOld];
+      }
+      cntOld++;
+    }
+    if (old[cntOld] == '\n') {
+      new[cntNew++] = '\r';
+      new[cntNew++] = '\n';
+    }
+    else if (old[cntOld] != '\r') {
+      new[cntNew++] = old[cntOld];
+    } 
+    message = [(NSString *)[NSString alloc] 
+                  initWithCString:new length:cntNew];
+    if (new) free(new); new = NULL;
+  }
+  
+  icmd = [NSString stringWithFormat:@"append \"%@\" (%@) {%d}",
+                     _folder,
+                     [flags componentsJoinedByString:@" "],
+                     [message cStringLength]];
+  result = [self processCommand:icmd
+                 withTag:YES withNotification:NO];
+  
+  if ([[result objectForKey:@"ContinuationResponse"] boolValue])
+    result = [self processCommand:message withTag:NO];
+
+  [message release]; message = nil;
+
+  return [self->normer normalizeResponse:result];
+}
+
+- (void)_handleSearchExprIssue:(NSString *)reason qualifier:(EOQualifier *)_q {
+  NSString     *descr;
+  NSException  *exception = nil;                                             
+  NSDictionary *ui;
+  
+  if (PreventExceptions != 0)
+    return;
+  
+  if (_q == nil) _q = (id)[NSNull null];                
+  
+  descr = @"Could not process qualifier for imap search "; 
+  descr = [descr stringByAppendingString:reason];           
+  
+  exception = [[NGImap4SearchException alloc] initWithFormat:@"%@", descr];    
+  ui = [NSDictionary dictionaryWithObject:_q forKey:@"qualifier"];
+  [exception setUserInfo:ui];
+  [self->context setLastException:exception];
+  [exception release];
+}
+
+- (NSString *)_searchExprForQual:(EOQualifier *)_qualifier {
+  id result;
+  
+  if (_qualifier == nil)
+    return @" ALL";
+  
+  result = [_qualifier imap4SearchString];
+  if ([result isKindOfClass:[NSException class]]) {
+    [self _handleSearchExprIssue:[(NSException *)result reason]
+          qualifier:_qualifier];
+    return nil;
+  }
+  return result;
+}
+
+/* siehe draft-ietf-imapext-thread-12.txt
+   returns an array of uids in sort order */
+
+- (NSDictionary *)threadBySubject:(BOOL)_bySubject
+  charset:(NSString *)_charSet
+{
+  NSString *threadStr;
+  NSString *threadAlg;
+
+  if (_bySubject)
+    threadAlg = @"REFERENCES";
+  else
+    threadAlg = @"ORDEREDSUBJECT";
+    
+  
+  if (![_charSet length])
+    _charSet = @"UTF-8";
+
+  threadStr = [NSString stringWithFormat:@"UID THREAD %@ %@ ALL",
+                      threadAlg, _charSet];
+
+  return [self->normer normalizeThreadResponse:
+               [self processCommand:threadStr]];
+}
+
+- (NSDictionary *)sort:(NSArray *)_sortOrderings
+  qualifier:(EOQualifier *)_qual
+{
+  /* siehe draft-ietf-imapext-sort */
+  /* returns an array of uids in sort order */
+  NSMutableString *sortStr;
+  NSEnumerator    *enumerator;
+  EOSortOrdering  *so;
+  BOOL            isFirst = YES;
+
+  sortStr = [NSMutableString stringWithCapacity:128];
+  
+  if ([_sortOrderings count] == 0)
+    return [NSDictionary dictionaryWithObjectsAndKeys:@"result", NoNumber,nil];
+  
+  enumerator = [_sortOrderings objectEnumerator];
+
+  [sortStr appendString:@"UID SORT ("];
+  
+  while ((so = [enumerator nextObject])) {
+    SEL      sel;
+    NSString *key;
+    
+    key = [[so key] uppercaseString];
+    
+    if ([key length] == 0)
+      continue;
+
+    if (![AllowedSortKeys containsObject:key]) {
+      [self logWithFormat:@"ERROR[%s] key %@ is not allowed here!",
+            __PRETTY_FUNCTION__, key];
+      continue;
+    }
+    if (isFirst)
+      isFirst = NO;
+    else
+      [sortStr appendString:@" "];
+    sel = [so selector];
+
+    if (sel_eq(sel, EOCompareDescending) ||
+        sel_eq(sel, EOCompareCaseInsensitiveDescending)) {
+      [sortStr appendString:@"REVERSE "];
+    }
+    [sortStr appendString:[so key]];
+  }
+  if (isFirst) { /* found no valid key use date sorting */
+    [sortStr appendString:@"DATE"];
+#if 0    
+    return [NSDictionary dictionaryWithObjectsAndKeys:
+                          NoNumber, @"result", nil];
+#endif    
+  }
+  [sortStr appendString:@") "];
+  // TODO: make that the other way around! should be an ivar in the client
+  [sortStr appendString:[[self context] sortEncoding]];
+  [sortStr appendString:[self _searchExprForQual:_qual]];
+  
+  return [self->normer normalizeSortResponse:[self processCommand:sortStr]];
+}
+
+- (NSDictionary *)searchWithQualifier:(EOQualifier *)_qualifier {
+  NSString *s;
+  
+  s = [self _searchExprForQual:_qualifier];
+  if ([s length] == 0) {
+    // TODO: should set last-exception?
+    [self logWithFormat:@"ERROR(%s): could not process search qualifier: %@",
+          __PRETTY_FUNCTION__, _qualifier];
+    return nil;
+  }
+  
+  s = [@"search" stringByAppendingString:s];
+  return [self->normer normalizeSearchResponse:[self processCommand:s]];
+}
+
+/* Private Methods */
+
+- (NSException *)_processCommandParserException:(NSException *)_exception {
+  NSLog(@"ERROR(%s): catched IMAP4 parser exception %@: %@",
+       __PRETTY_FUNCTION__, [_exception name], [_exception reason]);
+  [self closeConnection];
+  [self->context setLastException:_exception];
+  return nil;
+}
+- (NSException *)_processUnknownCommandParserException:(NSException *)_ex {
+  NSLog(@"ERROR(%s): catched non-IMAP4 parsing exception %@: %@",
+       __PRETTY_FUNCTION__, [_ex name], [_ex reason]);
+  return nil;
+}
+
+- (NSException *)_handleShutdownDuringCommandException:(NSException *)_ex {
+  NSLog(@"ERROR(%s): IMAP4 socket was shut down by server %@: %@",
+       __PRETTY_FUNCTION__, [_ex name], [_ex reason]);
+  [self closeConnection];
+  [self->context setLastException:_ex];
+  return nil;
+}
+
+- (BOOL)_isShutdownException:(NSException *)_ex {
+  return [[_ex name] isEqualToString:@"NGSocketShutdownDuringReadException"];
+}
+
+- (BOOL)_isLoginCommand:(NSString *)_command {
+  return [_command hasPrefix:@"login"];
+}
+
+- (NGHashMap *)processCommand:(NSString *)_command withTag:(BOOL)_tag
+  withNotification:(BOOL)_notification logText:(NSString *)_txt
+{
+  NGHashMap    *map;
+  BOOL         tryReconnect;
+  int          reconnectCnt;
+  NSException  *exception;
+
+  struct timeval tv;
+  double         ti = 0.0;
+
+  if (ProfileImapEnabled == 1) {
+    gettimeofday(&tv, NULL);
+    ti =  (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0);
+    fprintf(stderr, "{");
+  }
+  tryReconnect = NO;
+  reconnectCnt = 0;
+  map          = nil;
+  exception    = nil;
+
+  do {
+    tryReconnect  = NO;
+    [self->context resetLastException];
+    NS_DURING {
+      NSException *e = nil; // TODO: try to remove exception handler
+      
+      [self sendCommand:_command withTag:_tag logText:_txt];
+      map = [self->parser parseResponseForTagId:self->tagId exception:&e];
+      [e raise];
+      tryReconnect = NO;
+    }
+    NS_HANDLER {
+      if ([localException isKindOfClass:[NGImap4ParserException class]]) {
+       [[self _processCommandParserException:localException] raise];
+      }
+      else if ([self _isShutdownException:localException]) {
+       [[self _handleShutdownDuringCommandException:localException] raise];
+      }
+      else {
+        [[self _processUnknownCommandParserException:localException] raise];
+        if (reconnectCnt == 0) {
+          if (![self _isLoginCommand:_command]) {
+            reconnectCnt++;
+            tryReconnect = YES;
+            exception    = localException;
+          }
+        }
+       [self closeConnection];
+       [self->context setLastException:localException];
+      }
+    }
+    NS_ENDHANDLER;
+
+    if (tryReconnect) {
+      [self reconnect];
+    }
+    else if ([map objectForKey:@"bye"] && ![_command hasPrefix:@"logout"]) {
+      if (reconnectCnt == 0) {
+        reconnectCnt++;
+        tryReconnect = YES;
+        [self reconnect];
+      }
+    }
+  } while (tryReconnect);
+
+  if ([self->context lastException]) {
+    if (exception) {
+      [self->context setLastException:exception];
+    }
+    return nil;
+  }
+  if (_notification) [self sendResponseNotification:map];
+
+  if (ProfileImapEnabled == 1) {
+    gettimeofday(&tv, NULL);
+    ti = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0) - ti;
+    fprintf(stderr, "}[%s] <Send Command [%s]> : time needed: %4.4fs\n",
+           __PRETTY_FUNCTION__, [_command cString], ti < 0.0 ? -1.0 : ti);    
+  }
+  return map;
+}
+
+- (NGHashMap *)processCommand:(NSString *)_command withTag:(BOOL)_tag
+  withNotification:(BOOL)_notification
+{
+  return [self processCommand:_command withTag:_tag
+               withNotification:_notification
+               logText:_command];
+}
+
+- (NGHashMap *)processCommand:(NSString *)_command withTag:(BOOL)_tag {
+  return [self processCommand:_command withTag:_tag withNotification:YES
+               logText:_command];
+}
+
+- (NGHashMap *)processCommand:(NSString *)_command {
+  return [self processCommand:_command withTag:YES withNotification:YES
+               logText:_command];
+}
+
+- (NGHashMap *)processCommand:(NSString *)_command logText:(NSString *)_txt {
+  return [self processCommand:_command withTag:YES withNotification:YES
+               logText:_txt];
+}
+
+- (void)sendCommand:(NSString *)_command withTag:(BOOL)_tag
+  logText:(NSString *)_txt
+{
+  NSString      *command;
+  NGCTextStream *txtStream;
+
+  txtStream = [self textStream];
+
+  if (_tag) {
+    self->tagId++;
+
+    command = [NSString stringWithFormat:@"%d %@", self->tagId, _command];
+    if (self->debug) {
+      _txt = [NSString stringWithFormat:@"%d %@", self->tagId, _txt];
+    }
+  }
+  else
+    command = _command;
+
+  if (self->debug) {
+    if ([_txt length] > 5000) {
+      fprintf(stderr, "C[%p]: %s...\n", self, [[_txt substringToIndex:5000]
+                                                  cString]);
+    }
+    else {
+      fprintf(stderr, "C[%p]: %s\n", self, [_txt cString]);
+    }
+  }
+  
+  if (![txtStream writeString:command])
+    [self->context setLastException:[txtStream lastException]];
+  else if (![txtStream writeString:@"\r\n"])
+    [self->context setLastException:[txtStream lastException]];
+  else if (![txtStream flush])
+    [self->context setLastException:[txtStream lastException]];
+}
+  
+- (void)sendCommand:(NSString *)_command withTag:(BOOL)_tag {
+  [self sendCommand:_command withTag:_tag logText:_command];
+}
+
+- (void)sendCommand:(NSString *)_command {
+  [self sendCommand:_command withTag:YES logText:_command];
+}
+
+static inline NSArray *_flags2ImapFlags(NGImap4Client *self, NSArray *_flags) {
+  NSEnumerator *enumerator;
+  NSArray      *result;
+  id           obj;
+  id           *objs;
+  unsigned     cnt;
+
+  objs = calloc([_flags count] + 2, sizeof(id));
+  cnt  = 0;
+  enumerator = [_flags objectEnumerator];
+  while ((obj = [enumerator nextObject])) {
+    objs[cnt] = [@"\\" stringByAppendingString:obj];
+    cnt++;
+  }
+  result = [NSArray arrayWithObjects:objs count:cnt];
+  if (objs) free(objs);
+  return result;
+}
+
+- (NSString *)_folder2ImapFolder:(NSString *)_folder {
+  NSArray *array;
+  
+  if (self->delimiter == nil) {
+    NSDictionary *res;
+
+    res = [self list:@"" pattern:@""];
+
+    if (!_checkResult(self->context, res, __PRETTY_FUNCTION__))
+      return nil;
+  }
+
+  array = [_folder pathComponents];
+
+  if ([array count] > 0) {
+    NSString *o;
+
+    o = [array objectAtIndex:0];
+    if (([o isEqualToString:@"/"]) || ([o length] == 0))
+      array = [array subarrayWithRange:NSMakeRange(1, [array count] - 1)];
+    
+    o = [array lastObject];
+    if (([o length] == 0) || ([o isEqualToString:@"/"]))
+      array = [array subarrayWithRange:NSMakeRange(0, [array count] - 1)];
+  }
+  return [[array componentsJoinedByString:self->delimiter]
+                 stringByEncodingImap4FolderName];
+}
+
+- (NSString *)_imapFolder2Folder:(NSString *)_folder {
+  NSArray *array;
+  
+  array = [NSArray arrayWithObject:@""];
+
+  if ([self delimiter] == nil) {
+    NSDictionary *res;
+    
+    res = [self list:@"" pattern:@""]; // fill the delimiter ivar?
+    if (!_checkResult(self->context, res, __PRETTY_FUNCTION__))
+      return nil;
+  }
+  
+  array = [array arrayByAddingObjectsFromArray:
+                   [_folder componentsSeparatedByString:[self delimiter]]];
+  
+  return [[NSString pathWithComponents:array] stringByDecodingImap4FolderName];
+}
+
+- (void)setContext:(NGImap4Context *)_ctx {
+  self->context = _ctx;
+}
+- (NGImap4Context *)context {
+  return self->context;
+}
+
+/* ConnectionRegistration */
+
+- (void)removeFromConnectionRegister {
+  unsigned cnt;
+  
+  for (cnt = 0; cnt < MaxImapClients; cnt++) {
+    if (ImapClients[cnt] == self)
+      ImapClients[cnt] = nil;
+  }
+}
+
+- (void)registerConnection {
+  int cnt;
+
+  cnt =  CountClient % MaxImapClients;
+
+  if (ImapClients[cnt]) {
+    [(NGImap4Context *)ImapClients[cnt] closeConnection];
+  }
+  ImapClients[cnt] = self;
+  CountClient++;
+}
+
+- (id<NGExtendedTextStream>)textStream {
+  if (self->text == nil) {
+    if ([self->context lastException] == nil)
+      [self reconnect];
+  }
+  return self->text;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  [ms appendFormat:@" socket=%@", [self socket]];
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* NGImap4Client; */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Context.h b/skyrix-core/NGMime/NGImap4/NGImap4Context.h
new file mode 100644 (file)
index 0000000..d059987
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __OGo_NGImap4_NGImap4Context_H__
+#define __OGo_NGImap4_NGImap4Context_H__
+
+#import <Foundation/NSObject.h>
+#include <NGImap4/NGImap4Support.h>
+
+@class NSDictionary, NGHashMap, NSMutableArray, NSURL, NSException;
+@class EOGlobalID;
+@class NGImap4Client, NGImap4Folder, NGImap4ServerRoot;
+
+@interface NGImap4Context : NSObject <NGImap4ResponseReceiver>
+{
+  NSDictionary      *connectionDictionary;
+  NSMutableArray    *folderForRefresh;
+  NGImap4Client     *client;
+  NGImap4Folder     *selectedFolder; /* not retained */
+  NGImap4Folder     *trashFolder;    /* not retained */
+  NGImap4Folder     *sentFolder;     /* not retained */
+  NGImap4Folder     *draftsFolder;   /* not retained */
+  NGImap4Folder     *inboxFolder;    /* not retained */  
+  NGImap4ServerRoot *serverRoot;     /* not retained */
+
+  NSArray           *capability; // TODO: array of what?
+
+  NSString *sentFolderName;
+  NSString *trashFolderName;
+  NSString *draftsFolderName;
+
+  NSString *serverName;
+  NSString *serverKind;
+  NSNumber *serverVersion;
+  NSNumber *serverSubVersion;
+  NSNumber *serverTag;
+  
+  BOOL syncMode;
+  
+  NSException *lastException;
+
+  NSURL *url;
+
+  int canSort;
+  int canQuota;
+
+  NSString *sortEncoding;
+  int      subscribeFolderFailed;
+  int      showOnlySubscribedInRoot;
+  int      showOnlySubscribedInSubFolders;
+}
+
+
++ (id)imap4ContextWithURL:(id)_url;
++ (id)imap4ContextWithConnectionDictionary:(NSDictionary *)_connection;
+- (id)initWithNSURL:(NSURL *)_url;
+- (id)initWithURL:(id)_url;
+- (id)initWithConnectionDictionary:(NSDictionary *)_connection;
+
+/* accessors */
+
+- (NGImap4Client *)client;
+- (EOGlobalID *)serverGlobalID;
+
+- (NSURL *)url;
+
+/* folder tracking */
+
+- (BOOL)isSelectedFolder:(NGImap4Folder *)_folder;
+- (BOOL)registerAsSelectedFolder:(NGImap4Folder *)_folder;
+- (BOOL)removeSelectedFolder:(NGImap4Folder *)_folder;
+
+- (BOOL)openConnection;
+- (BOOL)closeConnection;
+
+// NGImap4ResponseReceiver protocol
+
+- (void)responseNotificationFrom:(NGImap4Client *)_client
+  response:(NSDictionary *)_dict;
+
+/* special folders */
+
+- (id)trashFolder;
+- (id)sentFolder;
+- (id)draftsFolder;
+- (id)inboxFolder;
+- (id)serverRoot;
+- (void)setSentFolder:(NGImap4Folder *)_folder;
+- (void)setTrashFolder:(NGImap4Folder *)_folder;
+- (void)setDraftsFolder:(NGImap4Folder *)_folder;
+
+- (void)resetSpecialFolders;
+
+- (BOOL)hasNewMessages;
+/* returns all new messages from registered folder and inbox */
+- (NSArray *)newMessages; // TODO: should be a datasource and/or qual instead!
+
+- (BOOL)registerForRefresh:(NGImap4Folder *)_folder;
+- (BOOL)removeFromRefresh:(NGImap4Folder *)_folder;
+- (BOOL)removeAllFromRefresh;
+- (BOOL)refreshFolder;
+
+- (NGImap4Folder *)folderWithName:(NSString *)_name;
+- (NGImap4Folder *)folderWithName:(NSString *)_name caseInsensitive:(BOOL)_b;
+
+- (BOOL)createFolderWithPath:(NSString *)_name;
+
+- (NSString *)host;
+- (NSString *)login;
+
+- (id)serverName;
+- (id)serverKind;
+- (id)serverVersion;
+- (id)serverSubVersion;
+- (id)serverTag;
+
+- (BOOL)isInSyncMode;
+- (void)enterSyncMode;
+- (void)leaveSyncMode;
+- (void)resetSync;
+
+- (void)setLastException:(NSException *)_exception;
+- (NSException *)lastException;
+- (void)resetLastException;
+
+/* server depending defaults */
+
+- (BOOL)subscribeFolderFailed;
+- (BOOL)showOnlySubscribedInRoot;
+- (BOOL)showOnlySubscribedInSubFolders;
+- (NSString *)sortEncoding;
+
+- (void)setSortEncoding:(NSString *)_str;
+- (void)setSubscribeFolderFailed:(BOOL)_b;
+- (void)setShowOnlySubscribedInRoot:(BOOL)_b;
+- (void)setShowOnlySubscribedInSubFolders:(BOOL)_b;
+
+/* URL based factory */
+
++ (id)messageWithURL:(id)_url; /* create context, then message */
+- (id)messageWithURL:(id)_url;
+- (id)folderWithURL:(id)_url;
+
+@end
+
+@interface NGImap4Context(Capability)
+
+- (BOOL)canSort;
+- (BOOL)canQuota;
+
+@end /* NGImap4Context(Capability) */
+
+#endif /* __OGo_NGImap4_NGImap4Context_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Context.m b/skyrix-core/NGMime/NGImap4/NGImap4Context.m
new file mode 100644 (file)
index 0000000..2f77c50
--- /dev/null
@@ -0,0 +1,961 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGImap4Context.h"
+#include "NGImap4Client.h"
+#include "NGImap4Folder.h"
+#include "NGImap4ServerRoot.h"
+#include "NGImap4Support.h"
+#include "NGImap4Functions.h"
+#include "imCommon.h"
+
+@interface NGImap4Context(Private)
+- (void)initializeSentFolder;
+- (void)initializeTrashFolder;
+- (void)initializeDraftsFolder;
+- (void)initializeInboxFolder;
+- (void)initializeServerRoot;
+
+- (void)_setSortEncoding:(NSString *)_str;
+- (void)_setSubscribeFolderFailed:(BOOL)_b;
+- (void)_setShowOnlySubscribedInRoot:(BOOL)_b;
+- (void)_setShowOnlySubscribedInSubFolders:(BOOL)_b;
+@end
+
+@implementation NGImap4Context
+
+static id  DefaultForSortEncoding                   = nil;
+static id  DefaultForSubscribeFailed                = nil;
+static id  DefaultForShowOnlySubscribedInRoot       = nil;
+static id  DefaultForShowOnlySubscribedInSubFolders = nil;
+static int ImapLogEnabled                           = -1;
+
++ (void)initialize {
+  NSUserDefaults *ud;
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+
+  ud = [NSUserDefaults standardUserDefaults];
+
+  DefaultForSortEncoding    = [[ud stringForKey:@"ImapSortEncoding"] copy];
+  DefaultForSubscribeFailed = 
+    [[ud stringForKey:@"ImapSubscribedCouldFailed"] copy];
+  DefaultForShowOnlySubscribedInSubFolders =
+    [[ud stringForKey:@"ShowOnlySubscribedInSubFolders"] copy];
+  DefaultForShowOnlySubscribedInRoot =
+    [[ud stringForKey:@"ShowOnlySubscribedInRoot"] copy];
+  
+  ImapLogEnabled = [ud boolForKey:@"ImapLogEnabled"]?1:0;
+}
+
++ (id)imap4ContextWithURL:(id)_url {
+  if (_url == nil)
+    return nil;
+  if (![_url isKindOfClass:[NSURL class]]) 
+    _url = [NSURL URLWithString:[_url stringValue]];
+  
+  return [[(NGImap4Context *)[self alloc] initWithURL:_url] autorelease];
+}
++ (id)imap4ContextWithConnectionDictionary:(NSDictionary *)_connection {
+  return [[[self alloc] initWithConnectionDictionary:_connection] autorelease];
+}
+
+- (id)initWithConnectionDictionary:(NSDictionary *)_connection {
+  if ((self = [super init])) {
+    self->connectionDictionary = [_connection copy];
+    self->folderForRefresh = [[NSMutableArray alloc] initWithCapacity:512];
+    self->syncMode = NO;
+
+    self->subscribeFolderFailed = (DefaultForSubscribeFailed)
+      ? [DefaultForSubscribeFailed boolValue]?1:0
+      : -1;
+
+    self->showOnlySubscribedInRoot = (DefaultForShowOnlySubscribedInRoot)
+      ? [DefaultForShowOnlySubscribedInRoot boolValue]?1:0
+      : -1;
+
+    self->showOnlySubscribedInSubFolders =
+      (DefaultForShowOnlySubscribedInSubFolders)
+      ? [DefaultForShowOnlySubscribedInSubFolders boolValue]?1:0
+      : -1;
+
+    self->sortEncoding = (DefaultForSortEncoding)
+      ? [DefaultForSortEncoding retain]
+      : nil;
+
+  }
+  return self;
+}
+- (id)initWithNSURL:(NSURL *)_url {
+  NSMutableDictionary *md;
+  id                  tmp;
+  
+  if (_url == nil) {
+    [self release];
+    return nil;
+  }
+  
+  md = [NSMutableDictionary dictionaryWithCapacity:4];
+  if ((tmp = [_url host]))     [md setObject:tmp forKey:@"host"];
+  if ((tmp = [_url port]))     [md setObject:tmp forKey:@"port"];
+  if ((tmp = [_url user]))     [md setObject:tmp forKey:@"login"];
+  if ((tmp = [_url password])) [md setObject:tmp forKey:@"passwd"];
+  
+  if ([[_url scheme] isEqualToString:@"imaps"])
+    [md setObject:[NSNumber numberWithBool:YES] forKey:@"SSL"];
+  
+  return [self initWithConnectionDictionary:md];
+}
+- (id)initWithURL:(id)_url {
+  if ((_url != nil) && ![_url isKindOfClass:[NSURL class]])
+    _url = [NSURL URLWithString:[_url stringValue]];
+  
+  return [self initWithNSURL:_url];
+}
+
+- (void)dealloc {
+  [self->url release];
+  [self->client removeFromResponseNotification:self];
+  [self->connectionDictionary release];
+  [self->client           release];
+  [self->folderForRefresh release];
+  [self->serverName       release];       
+  [self->serverKind       release];       
+  [self->serverVersion    release];    
+  [self->serverSubVersion release]; 
+  [self->serverTag        release];        
+  [self->lastException    release];
+
+  self->selectedFolder = nil; /* not retained */  
+  self->trashFolder    = nil; /* not retained */  
+  self->draftsFolder   = nil; /* not retained */  
+  self->sentFolder     = nil; /* not retained */
+  self->inboxFolder    = nil; /* not retained */
+  self->serverRoot     = nil; /* not retained */
+
+  [self->capability   release];
+  [self->sortEncoding release];
+  
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSException *)lastException {
+  return self->lastException;
+}
+
+- (void)setLastException:(NSException *)_exception {
+  ASSIGN(self->lastException, _exception);
+}
+
+- (void)resetLastException {
+  [self->lastException release]; self->lastException = nil;
+}
+
+- (NGImap4Client *)client {
+  if (self->client == nil)
+    [self openConnection];
+  return self->client;
+}
+
+- (EOGlobalID *)serverGlobalID {
+  if (self->client == nil) {
+    // TODO: construct global-id using connectionDictionary!
+    [self logWithFormat:@"WARNING: could not construct GID (client not set!)"];
+    return nil;
+  }
+  return [self->client serverGlobalID];
+}
+
+- (NSURL *)url {
+  NSString *scheme;
+  
+  if (self->url)
+    return self->url;
+  
+  scheme = [[self->connectionDictionary objectForKey:@"SSL"] boolValue]
+    ? @"imaps" : @"imap";
+  
+  self->url = [[NSURL alloc]
+               initWithScheme:scheme
+               host:[self->connectionDictionary objectForKey:@"host"]
+               path:nil];
+  return self->url;
+}
+
+/* folder tracking */
+
+- (BOOL)isSelectedFolder:(NGImap4Folder *)_folder {
+  return [self->selectedFolder isEqual:_folder];
+}
+
+- (void)setSelectedFolder:(NGImap4Folder *)_folder {
+  self->selectedFolder = _folder;
+}
+
+- (BOOL)registerAsSelectedFolder:(NGImap4Folder *)_folder {
+  id tmp;
+  
+  if (self->selectedFolder == _folder)
+    return YES;
+  
+  if ([_folder noselect])
+    return NO;
+  
+  tmp = self->selectedFolder;
+  self->selectedFolder = _folder;
+  if (![_folder selectImmediately:YES]) {
+    self->selectedFolder = tmp;
+    return NO;
+  }
+
+  return YES;
+}
+
+- (BOOL)removeSelectedFolder:(NGImap4Folder *)_folder {
+  if (self->selectedFolder == _folder)
+    self->selectedFolder = nil;
+  return YES;
+}
+
+- (BOOL)openConnection {
+  NSString *login;
+  NSString *passwd;
+  NSString *host;
+
+  login  = [self->connectionDictionary objectForKey:@"login"];
+  passwd = [self->connectionDictionary objectForKey:@"passwd"];
+  host   = [self->connectionDictionary objectForKey:@"host"];
+
+  [self resetSpecialFolders];
+
+  if ((login == nil) || (passwd == nil) || (host == nil)) {
+    id exc;
+    
+    exc = [[NGImap4ConnectionException alloc] 
+           initWithFormat:
+             @"missing login, passwd or host in connection-dictionary <%@>",
+             self->connectionDictionary];
+    ASSIGN(self->lastException, exc);
+    [exc release];
+    return NO;
+  }
+  if (self->client == nil) {
+    self->client = [[NGImap4Client alloc] initWithHost:host];
+    [self->client registerForResponseNotification:self];
+    [self->client setContext:self];
+  }
+  if (![[self->client isConnected] boolValue]) {
+    NSDictionary *res;
+    
+    [self resetLastException];
+    
+    res = [self->client openConnection];
+    if (!_checkResult(self, res, __PRETTY_FUNCTION__))
+      return NO;
+    
+    [self->serverName       release]; self->serverName       = nil;
+    [self->serverKind       release]; self->serverKind       = nil;
+    [self->serverVersion    release]; self->serverVersion    = nil;
+    [self->serverSubVersion release]; self->serverSubVersion = nil;
+    [self->serverTag        release]; self->serverTag        = nil;
+
+    self->serverName = [[res objectForKey:@"server"]     retain];
+    self->serverKind = [[res objectForKey:@"serverKind"] retain];
+
+    if (ImapLogEnabled) {
+      [self logWithFormat:@"Server greeting: <%@> parse serverkind: <%@>",
+            self->serverName, self->serverKind];
+    }
+    
+    // TODO: move capability to specialized object!
+    //   Note: capability of the IMAP4 server should be always configurable
+    //         using defaults because the identification might be broken for
+    //         security reasons
+    
+    if (self->serverKind != nil) {
+      self->serverVersion    = [[res objectForKey:@"version"]    retain];
+      self->serverSubVersion = [[res objectForKey:@"subversion"] retain];
+      self->serverTag        = [[res objectForKey:@"tag"]        retain];
+    }
+    if ([self->serverKind isEqual:@"courier"]) {
+      [self _setSortEncoding:@"US-ASCII"];
+      [self _setSubscribeFolderFailed:NO];
+      [self _setShowOnlySubscribedInRoot:0];
+      [self _setShowOnlySubscribedInSubFolders:0];
+    }
+    else if ([self->serverKind isEqual:@"washington"]) {
+      [self _setSortEncoding:@"UTF-8"];
+      [self _setSubscribeFolderFailed:YES];
+      [self _setShowOnlySubscribedInRoot:1];
+      [self _setShowOnlySubscribedInSubFolders:1];
+    }
+    else if ([self->serverKind isEqual:@"cyrus"]) {
+      [self _setSortEncoding:@"UTF-8"];
+      [self _setSubscribeFolderFailed:YES];
+      [self _setShowOnlySubscribedInRoot:0];
+      [self _setShowOnlySubscribedInSubFolders:0];
+    }
+    if (ImapLogEnabled)
+      [self logWithFormat:@"sortEncoding %@ subscribeFolderFailed %@ "
+            @"showOnlySubscribedInSubFolders %@ showOnlySubscribedInRoot %@",
+            [self sortEncoding],
+            [self subscribeFolderFailed]         ? @"YES" : @"NO",
+            [self showOnlySubscribedInSubFolders]? @"YES" : @"NO",
+            [self showOnlySubscribedInRoot]      ? @"YES" : @"NO"];
+      
+    [self resetLastException];
+    res = [self->client login:login password:passwd];
+    if (!_checkResult(self, res, __PRETTY_FUNCTION__))
+      return NO;
+  }
+  {
+    NSDictionary *res;
+
+    [self->capability release]; self->capability = nil;
+    res = [self->client capability];
+
+    if (!_checkResult(self, res, __PRETTY_FUNCTION__))
+      return NO;
+
+    self->capability = [[res objectForKey:@"capability"] retain];
+  }
+
+  self->canSort  = -1;
+  self->canQuota = -1;
+  
+  return YES;
+}
+
+- (void)_setSortEncoding:(NSString *)_str {
+  if (!DefaultForSortEncoding)
+    ASSIGN(self->sortEncoding, _str);
+}
+
+- (void)_setSubscribeFolderFailed:(BOOL)_b {
+  if (!DefaultForSubscribeFailed)
+    self->subscribeFolderFailed = _b?1:0;
+}
+
+- (void)_setShowOnlySubscribedInRoot:(BOOL)_b {
+  if (!DefaultForShowOnlySubscribedInRoot)
+    self->showOnlySubscribedInRoot = _b?1:0;
+}
+
+- (void)_setShowOnlySubscribedInSubFolders:(BOOL)_b {
+  if (!DefaultForShowOnlySubscribedInSubFolders)
+    self->showOnlySubscribedInSubFolders = _b?1:0;
+}
+
+- (void)setSortEncoding:(NSString *)_str {
+  ASSIGN(self->sortEncoding, _str);
+}
+
+- (void)setSubscribeFolderFailed:(BOOL)_b {
+  self->subscribeFolderFailed = _b?1:0;
+}
+
+- (void)setShowOnlySubscribedInRoot:(BOOL)_b {
+  self->showOnlySubscribedInRoot = _b?1:0;
+}
+
+- (void)setShowOnlySubscribedInSubFolders:(BOOL)_b {
+  self->showOnlySubscribedInSubFolders = _b?1:0;
+}
+
+- (BOOL)closeConnection {
+  [self->client closeConnection];
+  [self resetSpecialFolders];
+  [self->capability release]; self->capability = nil;
+  self->canSort = -1;
+  self->canQuota = -1;
+
+  
+  return YES;
+}
+
+/*"
+**  NGImap4ResponseReceiver protocol
+**  If the NGImap4Context receive a response-notification it
+**  updates the selected folder
+"*/
+
+- (void)responseNotificationFrom:(NGImap4Client *)_client
+   response:(NSDictionary *)_dict
+{
+  if (![[_dict objectForKey:@"result"] boolValue]) {
+    id       exc;
+    NSString *str;
+    
+    if ((str = [_dict objectForKey:@"reason"]) == nil)
+      str = @"Response failed";
+    
+    exc = [[NGImap4ResponseException alloc] 
+      initWithName:@"NGImap4ResponseException" reason:str userInfo:_dict];
+    ASSIGN(self->lastException, exc);
+    return;
+  }
+
+  if (self->selectedFolder)
+    [self->selectedFolder processResponse:_dict];
+}
+
+- (id)trashFolder {
+  if (self->trashFolder == nil)
+    [self initializeTrashFolder];
+  return self->trashFolder;
+}
+- (void)setTrashFolder:(NGImap4Folder *)_folder {
+  self->trashFolder = _folder;
+}
+
+- (id)sentFolder {
+  if (self->sentFolder == nil)
+    [self initializeSentFolder];
+  return self->sentFolder;
+}
+- (void)setSentFolder:(NGImap4Folder *)_folder {
+  self->sentFolder = _folder;
+}
+
+- (id)draftsFolder {
+  if (self->draftsFolder == nil)
+    [self initializeDraftsFolder];
+  return self->draftsFolder;
+}
+- (void)setDraftsFolder:(NGImap4Folder *)_folder {
+  self->draftsFolder = _folder;
+}
+
+- (id)inboxFolder {
+  if (self->inboxFolder == nil)
+    [self initializeInboxFolder];
+  return self->inboxFolder;
+}
+
+- (id)serverRoot {
+  if (self->serverRoot == nil)
+    [self initializeServerRoot];
+  return self->serverRoot;
+}
+
+- (void)initializeServerRoot {
+  if (self->serverRoot == nil) {
+    /*
+      Note: serverRoot is not retained by NGImap4Context to avoid a
+      retain cycle. This is why the object is autoreleased immediatly
+      after creation (the usercode uses -serverRoot to access the result).
+    */
+    [self resetSpecialFolders];
+    self->serverRoot = [[NGImap4ServerRoot alloc]
+                                           initServerRootWithContext:self];
+    self->serverRoot = [self->serverRoot autorelease];
+  }
+}
+
+- (void)_checkFolder:(id)_folder folderName:(NSString *)_name
+{
+  NSDictionary *res;
+  NSArray      *list;
+
+  [self resetLastException];
+  res = [self->client list:@"" pattern:_name];
+
+  if (![[res objectForKey:@"result"] boolValue])
+    return;
+
+  list = [res objectForKey:@"list"];
+
+  if ([list count]) { /* folder exist but is not subscribed */
+    [self->client subscribe:_name];
+  }
+  else { /* try to create folder */
+    [_folder createSubFolderWithName:[_name lastPathComponent]];
+  }
+  [_folder resetSubFolders];
+  [self->lastException release]; self->lastException = nil;
+}
+
+- (NGImap4Folder *)_getFolderWithName:(NSString *)_name {
+  NSEnumerator  *enumerator;
+  NGImap4Folder *folder;
+
+  if (self->serverRoot == nil)
+    [self initializeServerRoot];
+
+  enumerator = [[self->serverRoot subFolders] objectEnumerator];
+  while ((folder = [enumerator nextObject])) {
+    NSString *name;
+
+    name = [[folder name] lowercaseString];
+
+    if ([name isEqualToString:[_name lowercaseString]]) {
+      return folder;
+    }
+  }
+  if ([[_name lowercaseString] isEqual:@"inbox"]) {
+    [self resetLastException];
+    [self->client subscribe:_name];
+    if (self->lastException != nil) {
+      [self->serverRoot createSubFolderWithName:_name];
+      [self->lastException release]; self->lastException = nil;
+    }
+    [self resetSpecialFolders];
+  }
+  else {
+    if ([[self inboxFolder] noinferiors]) {
+      /* try to create Sent/Trash/Drafts in root */
+      [self _checkFolder:self->serverRoot folderName:_name];
+    }
+    else {
+      /* take a look in inbox */
+      NGImap4Folder *f;
+      NSString      *absoluteName;
+
+      f      = [self inboxFolder];
+      folder = [f subFolderWithName:[_name lowercaseString]
+                  caseInsensitive:YES];
+      if (folder != nil)
+        return folder;
+      
+      absoluteName = [[f absoluteName] stringByAppendingPathComponent:_name];
+      
+      [self _checkFolder:f folderName:absoluteName];
+    }
+  }
+  return nil;
+}
+
+- (NSString *)sentFolderName {
+  static NSString *SentFolderName = nil;
+
+  if (SentFolderName == nil) {
+    SentFolderName = [[[NSUserDefaults standardUserDefaults]
+                                      stringForKey:@"ImapSentFolderName"]
+                                       retain];
+
+    if (!SentFolderName)
+      SentFolderName = @"Sent";
+  }
+  return SentFolderName;
+}
+
+- (NSString *)trashFolderName {
+  static NSString *TrashFolderName = nil;
+
+  if (TrashFolderName == nil) {
+    TrashFolderName = [[[NSUserDefaults standardUserDefaults]
+                                      stringForKey:@"ImapTrashFolderName"]
+                                       retain];
+
+    if (!TrashFolderName)
+      TrashFolderName = @"Trash";
+  }
+  return TrashFolderName;
+}
+
+- (NSString *)draftsFolderName {
+  static NSString *DraftsFolderName = nil;
+
+  if (DraftsFolderName == nil) {
+    DraftsFolderName = [[[NSUserDefaults standardUserDefaults]
+                                      stringForKey:@"ImapDraftsFolderName"]
+                                       retain];
+
+    if (!DraftsFolderName)
+      DraftsFolderName = @"Drafts";
+  }
+  return DraftsFolderName;
+}
+
+- (void)initializeSentFolder {
+  if ((self->sentFolder = [self _getFolderWithName:
+                                [self sentFolderName]]) == nil)
+    self->sentFolder = [self _getFolderWithName:
+                             [self sentFolderName]];
+  if (self->sentFolder == nil)
+    NSLog(@"WARNING[%s]: Couldn't find/create sentFolder", __PRETTY_FUNCTION__);
+}
+
+- (void)initializeTrashFolder {
+  if ((self->trashFolder = [self _getFolderWithName:
+                                 [self trashFolderName]]) == nil)
+    self->trashFolder = [self _getFolderWithName:[self trashFolderName]];
+  if (self->trashFolder == nil)
+    NSLog(@"WARNING[%s]: Couldn't find/create trashFolder", __PRETTY_FUNCTION__);
+}
+
+- (void)initializeDraftsFolder {
+  if ((self->draftsFolder = [self _getFolderWithName:
+                                  [self draftsFolderName]]) == nil)
+    self->draftsFolder = [self _getFolderWithName:
+                               [self draftsFolderName]];
+  if (self->draftsFolder == nil)
+    NSLog(@"WARNING[%s]: Couldn't find/create draftsFolder", __PRETTY_FUNCTION__);
+}
+
+- (void)initializeInboxFolder {
+  if ((self->inboxFolder = [self _getFolderWithName:@"Inbox"]) == nil)
+    self->inboxFolder = [self _getFolderWithName:@"Inbox"];
+  
+  if (self->inboxFolder == nil)
+    NSLog(@"WARNING[%s]: Couldn't find/create inbox", __PRETTY_FUNCTION__);
+}
+
+- (NGImap4Folder *)folderWithName:(NSString *)_name {
+  return [self folderWithName:_name caseInsensitive:NO];
+}
+
+- (NGImap4Folder *)folderWithName:(NSString *)_name
+  caseInsensitive:(BOOL)_caseIn 
+{
+  NSEnumerator  *enumerator;
+  id            obj;
+  NGImap4Folder *f;
+
+  [self resetLastException];
+  enumerator = [[_name componentsSeparatedByString:@"/"] objectEnumerator];
+  f          = [self serverRoot];
+  
+  while ((obj = [enumerator nextObject])) {
+    if ([obj length] > 0)
+      f = [f subFolderWithName:obj caseInsensitive:_caseIn];
+  }
+  return self->lastException ? nil : f;
+}
+
+- (BOOL)createFolderWithPath:(NSString *)_name {
+  NSEnumerator      *enumerator;
+  id<NGImap4Folder> f1, f2; 
+  NSString          *name;
+
+  [self resetLastException];
+  
+  enumerator = [[_name componentsSeparatedByString:@"/"] objectEnumerator];
+  f1         = [self serverRoot];
+  f2         = nil;
+  while ((name = [enumerator nextObject])) {
+    if ((f2 = [f1 subFolderWithName:name caseInsensitive:YES]) == nil)
+      break;
+    f1 = f2;
+  }
+  if (name != nil) {
+    do {
+      if (![f1 createSubFolderWithName:name])
+        break;
+      f1 = [f1 subFolderWithName:name caseInsensitive:YES];
+    } while ((name = [enumerator nextObject]));
+  }
+  return self->lastException ? NO : YES;
+}
+
+- (void)resetSpecialFolders {
+  self->sentFolder   = nil;
+  self->trashFolder  = nil;
+  self->draftsFolder = nil;
+  self->inboxFolder  = nil;
+  self->serverRoot   = nil;
+}
+
+- (NSArray *)newMessages {
+  NSEnumerator   *enumerator;
+  NGImap4Folder  *f;
+  NSMutableArray *result;
+  EOQualifier    *qual;
+
+  [self resetLastException];
+  
+  qual   = [EOQualifier qualifierWithQualifierFormat:@"flags = \"recent\""];
+  result = [NSMutableArray array];
+  
+  [self->inboxFolder status];
+  if ([self->inboxFolder hasNewMessagesSearchRecursiv:NO]) {
+    NSArray *array;
+
+    array = [self->inboxFolder messagesForQualifier:qual];
+    if (array != nil)
+      [result addObjectsFromArray:array];
+  }
+  enumerator = [self->folderForRefresh objectEnumerator];  
+  while ((f = [enumerator nextObject])) {
+    [f status];
+    if ([f hasNewMessagesSearchRecursiv:NO]) {
+    NSArray *array;
+
+    array = [self->inboxFolder messagesForQualifier:qual];
+    if (array != nil)
+      [result addObjectsFromArray:array];
+    }
+  }
+  return self->lastException ? nil : result;
+}
+
+- (BOOL)hasNewMessages {
+  NSEnumerator  *enumerator;
+  NGImap4Folder *f;
+  BOOL          result;
+
+  [self resetLastException];
+  
+  [self->inboxFolder status];
+  if ([self->inboxFolder hasNewMessagesSearchRecursiv:NO])
+    return YES;
+
+  result     = NO;
+  enumerator = [self->folderForRefresh objectEnumerator];
+  
+  while ((f = [enumerator nextObject])) {
+    [f status];
+    if ([f hasNewMessagesSearchRecursiv:NO]) {
+      result = YES;
+      break;
+    }
+  }
+  return self->lastException ? NO : result;
+}
+
+- (NSString *)host {
+  return [self->connectionDictionary objectForKey:@"host"];
+}
+- (NSString *)login {
+  return [self->connectionDictionary objectForKey:@"login"];
+}
+
+- (BOOL)registerForRefresh:(NGImap4Folder *)_folder {
+  [self->folderForRefresh addObject:_folder];
+  return YES;
+}
+
+- (BOOL)removeFromRefresh:(NGImap4Folder *)_folder {
+  [self->folderForRefresh removeObject:_folder];
+  return YES;
+}
+
+- (BOOL)removeAllFromRefresh {
+  [self->folderForRefresh removeAllObjects];
+  return YES;
+}
+
+- (BOOL)refreshFolder {
+  // TODO: explain
+  //       this runs status on each folder and status triggers notifications?
+  NSEnumerator  *enumerator;
+  NGImap4Folder *f;
+  BOOL          refreshInbox = NO;
+
+  if ([self lastException] != nil)
+    return NO;
+  
+  enumerator = [self->folderForRefresh objectEnumerator];
+
+  [self resetLastException];
+
+  while ((f = [enumerator nextObject])) {
+    if ([f isEqual:self->inboxFolder])
+      refreshInbox = YES;
+    
+    [f status];
+  }
+  
+  if (!refreshInbox)
+    [self->inboxFolder status];
+    
+  return self->lastException ? NO : YES;
+}
+
+- (id)serverName {
+  return self->serverName;
+}
+- (id)serverKind {
+  return self->serverKind;
+}
+- (id)serverVersion {
+  return self->serverVersion;
+}
+- (id)serverSubVersion {
+  return self->serverSubVersion;
+}
+- (id)serverTag {
+  return self->serverTag;
+}
+
+/* synchronize */
+
+- (void)resetSync {
+  if (self->syncMode) 
+    [self->serverRoot resetSync];
+  else
+    [self logWithFormat:@"WARNING: resetSync has no effect if syncMode == NO"];
+}
+
+- (BOOL)isInSyncMode {
+  return self->syncMode;
+}
+
+- (void)enterSyncMode {
+  self->syncMode = YES;
+  [self resetSync];
+}
+
+- (void)leaveSyncMode {
+  self->syncMode = NO;
+}
+
+- (BOOL)showOnlySubscribedInRoot {
+  if (self->showOnlySubscribedInRoot == -1)
+    return NO;
+  
+  return (self->showOnlySubscribedInRoot == 1) ? YES : NO;
+}
+
+- (BOOL)showOnlySubscribedInSubFolders {
+  if (self->showOnlySubscribedInSubFolders == -1)
+    return NO;
+  
+  return (self->showOnlySubscribedInSubFolders == 1) ? YES : NO;
+}
+
+- (BOOL)subscribeFolderFailed {
+  if (self->subscribeFolderFailed == -1)
+    return YES;
+  
+  return (self->subscribeFolderFailed == 1) ? YES : NO;
+}
+
+- (NSString *)sortEncoding {
+  if (self->sortEncoding == nil)
+    self->sortEncoding = @"UTF-8";
+  
+  return self->sortEncoding;
+}
+
+/* Capability */
+
+- (BOOL)canSort {
+  if (self->capability == nil) {
+    if (![self openConnection])
+      return NO;
+  }
+  if (self->canSort == -1) {
+    self->canSort =
+      ([self->capability containsObject:@"sort"])? 1 : 0;
+  }
+  return self->canSort;
+}
+
+- (BOOL)canQuota {
+  if (self->capability == nil) {
+    if (![self openConnection])
+      return NO;
+  }
+  if (self->canQuota == -1) {
+    self->canQuota =
+      ([self->capability containsObject:@"quota"])? 1 : 0;
+  }
+  return self->canQuota;
+}
+
+/* URL based factory */
+
++ (id)messageWithURL:(id)_url {
+  NGImap4Context *ctx;
+  
+  if (_url == nil) 
+    return nil;
+  if (![_url isKindOfClass:[NSURL class]]) 
+    _url = [NSURL URLWithString:[_url stringValue]];
+  
+  if ((ctx = [self imap4ContextWithURL:_url]) == nil) {
+    NSLog(@"WARNING(%s): got no IMAP4 context for URL: %@", 
+         __PRETTY_FUNCTION__, _url);
+    return nil;
+  }
+  return [ctx messageWithURL:_url];
+}
+- (id)folderWithURL:(id)_url {
+  NSString *path, *folderPath;
+  
+  if (_url != nil && ![_url isKindOfClass:[NSURL class]]) 
+    _url = [NSURL URLWithString:[_url stringValue]];
+  if (_url == nil) 
+    return nil;
+  
+  path       = [_url path];
+  folderPath = [path stringByDeletingLastPathComponent];
+  
+  return [self folderWithName:folderPath];
+}
+- (id)messageWithURL:(id)_url {
+  NSString      *path, *folderPath;
+  NGImap4Folder *f;
+  unsigned      messageID;
+  
+  if (_url != nil && ![_url isKindOfClass:[NSURL class]]) 
+    _url = [NSURL URLWithString:[_url stringValue]];
+  if (_url == nil) 
+    return nil;
+  
+  path       = [_url path];
+  folderPath = [path stringByDeletingLastPathComponent];
+  messageID  = [[path lastPathComponent] intValue];
+  
+  if ((f = [self folderWithName:folderPath]) == nil) {
+    [self logWithFormat:@"WARNING(%s): missing folder for URL: '%@'",
+          __PRETTY_FUNCTION__, _url];
+    return nil;
+  }
+  return [f messageWithUid:messageID];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  NSString *tmp;
+
+  ms = [NSMutableString stringWithCapacity:64];
+
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if ((tmp = [self host]))
+    [ms appendFormat:@" host=%@", tmp];
+  if ((tmp = [self login]))
+    [ms appendFormat:@" login=%@", tmp];
+  
+  [ms appendFormat:@" server='%@'/%@/%@.%@/%@",
+        [self serverName],
+        [self serverKind],
+        [self serverVersion],
+        [self serverSubVersion],
+        [self serverTag]];
+  
+  if (self->syncMode)
+    [ms appendString:@" syncmode"];
+  
+  [ms appendString:@">"];
+
+  return ms;
+}
+
+@end /* NGImap4Context(Capability) */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4DataSource.h b/skyrix-core/NGMime/NGImap4/NGImap4DataSource.h
new file mode 100644 (file)
index 0000000..7bb90c8
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGImap4_NGImap4DataSource_H__
+#define __NGImap4_NGImap4DataSource_H__
+
+#import <NGExtensions/EODataSource+NGExtensions.h>
+#import <NGImap4/NGImap4Folder.h>
+
+@class NSArray;
+@class NGImap4Folder;
+@class EOFetchSpecification;
+
+@interface NGImap4DataSource : EODataSource
+{
+@protected
+  EOFetchSpecification *fspec;
+  NSArray       *messages;
+  NGImap4Folder *folder;
+  int           oldExists; // remember the 'exists' flag of the folder
+  int           oldUnseen; // remember the 'unseen' flag of the folder
+
+  NSArray       *oldUnseenMessages;
+}
+
+- (id)initWithFolder:(NGImap4Folder *)_folder;
+
+- (void)setFolder:(NGImap4Folder *)_folder;
+- (NGImap4Folder *)folder;
+
+- (int)oldExists;
+- (int)oldUnseen;
+
+@end /* __NGImap4_NGImap4DataSource_H__ */
+
+#endif
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4DataSource.m b/skyrix-core/NGMime/NGImap4/NGImap4DataSource.m
new file mode 100644 (file)
index 0000000..31aacfb
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGImap4DataSource.h"
+#include <NGStreams/NGSocketExceptions.h>
+#include "imCommon.h"
+
+@interface NGImap4DataSource(PrivateMethodes)
+- (NSArray *)fetchMessages;
+@end
+
+@interface EOQualifier(IMAPAdditions)
+- (BOOL)isImap4UnseenQualifier;
+@end
+
+@implementation NGImap4DataSource
+
+static BOOL profileDS = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  if ((profileDS = [ud boolForKey:@"ProfileImap4DataSource"]))
+    NSLog(@"NGImap4DataSource: Profiling enabled!");
+}
+
+- (NSNotificationCenter *)notificationCenter {
+  static NSNotificationCenter *nc = nil;
+  if (nc == nil) nc = [[NSNotificationCenter defaultCenter] retain];
+  return nc;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    NSNotificationCenter *nc = [self notificationCenter];
+    
+    [nc addObserver:self
+        selector:@selector(mailsWereDeleted:)
+        name:@"LSWImapMailWasDeleted"
+        object:nil];
+
+    [nc addObserver:self
+        selector:@selector(folderWasMoved:)
+        name:@"LSWImapMailFolderWasDeleted"
+        object:nil];
+    
+    [nc addObserver:self
+        selector:@selector(flagsWereChanged:)
+        name:@"LSWImapMailFlagsChanged"
+        object:nil];
+  }
+  return self;
+}
+- (id)initWithFolder:(NGImap4Folder *)_folder {
+  if ((self = [self init])) {
+    [self setFolder:_folder];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[self notificationCenter] removeObserver:self];
+  [self->folder   release];
+  [self->fspec    release];
+  [self->messages release];
+  [self->oldUnseenMessages release];
+  [super dealloc];
+}
+
+/* operations */
+
+- (void)folderWasMoved:(id)_obj {
+  [self->folder   release]; self->folder   = nil;
+  [self->messages release]; self->messages = nil;
+  [self->oldUnseenMessages release]; self->oldUnseenMessages = nil;
+}
+
+- (void)mailsWereDeleted:(id)_obj {
+  [self->messages          release]; self->messages          = nil;
+  [self->oldUnseenMessages release]; self->oldUnseenMessages = nil;
+}
+
+- (void)flagsWereChanged:(id)_obj {
+  [self postDataSourceChangedNotification];
+}
+
+- (NSArray *)fetchObjects {
+  NSAutoreleasePool *pool;
+  NSArray *tmp;
+  
+  if (self->messages) {
+    if (profileDS) [self logWithFormat:@"fetchObjects: already fetched."];
+    return self->messages;
+  }
+    
+  pool = [[NSAutoreleasePool alloc] init];
+  {  
+    if (profileDS) [self logWithFormat:@"fetchObjects: fetch ..."];
+    
+    tmp = (self->folder) ? [self fetchMessages] : [NSArray array];
+    
+    if (profileDS) [self logWithFormat:@"fetchObjects:   done ..."];
+    ASSIGN(self->messages, tmp);
+  }
+  [pool release];
+  if (profileDS) [self logWithFormat:@"fetchObjects:   pool released."];
+  
+  return self->messages;
+}
+
+- (void)clear {
+  if (profileDS) [self logWithFormat:@"clear: do ..."];
+  [self->messages release];
+  self->messages = nil;
+  if (profileDS) [self logWithFormat:@"clear: done."];
+}
+
+- (void)setFolder:(NGImap4Folder *)_folder {
+  ASSIGN(self->folder, _folder);
+  
+  [self->messages          release]; self->messages          = nil;
+  [self->oldUnseenMessages release]; self->oldUnseenMessages = nil;
+  
+  [self postDataSourceChangedNotification];
+}
+- (NGImap4Folder *)folder {
+  return self->folder;
+}
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fetchSpec {
+  if ([_fetchSpec isEqual:self->fspec]) return;
+  
+  ASSIGN(self->fspec, _fetchSpec);
+  [self->messages release]; self->messages = nil;
+  [self postDataSourceChangedNotification];
+}
+- (EOFetchSpecification *)fetchSpecification {
+  return self->fspec;
+}
+
+- (int)oldExists {
+  return self->oldExists;
+}
+- (int)oldUnseen {
+  return self->oldUnseen;
+}
+
+/* private methodes */
+
+- (NSException *)handleImapException:(NSException *)_exception {
+  if ([_exception isKindOfClass:[NGImap4ResponseException class]]) {
+    NSDictionary *record;
+    NSString *str;
+    
+    record = [[_exception userInfo] objectForKey:@"RawResponse"];
+    record = [record objectForKey:@"ResponseResult"];
+    str    = [record objectForKey:@"description"];
+    fprintf(stderr, "%s", [str cString]);
+  }    
+  else if ([_exception isKindOfClass:[NGIOException class]]) {
+    fprintf(stderr, "%s", [[_exception reason] cString]);
+  }
+  else if ([_exception isKindOfClass:[NGImap4Exception class]]) {
+    fprintf(stderr, "%s", [[_exception description] cString]);
+  }
+  else {
+    fprintf(stderr, "\n");
+    return _exception;
+  }
+  fprintf(stderr, "\n");
+  return nil;
+}
+
+- (NSArray *)_processUnseen:(NSArray *)result {
+  if (profileDS) [self logWithFormat:@"process unseen ..."];
+    
+  if (self->oldUnseenMessages) { // this implies, the folder hasn't changed
+      NSMutableSet *set = nil;
+      
+      set = [[NSMutableSet alloc] initWithArray:result];
+      [set addObjectsFromArray:self->oldUnseenMessages];
+      result = [[[set allObjects] retain] autorelease];
+      [set release];
+  }
+  [self->oldUnseenMessages release]; self->oldUnseenMessages = nil;
+  ASSIGN(self->oldUnseenMessages, result);
+    
+  if (profileDS) [self logWithFormat:@"process unseen: done."];
+  return result;
+}
+- (NSArray *)_sortMessages:(NSArray *)result {
+  NSArray *sortOrderings;
+
+  if ((sortOrderings = [[self fetchSpecification] sortOrderings]) == nil)
+    return result;
+  
+  if (profileDS) [self logWithFormat:@"sort messages ..."];
+  result = [result sortedArrayUsingKeyOrderArray:sortOrderings];
+  if (profileDS) [self logWithFormat:@"sort messages: done."];
+  return result;
+}
+
+- (NSArray *)fetchMessages {
+  EOQualifier *qualifier;
+  NSArray     *result  = nil;
+
+  if (profileDS) [self logWithFormat:@"fetchMessages: fetch ..."];
+  
+  qualifier = [[self fetchSpecification] qualifier];
+  
+  NS_DURING {
+    if (![qualifier isImap4UnseenQualifier]) {
+      [self->oldUnseenMessages release];
+      self->oldUnseenMessages = nil;
+    }
+    
+    if (profileDS) [self logWithFormat:@"fetchMessages:   exists&unseen ..."];
+    self->oldExists = [self->folder exists];
+    self->oldUnseen = [self->folder unseen];
+    
+    if (profileDS) [self logWithFormat:@"fetchMessages:   messages ..."];
+    result = (qualifier == nil)
+      ? [self->folder messages]
+      : [self->folder messagesForQualifier:qualifier];
+    if (profileDS) [self logWithFormat:@"fetchMessages:   messages done ..."];
+  }
+  NS_HANDLER {
+    [[self handleImapException:localException] raise];
+    result = [NSArray array];
+  }
+  NS_ENDHANDLER;
+  
+  if (profileDS) [self logWithFormat:@"fetchMessages:   ex handler done ..."];
+  
+  if ([qualifier isImap4UnseenQualifier])
+    result = [self _processUnseen:result];
+  
+  result = [self _sortMessages:result];
+  if (profileDS) [self logWithFormat:@"fetchMessages: done."];
+  return result;
+}
+
+@end /* NGImap4DataSource */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4FileManager.h b/skyrix-core/NGMime/NGImap4/NGImap4FileManager.h
new file mode 100644 (file)
index 0000000..6d58b66
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef  __NGImap4FileManager_H__
+#define __NGImap4FileManager_H__
+
+#import <Foundation/NSObject.h>
+#include <NGExtensions/NGFileManager.h>
+
+@class NSArray, NSString, NSData, NSDictionary, NSURL;
+@class NGImap4Context, NGImap4Folder, NGImap4Message;
+@class EODataSource;
+
+@interface NGImap4FileManager : NGFileManager
+{
+  NGImap4Context *imapContext;
+  NGImap4Folder  *rootFolder;
+  NGImap4Folder  *currentFolder;
+}
+
+- (id)initWithURL:(NSURL *)_url;
+- (id)initWithUser:(NSString *)_user
+  password:(NSString *)_pwd
+  host:(NSString *)_host;
+
+/* operations */
+
+- (id)imapContext;
+
+- (BOOL)createDirectoryAtPath:(NSString *)_path
+  attributes:(NSDictionary *)_attributes;
+- (BOOL)changeCurrentDirectoryPath:(NSString *)_path;
+- (NSString *)currentDirectoryPath;
+- (NGImap4Folder *)currentFolder;
+
+- (NGImap4Message *)messageAtPath:(NSString *)_path;
+- (NSData *)contentsAtPath:(NSString *)_path part:(NSString *)_part;
+- (NSData *)contentsAtPath:(NSString *)_path;
+- (NSArray *)directoryContentsAtPath:(NSString *)_path;
+- (NSArray *)directoriesAtPath:(NSString *)_path;
+- (NSArray *)filesAtPath:(NSString *)_path;
+- (NSArray *)directoryContentsAtPath:(NSString *)_path
+  directories:(BOOL)_dirs
+  files:(BOOL)_files;
+- (EODataSource *)dataSourceAtPath:(NSString *)_path;
+
+- (BOOL)fileExistsAtPath:(NSString *)_path;
+- (BOOL)fileExistsAtPath:(NSString *)_path isDirectory:(BOOL *)_isDir;
+- (BOOL)isReadableFileAtPath:(NSString *)_path;
+- (BOOL)isWritableFileAtPath:(NSString *)_path;
+- (BOOL)isExecutableFileAtPath:(NSString *)_path;
+- (BOOL)isDeletableFileAtPath:(NSString *)_path;
+
+- (BOOL)syncMode;
+- (void)setSyncMode:(BOOL)_bool;
+
+@end
+
+#endif /* __NGImap4FileManager_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4FileManager.m b/skyrix-core/NGMime/NGImap4/NGImap4FileManager.m
new file mode 100644 (file)
index 0000000..f72d8b7
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGImap4FileManager.h"
+#include <NGImap4/NGImap4Folder.h>
+#include <NGImap4/NGImap4Context.h>
+#include <NGImap4/NGImap4Message.h>
+#include <NGExtensions/NGFileFolderInfoDataSource.h>
+#include "imCommon.h"
+#include <NGImap4/NGImap4DataSource.h>
+
+@interface NGImap4FileManager(Privates)
+
+- (BOOL)loginWithUser:(NSString *)_user
+  password:(NSString *)_pwd
+  host:(NSString *)_host;
+
+- (NGImap4Folder *)_lookupFolderAtPath:(NSArray *)_paths;
+
+- (NGImap4Folder *)_lookupFolderAtPathString:(NSString *)_path;
+
+- (EOQualifier *)_qualifierForFileName:(NSString *)_filename;
+@end
+
+@implementation NGImap4FileManager
+
++ (int)version {
+  return [super version] + 0 /* v0 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 0,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithUser:(NSString *)_user
+  password:(NSString *)_pwd
+  host:(NSString *)_host
+{
+  if ((self = [super init])) {
+    if (![self loginWithUser:_user password:_pwd host:_host]) {
+      [self logWithFormat:@"could not login user '%@' host '%@'.", 
+              _user, _host];
+      [self release];
+      return nil;
+    }
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithUser:nil password:nil host:nil];
+}
+- (id)initWithURL:(NSURL *)_url {
+  if (_url == nil) {
+    [self release];
+    return nil;
+  }
+  
+  if ((self = [super init])) {
+    self->imapContext = [NGImap4Context alloc]; /* keep gcc happy */
+    if ((self->imapContext = [self->imapContext initWithURL:_url]) == nil){
+      [self logWithFormat:@"ERROR: got no IMAP4 context for url %@ ...",_url];
+      [self release];
+      return nil;
+    }
+    
+    [self->imapContext enterSyncMode];
+    
+    if (![self->imapContext openConnection]) {
+      [self logWithFormat:@"ERROR: could not open IMAP4 connection ..."];
+      [self release];
+      return nil;
+    }
+    
+    if ((self->rootFolder = [[self->imapContext serverRoot] retain]) == nil) {
+      [self logWithFormat:@"ERROR: did not find root folder ..."];
+      [self release];
+      return nil;
+    }
+    if ((self->currentFolder=[[self->imapContext inboxFolder] retain])==nil) {
+      [self logWithFormat:@"ERROR: did not find inbox folder ..."];
+      [self release];
+      return nil;
+    }
+    
+    if (![[_url path] isEqualToString:@"/"]) {
+      if (![self changeCurrentDirectoryPath:[_url path]]) {
+       [self logWithFormat:@"ERROR: couldn't change to URL path: %@", _url];
+       [self release];
+       return nil;
+      }
+    }
+  }
+  return self;
+}
+
+- (id)imapContext {
+  return self->imapContext;
+}
+
+- (void)dealloc {
+  [self->currentFolder release];
+  [self->imapContext   release];
+  [self->rootFolder    release];
+  [super dealloc];
+}
+
+/* operations */
+
+- (BOOL)loginWithUser:(NSString *)_user
+  password:(NSString *)_pwd
+  host:(NSString *)_host
+{
+  NSException  *loginException;
+  NSDictionary *conDict;
+  
+  [self->imapContext   release]; self->imapContext   = nil;
+  [self->rootFolder    release]; self->rootFolder    = nil;
+  [self->currentFolder release]; self->currentFolder = nil;
+  
+  conDict = [NSDictionary dictionaryWithObjectsAndKeys:
+                            _user ? _user : @"anonymous", @"login",
+                            _pwd  ? _pwd  : @"",          @"passwd",
+                            _host ? _host : @"localhost", @"host",
+                            nil];
+  
+  loginException = nil;
+  
+  self->imapContext =
+    [[NGImap4Context alloc] initWithConnectionDictionary:conDict];
+  [self->imapContext enterSyncMode];
+  
+  if (![self->imapContext openConnection])
+    return NO;
+  
+  if ((self->rootFolder = [[self->imapContext serverRoot] retain]) == nil)
+    return NO;
+  if ((self->currentFolder = [[self->imapContext inboxFolder] retain]) == nil)
+    return NO;
+  
+  return YES;
+}
+
+/* internals */
+
+- (id<NGImap4Folder>)_lookupFolderAtPath:(NSArray *)_paths {
+  NSEnumerator  *e;
+  NSString      *path;
+  id<NGImap4Folder> folder;
+
+  folder = self->currentFolder;
+
+  e = [_paths objectEnumerator];
+  while ((path = [e nextObject]) && (folder != nil)) {
+    if ([path isEqualToString:@"."])
+      continue;
+    if ([path isEqualToString:@""])
+      continue;
+    if ([path isEqualToString:@".."]) {
+      folder = [folder parentFolder];
+      continue;
+    }
+    if ([path isEqualToString:@"/"]) {
+      folder = self->rootFolder;
+      continue;
+    }
+    
+    folder = [folder subFolderWithName:path caseInsensitive:NO];
+  }
+
+  return folder;
+}
+- (NGImap4Folder *)_lookupFolderAtPathString:(NSString *)_path {
+  return [self _lookupFolderAtPath:[_path pathComponents]];
+}
+
+- (EOQualifier *)_qualifierForFileName:(NSString *)_filename {
+  return [EOQualifier qualifierWithQualifierFormat:@"uid=%@", _filename];
+}
+
+/* directory ops */
+
+- (BOOL)createDirectoryAtPath:(NSString *)_path
+  attributes:(NSDictionary *)_attributes
+{
+  NGImap4Folder *folder;
+  NSString *filename;
+  
+  if (![_path isAbsolutePath])
+    _path = [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
+  
+  filename = [_path lastPathComponent];
+  _path    = [_path stringByDeletingLastPathComponent];
+  
+  if ((folder = [self _lookupFolderAtPathString:_path]) == nil)
+    return NO;
+  
+  return [folder createSubFolderWithName:filename];
+}
+
+- (BOOL)changeCurrentDirectoryPath:(NSString *)_path {
+  NGImap4Folder *folder;
+
+  if ([_path length] == 0)
+    return NO;
+
+  if (![_path isAbsolutePath]) {
+    _path = [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
+  }
+
+  if ((folder = [self _lookupFolderAtPathString:_path]) == nil)
+    return NO;
+
+  ASSIGN(self->currentFolder, folder);
+
+  return YES;
+}
+
+- (NSString *)currentDirectoryPath {
+  if ([self->currentFolder isEqual:[self->currentFolder parentFolder]] ||
+      [self->currentFolder parentFolder] == nil)
+    return @"/";
+  else return [self->currentFolder absoluteName];
+}
+
+- (NGImap4Folder *)currentFolder {
+  return self->currentFolder;
+}
+
+/* operations */
+
+- (NSArray *)directoryContentsAtPath:(NSString *)_path {
+  return [self directoryContentsAtPath:_path directories:YES files:YES];
+}
+
+- (NSArray *)directoriesAtPath:(NSString *)_path {
+  return [self directoryContentsAtPath:_path directories:YES files:NO];
+}
+
+- (NSArray *)filesAtPath:(NSString *)_path {
+  return [self directoryContentsAtPath:_path directories:NO files:YES];
+}
+
+- (NSArray *)directoryContentsAtPath:(NSString *)_path
+  directories:(BOOL)_dirs
+  files:(BOOL)_files
+{
+  NGImap4Folder  *folder;
+  NSMutableArray *results;
+  NSEnumerator   *e;
+  NGImap4Folder  *tmp;
+  NGImap4Message *msg;
+
+  if (![_path isAbsolutePath])
+    _path = [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
+
+  if ((folder = [self _lookupFolderAtPath:[_path pathComponents]]) == nil)
+    /* folder does not exist */
+    return nil;
+
+  results = [NSMutableArray arrayWithCapacity:64];
+
+  /* add folders */
+  if (_dirs) {
+    e = [[folder subFolders] objectEnumerator];
+    while ((tmp = [e nextObject]))
+      [results addObject:[tmp name]];
+  }
+
+  /* add messages */
+  if (_files) {
+    e = [[folder messages] objectEnumerator];
+    while ((msg = [e nextObject]))
+      [results addObject:[NSString stringWithFormat:@"%d", [msg uid]]];
+  }
+
+  return results;
+}
+
+- (NGImap4Message *)messageAtPath:(NSString *)_path {
+  NGImap4Folder  *folder;
+  NSString       *filename;
+  EOQualifier    *q;
+  NSArray        *msgs;
+  NGImap4Message *msg;
+
+  if (![_path isAbsolutePath])
+    _path = [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
+  
+  filename = [_path lastPathComponent];
+  _path    = [_path stringByDeletingLastPathComponent];
+
+  if ((folder = [self _lookupFolderAtPath:[_path pathComponents]]) == nil)
+    return nil;
+
+  q = [self _qualifierForFileName:filename];
+  //NSLog(@"qualifier: %@", q);
+
+  msgs = [folder messagesForQualifier:q maxCount:2];
+  if ([msgs count] == 0) {
+    /* no such message .. */
+    return nil;
+  }
+  if ([msgs count] > 1) {
+    NSLog(@"multiple messages for uid %@", filename);
+    return nil;
+  }
+  msg = [msgs objectAtIndex:0];
+  return msg;
+}
+
+- (NSData *)contentsAtPath:(NSString *)_path {
+  return [self contentsAtPath:_path part:@""];
+}
+
+- (NSData *)contentsAtPath:(NSString *)_path part:(NSString *)_part {
+  NSString      *fileName;
+  NGImap4Folder *folder;
+
+  if (![_path isAbsolutePath])
+    _path = [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
+
+  fileName = [_path lastPathComponent];
+  _path    = [_path stringByDeletingLastPathComponent];
+
+  if ((folder = [self _lookupFolderAtPath:[_path pathComponents]]) == nil)
+    return nil;
+
+  return [folder blobForUid:[fileName unsignedIntValue] part:_part];
+}
+
+- (BOOL)fileExistsAtPath:(NSString *)_path {
+  BOOL isDir;
+  return [self fileExistsAtPath:_path isDirectory:&isDir];
+}
+- (BOOL)fileExistsAtPath:(NSString *)_path isDirectory:(BOOL *)_isDir {
+  NSArray       *paths;
+  NSString      *fileName;
+  NGImap4Folder *folder;
+  
+  if (![_path isAbsolutePath])
+    _path = [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
+  
+  fileName = [_path lastPathComponent];
+  _path    = [_path stringByDeletingLastPathComponent];
+  paths    = [_path pathComponents];
+
+  folder = [self _lookupFolderAtPath:paths];
+
+  // NSLog(@"paths: %@, file %@, folder %@", paths, fileName, folder);
+  
+  if (folder == nil)
+    return NO;
+
+  if ([fileName isEqualToString:@"."]) {
+    *_isDir = YES;
+    return YES;
+  }
+  if ([fileName isEqualToString:@".."]) {
+    *_isDir = YES;
+    return YES;
+  }
+  
+  if ([folder subFolderWithName:fileName caseInsensitive:NO]) {
+    *_isDir = YES;
+    return YES;
+  }
+
+  *_isDir = NO;
+
+  /* check for message 'file' */
+  {
+    EOQualifier *q;
+    NSArray *msgs;
+
+    q = [self _qualifierForFileName:fileName];
+    msgs = [folder messagesForQualifier:q maxCount:2];
+
+    if ([msgs count] > 0)
+      return YES;
+  }
+  
+  return NO;
+}
+
+- (BOOL)isReadableFileAtPath:(NSString *)_path {
+  return [self fileExistsAtPath:_path];
+}
+- (BOOL)isWritableFileAtPath:(NSString *)_path {
+  return [self fileExistsAtPath:_path];
+}
+- (BOOL)isExecutableFileAtPath:(NSString *)_path {
+  return NO;
+}
+- (BOOL)isDeletableFileAtPath:(NSString *)_path {
+  return [self fileExistsAtPath:_path];
+}
+
+/* attributes */
+
+- (NSDictionary *)_fileAttributesOfFolder:(id<NGImap4Folder>)_folder {
+  NSMutableDictionary *attrs;
+  id tmp;
+
+  attrs = [NSMutableDictionary dictionaryWithCapacity:12];
+  
+  if ((tmp = [_folder absoluteName]))
+    [attrs setObject:tmp forKey:NSFilePath];
+  if ((tmp = [_folder name]))
+    [attrs setObject:tmp forKey:NSFileName];
+  if ((tmp = [[_folder parentFolder] absoluteName]))
+    [attrs setObject:tmp forKey:NSParentPath];
+  
+  [attrs setObject:[self->imapContext login] forKey:NSFileOwnerAccountName];
+  [attrs setObject:NSFileTypeDirectory forKey:NSFileType];
+  
+  return attrs;
+}
+
+- (NSDictionary *)_fileAttributesOfMessage:(NGImap4Message *)_msg
+  inFolder:(NGImap4Folder *)_folder
+{
+  NSMutableDictionary *attrs;
+  NSString            *fileName, *filePath;
+  NSDictionary        *headers;
+  id                  tmp;
+
+  static NGMimeHeaderNames *Fields = NULL;
+
+  if (!Fields)
+    Fields = (NGMimeHeaderNames *)[NGMimePartParser headerFieldNames];
+  
+  
+  headers = (id)[_msg headers];
+  //NSLog(@"headers: %@", headers);
+  
+  fileName = [NSString stringWithFormat:@"%i", [_msg uid]];
+  filePath = [[_folder absoluteName] stringByAppendingPathComponent:fileName];
+  attrs    = [NSMutableDictionary dictionaryWithCapacity:12];
+  
+  if (filePath) [attrs setObject:filePath forKey:NSFilePath];
+  if (fileName) [attrs setObject:fileName forKey:NSFileName];
+  
+  if ((tmp = [_folder absoluteName]))
+    [attrs setObject:tmp forKey:NSParentPath];
+  
+  if ((tmp = [headers objectForKey:@"date"])) {
+    /* should parse date ? */
+    NSCalendarDate *date;
+
+    if ([tmp isKindOfClass:[NSDate class]])
+      date = tmp;
+    else {
+      NGMimeRFC822DateHeaderFieldParser *parser;
+      parser = [[NGMimeRFC822DateHeaderFieldParser alloc] init];
+      date = [parser parseValue:
+                     [tmp dataUsingEncoding:[NSString defaultCStringEncoding]]
+                     ofHeaderField:@"date"];
+      [parser release];
+    }
+    
+    if (date == nil)
+      NSLog(@"couldn't parse date: %@", tmp);
+    
+    [attrs setObject:date ? date : tmp forKey:NSFileModificationDate];
+  }
+  
+  if ((tmp = [headers objectForKey:Fields->from]))
+    [attrs setObject:tmp forKey:@"NGImapFrom"];
+  if ((tmp = [headers objectForKey:Fields->xMailer]))
+    [attrs setObject:tmp forKey:@"NGImapMailer"];
+  if ((tmp = [headers objectForKey:Fields->organization]))
+    [attrs setObject:tmp forKey:@"NGImapOrganization"];
+  if ((tmp = [headers objectForKey:Fields->to]))
+    [attrs setObject:tmp forKey:@"NGImapReceiver"];
+  if ((tmp = [headers objectForKey:Fields->subject]))
+    [attrs setObject:tmp forKey:@"NGImapSubject"];
+  if ((tmp = [headers objectForKey:Fields->contentType]))
+    [attrs setObject:tmp forKey:@"NGImapContentType"];
+  
+  [attrs setObject:[self->imapContext login] forKey:NSFileOwnerAccountName];
+  [attrs setObject:[NSNumber numberWithInt:[_msg size]] forKey:NSFileSize];
+
+  if ((tmp = [headers objectForKey:Fields->messageID]))
+    [attrs setObject:tmp forKey:@"NSFileIdentifier"];
+  else {
+    [attrs setObject:[NSNumber numberWithInt:[_msg uid]]
+           forKey:@"NSFileIdentifier"];
+  }
+  
+  [attrs setObject:NSFileTypeRegular forKey:NSFileType];
+  
+  return attrs;
+}
+
+- (NSDictionary *)fileAttributesAtPath:(NSString *)_path
+  traverseLink:(BOOL)flag
+{
+  NSString      *fileName;
+  NGImap4Folder *folder, *sfolder;
+  
+  if (![_path isAbsolutePath])
+    _path = [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
+  
+  fileName = [_path lastPathComponent];
+  _path    = [_path stringByDeletingLastPathComponent];
+  
+  if ((folder = [self _lookupFolderAtPath:[_path pathComponents]]) == nil)
+    return nil;
+  
+  /* check for folder */
+  
+  if ([fileName isEqualToString:@"."])
+    return [self _fileAttributesOfFolder:folder];
+  if ([fileName isEqualToString:@".."])
+    return [self _fileAttributesOfFolder:[folder parentFolder]];
+  
+  if ((sfolder = [folder subFolderWithName:fileName caseInsensitive:NO])) 
+    return [self _fileAttributesOfFolder:sfolder];
+
+  /* check for messages */
+  {
+    EOQualifier *q;
+    NSArray *msgs;
+    
+    q = [self _qualifierForFileName:fileName];
+    msgs = [folder messagesForQualifier:q maxCount:2];
+
+    if ([msgs count] == 0) {
+      /* msg does not exist */
+      //NSLog(@"did not find msg for qualifier %@ in folder %@", q, folder);
+      return nil;
+    }
+    
+    return [self _fileAttributesOfMessage:[msgs objectAtIndex:0]
+                 inFolder:folder];
+  }
+}
+
+- (NSDictionary *)fileSystemAttributesAtPath:(NSString *)_path {
+  NSMutableDictionary *dict;
+  id tmp;
+
+  dict = [NSMutableDictionary dictionaryWithCapacity:12];
+
+  if ((tmp = [self->imapContext host]))
+    [dict setObject:tmp forKey:@"host"];
+  if ((tmp = [self->imapContext login]))
+    [dict setObject:tmp forKey:@"login"];
+  if ((tmp = [self->imapContext serverName]))
+    [dict setObject:tmp forKey:@"serverName"];
+  if ((tmp = [self->imapContext serverKind]))
+    [dict setObject:tmp forKey:@"serverKind"];
+  if ((tmp = [self->imapContext serverVersion]))
+    [dict setObject:tmp forKey:@"serverVersion"];
+  if ((tmp = [self->imapContext serverTag]))
+    [dict setObject:tmp forKey:@"serverTag"];
+
+  if ((tmp = [[self->imapContext trashFolder] absoluteName]))
+    [dict setObject:tmp forKey:@"trashFolderPath"];
+  if ((tmp = [[self->imapContext sentFolder] absoluteName]))
+    [dict setObject:tmp forKey:@"sentFolderPath"];
+  if ((tmp = [[self->imapContext draftsFolder] absoluteName]))
+    [dict setObject:tmp forKey:@"draftsFolderPath"];
+  if ((tmp = [[self->imapContext inboxFolder] absoluteName]))
+    [dict setObject:tmp forKey:@"inboxFolderPath"];
+  if ((tmp = [[self->imapContext serverRoot] absoluteName]))
+    [dict setObject:tmp forKey:@"rootFolderPath"];
+  
+  return dict;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:64];
+
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  [ms appendFormat:@" ctx=%@",  self->imapContext];
+  [ms appendFormat:@" root=%@", self->rootFolder];
+  [ms appendFormat:@" wd=%@",   self->currentFolder];
+  [ms appendString:@">"];
+
+  return ms;
+}
+
+- (EODataSource *)dataSourceAtPath:(NSString *)_path {
+  NGImap4Folder *f;
+  
+  if ((f = [self _lookupFolderAtPath:[_path pathComponents]]) == nil)
+    return nil;
+    
+  return [[[NGImap4DataSource alloc] initWithFolder:f] autorelease];
+}
+
+- (BOOL)syncMode {
+  return [self->imapContext isInSyncMode];
+}
+
+- (void)setSyncMode:(BOOL)_bool {
+  if (_bool)
+    [self->imapContext enterSyncMode];
+  else
+    [self->imapContext leaveSyncMode];
+}
+
+@end /* NGImap4FileManager */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Folder.h b/skyrix-core/NGMime/NGImap4/NGImap4Folder.h
new file mode 100644 (file)
index 0000000..62e50dd
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+  Copyright (C) 2000-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$
+#ifndef __Networking_NGImap4_NGImap4Folder_H__
+#define __Networking_NGImap4_NGImap4Folder_H__
+
+#import <Foundation/Foundation.h>
+#import <NGMime/NGPart.h>
+#import <NGImap4/NGImap4Support.h>
+
+#define USE_MESSAGE_CACHE 0
+
+@class NSArray, NSString, NSMutableArray, NSNumber;
+@class EOGlobalID, EOQualifier;
+@class NGHashMap;
+@class NGImap4Context, NGImap4Message, NGImap4FolderMailRegistry;
+@class NGImap4FolderFlags;
+
+@interface NGImap4Folder : NSObject <NGImap4Folder>
+{
+@private  
+  NGImap4FolderFlags *flags;
+  NSString           *name;
+  NSURL              *url;
+  EOGlobalID         *globalID;
+  NGImap4Context     *context;
+  NSArray            *subFolders;
+
+  NSArray            *msn2UidCache;
+  
+  id<NGImap4Folder> parentFolder; // not retained
+
+  NSNumber *isReadOnly;
+  NSArray  *messageFlags;
+  
+  int exists;
+  int recent;
+  int unseen;
+  
+  BOOL selectSyncState;
+  
+  int maxQuota;
+  int usedSpace;
+  int overQuota;
+
+  struct {
+    BOOL select:1;
+    BOOL status:1;
+    BOOL quota:1;
+  } failedFlags;
+  
+  NGImap4FolderMailRegistry *mailRegistry;
+  
+#if USE_MESSAGE_CACHE
+  int cacheIdx;
+  
+  NSMutableArray *messages;  
+  NSMutableArray *qualifierCache;
+  NSMutableArray *messagesCache;
+#endif  
+}
+
+- (id)initWithContext:(NGImap4Context *)_context
+  name:(NSString *)_name
+  flags:(NSArray *)_flags
+  parentFolder:(id<NGImap4Folder>)_folder;
+
+- (BOOL)isEqual:(id)_obj;
+- (BOOL)isEqualToImap4Folder:(NGImap4Folder *)_folder;
+
+/* accessors */
+
+- (NGImap4Context *)context;
+- (NSException *)lastException;
+- (void)resetLastException;
+- (id<NGImap4Folder>)parentFolder;
+
+- (NSString *)name;
+- (NSString *)absoluteName;
+- (NSArray *)flags;
+
+- (NSData *)blobForUid:(unsigned)_mUid
+  part:(NSString *)_part;
+
+- (NSArray *)fetchSortedMessages:(NSArray *)_so;
+
+- (void)bulkFetchHeadersFor:(NSArray *)_array inRange:(NSRange)_aRange;
+- (void)bulkFetchHeadersFor:(NSArray *)_array inRange:(NSRange)_aRange
+  withAllUnread:(BOOL)_allUnread;
+
+- (NSArray *)fetchSortedMessages:(NSRange)_aRange
+  sortOrderings:(NSArray *)_so;
+- (NSArray *)messageFlags;
+- (NSArray *)messages;
+- (NSArray *)messagesForQualifier:(EOQualifier *)_qualifier;
+- (NSArray *)messagesForQualifier:(EOQualifier *)_qualifier maxCount:(int)_cnt;
+- (NSArray *)subFolders;
+- (NGImap4Folder *)subFolderWithName:(NSString *)_name
+  caseInsensitive:(BOOL)_caseIns;
+- (NGImap4Message *)messageForUid:(unsigned)_mUid
+  sortOrderings:(NSArray *)_so
+  onlyUnread:(BOOL)_unread
+  nextMessage:(BOOL)_next;
+
+- (BOOL)isReadOnly;
+- (int)exists;
+- (int)recent;
+- (int)unseen;
+
+- (BOOL)noselect;
+- (BOOL)noinferiors;
+- (BOOL)nonexistent;
+- (BOOL)haschildren;
+- (BOOL)hasnochildren;
+- (BOOL)marked;
+- (BOOL)unmarked;
+
+/* this folder or its subfolders */
+
+- (BOOL)hasNewMessagesSearchRecursiv:(BOOL)_recursiv;
+- (BOOL)hasUnseenMessagesSearchRecursiv:(BOOL)_recursiv;
+- (BOOL)hasNewMessagesSearchRecursiv:(BOOL)_rec    fetchOnDemand:(BOOL)_fetch;
+- (BOOL)hasUnseenMessagesSearchRecursiv:(BOOL)_rec fetchOnDemand:(BOOL)_fetch;
+
+/* Notifications */
+
+- (void)processResponse:(NSDictionary *)_dict;
+
+/* Actions */
+- (BOOL)status;
+- (BOOL)select;
+/* if imm == YES syncState will be ignored */
+- (BOOL)selectImmediately:(BOOL)_imm;
+- (void)expunge;
+
+- (BOOL)addFlag:(NSString *)_flag toMessages:(NSArray *)_messages;
+- (BOOL)removeFlag:(NSString *)_flag fromMessages:(NSArray *)_messages;
+- (BOOL)renameTo:(NSString *)_name;
+
+/* returns quota in kBytes */
+- (int)usedSpace;
+- (int)maxQuota;
+- (BOOL)isOverQuota; /* evaluate ALERT sequences during select */
+
+- (BOOL)deleteMessages:(NSArray *)_messages;
+- (BOOL)deleteAllMessages;
+- (BOOL)moveMessages:(NSArray *)_messages toFolder:(NGImap4Folder *)_folder;
+- (BOOL)copyMessages:(NSArray *)_messages toFolder:(NGImap4Folder *)_folder;
+- (BOOL)appendMessage:(NSData *)_msg;
+
+- (BOOL)deleteSubFolder:(NGImap4Folder *)_folder;
+- (BOOL)createSubFolderWithName:(NSString *)_name;
+- (BOOL)copySubFolder:(NGImap4Folder *)_f to:(NGImap4Folder *)_folder;
+- (BOOL)moveSubFolder:(NGImap4Folder *)_f to:(NGImap4Folder *)_folder;
+
+- (BOOL)isInTrash;
+
+- (void)resetFolder;
+- (void)resetSubFolders;
+- (void)resetStatus;
+
+- (void)resetSync;
+
+- (NSURL *)url;
+- (EOGlobalID *)serverGlobalID;
+- (EOGlobalID *)globalID;
+
+/* message factory */
+
+- (id)messageWithUid:(unsigned int)_uid;
+
+/* message registry */
+
+- (NGImap4FolderMailRegistry *)mailRegistry;
+
+@end
+
+#endif /* __Networking_NGImap4_NGImap4Folder_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Folder.m b/skyrix-core/NGMime/NGImap4/NGImap4Folder.m
new file mode 100644 (file)
index 0000000..b96b1ad
--- /dev/null
@@ -0,0 +1,2018 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGImap4Folder.h"
+#include "NGImap4Context.h"
+#include "NGImap4Client.h"
+#include "NGImap4Message.h"
+#include "NGImap4Functions.h"
+#include "NGImap4FolderGlobalID.h"
+#include "NGImap4FolderMailRegistry.h"
+#include "NGImap4FolderFlags.h"
+#include "imCommon.h"
+
+@interface NGImap4Message(Private)
+
+- (void)_setHeaders:(NGHashMap *)_headers
+  size:(unsigned)_size
+  flags:(NSArray *)_flags;
+
+- (BOOL)isComplete;
+- (void)setIsRead:(BOOL)_isRead;
+
+@end /* NGImap4Message(Private) */
+
+
+@interface NGImap4Context(Private)
+- (void)setLastException:(NSException *)_exception;
+- (void)setSelectedFolder:(NGImap4Folder *)_folder;
+@end /* NGImap4Context(Private) */
+
+@interface NGImap4Folder(Private)
+
+- (void)_resetFolder;
+- (void)_resetSubFolder;
+- (void)quota;
+- (NSArray *)initializeMessagesFrom:(unsigned)_from to:(unsigned)_to;
+- (NSArray *)initializeMessages;
+- (void)initializeSubFolders;
+- (void)addSubFolder:(NGImap4Folder *)_folder;
+- (BOOL)flag:(NSString*)_doof toMessages:(NSArray*)_msg add:(NSNumber*)_n;
+- (BOOL)flagToAllMessages:(NSString *)_flag add:(NSNumber *)_add;
+- (NSArray *)fetchMessagesFrom:(unsigned)_from to:(unsigned)_to;
+#if USE_MESSAGE_CACHE
+- (void)resetQualifierCache;
+#endif
+- (void)setRecent:(NSNumber *)_rec exists:(NSNumber *)_exists;
+- (void)clearParentFolder;
+
+- (BOOL)_testMessages:(NSArray *)_msgs operation:(NSString *)_op;
+- (NSArray *)_getMsnRanges:(NSArray *)_msgs;
+- (NSArray *)_calculateSequences:(NSMutableArray *)_numbers count:(int)_cnt;
+
+- (NSNotificationCenter *)notificationCenter;
+- (void)_registerForNotifications;
+
+@end /* NGImap4Folder(Private) */
+
+
+@implementation NGImap4Folder
+
+static NSNumber *YesNumber   = nil;
+static NSNumber *NoNumber    = nil;
+static NSArray  *StatusFlags = nil;
+static NSArray  *UnseenFlag  = nil;
+static BOOL     ImapDebugEnabled = NO;
+
+static int ShowNonExistentFolder                      = -1;
+static int IgnoreHasNoChildrenFlag                    = -1;
+static int FetchNewUnseenMessagesInSubFoldersOnDemand = -1;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  YesNumber = [[NSNumber numberWithBool:YES] retain];
+  NoNumber  = [[NSNumber numberWithBool:NO]  retain];
+
+  StatusFlags = [[NSArray alloc]
+                 initWithObjects:@"messages", @"recent", @"unseen", nil];
+  UnseenFlag = [[NSArray alloc] initWithObjects:@"unseen", nil];
+
+  ShowNonExistentFolder   = [ud boolForKey:@"ShowNonExistentFolder"] ? 1 : 0;
+  IgnoreHasNoChildrenFlag = [ud boolForKey:@"IgnoreHasNoChildrenFlag"] ? 1 : 0;
+  ImapDebugEnabled        = [ud boolForKey:@"ImapDebugEnabled"];
+  
+  FetchNewUnseenMessagesInSubFoldersOnDemand =
+      [ud boolForKey:@"FetchNewUnseenMessagesInSubFoldersOnDemand"] ? 1 : 0;
+}
+
+- (id)init {
+  [self release];
+  [self logWithFormat:@"ERROR: cannot init NGImap4Folder with -init!"];
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (void)_setupMessageCache {
+#if USE_MESSAGE_CACHE
+  self->cacheIdx       = 0;    
+  self->qualifierCache =
+    [[NSMutableArray alloc] initWithCapacity:MAX_QUALIFIER_CACHE];
+  self->messagesCache  =
+    [[NSMutableArray alloc] initWithCapacity:MAX_QUALIFIER_CACHE];
+#endif    
+}
+
+- (id)initWithContext:_context
+  name:(NSString *)_name
+  flags:(NSArray *)_flags
+  parentFolder:(id<NGImap4Folder>)_folder
+{
+  if ((self = [super init])) {
+    self->context      = [_context retain];
+    self->flags        = [[NGImap4FolderFlags alloc] initWithFlagArray:_flags];
+    self->name         = [_name copy];
+    self->parentFolder = _folder;
+    self->mailRegistry = [[NGImap4FolderMailRegistry alloc] init];
+    
+    /* mark as 'to be fetched' */
+    self->exists            = -1;
+    self->recent            = -1;
+    self->unseen            = -1;
+    self->usedSpace         = -1;
+    self->maxQuota          = -1;
+    self->overQuota         = -1;
+    
+    self->failedFlags.status = NO;
+    self->failedFlags.select = NO;
+    self->failedFlags.quota  = NO;
+    
+    // TODO: this also looks pretty weird!
+    if ([[self->name lowercaseString] isEqualToString:@"/inbox"] &&
+        [self->flags doNotSelectFolder]) {
+      NSDictionary *res;
+
+      [self resetLastException];
+      
+      res = [[self->context client] subscribe:[self absoluteName]];
+
+      if ([self lastException] != nil) {
+        [self release];
+        return nil;
+      }
+      
+      if ([[res objectForKey:@"result"] boolValue])
+       [self->flags allowFolderSelect];
+    }
+    
+    [self _registerForNotifications];
+    [self _setupMessageCache];
+  }
+#if NGIMAP_FOLDER_DEBUG
+  return [self->context registerFolder:self];
+#else  
+  return self;
+#endif  
+}
+
+- (void)dealloc {
+  [[self notificationCenter] removeObserver:self];
+  [self->context removeSelectedFolder:self];
+  [self->subFolders makeObjectsPerformSelector:@selector(clearParentFolder)];
+  
+  [self->mailRegistry release];
+  [self->msn2UidCache release];
+  [self->context      release];
+  [self->flags        release];
+  [self->name         release];
+  [self->subFolders   release]; 
+  [self->messageFlags release];
+  [self->url          release];
+#if USE_MESSAGE_CACHE
+  [self->messages       release];
+  [self->qualifierCache release];
+  [self->messagesCache  release];
+#endif
+  self->isReadOnly   = nil;
+  self->parentFolder = nil;
+  
+  [super dealloc];
+}
+
+- (BOOL)isEqual:(id)_obj {
+  if (self == _obj)
+    return YES;
+  if ([_obj isKindOfClass:[NGImap4Folder class]])
+    return [self isEqualToImap4Folder:_obj];
+  return NO;
+}
+
+- (BOOL)isEqualToImap4Folder:(NGImap4Folder *)_folder {
+  if (self == _folder)
+    return YES;
+  if (([[_folder absoluteName] isEqualToString:self->name]) &&
+      [_folder context] == self->context) {
+    return YES;
+  }
+  return NO;
+}
+
+/* accessors */
+
+- (NSException *)lastException {
+  return [self->context lastException];
+}
+- (void)resetLastException {
+  [self->context resetLastException];
+}
+
+- (NGImap4Context *)context {
+  return self->context;
+}
+
+- (NSString *)name {
+  return [[self absoluteName] lastPathComponent];
+}
+
+- (NSString *)absoluteName {
+  return self->name;
+}
+
+- (NSArray *)flags {
+  return [self->flags flagArray];
+}
+
+- (NSArray *)messages {
+  return [self initializeMessages];
+}
+
+- (BOOL)_checkResult:(NSDictionary *)_dict cmd:(const char *)_command {
+  return _checkResult(self->context, _dict, _command);
+}
+
+- (NSArray *)messagesForQualifier:(EOQualifier *)_qualifier
+  maxCount:(int)_cnt
+{
+  // TODO: split up method
+  NSMutableArray    *mes  = nil;
+  NSMutableArray    *msn  = nil;
+  NSDictionary      *dict = nil;
+  NSAutoreleasePool *pool = nil;
+
+  if ([self->flags doNotSelectFolder] || self->failedFlags.select)
+    return nil;
+  
+  if (![self->context registerAsSelectedFolder:self])
+    return nil;
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+#if USE_MESSAGE_CACHE  
+  if (self->cacheIdx > 0) {
+    NSEnumerator *qualifierEnum = nil;
+    EOQualifier  *qual          = nil;
+    int          cnt            = 0;
+
+    qualifierEnum = [self->qualifierCache objectEnumerator];
+
+    while ((qual = [qualifierEnum nextObject])) {
+      if ([qual isEqual:_qualifier]) {
+        NSArray *m;
+        
+        m = [[self->messagesCache objectAtIndex:cnt] retain];
+        [pool release];
+        return [m autorelease];
+      }
+      cnt++;
+    }
+  }
+#endif
+  [self resetLastException];
+  
+  dict = [[self->context client] searchWithQualifier:_qualifier];
+
+  if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__])
+    return nil;
+
+  msn  = [[dict objectForKey:@"search"] mutableCopy];
+  
+  if ((msn == nil) || ([msn count] == 0)) {
+    mes = [NSArray array];
+  }
+  else {
+    NSEnumerator *seq = nil;
+    NSDictionary *obj = nil;
+    
+    mes = [NSMutableArray arrayWithCapacity:512];
+    seq = [[self _calculateSequences:msn count:_cnt] objectEnumerator];
+    while ((obj = [seq nextObject])) {
+      NSArray *a;
+      
+      a = [self fetchMessagesFrom:
+                 [[obj objectForKey:@"start"] unsignedIntValue]
+                to:[[obj objectForKey:@"end"] unsignedIntValue]];
+      
+      if ([self lastException] != nil)
+        break;
+      
+      if (a)
+        [mes addObjectsFromArray:a];
+    }
+    mes = [[mes copy] autorelease];
+  }
+  [msn release];
+
+#if USE_MESSAGE_CACHE  
+  if (self->cacheIdx == 5)
+    self->cacheIdx = 0;
+
+  if ([self->qualifierCache count] == self->cacheIdx)
+    [self->qualifierCache addObject:_qualifier];
+  else
+    [self->qualifierCache replaceObjectAtIndex:self->cacheIdx
+         withObject:_qualifier];
+  if ([self->messagesCache count] == self->cacheIdx)
+    [self->messagesCache addObject:mes];
+  else {
+    [self->messagesCache replaceObjectAtIndex:self->cacheIdx
+                         withObject:mes];
+  }
+  self->cacheIdx++;
+#endif  
+  
+  mes = [mes retain];
+  [pool release];
+
+  if ([self lastException]) {
+    [mes release];
+    return nil;
+  }
+  return [mes autorelease];
+}
+
+- (NSArray *)messagesForQualifier:(EOQualifier *)_qualifier {
+  return [self messagesForQualifier:_qualifier maxCount:-1];
+}
+
+- (NSArray *)messageFlags {
+  if (self->messageFlags == nil)
+    [self->context registerAsSelectedFolder:self];
+  return self->messageFlags;
+}
+
+- (NSArray *)subFolders {
+  if (self->subFolders == nil)
+    [self initializeSubFolders];
+  return self->subFolders;
+}
+
+- (NGImap4Folder *)subFolderWithName:(NSString *)_name
+  caseInsensitive:(BOOL)_caseIns {
+  return _subFolderWithName(self, _name, _caseIns);
+}
+
+- (id<NGImap4Folder>)parentFolder {
+  return self->parentFolder;
+}
+
+- (BOOL)isReadOnly {
+  if (self->isReadOnly == nil)
+    [self->context registerAsSelectedFolder:self];
+  return (self->isReadOnly == YesNumber) ? YES : NO;
+}
+
+/* flags */
+
+- (BOOL)noselect {
+  return [self->flags doNotSelectFolder];
+}
+- (BOOL)noinferiors {
+  return [self->flags doesNotSupportSubfolders];
+}
+- (BOOL)nonexistent {
+  return [self->flags doesNotExist];
+}
+- (BOOL)haschildren {
+  return [self->flags hasSubfolders];
+}
+- (BOOL)hasnochildren {
+  return [self->flags hasNoSubfolders];
+}
+- (BOOL)marked {
+  return [self->flags isMarked];
+}
+- (BOOL)unmarked {
+  return [self->flags isUnmarked];
+}
+
+- (int)exists {
+  if (self->exists == -1) {
+    [self status];
+  }
+  return self->exists;
+}
+
+- (int)recent {
+  if (self->recent == -1)
+    [self status];
+  
+  return self->recent;
+}
+
+- (int)unseen {
+  if (self->unseen == -1)
+    [self status];
+  
+  return self->unseen;
+}
+
+- (BOOL)isOverQuota {
+  if (self->overQuota == -1)
+    [self->context registerAsSelectedFolder:self];
+  
+  return (self->overQuota == 1)? YES : NO;
+}
+
+- (int)usedSpace {
+  if (self->usedSpace == -1)
+    [self quota];
+  
+  return self->usedSpace;
+}
+
+- (int)maxQuota {
+  if (self->maxQuota == -1)
+    [self quota];
+  
+  return self->maxQuota;
+}
+
+- (BOOL)hasNewMessagesSearchRecursiv:(BOOL)_rec fetchOnDemand:(BOOL)_fetch {
+  if (_fetch) {
+    if (([self recent] > 0) && ([self unseen] > 0))
+      return YES;
+  }
+  else {
+    if ((self->recent > 0) && (self->unseen > 0))
+      return YES;
+  }
+  
+  if (_rec)
+    return _hasNewMessagesInSubFolder(self, _fetch);
+  
+  return NO;
+}
+
+- (BOOL)hasNewMessagesSearchRecursiv:(BOOL)_recursiv {
+  if (([self recent] > 0) && ([self unseen] > 0))
+    return YES;
+
+  if (_recursiv) {
+    return _hasNewMessagesInSubFolder(self,
+              FetchNewUnseenMessagesInSubFoldersOnDemand);
+  }
+  return NO;
+}
+
+- (BOOL)hasUnseenMessagesSearchRecursiv:(BOOL)_rec fetchOnDemand:(BOOL)_fetch {
+  if (_fetch) {
+    if ([self unseen] > 0)
+      return YES;
+  }
+  else
+    if (self->unseen > 0)
+      return YES;
+
+  if (_rec)
+    return _hasUnseenMessagesInSubFolder(self, _fetch);
+  
+  return NO;
+}
+
+- (BOOL)hasUnseenMessagesSearchRecursiv:(BOOL)_recursiv {
+  if ([self unseen] > 0)
+    return YES;
+
+  if (_recursiv)
+    return
+      _hasUnseenMessagesInSubFolder(self,
+                                    FetchNewUnseenMessagesInSubFoldersOnDemand);
+  return NO;
+}
+
+/* notifications (fix that junk!) */
+
+- (NSNotificationCenter *)notificationCenter {
+  static NSNotificationCenter *nc = nil;
+  if (nc == nil)
+    nc = [[NSNotificationCenter defaultCenter] retain];
+  return nc;
+}
+
+- (NSString *)resetFolderNotificationName {
+  return [@"NGImap4FolderReset_" stringByAppendingString:[self absoluteName]];
+}
+- (NSString *)resetSubfolderNotificationName {
+  return [@"NGImap4SubFolderReset__" 
+           stringByAppendingString:[self absoluteName]];
+}
+
+- (void)_registerForNotifications {
+  NSNotificationCenter *nc;
+  NSString             *n;
+
+  nc = [self notificationCenter];
+  n  = [self absoluteName];
+      
+  // TODO: fix that junk!
+  if ([n length] > 0) {
+    [nc addObserver:self selector:@selector(_resetFolder)
+        name:[self resetFolderNotificationName]
+        object:nil];
+    [nc addObserver:self selector:@selector(_resetSubFolder)
+        name:[self resetSubfolderNotificationName]
+        object:nil];
+  }
+}
+
+- (void)_postResetFolderNotification {
+  [[self notificationCenter] postNotificationName:
+                               [self resetFolderNotificationName] 
+                             object:nil];
+}
+- (void)_postResetSubfolderNotification {
+  [[self notificationCenter] postNotificationName:
+                               [self resetSubfolderNotificationName] 
+                             object:nil];
+}
+
+/* private methods */
+
+- (NSArray *)initializeMessages {
+  return [self initializeMessagesFrom:0 to:[self exists]];
+}
+
+- (NSArray *)initializeMessagesFrom:(unsigned)_from to:(unsigned)_to {
+#if USE_MESSAGE_CACHE  
+  if (self->messages == nil) {
+    self->messages = [[NSMutableArray alloc] initWithCapacity:_to];
+  }
+  [self->messages addObjectsFromArray:[self fetchMessagesFrom:_from to:_to]];
+  return self->messages;
+#else
+  return [self fetchMessagesFrom:_from to:_to];
+#endif  
+}
+
+- (NGImap4Message *)createMessageForUid:(unsigned)_uid
+  headers:(id)_headers size:(unsigned)_size flags:(NSArray *)_flags
+{
+  return [[NGImap4Message alloc] initWithUid:_uid
+                                 headers:_headers size:_size flags:_flags
+                                 folder:self context:self->context];
+}
+
+- (NSArray *)_buildMessagesFromFetch:(NSDictionary *)_fetch
+  usingMessages:(NSDictionary *)_messages
+{
+  NSEnumerator        *mEnum;
+  NSDictionary        *m;
+  NGMimeMessageParser *parser;
+  NSMutableArray      *mes;
+  NSAutoreleasePool   *pool;
+
+  pool  = [[NSAutoreleasePool alloc] init];
+  mEnum = [[_fetch objectForKey:@"fetch"] objectEnumerator];
+  mes   = nil;
+  
+  if (_messages == nil)
+    mes = [[NSMutableArray alloc] initWithCapacity:512];
+  
+  parser = [[[NGMimeMessageParser alloc] init] autorelease];
+  // TODO: should we disable parsing of some headers? but which?
+  //       is this method only for parsing headers?!
+  
+  while ((m = [mEnum nextObject])) {
+    NGDataStream *stream = nil;
+    NSData *headerData;
+    id headers, uid, f, size;
+    
+    headerData = [m objectForKey:@"header"];
+    uid        = [m objectForKey:@"uid"];
+    f          = [m objectForKey:@"flags"];
+    size       = [m objectForKey:@"size"];
+    
+    if (headerData == nil || uid == nil || f == nil || size == nil) {
+      [self logWithFormat:@"WARNING[%s]: got no header, uid, flags, size "
+            @"for %@", __PRETTY_FUNCTION__, m];
+      continue;
+    }
+    if (([f containsObject:@"recent"]) && ([f containsObject:@"seen"])) {
+        f = [f mutableCopy];
+        [f removeObject:@"recent"];
+        [f autorelease];
+    }
+    
+    /* setup parser */
+    stream = [[NGDataStream alloc] initWithData:headerData 
+                                  mode:NGStreamMode_readOnly];
+    [parser prepareForParsingFromStream:stream];
+    [stream release]; stream = nil;
+    
+    /* parse */
+    headers = [parser parseHeader];
+    
+    if (_messages) {
+      NGImap4Message *msg;
+      
+      if ((msg = [_messages objectForKey:uid]) == nil) {
+        [self logWithFormat:@"WARNING[%s]: missing message for uid %@ from "
+                @"fetch %@ in dict %@", __PRETTY_FUNCTION__,
+                uid, _fetch, _messages];
+        continue;
+      }
+      [msg _setHeaders:headers size:[size intValue] flags:f];
+    }
+    else {
+      NGImap4Message *m;
+      
+      m = [self createMessageForUid:[uid unsignedIntValue]
+               headers:headers size:[size unsignedIntValue] flags:f];
+      if (m) [mes addObject:m];
+      [m release];
+    }
+  }
+  m = [mes copy];
+  [mes release]; mes = nil;
+  [pool release];
+  
+  return [m autorelease];;
+}
+
+- (NSArray *)_buildMessagesFromFetch:(NSDictionary *)_fetch {
+  return [self _buildMessagesFromFetch:_fetch usingMessages:nil];
+}
+
+- (NSArray *)_messageIds:(NSArray *)_so onlyUnseen:(BOOL)_unseen {
+  NSAutoreleasePool  *pool;
+  NSDictionary       *dict;
+  NSArray            *uids;
+  static EOQualifier *UnseenQual = nil;
+
+  uids = nil;
+  
+  /* hack for sorting for unseen/seen */
+  if (UnseenQual == nil) {
+    UnseenQual = [[EOKeyValueQualifier alloc]
+                                       initWithKey:@"flags"
+                                       operatorSelector:
+                                       EOQualifierOperatorEqual
+                                       value:@"unseen"];
+  }
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  if ([_so count] == 1) {
+    EOSortOrdering *so;
+
+    so = [_so lastObject];
+
+    if ([[so key] isEqualToString:@"unseen"]) {
+      static NSArray        *DateSo     = nil;
+      static EOQualifier    *SeenQual   = nil;
+      
+      NSMutableArray *muids;
+      EOQualifier    *qual1, *qual2; 
+
+      if (DateSo == nil) {
+        DateSo = [[NSArray alloc] initWithObjects:
+                          [EOSortOrdering sortOrderingWithKey:@"date"
+                                           selector:[so selector]], nil];
+      }
+      if (SeenQual == nil) {
+        SeenQual = [[EOKeyValueQualifier alloc]
+                                         initWithKey:@"flags"
+                                         operatorSelector:
+                                         EOQualifierOperatorEqual
+                                         value:@"seen"];
+      }
+      muids = [[NSMutableArray alloc] initWithCapacity:255];
+
+      if (sel_eq([so selector], EOCompareAscending) ||
+          sel_eq([so selector], EOCompareCaseInsensitiveAscending)) {
+        qual1 = UnseenQual;
+        if (_unseen)
+          qual2 = nil;
+        else
+          qual2 = SeenQual;
+      }
+      else {
+        if (_unseen)
+          qual1 = nil;
+        else
+          qual1 = SeenQual;
+        
+        qual2 = UnseenQual;
+      }
+
+      if (qual1) {
+        dict = [[self->context client] sort:DateSo qualifier:qual1];
+
+        if (![[dict objectForKey:@"result"] boolValue]) {
+          [self logWithFormat:@"ERROR[%s](1): sort failed (sortOrderings %@, "
+                @"qual1 %@)", __PRETTY_FUNCTION__, DateSo, qual1];
+          return nil;
+        }
+        [muids addObjectsFromArray:[dict objectForKey:@"sort"]];
+      }
+      if (qual2) {
+        dict = [[self->context client] sort:DateSo qualifier:qual2];
+
+        if (![[dict objectForKey:@"result"] boolValue]) {
+          [self logWithFormat:@"ERROR[%s](2): sort failed (sortOrderings %@, "
+                @"qual2 %@ ", __PRETTY_FUNCTION__, DateSo, qual2];
+          return nil;
+        }
+        [muids addObjectsFromArray:[dict objectForKey:@"sort"]];
+      }
+      uids = [muids copy];
+      [muids release]; muids = nil;
+    }
+  }
+  if (uids == nil) {
+    EOQualifier *qual;
+
+    if (![_so count]) {
+      static NSArray *ArrivalSO = nil;
+
+      if (ArrivalSO == nil) {
+        ArrivalSO =
+          [[NSArray alloc]
+                    initWithObjects:
+                    [EOSortOrdering sortOrderingWithKey:@"arrival"
+                                    selector:EOCompareAscending], nil];
+      }
+      _so = ArrivalSO;
+    }
+    if (_unseen) {
+      qual = UnseenQual;
+    }
+    else
+      qual = nil;
+
+    [self resetLastException];
+    
+    dict = [[self->context client] sort:_so qualifier:qual];
+
+    if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__])
+      return nil;
+
+    uids = [[dict objectForKey:@"sort"] retain];
+  }
+  [pool release]; pool = nil;
+  
+  return [uids autorelease];
+}
+
+- (NSData *)blobForUid:(unsigned)_mUid part:(NSString *)_part {
+  NSDictionary *result;
+  NSArray      *fetchResults;
+  NSString     *bodyKey;
+  NSArray      *uids, *parts;
+  
+  if (![self->context registerAsSelectedFolder:self])
+    return nil;
+
+  bodyKey = [NSString stringWithFormat:@"body[%@]", _part?_part:@""];
+  uids    = [NSArray arrayWithObject:[NSNumber numberWithUnsignedInt:_mUid]];
+  parts   = [NSArray arrayWithObject:bodyKey];
+  
+  result = [[self->context client] fetchUids:uids parts:parts];
+  if (![self _checkResult:result cmd:__PRETTY_FUNCTION__]) {
+    [self debugWithFormat:@"Note: _checkResult: rejected result %d/%@: %@",
+            _mUid, _part, result];
+    return nil;
+  }
+  else if (result == nil) {
+    [self debugWithFormat:@"Note: got no result for %d/%@", _mUid, _part];
+    return nil;
+  }
+  
+  fetchResults = [result objectForKey:@"fetch"];
+  if ([fetchResults count] == 0)
+    [self debugWithFormat:@"found no fetch result"];
+  
+  // TODO: using 'lastObject' is certainly wrong? need to search for body
+  result = [fetchResults lastObject];
+  
+  if ((result = [result objectForKey:@"body"]) == nil)
+    [self debugWithFormat:@"found no body in fetch results: %@", fetchResults];
+  
+  return [result objectForKey:@"data"];
+}
+
+- (NGImap4Message *)messageForUid:(unsigned)_mUid
+  sortOrderings:(NSArray *)_so
+  onlyUnread:(BOOL)_unread
+  nextMessage:(BOOL)_next
+{
+  NSArray      *uids, *allSortUids;
+  NSEnumerator *enumerator;
+  NSNumber     *uid, *eUid, *lastUid;
+  
+  if ([self->flags doNotSelectFolder] || self->failedFlags.select)
+    return nil;
+  
+  uid         = [NSNumber numberWithUnsignedInt:_mUid];
+  allSortUids = [self _messageIds:_so onlyUnseen:NO];
+  uids        = _unread ? [self _messageIds:_so onlyUnseen:_unread] : nil;
+  enumerator  = [allSortUids objectEnumerator];
+  lastUid     = nil;
+  
+  while ((eUid = [enumerator nextObject])) {
+    if ([uid isEqual:eUid])
+      break;
+
+    if (_unread) {
+      if ([uids containsObject:eUid])
+        lastUid = eUid;
+    }
+    else
+      lastUid = eUid;
+  }
+  if (eUid == nil) {
+    [self logWithFormat:@"WARNING[%s]: Couldn`t found next/prev message "
+          @"(missing orig. message %d for sortordering %@",
+          __PRETTY_FUNCTION__, _mUid, _so];
+    return nil;
+  }
+  if (_next) {
+    if (_unread) {
+      while ((uid = [enumerator nextObject])) {
+        if ([uids containsObject:uid])
+          break;
+      }
+    }
+    else
+      uid = [enumerator nextObject];
+  }
+  else {
+    uid = lastUid;
+  }
+  if (uid == nil)
+    return nil;
+  
+  return [[[NGImap4Message alloc] initWithUid:[uid unsignedIntValue]
+                                 folder:self context:self->context]
+                                 autorelease];
+}
+
+/*
+  build NGImap4Messages with sorted uids
+*/
+
+- (NSArray *)fetchSortedMessages:(NSArray *)_so {
+  NSArray           *uids, *array;
+  NSMutableArray    *marray;
+  NSAutoreleasePool *pool;
+  NSEnumerator      *enumerator;
+  NSNumber          *uid;
+  
+  if ([self->flags doNotSelectFolder] || self->failedFlags.select)
+    return nil;
+
+  if (![self->context registerAsSelectedFolder:self])
+    return nil;
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  if (![_so count]) {
+    return [self messages];
+  }
+  
+  if (!(uids = [self _messageIds:_so onlyUnseen:NO]))
+    return [self messages];
+
+  enumerator = [uids objectEnumerator];
+  marray     = [[NSMutableArray alloc] initWithCapacity:[uids count]];
+  
+  while ((uid = [enumerator nextObject])) {
+    NGImap4Message *m;
+    
+    m = [[NGImap4Message alloc] initWithUid:[uid intValue]
+                               folder:self context:self->context];
+    if (m) [marray addObject:m];
+    [m release];
+  }
+  array = [marray shallowCopy];
+
+  [marray release]; marray = nil;
+  [pool release];   pool   = nil;
+  
+  return [array autorelease];
+}
+
+/*
+  fetch headers for _array in range (for use with fetchSortedMessages)
+*/
+
+- (void)bulkFetchHeadersFor:(NSArray *)_array inRange:(NSRange)_aRange
+  withAllUnread:(BOOL)_unread
+{
+  NSArray             *messages, *uids;
+  NSAutoreleasePool   *pool;
+  NSEnumerator        *enumerator;
+  NGImap4Message      *message;
+  NSMutableDictionary *messageMapping;
+  NSDictionary        *dict;
+  NSArray             *unreadUids;
+  
+  if ([self->flags doNotSelectFolder])
+    return;
+
+  if (_aRange.length == 0)
+    return;
+
+  if (![self->context registerAsSelectedFolder:self])
+    return;
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  if (_aRange.location >= [_array count]) {
+    return;
+  }
+  if (_aRange.location + _aRange.length > [_array count]) {
+    _aRange.length = [_array count] - _aRange.location;
+  }
+  messages   = [_array subarrayWithRange:_aRange];
+  unreadUids = nil;
+  
+  if (_unread) {
+    EOQualifier  *q;
+    NSDictionary *d;
+
+    q = [EOQualifier qualifierWithQualifierFormat:@"flags = \"unseen\""];
+    d = [[self->context client] searchWithQualifier:q];
+
+    if ([[d objectForKey:@"result"] boolValue])
+      unreadUids = [d objectForKey:@"search"];
+  }
+  enumerator     = [messages objectEnumerator];
+  messageMapping = [NSMutableDictionary dictionaryWithCapacity:
+                                        [messages count]];
+  while ((message = [enumerator nextObject])) {
+    if (![message isComplete])
+      [messageMapping setObject:message
+                      forKey:[NSNumber numberWithUnsignedInt:[message uid]]];
+  }
+  if ([ unreadUids count]) {
+    enumerator = [_array objectEnumerator];
+    while ((message = [enumerator nextObject])) {
+      NSNumber *number;
+
+      number = [NSNumber numberWithUnsignedInt:[message uid]];
+
+      if ([unreadUids containsObject:number])
+        [messageMapping setObject:message forKey:number];
+    }
+  }
+  if ([messageMapping count] > 0) {
+    static NSArray *sortKeys = nil;
+    
+    uids = [messageMapping allKeys];
+    
+    if (sortKeys == nil) {
+      sortKeys = [[NSArray alloc] initWithObjects:@"uid",
+                                                  @"rfc822.header",
+                                                  @"rfc822.size", @"flags",
+                                                  nil];
+    }
+    dict = [[self->context client] fetchUids:uids parts:sortKeys];
+    if ([self _checkResult:dict cmd:__PRETTY_FUNCTION__]) {
+      [self _buildMessagesFromFetch:dict usingMessages:messageMapping];
+
+      if (_unread) { /* set unfetched messeges to unread */
+        NSEnumerator   *enumerator;
+        NGImap4Message *m;
+
+        enumerator = [_array objectEnumerator];
+
+        while ((m = [enumerator nextObject])) {
+          NSNumber *n;
+
+          n = [NSNumber numberWithUnsignedInt:[m uid]];
+
+          if (![uids containsObject:n])
+            [m setIsRead:YES];
+        }
+      }
+    }
+  }
+  [pool release]; pool = nil;
+  return;
+}
+
+- (void)bulkFetchHeadersFor:(NSArray *)_array inRange:(NSRange)_aRange {
+  [self bulkFetchHeadersFor:_array inRange:_aRange withAllUnread:NO];
+}
+
+/*
+  fetch only sorted messages in range
+*/
+
+- (NSArray *)fetchSortedMessages:(NSRange)_aRange
+  sortOrderings:(NSArray *)_so
+{
+  static NSArray *sortKeys = nil;
+  NSDictionary      *dict;
+  NSArray           *uids, *m;
+  NSAutoreleasePool *pool;
+  
+  if ([self->flags doNotSelectFolder] || self->failedFlags.select)
+    return nil;
+  
+  if (_aRange.length == 0)
+    return [NSArray array];
+
+  if (![self->context registerAsSelectedFolder:self])
+    return nil;
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  if ((uids = [self _messageIds:_so onlyUnseen:NO]) == nil)
+    return nil;
+  
+  if (_aRange.location + _aRange.length > [uids count])
+    _aRange.length = [uids count] - _aRange.location;
+  
+  uids = [uids subarrayWithRange:_aRange];
+  
+  if (sortKeys == nil) {
+    sortKeys = [[NSArray alloc] initWithObjects:@"uid",
+                                                @"rfc822.header",
+                                                @"rfc822.size", @"flags",
+                                                nil];
+  }
+  dict = [[self->context client] fetchUids:uids parts:sortKeys];
+
+  if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__])
+    return nil;
+  
+  m = [[self _buildMessagesFromFetch:dict] retain];
+  [pool release];
+  return [m autorelease];
+}
+
+- (NSArray *)fetchMessagesFrom:(unsigned)_from to:(unsigned)_to {
+  static NSArray *sortKeys = nil;
+  NSAutoreleasePool   *pool;
+  NSDictionary        *dict;
+  NSArray             *m;
+
+  if ([self->flags doNotSelectFolder])
+    return nil;
+  
+  if (_from == 0)
+    _from = 1;
+  
+  if (![self->context registerAsSelectedFolder:self])
+    return nil;
+  if (_to == 0)
+    return [NSArray array];
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  [self resetLastException];
+  
+  /* TODO: normalize sort-key arrays? */
+  if (sortKeys == nil) {
+    sortKeys = [[NSArray alloc] initWithObjects:@"uid",
+                                                @"rfc822.header",
+                                                @"rfc822.size", @"flags",
+                                                nil];
+  }
+  dict = [[self->context client] fetchFrom:_from to:_to parts:sortKeys];
+  if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__])
+    return nil;
+  
+  m = [[self _buildMessagesFromFetch:dict] retain];
+  
+  [pool release];
+  return [m autorelease];
+}
+
+- (void)initializeSubFolders {
+  NSString     *n;
+  NSEnumerator *folders;
+  NSDictionary *res;
+  id           folder, *objs;
+  unsigned     cnt, nl;
+  BOOL         showSubsrcFolders;
+  NSString     *pattern;
+  
+  if ([self->flags doesNotSupportSubfolders])
+    return;
+
+  if (!IgnoreHasNoChildrenFlag && [self->flags hasNoSubfolders])
+    return;
+    
+  if (self->subFolders)
+    [self resetSubFolders];
+  
+  [self resetLastException];
+  showSubsrcFolders = [self->context showOnlySubscribedInSubFolders];
+  
+  pattern = [[self absoluteName] stringByAppendingString:@"/%"];
+  res = (showSubsrcFolders)
+    ? [[self->context client] lsub:@"" pattern:pattern]
+    : [[self->context client] list:@"" pattern:pattern];
+  
+  if (![self _checkResult:res cmd:__PRETTY_FUNCTION__])
+    return;
+  
+  res = [res objectForKey:@"list"];
+
+  objs = calloc([res count] + 2, sizeof(id));
+  {
+    NSArray *names;
+    names   = [res allKeys];    
+    names   = [names sortedArrayUsingSelector:
+                     @selector(caseInsensitiveCompare:)];
+    folders = [names objectEnumerator];
+  }
+  
+  cnt = 0;
+  if (showSubsrcFolders) {
+    n  = [self absoluteName];
+    nl = [n length];
+  }
+  
+  while ((folder = [folders nextObject])) {
+    NGImap4Folder *newFolder;
+    NSArray *f;
+
+    f = [res objectForKey:folder];
+
+    if (!ShowNonExistentFolder) {
+      if ([f containsObject:@"nonexistent"])
+        continue;
+    }
+    newFolder = [NGImap4Folder alloc]; /* to keep gcc happy */
+    objs[cnt] = [[newFolder initWithContext:self->context
+                            name:folder flags:f parentFolder:self]
+                           autorelease];
+    if (objs[cnt] == nil)
+      break;
+    cnt++;
+  }
+  if (folder == nil)
+    self->subFolders = [[NSArray alloc] initWithObjects:objs count:cnt];
+  
+  if (objs) free(objs);
+}
+
+- (BOOL)select {
+  return [self selectImmediately:NO];
+}
+
+- (BOOL)selectImmediately:(BOOL)_imm {
+  NSDictionary *dict;
+
+  if ([self->flags doNotSelectFolder]) {
+    [self logWithFormat:@"WARNING[%s]: try to select folder with noselect "
+          @"flag <%@>", __PRETTY_FUNCTION__, self];
+    return NO;
+  }
+  if (self->failedFlags.select)
+    return NO;
+  
+  if (!_imm) {
+    if ([[self context] isInSyncMode] && self->selectSyncState)
+      return YES;
+  }
+  [self resetLastException];
+
+  dict = [[self->context client] select:[self absoluteName]];
+  if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__]) {
+    self->failedFlags.select = YES;
+    return NO;
+  }
+  [self->context setSelectedFolder:self];
+
+  ASSIGN(self->messageFlags, [dict objectForKey:@"flags"]);
+
+  self->isReadOnly = 
+    [[dict objectForKey:@"access"] isEqualToString:@"READ-WRITE"]
+    ? NoNumber : YesNumber;
+  
+  // TODO: isn't there a better way to check for overquota?
+  if ([[dict objectForKey:@"alert"] isEqualToString:@"Mailbox is over quota"])
+    self->overQuota = 1;
+  else
+    self->overQuota = 0;
+
+  [self setRecent:[dict objectForKey:@"recent"]
+        exists:[dict objectForKey:@"exists"]];
+  
+  self->maxQuota          = -1;
+  self->usedSpace         = -1;
+  self->failedFlags.quota = NO;
+  self->selectSyncState   = YES;
+
+  return YES;
+}
+
+- (BOOL)status {
+  NSDictionary *dict;
+
+  if ([self->flags doNotSelectFolder])
+    return NO;
+
+  if (self->failedFlags.status)
+    return NO;
+  
+  [self->context resetLastException];
+
+  dict = [[self->context client] status:[self absoluteName] flags:StatusFlags];
+
+  if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__]) {
+    self->unseen             = -1;
+    self->recent             = -1;
+    self->exists             = -1;
+    self->maxQuota           = -1;
+    self->usedSpace          = -1;
+    self->overQuota          = -1;
+    self->failedFlags.status = YES;
+    self->failedFlags.quota  = NO;
+    
+    return NO;
+  }
+  [self setRecent:[dict objectForKey:@"recent"]
+        exists:[dict objectForKey:@"messages"]];
+  self->unseen = [[dict objectForKey:@"unseen"] intValue];
+
+  return YES;
+}
+
+/* actions */
+
+- (void)resetFolder {
+  // TODO: shouldn't the post happen after the expunge?
+  [self _postResetFolderNotification];
+  [self expunge];
+}
+
+- (void)_resetFolder {
+#if USE_MESSAGE_CACHE  
+  [self resetQualifierCache];
+#endif
+  [self->msn2UidCache release]; self->msn2UidCache = nil;       
+  [self->flags        release]; self->flags        = nil;
+  [self->messageFlags release]; self->messageFlags = nil;
+#if USE_MESSAGE_CACHE  
+  [self->messages     release]; self->messages     = nil;  
+#endif
+  self->maxQuota           = -1;
+  self->usedSpace          = -1;
+  self->overQuota          = -1;
+  self->failedFlags.select = NO;
+  self->failedFlags.quota  = NO;
+  self->isReadOnly         = nil;
+  [self resetStatus];
+}
+
+- (void)resetStatus {
+  self->unseen             = -1;
+  self->exists             = -1;
+  self->recent             = -1;
+  self->failedFlags.status = NO;
+}
+
+- (void)_resetSubFolder {
+  id ctx;
+
+  ctx = [self context];
+  
+  if ((self->parentFolder == nil) || (self == [ctx inboxFolder]))
+    [ctx resetSpecialFolders];
+
+  [self->subFolders release]; self->subFolders = nil;
+}
+
+- (void)resetSubFolders {
+  // TODO: explain in detail what this does
+  NSString *n;
+  
+  n = [self absoluteName];
+  if ([n length] > 0)
+    [self _postResetSubfolderNotification];
+  else
+    [self _resetSubFolder];
+}
+
+- (BOOL)renameTo:(NSString *)_name {
+  NSString     *n;
+  NSDictionary *dict;
+
+  if ([self isReadOnly])
+    return NO;
+  
+  if ((_name == nil) || ([_name length] == 0))
+    return NO;
+  
+  n = [[self->name stringByDeletingLastPathComponent]
+                   stringByAppendingPathComponent:_name];
+
+  [self resetLastException];
+
+  dict = [[self->context client] rename:[self absoluteName] to:n];
+
+  if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__])
+    return NO;
+  
+  ASSIGNCOPY(self->name, n);
+  [self->globalID release]; self->globalID = nil;
+  
+  [self resetSubFolders];
+  dict = [[self->context client] subscribe:self->name];
+
+  if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__])
+    return NO;
+
+  return YES;
+}
+
+/* folder */
+
+- (BOOL)deleteSubFolder:(NGImap4Folder *)_folder {
+  if ([self isReadOnly])
+    return NO;
+  return _deleteSubFolder(self, _folder);;
+}
+
+- (BOOL)copySubFolder:(NGImap4Folder *)_f to:(NGImap4Folder *)_folder {
+  return _copySubFolder(self, _f, _folder);
+}
+
+- (BOOL)moveSubFolder:(NGImap4Folder *)_f to:(NGImap4Folder *)_folder {
+  if ([self isReadOnly])
+    return NO;
+  return _moveSubFolder(self, _f, _folder);
+}
+
+- (BOOL)createSubFolderWithName:(NSString *)_name {
+  if ([self isReadOnly])
+    return NO;
+  return _createSubFolderWithName(self, _name, YES);
+}
+
+- (void)expunge {
+  NSDictionary *dict;
+  
+  if ([self->flags doNotSelectFolder] || self->failedFlags.select)
+    return;
+
+  if ([self isReadOnly])
+    return;
+  if (![self->context registerAsSelectedFolder:self])
+    return;
+      
+  dict = [[self->context client] expunge];
+  if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__])
+    return;
+  
+  [self setRecent:[dict objectForKey:@"recent"]
+        exists:[dict objectForKey:@"exists"]];
+}
+
+- (BOOL)addFlag:(NSString *)_flag toMessages:(NSArray *)_messages {
+  return [self flag:_flag toMessages:_messages add:YesNumber];
+}
+
+- (BOOL)removeFlag:(NSString *)_flag fromMessages:(NSArray *)_messages {
+  return [self flag:_flag toMessages:_messages add:NoNumber];
+}
+
+- (BOOL)flag:(NSString *)_flag toMessages:(NSArray *)_messages
+  add:(NSNumber *)_add
+{
+  NSEnumerator   *enumerator;
+  NGImap4Message *message;
+  NSDictionary   *obj;
+  BOOL           add;
+  NSArray        *flagArray;
+  
+  add = [_add boolValue];   
+
+  if ([self->flags doNotSelectFolder])
+    return NO;
+
+  if (_flag == nil) {
+    [self logWithFormat:@"WARNING[%s]: try to set an empty flag",
+          __PRETTY_FUNCTION__];
+    return NO;
+  }
+  if ([self isReadOnly])
+    return NO;
+  
+  if (![self->context registerAsSelectedFolder:self])
+    return NO;
+
+  if (![self _testMessages:_messages operation:@"store"])
+    return NO;
+
+  [self resetLastException];
+  
+  enumerator = [[self _getMsnRanges:_messages] objectEnumerator];
+  if (enumerator == nil) {
+    [self resetStatus];
+    [self->context removeSelectedFolder:self];
+    return NO;
+  }
+  
+  flagArray = [_flag isNotNull] ? [NSArray arrayWithObject:_flag] : nil;
+  while ((obj = [enumerator nextObject])) {
+    NSDictionary *res;
+    int objEnd, objStart;
+    
+    if ((objEnd = [[obj objectForKey:@"end"] unsignedIntValue]) <= 0)
+      continue;
+    
+    objStart = [[obj objectForKey:@"start"] unsignedIntValue];
+    res = [[self->context client]
+                          storeFrom:objStart to:objEnd
+                          add:_add flags:flagArray];
+
+    if (![self _checkResult:res cmd:__PRETTY_FUNCTION__])
+      break;
+  }
+  if (obj)
+    return NO;
+
+  enumerator = [_messages objectEnumerator];
+  while ((message = [enumerator nextObject])) {
+    if (add)
+      [message addFlag:_flag];
+    else
+      [message removeFlag:_flag];
+  }
+  [self resetStatus];
+  return YES;
+}
+
+- (BOOL)flagToAllMessages:(NSString *)_flag add:(NSNumber *)_add {
+#if USE_MESSAGE_CACHE
+  BOOL            add        = [_add boolValue];
+  NSEnumerator   *enumerator = nil;
+  NGImap4Message *m          = nil;
+#endif
+
+  if ([self->flags doNotSelectFolder])
+    return NO;
+  
+  if (_flag == nil)
+    return NO;
+
+  if ([self isReadOnly])
+    return NO;
+
+  if (![self->context registerAsSelectedFolder:self])
+    return NO;
+
+  
+  if ([self exists] > 0) {
+    NSDictionary *res;
+    
+    [self resetLastException];
+    
+    res = [[self->context client] storeFrom:0 to:[self exists]
+                                  add:_add
+                                  flags:[NSArray arrayWithObject:_flag]];
+
+    if (![self _checkResult:res cmd:__PRETTY_FUNCTION__])
+      return NO;
+    
+#if USE_MESSAGE_CACHE
+    enumerator = [self->messages objectEnumerator];
+    while ((m = [enumerator nextObject])) {
+      (add)
+        ? [m addFlag:_flag]
+        : [m removeFlag:_flag];
+    }
+#endif
+  }
+  return YES;
+}
+
+- (BOOL)deleteAllMessages {
+  if ([self isReadOnly])
+    return NO;
+
+  if ([self flagToAllMessages:@"Deleted" add:YesNumber]) {
+    [self resetFolder];
+    return YES;
+  }
+  return NO;
+}
+
+- (BOOL)deleteMessages:(NSArray *)_messages {
+  if ([self isReadOnly])
+    return NO;
+
+  if ([self addFlag:@"Deleted" toMessages:_messages]) {
+    [self resetFolder];
+    return YES;
+  }
+  return NO;
+}
+
+- (BOOL)moveMessages:(NSArray *)_messages toFolder:(NGImap4Folder *)_folder {
+  if ([self isReadOnly])
+    return NO;
+
+  if (_folder != nil) {
+    if ([self copyMessages:_messages toFolder:_folder]) {
+      return [self deleteMessages:_messages];
+    }
+  }
+  return NO;
+}
+
+- (BOOL)copyMessages:(NSArray *)_messages toFolder:(NGImap4Folder *)_folder {
+  NSEnumerator *enumerator;
+  NSDictionary *obj;
+  NSString     *folderName;
+
+  if ([self->flags doNotSelectFolder])
+    return NO;
+  
+  folderName = [_folder absoluteName];  
+
+  if (_folder == nil) {
+    [self logWithFormat:@"WARNING[%s]: try to copy to nil folder",
+          __PRETTY_FUNCTION__];
+    return NO;
+  }
+  [self resetLastException];
+  
+  if ([_folder isReadOnly]) {
+    NGImap4ResponseException *exc;
+
+    [self logWithFormat:@"WARNING[%s]: try to copy to readonly folder %@",
+          __PRETTY_FUNCTION__, _folder];
+
+    exc = [[NGImap4ResponseException alloc] initWithFormat:
+                                            @"copy to read only folder"];
+    [self->context setLastException:exc];
+    [exc release]; exc = nil;
+    return NO;
+  }
+  if (![self->context registerAsSelectedFolder:self])
+    return NO;
+  
+  if (![self _testMessages:_messages operation:@"copy"])
+    return NO;
+  
+  enumerator = [[self _getMsnRanges:_messages] objectEnumerator];
+  if (enumerator == nil) {
+    [self resetStatus];
+    [self->context removeSelectedFolder:self];
+    return NO;
+  }
+  
+  [self resetLastException];
+  if (![self->context registerAsSelectedFolder:self])
+    return NO;
+  
+  while ((obj = [enumerator nextObject])) {
+    int objEnd;
+    
+    objEnd = [[obj objectForKey:@"end"] unsignedIntValue];
+
+    if (objEnd > 0) {
+      NSDictionary *res;
+      unsigned int start;
+      
+      start = [[obj objectForKey:@"start"] unsignedIntValue];
+      res = [[self->context client]
+                            copyFrom:start to:objEnd toFolder:folderName];
+      if (![self _checkResult:res cmd:__PRETTY_FUNCTION__])
+        break;
+    }
+  }
+  [_folder resetFolder];
+  return (obj == nil) ? YES : NO;
+}
+
+- (BOOL)appendMessage:(NSData *)_msg {
+  if ([self isReadOnly])
+    return NO;
+
+  if (_msg != nil) {
+    NSDictionary *dict;
+
+    dict = [[self->context client]
+                           append:_msg toFolder:[self absoluteName]
+                           withFlags:[NSArray arrayWithObject:@"seen"]];
+
+    if ([self _checkResult:dict cmd:__PRETTY_FUNCTION__]) {
+      [self resetFolder];
+      return YES;
+    }
+  }
+  return NO;
+}
+
+#if USE_MESSAGE_CACHE
+- (void)resetQualifierCache {
+  self->cacheIdx = 0;
+  [self->qualifierCache removeAllObjects];
+}
+#endif
+
+/* notifications */
+
+- (void)setRecent:(NSNumber *)_rec exists:(NSNumber *)_exists {
+#if USE_MESSAGE_CACHE  
+  BOOL resetQualifier = NO;
+  if (_rec != nil) {
+    int tmp = [_rec intValue];
+      if (self->recent != tmp) {
+        self->recent   = tmp;
+        resetQualifier = YES;
+      }
+  }
+  if (_exists != nil) {
+    int tmp = [_exists intValue];
+    if (self->exists != tmp) {
+      self->exists = tmp;
+      resetQualifier = YES;
+    }
+  }
+  if (resetQualifier) 
+    [self resetQualifierCache];
+#else
+  {
+    if (_exists != nil) {
+      int      e;
+
+      e = [_exists intValue];
+
+      if (e == 0) {
+        self->exists = 0;
+        self->recent = 0;
+        self->unseen = 0;
+      }
+      else {
+        int      r;
+    
+        r  = [_rec intValue];
+
+        if ((e != self->exists) || (r != self->recent)) {
+          self->exists = e;
+          self->recent = r;
+          self->unseen = -1;
+        }
+      }
+    }
+  }
+#endif  
+}
+
+- (void)processResponse:(NSDictionary *)_dict {
+#if USE_MESSAGE_CACHE  
+  id exp = [_dict objectForKey:@"expunge"];
+#endif
+
+  [self setRecent:[_dict objectForKey:@"recent"]
+        exists:[_dict objectForKey:@"exists"]];
+
+#if USE_MESSAGE_CACHE  
+  if ((exp != nil) && ([exp count] > 0) && ([self->messages count] > 0)) {
+    NSEnumerator *enumerator;
+    id           obj;
+    
+    enumerator = [exp objectEnumerator];
+    while ((obj = [enumerator nextObject])) {
+      int n = [obj intValue] - 1;
+
+      [self->messages removeObjectAtIndex:n];
+    }
+    [self resetQualifierCache];
+  }
+#endif  
+}
+
+- (BOOL)isInTrash {
+  id<NGImap4Folder> f, trash;
+
+  trash = [self->context trashFolder];
+
+  if (trash == nil) {
+    [self logWithFormat:@"WARNING[%s]: No trash folder was set",
+          __PRETTY_FUNCTION__];
+    return NO;
+  }
+
+  for (f = self; f; f = [f parentFolder]) {
+    if ([f isEqual:trash])
+      return YES;
+  }
+  return NO;
+}
+
+- (void)resetSync {
+  NSEnumerator *enumerator;
+  id           folder;
+
+  self->selectSyncState = NO;
+  
+  if (self->subFolders == nil)
+    return;
+  
+  enumerator = [[self subFolders] objectEnumerator];
+  while ((folder = [enumerator nextObject]))
+    [folder resetSync];
+}
+
+- (NSURL *)url {
+  NSURL *base;
+  
+  if (self->url)
+    return self->url;
+
+  base = [self->context url];
+
+  self->url = [[NSURL alloc]
+               initWithScheme:[base scheme]
+               host:[base host]
+               path:[self absoluteName]];
+  return self->url;
+}
+
+- (EOGlobalID *)serverGlobalID {
+  return [self->context serverGlobalID];
+}
+- (EOGlobalID *)globalID {
+  if (self->globalID)
+    return self->globalID;
+
+  self->globalID = [[NGImap4FolderGlobalID alloc] initWithServerGlobalID:
+                                                   [self serverGlobalID]
+                                                 andAbsoluteName:
+                                                   [self absoluteName]];
+  return self->globalID;
+}
+
+/* quota information */
+
+- (void)quota {
+  NSString     *n;
+  NSDictionary *quota;
+
+  if (self->failedFlags.quota)
+    return;
+
+  if (![self->context canQuota]) {
+    [self logWithFormat:@"WARNING[%s] call quota but capability contains"
+          @" no quota string", __PRETTY_FUNCTION__];
+    return;
+  }
+  n     = [self absoluteName];
+  [self resetLastException];
+
+  if ([self->flags doNotSelectFolder])
+    return;
+  
+  quota = [[self->context client] getQuotaRoot:n];
+
+  if (![self _checkResult:quota cmd:__PRETTY_FUNCTION__]) {
+    self->failedFlags.quota = YES;
+    return;
+  }
+  
+  quota = [quota objectForKey:@"quotas"];
+  quota = [quota objectForKey:n];
+  
+  self->maxQuota  = [[quota objectForKey:@"maxQuota"]  intValue];
+  self->usedSpace = [[quota objectForKey:@"usedSpace"] intValue];
+}
+
+
+- (BOOL)_testMessages:(NSArray *)_messages operation:(NSString *)_operation {
+  NSEnumerator *enumerator;
+  id           obj;
+  
+  enumerator = [_messages objectEnumerator];
+  while ((obj = [enumerator nextObject])) {
+    if ([obj folder] != self) {
+      [self logWithFormat:@"ERROR: try to %@ mails in folder who didn`t own"
+            @" this mail \nFolder %@\nMail %@ allMessages %@",
+            _operation, self, obj, _messages];
+      return NO;
+    }
+  }
+  return YES;
+}
+
+- (NSArray *)_getMsnRanges:(NSArray *)_messages {
+  // TODO: might split up? document!
+  static NSArray      *UidKey     = nil;
+  
+  NSArray             *result;
+  NSMutableDictionary *map;
+  NSMutableArray      *msn;
+  NSEnumerator        *enumerator;  
+  NSDictionary        *obj;
+  NSAutoreleasePool   *pool;
+  NGImap4Message      *message;
+  
+  if ([self exists] == 0)
+    return [NSArray array];
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  if (UidKey == nil) {
+    id objs = nil;
+
+    objs   = @"uid";
+    UidKey = [[NSArray alloc] initWithObjects:&objs count:1];
+  }
+
+  [self resetLastException];
+  
+  if (![self->context registerAsSelectedFolder:self])
+    return nil;
+
+  if ([_messages count] > [self->msn2UidCache count]) {
+    [self->msn2UidCache release]; 
+    self->msn2UidCache = nil;
+  }
+  
+  if (!self->msn2UidCache) {
+    NSDictionary *res;
+
+    res = [[self->context client] fetchFrom:1 to:[self exists] parts:UidKey];
+
+    if (![self _checkResult:res cmd:__PRETTY_FUNCTION__])
+      return nil;
+    
+    self->msn2UidCache = [[res objectForKey:@"fetch"] retain];
+  }
+  map = [[NSMutableDictionary alloc] initWithCapacity:
+                                     [self->msn2UidCache count]];
+  enumerator = [self->msn2UidCache objectEnumerator];
+  
+  while ((obj = [enumerator nextObject]))
+    [map setObject:[obj objectForKey:@"msn"] forKey:[obj objectForKey:@"uid"]];
+  
+  msn = [[NSMutableArray alloc] initWithCapacity:[_messages count]];
+  enumerator = [_messages objectEnumerator];
+  while ((message = [enumerator nextObject])) {
+    id m;
+    
+    m = [map objectForKey:[NSNumber numberWithUnsignedInt:[message uid]]];
+    
+    if (m == nil) {
+      [self logWithFormat:@"WARNING[%s]: Couldn`t map a message sequence "
+            @"number to message %@ numbers %@ messages %@ "
+            @"self->msn2UidCache %@",
+            __PRETTY_FUNCTION__, message, map, _messages, self->msn2UidCache];
+      [msn  release];
+      [map  release];
+      [pool release];
+      return nil;
+    }
+    [msn addObject:m];
+  }
+  [map release]; map = nil;
+  
+  result = [self _calculateSequences:msn count:-1];
+  
+  result = [result retain];
+  [msn release]; msn = nil;
+  [pool release];
+  return [result autorelease];
+}
+
+- (NSArray *)_calculateSequences:(NSMutableArray *)_numbers count:(int)_cnt {
+  // TODO: might split up? document! This looks pretty weird
+  NSAutoreleasePool   *pool;
+  NSEnumerator        *enumerator;
+  NSMutableDictionary *range;
+  NSMutableArray      *ranges;
+  id                  obj, buffer;
+  int                 cntMsgs;
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  if (_cnt == -1)
+    _cnt = [_numbers count];
+  
+  [_numbers sortUsingSelector:@selector(compare:)];
+  
+  ranges     = [NSMutableArray arrayWithCapacity:[_numbers count]];
+  enumerator = [_numbers objectEnumerator];
+  buffer     = [NSNumber numberWithInt:0];
+  range      = nil;
+  cntMsgs    = 0;
+  while (((obj = [enumerator nextObject])) && (cntMsgs < _cnt)) {
+    cntMsgs++;
+    if (range == nil) {
+      range = [NSMutableDictionary dictionaryWithCapacity:2];
+      [range setObject:buffer forKey:@"start"];
+    }
+    
+    if ([obj intValue] != [buffer intValue] + 1) {
+      NSDictionary *ir;
+      
+      [range setObject:buffer forKey:@"end"];
+      ir = [range copy];
+      [ranges addObject:ir];
+      [ir release];
+      range = nil;
+    }
+    buffer = obj;
+  }
+  if (range != nil) {
+    [range setObject:buffer forKey:@"end"];
+    [ranges addObject:range];
+  }
+  else {
+    NSDictionary *d;
+    
+    d = [[NSDictionary alloc] initWithObjectsAndKeys:
+                               buffer, @"start", buffer, @"end", nil];
+    [ranges addObject:d];
+    [d release];
+  }
+  range = [ranges objectAtIndex:0];
+  if ([[range objectForKey:@"end"] intValue] == 0)
+    [ranges removeObjectAtIndex:0];
+  
+  obj = [ranges copy];
+  [pool release];
+  return [obj autorelease];
+}
+
+- (void)clearParentFolder {
+  self->parentFolder = nil;
+}
+
+/* message factory */
+
+- (id)messageWithUid:(unsigned int)_uid {
+  return [[[NGImap4Message alloc] 
+                          initWithUid:_uid folder:self context:[self context]]
+                          autorelease];
+}
+
+/* message registry */
+
+- (NGImap4FolderMailRegistry *)mailRegistry {
+  return self->mailRegistry;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return ImapDebugEnabled;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  NSString        *tmp;
+
+  ms = [NSMutableString stringWithCapacity:64];
+
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if ((tmp = [self name]))
+    [ms appendFormat:@" name=%@", tmp];
+  if ((tmp = [self absoluteName]))
+    [ms appendFormat:@" absolute=%@", tmp];
+  if ((tmp = [[self flags] componentsJoinedByString:@","]))
+    [ms appendFormat:@" flags=%@", tmp];
+  
+  [ms appendString:@">"];
+
+  return ms;
+}
+
+@end /* NGImap4Folder */
+
+#if 0
+@implementation NSData(xxxx)
+- (NSString *)description {
+  return [NSString stringWithFormat:@"NSData len: %d",
+                   [self length]];
+}
+@end
+#endif
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4FolderFlags.h b/skyrix-core/NGMime/NGImap4/NGImap4FolderFlags.h
new file mode 100644 (file)
index 0000000..cb7dff9
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGImap4_NGImap4FolderFlags_H__
+#define __NGImap4_NGImap4FolderFlags_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSArray;
+
+@interface NGImap4FolderFlags : NSObject
+{
+  NSArray *flags; // TODO: document
+  
+  struct {
+    BOOL nonexistent:1; /* Cyrus set this flag, 
+                          if the folder exist in cache only */
+    BOOL noselect:1;
+    BOOL haschildren:1;
+    BOOL hasnochildren:1;
+    BOOL noinferiors:1;
+    BOOL marked:1;
+    BOOL unmarked:1;
+  } listFlags;
+}
+
+- (id)initWithFlagArray:(NSArray *)_array;
+
+/* accessors */
+
+- (NSArray *)flagArray;
+- (BOOL)doNotSelectFolder;
+- (BOOL)doesNotSupportSubfolders;
+- (BOOL)doesNotExist;
+- (BOOL)hasSubfolders;
+- (BOOL)hasNoSubfolders;
+- (BOOL)isMarked;
+- (BOOL)isUnmarked;
+
+/* operations */
+
+- (void)allowFolderSelect;
+
+@end
+
+#endif /* __NGImap4_NGImap4FolderFlags_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4FolderFlags.m b/skyrix-core/NGMime/NGImap4/NGImap4FolderFlags.m
new file mode 100644 (file)
index 0000000..f3ce1e6
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGImap4FolderFlags.h"
+#include "common.h"
+
+@implementation NGImap4FolderFlags
+
+- (id)initWithFlagArray:(NSArray *)_array {
+  if ((self = [super init])) {
+    self->flags = [_array copy];
+
+    // TODO: this is pretty weird
+    self->listFlags.noselect    = [self->flags containsObject:@"noselect"];
+    self->listFlags.noinferiors = [self->flags containsObject:@"noinferiors"];
+    self->listFlags.nonexistent = [self->flags containsObject:@"nonexistent"];
+    self->listFlags.haschildren = [self->flags containsObject:@"haschildren"];
+    self->listFlags.marked      = [self->flags containsObject:@"marked"];
+    self->listFlags.unmarked    = [self->flags containsObject:@"unmarked"];
+    
+    self->listFlags.hasnochildren = 
+      [self->flags containsObject:@"hasnochildren"];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithFlagArray:nil];
+}
+
+- (void)dealloc {
+  [self->flags release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSArray *)flagArray {
+  return self->flags;
+}
+
+- (BOOL)doNotSelectFolder {
+  return self->listFlags.noselect ? YES : NO;
+}
+- (BOOL)doesNotSupportSubfolders {
+  return self->listFlags.noinferiors ? YES : NO;
+}
+- (BOOL)doesNotExist {
+  return self->listFlags.nonexistent ? YES : NO;
+}
+- (BOOL)hasSubfolders {
+  return self->listFlags.haschildren ? YES : NO;
+}
+- (BOOL)hasNoSubfolders {
+  return self->listFlags.hasnochildren ? YES : NO;
+}
+- (BOOL)isMarked {
+  return self->listFlags.marked ? YES : NO;
+}
+- (BOOL)isUnmarked {
+  return self->listFlags.unmarked ? YES : NO;
+}
+
+/* operations */
+
+- (void)allowFolderSelect {
+  NSMutableArray *ma;
+  NSArray *tmp;
+  
+  self->listFlags.noselect = NO;
+  
+  tmp = self->flags;
+  ma = [tmp mutableCopy];
+  [ma removeObject:@"noselect"];
+  self->flags = [ma copy];
+  [tmp release];
+}
+
+@end /* NGImap4FolderFlags */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4FolderGlobalID.h b/skyrix-core/NGMime/NGImap4/NGImap4FolderGlobalID.h
new file mode 100644 (file)
index 0000000..3ee8274
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGImap4_NGImap4FolderGlobalID_H__
+#define __NGImap4_NGImap4FolderGlobalID_H__
+
+#include <EOControl/EOGlobalID.h>
+
+@interface NGImap4FolderGlobalID : EOGlobalID < NSCopying >
+{
+  EOGlobalID *serverGlobalID;
+  NSString   *absoluteName;
+}
+
++ (id)imap4FolderGlobalIDWithServerGlobalID:(EOGlobalID *)_gid 
+  andAbsoluteName:(NSString *)_name;
+- (id)initWithServerGlobalID:(EOGlobalID *)_gid 
+  andAbsoluteName:(NSString *)_name;
+
+/* accessors */
+
+- (EOGlobalID *)serverGlobalID;
+- (NSString *)absoluteName;
+
+/* comparison */
+
+- (BOOL)isEqualToImap4FolderGlobalID:(NGImap4FolderGlobalID *)_other;
+
+@end
+
+#endif /* __NGImap4_NGImap4FolderGlobalID_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4FolderGlobalID.m b/skyrix-core/NGMime/NGImap4/NGImap4FolderGlobalID.m
new file mode 100644 (file)
index 0000000..701abed
--- /dev/null
@@ -0,0 +1,89 @@
+// $Id$
+
+#include "NGImap4FolderGlobalID.h"
+#include "common.h"
+
+@implementation NGImap4FolderGlobalID
+
++ (id)imap4FolderGlobalIDWithServerGlobalID:(EOGlobalID *)_gid 
+  andAbsoluteName:(NSString *)_name
+{
+  NGImap4FolderGlobalID *gid;
+
+  gid = [[self alloc] initWithServerGlobalID:_gid andAbsoluteName:_name];
+  return [gid autorelease];
+}
+- (id)initWithServerGlobalID:(EOGlobalID *)_gid 
+  andAbsoluteName:(NSString *)_name
+{
+  if ((self = [super init])) {
+    self->serverGlobalID = [_gid  retain];
+    self->absoluteName   = [_name copy];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithServerGlobalID:nil andAbsoluteName:nil];
+}
+
+- (void)dealloc {
+  [self->serverGlobalID release];
+  [self->absoluteName   release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (EOGlobalID *)serverGlobalID {
+  return self->serverGlobalID;
+}
+- (NSString *)absoluteName {
+  return self->absoluteName;
+}
+
+/* comparison */
+
+- (unsigned)hash {
+  return [self->absoluteName hash];
+}
+
+- (BOOL)isEqualToImap4FolderGlobalID:(NGImap4FolderGlobalID *)_other {
+  if (_other == nil)
+    return NO;
+  if (self == _other)
+    return YES;
+  
+  if (self->absoluteName != _other->absoluteName) {
+    if (![self->absoluteName isEqualToString:_other->absoluteName])
+      return NO;
+  }
+  if (self->serverGlobalID != _other->serverGlobalID) {
+    if (![self->serverGlobalID isEqual:_other->serverGlobalID])
+      return NO;
+  }
+  
+  return YES;
+}
+
+- (BOOL)isEqual:(id)_otherObject {
+  if (_otherObject == self)
+    return YES;
+  if (![_otherObject isKindOfClass:[self class]])
+    return NO;
+  
+  return [self isEqualToImap4FolderGlobalID:_otherObject];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+/* support for some older code expecting only EO global IDs */
+
+- (NSString *)entityName {
+  return @"NGImap4Folder";
+}
+
+@end /* NGImap4FolderGlobalID */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4FolderMailRegistry.h b/skyrix-core/NGMime/NGImap4/NGImap4FolderMailRegistry.h
new file mode 100644 (file)
index 0000000..584bafd
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGImap4_NGImap4FolderMailRegistry_H__
+#define __NGImap4_NGImap4FolderMailRegistry_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+@class NGImap4Message;
+
+/*
+  NGImap4FolderMailRegistry
+
+  Note: the registry does not retain the mails.
+*/
+
+@interface NGImap4FolderMailRegistry : NSObject
+{
+  unsigned int capacity;
+  unsigned int len;
+  id           *observers;
+}
+
+/* operations */
+
+- (void)registerObject:(NGImap4Message *)_mail;
+- (void)forgetObject:(NGImap4Message *)_mail;
+
+/* notifications */
+
+- (void)postFlagAdded:(NSString *)_flag   inMessage:(NGImap4Message *)_msg;
+- (void)postFlagRemoved:(NSString *)_flag inMessage:(NGImap4Message *)_msg;
+
+@end
+
+#endif /* __NGImap4_NGImap4FolderMailRegistry_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4FolderMailRegistry.m b/skyrix-core/NGMime/NGImap4/NGImap4FolderMailRegistry.m
new file mode 100644 (file)
index 0000000..c3d29f5
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGImap4FolderMailRegistry.h"
+#include "NGImap4Message.h"
+#include "common.h"
+
+@interface NGImap4Message(UsedPrivates)
+- (NSString *)_addFlagNotificationName;
+- (NSString *)_removeFlagNotificationName;
+- (void)_addFlag:(NSNotification *)_n;
+- (void)_removeFlag:(NSNotification *)_n;
+@end
+
+typedef enum {
+  NGImap4_FlagAdd = 0,
+  NGImap4_FlagDel = 1
+} NGImap4FlagOp;
+
+@implementation NGImap4FolderMailRegistry
+
+static BOOL useObjectObserver = NO;
+static BOOL logFlagPostings   = NO;
+static BOOL useFlatArray      = YES;
+static int  initialCapacity   = 100;
+static NSNotificationCenter *nc = nil;
+static Class DictClass = Nil;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  BOOL useOwnNC  = YES;
+  BOOL disableNC = NO;
+  
+  useFlatArray = [ud boolForKey:@"ImapUseOldMailNotificationSystem"]?NO:YES;
+  if (useFlatArray) {
+    disableNC = YES;
+    NSLog(@"Note: using flat-array message notifications!");
+  }
+  
+  if (disableNC) {
+    nc = nil;
+    if (!useFlatArray)
+      NSLog(@"WARNING: NGImap4Message notifications disabled!");
+  }
+  else {
+    nc = useOwnNC
+      ? [[NSNotificationCenter alloc] init]
+      : [[NSNotificationCenter defaultCenter] retain];
+  }
+  DictClass = [NSDictionary class];
+}
+
+- (void)dealloc {
+  if (self->observers) free(self->observers);
+  [super dealloc];
+}
+
+/* flat array */
+
+- (void)_ensureArraySize {
+  if (self->capacity > self->len)
+    return;
+
+  if (self->observers == NULL) {
+    self->capacity  = initialCapacity;
+    self->observers = calloc(self->capacity, sizeof(id));
+  }
+  else {
+    self->capacity *= 2;
+    self->observers = realloc(self->observers, (self->capacity * sizeof(id)));
+  }
+}
+
+/* operations */
+
+- (void)registerObject:(NGImap4Message *)_mail {
+  if (_mail == nil)
+    return;
+  
+  if (useFlatArray) {
+    if (self->capacity <= self->len)
+      [self _ensureArraySize];
+    
+    self->observers[self->len] = _mail;
+    self->len++;
+  }
+  else {
+    if (useObjectObserver) {
+      [nc addObserver:_mail selector:@selector(_addFlag:)
+         name:@"NGImap4MessageAddFlag"
+         object:[_mail globalID]];
+      [nc addObserver:_mail selector:@selector(_removeFlag:)
+         name:@"NGImap4MessageRemoveFlag"
+         object:[_mail globalID]];
+    }
+    else {
+      [nc addObserver:_mail selector:@selector(_addFlag:)
+         name:[_mail _addFlagNotificationName]
+         object:nil];
+      [nc addObserver:_mail selector:@selector(_removeFlag:)
+         name:[_mail _removeFlagNotificationName]
+         object:nil];
+    }
+  }
+}
+
+- (void)forgetObject:(NGImap4Message *)_mail {
+  register signed int i;
+    
+  if (_mail == nil)
+    return;
+
+  if (!useFlatArray) {
+    [nc removeObserver:_mail];
+    return;
+  }
+  
+  /* scan for index to be deleted ... */
+  for (i = self->len - 1; i >= 0; i--) {
+    if (self->observers[i] == _mail) {
+      /* found */
+      break;
+    }
+  }
+    
+  if (i >= 0) { /* found */
+    self->observers[i] = self->observers[self->len - 1];
+    self->len--;
+  }
+  else
+    [self logWithFormat:@"did not find object to be removed!"];
+}
+
+/* notifications */
+
+static NSString *keys[2] = { @"flag", nil };
+
+- (void)postFlagChange:(NGImap4FlagOp)_op flag:(NSString *)_flag 
+  inMessage:(NGImap4Message *)_msg 
+{
+  NSDictionary *ui;
+  
+  if (_flag == nil) return;
+  if (_msg  == nil) return;
+  
+  if (logFlagPostings) {
+    [self logWithFormat:@"%s flag '%@' msg %d (0x%08X)", 
+           (_op == NGImap4_FlagAdd ? "add" : "del"), _flag, [_msg uid], _msg];
+  }
+  
+  // TODO: pretty lame
+  ui = [[DictClass alloc] initWithObjects:&_flag forKeys:keys count:1];
+  
+  if (useFlatArray) {
+    register signed int i;
+    register unsigned   suid;
+    NSNotification *notification = nil;
+    
+    suid = [_msg uid];
+    
+    /* fullscan (duplicates are possible, both uid and id!) */
+    for (i = self->len - 1; i >= 0; i--) {
+      if (self->observers[i] != _msg) {
+       if ([self->observers[i] uid] != suid)
+         // TODO: we might want to cache the selector
+         // TODO: we even might want to cache the uid in the array?
+         continue;
+      }
+      
+      /* OK, either exact match or uid match */
+      
+      if (notification == nil) {
+       NSString *n;
+
+       n = (_op == NGImap4_FlagAdd
+            ? @"NGImap4MessageAddFlag" : @"NGImap4MessageRemoveFlag");
+#if !LIB_FOUNDATION_LIBRARY
+        notification = [NSNotification notificationWithName:n 
+                                       object:_msg userInfo:ui];
+#else
+       notification = [[NSNotification alloc] initWithName:n
+                                              object:_msg
+                                              userInfo:ui];
+#endif
+      }
+      
+      if (logFlagPostings)
+       [self logWithFormat:@"  post to 0x%08X ...", self->observers[i]];
+      
+      if (_op == NGImap4_FlagAdd)
+       [self->observers[i] _addFlag:notification];
+      else
+       [self->observers[i] _removeFlag:notification];
+
+      if (logFlagPostings)
+       [self logWithFormat:@"  done post to 0x%08X.", self->observers[i]];
+    }
+    
+#if LIB_FOUNDATION_LIBRARY
+    if (notification)
+      [notification release];
+#endif
+  }
+  else if (useObjectObserver) {
+    [nc postNotificationName:
+         (_op == NGImap4_FlagAdd
+          ? @"NGImap4MessageAddFlag" : @"NGImap4MessageRemoveFlag")
+       object:[_msg globalID] 
+       userInfo:ui];
+  }
+  else {
+    [nc postNotificationName:
+         (_op == NGImap4_FlagAdd
+          ? [_msg _addFlagNotificationName] 
+          : [_msg _removeFlagNotificationName])
+       object:nil userInfo:ui];
+  }
+  
+  [ui release];
+}
+
+- (void)postFlagAdded:(NSString *)_flag inMessage:(NGImap4Message *)_msg {
+  [self postFlagChange:NGImap4_FlagAdd flag:_flag inMessage:_msg];
+}
+- (void)postFlagRemoved:(NSString *)_flag inMessage:(NGImap4Message *)_msg {
+  [self postFlagChange:NGImap4_FlagDel flag:_flag inMessage:_msg];
+}
+
+@end /* NGImap4FolderMailRegistry */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Functions.h b/skyrix-core/NGMime/NGImap4/NGImap4Functions.h
new file mode 100644 (file)
index 0000000..dad3279
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGImap4_NGImap4Functions_H__
+#define __NGMime_NGImap4_NGImap4Functions_H__
+
+#import <Foundation/NSObject.h>
+#include <NGImap4/NGImap4Folder.h>
+
+@class NSString, NSException;
+
+@interface NGImap4FolderHandler : NSObject
+
++ (id)sharedImap4FolderHandler;
+
+- (NGImap4Folder *)subfolderWithName:(NSString *)_name
+  parentFolder:(id<NGImap4Folder>)_parent
+  ignoreCase:(BOOL)_caseIns;
+
+- (BOOL)isFolder:(id<NGImap4Folder>)_child 
+  aSubfolderOf:(id<NGImap4Folder>)_parent;
+
+- (NSException *)createSubfolderWithName:(NSString *)_name
+  parentFolder:(id<NGImap4Folder>)_parent
+  append:(BOOL)_append;
+
+@end
+
+NGImap4Folder *_subFolderWithName(id<NGImap4Folder> self, NSString *_name,
+                                  BOOL _caseIns);
+BOOL _checkResult(NGImap4Context *_ctx, NSDictionary *_dict,
+                  const char *_command);
+BOOL _isSubFolder(id<NGImap4Folder> self, id<NGImap4Folder>_folder);
+BOOL _hasNewMessagesInSubFolder(id<NGImap4Folder> self, BOOL _fetch);
+BOOL _hasUnseenMessagesInSubFolder(id<NGImap4Folder> self, BOOL _fetch);
+BOOL _deleteSubFolder(id<NGImap4Folder> self, NGImap4Folder *_folder);
+BOOL _copySubFolder(id<NGImap4Folder> self,
+                    id<NGImap4Folder> _f, id<NGImap4Folder> _toFolder);
+BOOL _moveSubFolder(id<NGImap4Folder> self, NGImap4Folder *_f,
+                    id<NGImap4Folder>_folder);
+BOOL _createSubFolderWithName(id<NGImap4Folder> self, NSString *_name, BOOL _app);
+
+#endif /* __NGMime_NGImap4_NGImap4Functions_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Functions.m b/skyrix-core/NGMime/NGImap4/NGImap4Functions.m
new file mode 100644 (file)
index 0000000..3647ca1
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGImap4/NGImap4Functions.h>
+#include <NGImap4/NGImap4Folder.h>
+#include <NGImap4/NGImap4Support.h>
+#include <NGImap4/NGImap4Context.h>
+#include <NGImap4/NGImap4Client.h>
+#include "imCommon.h"
+
+@interface NGImap4Context(Private)
+- (void)setLastException:(NSException *)_exception;
+@end /*NGImap4Context(Private) */
+
+@implementation NGImap4FolderHandler
+
+static int                  LogImapEnabled = -1;
+static NGImap4FolderHandler *sharedHandler = nil; // THREAD
+
++ (id)sharedImap4FolderHandler {
+  if (sharedHandler == nil)
+    sharedHandler = [[self alloc] init];
+  return sharedHandler;
+}
+
+void _checkDefault() {
+  if (LogImapEnabled == -1) {
+    LogImapEnabled = [[NSUserDefaults standardUserDefaults]
+                                      boolForKey:@"ImapLogEnabled"]?1:0;
+  }
+}
+
+BOOL _checkResult(NGImap4Context *_ctx, NSDictionary *_dict,
+                  const char *_command)
+{
+  _checkDefault();
+  if (![[_dict objectForKey:@"result"] boolValue]) {
+    if (![_ctx lastException]) {
+      NGImap4ResponseException *exc;
+
+      if (LogImapEnabled) {
+        NSLog(@"ERROR[%s]: got error during %s: %@",
+            __PRETTY_FUNCTION__, _command, _dict);
+      }
+      exc = [[NGImap4ResponseException alloc]
+                                       initWithFormat:
+                                       [_dict objectForKey:@"reason"]];
+      [_ctx setLastException:exc];
+      [_ctx removeAllFromRefresh];
+      [exc release]; exc = nil;
+    }
+    return NO;
+  }
+  return YES;
+}
+
+- (BOOL)isFolder:(id<NGImap4Folder>)_child 
+  aSubfolderOf:(id<NGImap4Folder>)_parent
+{
+  return _isSubFolder(_parent, _child);
+}
+BOOL _isSubFolder(id<NGImap4Folder> parentFolder, id<NGImap4Folder>_folder) {
+  NSEnumerator  *enumerator;
+  NGImap4Folder *folder;
+  
+  enumerator = [[parentFolder subFolders] objectEnumerator];
+  while ((folder = [enumerator nextObject])) {
+    if ([_folder isEqual:folder])
+      break;
+    
+    if ([[parentFolder context] lastException])
+      return NO;
+  }
+  return (folder != nil) ? YES : NO;
+}
+
+- (NGImap4Folder *)subfolderWithName:(NSString *)_name
+  parentFolder:(id<NGImap4Folder>)_parent
+  ignoreCase:(BOOL)_caseIns
+{
+  return _subFolderWithName(_parent, _name, _caseIns);
+}
+NGImap4Folder *_subFolderWithName
+(id<NGImap4Folder> _parent, NSString *_name, BOOL _caseIns) 
+{
+  NSEnumerator  *enumerator;
+  NGImap4Folder *f;
+
+  if (_caseIns)
+    _name = [_name lowercaseString];
+
+  enumerator = [[_parent subFolders] objectEnumerator];
+  while ((f = [enumerator nextObject])) {
+    NSString *n;
+
+    n = [f name];
+    if (_caseIns) 
+      n = [n lowercaseString];
+
+    if ([n isEqualToString:_name])
+      return f;
+
+    if ([[_parent context] lastException])
+      return NO;
+  }
+  return nil;
+}
+
+BOOL _hasNewMessagesInSubFolder(id<NGImap4Folder> _parent, BOOL _fetch) {
+  NSEnumerator *enumerator;
+  id           obj;
+  
+  enumerator = [[_parent subFolders] objectEnumerator];
+  while ((obj = [enumerator nextObject])) {
+    if ([obj hasNewMessagesSearchRecursiv:YES fetchOnDemand:_fetch])
+      return YES;
+
+    if ([[_parent context] lastException])
+      return NO;
+  }
+  return NO;
+}
+
+BOOL _hasUnseenMessagesInSubFolder(id<NGImap4Folder> self, BOOL _fetch) {
+  NSEnumerator *enumerator;
+  id           obj;
+  
+  enumerator = [[self subFolders] objectEnumerator];
+  while ((obj = [enumerator nextObject])) {
+    if ([obj hasUnseenMessagesSearchRecursiv:YES fetchOnDemand:_fetch])
+      return YES;
+
+    if ([[self context] lastException])
+      return NO;
+  }
+  return NO;
+}
+
+BOOL _deleteSubFolder(id<NGImap4Folder> self, NGImap4Folder *_folder) {
+  /* TODO: jr, why is this a function and not a method ?
+     AW: they will be used in 2 different classes ...
+         'grep _deleteSubFolder *.m' */
+  
+  NSEnumerator  *enumerator;
+  NGImap4Folder *folder;
+  id            ctx;
+
+  _checkDefault();
+    
+  ctx = [self context];
+
+  [ctx resetLastException];
+  
+  if (!_isSubFolder(self, _folder)) {
+    if (LogImapEnabled) {
+      NSLog(@"ERROR: Couldn`t delete %@ because it`s no subfolder of %@",
+            _folder, self);
+    }
+    return NO;
+  }
+  enumerator = [[_folder subFolders] objectEnumerator];
+  
+  while ((folder = [enumerator nextObject])) {
+    [_folder deleteSubFolder:folder];
+
+    if ([ctx lastException]) {
+      [self resetSubFolders];
+      return NO;
+    }
+  }
+  if (![_folder isReadOnly] && ![_folder noselect])  {
+    NSDictionary *result;
+
+    if ([self isKindOfClass:[NGImap4Folder class]]) { 
+      if (![ctx registerAsSelectedFolder:(NGImap4Folder *)self]) {
+        [self resetSubFolders];
+        return NO;
+      }
+    }
+    [ctx resetLastException];
+    
+    result = [(id)[ctx client] delete:[_folder absoluteName]];
+
+    if (!_checkResult(ctx, result, __PRETTY_FUNCTION__)) {
+      [self resetSubFolders];
+      return NO;
+    }
+    [self resetSubFolders];
+    [ctx removeFromRefresh:_folder];
+    return YES;
+  }
+  return NO;
+}
+
+BOOL _copySubFolder(id<NGImap4Folder> self,
+                    id<NGImap4Folder> _f, id<NGImap4Folder> _toFolder)
+{
+  /* TODO: jr, why is this a function and not a method ? 
+     AW: they will be used in 2 different classes ...
+         'grep _deleteSubFolder *.m' */
+  
+  NSEnumerator  *enumerator;
+  NGImap4Folder *folder, *subFolder;  
+  NSString      *folderName;
+
+  _checkDefault();
+  
+  if (!_isSubFolder(self, _f)) {
+    if (LogImapEnabled) {
+      NSLog(@"ERROR: Couldn`t copy %@ because it`s no subfolder of %@",
+            _f, self);
+    }
+    return NO;
+  }
+  if ([[_toFolder absoluteName] hasPrefix:[_f absoluteName]]) {
+    if (LogImapEnabled) {
+      NSLog(@"ERROR: Couldn`t copy %@ is subFolder from %@",
+            _toFolder, _f);
+    }
+    return NO;
+  }
+  
+  if ([self isEqual:_toFolder])
+    return YES;
+  
+  folderName = [_f name];
+  self       = [self retain];
+  
+  if (![_toFolder createSubFolderWithName:folderName]) {
+    return NO;
+  }
+  [self autorelease];
+  enumerator = [[_toFolder subFolders] objectEnumerator];
+  while ((folder = [enumerator nextObject])) {
+    if ([[folder name] isEqualToString:folderName])
+      break;
+    
+    if ([[self context] lastException])
+      return NO;
+  }
+  if (!folder)
+    return NO;
+
+  if (![_f noselect]) {
+    
+    if (![[self context] registerAsSelectedFolder:(NGImap4Folder *)_f])
+      return NO;
+    
+    if ([_f exists] > 0) {
+      NSDictionary *res;
+      
+      res = [[[self context] client] copyFrom:0 to:[_f exists]
+                                     toFolder:[folder absoluteName]];
+      if (!_checkResult([self context], res, __PRETTY_FUNCTION__))
+        return NO;
+    }
+  }
+  [folder resetFolder];
+  enumerator = [[_f subFolders] objectEnumerator];
+  while ((subFolder = [enumerator nextObject])) {
+    if (![_f copySubFolder:subFolder to:folder])
+      break;
+
+    if ([[self context] lastException])
+      return NO;
+  }
+  return (subFolder == nil) ? YES : NO;
+}
+
+BOOL _moveSubFolder(id<NGImap4Folder> self, NGImap4Folder *_f,
+                    id<NGImap4Folder>_folder) 
+{
+  if (!_isSubFolder(self, _f))
+    return NO;
+
+  if ([[_folder absoluteName] hasSuffix:[_f absoluteName]])
+    /* _folder is the same as or a subfolder from _f */
+    return NO;
+
+  if ([_folder isEqual:self])
+    return YES;
+
+  if (![self copySubFolder:_f to:(NGImap4Folder *)_folder])
+    return NO;
+  
+  return [self deleteSubFolder:_f];
+}
+
+BOOL _createSubFolderWithName(id<NGImap4Folder> self, NSString *_name,
+                              BOOL _append)
+{
+  NGImap4Context *ctx;
+  NSRange        r;
+  NSDictionary   *res;
+
+  if (_name == nil)
+    return NO;
+
+  ctx = [self context];
+  r   = [_name rangeOfString:[[ctx client] delimiter]];
+  if (r.length > 0) {
+    NSException *e;
+    
+    e = [[NGImap4Exception alloc]
+         initWithFormat:@"It`s not allowed to use '%@' in "
+           @"a foldername <%@>", [[ctx client] delimiter],
+           _name];
+    [ctx setLastException:e];
+    [e release];
+    return NO;
+  }
+  
+  [ctx resetLastException];
+  if (_append)
+    _name = [[self absoluteName] stringByAppendingPathComponent:_name];
+
+  res = [[ctx client] create:_name];
+  if (!_checkResult(ctx, res, __PRETTY_FUNCTION__))
+    return NO;
+
+  res = [[ctx client] subscribe:_name];
+
+  if (!_checkResult(ctx, res, __PRETTY_FUNCTION__))
+    return NO;
+
+  [self resetSubFolders];
+  return YES;
+}
+- (NSException *)createSubfolderWithName:(NSString *)_name
+  parentFolder:(id<NGImap4Folder>)_parent
+  append:(BOOL)_append
+{
+  if (_createSubFolderWithName(_parent, _name, _append))
+    return nil;
+  
+  return [[_parent context] lastException];
+}
+
+@end /* NGImap4FolderHandler */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Message+BodyStructure.h b/skyrix-core/NGMime/NGImap4/NGImap4Message+BodyStructure.h
new file mode 100644 (file)
index 0000000..caa2eb7
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGImap4Message_BodyStructure_H__
+#define __NGImap4Message_BodyStructure_H__
+
+
+@interface NSCalendarDate(RFC822Dates)
++ (NSCalendarDate *)calendarDateWithRfc822DateString:(NSString *)_str;
+@end /* NSString(RFC822Dates) */
+
+@interface NGImap4Message(BodyStructure)
+
+static id _buildMultipartMessage(id self, NSURL *_baseUrl, NSDictionary *_dict,
+                                 id<NGMimePart>_part);
+static id _buildMessage(id self, NSURL *_baseUrl, NSDictionary *_dict);
+static id _buildPart(id self, NSURL *_baseUrl, NSDictionary *_dict);
+static id _buildMimeBodyPart(id self, NSDictionary *_dict);
+static id _buildMimeMessageBody(id self, NSURL *_baseUrl, NSDictionary *_dict,
+                                id<NGMimePart>_part);
+@end  /* NGImap4Message(BodyStructure) */
+
+@implementation NGImap4Message(BodyStructure)
+       
+static id _buildMultipartMessage(id self, NSURL *_baseUrl, NSDictionary *_dict,
+                                 id<NGMimePart>_part) {
+  NGMimeMultipartBody *body;
+  NSEnumerator        *enumerator;
+  NSDictionary        *part;
+  int                 cnt;
+  
+  body = [[NGMimeMultipartBody alloc] initWithPart:_part];
+  enumerator = [[_dict objectForKey:@"parts"] objectEnumerator];
+
+  cnt = 1;
+  while ((part = [enumerator nextObject])) {
+    NSURL *url;
+
+    {
+      NSString *baseStr;
+
+      baseStr = [_baseUrl absoluteString];
+
+      if ([baseStr hasSuffix:@"="])
+        url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%d",
+                                             baseStr, cnt]];
+      else
+        url = [NSURL URLWithString:[NSString stringWithFormat:@"%@.%d",
+                                             baseStr, cnt]];
+    }
+    [body addBodyPart:_buildPart(self, url, part)];
+    cnt++;
+  }
+  return [body autorelease];
+}
+
+static id _buildMessage(id self, NSURL *_baseUrl, NSDictionary *_dict) {
+  NGMutableHashMap *map;
+  NGMimeMessage    *message;
+  NSString         *value;
+
+  static NGMimeHeaderNames *Fields = NULL;
+
+  if (!Fields)
+    Fields = (NGMimeHeaderNames *)[NGMimePartParser headerFieldNames];
+  
+
+  map = [NGMutableHashMap hashMapWithCapacity:4];
+
+  if ((value = [_dict objectForKey:@"subject"])) {
+    [map setObject:value forKey:Fields->subject];
+  }
+  if ((value = [_dict objectForKey:@"messageId"])) {
+    [map setObject:value forKey:Fields->messageID];
+  }
+  if ((value = [_dict objectForKey:@"in-reply-to"])) {
+    [map setObject:value forKey:@"in-reply-to"];
+  }
+  if ((value = [_dict objectForKey:Fields->contentLength])) {
+    [map setObject:value forKey:Fields->contentLength];
+  }
+  if ((value = [_dict objectForKey:@"date"])) {
+    NSCalendarDate *d;
+
+    if ((d = [NSCalendarDate calendarDateWithRfc822DateString:value])) 
+      [map setObject:d forKey:Fields->date];
+  }
+  {
+    NSEnumerator   *enumerator;
+    id             obj;
+    static NSArray *Array = nil;
+
+    if (Array == nil) {
+      Array = [[NSArray alloc] initWithObjects:
+                               Fields->from,
+                               @"sender",
+                               Fields->replyTo,
+                               Fields->to,
+                               Fields->cc,
+                               @"bcc", nil];
+    }
+    enumerator = [Array objectEnumerator];
+    while ((obj = [enumerator nextObject])) {
+      NSArray *addrs;
+
+      if ((addrs = [_dict objectForKey:obj])) {
+        NSEnumerator *addrEnum;
+        NSDictionary *addr;
+        NSMutableString *str;
+
+        addrEnum = [addrs objectEnumerator];
+        str      = nil;
+        while ((addr = [addrEnum nextObject])) {
+          NSString *personalName, *mailboxName, *hostName;
+          if (!str) {
+            str = [NSMutableString stringWithCapacity:32];
+          }
+          else {
+            [str appendString:@", "];
+          }
+          personalName = [addr objectForKey:@"personalName"];
+          mailboxName  = [addr objectForKey:@"mailboxName"];
+          hostName     = [addr objectForKey:@"hostName"];
+
+          if ([personalName length]) {
+            [str appendFormat:@"\"%@\" <%@@%@>", personalName,
+                 mailboxName, hostName];
+          }
+          else {
+            [str appendFormat:@"%@@%@", mailboxName, hostName];
+          }
+        }
+        if (str)
+          [map setObject:str forKey:obj];
+      }
+    }
+  }
+  {
+    id part, tmp, body;
+
+    part = _buildPart(self, _baseUrl, [_dict objectForKey:@"body"]);
+
+    [map setObject:[part contentType] forKey:Fields->contentType];
+
+    if (![[map valueForKey:Fields->contentTransferEncoding] length]) {
+      if ((tmp = [[part valuesOfHeaderFieldWithName:
+                        Fields->contentTransferEncoding] nextObject])) {
+        [map setObject:tmp forKey:Fields->contentTransferEncoding];
+      }
+    }
+    if (![[map valueForKey:Fields->contentLength] intValue]) {
+      if ((tmp = [[part valuesOfHeaderFieldWithName:Fields->contentLength]
+                  nextObject])) {
+        [map setObject:tmp forKey:Fields->contentLength];
+      }
+    }
+    message = [NGMimeMessage messageWithHeader:map];
+
+    if ([(body = [part body]) isKindOfClass:[NSURL class]]) {
+      NSString *baseStr;
+
+      baseStr = [body absoluteString];
+
+      if ([baseStr hasPrefix:@"="]) {
+        body = [NSURL URLWithString:[NSString stringWithFormat:@"%@1",
+                                              baseStr]];
+      }
+      else
+        body = [NSURL URLWithString:[NSString stringWithFormat:@"%@.1",
+                                              baseStr]];
+    }
+    [message setBody:body];
+  }
+  return message;
+}
+
+static id _buildPart(id self, NSURL *_baseUrl, NSDictionary *_dict) {
+  NSString       *type, *subType;
+  NGMimeBodyPart *part;
+  NSURL          *url;
+
+  url     = _baseUrl;
+  type    = [[_dict objectForKey:@"type"] lowercaseString]; 
+  subType = [[_dict objectForKey:@"subtype"] lowercaseString];
+  part = _buildMimeBodyPart(self, _dict);
+    
+  if ([type isEqualToString:@"multipart"]) {
+    [part setBody:_buildMultipartMessage(self, url, _dict, part)];
+  }
+  else if ([type isEqualToString:@"message"] &&
+           [subType isEqualToString:@"rfc822"]) {
+    [part setBody:_buildMessage(self, url, _dict)];
+  }
+  else {
+    [part setBody:url];
+  }
+  return part;
+}
+
+static id _buildMimeBodyPart(id self, NSDictionary *_dict)
+{
+  NGMutableHashMap *dict;
+  NSString         *value;
+  NGMimeType       *type;
+  static NGMimeHeaderNames *Fields = NULL;
+
+  if (!Fields)
+    Fields = (NGMimeHeaderNames *)[NGMimePartParser headerFieldNames];
+  
+
+  dict = [NGMutableHashMap hashMapWithCapacity:8];
+
+  type = [NGMimeType mimeType:[[_dict objectForKey:@"type"] lowercaseString]
+                     subType:[[_dict objectForKey:@"subtype"] lowercaseString]
+                     parameters:[_dict objectForKey:@"parameterList"]];
+
+  [dict setObject:type forKey:Fields->contentType];
+
+  if (([value = [_dict objectForKey:@"bodyId"] length])) {
+    [dict setObject:value forKey:Fields->messageID];
+  }
+
+  if (([value = [_dict objectForKey:@"size"] length])) {
+    [dict setObject:value forKey:Fields->contentLength];
+  }
+  if (([value = [_dict objectForKey:@"encoding"] length])) {
+    [dict setObject:[value lowercaseString]
+          forKey:Fields->contentTransferEncoding];
+  }
+  return [NGMimeBodyPart bodyPartWithHeader:dict];
+}
+
+
+static id _buildMimeMessageBody(id self, NSURL *_baseUrl, NSDictionary *_dict,
+                                id<NGMimePart>_part)
+{
+  NSString *type, *subType;
+  NSURL    *url;
+  id       result;
+
+  type    = [[_dict objectForKey:@"type"] lowercaseString];
+  subType = [[_dict objectForKey:@"subtype"] lowercaseString];
+
+  url = [NSURL URLWithString:[[_baseUrl absoluteString]
+                                        stringByAppendingString:@"?part="]];
+  if ([type isEqualToString:@"multipart"]) {
+    result = _buildMultipartMessage(self, url, _dict, _part);
+  }
+  else {
+    if ([type isEqualToString:@"message"] &&
+        [subType isEqualToString:@"rfc822"]) {
+      result = _buildMessage(self, url, _dict);
+    }
+    else {
+      result = [NSURL URLWithString:[[_baseUrl absoluteString]
+                                        stringByAppendingString:@"?part=1"]];
+    }
+  }
+  return result;
+}
+
+@end /* NGImap4Message(BodyStructure) */
+
+#endif /* __NGImap4Message_BodyStructure_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Message.h b/skyrix-core/NGMime/NGImap4/NGImap4Message.h
new file mode 100644 (file)
index 0000000..2a6d103
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __Database_NGImap4_NGImap4Message_H__
+#define __Database_NGImap4_NGImap4Message_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMime/NGPart.h>
+#include <NGImap4/NGImap4Support.h>
+
+@class NSArray, NSMutableDictionary;
+@class EOGlobalID;
+@class NGHashMap;
+@class NGImap4Context, NGImap4Folder, NGImap4FolderMailRegistry;
+
+@interface NGImap4Message : NSObject
+{
+@protected
+  NGHashMap      *headers;
+  unsigned       uid;
+  int            size;
+  NSArray        *flags;
+
+  id<NGMimePart> message;
+  id<NGMimePart> bodyStructure;
+  NSData         *rawData;
+
+  NGImap4Context *context;
+  NGImap4Folder  *folder; // not retained
+  NGImap4FolderMailRegistry *mailRegistry;
+  
+  NSURL          *url;
+  EOGlobalID     *globalID;
+
+  NSMutableDictionary *bodyStructureContent;
+
+  NSString *removeFlagNotificationName;
+  NSString *addFlagNotificationName;
+  
+  int isRead;
+}
+
+- (id)initWithUid:(unsigned)_uid folder:(NGImap4Folder *)_folder
+  context:(NGImap4Context *)_ctx;
+
+- (id)initWithUid:(unsigned)_uid headers:(NGHashMap *)_header
+  size:(unsigned)_size flags:(NSArray *)_flags folder:(NGImap4Folder *)_folder
+  context:(NGImap4Context *)_ctx;
+
+/* accessors */
+
+- (NSException *)lastException;
+- (void)resetLastException;
+- (NGHashMap *)headers;
+- (int)size;
+- (unsigned)uid;
+- (NSArray *)flags;
+
+- (NSData *)contentsOfPart:(NSString *)_part;
+- (id<NGMimePart>)bodyStructure;
+- (id<NGMimePart>)message;
+- (NSData *)rawData;
+
+- (NGImap4Folder *)folder;
+- (NGImap4Context *)context;
+
+- (NSURL *)url;
+- (EOGlobalID *)globalID;
+
+/* flag processing */
+
+- (void)addFlag:(NSString *)_flag;
+- (void)removeFlag:(NSString *)_flag;
+
+- (BOOL)isRead;
+- (void)markRead;
+- (void)markUnread;
+
+- (BOOL)isFlagged;
+- (void)markFlagged;
+- (void)markUnFlagged;
+
+- (BOOL)isAnswered;
+- (void)markAnswered;
+- (void)markNotAnswered;
+
+/* equality */
+
+- (BOOL)isEqual:(id)_obj;
+- (BOOL)isEqualToNGImap4Message:(NGImap4Message *)_messages;
+
+@end
+
+#endif /* __Database_NGImap4_NGImap4Message_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Message.m b/skyrix-core/NGMime/NGImap4/NGImap4Message.m
new file mode 100644 (file)
index 0000000..71c1b05
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGImap4Message.h"
+#include "NGImap4Folder.h"
+#include "NGImap4Context.h"
+#include "NGImap4Functions.h"
+#include "NGImap4Client.h"
+#include "NGImap4MessageGlobalID.h"
+#include "NGImap4FolderMailRegistry.h"
+#include <NGExtensions/NGFileManager.h>
+#include "imCommon.h"
+
+#include "NGImap4Message+BodyStructure.h"
+
+@interface NGImap4Message(Internals)
+
+- (void)initializeMessage;
+- (void)fetchMessage;
+- (void)parseMessage;
+- (void)generateBodyStructure;
+- (NSString *)_addFlagNotificationName;
+- (NSString *)_removeFlagNotificationName;
+- (void)_removeFlag:(id)_obj;
+- (void)_addFlag:(id)_obj;
+- (void)setIsRead:(BOOL)_isRead;
+
+@end /* NGImap4Message(Internals) */
+
+#define USE_OWN_GLOBAL_ID 1
+
+@implementation NGImap4Message
+
+static Class             NumClass   = Nil;
+static NSNumber          *YesNumber = nil;
+static NSNumber          *NoNumber  = nil;
+static NGMimeHeaderNames *Fields    = NULL;
+static NSArray           *CoreMsgAttrNames = nil;
+static NSArray           *bodyNameArray    = nil;
+static NSArray           *rfc822NameArray  = nil;
+static BOOL              debugFlags        = NO;
+static BOOL              ImapDebugEnabled  = NO;
+
++ (int)version {
+  return 2;
+}
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  NumClass = [NSNumber class];
+  YesNumber = [[NumClass numberWithBool:YES] retain];
+  NoNumber  = [[NumClass numberWithBool:NO]  retain];  
+  Fields    = (NGMimeHeaderNames *)[NGMimePartParser headerFieldNames];
+  
+  CoreMsgAttrNames = [[NSArray alloc] initWithObjects:@"rfc822.header",
+                                          @"rfc822.size", @"flags", nil];
+  bodyNameArray   = [[NSArray alloc] initWithObjects:@"body", nil];
+  rfc822NameArray = [[NSArray alloc] initWithObjects:@"rfc822", nil];
+  
+  ImapDebugEnabled = [ud boolForKey:@"ImapDebugEnabled"];
+}
+
+- (id)initWithUid:(unsigned)_uid folder:(NGImap4Folder *)_folder
+  context:(NGImap4Context *)_ctx
+{
+  return [self initWithUid:_uid headers:nil size:-1 flags:nil
+               folder:_folder context:_ctx];
+}
+
+- (id)initWithUid:(unsigned)_uid headers:(NGHashMap *)_headers
+  size:(unsigned)_size flags:(NSArray *)_flags folder:(NGImap4Folder *)_folder
+  context:(NGImap4Context *)_ctx
+{
+  if ((self = [super init])) {
+    self->uid     = _uid;
+    self->size    = _size;
+    self->folder  = _folder;
+    self->headers = [_headers retain];
+    self->flags   = [_flags   retain];
+    self->context = [_ctx     retain];
+    self->isRead  = -1;
+    
+    if (self->folder) {
+      // Note: we can safely retain the registry since it doesn't retain the
+      //       mails
+      self->mailRegistry = [[self->folder mailRegistry] retain];
+      [self->mailRegistry registerObject:self];
+    }
+    else
+      [self logWithFormat:@"WARNING(-init): not attached to a folder!"];
+    
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (self->mailRegistry) {
+    [self->mailRegistry forgetObject:self];
+    [self->mailRegistry release];
+  }
+  else
+    [self logWithFormat:@"WARNING(-dealloc): not attached to a registry!"];
+  
+  [self->headers              release];
+  [self->flags                release];
+  [self->context              release];
+  [self->rawData              release];
+  [self->message              release];
+  [self->bodyStructure        release];
+  [self->url                  release];
+  [self->bodyStructureContent release];
+  [self->globalID             release];
+  [self->removeFlagNotificationName release];
+  [self->addFlagNotificationName    release];
+  self->folder = nil;
+  [super dealloc];
+}
+
+/* internal methods */
+
+- (void)_setHeaders:(NGHashMap *)_headers
+  size:(unsigned)_size
+  flags:(NSArray *)_flags
+{
+  ASSIGN(self->headers, _headers);
+  ASSIGN(self->flags,   _flags);
+  self->size = _size;
+}
+
+- (BOOL)isComplete {
+  return (self->headers != nil) && (self->flags != nil);
+}
+
+/* accessors */
+
+- (NSException *)lastException {
+  return [self->context lastException];
+}
+- (void)resetLastException {
+  [self->context resetLastException];
+}
+
+- (unsigned)uid {
+  return self->uid;
+}
+
+- (NGHashMap *)headers {
+  if (self->headers == nil)
+    [self initializeMessage];
+  return self->headers;
+}
+
+- (int)size {
+  if (self->size == -1)
+    [self initializeMessage];
+  return self->size;
+}
+
+- (NSArray *)flags {
+  if (self->flags == nil)
+    [self initializeMessage];
+  return self->flags;
+}
+
+- (NSData *)rawData {
+  if (self->rawData == nil)
+    [self fetchMessage];
+  return self->rawData;
+}
+
+- (NSData *)contentsOfPart:(NSString *)_part {
+  NSData *result;
+
+  if (_part == nil)
+    _part = @"";
+  
+  if (self->bodyStructureContent == nil) {
+    self->bodyStructureContent = 
+      [[NSMutableDictionary alloc] initWithCapacity:8];
+  }
+  
+  if ((result = [self->bodyStructureContent objectForKey:_part]) == nil) {
+    if ((result = [self->folder blobForUid:self->uid part:_part]))
+      [self->bodyStructureContent setObject:result forKey:_part];
+  }
+  return result;
+}
+
+- (id<NGMimePart>)bodyStructure {
+  if (self->bodyStructure == nil)
+    [self generateBodyStructure];
+  
+  return self->bodyStructure;
+}
+
+- (id<NGMimePart>)message {
+  if (self->message == nil) 
+    [self parseMessage];
+  return self->message;
+}
+
+- (NGImap4Folder *)folder {
+  return self->folder;
+}
+
+- (NGImap4Context *)context {
+  return self->context;
+}
+
+- (BOOL)isRead {
+  if ((self->flags == nil) && (self->isRead != -1))
+    return (self->isRead == 1) ? YES : NO;
+
+  return [[self flags] containsObject:@"seen"];
+}
+
+- (void)markRead {
+  if (![self isRead])
+    [self addFlag:@"seen"];
+
+  [self removeFlag:@"recent"];
+}
+
+- (void)markUnread {
+  if ([self isRead]);
+  [self removeFlag:@"seen"];
+}
+
+- (BOOL)isFlagged {
+  return [[self flags] containsObject:@"flagged"];
+}
+
+- (void)markFlagged {
+  if (![self isFlagged])
+    [self addFlag:@"flagged"];
+}
+
+- (void)markUnFlagged {
+  if ([self isFlagged]) {
+    [self removeFlag:@"flagged"];
+  }
+}
+
+- (BOOL)isAnswered {
+  return [[self flags] containsObject:@"answered"];
+}
+
+- (void)markAnswered {
+  if (![self isAnswered])
+    [self addFlag:@"answered"];
+}
+
+- (void)markNotAnswered {
+  if ([self isAnswered])
+    [self removeFlag:@"answered"];
+}
+
+- (void)addFlag:(NSString *)_flag {
+  NSDictionary *res;
+  
+  if (_flag == nil)
+    return;
+  
+  if (self->mailRegistry) 
+    [self->mailRegistry postFlagAdded:_flag inMessage:self];
+  else
+    [self logWithFormat:@"WARNING(-addFlag:): no folder attached to message!"];
+  
+  if (![[self->folder messageFlags] containsObject:_flag])
+    return;
+    
+  if (![self->context registerAsSelectedFolder:self->folder])
+    return;
+  res = [[self->context client] storeUid:self->uid add:YesNumber
+                               flags:[NSArray arrayWithObject:_flag]];
+  if (!_checkResult(self->context, res, __PRETTY_FUNCTION__))
+    return;
+  
+  [self->folder resetStatus];
+}
+
+- (void)removeFlag:(NSString *)_flag {
+  NSDictionary *res;
+    
+  if (_flag == nil) return;
+  
+  if (self->mailRegistry) 
+    [self->mailRegistry postFlagRemoved:_flag inMessage:self];
+  else
+    [self logWithFormat:@"WARNING(-remFlag:): no folder attached to message!"];
+  
+  if (![[self->folder messageFlags] containsObject:_flag])
+    return;
+  
+  if (![self->context registerAsSelectedFolder:self->folder])
+    return;
+
+  res = [[self->context client] storeUid:self->uid add:NoNumber
+                               flags:[NSArray arrayWithObject:_flag]];
+  if (!_checkResult(self->context, res, __PRETTY_FUNCTION__))
+    return;
+    
+  [self->folder resetStatus];
+}
+
+/* equality */
+
+- (BOOL)isEqual:(id)_obj {
+  if (_obj == self)
+    return YES;
+  if ([_obj isKindOfClass:[NGImap4Message class]])
+    return [self isEqualToNGImap4Message:_obj];
+  return NO;
+}
+
+- (BOOL)isEqualToNGImap4Message:(NGImap4Message *)_messages {
+  if ([_messages uid] != self->uid)
+    return NO;
+  if (![[_messages context] isEqual:self->context])
+    return NO;
+  if (![[_messages folder] isEqual:self->folder])
+    return NO;
+  
+  return YES;
+}
+
+- (unsigned)hash {
+  return self->uid;
+}
+
+- (EOGlobalID *)globalID {
+#if USE_OWN_GLOBAL_ID
+  EOGlobalID *fgid;
+  
+  if (self->globalID)
+    return self->globalID;
+
+  if ((fgid = [[self folder] globalID]) == nil) {
+    [self logWithFormat:@"WARNING(-globalID): got no globalID for folder: %@",
+            [self folder]];
+  }
+  
+  self->globalID = [[NGImap4MessageGlobalID alloc] initWithFolderGlobalID:fgid
+                                                   andUid:[self uid]];
+  return self->globalID;
+#else
+  id keys[4];
+
+  if (self->globalID)
+    return self->globalID;
+  
+  // TODO: this needs to be invalidated, if a folder is moved!
+  
+  keys[0] = [NumClass numberWithUnsignedInt:[self uid]];
+  keys[1] = [[self folder]  absoluteName];
+  keys[2] = [[self context] host];
+  keys[3] = [[self context] login];
+  
+  globalID = [[EOKeyGlobalID globalIDWithEntityName:@"NGImap4Message"
+                             keys:keys keyCount:4
+                             zone:NULL] retain];
+  return globalID;
+#endif
+}
+
+/* key-value coding */
+
+- (id)valueForKey:(NSString *)_key {
+  // TODO: might want to add some more caching
+  unsigned len;
+  id v = nil;
+  
+  if ((len = [_key length]) == 0)
+    return nil;
+  
+  if ([_key characterAtIndex:0] == 'N') {
+    if (len < 9)
+      ;
+    else if ([_key isEqualToString:@"NSFileIdentifier"])
+      v = [[self headers] objectForKey:Fields->messageID];
+    else if ([_key isEqualToString:NSFileSize])
+      v = [NumClass numberWithInt:[self size]];
+    else if ([_key isEqualToString:NSFileModificationDate])
+      v = [[self headers] objectForKey:Fields->date];
+    else if ([_key isEqualToString:NSFileType])
+      v = NSFileTypeRegular;
+    else if ([_key isEqualToString:NSFileOwnerAccountName])
+      v = [self->context login];
+    else if ([_key isEqualToString:@"NGFileSubject"])
+      v = [[self headers] objectForKey:Fields->subject];
+    else if ([_key isEqualToString:@"NSFileSubject"])
+      v = [[self headers] objectForKey:Fields->subject];
+    else if ([_key isEqualToString:@"NGFilePath"]) 
+      v = [NSString stringWithFormat:@"%@/%d",
+                     [self->folder absoluteName],
+                     [self uid]];
+    else if ([_key isEqualToString:@"url"])
+      v = [self url];
+
+    if (v) return v;
+  }
+  
+  if ((v = [[self headers] objectForKey:_key]))
+    return v;
+  
+  return [super valueForKey:_key];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  id tmp;
+  
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  [ms appendFormat:@" uid=%d size=%d", self->uid, self->size];
+
+  if (self->headers) {
+    tmp = [[self headers] objectForKey:@"subject"];
+    if ([tmp length] > 0)
+      [ms appendFormat:@" subject='%@'", tmp];
+    else
+      [ms appendString:@" no-subject"];
+  }
+  else {
+    [ms appendString:@" [header not fetched]"];
+  }
+  tmp = [self->folder absoluteName];
+  if (tmp)
+    [ms appendFormat:@" folder='%@'", tmp];
+
+  if (self->flags) {
+  tmp = [self flags];
+
+  if ([tmp count] > 0)
+    [ms appendFormat:@"flags: (%@)", [tmp componentsJoinedByString:@", "]];
+  else
+    [ms appendString:@"no-flags"];
+  }
+  else {
+    [ms appendString:@" [flags not fetched]"];
+  }
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+- (NSURL *)url {
+  NSURL    *base;
+  NSString *path, *s;
+  char buf[64];
+  
+  if (self->url) return self->url;
+
+  base = [self->folder url];
+  
+  sprintf(buf, "%d", [self uid]);
+  s = [[NSString alloc] initWithCString:buf];
+  path = [[base path] stringByAppendingPathComponent:s];
+  [s release];
+  
+  self->url = [[NSURL alloc] initWithScheme:[base scheme]
+                            host:[base host]
+                            path:path];
+  return self->url;
+}
+
+/* Internals */
+
+- (void)initializeMessage {
+  NSDictionary        *dict;
+  NSDictionary        *fetch;
+  NSAutoreleasePool   *pool;
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  if (![self->context registerAsSelectedFolder:self->folder])
+    return;
+  
+  [self resetLastException];
+
+  dict = [[self->context client]
+                         fetchUid:self->uid
+                         parts:CoreMsgAttrNames];
+
+  if (!_checkResult(self->context, dict, __PRETTY_FUNCTION__))
+    return;
+  
+  fetch = [[[dict objectForKey:@"fetch"] objectEnumerator] nextObject];
+
+  if (fetch == nil) {
+    NSLog(@"WARNING[%s] : couldn`t fetch message with id %d",
+          __PRETTY_FUNCTION__, self->uid);
+    return;
+  }
+  {
+    id                  h, f, s;
+    NGMimeMessageParser *parser;
+    NGDataStream        *stream;  
+
+    h   = [fetch objectForKey:@"header"];
+    f   = [fetch objectForKey:@"flags"];
+    s   = [fetch objectForKey:@"size"];
+
+    if ((h == nil) || (f == nil) || (s == nil)) {
+      NSLog(@"WARNING[%s]: got no header, flags, size for %@",
+            __PRETTY_FUNCTION__, fetch);
+      return;
+    }
+    parser = [[[NGMimeMessageParser alloc] init] autorelease];
+    stream = [[[NGDataStream alloc] initWithData:h] autorelease];
+    
+    [parser prepareForParsingFromStream:stream];
+    
+    ASSIGN(self->headers, [parser parseHeader]);
+
+    self->size = [s intValue];
+
+    if (([f containsObject:@"recent"]) && ([f containsObject:@"seen"])) {
+      f = [[f mutableCopy] autorelease];
+      [f removeObject:@"recent"];
+    }
+    ASSIGNCOPY(self->flags, f);
+  }
+  [pool release]; pool = nil;
+}
+
+- (void)fetchMessage {
+  NSDictionary *dict, *fetch;
+
+  if (![self->context registerAsSelectedFolder:self->folder])
+    return;
+
+  [self resetLastException];
+  
+  dict = [[self->context client] fetchUid:self->uid parts:rfc822NameArray];
+  if (!_checkResult(self->context, dict, __PRETTY_FUNCTION__))
+      return;
+  
+  fetch = [[[dict objectForKey:@"fetch"] objectEnumerator] nextObject];
+
+  if (fetch == nil) {
+    NSLog(@"WARNING[%s]: couldn`t fetch message with id %d",
+          __PRETTY_FUNCTION__, self->uid);
+    return;
+  }
+  ASSIGN(self->rawData, [fetch objectForKey:@"message"]);
+}
+
+- (void)_processBodyStructureEncoding:(NSDictionary *)bStruct {
+  NGHashMap *orgH;
+  NGMutableHashMap *h;
+
+  orgH = [self headers];
+
+  if ([[orgH objectForKey:@"encoding"] length] != 0)
+    return;
+      
+  h = [[self headers] mutableCopy];
+  
+  [h setObject:[[bStruct objectForKey:@"encoding"] lowercaseString]
+     forKey:@"content-transfer-encoding"];
+  
+  ASSIGNCOPY(self->headers, h);
+  [h release];
+}
+- (void)generateBodyStructure {
+  NSDictionary *dict, *bStruct;
+  NSArray      *fetchResponses;
+
+  [self->bodyStructure release]; self->bodyStructure = nil;
+
+  [self resetLastException];
+
+  if (![self->context registerAsSelectedFolder:self->folder])
+    return;
+  
+  dict = [[self->context client] fetchUid:self->uid parts:bodyNameArray];
+  
+  if (!(_checkResult(self->context, dict, __PRETTY_FUNCTION__)))
+    return;
+
+  /*
+    TODO: the following seems to fail with Courier, see OGo bug #800:
+    ---snip---
+    C[0x8b4e754]: 27 uid fetch 635 (body)
+    S[0x8c8b4e4]: * 627 FETCH (UID 635 BODY 
+      ("text" "plain" ("charset" "iso-8859-1" "format" "flowed") 
+      NIL NIL "8bit" 2474 51))
+    S[0x8c8b4e4]: * 627 FETCH (FLAGS (\Seen))
+    S[0x8c8b4e4]: 27 OK FETCH completed.
+    Jun 26 18:38:15 OpenGroupware [30904]: <0x08A73DCC[NGImap4Message]>
+      WARNING[-[NGImap4Message generateBodyStructure]]: could not fetch body of
+      message with id 635
+  */
+  
+  fetchResponses = [dict objectForKey:@"fetch"];
+  if ([fetchResponses count] == 1) {
+    /* like with Cyrus, "old" behaviour */
+    bStruct = 
+      [(NSDictionary *)[fetchResponses lastObject] objectForKey:@"body"];
+  }
+  else if ([fetchResponses count] == 0) {
+    /* no results */
+    bStruct = nil;
+  }
+  else {
+    /* need to scan for the 'body' response, Courier 'behaviour' */
+    NSEnumerator *e;
+    NSDictionary *response;
+    
+    bStruct = nil;
+    e = [fetchResponses objectEnumerator];
+    while ((response = [e nextObject])) {
+      if ((bStruct = [response objectForKey:@"body"]) != nil)
+       break;
+    }
+  }
+  
+  if (bStruct == nil) {
+    [self logWithFormat:
+           @"WARNING[%s]: could not fetch body of message with id %d.",
+            __PRETTY_FUNCTION__, self->uid];
+    if (ImapDebugEnabled) {
+      [self logWithFormat:@"  raw:   %@", dict];
+      [self logWithFormat:@"  fetch: %@", [dict objectForKey:@"fetch"]];
+      [self logWithFormat:@"  last:  %@", 
+             [[dict objectForKey:@"fetch"] lastObject]];
+    }
+    return;
+  }
+  
+  /* set encoding */
+  if ([[bStruct objectForKey:@"encoding"] length] > 0)
+    [self _processBodyStructureEncoding:bStruct];
+  
+  self->bodyStructure = [[NGMimeMessage alloc] initWithHeader:[self headers]];
+  [self->bodyStructure setBody:
+       _buildMimeMessageBody(self, [self url], bStruct, self->bodyStructure)];
+}
+
+- (void)parseMessage {
+  NGMimeMessageParser *parser;
+
+  parser = [[NGMimeMessageParser alloc] init];
+  ASSIGN(self->message, [parser parsePartFromData:[self rawData]]);
+  [parser release];
+}
+
+/* flag notifications */
+
+- (NSString *)_addFlagNotificationName {
+  if (self->addFlagNotificationName)
+    return self->addFlagNotificationName;
+  
+  self->addFlagNotificationName =
+      [[NSString alloc]
+                 initWithFormat:@"NGImap4MessageAddFlag_%@_%d",
+                 [[self folder] absoluteName], self->uid];
+  
+  return self->addFlagNotificationName;
+}
+
+- (NSString *)_removeFlagNotificationName {
+  if (self->removeFlagNotificationName)
+    return self->removeFlagNotificationName;
+  
+  self->removeFlagNotificationName =
+      [[NSString alloc]
+                 initWithFormat:@"NGImap4MessageRemoveFlag_%@_%d",
+                 [[self folder] absoluteName], self->uid];
+  return self->removeFlagNotificationName;
+}
+
+- (void)_removeFlag:(NSNotification *)_notification {
+  NSMutableArray *tmp;
+  NSString *flag;
+
+  flag = [[_notification userInfo] objectForKey:@"flag"];
+  if (debugFlags) [self logWithFormat:@"_del flag: %@", flag];
+
+  if (![self->flags containsObject:flag]) {
+    if (debugFlags) [self logWithFormat:@"  not set."];
+    return;
+  }
+
+  tmp = [self->flags mutableCopy];
+  [tmp removeObject:flag];
+
+  ASSIGNCOPY(self->flags, tmp);
+  [tmp release];
+}
+- (void)_addFlag:(NSNotification *)_notification {
+  NSArray  *tmp;
+  NSString *flag;
+
+  flag = [[_notification userInfo] objectForKey:@"flag"];
+  if (debugFlags) [self logWithFormat:@"_add flag: %@", flag];
+  
+  if ([self->flags containsObject:flag]) {
+    if (debugFlags) [self logWithFormat:@"  already set."];
+    return;
+  }
+  
+  tmp = self->flags;
+  self->flags = [[self->flags arrayByAddingObject:flag] copy];
+  [tmp release];
+}
+
+- (void)setIsRead:(BOOL)_isRead {
+  self->isRead = (_isRead)?1:0;
+}
+
+@end /* NGImap4Message */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4MessageGlobalID.h b/skyrix-core/NGMime/NGImap4/NGImap4MessageGlobalID.h
new file mode 100644 (file)
index 0000000..d065a4e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGImap4_NGImap4MessageGlobalID_H__
+#define __NGImap4_NGImap4MessageGlobalID_H__
+
+#include <EOControl/EOGlobalID.h>
+
+@interface NGImap4MessageGlobalID : EOGlobalID < NSCopying >
+{
+  EOGlobalID   *folderGlobalID;
+  unsigned int uid;
+}
+
++ (id)imap4MessageGlobalIDWithFolderGlobalID:(EOGlobalID *)_gid 
+  andUid:(unsigned int)_uid;
+- (id)initWithFolderGlobalID:(EOGlobalID *)_gid andUid:(unsigned int)_uid;
+
+/* accessors */
+
+- (EOGlobalID *)folderGlobalID;
+- (unsigned int)uid;
+
+/* comparison */
+
+- (unsigned)hash;
+
+- (BOOL)isEqualToImap4MessageGlobalID:(NGImap4MessageGlobalID *)_other;
+- (BOOL)isEqual:(id)_otherObject;
+
+@end
+
+#endif /* __NGImap4_NGImap4MessageGlobalID_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4MessageGlobalID.m b/skyrix-core/NGMime/NGImap4/NGImap4MessageGlobalID.m
new file mode 100644 (file)
index 0000000..bbd862a
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGImap4MessageGlobalID.h"
+#include "common.h"
+
+@implementation NGImap4MessageGlobalID
+
++ (id)imap4MessageGlobalIDWithFolderGlobalID:(EOGlobalID *)_gid 
+  andUid:(unsigned int)_uid
+{
+  NGImap4MessageGlobalID *gid;
+  
+  gid = [[self alloc] initWithFolderGlobalID:_gid andUid:_uid];
+  return [gid autorelease];
+}
+
+- (id)initWithFolderGlobalID:(EOGlobalID *)_gid andUid:(unsigned int)_uid {
+  if ((self = [super init])) {
+    self->folderGlobalID = [_gid retain];
+    self->uid            = _uid;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithFolderGlobalID:nil andUid:0];
+}
+
+- (void)dealloc {
+  [self->folderGlobalID release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (EOGlobalID *)folderGlobalID {
+  return self->folderGlobalID;
+}
+- (unsigned int)uid {
+  return self->uid;
+}
+
+/* comparison */
+
+- (unsigned)hash {
+  return self->uid;
+}
+
+- (BOOL)isEqualToImap4MessageGlobalID:(NGImap4MessageGlobalID *)_other {
+  if (_other == nil)
+    return NO;
+  if (self == _other)
+    return YES;
+  if (self->uid != _other->uid)
+    return NO;
+  
+  return (self->folderGlobalID == _other->folderGlobalID)
+    ? YES
+    : [self->folderGlobalID isEqual:_other->folderGlobalID];
+}
+
+- (BOOL)isEqual:(id)_otherObject {
+  if (_otherObject == self)
+    return YES;
+  if (![_otherObject isKindOfClass:[self class]])
+    return NO;
+  
+  return [self isEqualToImap4MessageGlobalID:_otherObject];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+/* compatibility to some older stuff */
+
+- (NSString *)entityName {
+  return @"NGImap4Message";
+}
+
+// TODO: emulate EOKeyGlobalID
+
+@end /* NGImap4MessageGlobalID */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4ResponseNormalizer.h b/skyrix-core/NGMime/NGImap4/NGImap4ResponseNormalizer.h
new file mode 100644 (file)
index 0000000..aea0d10
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGImap4_NGImap4ResponseNormalizer_H__
+#define __NGImap4_NGImap4ResponseNormalizer_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSDictionary, NSMutableDictionary;
+@class NGHashMap;
+@class NGImap4Client;
+
+@interface NGImap4ResponseNormalizer : NSObject
+{
+  NGImap4Client *client; // non-retained
+}
+
+- (id)initWithClient:(NGImap4Client *)_client;
+
+/* primary */
+
+- (NSMutableDictionary *)normalizeResponse:(NGHashMap *)_map;
+
+/* specific */
+
+- (NSDictionary *)normalizeFetchResponse:(NGHashMap *)_map;
+- (NSDictionary *)normalizeOpenConnectionResponse:(NGHashMap *)_map;
+- (NSDictionary *)normalizeListResponse:(NGHashMap *)_map;
+- (NSDictionary *)normalizeSelectResponse:(NGHashMap *)_map;
+- (NSDictionary *)normalizeStatusResponse:(NGHashMap *)_map;
+- (NSDictionary *)normalizeSearchResponse:(NGHashMap *)_map;
+- (NSDictionary *)normalizeSortResponse:(NGHashMap *)_map;
+- (NSDictionary *)normalizeThreadResponse:(NGHashMap *)_map;
+- (NSDictionary *)normalizeCapabilityRespone:(NGHashMap *)_map;
+- (NSDictionary *)normalizeQuotaResponse:(NGHashMap *)_map;
+
+@end
+
+#endif /* __NGImap4_NGImap4ResponseNormalizer_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4ResponseNormalizer.m b/skyrix-core/NGMime/NGImap4/NGImap4ResponseNormalizer.m
new file mode 100644 (file)
index 0000000..1176a0d
--- /dev/null
@@ -0,0 +1,634 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGImap4ResponseNormalizer.h"
+#include "NGImap4Client.h"
+#include "common.h"
+
+@interface NGImap4Client(UsedPrivates)
+- (NSString *)delimiter;
+- (NSString *)_imapFolder2Folder:(NSString *)_folder;
+@end
+
+@implementation NGImap4ResponseNormalizer
+
+static __inline__ NSArray *
+_imapFlags2Flags(NGImap4ResponseNormalizer *, NSArray *);
+
+static NSDictionary *VersionPrefixDict = nil;
+
+static NSNumber *YesNumber     = nil;
+static NSNumber *NoNumber      = nil;
+static Class    DictClass      = Nil;
+static Class    StrClass       = Nil;
+static int      LogImapEnabled = -1;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  YesNumber = [[NSNumber numberWithBool:YES] retain];
+  NoNumber  = [[NSNumber numberWithBool:NO]  retain];
+  
+  DictClass      = [NSDictionary class];
+  StrClass       = [NSString     class];
+  LogImapEnabled = [ud boolForKey:@"ImapLogEnabled"]?1:0;
+
+  /*
+    cyrus   - * OK defiant Cyrus IMAP4 v2.0.16 server ready
+    courier - * OK Courier-IMAP ready. Copyright 1998-2002 Double
+                Precision, Inc.  See COPYING for distribution information.
+  */
+  if (VersionPrefixDict == nil) {
+    VersionPrefixDict =
+      [[DictClass alloc] initWithObjectsAndKeys:
+                             @"cyrus imap4 v", @"cyrus",
+                              @" imap4rev1 ",   @"washington", 
+                              @"courier",       @"courier", nil];
+  }
+}
+
+- (id)initWithClient:(NGImap4Client *)_client {
+  if ((self = [super init])) {
+    self->client = _client; /* non-retained */
+  }
+  return self;
+}
+
+/* client callbacks */
+
+- (void)closeConnection {
+  [(id)self->client closeConnection];
+}
+
+- (NSString *)delimiter {
+  return [self->client delimiter];
+}
+
+/* folder handling */
+
+- (NSString *)_imapFolder2Folder:(NSString *)_folder {
+  return [self->client _imapFolder2Folder:_folder];
+}
+
+/* primary */
+
+- (NSMutableDictionary *)normalizeResponse:(NGHashMap *)_map {
+  /*
+    Filter for all responses
+    result  : NSNumber (response result)
+    exists  : NSNumber (number of exists mails in selected folder
+    recent  : NSNumber (number of recent mails in selected folder
+    expunge : NSArray  (message sequence number of expunged mails in selected 
+                        folder)
+  */
+  NSMutableDictionary *result;
+  id                  obj;
+  NSDictionary        *respRes;
+  
+  if (_map == nil)
+    return (id)[NSMutableDictionary dictionary];
+  
+  respRes = [[_map objectEnumeratorForKey:@"ResponseResult"] nextObject];
+  result  = [NSMutableDictionary dictionaryWithCapacity:32];
+  [result setObject:_map forKey:@"RawResponse"];
+  
+  if ((obj = [_map objectForKey:@"bye"])) {
+    [result setObject:NoNumber forKey:@"result"];
+    [result setObject:obj forKey:@"reason"];
+    [self closeConnection];
+    return result;
+  }
+
+  if ([[respRes objectForKey:@"result"] isEqual:@"ok"]) {
+    [result setObject:YesNumber forKey:@"result"];
+  }
+  else {
+    id tmp = nil;
+    [result setObject:NoNumber forKey:@"result"];
+    if ((tmp = [respRes objectForKey:@"description"]) != nil) {
+      [result setObject:tmp forKey:@"reason"];
+    }
+    return result;
+  }
+  if ((obj = [[_map objectEnumeratorForKey:@"exists"] nextObject]) != nil) { // 
+    [result setObject:obj forKey:@"exists"];
+  }
+  if ((obj = [[_map objectEnumeratorForKey:@"recent"] nextObject]) != nil) {
+    [result setObject:obj forKey:@"recent"];
+  }
+  if ((obj = [_map objectsForKey:@"expunge"]) != nil)
+    [result setObject:obj forKey:@"expunge"];
+  
+  return result;
+}
+
+- (NSDictionary *)normalizeSortResponse:(NGHashMap *)_map {
+  /* filter for sort response (search  : NSArray (msn)) */
+  id                  obj;
+  NSMutableDictionary *result;
+
+  result = [self normalizeResponse:_map];
+  
+  if ((obj = [[_map objectEnumeratorForKey:@"sort"] nextObject]))
+    [result setObject:obj forKey:@"sort"];
+  
+  return result;
+}
+
+- (NSDictionary *)normalizeCapabilityRespone:(NGHashMap *)_map {
+  /* filter for capability response: capability  : NSArray */
+  id                  obj;
+  NSMutableDictionary *result;
+
+  result = [self normalizeResponse:_map];
+  
+  if ((obj = [[_map objectEnumeratorForKey:@"capability"] nextObject]))
+    [result setObject:obj forKey:@"capability"];
+  
+  return result;
+}
+
+- (NSDictionary *)normalizeThreadResponse:(NGHashMap *)_map {
+  /* filter for thread response: thread  : NSArray (msn) */
+  id                  obj;
+  NSMutableDictionary *result;
+
+  result = [self normalizeResponse:_map];
+  
+  if ((obj = [[_map objectEnumeratorForKey:@"thread"] nextObject]))
+    [result setObject:obj forKey:@"thread"];
+  
+  return result;
+}
+
+- (NSDictionary *)normalizeSearchResponse:(NGHashMap *)_map {
+  /* filter for search response: search  : NSArray (msn) */
+  id                  obj;
+  NSMutableDictionary *result;
+
+  result = [self normalizeResponse:_map];
+  
+  if ((obj = [[_map objectEnumeratorForKey:@"search"] nextObject]))
+    [result setObject:obj forKey:@"search"];
+  
+  return result;
+}
+
+- (NSDictionary *)normalizeSelectResponse:(NGHashMap *)_map {
+  /*
+    filter for select response
+      flags  : NSArray
+      unseen : NSNumber
+      access  : NSString ([READ-WRITE], ... )
+  */
+  NSDictionary        *obj;
+  NSEnumerator        *enumerator;
+  NSMutableDictionary *result;
+  id flags;
+  
+  result = [self normalizeResponse:_map];
+  
+  if ((flags = [[_map objectEnumeratorForKey:@"flags"] nextObject]))
+    [result setObject:_imapFlags2Flags(self, flags) forKey:@"flags"];
+  
+  enumerator = [_map objectEnumeratorForKey:@"ok"];
+  while ((obj = [enumerator nextObject])) {
+    id o;
+    
+    if ((o = [obj  objectForKey:@"unseen"]))
+      [result setObject:o forKey:@"unseen"];
+  }
+  
+  enumerator = [_map objectEnumeratorForKey:@"no"];
+  while ((obj = [enumerator nextObject])) {
+    id o;
+    
+    if ([obj isKindOfClass:DictClass]) {
+      if ((o = [obj  objectForKey:@"ALERT"]))
+        [result setObject:o forKey:@"alert"];
+    }
+    else {
+      [result setObject:obj forKey:@"alert"];
+    }
+  }
+  
+  obj = [_map objectForKey:@"ResponseResult"];
+  if ((obj = [obj objectForKey:@"flag"]))
+    [result setObject:obj forKey:@"access"];
+  
+  return result;
+}
+
+- (NSDictionary *)normalizeStatusResponse:(NGHashMap *)_map {
+  /*
+    filter for status response
+      messages  : NSNumber
+      recent    : NSNumber
+      unseen    : NSNumber
+  */
+  NSDictionary        *obj;
+  NSMutableDictionary *result;
+  id                  o;
+  
+  result = [self normalizeResponse:_map];
+  
+  obj = [[_map objectEnumeratorForKey:@"status"] nextObject];
+  obj = [obj objectForKey:@"flags"];
+  
+  if ((o = [obj  objectForKey:@"messages"]) != nil)
+    [result setObject:o forKey:@"messages"];
+  
+  if ((o = [obj  objectForKey:@"recent"]) != nil) {
+    if ([result objectForKey:@"recent"] == nil)
+      [result setObject:o forKey:@"recent"];
+  }
+  if ((o = [obj  objectForKey:@"unseen"]) != nil)
+    [result setObject:o forKey:@"unseen"];
+  
+  return result;
+}
+
+/*
+  filter for fetch response
+    fetch : NSArray (fetch responses)
+      'header'  - RFC822.HEADER
+      'text'    - RFC822.TEXT
+      'size'    - SIZE
+      'flags'   - FLAGS
+      'uid'     - UID
+      'msn'     - message sequence number
+      'message' - RFC822
+      'body   ' - (dictionary with bodystructure)
+
+  This walks over all 'fetch' responses in the map and adds a 'normalized'
+  dictionary for each response to the 'fetch' key of the normalized response
+  dictionary (as retrieved by 'normalizeResponse')
+*/
+- (NSDictionary *)normalizeFetchResponse:(NGHashMap *)_map {
+  /*
+    Raw Sample (Courier):
+      C[0x8b4e754]: 27 uid fetch 635 (body)
+      S[0x8c8b4e4]: * 627 FETCH (UID 635 BODY 
+        ("text" "plain" ("charset" "iso-8859-1" "format" "flowed") 
+        NIL NIL "8bit" 2474 51))
+      S[0x8c8b4e4]: * 627 FETCH (FLAGS (\Seen))
+      S[0x8c8b4e4]: 27 OK FETCH completed.
+    - this results in two result records (one for UID and one for FLAGS)
+      TODO: should we coalesce?
+
+    Raw Sample (Cyrus):
+      C[0x8c8ec64]: 14 uid fetch 20199 (body)
+      S[0x8da46a4]: * 93 FETCH (UID 20199 BODY 
+        ((("TEXT" "PLAIN" ("CHARSET" "utf-8") NIL "signed data" "7BIT" 691 17)
+          ("APPLICATION" "PKCS7-SIGNATURE" ("NAME" "smime.p7s") NIL 
+           "signature" "BASE64" 2936) "SIGNED")
+          ("TEXT" "PLAIN" ("CHARSET" "us-ascii") NIL NIL "7BIT" 146 4) 
+          "MIXED"))
+      S[0x8da46a4]: 14 OK Completed
+    - UID key is mapped to 'uid'
+    - BODY key is mapped to a nested body structure
+    - MSN is added for the '93'? (TODO: make sure this is the case)
+
+    Sample returns (not for the above code!):
+      {
+        // other message stuff
+        fetch = (
+          {
+            header = < NSData containing the header >;
+            size   = 3314;
+            uid    = 20187;
+            msn    = 72;
+            flags  = ( answered, deleted, seen );
+          },
+          ... for each fetch message ...
+        )
+      }
+  */
+  NSMutableDictionary *result;
+  id                  obj;
+  NSEnumerator        *enumerator;
+  NSMutableArray      *fetchResponseRecords;
+
+  // TODO: describe what the generic normalize does.
+  //       Q: do we need to run this before the following section or can we
+  //          call this method just before [result setObject:...] ? (I guess
+  //          the latter, because 'result' is not accessed, but who knows
+  //          about side effects in this JR cruft :-( )
+  result = [self normalizeResponse:_map];
+  
+  fetchResponseRecords = [[NSMutableArray alloc] initWithCapacity:512];
+  
+  /* walk over each response tag which is keyed by 'fetch' in the hashmap */
+  enumerator = [_map objectEnumeratorForKey:@"fetch"];
+  while ((obj = [enumerator nextObject])) {
+    // TODO: shouldn't we use a specific object instead of NSDict for that?
+    NSDictionary *entry;
+    NSEnumerator *keyEnum;
+    NSString     *key;
+    NSString     *keys[9];
+    id           values[9];
+    unsigned     count;
+    id (*objForKey)(id, SEL, id);
+    
+    /*
+       Process one 'fetch' reponse dictionary, walk over each key of the 
+       dict and check for a collection of known response keys.
+    */
+    count     = 0;
+    keyEnum   = [obj keyEnumerator];    
+    objForKey = (void *)[obj methodForSelector:@selector(objectForKey:)];
+    
+    // TODO: this should add some error handling wrt the count?
+    // TODO: this could return multiple values for the same key?! => fix that
+    while ((key = [keyEnum nextObject]) && (count < 9)) {
+      unsigned klen;
+      unichar  c;
+      
+      if ((klen = [key length]) < 3)
+       continue;
+      c = [key characterAtIndex:0];
+      
+      switch (c) {
+      case 'b':
+        /* Note: we check for _prefix_! eg body[1] is valid too */
+       if (klen > 3 && [key hasPrefix:@"body"]) {
+         keys[count]   = @"body";
+         values[count] = objForKey(obj, @selector(objectForKey:), key);
+         count++;
+       }
+       break;
+      case 'f':
+       if (klen == 5 && [key isEqualToString:@"flags"]) {
+         id rawFlags;
+         
+         rawFlags = objForKey(obj, @selector(objectForKey:), key);
+         keys[count]   = @"flags";
+         values[count] = _imapFlags2Flags(self, rawFlags);
+         count++;
+       }
+       break;
+      case 'm':
+       if (klen == 3 && [key isEqualToString:@"msn"]) {
+         keys[count]   = @"msn";
+         values[count] = objForKey(obj, @selector(objectForKey:), key);
+         count++;
+       }
+       break;
+      case 'r':
+       if (klen == 6 && [key isEqualToString:@"rfc822"]) {
+         keys[count]   = @"message";
+         values[count] = objForKey(obj, @selector(objectForKey:), key);
+         count++;
+       }
+       else if (klen == 13 && [key isEqualToString:@"rfc822.header"]) {
+         keys[count]   = @"header";
+         values[count] = objForKey(obj, @selector(objectForKey:), key);
+         count++;
+       }
+       else if (klen == 11 && [key isEqualToString:@"rfc822.text"]) {
+         keys[count]   = @"text";
+         values[count] = objForKey(obj, @selector(objectForKey:), key);
+         count++;
+       }
+       else if (klen == 11 && [key isEqualToString:@"rfc822.size"]) {
+         keys[count]   = @"size";
+         values[count] = objForKey(obj, @selector(objectForKey:), key);
+         count++;
+       }
+       break;
+      case 'u':
+       if (klen == 3 && [key isEqualToString:@"uid"]) {
+         keys[count]   = @"uid";
+         values[count] = objForKey(obj, @selector(objectForKey:), key);
+         count++;
+       }
+       break;
+      }
+    }
+    
+    /* create dictionary */
+    
+    entry = count > 0
+      ? [[DictClass alloc] initWithObjects:values forKeys:keys count:count]
+      : nil;
+    
+    if (entry == nil)
+      continue;
+    
+    [fetchResponseRecords addObject:entry];
+    [entry release]; entry = nil;
+  }
+  
+  /* make response array immutable and add to normalized result */
+  obj = [fetchResponseRecords copy];
+  [fetchResponseRecords release];
+  [result setObject:obj forKey:@"fetch"];
+  [obj release];
+  
+  return [[result copy] autorelease];
+}
+
+- (NSDictionary *)normalizeQuotaResponse:(NGHashMap *)_map {
+  /* filter for quota responses */
+  NSMutableDictionary *result, *quotaRoot, *quota, *tmp;
+  id                  obj;
+  NSEnumerator        *enumerator;
+
+  result     = [self normalizeResponse:_map];
+  quotaRoot  = [_map objectForKey:@"quotaRoot"];
+  quota      = [_map objectForKey:@"quota"];
+  enumerator = [quotaRoot keyEnumerator];
+  tmp        = [NSMutableDictionary dictionaryWithCapacity:[quota count]];
+  
+  while ((obj = [enumerator nextObject])) {
+    NSString     *qRoot;
+    NSDictionary *qDesc;
+
+    qRoot = [quotaRoot objectForKey:obj];
+
+    if (![qRoot length]) {
+      if (LogImapEnabled) {
+        [self logWithFormat:@"%s: missing quotaroot for %@",
+              __PRETTY_FUNCTION__, obj];
+      }
+      continue;
+    }
+    qDesc = [quota objectForKey:qRoot];
+
+    if ([qDesc count] == 0) {
+      if (LogImapEnabled) {
+        [self logWithFormat:@"%s: missing quota description for"
+              @" folder %@ root %@",
+              __PRETTY_FUNCTION__, obj, qRoot];
+      }
+      continue;
+    }
+    [tmp setObject:qDesc forKey:[self _imapFolder2Folder:obj]];
+  }
+  [result setObject:tmp forKey:@"quotas"];
+  return [[result copy] autorelease];
+}
+
+
+/*
+** filter for open connection
+*/
+
+- (NSDictionary *)normalizeOpenConnectionResponse:(NGHashMap *)_map {
+  NSMutableDictionary *result;
+  id obj;
+
+  result = [self normalizeResponse:_map];
+  
+  obj = [[_map objectEnumeratorForKey:@"ok"] nextObject];
+  if (obj == nil) {
+    [result setObject:NoNumber forKey:@"result"];
+    return result;
+  }
+  
+  if ([obj isKindOfClass:DictClass])
+    obj = [(NSDictionary *)obj objectForKey:@"comment"];
+
+  if ([obj isKindOfClass:StrClass]) {
+    NSEnumerator *enumerator;
+    id           key;
+    NSString     *lowServer;
+    
+    [result setObject:obj forKey:@"server"];
+    
+    enumerator = [VersionPrefixDict keyEnumerator];
+    lowServer  = [obj lowercaseString];
+
+    while ((key = [enumerator nextObject])) {
+      NSString *pref;
+      NSArray  *vers;
+      NSRange  r;
+        
+      pref  = [VersionPrefixDict objectForKey:key];
+      r     = [lowServer rangeOfString:pref];
+      
+      if (r.length == 0) continue;
+        
+      [result setObject:key forKey:@"serverKind"];
+      if (![key isEqualToString:@"cyrus"])
+        continue;
+        
+      /* cyrus server, collect version */
+        
+      vers = [[lowServer substringFromIndex:(r.location + [pref length])]
+                         componentsSeparatedByString:@"."];
+      
+      if ([vers count] > 2) {
+        NSNumber *n;
+          
+        n = [NSNumber numberWithInt:[[vers objectAtIndex:0] intValue]];
+        [result setObject:n forKey:@"version"];
+
+        n = [NSNumber numberWithInt:[[vers objectAtIndex:1] intValue]];
+        [result setObject:n forKey:@"subversion"];
+          
+        n = [NSNumber numberWithInt:[[vers objectAtIndex:2] intValue]];
+        [result setObject:n forKey:@"tag"];
+      }
+      break;
+    }
+  }
+  [result setObject:YesNumber forKey:@"result"];
+  
+  return result;
+}
+
+/*
+** filter for list
+**       list : NSDictionary (folder name as key and flags as value)
+*/
+
+- (NSDictionary *)normalizeListResponse:(NGHashMap *)_map {
+  NSMutableDictionary *result;
+  id                  obj;
+  NSAutoreleasePool   *pool;
+  NSDictionary        *rr;
+  
+  pool   = [[NSAutoreleasePool alloc] init];
+  result = [self normalizeResponse:_map];
+  
+  if ((obj = [_map objectsForKey:@"list"]) != nil) {
+    NSEnumerator        *enumerator;
+    NSDictionary        *o;
+    NSMutableDictionary *folder;
+    
+    enumerator = [obj objectEnumerator];
+    folder     = [[NSMutableDictionary alloc] init];
+    
+    while ((o = [enumerator nextObject])) {
+      [folder setObject:_imapFlags2Flags(self, [o objectForKey:@"flags"])
+              forKey:[self _imapFolder2Folder:[o objectForKey:@"folderName"]]];
+    }
+    
+    {
+      NSDictionary *f;
+      
+      f = [folder copy];
+      [result setObject:f forKey:@"list"];
+      [f release];      f      = nil;
+      [folder release]; folder = nil;
+    }
+  }
+  rr = [result copy];
+  [pool release];
+  
+  return [rr autorelease];
+}
+
+/* flags */
+
+static inline NSArray *
+_imapFlags2Flags(NGImap4ResponseNormalizer *self, NSArray *_flags) 
+{
+  NSEnumerator *enumerator;
+  NSArray      *result;
+  id           obj, *objs;
+  unsigned     cnt;
+  
+  objs = calloc([_flags count] + 2, sizeof(id));
+  
+  enumerator = [_flags objectEnumerator];
+  cnt = 0;
+  while ((obj = [enumerator nextObject])) {
+    if ([obj length] == 0)
+      continue;
+    
+    if (![[obj substringToIndex:1] isEqualToString:@"\\"])
+      continue;
+
+    objs[cnt] = [obj substringFromIndex:1];
+    cnt++;
+  }
+  result = [NSArray arrayWithObjects:objs count:cnt];
+  if (objs) free(objs);
+  return result;
+}
+
+@end /* NGImap4ResponseNormalizer */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4ResponseParser.h b/skyrix-core/NGMime/NGImap4/NGImap4ResponseParser.h
new file mode 100644 (file)
index 0000000..f716852
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __OGo_NGImap4_NGImap4ResponseParser_H__
+#define __OGo_NGImap4_NGImap4ResponseParser_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSException.h>
+#include <NGStreams/NGSocketProtocols.h>
+#include <NGImap4/NGImap4Support.h>
+
+@class NSString, NSException, NSMutableString;
+@class NGHashMap, NGByteBuffer;
+
+@interface NGImap4ResponseParser : NSObject
+{
+  NGByteBuffer     *buffer;    
+  BOOL             debug;
+  NSMutableString  *lineDebug;
+  
+  int (*la)(id, SEL, unsigned);
+
+  NSMutableString *serverResponseDebug;
+}
+
++ (id)parserWithStream:(id<NGActiveSocket>)_stream;
+- (id)initWithStream:(id<NGActiveSocket>)_stream;
+
+/* parsing */
+
+- (NGHashMap *)parseResponseForTagId:(int)_tag exception:(NSException **)e_;
+- (NGHashMap *)parseSieveResponse;
+
+@end
+
+#endif /* __OGo_NGImap4_NGImap4ResponseParser_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4ResponseParser.m b/skyrix-core/NGMime/NGImap4/NGImap4ResponseParser.m
new file mode 100644 (file)
index 0000000..422f666
--- /dev/null
@@ -0,0 +1,1733 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGImap4ResponseParser.h"
+#include "NGImap4Support.h"
+#include "imCommon.h"
+
+// TODO(hh): code is now prepared for last-exception, but currently it just
+//           raises and may leak the exception object
+
+@implementation NGImap4ResponseParser
+
+#define __la(__SELF__, __LACNT) \
+  ((__SELF__->la == NULL) \
+    ? [__SELF__->buffer la:__LACNT]\
+    : __SELF__->la(__SELF__->buffer, @selector(la:), __LACNT))
+
+static __inline__ int _la(NGImap4ResponseParser *self, unsigned _laCnt) {
+  char c = __la(self, _laCnt);
+  
+  if (c == '\r')
+    return _la(self, _laCnt + 1);
+  
+  return c;
+}
+
+static NSDictionary *_parseBody(NGImap4ResponseParser *self);
+static NSDictionary *_parseBodyContent(NGImap4ResponseParser *self);
+static NSString *_parseBodyString(NGImap4ResponseParser *self,
+                                  BOOL _convertString);
+static NSString *_parseBodyDecodeString(NGImap4ResponseParser *self,
+                                        BOOL _convertString,
+                                        BOOL _decode);
+static NSDictionary *_parseBodyParameterList(NGImap4ResponseParser *self);
+static NSArray *_parseAddressStructure(NGImap4ResponseParser *self);
+static NSArray *_parseParenthesizedAddressList(NGImap4ResponseParser *self);
+static NSDictionary *_parseSingleBody(NGImap4ResponseParser *self);
+static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self);
+static int _parseTaggedResponse(NGImap4ResponseParser *self,
+                                NGMutableHashMap *result_);
+static void _parseUntaggedResponse(NGImap4ResponseParser *self,
+                                   NGMutableHashMap *result_);
+static BOOL _parseByeUntaggedResponse(NGImap4ResponseParser *self,
+                                      NGMutableHashMap *result_);
+static BOOL _parseNumberUntaggedResponse(NGImap4ResponseParser *self,
+                                         NGMutableHashMap *result_);
+static NSArray *_parseFlagArray(NGImap4ResponseParser *self);
+static BOOL _parseFlagsUntaggedResponse(NGImap4ResponseParser *self,
+                                        NGMutableHashMap *result_);
+static BOOL _parseOkUntaggedResponse(NGImap4ResponseParser *self,
+                                     NGMutableHashMap *result_);
+static BOOL _parseBadUntaggedResponse(NGImap4ResponseParser *self,
+                                      NGMutableHashMap *result_);
+static BOOL _parseNoUntaggedResponse(NGImap4ResponseParser *self,
+                                     NGMutableHashMap *result_);
+static BOOL _parseThreadResponse(NGImap4ResponseParser *self,
+                                 NGMutableHashMap *result_);
+static BOOL _parseStatusResponse(NGImap4ResponseParser *self,
+                                 NGMutableHashMap *result_);
+static BOOL _parseListOrLSubResponse(NGImap4ResponseParser *self,
+                                     NGMutableHashMap *result_);
+static BOOL _parseCapabilityResponse(NGImap4ResponseParser *self,
+                                     NGMutableHashMap *result_);
+static BOOL _parseSearchResponse(NGImap4ResponseParser *self,
+                                 NGMutableHashMap *result_);
+static NSArray *_parseThread(NGImap4ResponseParser *self);
+static BOOL _parseSortResponse(NGImap4ResponseParser *self,
+                               NGMutableHashMap *result_);
+static NSNumber *_parseUnsigned(NGImap4ResponseParser *self);
+static NSString *_parseUntil(NGImap4ResponseParser *self, char _c);
+static NSString *_parseUntil2(NGImap4ResponseParser *self, char _c1, char _c2);
+static __inline__ void _match(NGImap4ResponseParser *self, char _match);
+static __inline__ void _consume(NGImap4ResponseParser *self, unsigned _cnt);
+static void _parseContinuationResponse(NGImap4ResponseParser *self,
+                                       NGMutableHashMap *result_);
+static NSData *_parseData(NGImap4ResponseParser *self);
+
+static void _parseSieveRespone(NGImap4ResponseParser *self,
+                               NGMutableHashMap *result_);
+static BOOL _parseGreetingsSieveResponse(NGImap4ResponseParser *self,
+                                         NGMutableHashMap *result_);
+static BOOL _parseDataSieveResponse(NGImap4ResponseParser *self,
+                                    NGMutableHashMap *result_);
+static BOOL _parseOkSieveResponse(NGImap4ResponseParser *self,
+                                  NGMutableHashMap *result_);
+static BOOL _parseNoSieveResponse(NGImap4ResponseParser *self,
+                                  NGMutableHashMap *result_);
+static NSString *_parseContentSieveResponse(NGImap4ResponseParser *self);
+static NSString *_parseStringSieveResponse(NGImap4ResponseParser *self);
+
+static BOOL _parseQuotaResponse(NGImap4ResponseParser *self,
+                                NGMutableHashMap *result_);
+static BOOL _parseQuotaRootResponse(NGImap4ResponseParser *self,
+                                    NGMutableHashMap *result_);
+
+static unsigned int     LaSize              = 4097;
+static unsigned         UseMemoryMappedData = 0;
+static unsigned         Imap4MMDataBoundary = 0;
+static BOOL             debugOn             = NO;
+static BOOL             debugDataOn         = NO;
+static NSStringEncoding encoding;
+static Class            StrClass = Nil;
+static Class            NumClass      = Nil;
+static NSStringEncoding defCStringEncoding;
+static NSNumber         *YesNum = nil;
+static NSNumber         *NoNum  = nil;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+
+  encoding = [NGMimePartParser defaultHeaderFieldEncoding];
+  defCStringEncoding = [NSString defaultCStringEncoding];
+  
+  debugOn             = [ud boolForKey:@"ImapDebugEnabled"];
+  UseMemoryMappedData = [ud boolForKey:@"NoMemoryMappedDataForImapBlobs"]?0:1;
+  Imap4MMDataBoundary = [ud integerForKey:@"Imap4MMDataBoundary"];
+  
+  if (Imap4MMDataBoundary < 10)
+    /* Note: this should be larger than a usual header size! */
+    Imap4MMDataBoundary = 2 * LaSize;
+  
+  StrClass = [NSString class];
+  NumClass      = [NSNumber class];
+  YesNum        = [[NumClass numberWithBool:YES] retain];
+  NoNum         = [[NumClass numberWithBool:NO]  retain];
+}
+
++ (id)parserWithStream:(id<NGActiveSocket>)_stream {
+  NGImap4ResponseParser *parser;
+
+  parser = [NGImap4ResponseParser alloc]; /* seperate line to keep gcc happy */
+  return [[parser initWithStream:_stream] autorelease];
+}
+
+- (id)initWithStream:(id<NGActiveSocket>)_stream {
+  // designated initializer
+  if (_stream == nil) {
+    [self logWithFormat:@"%s: got no stream ...", __PRETTY_FUNCTION__];
+    [self release];
+    return nil;
+  }
+  
+  if ((self = [super init])) {
+    id s;
+    
+    s = [(NGBufferedStream *)[NGBufferedStream alloc] initWithSource:_stream];
+    self->buffer = [NGByteBuffer alloc];
+    self->buffer = [self->buffer initWithSource:s la:LaSize];
+    [s release];
+    
+    if ([self->buffer respondsToSelector:@selector(methodForSelector:)])
+      self->la = (int(*)(id, SEL, unsigned))
+        [self->buffer methodForSelector:@selector(la:)];
+    
+    self->debug = debugOn;
+  }
+  return self;
+}
+
+- (id)init {
+  [self release];
+  [NSException raise:@"InvalidUseOfMethodException"
+              format:
+                @"calling -init on the NGImap4ResponseParser is not allowed"];
+  return nil;
+}
+
+- (void)dealloc {
+  [self->buffer release];
+  if (self->debug)
+    [self->serverResponseDebug release];
+  [super dealloc];
+}
+
+/* exception handling */
+
+- (void)setLastException:(NSException *)_exc {
+  // TODO: support last exception
+  [_exc raise];
+}
+
+/*
+** Parse Sieve Responses
+*/
+
+- (NGHashMap *)parseSieveResponse {
+  NGMutableHashMap *result;
+
+  if (self->debug) {
+    if (self->serverResponseDebug != nil)
+      [self->serverResponseDebug release];
+    self->serverResponseDebug = [[NSMutableString alloc] initWithCapacity:512];
+  }
+  result = [NGMutableHashMap hashMapWithCapacity:64];
+
+  if (_la(self,0) == -1) {
+    [self setLastException:[self->buffer lastException]];
+    return nil;
+  }
+  
+  _parseSieveRespone(self, result);
+  return result;
+}
+
+- (NGHashMap *)parseResponseForTagId:(int)_tag exception:(NSException **)ex_ {
+  /* parse a response from the server, _tag!=-1 parse until tagged response */
+  // TODO: is NGHashMap really necessary here?
+  BOOL             endOfCommand;
+  NGMutableHashMap *result;
+  
+  if (ex_) *ex_ = nil;
+  
+  if (self->debug) {
+    [self->serverResponseDebug release]; self->serverResponseDebug = nil;
+    self->serverResponseDebug = [[NSMutableString alloc] initWithCapacity:512];
+  }
+  
+  result = [NGMutableHashMap hashMapWithCapacity:64];
+  
+  if (_la(self, 0) == -1) {
+    [self logWithFormat:@"%s: catched: %@", __PRETTY_FUNCTION__,
+            [self->buffer lastException]];
+    
+    if (ex_) {
+      *ex_ = [self->buffer lastException];
+      return nil;
+    }
+    else {
+      [self setLastException:[self->buffer lastException]];
+      return nil;
+    }
+  }
+  for (endOfCommand = NO; !endOfCommand; ) {
+    unsigned char l0;
+    
+    l0 = _la(self, 0);
+    
+    if (l0 == '*') { /* those starting with '* ' */
+      _parseUntaggedResponse(self, result);
+      if ([result objectForKey:@"bye"]) {
+        endOfCommand = YES;
+      }
+      else {
+        if (_tag == -1) {
+          if ([result objectForKey:@"ok"] != nil)
+            endOfCommand = YES;
+        }
+      }
+    }
+    else if (l0 == '+') { /* starting with a '+'? */
+      _parseContinuationResponse(self, result);
+      endOfCommand = YES;
+    }
+    else if (isdigit(l0)) {
+      /* those starting with a number '24 ', eg '24 OK Completed' */
+      endOfCommand = (_parseTaggedResponse(self, result) == _tag);
+    }
+  }
+  return result;
+}
+- (NGHashMap *)parseResponseForTagId:(int)_tag {
+  // DEPRECATED
+  NSException *e = nil;
+  NGHashMap   *hm;
+
+  hm = [self parseResponseForTagId:_tag exception:&e];
+  if (e) {
+    [self setLastException:e];
+    return nil;
+  }
+  return hm;
+}
+
+static void _parseSieveRespone(NGImap4ResponseParser *self,
+                               NGMutableHashMap *result_)
+{
+  if (_parseGreetingsSieveResponse(self, result_)) 
+    return;
+  if (_parseDataSieveResponse(self, result_))    // la: 1
+    return;
+  if (_parseOkSieveResponse(self, result_))     // la: 2
+    return; 
+  if (_parseNoSieveResponse(self, result_))     // la: 2
+    return;
+}
+
+static NSData *_parseData(NGImap4ResponseParser *self) {
+  NSData   *result;
+  unsigned size;
+  NSNumber *n;
+
+  if (_la(self, 0) != '{')
+    return nil;
+  
+  if (debugDataOn) [self logWithFormat:@"parse data ..."];
+
+  /* got header */
+  result = nil;  
+    
+  _consume(self, 1);
+  if ((n = _parseUnsigned(self)) == nil) {
+      NSException *e;
+
+      e = [[NGImap4ParserException alloc] 
+           initWithFormat:@"expect a number between {}"];
+      [self setLastException:[e autorelease]];
+      return nil;
+  }
+  if (debugDataOn) [self logWithFormat:@"  parse data: %@", n];
+  _match(self, '}');
+  _match(self, '\n');
+
+  size = [n intValue];
+  
+  if (UseMemoryMappedData && (size > Imap4MMDataBoundary)) {
+      static NSProcessInfo *Pi = nil;
+      NGFileStream *stream;
+      
+      unsigned char buf[LaSize + 2];
+      unsigned char tmpBuf[LaSize + 2];
+      unsigned      wasRead = 0;
+      NSString      *path;
+      signed char   lastChar; // must be signed
+      
+      if (debugDataOn) [self logWithFormat:@"  using memory mapped data  ..."];
+      
+      if (Pi == nil)
+        Pi = [[NSProcessInfo processInfo] retain];
+
+      path   = [Pi temporaryFileName];
+      stream = [NGFileStream alloc]; /* extra line to keep gcc happy */
+      stream = [stream initWithPath:path];
+
+      if (![stream openInMode:NGFileWriteOnly]) {
+       NSException *e;
+
+       e = [[NGImap4ParserException alloc]
+             initWithFormat:@"Could not open temporary file %@", path];
+        [self setLastException:[e autorelease]];
+       return nil;
+      }
+      
+      lastChar = -1;
+      while (wasRead < size) {
+        unsigned readCnt, bufCnt, tmpSize, cnt, tmpBufCnt;
+
+        bufCnt = 0;
+        
+        if (lastChar != -1) {
+          buf[bufCnt++] = lastChar;
+          lastChar = -1;
+        }
+        
+        [self->buffer la:(size - wasRead <  LaSize) 
+             ? (size - wasRead)
+             : LaSize];
+        
+        readCnt = [self->buffer readBytes:buf+bufCnt count:size - wasRead];
+        
+        wasRead+=readCnt;
+        bufCnt +=readCnt;
+
+        tmpSize   = bufCnt - 1;
+        cnt       = 0;
+        tmpBufCnt = 0;
+        
+        while (cnt < tmpSize) {
+          if ((buf[cnt] == '\r') && (buf[cnt+1] == '\n')) {
+            cnt++;
+          }
+          tmpBuf[tmpBufCnt++] = buf[cnt++];
+        }
+        if (cnt < bufCnt) {
+          lastChar = buf[cnt];
+        }
+        [stream writeBytes:tmpBuf count:tmpBufCnt];
+      }
+      if (lastChar != -1) {
+        [stream writeBytes:&lastChar count:1];
+      }
+      [stream close];
+      [stream release]; stream = nil;
+      result = [NSData dataWithContentsOfMappedFile:path];
+      [[NSFileManager defaultManager] removeFileAtPath:path handler:nil];
+
+      return result;
+  }
+
+  {
+    unsigned char *buf = NULL;
+    unsigned wasRead   = 0;
+    char *tmpBuf;
+    unsigned cnt, tmpBufCnt, tmpSize;
+          
+    buf = malloc(sizeof(char) * size + 10);
+      
+    while (wasRead < size) {
+      [self->buffer la:(size - wasRead <  LaSize) ? (size - wasRead) : LaSize];
+            
+      wasRead += [self->buffer readBytes:(buf + wasRead) 
+                              count:(size - wasRead)];
+    }
+    
+    /* normalize response  \r\n -> \n */
+       
+    tmpBuf    = malloc(sizeof(char) * size + 10);
+    cnt       = 0;
+    tmpBufCnt = 0;
+    tmpSize   = size - 1;
+    while (cnt < tmpSize) {
+      if ((buf[cnt] == '\r') && (buf[cnt+1] == '\n')) {
+       cnt++;
+      }
+      tmpBuf[tmpBufCnt++] = buf[cnt++];
+    }
+    if (cnt < size)
+      tmpBuf[tmpBufCnt++] = buf[cnt++];
+    
+    result = [NSData dataWithBytesNoCopy:tmpBuf length:tmpBufCnt];
+    
+    if (buf) free(buf); buf = NULL;
+    return result;
+  }
+}
+
+static int _parseTaggedResponse(NGImap4ResponseParser *self,
+                                NGMutableHashMap *result_) 
+{
+  NSDictionary *d;
+  NSNumber *tag  = nil;
+  NSString *res  = nil;
+  NSString *desc = nil;
+  NSString *flag = nil;
+  
+  if ((tag  = _parseUnsigned(self)) == nil) {
+    NSException *e;
+    
+    if (self->debug) {
+      e = [[NGImap4ParserException alloc]
+           initWithFormat:@"expect a number at begin of tagged response <%@>",
+           self->serverResponseDebug];
+    }
+    else {
+      e = [[NGImap4ParserException alloc]
+           initWithFormat:@"expect a number at begin of tagged response"];
+    }
+    e = [e autorelease];
+    [self setLastException:e];
+    return -1;
+  }
+  
+  _match(self, ' ');
+  res  = [_parseUntil(self, ' ') lowercaseString];
+  if (_la(self, 0) == '[') { /* Found flag like [READ-ONLY] */
+    _consume(self, 1);
+    flag = _parseUntil(self, ']');
+  }
+  desc = _parseUntil(self, '\n');
+  /*
+    ATTENTION: if no flag was set, flag == nil, in this case all key-value 
+               pairs after flag will be ignored
+  */
+  d = [[NSDictionary alloc] initWithObjectsAndKeys:
+                             tag,  @"tagId",
+                             res,  @"result",
+                             desc, @"description",
+                             flag, @"flag", nil];
+  [result_ addObject:d forKey:@"ResponseResult"];
+  [d release];
+  return [tag intValue];
+}
+
+static void _parseUntaggedResponse(NGImap4ResponseParser *self,
+                                   NGMutableHashMap *result_) 
+{
+  // TODO: is it really required by IMAP4 that responses are uppercase?
+  // TODO: apparently this code *breaks* with lowercase detection on!
+  unsigned char l0, l1 = 0;
+  _match(self, '*');
+  _match(self, ' ');
+  
+  l0 = _la(self, 0);
+  switch (l0) {
+  case 'B':
+    l1 = _la(self, 1);
+    if (l1 == 'A' && _parseBadUntaggedResponse(self, result_))    // la: 3
+      return;
+    if (l1 == 'Y' && _parseByeUntaggedResponse(self, result_))    // la: 3
+      return;
+    break;
+
+  case 'C':
+    if (_parseCapabilityResponse(self, result_))         // la: 10
+      return;
+    break;
+
+  case 'F':
+    if (_parseFlagsUntaggedResponse(self, result_))  // la: 5
+      return;
+    break;
+
+  case 'L':
+    if (_parseListOrLSubResponse(self, result_))     // la: 4
+      return;
+    break;
+
+  case 'N':
+    if (_parseNoUntaggedResponse(self, result_))     // la: 2
+      return;
+    break;
+
+  case 'O':
+    if (_parseOkUntaggedResponse(self, result_))     // la: 2
+      /* eg "* OK Completed" */
+      return;
+    break;
+
+  case 'R':
+    break;
+
+  case 'S':
+    switch (_la(self, 1)) {
+    case 'O': // SORT
+      if (_parseSortResponse(self, result_))         // la: 4
+       return;
+      break;
+    case 'E': // SEARCH
+      if (_parseSearchResponse(self, result_))         // la: 5
+       return;
+      break;
+    case 'T': // STATUS
+      if (_parseStatusResponse(self, result_))         // la: 6
+       /* eg "* STATUS INBOX (MESSAGES 0 RECENT 0 UNSEEN 0)" */
+       return;
+      break;
+    }
+    break;
+
+  case 'T':
+    if (_parseThreadResponse(self, result_))         // la: 6
+      return;
+    break;
+    
+  case 'Q':
+    if (_parseQuotaResponse(self, result_))          // la: 6
+      return;
+    if (_parseQuotaRootResponse(self, result_))         // la: 10
+      return;
+    break;
+
+  case '0': case '1': case '2': case '3': case '4':
+  case '5': case '6': case '7': case '8': case '9':
+    if (_parseNumberUntaggedResponse(self, result_)) // la: 5
+      /* eg "* 928 FETCH ..." */
+      return;
+    break;
+  }
+  
+  // TODO: what if none matches?
+  [self logWithFormat:@"%s: no matching tag specifier?", __PRETTY_FUNCTION__];
+}
+
+static void _parseContinuationResponse(NGImap4ResponseParser *self,
+                                       NGMutableHashMap *result_) {
+  _match(self, '+');
+  _match(self, ' ');
+
+  [result_ addObject:YesNum forKey:@"ContinuationResponse"];
+  [result_ addObject:_parseUntil(self, '\n') forKey:@"description"];
+}
+
+static BOOL _parseListOrLSubResponse(NGImap4ResponseParser *self,
+                                     NGMutableHashMap *result_) {
+  if (((_la(self, 0) == 'L')
+       && (_la(self, 1) == 'I')
+       && (_la(self, 2) == 'S')
+       && (_la(self, 3) == 'T')
+       && (_la(self, 4) == ' ')) ||
+      ((_la(self, 0) == 'L')
+       && (_la(self, 1) == 'S')
+       && (_la(self, 2) == 'U')
+       && (_la(self, 3) == 'B')
+       && (_la(self, 4) == ' '))) {
+    NSArray  *flags = nil;
+    NSString *delim = nil;
+    NSString *name  = nil;
+    NSDictionary *d;
+    
+    _consume(self, 5);
+
+    flags = _parseFlagArray(self);
+
+    _match(self, ' ');
+
+    if (_la(self, 0) == '"') {
+      _match(self, '"');
+      delim = _parseUntil(self, '"');
+      _match(self, ' ');
+    }
+    else {
+      _parseUntil(self, ' ');
+      delim = nil;
+    }
+    if (_la(self, 0) == '"') {
+      _consume(self, 1);
+      name = _parseUntil(self, '"');
+      _parseUntil(self, '\n');
+    }
+    else {
+      name = _parseUntil(self, '\n');
+    }
+
+    d = [[NSDictionary alloc] initWithObjectsAndKeys:
+                               name, @"folderName",
+                               flags, @"flags",
+                               delim, @"delimiter", nil];
+    [result_ addObject:d forKey:@"list"];
+    [d release];
+    return YES;
+  }
+  return NO;
+}
+
+static BOOL _parseCapabilityResponse(NGImap4ResponseParser *self,
+                                     NGMutableHashMap *result_) {
+  if ((_la(self, 0)     == 'C')
+      && (_la(self, 1)  == 'A')
+      && (_la(self, 2)  == 'P')
+      && (_la(self, 3)  == 'A')
+      && (_la(self, 4)  == 'B')
+      && (_la(self, 5)  == 'I')
+      && (_la(self, 6)  == 'L')
+      && (_la(self, 7)  == 'I')
+      && (_la(self, 8)  == 'T')
+      && (_la(self, 9)  == 'Y')
+      && (_la(self, 10) == ' ')) {
+    NSString *caps;
+
+    caps = _parseUntil(self, '\n');
+    {
+      NSEnumerator   *enumerator;
+      id             obj;
+      NSMutableArray *array;
+      NSArray        *tmp;
+
+      array = [[NSMutableArray alloc] initWithCapacity:16];
+
+      enumerator = [[caps componentsSeparatedByString:@" "] objectEnumerator];
+      while ((obj = [enumerator nextObject])) {
+        [array addObject:[obj lowercaseString]];
+      }
+      tmp = [array shallowCopy];
+      [result_ addObject:tmp forKey:@"capability"];
+
+      [array release]; array = nil;
+      [tmp   release]; tmp   = nil;
+    }
+    return YES;
+  }
+  return NO;
+}
+
+static BOOL _parseSearchResponse(NGImap4ResponseParser *self,
+                                 NGMutableHashMap *result_) {
+  if ((_la(self, 0) == 'S')
+      && (_la(self, 1) == 'E')
+      && (_la(self, 2) == 'A')
+      && (_la(self, 3) == 'R')
+      && (_la(self, 4) == 'C')
+      && (_la(self, 5) == 'H')) {
+
+    NSMutableArray *msn = nil;
+
+    _consume(self, 6);
+
+    msn = [NSMutableArray arrayWithCapacity:128];
+
+    while (_la(self, 0) == ' ') {
+      _consume(self, 1);
+      [msn addObject:_parseUnsigned(self)];
+    }
+    _parseUntil(self, '\n');
+    [result_ addObject:msn forKey:@"search"];
+    return YES;
+  }
+  return NO;
+}
+
+static BOOL _parseSortResponse(NGImap4ResponseParser *self,
+                                 NGMutableHashMap *result_) {
+  if ((_la(self, 0) == 'S')
+      && (_la(self, 1) == 'O')
+      && (_la(self, 2) == 'R')
+      && (_la(self, 3) == 'T')) {
+
+    NSMutableArray *msn = nil;
+
+    _consume(self, 4);
+
+    msn = [NSMutableArray arrayWithCapacity:128];
+
+    while (_la(self, 0) == ' ') {
+      _consume(self, 1);
+      [msn addObject:_parseUnsigned(self)];
+    }
+    _parseUntil(self, '\n');
+    [result_ addObject:msn forKey:@"sort"];
+    return YES;
+  }
+  return NO;
+}
+
+static BOOL _parseQuotaResponse(NGImap4ResponseParser *self,
+                                NGMutableHashMap *result_) {
+  if ((_la(self, 0) == 'Q')
+      && (_la(self, 1) == 'U')
+      && (_la(self, 2) == 'O')
+      && (_la(self, 3) == 'T')
+      && (_la(self, 4) == 'A')
+      && (_la(self, 5) == ' ')) {
+
+    NSString            *qRoot;
+    NSMutableDictionary *parse;
+    NSMutableDictionary *quota;
+
+    _consume(self, 6);
+
+    quota = [result_ objectForKey:@"quota"];
+
+    if (!quota) {
+      quota = [NSMutableDictionary dictionaryWithCapacity:2];
+      [result_ setObject:quota forKey:@"quota"];
+    }
+    
+    parse = [NSMutableDictionary dictionaryWithCapacity:3];
+    qRoot = _parseUntil2(self, ' ', '\n');
+
+    if (_la(self, 0) == ' ') {
+      _consume(self, 1);
+
+      if (_la(self, 0) == '(') {
+        _consume(self,1);
+        if (_la(self, 0) == ')') { /* empty quota response */
+          _consume(self,1);
+        }
+        else {
+          NSString *key;
+
+          key = _parseUntil(self, ' ');
+          key = [key lowercaseString];
+          if ([key isEqualToString:@"storage"]) {
+            NSString *used, *max;
+
+            used = _parseUntil(self, ' ');
+            max  = _parseUntil(self, ')');
+
+            [parse setObject:used forKey:@"usedSpace"];
+            [parse setObject:max  forKey:@"maxQuota"];
+          }
+          else {
+            NSString *v;
+
+            v = _parseUntil(self, ')');
+
+            [parse setObject:v forKey:@"resource"];
+          }
+        }
+      }
+      [quota setObject:parse forKey:qRoot];
+    }
+    _parseUntil(self, '\n');
+    
+    return YES;
+  }
+  return NO;
+}
+
+static BOOL _parseQuotaRootResponse(NGImap4ResponseParser *self,
+                                    NGMutableHashMap *result_)
+{
+  if ((_la(self, 0) == 'Q')
+      && (_la(self, 1) == 'U')
+      && (_la(self, 2) == 'O')
+      && (_la(self, 3) == 'T')
+      && (_la(self, 4) == 'A')
+      && (_la(self, 5) == 'R')
+      && (_la(self, 6) == 'O')
+      && (_la(self, 7) == 'O')
+      && (_la(self, 8) == 'T')
+      && (_la(self, 9) == ' ')) {
+    NSString *folderName, *folderRoot;
+    NSMutableDictionary *dict;
+
+    _consume(self, 10);
+
+    dict = [result_ objectForKey:@"quotaRoot"];
+
+    if (!dict) {
+      dict = [NSMutableDictionary dictionaryWithCapacity:2];
+      [result_ setObject:dict forKey:@"quotaRoot"];
+    }
+    if (_la(self, 0) == '"') {
+      _consume(self , 1);
+      folderName = _parseUntil(self, '"');
+    }
+    else {
+      folderName = _parseUntil2(self, '\n', ' ');
+    }
+    if (_la(self, 0) == ' ') {
+      _consume(self, 1);
+      folderRoot = _parseUntil(self, '\n');
+    }
+    else {
+      _consume(self, 1);
+      folderRoot = nil;
+    }
+    if ([folderName length] && [folderRoot length]) {
+      [dict setObject:folderRoot forKey:folderName];
+    }
+    return YES;
+  }
+  return NO;
+}
+
+static NSArray *_parseThread(NGImap4ResponseParser *self) {
+  NSMutableArray *array;
+  NSNumber       *msg;
+    
+  array = [NSMutableArray arrayWithCapacity:64];
+
+  if (_la(self, 0) == '(') {
+    _consume(self, 1);
+  }
+  while (1) {
+    if (_la(self, 0) == '(') {
+      id a;
+      a = _parseThread(self);
+      [array addObject:a];
+    }
+    else if ((msg = _parseUnsigned(self))) {
+      [array addObject:msg];
+    }
+    else {
+      return nil;
+    }
+    if (_la(self, 0) == ')')
+      break;
+    else if (_la(self, 0) == ' ')
+      _consume(self, 1);
+  }
+  _match(self, ')');
+  return array;
+}
+
+
+static BOOL _parseThreadResponse(NGImap4ResponseParser *self,
+                                 NGMutableHashMap *result_) {
+  if ((_la(self, 0) == 'T')
+      && (_la(self, 1) == 'H')
+      && (_la(self, 2) == 'R')
+      && (_la(self, 3) == 'E')
+      && (_la(self, 4) == 'A')
+      && (_la(self, 5) == 'D')) {
+
+    NSMutableArray *msn;
+
+    _consume(self, 6);
+
+    if (_la(self, 0) == ' ') {
+      _consume(self, 1);
+    }
+    else {
+      [result_ addObject:[NSArray array] forKey:@"thread"];
+      return YES;
+    }
+    msn = [NSMutableArray arrayWithCapacity:64];
+    while ((_la(self, 0) == '(')) {
+      NSArray *array;
+      if ((array = _parseThread(self)))
+        [msn addObject:array];
+    }
+    _parseUntil(self, '\n');
+    [result_ addObject:msn forKey:@"thread"];
+    return YES;
+  }
+  return NO;
+}
+
+static BOOL _parseStatusResponse(NGImap4ResponseParser *self,
+                                 NGMutableHashMap *result_) {
+  if ((_la(self, 0) == 'S')
+      && (_la(self, 1) == 'T')
+      && (_la(self, 2) == 'A')
+      && (_la(self, 3) == 'T')
+      && (_la(self, 4) == 'U')
+      && (_la(self, 5) == 'S')       
+      && (_la(self, 6) == ' ')) {
+    NSString            *name  = nil;
+    NSMutableDictionary *flags = nil;
+    NSDictionary *d;
+    
+    _consume(self, 7);
+
+    if (_la(self, 0) == '"') {
+      _consume(self, 1);
+      name = _parseUntil(self, '"');
+      _match(self, ' ');
+    }
+    else {
+      name = _parseUntil(self, ' ');
+    }
+    _match(self, '(');
+    flags = [NSMutableDictionary dictionaryWithCapacity:8];
+    
+    while (_la(self, 0) != ')') {
+      NSString *key   = _parseUntil(self, ' ');
+      id       value = _parseUntil2(self, ' ', ')');
+
+      if (_la(self, 0) == ' ')
+        _consume(self, 1);
+      
+      [flags setObject:[NumClass numberWithInt:[value intValue]]
+             forKey:[key lowercaseString]];
+    }
+    _match(self, ')');
+    _parseUntil(self, '\n');
+
+    d = [[NSDictionary alloc] initWithObjectsAndKeys:
+                               name, @"folderName",
+                               flags, @"flags", nil];
+    [result_ addObject:d forKey:@"status"];
+    [d release];
+    return YES;
+  }
+  return NO;
+}
+
+static BOOL _parseByeUntaggedResponse(NGImap4ResponseParser *self,
+                                      NGMutableHashMap *result_) {
+  if ((_la(self, 0) == 'B')
+      && (_la(self, 1) == 'Y')
+      && (_la(self, 2) == 'E')
+      && (_la(self, 3) == ' ')) {
+    NSString *reason = nil;
+
+    _consume(self, 4);
+    reason = _parseUntil(self, '\n');
+    [result_ addObject:reason forKey:@"bye"];
+    return YES;
+  }
+  return NO;
+}
+
+static BOOL _parseNumberUntaggedResponse(NGImap4ResponseParser *self,
+                                         NGMutableHashMap *result_) {
+  NSNumber *number = nil;
+  NSString *key    = nil;
+
+  if ((number = _parseUnsigned(self)) == nil)
+    return NO;
+  
+  _match(self, ' ');
+  
+  if ((_la(self, 0) == 'F')
+      && (_la(self, 1) == 'E')
+      && (_la(self, 2) == 'T')
+      && (_la(self, 3) == 'C')
+      && (_la(self, 4) == 'H')
+      && (_la(self, 5) == ' ')) { /* got a fetch response (fetch request) */
+    /* eg: "FETCH (FLAGS (\Seen) UID 5 RFC822.HEADER {2903}" */
+    NSMutableDictionary *fetch = nil;
+
+    fetch = [[NSMutableDictionary alloc] initWithCapacity:10];
+    
+    _consume(self, 6);
+    _match(self, '(');
+    while (_la(self, 0) != ')') {
+      NSString *key = nil;
+      
+      key = [_parseUntil(self, ' ') lowercaseString];
+      if ([key hasPrefix:@"body["]) {
+        [fetch setObject:_parseBodyContent(self) forKey:key];
+      }
+      else if ([key isEqualToString:@"body"]) {
+        [fetch setObject:_parseBody(self) forKey:key];
+      }
+      else if ([key isEqualToString:@"flags"]) {
+        [fetch setObject:_parseFlagArray(self) forKey:key];
+      }
+      else if ([key isEqualToString:@"uid"]) {
+        [fetch setObject:_parseUnsigned(self) forKey:key];
+      }
+      else if ([key isEqualToString:@"rfc822.size"]) {
+        [fetch setObject:_parseUnsigned(self) forKey:key];
+      }
+      else if ([key hasPrefix:@"rfc822"]) {
+        NSData *data;
+
+        if (_la(self, 0) == '"') {
+          NSString *str;
+          _consume(self,1);
+
+          str = _parseUntil(self, '"');
+          data = [str dataUsingEncoding:defCStringEncoding];
+        }
+        else 
+          data = _parseData(self);
+
+        if (data)
+          [fetch setObject:data forKey:key];
+      }
+      else {
+       NSException *e;
+
+       e = [[NGImap4ParserException alloc] initWithFormat:
+                                             @"unsupported fetch %@", key];
+        [self setLastException:[e autorelease]];
+       return NO;
+      }
+      if (_la(self, 0) == ' ')
+        _consume(self, 1);
+    }
+    if (fetch) {
+      [fetch setObject:number forKey:@"msn"];
+      [result_ addObject:fetch forKey:@"fetch"];
+      _consume(self, 1); /* consume ')' */
+      _match(self, '\n');
+    }
+    else { /* no correct fetch line */
+      _parseUntil(self, '\n');
+    }
+
+    [fetch release]; fetch = nil;
+
+    return YES;
+  }
+
+  { /* got a number request from select like  exists or recent */
+    key = _parseUntil(self, '\n');
+    [result_ addObject:number forKey:[key lowercaseString]];
+  }
+  return YES;
+}
+
+static BOOL _parseGreetingsSieveResponse(NGImap4ResponseParser *self,
+                                         NGMutableHashMap *result_) 
+{
+  BOOL isOK;
+  
+  while (!(isOK = _parseOkSieveResponse(self, result_))) {
+    NSString *key, *value;
+
+    if (!(key = _parseStringSieveResponse(self))) {
+      break;
+    }
+    if (_la(self, 0) == ' ') {
+      _consume(self, 1);
+
+      if (!(value = _parseStringSieveResponse(self))) {
+        break;
+      }
+    }
+    else {
+      value = @"";
+    }
+    _parseUntil(self, '\n');
+    [result_ addObject:value forKey:[key lowercaseString]];
+  }
+  return isOK;
+}
+
+static BOOL _parseDataSieveResponse(NGImap4ResponseParser *self,
+                                   NGMutableHashMap *result_) 
+{
+  NSString *str;
+  NSData   *data;
+
+  if ((data = _parseData(self)) == nil)
+    return NO;
+  
+  str = [[StrClass alloc] initWithData:data encoding:defCStringEncoding];
+  [result_ setObject:str forKey:@"data"];
+  [str release]; str = nil;
+  return YES;
+}
+
+static BOOL _parseOkSieveResponse(NGImap4ResponseParser *self,
+                                  NGMutableHashMap *result_) 
+{
+  if (!((_la(self, 0) == 'O') && (_la(self, 1) == 'K')))
+    return NO;
+    
+  _consume(self, 2);
+
+  if (_la(self, 0) == ' ') {
+      NSString *reason;
+
+      if ((reason = _parseContentSieveResponse(self)))
+        [result_ addObject:reason forKey:@"reason"];
+  }
+  _parseUntil(self, '\n');
+
+  [result_ addObject:YesNum forKey:@"ok"];
+  return YES;
+}
+
+static BOOL _parseNoSieveResponse(NGImap4ResponseParser *self,
+                                  NGMutableHashMap *result_) 
+{
+  NSString *data;
+  
+  if (!((_la(self, 0)=='N') && (_la(self, 1)=='O') && (_la(self, 2)==' ')))
+    return NO;
+    
+  _consume(self, 3);
+
+  data = _parseContentSieveResponse(self);
+    
+  [result_ addObject:NoNum forKey:@"ok"];
+  if (data) [result_ addObject:data forKey:@"reason"];
+  return YES;
+}
+
+static NSString *_parseContentSieveResponse(NGImap4ResponseParser *self) {
+  NSString *str;
+  NSData *data;
+  
+  if ((str = _parseStringSieveResponse(self)))
+    return str;
+  
+  if ((data = _parseData(self)) == nil)
+    return nil;
+  
+  return [[[StrClass alloc] initWithData:data encoding:defCStringEncoding]
+                          autorelease];
+}
+
+static NSString *_parseStringSieveResponse(NGImap4ResponseParser *self) {
+  if (_la(self, 0) != '"')
+    return nil;
+  
+  _consume(self, 1);
+  return _parseUntil(self, '"');
+}
+
+static NSString *_parseBodyDecodeString(NGImap4ResponseParser *self,
+                                        BOOL _convertString,
+                                        BOOL _decode)
+{
+
+  NSString *str;
+  
+  if (_la(self, 0) == '"') {
+    _consume(self, 1);
+    str = _parseUntil(self, '"');
+  }
+  else if (_la(self, 0) == '{') {
+    NSData *data;
+    
+    if (debugDataOn) [self logWithFormat:@"parse body decode string"];
+    data = _parseData(self);
+
+    if (_decode)
+      data = [data decodeQuotedPrintableValueOfMIMEHeaderField:nil];
+    
+    return [[[StrClass alloc] initWithData:data encoding:encoding]
+                            autorelease];
+  }
+  else {
+    str = _parseUntil2(self, ' ', ')');
+  }
+  if (_convertString) {
+    if ([[str lowercaseString] isEqualToString:@"nil"])
+      str = @"";
+  }
+  if (_decode) {
+    id  d;
+
+    d = [str dataUsingEncoding:defCStringEncoding];
+    d = [d decodeQuotedPrintableValueOfMIMEHeaderField:nil];
+
+    if ([d isKindOfClass:StrClass])
+      str = d;
+    else {
+      str = [[[StrClass alloc] initWithData:d encoding:encoding]
+                             autorelease];
+    }
+  }
+  return str;
+}
+
+
+static NSString *_parseBodyString(NGImap4ResponseParser *self,
+                                  BOOL _convertString)
+{
+  return _parseBodyDecodeString(self, _convertString, NO);
+}
+
+static NSDictionary *_parseBodyParameterList(NGImap4ResponseParser *self)
+{
+  NSMutableDictionary *list;
+
+  if (_la(self, 0) == '(') {
+    _consume(self, 1);
+
+    list = [NSMutableDictionary dictionaryWithCapacity:4];
+  
+    while (_la(self,0) != ')') {
+      NSString *key, *value;
+
+      if (_la(self, 0) == ' ')
+        _consume(self, 1);
+      
+      key = _parseBodyString(self, YES);
+      _match(self, ' ');
+      value = _parseBodyDecodeString(self, YES, YES);
+
+      [list setObject:value forKey:[key lowercaseString]];
+    }
+    _match(self, ')');
+  }
+  else {
+    NSString *str;
+    str = _parseBodyString(self, YES);
+
+    if ([str length] > 0) {
+      NSLog(@"%s: got unexpected string %@", __PRETTY_FUNCTION__, str);
+    }
+    list = (id)[NSDictionary dictionary];
+  }
+  return list;
+}
+
+static NSArray *_parseAddressStructure(NGImap4ResponseParser *self) {
+  NSString *personalName, *sourceRoute, *mailboxName, *hostName;
+  
+  _match(self, '(');
+  personalName = _parseBodyString(self, YES);
+  _match(self, ' ');
+  sourceRoute = _parseBodyString(self, YES);
+  _match(self, ' ');
+  mailboxName = _parseBodyString(self, YES);
+  _match(self, ' ');
+  hostName = _parseBodyString(self, YES);
+  _match(self, ')');
+  return [NSDictionary dictionaryWithObjectsAndKeys:
+                       personalName, @"personalName",
+                       sourceRoute,  @"sourceRoute",
+                       mailboxName,  @"mailboxName",
+                       hostName,     @"hostName", nil];
+}
+
+static NSArray *_parseParenthesizedAddressList(NGImap4ResponseParser *self) {
+  NSMutableArray *result;
+  result = [NSMutableArray arrayWithCapacity:8];
+
+  if (_la(self, 0) == '(') {
+    _consume(self, 1);
+    while (_la(self, 0) != ')') {
+      [result addObject:_parseAddressStructure(self)];
+    }
+    _consume(self, 1);
+  }
+  else {
+    NSString *str;
+    str = _parseBodyString(self, YES);
+
+    if ([str length] > 0) {
+      NSLog(@"%s: got unexpected string %@", __PRETTY_FUNCTION__, str);
+    }
+    result = (id)[NSArray array];
+  }
+  return result;
+}
+
+static NSDictionary *_parseSingleBody(NGImap4ResponseParser *self) {
+  NSString            *type, *subtype, *bodyId, *description,
+                      *encoding, *bodysize;
+  NSDictionary        *parameterList;
+  NSMutableDictionary *dict;
+
+  type = [_parseBodyString(self, YES) lowercaseString];
+  _match(self, ' ');
+  subtype = _parseBodyString(self, YES);
+  _match(self, ' ');
+  parameterList = _parseBodyParameterList(self);
+  _match(self, ' ');
+  bodyId = _parseBodyString(self, YES);
+  _match(self, ' ');
+  description = _parseBodyString(self, YES);
+  _match(self, ' ');
+  encoding = _parseBodyString(self, YES);
+  _match(self, ' ');
+  bodysize = _parseBodyString(self, YES);
+
+  dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                              type, @"type",
+                              subtype, @"subtype",
+                              parameterList, @"parameterList",
+                              bodyId,        @"bodyId",
+                              description,   @"description",
+                              encoding,      @"encoding",
+                              bodysize,      @"size", nil];
+  
+  if ([type isEqualToString:@"text"]) {
+    _match(self, ' ');
+    [dict setObject:_parseBodyString(self, YES) forKey:@"lines"];
+  }
+  else if ([type isEqualToString:@"message"]) {
+    if (_la(self, 0) != ')') {
+      _match(self, ' ');
+      _match(self, '(');
+      [dict setObject:_parseBodyString(self, YES) forKey:@"date"];
+      _match(self, ' ');
+      [dict setObject:_parseBodyString(self, YES) forKey:@"subject"];
+      _match(self, ' ');
+      [dict setObject:_parseParenthesizedAddressList(self) forKey:@"from"];
+      _match(self, ' ');
+      [dict setObject:_parseParenthesizedAddressList(self) forKey:@"sender"];
+      _match(self, ' ');
+      [dict setObject:_parseParenthesizedAddressList(self)
+            forKey:@"reply-to"];
+      _match(self, ' ');
+      [dict setObject:_parseParenthesizedAddressList(self) forKey:@"to"];
+      _match(self, ' ');
+      [dict setObject:_parseParenthesizedAddressList(self) forKey:@"cc"];
+      _match(self, ' ');
+      [dict setObject:_parseParenthesizedAddressList(self) forKey:@"bcc"];
+      _match(self, ' ');
+      [dict setObject:_parseBodyString(self, YES) forKey:@"in-reply-to"];
+      _match(self, ' ');
+      [dict setObject:_parseBodyString(self, YES) forKey:@"messageId"];
+      _match(self, ')');
+      _match(self, ' ');
+      [dict setObject:_parseBody(self) forKey:@"body"];
+      _match(self, ' ');
+      [dict setObject:_parseBodyString(self, YES) forKey:@"bodyLines"];
+    }
+  }
+  return dict;
+}
+
+static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self) {
+  NSMutableArray *parts;
+  NSString       *kind;
+
+  parts = [NSMutableArray arrayWithCapacity:4];
+
+  while (_la(self, 0) == '(') {
+    [parts addObject:_parseBody(self)];
+  }
+  _match(self, ' ');
+  kind = _parseBodyString(self, YES);
+  return [NSDictionary dictionaryWithObjectsAndKeys:
+                       parts,        @"parts",
+                       @"multipart", @"type",
+                       kind        , @"subtype", nil];
+}
+
+static NSDictionary *_parseBody(NGImap4ResponseParser *self) {
+  NSDictionary *result;
+
+  _match(self, '(');
+
+  if (_la(self, 0) == '(') {
+    result = _parseMultipartBody(self);
+  }
+  else {
+    result = _parseSingleBody(self);
+  }
+  if (_la(self,0) != ')') {
+    NSString *str;
+
+    str = _parseUntil(self, ')');
+    NSLog(@"%s: got noparsed content %@", __PRETTY_FUNCTION__,
+          str);
+  }
+  else 
+    _consume(self, 1);
+
+  return result;
+}
+
+static NSDictionary *_parseBodyContent(NGImap4ResponseParser *self) {
+  NSData *data;
+
+  if (_la(self, 0) == '"') {
+    NSString *str;
+    _consume(self,1);
+    
+    str = _parseUntil(self, '"');
+    data = [str dataUsingEncoding:defCStringEncoding];
+  }
+  else 
+    data = _parseData(self);
+  
+  return [NSDictionary dictionaryWithObject:data forKey:@"data"];
+}
+
+
+static NSArray *_parseFlagArray(NGImap4ResponseParser *self) {
+  NSString *flags;
+  
+  _match(self, '(');
+  
+  flags = _parseUntil(self, ')');
+  if ([flags length] == 0) {
+    static NSArray *emptyArray = nil;
+    if (emptyArray == nil) emptyArray = [[NSArray alloc] init];
+    return emptyArray;
+  }
+  else
+    return [[flags lowercaseString] componentsSeparatedByString:@" "];
+}
+
+static BOOL _parseFlagsUntaggedResponse(NGImap4ResponseParser *self,
+                                        NGMutableHashMap *result_) {
+  if ((_la(self, 0) == 'F')
+      && (_la(self, 1) == 'L')
+      && (_la(self, 2) == 'A')
+      && (_la(self, 3) == 'G')
+      && (_la(self, 4) == 'S')      
+      && (_la(self, 5) == ' ')) {
+    _consume(self, 6);
+    [result_ addObject:_parseFlagArray(self) forKey:@"flags"];
+    _match(self, '\n');
+    return YES;
+  }
+  return NO;
+}
+
+static BOOL _parseBadUntaggedResponse(NGImap4ResponseParser *self,
+                                     NGMutableHashMap *result_) 
+{
+  if (!((_la(self, 0)=='B') && (_la(self, 1)=='A') && (_la(self, 2)=='D')      
+       && (_la(self, 3) == ' ')))
+    return NO;
+
+  _consume(self, 4);
+  [result_ addObject:_parseUntil(self, '\n') forKey:@"bad"];
+  return YES;
+}
+
+static BOOL _parseNoOrOkArguments(NGImap4ResponseParser *self,
+                                  NGMutableHashMap *result_, NSString *_key) 
+{
+  NSString *obj;
+
+  obj = nil;
+  
+  if (_la(self, 0) == '[') {
+    NSString *key;
+      
+    _consume(self, 1);
+    key = _parseUntil2(self, ']', ' ');
+
+    /* possible kinds of untagged OK responses are either
+     * OK [ALERT] System shutdown in 10 minutes
+     or               
+     * OK [UNSEEN 14]
+     or
+     * OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen \*)]
+     */
+    if (_la(self, 0) == ']') {
+
+      _consume(self, 1);
+      if (_la(self, 0) == ' ') {
+        id value;
+        
+        _consume(self, 1);
+        value = _parseUntil(self, '\n');
+        if ([value length] > 0) {
+          obj = [[NSDictionary alloc] 
+                 initWithObjects:&value forKeys:&key count:1];
+       }
+        else
+          obj = [key retain];
+      }
+      else {
+        obj = [key retain];
+        _parseUntil(self, '\n');
+      }
+    }
+    else { /* _la(self, 0) should be ' ' */
+      id value;
+
+      value = nil;
+      
+      _consume(self, 1);
+      if (_la(self, 0) == '(') {
+        value = _parseFlagArray(self);
+        _consume(self, 1); /* consume ']' */
+      }
+      else {
+        value = _parseUntil(self, ']');
+      }
+      {
+        id tmp;
+
+        tmp = _parseUntil(self, '\n');
+        
+        obj = [[NSDictionary alloc] initWithObjectsAndKeys:
+                            value, key,
+                            tmp,   @"comment", nil];
+      }
+    }
+  }
+  else
+    obj = [_parseUntil(self, '\n') retain];
+
+  [result_ addObject:obj forKey:_key];
+  [obj release];
+  return YES;
+}
+
+
+static BOOL _parseNoUntaggedResponse(NGImap4ResponseParser *self,
+                                     NGMutableHashMap *result_) 
+{
+  if (!((_la(self, 0)=='N') && (_la(self, 1)=='O') && (_la(self, 2)==' ')))
+    return NO;
+
+  _consume(self, 3);
+  return _parseNoOrOkArguments(self, result_, @"no");
+}
+
+static BOOL _parseOkUntaggedResponse(NGImap4ResponseParser *self,
+                                     NGMutableHashMap *result_) 
+{
+  if (!((_la(self, 0)=='O') && (_la(self, 1)=='K') && (_la(self, 2)==' ')))
+    return NO;
+  
+  _consume(self, 3);
+  return _parseNoOrOkArguments(self, result_, @"ok");
+}
+
+static NSNumber *_parseUnsigned(NGImap4ResponseParser *self) {
+  unsigned      n;
+  unsigned char c;
+  BOOL     isNumber;
+
+  isNumber = NO;  
+  n        = 0;  
+  c        = _la(self, 0);
+  
+  while ((c >= '0') && (c <= '9')) {
+    _consume(self, 1);
+    isNumber = YES;
+    n        = 10 * n + (c - 48);
+    c        = _la(self, 0);
+  }
+  if (!isNumber)
+    return nil;
+  
+  return [NumClass numberWithUnsignedInt:n];
+}
+
+static NSString *_parseUntil(NGImap4ResponseParser *self, char _c) {
+  /*
+    _parseUntil(self, char) consume the stop char
+    normalize \r\n constructions
+  */
+  // TODO: optimize!
+  char            buf[1024], c;
+  NSMutableString *str;
+  unsigned        cnt;
+
+  cnt = 0;
+  str = nil;  
+  while ((c = _la(self, 0)) != _c) {
+    buf[cnt] = c;
+    _consume(self, 1);
+    cnt++;
+    if (cnt == 1024) {
+      if (str == nil)
+        str = (NSMutableString *)
+          [NSMutableString stringWithCString:buf length:1024];
+      else {
+        NSString *s;
+        
+        s = [(NSString *)[StrClass alloc] initWithCString:buf length:1024];
+        [str appendString:s];
+        [s release];
+      }
+      cnt = 0;
+    }
+  }
+  _consume(self,1); /* consume known stop char */
+  if (_c == '\n' && cnt > 0) {
+    if (buf[cnt-1] == '\r')
+      cnt--;
+  }
+  
+  if (str == nil)
+    return [StrClass stringWithCString:buf length:cnt];
+  else {
+    NSString *s, *s2;
+    
+    s = [(NSString *)[StrClass alloc] initWithCString:buf length:cnt];
+    s2 = [str stringByAppendingString:s];
+    [s release];
+    return s2;
+  }
+}
+
+static NSString *_parseUntil2(NGImap4ResponseParser *self, char _c1, char _c2){
+  /* _parseUntil2(self, char, char) doesn`t consume the stop-chars */
+  char            buf[1024], c;
+  NSMutableString *str;
+  unsigned        cnt;
+
+  cnt = 0;
+  c   = _la(self, 0);
+  str = nil;
+  
+  while ((c != _c1) && (c != _c2)) {
+    buf[cnt] = c;
+    _consume(self, 1);
+    cnt++;
+    if (cnt == 1024) {
+      if (str == nil)
+        str = (NSMutableString *)
+                 [NSMutableString stringWithCString:buf length:1024];
+      else {
+        NSString *s;
+        s = [(NSString *)[StrClass alloc] initWithCString:buf length:1024];
+        [str appendString:s];
+        [s release];
+      }
+      
+      cnt = 0;
+    }
+    c = _la(self, 0);    
+  }
+
+  if (str == nil)
+    return [StrClass stringWithCString:buf length:cnt];
+  
+  {
+    NSString *s, *s2;
+    
+    s = [(NSString *)[StrClass alloc] initWithCString:buf length:cnt];
+    s2 = [str stringByAppendingString:s];
+    [s release];
+    return s2;
+  }
+}
+
+
+static __inline__ void _match(NGImap4ResponseParser *self, char _match) {
+  if (_la(self,0) == _match) {
+    _consume(self, 1);
+    return;
+  }
+  {
+    NSException *e;
+    if (self->debug) {
+      e = [[NGImap4ParserException alloc]
+                                     initWithFormat:@"unexpected char <%c> "
+                                     @"expected <%c> <%@>",
+                                     _la(self, 0), _match,
+                                     self->serverResponseDebug];
+    }
+    else {
+      e = [[NGImap4ParserException alloc]
+                                     initWithFormat:@"unexpected char <%c> "
+                                     @"expected <%c>",
+                                     _la(self, 0), _match];
+    }
+    e = [e autorelease];
+    [self setLastException:e];
+  }
+}
+
+static __inline__ void _consume(NGImap4ResponseParser *self, unsigned _cnt) {
+  /* Normalize end of line */
+
+  if (_cnt == 0)
+    return;
+  
+  _cnt +=  (__la(self, _cnt - 1) == '\r') ? 1 : 0;
+  
+  if (self->debug) {
+    unsigned cnt;
+    
+    for (cnt = 0; cnt < _cnt; cnt++) {
+      NSString *s;
+      unichar c = _la(self, cnt);
+      
+      if (c == '\r')
+       continue;
+        
+      s = [[StrClass alloc] initWithCharacters:&c length:1];
+      [self->serverResponseDebug appendString:s];
+      [s release];
+      
+      if (c == '\n') {
+          if ([self->serverResponseDebug cStringLength] > 2) {
+            fprintf(stderr, "S[%p]: %s", self,
+                    [self->serverResponseDebug cString]);
+          }
+          [self->serverResponseDebug release];
+          self->serverResponseDebug = 
+            [[NSMutableString alloc] initWithCapacity:512];
+      }
+    }
+  }
+  [self->buffer consume:_cnt];
+}
+
+@end /* NGImap4ResponseParser */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4ServerGlobalID.h b/skyrix-core/NGMime/NGImap4/NGImap4ServerGlobalID.h
new file mode 100644 (file)
index 0000000..63950b7
--- /dev/null
@@ -0,0 +1,32 @@
+// $Id$
+
+#ifndef __NGImap4_NGImap4ServerGlobalID_H__
+#define __NGImap4_NGImap4ServerGlobalID_H__
+
+#include <EOControl/EOGlobalID.h>
+
+@interface NGImap4ServerGlobalID : EOGlobalID < NSCopying >
+{
+  NSString *hostName;
+  NSString *login;
+  int      port;
+}
+
++ (id)imap4ServerGlobalIDForHostname:(NSString *)_host port:(int)_port
+  login:(NSString *)_login;
+- (id)initWithHostname:(NSString *)_host port:(int)_port
+  login:(NSString *)_login;
+
+/* accessors */
+
+- (NSString *)hostName;
+- (NSString *)login;
+- (int)port;
+
+/* comparison */
+
+- (BOOL)isEqualToImap4ServerGlobalID:(NGImap4ServerGlobalID *)_other;
+
+@end
+
+#endif /* __NGImap4_NGImap4ServerGlobalID_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4ServerGlobalID.m b/skyrix-core/NGMime/NGImap4/NGImap4ServerGlobalID.m
new file mode 100644 (file)
index 0000000..974ce1b
--- /dev/null
@@ -0,0 +1,94 @@
+// $Id$
+
+#include "NGImap4ServerGlobalID.h"
+#include "common.h"
+
+@implementation NGImap4ServerGlobalID
+
++ (id)imap4ServerGlobalIDForHostname:(NSString *)_host port:(int)_port
+  login:(NSString *)_login
+{
+  NGImap4ServerGlobalID *gid;
+
+  gid = [[self alloc] initWithHostname:_host port:_port login:_login];
+  return [gid autorelease];
+}
+
+- (id)initWithHostname:(NSString *)_host port:(int)_p login:(NSString *)_l {
+  if ((self = [super init])) {
+    self->hostName = [_host copy];
+    self->login    = [_l    copy];
+    self->port     = _p;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithHostname:nil port:0 login:nil];
+}
+
+- (void)dealloc {
+  [self->hostName release];
+  [self->login    release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)hostName {
+  return self->hostName;
+}
+- (NSString *)login {
+  return self->login;
+}
+- (int)port {
+  return self->port;
+}
+
+/* comparison */
+
+- (unsigned)hash {
+  return [self->login hash];
+}
+
+- (BOOL)isEqualToImap4ServerGlobalID:(NGImap4ServerGlobalID *)_other {
+  if (_other == nil)
+    return NO;
+  if (self == _other)
+    return YES;
+  
+  if (self->login != _other->login) {
+    if (![self->login isEqualToString:_other->login])
+      return NO;
+  }
+  if (self->hostName != _other->hostName) {
+    if (![self->hostName isEqualToString:_other->hostName])
+      return NO;
+  }
+  if (self->port != _other->port)
+    return NO;
+  
+  return YES;
+}
+
+- (BOOL)isEqual:(id)_otherObject {
+  if (_otherObject == self)
+    return YES;
+  if (![_otherObject isKindOfClass:[self class]])
+    return NO;
+  
+  return [self isEqualToImap4ServerGlobalID:_otherObject];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+/* support for some older code expecting only EO global IDs */
+
+- (NSString *)entityName {
+  return @"NGImap4Client";
+}
+
+@end /* NGImap4ServerGlobalID */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4ServerRoot.h b/skyrix-core/NGMime/NGImap4/NGImap4ServerRoot.h
new file mode 100644 (file)
index 0000000..b8d8437
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+#ifndef __Networking_NGImap4_NGImap4ServerRoot_H__
+#define __Networking_NGImap4_NGImap4ServerRoot_H__
+
+#import  <Foundation/Foundation.h>
+#include <NGMime/NGPart.h>
+#include <NGImap4/NGImap4Support.h>
+
+@class NSArray, NSString, NSMutableArray, NSNumber;
+@class NGHashMap, NGImap4Context, EOQualifier;
+
+@interface NGImap4ServerRoot : NSObject <NGImap4Folder>
+{
+@private  
+  NSString       *name;
+  NGImap4Context *context;
+  NSArray        *subFolders;
+  BOOL           noinferiors;
+}
+
++ (id)serverRootWithContext:(NGImap4Context *)_context;
+
+- (id)initServerRootWithContext:(NGImap4Context *)_context;
+
+- (NSException *)lastException;
+- (void)resetLastException;
+
+- (BOOL)isEqual:(id)_obj;
+- (BOOL)isEqualToServerRoot:(NGImap4ServerRoot *)_root;
+
+- (NGImap4Context *)context;
+- (NGImap4Folder *)parentFolder;
+
+- (NSString *)name;
+- (NSString *)absoluteName;
+- (BOOL)renameTo:(NSString *)_name;
+- (BOOL)isInTrash;
+
+- (NSArray *)messageFlags;
+- (NSArray *)messages;
+- (NSArray *)messagesForQualifier:(EOQualifier *)_qualifier;
+- (NSArray *)messagesForQualifier:(EOQualifier *)_qualifier maxCount:(int)_cnt;
+- (BOOL)deleteMessages:(NSArray *)_messages;
+- (BOOL)deleteAllMessages;
+- (BOOL)moveMessages:(NSArray *)_messages toFolder:(NGImap4Folder *)_folder;
+- (BOOL)copyMessages:(NSArray *)_messages toFolder:(NGImap4Folder *)_folder;
+- (BOOL)appendMessage:(NSData *)_msg;
+
+- (BOOL)hasNewMessagesSearchRecursiv:(BOOL)_recursiv;
+- (BOOL)hasNewMessagesSearchRecursiv:(BOOL)_recursiv fetchOnDemand:(BOOL)_fetch;
+
+- (BOOL)hasNewMessagesSearchRecursiv:(BOOL)_recursiv fetchOnDemand:(BOOL)_fetch;
+- (BOOL)hasUnseenMessagesSearchRecursiv:(BOOL)_recursiv;
+
+- (BOOL)addFlag:(NSString *)_flag toMessages:(NSArray *)_messages;
+- (BOOL)removeFlag:(NSString *)_flag fromMessages:(NSArray *)_messages;
+
+- (NSArray *)subFolders;
+- (NGImap4Folder *)subFolderWithName:(NSString *)_name
+  caseInsensitive:(BOOL)_caseIns;
+- (BOOL)deleteSubFolder:(NGImap4Folder *)_folder;
+- (BOOL)createSubFolderWithName:(NSString *)_name;
+- (BOOL)copySubFolder:(NGImap4Folder *)_f to:(NGImap4Folder *)_folder;
+- (BOOL)moveSubFolder:(NGImap4Folder *)_f to:(NGImap4Folder *)_folder;
+
+- (BOOL)isReadOnly;
+
+- (BOOL)noselect;
+- (BOOL)noinferiors;
+- (BOOL)nonexistent;
+- (BOOL)haschildren;
+- (BOOL)marked;
+- (BOOL)unmarked;
+
+- (int)exists;
+- (int)recent;
+- (int)unseen;
+- (void)status;
+- (void)select;
+- (void)expunge;
+
+- (void)resetFolder;
+- (void)resetSubFolders;
+- (void)resetStatus;
+
+- (void)resetSync;
+
+- (void)bulkFetchHeadersFor:(NSArray *)_array inRange:(NSRange)_aRange;
+
+- (void)bulkFetchHeadersFor:(NSArray *)_array inRange:(NSRange)_aRange
+  withAllUnread:(BOOL)_unread;
+
+@end
+
+#endif /* __Networking_NGImap4_NGImap4ServerRoot_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4ServerRoot.m b/skyrix-core/NGMime/NGImap4/NGImap4ServerRoot.m
new file mode 100644 (file)
index 0000000..b11f22d
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGImap4ServerRoot.h"
+#include "NGImap4Context.h"
+#include "NGImap4Client.h"
+#include "NGImap4Message.h"
+#include "NGImap4Functions.h"
+#include "NGImap4Folder.h"
+#include "imCommon.h"
+
+@interface NGImap4ServerRoot(Private)
+- (void)initializeSubFolders;
+@end
+
+@implementation NGImap4ServerRoot
+
+static int ShowNonExistentFolder                      = -1;
+static int FetchNewUnseenMessagesInSubFoldersOnDemand = -1;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
+  // TODO: document the meaning!
+  ShowNonExistentFolder =
+    [ud boolForKey:@"ShowNonExistentFolder"] ? 1 : 0;
+  FetchNewUnseenMessagesInSubFoldersOnDemand =
+    [ud boolForKey:@"FetchNewUnseenMessagesInSubFoldersOnDemand"] ? 1 : 0;
+}
+
++ (id)serverRootWithContext:(NGImap4Context *)_context {
+  return [[[self alloc] initServerRootWithContext:_context] autorelease];
+}
+
+- (id)init {
+  [self release];
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (id)initServerRootWithContext:(NGImap4Context *)_context {
+  if ((self = [super init])) {
+    self->context    = [_context retain];
+    self->name       = [[_context host] copy];
+    self->subFolders = nil;
+
+    self->noinferiors = ([[_context serverKind] isEqualToString:@"courier"])
+      ? YES : NO;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->context    resetSpecialFolders];
+  [self->context    release];
+  [self->name       release];
+  [self->subFolders makeObjectsPerformSelector:@selector(clearParentFolder)];
+  [self->subFolders release];
+  [super dealloc];
+}
+
+- (NSException *)lastException {
+  return [self->context lastException];
+}
+- (void)resetLastException {
+  [self->context resetLastException];
+}
+
+- (BOOL)isEqual:(id)_obj {
+  if (self == _obj)
+    return YES;
+  if ([_obj isKindOfClass:[NGImap4ServerRoot class]])
+    return [self isEqualToServerRoot:_obj];
+  return NO;
+}
+
+- (BOOL)isEqualToServerRoot:(NGImap4ServerRoot *)_root {
+  if (_root == self)
+    return YES;
+  if ([_root context] == self->context)
+    return YES;
+  return NO;
+}
+
+/* accessors */
+
+- (NGImap4Context *)context {
+  return self->context;
+}
+
+- (NSString *)name {
+  return self->name;
+}
+
+- (NSString *)absoluteName {
+  return self->name;
+}
+
+- (NSArray *)messages {
+  return nil;
+}
+
+- (NSArray *)messagesForQualifier:(EOQualifier *)_qualifier {
+  return nil;
+}
+
+- (NSArray *)messagesForQualifier:(EOQualifier *)_q maxCount:(int)_cnt {
+  return nil;
+}
+
+- (NSArray *)fetchSortedMessages:(NSArray *)_so {
+  return nil;
+}
+
+- (void)bulkFetchHeadersFor:(NSArray *)_array inRange:(NSRange)_aRange {
+}
+
+- (void)bulkFetchHeadersFor:(NSArray *)_array inRange:(NSRange)_aRange
+  withAllUnread:(BOOL)_unread
+{
+}
+
+- (NSArray *)messageFlags { 
+  return nil;
+}
+
+- (NSArray *)subFolders {
+  if (self->subFolders == nil)
+    [self initializeSubFolders];
+  return self->subFolders;
+}
+
+- (NGImap4Folder *)subFolderWithName:(NSString *)_name
+  caseInsensitive:(BOOL)_caseIns
+{
+  return _subFolderWithName(self, _name, _caseIns);
+}
+
+- (id<NGImap4Folder>)parentFolder {
+  return nil;
+}
+
+- (BOOL)isReadOnly {
+  return YES;
+}
+
+- (BOOL)noinferiors {
+  return self->noinferiors;
+}
+
+- (BOOL)noselect {
+  return YES;
+}
+
+- (BOOL)nonexistent {
+  return NO;
+}
+- (BOOL)haschildren {
+  return YES;
+}
+- (BOOL)hasnochildren {
+  return NO;
+}
+- (BOOL)marked {
+  return NO;
+}
+- (BOOL)unmarked {
+  return NO;
+}
+
+- (int)exists {
+  return 0;
+}
+
+- (int)recent {
+  return 0;
+}
+
+- (int)unseen {
+  return 0;
+}
+
+- (int)usedSpace {
+  return 0;
+}
+
+- (int)maxQuota {
+  return 0;
+}
+
+- (BOOL)isOverQuota {
+  return NO;
+}
+
+- (BOOL)hasNewMessagesSearchRecursiv:(BOOL)_recursiv fetchOnDemand:(BOOL)_fetch {
+  if (_recursiv)
+    return _hasNewMessagesInSubFolder(self, _fetch);
+  return NO;
+}
+
+- (BOOL)hasNewMessagesSearchRecursiv:(BOOL)_recursiv {
+  if (!_recursiv)
+    return NO;
+  return _hasNewMessagesInSubFolder(self,
+            FetchNewUnseenMessagesInSubFoldersOnDemand);
+}
+
+- (BOOL)hasUnseenMessagesSearchRecursiv:(BOOL)_recursiv 
+  fetchOnDemand:(BOOL)_fetch 
+{
+  if (_recursiv)
+    return _hasUnseenMessagesInSubFolder(self, _fetch);
+  return NO;
+}
+
+- (BOOL)hasUnseenMessagesSearchRecursiv:(BOOL)_recursiv {
+  if (_recursiv) {
+    return _hasUnseenMessagesInSubFolder(self,
+              FetchNewUnseenMessagesInSubFoldersOnDemand);
+  }
+  return NO;
+}
+
+// private methods
+
+/*"
+** Should only happens if folder is rootfolder
+"*/
+
+- (void)initializeSubFolders {
+  NSEnumerator *folders;
+  NSDictionary *res;
+  id           *objs, folder;
+  unsigned     cnt;
+  BOOL         gotInbox;
+  
+  if (self->subFolders != nil) {
+    [self resetSubFolders];
+  }
+
+  if ([self->context showOnlySubscribedInRoot]) {
+    res = [[self->context client] lsub:@"" pattern:@"%"];
+  }
+  else {
+    res = [[self->context client] list:@"" pattern:@"%"];
+  }
+
+  if (!_checkResult(self->context, res, __PRETTY_FUNCTION__))
+    return;
+  
+  res = [res objectForKey:@"list"];
+
+  objs = calloc([res count] + 2, sizeof(id));
+  {
+    NSArray *names;
+    
+    names   = [res allKeys];
+    names   = [names sortedArrayUsingSelector:
+                       @selector(caseInsensitiveCompare:)];
+    folders = [names objectEnumerator];
+  }
+  cnt      = 0;
+  gotInbox = NO;
+  
+  while ((folder = [folders nextObject])) {
+    NSArray *f;
+
+    f = [res objectForKey:folder];
+
+    if (!ShowNonExistentFolder) {
+      if ([f containsObject:@"nonexistent"])
+        continue;
+    }
+
+    objs[cnt] = [[[NGImap4Folder alloc] initWithContext:self->context
+                                       name:folder flags:f parentFolder:self] 
+                                autorelease];
+    cnt++;
+    
+    if ([[folder lowercaseString] isEqualToString:@"/inbox"])
+      gotInbox = YES;
+  }
+  if (!gotInbox && [self->context showOnlySubscribedInRoot]) {
+    /* try unsubscribed */
+    res = [[[self->context client] list:@"" pattern:@"%"] objectForKey:@"list"];
+
+    {
+      NSArray *names;
+    
+      names   = [res allKeys];
+      names   = [names sortedArrayUsingSelector:
+                       @selector(caseInsensitiveCompare:)];
+      folders = [names objectEnumerator];
+    }
+    while ((folder = [folders nextObject])) {
+      if ([[folder lowercaseString] isEqualToString:@"/inbox"]) {
+        objs[cnt] = [[[NGImap4Folder alloc] initWithContext:self->context
+                                           name:folder 
+                                           flags:[res objectForKey:folder]
+                                           parentFolder:self]
+                                    autorelease];
+       cnt++;
+        break;
+      }
+    }
+  }
+  self->subFolders = [[NSArray alloc] initWithObjects:objs count:cnt];
+  if (objs) free(objs); objs = NULL;
+}
+
+- (void)select {
+}
+
+- (void)status {
+}
+
+/* actions */
+
+- (void)resetFolder {
+}
+
+- (void)resetStatus {
+}
+
+- (void)resetSubFolders {
+  [self->context resetSpecialFolders];
+  [self->subFolders release]; self->subFolders = nil;
+}
+
+- (BOOL)renameTo:(NSString *)_name {
+  return NO;
+}
+
+/* folder */
+
+- (BOOL)deleteSubFolder:(NGImap4Folder *)_folder {
+  return _deleteSubFolder(self, _folder);
+}
+
+- (BOOL)copySubFolder:(NGImap4Folder *)_f to:(id<NGImap4Folder>)_folder {
+  return _copySubFolder(self, _f, _folder);
+}
+
+- (BOOL)moveSubFolder:(NGImap4Folder *)_f to:(id<NGImap4Folder>)_folder {
+  return _moveSubFolder(self, _f, _folder);
+}
+
+- (BOOL)createSubFolderWithName:(NSString *)_name {
+  return _createSubFolderWithName(self, _name, NO);
+}
+
+- (void)expunge {
+}
+
+- (BOOL)addFlag:(NSString *)_flag toMessages:(NSArray *)_messages {
+  return NO;
+}
+
+- (BOOL)removeFlag:(NSString *)_flag fromMessages:(NSArray *)_messages {
+  return NO;
+}
+
+- (BOOL)flag:(NSString *)_flag toMessages:(NSArray *)_messages
+        add:(NSNumber *)_add
+{
+  return NO;
+}
+
+- (BOOL)flagToAllMessages:(NSString *)_flag add:(NSNumber *)_add {
+  return NO;
+}
+
+- (BOOL)deleteAllMessages {
+  return NO;
+}
+
+- (BOOL)deleteMessages:(NSArray *)_messages {
+  return NO;
+}
+
+- (BOOL)moveMessages:(NSArray *)_messages toFolder:(NGImap4Folder *)_folder {
+  return NO;
+}
+
+- (BOOL)copyMessages:(NSArray *)_messages toFolder:(NGImap4Folder *)_folder {
+  return NO;
+}
+
+- (BOOL)appendMessage:(NSData *)_msg {
+  return NO;
+}
+
+- (BOOL)isInTrash {
+  return NO;
+}
+
+- (NSString *)description {
+  NSMutableString *ms;
+  NSString *tmp;
+
+  ms = [NSMutableString stringWithCapacity:64];
+
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if ((tmp = [self name]))
+    [ms appendFormat:@" name=%@", tmp];
+  if ((tmp = [self absoluteName]))
+    [ms appendFormat:@" absolute=%@", tmp];
+  
+  [ms appendString:@">"];
+
+  return ms;
+}
+
+- (void)resetSync {
+  NSEnumerator *enumerator;
+  id           folder;
+
+  enumerator = [[self subFolders] objectEnumerator];
+  
+  while ((folder = [enumerator nextObject])) {
+    [folder resetSync];
+  }
+}
+
+@end /* NGImap4ServerRoot */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Support.h b/skyrix-core/NGMime/NGImap4/NGImap4Support.h
new file mode 100644 (file)
index 0000000..e692ae6
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __Networking_NGImap4_NGImap4Support_H__
+#define __Networking_NGImap4_NGImap4Support_H__
+
+#import <Foundation/NSException.h>
+
+@class NSDictionary, NSString, NSArray, EOQualifier, NSNumber, NSData;
+@class NGImap4Client, NGImap4Context, NGImap4Folder;
+
+@protocol NGImap4Folder <NSObject>
+
+- (NGImap4Context *)context;
+- (NGImap4Folder *)parentFolder;
+
+- (NSString *)name;
+- (NSString *)absoluteName;
+- (BOOL)renameTo:(NSString *)_name;
+- (BOOL)isInTrash;
+
+- (NSArray *)messageFlags;
+- (NSArray *)messages;
+- (NSArray *)messagesForQualifier:(EOQualifier *)_qualifier;
+- (NSArray *)messagesForQualifier:(EOQualifier *)_qualifier maxCount:(int)_cnt;
+- (BOOL)deleteMessages:(NSArray *)_messages;
+- (BOOL)deleteAllMessages;
+- (BOOL)moveMessages:(NSArray *)_messages toFolder:(NGImap4Folder *)_folder;
+- (BOOL)copyMessages:(NSArray *)_messages toFolder:(NGImap4Folder *)_folder;
+- (BOOL)appendMessage:(NSData *)_msg;
+- (BOOL)hasNewMessagesSearchRecursiv:(BOOL)_recursiv;
+- (BOOL)hasUnseenMessagesSearchRecursiv:(BOOL)_recursiv;
+- (BOOL)addFlag:(NSString *)_flag toMessages:(NSArray *)_messages;
+- (BOOL)removeFlag:(NSString *)_flag fromMessages:(NSArray *)_messages;
+
+- (NSArray *)subFolders;
+- (NGImap4Folder *)subFolderWithName:(NSString *)_name
+  caseInsensitive:(BOOL)_caseIns;
+- (BOOL)deleteSubFolder:(NGImap4Folder *)_folder;
+- (BOOL)createSubFolderWithName:(NSString *)_name;
+- (BOOL)copySubFolder:(NGImap4Folder *)_f to:(NGImap4Folder *)_folder;
+- (BOOL)moveSubFolder:(NGImap4Folder *)_f to:(NGImap4Folder *)_folder;
+
+- (BOOL)isReadOnly;
+- (BOOL)noselect;
+- (BOOL)noinferiors;
+
+- (int)exists;
+- (int)recent;
+- (int)unseen;
+- (void)status;
+- (void)select;
+- (void)expunge;
+
+- (int)usedSpace;
+- (int)maxQuota;
+- (BOOL)isOverQuota;
+
+- (void)resetFolder;
+- (void)resetSubFolders;
+- (void)resetStatus;
+
+- (void)resetSync;
+
+
+@end
+
+@protocol NGImap4ResponseReceiver
+- (void)responseNotificationFrom:(NGImap4Client *)_client
+  response:(NSDictionary *)_dict;
+@end
+
+@interface NGImap4Exception : NSException
+@end
+
+@interface NGImap4ParserException : NGImap4Exception
+@end
+@interface NGImap4ConnectionException : NGImap4Exception
+@end
+@interface NGImap4ResponseException : NGImap4Exception
+@end
+@interface NGImap4SearchException : NGImap4Exception
+@end
+
+#endif /* __Networking_NGImap4_NGImap4Support_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGImap4Support.m b/skyrix-core/NGMime/NGImap4/NGImap4Support.m
new file mode 100644 (file)
index 0000000..c4b471f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGImap4Support.h"
+#include "NGImap4Client.h"
+#include "imCommon.h"
+
+@implementation NGImap4Exception
+@end
+
+@implementation NGImap4ConnectionException
+@end
+
+@implementation NGImap4ResponseException
+@end
+
+@implementation NGImap4SearchException
+@end
+
+@implementation NGImap4ParserException
+@end
+
diff --git a/skyrix-core/NGMime/NGImap4/NGSieveClient.h b/skyrix-core/NGMime/NGImap4/NGSieveClient.h
new file mode 100644 (file)
index 0000000..d44c720
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __Networking_NGImap4_NGSieveClient_H__
+#define __Networking_NGImap4_NGSieveClient_H__
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGStreams.h>
+#include <NGStreams/NGSocketProtocols.h>
+#include <NGImap4/NGImap4Support.h>
+#include <NGImap4/NGImap4ResponseParser.h>
+
+@class NSMutableArray, NSString, NSNumber, NSDictionary, NSArray;
+@class NGSieveResponseParser, EOQualifier, NGHashMap;
+
+typedef enum {
+  UnConnected_NGSieveState = 1,
+  NonAuthenticated_NGSieveState,
+  Authenticated_NGSieveState,
+} NGSieveState;
+
+@interface NGSieveClient : NSObject
+{
+@protected
+  id<NGActiveSocket>       socket;
+  id<NGExtendedTextStream> text;
+  id<NGSocketAddress>      address;
+  NGImap4ResponseParser    *parser;
+
+  BOOL     isLogin;
+
+  NSString *login;
+  NSString *password;
+
+  BOOL debug;
+}
+
++ (id)clientWithAddress:(id<NGSocketAddress>)_address;
++ (id)clientWithHost:(id)_host;
+
+- (id)initWithHost:(id)_host;
+- (id)initWithAddress:(id<NGSocketAddress>)_address;
+
+// equality
+
+- (BOOL)isEqual:(id)_obj;
+- (BOOL)isEqualToSieveClient:(NGSieveClient *)_obj;
+
+// accessors
+
+- (id<NGActiveSocket>)socket;
+- (id<NGSocketAddress>)address;
+
+// connection
+
+- (NSDictionary *)openConnection;
+- (void)closeConnection;
+- (NSNumber *)isConnected;
+- (void)reconnect;
+
+// commands
+
+- (NSDictionary *)login:(NSString *)_login password:(NSString *)_passwd;
+- (NSDictionary *)logout;
+
+- (NSDictionary *)getScript:(NSString *)_scriptName;
+- (NSDictionary *)putScript:(NSString *)_name script:(NSString *)_script;
+- (NSDictionary *)setActiveScript:(NSString *)_name;
+- (NSDictionary *)deleteScript:(NSString *)_script;
+- (NSDictionary *)listScript:(NSString *)_script;
+
+- (NSString *)description;
+
+@end
+#endif /* __Networking_NGSieve_NGSieveClient_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NGSieveClient.m b/skyrix-core/NGMime/NGImap4/NGSieveClient.m
new file mode 100644 (file)
index 0000000..a25db58
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <unistd.h>
+
+#include "NGSieveClient.h"
+#include "NGImap4Support.h"
+#include "NGImap4ResponseParser.h"
+#include "NSString+Imap4.h"
+#include "imCommon.h"
+#include <sys/time.h>
+
+@interface NGSieveClient(Private)
+
+- (NGHashMap *)processCommand:(NSString *)_command;
+- (NGHashMap *)processCommand:(NSString *)_command logText:(NSString *)_txt;
+
+- (void)sendCommand:(NSString *)_command;
+- (void)sendCommand:(NSString *)_command logText:(NSString *)_txt;
+
+- (NSMutableDictionary *)normalizeResponse:(NGHashMap *)_map;
+- (NSMutableDictionary *)normalizeOpenConnectionResponse:(NGHashMap *)_map;
+- (NSDictionary *)login;
+
+@end
+
+/*"
+**  An implementation of an Imap4 client
+**
+** A folder name always looks like an absolute filename (/inbox/doof) 
+**
+"*/
+
+@implementation NGSieveClient
+
+static int      defaultSievePort = 143;
+static NSNumber *YesNumber = nil;
+static NSNumber *NoNumber  = nil;
+static BOOL     ProfileImapEnabled = NO;
+static BOOL     LOG_PASSWORD       = NO;
+static BOOL     debugImap4         = NO;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  NSUserDefaults *ud;
+  if (didInit) return;
+  didInit = YES;
+  
+  ud = [NSUserDefaults standardUserDefaults];
+  LOG_PASSWORD       = [ud boolForKey:@"SieveLogPassword"];
+  ProfileImapEnabled = [ud boolForKey:@"ProfileImapEnabled"];
+  debugImap4         = [ud boolForKey:@"ImapDebugEnabled"];
+  
+  YesNumber = [[NSNumber numberWithBool:YES] retain];
+  NoNumber  = [[NSNumber numberWithBool:NO] retain];
+}
+
++ (id)clientWithAddress:(id<NGSocketAddress>)_address {
+  return
+    [[(NGSieveClient *)[self alloc] initWithAddress:_address] autorelease];
+}
+
++ (id)clientWithHost:(id)_host {
+  return [[[self alloc] initWithHost:_host] autorelease];
+}
+
+- (id)initWithHost:(id)_host {
+  NGInternetSocketAddress *a;
+  a = [NGInternetSocketAddress addressWithPort:defaultSievePort onHost:_host];
+  return [self initWithAddress:a];
+}
+
+/**"
+ ** designated initializer
+"**/
+
+- (id)initWithAddress:(id<NGSocketAddress>)_address {
+  if ((self = [super init])) {
+    self->address = [_address retain];
+    self->debug = debugImap4;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->text     release];
+  [self->address  release];
+  [self->socket   release];
+  [self->parser   release];
+  [self->login    release];
+  [self->password release];
+  [super dealloc];
+}
+
+/* equality */
+
+- (BOOL)isEqual:(id)_obj {
+  if (_obj == self)
+    return YES;
+  if ([_obj isKindOfClass:[NGSieveClient class]])
+    return [self isEqualToSieveClient:_obj];
+  return NO;
+}
+
+- (BOOL)isEqualToSieveClient:(NGSieveClient *)_obj {
+  if (_obj == self) return YES;
+  if (_obj == nil)  return NO;
+  return [[_obj address] isEqual:self->address];
+}
+
+/* accessors */
+
+- (id<NGActiveSocket>)socket {
+  return self->socket;
+}
+
+- (id<NGSocketAddress>)address {
+  return self->address;
+}
+
+/* connection */
+
+/*"
+** Opens a connection to given Host.
+"*/
+
+- (NSDictionary *)openConnection {
+  struct timeval tv;
+  double         ti = 0.0;
+  
+  if (ProfileImapEnabled) {
+    gettimeofday(&tv, NULL);
+    ti =  (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0);
+  }
+
+  [self->socket release]; self->socket = nil;
+  [self->parser release]; self->parser = nil;
+  [self->text   release]; self->text   = nil;
+  
+  self->socket =
+    [[NGActiveSocket socketConnectedToAddress:self->address] retain];
+  self->text   = 
+    [(NGCTextStream *)[NGCTextStream alloc] initWithSource:self->socket];
+  self->parser = [[NGImap4ResponseParser alloc] initWithStream:self->socket];
+
+  /* receive greeting from server without tag-id */
+
+  if (ProfileImapEnabled) {
+    gettimeofday(&tv, NULL);
+    ti = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0) - ti;
+    fprintf(stderr, "[%s] <openConnection> : time needed: %4.4fs\n",
+           __PRETTY_FUNCTION__, ti < 0.0 ? -1.0 : ti);    
+  }
+  return [self normalizeOpenConnectionResponse:
+               [self->parser parseSieveResponse]];
+}
+
+/*"
+** Check whether stream is already open (could be closed because server-timeout)
+"*/
+
+- (NSNumber *)isConnected {
+  return [NSNumber numberWithBool:
+                     (self->socket == nil)
+                     ? NO : [(NGActiveSocket *)self->socket isAlive]];
+}
+
+/*"
+** Close a consisting connection.
+"*/
+
+- (void)closeConnection {
+  [self->socket close];
+  [self->socket release]; self->socket = nil;
+  [self->text   release]; self->text   = nil; 
+  [self->parser release]; self->parser = nil;
+}
+
+/*"
+** login with plaintext password authenticating
+"*/
+
+- (NSDictionary *)login:(NSString *)_login password:(NSString *)_passwd {
+  if ((_login == nil) || (_passwd == nil))
+    return nil;
+
+  [self->login    release]; self->login    = nil;
+  [self->password release]; self->password = nil;
+  
+  self->login    = [_login  copy];
+  self->password = [_passwd copy];
+  return [self login];
+}
+
+- (void)reconnect {
+  [self closeConnection];  
+  [self openConnection];
+  [self login];
+}
+
+- (NSDictionary *)login {
+  NGHashMap *map  = nil;
+  NSData    *auth;
+  char      *buf;
+  int       bufLen, logLen;
+
+
+  logLen = [self->login cStringLength];
+  bufLen = (logLen*2) + [self->password cStringLength] +2;
+
+  buf = calloc(sizeof(char), bufLen);
+
+  sprintf(buf, "%s %s %s", 
+          [self->login cString], [self->login cString],
+          [self->password cString]);
+  
+  buf[logLen] = '\0';
+  buf[logLen*2+1] = '\0';
+  
+  auth = [NSData dataWithBytesNoCopy:buf length:bufLen];
+  auth = [auth dataByEncodingBase64];
+
+  if (LOG_PASSWORD == 1) {
+    map = [self processCommand:[NSString stringWithFormat:
+                                         @"AUTHENTICATE \"PLAIN\" {%d+}\r\n%s",
+                                         [auth length], [auth bytes]]];
+  }
+  else {
+    map = [self processCommand:[NSString stringWithFormat:
+                                         @"AUTHENTICATE \"PLAIN\" {%d+}\r\n%s",
+                                         [auth length], [auth bytes]]
+                logText:@"AUTHENTICATE \"PLAIN\" {%d+}\r\nLOGIN:PASSWORD\r\n"];
+  }
+  return [self normalizeResponse:map];
+}
+
+/*
+** logout from the connected host and close the connection
+*/
+
+- (NSDictionary *)logout {
+  NGHashMap *map = [self processCommand:@"logout"];
+
+  [self closeConnection];
+  return [self normalizeResponse:map];
+}
+
+- (NSDictionary *)getScript:(NSString *)_scriptName {
+  [self notImplemented:_cmd];
+  return nil;
+}
+
+- (BOOL)isValidScriptName:(NSString *)_name {
+  return ([_name length] == 0) ? NO : YES;
+}
+
+- (NSDictionary *)putScript:(NSString *)_name script:(NSString *)_script {
+  NGHashMap *map;
+  NSString  *s;
+  
+  if (![self isValidScriptName:_name]) {
+    [self logWithFormat:@"%s: missing script-name", __PRETTY_FUNCTION__];
+    return nil;
+  }
+  if ([_script length] == 0) {
+    [self logWithFormat:@"%s: missing script", __PRETTY_FUNCTION__];
+    return nil;
+  }
+  
+  s = [NSString stringWithFormat:
+                  @"PUTSCRIPT \"%@\" {%d+}\r\n%@\r\n",
+                  _name, [_script length], _script];
+  map = [self processCommand:s];
+  return [self normalizeResponse:map];
+}
+
+- (NSDictionary *)setActiveScript:(NSString *)_name {
+  NGHashMap *map;
+  
+  if (![self isValidScriptName:_name]) {
+    NSLog(@"%s: missing script-name", __PRETTY_FUNCTION__);
+    return nil;
+  }
+  map = [self processCommand:
+              [NSString stringWithFormat:@"SETACTIVE \"%@\"\r\n", _name]];
+  return [self normalizeResponse:map];
+}
+
+- (NSDictionary *)deleteScript:(NSString *)_name {
+  NGHashMap *map;
+  NSString  *s;
+
+  if (![self isValidScriptName:_name]) {
+    NSLog(@"%s: missing script-name", __PRETTY_FUNCTION__);
+    return nil;
+  }
+
+  s = [NSString stringWithFormat:@"DELETESCRIPT \"%@\"\r\n", _name];
+  map = [self processCommand:s];
+  return [self normalizeResponse:map];
+}
+- (NSDictionary *)listScript:(NSString *)_script {
+  [self notImplemented:_cmd];
+  return nil;
+}
+
+
+/*
+** Filter for all responses
+**       result  : NSNumber (response result)
+**       exists  : NSNumber (number of exists mails in selectet folder
+**       recent  : NSNumber (number of recent mails in selectet folder
+**       expunge : NSArray  (message sequence number of expunged mails
+                             in selectet folder)
+*/
+
+- (NSMutableDictionary *)normalizeResponse:(NGHashMap *)_map {
+  id keys[3], values[3];
+  NSParameterAssert(_map != nil);
+  
+  keys[0] = @"RawResponse"; values[0] = _map;
+  keys[1] = @"result";
+  values[1] = [[_map objectForKey:@"ok"] boolValue] ? YesNumber : NoNumber;
+  return [NSMutableDictionary dictionaryWithObjects:values
+                              forKeys:keys count:2];
+}
+
+/*
+** filter for open connection
+*/
+
+- (NSDictionary *)normalizeOpenConnectionResponse:(NGHashMap *)_map {
+  NSMutableDictionary *result;
+  NSString *tmp;
+
+  result = [self normalizeResponse:_map];
+  
+  if (![[[_map objectEnumeratorForKey:@"ok"] nextObject] boolValue])
+    return result;
+
+  if ((tmp = [_map objectForKey:@"implementation"]))
+    [result setObject:tmp forKey:@"server"];
+  if ((tmp = [_map objectForKey:@"sieve"]))
+    [result setObject:tmp forKey:@"capabilities"];
+  return result;
+}
+
+
+/*
+** filter for list
+**       list : NSDictionary (folder name as key and flags as value)
+*/
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<Imap4Client[0x%08X]: socket=%@>",
+                     (unsigned)self, [self socket]];
+}
+
+/* Private Methods */
+
+- (BOOL)handleProcessException:(NSException *)_exception
+  repetitionCount:(int)_cnt
+{
+  if (_cnt > 3) {
+    [_exception raise];
+    return NO;
+  }
+  
+  if ([_exception isKindOfClass:[NGIOException class]]) {
+    [self logWithFormat:
+            @"WARNING: got exception try to restore connection: %@", 
+            _exception];
+    return YES;
+  }
+  if ([_exception isKindOfClass:[NGImap4ParserException class]]) {
+    [self logWithFormat:
+            @"WARNING: Got Parser-Exception try to restore connection: %@",
+            _exception];
+    return YES;
+  }
+  
+  [_exception raise];
+  return NO;
+}
+
+- (void)waitPriorReconnectWithRepetitionCount:(int)_cnt {
+  unsigned timeout;
+  
+  timeout = _cnt * 4;
+  [self logWithFormat:@"reconnect to %@, sleeping %d seconds ...",
+          self->address, timeout];
+  sleep(timeout);
+  [self logWithFormat:@"reconnect ..."];
+}
+
+- (NGHashMap *)processCommand:(NSString *)_command logText:(NSString *)_txt {
+  NGHashMap *map          = nil;
+  BOOL      repeatCommand = NO;
+  int       repeatCnt     = 0;
+
+  struct timeval tv;
+  double         ti = 0.0;
+
+  if (ProfileImapEnabled) {
+    gettimeofday(&tv, NULL);
+    ti =  (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0);
+    fprintf(stderr, "{");
+  }
+  do { /* TODO: shouldn't that be a while loop? */
+    if (repeatCommand) {
+      if (repeatCnt > 1)
+        [self waitPriorReconnectWithRepetitionCount:repeatCnt];
+      
+      repeatCnt++;
+      [self reconnect];
+      repeatCommand = NO;
+    }
+    
+    NS_DURING {
+      [self sendCommand:_command logText:_txt];
+      map = [self->parser parseSieveResponse];
+    }
+    NS_HANDLER {
+      repeatCommand = [self handleProcessException:localException
+                            repetitionCount:repeatCnt];
+    }
+    NS_ENDHANDLER;    
+  }
+  while (repeatCommand);
+  
+  if (ProfileImapEnabled) {
+    gettimeofday(&tv, NULL);
+    ti = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0) - ti;
+    fprintf(stderr, "}[%s] <Send Command> : time needed: %4.4fs\n",
+           __PRETTY_FUNCTION__, ti < 0.0 ? -1.0 : ti);    
+  }
+  
+  return map;
+}
+
+- (NGHashMap *)processCommand:(NSString *)_command {
+  return [self processCommand:_command logText:_command];
+}
+
+- (void)sendCommand:(NSString *)_command logText:(NSString *)_txt {
+  NSString *command       = nil;
+
+  command = _command;
+
+  if (self->debug)
+    fprintf(stderr, "C: %s\n", [_txt cString]);
+  
+  [self->text writeString:command];
+  [self->text writeString:@"\r\n"];
+  [self->text flush];
+}
+
+- (void)sendCommand:(NSString *)_command {
+  [self sendCommand:_command logText:_command];
+}
+
+@end /* NGSieveClient */
diff --git a/skyrix-core/NGMime/NGImap4/NSString+Imap4.h b/skyrix-core/NGMime/NGImap4/NSString+Imap4.h
new file mode 100644 (file)
index 0000000..cecde8e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGImap4_NSString_Imap4_H__
+#define __NGImap4_NSString_Imap4_H__
+
+#import <Foundation/NSString.h>
+
+@interface NSString(Imap4)
+
+/* WARNING: this should encode/decode to NSData !!! */
+- (NSString *)stringByEncodingImap4FolderName;
+- (NSString *)stringByDecodingImap4FolderName;
+
+- (NSString *)stringByEscapingImap4Password;
+
+@end
+
+#endif /* __NGImap4_NSString_Imap4_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/NSString+Imap4.m b/skyrix-core/NGMime/NGImap4/NSString+Imap4.m
new file mode 100644 (file)
index 0000000..e49966c
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGImap4/NSString+Imap4.h>
+#include "imCommon.h"
+
+/* TODO: NOT UNICODE SAFE (uses cString) */
+
+static void _encodeToModifiedUTF7(unsigned char *_buf, int encLen,
+                                  unsigned char **result_,
+                                  unsigned int *cntRes_);
+static int _decodeOfModifiedUTF7(char *_target, unsigned _targetLen,
+                                 unsigned *usedBytes_ ,
+                                 unsigned char **buffer_,
+                                 int *bufLen_, int maxBuf);
+
+@implementation NSString(Imap4)
+
+- (NSString *)stringByEncodingImap4FolderName {
+  /* doof.d& --> doof.d&- */
+  unsigned char *buf    = NULL;
+  unsigned char *res    = NULL;
+  unsigned int  len     = 0;
+  unsigned int  cnt     = 0;
+  unsigned int  cntRes  = 0;
+  NSString      *result = nil;
+
+  len = [self cStringLength];
+  buf = calloc(len + 3, sizeof(char));  
+  res = calloc((len * 6) + 3, sizeof(char));  
+  buf[len] = '\0';
+  res[len * 6] = '\0';  
+  [self getCString:buf];
+
+  while (cnt < len) {
+    int c = buf[cnt];
+    if (((c > 31) && (c < 38)) ||
+        ((c > 38) && (c < 127))) {
+      res[cntRes++] = c;
+      cnt++;
+    }
+    else {
+      if (c == '&') {
+        res[cntRes++]  = '&';
+        res[cntRes++]  = '-';
+        cnt++;
+      }
+      else {
+        int start;
+
+        start = cnt;
+
+        while (cnt < (len - 1)) {
+          int c = buf[cnt + 1];
+          if (((c > 31) && (c < 38)) ||
+              ((c > 38) && (c < 127)) ||
+              (c == '&')) {
+            break;
+          }
+          else {
+            cnt++;
+          }
+        }
+        {
+          unsigned length;
+          
+          res[cntRes++] = '&';
+
+          length = cnt - start + 1;
+          
+          _encodeToModifiedUTF7(buf+start, length, &res, &cntRes);
+          
+          res[cntRes++] = '-';
+          cnt++;
+        }
+      }
+    }
+  }
+  result = [[NSString alloc] initWithCStringNoCopy:res
+                               length:cntRes
+                               freeWhenDone:YES];
+  free(buf); buf = NULL;
+  return [result autorelease];
+}
+
+- (NSString *)stringByDecodingImap4FolderName {
+  /* doof/d&- --> doof/d& */
+  unsigned char *buf    = NULL;
+  unsigned char *res    = NULL;
+  unsigned int  len     = 0;
+  unsigned int  cnt     = 0;
+  unsigned int  cntRes  = 0;
+  NSString      *result = nil;
+
+  if ((len = [self cStringLength]) == 0)
+    return @"";
+  
+  buf = calloc(len + 3, sizeof(unsigned char));
+  res = calloc(len + 3, sizeof(unsigned char));  
+  buf[len] = '\0';
+  res[len] = '\0';
+  
+  [self getCString:buf];
+  
+  while (cnt < (len - 1)) { /* &- */
+    unsigned char c;
+
+    c = buf[cnt];
+
+    if (c == '&') {
+      if (buf[cnt + 1] == '-') {
+        res[cntRes++] = '&';
+        cnt += 2;
+      }
+      else {
+        unsigned      usedBytes = 0;
+        unsigned char *buffer;
+        int           maxBuf, bufLen;
+
+        cnt++;
+        maxBuf = 511;
+        bufLen = 0;
+        buffer = calloc(maxBuf + 3, sizeof(char));
+        
+        if (_decodeOfModifiedUTF7(buf + cnt, len - cnt, &usedBytes , &buffer,
+                                  &bufLen, maxBuf) == 0) {
+          int  cnt1;
+          
+          cnt1 = 0;
+          while (cnt1 < bufLen) {
+            res[cntRes++] = buffer[cnt1++];
+          }
+          cnt += usedBytes;
+        }
+        else {
+          NSCAssert(NO, @"couldn't decode UTF-7 ..");
+        }
+        free(buffer); buffer = NULL;
+      }
+    }
+    else {
+      res[cntRes++] = c;
+      cnt++;
+    }
+  }
+  if (cnt < len)
+    res[cntRes++] = buf[cnt++];
+  
+  result = [[NSString alloc] initWithCStringNoCopy:res
+                             length:cntRes
+                             freeWhenDone:YES];
+  free(buf); buf = NULL;
+  return [result autorelease];
+}
+
+- (NSString *)stringByEscapingImap4Password {
+  // TODO: Unicode, perf
+  unsigned char       *buffer;
+  const unsigned char *chars;
+  unsigned            len, i, j;
+
+  len   = [self cStringLength];
+  chars = [self cString];
+
+  buffer = calloc(len * 2 + 2, sizeof(char));
+  buffer[len * 2] = '\0';
+
+  for (i = 0, j = 0; i < len; i++, j++) {
+      BOOL conv = NO;
+      
+      if (chars[i] <= 0x1F || chars[i] > 0x7F) {
+        conv = YES;
+      }
+      switch (chars[i]) {
+        case '(':
+        case ')':
+        case '{':
+        case ' ':
+        case '%':
+        case '*':
+        case '"':
+        case '\\':
+          conv = YES;
+      }
+
+      if (conv) {
+        buffer[j++] = '\\';
+      }
+      buffer[j] = chars[i];
+    }
+  
+  return [[(NSString *)[NSString alloc] 
+            initWithCString:buffer length:j] autorelease];
+}
+
+@end /* NSString(Imap4) */
+
+static void writeChunk(int _c1, int _c2, int _c3, int _pads,
+                       unsigned char **result_,
+                       unsigned int *cntRes_);
+
+static int getChar(int _cnt, int *cnt_, unsigned char *_buf) {
+  int result;
+  
+  if ((_cnt % 2)) {
+    result = _buf[*cnt_];
+    (*cnt_)++;
+  }
+  else {
+    result = 0;
+  }
+  return result;
+}
+static void _encodeToModifiedUTF7(unsigned char *_buf, int encLen,
+                                  unsigned char **result_, unsigned int *cntRes_)
+{
+  int c1, c2, c3;
+  int cnt, cntAll;
+
+  cnt    = 0;
+  cntAll = 0;
+
+  while (cnt < encLen) {
+    c1 = getChar(cntAll++, &cnt, _buf);
+    if (cnt == encLen) {
+      writeChunk(c1, 0, 0, 2, result_, cntRes_);
+    }
+    else {
+      c2 = getChar(cntAll++, &cnt, _buf);
+      if (cnt == encLen) {
+        writeChunk(c1, c2, 0, 1, result_, cntRes_);
+      }
+      else {
+        c3 = getChar(cntAll++, &cnt, _buf);
+        writeChunk(c1, c2, c3, 0, result_, cntRes_);
+      }
+    }
+  }
+}
+
+/* check metamail output for correctness */
+
+static unsigned char basis_64[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static void writeChunk(int c1, int c2, int c3, int pads, unsigned char **result_,
+                       unsigned int *cntRes_) {
+  unsigned char c;
+
+  c = basis_64[c1>>2];
+  (*result_)[*cntRes_] = c;
+  (*cntRes_)++;
+  
+  c = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
+
+  (*result_)[*cntRes_] = c;
+  (*cntRes_)++;
+  
+  
+  if (pads == 2) {
+    ;
+  }
+  else if (pads) {
+    c = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
+    (*result_)[*cntRes_] = c;
+    (*cntRes_)++;
+  }
+  else {
+    c = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
+    
+    (*result_)[*cntRes_] = c;
+    (*cntRes_)++;
+    
+    c = basis_64[c3 & 0x3F];
+    (*result_)[*cntRes_] = c;
+    (*cntRes_)++;
+  }
+}
+
+static char index_64[128] = {
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
+    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
+    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+};
+
+#define char64(c)  (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
+
+static int _decodeOfModifiedUTF7(char *_target, unsigned _targetLen,
+                                 unsigned *usedBytes_ , unsigned char **buffer_,
+                                 int *bufLen_, int maxBuf)
+{
+  int c1, c2, c3, c4;
+  unsigned int cnt;
+  
+  for (cnt = 0; cnt < _targetLen; ) {
+    c1 = '=';
+    c2 = '=';
+    c3 = '=';
+    c4 = '=';
+
+    c1 = _target[cnt++];
+
+    if (c1 == '-') {
+      (*usedBytes_)++;
+      return 0;
+    }
+    if (cnt < _targetLen)
+      c2 = _target[cnt++];
+
+    if (c2 == '-') {
+      (*usedBytes_)+=2;
+      return 0;
+    }
+    
+    (*usedBytes_) += 2;
+
+    if (cnt < _targetLen) {
+      c3 = _target[cnt++];
+      (*usedBytes_)++;
+    }
+
+    if (cnt < _targetLen) {
+      c4 = _target[cnt++];
+      if (c3 != '-')
+        (*usedBytes_)++;
+    }
+    
+    if (c2 == -1 || c3 == -1 || c4 == -1) {
+      fprintf(stderr, "Warning: base64 decoder saw premature EOF!\n");
+      return 0;
+    }
+
+    if (c1 == '=' || c2 == '=') {
+      continue;
+    }
+    
+    c1 = char64(c1);
+    c2 = char64(c2);
+    
+    if (*bufLen_ < maxBuf) {
+      unsigned char c;
+
+      c = ((c1<<2) | ((c2&0x30)>>4));
+
+      if (c) {
+        (*buffer_)[*bufLen_] = c;
+        *bufLen_ = *bufLen_ + 1;
+      }
+    }
+    if (c3 == '-') {
+      return 0;
+    }
+    else if (c3 == '=') {
+      continue;
+    } else {
+      
+      c3 = char64(c3);
+
+      if (*bufLen_ < maxBuf) {
+        unsigned char c;
+        c = (((c2&0XF) << 4) | ((c3&0x3C) >> 2));
+        if (c) {
+          (*buffer_)[*bufLen_] = c;
+          *bufLen_ = *bufLen_ + 1;
+        }
+      }
+
+      if (c4 == '-') {
+        return 0;
+      }
+      else if (c4 == '=') {
+        continue;
+      } else {
+        c4 = char64(c4);
+
+        if (*bufLen_ < maxBuf) {
+          unsigned char c;
+
+          c = (((c3&0x03) <<6) | c4);
+          if (c) {
+            (*buffer_)[*bufLen_] = c;
+            (*bufLen_) = (*bufLen_) + 1;
+          }
+        }
+      }
+    }
+  }
+  return 0;
+}
diff --git a/skyrix-core/NGMime/NGImap4/README b/skyrix-core/NGMime/NGImap4/README
new file mode 100644 (file)
index 0000000..820d063
--- /dev/null
@@ -0,0 +1,106 @@
+# $Id$
+
+NGImap4 Library
+  Copyright (C) 2000-2004 SKYRIX Software AG
+  
+  NSUserDefaults
+  ==============
+
+    Default                 | Type   | Example Value
+    =============================================================
+    ImapDebugEnabled          BOOL     NO
+    ProfileImapEnabled        BOOL     NO
+    ShowNonExistentFolder     BOOL     NO
+    FetchNewUnseenMessagesInSubFoldersOnDemand BOOL NO
+    ImapLogEnabled
+    ImapPreventConnectionExceptions
+    NGImapMaxConnectionCount
+    ImapDebugQualifierGeneration
+
+  Notifications
+  =============
+  
+    NGImap4DataSource
+    - postDataSourceChangedNotification
+    - observes: 
+      - LSWImapMailWasDeleted          (resets DS)
+      - LSWImapMailFolderWasDeleted     (resets DS + folder)
+      - LSWImapMailFlagsChanged                (post DS changed notification)
+    
+    NGImap4Message
+    - Update: this is now coordinated using a specialized notification 
+              mechanism attached to the folder
+    - used to broadcast changes to messages with the same uid?
+      - not reliable across accounts?!
+    - posts: _addFlagNotificationName + _removeFlagNotificationName
+      NGImap4MessageAddFlag_    + folder + uid
+      NGImap4MessageRemoveFlag_ + folder + uid
+    - observes: the above notifications (object is nil)
+
+    NGImap4Folder
+    - used to broadcast changes to folders with the same path?
+      - not reliable across accounts?!
+    - -resetFolder posts:     "NGImap4FolderReset_"    + [self absoluteName]
+    - -resetSubFolders posts: "NGImap4SubFolderReset_" + [self absoluteName]
+    - observes: the above notifications on its own folder name (object is nil)
+
+  Parsing/Fetching
+  ================
+
+  a) NGImap4Client issues fetch command and parses "raw" response
+  b) NGImap4ResponseNormalizer "normalizes" the "raw" response to a dict (?)
+  c) NGImap4Folder issues _buildMessagesFromFetch:
+     - 'fetch' dict key contains array of 'normalized raw' entries
+     - uses NGMimeMessageParser and NGDataStream to parse 'raw' header
+
+  Notes
+  =====
+
+  - folder hierarchies are cached and synchronized using a somewhat broken
+    notification system
+    - you can trigger a reload of the subfolders by calling -resetSubFolders,
+      eg on the context's -serverRoot or -inboxFolder
+      - TODO: find out whether this is a deep operation
+    - resetSpecialFolders might also help, this 'nils' the default folders
+
+  Class-Hierachy
+  ==============
+
+    NSObject
+      NGImap4Client
+      NGImap4Context            <NGImap4ResponseReceiver>
+      NGImap4Folder
+      NGImap4Message
+      NGImap4ResponseParser
+      NGImap4FolderFlags
+      NGImap4FolderMailRegistry
+
+      NSException
+        NGImap4Exception
+          NGImap4ConnectionException
+          NGImap4ParserException
+          NGImap4ResponseException
+          NGImap4SearchException
+
+      EODataSource
+        NGImap4DataSource
+
+      NGFileManager
+        NGImap4FileManager
+
+  Categories
+  ==========
+
+  Protocols
+  =========
+
+    NGImap4ResponseReceiver
+
+  Log Topics
+  ==========
+
+--
+Helge Hess (helge.hess@opengroupware.org)
+created, MDlink online service center, 1998-10-22
+updated 2002-07-09
+updated 2004-01-15
diff --git a/skyrix-core/NGMime/NGImap4/SxCore-NGImap4Flow.graffle b/skyrix-core/NGMime/NGImap4/SxCore-NGImap4Flow.graffle
new file mode 100644 (file)
index 0000000..53516c6
--- /dev/null
@@ -0,0 +1,4186 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CanvasColor</key>
+       <dict>
+               <key>a</key>
+               <string>1</string>
+               <key>w</key>
+               <string>1</string>
+       </dict>
+       <key>ColumnAlign</key>
+       <integer>0</integer>
+       <key>ColumnSpacing</key>
+       <real>3.600000e+01</real>
+       <key>GraphDocumentVersion</key>
+       <integer>2</integer>
+       <key>GraphicsList</key>
+       <array>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2369</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 rootFolder}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>5.712345e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{698.143, 216}</string>
+                               <string>{702, 270}</string>
+                               <string>{612, 360}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2314</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{593, 501}, {170, 15}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>2368</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 by helge.hess@opengroupware.org}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2367</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 currentFolder}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>3.028804e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{686.571, 216}</string>
+                               <string>{621, 270}</string>
+                               <string>{604.636, 360}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2314</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2366</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 imapContext}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>3.361621e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{639, 207}</string>
+                               <string>{549, 207}</string>
+                               <string>{450, 207}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2314</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2318</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2365</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 oldUnseenMessages}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>6.675532e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{374.25, 486}</string>
+                               <string>{333, 441}</string>
+                               <string>{182.571, 387}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledDoubleArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2361</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2318</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2364</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 messages}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>4.175532e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{348, 486}</string>
+                               <string>{279, 468}</string>
+                               <string>{169.65, 387}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledDoubleArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2361</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2363</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 folder}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>4.270993e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{403.714, 486}</string>
+                               <string>{531, 432}</string>
+                               <string>{592.714, 378}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2361</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2362</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 subfolders}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>4.958656e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{627, 378}</string>
+                               <string>{675, 396}</string>
+                               <string>{684, 360}</string>
+                               <string>{647.902, 364.011}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{324, 486}, {117, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2361</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4FileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGImap4DataSource}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2319</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2360</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 parser}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>6.553997e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{354.157, 108}</string>
+                               <string>{437.776, 63}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2326</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2319</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2359</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 parser}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>5.183397e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{594, 52.5681}</string>
+                               <string>{522, 53.3071}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2358</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{594, 45}, {81, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2358</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Client.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGSieveClient}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2356</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2357</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 bodyStructureContent}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>6.346480e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{162, 387}</string>
+                               <string>{198, 459}</string>
+                               <string>{150.75, 486}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2318</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 486}, {72, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2356</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NSDictionary}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{9, 432}, {63, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2355</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundRect</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NSURL}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2354</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 folder}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.303191e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{213.076, 386.55}</string>
+                               <string>{450, 423}</string>
+                               <string>{577.5, 378}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>Arrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2318</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2352</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2353</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 headers}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>6.187268e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{141.094, 369}</string>
+                               <string>{61.0156, 324}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2318</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{9, 306}, {72, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2352</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGHashMap}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2351</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 context}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>5.607856e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{160.8, 369}</string>
+                               <string>{207, 243}</string>
+                               <string>{361.812, 214.852}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2318</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2349</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2350</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 rawData}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>4.547872e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{114.75, 387}</string>
+                               <string>{72, 396}</string>
+                               <string>{51.75, 369}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2318</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{9, 351}, {72, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2349</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NSData}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2346</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2348</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 bodyStructure}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>8.856383e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{154.269, 387}</string>
+                               <string>{138.212, 432}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2318</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2345</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2347</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 message}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>6.409575e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{152.975, 369}</string>
+                               <string>{130.496, 324}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2318</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 432}, {72, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2346</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGMimePart}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{90, 306}, {72, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2345</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGMimePart}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2311</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2344</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 parentFolder}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>8.111702e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{558, 371.647}</string>
+                               <string>{450, 378}</string>
+                               <string>{412.5, 333}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2343</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 context}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>4.654255e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{601.2, 360}</string>
+                               <string>{576, 234}</string>
+                               <string>{449.035, 213.953}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2341</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2342</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 url}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>5.496911e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{613.249, 378}</string>
+                               <string>{696.139, 450}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{675, 450}, {63, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2341</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundRect</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NSURL}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2340</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 context}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>3.962766e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{288, 342}</string>
+                               <string>{288, 270}</string>
+                               <string>{388.286, 216}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2310</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2339</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 subfolders}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.356383e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{312, 360}</string>
+                               <string>{432, 405}</string>
+                               <string>{561.436, 377.75}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledDoubleArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2310</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2337</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2338</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 address}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>6.711531e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{336.899, 108}</string>
+                               <string>{333.9, 63}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2326</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{297, 36}, {72, 27}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2337</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundRect</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGSocket\
+Address}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2336</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 context}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>5.311450e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{336.24, 126}</string>
+                               <string>{331.2, 162}</string>
+                               <string>{390.24, 198}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>Arrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2326</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2307</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2335</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 responseReceiver}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>4.381792e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{320.4, 126}</string>
+                               <string>{252, 162}</string>
+                               <string>{252, 189}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledDoubleArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2326</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2332</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2334</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 text}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>6.478347e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{305.906, 108}</string>
+                               <string>{201.257, 78.5482}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2326</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2330</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2333</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 source}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>4.899368e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{162, 81}</string>
+                               <string>{162, 126}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2332</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{117, 54}, {90, 27}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2332</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundRect</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGExtended\
+TextStream}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2330</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2331</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 socket}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>5.183075e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{297.102, 122.01}</string>
+                               <string>{197.362, 134.922}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2326</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{126, 126}, {72, 27}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2330</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundRect</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGActive\
+Socket}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2328</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2329</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 lastException}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>7.845744e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{414, 198}</string>
+                               <string>{513, 99}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{477, 81}, {90, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2328</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundRect</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NSException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2326</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2327</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{398.261, 198}</string>
+                               <string>{344.251, 126}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{297, 108}, {81, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2326</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Client.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGImap4Client}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2310</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2325</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 serverRoot}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>2.739362e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{397.685, 216}</string>
+                               <string>{295.312, 342}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2324</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 trashFolder\
+sentFolder\
+draftsFolder\
+inboxFolder}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>3.803191e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{423, 216}</string>
+                               <string>{549, 279}</string>
+                               <string>{597.6, 360}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>Arrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2311</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2323</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 selectedFolder}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>2.632979e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{412, 216}</string>
+                               <string>{468, 288}</string>
+                               <string>{420.75, 315}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2311</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2322</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 folderForRefresh}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>7.526596e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{405, 216}</string>
+                               <string>{405, 315}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledDoubleArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2320</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2321</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 connectionDictionary}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>7.367021e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{422.053, 198}</string>
+                               <string>{541.421, 135}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{522, 108}, {90, 27}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2320</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundRect</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 Connection\
+Dictionary}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{387, 45}, {135, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2319</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4ResponseParser.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGImap4ResponseParser}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 369}, {117, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2318</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Message.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGImap4Message}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{675, 135}, {81, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2317</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0</string>
+                                               <key>g</key>
+                                               <string>0</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs20 \cf0 NGFileManager}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{675, 162}, {81, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2316</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0.5</string>
+                                               <key>g</key>
+                                               <string>1</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGFileManager}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2316</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2315</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{715.5, 153}</string>
+                               <string>{715.5, 162}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0</string>
+                                               <key>g</key>
+                                               <string>0</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2317</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{639, 198}, {117, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2314</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4FileManager.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGImap4FileManager}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2314</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2313</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{711, 180}</string>
+                               <string>{702, 198}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2316</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{558, 360}, {90, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2312</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Folder.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGImap4Folder}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{360, 315}, {90, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2311</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0</string>
+                                               <key>g</key>
+                                               <string>0</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs20 \cf0 NGImap4Folder}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{234, 342}, {108, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2310</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4ServerRoot.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGImap4ServerRoot}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2312</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2309</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{442.344, 333}</string>
+                               <string>{562.846, 360.002}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0</string>
+                                               <key>g</key>
+                                               <string>0</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2311</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2310</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2308</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{375.979, 333}</string>
+                               <string>{331.99, 342}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0</string>
+                                               <key>g</key>
+                                               <string>0</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2311</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{180, 189}, {144, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2307</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0</string>
+                                               <key>g</key>
+                                               <string>0</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs20 \cf0 NGImap4ResponseReceiver}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{360, 198}, {90, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>2306</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Context.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NGImap4Context}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2306</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2305</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{324, 201.717}</string>
+                               <string>{360, 204.065}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>a</key>
+                                               <string>1</string>
+                                               <key>b</key>
+                                               <string>0</string>
+                                               <key>g</key>
+                                               <string>0</string>
+                                               <key>r</key>
+                                               <string>1</string>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2307</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{8.75, 10}, {117, 36}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>2304</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\b\fs48 \cf0 NGImap4}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2355</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2303</integer>
+                       <key>Labels</key>
+                       <array>
+                               <dict>
+                                       <key>FixedWidth</key>
+                                       <real>2.300000e+01</real>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs20 \cf0 url}</string>
+                                       </dict>
+                                       <key>LabelVisible</key>
+                                       <string>YES</string>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>7.302684e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>1.000000e-01</real>
+                               </dict>
+                               <dict>
+                                       <key>Label</key>
+                                       <dict>
+                                               <key>Align</key>
+                                               <integer>0</integer>
+                                       </dict>
+                                       <key>Offset</key>
+                                       <real>0.000000e+00</real>
+                                       <key>Position</key>
+                                       <real>9.000000e-01</real>
+                               </dict>
+                       </array>
+                       <key>Points</key>
+                       <array>
+                               <string>{141.25, 387}</string>
+                               <string>{57.2917, 432}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>2318</integer>
+                       </dict>
+               </dict>
+       </array>
+       <key>GridInfo</key>
+       <dict/>
+       <key>HPages</key>
+       <integer>1</integer>
+       <key>ImageCounter</key>
+       <integer>1</integer>
+       <key>IsPalette</key>
+       <string>NO</string>
+       <key>Layers</key>
+       <array>
+               <dict>
+                       <key>Lock</key>
+                       <string>NO</string>
+                       <key>Name</key>
+                       <string>Layer 1</string>
+                       <key>Print</key>
+                       <string>YES</string>
+                       <key>View</key>
+                       <string>YES</string>
+               </dict>
+       </array>
+       <key>LayoutInfo</key>
+       <dict>
+               <key>AutoAdjust</key>
+               <string>YES</string>
+               <key>MagneticFieldCenter</key>
+               <string>{0, 0}</string>
+       </dict>
+       <key>MagnetsEnabled</key>
+       <string>YES</string>
+       <key>PageBreakColor</key>
+       <dict>
+               <key>a</key>
+               <string>1</string>
+               <key>w</key>
+               <string>0.666667</string>
+       </dict>
+       <key>PageBreaks</key>
+       <string>YES</string>
+       <key>PageSetup</key>
+       <data>
+       BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE
+       hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpFJKEhIQITlNT
+       dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE
+       mZkLTlNQYXBlclNpemWGkoSEhAdOU1ZhbHVlAJSEASqEhAx7X05TU2l6ZT1mZn2cgQNK
+       gQJThpKEmZkZTlNQcmludFJldmVyc2VPcmllbnRhdGlvboaShISECE5TTnVtYmVyAJ2b
+       hIQBc54AhpKEmZkUTlNWZXJ0aWNhbFBhZ2luYXRpb26GkoShm6KeAIaShJmZFE5TVmVy
+       dGljYWxseUNlbnRlcmVkhpKEoZuingGGkoSZmQ5OU1BNUGFnZUZvcm1hdIaShISEBk5T
+       RGF0YQCUl4ElUIQHWzk1NTJjXTw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVU
+       Ri04Ij8+CjwhRE9DVFlQRSBwbGlzdCBQVUJMSUMgIi0vL0FwcGxlIENvbXB1dGVyLy9E
+       VEQgUExJU1QgMS4wLy9FTiIgImh0dHA6Ly93d3cuYXBwbGUuY29tL0RURHMvUHJvcGVy
+       dHlMaXN0LTEuMC5kdGQiPgo8cGxpc3QgdmVyc2lvbj0iMS4wIj4KPGRpY3Q+Cgk8a2V5
+       PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LkZvcm1hdHRpbmdQcmludGVyPC9rZXk+
+       Cgk8ZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5
+       PgoJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCTxr
+       ZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5pdGVtQXJyYXk8L2tleT4KCQk8YXJyYXk+
+       CgkJCTxkaWN0PgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5Gb3Jt
+       YXR0aW5nUHJpbnRlcjwva2V5PgoJCQkJPHN0cmluZz5ocDIyMDBkdG48L3N0cmluZz4K
+       CQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jbGllbnQ8L2tleT4KCQkJCTxz
+       dHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQkJPGtleT5j
+       b20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8L2tleT4KCQkJCTxkYXRlPjIwMDQt
+       MDEtMTVUMTU6NTQ6MzNaPC9kYXRlPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlj
+       a2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJPGludGVnZXI+MDwvaW50ZWdlcj4KCQkJPC9k
+       aWN0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+Cgk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdl
+       Rm9ybWF0LlBNSG9yaXpvbnRhbFJlczwva2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBw
+       bGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5w
+       cmludGluZ21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNr
+       ZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFycmF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+Y29t
+       LmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1Ib3Jpem9udGFsUmVzPC9rZXk+CgkJCQk8
+       cmVhbD43LjIwMDAwMDAwMDAwMDAwMGUrMDE8L3JlYWw+CgkJCQk8a2V5PmNvbS5hcHBs
+       ZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQk8c3RyaW5nPmNvbS5hcHBsZS5w
+       cmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRp
+       Y2tldC5tb2REYXRlPC9rZXk+CgkJCQk8ZGF0ZT4yMDA0LTAxLTE1VDE0OjQ3OjQzWjwv
+       ZGF0ZT4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tl
+       eT4KCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJ
+       PC9kaWN0PgoJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTU9yaWVudGF0
+       aW9uPC9rZXk+Cgk8ZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3Jl
+       YXRvcjwva2V5PgoJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3Ry
+       aW5nPgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5pdGVtQXJyYXk8L2tleT4K
+       CQk8YXJyYXk+CgkJCTxkaWN0PgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZv
+       cm1hdC5QTU9yaWVudGF0aW9uPC9rZXk+CgkJCQk8aW50ZWdlcj4yPC9pbnRlZ2VyPgoJ
+       CQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJCQkJPHN0
+       cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJCQk8a2V5PmNv
+       bS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGRhdGU+MjAwNC0w
+       MS0xNVQxNTo1NDozM1o8L2RhdGU+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNr
+       ZXQuc3RhdGVGbGFnPC9rZXk+CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQk8L2Rp
+       Y3Q+CgkJPC9hcnJheT4KCTwvZGljdD4KCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VG
+       b3JtYXQuUE1TY2FsaW5nPC9rZXk+Cgk8ZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmlu
+       dC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5n
+       bWFuYWdlcjwvc3RyaW5nPgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5pdGVt
+       QXJyYXk8L2tleT4KCQk8YXJyYXk+CgkJCTxkaWN0PgoJCQkJPGtleT5jb20uYXBwbGUu
+       cHJpbnQuUGFnZUZvcm1hdC5QTVNjYWxpbmc8L2tleT4KCQkJCTxyZWFsPjEuMDAwMDAw
+       MDAwMDAwMDAwZSswMDwvcmVhbD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tl
+       dC5jbGllbnQ8L2tleT4KCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdl
+       cjwvc3RyaW5nPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8
+       L2tleT4KCQkJCTxkYXRlPjIwMDQtMDEtMTVUMTU6NTQ6MzNaPC9kYXRlPgoJCQkJPGtl
+       eT5jb20uYXBwbGUucHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJPGludGVn
+       ZXI+MDwvaW50ZWdlcj4KCQkJPC9kaWN0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+Cgk8a2V5
+       PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNVmVydGljYWxSZXM8L2tleT4KCTxk
+       aWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jcmVhdG9yPC9rZXk+CgkJ
+       PHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJPGtleT5j
+       b20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheTwva2V5PgoJCTxhcnJheT4KCQkJ
+       PGRpY3Q+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNVmVydGlj
+       YWxSZXM8L2tleT4KCQkJCTxyZWFsPjcuMjAwMDAwMDAwMDAwMDAwZSswMTwvcmVhbD4K
+       CQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jbGllbnQ8L2tleT4KCQkJCTxz
+       dHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQkJPGtleT5j
+       b20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8L2tleT4KCQkJCTxkYXRlPjIwMDQt
+       MDEtMTVUMTQ6NDc6NDNaPC9kYXRlPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlj
+       a2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJPGludGVnZXI+MDwvaW50ZWdlcj4KCQkJPC9k
+       aWN0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+Cgk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdl
+       Rm9ybWF0LlBNVmVydGljYWxTY2FsaW5nPC9rZXk+Cgk8ZGljdD4KCQk8a2V5PmNvbS5h
+       cHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCTxzdHJpbmc+Y29tLmFwcGxl
+       LnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRp
+       Y2tldC5pdGVtQXJyYXk8L2tleT4KCQk8YXJyYXk+CgkJCTxkaWN0PgoJCQkJPGtleT5j
+       b20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTVZlcnRpY2FsU2NhbGluZzwva2V5PgoJ
+       CQkJPHJlYWw+MS4wMDAwMDAwMDAwMDAwMDBlKzAwPC9yZWFsPgoJCQkJPGtleT5jb20u
+       YXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJCQkJPHN0cmluZz5jb20uYXBw
+       bGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmlu
+       dC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGRhdGU+MjAwNC0wMS0xNVQxNTo1NDoz
+       M1o8L2RhdGU+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbGFn
+       PC9rZXk+CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQk8L2RpY3Q+CgkJPC9hcnJh
+       eT4KCTwvZGljdD4KCTxrZXk+Y29tLmFwcGxlLnByaW50LnN1YlRpY2tldC5wYXBlcl9p
+       bmZvX3RpY2tldDwva2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFn
+       ZUZvcm1hdC5QTUFkanVzdGVkUGFnZVJlY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5j
+       b20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmluZz5jb20u
+       YXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJCTxrZXk+Y29tLmFwcGxlLnBy
+       aW50LnRpY2tldC5pdGVtQXJyYXk8L2tleT4KCQkJPGFycmF5PgoJCQkJPGRpY3Q+CgkJ
+       CQkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTUFkanVzdGVkUGFnZVJl
+       Y3Q8L2tleT4KCQkJCQk8YXJyYXk+CgkJCQkJCTxyZWFsPjAuMDAwMDAwMDAwMDAwMDAw
+       ZSswMDwvcmVhbD4KCQkJCQkJPHJlYWw+MC4wMDAwMDAwMDAwMDAwMDBlKzAwPC9yZWFs
+       PgoJCQkJCQk8cmVhbD41LjcwOTYwMDIxOTcyNjU2MmUrMDI8L3JlYWw+CgkJCQkJCTxy
+       ZWFsPjguMTc0NDAwMDI0NDE0MDYyZSswMjwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJ
+       CTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3Ry
+       aW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCQk8a2V5PmNv
+       bS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJCTxkYXRlPjIwMDQt
+       MDEtMTVUMTU6NTQ6MzNaPC9kYXRlPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRp
+       Y2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQkJ
+       PC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmlu
+       dC5QYWdlRm9ybWF0LlBNQWRqdXN0ZWRQYXBlclJlY3Q8L2tleT4KCQk8ZGljdD4KCQkJ
+       PGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmlu
+       Zz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJCTxrZXk+Y29tLmFw
+       cGxlLnByaW50LnRpY2tldC5pdGVtQXJyYXk8L2tleT4KCQkJPGFycmF5PgoJCQkJPGRp
+       Y3Q+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTUFkanVzdGVk
+       UGFwZXJSZWN0PC9rZXk+CgkJCQkJPGFycmF5PgoJCQkJCQk8cmVhbD4tMS4yMDM5OTc4
+       MDI3MzQzNzVlKzAxPC9yZWFsPgoJCQkJCQk8cmVhbD4tMS4yNTU5OTk3NTU4NTkzNzVl
+       KzAxPC9yZWFsPgoJCQkJCQk8cmVhbD41LjgyOTYwMDIxOTcyNjU2MmUrMDI8L3JlYWw+
+       CgkJCQkJCTxyZWFsPjguMjk0NDAwMDI0NDE0MDYyZSswMjwvcmVhbD4KCQkJCQk8L2Fy
+       cmF5PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jbGllbnQ8L2tleT4K
+       CQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJ
+       CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJCTxk
+       YXRlPjIwMDQtMDEtMTVUMTU6NTQ6MzNaPC9kYXRlPgoJCQkJCTxrZXk+Y29tLmFwcGxl
+       LnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4wPC9pbnRl
+       Z2VyPgoJCQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5h
+       cHBsZS5wcmludC5QYXBlckluZm8uUE1Db25zdHJhaW5lZFBhcGVyPC9rZXk+CgkJPGRp
+       Y3Q+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jcmVhdG9yPC9rZXk+CgkJ
+       CTxzdHJpbmc+Q1VQU19DUEw8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQu
+       dGlja2V0Lml0ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGljdD4KCQkJCQk8
+       a2V5PmNvbS5hcHBsZS5wcmludC5QYXBlckluZm8uUE1Db25zdHJhaW5lZFBhcGVyPC9r
+       ZXk+CgkJCQkJPGZhbHNlLz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQu
+       Y2xpZW50PC9rZXk+CgkJCQkJPHN0cmluZz5DVVBTX0NQTDwvc3RyaW5nPgoJCQkJCTxr
+       ZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+
+       MjAwNC0wMS0xNVQxNTo1NDoyNFo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUucHJp
+       bnQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjE8L2ludGVnZXI+
+       CgkJCQk8L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+Y29tLmFwcGxl
+       LnByaW50LlBhcGVySW5mby5QTVBhcGVyTmFtZTwva2V5PgoJCTxkaWN0PgoJCQk8a2V5
+       PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCQk8c3RyaW5nPkNV
+       UFNfQ1BMPC9zdHJpbmc+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5pdGVt
+       QXJyYXk8L2tleT4KCQkJPGFycmF5PgoJCQkJPGRpY3Q+CgkJCQkJPGtleT5jb20uYXBw
+       bGUucHJpbnQuUGFwZXJJbmZvLlBNUGFwZXJOYW1lPC9rZXk+CgkJCQkJPHN0cmluZz5p
+       c28tYTQ8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xp
+       ZW50PC9rZXk+CgkJCQkJPHN0cmluZz5DVVBTX0NQTDwvc3RyaW5nPgoJCQkJCTxrZXk+
+       Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+MjAw
+       NC0wMS0xNVQxNTo1NDoyNFo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQu
+       dGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjE8L2ludGVnZXI+CgkJ
+       CQk8L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+Y29tLmFwcGxlLnBy
+       aW50LlBhcGVySW5mby5QTVVuYWRqdXN0ZWRQYWdlUmVjdDwva2V5PgoJCTxkaWN0PgoJ
+       CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCQk8c3Ry
+       aW5nPkNVUFNfQ1BMPC9zdHJpbmc+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tl
+       dC5pdGVtQXJyYXk8L2tleT4KCQkJPGFycmF5PgoJCQkJPGRpY3Q+CgkJCQkJPGtleT5j
+       b20uYXBwbGUucHJpbnQuUGFwZXJJbmZvLlBNVW5hZGp1c3RlZFBhZ2VSZWN0PC9rZXk+
+       CgkJCQkJPGFycmF5PgoJCQkJCQk8cmVhbD4wLjAwMDAwMDAwMDAwMDAwMGUrMDA8L3Jl
+       YWw+CgkJCQkJCTxyZWFsPjAuMDAwMDAwMDAwMDAwMDAwZSswMDwvcmVhbD4KCQkJCQkJ
+       PHJlYWw+OC4xNzQ0MDAwMjQ0MTQwNjJlKzAyPC9yZWFsPgoJCQkJCQk8cmVhbD41Ljcw
+       OTYwMDIxOTcyNjU2MmUrMDI8L3JlYWw+CgkJCQkJPC9hcnJheT4KCQkJCQk8a2V5PmNv
+       bS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQkJPHN0cmluZz5DVVBT
+       X0NQTDwvc3RyaW5nPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2RE
+       YXRlPC9rZXk+CgkJCQkJPGRhdGU+MjAwNC0wMS0xNVQxNTo1NDoyNFo8L2RhdGU+CgkJ
+       CQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJ
+       CTxpbnRlZ2VyPjE8L2ludGVnZXI+CgkJCQk8L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9k
+       aWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVVuYWRqdXN0ZWRQ
+       YXBlclJlY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlj
+       a2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmluZz5DVVBTX0NQTDwvc3RyaW5nPgoJCQk8
+       a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJh
+       eT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5Q
+       TVVuYWRqdXN0ZWRQYXBlclJlY3Q8L2tleT4KCQkJCQk8YXJyYXk+CgkJCQkJCTxyZWFs
+       Pi0xLjI1NTk5OTc1NTg1OTM3NWUrMDE8L3JlYWw+CgkJCQkJCTxyZWFsPi0xLjIwMDAw
+       MDAwMDAwMDAwMGUrMDE8L3JlYWw+CgkJCQkJCTxyZWFsPjguMjk0NDAwMDI0NDE0MDYy
+       ZSswMjwvcmVhbD4KCQkJCQkJPHJlYWw+NS44MzAwMDAwMDAwMDAwMDBlKzAyPC9yZWFs
+       PgoJCQkJCTwvYXJyYXk+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNs
+       aWVudDwva2V5PgoJCQkJCTxzdHJpbmc+Q1VQU19DUEw8L3N0cmluZz4KCQkJCQk8a2V5
+       PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJCTxkYXRlPjIw
+       MDQtMDEtMTVUMTU6NTQ6MjRaPC9kYXRlPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50
+       LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4xPC9pbnRlZ2VyPgoJ
+       CQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5w
+       cmludC5QYXBlckluZm8ucHBkLlBNUGFwZXJOYW1lPC9rZXk+CgkJPGRpY3Q+CgkJCTxr
+       ZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jcmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+
+       Q1VQU19DUEw8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lml0
+       ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5h
+       cHBsZS5wcmludC5QYXBlckluZm8ucHBkLlBNUGFwZXJOYW1lPC9rZXk+CgkJCQkJPHN0
+       cmluZz5BNDwvc3RyaW5nPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5j
+       bGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPkNVUFNfQ1BMPC9zdHJpbmc+CgkJCQkJPGtl
+       eT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8L2tleT4KCQkJCQk8ZGF0ZT4y
+       MDA0LTAxLTE1VDE1OjU0OjI0WjwvZGF0ZT4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmlu
+       dC50aWNrZXQuc3RhdGVGbGFnPC9rZXk+CgkJCQkJPGludGVnZXI+MTwvaW50ZWdlcj4K
+       CQkJCTwvZGljdD4KCQkJPC9hcnJheT4KCQk8L2RpY3Q+CgkJPGtleT5jb20uYXBwbGUu
+       cHJpbnQuUHJpbnRTZXR0aW5ncy5QTVBhcGVyQWRkZWRUb1N1Ym1lbnU8L2tleT4KCQk8
+       ZGljdD4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4K
+       CQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJCTxr
+       ZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5pdGVtQXJyYXk8L2tleT4KCQkJPGFycmF5
+       PgoJCQkJPGRpY3Q+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQuUHJpbnRTZXR0aW5n
+       cy5QTVBhcGVyQWRkZWRUb1N1Ym1lbnU8L2tleT4KCQkJCQk8dHJ1ZS8+CgkJCQkJPGtl
+       eT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJCQkJCTxzdHJpbmc+
+       Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQkJCTxrZXk+Y29tLmFw
+       cGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+MjAwNC0wMS0x
+       NVQxNTo1NDoyOFo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0
+       LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCQk8L2Rp
+       Y3Q+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRp
+       Y2tldC5BUElWZXJzaW9uPC9rZXk+CgkJPHN0cmluZz4wMC4yMDwvc3RyaW5nPgoJCTxr
+       ZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5wcml2YXRlTG9jazwva2V5PgoJCTxmYWxz
+       ZS8+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LnR5cGU8L2tleT4KCQk8c3Ry
+       aW5nPmNvbS5hcHBsZS5wcmludC5QYXBlckluZm9UaWNrZXQ8L3N0cmluZz4KCTwvZGlj
+       dD4KCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5BUElWZXJzaW9uPC9rZXk+Cgk8
+       c3RyaW5nPjAwLjIwPC9zdHJpbmc+Cgk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQu
+       cHJpdmF0ZUxvY2s8L2tleT4KCTxmYWxzZS8+Cgk8a2V5PmNvbS5hcHBsZS5wcmludC50
+       aWNrZXQudHlwZTwva2V5PgoJPHN0cmluZz5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1h
+       dFRpY2tldDwvc3RyaW5nPgo8L2RpY3Q+CjwvcGxpc3Q+CoaShJmZD05TUHJpbnRBbGxQ
+       YWdlc4aSoJKEmZkLTlNQYXBlck5hbWWGkoSZmQJBNIaShJmZFU5TSG9yaXpvbmFsUGFn
+       aW5hdGlvboaShKGbop4AhpKEmZkWTlNIb3Jpem9udGFsbHlDZW50ZXJlZIaSppKEmZkJ
+       TlNQcmludGVyhpKEhIQJTlNQcmludGVyAJSShJmZCWhwMjIwMGR0boaGkoSZmQhOU0Nv
+       cGllc4aShKGbhIQBU6IBhpKEmZkPTlNTY2FsaW5nRmFjdG9yhpKEoZuEhAFmowGGkoSZ
+       mQ1OU1JpZ2h0TWFyZ2luhpKEoZu5oySGkoSZmQ5OU0JvdHRvbU1hcmdpboaShKGbuaMk
+       hpKEmZkMTlNMZWZ0TWFyZ2luhpKEoZu5oySGkoSZmQtOU1RvcE1hcmdpboaShKGbuaMk
+       hpKEmZkKTlNMYXN0UGFnZYaShKGbhJeXgn////+GkoSZmQtOU0ZpcnN0UGFnZYaShKGb
+       tqIBhpKEmZkNTlNPcmllbnRhdGlvboaShKGbop4BhoaG
+       </data>
+       <key>RowAlign</key>
+       <integer>0</integer>
+       <key>RowSpacing</key>
+       <real>3.600000e+01</real>
+       <key>VPages</key>
+       <integer>1</integer>
+       <key>WindowInfo</key>
+       <dict>
+               <key>Frame</key>
+               <string>{{-4, 56}, {913, 794}}</string>
+               <key>VisibleRegion</key>
+               <string>{{-64, -97}, {898, 717}}</string>
+               <key>Zoom</key>
+               <string>1</string>
+       </dict>
+</dict>
+</plist>
diff --git a/skyrix-core/NGMime/NGImap4/TODO b/skyrix-core/NGMime/NGImap4/TODO
new file mode 100644 (file)
index 0000000..a30bbc4
--- /dev/null
@@ -0,0 +1,54 @@
+# $Id: TODO,v 1.10 2004/04/02 12:42:33 helge Exp $
+
+- OGo bug #660
+
+- SkyImapMailActions does mail discovery based on an IMAP4 URL
+  /OpenGroupware/x/SkyImapMailActions/viewImapMail?listName=MailList&\
+    url=imap%3A%2F%2Flocalhost%2FINBOX%2FGNUstep%2F999
+  - this uses NGImap4Message +messageWithURL:context:
+  - TODO: should be invoke messageWithURL:context: on context?
+    - done: NGImap4Message constructors deprecated, added new ctx methods
+
+- check qualifier processing, eg "flags='unseen'" etc
+
+NGImap4Message
+==============
+- find out who actually instantiates a message
+- find out whether a folder is always attached to a message
+  OpenGroupware.org> find . -name "*.m" -exec grep -l " initWithUid" \{\} \;
+  ./SOPE/skyrix-core/NGMime/NGImap4/NGImap4Folder.m
+  ./SOPE/skyrix-core/NGMime/NGImap4/NGImap4Message.m
+
+- where is NGImap4Message referenced?:
+  - skyrix-core/NGMime/NGImap4
+  - WebUI/Common/BaseUI/SkyFavorites (why?)
+    - calculates a "favorite" drag type - might use the entityName of the gid?
+    - does not use message GID for activation
+  - WebUI/Mailer/OGoWebMail
+  - SandStorm/skymaild/DirectAction+Mail.m
+
+NGImap4Folder
+=============
+- replace notification center
+- make flags array a specialized object, use bits for flag storage?
+  - persistent custom flags are possible in Cyrus? (eg junk?)
+- document flags array
+- maybe add a "folderstate" object containing 'exists', 'recent', 'unseen'
+- remove all that message-cache thing?!
+
+NGImap4Context
+==============
+- document content of capability header in @interface
+- find out about -folderForRefresh
+- move sentFolderName, trashFolderName to a separate Imap4ContextConfig object
+- add a more generic "capability" object
+  - move canSort, canQuota into that
+- make "int" bitfield flags
+
+NGImap4Client
+=============
+- move "normalize" stuff to a separate "normalizer" object
+- use NSURL for keeping connection info?
+- use bitfield flags for debug, useSSL or isLogin
+- can we remove the dependency of the back-link to NGImap4Context?
+- should have an async API!
diff --git a/skyrix-core/NGMime/NGImap4/imCommon.h b/skyrix-core/NGMime/NGImap4/imCommon.h
new file mode 100644 (file)
index 0000000..0d4f498
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGImap4_common_H__
+#define __NGImap4_common_H__
+
+#import <Foundation/Foundation.h>
+
+#if LIB_FOUNDATION_LIBRARY
+#  include <extensions/exceptions/GeneralExceptions.h>
+#elif NeXT_Foundation_LIBRARY
+#  import <NGExtensions/NGObjectMacros.h>
+#  import <NGExtensions/NSString+Ext.h>
+#  if 0 /* no more FoundationExt */
+#    import <FoundationExt/GeneralExceptions.h>
+#    import <FoundationExt/NSException.h>
+#    import <FoundationExt/MissingMethods.h>
+#  endif
+#endif
+
+#include <EOControl/EOControl.h>
+#include <NGExtensions/NGExtensions.h>
+#include <NGStreams/NGStreams.h>
+#include <NGStreams/NGNet.h>
+#include <NGMime/NGMime.h>
+#include <NGMail/NGMail.h>
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+#  ifndef sel_eq
+#    define sel_eq(__A__,__B__) (__A__==__B__)
+#  endif
+#endif
+
+@interface NSObject(OSXHacks)
+- (void)subclassResponsibility:(SEL)_acmd;
+- (void)notImplemented:(SEL)_acmd;
+@end
+
+@interface NSException (setUserInfo)
+- (id)setUserInfo:(NSDictionary *)_info;
+@end
+
+#endif /* __NGImap4_common_H__ */
diff --git a/skyrix-core/NGMime/NGImap4/imTimeMacros.h b/skyrix-core/NGMime/NGImap4/imTimeMacros.h
new file mode 100644 (file)
index 0000000..93c23fd
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+#if 0
+
+#include <sys/time.h>
+
+#define TIME_START(_timeDescription) \
+{ \
+  struct timeval tv; \
+  double ti; \
+  char *timeDescription; \
+  unsigned int vm, vm1; \
+  \
+  *(&vm) = 0; \
+  *(&ti) = 0; \
+  {\
+    NSAutoreleasePool *p__1; \
+    p__1 = [NSAutoreleasePool new]; \
+    vm = [[NSProcessInfo processInfo] virtualMemorySize]; \
+    [p__1 release];\
+  }\
+  timeDescription = _timeDescription; \
+  gettimeofday(&tv, NULL); \
+  ti =  (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0 ); \
+  fprintf(stderr, "{"); \
+
+
+#define TIME_END gettimeofday(&tv, NULL); \
+  gettimeofday(&tv, NULL); \
+  { \
+    NSAutoreleasePool *p__1 = [NSAutoreleasePool new]; \
+    vm1 = [[NSProcessInfo processInfo] virtualMemorySize]; \
+    [p__1 release]; \
+  }; \
+  ti = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0) - ti; \
+  fprintf(stderr,\
+          "}%s: <%s> : time needed: %4.4fs memory wasted %d absolut"\
+          " %d\n", __PRETTY_FUNCTION__, timeDescription, \
+          ti < 0.0 ? -1.0 : ti, vm1 - vm, vm1); \
+}
+
+#else
+
+#define TIME_START(_timeDescription)
+
+#define TIME_END
+
+#endif
diff --git a/skyrix-core/NGMime/NGMail/.cvsignore b/skyrix-core/NGMime/NGMail/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-core/NGMime/NGMail/COPYING b/skyrix-core/NGMime/NGMail/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-core/NGMime/NGMail/ChangeLog b/skyrix-core/NGMime/NGMail/ChangeLog
new file mode 100644 (file)
index 0000000..970022f
--- /dev/null
@@ -0,0 +1,226 @@
+2004-07-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMBoxReader.m: fixed a gcc 3.4 warning (v4.2.170)
+
+2004-06-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMailAddressParser.m: added stronger typing for gcc 3.4 (v4.2.161)
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGMailAddressParser.m: major code cleanups, cache YES number, cache
+         NSString class (v4.2.160)
+
+2004-02-10  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * NGMBoxReader.m, NGPop3Client.m, NGSmtpClient.m: fixed compilation 
+         warnings on OSX (v4.2.151)
+       
+2004-02-08  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.150
+
+       * NGMimeMessageGenerator.m: expose _base64Encoding function (should
+         be some category?)
+
+       * GNUmakefile, NGMimeMessageGenerator.m: moved body generators to
+         separate source files
+
+Wed Jun 11 11:15:48 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeMessageParser: use unicode, use named encoding to encode 
+         header fields (if default 
+         'UseFoundationStringEncodingForMimeHeader' = YES, libFoundation 
+         string encoding will be used (v4.2.113)
+Wed May 14 12:58:44 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeMessageParser.m: code cleanups, fix a decode quoted printable 
+         bug (sometimes last char was ignored) (v4.2.107)
+
+2003-04-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeMessageGenerator.m, NGMimeMessageParser.m: some gcc 3.3 
+         signed/unsigned warnings fixed (v4.2.97)
+
+       * NGPop3Client.m: some gcc 3.3 signed/unsigned warnings fixed (v4.2.96)
+
+Mon Feb 17 18:21:33 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeMessageParser: add NGMimeRfc822BodyParser, 
+         add delegate method bodyParserForPart: to call the 
+         NGMimeRfc822BodyParser (v4.2.86)
+
+Mon Jan 27 19:13:34 2003    <jan@skyrix.com>
+
+       * NGMimeMessageGenerator.m: code cleanups, use disk blob handling from
+         NGMime (v4.2.73)
+
+Tue Jan 21 18:16:46 2003    <jan@skyrix.com>
+
+       * NGMimeMessageParser.m: increase version (NGMimePartParser got 
+         new instance vars) (v4.2.70)
+
+2003-01-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeMessageParser.h: added some docu to header
+
+Mon Oct 21 16:15:58 2002  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeMessageParser.m: remove logs (v4.2.26)
+
+2002-08-15  Helge Hess  <helge.hess@skyrix.com>
+       
+       * NGMimeMessageParser.m: fixed decoding of quoted printable fields,
+         which was completly broken after the last change by JR :-( Still
+         to be tested ...
+         (v4.2.21) fixes SuSE Bug 17579
+       
+       * NGMimeMessageParser.m: some cleanups, changed some "char" variables
+         to "unsigned char", do not allocate buffer on stack, but in the heap,
+         use NSStringClass more often, moved decoding code in an NSData
+         category to make testing easier
+         Note: the changed from 2002-07-10 probably broke umlaut handling,
+         SuSE Bug 17579 (added a small tool in samples which reproduces the
+         problem)
+
+- 2002-07-23 v4.2.19 (hh)
+- 2002-07-17 v4.2.18 (jr)
+- 2002-07-17 v4.2.17 (hh)
+
+2002-07-10  Jan Reichmann  <jr@skyrix.com>
+
+       * NGMimeMessageParser.m: added optimization, got a 100% gain for
+         listing IMAP folders
+
+- 2002-07-10 v4.2.16 (hh) [before the changes above were applied ???]
+- 2002-07-09 v4.2.15 (hh) [extracted from CVS]
+- 2002-07-09 v4.2.14 (hh) [extracted from CVS]
+
+2002-07-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeMessageParser.m: use NGMimeType string->charset decoding,
+         fixes a bug with uppercase charset names
+
+- 2002-07-08 v4.2.13 (hh) [extracted from CVS]
+- 2002-07-08 v4.2.12 (hh) [extracted from CVS]
+
+2002-07-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeMessage.m: fixed a (non-serious) bug in +initialize (wasn't 
+         properly protected against multiple calls), some cleanup
+
+- 2002-06-13 v4.2.11 (jr) [extracted from CVS]
+- 2002-06-11 v4.2.10 (jr) [extracted from CVS]
+- 2002-06-10 v4.2.9  (jr) [extracted from CVS]
+- 2002-06-10 v4.2.8  (jr) [extracted from CVS]
+
+Mon Jun 10 20:22:20 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMailAddressParser.m: fixed address parsing bug
+       (delete white spaces between phrases) 
+
+Thu Mar 14 15:05:53 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMailAddressParser.m: fixed mail-address parsing bug
+
+Thu Nov  1 16:08:13 2001  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMimeMessageGenerator.m: fixed utf8 encoding bug
+
+Thu Oct 25 09:41:00 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeMessageGenerator.m: fixed content-type access bug (use
+         -contentType method to access content types)
+
+Wed Oct 24 15:04:22 2001  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGMimeMessageGenerator.m: add 8 bit Headerfield encoding default
+
+Wed Oct 24 12:54:58 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * updated to SKYRiXgreen version (mail address parser, message gen)
+
+Thu Oct 11 17:32:38 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMimeMessage.m: make string-header safe
+
+Thu Aug  9 13:21:22 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGMBoxReader.m: use -initWithPath:, no use of NGFileUrl anymore
+
+Mon Apr  2 14:09:11 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMailAddressParser.h: add doc
+
+Wed Mar  7 16:46:43 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeMessage.m: fixed body == NSString bug
+
+Mon Mar  5 16:29:40 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeMessage.[hm]: if content-type is nil either text or 
+       application/octet-stream will be returned
+
+Mon Jan 29 16:22:27 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeMessageParser.m: fixed encoding bug
+
+Fri Jan 26 18:53:10 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * NGMimeMessageGenerator.m: fixed content bug
+
+       * NGMailAddressParser.m: fixed outlock mail-address parse bug
+
+Tue Jun  6 17:39:08 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMailAddressParser.[mh]: fixed type bug (char --> unsigned char)
+
+       * NGMailAddressParser.m: fixed parse bug
+
+Tue May 30 15:25:41 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMailAddressParser.m: add parseAddressList (addresses seperated 
+       by comma)
+
+Tue Apr 25 15:29:35 2000  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeMessageGenerator.m (_base64Encoding): if the body should be 
+       encoded and the content-type isn`t exits, 
+       set application/octet-stream as content-type
+
+       * NGMimeMessageGenerator.m (_base64Encoding): if no 
+
+Tue Feb 29 18:27:29 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * MOF3 import
+
+Thu Sep  2 21:09:41 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * added class versions and superclass version checks
+
+Wed Aug 25 13:40:32 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeMessageParser.m: L 93 fixed appendLC bug (set appendLC = NO)
+
+Thu Jul 22 14:28:12 1999  Jan Reichmann  <jan@mdlink.de>
+
+       * NGMimeMessageGenerator.m (_base64Encoding): insert quoted-printable 
+         encoding for text/* Mimeparts
+
+Fri Apr 16 18:00:50 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * mbox parser rewritten for better speed
+
+Mon Apr 12 16:47:33 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * use #include instead of #import, modified headers to support #include
+
+Fri Nov 27 15:37:04 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * started WIN32 port
+
+1998-10-09  Helge Hess  <helge@trex.mdlink.de>
+
+       * created ChangeLog
+
diff --git a/skyrix-core/NGMime/NGMail/GNUmakefile b/skyrix-core/NGMime/NGMail/GNUmakefile
new file mode 100644 (file)
index 0000000..40aaf7c
--- /dev/null
@@ -0,0 +1,53 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT)
+
+SUBPROJECT_NAME = NGMail
+
+NGMail_HEADER_FILES_DIR         = .
+NGMail_HEADER_FILES_INSTALL_DIR = /NGMail
+
+NGMail_HEADER_FILES = \
+       NGMailDecls.h           \
+       NGMail.h                \
+       NGMailAddressList.h     \
+       NGMailAddressParser.h   \
+       NGMailAddress.h         \
+       NGMimeMessage.h         \
+       NGMimeMessageGenerator.h\
+       NGMimeMessageParser.h   \
+       NGMBoxReader.h          \
+       NGPop3Client.h          \
+       NGPop3Support.h         \
+       NGSmtpClient.h          \
+       NGSmtpSupport.h         \
+
+NGMail_OBJC_FILES = \
+       NGMail.m                \
+       NGMailAddressList.m     \
+       NGMailAddressParser.m   \
+       NGMailAddress.m         \
+       NGMimeMessage.m         \
+       NGMimeMessageGenerator.m\
+       NGMimeMessageParser.m   \
+       NGMBoxReader.m          \
+       NGPop3Client.m          \
+       NGPop3Support.m         \
+       NGSmtpClient.m          \
+       NGSmtpSupport.m         \
+       \
+       NGMimeMessageBodyGenerator.m            \
+       NGMimeMessageMultipartBodyGenerator.m   \
+       NGMimeMessageRfc822BodyGenerator.m      \
+       NGMimeMessageTextBodyGenerator.m        \
+
+NGMail_INCLUDE_DIRS += \
+       -I.. -I../..            \
+       -I../../NGStreams/      \
+       -I../../NGExtensions/
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/NGMime/NGMail/NGMBoxReader.h b/skyrix-core/NGMime/NGMail/NGMBoxReader.h
new file mode 100644 (file)
index 0000000..9a0cdd5
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_NGMBoxReader_H__
+#define __NGMail_NGMBoxReader_H__
+
+#import <Foundation/NSEnumerator.h>
+
+#import <NGStreams/NGStreamProtocols.h>
+#import <NGMime/NGPart.h>
+
+@class NSString, NSDictionary;
+
+@interface NGMBoxReader : NSEnumerator
+{
+@protected
+  id<NGByteSequenceStream> source;
+  NSString *lastDate;
+  NSString *separator;
+  BOOL     isEndOfStream;
+
+  IMP readByte;
+}
+
++ (id)readerForMBox:(NSString *)_path;
++ (id)mboxWithSource:(id<NGByteSequenceStream>)_source;
+                      
+- (id)initWithSource:(id<NGByteSequenceStream>)_source;
+
+- (id<NGMimePart>)nextMessage; // same as -nextObject
+
+@end
+
+#endif /* __NGMail_NGMBoxReader_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGMBoxReader.m b/skyrix-core/NGMime/NGMail/NGMBoxReader.m
new file mode 100644 (file)
index 0000000..48ec796
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMBoxReader.h"
+#include "NGMimeMessageParser.h"
+#include "common.h"
+
+@implementation NGMBoxReader
+
++ (int)version {
+  return 2;
+}
+
+static inline int __readByte(NGMBoxReader *self);
+static inline void
+__appendByte(NGMBoxReader *self, NSMutableData *_data, IMP _readBytes, int _c);
+
++ (id)readerForMBox:(NSString *)_path {
+  NGFileStream     *fs;
+  NGBufferedStream *bs;
+
+  fs = [NGFileStream alloc]; /* to keep gcc 3.4 happy */
+  fs = [[fs initWithPath:_path] autorelease];
+  bs = [NGBufferedStream filterWithSource:fs];
+
+  [fs openInMode:NGFileReadOnly];
+
+  return [[(NGMBoxReader *)[self alloc] initWithSource:bs] autorelease];
+}
+
++ (id)mboxWithSource:(id<NGByteSequenceStream>)_in {
+  return [[(NGMBoxReader *)[self alloc] initWithSource:_in] autorelease];
+}
+
+- (id)init {
+  return [self initWithSource:nil];
+}
+
+- (id)initWithSource:(id<NGByteSequenceStream>)_in {
+  if ((self = [super init])) {
+    self->source        = [_in retain];
+    self->isEndOfStream = NO;
+    self->lastDate      = nil;
+    self->separator     = @"From -";
+
+    self->readByte =
+      [self->source respondsToSelector:@selector(methodForSelector:)]
+      ? [(NSObject *)self->source methodForSelector:@selector(readByte)]
+      : NULL;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->source    release];
+  [self->lastDate  release];
+  [self->separator release];
+  self->readByte = NULL;
+  [super dealloc];
+}
+
+- (id<NGMimePart>)nextMessage {
+
+  // Macros
+#define AppendBytes(_buf, _cnt) \
+  appendBytes(msgData, @selector(appendBytes:length:), _buf, _cnt)
+
+#define AppendByte(_c) \
+  __appendByte(self, msgData, appendBytes, _c)
+
+  // Method  
+  NSMutableData       *msgData    = nil;
+  IMP                 appendBytes = NULL;
+
+  const int bufLen = 256;
+  int       bufCnt = 0;
+  int       c      = 0;
+  char      buf[bufLen];  
+  
+  int        sepLength  = [self->separator length];
+  const char *sepStrbuf = NULL;
+
+  sepStrbuf = [self->separator cString];
+  
+  msgData     = [[NSMutableData allocWithZone:[self zone]]
+                                initWithCapacity:4096];
+  
+  appendBytes = [msgData methodForSelector:@selector(appendBytes:length:)];
+  //read from-line
+
+  if (self->isEndOfStream)
+    return nil;
+
+  if (self->lastDate == nil) {
+    // start of MBox from-line length < 255
+    bufCnt = 0;
+    while (bufCnt < sepLength) { // parse form
+      c = __readByte(self);
+      buf[bufCnt++] = c;
+    }
+    if (strncmp(buf, sepStrbuf, sepLength) != 0) {
+      NSLog(@"WARNING: no %@ at begin of MBox %s", self->separator, buf);
+    }
+    bufCnt = 0;
+    while ((c = __readByte(self)) != '\n') { // parse date < 255
+      buf[bufCnt++] = c;
+      if (bufCnt >= bufLen) {
+        NSLog(@"WARNING: too long from-line");
+        break;
+      }
+    }
+    if (buf[bufCnt - 1] == '\r')
+      self->lastDate = [[NSString allocWithZone:[self zone]] initWithCString:buf
+                                                             length:bufCnt-1];
+    else
+      self->lastDate = [[NSString allocWithZone:[self zone]] initWithCString:buf
+                                                             length:bufCnt];
+    bufCnt = 0;
+  }
+  c = -2;
+  do {
+    if (c != -2) {     
+      AppendBytes(buf, bufCnt); // write buffer to data
+      bufCnt = 0;
+      if (c != '\n') { // no end of line
+        AppendByte(c);
+        while ((c = __readByte(self)) != '\n') {
+          buf[bufCnt++] = c;
+          if (bufCnt >= bufLen) {
+            AppendBytes(buf, bufCnt);
+            bufCnt = 0;
+          }
+        }
+        if (bufCnt > 0) {
+          AppendBytes(buf, bufCnt);
+          bufCnt = 0;
+        }
+        AppendByte(c);
+      }
+      else
+        AppendByte(c);
+    }
+    
+    while ((c = __readByte(self)) != '\n' &&
+           bufCnt < sepLength) {        // read oly until seperator length    
+      if (c == -1)
+        break;
+      buf[bufCnt++] = c;
+    }
+    if (c == -1)
+      break;
+  } while (strncmp(buf, sepStrbuf, sepLength) != 0);
+    
+  if (c == -1) {
+    self->isEndOfStream = YES;
+  } 
+  else { // read from-line
+    bufCnt = 0;
+    while ((c = __readByte(self)) != '\n') { // from-line is not longer
+                                     // than 255 ( I hope it :))
+      buf[bufCnt++] = c;
+      if (bufCnt >= bufLen) {
+        NSLog(@"WARNING: too long from-line");
+        break;
+      }
+    }
+    [self->lastDate release];
+    self->lastDate = [[NSString alloc] initWithCString:buf length:bufCnt];
+    bufCnt = 0;
+  }
+
+  if ([msgData length] == 0) // end, no msg data
+    return nil;
+      
+  {  // build result
+    NGMimeMessageParser *parser = nil;
+    NGDataStream        *stream = nil;
+    id<NGMimePart> part;
+
+    *(&part) = nil;
+    
+    parser = [[NGMimeMessageParser alloc] init];
+    stream = [[NGDataStream alloc] initWithData:msgData];
+
+    NS_DURING
+      part = [parser parsePartFromStream:stream];
+    NS_HANDLER {}
+    NS_ENDHANDLER;
+
+    if (part == nil) {
+      fprintf(stderr, "mbox: failed to parse message:\n%s",
+              [[NSString stringWithCString:[msgData bytes]
+                         length:[msgData length]] cString]);
+    }
+
+    [parser  release]; parser  = nil;
+    [stream  release]; stream  = nil;    
+    [msgData release]; msgData = nil;
+    
+    return part;
+  }
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X] source=%@ endOfStream=%@",
+                     NSStringFromClass([self class]), (unsigned)self,
+                     self->source, self->isEndOfStream ? @"YES" : @"NO"];
+}
+
+
+/* functions */
+
+static inline int __readByte(NGMBoxReader *self) {
+  return (self->readByte)
+    ? (int)self->readByte(self->source, @selector(readByte))
+    : [self->source readByte];
+}
+
+static inline void __appendByte(NGMBoxReader *self, NSMutableData *_data,
+                                IMP _readBytes, int _c) {
+  unsigned char c = _c;
+  _readBytes(_data, @selector(appendBytes:length:), &c, 1);
+}
+
+@end
diff --git a/skyrix-core/NGMime/NGMail/NGMail-Info.plist b/skyrix-core/NGMime/NGMail/NGMail-Info.plist
new file mode 100644 (file)
index 0000000..0b20bad
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGMail</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.core.NGMail</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-core/NGMime/NGMail/NGMail.h b/skyrix-core/NGMime/NGMail/NGMail.h
new file mode 100644 (file)
index 0000000..b6f336e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_H__
+#define __NGMail_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMail/NGMBoxReader.h>
+#include <NGMail/NGPop3Client.h>
+#include <NGMail/NGSmtpClient.h>
+#include <NGMail/NGMimeMessage.h>
+#include <NGMail/NGMimeMessageGenerator.h>
+#include <NGMail/NGMimeMessageParser.h>
+#include <NGMail/NGMailAddress.h>
+#include <NGMail/NGMailAddressList.h>
+#include <NGMail/NGMailAddressParser.h>
+
+// kit class
+
+@interface NGMail : NSObject
+@end
+
+#define LINK_NGMail \
+  static void __link_NGMail(void) { \
+    [NGMail self];   \
+    __link_NGMail(); \
+  }
+
+#endif /* __NGMail_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGMail.m b/skyrix-core/NGMime/NGMail/NGMail.m
new file mode 100644 (file)
index 0000000..f6c9f2a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMail.h"
+#include "NGMBoxReader.h"
+#include "NGPop3Client.h"
+#include "NGSmtpClient.h"
+#include "NGMimeMessage.h"
+#include "NGMimeMessageParser.h"
+#include "NGMimeMessageGenerator.h"
+#include "NGMailAddress.h"
+#include "NGMailAddressList.h"
+#include "NGMailAddressParser.h"
+
+#import <NGStreams/NGStreams.h>
+#import <NGMime/NGMime.h>
+
+@implementation NGMail
+
+/*
+  all this is required when compiling on GNUstep without shared
+  libraries. eg gprof profiling only works with static binaries,
+  therefore this is sometimes required. sigh.
+*/
+
+- (void)_staticLinkClasses {
+  [NGMailAddress          self];
+  [NGMailAddressList      self];
+  [NGMailAddressParser    self];
+  [NGMimeMessage          self];
+  [NGMimeMessageParser    self];
+  [NGMimeMessageGenerator self];
+  
+  [NGMBoxReader self];
+  [NGPop3Client self];
+  [NGSmtpClient self];
+
+  [NGMime self];
+}
+
+- (void)_staticLinkModules {
+  [NGStreams class];
+  [NGMime    class];
+}
+
+@end /* NGMail */
diff --git a/skyrix-core/NGMime/NGMail/NGMailAddress.h b/skyrix-core/NGMime/NGMail/NGMailAddress.h
new file mode 100644 (file)
index 0000000..d8a605c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGMail_NGMailAddress_H__
+#define __NGMail_NGMailAddress_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+
+@interface NGMailAddress : NSObject < NSCopying, NSCoding >
+{
+@protected
+  NSString *address;
+  NSString *displayName;
+  NSString *route;
+}
+
++ (id)mailAddressWithAddress:(NSString *)_address
+   displayName:(NSString *)_owner
+   route:(NSString *)_route;
+
+- (id)initWithAddress:(NSString *)_address
+   displayName:(NSString *)_owner
+   route:(NSString *)_route;
+
+// equality
+
+- (BOOL)isEqual:(id)_anObject;
+
+// accessors
+
+- (void)setAddress:(NSString *)_string;
+- (NSString *)address;
+
+- (void)setDisplayName:(NSString *)_displayName;
+- (NSString *)displayName;
+
+- (void)setRoute:(NSString *)_route;
+- (NSString *)route;
+
+@end
+
+#endif /* __NGMail_NGMailAddress_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGMailAddress.m b/skyrix-core/NGMime/NGMail/NGMailAddress.m
new file mode 100644 (file)
index 0000000..37773cb
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$ 
+
+#include "NGMailAddress.h"
+#include "common.h"
+
+@implementation NGMailAddress
+
++ (int)version {
+  return 2;
+}
+
++ (id)mailAddressWithAddress:(NSString *)_address
+  displayName:(NSString *)_owner
+  route:(NSString *)_route
+{
+  return [[[NGMailAddress alloc] initWithAddress:_address
+                                 displayName:_owner
+                                 route:_route] autorelease];
+}
+
+- (id)initWithAddress:(NSString *)_address
+  displayName:(NSString *)_owner
+  route:(NSString *)_route
+{
+  if ((self = [self init])) {
+    NSZone *zone = [self zone];
+    self->address     = [_address copyWithZone:zone];
+    self->displayName = [_owner   copyWithZone:zone];
+    self->route       = [_route   copyWithZone:zone];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->address     release];
+  [self->displayName release];
+  [self->route       release];
+  [super dealloc];  
+}
+
+/* equality */
+
+- (BOOL)isEqual:(id)_anObject {
+  if ([_anObject isKindOfClass:[NGMailAddress class]]) {
+    NGMailAddress *a = _anObject;
+    
+    return (([self->address     isEqualToString:[a address]])   &&
+            ([self->displayName isEqualToString:[a displayName]]) &&
+            ([self->route       isEqualToString:[a route]]));
+  }
+  return NO;
+}
+
+- (unsigned)hash {
+  return [self->address hash];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_encoder {
+  [_encoder encodeObject:address]; 
+  [_encoder encodeObject:displayName];
+  [_encoder encodeObject:route];  
+}
+
+- (id)initWithCoder:(NSCoder *)_decoder {
+  id _address, _displayName, _route;
+  
+  _address     = [_decoder decodeObject];
+  _displayName = [_decoder decodeObject];
+  _route       = [_decoder decodeObject];
+  return [self initWithAddress:_address 
+               displayName:_displayName 
+               route:_route];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[NGMailAddress allocWithZone:_zone] initWithAddress:self->address
+                                              displayName:self->displayName
+                                              route:self->route];
+}
+- (id)copy {
+  return [self copyWithZone:[self zone]];
+}
+
+/* accessors */
+
+- (void)setAddress:(NSString *)_string {
+  ASSIGN(self->address, _string);
+}
+- (NSString *)address {
+  return self->address;
+}
+
+- (void)setDisplayName:(NSString *)_displayName {
+  ASSIGN(self->displayName, _displayName);
+}
+- (NSString *)displayName {
+ return self->displayName;
+}
+
+- (void)setRoute:(NSString *)_route {
+  ASSIGN(self->route, _route);
+}
+- (NSString *)route {
+  return self->route;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"\"%s\" <%s> | route: %s",
+                     [self->displayName cString],
+                     [self->address     cString],
+                     [self->route       cString]];
+}
+
+@end /* NGMailAddress */
diff --git a/skyrix-core/NGMime/NGMail/NGMailAddressList.h b/skyrix-core/NGMime/NGMail/NGMailAddressList.h
new file mode 100644 (file)
index 0000000..bb1a8c1
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_NGMailAddressList_H__
+#define __NGMail_NGMailAddressList_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSMutableSet, NSSet, NSString, NSEnumerator;
+@class NGMailAddress;
+
+@interface NGMailAddressList : NSObject < NSCoding, NSCopying >
+{
+@protected
+  NSMutableSet *addresses;
+  NSString     *groupName;
+}
+
++ (id)mailAddressListWithAddresses:(NSSet *)_addresses
+   groupName:(NSString *)_groupName;
+
+- (id)init;
+- (id)initWithAddresses:(NSSet *)_addresses
+   groupName:(NSString *)_groupName;
+
+// addresses
+
+- (void)addAddress:(NGMailAddress *)_address;
+
+// accessors
+
+- (NSEnumerator *)addresses;
+
+- (void)setGroupName:(NSString *)_name;
+- (NSString *)groupName;
+
+
+@end
+
+#endif /* __NGMail_NGMailAddressList_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGMailAddressList.m b/skyrix-core/NGMime/NGMail/NGMailAddressList.m
new file mode 100644 (file)
index 0000000..536bf63
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMailAddressList.h"
+#include "common.h"
+
+@implementation NGMailAddressList
+
++ (int)version {
+  return 2;
+}
+
++ (id)mailAddressListWithAddresses:(NSSet *)_addresses
+  groupName:(NSString *)_groupName {
+  return [[[NGMailAddressList alloc] initWithAddresses:_addresses
+                                     groupName:_groupName] autorelease];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->addresses = [[NSMutableSet alloc] init];
+  }
+  return self;
+}
+
+- (id)initWithAddresses:(NSSet *)_addresses groupName:(NSString *)_groupName {
+  if ((self = [self init])) {
+    if (_addresses)
+      [self->addresses unionSet:_addresses];
+    self->groupName = [_groupName copy];;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->addresses release];
+  [self->groupName release];
+  [super dealloc];
+}
+
+- (void)addAddress:(NGMailAddress *)_address {
+  [self->addresses addObject:_address];
+}
+
+/* equality */
+
+- (BOOL)isEqual:(id)_anObject {
+  if ([_anObject isKindOfClass:[NGMailAddressList class]]) {
+    BOOL  result = NO;
+    NSSet *set   = nil;
+
+    if (![self->groupName isEqualToString:[_anObject groupName]])
+      return NO;
+
+    set = [[NSSet alloc]
+                  initWithObjectsFromEnumerator:
+                    [(NGMailAddressList *)_anObject addresses]];
+    result = [self->addresses isEqualToSet:set];
+    [set release]; set = nil;
+    return result;
+  }
+  return NO;
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_encoder {
+  [_encoder encodeObject:self->addresses];
+  [_encoder encodeObject:self->groupName];
+}
+
+- (id)initWithCoder:(NSCoder *)_decoder {
+  id _addresses, _groupName;
+
+  _addresses   = [_decoder decodeObject];
+  _groupName   = [_decoder decodeObject];
+
+  return [self initWithAddresses:_addresses groupName:_groupName];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[NGMailAddressList allocWithZone:_zone]
+                             initWithAddresses:self->addresses
+                             groupName:self->groupName];
+}
+
+/* accessors */
+
+- (NSEnumerator *)addresses {
+  return [self->addresses objectEnumerator];
+}
+
+- (void)setGroupName:(NSString *)_name {
+  ASSIGN(self->groupName, _name);
+}
+- (NSString *)groupName {
+ return self->groupName;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"GroupName: %s \n %@\n",
+                     [self->groupName cString],
+                     self->addresses];
+}
+
+@end /* NGMailAddressList */
diff --git a/skyrix-core/NGMime/NGMail/NGMailAddressParser.h b/skyrix-core/NGMime/NGMail/NGMailAddressParser.h
new file mode 100644 (file)
index 0000000..2a53ba5
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGMail_NGMailAddressParser_H__
+#define __NGMail_NGMailAddressParser_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSData, NSString, NSArray;
+@class NGMailAddressList;
+
+/*
+  use RFC 822
+*/
+
+@interface NGMailAddressParser : NSObject
+{
+@private
+  unsigned char *data;
+  int           dataPos;
+  int           errorPos;  
+  int           maxLength;
+}
+
++ (id)mailAddressParserWithString:(NSString *)_string;
++ (id)mailAddressParserWithData:(NSData *)_data;
++ (id)mailAddressParserWithCString:(char *)_cString;
+- (id)initWithCString:(const unsigned char *)_cstr length:(int unsigned)_len;
+
+/* parsing */
+
+- (id)parse; // returns NGMailAddressList/NGMailAddress or nil on error
+- (NSArray *)parseAddressList;
+
+/* error information */
+
+- (int)errorPosition;
+
+@end
+
+#endif /* __NGMail_NGMailAddressParser_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGMailAddressParser.m b/skyrix-core/NGMime/NGMail/NGMailAddressParser.m
new file mode 100644 (file)
index 0000000..c93dfcb
--- /dev/null
@@ -0,0 +1,999 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMailAddressParser.h"
+#include "NGMailAddress.h"
+#include "NGMailAddressList.h"
+#include "common.h"
+
+@interface NGMailAddressParser(PrivateMethods)
+- (id)parseQuotedString:(BOOL)_guestMode;
+- (id)parseWord:(BOOL)_guestMode;
+- (id)parsePhrase:(BOOL)_guestMode;
+- (id)parseLocalPart:(BOOL)_guestMode;
+- (id)parseDomain:(BOOL)_guestMode;
+- (id)parseAddrSpec:(BOOL)_guestMode;
+- (id)parseRouteAddr:(BOOL)_guessMode;
+- (id)parseGroup:(BOOL)_guessMode;
+- (id)parseMailBox:(BOOL)_guessMode;
+- (id)parseAddress:(BOOL)_guessMode;
+@end
+
+@implementation NGMailAddressParser
+
+static Class    StrClass = Nil;
+static NSNumber *yesNum  = nil;
+
++ (int)version {
+  return 2;
+}
+
++ (void)initialize {
+  if (yesNum == nil) yesNum = [[NSNumber numberWithBool:YES] retain];
+  StrClass = [NSString class];
+}
+
+static inline NSString *mkStrObj(const unsigned char *s, unsigned int l) {
+  return [(NSString *)[StrClass alloc] initWithCString:s length:l];
+}
+
+static inline id parseWhiteSpaces(NGMailAddressParser *self, BOOL _guessMode) {
+  id   returnValue = nil;
+  char text[self->maxLength];
+  int  length      = 0;
+  
+  while ((self->data[self->dataPos] == ' ')  ||
+         (self->data[self->dataPos] == '\n')) {
+    text[length++] = ' ';    
+    self->dataPos++;
+  }
+  if (length) {
+    if (_guessMode)
+      returnValue = yesNum;
+    else {
+      returnValue =
+        [[(NSString *)[StrClass alloc] initWithCString:text length:length] 
+          autorelease];
+    }
+  }
+  return returnValue;
+}
+
+
+static inline id parseAtom(NGMailAddressParser *self, BOOL _guessMode) {
+  int  keepPos     = self->dataPos; // keep reference for backtracking
+  id   returnValue = nil;
+  BOOL isAtom      = YES;
+  char text[self->maxLength];  // token text
+  int  length      = 0;  // token text length
+  BOOL done        = NO;
+
+  do {
+    if (self->dataPos == self->maxLength) { // end of text is reached
+      isAtom = (length > 0);
+      done   = YES;
+    }
+    else {
+      register unsigned char c = self->data[self->dataPos];
+      
+      switch (c) {
+        case '(' :  case ')': case '<': case '>':
+        case '@' :  case ',': case ';': case ':':
+        case '\\':  case '"': case '.': case '[':
+        case ']' :  case ' ': case 127:
+          isAtom = (length > 0);
+          done   = YES;
+          break;
+
+        default:
+          if (c < 32) {
+            isAtom = (length > 0);
+            done   = YES;
+          }
+          else {
+            text[length] = c;  // store char in text
+            length++;          // increase text size
+            (self->dataPos)++; // go ahead
+          }
+      }
+    }
+  }
+  while (!done);
+  
+  if (isAtom) {
+    if (_guessMode) {
+      NSCAssert(length > 0, @"no atom with length=0");
+      returnValue =  yesNum;
+    }
+    else {
+      NSCAssert(length > 0, @"no atom with length=0");
+      returnValue = [mkStrObj(text, length) autorelease];
+      NSCAssert([returnValue isKindOfClass:StrClass], @"got no string ..");
+    }
+  }
+  else {
+    self->dataPos = keepPos;
+    returnValue = nil;
+  }
+  return returnValue;
+}
+
+static inline id parseQuotedPair(NGMailAddressParser *self, BOOL _guessMode) {
+  id   returnValue  = nil;
+
+  if ((self->maxLength - (self->dataPos)) < 3) {
+    returnValue =  nil;
+  }
+  else {
+    if (self->data[self->dataPos] == '\\') {
+      self->dataPos = self->dataPos + 2;      
+      if (_guessMode)
+        returnValue = yesNum;
+      else {
+        returnValue =
+          [mkStrObj(&(self->data[self->dataPos - 1]), 1) autorelease];
+      }
+    }
+  }
+  return returnValue;
+}
+
+static inline id parseQText(NGMailAddressParser *self, BOOL _guessMode) {
+  int  keepPos     = self->dataPos; // keep reference for backtracking
+  id   returnValue = nil;
+  BOOL isQText    = YES;
+  char text[self->maxLength];  // token text
+  int  length      = 0;  // token text length
+  BOOL done        = YES;
+
+  do {
+    if (self->dataPos == self->maxLength) { // end of text is reached
+      isQText = (length > 0);
+      done    = YES;
+    }
+    else {
+      register char c = self->data[self->dataPos];
+      
+      switch ((int)c) {
+        case '"' :  
+        case '\\':
+        case 13  :
+          isQText = (length > 0);
+          done    = YES;
+          break;
+
+        default: {
+            text[length] = c;  // store char in text
+            length++;          // increase text size
+            (self->dataPos)++; // go ahead
+          }
+      }
+    }
+  }
+  while (!done);
+
+  if (isQText) {
+    if (_guessMode) {
+      NSCAssert(length > 0, @"no qtext with length=0");
+      returnValue = yesNum;
+    }
+    else {
+      NSCAssert(length > 0, @"no qtext with length=0");
+      returnValue = [mkStrObj(text, length) autorelease];
+      NSCAssert([returnValue isKindOfClass:StrClass],
+               @"got no string ..");
+    }
+  }
+  else {
+    self->dataPos = keepPos;
+    returnValue = nil;
+  }
+  return returnValue;
+}
+
+static inline id parseDText(NGMailAddressParser *self, BOOL _guessMode) {
+  int  keepPos     = self->dataPos; // keep reference for backtracking
+  id   returnValue = nil;
+  BOOL isDText    = YES;
+  char text[self->maxLength];  // token text
+  int  length      = 0;  // token text length
+  BOOL done        = YES;
+
+  do {
+    if (self->dataPos == self->maxLength) { // end of text is reached
+      isDText = (length > 0);
+      done    = YES;
+    }
+    else {
+      register char c = self->data[self->dataPos];
+      
+      switch ((int)c) {
+        case '[':  case ']':
+        case '\\': case 13:
+          isDText = (length > 0);
+          done    = YES;
+          break;
+
+        default: {
+            text[length] = c;  // store char in text
+            length++;          // increase text size
+            (self->dataPos)++; // go ahead
+          }
+      }
+    }
+  }
+  while (!done);
+
+  if (isDText) {
+    if (_guessMode) {
+      NSCAssert(length > 0, @"no dtext with length=0");
+      returnValue =  yesNum;
+    }
+    else {
+      NSCAssert(length > 0, @"no dtext with length=0");
+      returnValue = [mkStrObj(text, length) autorelease];
+      NSCAssert([returnValue isKindOfClass:StrClass],
+               @"got no string ..");
+    }
+  }
+  else {
+    self->dataPos = keepPos;
+    returnValue = nil;
+  }
+  return returnValue;
+}
+
+static inline id parseDomainLiteral(NGMailAddressParser *self, BOOL _guessMode) {
+  int             keepPos          = self->dataPos;
+  id              returnValue      = nil;
+  BOOL            returnOK         = NO;
+
+  if (_guessMode) {
+    if (self->data[self->dataPos] != '[')
+      return nil;
+
+    (self->dataPos)++; // skip starting '"'
+
+    // parses: "suafdjksfd \"sdafsadf"
+    while (self->data[self->dataPos] != ']') {
+      if (self->data[self->dataPos] == '\\') {// skip quoted chars 
+        (self->dataPos)++;
+      }
+      (self->dataPos)++;
+      if (self->dataPos >= self->maxLength) {
+        return nil;
+      }
+    }
+    (self->dataPos)++; // skip closing '"'
+    returnValue = yesNum;
+  }
+  else {
+    if (self->data[self->dataPos++] == '[') {
+      NSMutableString *ms;
+      id result = nil;
+      
+      ms = [NSMutableString stringWithCapacity:10];
+      do {
+        if ((result = parseQuotedPair(self, NO)))
+          [ms appendString:result];
+        else {
+          if ((result = parseDText(self, NO))) 
+            [ms appendString:result];        
+        }
+      }
+      while (result);
+      returnValue = ms;
+      
+      if (self->data[self->dataPos++] == ']')
+        returnOK = YES;
+    }
+    if (!returnOK) {
+      if (returnValue)
+        returnValue = nil;
+      
+      self->dataPos = keepPos;
+    }
+  }
+  return returnValue;
+}
+
+/* constructors */
+
++ (id)mailAddressParserWithString:(NSString *)_string {
+  return [[(NGMailAddressParser *)[self alloc] 
+                                 initWithCString:[_string cString]
+                                 length:[_string cStringLength]] autorelease];
+}
++ (id)mailAddressParserWithData:(NSData *)_data {
+  return [[(NGMailAddressParser *)[self alloc] 
+                                 initWithCString:(char *)[_data bytes]
+                                 length:[_data length]] autorelease];
+}
++ (id)mailAddressParserWithCString:(char *)_cString {
+  return [[(NGMailAddressParser *)[self alloc] 
+                                 initWithCString:_cString
+                                 length:strlen(_cString)] autorelease];
+}
+- (id)initWithCString:(const unsigned char *)_cstr length:(int unsigned)_len {
+  if ((self = [super init])) {
+    self->data      = (unsigned char *)_cstr;
+    self->maxLength = _len;
+    self->dataPos   = 0;
+    self->errorPos  = -1;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithCString:NULL length:0];
+}
+
+- (void)dealloc {
+  self->data      = NULL;
+  self->maxLength = 0;
+  self->dataPos   = 0;
+  [super dealloc];
+}
+
+/* parsing */
+
+- (id)_parseQuotedStringInGuessMode {
+  int keepPos;
+  
+  if (self->data[self->dataPos] != '"')
+    return nil;
+
+  keepPos = self->dataPos;
+  (self->dataPos)++; // skip starting '"'
+
+  // parses: "suafdjksfd \"sdafsadf"
+  while (self->data[self->dataPos] != '"') {
+    if (self->data[self->dataPos] == '\\') /* skip quoted chars  */
+      (self->dataPos)++;
+
+    (self->dataPos)++;
+    if (self->dataPos >= self->maxLength) {
+      self->dataPos = keepPos;
+      return nil;
+    }
+  }
+  (self->dataPos)++; // skip closing '"'
+  return yesNum;
+}
+
+- (id)parseQuotedString:(BOOL)_guessMode {
+  int  keepPos     = self->dataPos;
+  id   returnValue = nil;
+  BOOL returnOK    = NO;
+
+  if (_guessMode)
+    return [self _parseQuotedStringInGuessMode];
+
+  if (data[dataPos++] == '"') {
+    NSMutableString *ms;
+    id result = nil;
+    
+    ms = [NSMutableString stringWithCapacity:10];
+    do {
+      if ((result = parseQuotedPair(self, NO)))
+        [ms appendString:result];
+      else {
+        if ((result = parseQText(self, NO))) 
+          [ms appendString:result];        
+      }
+    }
+    while (result);
+    returnValue = ms;
+    
+    if (data[dataPos++] == '"')
+      returnOK = YES;
+  }
+  if (!returnOK) {
+    returnValue = nil;
+    dataPos = keepPos;
+  }
+  return returnValue;  
+}
+
+- (id)parseWord:(BOOL)_guessMode {
+  id returnValue;
+  
+  if ((returnValue = [self parseQuotedString:_guessMode]) == nil)
+    returnValue = parseAtom(self, _guessMode);
+  
+  return returnValue;
+}
+
+- (id)_parsePhraseInGuessMode {
+  BOOL isPhrase    = NO;
+  id   returnValue = nil;
+  id   result;
+  
+  do {
+    if ((result = parseWhiteSpaces(self, YES))) {
+      isPhrase = YES;
+      continue;
+    }
+    
+    if ((result = [self parseWord:YES])) {
+      isPhrase = YES;
+      [(NSMutableString *)returnValue appendString:result];
+      result = parseWhiteSpaces(self, YES);
+    }
+  }
+  while (result);
+  
+  return !isPhrase ? nil : yesNum;
+}
+
+- (id)parsePhrase:(BOOL)_guessMode {
+  BOOL isPhrase    = NO;
+  id   returnValue = nil;
+  id   result      = nil;      
+  NSString *tmp;
+
+  if (_guessMode)
+    return [self _parsePhraseInGuessMode];
+
+  returnValue = [NSMutableString stringWithCapacity:10];
+  tmp         = nil;
+
+  do {
+    if ((result = parseWhiteSpaces(self, _guessMode))) {
+        tmp = result;
+        ;
+        //        isPhrase = YES;
+        //        [returnValue appendString:result];
+    }
+    else if ((result = [self parseWord:_guessMode])) {
+        isPhrase = YES;
+
+        if (tmp)
+          [(NSMutableString *)returnValue appendString:tmp];
+
+        tmp = nil;
+          
+        [(NSMutableString *)returnValue appendString:result];
+        if (self->dataPos < self->maxLength) {
+          if (self->data[self->dataPos] == '.') {
+            [(NSMutableString *)returnValue appendString:@"."];
+            self->dataPos++;
+          }
+        }
+    }
+  } 
+  while (result);
+  
+  if (!isPhrase || ([returnValue length] == 0))
+      returnValue = nil;
+  
+  return returnValue;
+}
+
+- (id)_parseLocalPartInGuessMode {
+  id result;
+  
+  if (![self parseWord:YES])
+    return nil;
+
+  do {
+    result = nil;
+    if (self->data[self->dataPos] == '.') {
+      self->dataPos++;
+      result = [self parseWord:YES];
+    }
+  }
+  while (result);
+  
+  return yesNum;
+}
+
+- (id)parseLocalPart:(BOOL)_guessMode {
+  NSMutableString *ms;
+  id       returnValue = nil;
+  NSString *result = nil;
+  
+  if (_guessMode)
+    return [self _parseLocalPartInGuessMode];
+  
+  if ((returnValue = [self parseWord:NO]) == nil)
+    return nil;
+  
+  ms = [[returnValue mutableCopy] autorelease];
+      
+  do {
+    if (self->data[self->dataPos] == '.') {
+      self->dataPos++;
+      result = [self parseWord:NO];
+      
+      if (result) {
+       NSAssert([result isKindOfClass:StrClass],
+                @"parseWord should return string");
+            
+       [ms appendString:@"."];
+       [ms appendString:result];
+      }
+    }
+    else
+      result = nil;
+  } 
+  while (result != nil);
+  
+  return ms;
+}
+
+- (id)_parseDomainInGuessMode {
+  id returnValue = nil;
+  id result      = nil;
+
+    returnValue = parseAtom(self, YES);
+    if (!result)
+      returnValue = parseDomainLiteral(self, YES);
+    if (returnValue) {
+      do {
+        result = nil;
+        if (self->data[self->dataPos] == '.') {
+          self->dataPos++;
+          result = parseAtom(self,YES);
+          if (!result)
+            result = parseDomainLiteral(self, YES);
+        }
+      } while (result);
+    }
+    return returnValue;
+}
+
+- (id)parseDomain:(BOOL)_guessMode {
+  NSMutableString *ms;
+  id result;
+
+  if (_guessMode)
+    return [self _parseDomainInGuessMode];
+
+  if ((result = parseAtom(self, NO)) == nil)
+    result = parseDomainLiteral(self, NO);
+  
+  if (result == nil)
+    return nil;
+
+  ms = [[result mutableCopyWithZone:[self zone]] autorelease];
+  do {
+    if (self->data[self->dataPos] == '.') {
+      self->dataPos++;
+          
+      result = parseAtom(self,NO);
+      if (result == nil)
+       result = parseDomainLiteral(self, NO);
+          
+      if (result) {
+       [ms appendString:@"."];
+       [ms appendString:result];
+      }
+    }
+    else
+      result = nil;
+  }
+  while (result);
+  return ms;
+}
+
+- (id)parseAddrSpec:(BOOL)_guessMode {
+  NSMutableString *returnValue  = nil;
+  id   result;
+  int  keepPos      = self->dataPos;
+  BOOL returnStatus = NO;
+  
+  if (_guessMode) {
+    id ret;
+    
+    ret = nil;
+    if ([self parseLocalPart:YES]) {
+      if (self->data[self->dataPos] == '@') {
+        dataPos++;
+        if ([self parseDomain:YES]) {
+          ret = yesNum;
+        }
+      }
+    }
+    return ret;
+  }
+  
+  if ((result = [self parseLocalPart:NO]) != nil) {
+    returnValue = [[result mutableCopy] autorelease];
+    result = nil;
+    
+    if (self->data[self->dataPos] == '@') {
+      self->dataPos++;
+       
+      if ((result = [self parseDomain:NO])) {
+        [returnValue appendString:@"@"];
+        [returnValue appendString:result];
+        returnStatus = YES;
+      }
+    }
+  }
+  if (!returnStatus) {
+      returnValue = nil;
+      dataPos = keepPos;
+  }
+  return returnValue;
+}
+
+- (id)_parseRouteInGuessMode {
+  id   result  = nil;
+  int  keepPos = self->dataPos;
+  BOOL status  = YES;
+    
+  if (self->data[self->dataPos] == '@') {
+    status = NO;
+    if ((result = [self parseDomain:YES]))
+      status = YES;
+  }
+  if (status) {
+    parseWhiteSpaces(self,YES);
+    status = (self->data[self->dataPos] == ':') ? YES : NO;
+  }
+  if (status)
+    return yesNum;
+
+  self->dataPos = keepPos;
+  return nil;
+}
+- (id)parseRoute:(BOOL)_guessMode {
+  NSMutableString *returnValue;
+  id   result      = nil;
+  int  keepPos;
+  BOOL status = YES;
+  
+  if (_guessMode)
+    return [self _parseRouteInGuessMode];
+
+  keepPos     = self->dataPos;
+  returnValue = [NSMutableString stringWithCapacity:10];
+  if (self->data[self->dataPos] == '@') {
+      status = NO;
+      self->dataPos++;
+      if ((result = [self parseDomain:NO])) {
+        status = YES;
+        [returnValue appendString:result];
+      }
+  }
+  if (status) {
+      parseWhiteSpaces(self,NO);
+      if (self->data[self->dataPos] == ':') {
+        status = YES;
+        self->dataPos++;        
+      }
+      else {
+        status = NO;
+      }
+  }
+  if (!status) {
+    returnValue = nil;
+    self->dataPos = keepPos;
+  }
+  return returnValue;
+}
+
+- (id)_parseRouteAddrInGuessMode {
+  int  keepPos      = self->dataPos;
+  id   returnValue  = nil;
+  id   result       = nil;
+  BOOL returnStatus = NO;
+
+    if (self->data[self->dataPos] == '<') {
+      dataPos++;
+      result = [self parseRoute:YES];
+      parseWhiteSpaces(self, YES);      
+      if ((result = [self parseAddrSpec:YES])) {
+        parseWhiteSpaces(self, YES);
+        if (self->data[self->dataPos] == '>') {
+          self->dataPos++;
+          returnStatus = YES;
+        }
+      }
+      else if ((result = [self parseWord:YES])) {
+        parseWhiteSpaces(self, YES);
+        if (self->data[self->dataPos] == '>') {
+          self->dataPos++;
+          returnStatus = YES;
+        }
+      }
+    }
+    if (returnStatus) {
+      returnValue = yesNum;
+    }
+    else {
+      returnValue = nil;
+      dataPos     = keepPos;      
+    }
+    return returnValue;
+}
+
+- (id)parseRouteAddr:(BOOL)_guessMode {
+  NSMutableDictionary *returnValue  = nil;
+  int  keepPos;
+  id   result       = nil;
+  BOOL returnStatus = NO;
+  
+  if (_guessMode) 
+    return [self _parseRouteAddrInGuessMode];
+
+  keepPos     = self->dataPos;
+  returnValue = [NSMutableDictionary dictionaryWithCapacity:2];
+  if (self->data[self->dataPos] == '<') {
+    dataPos++;
+    if ((result = [self parseRoute:NO]))
+      [returnValue setObject:result forKey:@"route"];
+
+    parseWhiteSpaces(self, NO);
+    if ((result = [self parseAddrSpec:NO])) {
+        parseWhiteSpaces(self, NO);
+        if (self->data[self->dataPos] == '>') {
+          self->dataPos++;
+          [returnValue setObject:result forKey:@"address"];
+          returnStatus = YES;
+        }
+    }
+    else if ((result = [self parseWord:NO])) {
+        parseWhiteSpaces(self, NO);
+        if (self->data[self->dataPos] == '>') {
+          self->dataPos++;
+          [returnValue setObject:result forKey:@"address"];
+          returnStatus = YES;
+        }
+    }
+  }
+  if (!returnStatus) {
+    returnValue = nil;
+    if (!(self->errorPos == -1))
+      self->errorPos = self->dataPos;
+    self->dataPos    = keepPos;
+  }
+  return returnValue;
+}
+
+- (id)parseMailBox:(BOOL)_guessMode {
+  id   returnValue  = nil;
+  id   result       = nil;
+  int  keepPos      = self->dataPos;
+  BOOL returnStatus = NO;
+
+  if (_guessMode) {
+    if ((result = [self parseAddrSpec:YES])) {
+      returnStatus = YES;
+    }
+    else {
+      if ((result = [self parsePhrase:YES])) {
+        parseWhiteSpaces(self, YES);
+        if ((result = [self parseRouteAddr:YES])) {
+          returnStatus = YES;
+        }
+      }
+    }
+    if (!returnStatus) {
+      self->dataPos = keepPos;
+      returnValue  = nil;
+    }
+    else {
+      returnValue = yesNum;
+    }
+  }
+  else {
+    if ((result = [self parseAddrSpec:NO])) {
+      returnValue = [NGMailAddress mailAddressWithAddress:result
+                                   displayName:nil
+                                   route:nil];
+      returnStatus = YES;
+    }
+    else if ((result = [self parseRouteAddr:NO])) {
+      returnValue =
+        [NGMailAddress mailAddressWithAddress:
+                         [(NSDictionary *)result objectForKey:@"address"]
+                       displayName:nil
+                       route:nil];
+      returnStatus = YES;
+    }
+    else {
+      returnValue = [[[NGMailAddress alloc] init] autorelease];
+      
+      if ((result = [self parsePhrase:NO])) {
+        [returnValue setDisplayName:result];
+        parseWhiteSpaces(self, NO);        
+        if ((result = [self parseRouteAddr:NO])) {
+          [returnValue setAddress:
+                         [(NSDictionary *)result objectForKey:@"address"]];
+          [returnValue setRoute:
+                         [(NSDictionary *)result objectForKey:@"route"]];
+          returnStatus = YES;
+        }
+      }
+    }
+    if (!returnStatus) { /* try to read until eof or next ',' */
+      self->dataPos = keepPos;
+      
+      if ((result = [self parseRouteAddr:NO])) {
+        returnValue = [[[NGMailAddress alloc] init] autorelease];
+        [returnValue setAddress:
+                       [(NSDictionary *)result objectForKey:@"address"]];
+        returnStatus = YES;
+      }
+    }
+    if (!returnStatus) { /* try to read until eof or next ',' */
+      self->dataPos = keepPos;
+      
+      if ((result = [self parseWord:NO])) {
+        returnValue = [[[NGMailAddress alloc] init] autorelease];
+        [returnValue setAddress:result];
+        returnStatus = YES;
+      }
+    }
+    if (!returnStatus) {
+      if (!(self->errorPos == -1))
+        self->errorPos = self->dataPos;
+
+      self->dataPos = keepPos;
+      returnValue  = nil;
+    }
+  }
+  return returnValue;
+}
+
+- (id)parseGroup:(BOOL)_guessMode {
+  id   returnValue  = nil;
+  id   result       = nil;
+  int  keepPos      = self->dataPos;
+  BOOL returnStatus = NO;
+  
+  if (_guessMode) {
+    if ((result = [self parsePhrase:YES])) {
+      if (self->data[self->dataPos] == ':') { 
+        self->dataPos++;
+        parseWhiteSpaces(self, YES);                      
+        if ((result = [self parseMailBox:YES])) {
+          do {
+            parseWhiteSpaces(self, YES);              
+            result = nil;
+            if (self->data[self->dataPos] == ',') {
+              self->dataPos++;
+              parseWhiteSpaces(self, YES);              
+              result = [self parseMailBox:YES];
+            }
+          } while (result);
+          parseWhiteSpaces(self, YES);                        
+          if (self->data[self->dataPos] == ';') {
+            self->dataPos++;
+            returnStatus = YES;
+          }
+        }
+      }
+    }
+    if (!returnStatus) {
+      returnValue = nil;
+      self->dataPos = keepPos;
+    }
+    else {
+      returnValue = yesNum;
+    }
+  }
+  else {
+    returnValue = [[[NGMailAddressList alloc] init] autorelease];
+    if ((result = [self parsePhrase:NO])) {
+      [returnValue setGroupName:result];
+      if (self->data[self->dataPos] == ':') {
+        self->dataPos++;
+        parseWhiteSpaces(self, NO);
+        if ((result = [self parseMailBox:NO])) {
+          [returnValue addAddress:result];
+          do {
+            parseWhiteSpaces(self, NO);
+            result = nil;            
+            if (self->data[self->dataPos] == ',') {
+              self->dataPos++;
+              parseWhiteSpaces(self, NO);              
+              result = [self parseMailBox:NO];
+              if (result) {
+                [returnValue addAddress:result];
+              }
+            }
+          } while (result);
+          parseWhiteSpaces(self, NO);                        
+          if (self->data[self->dataPos] == ';') {
+            self->dataPos++;
+            returnStatus = YES;
+          }
+        }
+      }
+    }
+    if (!returnStatus) {
+      returnValue = nil;
+      self->dataPos = keepPos;
+    }
+  }
+  return returnValue;
+}
+
+- (id)parseAddress:(BOOL)_guessMode {
+  id  returnValue = nil;
+  int keepPos     = self->dataPos;
+  
+  if (_guessMode) {
+    returnValue = [self parseMailBox:YES];
+    if (!returnValue)
+      returnValue = [self parseGroup:YES];
+    if (!returnValue)
+      self->dataPos = keepPos;
+  }
+  else {
+    returnValue = [self parseMailBox:NO];
+    if (!returnValue)
+      returnValue = [self parseGroup:NO];
+    if (!returnValue)
+      self->dataPos = keepPos;
+  }
+  return returnValue;
+}
+
+- (NSArray *)parseAddressList {
+  NGMailAddress  *address = nil;
+  NSMutableArray *addrs   = nil;
+
+  addrs = [NSMutableArray arrayWithCapacity:16];
+  while (self->dataPos < self->maxLength) {
+    address = [self parseAddress:NO];
+    if (address)
+      [addrs addObject:address];
+    else
+      break;
+    
+    if (self->dataPos < self->maxLength) {
+      parseWhiteSpaces(self, NO);
+      if (self->dataPos < self->maxLength) {
+        if (self->data[self->dataPos] == ',') {
+          self->dataPos++;
+          if (self->dataPos < self->maxLength)
+            parseWhiteSpaces(self, NO);
+        }
+      }
+    }
+  }
+  return [[addrs copy] autorelease];
+}
+
+- (id)parse { 
+  dataPos  = 0;
+  errorPos = -1;
+  return [self parseAddress:NO];
+}
+
+- (int)errorPosition {
+  return self->errorPos;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [StrClass stringWithFormat:@"<%@[0x%08X]>",
+                     NSStringFromClass([self class]),
+                     (unsigned)self];
+}
+
+@end /* NGMailAddressParser */
diff --git a/skyrix-core/NGMime/NGMail/NGMailDecls.h b/skyrix-core/NGMime/NGMail/NGMailDecls.h
new file mode 100644 (file)
index 0000000..41262cb
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_NGStreamDecls_H__
+#define __NGMail_NGStreamDecls_H__
+
+#if BUILD_libNGMail_DLL
+#  define NGMail_EXPORT __declspec(dllexport)
+#elif libNGMail_ISDLL
+#  define NGMail_EXPORT extern __declspec(dllimport)
+#else
+#  define NGMail_EXPORT extern
+#endif
+
+#endif /* __NGMail_NGStreamDecls_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGMimeMessage.h b/skyrix-core/NGMime/NGMail/NGMimeMessage.h
new file mode 100644 (file)
index 0000000..5b51ead
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_NGMimeMessage_H__
+#define __NGMail_NGMimeMessage_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMime/NGPart.h>
+
+@class NGHashMap;
+
+/*
+  NGMimeMessage represents a RFC822 message with MIME extensions.
+*/
+
+@interface NGMimeMessage : NSObject < NGMimePart >
+{
+@protected
+  NGHashMap  *header;
+  id         body;
+  NGMimeType *mimeType;
+}
+
++ (id)messageWithHeader:(NGHashMap *)_headers;
+- (id)initWithHeader:(NGHashMap *)_headers; // designated initializer
+
+// NGPart
+
+- (NSEnumerator *)valuesOfHeaderFieldWithName:(NSString *)_name;
+- (NSEnumerator *)headerFieldNames;
+
+- (void)setBody:(id)_body;
+- (id)body;
+
+// NGMimePart
+
+- (NGMimeType *)contentType;
+- (NSString *)contentId;
+- (NSArray *)contentLanguage;
+- (NSString *)contentMd5;
+- (NSString *)encoding;
+- (NSString *)contentDescription;
+
+@end
+
+#endif /* __NGMail_NGMimeMessage_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGMimeMessage.m b/skyrix-core/NGMime/NGMail/NGMimeMessage.m
new file mode 100644 (file)
index 0000000..02c0ba6
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeMessage.h"
+#include "common.h"
+
+@implementation NGMimeMessage
+
+static NGMimeType *defaultTextType = nil;
+static NGMimeType *defaultDataType = nil;
+
++ (int)version {
+  return 2;
+}
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+    
+    defaultTextType = 
+      [[NGMimeType mimeType:@"text/plain; charset=us-ascii"] retain];
+    defaultDataType = 
+      [[NGMimeType mimeType:@"application/octet-stream"] retain];
+  }
+}
+  
++ (id)messageWithHeader:(NGHashMap *)_header {
+  return [[[self alloc] initWithHeader:_header] autorelease];
+}
+
+- (id)init {
+  return [self initWithHeader:nil];
+}
+- (id)initWithHeader:(NGHashMap *)_header {
+  if ((self = [super init])) {
+    self->header = [_header retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->header   release];
+  [self->body     release];
+  [self->mimeType release];
+  [super dealloc];
+}
+
+/* NGPart */
+
+- (NSEnumerator *)valuesOfHeaderFieldWithName:(NSString *)_name {
+  if ([_name isEqualToString:@"content-type"] == YES) {
+    return [[NSArray arrayWithObject:[self contentType]] objectEnumerator];
+  }
+  return [self->header objectEnumeratorForKey:_name];
+}
+- (NSEnumerator *)headerFieldNames {
+  return [self->header keyEnumerator];
+}
+
+- (void)setBody:(id)_body {
+  ASSIGN(self->body,     _body);
+  ASSIGN(self->mimeType, (id)nil);
+}
+- (id)body {
+  return self->body;
+}
+
+/* NGMimePart */
+
+- (NGMimeType *)autodetectContentType {
+  NGMimeType *type = nil;
+  
+  if ((self->body != nil) &&
+      ([self->body isKindOfClass:[NSData class]] == YES)) {
+    const char *bytes = NULL;
+    unsigned   length = 0;
+
+    bytes  = [self->body bytes];
+    length = [self->body length];
+        
+    while (length > 0) {
+      if ((unsigned char)*bytes > 127) {
+       break;
+      }
+      bytes++;
+      length--;
+    }
+    type = (length > 0) ? defaultDataType : defaultTextType;
+  }
+  else
+    type = defaultTextType;
+  
+  return type;
+}
+
+- (NGMimeType *)contentType {
+  if (self->mimeType == nil) {
+    NGMimeType *type = nil;
+    
+    if ((type = [self->header objectForKey:@"content-type"]) == nil)
+      type = [self autodetectContentType];
+    
+    if (![type isKindOfClass:[NGMimeType class]])
+      type = [NGMimeType mimeType:[type stringValue]];
+    
+    ASSIGNCOPY(self->mimeType, type);
+  }
+  return self->mimeType;
+}
+
+- (NSString *)contentId {
+  return [[self->header objectForKey:@"content-id"] stringValue];
+}
+
+- (NSArray *)contentLanguage {
+  return [self->header objectForKey:@"content-language"];
+}
+
+- (NSString *)contentMd5 {
+  return [[self->header objectForKey:@"content-md5"] stringValue];
+}
+
+- (NSString *)encoding {
+  return [[self->header objectForKey:@"content-transfer-encoding"] stringValue];
+}
+
+- (NSString *)contentDescription {
+  return [self->header objectForKey:@"content-description"];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *d = [NSMutableString stringWithCapacity:64];
+  id b = [self body];
+
+  [d appendFormat:@"<%@[0x%08X]: header=%@",
+       NSStringFromClass([self class]), self, self->header];
+
+  if ([b isKindOfClass:[NSString class]] || [b isKindOfClass:[NSData class]]) {
+    if ([b length] < 512)
+      [d appendFormat:@" body=%@", b];
+    else
+      [d appendFormat:@" body[len=%i]", [b length]];
+  }
+  else
+    [d appendFormat:@" body=%@", b];
+
+  [d appendString:@">"];
+
+  return d;
+}
+
+@end /* NGMimeMessage */
diff --git a/skyrix-core/NGMime/NGMail/NGMimeMessageBodyGenerator.m b/skyrix-core/NGMime/NGMail/NGMimeMessageBodyGenerator.m
new file mode 100644 (file)
index 0000000..1b937f2
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeMessageGenerator.h"
+#include "NGMimeMessage.h"
+#include "common.h"
+
+@implementation NGMimeMessageBodyGenerator
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (NSData *)encodeData:(NSData *)_data
+  forPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders
+{
+  return _base64Encoding(self, _data, _part, _addHeaders);
+}
+
+@end /* NGMimeMessageBodyGenerator */
diff --git a/skyrix-core/NGMime/NGMail/NGMimeMessageGenerator.h b/skyrix-core/NGMime/NGMail/NGMimeMessageGenerator.h
new file mode 100644 (file)
index 0000000..bfc7211
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeMessageGenerator_H__
+#define __NGMime_NGMimeMessageGenerator_H__
+
+#include <NGMime/NGMimePartGenerator.h>
+#include <NGMime/NGMimeBodyGenerator.h>
+
+/*
+  Parses Rfc822 Mime Message Parts
+*/
+
+@interface NGMimeMessageBodyGenerator : NGMimeBodyGenerator
+@end
+
+@interface NGMimeMessageTextBodyGenerator : NGMimeTextBodyGenerator
+@end
+
+@interface NGMimeMessageMultipartBodyGenerator : NGMimeMultipartBodyGenerator
+@end
+
+@interface NGMimeMessageRfc822BodyGenerator : NGMimeRfc822BodyGenerator
+@end
+
+@interface NGMimeMessageGenerator : NGMimePartGenerator
+@end
+
+extern NSData *
+_base64Encoding(NGMimeBodyGenerator *self,
+                NSData *_data_,
+                id<NGMimePart>_part,
+                NGMutableHashMap *_addHeaders);
+
+#endif /*__NGMime_NGMimeMessageGenerator_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGMimeMessageGenerator.m b/skyrix-core/NGMime/NGMail/NGMimeMessageGenerator.m
new file mode 100644 (file)
index 0000000..6e4dcc2
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeMessageGenerator.h"
+#include "NGMimeMessage.h"
+#include "NGMimeFileData.h"
+#include "common.h"
+
+/* Defaults
+  Mail_Use_8bit_Encoding_For_Text[BOOL] --
+    Use 8bit content-transfer-encoding for
+    text messages
+*/
+
+NSData *
+_base64Encoding(NGMimeBodyGenerator *self,
+                NSData *_data_,
+                id<NGMimePart>_part,
+                NGMutableHashMap *_addHeaders)
+{
+  NSString   *transEnc = nil;  
+  const char *bytes    = NULL;
+  unsigned   length    = 0;
+
+  if ([_data_ isKindOfClass:[NGMimeFileData class]])
+    return _data_;
+  
+  bytes  = [_data_ bytes];
+  length = [_data_ length];
+
+  while (length > 0) {
+    if ((unsigned char)*bytes > 127) {
+      break;
+    }
+    bytes++;
+    length--;
+  }
+  if (length > 0) { // should be encoded
+    NGMimeType *type;
+
+    type = [_part contentType];
+    
+    if ([[type type] isEqualToString:@"text"] == YES) {
+      BOOL use8bit;
+
+      use8bit = [[NSUserDefaults standardUserDefaults]
+                                 boolForKey:
+                                   @"Mail_Use_8bit_Encoding_For_Text"];
+
+      if (use8bit) {
+        transEnc = @"8bit";
+      }
+      else {
+        _data_   = [_data_ dataByEncodingQuotedPrintable];
+        transEnc = @"quoted-printable";
+      }
+    }
+    else {
+      _data_   = [_data_ dataByEncodingBase64];
+      transEnc = @"base64";
+
+      if (type == nil) {
+        [_addHeaders setObject:[NGMimeType mimeType:@"application"
+                                           subType:@"octet-stream"]
+                     forKey:@"content-type"];
+      }
+    }
+  }
+  else { // no encoding
+    transEnc = @"7bit";
+  }
+  [_addHeaders setObject:transEnc forKey:@"content-transfer-encoding"];
+  [_addHeaders setObject:[NSNumber numberWithInt:[_data_ length]]
+                      forKey:@"content-length"];
+  return _data_;
+}
+
+@implementation NGMimeMessageGenerator
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+/* header field specifics */
+
+- (NSData *)generateDataForHeaderField:(NSString *)_headerField
+  value:(id)_value
+{
+  NSData *data = nil;
+
+  data = [super generateDataForHeaderField:_headerField
+                value:_value];
+  {
+    const char   *bytes  = NULL;
+    unsigned int length  = 0;
+    unsigned int desLen  = 0;
+    char         *des    = NULL;
+    unsigned int cnt     = 0;
+    BOOL         doEnc   = NO;
+    NSString     *str;
+
+#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+    str = [[NSString alloc] initWithData:data
+                            encoding:NSISOLatin1StringEncoding];
+#else
+    str = [[NSString alloc] initWithData:data
+                            encoding:NSISOLatin9StringEncoding];
+#endif
+    str = [str autorelease];
+    
+    bytes  = [str cString];
+    length = [str cStringLength];
+
+    while (cnt < length) {
+      if ((unsigned char)bytes[cnt] > 127) {
+        doEnc = YES;
+        break;
+      }
+      cnt++;
+    }
+    if (doEnc == YES) {
+      char        iso[]     = "=?iso-8859-15?q?";
+      unsigned    isoLen    = 16;
+      char        isoEnd[]  = "?=";
+      unsigned    isoEndLen = 2;
+      
+      desLen = length * 3 + 20;
+
+      des = NGMallocAtomic(sizeof(char) * desLen + 2);
+      
+      // memcpy(des, bytes, cnt);
+      memcpy(des, iso, isoLen);
+      desLen = NGEncodeQuotedPrintableMime(bytes, length,
+                                           des + isoLen, desLen - isoLen);
+      if ((int)desLen != -1) {
+        memcpy(des + isoLen + desLen, isoEnd, isoEndLen);
+        
+        data = [NSData dataWithBytesNoCopy:des
+                         length:(isoLen + desLen + isoEndLen)];
+      }
+      else {
+        NSLog(@"WARNING: An error occour during quoted-printable decoding");
+        if (des) NGFree(des);
+      }
+    }
+  }
+  return data;
+}
+
+
+/*
+  content-transfer-encoding
+*/
+
+- (id<NGMimeBodyGenerator>)defaultBodyGenerator {
+  id gen;
+
+  gen  = [[NGMimeMessageBodyGenerator allocWithZone:[self zone]] init];
+  [gen setUseMimeData:self->useMimeData];
+  return gen;
+}
+
+- (id<NGMimeBodyGenerator>)generatorForBodyOfPart:(id<NGMimePart>)_part {
+  id<NGMimeBodyGenerator> bodyGen      = nil;
+  NGMimeType              *contentType = nil;
+  NSString                *type        = nil;
+  
+  if (self->delegateRespondsTo.generatorGeneratorForBodyOfPart)
+    bodyGen = [self->delegate mimePartGenerator:self
+                              generatorForBodyOfPart:self->part];
+
+  if (bodyGen)
+    return bodyGen;
+
+  contentType = [_part contentType];
+  if (contentType == nil) {
+    contentType = [self defaultContentTypeForPart:_part];
+  }
+  if (contentType == nil) {
+    NSLog(@"WARNING: no content-type");
+    return nil;
+  }
+  type = [contentType type];
+  if ([type isEqualToString:NGMimeTypeMultipart]) {
+    bodyGen = [[[NGMimeMessageMultipartBodyGenerator alloc] init] autorelease];
+  }
+  else if ([type isEqualToString:NGMimeTypeText]) {
+    bodyGen = [[[NGMimeMessageTextBodyGenerator alloc] init] autorelease];
+  }
+  else if (([type isEqualToString:NGMimeTypeMessage]) &&
+           [[contentType subType] isEqualToString:@"rfc822"]) {
+    bodyGen = [[[NGMimeMessageRfc822BodyGenerator alloc] init] autorelease];
+  }
+  [(id)bodyGen setUseMimeData:self->useMimeData];
+  return bodyGen;
+}
+
+@end /* NGMimeMessageGenerator */
diff --git a/skyrix-core/NGMime/NGMail/NGMimeMessageMultipartBodyGenerator.m b/skyrix-core/NGMime/NGMail/NGMimeMessageMultipartBodyGenerator.m
new file mode 100644 (file)
index 0000000..cab7457
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeMessageGenerator.h"
+#include "NGMimeMessage.h"
+#include "common.h"
+
+@implementation NGMimeMessageMultipartBodyGenerator
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id<NGMimePartGenerator>)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen
+  generatorForPart:(id<NGMimePart>)_part 
+{
+  id gen;
+
+  gen = [[[NGMimeMessageGenerator alloc] init] autorelease];
+  [gen setUseMimeData:self->useMimeData];
+  return gen;
+}
+
+@end /* NGMimeMessageMultipartBodyGenerator */
diff --git a/skyrix-core/NGMime/NGMail/NGMimeMessageParser.h b/skyrix-core/NGMime/NGMail/NGMimeMessageParser.h
new file mode 100644 (file)
index 0000000..552a609
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeMessageParser_H__
+#define __NGMime_NGMimeMessageParser_H__
+
+#include <NGMime/NGMimePartParser.h>
+
+/*
+  NGMimeMessageParser
+  
+  This class is used to parse RFC 822 MIME messages. It's the correct
+  class to parse email messages.
+  
+  Usage:
+    data = [NSData dataWithContentsOfMappedFile:@"MyMail.eml"];
+    parser = [[NGMimeMessageParser alloc] init];
+    part = [parser parsePartFromData:data];
+    NSLog(@"Subject: %@", [part valuesOfHeaderFieldWithName:@"subject"]);
+    [parser release];
+*/
+
+@interface NGMimeMessageParser : NGMimePartParser
+@end
+
+@interface NSData(MimeQPHeaderFieldDecoding)
+
+/*
+  This method decodes header fields which contain quoted
+  printable information.
+  Note that the return value can be both, an NSString or
+  an NSData depending on the case.
+
+  Sample: 
+   attachment; filename="langerp=?iso-8859-15?q?=FC=E4=F6=20Name=F6=F6=F6=201234456=2Exls?="
+*/
+- (id)decodeQuotedPrintableValueOfMIMEHeaderField:(NSString *)_field;
+
+@end
+
+@interface NGMimeRfc822BodyParser : NGMimeBodyParser
+@end
+
+
+#endif /* __NGMime_NGMimeMessageParser_H__ */
+
diff --git a/skyrix-core/NGMime/NGMail/NGMimeMessageParser.m b/skyrix-core/NGMime/NGMail/NGMimeMessageParser.m
new file mode 100644 (file)
index 0000000..f3c68b9
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeMessageParser.h"
+#include "NGMimeMessage.h"
+#include "common.h"
+
+
+
+@interface NGMimeMessageParserDelegate : NSObject
+@end
+
+@implementation NGMimeMessageParserDelegate
+
+static int   UseFoundationStringEncodingForMimeHeader = -1;
+static Class NGMimeMessageParserClass                 = NULL; 
+
++ (void)initialize {
+  if (UseFoundationStringEncodingForMimeHeader == -1) {
+    UseFoundationStringEncodingForMimeHeader
+      = [[NSUserDefaults standardUserDefaults]
+                         boolForKey:@"UseFoundationStringEncodingForMimeHeader"]
+      ? 1 : 0;
+  }
+  if (NGMimeMessageParserClass == NULL) {
+    NGMimeMessageParserClass = [NGMimeMessageParser class];
+  }
+}
+
+- (id)parser:(id)_parser parseHeaderField:(NSString *)_field data:(NSData *)_data
+{
+  id v = nil;
+
+  if ([_parser isKindOfClass:NGMimeMessageParserClass] == NO) {
+    NGMimeMessageParser *parser = nil;
+
+    parser = [[NGMimeMessageParserClass alloc] init];
+    v = [parser valueOfHeaderField:_field data:_data];
+    [parser release]; parser = nil;
+  }
+  return v;
+}
+
+- (id<NGMimeBodyParser>)parser:(NGMimePartParser *)_parser
+  bodyParserForPart:(id<NGMimePart>)_part
+{
+  id                   ctype;
+  NGMimeType           *contentType;
+
+  ctype = [_part contentType];
+  
+  contentType = ([ctype isKindOfClass:[NGMimeType class]])
+    ? ctype
+    : [NGMimeType mimeType:[ctype stringValue]];
+  
+  if ([[contentType type] isEqualToString:@"message"] &&
+      [[contentType subType] isEqualToString:@"rfc822"]) {
+    return [[[NGMimeRfc822BodyParser alloc] init] autorelease];
+  }
+  return nil;
+}
+
+
+@end /* NGMimeMessageParserDelegate */
+
+@implementation NGMimeMessageParser
+
+static Class NSStringClass = Nil;
+
++ (int)version {
+  return 3;
+}
++ (void)initialize {
+  NSAssert2([super version] == 3,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  if (NSStringClass == Nil)
+    NSStringClass = [NSString class];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    [self setDelegate:[NGMimeMessageParserDelegate new]];
+  }
+  return self;
+}
+
+/* factory */
+
+- (id<NGMimePart>)producePartWithHeader:(NGHashMap *)_header {
+  return [NGMimeMessage messageWithHeader:_header];
+}
+
+/* header field specifics */
+
+- (id)valueOfHeaderField:(NSString *)_name data:(id)_data {
+  // check data for 8-bit headerfields (RFC 2047 (MIME PART III))
+  
+  /* check whether we got passed a string ... */
+  if ([_data isKindOfClass:NSStringClass]) {
+    NSLog(@"%s: WARNING unexpected class for headerfield %@ (value %@)",
+          __PRETTY_FUNCTION__, _name, _data);
+    return [super valueOfHeaderField:_name data:_data];
+  }
+  _data = [_data decodeQuotedPrintableValueOfMIMEHeaderField:_name];
+  return [super valueOfHeaderField:_name data:_data];
+}
+
+@end /* NGMimeMessageParser */
+
+@implementation NSData(MimeQPHeaderFieldDecoding)
+
+- (id)decodeQuotedPrintableValueOfMIMEHeaderField:(NSString *)_name {
+  // check data for 8-bit headerfields (RFC 2047 (MIME PART III))
+  static Class NGMimeTypeClass = Nil;
+  enum {
+    NGMimeMessageParser_quoted_start   = 1,
+    NGMimeMessageParser_quoted_charSet = 2,
+    NGMimeMessageParser_quoted_qpData  = 3,
+    NGMimeMessageParser_quoted_end     = 4
+  } status = NGMimeMessageParser_quoted_start;
+  unsigned int        length;
+  const unsigned char *bytes, *firstEq;
+  BOOL foundQP = NO;
+
+  if (NSStringClass   == Nil) NSStringClass   = [NSString class];
+  if (NGMimeTypeClass == Nil) NGMimeTypeClass = [NGMimeType class];
+  
+  length = [self length];
+  
+  /* check whether the string is long enough to be quoted etc */
+  if (length <= 6)
+    return self;
+  
+  /* check whether the string contains QP tokens ... */
+  bytes = [self bytes];
+  
+  if ((firstEq = memchr(bytes, '=', length)) == NULL)
+    return self;
+  
+  /* process data ... (quoting etc) */
+  {
+    unichar       *buffer;
+    unsigned int  bufLen, maxBufLen;
+    NSString      *charset;
+    BOOL          appendLC;
+    int           cnt, tmp;
+    unsigned char encoding;
+    
+    buffer = calloc(sizeof(unichar), length + 13);
+    
+    maxBufLen             = length + 3;
+    buffer[maxBufLen - 1] = '\0';
+    bufLen                = 0;
+    
+    encoding = 0;
+    tmp      = -1;
+    appendLC = YES;      
+    charset  = nil;
+    status   = NGMimeMessageParser_quoted_start;
+
+    /* copy data up to first '=' sign */
+    if ((cnt = (firstEq - bytes)) > 0) {
+      for (; bufLen < cnt; bufLen++) 
+        buffer[bufLen] = bytes[bufLen];
+    }
+    
+    for (; cnt < (length-1); cnt++) {
+      appendLC = YES;      
+      
+      if (status == NGMimeMessageParser_quoted_start) {
+        if ((bytes[cnt] == '=') && (bytes[cnt + 1] == '?')) { // found begin
+          cnt++;
+          status = NGMimeMessageParser_quoted_charSet;
+        }
+        else { // other char
+          if (bytes[cnt + 1] != '=') {
+            buffer[bufLen++] = bytes[cnt];
+            buffer[bufLen++] = bytes[cnt+1];
+            cnt++;
+            if (cnt >= length - 1)
+              appendLC = NO;
+          }
+          else {
+            buffer[bufLen++] = bytes[cnt];
+          }
+        }
+      }
+      else if (status == NGMimeMessageParser_quoted_charSet) {
+        if (tmp == -1)
+          tmp = cnt;
+       
+        if (bytes[cnt] == '?') {
+          charset = 
+           [NSStringClass stringWithCString:(bytes + tmp) length:cnt - tmp];
+          tmp = -1;
+         
+          if ((length - cnt) > 2) { 
+           // set encoding (eg 'q' for quoted printable)
+            cnt++; // skip '?'
+            encoding = bytes[cnt];
+            cnt++; // skip encoding
+            status = NGMimeMessageParser_quoted_qpData;
+          }
+          else { // unexpected end
+            NSLog(@"WARNING: unexpected end of header");
+            appendLC = NO;
+            break;
+          }
+        }
+      }
+      else if (status == NGMimeMessageParser_quoted_qpData) {
+        if (tmp == -1)
+          tmp = cnt;
+       
+        if ((bytes[cnt] == '?') && (bytes[cnt + 1] == '=')) {
+          NSData           *tmpData;
+          NSString         *tmpStr;
+         unsigned int     tmpLen;
+         
+          tmpData = _rfc2047Decoding(encoding, bytes + tmp, cnt - tmp);
+         foundQP = YES;
+
+         /* 
+            create a temporary string for charset conversion ... 
+            Note: the headerfield is currently held in ISO Latin 1
+         */
+          tmpStr = nil;
+          
+          if (!UseFoundationStringEncodingForMimeHeader) {
+            tmpStr = [NSStringClass stringWithData:tmpData
+                                    usingEncodingNamed:charset];
+          }
+          if (tmpStr == nil) {
+            NSStringEncoding enc;
+            
+            enc    = [NGMimeTypeClass stringEncodingForCharset:charset];
+            tmpStr = [[[NSStringClass alloc] initWithData:tmpData encoding:enc]
+                                      autorelease];
+          }
+         tmpLen = [tmpStr length];
+         
+         if ((tmpLen + bufLen) < maxBufLen) {
+           [tmpStr getCharacters:(buffer + bufLen)];
+           bufLen += tmpLen;
+         }
+         else {
+           NSLog(@"ERROR[%s]: quoted data to large --> ignored %@",
+                 __PRETTY_FUNCTION__, tmpStr);
+         }
+          tmp = -1;
+          cnt++;
+          appendLC = YES;
+          status   = NGMimeMessageParser_quoted_start;
+        }
+      }
+    }
+    if (appendLC == YES) {
+      if (cnt < length) {
+        buffer[bufLen] = bytes[cnt];
+        bufLen++;
+      }
+    }
+    buffer[bufLen] = '\0';
+    {
+      id data;
+
+      data = nil;
+      
+      if (buffer && foundQP) {
+        data = [[[NSString alloc] initWithCharacters:buffer length:bufLen]
+                           autorelease];
+        if (data == nil) {
+          NSLog(@"%s: got no string for buffer '%s', length '%i' !", 
+                __PRETTY_FUNCTION__,
+                buffer, bufLen);
+        }
+      }
+      if (!data) {
+        data = self;
+      }
+      free(buffer); buffer = NULL;
+      return data;
+    }
+  }
+  return self;
+}
+
+@end /* NSData(MimeQPHeaderFieldDecoding) */
+
+@implementation NGMimeRfc822BodyParser
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)parseBodyOfPart:(id<NGMimePart>)_part data:(NSData *)_data
+  delegate:(id)_d
+{
+  id<NGMimePart> body;
+  id             parser; // NGMimeMessageParser
+
+  parser = [[NGMimeMessageParser alloc] init];
+  body = [parser parsePartFromData:_data];
+  [parser release]; parser = nil;
+  
+  return body;
+}
+
+@end /* NGMimeRfc822BodyParser */
diff --git a/skyrix-core/NGMime/NGMail/NGMimeMessageRfc822BodyGenerator.m b/skyrix-core/NGMime/NGMail/NGMimeMessageRfc822BodyGenerator.m
new file mode 100644 (file)
index 0000000..2c995b2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeMessageGenerator.h"
+#include "NGMimeMessage.h"
+#include "common.h"
+
+@implementation NGMimeMessageRfc822BodyGenerator
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id<NGMimePartGenerator>)generatorForPart:(id<NGMimePart>)_part {
+  id gen;
+
+  gen = [[[NGMimeMessageGenerator alloc] init] autorelease];
+
+  [gen setUseMimeData:self->useMimeData];
+  
+  return gen;
+}
+
+@end /* NGMimeMessageRfc822BodyGenerator */
diff --git a/skyrix-core/NGMime/NGMail/NGMimeMessageTextBodyGenerator.m b/skyrix-core/NGMime/NGMail/NGMimeMessageTextBodyGenerator.m
new file mode 100644 (file)
index 0000000..e248910
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeMessageGenerator.h"
+#include "NGMimeMessage.h"
+#include "common.h"
+
+@implementation NGMimeMessageTextBodyGenerator
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (NSData *)encodeData:(NSData *)_data
+  forPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders
+{
+  return _base64Encoding(self, _data, _part, _addHeaders);
+}
+
+@end /* NGMimeMessageTextBodyGenerator */
diff --git a/skyrix-core/NGMime/NGMail/NGPop3Client.h b/skyrix-core/NGMime/NGMail/NGPop3Client.h
new file mode 100644 (file)
index 0000000..eb44ab7
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_NGPop3Client_H__
+#define __NGMail_NGPop3Client_H__
+
+#import <Foundation/NSObject.h>
+#import <NGStreams/NGStreams.h>
+#import <NGStreams/NGSocketProtocols.h>
+
+@class NSString, NSData;
+@class NGBufferedStream;
+@class NGMimeMessage;
+
+typedef enum {
+  NGPop3State_unconnected = 1,
+  NGPop3State_AUTHORIZATION,
+  NGPop3State_TRANSACTION,
+  NGPop3State_UPDATE
+} NGPop3State;
+
+@class NGPop3Response, NGPop3MessageInfo;
+
+@interface NGPop3Client : NSObject
+{
+@protected
+  id<NGActiveSocket>       socket;
+  NGBufferedStream         *connection;
+  id<NGExtendedTextStream> text;
+
+  NGPop3State    state;
+  NGPop3Response *lastResponse;
+  BOOL isDebuggingEnabled;
+}
+
++ (id)pop3Client;
+- (id)initWithSocket:(id<NGActiveSocket>)_socket; // designated initializer
+
+// accessors
+
+- (id<NGActiveSocket>)socket;
+- (NGPop3State)state;
+- (NGPop3Response *)lastResponse;
+
+- (void)setDebuggingEnabled:(BOOL)_flag;
+- (BOOL)isDebuggingEnabled;
+
+// connection
+
+- (BOOL)connectToHost:(id)_host;
+- (BOOL)connectToAddress:(id<NGSocketAddress>)_address;
+- (void)disconnect;
+
+// state
+
+- (void)requireState:(NGPop3State)_state;
+- (void)gotoState:(NGPop3State)_state;
+
+// commands
+
+- (NGPop3Response *)sendCommand:(NSString *)_command;
+- (NGPop3Response *)sendCommand:(NSString *)_command argument:(NSString *)arg;
+- (NGPop3Response *)sendCommand:(NSString *)_command intArgument:(int)_argument;
+
+// service commands
+
+- (BOOL)login:(NSString *)_user password:(NSString *)_passwd;
+- (BOOL)quit;
+
+- (BOOL)statMailDropCount:(int *)_count size:(int *)_size;
+- (NGPop3MessageInfo *)listMessage:(int)_messageNumber;
+- (NSEnumerator *)listMessages;
+- (NSData *)retrieveMessage:(int)_msgNumber;
+- (BOOL)deleteMessage:(int)_msgNumber;
+- (BOOL)noop;
+- (BOOL)reset;
+
+// optional service commands
+
+- (NSData *)retrieveMessage:(int)_msgNumber bodyLineCount:(int)_numberOfLines;
+- (NSDictionary *)uniqueIdMappings;
+- (NSString *)uniqueIdOfMessage:(int)_msgNumber;
+
+// MIME support
+
+- (NSEnumerator *)messageEnumerator;
+- (NGMimeMessage *)messageWithNumber:(int)_messageNumber;
+
+@end
+
+#endif /* __NGMail_NGPop3Client_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGPop3Client.m b/skyrix-core/NGMime/NGMail/NGPop3Client.m
new file mode 100644 (file)
index 0000000..95aa514
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGPop3Client.h"
+#include "NGPop3Support.h"
+#include "NGMimeMessageParser.h"
+#include "NGMimeMessage.h"
+#include "common.h"
+
+@implementation NGPop3Client
+
++ (int)version {
+  return 2;
+}
+
++ (id)pop3Client {
+  NGActiveSocket *s;
+  
+  s = [NGActiveSocket socketInDomain:[NGInternetSocketDomain domain]];
+  return [[[self alloc] initWithSocket:s] autorelease];
+}
+
+- (id)init {
+  NSLog(@"%@: init not supported, use initWithSocket: ..", self);
+  [self release];
+  return nil;
+}
+
+- (id)initWithSocket:(id<NGActiveSocket>)_socket {
+  if ((self = [super init])) {
+    self->socket = [_socket retain];
+    NSAssert(self->socket, @"invalid socket parameter");
+    
+    self->connection = 
+      [(NGBufferedStream *)[NGBufferedStream alloc] initWithSource:_socket];
+    self->text = 
+      [(NGCTextStream *)[NGCTextStream alloc] initWithSource:self->connection];
+    
+    self->state = [self->socket isConnected]
+      ? NGPop3State_AUTHORIZATION
+      : NGPop3State_unconnected;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->text         release];
+  [self->connection   release];
+  [self->socket       release];
+  [self->lastResponse release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id<NGActiveSocket>)socket {
+  return self->socket;
+}
+
+- (NGPop3State)state {
+  return self->state;
+}
+
+- (NGPop3Response *)lastResponse {
+  return self->lastResponse;
+}
+
+- (void)setDebuggingEnabled:(BOOL)_flag {
+  self->isDebuggingEnabled = _flag;
+}
+- (BOOL)isDebuggingEnabled {
+  return self->isDebuggingEnabled;
+}
+
+/* connection */
+
+- (BOOL)connectToAddress:(id<NGSocketAddress>)_address {
+  NSString *greeting = nil;
+
+  [self requireState:NGPop3State_unconnected];
+  
+  [self->socket connectToAddress:_address];
+
+  // receive greeting from server
+  greeting = [self->text readLineAsString];
+  if (self->isDebuggingEnabled)
+    [NGTextErr writeFormat:@"S: %@\n", greeting];
+
+  // is it a welcome ?
+  if (![greeting hasPrefix:@"+OK"])
+    return NO;
+
+  // we are welcome, need to authorize
+  [self gotoState:NGPop3State_AUTHORIZATION];
+
+  return YES;
+}
+- (BOOL)connectToHost:(id)_host {
+  return [self connectToAddress:[NGInternetSocketAddress addressWithService:@"pop3"
+                                                         onHost:_host
+                                                         protocol:@"tcp"]];
+}
+
+- (void)disconnect {
+  [text   flush];
+  [socket close];
+  [self   gotoState:NGPop3State_unconnected];
+}
+
+/* commands */
+
+- (NGPop3Response *)receiveSimpleReply {
+  NSString *line = [self->text readLineAsString];
+
+  if (line) {
+    NGPop3Response *response = [NGPop3Response responseWithLine:line];
+    ASSIGN(self->lastResponse, response);
+  }
+  else {
+    [self->lastResponse release];
+    self->lastResponse = nil;
+  }
+  return self->lastResponse;
+}
+
+- (BOOL)receiveMultilineReply:(NSMutableData *)_data {
+  enum {
+    NGPop3_begin,
+    NGPop3_foundCR,
+    NGPop3_foundCRLF,
+    NGPop3_foundCRLFP,
+    NGPop3_done
+  } pState = NGPop3_begin;
+  void (*addBytes)(id self, SEL _cmd, void *buffer, unsigned int _bufLen);
+  int c;
+
+  addBytes = (void*)[_data methodForSelector:@selector(appendBytes:length:)];
+
+  do {
+    c = [self->connection readByte];
+    if (c == -1) {
+      NSLog(@"ERROR: connection was shut down ..");
+      break;
+    }
+
+    /*
+    if (c >= 32) printf("%i '%c'\n", c, c);
+    else         printf("%i\n", c);
+    */
+    
+    NSAssert((c >= 0) && (c <= 255), @"invalid byte read ..");
+
+    if (pState == NGPop3_foundCRLFP) {
+      if (c == '\r') { // CR LF . CR
+        addBytes(_data, @selector(appendBytes:length:), "\r\n", 2);
+        c = [self->connection readByte];
+        if (c == '\n') {
+          pState = NGPop3_done;
+        }
+        else {
+          char c8 = c;
+          NSLog(@"WARNING: found strange sequence: 'CR LF . CR 0x%x'", c);
+          addBytes(_data, @selector(appendBytes:length:), ".\r", 2);
+          addBytes(_data, @selector(appendBytes:length:), &c8, 1);
+          pState = NGPop3_begin;
+        }
+      }
+      else if (c == '\n') { // CR LF . LF
+        NSLog(@"WARNING: found strange sequence: 'CR LF . LF'");
+        addBytes(_data, @selector(appendBytes:length:), "\r\n.\n", 4);
+        pState = NGPop3_begin;
+      }
+      else { // CR LF . (.|other)
+        char c8 = c;
+        if (c != '.')
+          NSLog(@"WARNING: expected '\\r\\n.\\r' or '\\r\\n..', got '\\r\\n.%c'", c);
+        addBytes(_data, @selector(appendBytes:length:), "\r\n", 2);
+        addBytes(_data, @selector(appendBytes:length:), &c8, 1);
+        pState = NGPop3_begin;
+        continue;
+      }
+    }
+    else if (pState == NGPop3_foundCRLF) {
+      if (c == '.') { // found: CR LF .
+        pState = NGPop3_foundCRLFP;
+        continue;
+      }
+      else if (c == '\r') {
+        addBytes(_data, @selector(appendBytes:length:), "\r\n", 2);
+        pState = NGPop3_foundCR;
+        continue;
+      }
+      else {
+        char c8 = c;
+        addBytes(_data, @selector(appendBytes:length:), "\r\n", 2);
+        addBytes(_data, @selector(appendBytes:length:), &c8, 1);
+        pState = NGPop3_begin;
+      }
+    }
+    else if (pState == NGPop3_foundCR) {
+      if (c == '\n') { // found CR LF
+        pState = NGPop3_foundCRLF;
+        continue;
+      }
+      else {
+        char c8 = c;
+        addBytes(_data, @selector(appendBytes:length:), "\r", 1);
+        addBytes(_data, @selector(appendBytes:length:), &c8, 1);
+        pState = NGPop3_begin;
+      }
+    }
+    else if (c == '\r') {
+      pState = NGPop3_foundCR;
+      continue;
+    }
+    /*
+    else if (c == '\n') {
+      NSLog(@"WARNING: found LF without leading CR ..");
+      pState = NGPop3_foundCRLF;
+      continue;
+      }*/
+    else {
+      char c8 = c;
+      addBytes(_data, @selector(appendBytes:length:), &c8, 1);
+    }
+  }
+  while(pState != NGPop3_done);
+  
+  return (pState == NGPop3_done) ? YES : NO;
+}
+
+- (NGPop3Response *)sendCommand:(NSString *)_command {
+  if (self->isDebuggingEnabled) {
+    [NGTextOut writeFormat:@"C: %@\n", _command];
+    [NGTextOut flush];
+  }
+  
+  [text writeString:_command];
+  [text writeString:@"\r\n"];
+  [text flush];
+  return [self receiveSimpleReply];
+}
+
+- (NGPop3Response *)sendCommand:(NSString *)_command argument:(NSString *)_argument {
+  if (self->isDebuggingEnabled) {
+    if (![_command isEqualToString:@"PASS"])
+      [NGTextOut writeFormat:@"C: %@ %@\n", _command, _argument];
+    else
+      [NGTextOut writeFormat:@"C: PASS <hidden>\n"];
+  }
+  
+  [text writeString:_command];
+  [text writeFormat:@" %s\r\n", [_argument cString]];
+  [text flush];
+  return [self receiveSimpleReply];
+}
+- (NGPop3Response *)sendCommand:(NSString *)_command intArgument:(int)_argument {
+  if (self->isDebuggingEnabled) {
+    if (![_command isEqualToString:@"PASS"])
+      [NGTextOut writeFormat:@"C: %@ %i\n", _command, _argument];
+    else
+      [NGTextOut writeFormat:@"C: PASS <hidden>\n"];
+  }
+  
+  [text writeString:_command];
+  [text writeFormat:@" %i\r\n", _argument];
+  [text flush];
+  return [self receiveSimpleReply];
+}
+- (NGPop3Response *)sendCommand:(NSString *)_command
+  intArgument:(int)_arg1 intArgument:(int)_arg2 {
+
+  if (self->isDebuggingEnabled) {
+    if (![_command isEqualToString:@"PASS"])
+      [NGTextOut writeFormat:@"C: %@ %i %i\n", _command, _arg1, _arg2];
+    else
+      [NGTextOut writeFormat:@"C: PASS <hidden>\n"];
+  }
+  
+  [text writeString:_command];
+  [text writeFormat:@" %i %i\r\n", _arg1, _arg2];
+  [text flush];
+  return [self receiveSimpleReply];
+}
+
+// state
+
+- (void)requireState:(NGPop3State)_state {
+  if (_state != [self state]) {
+    [[[NGPop3StateException alloc]
+       initWithClient:self
+       requiredState:_state] raise];
+  }
+}
+
+- (void)gotoState:(NGPop3State)_state {
+  self->state = _state;
+}
+
+// service commands
+
+- (BOOL)login:(NSString *)_user password:(NSString *)_passwd {
+  NGPop3Response *reply = nil;
+
+  [self requireState:NGPop3State_AUTHORIZATION];
+
+  reply = [self sendCommand:@"USER" argument:_user];
+  if ([reply isPositive]) {
+    reply = [self sendCommand:@"PASS" argument:_passwd];
+    if ([reply isPositive]) {
+      [self gotoState:NGPop3State_TRANSACTION];
+      return YES;
+    }
+  }
+  NSLog(@"POP3 authorization of user %@ failed ..", _user);
+
+  return NO;
+}
+
+- (BOOL)quit {
+  NGPop3Response *reply = nil;
+
+  reply = [self sendCommand:@"QUIT"];
+  if ([reply isPositive]) {
+    unsigned int waitBytes = 0;
+    
+    if (self->state == NGPop3State_TRANSACTION)
+      self->state = NGPop3State_UPDATE;
+
+    if (self->isDebuggingEnabled)
+      [NGTextErr writeFormat:@"S: %@\n", [reply line]];
+
+    // wait for connection close ..
+    while ([self->connection readByte] != -1)
+      waitBytes++;
+
+    self->state = NGPop3State_unconnected;
+  }
+  return [reply isPositive];
+}
+
+- (BOOL)statMailDropCount:(int *)_count size:(int *)_size {
+  NGPop3Response *reply = nil;
+  [self requireState:NGPop3State_TRANSACTION];
+  *_count = 0;
+  *_size  = 0;
+
+  reply = [self sendCommand:@"STAT"];
+
+  if ([reply isPositive]) {
+    const char *cstr = [[reply line] cString];
+
+    while ((*cstr != '\0') && (*cstr != ' ')) cstr++;
+    if (*cstr == '\0') return NO;
+    cstr++;
+
+    *_count = atoi(cstr);
+    while ((*cstr != '\0') && (*cstr != ' ')) cstr++;
+    if (*cstr == '\0') return NO;
+    cstr++;
+    
+    *_size = atoi(cstr);
+    return YES;
+  }
+  else
+    return NO;
+}
+
+- (NGPop3MessageInfo *)listMessage:(int)_messageNumber {
+  NGPop3Response *reply = nil;
+  [self requireState:NGPop3State_TRANSACTION];
+
+  reply = [self sendCommand:@"LIST" intArgument:_messageNumber];
+  if ([reply isPositive]) {
+    const char *cstr = index([[reply line] cString], ' ');
+
+    if (cstr) {
+      int msgNum;
+      cstr++;
+      msgNum = atoi(cstr);
+      cstr = index(cstr, ' ') + 1;
+      if (cstr > (char *)1) {
+        NGPop3MessageInfo *info   = nil;
+        int               msgSize = atoi(cstr);
+
+        info = [NGPop3MessageInfo infoForMessage:msgNum size:msgSize client:self];
+        return info;
+      }
+    }
+    NSLog(@"ERROR: invalid reply line '%@' ..", [reply line]);
+  }
+  return nil;
+}
+
+- (NSEnumerator *)listMessages {
+  NGPop3Response *reply = nil;
+  [self requireState:NGPop3State_TRANSACTION];
+
+  reply = [self sendCommand:@"LIST"];
+  if ([reply isPositive]) {
+    NSMutableArray *array = nil;
+    NSString       *line  = nil;
+    
+    array = [NSMutableArray arrayWithCapacity:128];
+
+    line = [self->text readLineAsString];
+    while ((line != nil) && (![line isEqualToString:@"."])) {
+      NGPop3MessageInfo *info = nil;
+      const char        *cstr = (char *)[line cString];
+      int               msgNum, msgSize;
+
+      msgNum = atoi(cstr);
+      cstr = index(cstr, ' ') + 1;
+      if (cstr > (char *)1)
+        msgSize = atoi(cstr);
+      else {
+        NSLog(@"WARNING(%s): invalid reply line '%@'", __PRETTY_FUNCTION__, line);
+        msgSize = 0;
+      }
+
+      info = [NGPop3MessageInfo infoForMessage:msgNum size:msgSize client:self];
+
+      if (info)
+        [array addObject:info];
+      else
+        NSLog(@"ERROR: could not produce info for line '%@'", line);
+      line = [self->text readLineAsString];
+    }
+
+    return [array objectEnumerator];
+  }
+  else
+    return nil;
+}
+
+- (NSData *)retrieveMessage:(int)_msgNumber {
+  NGPop3Response *reply = nil;
+  [self requireState:NGPop3State_TRANSACTION];
+
+  reply = [self sendCommand:@"RETR" intArgument:_msgNumber];
+  if ([reply isPositive]) {
+    NSMutableData *data = nil;
+    const char    *cstr = index([[reply line] cString], ' ');
+    unsigned msgSize = -1;
+
+    if (cstr) {
+      cstr++;
+      msgSize = atoi(cstr);
+      data = [NSMutableData dataWithCapacity:msgSize + 1];
+    }
+    else
+      data = [NSMutableData dataWithCapacity:1024];
+
+    if ([self receiveMultilineReply:data]) {
+      if ((msgSize > 0) && ([data length] > msgSize)) {
+        NSLog(@"data was longer than message size ..");
+        //[data setLength:msgSize];
+      }
+      return data;
+    }
+  }
+  return nil;
+}
+
+- (BOOL)deleteMessage:(int)_msgNumber {
+  NGPop3Response *reply = nil;
+  [self requireState:NGPop3State_TRANSACTION];
+
+  reply = [self sendCommand:@"DELE" intArgument:_msgNumber];
+  if ([reply isPositive]) {
+    return YES;
+  }
+  return NO;
+}
+
+- (BOOL)noop {
+  [self requireState:NGPop3State_TRANSACTION];
+  return [[self sendCommand:@"NOOP"] isPositive];
+}
+
+- (BOOL)reset {
+  [self requireState:NGPop3State_TRANSACTION];
+  return [[self sendCommand:@"RSET"] isPositive];
+}
+
+// optional service commands
+
+- (NSData *)retrieveMessage:(int)_msgNumber bodyLineCount:(int)_numberOfLines {
+  NGPop3Response *reply = nil;
+  [self requireState:NGPop3State_TRANSACTION];
+
+  reply = [self sendCommand:@"TOP"
+                intArgument:_msgNumber
+                intArgument:_numberOfLines];
+  if ([reply isPositive]) {
+    NSMutableData *data = nil;
+    const char    *cstr = index([[reply line] cString], ' ');
+    int  msgSize = -1;
+
+    if (cstr) {
+      cstr++;
+      msgSize = atoi(cstr);
+    }
+    data = [NSMutableData dataWithCapacity:1024];
+
+    if ([self receiveMultilineReply:data])
+      return data;
+  }
+  return nil;
+}
+
+- (NSDictionary *)uniqueIdMappings {
+  NGPop3Response *reply = nil;
+  [self requireState:NGPop3State_TRANSACTION];
+
+  reply = [self sendCommand:@"UIDL"];
+  if ([reply isPositive]) {
+    NSMutableDictionary *dict = nil;
+    NSString            *line  = nil;
+
+    dict = [NSMutableDictionary dictionaryWithCapacity:256];
+
+    line = [self->text readLineAsString];
+    while ((line != nil) && (![line isEqualToString:@"."])) {
+      const char *cstr = index([line cString], ' ');
+
+      if (cstr) {
+        int msgNum = atoi([line cString]);
+
+        cstr++;
+        [dict setObject:[NSString stringWithCString:cstr]
+              forKey:[NSNumber numberWithInt:msgNum]];
+      }
+      else {
+        NSLog(@"WARNING(%s): invalid reply line '%@'", __PRETTY_FUNCTION__, line);
+      }
+      line = [self->text readLineAsString];
+    }
+
+    return dict;
+  }
+  else
+    return nil;
+}
+
+- (NSString *)uniqueIdOfMessage:(int)_messageNumber {
+  NGPop3Response *reply = nil;
+  [self requireState:NGPop3State_TRANSACTION];
+
+  reply = [self sendCommand:@"UIDL" intArgument:_messageNumber];
+  if ([reply isPositive]) {
+    const char *cstr = index([[reply line] cString], ' ');
+
+    if (cstr) { // found message number
+      cstr = index(cstr + 1, ' ');
+      if (cstr) { // found u-id
+        cstr++;
+        return [NSString stringWithCString:cstr];
+      }
+    }
+    NSLog(@"ERROR: invalid reply line '%@' ..", [reply line]);
+  }
+  return nil;
+}
+
+/* MIME support */
+
+- (NSEnumerator *)messageEnumerator {
+  return [[[NGPop3MailDropEnumerator alloc]
+              initWithMessageInfoEnumerator:[self listMessages]] autorelease];
+}
+- (NGMimeMessage *)messageWithNumber:(int)_messageNumber {
+  NSData *msgData = [self retrieveMessage:_messageNumber];
+  
+  if (msgData) {
+    NGDataStream        *msgStream;
+    NGMimeMessageParser *parser;
+    NGMimeMessage       *message;
+
+    msgStream = [[NGDataStream alloc] initWithData:msgData];
+    parser    = [[NGMimeMessageParser alloc] init];
+    *(&message) = nil;
+
+    NS_DURING
+      message = (NGMimeMessage *)[parser parsePartFromStream:msgStream];
+    NS_HANDLER
+      message = nil;
+    NS_ENDHANDLER;
+
+    message = [message retain];
+
+    [parser    release]; parser    = nil;
+    [msgStream release]; msgStream = nil;
+    msgData = nil;
+    
+    return [message autorelease];
+  }
+  else
+    return nil;
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<POP3Client[0x%08X]: socket=%@>",
+                     (unsigned)self, [self socket]];
+}
+
+@end
diff --git a/skyrix-core/NGMime/NGMail/NGPop3Support.h b/skyrix-core/NGMime/NGMail/NGPop3Support.h
new file mode 100644 (file)
index 0000000..1e7d5cd
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_NGPop3Support_H__
+#define __NGMail_NGPop3Support_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMail/NGPop3Client.h>
+
+@class NSString;
+
+@interface NGPop3Response : NSObject
+{
+@protected
+  NSString *line;
+}
+
++ (id)responseWithLine:(NSString *)_line;
+
+// accessors
+
+- (BOOL)isPositive;
+- (NSString *)line;
+
+@end
+
+@interface NGPop3MessageInfo : NSObject
+{
+@protected
+  NGPop3Client *client;
+  int          messageNumber;
+  int          messageSize;
+}
+
++ (id)infoForMessage:(int)_num size:(int)_size client:(NGPop3Client *)_client;
+
+// accessors
+
+- (int)messageNumber;
+- (int)size;
+- (NGPop3Client *)pop3Client;
+
+@end
+
+#import <Foundation/NSEnumerator.h>
+
+@interface NGPop3MailDropEnumerator : NSEnumerator
+{
+@protected
+  NSEnumerator *msgInfos;
+}
+
+- (id)initWithMessageInfoEnumerator:(NSEnumerator *)_infos;
+- (id)nextObject;
+
+@end
+
+@interface NGPop3Exception : NSException
+@end
+
+@interface NGPop3StateException : NGPop3Exception
+{
+@protected
+  NGPop3State requiredState;
+}
+
+- (id)initWithClient:(NGPop3Client *)_client requiredState:(NGPop3State)_state;
+- (NGPop3State)requiredState;
+
+@end
+
+#endif /* __NGMail_NGPop3Support_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGPop3Support.m b/skyrix-core/NGMime/NGMail/NGPop3Support.m
new file mode 100644 (file)
index 0000000..8b86b81
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGPop3Support.h"
+#include "NGPop3Client.h"
+#include "common.h"
+
+@implementation NGPop3Response
+
++ (int)version {
+  return 2;
+}
+
+- (id)initWithLine:(NSString *)_line {
+  if ((self = [super init])) {
+    self->line = [_line copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->line release];
+  [super dealloc];
+}
+
++ (id)responseWithLine:(NSString *)_line {
+  return [[[self alloc] initWithLine:_line] autorelease];
+}
+
+/* accessors */
+
+- (BOOL)isPositive {
+  return [self->line hasPrefix:@"+OK"];
+}
+- (NSString *)line {
+  return self->line;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<Pop3Reply[0x%08X]: positive=%s line=%@>",
+                     (unsigned)self,
+                     [self isPositive] ? "YES" : "NO",
+                     [self line]];
+}
+
+@end /* NGPop3Response */
+
+@implementation NGPop3MessageInfo
+
++ (int)version {
+  return 2;
+}
+
+- (id)initWithNumber:(int)_num size:(int)_size client:(NGPop3Client *)_client{
+  if ((self = [super init])) {
+    self->messageNumber = _num;
+    self->messageSize   = _size;
+    self->client        = [_client retain];
+  }
+  return self;
+}
+
++ (id)infoForMessage:(int)_num size:(int)_size client:(NGPop3Client *)_client {
+  return [[[self alloc] initWithNumber:_num size:_size client:_client] autorelease];
+}
+
+- (void)dealloc {
+  [self->client release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (int)messageNumber {
+  return self->messageNumber;
+}
+
+- (int)size {
+  return self->messageSize;
+}
+
+- (NGPop3Client *)pop3Client {
+  return self->client;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<Pop3MsgInfo[0x%08X]: number=%i size=%i>",
+                     (unsigned)self, [self messageNumber], [self size]];
+}
+
+@end /* NGPop3Response */
+
+@implementation NGPop3MailDropEnumerator
+
++ (int)version {
+  return 2;
+}
+
+- (id)initWithMessageInfoEnumerator:(NSEnumerator *)_infos {
+  self->msgInfos = [_infos retain];
+  return self;
+}
+
+- (void)dealloc {
+  [self->msgInfos release];
+  [super dealloc];
+}
+
+- (id)nextObject {
+  NGPop3MessageInfo *info    = [self->msgInfos nextObject];
+  NGMimeMessage     *message = nil;
+
+  if (info != nil) {
+    message = [[info pop3Client] messageWithNumber:[info messageNumber]];
+    if (message == nil) {
+      NSLog(@"ERROR: could not retrieve message %i, skipping", [info messageNumber]);
+      message = [self nextObject];
+    }
+  }
+  return message;
+}
+
+@end /* NGPop3MailDropEnumerator */
+
+// ******************** Exceptions ********************
+
+@implementation NGPop3Exception
+
++ (int)version {
+  return 2;
+}
+
+@end /* NGPop3Exception */
+
+@implementation NGPop3StateException
+
++ (int)version {
+  return 2;
+}
+
+- (id)init {
+  return [self initWithClient:nil requiredState:0];
+}
+
+- (id)initWithClient:(NGPop3Client *)_client requiredState:(NGPop3State)_state {
+  NSString *stateString = nil;
+
+  switch(_state) {
+    case NGPop3State_unconnected:   stateString = @"unconnected";   break;
+    case NGPop3State_AUTHORIZATION: stateString = @"AUTHORIZATION"; break;
+    case NGPop3State_TRANSACTION:   stateString = @"TRANSACTION";   break;
+    case NGPop3State_UPDATE:        stateString = @"UPDATE";        break;
+    default:
+      stateString = @"unknown";
+      break;
+  }
+  
+  if ((self = [super initWithFormat:@"operation can only perform in state %@",
+                     stateString])) {
+    self->requiredState = _state;
+  }
+  return self;
+}
+
+// accessors
+
+- (NGPop3State)requiredState {
+  return self->requiredState;
+}
+
+@end /* NGPop3StateException */
diff --git a/skyrix-core/NGMime/NGMail/NGSmtpClient.h b/skyrix-core/NGMime/NGMail/NGSmtpClient.h
new file mode 100644 (file)
index 0000000..061fd15
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_NGSmtpClient_H__
+#define __NGMail_NGSmtpClient_H__
+
+#import <Foundation/NSObject.h>
+#import <NGStreams/NGStreams.h>
+#import <NGStreams/NGSocketProtocols.h>
+
+@class NSString;
+@class NGSmtpResponse;
+
+/*
+  RFC 821 - SMTP
+
+  This class implements the Simple Mail Transfer Protocol as specified in RFC821.
+*/
+
+typedef enum {
+  NGSmtpState_unconnected = 1,
+  NGSmtpState_connected,
+  NGSmtpState_TRANSACTION
+} NGSmtpState;
+
+@interface NGSmtpClient : NSObject
+{
+@protected
+  id<NGActiveSocket>       socket;
+  NGBufferedStream         *connection;
+  id<NGExtendedTextStream> text;
+
+  NGSmtpState state;
+  BOOL isDebuggingEnabled;
+
+  struct {
+    BOOL hasExpand:1;
+    BOOL hasSize:1;
+    BOOL hasHelp:1;
+    BOOL hasPipelining;
+  } extensions;
+}
+
++ (id)smtpClient;
+- (id)initWithSocket:(id<NGActiveSocket>)_socket; // designated initializer
+
+// accessors
+
+- (id<NGActiveSocket>)socket;
+- (NGSmtpState)state;
+
+- (void)setDebuggingEnabled:(BOOL)_flag;
+- (BOOL)isDebuggingEnabled;
+
+// connection
+
+- (BOOL)connectToHost:(id)_host;
+- (BOOL)connectToAddress:(id<NGSocketAddress>)_address;
+- (void)disconnect;
+
+// state
+
+- (void)requireState:(NGSmtpState)_state;
+- (void)denyState:(NGSmtpState)_state;
+- (void)gotoState:(NGSmtpState)_state;
+
+// replies
+
+- (NGSmtpResponse *)receiveReply;
+
+// commands
+
+- (NGSmtpResponse *)sendCommand:(NSString *)_command;
+- (NGSmtpResponse *)sendCommand:(NSString *)_command argument:(NSString *)arg;
+
+// service commands
+
+- (BOOL)quit;
+- (BOOL)helloWithHostname:(NSString *)_host;
+- (BOOL)hello;
+- (BOOL)noop;
+- (BOOL)reset;
+
+- (NSString *)help;
+- (NSString *)helpForTopic:(NSString *)_topic;
+
+- (BOOL)verifyAddress:(id)_address;
+
+// transaction commands
+
+- (BOOL)mailFrom:(id)_sender;
+- (BOOL)recipientTo:(id)_receiver;
+- (BOOL)sendData:(NSData *)_data;
+
+@end
+
+#endif /* __NGMail_NGSmtpClient_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGSmtpClient.m b/skyrix-core/NGMime/NGMail/NGSmtpClient.m
new file mode 100644 (file)
index 0000000..115f640
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGSmtpClient.h"
+#include "NGSmtpSupport.h"
+#include "NGSmtpReplyCodes.h"
+#include "common.h"
+
+@interface NGSmtpClient(PrivateMethods)
+- (void)_fetchExtensionInfo;
+@end
+
+@implementation NGSmtpClient
+
++ (int)version {
+  return 2;
+}
+
++ (id)smtpClient {
+  NGActiveSocket *s;
+  s = [NGActiveSocket socketInDomain:[NGInternetSocketDomain domain]];
+  return [[[self alloc] initWithSocket:s] autorelease];
+}
+
+- (id)init {
+  NSLog(@"%@: init not supported, use initWithSocket: ..", self);
+  [self release];
+  return nil;
+}
+
+- (id)initWithSocket:(id<NGActiveSocket>)_socket { // designated initializer
+  if ((self = [super init])) {
+    self->socket = [_socket retain];
+    NSAssert(self->socket, @"invalid socket parameter");
+
+    [self setDebuggingEnabled:YES];
+
+    self->connection = 
+      [(NGBufferedStream *)[NGBufferedStream alloc] initWithSource:_socket];
+    self->text = 
+      [(NGCTextStream *)[NGCTextStream alloc] initWithSource:self->connection];
+
+    self->state = [self->socket isConnected]
+      ? NGSmtpState_connected
+      : NGSmtpState_unconnected;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->text       release];
+  [self->connection release];
+  [self->socket     release];
+  [super dealloc];
+}
+
+// accessors
+
+- (id<NGActiveSocket>)socket {
+  return self->socket;
+}
+
+- (NGSmtpState)state {
+  return self->state;
+}
+
+- (void)setDebuggingEnabled:(BOOL)_flag {
+  self->isDebuggingEnabled = _flag;
+}
+- (BOOL)isDebuggingEnabled {
+  return self->isDebuggingEnabled;
+}
+
+// connection
+
+- (BOOL)connectToHost:(id)_host {
+  return [self connectToAddress:
+                 [NGInternetSocketAddress addressWithService:@"smtp"
+                                          onHost:_host protocol:@"tcp"]];
+}
+
+- (BOOL)connectToAddress:(id<NGSocketAddress>)_address {
+  NGSmtpResponse *greeting = nil;
+
+  [self requireState:NGSmtpState_unconnected];
+  
+  if (self->isDebuggingEnabled)
+    [NGTextErr writeFormat:@"C: connect to %@\n", _address];
+  
+  [self->socket connectToAddress:_address];
+
+  // receive greetings from server
+  greeting = [self receiveReply];
+  if (self->isDebuggingEnabled)
+    [NGTextErr writeFormat:@"S: %@\n", greeting];
+
+  if ([greeting isPositive]) {
+    [self gotoState:NGSmtpState_connected];
+    [self _fetchExtensionInfo];
+
+    if (self->isDebuggingEnabled) {
+      if (self->extensions.hasPipelining)
+        [NGTextErr writeFormat:@"S: pipelining extension supported.\n"];
+      if (self->extensions.hasSize)
+        [NGTextErr writeFormat:@"S: size extension supported.\n"];
+      if (self->extensions.hasHelp)
+        [NGTextErr writeFormat:@"S: help extension supported.\n"];
+      if (self->extensions.hasExpand)
+        [NGTextErr writeFormat:@"S: expand extension supported.\n"];
+    }
+    return YES;
+  }
+  else {
+    [self disconnect];
+    return NO;
+  }
+}
+
+- (void)disconnect {
+  [text   flush];
+  [socket close];
+  [self gotoState:NGSmtpState_unconnected];
+}
+
+// state
+
+- (void)requireState:(NGSmtpState)_state {
+  if (_state != [self state]) {
+    [NSException raise:@"SMTPException"
+                 format:@"require state %i, now in %i", _state, [self state]];
+  }
+}
+- (void)denyState:(NGSmtpState)_state {
+  if ([self state] == _state) {
+    [NSException raise:@"SMTPException"
+                 format:@"not allowed in state %i", [self state]];
+  }
+}
+
+- (void)gotoState:(NGSmtpState)_state {
+  self->state = _state;
+}
+
+- (BOOL)isTransactionInProgress {
+  return (self->state == NGSmtpState_TRANSACTION);
+}
+- (void)abortTransaction {
+  [self gotoState:NGSmtpState_connected];
+}
+
+// replies
+
+- (NGSmtpResponse *)receiveReply {
+  NSMutableString *desc = nil;
+  NSString        *line = nil;
+  NGSmtpReplyCode code  = -1;
+
+  line = [self->text readLineAsString];
+  if ([line length] < 4) {
+    NSLog(@"SMTP: reply has invalid format (%@)", line);
+    return nil;
+  }
+  code = [[line substringToIndex:3] intValue];
+  //if (self->isDebuggingEnabled)
+  //  [NGTextErr writeFormat:@"S: reply with code %i follows ..\n", code];
+
+  desc = [NSMutableString stringWithCapacity:[line length]];
+  while ([line characterAtIndex:3] == '-') {
+    if ([line length] < 4) {
+      NSLog(@"SMTP: reply has invalid format (text=%@, line=%@)", desc, line);
+      break;
+    }
+    [desc appendString:[line substringFromIndex:4]];
+    [desc appendString:@"\n"];
+    line = [self->text readLineAsString];
+  }
+  if ([line length] >= 4)
+    [desc appendString:[line substringFromIndex:4]];
+
+  return [NGSmtpResponse responseWithCode:code text:desc];
+}
+
+// commands
+
+- (NGSmtpResponse *)sendCommand:(NSString *)_command {
+  if (self->isDebuggingEnabled) {
+    [NGTextOut writeFormat:@"C: %@\n", _command];
+    [NGTextOut flush];
+  }
+  
+  [text writeString:_command];
+  [text writeString:@"\r\n"];
+  [text flush];
+  return [self receiveReply];
+}
+- (NGSmtpResponse *)sendCommand:(NSString *)_command argument:(NSString *)_argument {
+  if (self->isDebuggingEnabled) {
+    [NGTextOut writeFormat:@"C: %@ %@\n", _command, _argument];
+    [NGTextOut flush];
+  }
+  
+  [text writeString:_command];
+  [text writeString:@" "];
+  [text writeString:_argument];
+  [text writeString:@"\r\n"];
+  [text flush];
+  return [self receiveReply];
+}
+
+// service commands
+
+- (void)_fetchExtensionInfo {
+  NGSmtpResponse *reply = nil;
+  NSString       *hostName = nil;
+  
+  hostName = [(NGInternetSocketAddress *)[self->socket localAddress] hostName];
+
+  reply = [self sendCommand:@"EHLO" argument:hostName];
+  if ([reply code] == NGSmtpActionCompleted) {
+    NSEnumerator *lines = [[[reply text] componentsSeparatedByString:@"\n"]
+                                   objectEnumerator];
+    NSString     *line = nil;
+
+    if (self->isDebuggingEnabled) [NGTextErr writeFormat:@"S: %@\n", reply];
+
+    while ((line = [lines nextObject])) {
+      if ([line hasPrefix:@"EXPN"])
+        self->extensions.hasExpand = YES;
+      else if ([line hasPrefix:@"SIZE"])
+        self->extensions.hasSize = YES;
+      else if ([line hasPrefix:@"PIPELINING"])
+        self->extensions.hasPipelining = YES;
+      else if ([line hasPrefix:@"HELP"])
+        self->extensions.hasHelp = YES;
+    }
+    lines = nil;
+  }
+  else {
+    if (self->isDebuggingEnabled) {
+      [NGTextErr writeFormat:@"S: %@\n", reply];
+      [NGTextErr writeFormat:@" .. could not get extension info.\n"];
+    }
+  }
+}
+
+- (BOOL)_simpleServiceCommand:(NSString *)_command expectCode:(NGSmtpReplyCode)_code {
+  NGSmtpResponse *reply = nil;
+
+  [self denyState:NGSmtpState_unconnected];
+
+  reply = [self sendCommand:_command];
+  if (self->isDebuggingEnabled) [NGTextErr writeFormat:@"S: %@\n", reply];
+  if ([reply isPositive]) {
+    if ([reply code] != _code)
+      NSLog(@"SMTP(%@): expected reply code %i, got code %i ..",
+            _command, _code, [reply code]);
+    return YES;
+  }
+  return NO;
+}
+
+- (BOOL)quit {
+  NGSmtpResponse *reply = nil;
+
+  [self requireState:NGSmtpState_connected];
+  
+  reply = [self sendCommand:@"QUIT"];
+  if (self->isDebuggingEnabled) [NGTextErr writeFormat:@"S: %@\n", reply];
+  if ([reply isPositive]) {
+    unsigned int waitBytes = 0;
+    
+    if ([reply code] == NGSmtpServiceClosingChannel) {
+      // wait for connection close ..
+      while ([self->connection readByte] != -1)
+        waitBytes++;
+    }
+    else
+      NSLog(@"SMTP(QUIT): unexpected reply code (%i), disconnecting ..", [reply code]);
+    return YES;
+  }
+  return NO;
+}
+
+- (BOOL)helloWithHostname:(NSString *)_host {
+  NGSmtpResponse *reply = nil;
+
+  [self denyState:NGSmtpState_unconnected];
+  
+  reply = [self sendCommand:@"HELO" argument:_host];
+  if (self->isDebuggingEnabled) [NGTextErr writeFormat:@"S: %@\n", reply];
+  if ([reply isPositive]) {
+    if ([reply code] != NGSmtpActionCompleted) {
+      NSLog(@"SMTP(HELO): expected reply code %i, got code %i ..",
+            NGSmtpActionCompleted, [reply code]);
+    }
+    return YES;
+  }
+  return NO;
+}
+- (BOOL)hello {
+  NSString *hostName = nil;
+  hostName = [(NGInternetSocketAddress *)[self->socket localAddress] hostName];
+  return [self helloWithHostname:hostName];
+}
+
+- (BOOL)noop {
+  return [self _simpleServiceCommand:@"NOOP" expectCode:NGSmtpActionCompleted];
+}
+
+- (BOOL)reset {
+  if ([self _simpleServiceCommand:@"RSET" expectCode:NGSmtpActionCompleted]) {
+    if ([self isTransactionInProgress])
+      [self abortTransaction];
+    return YES;
+  }
+  else
+    return NO;
+}
+
+- (NSString *)help {
+  NGSmtpResponse *reply = nil;
+
+  [self denyState:NGSmtpState_unconnected];
+  
+  reply = [self sendCommand:@"HELP"];
+  if (self->isDebuggingEnabled) [NGTextErr writeFormat:@"S: %@\n", reply];
+  if ([reply isPositive]) {
+    if ([reply code] != NGSmtpHelpMessage) {
+      NSLog(@"SMTP(HELP): expected reply code %i, got code %i ..",
+            NGSmtpHelpMessage, [reply code]);
+    }
+    return [reply text];
+  }
+  return nil;
+}
+- (NSString *)helpForTopic:(NSString *)_topic {
+  NGSmtpResponse *reply = nil;
+  [self denyState:NGSmtpState_unconnected];
+  
+  reply = [self sendCommand:@"HELP" argument:_topic];
+  if (self->isDebuggingEnabled) [NGTextErr writeFormat:@"S: %@\n", reply];
+  if ([reply isPositive]) {
+    if ([reply code] != NGSmtpHelpMessage) {
+      NSLog(@"SMTP(HELP): expected reply code %i, got code %i ..",
+            NGSmtpHelpMessage, [reply code]);
+    }
+    return [reply text];
+  }
+  return nil;
+}
+
+- (BOOL)verifyAddress:(id)_address {
+  NGSmtpResponse *reply = nil;
+  [self denyState:NGSmtpState_unconnected];
+
+  reply = [self sendCommand:@"VRFY" argument:[_address stringValue]];
+  if (self->isDebuggingEnabled) [NGTextErr writeFormat:@"S: %@\n", reply];
+  if ([reply isPositive]) {
+    if ([reply code] != NGSmtpActionCompleted) {
+      NSLog(@"SMTP(VRFY): expected reply code %i, got code %i ..",
+            NGSmtpActionCompleted, [reply code]);
+    }
+    return YES;
+  }
+  else if ([reply code] == NGSmtpMailboxNotFound) {
+    return NO;
+  }
+  else {
+    NSLog(@"SMTP(VRFY): expected positive or 550 reply code, got code %i ..", [reply code]);
+    return NO;
+  }
+}
+
+// transaction commands
+
+- (BOOL)mailFrom:(id)_sender {
+  NGSmtpResponse *reply  = nil;
+  NSString       *sender = nil;
+  [self requireState:NGSmtpState_connected];
+
+  sender = [@"FROM:" stringByAppendingString:[_sender stringValue]];
+  reply  = [self sendCommand:@"MAIL" argument:sender];
+  if ([reply isPositive]) {
+    if ([reply code] != NGSmtpActionCompleted) {
+      NSLog(@"SMTP(MAIL FROM): expected reply code %i, got code %i ..",
+            NGSmtpActionCompleted, [reply code]);
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (BOOL)recipientTo:(id)_receiver {
+  NGSmtpResponse *reply = nil;
+  NSString       *rcpt  = nil;
+  
+  [self requireState:NGSmtpState_TRANSACTION];
+  
+  rcpt  = [@"TO:" stringByAppendingString:[_receiver stringValue]];
+  reply = [self sendCommand:@"RCPT" argument:rcpt];
+  if ([reply isPositive]) {
+    if ([reply code] != NGSmtpActionCompleted) {
+      NSLog(@"SMTP(RCPT TO): expected reply code %i, got code %i ..",
+            NGSmtpActionCompleted, [reply code]);
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (BOOL)sendData:(NSData *)_data {
+  NGSmtpResponse *reply = nil;
+  
+  [self requireState:NGSmtpState_TRANSACTION];
+
+  reply = [self sendCommand:@"DATA"];
+  if (self->isDebuggingEnabled) [NGTextErr writeFormat:@"S: %@\n", reply];
+  if (([reply code] >= 300) && ([reply code] < 400)) {
+    if ([reply code] != NGSmtpStartMailInput) {
+      NSLog(@"SMTP(DATA): expected reply code %i, got code %i ..",
+            NGSmtpStartMailInput, [reply code]);
+    }
+    [self->text flush];
+
+    if (self->isDebuggingEnabled)
+      [NGTextErr writeFormat:@"C: data(%i bytes) ..\n", [_data bytes]];
+    
+    [self->connection safeWriteBytes:[_data bytes] count:[_data length]];
+    [self->connection safeWriteBytes:".\r\n" count:3];
+    [self->connection flush];
+
+    reply = [self receiveReply];
+    if (self->isDebuggingEnabled) [NGTextErr writeFormat:@"S: %@\n", reply];
+    if ([reply isPositive]) {
+      return YES;
+    }
+    else {
+      NSLog(@"SMTP(DATA): mail input failed, got code %i ..", [reply code]);
+    }
+  }
+  return NO;
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<SMTP-Client[0x%08X]: socket=%@>",
+                     (unsigned)self, [self socket]];
+}
+
+@end
diff --git a/skyrix-core/NGMime/NGMail/NGSmtpReplyCodes.h b/skyrix-core/NGMime/NGMail/NGSmtpReplyCodes.h
new file mode 100644 (file)
index 0000000..8040e18
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_NGSmtpReplyCodes_H__
+#define __NGMail_NGSmtpReplyCodes_H__
+
+/*
+  SMTP reply groups:
+
+    1yz Positive Preliminary reply
+
+       The command has been accepted, but the requested action is being held in
+       abeyance, pending confirmation of the information in this reply. The
+       sender-SMTP should send another command specifying whether to continue or
+       abort the action. 
+
+       [Note: SMTP does not have any commands that allow this type of reply, and
+        so does not have the continue or abort commands.]
+
+     2yz Positive Completion reply
+
+       The requested action has been successfully completed. A new request may
+       be initiated.
+
+     3yz Positive Intermediate reply
+
+       The command has been accepted, but the requested action is being held in
+       abeyance, pending receipt of further information. The sender-SMTP should
+       send another command specifying this information. This reply is used in
+       command sequence groups.
+
+     4yz Transient Negative Completion reply
+
+       The command was not accepted and the requested action did not occur.
+       However, the error condition is temporary and the action may be requested
+       again. The sender should return to the beginning of the command sequence
+       (if any). It is difficult to assign a meaning to "transient" when two
+       different sites (receiver- and sender- SMTPs) must agree on the
+       interpretation. Each reply in this category might have a different time
+       value, but the sender-SMTP is encouraged to try again.
+       A rule of thumb to determine if a reply fits into the 4yz or the 5yz
+       category (see below) is that replies are 4yz if they can be repeated
+       without any change in command form or in properties of the sender or
+       receiver. (E.g., the command is repeated identically and the receiver
+       does not put up a new implementation.)
+
+     5yz Permanent Negative Completion reply
+
+       The command was not accepted and the requested action did not occur. The
+       sender-SMTP is discouraged from repeating the exact request (in the same
+       sequence). Even some "permanent" error conditions can be corrected, so the
+       human user may want to direct the sender-SMTP to reinitiate the command
+       sequence by direct action at some point in the future (e.g., after the
+       spelling has been changed, or the user has altered the account status).
+
+   Second digit description:
+
+     The second digit encodes responses in specific categories: 
+
+     x0z Syntax 
+       These replies refer to syntax errors, syntactically correct commands that
+       don't fit any functional category, and unimplemented or superfluous
+       commands. 
+
+     x1z Information 
+       These are replies to requests for information, such as status or help. 
+
+     x2z Connections 
+       These are replies referring to the transmission channel. 
+
+     x3z Unspecified as yet. 
+     x4z Unspecified as yet. 
+
+     x5z Mail system 
+       These replies indicate the status of the receiver mail system vis-a-vis
+       the requested transfer or other mail system action. 
+*/
+
+typedef enum {
+  NGSmtpInvalidReplyCode          = -1,
+  
+  // 100 codes, positive preliminary reply
+
+  // 200 codes, positive completion reply
+  NGSmtpSystemStatus              = 211,
+  NGSmtpHelpMessage               = 214,
+  NGSmtpServiceReady              = 220,
+  NGSmtpServiceClosingChannel     = 221,
+  NGSmtpActionCompleted           = 250,
+  NGSmtpUserNotLocalWillForward   = 251,
+
+  // 300 codes, positive intermediate reply
+  NGSmtpStartMailInput            = 354,
+
+  // 400 codes, transient negative completion reply
+  NGSmtpServiceNotAvailable       = 421,
+  NGSmtpMailboxBusy               = 450,
+  NGSmtpErrorInProcessing         = 451,
+  NGSmtpInsufficientStorage       = 452,
+  
+  // 500 codes, permanent negative completion reply
+  NGSmtpInvalidCommand            = 500,
+  NGSmtpInvalidParameter          = 501,
+  NGSmtpCommandNotImplemented     = 502,
+  NGSmtpBadCommandSequence        = 503,
+  NGSmtpParameterNotImplemented   = 504,
+  NGSmtpMailboxNotFound           = 550,
+  NGSmtpUserNotLocalTryForward    = 551,
+  NGSmtpExceededStorageAllocation = 552,
+  NGSmtpMailboxNameNotAllowed     = 553,
+  NGSmtpTransactionFailed         = 554
+} NGSmtpReplyCode;
+
+#endif /* __NGMail_NGSmtpReplyCodes_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGSmtpSupport.h b/skyrix-core/NGMime/NGMail/NGSmtpSupport.h
new file mode 100644 (file)
index 0000000..9863885
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_NGSmtpSupport_H__
+#define __NGMail_NGSmtpSupport_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMail/NGSmtpReplyCodes.h>
+
+@class NSString;
+
+
+NSString *NGSmtpDescriptionForReplyCode(NGSmtpReplyCode _code);
+
+
+@interface NGSmtpResponse : NSObject
+{
+@protected
+  NGSmtpReplyCode code;
+  NSString        *text;
+}
+
++ (id)responseWithCode:(NGSmtpReplyCode)_code text:(NSString *)_text;
+
+// accessors
+
+- (NGSmtpReplyCode)code;
+- (NSString *)text;
+
+// special accessors
+
+- (NSString *)lastLine;
+
+- (BOOL)isPositive;          // <400 code groups
+- (BOOL)isTransientNegative; // 400 code group
+- (BOOL)isPermanentNegative; // 500 code group
+
+@end
+
+#endif /* __NGMail_NGSmtpSupport_H__ */
diff --git a/skyrix-core/NGMime/NGMail/NGSmtpSupport.m b/skyrix-core/NGMime/NGMail/NGSmtpSupport.m
new file mode 100644 (file)
index 0000000..0ce5846
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGSmtpSupport.h"
+#include "common.h"
+
+NSString *NGSmtpDescriptionForReplyCode(NGSmtpReplyCode _code) {
+  NSString *text = nil;
+  
+  switch (_code) {
+
+    // 100 codes, positive preliminary  reply
+
+    // 200 codes, positive completion reply
+
+    case NGSmtpSystemStatus:            // 211
+      text = @"System status, or system help reply";
+      break;
+    case NGSmtpHelpMessage:             // 214
+      text = @"Help message";
+      break;
+    case NGSmtpServiceReady:            // 220
+      text = @"<domain> Service ready";
+      break;
+    case NGSmtpServiceClosingChannel:   // 221
+      text = @"<domain> Service closing transmission channel";
+      break;
+    case NGSmtpActionCompleted:         // 250
+      text = @"Requested mail action okay, completed";
+      break;
+    case NGSmtpUserNotLocalWillForward: // 251
+      text = @"User not local; will forward to <forward-path>";
+      break;
+
+    // 300 codes, positive intermediate reply
+      
+    case NGSmtpStartMailInput: // 354
+      text = @"Start mail input; end with <CRLF>.<CRLF>";
+      break;
+
+    // 400 codes, transient negative completion reply
+      
+    case NGSmtpServiceNotAvailable: // 421
+      text = @"<domain> Service not available, closing transmission channel";
+      break;
+    case NGSmtpMailboxBusy:         // 450
+      text = @"Requested mail action not taken: mailbox unavailable [E.g., mailbox busy]";
+      break;
+    case NGSmtpErrorInProcessing:   // 451
+      text = @"Requested action aborted: local error in processing";
+      break;
+    case NGSmtpInsufficientStorage: // 452
+      text = @"Requested action not taken: insufficient system storage";
+      break;
+
+    // 500 codes, permanent negative completion reply
+      
+    case NGSmtpInvalidCommand:          // 500
+      text = @"Syntax error, command unrecognized "
+             @"[This may include errors such as command line too long]";
+      break;
+    case NGSmtpInvalidParameter:        // 501
+      text = @"Syntax error in parameters or arguments";
+      break;
+    case NGSmtpCommandNotImplemented:   // 502
+      text = @"Command not implemented";
+      break;
+    case NGSmtpBadCommandSequence:      // 503
+      text = @"Bad sequence of commands";
+      break;
+    case NGSmtpParameterNotImplemented: // 504
+      text = @"Command parameter not implemented";
+      break;
+      
+    case NGSmtpMailboxNotFound:           // 550
+      text = @"Requested action not taken: mailbox unavailable "
+             @"[E.g., mailbox not found, no access]";
+      break;
+    case NGSmtpUserNotLocalTryForward:    // 551
+      text = @"User not local; please try <forward-path>";
+      break;
+    case NGSmtpExceededStorageAllocation: // 552
+      text = @"Requested mail action aborted: exceeded storage allocation";
+      break;
+    case NGSmtpMailboxNameNotAllowed:     // 553
+      text = @"Requested action not taken: mailbox name not allowed"
+             @"[E.g., mailbox syntax incorrect]";
+      break;
+    case NGSmtpTransactionFailed:         // 554
+      text = @"Transaction failed";
+      break;
+    
+    default:
+      text = [NSString stringWithFormat:@"<SMTP ReplyCode: %i>", _code];
+      break;
+  }
+  return text;
+}
+
+@implementation NGSmtpResponse
+
++ (int)version {
+  return 2;
+}
+
+- (id)initWithCode:(NGSmtpReplyCode)_code text:(NSString *)_text {
+  if ((self = [super init])) {
+    self->code = _code;
+    self->text = [_text copy];
+  }
+  return self;
+}
+
++ (id)responseWithCode:(NGSmtpReplyCode)_code text:(NSString *)_text {
+  return [[[self alloc] initWithCode:_code text:_text] autorelease];
+}
+
+- (void)dealloc {
+  [self->text release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NGSmtpReplyCode)code {
+  return self->code;
+}
+
+- (NSString *)text {
+  return self->text;
+}
+
+/* values */
+
+- (int)intValue {
+  return [self code];
+}
+- (NSString *)stringValue {
+  return [self text];
+}
+
+/* special accessors */
+
+- (NSString *)lastLine {
+  const char *cstr = [[self text] cString];
+  unsigned   len   = [[self text] cStringLength];
+
+  if (cstr) {
+    cstr += len;   // goto '\0'
+    cstr--; len--; // goto last char
+    while ((*cstr != '\n') && (len > 0)) {
+      cstr--;
+      len--;
+    }
+  }
+  else
+    len = 0;
+  return (len > 0) ? [NSString stringWithCString:(cstr + 1)] : [self text];
+}
+
+- (BOOL)isPositive {
+  return ((self->code >= 200) && (self->code < 300));
+}
+
+- (BOOL)isTransientNegative {
+  return ((self->code >= 400) && (self->code < 500));
+}
+- (BOOL)isPermanentNegative {
+  return ((self->code >= 500) && (self->code < 600));
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<SMTP-Reply: code=%i line='%@'>",
+                     [self code], [self lastLine]];
+}
+
+@end /* NGSmtpResponse */
diff --git a/skyrix-core/NGMime/NGMail/README b/skyrix-core/NGMime/NGMail/README
new file mode 100644 (file)
index 0000000..208d16b
--- /dev/null
@@ -0,0 +1,19 @@
+// $Id$
+
+Copyright 2000-2003 - SKYRIX Software AG
+--------------------------------------------------------------------------------
+
+NGMail Objective-C Kit
+
+  Class-Hierachy
+  
+    NSObject
+      NGMBoxReader
+      NGPop3Client
+      NGPop3MessageInfo
+      NGSmtpClient
+      NGSmtpResponse
+  
+    NSException
+      NGPop3Exception
+        NGPop3StateException
diff --git a/skyrix-core/NGMime/NGMail/common.h b/skyrix-core/NGMime/NGMail/common.h
new file mode 100644 (file)
index 0000000..be6aba2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMail_common_H__
+#define __NGMail_common_H__
+
+#include <Foundation/Foundation.h>
+
+#include <NGExtensions/NGExtensions.h>
+#include <NGStreams/NGStreams.h>
+#include <NGStreams/NGNet.h>
+#include <NGMime/NGMime.h>
+
+#ifndef __MINGW32__
+#  include <strings.h>
+#endif
+
+#endif /* __NGMail_common_H__ */
diff --git a/skyrix-core/NGMime/NGMail/libNGMail.def b/skyrix-core/NGMime/NGMail/libNGMail.def
new file mode 100644 (file)
index 0000000..1e1ff9e
--- /dev/null
@@ -0,0 +1,21 @@
+EXPORTS
+       __objc_class_name_NGMBoxReader;
+       __objc_class_name_NGMail;
+       __objc_class_name_NGMailAddress;
+       __objc_class_name_NGMailAddressList;
+       __objc_class_name_NGMailAddressParser;
+       __objc_class_name_NGMimeMessage;
+       __objc_class_name_NGMimeMessageBodyGenerator;
+       __objc_class_name_NGMimeMessageGenerator;
+       __objc_class_name_NGMimeMessageMultipartBodyGenerator;
+       __objc_class_name_NGMimeMessageParser;
+       __objc_class_name_NGMimeMessageRfc822BodyGenerator;
+       __objc_class_name_NGMimeMessageTextBodyGenerator;
+       __objc_class_name_NGPop3Client;
+       __objc_class_name_NGPop3Exception;
+       __objc_class_name_NGPop3MailDropEnumerator;
+       __objc_class_name_NGPop3MessageInfo;
+       __objc_class_name_NGPop3Response;
+       __objc_class_name_NGPop3StateException;
+       __objc_class_name_NGSmtpClient;
+       __objc_class_name_NGSmtpResponse;
diff --git a/skyrix-core/NGMime/NGMime-Info.plist b/skyrix-core/NGMime/NGMime-Info.plist
new file mode 100644 (file)
index 0000000..29026be
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGMime</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.core.NGMime</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-core/NGMime/NGMime.h b/skyrix-core/NGMime/NGMime.h
new file mode 100644 (file)
index 0000000..7c721b0
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMime_H__
+#define __NGMime_NGMime_H__
+
+#include <NGMime/NGMimeBodyGenerator.h>
+#include <NGMime/NGMimeBodyParser.h>
+#include <NGMime/NGMimeBodyPart.h>
+#include <NGMime/NGMimeBodyPartParser.h>
+#include <NGMime/NGMimeExceptions.h>
+#include <NGMime/NGMimeGeneratorProtocols.h>
+#include <NGMime/NGMimeHeaderFieldGenerator.h>
+#include <NGMime/NGMimeHeaderFieldParser.h>
+#include <NGMime/NGMimeHeaderFields.h>
+#include <NGMime/NGMimeMultipartBody.h>
+#include <NGMime/NGMimePartGenerator.h>
+#include <NGMime/NGMimePartParser.h>
+#include <NGMime/NGMimeType.h>
+#include <NGMime/NGMimeUtilities.h>
+#include <NGMime/NGPart.h>
+
+// kit class
+
+@interface NGMime : NSObject
++ (NSString *)libraryVersion;
+@end
+
+#define LINK_NGMime \
+  static void __link_NGMime(void) { \
+    [NGMime self]; \
+    __link_NGMime(); \
+  }
+
+#endif /* __NGMime_NGMime_H__ */
diff --git a/skyrix-core/NGMime/NGMime.m b/skyrix-core/NGMime/NGMime.m
new file mode 100644 (file)
index 0000000..bd97c4a
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMime.h"
+
+#ifndef LIBRARY_MAJOR_VERSION
+#  if !COCOA_Foundation_LIBRARY && !NeXT_Foundation_LIBRARY
+#    warning library version not passed in as a default (using 4.2.0)
+#  endif
+#  define LIBRARY_MAJOR_VERSION 4
+#endif
+#ifndef LIBRARY_MINOR_VERSION
+#  define LIBRARY_MINOR_VERSION 2
+#endif
+#ifndef LIBRARY_SUBMINOR_VERSION
+#  define LIBRARY_SUBMINOR_VERSION 0
+#endif
+
+@implementation NGMime
+
++ (NSString *)libraryVersion {
+  static NSString *Version = nil;
+
+  if (Version == nil) {
+    Version = [[NSString alloc] initWithFormat:@"NGMime_%d.%d.%d",
+                        LIBRARY_MAJOR_VERSION, LIBRARY_MINOR_VERSION,
+                        LIBRARY_SUBMINOR_VERSION];
+  }
+  return Version;
+}
+
+
+
+- (void)_staticLinkClasses {
+}
+
+- (void)_staticLinkModules {
+}
+
+@end /* NGMime */
diff --git a/skyrix-core/NGMime/NGMimeAddressHeaderFieldGenerator.m b/skyrix-core/NGMime/NGMimeAddressHeaderFieldGenerator.m
new file mode 100644 (file)
index 0000000..e1aea78
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeHeaderFieldGenerator.h"
+#include "NGMimeHeaderFields.h"
+#include <NGMail/NGMailAddressParser.h>
+#include <NGMime/NGMimePartParser.h>
+#include "common.h"
+
+@interface NSObject(UsedProtocols)
+- (NSString *)displayName; // hh: where is that implemented ?
+@end
+
+@implementation NGMimeAddressHeaderFieldGenerator
+
+static int UseLFSeperatedAddressEntries = -1;
+
++ (int)version {
+  return 2;
+}
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
+  if (UseLFSeperatedAddressEntries == -1) {
+    id o;
+
+    if ((o = [ud objectForKey:@"UseLFSeperatedAddressEntries"]))
+      UseLFSeperatedAddressEntries = [o boolValue]?1:0;
+    else
+      UseLFSeperatedAddressEntries = 1;
+  }
+}
+
+/* operation */
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value
+{
+  NGMailAddressParser *parser;
+  NSMutableString     *result;
+  NSData              *data;
+  id                  obj;
+  NSEnumerator        *enumerator;
+  
+  parser = ([_value isKindOfClass:[NSString class]])
+    ? [NGMailAddressParser mailAddressParserWithString:_value]
+    : [NGMailAddressParser mailAddressParserWithData:_value];
+  
+  enumerator = [[parser parseAddressList] objectEnumerator];
+  result     = [[NSMutableString alloc] initWithCapacity:128];
+  
+  while ((obj = [enumerator nextObject])) {
+    NSString   *tmp;
+    char       *buffer;
+    unsigned   bufLen, cnt;
+    BOOL       doEnc;
+    
+    if ([result length] > 0) {
+      if (UseLFSeperatedAddressEntries == 1)
+        [result appendString:@",\n   "];
+      else
+        [result appendString:@", "];
+    }
+    
+    tmp    = [obj displayName];
+    bufLen = [tmp cStringLength];
+    
+    buffer = calloc(bufLen + 10, sizeof(char));
+    [tmp getCString:buffer];
+    
+    cnt   = 0;
+    doEnc = NO;
+    
+    while (cnt < bufLen) {
+      if ((unsigned char)buffer[cnt] > 127) {
+        doEnc = YES;
+        break;
+      }
+      cnt++;
+    }
+    
+    if (doEnc) {
+      unsigned char iso[]     = "=?iso-8859-15?q?";
+      unsigned      isoLen    = 16;
+      unsigned char isoEnd[]  = "?=";
+      unsigned      isoEndLen = 2;
+      unsigned      desLen;
+      unsigned char *des;
+      
+      free(buffer);
+      {
+        NSData *data;
+
+#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+        data = [tmp dataUsingEncoding:NSISOLatin1StringEncoding];
+#else
+        data = [tmp dataUsingEncoding:NSISOLatin9StringEncoding];
+#endif
+
+        bufLen  = [data length];
+        buffer =  malloc(bufLen+1);
+        [data getBytes:buffer];  buffer[bufLen] = '\0';
+      }
+          
+      desLen = bufLen * 3 + 20;
+      des    = calloc(desLen + 10, sizeof(char));
+      
+      memcpy(des, buffer, cnt);
+      memcpy(des + cnt, iso, isoLen);
+      desLen =
+        NGEncodeQuotedPrintableMime(buffer + cnt, bufLen - cnt,
+                                    des + cnt + isoLen,
+                                    desLen - cnt - isoLen);
+      if ((int)desLen != -1) {
+        memcpy(des + cnt + isoLen + desLen, isoEnd, isoEndLen);
+        tmp = [NSString stringWithCString:des
+                        length:(cnt + isoLen + desLen + isoEndLen)];
+      }
+      else {
+        [self logWithFormat:@"WARNING(%s:%i): An error occour during "
+               @"quoted-printable decoding",
+               __PRETTY_FUNCTION__, __LINE__];
+      }
+      if (des) free(des);
+    }
+    if (buffer) free(buffer); buffer = NULL;
+
+    if ([tmp length] > 0) {
+      [result appendString:@"\""];
+      [result appendString:tmp];
+      [result appendString:@"\""];
+      if ((tmp = [(NSHost *)obj address])) {
+        [result appendString:@" <"];
+        [result appendString:tmp];
+        [result appendString:@">"];
+      }
+    }
+    else if ((tmp = [(NSHost *)obj address])) {
+      [result appendString:tmp];
+    }
+  }
+  
+#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+  data = [result dataUsingEncoding:NSISOLatin1StringEncoding];
+#else
+  data = [result dataUsingEncoding:NSISOLatin9StringEncoding];
+#endif
+  [result release];
+  
+  return data;
+}
+
+@end /* NGMimeAddressHeaderFieldGenerator */
diff --git a/skyrix-core/NGMime/NGMimeBodyGenerator.h b/skyrix-core/NGMime/NGMimeBodyGenerator.h
new file mode 100644 (file)
index 0000000..fe0d3c9
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMimeGenerator_NGMimeBodyGenerator_H__
+#define __NGMimeGenerator_NGMimeBodyGenerator_H__
+
+#import <Foundation/NSObject.h>
+#import <NGMime/NGPart.h>
+#import <NGMime/NGMimeGeneratorProtocols.h>
+
+@class NSData, NSString, NSArray, NGMutableHashMap;
+@class NGMimeMultipartBodyGenerator, NGMimeMultipartBody;
+
+@interface NGMimeBodyGenerator : NSObject <NGMimeBodyGenerator>
+{
+  BOOL useMimeData;
+}
+- (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders
+  delegate:(id)_delegate;
+
+- (NSData *)encodeData:(NSData *)_data
+  forPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders;
+
+- (BOOL)useMimeData;
+- (void)setUseMimeData:(BOOL)_b;
+@end
+
+@interface NGMimeTextBodyGenerator : NGMimeBodyGenerator
+@end
+
+@interface NGMimeRfc822BodyGenerator : NGMimeBodyGenerator
+
+- (id<NGMimePartGenerator>)generatorForPart:(id<NGMimePart>)_part;
+
+@end
+
+@interface NGMimeMultipartBodyGenerator : NGMimeBodyGenerator
+
++ (NSString *)boundaryPrefix;
+
+- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
+  prefixForPart:(id<NGMimePart>)_part
+  mimeMultipart:(NGMimeMultipartBody *)_body;
+  
+- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
+  suffixForPart:(id<NGMimePart>)_part
+  mimeMultipart:(NGMimeMultipartBody *)_body;
+  
+- (id<NGMimePartGenerator>)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen
+  generatorForPart:(id<NGMimePart>)_part;
+
+- (NSData *)buildDataWithBoundary:(NSString *)_boundary
+  partsData:(NSArray *)_parts;
+
+- (NSString *)buildBoundaryForPart:(id<NGMimePart>)_part data:(NSArray *)_data
+  additionalHeaders:(NGMutableHashMap *)_addHeaders; 
+  
+@end
+
+#endif // __NGMimeGenerator_NGMimeBodyGenerator_H__
diff --git a/skyrix-core/NGMime/NGMimeBodyGenerator.m b/skyrix-core/NGMime/NGMimeBodyGenerator.m
new file mode 100644 (file)
index 0000000..c6050ae
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+  Copyright (C) 2000-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$
+
+#import "NGMimeBodyGenerator.h"
+#import "NGMimePartGenerator.h"
+#import "NGMimeMultipartBody.h"
+#import "NGMimeJoinedData.h"
+#import "NGMimeFileData.h"
+#import "common.h"
+#include <unistd.h>
+
+@implementation NGMimeBodyGenerator
+
++ (int)version {
+  return 2;
+}
+
+- (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders
+  delegate:(id)_delegate
+{
+  return [self encodeData:[_part body]
+               forPart:_part
+               additionalHeaders:_addHeaders];
+}
+
+- (NSData *)encodeData:(NSData *)_data
+  forPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders
+{
+  return _data;
+}
+
+- (BOOL)useMimeData {
+  return self->useMimeData;
+}
+
+- (void)setUseMimeData:(BOOL)_b {
+  self->useMimeData = _b;
+}
+
+@end /* NGMimeBodyGenerator */
+
+@implementation NGMimeTextBodyGenerator
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders
+  delegate:(id)_delegate
+{
+  NSStringEncoding encoding = [NSString defaultCStringEncoding];
+  NSData           *data    = nil;
+  id               body     = nil;
+  
+  body = [_part body];
+
+  if ([body isKindOfClass:[NSString class]]) {
+    data = [body dataUsingEncoding:encoding];
+  }
+  else
+    data = body;
+#if 0  
+  else {
+    NSLog(@"WARNING: textBodyGenerator expect that body is"
+          @" kind of class NSString");
+  }
+#endif  
+  if (data == nil) {
+    NSLog(@"WARNING(%s): generate empty body", __PRETTY_FUNCTION__);
+    data = [NSData data];
+  }
+  return [self encodeData:data forPart:_part additionalHeaders:_addHeaders];
+}
+
+@end /* NGMimeTextBodyGenerator */
+
+@implementation NGMimeRfc822BodyGenerator
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id<NGMimePartGenerator>)generatorForPart:(id<NGMimePart>)_part {
+  id g;
+
+  g = [[[NGMimePartGenerator allocWithZone:[self zone]] init]
+                             autorelease];
+  [g setUseMimeData:self->useMimeData];
+  return g;
+}
+
+- (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders
+  delegate:(id)_delegate
+{
+  NSData              *data = nil;
+  NGMimePartGenerator *gen  = nil;
+  
+  gen = (NGMimePartGenerator *)[self generatorForPart:_part];
+  [gen setDelegate:_delegate];
+  data = [gen generateMimeFromPart:[_part body]];
+  return data;
+}
+
+@end /* NGMimeRfc822BodyGenerator */
+
+
+@implementation NGMimeMultipartBodyGenerator
+
+static Class NGMimeFileDataClass   = Nil;
+static Class NGMimeJoinedDataClass = Nil;
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+
+  NGMimeFileDataClass   = [NGMimeFileData class];
+  NGMimeJoinedDataClass = [NGMimeJoinedData class];
+}
+
++ (NSString *)boundaryPrefix {
+  static NSString *BoundaryPrefix = nil;
+  
+  if (BoundaryPrefix == nil) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    BoundaryPrefix = 
+      [[ud stringForKey:@"NGMime_MultipartBoundaryPrefix"] copy];
+    if (BoundaryPrefix == nil)
+      BoundaryPrefix = @"--=_=-_OpenGroupware_org_NGMime";
+  }
+  return BoundaryPrefix;
+}
+
+static inline BOOL _isBoundaryInArray(NGMimeMultipartBodyGenerator *self,
+                                      NSString *_boundary,
+                                      NSArray *_data)
+{
+  const unsigned char *boundary;
+  unsigned int length;
+  NSEnumerator *enumerator;
+  NSData       *data;
+  BOOL         wasFound;
+
+  boundary   = [_boundary cString];
+  length     = [_boundary length];
+  enumerator = [_data objectEnumerator];
+  data       = nil;
+  wasFound   = NO;
+  
+  while ((data = [enumerator nextObject])) {
+    const unsigned char *bytes;
+    unsigned int dataLen;
+    unsigned     cnt;
+    
+    if ([data isKindOfClass:NGMimeFileDataClass] ||
+        [data isKindOfClass:NGMimeJoinedDataClass])
+      continue;
+    
+    bytes   = [data bytes];
+    dataLen = [data length];
+    cnt     = 0;
+    
+    if (dataLen < length)
+      return NO;
+      
+    while ((cnt < dataLen) && ((dataLen - cnt) >= length)) {
+      if (bytes[cnt + 2] != '-') { // can`t be a boundary
+       cnt++;
+       continue;
+      }
+
+      if (bytes[cnt] == '\n') {// LF*-
+       if (bytes[cnt + 1] == '-') { // LF--
+         if (strncmp(boundary, bytes + cnt + 3, length) == 0) {
+           wasFound = YES;
+           break;
+         }
+       }
+      }
+      else if (bytes[cnt] == '\r') { //CR*-
+       if (bytes[cnt + 1] == '-') { //CR--
+         if (strncmp(boundary, bytes + cnt + 3, length) == 0) {
+           wasFound = YES;
+           break;
+         }
+       }
+       else if ((bytes[cnt + 1] == '\n') && (bytes[cnt + 3] == '-')) {
+         if (strncmp(boundary, bytes + cnt + 4, length) == 0) { // CRLF--
+           wasFound = YES;
+           break;
+         }
+       }
+      }
+      cnt++;
+    }
+  }
+  return wasFound;
+}
+
+- (NSString *)buildBoundaryForPart:(id<NGMimePart>)_part data:(NSArray *)_data
+  additionalHeaders:(NGMutableHashMap *)_addHeaders 
+{
+  static   int       BoundaryUniqueCount = 0;
+  NSString *boundary = nil;
+  BOOL     isUnique  = NO;
+  unsigned pid;
+  
+  if ((boundary = [[_part contentType] valueOfParameter:@"boundary"]))
+    return boundary;
+  
+#if defined(__WIN32__)
+  pid = GetCurrentProcessId();
+#else
+  pid = getpid();
+#endif
+  
+  boundary = [NSString stringWithFormat:
+                       @"--%@-%d-%f-%d------",
+                       [NGMimeMultipartBodyGenerator boundaryPrefix],
+                       pid, [[NSDate date] timeIntervalSince1970],
+                       BoundaryUniqueCount++];
+  while (!isUnique) {
+    isUnique = _isBoundaryInArray(self, boundary, _data) ? NO : YES;
+    if (!isUnique)
+      boundary = [NSString stringWithFormat:
+                           @"--%@-%d-%f-%d-----",
+                           [NGMimeMultipartBodyGenerator boundaryPrefix],
+                           pid, [[NSDate date] timeIntervalSince1970],
+                           BoundaryUniqueCount++];
+  }
+  { // setting content-type with boundary
+    NGMimeType *type = nil;
+
+    type = [_part contentType];
+    
+    if (type == nil) {
+      NSDictionary *d;
+
+      d = [[NSDictionary alloc] initWithObjectsAndKeys:
+                                 boundary, @"boundary", nil];
+      type = [NGMimeType mimeType:@"multipart" subType:@"mixed"
+                         parameters:d];
+      [d release];
+    }
+    else {
+      NSMutableDictionary *dict = nil;
+      
+      dict = [NSMutableDictionary dictionaryWithDictionary:
+                                    [type parametersAsDictionary]];
+      [dict setObject:boundary forKey:@"boundary"];
+      type = [NGMimeType mimeType:[type type] subType:[type subType]
+                         parameters:dict];
+    }
+    [_addHeaders setObject:type forKey:@"content-type"];
+  }
+  return boundary;
+}
+
+- (NSData *)buildDataWithBoundary:(NSString *)_boundary
+  partsData:(NSArray *)_parts
+{
+  NSEnumerator  *enumerator;
+  NSData        *part;
+  NSMutableData *data;
+
+  data = (self->useMimeData)
+    ? [[[NGMimeJoinedData alloc] init] autorelease]
+    : [NSMutableData dataWithCapacity:4096];
+  
+  enumerator = [_parts objectEnumerator];
+  while ((part = [enumerator nextObject])) {
+    [data appendBytes:"--" length:2];
+    [data appendBytes:[_boundary cString] length:[_boundary length]];
+    [data appendBytes:"\n" length:1];
+    [data appendData:part];
+    [data appendBytes:"\n" length:1];
+  }
+  [data appendBytes:"--" length:2];
+  [data appendBytes:[_boundary cString] length:[_boundary length]];
+  [data appendBytes:"--\n" length:3];
+  return data;
+}
+
+- (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders
+  delegate:(id)_delegate
+{
+  // TODO: split up
+  NGMimeMultipartBody *body       = nil;
+  NSMutableData       *data       = nil;
+  id                  tmp         = nil;
+  NSArray             *parts      = nil;
+  id<NGMimePart>      part        = nil;
+  NSEnumerator        *enumerator = nil;
+  NSString            *boundary   = nil;
+  NSMutableArray      *partsData  = nil;
+  NSAutoreleasePool   *pool;
+
+  body = [_part body];
+
+  if (body == nil)
+    return [NSData data];
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  NSAssert1([body isKindOfClass:[NGMimeMultipartBody class]],
+            @"NGMimeMultipartBodyGenerator expect a NGMimeMultipartBody "
+            @"as body of part\n part: %@\n", _part);
+
+  data = (self->useMimeData)
+    ? [[[NGMimeJoinedData alloc] init] autorelease]
+    : [NSMutableData dataWithCapacity:4096];
+
+  if ([_delegate respondsToSelector:
+                   @selector(multipartBodyGenerator:prefixForPart:)])
+    tmp = [_delegate multipartBodyGenerator:self prefixForPart:_part];
+  else 
+    tmp = [self multipartBodyGenerator:self prefixForPart:_part
+                mimeMultipart:body];
+  if (tmp != nil) {
+    NSAssert([tmp isKindOfClass:[NSString class]],
+             @"prefix should be a NSString");
+    [data appendBytes:[tmp cString] length:[tmp length]];
+  }
+  
+  parts      = [body parts];
+  enumerator = [parts objectEnumerator];
+  partsData  = [[NSMutableArray allocWithZone:[self zone]] initWithCapacity:4];
+
+  while ((part = [enumerator nextObject])) {
+    id<NGMimePartGenerator> gen = nil;
+
+    if ([_delegate respondsToSelector:
+                   @selector(multipartBodyGenerator:generatorForPart:)]) {
+      gen = [_delegate multipartBodyGenerator:self generatorForPart:part];
+    }
+    else {
+      gen = [self multipartBodyGenerator:self generatorForPart:part];
+      [gen setDelegate:_delegate];
+      [(id)gen setUseMimeData:self->useMimeData];
+    }
+    if (gen == nil) {
+      NSLog(@"WARNING(%s): got no generator", __PRETTY_FUNCTION__);
+      continue;
+    }
+    tmp = [gen generateMimeFromPart:part];
+    if (tmp != nil) {
+      [partsData addObject:tmp];
+    }
+  }
+  boundary = [self buildBoundaryForPart:_part data:partsData
+                   additionalHeaders:_addHeaders];
+  tmp      = [self buildDataWithBoundary:boundary partsData:partsData];
+
+  if (tmp != nil) {
+    [data appendData:tmp];
+  }
+  else {
+    NSLog(@"WARNING(%s): couldn`t build multipart data", __PRETTY_FUNCTION__);
+  }
+  if ([_delegate respondsToSelector:
+                   @selector(multipartBodyGenerator:suffixForPart:)])
+    tmp = [_delegate multipartBodyGenerator:self suffixForPart:_part];
+  else 
+    tmp = [self multipartBodyGenerator:self suffixForPart:_part
+                mimeMultipart:body];
+  if (tmp != nil) {
+    NSAssert([tmp isKindOfClass:[NSString class]],
+             @"suffix should be a NSString");
+    [data appendBytes:[tmp cString] length:[tmp length]];
+  }
+  [partsData release]; partsData = nil;
+  [data retain];
+  [pool release];
+  return [data autorelease];
+}
+
+- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
+  prefixForPart:(id<NGMimePart>)_part
+  mimeMultipart:(NGMimeMultipartBody *)_body {
+  
+  return @""; // [_body prefix];
+}
+
+- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
+  suffixForPart:(id<NGMimePart>)_part
+  mimeMultipart:(NGMimeMultipartBody *)_body {
+
+  return @""; //[_body suffix];
+}
+
+- (id<NGMimePartGenerator>)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen
+  generatorForPart:(id<NGMimePart>)_part
+{
+  id gen;
+  
+  gen = [[NGMimePartGenerator alloc] init];
+  [gen setUseMimeData:self->useMimeData];
+  return [gen autorelease];
+}
+
+@end /* NGMimeMultipartBodyGenerator */
diff --git a/skyrix-core/NGMime/NGMimeBodyParser.h b/skyrix-core/NGMime/NGMimeBodyParser.h
new file mode 100644 (file)
index 0000000..70be604
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeBodyParser_H__
+#define __NGMime_NGMimeBodyParser_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMime/NGPart.h>
+
+@class NSData;
+
+@protocol NGMimeBodyParser < NSObject >
+
+- (id)parseBodyOfPart:(id<NGMimePart>)_part
+  data:(NSData *)_data
+  delegate:(id)_delegate;
+
+@end
+
+@interface NGMimeBodyParser : NSObject < NGMimeBodyParser >
+@end
+
+@interface NGMimeTextBodyParser : NGMimeBodyParser
+@end
+
+@class NGMimePartParser;
+@class NGMimeMultipartBody;
+
+/*
+  A multipart body is a part body that contains body-parts separated
+  by boundary lines.
+*/
+@interface NGMimeMultipartBodyParser : NGMimeBodyParser
+
+- (BOOL)parseBody:(NGMimeMultipartBody *)_body
+  ofMultipart:(id<NGMimePart>)_part
+  data:(NSData *)_data
+  delegate:(id)_d;
+
+- (id<NGMimePart>)parseBodyPartWithData:(NSData *)_rawData
+  inMultipart:(id<NGMimePart>)_multipart
+  parser:(NGMimePartParser *)_parser; // usually a NGMimeBodyPartParser
+
+@end
+
+@interface NSObject(NGMimeMultipartBodyParserDelegate)
+
+- (BOOL)multipartBodyParser:(NGMimeMultipartBodyParser *)_parser
+  immediatlyParseBodyOfMultipart:(id<NGMimePart>)_part
+  data:(NSData *)_data;
+
+- (void)multipartBodyParser:(NGMimeMultipartBodyParser *)_parser
+  foundPrefix:(NSData *)_prefix
+  inMultipart:(id<NGMimePart>)_part;
+
+- (void)multipartBodyParser:(NGMimeMultipartBodyParser *)_parser
+  foundSuffix:(NSData *)_suffix
+  inMultipart:(id<NGMimePart>)_part;
+
+- (NGMimePartParser *)multipartBodyParser:(NGMimeMultipartBodyParser *)_parser
+  parserForEntity:(NSData *)_data
+  inMultipart:(id<NGMimePart>)_part;
+
+@end
+
+#endif /* __NGMime_NGMimeBodyParser_H__ */
diff --git a/skyrix-core/NGMime/NGMimeBodyParser.m b/skyrix-core/NGMime/NGMimeBodyParser.m
new file mode 100644 (file)
index 0000000..34a3b5d
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeBodyParser.h"
+#include "NGMimeBodyPartParser.h"
+#include "NGMimeMultipartBody.h"
+#include "common.h"
+
+@implementation NGMimeBodyParser
+
++ (int)version {
+  return 2;
+}
+
+- (id)parseBodyOfPart:(id<NGMimePart>)_part
+  data:(NSData *)_data
+  delegate:(id)_d
+{
+  return _data;
+}
+
+@end /* NGMimeBodyParser */
+
+@implementation NGMimeTextBodyParser
+
+static int UseFoundationStringEncodingForMimeText = -1;
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  if (UseFoundationStringEncodingForMimeText == -1) {
+    UseFoundationStringEncodingForMimeText =
+      [ud boolForKey:@"UseFoundationStringEncodingForMimeText"]?1:0;
+  }
+}
+
+- (id)parseBodyOfPart:(id<NGMimePart>)_part data:(NSData *)_data
+  delegate:(id)_d
+{
+  NSString *charset;
+  id       ctype, body;
+
+  if (_data == nil) return nil;
+  
+  ctype = [_part contentType];
+  
+  if (![ctype isKindOfClass:[NGMimeType class]])
+    ctype = [NGMimeType mimeType:[ctype stringValue]];
+  
+  charset = [[ctype valueOfParameter:NGMimeParameterTextCharset]
+                    lowercaseString];
+  body     = nil;
+  
+  if (!UseFoundationStringEncodingForMimeText) {
+    if (![_data length])
+      return @"";
+
+    if (![[charset lowercaseString] isEqualToString:@"us-ascii"] &&
+        [charset length]) {
+      body = [NSString stringWithData:_data usingEncodingNamed:charset];
+    }
+  }
+  if (!body) {
+    NSStringEncoding encoding;
+    
+    encoding = [NGMimeType stringEncodingForCharset:charset];
+  
+    body = [[[NSString alloc]
+                       initWithData:_data
+                       encoding:encoding] autorelease];
+  }
+  return body;
+}
+
+@end /* NGMimeTextBodyParser */
+
diff --git a/skyrix-core/NGMime/NGMimeBodyPart.h b/skyrix-core/NGMime/NGMimeBodyPart.h
new file mode 100644 (file)
index 0000000..ca6a40a
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeBodyPart_H__
+#define __NGMime_NGMimeBodyPart_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMime/NGPart.h>
+
+@class NGHashMap;
+
+/*
+  NGMimeBodyPart is a part that is contained in a multipart body.
+*/
+@interface NGMimeBodyPart : NSObject < NGMimePart >
+{
+@protected
+  NGHashMap *header;
+  id        body;
+}
+
++ (id)bodyPartWithHeader:(NGHashMap *)_headers;
+- (id)initWithHeader:(NGHashMap *)_headers; // designated initializer
+
+/* NGPart */
+
+- (NSEnumerator *)valuesOfHeaderFieldWithName:(NSString *)_name;
+- (NSEnumerator *)headerFieldNames;
+
+- (void)setBody:(id)_body;
+- (id)body;
+
+/* NGMimePart */
+
+- (NGMimeType *)contentType;
+- (NSString *)contentId;
+- (NSArray *)contentLanguage;
+- (NSString *)contentMd5;
+- (NSString *)encoding;
+- (NSString *)contentDescription;
+
+@end
+
+#endif /* __NGMime_NGMimeBodyPart_H__ */
diff --git a/skyrix-core/NGMime/NGMimeBodyPart.m b/skyrix-core/NGMime/NGMimeBodyPart.m
new file mode 100644 (file)
index 0000000..633ca77
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeBodyPart.h"
+#include "NGMimeType.h"
+#include "common.h"
+#include "NGMimeFileData.h"
+#include <NGMime/NGMimePartParser.h>
+
+@implementation NGMimeBodyPart
+
++ (int)version {
+  return 2;
+}
+
+static NGMimeType *defaultType = nil;
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+    
+    defaultType =
+      [[NGMimeType mimeType:@"text/plain; charset=us-ascii"] retain];
+  }
+}
+  
++ (id)bodyPartWithHeader:(NGHashMap *)_header {
+  return [[[self alloc] initWithHeader:_header] autorelease];
+}
+
+- (id)initWithHeader:(NGHashMap *)_header {
+  if ((self = [super init])) {
+    self->header = [_header retain];
+    self->body   = nil;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithHeader:nil];
+}
+
+- (void)dealloc {
+  [self->header release];
+  [self->body   release];
+  [super dealloc];
+}
+
+/* NGPart */
+
+- (NSEnumerator *)valuesOfHeaderFieldWithName:(NSString *)_name {
+  return [self->header objectEnumeratorForKey:_name];
+}
+- (NSEnumerator *)headerFieldNames {
+  return [self->header keyEnumerator];
+}
+
+- (void)setBody:(id)_body {
+  ASSIGN(self->body, _body);
+}
+- (id)body {
+  return self->body;
+}
+
+/* NGMimePart */
+
+- (NGMimeType *)contentType {
+  id type;
+  static NGMimeHeaderNames *Fields = NULL;
+
+  if (!Fields)
+    Fields = (NGMimeHeaderNames *)[NGMimePartParser headerFieldNames];
+  
+  
+  type = [self->header objectForKey:Fields->contentType];
+  
+  if (![type isKindOfClass:[NGMimeType class]])
+    type = [NGMimeType mimeType:[type stringValue]];
+  
+  return (type != nil ? type : defaultType);
+}
+
+- (NSString *)contentId {
+  return [[self->header objectForKey:@"content-id"] stringValue];
+}
+
+- (NSArray *)contentLanguage {
+  id value;
+  
+  value = [self->header objectForKey:@"content-language"];
+  if (![value isKindOfClass:[NSArray class]])
+    value = [value componentsSeparatedByString:@","];
+
+  return value;
+}
+
+- (NSString *)contentMd5 {
+  return [[self->header objectForKey:@"content-md5"] stringValue];
+}
+
+- (NSString *)encoding {
+  return [[self->header objectForKey:@"content-transfer-encoding"]
+                        stringValue];
+}
+
+- (NSString *)contentDescription {
+  return [[self->header objectForKey:@"content-description"] stringValue];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *d = [[NSMutableString alloc] init];
+  id b = [self body];
+
+  [d appendFormat:@"<%@[0x%08X]: header=%@",
+       NSStringFromClass([self class]), self, self->header];
+
+  if (b) [d appendFormat:@" bodyClass=%@", NSStringFromClass([b class])];
+
+  if ([b isKindOfClass:[NGMimeFileData class]]) {
+    [d appendFormat:@" body=%@", b];
+  }
+  else if ([b isKindOfClass:[NSString class]] ||
+           [b isKindOfClass:[NSData class]]) {
+    if ([b length] < 512) {
+      [d appendFormat:@" bodyLen=%i body=%@", [b length], b];
+    }
+    else
+      [d appendFormat:@" body[len=%i]", [b length]];
+  }
+  else
+    [d appendFormat:@" body=%@", b];
+  
+
+  [d appendString:@">"];
+
+  return AUTORELEASE(d);
+}
+
+@end /* NGMimeBodyPart */
diff --git a/skyrix-core/NGMime/NGMimeBodyPartParser.h b/skyrix-core/NGMime/NGMimeBodyPartParser.h
new file mode 100644 (file)
index 0000000..cd47915
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeBodyPartParser_H__
+#define __NGMime_NGMimeBodyPartParser_H__
+
+#include <NGMime/NGMimePartParser.h>
+
+/*
+  Parses body-parts. Body-parts are the parts contained in a multipart body.
+  The multipart body is parsed by a NGMimeMultipartBodyParser.
+*/
+
+@interface NGMimeBodyPartParser : NGMimePartParser
+
+@end
+
+#endif /* __NGMime_NGMimeBodyPartParser_H__ */
diff --git a/skyrix-core/NGMime/NGMimeBodyPartParser.m b/skyrix-core/NGMime/NGMimeBodyPartParser.m
new file mode 100644 (file)
index 0000000..8f5073c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeBodyPartParser.h"
+#include "NGMimeBodyPart.h"
+#include "common.h"
+
+@implementation NGMimeBodyPartParser
+
++ (int)version {
+  return 3;
+}
++ (void)initialize {
+  NSAssert2([super version] == 3,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (NGMimeType *)defaultContentTypeForPart:(id<NGMimePart>)_part {
+  return [NGMimeType mimeType:@"text/plain"];
+}
+
+- (id<NGMimePart>)producePartWithHeader:(NGHashMap *)_header {
+  return [NGMimeBodyPart bodyPartWithHeader:_header];
+}
+
+- (void)parseBodyOfPart:(id<NGMimePart>)_part {
+  [super parseBodyOfPart:_part];
+}
+
+@end /* NGMimeBodyPartParser */
diff --git a/skyrix-core/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m b/skyrix-core/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m
new file mode 100644 (file)
index 0000000..c7421fb
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeHeaderFieldGenerator.h"
+#include "NGMimeHeaderFields.h"
+#include "common.h"
+
+@implementation NGMimeContentDispositionHeaderFieldGenerator
+
++ (int)version {
+  return 2;
+}
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value
+{
+  NGMimeContentDispositionHeaderField *field;
+  NSString      *tmp;
+  NSMutableData *data;
+  
+  field = _value;
+  if (field == nil) {
+    [self logWithFormat:@"WARNING(%s): Content-Disposition field is empty",
+          __PRETTY_FUNCTION__];
+    return [NSData data];
+  }
+  
+  if ([_value isKindOfClass:[NSString class]])
+    return [_value dataUsingEncoding:NSUTF8StringEncoding];
+  
+  // TODO: move the stuff below to some NSString or NSData category?
+  
+  data = [NSMutableData dataWithCapacity:64];
+  tmp  = [field type];
+  [data appendBytes:[tmp cString] length:[tmp length]];
+  tmp = [field filename];
+  if (tmp != nil) {
+    [data appendBytes:"; " length:2];
+    [data appendBytes:"filename=\"" length:10];
+    {
+      unsigned char *ctmp;
+      int  cnt, len;
+      BOOL doEnc;
+      
+      // TODO: unicode?
+      len  = [tmp cStringLength];
+      ctmp = malloc(len + 3);
+      [tmp getCString:ctmp]; ctmp[len] = '\0';
+      cnt  = 0;
+      doEnc = NO;
+      while (cnt < len) {
+        if ((unsigned char)ctmp[cnt] > 127) {
+          doEnc = YES;
+          break;
+        }
+        cnt++;
+      }
+      if (doEnc) {
+        char        iso[]     = "=?iso-8859-15?q?";
+        unsigned    isoLen    = 16;
+        char        isoEnd[]  = "?=";
+        unsigned    isoEndLen = 2;
+        unsigned    desLen;
+        char        *des;
+      
+        free(ctmp);
+        {
+          NSData *data;
+
+#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+          data = [tmp dataUsingEncoding:NSISOLatin1StringEncoding];
+#else
+          data = [tmp dataUsingEncoding:NSISOLatin9StringEncoding];
+#endif
+
+          len  = [data length];
+          ctmp =  malloc(len+1);
+          [data getBytes:ctmp];  ctmp[len] = '\0';
+        }
+          
+        desLen = len * 3 + 20;
+        des    = calloc(desLen + 10, sizeof(char));
+      
+        memcpy(des, ctmp, cnt);
+        memcpy(des + cnt, iso, isoLen);
+        desLen =
+             NGEncodeQuotedPrintableMime(ctmp + cnt, len - cnt,
+                                         des + cnt + isoLen,
+                                         desLen - cnt - isoLen);
+        if ((int)desLen != -1) {
+          memcpy(des + cnt + isoLen + desLen, isoEnd, isoEndLen);
+          [data appendBytes:des length:(cnt + isoLen + desLen + isoEndLen)];
+        }
+        else {
+          [self logWithFormat:@"WARNING(%s:%i): An error occour during "
+               @"quoted-printable decoding",
+                __PRETTY_FUNCTION__, __LINE__];
+        }
+        if (des) free(des);
+      }
+      else {
+        [data appendBytes:ctmp length:len];
+      }
+    }
+      //      [data appendBytes:[tmp cString] length:[tmp length]];
+      [data appendBytes:"\"" length:1];
+  }
+  return data;
+}
+  
+@end /* NGMimeContentDispositionHeaderFieldGenerator */
diff --git a/skyrix-core/NGMime/NGMimeContentDispositionHeaderFieldParser.m b/skyrix-core/NGMime/NGMimeContentDispositionHeaderFieldParser.m
new file mode 100644 (file)
index 0000000..bd902ca
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeHeaderFieldParser.h"
+#include "NGMimeHeaderFields.h"
+#include "NGMimeUtilities.h"
+#include "common.h"
+
+@implementation NGMimeContentDispositionHeaderFieldParser
+
+static BOOL StripLeadingSpaces = NO;
+static BOOL MimeLogEnabled     = NO;
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  StripLeadingSpaces = [self doesStripLeadingSpaces];
+  MimeLogEnabled     = [self isMIMELogEnabled];
+}
+
+- (id)parseValue:(NSString *)_data ofHeaderField:(NSString *)_field {
+  unsigned   len = [_data length];
+  unichar    src[len+1];
+  unsigned   cnt;
+  BOOL       didModify;
+  NSString   *str;
+  
+  didModify = NO;
+  cnt       = 0;
+
+  [_data getCharacters:src];
+  
+  // strip leading spaces
+  if (StripLeadingSpaces) {
+    while (isRfc822_LWSP(src[cnt]) && (len > 0)) {
+      cnt++;
+      len--;
+      didModify = YES;
+    }
+  }
+  // strip trailing spaces
+  while (len > 0) {
+    if (isRfc822_LWSP(src[len - 1])) {
+      len--;
+      didModify = YES;
+    }
+    else
+      break;
+  }
+  if (len == 0) {
+    if (MimeLogEnabled) 
+      [self logWithFormat:@"WARNING(%s): empty value for header field %@ ..",
+            __PRETTY_FUNCTION__, _field];
+    return nil;
+  }
+  str = nil;
+  
+  if (didModify)
+    str = [[[NSString alloc] initWithCharacters:src+cnt length:len] autorelease];
+  else
+    str = _data;
+  
+  return [[[NGMimeContentDispositionHeaderField alloc] initWithString:str]
+                                                autorelease];
+}
+
+@end /* NGMimeContentDispositionHeaderFieldParser */
diff --git a/skyrix-core/NGMime/NGMimeContentLengthHeaderFieldGenerator.m b/skyrix-core/NGMime/NGMimeContentLengthHeaderFieldGenerator.m
new file mode 100644 (file)
index 0000000..b8fcfc2
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeHeaderFieldGenerator.h"
+#include "NGMimeHeaderFields.h"
+#include "common.h"
+
+@implementation NGMimeContentLengthHeaderFieldGenerator
+
++ (int)version {
+  return 2;
+}
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value
+{
+  // TODO: rewrite for ASCII and plain buffer - much faster ...
+  if (_value == nil) {
+    NSLog(@"WARNING(%s): empty content length field", __PRETTY_FUNCTION__);
+    return [NSData data];
+  }
+  
+  return [[_value stringValue] dataUsingEncoding:NSUTF8StringEncoding];
+}
+  
+@end /* NGMimeContentLengthHeaderFieldGenerator */
diff --git a/skyrix-core/NGMime/NGMimeContentLengthHeaderFieldParser.m b/skyrix-core/NGMime/NGMimeContentLengthHeaderFieldParser.m
new file mode 100644 (file)
index 0000000..f3ce7a1
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeHeaderFieldParser.h"
+#include "NGMimeHeaderFields.h"
+#include "NGMimeUtilities.h"
+#include "common.h"
+
+@implementation NGMimeContentLengthHeaderFieldParser
+
++ (int)version {
+  return 2;
+}
+
+- (id)parseValue:(NSString *)_data ofHeaderField:(NSString *)_field {
+  const char *buf, *ptr;
+    
+  _data = [self removeCommentsFromValue:_data];
+  buf   = [_data cString];
+  ptr = buf;
+  while (!isRfc822_DIGIT(*ptr) && (*ptr != '\0'))
+    ptr++;
+
+  if (isRfc822_DIGIT(*ptr))
+    return [NSNumber numberWithUnsignedInt:atol(ptr)];
+  else {
+    NSLog(@"WARNING(%s): invalid content-length field value (value='%s')",
+          __PRETTY_FUNCTION__, buf);
+    return nil;
+  }
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<MimeContentLengthHeaderFieldParser: object=0x%08X>",
+                     (unsigned)self];
+}
+
+@end /* NGMimeContentLengthHeaderFieldParser */
diff --git a/skyrix-core/NGMime/NGMimeContentTypeHeaderFieldGenerator.m b/skyrix-core/NGMime/NGMimeContentTypeHeaderFieldGenerator.m
new file mode 100644 (file)
index 0000000..6a2545d
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeHeaderFieldGenerator.h"
+#include "NGMimeHeaderFields.h"
+#include "common.h"
+
+@implementation NGMimeContentTypeHeaderFieldGenerator
+
++ (int)version {
+  return 2;
+}
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value
+{
+  NGMimeType    *type = nil; // only one content-type field
+  NSString      *tmp  = nil;
+  NSMutableData *data = nil;
+  unsigned char *ctmp = NULL;
+  unsigned      len   = 0;
+  
+  type = _value;
+
+  if (type == nil) {
+    NSLog(@"WARNING(%s): empty content type field", __PRETTY_FUNCTION__);
+    return [NSData dataWithBytes:"application/octet" length:17];
+  }
+  if ([_value isKindOfClass:[NSString class]]) {
+    return [_value dataUsingEncoding:NSUTF8StringEncoding];
+  }
+  
+  if (![type isKindOfClass:[NGMimeType class]]) {
+    NSLog(@"WARNING(%s): invalid MIME type value (%@) !", __PRETTY_FUNCTION__,
+          type);
+    return [NSData dataWithBytes:"application/octet" length:17];
+  }
+  
+  data = [NSMutableData dataWithCapacity:64];
+  
+  tmp = [type type];
+  NSAssert(tmp, @"type should not be nil");
+  len  = [tmp length];
+  ctmp = malloc(len + 1);
+  [tmp getCString:ctmp]; ctmp[len] = '\0';
+  [data appendBytes:ctmp length:len];
+  free(ctmp);
+  
+  [data appendBytes:"//" length:1];
+  
+  tmp = [type subType];
+  if (tmp != nil) {
+    len  = [tmp length];
+    ctmp = malloc(len + 1);
+    [tmp getCString:ctmp]; ctmp[len] = '\0';
+    [data appendBytes:ctmp length:len];
+    free(ctmp);
+  }
+  else
+    [data appendBytes:"*" length:1];
+
+  {  // parameters
+    NSEnumerator *enumerator = [type parameterNames];
+    NSString     *name       = nil;
+    NSString     *value      = nil;
+    
+    while ((name = [enumerator nextObject])) {
+      value = [type valueOfParameter:name];
+      if (![value isKindOfClass:[NSString class]]) {
+        NSLog(@"ERROR[%s]: parameter should be a NSString headerField: %@ "
+              @"value %@", __PRETTY_FUNCTION__, _headerField, _value);
+        continue;
+      }
+      [data appendBytes:"; " length:2];
+      
+      len  = [name cStringLength];
+      ctmp = malloc(len + 1);
+      [name getCString:ctmp]; ctmp[len] = '\0';
+      [data appendBytes:ctmp length:len];
+      free(ctmp);
+
+      /*
+        this confuses GroupWise: "= \"" (a space)
+      */
+      [data appendBytes:"=\"" length:2];
+
+      /* check for encoding */
+      {
+        unsigned cnt;
+        BOOL doEnc;
+        
+        len  = [value cStringLength];
+        ctmp = malloc(len + 1);
+        [value getCString:ctmp]; ctmp[len] = '\0';
+        cnt  = 0;
+        doEnc = NO;
+        while (cnt < len) {
+          if ((unsigned char)ctmp[cnt] > 127) {
+            doEnc = YES;
+            break;
+          }
+          cnt++;
+        }
+        if (doEnc) {
+          unsigned char iso[]     = "=?iso-8859-15?q?";
+          unsigned      isoLen    = 16;
+          unsigned char isoEnd[]  = "?=";
+          unsigned      isoEndLen = 2;
+          unsigned      desLen;
+          unsigned char *des;
+         
+          if (ctmp) free(ctmp);
+          {
+            NSData *data;
+
+#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+            data = [value dataUsingEncoding:NSISOLatin1StringEncoding];
+#else
+            data = [value dataUsingEncoding:NSISOLatin9StringEncoding];
+#endif
+
+            len  = [data length];
+            ctmp =  malloc(len+1);
+            [data getBytes:ctmp];  ctmp[len] = '\0';
+          }
+          
+          desLen = len * 3 + 20;
+          des    = calloc(desLen + 10, sizeof(char));
+      
+          memcpy(des, ctmp, cnt);
+          memcpy(des + cnt, iso, isoLen);
+          desLen =
+               NGEncodeQuotedPrintableMime(ctmp + cnt, len - cnt,
+                                           des + cnt + isoLen,
+                                           desLen - cnt - isoLen);
+          if ((int)desLen != -1) {
+            memcpy(des + cnt + isoLen + desLen, isoEnd, isoEndLen);
+            [data appendBytes:des length:(cnt + isoLen + desLen + isoEndLen)];
+          }
+          else {
+            NSLog(@"WARNING: An error occour during quoted-printable decoding");
+          }
+          if (des) free(des);
+        }
+        else {
+          [data appendBytes:ctmp length:len];
+        }
+          free(ctmp);
+      }
+      [data appendBytes:"\"" length:1];      
+    }
+  }
+  return data;
+}
+
+@end /* NGMimeContentTypeHeaderFieldGenerator */
diff --git a/skyrix-core/NGMime/NGMimeContentTypeHeaderFieldParser.m b/skyrix-core/NGMime/NGMimeContentTypeHeaderFieldParser.m
new file mode 100644 (file)
index 0000000..11a4c6b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeHeaderFieldParser.h"
+#include "NGMimeHeaderFields.h"
+#include "NGMimeUtilities.h"
+#include "common.h"
+
+@implementation NGMimeContentTypeHeaderFieldParser
+
+static BOOL StripLeadingSpaces = NO;
+static BOOL MimeLogEnabled     = NO;
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  StripLeadingSpaces = [self doesStripLeadingSpaces];
+  MimeLogEnabled     = [self isMIMELogEnabled];
+}
+
+- (id)parseValue:(NSString *)_data ofHeaderField:(NSString *)_field {
+  NSString *typeString;
+  unsigned len;
+
+  _data = [self removeCommentsFromValue:_data];
+  len   = [_data length];
+
+  if (len == 0) {
+    if (MimeLogEnabled) {
+      [self logWithFormat:@"WARNING(%s): empty value for header field %@ ..",
+            __PRETTY_FUNCTION__, _field];
+    }
+    return [NGMimeType mimeType:@"text/plain"];
+  }
+  typeString = nil;
+  if (StripLeadingSpaces) {
+    unichar src[len + 1];
+    int     cnt;
+
+    cnt    = 0;
+    [_data getCharacters:src];
+
+    while (isRfc822_LWSP(src[cnt]) && (len > 0)) {
+      cnt++;
+      len--;
+    }
+    if (cnt > 0)
+      typeString = [[[NSString alloc] initWithCharacters:src+cnt length:len]
+                               autorelease];
+  }
+  if (!typeString) 
+    typeString = _data;
+
+  NSAssert(typeString, @"type string allocation failed ..");
+
+  return [NGMimeType mimeType:typeString];
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<MimeContentTypeHeaderFieldParser: object=0x%08X>",
+                     (unsigned)self];
+}
+
+@end /* NGMimeContentTypeHeaderFieldParser */
diff --git a/skyrix-core/NGMime/NGMimeDecls.h b/skyrix-core/NGMime/NGMimeDecls.h
new file mode 100644 (file)
index 0000000..3eecb42
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeDecls_H__
+#define __NGMime_NGMimeDecls_H__
+
+#if BUILD_libNGMime_DLL
+#  define NGMime_EXPORT  __declspec(dllexport)
+#  define NGMime_DECLARE __declspec(dllexport)
+#elif libNGMime_ISDLL
+#  define NGMime_EXPORT  extern __declspec(dllimport)
+#  define NGMime_DECLARE extern __declspec(dllimport)
+#else
+#  define NGMime_EXPORT  extern
+#  define NGMime_DECLARE 
+#endif
+
+#endif /* __NGMime_NGMimeDecls_H__ */
diff --git a/skyrix-core/NGMime/NGMimeExceptions.h b/skyrix-core/NGMime/NGMimeExceptions.h
new file mode 100644 (file)
index 0000000..3548770
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeExceptions_H__
+#define __NGMime_NGMimeExceptions_H__
+
+#import <Foundation/NSException.h>
+
+@interface NGMimeException : NSException
+@end
+
+@interface NGMimeParserException : NGMimeException
+@end
+
+#endif /* __NGMime_NGMimeExceptions_H__ */
diff --git a/skyrix-core/NGMime/NGMimeExceptions.m b/skyrix-core/NGMime/NGMimeExceptions.m
new file mode 100644 (file)
index 0000000..4da4175
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeExceptions.h"
+#include "common.h"
+
+@implementation NGMimeException
+
++ (int)version {
+  return 2;
+}
+
+- (id)init {
+  return [self initWithReason:@"a MIME exception occured"];
+}
+  
+@end /* NGMimeException */
+
+@implementation NGMimeParserException
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)init {
+  return [self initWithReason:@"a MIME exception occured during parsing"];
+}
+
+@end /* NGMimeParserException */
diff --git a/skyrix-core/NGMime/NGMimeFileData.h b/skyrix-core/NGMime/NGMimeFileData.h
new file mode 100644 (file)
index 0000000..1f92abf
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeFileData_H__
+#define __NGMime_NGMimeFileData_H__
+
+#import <Foundation/NSData.h>
+
+@class NSString;
+
+@interface NGMimeFileData : NSData
+{
+  NSString *path;
+  BOOL     removeFile;
+  int      length;
+}
+
+
+- (id)initWithPath:(NSString *)_path removeFile:(BOOL)_remove;
+
+- (BOOL)appendDataToFileDesc:(int)_fd;
+
+@end /* NGMimeFileData */
+
+#endif /* __NGMime_NGMimeFileData_H__ */
diff --git a/skyrix-core/NGMime/NGMimeFileData.m b/skyrix-core/NGMime/NGMimeFileData.m
new file mode 100644 (file)
index 0000000..62150d9
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeFileData.h"
+#include "common.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+@implementation NGMimeFileData
+
+static NSString      *TmpPath = nil;
+static NSProcessInfo *Pi      = nil;
+static unsigned      tmpmask  = 0600;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  if (TmpPath == nil) {
+    TmpPath = [ud stringForKey:@"NGMimeBuildMimeTempDirectory"];
+    if (TmpPath == nil) TmpPath = @"/tmp/";
+    TmpPath = [[TmpPath stringByAppendingPathComponent:@"OGo"] copy];
+  }
+  if (Pi == nil) Pi = [[NSProcessInfo processInfo] retain];
+}
+
+- (id)initWithPath:(NSString *)_path removeFile:(BOOL)_remove {
+  if ((self = [super init])) {
+    if (![[NSFileManager defaultManager] fileExistsAtPath:_path]) {
+      NSLog(@"ERROR[%s]: missing file at path %@", __PRETTY_FUNCTION__, _path);
+      [self release];
+      return nil;
+    }
+    self->path       = [_path copy];
+    self->removeFile = _remove;
+    self->length     = -1;
+  }
+  return self;
+}
+
+- (id)initWithBytes:(const void*)_bytes
+  length:(unsigned int)_length
+{
+  NSString *filename = nil;
+  int      fd;
+  
+  filename = [Pi temporaryFileName:TmpPath];
+
+  fd = open([filename fileSystemRepresentation],
+            O_WRONLY | O_CREAT | O_TRUNC, tmpmask);
+  if (fd == -1) {
+    fprintf(stderr, "Could not open file for writing %s: %s\n",
+            [filename fileSystemRepresentation], strerror(errno));
+    [self release];
+    return nil;
+  }
+  if (write(fd, _bytes, _length) != (int)_length) {
+    fprintf(stderr, "Failed to write %i bytes to %s: %s\n",
+            _length, [filename fileSystemRepresentation], strerror(errno));
+    close(fd);
+    [self release];
+    return nil;
+  }
+  return [self initWithPath:filename removeFile:YES];
+}
+
+- (void)dealloc {
+  if (self->removeFile) {
+    [[NSFileManager defaultManager]
+                    removeFileAtPath:self->path handler:nil];
+  }
+  [self->path release];
+  [super dealloc];
+}
+
+- (NSData *)_data {
+  return [NSData dataWithContentsOfMappedFile:self->path];
+}
+
+- (id)copyWithZone:(NSZone *)zone {
+  return [self retain];
+}
+
+- (const void*)bytes {
+  return [[self _data] bytes];
+}
+
+- (unsigned int)length {
+  if (self->length == -1) {
+    self->length = [[[[NSFileManager defaultManager]
+                                     fileAttributesAtPath:self->path
+                                     traverseLink:NO]
+                                     objectForKey:NSFileSize] intValue];
+  }
+  return self->length;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X[%@]: path=%@>",
+                     self, NSStringFromClass([self class]), self->path];
+}
+
+- (BOOL)appendDataToFileDesc:(int)_fd {
+  NGFileStream *fs;
+  int  bufCnt = 8192;
+  char buffer[bufCnt];
+  BOOL result;
+  int  fileLen;
+
+  if (![[NSFileManager defaultManager] isReadableFileAtPath:self->path]) {
+    NSLog(@"ERROR[%s] missing file at path %@", __PRETTY_FUNCTION__, 
+          self->path);
+    return NO;
+  }
+  
+  fileLen = [self length];
+  result  = YES;
+  fs      = [NGFileStream alloc]; /* to keep gcc 3.4 happy */
+  fs      = [fs initWithPath:self->path];
+
+  if (![fs openInMode:@"r"]) {
+    NSLog(@"%s: could not open file stream ... %@",
+          __PRETTY_FUNCTION__, self->path);
+    [fs release]; fs = nil;
+    return NO;
+  }
+
+  NS_DURING {
+    int read;
+    int alreadyRead;
+
+    alreadyRead = 0;
+    
+    read = (bufCnt > (fileLen - alreadyRead)) ? fileLen - alreadyRead : bufCnt;
+        
+    while ((read = [fs readBytes:buffer count:read])) {
+      alreadyRead += read;
+      if (write(_fd, buffer, read) != read) {
+        fprintf(stderr, "%s: Failed to write %i bytes to file\n",
+                __PRETTY_FUNCTION__, read);
+        result = NO;
+        break;
+      }
+      if (alreadyRead == fileLen)
+        break;
+    }
+  }
+  NS_HANDLER {
+    printf("got exceptions %s\n", [[localException description] cString]);
+    if (![localException isKindOfClass:[NGEndOfStreamException class]]) {
+      [fs release]; fs = nil;
+      result = NO;
+    }
+  }
+  NS_ENDHANDLER;
+  [fs release]; fs = nil;
+  return result;
+}
+
+@end /* NGMimeFileData */
diff --git a/skyrix-core/NGMime/NGMimeGeneratorProtocols.h b/skyrix-core/NGMime/NGMimeGeneratorProtocols.h
new file mode 100644 (file)
index 0000000..b2dfa6f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMimeGenerator_NGMimeGeneratorProtocols_H__
+#define __NGMimeGenerator_NGMimeGeneratorProtocols_H__
+
+#import <Foundation/NSObject.h>
+#import <NGMime/NGPart.h>
+
+@class NSData, NGMutableHashMap;
+
+@protocol NGMimePartGenerator <NSObject>
+
+/* generate mime from part and store it in _file */
+- (NSString *)generateMimeFromPartToFile:(id<NGMimePart>)_part;
+
+- (NSData *)generateMimeFromPart:(id<NGMimePart>)_part;
+- (void)setDelegate:(id)_delegate;
+- (id)delegate;
+- (void)setUseMimeData:(BOOL)_useMimeData;
+
+@end
+
+@protocol NGMimeBodyGenerator < NSObject >
+
+- (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders
+  delegate:(id)_delegate;
+
+- (NSData *)encodeData:(NSData *)_data
+  forPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_addHeaders;
+
+/* use mime data objects to store mime objects on disk instead in memory */
+
+- (void)setUseMimeData:(BOOL)_useMimeData;
+@end
+
+@protocol NGMimeHeaderFieldGenerator < NSObject >
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value;
+
+@end
+
+#endif // __NGMimeGenerator_NGMimeGeneratorProtocols_H__
diff --git a/skyrix-core/NGMime/NGMimeHeaderFieldGenerator.h b/skyrix-core/NGMime/NGMimeHeaderFieldGenerator.h
new file mode 100644 (file)
index 0000000..94d1894
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGMime_NGHeaderFieldGenerator_H__
+#define __NGMime_NGHeaderFieldGenerator_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMime/NGMimeGeneratorProtocols.h>
+
+@class NSString, NSData, NSMutableDictionary;
+
+@interface NGMimeHeaderFieldGenerator : NSObject <NGMimeHeaderFieldGenerator>
+
++ (id)headerFieldGenerator;
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value;
+
+@end
+
+@interface NGMimeContentTypeHeaderFieldGenerator : NGMimeHeaderFieldGenerator
+@end
+
+@interface NGMimeContentLengthHeaderFieldGenerator : NGMimeHeaderFieldGenerator
+@end
+
+@interface NGMimeRFC822DateHeaderFieldGenerator : NGMimeHeaderFieldGenerator
+@end
+
+@interface NGMimeContentDispositionHeaderFieldGenerator :
+                                                     NGMimeHeaderFieldGenerator
+@end
+
+@interface NGMimeStringHeaderFieldGenerator : NGMimeHeaderFieldGenerator
+@end
+
+@interface NGMimeAddressHeaderFieldGenerator : NGMimeHeaderFieldGenerator
+@end
+
+@interface NGMimeHeaderFieldGeneratorSet : NSObject <NGMimeHeaderFieldGenerator>
+{
+@protected
+  NSMutableDictionary            *fieldNameToGenerate;
+  id<NGMimeHeaderFieldGenerator> defaultGenerator;
+}
+
++ (id)headerFieldGeneratorSet;
++ (id)defaultRfc822HeaderFieldGeneratorSet;
+
+- (id)init;
+- (id)initWithDefaultGenerator:(id<NGMimeHeaderFieldGenerator>)_gen;
+
+/* accessors */
+
+- (void)setGenerator:(id<NGMimeHeaderFieldGenerator>)_gen
+  forField:(NSString *)_name;
+
+- (void)setDefaultGenerator:(id<NGMimeHeaderFieldGenerator>)_gen;
+- (id<NGMimeHeaderFieldGenerator>)_gen;
+
+/* operation */
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value;
+
+@end
+
+extern int NGEncodeQuotedPrintableMime
+(const unsigned char *_src, unsigned _srcLen,
+ unsigned char *_dest, unsigned _destLen);
+
+#endif // __NGMime_NGHeaderFieldGenerator_H__
diff --git a/skyrix-core/NGMime/NGMimeHeaderFieldGenerator.m b/skyrix-core/NGMime/NGMimeHeaderFieldGenerator.m
new file mode 100644 (file)
index 0000000..68a2024
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeHeaderFieldGenerator.h"
+#include "NGMimeHeaderFields.h"
+#include "common.h"
+
+@implementation NGMimeHeaderFieldGenerator
+
++ (int)version {
+  return 2;
+}
+
++ (id)headerFieldGenerator {
+  return [[[self alloc] init] autorelease];
+}
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value
+{
+  [self subclassResponsibility:_cmd];
+  return nil;
+}
+
+@end /* NGMimeHeaderFieldGenerator */
+
+#if 1
+int NGEncodeQuotedPrintableMime
+(const unsigned char *_src, unsigned _srcLen,
+ unsigned char *_dest, unsigned _destLen) 
+{
+  /* decode also spaces*/
+  unsigned cnt      = 0;
+  unsigned destCnt  = 0;
+  unsigned char
+    hexT[16] = {'0','1','2','3','4','5','6','7','8',
+                '9','A','B','C','D','E','F'};
+  
+  if (_srcLen > _destLen)
+    return -1;
+  
+  for (cnt = 0; (cnt < _srcLen) && (destCnt < _destLen); cnt++) {
+    register unsigned char c = _src[cnt];
+    
+    if (((c > 47) && (c < 58)) ||
+        ((c > 64) && (c < 91)) ||
+        ((c > 96) && (c < 123))) {
+      // no quoting
+      _dest[destCnt] = c;
+      destCnt++;
+    }
+    else { // need to be quoted
+      if (_destLen - destCnt > 2) {
+        _dest[destCnt] = '='; destCnt++;
+        _dest[destCnt] = hexT[(c >> 4) & 15]; destCnt++;
+        _dest[destCnt] = hexT[c & 15]; destCnt++;
+      }
+      else 
+        break;
+    }
+  }
+  if (cnt < _srcLen)
+    return -1;
+  return destCnt;
+}
+
+#else /* TODO: this one was declared in NGMimeMessageGenerator, any diff? */
+
+static int NGEncodeQuotedPrintableMime(const char *_src, unsigned _srcLen,
+                                       char *_dest, unsigned _destLen) {
+  /* decode also spaces*/
+  unsigned cnt      = 0;
+  unsigned destCnt  = 0;
+  char     hexT[16] = {'0','1','2','3','4','5','6','7','8',
+                       '9','A','B','C','D','E','F'};
+  
+  if (_srcLen > _destLen)
+    return -1;
+  
+  for (cnt = 0; (cnt < _srcLen) && (destCnt < _destLen); cnt++) {
+    char c = _src[cnt];
+
+    if (((c > 47) && (c < 58)) ||
+        ((c > 64) && (c < 91)) ||
+        ((c > 96) && (c < 123))) { // no quoting
+      _dest[destCnt++] = c;
+    }
+    else { // need to be quoted
+      if (_destLen - destCnt > 2) {
+        _dest[destCnt++] = '=';
+        _dest[destCnt++] = hexT[(c >> 4) & 15];
+        _dest[destCnt++] = hexT[c & 15];
+      }
+      else 
+        break;
+    }
+  }
+  if (cnt < _srcLen)
+    return -1;
+  return destCnt;
+}
+
+#endif
diff --git a/skyrix-core/NGMime/NGMimeHeaderFieldGeneratorSet.m b/skyrix-core/NGMime/NGMimeHeaderFieldGeneratorSet.m
new file mode 100644 (file)
index 0000000..87d4e30
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeHeaderFieldGenerator.h"
+#include "NGMimeHeaderFields.h"
+#include "NGMimePartParser.h"
+#include "common.h"
+
+@implementation NGMimeHeaderFieldGeneratorSet
+
++ (int)version {
+  return 2;
+}
+
+static NGMimeHeaderFieldGeneratorSet *rfc822Set = nil;
+
++ (id)headerFieldGenerator {
+  return [[[self alloc] init] autorelease];
+}
+
++ (id)headerFieldGeneratorSet {
+  return [[[self alloc] init] autorelease];
+}
+
++ (id)defaultRfc822HeaderFieldGeneratorSet {
+  static NGMimeHeaderNames *Fields = NULL;
+  id gen;
+
+  if (!Fields)
+    Fields = (NGMimeHeaderNames *)[NGMimePartParser headerFieldNames];
+                    
+  if (rfc822Set)
+    return rfc822Set;
+  
+  rfc822Set = [[self alloc] init];
+
+  gen = [NGMimeContentDispositionHeaderFieldGenerator headerFieldGenerator];
+  if (gen)
+    [rfc822Set setGenerator:gen forField:Fields->contentDisposition];
+  
+  if ((gen = [NGMimeContentLengthHeaderFieldGenerator headerFieldGenerator]))
+    [rfc822Set setGenerator:gen forField:Fields->contentLength];
+  if ((gen = [NGMimeContentTypeHeaderFieldGenerator headerFieldGenerator]))
+    [rfc822Set setGenerator:gen forField:Fields->contentType];
+  if ((gen = [NGMimeRFC822DateHeaderFieldGenerator headerFieldGenerator]))
+    [rfc822Set setGenerator:gen forField:Fields->date];
+  
+  if ((gen = [NGMimeAddressHeaderFieldGenerator headerFieldGenerator])) {
+    [rfc822Set setGenerator:gen forField:@"resent-from"];
+    [rfc822Set setGenerator:gen forField:@"resent-to"];
+    [rfc822Set setGenerator:gen forField:Fields->to];
+    [rfc822Set setGenerator:gen forField:Fields->cc];
+    [rfc822Set setGenerator:gen forField:@"bcc"];
+    [rfc822Set setGenerator:gen forField:Fields->from];
+  }
+  
+  if ((gen = [NGMimeStringHeaderFieldGenerator headerFieldGenerator]))
+    [rfc822Set setDefaultGenerator:gen];
+  
+  return rfc822Set;
+}
+
+- (id)init {
+  return [self initWithDefaultGenerator:nil];
+}
+
+- (id)initWithDefaultGenerator:(id<NGMimeHeaderFieldGenerator>)_gen {
+  if ((self = [super init])) {
+    self->fieldNameToGenerate =
+      [[NSMutableDictionary allocWithZone:[self zone]]
+                            initWithCapacity:16];
+    self->defaultGenerator = [_gen retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->fieldNameToGenerate release];
+  [self->defaultGenerator    release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setGenerator:(id<NGMimeHeaderFieldGenerator>)_gen
+  forField:(NSString *)_name
+{
+  [self->fieldNameToGenerate setObject:_gen forKey:_name];
+}
+
+- (void)setDefaultGenerator:(id<NGMimeHeaderFieldGenerator>)_gen {
+  ASSIGN(self->defaultGenerator, _gen);
+}
+
+- (id<NGMimeHeaderFieldGenerator>)_gen {
+  return self->defaultGenerator;
+}
+
+/* operation */
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value
+{
+  NGMimeHeaderFieldGenerator *gen = nil;
+  
+  if ((gen = [self->fieldNameToGenerate objectForKey:_headerField]) == nil)
+    gen = (NGMimeHeaderFieldGenerator *)self->defaultGenerator;
+  
+  if (gen == nil) {
+    NSLog(@"WARNING(%s): no defaultGenerator is set", __PRETTY_FUNCTION__);
+    return [NSData data];
+  }
+  return [gen generateDataForHeaderFieldNamed:_headerField
+              value:_value];
+}
+
+@end /* NGMimeHeaderFieldGeneratorSet */
diff --git a/skyrix-core/NGMime/NGMimeHeaderFieldParser.h b/skyrix-core/NGMime/NGMimeHeaderFieldParser.h
new file mode 100644 (file)
index 0000000..e4b191e
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGMime_NGHeaderFieldParser_H__
+#define __NGMime_NGHeaderFieldParser_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSData, NSString, NSMutableDictionary;
+
+@protocol NGMimeHeaderFieldParser < NSObject >
+
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field;
+
+@end
+
+@interface NGMimeHeaderFieldParser : NSObject < NGMimeHeaderFieldParser >
+
++ (BOOL)isMIMELogEnabled;
++ (BOOL)doesStripLeadingSpaces;
+
+- (NSString *)removeCommentsFromValue:(NSString *)_rawValue;
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field; // abstract
+
+@end
+
+@interface NGMimeContentTypeHeaderFieldParser : NGMimeHeaderFieldParser
+@end
+
+@interface NGMimeRFC822DateHeaderFieldParser : NGMimeHeaderFieldParser
+@end
+
+@interface NGMimeContentLengthHeaderFieldParser : NGMimeHeaderFieldParser
+@end
+
+/*
+  Content-Disposition headers have the form:
+
+    disposition := "Content-Disposition" ":"
+                   disposition-type
+                   *(";" disposition-parm)
+
+    disposition-type := "inline"
+                      / "attachment"
+                      / extension-token
+                      ; values are not case-sensitive
+
+    disposition-parm := filename-parm / parameter
+    filename-parm := "filename" "=" value;
+
+  Content-Disposition values may not contain comments !
+*/
+@interface NGMimeContentDispositionHeaderFieldParser : NGMimeHeaderFieldParser
+@end
+
+/*
+  This strips spaces at the beginning and the end of the value, then it removes
+  all comments
+*/
+@interface NGMimeStringHeaderFieldParser : NGMimeHeaderFieldParser
+{
+@protected
+  BOOL removeComments; // default=YES
+}
+
+- (id)initWithRemoveComments:(BOOL)_flag;
+- (id)init;
+
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field;
+
+@end
+
+/*
+  This stores a mapping between header field parsers and field names.
+*/
+@interface NGMimeHeaderFieldParserSet : NSObject <NGMimeHeaderFieldParser,NSCopying>
+{
+@protected
+  NSMutableDictionary         *fieldNameToParser;
+  id<NGMimeHeaderFieldParser> defaultParser;
+}
+
++ (id)headerFieldParserSet;
++ (id)defaultRfc822HeaderFieldParserSet;
+- (id)init;
+- (id)initWithDefaultParser:(id<NGMimeHeaderFieldParser>)_parser;
+- (id)initWithParseSet:(NGMimeHeaderFieldParserSet *)_set;
+
+/* accessors */
+
+- (void)setParser:(id<NGMimeHeaderFieldParser>)_parser
+  forField:(NSString *)_name;
+
+- (void)setDefaultParser:(id<NGMimeHeaderFieldParser>)_parser;
+- (id<NGMimeHeaderFieldParser>)defaultParser;
+
+/* operation */
+
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field;
+
+@end
+
+#endif /* __NGMime_NGHeaderFieldParser_H__ */
diff --git a/skyrix-core/NGMime/NGMimeHeaderFieldParser.m b/skyrix-core/NGMime/NGMimeHeaderFieldParser.m
new file mode 100644 (file)
index 0000000..3fb2d5a
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeHeaderFieldParser.h"
+#include "NGMimeHeaderFields.h"
+#include "NGMimeUtilities.h"
+#include "common.h"
+#include <NGMime/NGMimePartParser.h>
+
+@implementation NGMimeHeaderFieldParser
+
+static int MimeLogEnabled     = -1;
+static int StripLeadingSpaces = -1;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  if (MimeLogEnabled == -1)
+    MimeLogEnabled = [ud boolForKey:@"MimeLogEnabled"]?1:0;
+  if (StripLeadingSpaces == -1)
+    StripLeadingSpaces = [ud boolForKey:@"StripLeadingSpaces"]?1:0;
+}
++ (BOOL)isMIMELogEnabled {
+  return MimeLogEnabled ? YES : NO;
+}
++ (BOOL)doesStripLeadingSpaces {
+  return StripLeadingSpaces ? YES : NO;
+}
+
++ (int)version {
+  return 2;
+}
+
+- (NSString *)removeCommentsFromValue:(NSString *)_rawValue {
+  unsigned int len = [_rawValue length];
+  unichar      bytes[len + 1];
+  unsigned int cnt;
+  NSString     *str;
+
+  if (_rawValue == NULL) return nil;
+
+  [_rawValue getCharacters:bytes];
+  bytes[len] = '\0';
+  cnt   = 0;
+  str   = nil;
+
+  while ((cnt < len) && (bytes[cnt] != '(')) cnt++;
+  
+  if (cnt < len) {
+    unichar  result[len+1];
+    int      resLen, commentNesting, begin;
+    BOOL     modifyValue;
+
+    resLen         = 0;
+    commentNesting = 0;
+    begin          = 0;
+    modifyValue    = NO;
+    
+    for (cnt = 0; cnt < len; cnt++) {
+      if (commentNesting == 0) {
+        if (isRfc822_QUOTE(bytes[cnt])) {
+          cnt++;
+          while ((cnt < len) && !isRfc822_QUOTE(bytes[cnt]))
+            cnt++;
+        }
+        else if (bytes[cnt] == '(') {
+          modifyValue = YES;
+          
+          if ((cnt - begin) > 0) {
+            int c;
+
+            for (c = begin; c < cnt; c++) 
+              result[resLen++]  = bytes[c];
+          }
+          commentNesting++;
+        }
+      }
+      else {
+        if (bytes[cnt] == ')') {
+          commentNesting--;
+          if (commentNesting == 0)
+            begin = (cnt + 1);
+        }
+        else if (bytes[cnt] == '(')
+          commentNesting++;
+      }
+    }
+    if (modifyValue) {
+      if ((cnt - begin) > 0) {
+        int c;
+
+        for (c = begin; c < cnt; c++)
+          result[resLen++]  = bytes[c];
+      }
+      str = [[[NSString alloc] initWithCharacters:result length:resLen]
+                        autorelease];
+    }
+  }
+  if (str == nil)
+    str = _rawValue;
+
+  if (MimeLogEnabled) {
+    if (str != _rawValue) {
+      [self logWithFormat:@"%s:%d remove comment [%@] -> [%@]",
+            __PRETTY_FUNCTION__, __LINE__, _rawValue, str];
+    }
+  }
+  return str;
+}
+
+- (NSData *)quotedPrintableDecoding:(NSData *)_value {
+  return _value;
+}
+
+- (id)parseValue:(NSString *)_data ofHeaderField:(NSString *)_field { 
+  // abstract
+  NSLog(@"ERROR(%s): subclass should override this method: %@",
+       __PRETTY_FUNCTION__, self);
+  return nil;
+}
+
+@end /* NGMimeHeaderFieldParser */
diff --git a/skyrix-core/NGMime/NGMimeHeaderFieldParserSet.m b/skyrix-core/NGMime/NGMimeHeaderFieldParserSet.m
new file mode 100644 (file)
index 0000000..cd15966
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeHeaderFieldParser.h"
+#include "NGMimeHeaderFields.h"
+#include "NGMimeUtilities.h"
+#include "common.h"
+#include <NGMime/NGMimePartParser.h>
+
+@implementation NGMimeHeaderFieldParserSet
+
++ (int)version {
+  return 2;
+}
+
+static NGMimeHeaderFieldParserSet *rfc822set = nil;
+
++ (id)headerFieldParserSet {
+  return [[[self alloc] init] autorelease];
+}
+
++ (id)defaultRfc822HeaderFieldParserSet {
+  id parser = nil;
+  static NGMimeHeaderNames *Fields = NULL;
+  
+  if (rfc822set)
+    return rfc822set;
+  
+  if (Fields == NULL)
+    Fields = (NGMimeHeaderNames *)[NGMimePartParser headerFieldNames];
+    
+  rfc822set = [[self alloc] init];
+
+  [rfc822set setParser:
+                 (parser = [[NGMimeContentTypeHeaderFieldParser alloc] init])
+            forField:Fields->contentType];
+  [parser release]; parser = nil;
+    
+  [rfc822set setParser:
+              (parser = [[NGMimeContentLengthHeaderFieldParser alloc] init])
+            forField:Fields->contentLength];
+  [parser release]; parser = nil;
+    
+  [rfc822set setParser:
+              (parser = [[NGMimeStringHeaderFieldParser alloc]
+                          initWithRemoveComments:NO])
+            forField:Fields->received];
+  [parser release]; parser = nil;
+    
+  [rfc822set setParser:
+                 (parser = [[NGMimeStringHeaderFieldParser alloc]
+                                 initWithRemoveComments:NO])
+            forField:Fields->subject];
+  [parser release]; parser = nil;
+    
+  [rfc822set setParser:
+                 (parser = [[NGMimeStringHeaderFieldParser alloc]
+                                 initWithRemoveComments:NO])
+            forField:@"x-face"];
+  [parser release]; parser = nil;
+
+  [rfc822set setParser:
+              (parser = [[NGMimeContentDispositionHeaderFieldParser alloc] 
+                          init])
+            forField:Fields->contentDisposition];
+  [parser release]; parser = nil;
+  [rfc822set setParser:
+              (parser = [[NGMimeRFC822DateHeaderFieldParser alloc] init])
+            forField:Fields->date];
+  [parser release]; parser = nil;
+  
+  return rfc822set;
+}
+
+- (id)init {
+  return [self initWithDefaultParser:
+                 [[[NGMimeStringHeaderFieldParser alloc] init] autorelease]];
+}
+- (id)initWithDefaultParser:(id<NGMimeHeaderFieldParser>)_parser {
+  if ((self = [super init])) {
+    self->fieldNameToParser = [[NSMutableDictionary alloc] initWithCapacity:32];
+    [self setDefaultParser:_parser];
+  }
+  return self;
+}
+- (id)initWithParseSet:(NGMimeHeaderFieldParserSet *)_set {
+  if ((self = [self initWithDefaultParser:[_set defaultParser]])) {
+    [self->fieldNameToParser addEntriesFromDictionary:_set->fieldNameToParser];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->fieldNameToParser release];
+  [self->defaultParser     release];
+  [super dealloc];
+}
+
+// accessors
+
+- (void)setParser:(id<NGMimeHeaderFieldParser>)_parser
+  forField:(NSString *)_name {
+
+  [self->fieldNameToParser setObject:_parser forKey:_name];
+}
+
+- (void)setDefaultParser:(id<NGMimeHeaderFieldParser>)_parser {
+  ASSIGN(self->defaultParser, _parser);
+}
+- (id<NGMimeHeaderFieldParser>)defaultParser {
+  return self->defaultParser;
+}
+
+/* operation */
+
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
+  id parser;
+
+  parser = [self->fieldNameToParser objectForKey:_field];
+  
+  if (parser == nil)
+    parser = [self defaultParser];
+
+  return [parser parseValue:_data ofHeaderField:_field];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  id           copy;
+  NSEnumerator *keys;
+  NSString     *key;
+
+  copy = [[NGMimeHeaderFieldParserSet allocWithZone:_zone]
+                                      initWithDefaultParser:
+                                        [self defaultParser]];
+  
+  keys = [self->fieldNameToParser keyEnumerator];
+  while ((key = [keys nextObject])) {
+    id value = [self->fieldNameToParser objectForKey:key];
+
+    [copy setParser:value forField:key];
+  }
+  return copy;
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<HeaderFieldParserSet: id=0x%08X map=%@ default=%@>",
+                     (unsigned)self, self->fieldNameToParser,
+                     [self defaultParser]];
+}
+
+@end /* NGMimeHeaderFieldParserSet */
diff --git a/skyrix-core/NGMime/NGMimeHeaderFields.h b/skyrix-core/NGMime/NGMimeHeaderFields.h
new file mode 100644 (file)
index 0000000..9bc9cf7
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeHeaderFields_H__
+#define __NGMime_NGMimeHeaderFields_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMime/NGMimeDecls.h>
+
+@class NSString, NSDictionary;
+
+/*
+  NGMimeContentDispositionHeaderField
+  
+  This class is a special value object for holding (and parsing)
+  the content of a content-disposition MIME header field (primarily
+  used for attachments).
+*/
+
+NGMime_EXPORT NSString *NGMimeContentDispositionInlineType;
+NGMime_EXPORT NSString *NGMimeContentDispositionAttachmentType;
+NGMime_EXPORT NSString *NGMimeContentDispositionFormType;
+
+@interface NGMimeContentDispositionHeaderField : NSObject
+{
+@protected
+  NSString     *type;
+  NSDictionary *parameters;
+}
+
+- (id)initWithString:(NSString *)_value;
+
+/* accessors */
+
+- (NSString *)type;
+
+/* parameters */
+
+- (NSString *)name;
+- (NSString *)filename;
+- (NSString *)valueOfParameterWithName:(NSString *)_name;
+
+- (NSString *)stringValue;
+- (NSString *)parametersAsString;
+- (BOOL)valueNeedsQuotes:(NSString *)_parameterValue;
+
+@end
+
+#endif /* __NGMime_NGMimeHeaderFields_H__ */
diff --git a/skyrix-core/NGMime/NGMimeHeaderFields.m b/skyrix-core/NGMime/NGMimeHeaderFields.m
new file mode 100644 (file)
index 0000000..e5a143c
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeHeaderFields.h"
+#include "NGMimeUtilities.h"
+#include "common.h"
+
+NGMime_DECLARE NSString *NGMimeContentDispositionInlineType     = @"inline";
+NGMime_DECLARE NSString *NGMimeContentDispositionAttachmentType = @"attachment";
+NGMime_DECLARE NSString *NGMimeContentDispositionFormType       = @"form-data";
+
+@implementation NGMimeContentDispositionHeaderField
+
+static int MimeLogEnabled = -1;
+
++ (int)version {
+  return 2;
+}
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  MimeLogEnabled = [ud boolForKey:@"MimeLogEnabled"] ? 1 : 0;
+}
+
+- (id)initWithString:(NSString *)_value {
+  unsigned len = [_value length];
+  unichar  buf[len+1];
+  
+  if (len == 0) {
+    [self logWithFormat:
+           @"WARNING(%s): no value for disposition header value!",
+            __PRETTY_FUNCTION__];
+    self = [self autorelease];
+    return nil;
+  }
+  
+  [_value getCharacters:buf];
+  buf[len] = '\0';
+  
+  if ((self = [super init])) {
+    unsigned cnt, start;
+
+    cnt = 0;
+    // skip leading spaces
+    
+    while (isRfc822_LWSP(buf[cnt])) cnt++;
+    
+    if (buf[cnt] == '\0') {
+      if (MimeLogEnabled) 
+        [self logWithFormat:@"WARNING(%s): no value for disposition header"
+              @" value !", __PRETTY_FUNCTION__];
+      self = [self autorelease];
+      return nil;
+    }
+    start = cnt;
+    
+    while ((buf[cnt] != ';') && (buf[cnt] != '\0') && !isRfc822_LWSP(buf[cnt]))
+      cnt++;
+
+    if (cnt <= start) {
+      if (MimeLogEnabled) 
+        [self logWithFormat:@"WARNING(%s): found no type in disposition "
+              @"header value (%@) !", __PRETTY_FUNCTION__, _value];
+      self = [self autorelease];
+      return nil;
+    }
+    
+    self->type = [[[NSString alloc]
+                             initWithCharacters:buf+start length:(cnt - start)]
+                             autorelease];
+    start      = 0;
+    self->type = [self->type lowercaseString];
+    self->type = [self->type retain];
+    
+    if (self->type == nil) {
+      if (MimeLogEnabled)
+        [self logWithFormat:@"WARNING(%s): found no type in disposition header "
+              @"value (%@) !", __PRETTY_FUNCTION__, _value];
+      self = [self autorelease];
+      return nil;
+    }
+    self->parameters = [parseParameters(self, _value, buf+cnt) retain];
+  }
+  return self;
+}
+
+- (id)init {
+  return [self initWithString:nil];
+}
+
+- (void)dealloc {
+  [self->type       release];
+  [self->parameters release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)type {
+  return self->type;
+}
+
+/* parameters */
+
+- (NSString *)name {
+  return [self->parameters objectForKey:@"name"];
+}
+- (NSString *)filename {
+  NSString *fn;
+
+  fn = [self->parameters objectForKey:@"filename"];
+
+  if (![fn isNotNull])
+    fn = nil;
+  
+  if (![fn length]) {
+    fn = [self name];
+  }
+  return fn;
+}
+
+- (NSString *)valueOfParameterWithName:(NSString *)_name {
+  return [self->parameters objectForKey:_name];
+}
+
+- (BOOL)valueNeedsQuotes:(NSString *)_parameterValue {
+  int     len = [_parameterValue length];
+  unichar cstr[len + 1];
+  int     cnt;
+
+  [_parameterValue getCharacters:cstr];
+
+  for (cnt = 0; cnt < len; cnt++) {
+
+    if (isMime_SpecialByte(cstr[cnt]))
+      return YES;
+
+    if (cstr[cnt] == 32)
+      return YES;
+  }
+  return NO;
+}
+
+- (NSString *)parametersAsString {
+  NSEnumerator *names;
+
+  if ((names = [self->parameters keyEnumerator])) {
+    NSMutableString *result = [NSMutableString stringWithCapacity:64];
+    NSString *name;
+
+    while ((name = [names nextObject])) {
+      id value = [[parameters objectForKey:name] stringValue];
+      [result appendString:@"; "];
+      [result appendString:name];
+      [result appendString:@"="];
+      if ([self valueNeedsQuotes:value]) {
+        [result appendString:@"\""];
+        [result appendString:value];
+        [result appendString:@"\""];
+      }
+      else
+        [result appendString:value];
+    }
+    return result;
+  }
+  else
+    return nil;
+}
+
+- (NSString *)stringValue {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:20];
+  [str appendString:type];
+  {
+    NSString *paras = [self parametersAsString];
+    if (paras) [str appendString:paras];
+  }
+  return str;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *d;
+
+  d = [[NSMutableString alloc] init];
+
+  [d appendFormat:@"<%@[0x%08X]: type=%@",
+       NSStringFromClass([self class]), self, self->type];
+
+  if (self->parameters)
+    [d appendFormat:@" parameters=%@", self->parameters];
+
+  [d appendString:@">"];
+  return [d autorelease];
+}
+
+@end /* NGMimeContentDispositionHeaderField */
diff --git a/skyrix-core/NGMime/NGMimeJoinedData.h b/skyrix-core/NGMime/NGMimeJoinedData.h
new file mode 100644 (file)
index 0000000..3cc6edb
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeJoinedData_H__
+#define __NGMime_NGMimeJoinedData_H__
+
+#import <Foundation/NSData.h>
+
+@class NSMutableArray;
+
+@interface NGMimeJoinedData : NSObject
+{
+  NSMutableArray *joinedDataObjects;
+}
+
+- (void)appendData:(NSData *)_data;
+
+- (void)appendBytes:(const void *)_bytes length:(unsigned int)_length;
+
+- (BOOL)writeToFile:(NSString*)_path atomically:(BOOL)_useAuxiliaryFile;
+
+@end /* NGMimeJoinedData */
+
+#endif /* __NGMime_NGMimeJoinedData_H__ */
diff --git a/skyrix-core/NGMime/NGMimeJoinedData.m b/skyrix-core/NGMime/NGMimeJoinedData.m
new file mode 100644 (file)
index 0000000..2c4623e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGMimeJoinedData.h"
+#include "timeMacros.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "NGMimeFileData.h"
+
+@implementation NGMimeJoinedData
+
+- (id)init {
+  if ((self = [super init])) {
+    self->joinedDataObjects = [[NSMutableArray alloc] initWithCapacity:16];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->joinedDataObjects release];
+  [super dealloc];
+}
+
+- (id)copyWithZone:(NSZone*)zone {
+    return RETAIN(self);
+}
+
+- (NSArray *)_joinedDataObjects {
+  return self->joinedDataObjects;
+}
+
+- (void)appendData:(NSData *)_data {
+  if ([_data isKindOfClass:[NGMimeJoinedData class]]) {
+    [self->joinedDataObjects addObjectsFromArray:
+         [(NGMimeJoinedData *)_data _joinedDataObjects]];
+  }
+  else
+    [self->joinedDataObjects addObject:_data];
+}
+
+- (void)appendBytes:(const void *)_bytes
+  length:(unsigned int)_length
+{
+  NSMutableData *data;
+
+  data = (NSMutableData *)[self->joinedDataObjects lastObject];
+
+  if ([data isKindOfClass:[NSMutableData class]]) {
+    [data appendBytes:_bytes length:_length];
+  }
+  else {
+    data = [NSMutableData dataWithBytes:_bytes length:_length];
+    [self->joinedDataObjects addObject:data];
+  }
+}
+
+- (BOOL)writeToFile:(NSString*)_path
+  atomically:(BOOL)_useAuxiliaryFile
+{
+  NSString      *filename = nil;
+  NSEnumerator  *enumerator;
+  NSData        *data;
+  volatile BOOL result;
+    
+  int fd;
+    
+  filename = _path;
+
+  fd = open([filename fileSystemRepresentation],
+            O_WRONLY | O_CREAT | O_TRUNC, 0600);
+  if (fd == -1) {
+    fprintf(stderr, "Could not open file for writing %s: %s\n",
+            [filename fileSystemRepresentation], strerror(errno));
+    return NO;
+  }
+
+  result     = YES;
+  enumerator = [self->joinedDataObjects objectEnumerator];
+
+  while ((data = [enumerator nextObject])) {
+
+    TIME_START("write bytes ");
+
+    if ([data isKindOfClass:[NGMimeFileData class]]) {
+      if (![(NGMimeFileData *)data appendDataToFileDesc:fd]) {
+        fprintf(stderr, "Failed to write %i bytes to %s: %s\n",
+                [data length],
+                [filename fileSystemRepresentation], strerror(errno));
+        close(fd);
+      }
+    }
+    else {
+      const void *bytes;
+      unsigned   len;
+
+      TIME_START("bytes ...")
+        bytes  = [data bytes];
+        len    = [data length];
+      TIME_END;
+      
+      if (write(fd, bytes, len) != (int)len) {
+        fprintf(stderr, "Failed to write %i bytes to %s: %s\n",
+                len, [filename fileSystemRepresentation], strerror(errno));
+        close(fd);
+        return NO;
+      }
+    }
+    TIME_END;
+  }
+  close(fd);
+        
+  return result;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X[%@]: joinedDataObjects=%d>",
+                   self, NSStringFromClass([self class]),
+                   [self->joinedDataObjects count]];
+}
+
+@end /* NGMimeJoinedData */
diff --git a/skyrix-core/NGMime/NGMimeMultipartBody.h b/skyrix-core/NGMime/NGMimeMultipartBody.h
new file mode 100644 (file)
index 0000000..ee3a32b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeMultipartBody_H__
+#define __NGMime_NGMimeMultipartBody_H__
+
+#import <Foundation/NSObject.h>
+#include <NGMime/NGPart.h>
+
+@class NSData, NSString, NSMutableArray;
+
+/*
+  Represents bodies of multipart entities.
+  Multipart bodies can be parsed 'on-demand'.
+
+  ATTENTION: the delegate is _required_ to persist until the multipart body
+             is parsed ! The body does not retain the delegate.
+*/
+
+@interface NGMimeMultipartBody : NSObject
+{
+@protected
+  id<NGMimePart> part;     /* non-retained */
+  NSString       *prefix;
+  NSString       *suffix;
+  NSMutableArray *bodyParts;
+
+  // for on-demand parsing
+  NSData         *rawData;
+  id             delegate; /* non-retained */
+  
+  struct {
+    BOOL isParsed:1;
+  } flags;
+}
+
+- (id)initWithPart:(id<NGMimePart>)_part; // designated initializer
+- (id)initWithPart:(id<NGMimePart>)_part
+  data:(NSData *)_data
+  delegate:(id)_delegate;
+
+// accessors
+
+- (id<NGMimePart>)part; // the part the body belongs to
+
+- (NSArray *)parts;
+- (void)addBodyPart:(id<NGPart>)_part;
+- (void)addBodyPart:(id<NGPart>)_part atIndex:(int)_idx;
+- (void)removeBodyPart:(id<NGPart>)_part;
+- (void)removeBodyPartAtIndex:(int)_idx;
+
+- (void)setPrefix:(NSString *)_prefix;
+- (NSString *)prefix;
+- (void)setSuffix:(NSString *)_suffix;
+- (NSString *)suffix;
+
+@end
+
+#endif /* __NGMime_NGMimeMultipartBody_H__ */
diff --git a/skyrix-core/NGMime/NGMimeMultipartBody.m b/skyrix-core/NGMime/NGMimeMultipartBody.m
new file mode 100644 (file)
index 0000000..83a56a4
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeMultipartBody.h"
+#include "NGMimeBodyParser.h"
+#include "common.h"
+
+@implementation NGMimeMultipartBody
+
++ (int)version {
+  return 2;
+}
+
+- (id)initWithPart:(id<NGMimePart>)_part {
+  if (_part == nil) {
+    NSLog(@"ERROR(%s): no part provided for multipart body !",
+         __PRETTY_FUNCTION__);
+    [self release];
+    return nil;
+  }
+  if ((self = [super init])) {
+    self->flags.isParsed = YES;
+  }
+  return self;
+}
+- (id)initWithPart:(id<NGMimePart>)_part data:(NSData *)_data 
+  delegate:(id)_del 
+{
+  if ((self = [self initWithPart:_part])) {
+    self->flags.isParsed = NO;
+    self->rawData        = [_data retain];
+    self->delegate       = _del;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithPart:nil];
+}
+
+- (void)dealloc {
+  [self->rawData   release];
+  [self->prefix    release];
+  [self->suffix    release];
+  [self->bodyParts release];
+  [super dealloc];
+}
+
+/* parsing */
+
+- (void)parse {
+  NGMimeMultipartBodyParser *parser = [[NGMimeMultipartBodyParser alloc] init];
+
+  self->flags.isParsed = YES;
+  
+  if (![parser parseBody:  self
+               ofMultipart:self->part
+               data:       self->rawData
+               delegate:   self->delegate])
+    NSLog(@"%@: error during parsing of multipart body (ignored)", self);
+
+  self->delegate = nil;
+
+  [parser release]; parser = nil;
+}
+
+static inline void _checkParse(NGMimeMultipartBody *self) {
+  if (!self->flags.isParsed) [self parse];
+}
+static inline void _checkArray(NGMimeMultipartBody *self) {
+  if (!self->flags.isParsed) [self parse];
+  if (self->bodyParts == nil)
+    self->bodyParts = [[NSMutableArray alloc] init];
+}
+
+/* accessors */
+
+- (id<NGMimePart>)part { // the part the body belongs to
+  return self->part;
+}
+
+- (NSArray *)parts {
+  return self->bodyParts;
+}
+
+- (void)addBodyPart:(id<NGPart>)_part {
+  _checkArray(self);
+  [self->bodyParts addObject:_part];
+}
+- (void)addBodyPart:(id<NGPart>)_part atIndex:(int)_idx {
+  _checkArray(self);
+  [self->bodyParts insertObject:_part atIndex:_idx];
+}
+
+- (void)removeBodyPart:(id<NGPart>)_part {
+  _checkArray(self);
+  [self->bodyParts removeObject:_part];
+}
+- (void)removeBodyPartAtIndex:(int)_idx {
+  _checkArray(self);
+  [self->bodyParts removeObjectAtIndex:_idx];
+}
+
+- (void)setPrefix:(NSString *)_prefix {
+  if (self->prefix != _prefix) {
+    [self->prefix release];
+    self->prefix = [_prefix copy];
+  }
+}
+- (NSString *)prefix {
+  return self->prefix;
+}
+
+- (void)setSuffix:(NSString *)_suffix {
+  if (self->suffix != _suffix) {
+    [self->suffix release];
+    self->suffix = [_suffix copy];
+  }
+}
+- (NSString *)suffix {
+  return self->suffix;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *d = [NSMutableString stringWithCapacity:64];
+
+  [d appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
+  
+  if (self->flags.isParsed) {
+    if (self->prefix)    [d appendFormat:@" prefix=%@", self->prefix];
+    if (self->suffix)    [d appendFormat:@" suffix=%@", self->suffix];
+    if (self->bodyParts) [d appendFormat:@" parts=%@",  self->bodyParts];
+  }
+  if (self->rawData) [d appendFormat:@" data=%@", self->rawData];
+  
+  [d appendString:@">"];
+  return d;
+}
+
+@end /* NGMimeMultipartBody */
diff --git a/skyrix-core/NGMime/NGMimeMultipartBodyParser.m b/skyrix-core/NGMime/NGMimeMultipartBodyParser.m
new file mode 100644 (file)
index 0000000..ee75087
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeBodyParser.h"
+#include "NGMimeBodyPartParser.h"
+#include "NGMimeMultipartBody.h"
+#include "common.h"
+
+@implementation NGMimeMultipartBodyParser
+
+static int MimeLogEnabled = -1;
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  MimeLogEnabled = [ud boolForKey:@"MimeLogEnabled"] ? 1 : 0;
+}
+
+// returns the postion of the '\r' that starts the boundary
+static inline const char
+*_findNextBoundary(const char *_from, unsigned _len,
+                   const char *_boundary, unsigned _boundaryLen, BOOL _isFirst)
+{
+  register unsigned pos  = 0;
+  register unsigned blen = _boundaryLen;
+
+  if (_isFirst) {
+    blen += 3; // -- + at least one EOL char at end of line
+    if (_len < blen) return NULL;  // too short to contain boundary
+    
+    for (pos = 0; (pos < _len) && (_len - pos > blen); pos++) {
+      if ((_from[pos] == '-') && (_from[pos + 1] == '-')) {
+        if (strncmp(&(_from[pos + 2]), _boundary, _boundaryLen) == 0) {
+          // found boundary;
+          return _from + pos;
+        }
+      }
+    }
+  }
+  else {
+    blen += 4; // -- + at least two EOL chars at start and end of line
+    if (_len < blen) return NULL; // too short to contain boundary
+
+    /* detect:
+         --boundary(--)?CR
+         CR--boundary(--)?CR
+         CRLF--boundary(--)?CRLF
+         LF--boundary(--)?LF
+    */
+    
+    for (pos = 0; (pos < _len) && ((_len - pos) > blen); pos++) {
+      if (_from[pos] == '\n') { // check for LF--
+        if ((_from[pos + 1] == '-') &&(_from[pos + 2] == '-')) {
+          // found LF--
+          if (strncmp(&(_from[pos + 3]), _boundary, _boundaryLen) == 0)
+            // found LF--boundary
+            return (_from + pos);
+        }
+      }
+      else if (_from[pos] == '\r') { // check for CR.-?
+        if ((_from[pos + 1] == '-') && (_from[pos + 2] == '-')) { // CHECK FOR CR--
+          // found CR--
+          if (strncmp(&(_from[pos + 3]), _boundary, _boundaryLen) == 0)
+            // found LF--boundary
+            return (_from + pos);
+        }
+        if ((_from[pos + 1] == '\n') && (_from[pos + 2] == '-')
+            && (_from[pos + 3] == '-')) {
+          // found CRLF--
+          if ((_len - pos) <= blen) {
+            // remaining part is too short for boundary starting with CRLF
+            break;
+          }
+          
+          if (strncmp(&(_from[pos + 4]), _boundary, _boundaryLen) == 0)
+            // found LF--boundary
+            return (_from + pos);
+        }
+      }
+      else if ((_from[pos] == '-') && (_from[pos + 1] == '-')) {
+        if (strncmp(&(_from[pos + 2]), _boundary, _boundaryLen) == 0) {
+            // found --boundary
+          return (_from + pos);
+        }
+      }
+    }
+  }
+  return NULL;
+}
+
+static inline BOOL
+_isEndBoundary(const char *_from, unsigned _len,
+               const char *_boundary, unsigned _boundaryLen)
+{
+  // no buffer out-of-bounds check, may cause segfault
+  
+  if (_len < (_boundaryLen + 8)) // + 2x CRLF and 2x '--'
+    return YES;
+
+  while (*_from != '-') _from++; // search first '-'
+  _from += 2; // skip '--'
+  
+  _from += _boundaryLen; // skip boundary;
+  return ((_from[0] == '-') && (_from[1] == '-')) ? YES : NO;
+}
+
+static inline const char *
+_skipBoundary(id self, const char *_from, unsigned _len, BOOL _first)
+{
+  register unsigned pos = 0;
+  register unsigned char c = 0;
+
+  if (_from == NULL) return NULL;
+
+  if (_from[0] == '-') { // skip '--'
+    c = 0; // EOL needs to be detected
+  }
+  else if (_from[1] == '-') { // skip CR-- or LF--
+    c = _from[0];
+    if ((c != '\n') && (c != '\r')) {
+      if (MimeLogEnabled) 
+        [self logWithFormat:@"WARNING(%s): invalid char before boundary '--'",
+              __PRETTY_FUNCTION__];
+    }
+    pos = 3;
+  }
+  else if (_from[2] == '-') { // skip CRLF--
+    c = _from[0];
+    if (c != '\r') {
+      if (MimeLogEnabled)
+        [self logWithFormat:@"WARNING(%s): missing CR before boundary 'LF--'",
+              __PRETTY_FUNCTION__];
+    }
+    c = _from[1];
+    if (c != '\n') {
+      if (MimeLogEnabled)
+        [self logWithFormat:@"WARNING(%s): missing LF before boundary '--' (after"
+              @"CR)", __PRETTY_FUNCTION__];
+    }
+    pos = 4;
+  }
+  else {
+    if (MimeLogEnabled)
+      [self logWithFormat:@"ERROR(%s): invalid parser state, skipping 4.",
+            __PRETTY_FUNCTION__];
+    pos = 4;
+  }
+
+  while (pos < _len) {
+    register unsigned char fc = _from[pos];
+    
+    if (c == 0) { // EOL detect (on first line)
+      if (fc == '\n') // LF
+        break;
+
+      if (fc == '\r') { // CR *
+        if ((pos + 1) == _len) // CR EOF
+          break;
+        else if (_from[pos + 1] == '\n') { // CRLF
+          pos++; // skip LF
+          break;
+        }
+        else // CR
+          break;
+      }
+    }
+    else if (fc == c) // EOL char is known
+      break;
+    
+    pos++;
+  }
+
+  if (pos < _len)
+    pos++; // skip EOL char
+  
+  return &(_from[pos]); // return pointer to position after char
+}
+
+- (NSArray *)_parseBody:(NGMimeMultipartBody *)_body
+  part:(id<NGMimePart>)_part data:(NSData *)_data
+  boundary:(const char *)_boundary length:(unsigned)_boundaryLen
+  delegate:(id)_delegate
+{
+  NSMutableArray    *result;
+  NSAutoreleasePool *pool;
+  const char *begin   = NULL;
+  const char *end     = NULL;
+  const char *buffer  = [_data bytes];
+  unsigned   len      = [_data length];
+  BOOL       isEOF    = NO;    
+
+  NSCAssert(buffer,                @"got no buffer");
+  NSCAssert(_boundary,             @"got no boundary");
+
+  result = [NSMutableArray arrayWithCapacity:7];
+  
+  // find first boundary and store prefix
+  
+  begin = _findNextBoundary(buffer, len, _boundary, _boundaryLen, YES);
+  
+  if (begin == NULL) {
+    if (MimeLogEnabled)
+      [self logWithFormat:@"WARNING(%s): Found multipart with no 1st boundary",
+            __PRETTY_FUNCTION__];
+    [result addObject:_data];
+    return result;
+  }
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  {
+    unsigned preLen = begin - buffer;
+    
+    if (preLen > 0) {
+      if ([_delegate respondsToSelector:
+                     @selector(multipartBodyParser:foundPrefix:inMultipart:)]) {
+        [_delegate multipartBodyParser:self
+                   foundPrefix:[NSData dataWithBytes:buffer length:preLen]
+                   inMultipart:_part];
+      }
+
+      [_body setPrefix:[NSString stringWithCString:buffer length:preLen]];
+    }
+  }
+
+  // skip first boundary
+  
+  begin = _skipBoundary(self, begin, len - (begin - buffer), YES);
+  NSCAssert(begin, @"could not skip 1st boundary ..");
+
+  // loop over multipart bodies and exit if end-boundary is found
+
+  do {
+
+    /* check for boundary denoting end of current part */
+    
+    end = _findNextBoundary(begin, len - (begin - buffer),
+                            _boundary,_boundaryLen, NO);
+    if (end == NULL) {
+      NSRange subDataRange;
+      NSData  *rawData = nil;
+
+      if (MimeLogEnabled)
+        [self logWithFormat:@"WARNING(%s): reached end of body without"
+              @" end-boundary", __PRETTY_FUNCTION__];
+      
+      subDataRange.location = (begin - buffer);
+      subDataRange.length   = ([_data length] + buffer - begin);
+      rawData = [_data subdataWithRange:subDataRange];
+      if (rawData)
+        [result addObject:rawData];
+      isEOF = YES;      
+      break;
+    }
+    else {
+      NSRange subDataRange;
+      NSData *rawData = nil;
+      
+      NSCAssert(end - begin >= 0, @"invalid range ..");
+
+      subDataRange.location = (begin - buffer);
+      subDataRange.length   = (end - begin);
+
+      rawData = [_data subdataWithRange:subDataRange];
+
+      if (rawData) {
+        [result addObject:rawData];
+      }
+      else {
+        NSLog(@"WARNING(%s): could not create rawdata for "
+              @" bodypart in multipart %@", __PRETTY_FUNCTION__,
+              _part);
+      }
+
+      /* check whether last read boundary was an end boundary */
+
+      if (_isEndBoundary(end, len - (end - buffer),
+                         _boundary, _boundaryLen)) {
+        isEOF = NO;
+        break;        
+      }
+      
+      /* skip non-end boundary */
+    
+      begin = _skipBoundary(self, end, len - (end - buffer), NO);
+    }
+  }
+  while (begin);
+
+  // skip end boundary and store suffix
+  if (!isEOF) {
+    if ((begin = _skipBoundary(self, end, len - (end - buffer), NO))) {   
+      unsigned sufLen;
+
+      sufLen = len - (begin - buffer);
+      
+      if (sufLen > 0) {
+        if ([_delegate respondsToSelector: @selector(multipartBodyParser:
+                                                     foundSuffix:
+                                                     inMultipart:)])
+            [_delegate multipartBodyParser:self
+                       foundSuffix:[NSData dataWithBytes:begin length:sufLen]
+                       inMultipart:_part];
+        
+        [_body setSuffix:[NSString stringWithCString:begin length:sufLen]];
+      }
+    }
+  }
+  
+  /* result is not contained in this pool, so no need to retain ... */
+  RELEASE(pool);
+
+  return result;
+}
+
+static NSString *_searchBoundary(NGMimeMultipartBodyParser *self,
+                                 NSData *_data) {
+  const char *buffer = [_data bytes];
+  int        length  = [_data length];  
+  int        pos     = 0;
+  BOOL       found   = NO;
+
+  if (length < 3)
+    return nil;
+
+  if ((buffer[0] == '-') && (buffer[1] == '-')) {   // no prefix
+    found = YES;
+    pos = 2;
+  }
+  else {
+    while (pos + 5 < length) {
+      if (buffer[pos + 2] != '-') {
+        // if third char is not a '-' it cannot be a boundary start
+        pos++;
+        continue;
+      }
+      
+      if (buffer[pos] == '\n') { // check for LF--
+        if (buffer[pos + 1] == '-') {
+          // found LF--
+          pos  += 3;
+          found = YES;
+          break;
+        }
+      }
+      else if (buffer[pos] == '\r') { // check for CR.-?
+        if ((buffer[pos + 1] == '-') ) { // CHECK FOR CR--
+          // found CR--
+          pos  += 3;
+          found = YES;
+          break;
+        }
+        if ((buffer[pos + 1] == '\n') && (buffer[pos + 3] == '-')) {
+          // found CRLF--
+          if ((length - pos) <= 4) {
+            // remaining part is too short for boundary starting with CRLF
+            break;
+          }
+          // found LF--boundary
+          pos  += 4;
+          found = YES;
+          break;
+        }
+      }
+      pos++;
+    }
+  }
+  if (found) {
+    int boundLength = 0;
+    
+    buffer += pos;
+    
+    while (((boundLength + pos) < length) &&
+           (buffer[boundLength] != '\n')  &&
+           (buffer[boundLength] != '\r')) {
+      boundLength++;
+    }
+    if ((boundLength + pos) < length) {
+      return [NSString stringWithCString:buffer length:boundLength]; 
+    }
+    else 
+      return nil;
+  }
+  else 
+    return nil;
+}
+
+- (id<NGMimePart>)parseBodyPartWithData:(NSData *)_rawData
+  inMultipart:(id<NGMimePart>)_multipart
+  parser:(NGMimePartParser *)_parser
+{
+  if (![_rawData length])
+    return nil;
+
+  return [_parser parsePartFromData:_rawData];
+}
+
+- (BOOL)parseBody:(NGMimeMultipartBody *)_body
+  ofMultipart:(id<NGMimePart>)_part
+  data:(NSData *)_data delegate:(id)_d
+{
+  NGMimeType *contentType  = nil;
+  NSString   *boundary     = nil;
+  NSArray    *rawBodyParts = nil;
+  BOOL       foundError    = NO;
+
+  contentType = [_part contentType];
+  boundary    = [contentType valueOfParameter:@"boundary"];
+  
+  if (boundary == nil)
+    boundary = _searchBoundary(self, _data);
+  
+  *(&foundError) = NO;
+  
+  *(&rawBodyParts) = [self _parseBody:_body part:_part data:_data
+                          boundary:[boundary cString]
+                          length:[boundary cStringLength]
+                          delegate:_d];
+
+  if (rawBodyParts) {
+    NGMimeBodyPartParser *bodyPartParser;
+    unsigned i, count;
+    BOOL     askDelegate = NO;
+
+    *(&count)          = [rawBodyParts count];    
+    *(&i)              = 0;
+    *(&bodyPartParser) = nil;
+
+    if ([_d respondsToSelector:
+              @selector(multipartBodyParser:parserForEntity:inMultipart:)]) {
+      *(&askDelegate) = YES;
+    }
+
+    for (i = 0; i < count; i++) {
+      NSString     *reason  =
+        @"ERROR: could not parse body part at index %i in multipart %@: %@";
+      NGMimePartParser *parser;
+      id               rawData;
+      id               bodyPart;
+
+      rawData      = [rawBodyParts objectAtIndex:i];      
+      *(&parser)   = bodyPartParser;
+      *(&bodyPart) = nil;
+
+      if (askDelegate) {
+        parser = [_d multipartBodyParser:self
+                     parserForEntity:rawData
+                     inMultipart:_part];
+        [parser setDelegate:_d];
+      }
+      else if (bodyPartParser == nil) {
+        bodyPartParser = [[NGMimeBodyPartParser alloc] init];
+        [bodyPartParser setDelegate:_d];
+        parser = bodyPartParser;
+      }
+
+      if (parser == nil) {
+        if (rawData) {
+         NSData *d;
+         
+         /* ensure that we have a copy, not a range on the full data */
+         d = [[NSData alloc] initWithBytes:[rawData bytes] 
+                             length:[rawData length]];
+          [_body addBodyPart:d];
+         RELEASE(d);
+       }
+      }
+      else {
+        NS_DURING {
+          if ([rawData length])
+            bodyPart = [self parseBodyPartWithData:rawData
+                             inMultipart:_part
+                             parser:parser];
+        }
+        NS_HANDLER {
+          NSLog(reason, i, _part, localException);
+          foundError = YES;
+        }
+        NS_ENDHANDLER;
+       
+        if (bodyPart) {
+          [_body addBodyPart:bodyPart];
+        }
+
+        parser = nil;
+      }
+    }
+    
+    RELEASE(bodyPartParser); bodyPartParser = nil;
+  }
+  return foundError;
+}
+
+- (BOOL)parseImmediatlyWithDelegate:(id)_delegate
+  multipart:(id<NGMimePart>)_part data:(NSData *)_data
+{
+  if ([_delegate respondsToSelector:
+          @selector(multipartBodyParser:immediatlyParseBodyOfMultipart:data:)]) {
+    BOOL result;
+
+    result = [_delegate multipartBodyParser:self
+                        immediatlyParseBodyOfMultipart:_part
+                        data:_data];
+    return result;
+  }
+  else
+    return YES;
+}
+
+- (id)parseBodyOfPart:(id<NGMimePart>)_part
+  data:(NSData *)_data delegate:(id)_d
+{
+  NGMimeMultipartBody *body;
+  NGMimeType *contentType;
+  NSString   *boundary;
+  unsigned   len;
+  
+  contentType = [_part contentType];
+  boundary    = [contentType valueOfParameter:@"boundary"];
+  len         = [_data length];
+  
+  if (len == 0)
+    return nil;
+  
+  if (contentType == nil) {
+    NSLog(@"ERROR [%s]: part %@ has no content type, cannot find out "
+          @"the boundary !", __PRETTY_FUNCTION__, _part);
+    return _data;
+  }
+  if (![contentType isCompositeType]) {
+    NSLog(@"ERROR [%s]: content type %@ of part %@ is not composite !",
+          __PRETTY_FUNCTION__, contentType, _part);
+    return _data;
+  }
+  if (boundary == nil) {
+    if (!(boundary = _searchBoundary(self, _data))) {
+      NSLog(@"ERROR [%s]: no boundary parameter in content "
+            @"type %@ of part %@ !",
+            __PRETTY_FUNCTION__, contentType, _part);
+      return _data;
+    }
+  }
+  if ([boundary length] > 70) {
+    if (MimeLogEnabled) 
+      [self logWithFormat:@"WARNING(%s): got boundary longer than 70 chars "
+            @"(not allowed by RFC) in type %@",
+            __PRETTY_FUNCTION__, contentType];
+  }
+  
+  if ([self parseImmediatlyWithDelegate:_d multipart:_part data:_data]) {
+    body = [[NGMimeMultipartBody alloc] initWithPart:_part];
+    body = AUTORELEASE(body);
+    
+    if (![self parseBody:body ofMultipart:_part data:_data delegate:_d])
+      ; // error
+  }
+  else {
+    body = [[NGMimeMultipartBody alloc]
+                                 initWithPart:_part data:_data delegate:_d];
+    body = AUTORELEASE(body);
+  }
+  
+  return body;
+}
+
+@end /* NGMimeMultipartBodyParser */
diff --git a/skyrix-core/NGMime/NGMimePartGenerator.h b/skyrix-core/NGMime/NGMimePartGenerator.h
new file mode 100644 (file)
index 0000000..1917378
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMimeGenerator_NGMimePartGenerator_H__
+#define __NGMimeGenerator_NGMimePartGenerator_H__
+
+#import <Foundation/NSObject.h>
+#import <NGMime/NGPart.h>
+#import <NGMime/NGMimeGeneratorProtocols.h>
+
+@class NSMutableData, NSData, NSString, NGHashMap, NGMutableHashMap;
+@class NGMimeType, NGMimePartGenerator;
+
+@interface NGMimePartGenerator : NSObject <NGMimePartGenerator>
+{
+@protected
+  NSMutableData  *result;  // result
+  id<NGMimePart> part;     // for generating
+  id             delegate; // not retained to prevent retain cycles
+
+  BOOL           useMimeData;
+  
+  void (*appendBytes)(id,SEL,const void*,unsigned int); /* cached method
+                                                           for result */
+  struct {
+    BOOL generatorGenerateDataForHeaderField:1;
+    BOOL generatorGeneratorForBodyOfPart:1;
+    BOOL generatorGenerateDataForBodyOfPart:1;
+  } delegateRespondsTo;
+}
+
++ (id)mimePartGenerator;
+
+/* generating mime from MimeMessage */
+- (NSData *)generateMimeFromPart:(id<NGMimePart>)_part;
+
+
+/* generate mime from part and store it in the returned filename */
+- (NSString *)generateMimeFromPartToFile:(id<NGMimePart>)_part;
+
+/* build data with current mime-header and the _additionalHeaders;
+   _additionalHeaders come from generateBodyData (boundary, encoding, ...) */
+- (NSData *)generateHeaderData:(NGHashMap *)_additionalHeaders;
+
+/* build the body; use -generatorForBodyOfPart */
+- (NSData *)generateBodyData:(NGMutableHashMap *)_additionalHeaders;
+
+/* call generateHeaderData and generateBodyData; manage additionalHeaders */
+- (void)generateData;
+
+/* set result and other stuff */
+- (BOOL)prepareForGenerationOfPart:(id<NGMimePart>)_part;
+
+/* setting the delegate */
+- (void)setDelegate:(id)_delegate;
+- (id)delegate;
+
+/* ----- hooks for subclasses ----- */
+
+/*
+  Generate a prefix and/or a suffix for a part. Can be used to write
+  HTTP response lines before the part.
+*/
+- (BOOL)generatePrefix;
+- (void)generateSuffix;
+
+/* if no content-type is set */
+- (NGMimeType *)defaultContentTypeForPart:(id<NGMimePart>)_part;
+
+/* returns header field generator for the specified field */
+- (id<NGMimeHeaderFieldGenerator>)generatorForHeaderField:(NSString *)_name;
+
+/* build data for the specified header; employ -generatorForHeaderField */
+
+- (NSData *)generateDataForHeaderField:(NSString *)_headerField
+  value:(id)_value;
+
+/* build data with the specified header; */
+
+- (NSData *)generateDataWithHeaderField:(NSString *)_headerField
+  values:(NSEnumerator *)_enumerator;
+
+/* looking for a NGMimeBodyGenerator in dependece to the content-type */
+- (id<NGMimeBodyGenerator>)generatorForBodyOfPart:(id<NGMimePart>)_part;
+
+/* ----- end hooks for subclasses ----- */
+
+/* accessors */
+- (id<NGMimePart>)part;
+
+@end
+
+@interface NSObject(NGMimePartGenerator)
+
+/*
+  The delegete has the opportunity to generate data for specified
+  header-field with the given enumerator. The classes of the values depends
+  on the _headerField name, normaly they are NSStrings
+*/   
+- (NSData *)mimePartGenerator:(id<NGMimePartGenerator>)_gen
+  generateDataForHeaderField:(NSString *)_headerField
+  value:(NSEnumerator *)_value;
+
+/*
+  The delegate can choose, which generator should be used, to generate
+  the specified NGMimePart.
+*/
+- (id<NGMimeBodyGenerator>)mimePartGenerator:(id<NGMimePartGenerator>)_gen
+  generatorForBodyOfPart:(id<NGMimePart>)_part;
+
+/*
+  The delegate has the opportunity to generate the whole body-part. Additional
+  headers like boundary can be set in _additionalHeaders.
+*/
+- (NSData *)mimePartGenerator:(id<NGMimePartGenerator>)_gen
+  generateDataForBodyOfPart:(id<NGMimePart>)_part
+  additionalHeaders:(NGMutableHashMap *)_additionalHeaders;
+
+/*
+  The delegate can set prefix and suffix for a multipart.
+*/
+- (NSString *)multipartBodyGenerator:(id<NGMimeBodyGenerator>)_bodyGen
+  prefixForPart:(id<NGMimePart>)_part;
+
+- (NSString *)multipartBodyGenerator:(id<NGMimeBodyGenerator>)_bodyGen
+  suffixForPart:(id<NGMimePart>)_part;
+
+/*
+  The delegate can select which NGMimeBodyGenerator should de used
+  for generate the given part.
+*/  
+- (id<NGMimePartGenerator>)multipartBodyGenerator:(id<NGMimeBodyGenerator>)
+  generatorForPart:(id<NGMimePart>)_part;
+
+- (BOOL)useMimeData;
+- (void)setUseMimeData:(BOOL)_b;
+
+@end
+
+#endif // __NGMimeGenerator_NGMimePartGenerator_H__
diff --git a/skyrix-core/NGMime/NGMimePartGenerator.m b/skyrix-core/NGMime/NGMimePartGenerator.m
new file mode 100644 (file)
index 0000000..64d9725
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "NGMimePartGenerator.h"
+#import "NGMimeHeaderFieldGenerator.h"
+#import "NGMimeBodyGenerator.h"
+#import "NGMimeJoinedData.h"
+#import <NGMime/NGMimeType.h>
+#import "common.h"
+
+@implementation NGMimePartGenerator
+
++ (int)version {
+  return 2;
+}
+
++ (id)mimePartGenerator {
+  return [[[self alloc] init] autorelease];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->part        = nil;
+    self->delegate    = nil;
+    self->appendBytes = NULL;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->result release];
+  [self->part   release];
+  self->appendBytes = NULL;
+  [super dealloc];
+}
+
+/* setting the delegate */
+
+- (void)setDelegate:(id)_delegate {
+  self->delegate = _delegate;
+
+  self->delegateRespondsTo.generatorGenerateDataForHeaderField =
+    [self->delegate respondsToSelector:
+         @selector(mimePartGenerator:generateDataForHeaderField:value:)];
+  
+  self->delegateRespondsTo.generatorGeneratorForBodyOfPart =
+    [self->delegate respondsToSelector:
+         @selector(mimePartGenerator:generatorForBodyOfPart:)];
+  
+  self->delegateRespondsTo.generatorGenerateDataForBodyOfPart =
+    [self->delegate respondsToSelector:
+         @selector(mimePartGenerator:generateDataForBodyOfPart:additionalHeaders:)];
+}
+
+- (id)delegate {
+  return self->delegate;
+}
+
+- (BOOL)prepareForGenerationOfPart:(id<NGMimePart>)_part {
+  {
+    id tmp = self->part;
+
+    self->part = _part;
+    
+    [self->part retain];
+    [tmp release]; tmp = nil;
+  }
+  if (self->result) {
+    [self->result release];
+    self->result = nil;
+  }
+  self->result = (self->useMimeData)
+    ? [[NGMimeJoinedData alloc] init]
+    : [[NSMutableData alloc] initWithCapacity:4096];
+    
+  
+  if ([self->result respondsToSelector:@selector(methodForSelector:)])
+    self->appendBytes = (void(*)(id,SEL,const void *, unsigned))
+                        [self->result methodForSelector:
+                                          @selector(appendBytes:length:)];
+  else
+    self->appendBytes = NULL;
+  return YES;
+}
+
+- (BOOL)generatePrefix {
+  return YES;
+}
+
+- (void)generateSuffix {
+}
+
+- (id<NGMimeHeaderFieldGenerator>)generatorForHeaderField:(NSString *)_name {
+  return [NGMimeHeaderFieldGeneratorSet defaultRfc822HeaderFieldGeneratorSet];
+}
+
+- (NSData *)generateDataForHeaderField:(NSString *)_headerField
+  value:(id)_value
+{
+  NSData *data = nil;
+
+  if (self->delegateRespondsTo.generatorGenerateDataForHeaderField)
+    data = [self->delegate mimePartGenerator:self
+                           generateDataForHeaderField:_headerField
+                           value:_value];
+  else {
+    data = [[self generatorForHeaderField:_headerField]
+                  generateDataForHeaderFieldNamed:_headerField
+                  value:_value];
+  }
+  return data;
+}
+
+- (NSData *)generateDataWithHeaderField:(NSString *)_headerField
+  values:(NSEnumerator *)_values
+{
+  NSMutableData *res   = nil;
+  NSData        *data  = nil;
+  id            value  = nil;
+  const char    *bytes = NULL;
+  unsigned      len    = 0;
+
+  res = [NSMutableData dataWithCapacity:64];
+  bytes = [_headerField cString];
+  len   = [_headerField length];
+  while (len > 0) {
+    if (*bytes != ' ')
+      break;
+    bytes++;
+    len--;
+  }
+  while ((value = [_values nextObject])) {
+    data = [self generateDataForHeaderField:(NSString *)_headerField
+                 value:value];
+    [res appendBytes:bytes length:len];
+    [res appendBytes:": " length:2];
+    [res appendData:data];
+    [res appendBytes:"\n" length:1];
+  }
+  return res;
+}
+  
+
+- (NSData *)generateHeaderData:(NGHashMap *)_additionalHeaders {
+  NSEnumerator     *headerFieldNames = nil;
+  NSString         *headerFieldName  = nil;
+  NGMutableHashMap *addHeaders       = nil;
+  NSMutableData    *data             = nil;
+
+  data = (self->useMimeData)
+    ? [[[NGMimeJoinedData alloc] init] autorelease]
+    : [NSMutableData dataWithCapacity:2048];
+  
+  headerFieldNames = [self->part headerFieldNames];
+  addHeaders       = [_additionalHeaders mutableCopy];
+
+  while ((headerFieldName = [headerFieldNames nextObject])) {
+    NSData       *headerFieldData = nil;
+    NSEnumerator *enumerator      = nil;
+    BOOL         reset;
+      
+    if ([[_additionalHeaders objectsForKey:headerFieldName] count] > 0) {
+      enumerator = [addHeaders objectEnumeratorForKey:headerFieldName];
+      reset = YES;
+    }
+    else {
+      reset = NO;
+      enumerator = [self->part valuesOfHeaderFieldWithName:headerFieldName];
+    }
+    headerFieldData = [self generateDataWithHeaderField:headerFieldName
+                            values:enumerator];
+    if (reset)
+      [addHeaders removeAllObjectsForKey:headerFieldName];
+    
+    if (headerFieldData)
+      [data appendData:headerFieldData];
+  }
+  headerFieldNames = [addHeaders keyEnumerator];
+  while ((headerFieldName = [headerFieldNames nextObject])) {
+    NSData *headerFieldData = nil;
+    headerFieldData = [self generateDataWithHeaderField:headerFieldName
+                            values:[addHeaders objectEnumeratorForKey:
+                                              headerFieldName]];
+    if (headerFieldData)
+      [data appendData:headerFieldData];
+  }
+  [addHeaders release]; addHeaders = nil;
+  return data;
+}
+
+- (NGMimeType *)defaultContentTypeForPart:(id<NGMimePart>)_part {
+  return [NGMimeType mimeType:@"application/octet"];
+}
+
+- (id<NGMimeBodyGenerator>)defaultBodyGenerator {
+  id<NGMimeBodyGenerator> gen;
+
+  gen = [[[NGMimeBodyGenerator alloc] init] autorelease];
+  [(id)gen setUseMimeData:self->useMimeData];
+  return gen;
+}
+
+- (id<NGMimeBodyGenerator>)generatorForBodyOfPart:(id<NGMimePart>)_part {
+  id<NGMimeBodyGenerator> bodyGen      = nil;
+  NGMimeType              *contentType = nil;
+  NSString                *type        = nil;
+  
+  if (self->delegateRespondsTo.generatorGeneratorForBodyOfPart)
+    bodyGen = [self->delegate mimePartGenerator:self
+                   generatorForBodyOfPart:self->part];
+
+  if (!bodyGen) {
+    contentType = [_part contentType];
+    if (contentType == nil) {
+      contentType = [self defaultContentTypeForPart:_part];
+    }
+    if (contentType == nil) {
+      NSLog(@"WARNING(%s): no content-type", __PRETTY_FUNCTION__);
+      return nil;
+    }
+    type = [contentType type];
+  
+    if ([type isEqualToString:NGMimeTypeMultipart]) {
+      bodyGen = [[[NGMimeMultipartBodyGenerator alloc] init] autorelease];
+    }
+    else if ([type isEqualToString:NGMimeTypeText]) {
+      bodyGen = [[[NGMimeTextBodyGenerator alloc] init] autorelease];
+    }
+    else if (([type isEqualToString:NGMimeTypeMessage]) &&
+             [[contentType subType] isEqualToString:@"rfc822"]) {
+      bodyGen = [[[NGMimeRfc822BodyGenerator alloc] init] autorelease];
+    }
+  }
+  [(id)bodyGen setUseMimeData:self->useMimeData];
+  return bodyGen;
+}
+
+- (NSData *)generateBodyData:(NGMutableHashMap *)_additionalHeaders {
+  NSData                  *data   = nil;
+  id<NGMimeBodyGenerator> bodyGen = nil;
+
+  if (self->delegateRespondsTo.generatorGenerateDataForBodyOfPart) {
+    data = [self->delegate mimePartGenerator:self
+                           generateDataForBodyOfPart:self->part
+                           additionalHeaders:_additionalHeaders];
+  }
+  else {
+    bodyGen = [self generatorForBodyOfPart:self->part];
+
+    if (bodyGen == nil) // no generator for body
+      bodyGen = [self defaultBodyGenerator];
+
+    [(id)bodyGen setUseMimeData:self->useMimeData];
+    
+    if (bodyGen == nil) {
+      id body = [self->part body];        
+      NSLog(@"WARNING(%s): no defaultBodyGenerator", __PRETTY_FUNCTION__);
+      if ([body isKindOfClass:[NSData class]]) {
+        data = body;
+      }
+      else if ([body isKindOfClass:[NSString class]]) {
+        data = [body dataUsingEncoding:[NSString defaultCStringEncoding]];
+      }
+    }
+    else {
+      data = [bodyGen generateBodyOfPart:self->part
+                      additionalHeaders:_additionalHeaders
+                      delegate:self->delegate];
+    }
+  }
+  return data;
+}
+
+- (void)generateData {
+  NGMutableHashMap *additionalHeaders = nil;
+  NSData           *bodyData          = nil;
+  NSData           *headerData        = nil;
+  
+  additionalHeaders = [[NGMutableHashMap alloc] initWithCapacity:16];
+  
+  bodyData   = [self generateBodyData:additionalHeaders];
+  headerData = [self generateHeaderData:additionalHeaders];
+
+  if (headerData != nil) {
+    [self->result appendData:headerData];
+    [self->result appendBytes:"\n" length:1];
+    if (bodyData != nil)
+      [self->result appendData:bodyData];
+  }
+  [additionalHeaders release];
+}
+
+- (NSData *)generateMimeFromPart:(id<NGMimePart>)_part {
+  [self prepareForGenerationOfPart:_part];
+  if ([self generatePrefix]) {
+    NSData *data;
+    
+    [self generateData];
+    [self generateSuffix];
+    data = self->result;
+    self->result = nil;
+    return [data autorelease];
+  }
+  return nil;
+}
+
+- (NSString *)generateMimeFromPartToFile:(id<NGMimePart>)_part {
+  NSString *filename = nil;
+
+  static NSString      *TmpPath = nil;
+  static NSProcessInfo *Pi      = nil;
+  
+  if (TmpPath == nil) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    
+    TmpPath = [ud stringForKey:@"NGMimeBuildMimeTempDirectory"];
+    if (TmpPath == nil)
+      TmpPath = @"/tmp/";
+    TmpPath = [[TmpPath stringByAppendingPathComponent:@"OGo"] copy];
+  }
+  if (Pi == nil)
+    Pi = [[NSProcessInfo processInfo] retain];
+
+  filename = [Pi temporaryFileName:TmpPath];
+
+  [self setUseMimeData:YES];
+
+  if (![[self generateMimeFromPart:_part]
+              writeToFile:filename atomically:YES]) {
+    NSLog(@"ERROR[%s] couldn`t write data to temorary file %@",
+          __PRETTY_FUNCTION__, filename);
+    return nil;
+  }
+  return filename;
+}
+
+- (id<NGMimePart>)part {
+  return self->part;
+}
+
+- (BOOL)useMimeData {
+  return self->useMimeData;
+}
+
+- (void)setUseMimeData:(BOOL)_b {
+  self->useMimeData = _b;
+}
+
+@end /* NGMimePartGenerator */
+  
diff --git a/skyrix-core/NGMime/NGMimePartParser.h b/skyrix-core/NGMime/NGMimePartParser.h
new file mode 100644 (file)
index 0000000..c1e005f
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimePartParser_H__
+#define __NGMime_NGMimePartParser_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+#import <NGStreams/NGStreamProtocols.h>
+#include <NGMime/NGPart.h>
+#include <NGMime/NGMimeHeaderFieldParser.h>
+#include <NGMime/NGMimeBodyParser.h>
+
+/*
+  NGMimePartParser
+  
+  This is an abstract class for parsing MIME parts.
+  
+  Known Subclasses:
+    NGMimeMessageParser  (parses RFC 822 MIME messages)
+    NGMimeBodyPartParser (parses the parts contained in a multipart structure)
+    NGHttpMessageParser  (parses HTTP messages)
+*/
+
+@class NSString, NSData;
+@class NGMutableHashMap, NGHashMap;
+@class NGByteBuffer;
+
+typedef struct _NGMimeHeaderNames {
+  NSString *accept;
+  NSString *acceptLanguage;
+  NSString *acceptEncoding;
+  NSString *acceptCharset;
+  NSString *cacheControl;
+  NSString *cc;
+  NSString *connection;
+  NSString *contentDisposition;
+  NSString *contentLength;
+  NSString *contentTransferEncoding;
+  NSString *contentType;
+  NSString *cookie;
+  NSString *date;
+  NSString *from;
+  NSString *host;
+  NSString *keepAlive;
+  NSString *messageID;
+  NSString *mimeVersion;
+  NSString *organization;
+  NSString *received;
+  NSString *returnPath;
+  NSString *referer;
+  NSString *replyTo;
+  NSString *subject;
+  NSString *to;
+  NSString *userAgent;
+  NSString *xMailer;
+} NGMimeHeaderNames;
+
+@interface NGMimePartParser : NSObject /* abstract */
+{
+@protected
+  NSData       *sourceData; /* for parsing with imutable data */
+  const char   *sourceBytes;
+  int          dataIdx;     /* data parsing index */
+  int          byteLen;
+  
+  NGByteBuffer *source; // for parsing with LA
+
+  /* cached selectors */
+  int (*readByte)(id, SEL);
+  int (*la)(id, SEL, unsigned);
+  void (*consume)(id, SEL);
+  void (*consumeCnt)(id, SEL, unsigned);
+
+  /* buffer-capacity and LA (has to be at least 4) */
+  int bufLen; 
+
+  /*
+    is set to the value of content-length header field
+    if contentLength == -1 -> read until EOF
+  */
+  int  contentLength;
+  BOOL useContentLength; // should be set in subclasses
+  NSString *contentTransferEncoding;
+  
+  id   delegate; // not retained to avoid retain cycles
+
+  struct {
+    BOOL parserWillParseHeader:1;
+    BOOL parserDidParseHeader:1;
+    BOOL parserKeepHeaderFieldData:1;
+    BOOL parserKeepHeaderFieldValue:1;
+    BOOL parserParseHeaderFieldData:1;
+    BOOL parserFoundCommentInHeaderField:1;
+    BOOL parserWillParseBodyOfPart:1;
+    BOOL parserDidParseBodyOfPart:1;
+    BOOL parserParseRawBodyDataOfPart:1;
+    BOOL parserBodyParserForPart:1;
+    BOOL parserDecodeBodyOfPart:1;
+  } delegateRespondsTo;
+
+  
+}
+
++ (NSStringEncoding)defaultHeaderFieldEncoding;
++ (NGMimeHeaderNames *)headerFieldNames;
+
+/* setting the delegate */
+
+- (void)setDelegate:(id)_delegate;
+- (id)delegate;
+
+/* parsing the whole part */
+
+- (id<NGMimePart>)parsePartFromStream:(id<NGStream>)_stream;
+- (id<NGMimePart>)parsePartFromData:(NSData *)_data;
+
+/* header field parsing */
+
+- (id<NGMimeHeaderFieldParser>)parserForHeaderField:(NSString *)_name;
+
+/* perform further parsing of the header value */
+
+- (id)valueOfHeaderField:(NSString *)_name data:(id)_data;
+
+// Parse headers until an empty line is seen, the delegate
+// can reject header fields from being included in the HashMap
+// This method can return <nil> to abort the parsing process.
+- (NGHashMap *)parseHeader;
+
+/* body parsing */
+
+- (id<NGMimePart>)producePartWithHeader:(NGHashMap *)_header;
+
+- (NSData *)decodeBody:(NSData *)_data ofPart:(id<NGMimePart>)_part;
+
+- (id<NGMimeBodyParser>)
+  parserForBodyOfPart:(id<NGMimePart>)_part data:(NSData *)_dt;
+
+- (NGMimeType *)defaultContentTypeForPart:(id<NGMimePart>)_part;
+
+- (void)parseBodyOfPart:(id<NGMimePart>)_part;
+
+/* hooks for subclasses */
+
+- (BOOL)parsePrefix; // returns NO to abort parsing
+- (void)parseSuffix;
+- (BOOL)prepareForParsingFromStream:(id<NGStream>)_stream;
+- (void)finishParsingOfPart:(id<NGMimePart>)_part;
+
+/* accessors */
+
+- (void)setUseContentLength:(BOOL)_use;
+- (BOOL)doesUseContentLength;
+
+- (NSData *)applyTransferEncoding:(NSString *)_encoding onData:(NSData *)_data;
+
+@end /* NGMimePartParser */
+
+@interface NSObject(NGMimePartParserDelegate)
+
+/*
+  Called before the parsing of the headers begins. The delegate can return NO to
+  stop parsing or YES to continue parsing.
+*/
+- (BOOL)parserWillParseHeader:(NGMimePartParser *)_parser;
+
+/*
+  This method is invoked when the parser finished parsing the complete header.
+  Those headers are available in the HashMap which is given to the delegate.
+*/
+- (void)parser:(NGMimePartParser *)_parser didParseHeader:(NGHashMap *)_headers;
+
+/*
+  This method is invoked when a header field was read in. The field value is
+  as raw data which may be further processed by a field-value-parser. With
+  this method the delegate becomes to opportunity to parse the value itself.
+  When implementing this method the delegate takes over full responsibility
+  for parsing the field-value, no header-parser is invoked by the MIME parser
+  automatically.
+*/
+- (id)parser:(NGMimePartParser *)_parser
+  parseHeaderField:(NSString *)_name
+  data:(NSData *)_data;
+
+/*
+  The delegate is asked whether the parser should proceed processing the header
+  field or whether the header field should be thrown away. Throwing away a header
+  field does not stop the parsing, it just ignores this field.
+*/
+- (BOOL)parser:(NGMimePartParser *)_parser
+  keepHeaderField:(NSString *)_name
+  data:(NSData *)_value;
+  
+/*
+  The delegate is asked whether the parser should proceed processing the header
+  field or whether the header field should be thrown away. Throwing away a header
+  field does not stop the parsing, it just ignores this field.
+  The value of the header is already parsed (this means in effect that the delegate
+  either didn't implement parser:keepHeader:data: or that it returned YES in this
+  method).
+*/
+- (BOOL)parser:(NGMimePartParser *)_parser
+  keepHeaderField:(NSString *)_name
+  value:(id)_value;
+
+/*
+  The parser found a comment in a header field. This comment could be stored for
+  further processing by the delegate. Comment are usually ignored.
+*/
+- (void)parser:(NGMimePartParser *)_parser
+  foundComment:(NSString *)_comment // can be nil, if keepComments==NO
+  inHeaderField:(NSString *)_name;
+
+/*
+  When the body of a part is read in appropriate content or content-transfer
+  encodings may need to be applied. Use this method to perform this operation.
+*/
+- (NSData *)parser:(NGMimePartParser *)_parser
+  decodeBody:(NSData *)_body
+  ofPart:(id<NGMimePart>)_part;
+
+/*
+  After the headers were parsed the parser creates an NGMimePart object which
+  containes the headers. It will then begin to read in the body of the MIME
+  message, usually first as an NSData object.
+  You can return NO if you want to stop parsing (eg based on some values in the
+  headers or YES if you want to have the parser read in the data of the body.
+*/
+- (BOOL)parser:(NGMimePartParser *)_parser
+  willParseBodyOfPart:(id<NGMimePart>)_part;
+
+/*
+  The parser successfully read in the body of the part.
+*/
+- (void)parser:(NGMimePartParser *)_parser
+  didParseBodyOfPart:(id<NGMimePart>)_part;
+
+/*
+  After the MIME parser read in the body as an NSData object the delegate can
+  parse the body data and assign the result to the _part.
+  The delegate can return NO if it decides not to parse the body. The builtin
+  parser sequence is applied in this case.
+  Instead of parsing the body itself the delegate can select an appropriate
+  parser for the body using the -parser:bodyParserForPart: delegate method.
+*/
+- (BOOL)parser:(NGMimePartParser *)_parser
+  parseRawBodyData:(NSData *)_data
+  ofPart:(id<NGMimePart>)_part;
+
+/*
+  If the delegate does not parse the body itself, it can still select an
+  appropriate body parser using this method.
+*/
+- (id<NGMimeBodyParser>)parser:(NGMimePartParser *)_parser
+  bodyParserForPart:(id<NGMimePart>)_part;
+
+@end /* NSObject(NGMimePartParserDelegate) */
+
+@interface NSObject(NGMimePartParser)
+
+- (void)parser:(NGMimePartParser *)_parser
+  setOriginalHeaderFieldName:(NSString *)_name;
+
+@end
+
+#endif /* __NGMime_NGMimePartParser_H__ */
diff --git a/skyrix-core/NGMime/NGMimePartParser.m b/skyrix-core/NGMime/NGMimePartParser.m
new file mode 100644 (file)
index 0000000..53060d1
--- /dev/null
@@ -0,0 +1,1343 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimePartParser.h"
+#include "NGMimeBodyParser.h"
+#include "NGMimeType.h"
+#include "NGMimeUtilities.h"
+#include "common.h"
+
+/* this tunes, how big reused data cache objects may get (10MB) */
+#define MAX_DATA_OBJECT_SIZE_CACHE (10*1024*1024)
+
+@implementation NGMimePartParser
+
+static Class StringClass  = Nil;
+static Class MStringClass = Nil;
+static Class DataClass    = Nil;
+static Class NSMutableDataClass = NULL;
+
+static NGMimeHeaderNames *HeaderNames = NULL;
+
++ (int)version {
+  return 3;
+}
+
+static int MimeLogEnabled = -1;
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  if (isInitialized) return;
+  isInitialized = YES;
+  
+  MimeLogEnabled     = [ud boolForKey:@"MimeLogEnabled"] ? 1 : 0;
+  MStringClass       = [NSMutableString class];
+  StringClass        = [NSString class];
+  DataClass          = [NSData class];
+  NSMutableDataClass = [NSMutableData class];
+}
+
+static inline int  _la(NGMimePartParser *self, int _la);
+static inline void _consume(NGMimePartParser *self, int _cnt);
+static inline BOOL _checkKey(NGMimePartParser *self, NGHashMap *_map,
+                             NSString *_key);
+
++ (NGMimeHeaderNames *)headerFieldNames {
+  if (HeaderNames == NULL) {
+    HeaderNames = malloc(sizeof(NGMimeHeaderNames));
+
+    HeaderNames->accept                  = @"accept";
+    HeaderNames->acceptLanguage          = @"accept-language";
+    HeaderNames->acceptEncoding          = @"accept-encoding";
+    HeaderNames->acceptCharset           = @"accept-charset";
+    HeaderNames->cacheControl            = @"cache-control";
+    HeaderNames->cc                      = @"cc";
+    HeaderNames->connection              = @"connection";
+    HeaderNames->contentDisposition      = @"content-disposition";
+    HeaderNames->contentLength           = @"content-length";
+    HeaderNames->contentTransferEncoding = @"content-transfer-encoding";
+    HeaderNames->contentType             = @"content-type";
+    HeaderNames->cookie                  = @"cookie";
+    HeaderNames->date                    = @"date";
+    HeaderNames->from                    = @"from";
+    HeaderNames->host                    = @"host";
+    HeaderNames->keepAlive               = @"keep-alive";
+    HeaderNames->messageID               = @"message-id";
+    HeaderNames->mimeVersion             = @"mime-version";
+    HeaderNames->organization            = @"organization";
+    HeaderNames->received                = @"received";
+    HeaderNames->returnPath              = @"return-path";
+    HeaderNames->referer                 = @"referer";
+    HeaderNames->replyTo                 = @"reply-to";
+    HeaderNames->subject                 = @"subject";
+    HeaderNames->to                      = @"to";
+    HeaderNames->userAgent               = @"user-agent";
+    HeaderNames->xMailer                 = @"x-mailer";
+  }
+  return HeaderNames;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->bufLen        = 1024;
+    self->contentLength = -1;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->contentTransferEncoding release];
+  [self->source     release];
+  [self->sourceData release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setDelegate:(id)_delegate {
+  self->delegate = _delegate;
+
+  self->delegateRespondsTo.parserWillParseHeader =
+    [self->delegate respondsToSelector:@selector(parserWillParseHeader:)];
+  
+  self->delegateRespondsTo.parserDidParseHeader =
+    [self->delegate respondsToSelector:@selector(parser:didParseHeader:)];
+
+  self->delegateRespondsTo.parserKeepHeaderFieldData =
+    [self->delegate respondsToSelector:@selector(parser:keepHeaderField:data:)];
+  
+  self->delegateRespondsTo.parserKeepHeaderFieldValue =
+    [self->delegate respondsToSelector:
+                      @selector(parser:keepHeaderField:value:)];
+
+  self->delegateRespondsTo.parserFoundCommentInHeaderField =
+    [self->delegate respondsToSelector:
+                      @selector(parser:foundComment:inHeaderField:)];
+
+  self->delegateRespondsTo.parserWillParseBodyOfPart =
+    [self->delegate respondsToSelector:@selector(parser:willParseBodyOfPart:)];
+  
+  self->delegateRespondsTo.parserDidParseBodyOfPart =
+    [self->delegate respondsToSelector:@selector(parser:didParseBodyOfPart:)];
+
+  self->delegateRespondsTo.parserParseRawBodyDataOfPart =
+    [self->delegate respondsToSelector:
+                      @selector(parser:parseRawBodyData:ofPart:)];
+  
+  self->delegateRespondsTo.parserBodyParserForPart =
+    [self->delegate respondsToSelector:@selector(parser:bodyParserForPart:)];
+
+  self->delegateRespondsTo.parserDecodeBodyOfPart =
+    [self->delegate respondsToSelector:@selector(parser:decodeBody:ofPart:)];
+
+  self->delegateRespondsTo.parserParseHeaderFieldData =
+    [self->delegate respondsToSelector:@selector(parser:parseHeaderField:data:)];
+}
+
+- (id)delegate {
+  return self->delegate;
+}
+
+/* header */
+
+- (id<NGMimeHeaderFieldParser>)parserForHeaderField:(NSString *)_name {
+  static id defParserSet = nil;
+  if (defParserSet == nil) {
+    defParserSet =
+      [[NGMimeHeaderFieldParserSet defaultRfc822HeaderFieldParserSet] retain];
+  }
+  return defParserSet;
+}
+
++ (NSStringEncoding)defaultHeaderFieldEncoding {
+  return NSISOLatin1StringEncoding;
+}
+
+- (id)valueOfHeaderField:(NSString *)_name data:(id)_data {
+  // TODO: use iconv (if available, eg not on OSX !!!) to convert
+  //       an unknown encoding to UTF-16 and create an NSConcrete*UTF16String
+  id<NGMimeHeaderFieldParser> parser;
+  NSString                    *tmp;
+  id value = nil;
+  
+  if (self->delegateRespondsTo.parserParseHeaderFieldData)
+    value = [delegate parser:self parseHeaderField:_name data:_data];
+  
+  if (value)
+    return value;
+  
+  if ([_data isKindOfClass:DataClass]) {
+    tmp = [[StringClass alloc]
+           initWithData:_data
+           encoding:[NGMimePartParser defaultHeaderFieldEncoding]];
+  }
+  else
+    tmp = [_data retain];
+  
+  if ((parser = [self parserForHeaderField:_name]))
+    value = [parser parseValue:tmp ofHeaderField:_name];
+  else
+    value = [tmp stringByTrimmingSpaces];
+  
+  value = [[value retain] autorelease];
+  [tmp release];
+  return value;
+}
+
+/*
+  possible constants:
+  
+  NGMime_CC                      = @"cc"; 
+  NGMime_To                      = @"to";                        : 2
+
+  NGMime_Date                    = @"date";
+  NGMime_Host                    = @"host";
+  NGMime_From                    = @"from";                      : 4
+
+  NGMime_Cookie                  = @"cookie"
+  NGMime_Accept                  = @"accept"                     : 6
+  
+  NGMime_Referer                 = @"referer"
+  NGMime_Subject                 = @"subject";                   : 7
+
+  NGMime_xMailer                 = @"x-mailer";
+  NGMime_ReplyTo                 = @"reply-to"
+  NGMime_Received                = @"received";                  : 8
+
+  NGMime_Connection              = @"connection"
+  NGMime_KeepAlive               = @"keep-alive"
+  NGMime_UserAgent               = @"user-agent";
+  NGMime_MessageID               = @"message-id";                : 10
+  
+  NGMime_ReturnPath              = @"return-path";               : 11
+
+  NGMime_MimeVersion             = @"mime-version";
+  NGMime_Organization            = @"organization";
+  NGMime_ContentType             = @"content-type";              : 12
+
+  NGMime_CacheControl            = @"cache-control"              : 13
+  
+  NGMime_AcceptCharset           = @"accept-charset"
+  NGMime_ContentLength           = @"content-length";            : 14
+
+  NGMime_AcceptEncoding          = @"accept-encoding"
+  NGMime_AcceptLanguage          = @"accept-language"            : 15
+
+  NGMime_ContentDisposition      = @"content-disposition";       : 19
+
+  NGMime_ContentTransferEncoding = @"content-transfer-encoding"; : 25
+*/
+
+static NSString *fieldNameForCString(id self, char *_cstring, int _len) {
+  if (HeaderNames == NULL)
+    [NGMimePartParser headerFieldNames];
+  
+  switch  (_len) {
+    case 0:
+      return @"";
+    case 2:
+      if (_cstring[0] == 'c' && _cstring[1] == 'c')
+        return HeaderNames->cc;
+      else if (_cstring[0] == 't' && _cstring[1] == 'o')
+        return HeaderNames->to;
+      break;
+    case 4:
+      if (_cstring[3] == 'e') {
+        if (strncmp(_cstring, "date", 4) == 0)
+          return HeaderNames->date;
+      }
+      else if (_cstring[3] == 'm') {
+        if (strncmp(_cstring, "from", 4) == 0)
+          return HeaderNames->from;
+      }
+      else if (_cstring[3] == 't') {
+        if (strncmp(_cstring, "host", 4) == 0)
+          return HeaderNames->host;
+      }
+      break;
+    case 6:
+      if (_cstring[5] == 't') {
+        if (strncmp(_cstring, "accept", 6) == 0)
+          return HeaderNames->accept;
+      }
+      if (_cstring[5] == 'e') {
+        if (strncmp(_cstring, "cookie", 6) == 0)
+          return HeaderNames->cookie;
+      }
+      break;
+    case 7:
+      if (_cstring[6] == 't') {
+        if (strncmp(_cstring, "subject", 7) == 0)
+          return HeaderNames->subject;
+      }
+      if (_cstring[6] == 'r') {
+        if (strncmp(_cstring, "referer", 7) == 0)
+          return HeaderNames->referer;
+      }
+      break;
+    case 8:
+      if (_cstring[5] == '-') {
+        if (strncmp(_cstring, "reply-to", 8) == 0)
+          return HeaderNames->replyTo;
+      }
+      if (_cstring[7] == 'd') {
+        if (strncmp(_cstring, "received", 8) == 0)
+          return HeaderNames->received;
+      }
+      if (_cstring[1] == '-') {
+        if (strncmp(_cstring, "x-mailer", 8) == 0)
+          return HeaderNames->xMailer;
+      }
+      break;
+    case 10:
+      if (_cstring[4] == '-') {
+        if (_cstring[6] == 'g') {
+          if (strncmp(_cstring, "user-agent", 10) == 0)
+            return HeaderNames->userAgent;
+        }
+        if (_cstring[6] == 'l') {
+          if (strncmp(_cstring, "keep-alive", 10) == 0)
+            return HeaderNames->keepAlive;
+        }
+      }
+      else if (_cstring[7] == '-') {
+        if (strncmp(_cstring, "message-id", 10) == 0)
+          return HeaderNames->messageID;
+      }
+      else if (_cstring[9] == 'n') {
+        if (strncmp(_cstring, "connection", 10) == 0)
+          return HeaderNames->connection;
+      }
+      break;
+    case 11:
+      if (_cstring[6] == '-') {
+        if (strncmp(_cstring, "return-path", 11) == 0)
+          return HeaderNames->returnPath;
+      }
+      break;
+    case 12:
+      if (_cstring[4] == '-') {
+        if (strncmp(_cstring, "mime-version", 12) == 0)
+          return HeaderNames->mimeVersion;
+      }
+      else if (_cstring[11] == 'n') {
+        if (strncmp(_cstring, "organization", 12) == 0)
+          return HeaderNames->organization;
+      }
+      else if (_cstring[7] == '-') {
+        if (strncmp(_cstring, "content-type", 12) == 0)
+          return HeaderNames->contentType;
+      }
+      break;
+    case 13:
+      if (_cstring[5] == '-') {
+        if (strncmp(_cstring, "cache-control", 13) == 0)
+          return HeaderNames->cacheControl;
+      }
+      break;
+    case 14:
+      if (_cstring[7] == '-') {
+        if (strncmp(_cstring, "content-length", 14) == 0) {
+          return HeaderNames->contentLength;
+        }
+      }
+      else if (_cstring[6] == '-') {
+        if (strncmp(_cstring, "accept-charset", 14) == 0)
+          return HeaderNames->acceptCharset;
+      }
+      break;
+    case 15:
+      if (_cstring[6] == '-') {
+        if (_cstring[7] == 'l') {
+          if (strncmp(_cstring, "accept-language", 15) == 0)
+            return HeaderNames->acceptLanguage;
+        }
+        else if (_cstring[7] == 'e') {
+          if (strncmp(_cstring, "accept-encoding", 15) == 0)
+            return HeaderNames->acceptEncoding;
+        }
+      }
+      break;
+    case 19:
+      if (_cstring[7] == '-') {
+        if (strncmp(_cstring, "content-disposition", 19) == 0)
+          return HeaderNames->contentDisposition;
+      }
+      break;
+    case 25:
+      if (_cstring[7] == '-') {
+        if (strncmp(_cstring, "content-transfer-encoding", 25) == 0)
+          return HeaderNames->contentTransferEncoding;
+      }
+      break;
+  }
+  {
+    NSString *result;
+
+    result = [NSString stringWithCString:_cstring length:_len];
+#if DEBUG & 0    
+    if (MimeLogEnabled)
+      [self logWithFormat:@"%s: found no headerfield constant for <%@>, "
+            @"generate new string", __PRETTY_FUNCTION__, result];
+#endif
+    return result;
+  }
+}
+
+
+- (NSString *)fieldNameForCString:(char *)_cstring length:(int)_len {
+  return fieldNameForCString(self, _cstring, _len);
+}
+
+- (NGHashMap *)parseHeader {
+  // TODO: split up this huge method!
+  /* parse headers until an empty line is seen */
+  NGMutableHashMap *header           = nil;
+  NSMutableData    *fieldValue       = nil;
+  NSMutableString  *fieldName        = nil;
+  NSString         *realFieldName    = nil;
+  BOOL             foundEndOfHeaders = NO;
+  int              bufCnt            = 0;
+  char             *buf              = NULL;
+  NSAutoreleasePool *pool;
+  
+  ASSIGN(self->contentTransferEncoding, (id)nil);
+  
+  if (self->delegateRespondsTo.parserWillParseHeader) {
+    if (![self->delegate parserWillParseHeader:self])
+      return nil;
+  }
+  
+  pool       = [[NSAutoreleasePool alloc] init];
+  fieldValue = [NSMutableData dataWithCapacity:512];
+  header     = [NGMutableHashMap hashMapWithCapacity:128];
+  buf        = calloc(self->bufLen, 1);
+  bufCnt     = *&bufCnt;
+  
+  while (!foundEndOfHeaders) {
+    int  c              = 0;
+    BOOL endOfFieldBody = NO;
+    
+    /* reset mutable vars */
+    
+    if (fieldName) {
+      [fieldName release];
+      fieldName = nil;
+    }
+    
+    [fieldValue setLength:0];
+    
+    /* parse fieldName */
+    {
+      unsigned fnlen;
+      BOOL lastWasCR;
+      
+      bufCnt    = 0;
+      fnlen     = 0;
+      lastWasCR = NO;
+      
+      while ((c = _la(self, 0)) != ':') {
+        if (c == -1)
+          /* EOF */
+          break;
+
+        /* check for leading '\r\n' or '\n' */
+        if (fnlen == 0) {
+          if (c == '\r') {
+            lastWasCR = YES;
+          }
+          else if (c == '\n') {
+            /* finish, found header starting with newline */
+            foundEndOfHeaders = YES;
+            endOfFieldBody    = YES;
+            self->useContentLength = NO;
+            _consume(self, 1); // consume newline
+            break; /* leave local loop */
+          }
+        }
+        else if ((fnlen == 1) && lastWasCR) {
+          if (c == '\n') {
+            /* finish, found \r\n */
+            foundEndOfHeaders = YES;
+            endOfFieldBody    = YES;
+            self->useContentLength = NO;
+            bufCnt = 0;
+            _consume(self, 1); // consume newline
+            break; /* leave local loop */
+          }
+        }
+        /* add to buffer */
+        buf[bufCnt] = c;
+        bufCnt++;
+        fnlen++;
+        
+        _consume(self, 1);
+      
+        if (bufCnt >= self->bufLen) {
+          register int i;
+
+          for (i = 0; i < bufCnt; i++)
+            buf[i] = tolower((int)buf[i]);
+
+          
+          if (fieldName == nil) {
+            fieldName = [[MStringClass alloc] initWithCString:buf length:bufCnt];
+          }
+          else {
+            NSString *s;
+
+            s = [[StringClass alloc] initWithCString:buf length:bufCnt];
+            [fieldName appendString:s];
+           [s release]; s = nil;
+          }
+          bufCnt = 0;
+        }
+      }
+      if (foundEndOfHeaders)
+        /* leave main loop */
+        break;
+      
+      if (bufCnt > 0) {
+        register int i;
+
+        for (i = 0; i < bufCnt; i++) 
+          buf[i] = tolower((int)buf[i]);
+       
+        if ([fieldName length] == 0) { 
+         /* const headernames are always smaller than bufLen */
+          realFieldName = fieldNameForCString(self, buf, bufCnt);
+        }
+        else {
+          NSString *s;
+
+          s = [[StringClass alloc] initWithCString:buf length:bufCnt];
+          [fieldName appendString:s];
+         [s release]; s = nil;
+          realFieldName = fieldName;
+         
+          if (c == -1) {
+            NSLog(@"WARNING(%s:%i): 1 an error occured during header-field "
+                  @" parsing (maybe end of stream) fieldName: %@",
+                  __PRETTY_FUNCTION__, __LINE__, fieldName);
+            foundEndOfHeaders = YES;
+            endOfFieldBody    = YES;
+          }
+        }
+      }
+      else {
+        realFieldName = fieldName;
+      }
+      _consume(self, 1);    // consume ':'
+    }
+    /* parse fieldBody */
+
+    bufCnt = 0;
+    while (!endOfFieldBody) {
+      int laC0 = _la(self, 0);
+      
+      if (laC0 == -1)
+        break;
+      
+      if (laC0 == '\r') {                        // CR
+        int laC1 = _la(self, 1);
+
+        if (isRfc822_LWSP(laC1)) {               // CR LSWSP
+          _consume(self, 2);  // folding
+        }
+        else if (laC1 == '\n') {                 // CR LF
+          int laC2 = _la(self, 2);
+
+          if (isRfc822_LWSP(laC2)) {             // CR LF LWSP
+            _consume(self, 3); // folding
+          }
+          else if (laC2 == '\r') {               // CR LF CR
+            int laC3 = _la(self, 3);
+
+            if (laC3 == '\n') {                  // CR LF CR LF
+              _consume(self, 4);
+              foundEndOfHeaders = YES;  // end of headers
+              endOfFieldBody    = YES;             
+            }
+            else {                               // CR LF CR *
+              _consume(self, 3); // ignored ??
+            }
+          }
+          else if (laC2 == '\n') {               // CR LF LF
+            _consume(self, 3);
+            foundEndOfHeaders = YES;  // end of headers
+            endOfFieldBody    = YES;            
+          }
+          else {                                 // CR LF *
+            _consume(self, 2);
+            endOfFieldBody = YES; //  next header field
+          }
+        }
+        else {                                   // CR *
+          _consume(self, 1);
+          endOfFieldBody = YES; // next header field
+        }
+      }
+      else  if (laC0 == '\n') {                  // LF
+        int laC1 = _la(self, 1);
+
+        if (isRfc822_LWSP(laC1)) {               // LF LWSP
+          _consume(self, 2); // folding
+        }
+        else if (laC1 == '\n') {                 // LF LF
+          _consume(self, 2);
+          foundEndOfHeaders = YES; // end of headers
+          endOfFieldBody    = YES; 
+        }
+        else if (laC1 == '\r') {                 // LF CR
+          int laC2 = _la(self, 2);
+          
+          if (isRfc822_LWSP(laC2)) {             // LF CR LWSP
+            _consume(self, 3); // folding
+          }
+          else if (laC2 == '\n') {               // LF CR LF
+            _consume(self, 3); //
+            foundEndOfHeaders = YES; // end of headers
+            endOfFieldBody    = YES; 
+          }
+          else {                                 // LF CR *
+            _consume(self, 2);
+            endOfFieldBody = YES; // next header field
+          }
+        }
+        else {                                   // LF *
+          _consume(self, 1);
+          endOfFieldBody = YES; // next header field
+        }
+      }
+      else {                                     // *
+        if ((bufCnt != 0) || (!isRfc822_LWSP(laC0))) {
+          /* ignore leading white spaces */
+          buf[bufCnt++] = laC0;
+        }
+        _consume(self, 1);
+        if (bufCnt >= self->bufLen) {
+          [fieldValue appendBytes:buf length:bufCnt];
+          bufCnt = 0;
+        }
+      }
+    }
+    if (bufCnt > 0) {
+      [fieldValue appendBytes:buf length:bufCnt];
+      bufCnt = 0;
+    }
+    if (!endOfFieldBody) {
+      [self logWithFormat:
+             @"WARNING(%s:%i): 2 an error occured during body parsing "
+              @"(maybe end of stream)", __PRETTY_FUNCTION__, __LINE__];
+      foundEndOfHeaders = YES;
+    }
+    if (realFieldName != nil) {
+      BOOL keepHeader = YES;
+
+      if (HeaderNames == NULL)
+        [NGMimePartParser headerFieldNames];
+
+      if (realFieldName == HeaderNames->contentTransferEncoding) {
+        int                 len;
+        const unsigned char *cstr;
+
+        len  = [fieldValue length];
+        cstr = [fieldValue bytes];
+          
+        keepHeader = NO; // don't keep content-tranfer-encodings
+          
+        while (isRfc822_LWSP(*cstr) && (len > 0)) { // strip leading spaces
+          cstr++;
+          len--;
+        }
+        if (len > 0) { // len==0 means the value was a string of LWSP
+          [self->contentTransferEncoding release];
+          self->contentTransferEncoding =
+            [[StringClass alloc] initWithCString:cstr length:len];
+        }
+        else
+          ASSIGN(self->contentTransferEncoding, (id)nil);
+      }
+      /*
+        take a look on content-length headers, since the parser
+        needs to know this for reading in the body ..
+      */
+      if (keepHeader && self->useContentLength) {
+        if (realFieldName == HeaderNames->contentLength) {
+          int                 len;
+         const unsigned char *cstr;
+          
+          len  = [fieldValue length];
+          cstr = [fieldValue bytes];
+
+          while (isRfc822_LWSP(*cstr) && (len > 0)) { // strip leading spaces
+            cstr++;
+            len--;
+          }
+          if (len > 0) { // len==0 means the value was a string of LWSP
+            unsigned char buf[len + 1];
+            int i = 0;
+
+            while (isdigit(*cstr) && (i < len)) { // extract following digits
+              buf[i++] = *cstr;
+              cstr++;
+            }
+            buf[i] = '\0'; // stop string after last digit (ignore the rest)
+            self->contentLength = atoi(buf);
+          }
+          else {
+            /* header value are only spaces */
+            self->contentLength = -1;
+          }
+        }
+      }
+      /* ask delegate if the header is to be kept */
+      if (keepHeader) {
+        if (self->delegateRespondsTo.parserKeepHeaderFieldData)
+          keepHeader = [self->delegate parser:self
+                                       keepHeaderField:realFieldName
+                                       data:fieldValue];
+      }
+      if (keepHeader) {
+        id value = nil;
+
+        value = [self valueOfHeaderField:realFieldName
+                      data:fieldValue];
+
+        if (value) {
+          value = [value retain];
+          /* ask delegate if the header is to be kept */
+          if (self->delegateRespondsTo.parserKeepHeaderFieldValue) {
+            keepHeader = [self->delegate parser:self
+                                         keepHeaderField:realFieldName
+                                         value:value];
+          }
+          if (keepHeader) {
+            NSAssert(realFieldName, @"missing field name ..");
+            NSAssert(value,     @"missing field value ..");
+
+            /*
+              check whether content-length, content-type,
+              subject already in hashmap
+            */
+            if (_checkKey(self, header, realFieldName))
+              [header addObject:value forKey:realFieldName];
+          }
+          [value release];
+        }
+      }
+    }
+  }
+  if (buf) {
+    free(buf);
+    buf = NULL;
+  }
+  
+  if (self->delegateRespondsTo.parserDidParseHeader)
+    [self->delegate parser:self didParseHeader:header];
+  
+  header = [header retain];
+  [pool release];
+  
+  return [header autorelease];
+}
+
+- (NSData *)readBodyUnknownLengthStream {
+  static NSMutableData *dataObject = nil;
+  NGIOReadMethodType readBytes = NULL;
+  NSData             *rbody;
+  NSMutableData      *body;
+  
+  int  bufCnt;
+  char buf[self->bufLen];
+  void (*appendBytes)(id,SEL,const void *,unsigned);
+  BOOL decodeBase64;
+
+  *(&readBytes) = NULL;
+  
+  if ([self->source respondsToSelector:@selector(methodForSelector:)]) {
+    readBytes = (NGIOReadMethodType)
+                [self->source methodForSelector:@selector(readBytes:count:)];
+  }
+  
+  *(&appendBytes) = NULL;
+  *(&bufCnt)      = 0;
+  
+  // THREAD
+  /* check whether we can reuse the dataObj ... */
+  if (dataObject) {
+    *(&body) = [dataObject autorelease];
+    dataObject = nil; /* mark as used ... */
+  }
+  else {
+    *(&body) = [[[NSMutableData alloc] initWithCapacity:100010] autorelease];
+  }
+
+  decodeBase64 = NO;
+  appendBytes  = (void(*)(id,SEL,const void *, unsigned))
+    [body methodForSelector:@selector(appendBytes:length:)];
+
+  NS_DURING {
+    while (YES) {
+      NSException *e;
+
+      NS_DURING {
+        _la(self, self->bufLen - 1);
+      }
+      NS_HANDLER {
+        if (![localException isKindOfClass:[NGEndOfStreamException class]])
+          [localException raise];
+      }
+      NS_ENDHANDLER;
+      
+      e = nil;
+      bufCnt = (readBytes != NULL)
+       ? readBytes(self->source, @selector(readBytes:count:),
+                   buf, self->bufLen)
+       : [self->source readBytes:buf count:self->bufLen];
+
+      if (bufCnt == NGStreamError) {
+       e = [self->source lastException];
+          
+       if ([e isKindOfClass:[NGEndOfStreamException class]])
+         /* leave loop */
+         break;
+       else
+         [e raise];
+      }
+      
+      /* perform any on-the-fly encodings */
+      
+      /* add to body data */
+      appendBytes(body, @selector(appendBytes:length:), buf, bufCnt);
+      bufCnt = 0;
+    }
+  }
+  NS_HANDLER {
+    if (![localException isKindOfClass:[NGEndOfStreamException class]])
+      [localException raise];
+  }
+  NS_ENDHANDLER;
+  if (bufCnt > 0) {
+    appendBytes(body, @selector(appendBytes:length:), buf, bufCnt);
+    bufCnt = 0;
+  }
+  
+  if (decodeBase64) {
+    ASSIGN(self->contentTransferEncoding, (id)nil);
+  }
+  rbody = [body copy];
+  // THREAD
+  /* remember that object for reuse ... */
+  if (dataObject == nil && [body length] < MAX_DATA_OBJECT_SIZE_CACHE) {
+    dataObject = [body retain];
+    [dataObject setLength:0];
+  }
+  
+  return [rbody autorelease];
+}
+
+- (NSData *)readBodyUnknownLengthData {
+  return [self->sourceData subdataWithRange:
+              NSMakeRange(self->dataIdx, self->byteLen - self->dataIdx)];
+}
+
+- (NSData *)readBodyUnknownLength {
+  return (self->source)
+    ? [self readBodyUnknownLengthStream]
+    : [self readBodyUnknownLengthData];
+}
+
+- (NSData *)readBodyWithKnownLengthFromStream:(unsigned)_len {
+  NGIOReadMethodType readBytes = NULL;
+  NSData             *rbody = nil;
+  unsigned char *buf = NULL;
+  int  readB     = 0;
+  
+  *(&readBytes) = NULL;
+  
+  if ([self->source respondsToSelector:@selector(methodForSelector:)]) {
+    readBytes = (NGIOReadMethodType)
+                [self->source methodForSelector:@selector(readBytes:count:)];
+  }
+  
+
+  *(&buf) = NULL;
+  readB   = 0;
+    
+  buf = calloc(_len, sizeof(char));
+    
+  NS_DURING {
+
+    NS_DURING {
+    if (self->contentLength > self->bufLen)
+      _la(self, self->bufLen - 1);
+    else
+      _la(self, self->contentLength - 1);
+    }
+    NS_HANDLER {
+      if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
+        fprintf(stderr,
+                "WARNING(%s): EOF occurred before whole content was read "
+                "(content-length=%i, read=%i)\n", __PRETTY_FUNCTION__,
+                self->contentLength, readB);
+      }
+      else {
+        if (buf) free(buf);
+        [localException raise];
+      }
+    }
+    NS_ENDHANDLER;
+      
+      
+    while (self->contentLength != readB) {
+      int tmp = self->contentLength - readB;
+        
+      readB += (readBytes != NULL)
+       ? readBytes(self->source, @selector(readBytes:count:),
+                   (buf + readB), tmp)
+       : [self->source readBytes:(buf + readB) count:tmp];
+
+      if (readB == NGStreamError) {
+       [[self->source lastException] raise];
+      }
+        
+      tmp = self->contentLength - readB;
+      if (tmp > 0) {
+       if (tmp > self->bufLen)
+         _la(self, self->bufLen - 1);
+       else
+         _la(self, tmp - 1);
+      }
+    }
+  }
+  NS_HANDLER {
+    if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
+      fprintf(stderr,
+             "WARNING(%s): EOF occurred before whole content was read "
+             "(content-length=%i, read=%i)\n", __PRETTY_FUNCTION__,
+             self->contentLength, readB);
+    }
+    else {
+      if (buf) free(buf);
+      [localException raise];
+    }
+  }
+  NS_ENDHANDLER;
+  
+  rbody = buf ? [NSData dataWithBytes:buf length:readB] : nil;
+  if (buf) free(buf);
+  return rbody;
+}
+
+- (NSData *)readBodyWithKnownLengthFromData:(unsigned)_len {
+  NSData *data;
+
+  data = [self->sourceData subdataWithRange:
+              NSMakeRange(self->dataIdx, self->byteLen - self->dataIdx)];
+  if ([data length] != _len) {
+    NSLog(@"%s[%i]: got wrong data %d _len %d", __PRETTY_FUNCTION__, __LINE__,
+          [data length], _len);
+    return nil;
+  }
+  return data;
+}
+
+- (NSData *)readBodyWithKnownLength:(unsigned)_len {
+  return (self->source)
+    ? [self readBodyWithKnownLengthFromStream:_len]
+    : [self readBodyWithKnownLengthFromData:_len];
+}
+
+- (NSData *)applyTransferEncoding:(NSString *)_encoding onData:(NSData *)_data{
+  // TODO: make this an NSData category
+  unsigned len;
+  unichar  c;
+  
+  if ((len = [_encoding length]) == 0)
+    return nil;
+  
+  _encoding = [_encoding lowercaseString];
+  
+  c = [_encoding characterAtIndex:0];
+  switch (c) {
+  case 'q':
+    if ([_encoding hasPrefix:@"quoted"])
+      return [_data dataByDecodingQuotedPrintable];
+    break;
+  case 'b':
+    if ([_encoding hasPrefix:@"base64"])
+      return [_data dataByDecodingBase64];
+    else if ([@"binary" isEqualToString:_encoding])
+      return _data;
+    break;
+  case '7':
+  case '8':
+  case 'i':
+    if (len == 4) {
+      if ([@"7bit" isEqualToString:_encoding])
+       return _data;
+      if ([@"8bit" isEqualToString:_encoding])
+       return _data;
+      break;
+    }
+    else if (len == 8) {
+      if ([@"identity" isEqualToString:_encoding])
+       return _data;
+    }
+
+  case 'u':
+    if (len == 12) {
+      if ([@"unknown-8bit" isEqualToString:_encoding])
+        return _data;
+    }
+  default:
+    break;
+  }
+  
+  return nil;
+}
+
+- (NSData *)readBody {
+  /* Read data of body and apply content-transfer-encoding if required. */
+  NSAutoreleasePool *pool;
+  NSData            *rbody = nil;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  if ((self->contentLength == -1) || (self->contentLength == 0)) {
+    rbody = [self readBodyUnknownLength];
+  }
+  else {
+    /* note: this is called only, if self->useContentLength is set ! */
+    rbody = [self readBodyWithKnownLength:self->contentLength];
+  }
+
+  if ([self->contentTransferEncoding length] > 0) {
+    NSData *new;
+    
+    new = [self applyTransferEncoding:self->contentTransferEncoding
+               onData:rbody];
+    if (new) {
+      ASSIGN(self->contentTransferEncoding, (id)nil);
+      rbody = new;
+    }
+    else {
+      [self logWithFormat:@"WARNING(%s): "
+             @"encountered unknown content-transfer-encoding: '%@'",
+              __PRETTY_FUNCTION__,
+              self->contentTransferEncoding];
+    }
+  }
+  
+  rbody = [rbody retain];
+  [pool release];
+  return [rbody autorelease];
+}
+
+- (NSData *)decodeBody:(NSData *)_data ofPart:(id<NGMimePart>)_part {
+  return (self->delegateRespondsTo.parserDecodeBodyOfPart)
+    ? [self->delegate parser:self decodeBody:_data ofPart:_part]
+    : _data;
+}
+
+- (NGMimeType *)defaultContentTypeForPart:(id<NGMimePart>)_part {
+  static NGMimeType *octetType = nil;
+  
+  if (octetType == nil)
+    octetType = [[NGMimeType mimeType:@"application/octet-stream"] retain];
+  return octetType;
+}
+
+- (id<NGMimeBodyParser>)parserForBodyOfPart:(id<NGMimePart>)_p
+  data:(NSData *)_dt
+{
+  id                   ctype;
+  NGMimeType           *contentType;
+  id<NGMimeBodyParser> bodyParser   = nil;
+  
+  ctype = [_p contentType];
+  
+  contentType = ([ctype isKindOfClass:[NGMimeType class]])
+    ? ctype
+    : [NGMimeType mimeType:[ctype stringValue]];
+  
+  if (self->delegateRespondsTo.parserBodyParserForPart) {
+    if ((bodyParser = [self->delegate parser:self bodyParserForPart:_p]))
+      return bodyParser;
+  }
+  
+  if (contentType == nil) {
+    contentType = [self defaultContentTypeForPart:_p];
+  }
+  
+  if (contentType) {
+    if ([[contentType type] isEqualToString:@"multipart"]) {
+      bodyParser = [[[NGMimeMultipartBodyParser alloc] init] autorelease];
+    }
+    else if ([[contentType type] isEqualToString:@"text"] &&
+             [[contentType subType] isEqualToString:@"plain"]) {
+      bodyParser = [[[NGMimeTextBodyParser alloc] init] autorelease];
+    }
+  }
+  return bodyParser;
+}
+
+- (void)parseBodyOfPart:(id<NGMimePart>)_part {
+  NGMimeBodyParser *parser  = nil;
+  NSData           *rawBody = nil;
+  id               body     = nil;
+
+  rawBody = [self readBody];
+
+  /* apply content-encoding, transfer-encoding and similiar */
+  rawBody = [self decodeBody:rawBody ofPart:_part];
+
+  if (self->delegateRespondsTo.parserParseRawBodyDataOfPart) {
+    BOOL didParse;
+
+    didParse =
+      [self->delegate parser:self parseRawBodyData:rawBody ofPart:_part];
+
+    if (didParse) return;
+  }
+  
+  parser = (NGMimeBodyParser *)[self parserForBodyOfPart:_part data:rawBody];
+  if (parser) {
+    /* make sure delegate keeps being around .. */
+    self->delegate = [[self->delegate retain] autorelease];
+
+    body = [parser parseBodyOfPart:_part
+                   data:rawBody
+                   delegate:self->delegate];
+  }
+  else if (rawBody) { /* no parser found for body */
+    if (body == nil) body = rawBody;
+  }
+  [_part setBody:body];
+}
+
+/* part */
+
+- (id<NGMimePart>)producePartWithHeader:(NGHashMap *)_header {
+  [self subclassResponsibility:_cmd];
+  return nil;
+}
+
+- (BOOL)prepareForParsingFromData:(NSData *)_data {
+  if (_data == nil)
+    return NO;
+
+  ASSIGN(self->sourceData, _data);
+  self->sourceBytes   = [self->sourceData bytes];
+  self->byteLen       = [self->sourceData length];
+  self->dataIdx       = 0;
+  self->contentLength = -1;
+
+  return YES;
+}
+
+- (BOOL)prepareForParsingFromStream:(id<NGStream>)_stream {
+  if (_stream == nil)
+    return NO;
+  
+  if (self->source != _stream) {
+    NGByteBuffer *bb;
+
+    bb = [NGByteBuffer alloc];
+    bb = [bb initWithSource:_stream la:self->bufLen];
+    [self->source release];
+    self->source = bb;
+  }
+  if ([self->source respondsToSelector:@selector(methodForSelector:)]) {
+    self->la         = (int (*)(id, SEL, unsigned))
+                       [self->source methodForSelector:@selector(la:)];
+    self->consume    = (void (*)(id, SEL))
+                       [self->source methodForSelector:@selector(consume)];
+    self->consumeCnt = (void (*)(id, SEL, unsigned))
+                       [self->source methodForSelector:@selector(consume:)];
+  }
+  else {
+    self->la         = NULL;
+    self->consume    = NULL;
+    self->consumeCnt = NULL;
+  }
+  self->contentLength = -1;
+
+  return YES;
+}
+
+- (void)finishParsingOfPart:(id<NGMimePart>)_part {
+  [self->source release]; self->source = nil;
+  self->contentLength = -1;
+  
+  self->la         = NULL;
+  self->consume    = NULL;
+  self->consumeCnt = NULL;
+}
+
+- (void)finishParsingOfPartFromData:(id<NGMimePart>)_part {
+  [self->sourceData release]; self->sourceData = nil;
+  self->sourceBytes   = NULL;
+  self->byteLen       = 0;
+  self->dataIdx       = 0;
+  self->contentLength = -1;
+}
+
+- (BOOL)parsePrefix {
+  return YES;
+}
+
+- (void)parseSuffix {
+}
+
+- (id<NGMimePart>)parsePart {
+  id<NGMimePart> part = nil;
+  NGHashMap *header;
+  BOOL      doParse = YES;
+  
+  if (![self parsePrefix])
+    return nil;
+  
+  if ((header = [self parseHeader]) == nil)
+    return nil;
+  
+  part = [self producePartWithHeader:header];
+  
+  doParse = (delegateRespondsTo.parserWillParseBodyOfPart)
+    ? [delegate parser:self willParseBodyOfPart:part]
+    : YES;
+  
+  if (doParse) {
+    NSAutoreleasePool *pool;
+
+    pool = [[NSAutoreleasePool alloc] init];
+    [self parseBodyOfPart:part];
+    [pool release];
+    
+    if (delegateRespondsTo.parserDidParseBodyOfPart)
+      [delegate parser:self didParseBodyOfPart:part];
+    
+    [self parseSuffix];
+  }
+  return part;
+}
+
+- (id<NGMimePart>)parsePartFromStream:(id<NGStream>)_stream {
+  id<NGMimePart> p;
+  
+  if (![self prepareForParsingFromStream:_stream])
+    return nil;
+  
+  p = [self parsePart];
+  [self finishParsingOfPart:p];
+  return p;
+}
+
+- (id<NGMimePart>)parsePartFromData:(NSData *)_data {
+  id<NGMimePart> part;
+  
+  if ([_data isKindOfClass:NSMutableDataClass]) {
+    NGDataStream *dataStream;
+  
+    dataStream = [NGDataStream streamWithData:_data];
+    part = [self parsePartFromStream:dataStream];
+    [dataStream close];
+    return part;
+  }
+
+  if ([self prepareForParsingFromData:_data]) {
+    part = [self parsePart];
+    [self finishParsingOfPartFromData:part];
+    return part;
+  }
+  
+  return nil;
+}
+
+/* accessors */
+
+- (BOOL)doesUseContentLength {
+  return self->useContentLength;
+}
+- (void)setUseContentLength:(BOOL)_use {
+  self->useContentLength = _use;
+}
+
+/* functions */
+
+static inline int _la(NGMimePartParser *self, int _la) {
+  if (self->source) {
+    return (self->la != NULL) ? self->la(self->source, @selector(la:), _la)
+      : [self->source la:_la];
+  }
+  else {
+    if ((self->dataIdx+_la) < self->byteLen)
+      return self->sourceBytes[self->dataIdx+_la];
+    else
+      return -1;
+  }
+}
+
+static inline void _consume(NGMimePartParser *self, int _cnt) {
+  if (self->source) {
+    if (_cnt == 1) {
+      if (self->consume != NULL)
+        self->consume(self->source, @selector(consume));
+      else
+        [self->source consume];
+    }
+    else {
+      if (self->consumeCnt != NULL)
+        self->consumeCnt(self->source, @selector(consume:), _cnt);
+      else
+        [self->source consume:_cnt];
+    }
+  }
+  else {
+    if ((self->dataIdx+_cnt) <= self->byteLen) {
+      self->dataIdx += _cnt;
+    }
+    else {
+      NSLog(@"%s[%i]: error try to read over buffer len self->dataIdx %d "
+            @"_cnt %d byteLen %d", __PRETTY_FUNCTION__, __LINE__,
+            self->dataIdx, _cnt, self->byteLen);
+    }
+  }
+}
+
+static inline BOOL _checkKey(NGMimePartParser *self, NGHashMap *_map,
+                             NSString *_key)
+{
+  if (HeaderNames == NULL)
+    [NGMimePartParser headerFieldNames];
+  
+  if  ((_key == HeaderNames->contentLength) ||
+       _key == HeaderNames->contentType) {
+    if ([_map countObjectsForKey:_key] > 0)
+      return NO;
+  }
+  return YES;
+}
+@end /* NGMimePartParser */
diff --git a/skyrix-core/NGMime/NGMimeRFC822DateHeaderFieldGenerator.m b/skyrix-core/NGMime/NGMimeRFC822DateHeaderFieldGenerator.m
new file mode 100644 (file)
index 0000000..1269f9f
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeHeaderFieldGenerator.h"
+#include "NGMimeHeaderFields.h"
+#include "common.h"
+
+@implementation NGMimeRFC822DateHeaderFieldGenerator
+
++ (int)version {
+  return 2;
+}
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value
+{
+  NSCalendarDate *date       = nil;
+  NSString       *dateString = nil;
+  
+  if ([_value isKindOfClass:[NSString class]])
+    return [_value dataUsingEncoding:NSUTF8StringEncoding];
+  
+  date = _value;
+
+  if (date == nil)
+    return [NSData data];
+  
+  if ([date respondsToSelector:@selector(descriptionWithCalendarFormat:)]) {
+    // TODO: do not use -descriptionWithCalendarFormat: !
+    //       - slow
+    //       - does not necessarily encode an English dayname!
+    dateString = [date descriptionWithCalendarFormat:
+                         @" %a, %d %b %Y %H:%M:%S %z"];
+  }
+  else
+    dateString = [date stringValue];
+  
+  return [dateString dataUsingEncoding:NSUTF8StringEncoding];
+}
+
+@end /* NGMimeRFC822DateHeaderFieldGenerator */
diff --git a/skyrix-core/NGMime/NGMimeRFC822DateHeaderFieldParser.m b/skyrix-core/NGMime/NGMimeRFC822DateHeaderFieldParser.m
new file mode 100644 (file)
index 0000000..092213e
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeHeaderFieldParser.h"
+#include "NGMimeHeaderFields.h"
+#include "NGMimeUtilities.h"
+#include "common.h"
+
+#define USE_CUSTOM_PARSER 1
+
+// TODO: if it works out, remove the old parser!
+
+@implementation NGMimeRFC822DateHeaderFieldParser
+
+static Class CalDateClass = Nil;
+#if USE_CUSTOM_PARSER
+static NSTimeZone *gmt   = nil;
+static NSTimeZone *gmt01 = nil;
+static NSTimeZone *gmt02 = nil;
+static NSTimeZone *gmt03 = nil;
+static NSTimeZone *gmt04 = nil;
+static NSTimeZone *gmt05 = nil;
+static NSTimeZone *gmt06 = nil;
+static NSTimeZone *gmt07 = nil;
+static NSTimeZone *gmt08 = nil;
+static NSTimeZone *gmt09 = nil;
+static NSTimeZone *gmt10 = nil;
+static NSTimeZone *gmt11 = nil;
+static NSTimeZone *gmt12 = nil;
+static NSTimeZone *gmtM01 = nil;
+static NSTimeZone *gmtM02 = nil;
+static NSTimeZone *gmtM03 = nil;
+static NSTimeZone *gmtM04 = nil;
+static NSTimeZone *gmtM05 = nil;
+static NSTimeZone *gmtM06 = nil;
+static NSTimeZone *gmtM07 = nil;
+static NSTimeZone *gmtM08 = nil;
+static NSTimeZone *gmtM09 = nil;
+static NSTimeZone *gmtM10 = nil;
+static NSTimeZone *gmtM11 = nil;
+static NSTimeZone *gmtM12 = nil;
+static NSTimeZone *gmtM13 = nil;
+static NSTimeZone *gmtM14 = nil;
+static NSTimeZone *met    = nil;
+#endif
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  CalDateClass = [NSCalendarDate class];
+#if USE_CUSTOM_PARSER
+  /* timezones which were actually used in a maillist mailbox */
+  gmt    = [[NSTimeZone timeZoneWithName:@"GMT"] retain];
+  met    = [[NSTimeZone timeZoneWithName:@"MET"] retain];
+  gmt01  = [[NSTimeZone timeZoneForSecondsFromGMT:  1 * (60 * 60)] retain];
+  gmt02  = [[NSTimeZone timeZoneForSecondsFromGMT:  2 * (60 * 60)] retain];
+  gmt03  = [[NSTimeZone timeZoneForSecondsFromGMT:  3 * (60 * 60)] retain];
+  gmt04  = [[NSTimeZone timeZoneForSecondsFromGMT:  4 * (60 * 60)] retain];
+  gmt05  = [[NSTimeZone timeZoneForSecondsFromGMT:  5 * (60 * 60)] retain];
+  gmt06  = [[NSTimeZone timeZoneForSecondsFromGMT:  6 * (60 * 60)] retain];
+  gmt07  = [[NSTimeZone timeZoneForSecondsFromGMT:  7 * (60 * 60)] retain];
+  gmt08  = [[NSTimeZone timeZoneForSecondsFromGMT:  8 * (60 * 60)] retain];
+  gmt09  = [[NSTimeZone timeZoneForSecondsFromGMT:  9 * (60 * 60)] retain];
+  gmt10  = [[NSTimeZone timeZoneForSecondsFromGMT: 10 * (60 * 60)] retain];
+  gmt11  = [[NSTimeZone timeZoneForSecondsFromGMT: 11 * (60 * 60)] retain];
+  gmt12  = [[NSTimeZone timeZoneForSecondsFromGMT: 12 * (60 * 60)] retain];
+  gmtM01 = [[NSTimeZone timeZoneForSecondsFromGMT: -1 * (60 * 60)] retain];
+  gmtM02 = [[NSTimeZone timeZoneForSecondsFromGMT: -2 * (60 * 60)] retain];
+  gmtM03 = [[NSTimeZone timeZoneForSecondsFromGMT: -3 * (60 * 60)] retain];
+  gmtM04 = [[NSTimeZone timeZoneForSecondsFromGMT: -4 * (60 * 60)] retain];
+  gmtM05 = [[NSTimeZone timeZoneForSecondsFromGMT: -5 * (60 * 60)] retain];
+  gmtM06 = [[NSTimeZone timeZoneForSecondsFromGMT: -6 * (60 * 60)] retain];
+  gmtM07 = [[NSTimeZone timeZoneForSecondsFromGMT: -7 * (60 * 60)] retain];
+  gmtM08 = [[NSTimeZone timeZoneForSecondsFromGMT: -8 * (60 * 60)] retain];
+  gmtM09 = [[NSTimeZone timeZoneForSecondsFromGMT: -9 * (60 * 60)] retain];
+  gmtM10 = [[NSTimeZone timeZoneForSecondsFromGMT:-10 * (60 * 60)] retain];
+  gmtM11 = [[NSTimeZone timeZoneForSecondsFromGMT:-11 * (60 * 60)] retain];
+  gmtM12 = [[NSTimeZone timeZoneForSecondsFromGMT:-12 * (60 * 60)] retain];
+  gmtM13 = [[NSTimeZone timeZoneForSecondsFromGMT:-13 * (60 * 60)] retain];
+  gmtM14 = [[NSTimeZone timeZoneForSecondsFromGMT:-14 * (60 * 60)] retain];
+#endif
+}
+
+/* 
+   All the date formats are more or less the same. If they start with a char
+   those can be skipped to the first digit (since it is the weekday name that
+   is unnecessary for date construction).
+   
+   TODO: use an own parser for that.
+*/
+
+#if !USE_CUSTOM_PARSER
+static NSString *numDateFormats[] = { /* dateformats starting with a number */
+  /*
+    day short-month year hour:minute:second timezoneoffset
+    eg: 01 Oct 1999 18:20:12 +0200
+  */
+  @"%d %b %Y %H:%M:%S %z",
+  
+  /*
+    day short-month year hour:minute:second timezonename
+    eg: 01 Oct 1999 18:20:12 EST
+  */
+  @"%d %b %Y %H:%M:%S %Z",
+  
+  /*
+    day short-month year hour:minute:second (timezoneoffset)
+    eg: 30 Sep 1999 21:00:05  (+0200)
+  */
+  @"%d %b %Y %H:%M:%S  (%z)",
+
+  /*
+    day short-month year hour:minute:second (timezonename)
+    eg: 30 Sep 1999 21:00:05  (MEST)
+  */
+  @"%d %b %Y %H:%M:%S  (%Z)",
+
+  /* eg: '16 Jun 2002 10:28 GMT' */
+  @"%d %b %Y %H:%M %Z",
+  
+  /* eg: '16 Jun 2002 10:28 +0000' */
+  @"%d %b %Y %H:%M %z",
+
+  /* terminate list */
+  nil
+};
+#endif
+
+static int parseMonthOfYear(unsigned char *s, unsigned int len) {
+  /*
+    This one is *extremely* forgiving, it only checks what is
+    necessary for the set below. This should work for both, English
+    and German.
+    
+    English: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+             J    F    M    A    M    J    J    A    S    O    N    D
+  */
+  if (len < 3) {
+    NSLog(@"RFC822 Parser: cannot process month name: '%s'", s);
+    return 0;
+  }
+  switch (toupper(*s)) {
+  case 'A': // April, August
+    if (toupper(s[1]) == 'P') return 4; // Apr
+    return 8; // Aug
+  case 'D': return 12; // Dec
+  case 'F': return  2; // Feb
+  case 'J': // Jan, Jun, Jul
+    if (toupper(s[1]) == 'A') return 1; // Jan
+    if (toupper(s[2]) == 'N') return 6; // Jun
+    return 7; // Jul
+  case 'M': // Mar, May
+    if (toupper(s[2]) == 'Y' || toupper(s[2]) == 'I') // May or Mai (German ;-)
+      return 5;
+    return 3; // Mar
+  case 'N': return 11; // Nov
+  case 'O': return 10; // Oct
+  case 'S': return  9; // Sep
+  default:
+    NSLog(@"RFC822 Parser: cannot process month name: '%s'", s);
+    return 0;
+  }
+}
+
+static NSTimeZone *parseTimeZone(unsigned char *s, unsigned int len) {
+  /*
+    WARNING: failed to parse RFC822 timezone: '+0530' \
+             (value='Tue, 13 Jul 2004 21:39:28 +0530')
+  */
+  unsigned char *p = s;
+  NSTimeZone    *tz;
+  NSString      *ts;
+  
+  if (len == 0) 
+    return nil;
+  
+  if (*s == '+' || *s == '-') {
+    if (len == 3) {
+      if (p[1] == '0' && p[2] == '0') // '+00' or '-00'
+       return gmt;
+      if (*s == '+') {
+       if (p[1] == '0' && p[2] == '1') // '+01'
+         return gmt01;
+       if (p[1] == '0' && p[2] == '2') // '+02'
+         return gmt02;
+      }
+    }
+    else if (len == 5) {
+      if (p[3] == '0' && p[4] == '0' && p[1] == '0') { // '?0x00'
+       if (p[2] == '0') // '+0000'
+         return gmt;
+       
+       if (*s == '+') {
+         if (p[2] == '1') return gmt01; // '+0100'
+         if (p[2] == '2') return gmt02; // '+0200'
+         if (p[2] == '3') return gmt03; // '+0300'
+         if (p[2] == '4') return gmt04; // '+0400'
+         if (p[2] == '5') return gmt05; // '+0500'
+         if (p[2] == '6') return gmt06; // '+0600'
+         if (p[2] == '7') return gmt07; // '+0700'
+         if (p[2] == '8') return gmt08; // '+0800'
+         if (p[2] == '9') return gmt09; // '+0900'
+       }
+       else if (*s == '-') {
+          if (p[2] == '1') return gmtM01; // '-0100'
+          if (p[2] == '2') return gmtM02; // '-0200'
+          if (p[2] == '3') return gmtM03; // '-0300'
+         if (p[2] == '4') return gmtM04; // '-0400'
+         if (p[2] == '5') return gmtM05; // '-0500'
+         if (p[2] == '6') return gmtM06; // '-0600'
+         if (p[2] == '7') return gmtM07; // '-0700'
+         if (p[2] == '8') return gmtM08; // '-0800'
+         if (p[2] == '9') return gmtM09; // '-0900'
+       }
+      }
+      else if (p[3] == '0' && p[4] == '0' && p[1] == '1') { // "?1x00"
+        if (*s == '+') {
+          if (p[2] == '0') return gmt10; // '+1000'
+          if (p[2] == '1') return gmt11; // '+1100'
+          if (p[2] == '2') return gmt12; // '+1200'
+        }
+        else if (*s == '-') {
+          if (p[2] == '0') return gmtM10; // '-1000'
+          if (p[2] == '1') return gmtM11; // '-1100'
+          if (p[2] == '2') return gmtM12; // '-1200'
+          if (p[2] == '3') return gmtM13; // '-1300'
+          if (p[2] == '4') return gmtM14; // '-1400'
+        }
+      }
+    }
+    else if (len == 7) {
+      /*
+        "MultiMail" submits timezones like this: 
+          "Tue, 9 Mar 2004 9:43:00 -05-500",
+        don't know what the "-500" trailer is supposed to mean? Apparently 
+        Thunderbird just uses the "-05", so do we.
+      */
+      
+      if (isdigit(p[1]) && isdigit(p[2]) && (p[3] == '-'||p[3] == '+')) {
+        unsigned char tmp[8];
+        
+        strncpy(tmp, p, 3);
+        tmp[3] = '0';
+        tmp[4] = '0';
+        tmp[5] = '\0';
+        return parseTimeZone(tmp, 5);
+      }
+    }
+  }
+  else if (*s == '0') {
+    if (len == 2) { // '00'
+      if (p[1] == '0') return gmt;
+      if (p[1] == '1') return gmt01;
+      if (p[1] == '2') return gmt02;
+    }
+    else if (len == 4) {
+      if (p[2] == '0' && p[3] == '0') { // '0x00'
+       if (p[1] == '0') return gmt;
+       if (p[1] == '1') return gmt01;
+       if (p[1] == '2') return gmt02;
+      }
+    }
+  }
+  else if (len == 3) {
+    if (strcasecmp(s, "GMT") == 0) return gmt;
+    if (strcasecmp(s, "MET") == 0) return met;
+  }
+  
+  if (isalpha(*s)) {
+    ts = [[NSString alloc] initWithCString:s length:len];
+  }
+  else {
+    char buf[len + 5];
+    
+    buf[0] = 'G'; buf[1] = 'M'; buf[2] = 'T';
+    if (*s == '+' || *s == '-') {
+      strcpy(&(buf[3]), s);
+    }
+    else {
+      buf[3] = '+';
+      strcpy(&(buf[4]), s);
+    }
+    ts = [[NSString alloc] initWithCString:buf];
+  }
+#if 0
+  NSLog(@"RFC822 TZ Parser: expensive: '%@'", ts);
+#endif
+  tz = [NSTimeZone timeZoneWithAbbreviation:ts];
+  [ts release];
+  return tz;
+}
+
+- (id)parseValue:(NSString *)_data ofHeaderField:(id)_field {
+  // TODO: use UNICODE
+  NSCalendarDate *date       = nil;
+  unsigned char  buf[256];
+  unsigned char  *bytes = buf, *pe;
+  unsigned       length = 0;
+#if USE_CUSTOM_PARSER
+  NSTimeZone     *tz = nil;
+  char  dayOfMonth, monthOfYear, hour, minute, second;
+  short year;
+  BOOL  flag;
+#else
+  NSString       *dateString = nil;
+#endif
+  
+  if ((length = [_data cStringLength]) > 254) {
+    [self logWithFormat:
+           @"header field value to large for date parsing: '%@'(%i)",
+           _data, length];
+    length = 254;
+  }
+  
+  [_data getCString:buf maxLength:length];
+  buf[length] = '\0';
+  
+  /* remove leading chars (skip to first digit, the day of the month) */
+  while (length > 0 && (!isdigit(*bytes))) {
+    bytes++;
+    length--;
+  }
+  
+  if (length == 0) {
+    NSLog(@"WARNING(%s): empty value for header field %@ ..",
+          __PRETTY_FUNCTION__, _field);
+    return [CalDateClass date];
+  }
+  
+#if USE_CUSTOM_PARSER // TODO: should be a category on NSCalendarDate
+  // TODO: optimize much further!
+  //   first part: '16 Jun 2002'
+  //   snd   part: '12:28[:11]'
+  //   trd   part: 'GMT' '+0000' '(MET)' '(+0200)'
+
+  /* defaults for early aborts */
+  tz     = gmt;
+  second = 0;
+  minute = 0;
+  
+  /* parse day of month */
+  
+  for (pe = bytes; isdigit(*pe); pe++)
+    ;
+  if (*pe == 0) goto failed;
+  *pe = '\0';
+  dayOfMonth = atoi(bytes);
+  bytes = pe + 1;
+  
+  /* parse month-abbrev (should be English, could be other langs) */
+  
+  while (!isalpha(*bytes)) { /* go to first char */
+    if (*bytes == '\0') goto failed;
+    bytes++;
+  }
+  for (pe = bytes; isalpha(*pe); pe++) /* find end of string */
+    ;
+  if (*pe == 0) goto failed;
+  *pe = '\0';
+  monthOfYear = parseMonthOfYear(bytes, (pe - bytes));
+  bytes = pe + 1;
+  
+  /* parse year */
+  
+  while (!isdigit(*bytes)) { /* go to first digit */
+    if (*bytes == '\0') goto failed;
+    bytes++;
+  }
+  for (pe = bytes; isdigit(*pe); pe++) /* find end of number */
+    ;
+  if (*pe == 0) goto failed;
+  *pe = '\0';
+  year = atoi(bytes);
+  bytes = pe + 1;
+  if (year >= 70 && year < 135) // Y2K
+    year += 1900;
+  else if (year >= 0 && year < 70) // Y2K
+    year += 2000;
+  
+  /* parse hour */
+  
+  while (!isdigit(*bytes)) { /* go to first digit */
+    if (*bytes == '\0') goto failed;
+    bytes++;
+  }
+  for (pe = bytes; isdigit(*pe); pe++) /* find end of number */
+    ;
+  flag = (*pe == 0);
+  *pe = '\0';
+  hour = bytes != pe ? atoi(bytes) : 0;
+  if (flag) goto finished; // this is: '12\0'
+  bytes = pe + 1;
+  
+  /* parse minute */
+  
+  while (!isdigit(*bytes)) { /* go to first digit */
+    if (*bytes == '\0') goto finished; // this is: '12  \0'
+    bytes++;
+  }
+  for (pe = bytes; isdigit(*pe); pe++) /* find end of number */
+    ;
+  flag = (*pe == 0);
+  *pe = '\0';
+  minute = bytes != pe ? atoi(bytes) : 0;
+  if (flag) goto finished; // this is: '12:23\0'
+  bytes = pe + 1;
+  
+  /* parse second - if available '13:13:23' vs '12:23\0' or '12:12 (MET)' */
+  
+  while (isspace(*bytes)) /* skip spaces */
+    bytes++;
+  if (*bytes == 0) goto finished; // this is: '12:23   \0'
+  if (isdigit(*bytes) || *bytes == ':') {
+    /* parse second */
+    while (!isdigit(*bytes)) { /* go to first digit, skip the ':' */
+      if (*bytes == '\0') goto finished;
+      bytes++;
+    }
+    
+    for (pe = bytes; isdigit(*pe); pe++) /* find end of number */
+      ;
+    flag = (*pe == 0);
+    *pe = '\0';
+    second = bytes != pe ? atoi(bytes) : 0;
+    if (flag) goto finished; // this is: '12:23:12\0'
+    bytes = pe + 1;
+  }
+  
+  /* parse timezone: 'GMT' '+0000' '(MET)' '(+0200)' */
+  // TODO: do we need to parse: "-0700 (PDT)" as "PDT"?
+  
+  while (isspace(*bytes) || *bytes == '(') /* skip spaces */
+    bytes++;
+  if (*bytes == 0) goto finished; // this is: '12:23:12 \0' or '12:12 ('
+  
+  for (pe = bytes; isalnum(*pe) || *pe == '-' || *pe == '+'; pe++)
+    ;
+  *pe = '\0';
+  if ((tz = parseTimeZone(bytes, (pe - bytes))) == nil) {
+    [self logWithFormat:
+            @"WARNING: failed to parse RFC822 timezone: '%s' (value='%@')",
+           bytes, _data];
+    tz = gmt;
+  }
+  
+  /* construct and return */
+ finished:  
+  date = [CalDateClass dateWithYear:year month:monthOfYear day:dayOfMonth
+                      hour:hour minute:minute second:second
+                      timeZone:tz];
+  if (date == nil) goto failed;
+
+#if 0  
+  printf("parsed '%s' to date: %s\n", 
+        [_data cString], [[date description] cString]);
+  //[self logWithFormat:@"parsed '%@' to date: %@", _data, date];
+#endif
+  return date;
+  
+ failed:
+  [self logWithFormat:@"WARNING: failed to parse RFC822 date field: '%@'",
+         _data];
+  return nil;
+
+#else
+  
+  dateString =
+    [[NSString alloc] initWithCString:bytes length:length];
+
+  /* check various date formats */
+  {
+    int i;
+    
+    for (i = 0, date = nil; (date == nil) && (numDateFormats[i] != nil); i++) {
+      date = [CalDateClass dateWithString:dateString
+                          calendarFormat:numDateFormats[i]];
+    }
+  }
+  
+  [dateString release]; dateString = nil;
+  
+  return [date y2kDate];
+#endif
+}
+
+@end /* NGMimeRFC822DateHeaderFieldParser */
diff --git a/skyrix-core/NGMime/NGMimeStringHeaderFieldGenerator.m b/skyrix-core/NGMime/NGMimeStringHeaderFieldGenerator.m
new file mode 100644 (file)
index 0000000..d089322
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeHeaderFieldGenerator.h"
+#include "NGMimeHeaderFields.h"
+#include "common.h"
+
+@implementation NGMimeStringHeaderFieldGenerator
+
++ (int)version {
+  return 2;
+}
+
+- (NSData *)generateDataForHeaderFieldNamed:(NSString *)_headerField
+  value:(id)_value
+{
+  if (_value == nil)
+    return [NSData data];
+
+  if ([_value isKindOfClass:[NSData class]])
+    return _value;
+
+  if (![_value isKindOfClass:[NSString class]])
+    _value = [_value stringValue];
+
+#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+  return [_value dataUsingEncoding:NSISOLatin1StringEncoding];
+#else
+  return [_value dataUsingEncoding:NSISOLatin9StringEncoding];
+#endif
+}
+
+@end /* NGMimeStringHeaderFieldGenerator */
diff --git a/skyrix-core/NGMime/NGMimeStringHeaderFieldParser.m b/skyrix-core/NGMime/NGMimeStringHeaderFieldParser.m
new file mode 100644 (file)
index 0000000..a9a4dd8
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGMimeHeaderFieldParser.h"
+#include "NGMimeHeaderFields.h"
+#include "NGMimeUtilities.h"
+#include "common.h"
+
+@implementation NGMimeStringHeaderFieldParser
+
+static BOOL StripLeadingSpaces = NO;
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  StripLeadingSpaces = [self doesStripLeadingSpaces];
+}
+
+- (id)initWithRemoveComments:(BOOL)_flag {
+  if ((self = [super init])) {
+    self->removeComments = _flag;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithRemoveComments:YES];
+}
+
+/* operation */
+
+- (id)parseValue:(NSString *)_value ofHeaderField:(NSString *)_field {
+  // TODO: fixup
+  unsigned len = [_value length];
+  unsigned cnt;
+  unichar  src[len+1];
+  NSString *res;
+
+  if (_value == nil)
+    return nil;
+  
+  if (len == 0)
+    return @"";
+
+  res = self->removeComments ? [self removeCommentsFromValue:_value] : _value;
+
+  if (StripLeadingSpaces) { /* currently be done during header field parsing */
+    [res getCharacters:src];
+    // strip leading spaces
+    cnt     = 0;
+  
+    while (isRfc822_LWSP(src[cnt]) && (len > 0)) {
+      cnt++;
+      len--;
+    }
+    if (cnt > 0)
+      res = [[[NSString alloc] initWithCharacters:src+cnt length:len]
+                        autorelease];
+  }
+  return res;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<MimeStringHeaderFieldParser: id=0x%08X"
+                     @" removesComments=%s>",
+                     (unsigned)self, self->removeComments ? "YES" : "NO"];
+}
+
+@end /* NGMimeStringHeaderFieldParser */
diff --git a/skyrix-core/NGMime/NGMimeType.h b/skyrix-core/NGMime/NGMimeType.h
new file mode 100644 (file)
index 0000000..638c95f
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGMime_NGMimeType_H__
+#define __NGMime_NGMimeType_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+#include <NGMime/NGMimeDecls.h>
+
+@class NSDictionary, NSString, NSEnumerator;
+
+// type & parameter constants
+
+NGMime_EXPORT NSString *NGMimeTypeText;
+NGMime_EXPORT NSString *NGMimeTypeAudio;
+NGMime_EXPORT NSString *NGMimeTypeVideo;
+NGMime_EXPORT NSString *NGMimeTypeImage;
+NGMime_EXPORT NSString *NGMimeTypeApplication;
+NGMime_EXPORT NSString *NGMimeTypeMultipart;
+NGMime_EXPORT NSString *NGMimeTypeMessage;
+
+NGMime_EXPORT NSString *NGMimeParameterTextCharset;
+
+/*
+  NGMimeType is a class cluster
+*/
+
+@interface NGMimeType : NSObject < NSCoding, NSCopying >
+{
+}
+
++ (id)mimeType:(NSString *)_type subType:(NSString *)_subType;
++ (id)mimeType:(NSString *)_type subType:(NSString *)_subType
+  parameters:(NSDictionary *)_parameters;
+
++ (id)mimeType:(NSString *)_stringValue;
+
++ (NSStringEncoding)stringEncodingForCharset:(NSString *)_s;
+
+/* type */
+
+- (NSString *)type;
+- (NSString *)subType;
+- (BOOL)isCompositeType;
+
+/* comparing types */
+
+- (BOOL)isEqualToMimeType:(NGMimeType *)_type;
+- (BOOL)isEqual:(id)_other;
+- (BOOL)hasSameGeneralType:(NGMimeType *)_other; // only the 'type' must match
+- (BOOL)hasSameType:(NGMimeType *)_other;        // parameters need not match
+- (BOOL)doesMatchType:(NGMimeType *)_other;      // interpretes wildcards
+
+// parameters
+
+- (NSEnumerator *)parameterNames;
+- (id)valueOfParameter:(NSString *)_parameterName;
+
+// representations
+
+- (NSDictionary *)parametersAsDictionary;
+- (NSString *)parametersAsString;
+- (BOOL)valueNeedsQuotes:(NSString *)_parameterValue;
+
+- (NSString *)stringValue;
+
+@end
+
+#endif /* __NGMime_NGMimeType_H__ */
diff --git a/skyrix-core/NGMime/NGMimeType.m b/skyrix-core/NGMime/NGMimeType.m
new file mode 100644 (file)
index 0000000..b57fe53
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGMimeType.h"
+#include "NGConcreteMimeType.h"
+#include "NGMimeUtilities.h"
+#include "common.h"
+
+NGMime_DECLARE NSString *NGMimeTypeText        = @"text";
+NGMime_DECLARE NSString *NGMimeTypeAudio       = @"audio";
+NGMime_DECLARE NSString *NGMimeTypeVideo       = @"video";
+NGMime_DECLARE NSString *NGMimeTypeImage       = @"image";
+NGMime_DECLARE NSString *NGMimeTypeApplication = @"application";
+NGMime_DECLARE NSString *NGMimeTypeMultipart   = @"multipart";
+NGMime_DECLARE NSString *NGMimeTypeMessage     = @"message";
+NGMime_DECLARE NSString *NGMimeParameterTextCharset = @"charset";
+
+static BOOL _parseMimeType(id self, NSString *_str, NSString **type,
+                           NSString **subType, NSDictionary **parameters);
+
+@implementation NGMimeType
+
++ (int)version {
+  return 2;
+}
+
+static NSMutableDictionary *typeToClass = nil;
+
+static inline Class
+classForType(NSString *_type, NSString *_subType, NSDictionary *_parameters)
+{
+  Class c = Nil;
+  if (_type == nil) return Nil;
+
+  if ([_type isEqualToString:@"*"] || [_subType isEqualToString:@"*"])
+    return [NGConcreteWildcardType class];
+
+  if ([_type isEqualToString:NGMimeTypeApplication]) {
+    if ([_subType isEqualToString:@"octet"])
+      return [NGConcreteAppOctetMimeType class];
+  }
+  if ([_type isEqualToString:NGMimeTypeText]) {
+    if ([_subType isEqualToString:@"x-vcard"])
+      return [NGConcreteTextVcardMimeType class];
+  }
+  
+  c = [typeToClass objectForKey:_type];
+  return c ? c : [NGConcreteGenericMimeType class];
+}
+static Class NSStringClass  = Nil;
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+
+    typeToClass = [[NSMutableDictionary alloc] initWithCapacity:10];
+    [typeToClass setObject:[NGConcreteTextMimeType  class] 
+                forKey:NGMimeTypeText];
+    [typeToClass setObject:[NGConcreteVideoMimeType class] 
+                forKey:NGMimeTypeVideo];
+    [typeToClass setObject:[NGConcreteAudioMimeType class] 
+                forKey:NGMimeTypeAudio];
+    [typeToClass setObject:[NGConcreteImageMimeType class] 
+                forKey:NGMimeTypeImage];
+    [typeToClass setObject:[NGConcreteApplicationMimeType class]
+                 forKey:NGMimeTypeApplication];
+    [typeToClass setObject:[NGConcreteMultipartMimeType class]
+                 forKey:NGMimeTypeMultipart];
+    [typeToClass setObject:[NGConcreteMessageMimeType class]
+                 forKey:NGMimeTypeMessage];
+  }
+}
+
++ (NSStringEncoding)stringEncodingForCharset:(NSString *)_s {
+  NSString         *charset;
+  NSStringEncoding encoding;
+  BOOL             foundUnsupported;
+
+  foundUnsupported = NO;  
+  charset          = [_s lowercaseString];
+  
+  if ([charset length] == 0)
+    encoding = [NSString defaultCStringEncoding];
+  
+  /* UTF-, ASCII */
+  else if ([charset isEqualToString:@"us-ascii"])
+    encoding = NSASCIIStringEncoding;
+  else if ([charset isEqualToString:@"utf-8"])
+    encoding = NSUTF8StringEncoding;
+  else if ([charset isEqualToString:@"utf-16"])
+    encoding = NSUnicodeStringEncoding;
+
+  /* ISO Latin 1 */
+  else if ([charset isEqualToString:@"iso-latin-1"])
+    encoding = NSISOLatin1StringEncoding;
+  else if ([charset isEqualToString:@"iso-8859-1"])
+    encoding = NSISOLatin1StringEncoding;
+  else if ([charset isEqualToString:@"8859-1"])
+    encoding = NSISOLatin1StringEncoding;
+  
+  /* some unsupported, but known encoding */
+  else if ([charset isEqualToString:@"ks_c_5601-1987"]) {
+    encoding = [NSString defaultCStringEncoding];
+    foundUnsupported = YES;
+  }
+  else if ([charset isEqualToString:@"euc-kr"]) {
+    encoding = [NSString defaultCStringEncoding];
+    foundUnsupported = YES;
+  }
+  else if ([charset isEqualToString:@"big5"]) {
+    encoding = [NSString defaultCStringEncoding];
+    foundUnsupported = YES;
+  }
+  else if ([charset isEqualToString:@"iso-2022-jp"]) {
+    encoding = [NSString defaultCStringEncoding];
+    foundUnsupported = YES;
+  }
+  else if ([charset isEqualToString:@"gb2312"]) {
+    encoding = [NSString defaultCStringEncoding];
+    foundUnsupported = YES;
+  }
+  else if ([charset isEqualToString:@"koi8-r"]) {
+    encoding = [NSString defaultCStringEncoding];
+    foundUnsupported = YES;
+  }
+  
+  else if ([charset isEqualToString:@"windows-1252"]) {
+    encoding = NSWindowsCP1252StringEncoding;
+  }
+  else if ([charset isEqualToString:@"iso-8859-2"]) {
+    encoding = NSISOLatin2StringEncoding;
+  }
+  else if ([charset isEqualToString:@"x-unknown"] ||
+           [charset isEqualToString:@"unknown"]) {
+    encoding = NSASCIIStringEncoding;
+  }
+  /* ISO Latin 9 */
+#if !(NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY)
+  else if ([charset isEqualToString:@"iso-latin-9"])
+    encoding = NSISOLatin9StringEncoding;
+  else if ([charset isEqualToString:@"iso-8859-15"])
+    encoding = NSISOLatin9StringEncoding;
+  else if ([charset isEqualToString:@"8859-15"])
+    encoding = NSISOLatin9StringEncoding;
+#endif
+  else {
+    [self logWithFormat:@"%s: unknown charset '%@'",
+          __PRETTY_FUNCTION__, _s];
+    encoding = [NSString defaultCStringEncoding];
+  }
+  return encoding;
+}
+
+// init
+
+- (id)initWithType:(NSString *)_type subType:(NSString *)_subType
+  parameters:(NSDictionary *)_parameters
+{
+  Class c;
+
+  c = classForType(_type, _subType, _parameters);
+  [self release];
+  
+  return [[c alloc] initWithType:_type subType:_subType
+                    parameters:_parameters];
+}
+
++ (id)mimeType:(NSString *)_type subType:(NSString *)_subType {
+  Class c;
+
+  c = classForType(_type, _subType, nil);
+  
+  NSAssert(c, @"did not find class for mimetype ..");
+
+  return [[[c alloc] initWithType:_type subType:_subType
+                     parameters:nil] autorelease];
+}
+
++ (id)mimeType:(NSString *)_type subType:(NSString *)_subType
+  parameters:(NSDictionary *)_parameters
+{
+  Class c;
+
+  c = classForType(_type, _subType, _parameters);
+  NSAssert(c, @"did not find class for mimetype ..");
+  
+  return [[[c alloc] initWithType:_type subType:_subType
+                     parameters:_parameters] autorelease];
+}
+
++ (id)mimeType:(NSString *)_stringValue {
+  NSString     *type, *subType;
+  NSDictionary *parameters;
+
+  if ([_stringValue length] == 0)
+    /* empty ... */
+    return nil;
+
+  parameters = nil;
+  type       = nil;
+  subType    = nil;
+
+  if (_parseMimeType(self, _stringValue, &type, &subType, &parameters)) {
+    Class c;
+    id    result;
+
+    c = classForType(type, subType, nil);
+    NSAssert(c,       @"did not find class for mimetype ..");
+    NSAssert(type,    @"didn't parse type ..");
+    NSAssert(subType, @"didn't parse subtype ..");
+
+    result = [c alloc];
+    NSAssert(result, @"allocation of mimetype failed ..");
+
+    result = [result initWithType:type subType:subType parameters:parameters];
+    NSAssert(result, @"initialization of mimetype failed ..");
+
+    result = [result autorelease];
+    NSAssert(result, @"autorelease of mimetype failed ..");
+
+    return result;
+  }
+  else {
+    [self logWithFormat:@"ERROR[%s]: parsing of mimetype '%@' failed !",
+          __PRETTY_FUNCTION__, _stringValue];
+    return nil; // parsing failed
+  }
+}
+
+/* types */
+
+- (NSString *)type {
+  [self subclassResponsibility:_cmd];
+  return nil;
+}
+- (NSString *)subType {
+  [self subclassResponsibility:_cmd];
+  return nil;
+}
+- (BOOL)isCompositeType {
+  [self subclassResponsibility:_cmd];
+  return NO;
+}
+
+/* comparing types */
+
+- (BOOL)isEqual:(id)_other {
+  if (_other == nil)  return NO;
+  if (_other == self) return YES;
+
+  return ([_other isKindOfClass:[NGMimeType class]])
+    ? [self isEqualToMimeType:_other]
+    : NO;
+}
+
+- (BOOL)isEqualToMimeType:(NGMimeType *)_type {
+  if (_type == nil)  return NO;
+  if (_type == self) return YES;
+
+  if (![self hasSameType:_type])
+    return NO;
+
+  if (![[_type parametersAsDictionary] isEqual:[self parametersAsDictionary]])
+    return NO;
+
+  return YES;
+}
+
+- (BOOL)hasSameGeneralType:(NGMimeType *)_other { // only the 'type' must match
+  if (_other == self) return YES;
+  if ([_other isCompositeType] != [self isCompositeType]) return NO;
+  if (![[_other type]    isEqualToString:[self type]])    return NO;
+  return YES;
+}
+- (BOOL)hasSameType:(NGMimeType *)_other { // parameters need not match
+  if (_other == nil)  return NO;
+  if (_other == self) return YES;
+  if ([_other isCompositeType] != [self isCompositeType]) return NO;
+  if (![[_other type]    isEqualToString:[self type]])    return NO;
+  if (![[_other subType] isEqualToString:[self subType]]) return NO;
+  return YES;
+}
+
+- (BOOL)doesMatchType:(NGMimeType *)_other { // interpretes wildcards
+  NSString *t, *st, *ot, *ost;
+
+  t   = [self type];
+  st  = [self subType];
+  ot  = [_other type];
+  ost = [_other subType];
+
+  if ([t isEqualToString:@"*"] || [ot isEqualToString:@"*"]) {
+    t   = @"*";
+    ot  = @"*";
+  }
+  if (![t  isEqualToString:ot]) return NO;
+
+  if ([st isEqualToString:@"*"] || [ost isEqualToString:@"*"]) {
+    ot  = @"*";
+    ost = @"*";
+  }
+  if (![st isEqualToString:ost]) return NO;
+  
+  return YES;
+}
+
+/* parameters */
+
+- (NSEnumerator *)parameterNames {
+  [self doesNotRecognizeSelector:_cmd]; // subclass
+  return nil;
+}
+- (id)valueOfParameter:(NSString *)_parameterName {
+  [self doesNotRecognizeSelector:_cmd]; // subclass
+  return nil;
+}
+
+/* representations */
+
+- (NSDictionary *)parametersAsDictionary {
+  NSMutableDictionary *parameters;
+  NSString            *name;
+  NSDictionary        *d;
+  NSEnumerator        *names;
+
+  if ((names = [self parameterNames]) == nil)
+    return nil;
+
+  parameters = [[NSMutableDictionary alloc] init];
+  while ((name = [names nextObject]))
+    [parameters setObject:[self valueOfParameter:name] forKey:name];
+
+  d = [parameters copy];
+  [parameters release];
+  return [d autorelease];
+}
+
+- (NSString *)parametersAsString {
+  NSEnumerator    *names;
+  NSMutableString *result;
+  NSString        *name;
+
+  if ((names = [self parameterNames]) == nil)
+    return nil;
+  
+  result = [NSMutableString stringWithCapacity:64];
+  while ((name = [names nextObject])) {
+    NSString *value;
+
+    value = [[self valueOfParameter:name] stringValue];
+    
+    [result appendString:@"; "];
+    [result appendString:name];
+    [result appendString:@"="];
+    
+    if ([self valueNeedsQuotes:value]) {
+      [result appendString:@"\""];
+      [result appendString:value];
+      [result appendString:@"\""];
+    }
+    else
+      [result appendString:value];
+  }
+  return result;
+}
+
+- (BOOL)valueNeedsQuotes:(NSString *)_parameterValue {
+  unsigned len = [_parameterValue cStringLength];
+  char     buf[len + 15];
+  char     *cstr;
+
+  cstr = &(buf[0]);
+
+  [_parameterValue getCString:cstr]; cstr[len] = '\0';
+  while (*cstr) {
+    if (isMime_SpecialByte(*cstr))
+      return YES;
+
+    if (*cstr == 32)
+      return YES;
+    
+    cstr++;
+  }
+  return NO;
+}
+
+- (NSString *)stringValue {
+  [self subclassResponsibility:_cmd];
+  return nil;
+}
+
+// NSCoding
+
+- (Class)classForCoder {
+  return [NGMimeType class];
+}
+
+- (void)encodeWithCoder:(NSCoder *)_encoder {
+  [_encoder encodeObject:[self type]];
+  [_encoder encodeObject:[self subType]];
+  [_encoder encodeObject:[self parametersAsDictionary]];
+}
+
+- (id)initWithCoder:(NSCoder *)_decoder {
+  NSString     *type, *subType;
+  NSDictionary *paras;
+
+  type    = [_decoder decodeObject];
+  subType = [_decoder decodeObject];
+  paras   = [_decoder decodeObject];
+
+  return [self initWithType:type subType:subType parameters:paras];
+}
+
+// NSCopying
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[NGMimeType allocWithZone:_zone]
+                      initWithType:[self type] subType:[self subType]
+                      parameters:[self parametersAsDictionary]];
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<NGMimeType: %@>", [self stringValue]];
+}
+
+@end /* NGMimeType */
+
+typedef struct {
+  NSString *image;
+  NSString *video;
+  NSString *audio;
+  NSString *text;
+  NSString *star;
+  NSString *application;
+  NSString *multipart;
+  NSString *message;
+} NGMimeTypeConstants;
+
+typedef struct {
+  NSString *plain;
+  NSString *star;
+  NSString *mixed;
+  NSString *jpeg;
+  NSString *png;
+  NSString *gif;
+  NSString *xml;
+  NSString *html;
+  NSString *css;
+  NSString *xMng;
+  NSString *xhtmlXml;
+  NSString *rfc822;
+  NSString *octetStream;
+} NGMimeSubTypeConstants;
+
+static NGMimeTypeConstants      *MimeTypeConstants      = NULL;
+static NGMimeSubTypeConstants   *MimeSubTypeConstants   = NULL;
+
+static NSString *_stringForType(char *_type, int _len) {
+  if (NSStringClass == Nil) NSStringClass = [NSString class];
+
+  if (MimeTypeConstants == NULL) {
+    MimeTypeConstants = malloc(sizeof(NGMimeTypeConstants));
+    MimeTypeConstants->image       = NGMimeTypeImage;
+    MimeTypeConstants->video       = NGMimeTypeVideo;
+    MimeTypeConstants->audio       = NGMimeTypeAudio;
+    MimeTypeConstants->text        = NGMimeTypeText;
+    MimeTypeConstants->star        = @"*";
+    MimeTypeConstants->application = NGMimeTypeApplication;
+    MimeTypeConstants->multipart   = NGMimeTypeMultipart;
+    MimeTypeConstants->message     = NGMimeTypeMessage;
+  }
+  switch (_len) {
+    case 0:
+      return @"";
+    case 1:
+      if (_type[0] == '*')
+        return MimeTypeConstants->star;
+      break;
+    case 4:
+      if (strncmp(_type, "text", 4) == 0) 
+        return MimeTypeConstants->text;
+      break;
+    case 5:
+      if (_type[0] == 'i') {
+        if (strncmp(_type, "image", 5) == 0) 
+          return MimeTypeConstants->image;
+      }
+      else if (_type[0] == 'v') {
+        if (strncmp(_type, "video", 5) == 0) 
+          return MimeTypeConstants->video;
+      }
+      else if (_type[0] == 'a') {
+        if (strncmp(_type, "audio", 5) == 0) 
+          return MimeTypeConstants->audio;
+      }
+      break;
+    case 7:
+      if (strncmp(_type, "message", 7) == 0)
+        return MimeTypeConstants->message;
+      break;
+    case 9:
+      if (strncmp(_type, "multipart", 9) == 0)
+        return MimeTypeConstants->multipart;
+      break;    case 11:
+      if (strncmp(_type, "application", 11) == 0)
+        return MimeTypeConstants->application;
+      break;
+  }
+  return [NSStringClass stringWithCString:_type length:_len];
+}
+
+static NSString *_stringForSubType(char *_type, int _len) {
+  if (NSStringClass == Nil) NSStringClass = [NSString class];
+
+  if (MimeSubTypeConstants == NULL) {
+    MimeSubTypeConstants = malloc(sizeof(NGMimeSubTypeConstants));
+
+    MimeSubTypeConstants->plain       = @"plain";
+    MimeSubTypeConstants->star        = @"*";
+    MimeSubTypeConstants->mixed       = @"mixed";
+    MimeSubTypeConstants->jpeg        = @"jpeg";
+    MimeSubTypeConstants->png         = @"png";
+    MimeSubTypeConstants->gif         = @"gif";
+    MimeSubTypeConstants->xml         = @"xml";
+    MimeSubTypeConstants->html        = @"html";
+    MimeSubTypeConstants->css         = @"css";
+    MimeSubTypeConstants->xMng        = @"xMng";
+    MimeSubTypeConstants->xhtmlXml    = @"xhtmlXml";
+    MimeSubTypeConstants->rfc822      = @"rfc822";
+    MimeSubTypeConstants->octetStream = @"octet-stream";
+  }
+  switch (_len) {
+    case 0:
+      return @"";
+
+    case 1:
+      if (_type[0] == '*')
+        return MimeSubTypeConstants->star;
+      break;
+    case 3:
+      if (_type[0] == 'p') {
+        if (strncmp(_type, "png", 3) == 0) 
+          return MimeSubTypeConstants->png;
+      }
+      else if (_type[0] == 'g') {
+        if (strncmp(_type, "gif", 3) == 0) 
+          return MimeSubTypeConstants->gif;
+      }
+      else if (_type[0] == 'c') {
+        if (strncmp(_type, "css", 3) == 0) 
+          return MimeSubTypeConstants->css;
+      }
+      else if (_type[0] == 'x') {
+        if (strncmp(_type, "xml", 3) == 0) 
+          return MimeSubTypeConstants->xml;
+      }
+      break;
+    case 4:
+      if (_type[0] == 'h') {
+        if (strncmp(_type, "html", 4) == 0) 
+          return MimeSubTypeConstants->html;
+      }
+      else if (_type[0] == 'j') {
+        if (strncmp(_type, "jpeg", 4) == 0) 
+          return MimeSubTypeConstants->jpeg;
+      }
+      break;
+    case 5:
+      if (_type[0] == 'p') {
+        if (strncmp(_type, "plain", 5) == 0) 
+          return MimeSubTypeConstants->plain;
+      }
+      else if (_type[0] == 'm') {
+        if (strncmp(_type, "mixed", 5) == 0) 
+          return MimeSubTypeConstants->mixed;
+      }
+      else if (_type[0] == 'x') {
+        if (strncmp(_type, "x-mng", 5) == 0) 
+          return MimeSubTypeConstants->xMng;
+      }
+      break;
+    case 6:
+      if (strncmp(_type, "rfc822", 6) == 0) 
+          return MimeSubTypeConstants->rfc822;
+      break;
+    case 9:
+      if (strncmp(_type, "xhtml+xml", 9) == 0) 
+          return MimeSubTypeConstants->xhtmlXml;
+      break;
+    case 12:
+      if (strncmp(_type, "octet-stream", 12) == 0) 
+          return MimeSubTypeConstants->octetStream;
+      break;
+  }
+  return [NSStringClass stringWithCString:_type length:_len];
+}
+
+static BOOL _parseMimeType(id self, NSString *_str, NSString **type,
+                           NSString **subType, NSDictionary **parameters)
+{
+  unsigned len;
+  unichar  *cstr, *tmp;
+  unsigned slen  = [_str length];
+  unichar  buf[slen + 1];
+
+  len  = 0;
+  cstr = &(buf[0]);
+
+  [_str getCharacters:buf]; buf[slen] = '\0';
+
+  /* skip leading spaces */
+  while (isRfc822_LWSP(*cstr) && (*cstr != '\0'))
+    cstr++;
+
+  /* type name */
+  tmp = cstr; // keep beginning of type name
+  len = 0;
+  while ((*cstr != '/') && (*cstr != '\0') && (*cstr != ';')) {
+    cstr++;
+    len++;
+  }
+  if (len == 0) return NO; // no type was read
+
+  {
+    unsigned char     buf[len + 1];
+    register unsigned i;
+    
+    buf[len] = '\0';
+    for (i = 0; i < len; i++) buf[i] = tolower(tmp[i]);
+    *type = _stringForType(buf, len);
+  }
+
+  if (*cstr == '/') { // subtype name
+    cstr++; // skip '/'
+
+    tmp = cstr; // keep beginning of subtype name
+    len = 0;
+    while ((*cstr != ';') && (!isRfc822_LWSP(*cstr)) && (*cstr != '\0')) {
+      cstr++;
+      len++;
+    }
+    if (len <= 0) {
+      *subType = @"*";
+      return YES; // no subtype was read      
+    }
+    else {
+      unsigned char     buf[len + 1];
+      register unsigned i;
+      
+      buf[len] = '\0';
+      for (i = 0; i < len; i++) buf[i] = tolower(tmp[i]);
+      *subType = _stringForSubType(buf, len);
+    }
+  }
+  else {
+    *subType = @"*";
+  }
+
+  // skip spaces
+  while (isRfc822_LWSP(*cstr) && (*cstr != '\0'))
+    cstr++;
+  
+  if (*cstr == ';') // skip ';' (parameter separator)
+    cstr++;
+
+  // skip spaces
+  while (isRfc822_LWSP(*cstr) && (*cstr != '\0'))
+    cstr++;
+
+  if (*cstr == '\0') { // string ends, no parameters defined
+    *parameters = nil;
+    return YES;
+  }
+  // parse parameters
+  *parameters = parseParameters(self, _str, cstr);
+  if (![*parameters count])
+    *parameters = nil;
+
+  return YES;
+}
diff --git a/skyrix-core/NGMime/NGMimeUtilities.h b/skyrix-core/NGMime/NGMimeUtilities.h
new file mode 100644 (file)
index 0000000..78c5089
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGMimeUtilities_H__
+#define __NGMime_NGMimeUtilities_H__
+
+#import <Foundation/Foundation.h>
+#import <NGExtensions/NGExtensions.h>
+#include <NGMime/NGMimeDecls.h>
+
+// ******************** RFC 822 ********************
+
+static inline BOOL isRfc822_SpecialByte(unsigned char _byte) {
+  switch (_byte) {
+  case '(': case ')': case '<': case '>': case '@':
+  case ',': case ';': case ':': case '"': case '\\':
+  case '.': case '[': case ']':
+    return YES;
+  default:
+    return NO;
+  }
+}
+
+// single chars
+NSDictionary *parseParameters(id self, NSString *_str, unichar *cstr);
+
+static inline BOOL isRfc822_CR(unsigned char _byte) {
+  return (_byte == 13);
+}
+static inline BOOL isRfc822_LF(unsigned char _byte) {
+  return (_byte == 10);
+}
+static inline BOOL isRfc822_HTAB(unsigned char _byte) {
+  return (_byte == 9);
+}
+static inline BOOL isRfc822_SPACE(unsigned char _byte) {
+  return (_byte == 32);
+}
+static inline BOOL isRfc822_QUOTE(unsigned char _byte) {
+  return (_byte == 34);
+}
+
+// ranges
+
+static inline BOOL isRfc822_CHAR(unsigned char _byte) {
+  return (_byte < 128);
+}
+
+static inline BOOL isRfc822_CTL(unsigned char _byte) {
+  return (_byte < 32) || (_byte == 127);
+}
+
+static inline BOOL isRfc822_ALPHA(unsigned char _byte) {
+  return (((_byte >= 65) && (_byte <= 90)) ||
+          ((_byte >= 97) && (_byte <= 122)));
+}
+
+static inline BOOL isRfc822_DIGIT(unsigned char _byte) {
+  return (_byte >= 48) && (_byte <= 57);
+}
+
+static inline BOOL isRfc822_LWSP(unsigned char _byte) {
+  return (isRfc822_SPACE(_byte) || isRfc822_HTAB(_byte));
+}
+
+
+static inline BOOL isRfc822_FieldNameChar(unsigned char _byte) {
+  return (isRfc822_CHAR(_byte) &&
+          !(isRfc822_CTL(_byte) || isRfc822_SPACE(_byte) || (_byte == ':')));
+}
+
+static inline BOOL isRfc822_AtomChar(unsigned char _byte) {
+  return (isRfc822_CHAR(_byte) &&
+          !(isRfc822_SpecialByte(_byte) || isRfc822_SPACE(_byte) ||
+            isRfc822_CTL(_byte)));
+}
+
+// ******************** MIME ***********************
+
+static inline BOOL isMime_SpecialByte(unsigned char _byte) {
+  switch (_byte) {
+  case '(': case ')': case '<': case '>': case '@':
+  case ',': case ';': case ':': case '"': case '\\':
+  case '/': case '=': case '[': case ']': case '?':
+    return YES;
+  default:
+    return NO;
+  }
+}
+
+static inline BOOL isMime_TokenChar(unsigned char _byte) {
+  return (isRfc822_CHAR(_byte) &&
+          !(isRfc822_CTL(_byte) || isRfc822_SPACE(_byte) ||
+            isMime_SpecialByte(_byte)));
+}
+
+static inline BOOL isMime_SafeChar(unsigned char _byte) {
+  return ((_byte >= 33 && _byte <= 60) || (_byte >= 62 && _byte <= 126));
+}
+
+static inline BOOL isMime_ValidTypeXTokenChar(unsigned char _byte) {
+  return !isRfc822_SPACE(_byte);
+}
+
+static inline BOOL isMime_ValidTypeAttributeChar(unsigned char _byte) {
+  return isMime_TokenChar(_byte);
+}
+
+static inline NSData *_quotedPrintableEncoding(NSData *_data) {
+  const char   *bytes  = [_data bytes];
+  unsigned int length  = [_data length];
+  NSData       *result = nil;  
+  char         *des    = NULL;
+  unsigned int desLen  = 0;
+  unsigned     cnt     = length;
+  const char   *test   = bytes;    
+  BOOL         doEnc   = NO;
+
+  while (cnt > 0) {
+    if ((unsigned char)*test > 127) {
+      doEnc = YES;
+      break;
+    }
+    test++;
+    cnt--;
+  }
+  if (!doEnc) return _data;
+  desLen = length *3;
+  des = NGMallocAtomic(sizeof(char) * desLen + 2);
+  
+  desLen = NGEncodeQuotedPrintable(bytes, length, des, desLen);
+  if ((int)desLen != -1) {
+    result = [NSData dataWithBytesNoCopy:des length:desLen];
+  }
+  else {
+    NSLog(@"WARNING(%s): An error occour during quoted-printable decoding",
+          __PRETTY_FUNCTION__);
+    if (des) NGFree(des);
+    result = _data;
+  }
+  return result;
+}
+
+static inline NSData *_rfc2047Decoding(char _enc, const char *_bytes,
+                                      unsigned int _length) 
+{
+  NSData *data = nil;
+
+  if ((_enc == 'b') || (_enc == 'B')) { // use BASE64 decoding
+    NSData *tmp;
+    
+    tmp = [[NSData alloc] initWithBytes:_bytes length:_length];
+    data = [tmp dataByDecodingBase64];
+    RELEASE(tmp);
+  }
+  else if ((_enc == 'q') || (_enc == 'Q')) { // use quoted-printable decoding
+    char   *dest    = NULL;
+    size_t destSize = 0;
+    size_t resSize  = 0;
+
+    destSize = _length;
+    dest = NGMallocAtomic(destSize * sizeof(char));
+    resSize = NGDecodeQuotedPrintable(_bytes, _length, dest, destSize);
+    if ((int)resSize != -1) {
+      data = [NSData dataWithBytesNoCopy:dest length:resSize];
+    }
+    else {
+      NSLog(@"WARNING(%s): An error occour during quoted-printable decoding",
+            __PRETTY_FUNCTION__);
+      NGFree(dest); dest = NULL;
+      data = [NSData dataWithBytes:_bytes length:_length];
+    }
+  }
+  else {
+    NSLog(@"WARNING(%s): unknown encoding type %c", __PRETTY_FUNCTION__, _enc);
+    data = [NSData dataWithBytes:_bytes length:_length];
+  }
+  return data;
+}
+
+#endif /* __NGMime_NGMimeUtilities_H__ */
diff --git a/skyrix-core/NGMime/NGMimeUtilities.m b/skyrix-core/NGMime/NGMimeUtilities.m
new file mode 100644 (file)
index 0000000..57386e4
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGMime/NGMimeType.h>
+#include <NGMime/NGMimeUtilities.h>
+
+typedef struct {
+  NSString *charset;
+  NSString *q;
+  NSString *boundary;
+  NSString *name;
+  NSString *fileName;
+  NSString *reportType;
+} NGMimeParameterConstants;
+
+static NGMimeParameterConstants *MimeParameterConstants = NULL;
+static Class                    NSStringClass           = Nil;
+static int                      MimeLogEnabled          = -1;
+
+static NSString *_stringForParameterName(char *_type, int _len) {
+  if (NSStringClass == Nil)
+    NSStringClass = [NSString class];
+
+  if (MimeLogEnabled == -1) {
+    MimeLogEnabled = [[NSUserDefaults standardUserDefaults]
+                                      boolForKey:@"MimeLogEnabled"]?1:0;
+  }
+
+  if (MimeParameterConstants == NULL) {
+    MimeParameterConstants = malloc(sizeof(NGMimeParameterConstants));
+
+    MimeParameterConstants->charset    = NGMimeParameterTextCharset;
+    MimeParameterConstants->q          = @"q";
+    MimeParameterConstants->name       = @"name";
+    MimeParameterConstants->boundary   = @"boundary";
+    MimeParameterConstants->fileName   = @"filename";
+    MimeParameterConstants->reportType = @"report-type";
+  }
+  switch (_len) {
+    case 0:
+      return @"";
+    case 1:
+      if (_type[0] == 'q')
+        return MimeParameterConstants->q;
+      break;
+    case 4:
+      if (strncmp(_type, "name", 4) == 0) 
+        return MimeParameterConstants->name;
+      break;
+    case 7:
+      if (strncmp(_type, "charset", 7) == 0) 
+        return MimeParameterConstants->charset;
+      break;
+    case 8:
+      if (strncmp(_type, "boundary", 8) == 0) 
+          return MimeParameterConstants->boundary;
+      if (strncmp(_type, "filename", 8) == 0) 
+          return MimeParameterConstants->fileName;
+      break;
+    case 11:
+      if (strncmp(_type, "report-type", 11) == 0) 
+          return MimeParameterConstants->reportType;
+      break;
+  }
+  return [NSStringClass stringWithCString:_type length:_len];
+}
+
+NSDictionary *parseParameters(id self, NSString *_str, unichar *cstr) {
+  if (*cstr != '\0') {
+    NSMutableDictionary *paras;
+
+    paras = [[NSMutableDictionary alloc] initWithCapacity:8];
+    do {
+      unsigned len;
+      unichar  *tmp;
+      NSString *attrName, *attrValue;
+
+      attrValue = nil;
+      attrName  = nil;
+
+      // consume end of previous entry (spaces and ';')
+      while ((*cstr == ';') || isRfc822_LWSP(*cstr))
+        cstr++;
+
+      // parse attribute
+      tmp = cstr;
+      len = 0;
+      while ((*cstr != '\0') && (isMime_ValidTypeAttributeChar(*cstr))) {
+        cstr++;
+        len++;
+      }
+      if (len == 0)
+        break;
+      {
+        unsigned char     buf[len + 1];
+        register unsigned i;
+
+        buf[len] = '\0';
+        for (i = 0; i < len; i++) buf[i] = tolower(tmp[i]);
+
+        attrName = _stringForParameterName(buf, len);
+      }
+      // skip spaces
+      while ((*cstr != '\0') && (isRfc822_LWSP(*cstr))) {
+        cstr++;
+      }
+      // no value was given for attribute
+      if (*cstr == '\0') {
+        if (MimeLogEnabled)
+          [self logWithFormat:@"WARNING(%s): attribute '%@' has no value in "
+                @"MimeType '%@'", __PRETTY_FUNCTION__, attrName, _str];
+        break; // exit loop
+      }
+
+      // expect '='
+      if (*cstr != '=') {
+        if (MimeLogEnabled) 
+          [self logWithFormat:@"WARNING(%s): attribute '%@', missing '=' "
+                @"in MimeType '%@'", __PRETTY_FUNCTION__, attrName, _str];
+        break; // exit loop
+      }
+      cstr++;
+
+      // skip spaces
+      while ((*cstr != '\0') && (isRfc822_LWSP(*cstr)))
+        cstr++;
+      
+      /* no value was given for parameter */
+      if (*cstr == '\0') {
+        if (MimeLogEnabled) 
+          [self logWithFormat:@"WARNING(%s): attribute '%@' has no value "
+                @"in MimeType '%@'", __PRETTY_FUNCTION__, attrName, _str];
+        break; // exit loop
+      }
+      
+      /* now parameter read value */
+      if (isRfc822_QUOTE(*cstr)) { // quoted value
+        cstr++;
+        tmp = cstr;
+        len = 0;
+        while (!isRfc822_QUOTE(*cstr) && (*cstr != '\0')) {
+          cstr++;
+          len++;
+        }
+        attrValue = [[[NSString alloc] initWithCharacters:tmp length:len]
+                                autorelease];
+          
+        if (*cstr == '\0') { // quote was not closed
+          if (MimeLogEnabled)  
+            [self logWithFormat:@"WARNING(%s): value-quotes in attribute "
+                  @"'%@' were not closed in MimeType '%@'",
+                  __PRETTY_FUNCTION__, attrName, _str];
+          break; // exit loop
+        }
+        cstr++; // skip closing quote
+      }
+      else { /* value without quotes */
+        tmp = cstr;
+        len = 0;
+
+        while (*cstr != '\0') {
+          if (isRfc822_SPACE(*cstr)) break;
+          if (isRfc822_CTL(*cstr))   break;
+            
+          if (*cstr == ';') break; /* parameter separator */
+            
+          cstr++;
+          len++;
+        }
+        attrValue = [[[NSString alloc] initWithCharacters:tmp length:len]
+                                autorelease];
+      }
+      /* store attr/value pair in dictionary */
+      [paras setObject:attrValue forKey:attrName];
+      attrName  = nil;
+      attrValue = nil;
+
+      /* skip spaces */
+      while ((*cstr != '\0') && (isRfc822_LWSP(*cstr)))
+        cstr++;
+
+      if (*cstr == ';') // skip ';' (attribute separator)
+        cstr++;
+      else if (*cstr == '\0') /* parsing is finished, exit loop */
+        break; // exit loop
+      else {
+        if (MimeLogEnabled) 
+          [self logWithFormat:@"WARNING(%s): expected end of string or ';', "
+                @"got '%c'%i (str='%@')", __PRETTY_FUNCTION__, *cstr,
+                *cstr, _str];
+        break; // exit loop
+      }
+      /* skip spaces */
+      while ((*cstr != '\0') && (isRfc822_LWSP(*cstr)))
+        cstr++;
+    }
+    while (YES);
+    return [paras autorelease];
+  }
+  return nil;
+}
+
+  
diff --git a/skyrix-core/NGMime/NGPart.h b/skyrix-core/NGMime/NGPart.h
new file mode 100644 (file)
index 0000000..9c007e6
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_NGPart_H__
+#define __NGMime_NGPart_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSData.h>
+
+/*
+  NGPart / NGMimePart
+  
+  Represents a MIME part, that is, a data block with associated header fields.
+*/
+
+@class NSEnumerator, NSString, NSArray;
+@class NGMimeType;
+
+@protocol NGPart < NSObject >
+
+- (NSEnumerator *)valuesOfHeaderFieldWithName:(NSString *)_name;
+- (NSEnumerator *)headerFieldNames;
+
+- (void)setBody:(id)_body;
+- (id)body;
+
+@end
+
+@protocol NGMimePart < NGPart >
+
+- (NGMimeType *)contentType;   // the content-type
+- (NSString *)contentId;       // get the Content-ID of this part
+- (NSArray *)contentLanguage;  // get the language tags from Content-Language
+- (NSString *)contentMd5;      // get the Content-MD5 digest of this part
+- (NSString *)encoding;        // get the transfer encoding of this part
+
+@end
+
+@interface NSData(DataPart) < NGMimePart >
+@end
+
+#endif /* __NGMime_NGPart_H__ */
diff --git a/skyrix-core/NGMime/NGPart.m b/skyrix-core/NGMime/NGPart.m
new file mode 100644 (file)
index 0000000..7df1aca
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGPart.h"
+#include "NGMimeType.h"
+#include "common.h"
+#include <NGMime/NGMimePartParser.h>
+
+@implementation NSData(DataPart)
+
+/* NGPart */
+
+- (NSEnumerator *)valuesOfHeaderFieldWithName:(NSString *)_name {
+  id value = nil;
+
+  static NGMimeHeaderNames *Fields = NULL;
+
+  if (!Fields)
+    Fields = (NGMimeHeaderNames *)[NGMimePartParser headerFieldNames];
+  
+  if ([_name isEqualToString:Fields->contentLength])
+    value = [NSNumber numberWithUnsignedInt:[self length]];
+  else if ([_name isEqualToString:Fields->contentType])
+    value = [self contentType];
+  else if ([_name isEqualToString:@"content-id"])
+    value = [self contentId];
+  else if ([_name isEqualToString:@"content-m5"])
+    value = [self contentMd5];
+  else if ([_name isEqualToString:@"content-language"])
+    value = [self contentLanguage];
+
+  if (value)
+    return [[NSArray arrayWithObject:value] objectEnumerator];
+  
+  return nil;
+}
+- (NSEnumerator *)headerFieldNames {
+  return nil;
+}
+
+- (void)setBody:(id)_body {
+  [self doesNotRecognizeSelector:_cmd];
+}
+- (id)body {
+  return self;
+}
+
+/* NGMimePart */
+
+- (NGMimeType *)contentType {
+  static NGMimeType *defType = nil;
+  if (defType == nil)
+    defType = [[NGMimeType mimeType:@"application/octet"] retain];
+  return defType;
+}
+- (NSString *)contentId {
+  return nil;
+}
+
+- (NSArray *)contentLanguage {
+  return nil;
+}
+- (NSString *)contentMd5 {
+  return nil;
+}
+- (NSString *)encoding {
+  return nil;
+}
+
+@end /* NSData(DataPart) */
+
+@implementation NSMutableData(DataPart)
+
+- (void)setBody:(id)_body {
+  [self setData:_body];
+}
+
+@end /* NSMutableData(DataPart) */
+
+void __link_NGPart(void) {
+  __link_NGPart();
+}
diff --git a/skyrix-core/NGMime/NSCalendarDate+RFC822.m b/skyrix-core/NGMime/NSCalendarDate+RFC822.m
new file mode 100644 (file)
index 0000000..2278126
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+
+@implementation NSCalendarDate(RFC822Dates)
+
+static NSString *dateFormats[] = {
+  /*
+    short-weekday, day short-month year hour:minute:second timezoneoffset
+    eg: Mon, 01 Mar 1999 13:13:13 +0000
+  */
+  @"%a, %d %b %Y %H:%M:%S %z",
+
+  /*
+    short-weekday, day short-month year hour:minute:second timezonename
+    eg: Mon, 01 Mar 1999 13:13:13 GMT
+  */
+  @"%a, %d %b %Y %H:%M:%S %Z",
+
+  /*
+    short-weekday, day short-month year hour:minute:second timezonename
+    eg: Mon, 01 Mar 1999 13:13 +0000
+  */
+  @"%a, %d %b %Y %H:%M %z",
+
+  /*
+    short-weekday, day short-month year hour:minute:second timezonename
+    eg: Mon, 01 Mar 1999 13:13 (+0000)
+  */
+  @"%a, %d %b %Y %H:%M (%z)",
+
+  /*
+    short-weekday, day short-month year hour:minute:second timezonename
+    eg: Mon, 01 Mar 1999 13:13 (GMT)
+  */
+  @"%a, %d %b %Y %H:%M (%Z)",
+
+  /*
+    short-weekday, day short-month year hour:minute:second
+    eg: Mon, 01 Mar 1999 13:13:13
+  */
+  @"%a, %d %b %Y %H:%M:%S",
+
+  /*
+    day short-month year hour:minute:second timezoneoffset
+    eg: 01 Oct 1999 18:20:12 +0200
+  */
+  @"%d %b %Y %H:%M:%S %z",
+  
+  /*
+    day short-month year hour:minute:second timezonename
+    eg: 01 Oct 1999 18:20:12 EST
+  */
+  @"%d %b %Y %H:%M:%S %Z",
+  
+  /*
+    day short-month year hour:minute:second (timezoneoffset)
+    eg: 30 Sep 1999 21:00:05  (+0200)
+  */
+  @"%d %b %Y %H:%M:%S  (%z)",
+
+  /*
+    day short-month year hour:minute:second (timezonename)
+    eg: 30 Sep 1999 21:00:05  (MEST)
+  */
+  @"%d %b %Y %H:%M:%S  (%Z)",
+  /*
+    day short-month year hour:minute:second (timezonename)
+    eg: 30 Sep 1999 21:00:05  (MEST)
+  */
+  @"%d %b %Y %H:%M:%S  (%Z)",
+
+  /*
+    short-weekday, day short-month year hour:minute:second timezoneoffset
+    eg: Mon, 01 Mar 1999 13:13:13 +0000
+  */
+  @"%a %b %d %H:%M:%S %Y  (%Z)",
+
+  /*
+    eg: '16 Jun 2002 10:28 GMT'
+  */
+  @"%d %b %Y %H:%M %Z",
+
+  /*
+    eg: '16 Jun 2002 10:28 +0000'
+  */
+  @"%d %b %Y %H:%M %z",
+
+  /* terminate list */
+  nil
+};
+
++ (NSCalendarDate *)calendarDateWithRfc822DateString:(NSString *)_str {
+  // TODO: optimize MUCH more - calformat parsing is *slow*
+  NSCalendarDate *date       = nil;
+  NSString       *dateString = nil;
+  int i;  
+  
+  dateString = [_str stringByTrimmingSpaces];
+  if ([dateString length] == 0)
+    return nil;
+  
+  /* check various date formats */
+  
+  for (i = 0, date = nil; (date == nil) && (dateFormats[i] != nil); i++) {
+    date = [NSCalendarDate dateWithString:dateString
+                          calendarFormat:dateFormats[i]];
+  }
+  return [date y2kDate];
+}
+
+@end /* NSCalendarDate(RFC822Dates) */
diff --git a/skyrix-core/NGMime/README b/skyrix-core/NGMime/README
new file mode 100644 (file)
index 0000000..b4e6b1c
--- /dev/null
@@ -0,0 +1,80 @@
+// $Id$
+
+Copyright 2000-2004
+SKYRIX Software AG - http://www.skyrix.com
+-------------------------------------------------------------------------------
+
+Defaults
+========
+  Mail_Use_8bit_Encoding_For_Text        - bool - 
+    Use 8bit content-transfer-encoding for text messages
+  UseLFSeperatedAddressEntries           - bool
+  NGMime_MultipartBoundaryPrefix         - string
+  UseFoundationStringEncodingForMimeText - bool
+  NGMimeBuildMimeTempDirectory           - string - "/tmp/"
+  MimeLogEnabled                         - bool
+  StripLeadingSpaces                     - bool
+
+Removed in SKYRiX 4.1, available in MOF3
+========================================
+
+  java.mail related stuff:
+    NGMimeFileDataSource
+    NGMimeFileTypeMap
+    NGMimeCommandMap
+    NGMimeDataHandler
+
+NGMime Objective-C Kit
+======================
+
+  Class-Hierachy
+
+    NSObject
+      NGMimeType                          < NSCopying, NSCoding >
+        NGParameterMimeType
+          NGConcreteApplicationMimeType
+          NGConcreteMultipartMimeType
+          NGConcreteMessageMimeType
+          NGConcreteImageMimeType
+          NGConcreteAudioMimeType
+          NGConcreteVideoMimeType
+        NGConcreteTextMimeType
+          NGConcreteAppOctetMimeType
+          NGConcreteGenericMimeType
+          NGConcreteWildcardType
+      NGMimeBodyParser                    < NGMimeBodyParser >
+        NGMimeTextBodyParser
+        NGMimeMultipartBodyParser
+      NGMimeBodyPart                      < NGPart, NGMimePart >
+      NGMimeHeaderFieldParser             < NGMimeHeaderFieldParser >
+        NGMimeContentTypeHeaderFieldParser
+        NGMimeContentLengthHeaderFieldParser
+        NGMimeStringHeaderFieldParser
+      NGMimeHeaderFieldParserSet          < NGMimeHeaderFieldParser,NSCopying >
+      NGMimeMultipartBody
+      NGMimePartParser
+        NGMimeBodyPartParser
+
+    NSException
+      NGMimeException
+        NGMimeParserException
+
+  Protocols
+
+    NSObject+NGMimeParserDelegate
+
+    NGMimeBodyParser
+    NGMimeHeaderFieldParser
+    NGPart
+    NGMimePart < NGPart >
+
+  Categories
+
+    NSData+DataPart
+    NSMutableData+DataPart
+
+--
+Helge Hess (helge.hess@opengroupware.org)
+1998-11-04
+updated: 2002-07-08
+updated: 2004-06-20
diff --git a/skyrix-core/NGMime/SxCore-NGMime.graffle b/skyrix-core/NGMime/SxCore-NGMime.graffle
new file mode 100644 (file)
index 0000000..551b02d
--- /dev/null
@@ -0,0 +1,4824 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+       <key>CanvasColor</key>
+       <dict>
+               <key>w</key>
+               <real>1.000000e+00</real>
+       </dict>
+       <key>ColumnAlign</key>
+       <integer>0</integer>
+       <key>ColumnSpacing</key>
+       <real>5.400000e+01</real>
+       <key>GraphDocumentVersion</key>
+       <integer>2</integer>
+       <key>GraphicsList</key>
+       <array>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{8.75, 730}, {109, 36}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>163</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\b\fs48 \cf0 NGMime}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{548.75, 730}, {109, 36}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>162</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\b\fs48 \cf0 NGMime}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{548.75, 10}, {109, 36}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>161</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\b\fs48 \cf0 NGMime}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{8.75, 10}, {109, 36}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>160</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\b\fs48 \cf0 NGMime}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 1368}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>159</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4ResponseParser.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4ResponseParser}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{819, 648}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>134</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteAudioMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{603, 648}, {198, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>135</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteMultipartMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{819, 504}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>136</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteGenericMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{603, 621}, {198, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>137</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteVideoMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{603, 594}, {198, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>138</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteApplicationMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{819, 477}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>139</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteAppOctetMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{819, 594}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>140</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteMessageMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{603, 450}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>141</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteTextMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{603, 495}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>142</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteTextVcardMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{711, 387}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>143</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{819, 450}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>144</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteWildcardType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{711, 549}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>145</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGParameterMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{819, 621}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>146</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteImageMimeType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>134</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>147</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{815.318, 567}</string>
+                                               <string>{903.682, 648}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>145</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>135</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>148</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{796.091, 567}</string>
+                                               <string>{711.409, 648}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>145</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>136</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>149</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{813.808, 405}</string>
+                                               <string>{905.192, 504}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>143</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>137</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>150</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{792.562, 567}</string>
+                                               <string>{714.938, 621}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>145</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>138</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>151</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{784.8, 567}</string>
+                                               <string>{722.7, 594}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>145</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>139</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>152</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{816.3, 405}</string>
+                                               <string>{902.7, 477}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>143</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>140</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>153</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{827.1, 567}</string>
+                                               <string>{891.9, 594}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>145</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>141</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>154</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{790.071, 405}</string>
+                                               <string>{712.929, 450}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>143</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>145</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>155</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{805.5, 405}</string>
+                                               <string>{805.5, 549}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>143</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>142</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>156</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{697.5, 468}</string>
+                                               <string>{697.5, 495}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>141</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>144</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>157</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{820.929, 405}</string>
+                                               <string>{898.071, 450}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>143</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>146</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>158</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{819, 567}</string>
+                                               <string>{900, 621}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>145</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>133</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{63, 495}, {126, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>132</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessage.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeMessage}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 1341}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>131</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Support.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGPop3MessageInfo}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{756, 1341}, {243, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>118</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageGenerator.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeMessageMultipartBodyGenerator}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{783, 1251}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>119</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyGenerator.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeMultipartBodyGenerator}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{666, 1314}, {243, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>120</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageGenerator.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeMessageTextBodyGenerator}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{693, 1224}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>121</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyGenerator.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeTextBodyGenerator}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{864, 1188}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>122</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageGenerator.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeMessageBodyGenerator}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{900, 1152}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>123</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeGeneratorProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGMimeBodyGenerator}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{585, 1287}, {243, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>124</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageGenerator.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeMessageRfc822BodyGenerator}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{612, 1197}, {189, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>125</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyGenerator.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeRfc822BodyGenerator}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{720, 1152}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>126</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyGenerator.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeBodyGenerator}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>118</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>127</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{877.5, 1269}</string>
+                                               <string>{877.5, 1341}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>119</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>119</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>128</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{803.864, 1170}</string>
+                                               <string>{870.136, 1251}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>126</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>122</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>129</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{837, 1170}</string>
+                                               <string>{918, 1188}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>126</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>126</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>130</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{900, 1161}</string>
+                                               <string>{873, 1161}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>123</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>117</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{99, 1017}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>112</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGFileManager}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{288, 1053}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>113</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4FileManager.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4FileManager}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{288, 1017}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>114</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGFileManager}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>114</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>115</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{252, 1026}</string>
+                                               <string>{288, 1026}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>112</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>113</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>116</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{364.5, 1035}</string>
+                                               <string>{364.5, 1053}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>114</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>111</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{801, 1035}, {252, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>110</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeContentTypeHeaderFieldGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{855, 36}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>101</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGMimeBodyParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{630, 72}, {171, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>102</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeRfc822BodyParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{810, 72}, {171, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>103</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeTextBodyParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{702, 36}, {135, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>104</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeBodyParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{684, 108}, {171, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>105</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeMultipartBodyParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>104</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>106</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{855, 45}</string>
+                                               <string>{837, 45}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>101</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>102</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>107</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{756, 54}</string>
+                                               <string>{729, 72}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>104</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>103</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>108</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{801, 54}</string>
+                                               <string>{864, 72}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>104</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>105</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>109</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{769.5, 54}</string>
+                                               <string>{769.5, 108}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>104</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>100</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{558, 1008}, {279, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>99</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeAddressHeaderFieldGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 1314}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>98</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Client.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4Client}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{846, 801}, {207, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>97</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeHeaderFieldGeneratorSet}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 1287}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>96</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGSmtpClient.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSmtpClient}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 1260}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>95</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGSmtpSupport.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSmtpResponse}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{801, 981}, {252, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>94</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeRFC822DateHeaderFieldGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{63, 450}, {126, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>93</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGPart.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGMimePart}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{198, 495}, {126, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>92</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyPart.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeBodyPart}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{225, 666}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>91</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageGenerator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeMessageGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{585, 207}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>73</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Support.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGPop3Exception}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{576, 243}, {144, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>74</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Support.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGPop3StateException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{900, 207}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>75</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{882, 243}, {162, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>76</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeParserException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{819, 324}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>77</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4ResponseException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{846, 288}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>78</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4SearchException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{621, 324}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>79</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4ParserException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{594, 288}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>80</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4ConnectionException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{747, 162}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>81</integer>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{747, 207}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>82</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4Exception}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>75</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>83</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{840.6, 180}</string>
+                                               <string>{932.4, 207}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>81</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>73</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>84</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{777.6, 180}</string>
+                                               <string>{680.4, 207}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>81</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>76</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>85</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{963, 225}</string>
+                                               <string>{963, 243}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>75</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>77</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>86</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{817.615, 225}</string>
+                                               <string>{901.385, 324}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>82</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>78</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>87</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{824, 225}</string>
+                                               <string>{922, 288}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>82</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>79</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>88</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{802.385, 225}</string>
+                                               <string>{718.615, 324}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>82</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>80</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>89</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{796, 225}</string>
+                                               <string>{698, 288}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>82</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>82</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>90</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{810, 180}</string>
+                                               <string>{810, 207}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>81</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>72</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{45, 963}, {261, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>60</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeRFC822DateHeaderFieldParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{243, 936}, {243, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>61</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeContentLengthHeaderFieldParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{126, 774}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>62</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeHeaderFieldParserSet}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{324, 774}, {162, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>63</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGMimeHeaderFieldParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{45, 909}, {261, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>64</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeContentTypeHeaderFieldParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{243, 882}, {243, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>65</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeStringHeaderFieldParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{126, 810}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>66</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeHeaderFieldParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{45, 855}, {261, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>67</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeContentDispositionHeaderFieldParser}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>61</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>68</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{226.607, 828}</string>
+                                               <string>{353.893, 936}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>66</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>62</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>69</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{324, 783}</string>
+                                               <string>{306, 783}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>63</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>66</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>70</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{357.75, 792}</string>
+                                               <string>{263.25, 810}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>63</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>65</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>71</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{234.562, 828}</string>
+                                               <string>{345.938, 882}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>66</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>59</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 1233}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>58</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeMultipartBody.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeMultipartBody}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{207, 405}, {144, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>57</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyPartParser.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeBodyPartParser}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{54, 306}, {180, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>56</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Support.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGPop3MailDropEnumerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{288, 72}, {171, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>55</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileFolderInfoDataSource.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGFileFolderInfoDataSource}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 1206}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>54</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMailAddressList.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMailAddressList}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 1179}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>53</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMailAddressParser.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMailAddressParser}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{126, 360}, {144, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>52</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimePartParser.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimePartParser}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{54, 405}, {144, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>51</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageParser.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeMessageParser}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{558, 954}, {279, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>50</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeContentLengthHeaderFieldGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{90, 72}, {171, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>49</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4DataSource.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4DataSource}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{801, 927}, {252, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>48</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeStringHeaderFieldGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 1152}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>47</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMailAddress.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMailAddress}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{198, 567}, {126, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>46</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Folder.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4Folder}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{99, 1125}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>45</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Message.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4Message}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{558, 1080}, {279, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>44</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFields.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeContentDispositionHeaderField}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{243, 306}, {180, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>43</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMBoxReader.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMBoxReader}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{288, 1152}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>42</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Client.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGPop3Client}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{144, 270}, {180, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>41</integer>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>5.000000e-01</real>
+                                               <key>g</key>
+                                               <real>1.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSEnumerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{288, 1125}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>40</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Support.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGPop3Response}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{63, 531}, {126, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>39</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGImap4Folder}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{63, 567}, {126, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>38</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4ServerRoot.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4ServerRoot}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{720, 756}, {189, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>37</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeGeneratorProtocols.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGMimeHeaderFieldGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{54, 144}, {180, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>36</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGImap4ResponseReceiver}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{54, 180}, {180, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>35</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Context.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGImap4Context}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{63, 630}, {135, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>34</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeGeneratorProtocols.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGMimePartGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{225, 630}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>33</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimePartGenerator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimePartGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{711, 846}, {207, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>32</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeHeaderFieldGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{558, 900}, {279, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>31</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMimeContentDispositionHeaderFieldGenerator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{189, 36}, {171, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>30</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EODataSource.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>5.000000e-01</real>
+                                               <key>g</key>
+                                               <real>1.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 EODataSource}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>132</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>29</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{126, 468}</string>
+                               <string>{126, 495}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>93</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>110</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>28</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{819.857, 864}</string>
+                               <string>{921.643, 1035}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>32</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>99</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>27</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{808, 864}</string>
+                               <string>{704, 1008}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>32</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>97</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>26</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{841.5, 774}</string>
+                               <string>{922.5, 801}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>37</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>94</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>25</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{822, 864}</string>
+                               <string>{919.5, 981}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>32</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>92</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>24</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{153, 468}</string>
+                               <string>{234, 495}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>93</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>120</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>23</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{787.5, 1242}</string>
+                               <string>{787.5, 1314}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>121</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>91</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>22</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{306, 648}</string>
+                               <string>{306, 666}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>33</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>74</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>21</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{648, 225}</string>
+                               <string>{648, 243}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>73</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>60</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>20</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{213.618, 828}</string>
+                               <string>{177.882, 963}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>66</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>57</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>19</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{214.2, 378}</string>
+                               <string>{262.8, 405}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>52</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>56</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>18</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{211.5, 288}</string>
+                               <string>{166.5, 306}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>41</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>55</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>17</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{299.25, 54}</string>
+                               <string>{348.75, 72}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>30</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>51</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>16</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{183.6, 378}</string>
+                               <string>{140.4, 405}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>52</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>50</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>15</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{804.75, 864}</string>
+                               <string>{707.25, 954}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>32</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>49</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>14</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{249.75, 54}</string>
+                               <string>{200.25, 72}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>30</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>121</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>13</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{795.375, 1170}</string>
+                               <string>{788.625, 1224}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>126</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>64</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>12</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{212.318, 828}</string>
+                               <string>{179.182, 909}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>66</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>48</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>11</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{827, 864}</string>
+                               <string>{914.5, 927}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>32</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>46</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>10</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{159.75, 549}</string>
+                               <string>{227.25, 567}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>39</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>124</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>9</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{706.5, 1215}</string>
+                               <string>{706.5, 1287}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>125</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>43</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{258.75, 288}</string>
+                               <string>{308.25, 306}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>41</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>125</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>7</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{778.5, 1170}</string>
+                               <string>{724.5, 1197}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>126</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>38</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>6</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{126, 549}</string>
+                               <string>{126, 567}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>39</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>32</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>5</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{814.5, 774}</string>
+                               <string>{814.5, 846}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>37</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>35</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>4</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{144, 162}</string>
+                               <string>{144, 180}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>36</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>33</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>3</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{198, 639}</string>
+                               <string>{225, 639}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>34</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>67</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>2</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{207.9, 828}</string>
+                               <string>{183.6, 855}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>66</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>31</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{795, 864}</string>
+                               <string>{717, 900}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>32</integer>
+                       </dict>
+               </dict>
+       </array>
+       <key>GridInfo</key>
+       <dict/>
+       <key>HPages</key>
+       <integer>2</integer>
+       <key>ImageCounter</key>
+       <integer>1</integer>
+       <key>IsPalette</key>
+       <string>NO</string>
+       <key>Layers</key>
+       <array>
+               <dict>
+                       <key>Lock</key>
+                       <string>NO</string>
+                       <key>Name</key>
+                       <string>Layer 1</string>
+                       <key>Print</key>
+                       <string>YES</string>
+                       <key>View</key>
+                       <string>YES</string>
+               </dict>
+       </array>
+       <key>LayoutInfo</key>
+       <dict>
+               <key>AutoAdjust</key>
+               <string>YES</string>
+               <key>HierarchicalOrientation</key>
+               <integer>0</integer>
+               <key>MagneticFieldCenter</key>
+               <string>{0, 0}</string>
+       </dict>
+       <key>MagnetsEnabled</key>
+       <string>YES</string>
+       <key>PageBreakColor</key>
+       <dict>
+               <key>w</key>
+               <real>3.333333e-01</real>
+       </dict>
+       <key>PageBreaks</key>
+       <string>YES</string>
+       <key>PageSetup</key>
+       <data>
+       BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE
+       hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpFZKEhIQITlNT
+       dHJpbmcBlIQBKw9OU1BhZ2VzUGVyU2hlZXSGkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVl
+       AJSEASqEhAFznQGGkoSZmRBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29s
+       Sm9ihpKEmZkOTlNCb3R0b21NYXJnaW6GkoSbnISEAWaeJIaShJmZC05TUGFwZXJOYW1l
+       hpKEmZkCQTSGkoSZmQ9OU1ByaW50QWxsUGFnZXOGkoSbnJ2dAIaShJmZDU5TSm9iRmVh
+       dHVyZXOGkoSWlwCGkoSZmQ1OU1JpZ2h0TWFyZ2luhpKEm5yiniSGkoSZmQhOU0NvcGll
+       c4aShJuchIQBU58BhpKEmZkPTlNTY2FsaW5nRmFjdG9yhpKEm5yEhAFkoAGGkoSZmQtO
+       U0ZpcnN0UGFnZYaShJucrZ8BhpKEmZkUTlNWZXJ0aWNhbFBhZ2luYXRpb26GkoSbnJ2d
+       AIaShJmZEk5TUmV2ZXJzZVBhZ2VPcmRlcoaShJuchIQBY6EAhpKEmZkVTlNIb3Jpem9u
+       YWxQYWdpbmF0aW9uhpKEm5ydnQCGkoSZmRZOU0hvcml6b250YWxseUNlbnRlcmVkhpKE
+       m5ydnQGGkoSZmQxOU0xlZnRNYXJnaW6GkoSbnKKeJIaShJmZDU5TT3JpZW50YXRpb26G
+       koSbnJ2dAIaShJmZGU5TUHJpbnRSZXZlcnNlT3JpZW50YXRpb26GkraShJmZCk5TTGFz
+       dFBhZ2WGkoSbnISXl4J/////hpKEmZkLTlNUb3BNYXJnaW6GkoSbnKKeJIaShJmZFE5T
+       VmVydGljYWxseUNlbnRlcmVkhpK7koSZmQtOU1BhcGVyU2l6ZYaShJychIQMe19OU1Np
+       emU9ZmZ9ooECU4EDSoaGhg==
+       </data>
+       <key>RowAlign</key>
+       <integer>0</integer>
+       <key>RowSpacing</key>
+       <real>9.000000e+00</real>
+       <key>VPages</key>
+       <integer>2</integer>
+       <key>WindowInfo</key>
+       <dict>
+               <key>Frame</key>
+               <string>{{83, 91}, {566, 801}}</string>
+               <key>VisibleRegion</key>
+               <string>{{-24, 0}, {1102, 1448}}</string>
+               <key>Zoom</key>
+               <string>0.5</string>
+       </dict>
+</dict>
+</plist>
diff --git a/skyrix-core/NGMime/TODO b/skyrix-core/NGMime/TODO
new file mode 100644 (file)
index 0000000..8230a60
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id: TODO,v 1.3 2004/05/16 19:08:35 helge Exp $
+
+NGMimeRFC822DateHeaderFieldGenerator:
+- do not use -descriptionWithCalendarFormat:
+
+- apparently a lot of code duplications for quoted printable decoding/encoding?
+  look for "?iso-8859" in:
+  - NGMimeAddressHeaderFieldGenerator.m
+  - NGMimeContentDispositionHeaderFieldGenerator.m
+  - NGMimeContentTypeHeaderFieldGenerator.m
diff --git a/skyrix-core/NGMime/Version b/skyrix-core/NGMime/Version
new file mode 100644 (file)
index 0000000..d9e65d0
--- /dev/null
@@ -0,0 +1,5 @@
+# $Id$
+
+SUBMINOR_VERSION:=171
+
+# v4.2.149 requires libNGStreams v4.2.34
diff --git a/skyrix-core/NGMime/common.h b/skyrix-core/NGMime/common.h
new file mode 100644 (file)
index 0000000..192cead
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGMime_common_H__
+#define __NGMime_common_H__
+
+// common include files
+
+#import <Foundation/Foundation.h>
+
+#if LIB_FOUNDATION_LIBRARY
+#  import <Foundation/exceptions/GeneralExceptions.h>
+#elif NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY
+#  import <NGExtensions/NGObjectMacros.h>
+#  import <NGExtensions/NSString+Ext.h>
+#endif
+
+#include <NGExtensions/NGExtensions.h>
+#include <NGStreams/NGStreams.h>
+
+#include "NGMimeType.h"
+
+#if !GNU_RUNTIME
+#  ifndef sel_eq
+#    define sel_eq(__A__, __B__) (__A__==__B__)
+#  endif
+#endif
+
+@interface NSObject(OSXHacks)
+- (void)subclassResponsibility:(SEL)_acmd;
+- (void)notImplemented:(SEL)_acmd;
+@end
+
+#endif /* __NGMime_common_H__ */
diff --git a/skyrix-core/NGMime/libNGMime.def b/skyrix-core/NGMime/libNGMime.def
new file mode 100644 (file)
index 0000000..30086d3
--- /dev/null
@@ -0,0 +1,62 @@
+EXPORTS
+       __objc_class_name_NGParameterMimeType;
+       __objc_class_name_NGConcreteTextMimeType;
+       __objc_class_name_NGConcreteTextVcardMimeType;
+       __objc_class_name_NGConcreteApplicationMimeType;
+       __objc_class_name_NGConcreteAppOctetMimeType;
+       __objc_class_name_NGConcreteImageMimeType;
+       __objc_class_name_NGConcreteAudioMimeType;
+       __objc_class_name_NGConcreteVideoMimeType;
+       __objc_class_name_NGConcreteMultipartMimeType;
+       __objc_class_name_NGConcreteMessageMimeType;
+       __objc_class_name_NGConcreteGenericMimeType;
+       __objc_class_name_NGConcreteWildcardType ;
+       __objc_class_name_NGMime;
+       __objc_class_name_NGMimeBodyGenerator;
+       __objc_class_name_NGMimeTextBodyGenerator;
+       __objc_class_name_NGMimeRfc822BodyGenerator;
+       __objc_class_name_NGMimeMultipartBodyGenerator;
+       __objc_class_name_NGMimeBodyParser;
+       __objc_class_name_NGMimeTextBodyParser;
+       __objc_class_name_NGMimeRfc822BodyParser;
+       __objc_class_name_NGMimeMultipartBodyParser;
+       __objc_class_name_NGMimeBodyPart;
+       __objc_class_name_NGMimeBodyPartParser;
+       __objc_class_name_NGMimeCommandMap;
+       __objc_class_name_NGMimeDataHandler;
+       __objc_class_name_NGMimeObjectDataHandler;
+       __objc_class_name_NGMimeException;
+       __objc_class_name_NGMimeParserException;
+       __objc_class_name_NGMimeFileDataSource;
+       __objc_class_name_NGMimeFileTypeMap;
+       __objc_class_name_NGMimeDefaultsFileTypeMap;
+       __objc_class_name_NGMimeHeaderFieldGenerator;
+       __objc_class_name_NGMimeRFC822DateHeaderFieldGenerator;
+       __objc_class_name_NGMimeContentTypeHeaderFieldGenerator;
+       __objc_class_name_NGMimeContentLengthHeaderFieldGenerator;
+       __objc_class_name_NGMimeContentDispositionHeaderFieldGenerator;
+       __objc_class_name_NGMimeStringHeaderFieldGenerator;
+       __objc_class_name_NGMimeHeaderFieldGeneratorSet;
+       __objc_class_name_NGMimeHeaderFieldParser;
+       __objc_class_name_NGMimeRFC822DateHeaderFieldParser;
+       __objc_class_name_NGMimeContentTypeHeaderFieldParser;
+       __objc_class_name_NGMimeContentLengthHeaderFieldParser;
+       __objc_class_name_NGMimeContentDispositionHeaderFieldParser;
+       __objc_class_name_NGMimeStringHeaderFieldParser;
+       __objc_class_name_NGMimeHeaderFieldParserSet;
+       __objc_class_name_NGMimeContentDispositionHeaderField;
+       __objc_class_name_NGMimeMultipartBody;
+       __objc_class_name_NGMimePartGenerator;
+       __objc_class_name_NGMimePartParser;
+       __objc_class_name_NGMimeType;
+       NGMimeTypeText;
+       NGMimeTypeAudio;
+       NGMimeTypeVideo;
+       NGMimeTypeImage;
+       NGMimeTypeApplication;
+       NGMimeTypeMultipart;
+       NGMimeTypeMessage;
+       NGMimeParameterTextCharset;
+       NGMimeContentDispositionInlineType;
+       NGMimeContentDispositionAttachmentType;
+       NGMimeContentDispositionFormType;
diff --git a/skyrix-core/NGMime/timeMacros.h b/skyrix-core/NGMime/timeMacros.h
new file mode 100644 (file)
index 0000000..c315aac
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+#if 0
+
+#include <sys/time.h>
+
+#define TIME_START(_timeDescription) \
+{ \
+  struct timeval tv; \
+  double ti; \
+  char *timeDescription; \
+  unsigned int vm, vm1, rss, rss1; \
+  static double AddedTime = 0; \
+  static NSProcessInfo *ProcessInfo = nil; \
+  static int CountCalls = 0; \
+  \
+  if (ProcessInfo == nil) \
+    ProcessInfo = [[NSProcessInfo processInfo] retain]; \
+  \
+  *(&vm)  = 0; \
+  *(&rss) = 0; \
+  *(&ti)  = 0; \
+  {\
+    NSAutoreleasePool *p__1; \
+    p__1 = [NSAutoreleasePool new]; \
+    vm   = [ProcessInfo virtualMemorySize]; \
+    rss  = [ProcessInfo residentSetSize] * 4096; \
+    [p__1 release];\
+  }\
+  timeDescription = _timeDescription; \
+  gettimeofday(&tv, NULL); \
+  ti =  (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0 ); \
+  fprintf(stderr, "{"); \
+
+
+#define TIME_END gettimeofday(&tv, NULL); \
+  gettimeofday(&tv, NULL); \
+  { \
+    NSAutoreleasePool *p__1 = [NSAutoreleasePool new]; \
+    vm1  = [ProcessInfo virtualMemorySize]; \
+    rss1 = [ProcessInfo residentSetSize] * 4096; \
+    [p__1 release]; \
+  }; \
+  ti = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0) - ti; \
+  AddedTime += ti; \
+  CountCalls++; \
+  fprintf(stderr,\
+          "}%s: <%s>[%d] : \n" \
+          "  time needed:           %4.4fs (%4.4fs) \n"\
+          "  memory wasted virtual: %d absolut %d \n" \
+          "  resident set size:     %d absolute %d\n", \
+          __PRETTY_FUNCTION__, timeDescription, CountCalls,\
+          ti < 0.0 ? -1.0 : ti, AddedTime, vm1 - vm, vm1, rss1 - rss, rss1); \
+}
+
+#else
+
+#define TIME_START(_timeDescription)
+
+#define TIME_END
+
+#endif
+
diff --git a/skyrix-core/NGStreams/.cvsignore b/skyrix-core/NGStreams/.cvsignore
new file mode 100644 (file)
index 0000000..fff156f
--- /dev/null
@@ -0,0 +1,8 @@
+shared_debug_obj
+shared_obj
+ix86
+config.cache
+config.log
+config.status
+autom4te.cache
+
diff --git a/skyrix-core/NGStreams/COPYING b/skyrix-core/NGStreams/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-core/NGStreams/COPYRIGHT b/skyrix-core/NGStreams/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-core/NGStreams/ChangeLog b/skyrix-core/NGStreams/ChangeLog
new file mode 100644 (file)
index 0000000..afb67e9
--- /dev/null
@@ -0,0 +1,368 @@
+2004-07-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGLocalSocketAddress.m: fixed a gcc 3.4 warning (v4.2.41)
+
+2004-07-05  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile.preamble: added missing library lookup path to EOControl,
+         this fixes OGo bug #820 (v4.2.40)
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile.preamble: added prebinding (v4.2.39)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.38)
+
+2004-02-11  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile.preamble: define OPENSSL_NO_KRB5 to keep Fedora and RH9
+         happy on compilation (v4.2.37)
+
+2004-02-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: enable SSL per default (this adds OpenSSL-devel as a
+         prerequisite unless you compile with ssl=no) (v4.2.36)
+
+2004-02-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGCTextStream.m, NGConcreteStreamFileHandle.m, NGFilterStream.m,
+         NGFilterTextStream.m: fixed minor compilation warnings on OSX 
+         (v4.2.35)
+
+2004-01-25  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.34
+
+       * NGDataStream.m: optimized processing for readonly streams (only call
+         -length and -bytes on the data object in the beginning) - this gives
+         us about 100ms when parsing 1000 IMAP4 headers (about 3-4% speedup)
+
+       * NGDataStream.m: added method to open a datastream in read-only mode
+         even with NSMutableData objects (allows for optimizations in the
+         stream)
+       
+2004-01-24  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.33
+
+       * NGBufferedStream.m, NGByteBuffer.m: avoid creation of buffered 
+         stream if the source is an NGDataStream (no buffering needed ;-), do
+         not create buffer streams when no source stream is passed in
+       
+       * NGDataStream.m: NGDataStream objects can now add as byte buffers on
+         their own - which removes a lot of unncessary overhead when parsing
+         NSData (this gives a speedup of about 10% when parsing IMAP4 mail
+         headers)
+
+2004-01-19  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGDataStream.m: properly return last-exception (always returned
+         nil!) - could have side-effects (v4.2.32)
+
+2004-01-12  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGDataStream.m: subminor cleanups (v4.2.31)
+
+2003-11-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * configure.in: patched to use GNUSTEP_MAKEFILES (as suggested by
+         chunsj@embian.com) (v4.2.30)
+
+2003-11-09  Helge Hess  <helge@groove.local>
+
+       * NGActiveSocket.m, NGFilterStream.m, NGStreamCoder.m: minor tweaks
+         for MacOSX (v4.2.29)
+
+2003-10-13  Helge Hess  <helge@opengroupware.org>
+
+       * GNUmakefile, GNUmakefile.postamble: removed NGStream+serialization,
+         NGActiveSocket+serialization from compilation - those files should
+         be removed completely as they aren't used anywhere (v4.2.28)
+
+2003-09-07  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * NGLocalSocketAddress.m, NGLocalSocketDomain.m:
+          include <sys/types.h> if __FreeBSD__ is defined. This will
+         currently affect FreeBSD 4.x only. (v4.2.27)
+
+2003-09-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * various fixes to warnings on MacOSX (v4.2.26)
+
+2003-09-06  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * configure.in: truncate target_os to "freebsd" on FreeBSD
+
+2003-09-01  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.25
+
+       * fixes for MacOSX
+
+       * GNUmakefile.postamble: do not generate config.h on MacOSX, use the
+         preconfigured on in the macosx subdir
+
+2003-07-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * small cleanups to the included headers to improve gstep-base
+         compatibility (v4.2.24)
+
+2003-07-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGGZipStream.m: removed dependency on zutil.h (v4.2.23)
+
+2003-05-26  Helge Hess  <helge.hess@skyrix.com>
+
+       * updated MacOSX support, removed dependencies on FoundationExt
+         (v4.2.22)
+
+2003-05-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGByteBuffer.m: fixed the last signed/unsigned warnings, smaller
+         cleanups to -la: (v4.2.21)
+
+2003-05-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.20
+
+       * fixed some more gcc 3.3 (signed/unsigned) warnings
+
+       * NGInternetSocketAddress.m: some change ?
+
+       * removed several gcc 3.3 warnings
+
+2003-01-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGSocket.m: allocate sockets in the NGInternetSocketDomain by default
+         (v4.2.19)
+
+2003-01-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * replaced some RETAIN macros (v4.2.18)
+
+2003-01-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGPassiveSocket.m, NGInternetSocketDomain.m: small code cleanups 
+         (v4.2.17)
+       
+2003-01-07  Helge Hess  <helge.hess@skyrix.com>
+       
+       * moved testsock.m to skyrix-core-42/samples/
+
+       * GNUmakefile: added optional SSL activation (using ssl=yes)
+
+       * v4.2.16
+
+       * changes for improved compilation on MacOSX, replaced RETAIN macros
+         with methods
+
+Mon Dec 30 13:51:15 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.15
+
+       * NGStreams/NGStreams.h: do not include NGStream+serialization.h
+
+       * NGStreams/NGNet.h: do not include NGActiveSocket+serialization.h
+
+       * NGByteBuffer.m: fixed a gcc 3.2 warning
+
+Fri Dec 27 10:50:56 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: removed NGStreamCoder from library
+
+       * testsock.m: rewritten to use a tool class
+
+       * NGStreamCoder.m: fixed some gcc 3.2 compiler warnings
+
+       * NGStreams/NGStreams.h: does not include NGStreamCoder.h
+       
+       * fixed Copyright headers in most files (v4.2.14)
+
+2002-11-01  Helge Hess  <helge.hess@skyrix.com>
+       
+       * NGDescriptorFunctions.m: added some debugging/logging (new default
+         NGLogDescriptorRecv) (v4.2.13)
+       
+2002-09-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * testsock.m: added various tests
+
+       * NGLockingStream.m, NGDataStream.m, NGFileStream.m, NGByteBuffer.m: 
+         removed compilation warnings
+        
+       * NGCTextStream.m: do not create a text stream if the source stream is
+          nil ...
+          
+        * started support for OpenSSL sockets (v4.2.12)
+       
+2002-08-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGInternetSocketAddress.m: fixed a compilation bug on hosts which
+         are have gethostbyaddr_r() but are not Linux (eg Solaris) (v4.2.11)
+       
+Thu Aug 29 16:46:25 2002  Jan Reichmann  <jan@skyrix.com>
+
+       * v4.2.10
+
+       * NGBase64Stream.m, NGConcreteStreamFileHandle.m, NGStream.m: 
+         fixed 'char-buffer in Exception Handler scope' bug
+
+2002-08-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * some tweaks to support OSX Jaguar (v4.2.9)
+       
+2002-08-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGFileStream.m: do not log, if the filestream is closed on
+         deallocation (v4.2.8)
+       
+Wed Aug 14 09:49:05 2002  Bjoern Stierand  <bjoern@skyrix.com>
+       
+       * NGNetUtilities.m (NGSocketAddressFromString): allows definition
+         of kernel bound addresses using 'host:auto' or '*:auto'
+         (v4.2.7)
+
+2002-07-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.6 [extracted from cvs]
+
+       * fixed a major retain cycle between stream exceptions and streams
+         (lastException ptr). In the case of datastreams this lead to huge
+         memory consumption if the stream reached EOF (the datastream was
+         never released and the whole data kept in memory, most notably this
+         resulted in a leaking MIME parser)
+         => fixes SuSE bug 16845
+       
+       * added DESIGN document (small ;-)
+
+Fri Jun 26 10:40:05 2002  Helge Hess <hh@skyrix.com>
+
+       * NGLocalSocketAddress.h: small fix for MacOSX
+
+Fri May 31 16:08:56 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       *  NGCTextStream.m, NGByteBuffer.m, NGActiveSocket.m, NGBufferedStream.m: remove NSLogs
+       *  NGDataStream.*: add exception-handling (raise version)
+       *  NGStreamExceptions.*: add +exceptionWithStream methods
+
+Tue May 21 12:26:03 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGActiveSocket.m: fixed a small exception related problem with
+         +socketConnectedToAddress: ...
+         v4.2.5 [extracted from cvs]
+
+Fri May 17 14:49:21 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NGGZipStream from NGZlib
+
+Mon Apr 29 13:46:11 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGByteBuffer.m: modified to support the new exception-less IO ...
+
+Tue Apr 23 12:32:23 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGActiveSocket.m: do not throw exception if connect failed (rather
+         set the last exception ...)
+
+Thu Mar 14 13:39:10 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGActiveSocket.m: marks itself as shut down, if the errno says so
+
+       * NGStream.m(NGSafe...): fixed exception handling
+
+       * NGActiveSocket.m(safeWriteBytes:length:): added IMP cache, fixed
+         exception handling bug ...
+
+       * NGBufferedStream.m: added flush buffer size check
+
+Wed Mar 13 17:24:47 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGCTextStream.m: added new exception handling
+
+       * NGTextStream.m: added +version, added lastException
+
+       * NGActiveSocket.m: does not throw exceptions in -read.. and -write..
+
+Mon Mar  4 11:05:54 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGActiveSocket.m: throws less exceptions (uses -lastException,retval)
+
+Mon Feb 25 18:43:13 2002  Helge Hess  <helge.hess@skyrix.com>
+       
+       * NGBufferedStream.m: checks return codes
+       
+Thu Feb 21 12:04:16 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGStreamExceptions.m: added -raiseOnStream:...
+
+Wed Feb 20 13:30:44 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * everything reworked not to throw exceptions ...
+
+Fri Dec  7 14:35:47 2001  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGByteBuffer.m: add profiling
+
+Mon Oct  8 17:47:01 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGLocalSocketAddress.m, NGPassiveSocket.m: better Linux-bug 
+         support ;-) (local sock addresses with length=2, as given by
+         accept())
+
+Thu Oct  4 11:15:34 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGInternetSocketAddress.m: fixed recursion bug
+
+Thu Aug  9 14:14:17 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed all NGUrl related stuff
+
+Thu Aug  9 14:00:04 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved URL escaping to NGExtensions
+
+       * NGFileStream.m: added -initWithPath:
+
+Tue May 15 19:05:45 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGActiveSocket.m: added max-retry count (20) for writeBytes: with 
+         errno==0
+
+Wed May  9 19:22:43 2001  Joerg Grimm  <joerg@trex2>
+
+       * NGActiveSocket.m: check for errno=0 if writeResult<0
+
+Mon Feb 26 11:13:12 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGActiveSocket.m: added more errno=0-on-fail checking
+
+Fri Feb 23 21:40:40 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGActiveSocket.m: check for errno=0 if result<0
+
+       * NGDescriptorFunctions.m: check for errno=0 if result<0
+
+Tue Jan 30 19:50:13 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGUrl.m: modified URL encoding/decoding stuff to use unsigned char
+
+Mon Sep 18 10:47:41 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGCTextStream.m: fixed bug in -writeString
+
+Tue Jun 13 19:40:41 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGUrl.m, NGFileUrl.m: doesn't use stack-based buffers anymore
+
+Fri Jun  9 17:38:27 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * GNUmakefile: added -Wall
+
+Tue Feb 29 17:08:45 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * MOF3 import
+
diff --git a/skyrix-core/NGStreams/DESIGN b/skyrix-core/NGStreams/DESIGN
new file mode 100644 (file)
index 0000000..49c8689
--- /dev/null
@@ -0,0 +1,9 @@
+# $Id: DESIGN,v 1.1.1.1 2003/07/09 22:57:26 cvs Exp $
+
+This library was roughly designed after the Java IO package. Additionally it
+fully supports Unix socket abstractions (domains, addresses and sockets).
+
+Some ObjC design decisions:
+- do not throw exceptions (but keep them in -lastException)
+- use protocols
+- support streaming operation
diff --git a/skyrix-core/NGStreams/GNUmakefile b/skyrix-core/NGStreams/GNUmakefile
new file mode 100644 (file)
index 0000000..372fba4
--- /dev/null
@@ -0,0 +1,96 @@
+#
+#   GNUmakefile
+#
+# $Id$
+
+include ../common.make
+include ./Version
+
+LIBRARY_NAME = libNGStreams
+libNGStreams_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libNGStreams_DLL_DEF                  = libNGStreams.def
+libNGStreams_HEADER_FILES_DIR         = NGStreams
+libNGStreams_HEADER_FILES_INSTALL_DIR = /NGStreams
+
+libNGStreams_HEADER_FILES = \
+       NGStreamsDecls.h                \
+       NGStreams.h                     \
+       NGStreamProtocols.h             \
+       NGTextStreamProtocols.h         \
+       NGBase64Stream.h                \
+       NGBufferedStream.h              \
+       NGByteCountStream.h             \
+       NGCTextStream.h                 \
+       NGConcreteStreamFileHandle.h    \
+       NGDataStream.h                  \
+       NGFileStream.h                  \
+       NGFilterStream.h                \
+       NGFilterTextStream.h            \
+       NGLockingStream.h               \
+       NGStream.h                      \
+       NGStreamExceptions.h            \
+       NGStringTextStream.h            \
+       NGTextStream.h                  \
+       NGDescriptorFunctions.h         \
+       NGStreamPipe.h                  \
+       NGByteBuffer.h                  \
+       NGCharBuffer.h                  \
+       NGTerminalSupport.h             \
+       \
+       NGActiveSocket.h                \
+       NGDatagramPacket.h              \
+       NGDatagramSocket.h              \
+       NGInternetSocketAddress.h       \
+       NGInternetSocketDomain.h        \
+       NGLocalSocketAddress.h          \
+       NGLocalSocketDomain.h           \
+       NGNet.h                         \
+       NGNetDecls.h                    \
+       NGNetUtilities.h                \
+       NGPassiveSocket.h               \
+       NGSocket.h                      \
+       NGSocketExceptions.h            \
+       NGSocketProtocols.h             \
+       \
+       NGGZipStream.h                  \
+
+libNGStreams_OBJC_FILES = \
+       NGStreams.m                     \
+       NGBase64Stream.m                \
+       NGBufferedStream.m              \
+       NGByteCountStream.m             \
+       NGCTextStream.m                 \
+       NGConcreteStreamFileHandle.m    \
+       NGDataStream.m                  \
+       NGFileStream.m                  \
+       NGFilterStream.m                \
+       NGFilterTextStream.m            \
+       NGLockingStream.m               \
+       NGStream.m                      \
+       NGStreamExceptions.m            \
+       NGStringTextStream.m            \
+       NGTextStream.m                  \
+       NGDescriptorFunctions.m         \
+       NGStreamPipe.m                  \
+       NGByteBuffer.m                  \
+       NGCharBuffer.m                  \
+       NGTerminalSupport.m             \
+       \
+       NGActiveSocket.m                \
+       NGDatagramPacket.m              \
+       NGDatagramSocket.m              \
+       NGInternetSocketAddress.m       \
+       NGInternetSocketDomain.m        \
+       NGLocalSocketAddress.m          \
+       NGLocalSocketDomain.m           \
+       NGNetUtilities.m                \
+       NGPassiveSocket.m               \
+       NGSocket.m                      \
+       NGSocketExceptions.m            \
+       \
+       NGGZipStream.m                  \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/NGStreams/GNUmakefile.postamble b/skyrix-core/NGStreams/GNUmakefile.postamble
new file mode 100644 (file)
index 0000000..0ec647d
--- /dev/null
@@ -0,0 +1,24 @@
+# $Id$
+
+ifeq ($(FOUNDATION_LIB),apple)
+
+ADDITIONAL_CPPFLAGS += -I./macosx
+
+else
+
+before-all :: config.status
+
+after-distclean::
+       rm -f config.cache config.log config.status config.h config.mak
+       rm -rf $(GNUSTEP_TARGET_CPU)
+
+$(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS)/config.h config.status : config.h.in configure
+       ./configure
+
+endif
+
+ifneq ($(GNUSTEP_TARGET_OS),cygwin32)
+configure : configure.in
+       autoconf configure.in > configure
+       chmod +x configure
+endif
diff --git a/skyrix-core/NGStreams/GNUmakefile.preamble b/skyrix-core/NGStreams/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..f9a9e45
--- /dev/null
@@ -0,0 +1,59 @@
+# $Id$
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+libNGStreams_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                                            \
+       -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+       -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)             \
+       -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+libNGStreams_LIB_DIRS += \
+       -L../NGExtensions/$(GNUSTEP_OBJ_DIR)    \
+       -L../EOControl/$(GNUSTEP_OBJ_DIR)
+endif
+
+libNGStreams_LIBRARIES_DEPEND_UPON += \
+       -lNGExtensions -lEOControl      \
+       -lDOM -lSaxObjC                 \
+       -lz
+
+libNGStreams_INCLUDE_DIRS += \
+       -I$(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS) \
+       -INGStreams             \
+       -I../NGExtensions       \
+       -I..
+
+# activating SSL support
+ifneq ($(ssl),no)
+libNGStreams_OBJC_FILES += NGActiveSSLSocket.m
+ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1 -DOPENSSL_NO_KRB5
+libNGStreams_LIBRARIES_DEPEND_UPON += -lssl -lcrypto
+endif
+
+ADDITIONAL_CPPFLAGS += -Wall -Wno-protocol
+
+# reentrant
+
+ifeq ($(reentrant),yes)
+ADDITIONAL_CPPFLAGS += -D_REENTRANT=1
+endif
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libNGStreams_PREBIND_ADDR="0xC1400000"
+libNGStreams_LDFLAGS += -seg1addr $(libNGStreams_PREBIND_ADDR)
+endif
+
+# Windows
+
+ifeq ($(GNUSTEP_TARGET_OS),mingw32)
+libNGStreams_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+libNGStreams_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
diff --git a/skyrix-core/NGStreams/NGActiveSSLSocket.m b/skyrix-core/NGStreams/NGActiveSSLSocket.m
new file mode 100644 (file)
index 0000000..14930dc
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGStreams/NGActiveSSLSocket.h>
+#include "common.h"
+
+#if HAVE_OPENSSL
+#  define id openssl_id
+#  include <openssl/ssl.h>
+#  undef id
+#endif
+
+@interface NGActiveSocket(UsedPrivates)
+- (BOOL)primaryConnectToAddress:(id<NGSocketAddress>)_address;
+@end
+
+@implementation NGActiveSSLSocket
+
+#if HAVE_OPENSSL
+
+#if STREAM_BIO
+static int streamBIO_bwrite(BIO *, const char *, int) {
+}
+static int streamBIO_bread(BIO *, char *, int) {
+}
+static int streamBIO_bputs(BIO *, const char *) {
+}
+static int streamBIO_bgets(BIO *, char *, int) {
+}
+static long streamBIO_ctrl(BIO *, int, long, void *) {
+}
+static int streamBIO_create(BIO *) {
+}
+static int streamBIO_destroy(BIO *) {
+}
+static long streamBIO_callback_ctrl(BIO *, int, bio_info_cb *) {
+}
+
+static BIO_METHOD streamBIO = {
+  0 /* type */,
+  "NGActiveSocket" /* name */,
+  streamBIO_bwrite,
+  streamBIO_bread,
+  streamBIO_bputs,
+  streamBIO_bgets,
+  streamBIO_ctrl,
+  streamBIO_create,
+  streamBIO_destroy,
+  streamBIO_callback_ctrl
+};
+
+// create: BIO_new(&streamBIO);
+
+#endif /* STREAM_BIO */
+
+- (id)initWithDomain:(id<NGSocketDomain>)_domain {
+  if ((self = [super initWithDomain:_domain])) {
+    //BIO *bio_err;
+    static BOOL didGlobalInit = NO;
+    
+    if (!didGlobalInit) {
+      /* Global system initialization*/
+      SSL_library_init();
+      SSL_load_error_strings();
+      didGlobalInit = YES;
+    }
+
+    /* An error write context */
+    //bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+    
+    /* Create our context*/
+    
+    if ((self->ctx = SSL_CTX_new(SSLv23_method())) == NULL) {
+      NSLog(@"ERROR(%s): couldn't create SSL context for v23 method !",
+            __PRETTY_FUNCTION__);
+      [self release];
+      return nil;
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (self->ctx) {
+    SSL_CTX_free(self->ctx);
+    self->ctx = NULL;
+  }
+  [super dealloc];
+}
+
+/* basic IO, reading and writing bytes */
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  if (self->ssl == NULL)
+    // should throw error
+    return NGStreamError;
+  
+  return SSL_read(self->ssl, _buf, _len);
+}
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  return SSL_write(self->ssl, _buf, _len);
+}
+
+/* connection and shutdown */
+
+- (BOOL)markNonblockingAfterConnect {
+  return NO;
+}
+- (BOOL)primaryConnectToAddress:(id<NGSocketAddress>)_address {
+  if (self->ctx == NULL) {
+    NSLog(@"ERROR(%s): ctx isn't setup yet !",
+          __PRETTY_FUNCTION__);
+    return NO;
+  }
+
+  if ((self->ssl = SSL_new(self->ctx)) == NULL) {
+    // should set exception !
+    NSLog(@"ERROR(%s): couldn't create SSL socket structure ...",
+          __PRETTY_FUNCTION__);
+    return NO;
+  }
+  
+  if (![super primaryConnectToAddress:_address])
+    /* could not connect to Unix socket ... */
+    return NO;
+  
+  /* probably we should create a BIO for streams !!! */
+  if ((self->sbio = BIO_new_socket(self->fd, BIO_NOCLOSE)) == NULL) {
+    NSLog(@"ERROR(%s): couldn't create SSL socket IO structure ...",
+          __PRETTY_FUNCTION__);
+    [self shutdown];
+    return NO;
+  }
+  
+  NSAssert(self->ctx,  @"missing SSL context ...");
+  NSAssert(self->ssl,  @"missing SSL socket ...");
+  NSAssert(self->sbio, @"missing SSL BIO ...");
+  
+  SSL_set_bio(self->ssl, self->sbio, self->sbio);
+  if (SSL_connect(self->ssl) <= 0) {
+    NSLog(@"ERROR(%s): couldn't setup SSL connection on socket ...",
+          __PRETTY_FUNCTION__);
+    [self shutdown];
+    return NO;
+  }
+  
+  return YES;
+}
+- (BOOL)shutdown {
+  if (self->ctx) {
+    SSL_CTX_free(self->ctx);
+    self->ctx = NULL;
+  }
+  return [super shutdown];
+}
+
+#else /* no OpenSSL available */
+
++ (void)initialize {
+  NSLog(@"WARNING: The NGActiveSSLSocket class was accessed, "
+        @"but OpenSSL support is turned off.");
+}
+- (id)initWithDomain:(id<NGSocketDomain>)_domain {
+  [self release];
+  return nil;
+}
+
+#endif
+
+@end /* NGActiveSSLSocket */
diff --git a/skyrix-core/NGStreams/NGActiveSocket+serialization.m b/skyrix-core/NGStreams/NGActiveSocket+serialization.m
new file mode 100644 (file)
index 0000000..eb073af
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGActiveSocket+serialization.h"
+#include "common.h"
+
+@implementation NGActiveSocket(serialization)
+
+// serialization
+
+- (void)serializeChar:(char)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(char), nil);
+}
+- (void)serializeShort:(short)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(short), nil);
+}
+- (void)serializeInt:(int)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(int), nil);
+}
+- (void)serializeLong:(long)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(long), nil);
+}
+
+- (void)serializeFloat:(float)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(float), nil);
+}
+- (void)serializeDouble:(double)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(double), nil);
+}
+- (void)serializeLongLong:(long long)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(long long), nil);
+}
+
+- (void)serializeCString:(const char *)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(char *), nil);
+}
+
+#if USE_SERIALIZER
+- (void)serializeDataAt:(const void*)_value ofObjCType:(const char*)_type
+  context:(id<NSObjCTypeSerializationCallBack>)_callback {
+
+  NGStreamSerializeObjC(self, _value, _type, _callback);
+}
+#endif
+
+// deserialization
+
+- (char)deserializeChar {
+  char c;
+  NGStreamDeserializeObjC(self, &c, @encode(char), nil);
+  return c;
+}
+- (short)deserializeShort {
+  short s;
+  NGStreamDeserializeObjC(self, &s, @encode(short), nil);
+  return s;
+}
+- (int)deserializeInt {
+  int i;
+  NGStreamDeserializeObjC(self, &i, @encode(int), nil);
+  return i;
+}
+- (long)deserializeLong {
+  long l;
+  NGStreamDeserializeObjC(self, &l, @encode(long), nil);
+  return l;
+}
+- (float)deserializeFloat {
+  float f;
+  NGStreamDeserializeObjC(self, &f, @encode(float), nil);
+  return f;
+}
+
+- (double)deserializeDouble {
+  double d;
+  NGStreamDeserializeObjC(self, &d, @encode(double), nil);
+  return d;
+}
+- (long long)deserializeLongLong {
+  long long l;
+  NGStreamDeserializeObjC(self, &l, @encode(long long), nil);
+  return l;
+}
+
+- (char *)deserializeCString {
+  char *result = NULL;
+  NGStreamDeserializeObjC(self, &result, @encode(char *), nil);
+  return result;
+}
+
+#if USE_SERIALIZER
+- (void)deserializeDataAt:(void *)_value ofObjCType:(const char *)_type
+  context:(id<NSObjCTypeSerializationCallBack>)_callback 
+{
+  NGStreamDeserializeObjC(self, _value, _type, _callback);
+}
+#endif
+
+@end /* NGActiveSocket(serialization) */
+
+void __link_NGActiveSocket_serialization(void) {
+  __link_NGActiveSocket_serialization();
+}
diff --git a/skyrix-core/NGStreams/NGActiveSocket.m b/skyrix-core/NGStreams/NGActiveSocket.m
new file mode 100644 (file)
index 0000000..5e23352
--- /dev/null
@@ -0,0 +1,1159 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "config.h"
+
+#if defined(HAVE_UNISTD_H) || defined(__APPLE__)
+#  include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#  include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+#  include <sys/filio.h>
+#endif
+#if defined(HAVE_SYS_IOCTL_H)
+#  include <sys/ioctl.h>
+#endif
+#if defined(HAVE_TIME_H) || defined(__APPLE__)
+#  include <time.h>
+#endif
+#if defined(HAVE_SYS_TIME_H) || defined(__APPLE__)
+#  include <sys/time.h>
+#endif
+#if defined(HAVE_FCNTL_H) || defined(__APPLE__)
+#  include <fcntl.h>
+#endif
+
+#if defined(__APPLE__)
+#  include <sys/types.h>
+#  include <sys/socket.h>
+#  include <sys/ioctl.h>
+#endif
+
+#if HAVE_WINDOWS_H && !defined(__CYGWIN32__)
+#  include <windows.h>
+#endif
+
+#if defined(WIN32) && !defined(__CYGWIN32__)
+#  include <winsock.h>
+#  define ioctl ioctlsocket
+#endif
+
+#include "common.h"
+
+#include <NGStreams/NGDescriptorFunctions.h>
+#include "NGActiveSocket.h"
+#include "NGSocketExceptions.h"
+#include "NGSocket+private.h"
+#include "common.h"
+
+#if !defined(POLLRDNORM)
+#  define POLLRDNORM POLLIN
+#endif
+
+@interface NGActiveSocket(PrivateMethods)
+
+- (id)_initWithDescriptor:(int)_fd
+  localAddress:(id<NGSocketAddress>)_local
+  remoteAddress:(id<NGSocketAddress>)_remote;
+
+@end
+
+@implementation NGActiveSocket
+
+#if !defined(WIN32) || defined(__CYGWIN32__)
+
++ (BOOL)socketPair:(id<NGSocket>[2])_pair inDomain:(id<NGSocketDomain>)_domain {
+  int fds[2];
+
+  _pair[0] = nil;
+  _pair[1] = nil;
+
+  if (socketpair([_domain socketDomain], SOCK_STREAM, [_domain protocol],
+                 fds) == 0) {
+    NGActiveSocket *s1 = nil;
+    NGActiveSocket *s2 = nil;
+    
+    s1 = [[self alloc] _initWithDomain:_domain descriptor:fds[0]];
+    s2 = [[self alloc] _initWithDomain:_domain descriptor:fds[1]];
+    s1 = [s1 autorelease];
+    s2 = [s2 autorelease];
+
+    if ((s1 != nil) && (s2 != nil)) {
+      s1->mode           = NGStreamMode_readWrite;
+      s1->receiveTimeout = 0.0;
+      s1->sendTimeout    = 0.0;
+      s2->mode           = NGStreamMode_readWrite;
+      s2->receiveTimeout = 0.0;
+      s2->sendTimeout    = 0.0;
+
+      _pair[0] = s1;
+      _pair[1] = s2;
+
+      return YES;
+    }
+    else
+      return NO;
+  }
+  else {
+    int      e       = errno;
+    NSString *reason = nil;
+
+    switch (e) {
+      case EACCES:
+        reason = @"Not allowed to create socket of this type";
+        break;
+      case ENOMEM:
+        reason = @"Could not create socket: Insufficient user memory available";
+        break;
+      case EPROTONOSUPPORT:
+        reason = @"The protocol is not supported by the address family or "
+                 @"implementation";
+        break;
+      case EPROTOTYPE:
+        reason = @"The socket type is not supported by the protocol";
+        break;
+      case EMFILE:
+        reason = @"Could not create socket: descriptor table is full";
+        break;
+      case EOPNOTSUPP:
+        reason = @"The specified protocol does not permit creation of socket "
+                 @"pairs";
+        break;
+
+#if DEBUG
+      case 0:
+        NSLog(@"WARNING(%s): socketpair() call failed, but errno=0",
+              __PRETTY_FUNCTION__);
+#endif
+      default:
+        reason = [NSString stringWithFormat:@"Could not create socketpair: %s",
+                             strerror(e)];
+        break;
+    }
+    [[[NGCouldNotCreateSocketException alloc]
+              initWithReason:reason domain:_domain] raise];
+    return NO;
+  }
+}
+
+#endif
+
++ (id)socketConnectedToAddress:(id<NGSocketAddress>)_address {
+  volatile id sock = [[self alloc] initWithDomain:[_address domain]];
+  
+  if (sock != nil) {
+    if (![sock connectToAddress:_address]) {
+      NSException *e;
+#if 0
+      NSLog(@"WARNING(%s): Couldn't connect to address %@: %@",
+            __PRETTY_FUNCTION__, _address, [sock lastException]);
+#endif
+      /*
+        this method needs to raise the exception, since no object is returned
+        in which we could check the -lastException ...
+      */
+      e = [[sock lastException] retain];
+      [self release];
+      e = [e autorelease];
+      [e raise];
+      return nil;
+    }
+    sock = [sock autorelease];
+  }
+  return sock;
+}
+
+- (id)initWithDomain:(id<NGSocketDomain>)_domain {
+  // designated initializer
+  if ((self = [super initWithDomain:_domain])) {
+    self->mode           = NGStreamMode_readWrite;
+    self->receiveTimeout = 0.0;
+    self->sendTimeout    = 0.0;
+  }
+  return self;
+}
+
+- (id)_initWithDescriptor:(int)_fd
+  localAddress:(id<NGSocketAddress>)_local
+  remoteAddress:(id<NGSocketAddress>)_remote 
+{
+  if ((self = [self _initWithDomain:[_local domain] descriptor:_fd])) {
+    ASSIGN(self->localAddress,  _local);
+    ASSIGN(self->remoteAddress, _remote);
+    self->mode = NGStreamMode_readWrite;
+    
+#if !defined(WIN32) || defined(__CYGWIN32__)
+    NGAddDescriptorFlag(self->fd, O_NONBLOCK);
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->remoteAddress release];
+  [super dealloc];
+}
+
+/* operations */
+
+- (NSException *)lastException {
+  return [super lastException];
+}
+
+- (void)raise:(NSString *)_name reason:(NSString *)_reason {
+  Class clazz;
+  NSException *e;
+  
+  clazz = NSClassFromString(_name);
+  NSAssert1(clazz, @"did not find exception class %@", _name);
+  
+  e = [clazz alloc];
+  if (_reason) {
+    if ([clazz instancesRespondToSelector:@selector(initWithReason:socket:)])
+      e = [(id)e initWithReason:_reason socket:self];
+    else if ([clazz instancesRespondToSelector:@selector(initWithStream:reason:)])
+      e = [(id)e initWithStream:self reason:_reason];
+    else if ([clazz instancesRespondToSelector:@selector(initWithSocket:)])
+      e = [(id)e initWithSocket:self];
+    else if ([clazz instancesRespondToSelector:@selector(initWithStream:)])
+      e = [(id)e initWithStream:self];
+    else
+      e = [e initWithReason:_reason];
+  }
+  else {
+    if ([clazz instancesRespondToSelector:@selector(initWithSocket:)])
+      e = [(id)e initWithSocket:self];
+    else if ([clazz instancesRespondToSelector:@selector(initWithStream:)])
+      e = [(id)e initWithStream:self];
+    else
+      e = [e init];
+  }
+  [self setLastException:e];
+  [e release];
+}
+- (void)raise:(NSString *)_name {
+  [self raise:_name reason:nil];
+}
+
+- (BOOL)markNonblockingAfterConnect {
+#if !defined(WIN32) || defined(__CYGWIN32__)
+  // mark socket as non-blocking
+  return YES;
+#else
+  // on Win we only support blocking sockets right now ...
+  return NO;
+#endif
+}
+
+- (BOOL)primaryConnectToAddress:(id<NGSocketAddress>)_address {
+  // throws
+  //   NGCouldNotConnectException  if the the connect() call fails
+
+  [self resetLastException];
+  
+  if (connect(fd,
+              (struct sockaddr *)[_address internalAddressRepresentation],
+              [_address addressRepresentationSize]) != 0) {
+    NSString *reason   = nil;
+    int      errorCode = errno;
+    NSException *e;
+    
+    switch (errorCode) {
+      case EACCES:
+        reason = @"search permission denied for element in path";
+        break;
+#if defined(WIN32) && !defined(__CYGWIN32__)
+      case WSAEADDRINUSE:
+        reason = @"address already in use";
+        break;
+      case WSAEADDRNOTAVAIL:
+        reason = @"address is not available on remote machine";
+        break;
+      case WSAEAFNOSUPPORT:
+        reason = @"addresses in the specified family cannot be used with the socket";
+        break;
+      case WSAEALREADY:
+        reason = @"a previous non-blocking attempt has not yet been completed";
+        break;
+      case WSAEBADF:
+        reason = @"descriptor is invalid";
+        break;
+      case WSAECONNREFUSED:
+        reason = @"connection refused";
+        break;
+      case WSAEINTR:
+        reason = @"connect was interrupted";
+        break;
+      case WSAEINVAL:
+        reason = @"the address length is invalid";
+        break;
+      case WSAEISCONN:
+        reason = @"socket is already connected";
+        break;
+      case WSAENETUNREACH:
+        reason = @"network is unreachable";
+        break;
+      case WSAETIMEDOUT:
+        reason = @"timeout occured";
+        break;
+#else
+      case EADDRINUSE:
+        reason = @"address already in use";
+        break;
+      case EADDRNOTAVAIL:
+        reason = @"address is not available on remote machine";
+        break;
+      case EAFNOSUPPORT:
+        reason = @"addresses in the specified family cannot be used with the socket";
+        break;
+      case EALREADY:
+        reason = @"a previous non-blocking attempt has not yet been completed";
+        break;
+      case EBADF:
+        reason = @"descriptor is invalid";
+        break;
+      case ECONNREFUSED:
+        reason = @"connection refused";
+        break;
+      case EINTR:
+        reason = @"connect was interrupted";
+        break;
+      case EINVAL:
+        reason = @"the address length is invalid";
+        break;
+      case EIO:
+        reason = @"an IO error occured";
+        break;
+      case EISCONN:
+        reason = @"socket is already connected";
+        break;
+      case ENETUNREACH:
+        reason = @"network is unreachable";
+        break;
+      case ETIMEDOUT:
+        reason = @"timeout occured";
+        break;
+#endif
+
+#if DEBUG
+      case 0:
+        NSLog(@"WARNING(%s): connect() call failed, but errno=0",
+              __PRETTY_FUNCTION__);
+#endif
+        
+      default:
+        reason = [NSString stringWithCString:strerror(errorCode)];
+        break;
+    }
+
+    reason = [NSString stringWithFormat:@"Could not connect to address %@: %@",
+                         _address, reason];
+    
+    e = [[NGCouldNotConnectException alloc]
+              initWithReason:reason socket:self address:_address];
+    [self setLastException:e];
+    [e release];
+    return NO;
+  }
+  
+  /* connect was successful */
+
+  ASSIGN(self->remoteAddress, _address);
+
+  if ([self markNonblockingAfterConnect]) {
+    /* mark socket as non-blocking */
+    NGAddDescriptorFlag(self->fd, O_NONBLOCK);
+    NSAssert((NGGetDescriptorFlags(self->fd) & O_NONBLOCK),
+             @"could not enable non-blocking mode ..");
+  }
+  return YES;
+}
+
+- (BOOL)connectToAddress:(id<NGSocketAddress>)_address {
+  // throws
+  //   NGSocketAlreadyConnectedException  if the socket is already connected
+  //   NGInvalidSocketDomainException     if the remote domain != local domain
+  //   NGCouldNotCreateSocketException    if the socket creation failed
+  
+  if ([self isConnected]) {
+    [[[NGSocketAlreadyConnectedException alloc]
+              initWithReason:@"Could not connected: socket is already connected"
+              socket:self address:self->remoteAddress] raise];
+    return NO;
+  }
+
+  // check whether the remote address is in the same domain like the bound one
+  if (flags.isBound) {
+    if (![[localAddress domain] isEqual:[_address domain]]) {
+      [[[NGInvalidSocketDomainException alloc]
+                initWithReason:@"local and remote socket domains are different"
+                socket:self domain:[_address domain]] raise];
+      return NO;
+    }
+  }
+  
+  // connect, remote-address is non-nil if this returns
+  if (![self primaryConnectToAddress:_address])
+    return NO;
+
+  // if the socket wasn't bound before (normal case), bind it now
+  if (!flags.isBound)
+    if (![self kernelBoundAddress]) return NO;
+  return YES;
+}
+
+- (void)_shutdownDuringOperation {
+  [self shutdown];
+}
+
+- (BOOL)shutdown {
+  if (self->fd != NGInvalidSocketDescriptor) {
+    if (self->mode != NGStreamMode_undefined) {
+      if (shutdown(self->fd, SHUT_RDWR) == 0)
+        self->mode = NGStreamMode_undefined;
+    }
+    
+#if defined(WIN32) && !defined(__CYGWIN32__)
+    if (closesocket(self->fd) == 0) {
+#else
+    if (close(self->fd) == 0) {
+#endif
+      self->fd = NGInvalidSocketDescriptor;
+    }
+    else {
+      NSLog(@"ERROR(%s): close of socket %@ (fd=%i) alive=%s failed: %s",
+            __PRETTY_FUNCTION__,
+            self, self->fd, [self isAlive] ? "YES" : "NO", strerror(errno));
+    }
+    
+    ASSIGN(self->remoteAddress, (id)nil);
+  }
+  return YES;
+}
+
+- (BOOL)shutdownSendChannel {
+  if (NGCanWriteInStreamMode(self->mode)) {
+    shutdown(self->fd, SHUT_WR);
+    
+    if (self->mode == NGStreamMode_readWrite)
+      self->mode = NGStreamMode_readOnly;
+    else {
+      self->mode = NGStreamMode_undefined;
+#if defined(WIN32) && !defined(__CYGWIN32__)
+      closesocket(self->fd);
+#else
+      close(self->fd);
+#endif
+      self->fd = NGInvalidSocketDescriptor;
+    }
+  }
+  return YES;
+}
+- (BOOL)shutdownReceiveChannel {
+  if (NGCanReadInStreamMode(self->mode)) {
+    shutdown(self->fd, SHUT_RD);
+    
+    if (self->mode == NGStreamMode_readWrite)
+      self->mode = NGStreamMode_writeOnly;
+    else {
+      self->mode = NGStreamMode_undefined;
+#if defined(WIN32) && !defined(__CYGWIN32__)
+      closesocket(self->fd);
+#else
+      close(self->fd);
+#endif
+      self->fd = NGInvalidSocketDescriptor;
+    }
+  }
+  return YES;
+}
+
+// ******************** accessors ******************
+
+- (id<NGSocketAddress>)remoteAddress {
+  return self->remoteAddress;
+}
+
+- (BOOL)isConnected {
+  return (self->remoteAddress != nil);
+}
+- (BOOL)isOpen {
+  return [self isConnected];
+}
+
+- (int)socketType {
+  return SOCK_STREAM;
+}
+
+- (void)setSendTimeout:(NSTimeInterval)_timeout {
+  self->sendTimeout = _timeout;
+}
+- (NSTimeInterval)sendTimeout {
+  return self->sendTimeout;
+}
+
+- (void)setReceiveTimeout:(NSTimeInterval)_timeout {
+  self->receiveTimeout = _timeout;
+}
+- (NSTimeInterval)receiveTimeout {
+  return self->receiveTimeout;
+}
+
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode {
+  short events = 0;
+
+  if ((![self isConnected]) || (fd == NGInvalidSocketDescriptor))
+    return NO;
+
+  if (NGCanReadInStreamMode(_mode))  events |= POLLRDNORM;
+  if (NGCanWriteInStreamMode(_mode)) events |= POLLWRNORM;
+
+  // timeout of 0 means return immediatly
+  return (NGPollDescriptor([self fileDescriptor], events, 0) == 1 ? NO : YES);
+}
+
+- (int)waitForMode:(NGStreamMode)_mode timeout:(NSTimeInterval)_timeout {
+  short events = 0;
+
+  if (NGCanReadInStreamMode(_mode))  events |= POLLRDNORM;
+  if (NGCanWriteInStreamMode(_mode)) events |= POLLWRNORM;
+
+  // timeout of 0 means return immediatly
+  return NGPollDescriptor([self fileDescriptor], events,
+                          (int)(_timeout * 1000.0));
+}
+
+- (unsigned)numberOfAvailableBytesForReading {
+  int len;
+
+  // need to check whether socket is connected
+  if (self->remoteAddress == nil) {
+    [self raise:@"NGSocketNotConnectedException"
+          reason:@"socket is not connected"];
+    return NGStreamError;
+  }
+  
+  if (!NGCanReadInStreamMode(self->mode)) {
+    [self raise:@"NGWriteOnlyStreamException"];
+    return NGStreamError;
+  }
+  
+#if !defined(WIN32) && !defined(__CYGWIN32__)
+  while (ioctl(self->fd, FIONREAD, &len) == -1) {
+    if (errno == EINTR) continue;
+    
+    [self raise:@"NGSocketException"
+          reason:@"could not get number of available bytes"];
+    return NGStreamError;
+  }
+#else
+  // PeekNamedPipe() on Win ...
+  len = 0;
+#endif
+  return len;
+}
+
+- (BOOL)isAlive {
+  if (self->fd == NGInvalidSocketDescriptor)
+    return NO;
+  
+  /* poll socket for input */
+  {
+    struct timeval to;
+    fd_set readMask;
+
+    while (YES) {
+      FD_ZERO(&readMask);
+      FD_SET(self->fd, &readMask);
+      to.tv_sec = to.tv_usec = 0;
+      
+      if (select(self->fd + 1, &readMask, NULL, NULL, &to) >= 0)
+        break;
+
+      switch (errno) {
+        case EINTR:
+          continue;
+        case EBADF:
+          goto notAlive;
+        default:
+          NSLog(@"socket select() failed: %s", strerror(errno));
+          goto notAlive;
+      }
+    }
+
+    /* no input is pending, connection is alive */
+    if (!FD_ISSET(self->fd, &readMask)) 
+      return YES;
+  }
+
+  /*
+    input is pending: If select() indicates pending input, but ioctl()
+    indicates zero bytes of pending input, the connection is broken
+  */
+  {
+#if defined(WIN32) && !defined(__CYGWIN32__)
+    u_long len;
+#else
+    int len;
+#endif
+    while (ioctl(self->fd, FIONREAD, &len) == -1) {
+      if (errno == EINTR) continue;
+      goto notAlive;
+    }
+    if (len > 0) return YES;
+  }
+  
+ notAlive:
+  /* valid descriptor, but not alive .. so we close the socket */
+#if defined(WIN32) && !defined(__CYGWIN32__)
+  closesocket(self->fd);
+#else
+  close(self->fd);
+#endif
+  self->fd = NGInvalidSocketDescriptor;
+  RELEASE(self->remoteAddress); self->remoteAddress = nil;
+  return NO;
+}
+// ******************** NGStream ********************
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  // throws
+  //   NGStreamReadErrorException    when the read call failed
+  //   NGSocketNotConnectedException when the socket is not connected
+  //   NGEndOfStreamException        when the end of the stream is reached
+  //   NGWriteOnlyStreamException    when the receive channel was shutdown
+  NSException *e = nil;
+  
+  if (self->fd == NGInvalidSocketDescriptor) {
+    [self raise:@"NGSocketException" reason:@"NGActiveSocket is not open"];
+    return NGStreamError;
+  }
+  
+  // need to check whether socket is connected
+  if (self->remoteAddress == nil) {
+    [self raise:@"NGSocketNotConnectedException"
+          reason:@"socket is not connected"];
+    return NGStreamError;
+  }
+  
+  if (!NGCanReadInStreamMode(self->mode)) {
+    [self raise:@"NGWriteOnlyStreamException"];
+    return NGStreamError;
+  }
+  
+  if (_len == 0) return 0;
+
+  {
+#if defined(WIN32) && !defined(__CYGWIN32__)
+    int readResult;
+
+    readResult = recv(self->fd, _buf, _len, 0);
+    if (readResult == 0) {
+      [self _shutdownDuringOperation];
+      [self raise:@"NGSocketShutdownDuringReadException"];
+      return NGStreamError;
+    }
+    else if (readResult < 0) {
+      int errorCode = WSAGetLastError();
+      
+      switch (errorCode) {
+        case WSAECONNRESET:
+          e = [[NGSocketConnectionResetException alloc] initWithStream:self];
+          break;
+        case WSAETIMEDOUT:
+          e = [[NGSocketTimedOutException alloc] initWithStream:self];
+          break;
+
+        case WSAEWOULDBLOCK:
+          NSLog(@"WARNING: descriptor would block ..");
+          
+        default:
+          e = [[NGStreamReadErrorException alloc]
+                    initWithStream:self errorCode:errorCode];
+          break;
+      }
+      if (e) {
+        [self setLastException:e];
+        [e release];
+        return NGStreamError;
+      }
+    }
+#else /* !WIN32 */
+    int readResult;
+
+    NSAssert(_buf,     @"invalid buffer");
+    NSAssert1(_len > 0, @"invalid length: %i", _len);
+   retry: 
+    readResult = NGDescriptorRecv(self->fd, _buf, _len, 0,
+                                  (self->receiveTimeout == 0.0)
+                                  ? -1 // block until data
+                                  : (int)(self->receiveTimeout * 1000.0));
+#if DEBUG
+    if ((readResult < 0) && (errno == EINVAL)) {
+      NSLog(@"%s: invalid argument in NGDescriptorRecv(%i, 0x%08X, %i, %i)",
+            __PRETTY_FUNCTION__,
+            self->fd, _buf, _len, 0,
+            (self->receiveTimeout == 0.0)
+            ? -1 // block until data
+            : (int)(self->receiveTimeout * 1000.0));
+    }
+#endif
+    
+    if (readResult == 0) {
+      [self _shutdownDuringOperation];
+      [self raise:@"NGSocketShutdownDuringReadException"];
+      return NGStreamError;
+    }
+    else if (readResult == -2) {
+      [self raise:@"NGSocketTimedOutException"];
+      return NGStreamError;
+    }
+    else if (readResult < 0) {
+      int errorCode = errno;
+
+      e = nil;
+      switch (errorCode) {
+        case 0:
+#if DEBUG
+          /* this happens with the Oracle7 adaptor !!! */
+          NSLog(@"WARNING(%s): readResult<0 (%i), but errno=0 - retry",
+                __PRETTY_FUNCTION__, readResult);
+#endif
+          goto retry;
+          break;
+          
+        case ECONNRESET:
+          e = [[NGSocketConnectionResetException alloc] initWithStream:self];
+          break;
+        case ETIMEDOUT:
+          e = [[NGSocketTimedOutException alloc] initWithStream:self];
+          break;
+
+        case EWOULDBLOCK:
+          NSLog(@"WARNING: descriptor would block ..");
+          
+        default:
+          e = [[NGStreamReadErrorException alloc]
+                    initWithStream:self errorCode:errorCode];
+          break;
+      }
+      if (e) {
+        [self setLastException:e];
+        [e release];
+        return NGStreamError;
+      }
+    }
+#endif /* !WIN32 */
+    return readResult;
+  }
+}
+
+#if defined(WIN32) && !defined(__CYGWIN32__)
+#warning fix exception handling
+
+- (unsigned)_winWriteBytes:(const void *)_buf count:(unsigned)_len {
+  NSException *e = nil;
+    int writeResult;
+
+    writeResult = send(self->fd, _buf, _len, 0);
+    
+    if (writeResult == 0) {
+      [self _shutdownDuringOperation];
+      [self raise:@"NGSocketShutdownDuringWriteException"];
+      return NGStreamError;
+    }
+    else if (writeResult < 0) {
+      int errorCode = WSAGetLastError();
+      
+      switch (errorCode) {
+        case WSAECONNRESET:
+          e = [[NGSocketConnectionResetException alloc] initWithStream:self];
+          break;
+        case WSAETIMEDOUT:
+          e = [[NGSocketTimedOutException alloc] initWithStream:self];
+          break;
+
+        case WSAEWOULDBLOCK:
+          NSLog(@"WARNING: descriptor would block ..");
+
+        default:
+          e = [[NGStreamWriteErrorException alloc]
+                    initWithStream:self errorCode:errno];
+          break;
+      }
+      if (e) {
+        [self setLastException:e];
+        [e release];
+        return NGStreamError;
+      }
+    }
+    return writeResult;
+}
+
+#else 
+
+- (unsigned)_unixWriteBytes:(const void *)_buf count:(unsigned)_len {
+   int writeResult;
+   int timeOut;
+   int retryCount;
+
+   retryCount = 0;
+   timeOut = (self->sendTimeout == 0.0)
+     ? -1 // block until data
+     : (int)(self->sendTimeout * 1000.0);
+   
+ wretry: 
+   writeResult = NGDescriptorSend(self->fd, _buf, _len, 0, timeOut);
+   
+   if (writeResult == 0) {
+     [self _shutdownDuringOperation];
+     [self raise:@"NGSocketShutdownDuringWriteException"];
+     return NGStreamError;
+   }
+   else if (writeResult == -2) {
+     [self raise:@"NGSocketTimedOutException"];
+     return NGStreamError;
+   }
+   else if (writeResult < 0) {
+     int errorCode = errno;
+     
+     switch (errorCode) {
+       case 0:
+#if DEBUG
+         /* this happens with the Oracle7 (on SuSE < 7.1??) adaptor !!! */
+         NSLog(@"WARNING(%s): writeResult<0 (%i), but errno=0 - retry",
+               __PRETTY_FUNCTION__, writeResult);
+#endif
+         retryCount++;
+         if (retryCount > 200000) {
+           NSLog(@"WARNING(%s): writeResult<0 (%i), but errno=0 - cancel retry "
+                 @"(already tried %i times !!!)",
+                 __PRETTY_FUNCTION__, writeResult, retryCount);
+           [self _shutdownDuringOperation];
+           [self raise:@"NGSocketShutdownDuringWriteException"];
+           return NGStreamError;
+           break;
+         }
+         sleep(retryCount);
+         goto wretry;
+         break;
+         
+       case ECONNRESET:
+         [self raise:@"NGSocketConnectionResetException"];
+         return NGStreamError;
+       case ETIMEDOUT:
+         [self raise:@"NGSocketTimedOutException"];
+         return NGStreamError;
+         
+       case EPIPE:
+         [self _shutdownDuringOperation];
+         [self raise:@"NGSocketShutdownDuringWriteException"];
+         return NGStreamError;
+         
+       case EWOULDBLOCK:
+         NSLog(@"WARNING: descriptor would block ..");
+         
+       default: {
+         NSException *e;
+         e = [[NGStreamWriteErrorException alloc]
+               initWithStream:self errorCode:errno];
+         [self setLastException:e];
+         [e release];
+         return NGStreamError;
+       }
+     }
+   }
+   return writeResult;
+}
+
+#endif 
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  // throws
+  //   NGStreamWriteErrorException   when the write call failed
+  //   NGSocketNotConnectedException when the socket is not connected
+  //   NGReadOnlyStreamException     when the send channel was shutdown
+  
+  if (_len == NGStreamError) {
+    NSLog(@"ERROR(%s): got NGStreamError passed in as length ...",
+          __PRETTY_FUNCTION__);
+    return NGStreamError;
+  }
+#if DEBUG
+  if (_len > (1024 * 1024 * 100 /* 100MB */)) {
+    NSLog(@"WARNING(%s): got passed in length %uMB (%u bytes, errcode=%u) ...",
+          __PRETTY_FUNCTION__, (_len / 1024 / 1024), _len, NGStreamError);
+  }
+#endif
+  
+  if (self->fd == NGInvalidSocketDescriptor) {
+    [self raise:@"NGSocketException" reason:@"NGActiveSocket is not open"];
+    return NGStreamError;
+  }
+  
+  // need to check whether socket is connected
+  if (self->remoteAddress == nil) {
+    [self raise:@"NGSocketNotConnectedException"
+          reason:@"socket is not connected"];
+    return NGStreamError;
+  }
+  
+  if (!NGCanWriteInStreamMode(self->mode)) {
+    [self raise:@"NGReadOnlyStreamException"];
+    return NGStreamError;
+  }
+  
+  //NSLog(@"writeBytes: count:%u", _len);
+  
+#if defined(WIN32) && !defined(__CYGWIN32__)
+  return [self _winWriteBytes:_buf count:_len];
+#else
+  return [self _unixWriteBytes:_buf count:_len];
+#endif
+}
+
+- (BOOL)flush {
+  return YES;
+}
+#if 0 
+- (BOOL)close {
+  return [self shutdown];
+}
+#endif 
+
+- (NGStreamMode)mode {
+  return self->mode;
+}
+
+/* methods method which write exactly _len bytes or fail */
+
+- (BOOL)safeReadBytes:(void *)_buf count:(unsigned)_len {
+  volatile int toBeRead;
+  int  readResult;
+  void *pos;
+  unsigned (*readBytes)(id, SEL, void *, unsigned);
+
+  *(&readBytes)  = (void *)[self methodForSelector:@selector(readBytes:count:)];
+  *(&toBeRead)   = _len;
+  *(&readResult) = 0;
+  *(&pos)        = _buf;
+  
+  while (YES) {
+    *(&readResult) =
+      readBytes(self, @selector(readBytes:count:), pos, toBeRead);
+    
+    if (readResult == NGStreamError) {
+      NSException *localException = [self lastException];
+      NSData *data;
+      
+      data = [NSData dataWithBytes:_buf length:(_len - toBeRead)];
+      
+      localException = [[[localException class] alloc]
+                          initWithStream:self
+                          readCount:(_len - toBeRead)
+                          safeCount:_len
+                          data:data];
+      [self setLastException:localException];
+      RELEASE(localException);
+    }
+    
+    NSAssert(readResult != 0, @"ERROR: readBytes may not return '0' ..");
+
+    if (readResult == toBeRead) {
+      // all bytes were read successfully, return
+      break;
+    }
+    
+    if (readResult < 1) {
+      [NSException raise:NSInternalInconsistencyException
+                   format:@"readBytes:count: returned a value < 1"];
+    }
+
+    toBeRead -= readResult;
+    pos      += readResult;
+  }
+  
+  return YES;
+}
+
+- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len {
+  int  toBeWritten = _len;
+  int  writeResult;
+  void *pos = (void *)_buf;
+
+  /* method cache (THREAD, reentrant) */
+  static Class lastClass = Nil;
+  static int  (*writeBytes)(id,SEL,const void*,unsigned) = NULL;
+
+  if (lastClass == *(Class *)self) {
+    if (writeBytes == NULL)
+      writeBytes =
+        (void *)[self methodForSelector:@selector(writeBytes:count:)];
+  }
+  else {
+    lastClass = *(Class *)self;
+    writeBytes = (void *)[self methodForSelector:@selector(writeBytes:count:)];
+  }
+  
+  while (YES) {
+    writeResult =
+      (int)writeBytes(self, @selector(writeBytes:count:), pos, toBeWritten);
+    
+    if (writeResult == NGStreamError) {
+      /* remember number of written bytes ??? */
+      return NO;
+    }
+    else if (writeResult == toBeWritten) {
+      // all bytes were written successfully, return
+      break;
+    }
+
+    if (writeResult < 1) {
+      [NSException raise:NSInternalInconsistencyException
+                   format:@"writeBytes:count: returned a value < 1 in stream %@",
+                     self];
+      return NO;
+    }
+    
+    toBeWritten -= writeResult;
+    pos         += writeResult;
+  }
+  return YES;
+}
+
+- (BOOL)mark {
+  return NO;
+}
+- (BOOL)rewind {
+  [self raise:@"NGStreamException" reason:@"stream doesn't support a mark"];
+  return NO;
+}
+- (BOOL)markSupported {
+  return NO;
+}
+
+// convenience methods
+
+- (int)readByte { // java semantics (-1 returned on EOF)
+  int result;
+  unsigned char c;
+  
+  result = [self readBytes:&c count:sizeof(unsigned char)];
+  
+  if (result != 1) {
+    static Class EOFExcClass = Nil;
+
+    if (EOFExcClass == Nil)
+      EOFExcClass = [NGEndOfStreamException class];
+    
+    if ([[self lastException] isKindOfClass:EOFExcClass])
+      [self resetLastException];
+    
+    return -1;
+  }
+  return (int)c;
+}
+
+/* description */
+
+- (NSString *)modeDescription {
+  NSString *result = @"<unknown>";
+  
+  switch ([self mode]) {
+    case NGStreamMode_undefined: result = @"<closed>"; break;
+    case NGStreamMode_readOnly:  result = @"r";        break;
+    case NGStreamMode_writeOnly: result = @"w";        break;
+    case NGStreamMode_readWrite: result = @"rw";       break;
+    default:
+      [[[NGUnknownStreamModeException alloc] initWithStream:self] raise];
+      break;
+  }
+  return result;
+}
+
+- (NSString *)description {
+  NSMutableString *d = [NSMutableString stringWithCapacity:64];
+
+  [d appendFormat:@"<%@[0x%08X]: mode=%@ address=%@",
+       NSStringFromClass([self class]),
+       (unsigned)self,
+       [self modeDescription], [self localAddress]];
+
+  if ([self isConnected])
+    [d appendFormat:@" connectedTo=%@", [self remoteAddress]];
+
+  if ([self sendTimeout] != 0.0) 
+    [d appendFormat:@" send-timeout=%4.3fs", [self sendTimeout]];
+  if ([self receiveTimeout] != 0.0) 
+    [d appendFormat:@" receive-timeout=%4.3fs", [self receiveTimeout]];
+
+  [d appendString:@">"];
+  return d;
+}
+
+@end /* NGActiveSocket */
+
+@implementation NGActiveSocket(DataMethods)
+
+- (NSData *)readDataOfLength:(unsigned int)_length {
+  unsigned readCount;
+  char buf[_length];
+
+  if (_length == 0) return [NSData data];
+
+  readCount = [self readBytes:buf count:_length];
+  return [NSData dataWithBytes:buf length:readCount];
+}
+
+- (NSData *)safeReadDataOfLength:(unsigned int)_length {
+  char buf[_length];
+
+  if (_length == 0) return [NSData data];
+  [self safeReadBytes:buf count:_length];
+  return [NSData dataWithBytes:buf length:_length];
+}
+
+- (unsigned int)writeData:(NSData *)_data {
+  return [self writeBytes:[_data bytes] count:[_data length]];
+}
+- (BOOL)safeWriteData:(NSData *)_data {
+  return [self safeWriteBytes:[_data bytes] count:[_data length]];
+}
+
+@end /* NGActiveSocket(DataMethods) */
+
+#include <NGStreams/NGBufferedStream.h>
+
+@implementation NGBufferedStream(FastSocketForwarders)
+
+- (BOOL)isConnected {
+  return [(id)self->source isConnected];
+}
+- (int)fileDescriptor {
+  return [(NSFileHandle *)self->source fileDescriptor];
+}
+
+@end /* NGBufferedStream(FastSocketForwarders) */
diff --git a/skyrix-core/NGStreams/NGBase64Stream.m b/skyrix-core/NGStreams/NGBase64Stream.m
new file mode 100644 (file)
index 0000000..782734e
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGBase64Stream.h"
+#include "NGCTextStream.h"
+
+static inline BOOL isbase64(char a) {
+  if (('A' <= a) && (a <= 'Z')) return YES;
+  if (('a' <= a) && (a <= 'z')) return YES;
+  if (('0' <= a) && (a <= '9')) return YES;
+  if ((a == '+') || (a == '/')) return YES;
+  return NO;
+}
+
+@implementation NGBase64Stream
+
+// ******************** decoding ********************
+
+static char dmap[256] = {
+  127, 127, 127, 127, 127, 127, 127, 127,      //   000-007
+  127, 127, 127, 127, 127, 127, 127, 127,      //   010-017
+  127, 127, 127, 127, 127, 127, 127, 127,      //   020-027
+  127, 127, 127, 127, 127, 127, 127, 127,      //   030-037
+  127, 127, 127, 127, 127, 127, 127, 127,      //   040-047   !"#$%&'
+  127, 127, 127,  62, 127, 127, 127,  63,      //   050-057  ()*+,-./
+   52,  53,  54,  55,  56,  57,  58,  59,      //   060-067  01234567
+   60,  61, 127, 127, 127, 126, 127, 127,      //   070-077  89:;<=>?
+
+  127,   0,   1,   2,   3,   4,   5,   6,      //   100-107  @ABCDEFG
+    7,   8,   9,  10,  11,  12,  13,  14,      //   110-117  HIJKLMNO
+   15,  16,  17,  18,  19,  20,  21,  22,      //   120-127  PQRSTUVW
+   23,  24,  25, 127, 127, 127, 127, 127,      //   130-137  XYZ[\]^_
+  127,  26,  27,  28,  29,  30,  31,  32,      //   140-147  `abcdefg
+   33,  34,  35,  36,  37,  38,  39,  40,      //   150-157  hijklmno
+   41,  42,  43,  44,  45,  46,  47,  48,      //   160-167  pqrstuvw
+   49,  50,  51, 127, 127, 127, 127, 127,      //   170-177  xyz{|}~
+
+  127, 127, 127, 127, 127, 127, 127, 127,      //   200-207
+  127, 127, 127, 127, 127, 127, 127, 127,      //   210-217
+  127, 127, 127, 127, 127, 127, 127, 127,      //   220-227
+  127, 127, 127, 127, 127, 127, 127, 127,      //   230-237
+  127, 127, 127, 127, 127, 127, 127, 127,      //   240-247
+  127, 127, 127, 127, 127, 127, 127, 127,      //   250-257
+  127, 127, 127, 127, 127, 127, 127, 127,      //   260-267
+  127, 127, 127, 127, 127, 127, 127, 127,      //   270-277
+
+  127, 127, 127, 127, 127, 127, 127, 127,      //   300-307
+  127, 127, 127, 127, 127, 127, 127, 127,      //   310-317
+  127, 127, 127, 127, 127, 127, 127, 127,      //   320-327
+  127, 127, 127, 127, 127, 127, 127, 127,      //   330-337
+  127, 127, 127, 127, 127, 127, 127, 127,      //   340-347
+  127, 127, 127, 127, 127, 127, 127, 127,      //   350-357
+  127, 127, 127, 127, 127, 127, 127, 127,      //   360-367
+  127, 127, 127, 127, 127, 127, 127, 127,      //   370-377
+};
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  unsigned char chunk[4]; // input buffer
+  unsigned char chunkLen; // input buffer length
+  unsigned      readLen = 0;
+
+  if (self->decBufferLen == 0) { // no bytes in buffer, read next token
+    register unsigned value;
+    {
+      volatile unsigned pos = 0, toGo = 4;
+      char     tmp[4];
+
+      memset(chunk, 126, sizeof(chunk)); // set all EOF
+
+      NS_DURING {
+        do {
+          unsigned      readCount = 0;
+          unsigned char i;
+
+          readCount = [super readBytes:tmp count:toGo];
+          NSAssert(readCount != 0, @"invalid result from readBytes:count:");
+
+          for (i = 0; i < readCount; i++) {
+            if (isbase64(tmp[(int)i])) {
+              chunk[pos] = tmp[(int)i];
+              pos++;
+              toGo--;
+            }
+          }
+        }
+        while (toGo > 0);
+      }
+      NS_HANDLER {
+        if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
+          if (pos == 0)
+            [localException raise];
+        }
+        else
+          [localException raise];
+      }
+      NS_ENDHANDLER;
+
+      chunkLen = pos;
+    }
+    NSAssert(chunkLen > 0, @"invalid chunk len (should have thrown EOF) ..");
+
+    if (chunkLen == 4) { // complete token
+      NSCAssert(self->decBufferLen  == 0, @"data pending in buffer ..");
+      NSCAssert(chunkLen == 4, @"invalid chunk size ..");
+  
+      value = ((dmap[chunk[0]] << 18) |
+               (dmap[chunk[1]] << 12) |
+               (dmap[chunk[2]] << 6) |
+               (dmap[chunk[3]]));
+  
+      self->decBuffer[0] = (unsigned char)(0xFF & (value >> 16));
+      self->decBuffer[1] = (unsigned char)(0xFF & (value >> 8));
+      self->decBuffer[2] = (unsigned char)(0xFF & (value));
+      self->decBufferLen = 3;
+    }
+    else {
+      unsigned char b0 = dmap[chunk[0]];
+      unsigned char b1 = dmap[chunk[1]];
+      unsigned char b2 = dmap[chunk[2]];
+      unsigned char b3 = dmap[chunk[3]];
+      char          eqCount = 0; // number of equal signs
+
+      NSCAssert(self->decBufferLen == 0, @"data pending in buffer ..");
+
+      if (b0 == 126) { b0 = 0; eqCount++; }
+      if (b1 == 126) { b1 = 0; eqCount++; }
+      if (b2 == 126) { b2 = 0; eqCount++; }
+      if (b3 == 126) { b3 = 0; eqCount++; }
+
+      value = ((b0 << 18) | (b1 << 12) | (b2 << 6) | (b3));
+
+      self->decBuffer[0] = (unsigned char)(value >> 16);
+      self->decBufferLen = 1;
+      if (eqCount <= 1) {
+        self->decBuffer[1] = (unsigned char)((value >> 8) & 0xFF);
+        self->decBufferLen = 2;
+        if (eqCount == 0) {
+          self->decBuffer[2] = (unsigned char)((value & 0xFF));
+          self->decBufferLen = 3;
+        }
+      }
+    }
+
+    NSAssert((self->decBufferLen > 0) && (self->decBufferLen < 4),
+             @"invalid result length ..");
+  }
+
+  // copy decoded bytes to output buffer
+  if (_len >= self->decBufferLen) {
+    readLen = self->decBufferLen;
+    memcpy(_buf, self->decBuffer, readLen);
+    self->decBufferLen = 0;
+  }
+  else {
+    readLen = _len;
+    NSAssert((readLen > 0) && (readLen < 3), @"invalid length ..");
+
+    if (readLen == 1) {
+      *(char *)_buf = self->decBuffer[0];
+      self->decBuffer[0] = self->decBuffer[1];
+      self->decBuffer[1] = self->decBuffer[2];
+      self->decBufferLen--;
+    }
+    else { // readLen == 2;
+      ((char *)_buf)[0] = self->decBuffer[0];
+      ((char *)_buf)[1] = self->decBuffer[1];
+      self->decBuffer[0] = self->decBuffer[2];
+      self->decBufferLen -= 2;
+    }
+  }
+  return readLen;
+}
+
+// ******************** encoding ********************
+
+static char emap[] = {
+  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',     // 0-7
+  'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',     // 8-15
+  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',     // 16-23
+  'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',     // 24-31
+  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',     // 32-39
+  'o', 'p', 'q', 'r', 's', 't', 'u', 'v',     // 40-47
+  'w', 'x', 'y', 'z', '0', '1', '2', '3',     // 48-55
+  '4', '5', '6', '7', '8', '9', '+', '/'      // 56-63
+};
+  
+static inline void _encodeToken(NGBase64Stream *self) {
+  int i = self->lineLength;
+
+  // ratio 3:4
+  self->line[i]     = emap[0x3F & (self->buf >> 18)]; // sextet 1 (octet 1)
+  self->line[i + 1] = emap[0x3F & (self->buf >> 12)]; // sextet 2 (octet 1 and 2)
+  self->line[i + 2] = emap[0x3F & (self->buf >> 6)];  // sextet 3 (octet 2 and 3)
+  self->line[i + 3] = emap[0x3F & (self->buf)];       // sextet 4 (octet 3)
+  self->lineLength += 4;
+  self->buf        =  0;
+  self->bufBytes   =  0;
+}
+
+static inline void _encodePartialToken(NGBase64Stream *self) {
+  int i = self->lineLength;
+
+  self->line[i]     = emap[0x3F & (self->buf >> 18)]; // sextet 1 (octet 1)
+  self->line[i + 1] = emap[0x3F & (self->buf >> 12)]; // sextet 2 (octet 1 and 2)
+  self->line[i + 2] = (self->bufBytes == 1) ? '=' : emap[0x3F & (self->buf >> 6)];
+  self->line[i + 3] = (self->bufBytes <= 2) ? '=' : emap[0x3F & (self->buf)];
+
+  self->lineLength += 4;
+  self->buf        =  0;
+  self->bufBytes   =  0;
+}
+
+static inline void _flushLine(NGBase64Stream *self) {
+  [self->source safeWriteBytes:self->line count:self->lineLength];
+  self->lineLength = 0;
+}
+
+static inline void 
+_encode(NGBase64Stream *self, const char *_in, unsigned _inLen) 
+{
+  // Given a sequence of input bytes, produces a sequence of output bytes
+  // using the base64 encoding.
+  register unsigned int i;
+
+  for (i = 0; i < _inLen; i++) {
+    if (self->bufBytes == 0)
+      self->buf = ((self->buf & 0xFFFF) | (_in[i] << 16));
+    else if (self->bufBytes == 1)
+      self->buf = ((self->buf & 0xFF00FF) | ((_in[i] << 8) & 0xFFFF));
+    else
+      self->buf = ((self->buf & 0xFFFF00) | (_in[i] & 0xFF));
+
+    if ((++(self->bufBytes)) == 3) {
+      _encodeToken(self);
+      if (self->lineLength >= 72)
+        _flushLine(self);
+    }
+
+    if (i == (_inLen - 1)) {
+      if ((self->bufBytes > 0) && (self->bufBytes < 3))
+        _encodePartialToken(self);
+      if (self->lineLength > 0)
+        _flushLine(self);
+    }
+  }
+
+  // reset line buffer
+  memset(self->line, 0, sizeof(self->line));
+}
+
+- (BOOL)close {
+  if (![self flush])  return NO;
+  if (![super close]) return NO;
+  return YES;
+}
+- (BOOL)flush {
+  // output buffer
+  if (self->bufBytes)
+    _encodePartialToken(self);
+  _flushLine(self);
+
+  // reset line buffer
+  memset(self->line, 0, sizeof(self->line));
+  
+  return [super flush];
+}
+
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  _encode(self, _buf, _len);
+  return _len;
+}
+
+@end /* NGBase64Stream */
diff --git a/skyrix-core/NGStreams/NGBufferedStream.m b/skyrix-core/NGStreams/NGBufferedStream.m
new file mode 100644 (file)
index 0000000..ad05d64
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "common.h"
+#include "NGBufferedStream.h"
+
+#define NEWLINE_CHAR '\n'
+#define WRITE_WARN_SIZE (1024 * 1024 * 100) /* 100MB */
+
+@implementation NGBufferedStream
+
+static const unsigned DEFAULT_BUFFER_SIZE = 512;
+static Class DataStreamClass = Nil;
+
++ (void)initialize {
+  DataStreamClass = NSClassFromString(@"NGDataStream");
+}
+
+// returns the number of bytes which where read from the buffer
+#define numberOfConsumedReadBufferBytes(self) \
+  ((self->readBufferSize == 0) ? 0 : (self->readBufferPos - self->readBuffer))
+
+// returns the number of bytes which can be read from buffer (without source access)
+#define numberOfAvailableReadBufferBytes(self) \
+  (self->readBufferFillSize - numberOfConsumedReadBufferBytes(self))
+
+// look whether all bytes in the buffer where consumed, if so, reset the buffer
+#define checkReadBufferFillState(self) \
+  if (numberOfAvailableReadBufferBytes(self) == 0) { \
+    self->readBufferPos = self->readBuffer; \
+    self->readBufferFillSize = 0;  \
+  }
+
+// ******************** constructors ********************
+
++ (id)filterWithSource:(id<NGStream>)_source bufferSize:(unsigned)_size {
+  if (_source == nil) return nil;
+  if (*(Class *)_source == DataStreamClass) return _source;
+  return [[[self alloc] initWithSource:_source bufferSize:_size] autorelease];
+}
+
+// TODO: can we reduced duplicate code here ...
+
+- (id)initWithSource:(id<NGStream>)_source bufferSize:(unsigned)_size {
+  if (_source == nil) {
+    [self release];
+    return nil;
+  }
+  if (*(Class *)_source == DataStreamClass) {
+    [self release];
+    return [_source retain];
+  }
+
+  if ((self = [super initWithSource:_source])) {
+    self->readBuffer  = calloc(_size, 1);
+    self->writeBuffer = calloc(_size, 1);
+    
+    self->readBufferPos       = self->readBuffer;
+    self->readBufferSize      = _size;
+    self->readBufferFillSize  = 0; // no bytes are read from source
+    self->writeBufferFillSize = 0;
+    self->writeBufferSize     = _size;
+    self->flags._flushOnNewline = 1;
+  }
+  return self;
+}
+
+- (id)initWithInputSource:(id<NGInputStream>)_source bufferSize:(unsigned)_s {
+  if (_source == nil) {
+    [self release];
+    return nil;
+  }
+  if (*(Class *)_source == DataStreamClass) {
+    [self release];
+    return [_source retain];
+  }
+
+  if ((self = [super initWithInputSource:_source])) {
+    self->readBuffer            = calloc(_s, 1);
+    self->readBufferPos         = self->readBuffer;
+    self->readBufferSize        = _s;
+    self->readBufferFillSize    = 0; // no bytes are read from source
+    self->flags._flushOnNewline = 1;
+  }
+  return self;
+}
+- (id)initWithOutputSource:(id<NGOutputStream>)_src bufferSize:(unsigned)_s {
+  if (_src == nil) {
+    [self release];
+    return nil;
+  }
+  if (*(Class *)_src == DataStreamClass) {
+    [self release];
+    return [_src retain];
+  }
+
+  if ((self = [super initWithOutputSource:_src])) {
+    self->writeBuffer           = calloc(_s, 1);
+    self->writeBufferFillSize   = 0;
+    self->writeBufferSize       = _s;
+    self->flags._flushOnNewline = 1;
+  }
+  return self;
+}
+
+- (id)initWithSource:(id<NGStream>)_source {
+  return [self initWithSource:_source bufferSize:DEFAULT_BUFFER_SIZE];
+}
+- (id)initWithInputSource:(id<NGInputStream>)_source {
+  return [self initWithInputSource:_source bufferSize:DEFAULT_BUFFER_SIZE];
+}
+- (id)initWithOutputSource:(id<NGOutputStream>)_source {
+  return [self initWithOutputSource:_source bufferSize:DEFAULT_BUFFER_SIZE];
+}
+
+- (void)dealloc {
+  [self flush];
+  
+  if (self->readBuffer) {
+    free(self->readBuffer);
+    self->readBuffer    = NULL;
+    self->readBufferPos = NULL;
+  }
+  self->readBufferFillSize = 0;
+  self->readBufferSize     = 0;
+
+  if (self->writeBuffer) {
+    free(self->writeBuffer);
+    self->writeBuffer = NULL;
+  }
+  self->writeBufferFillSize = 0;
+  self->writeBufferSize     = 0;
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setReadBufferSize:(unsigned)_size {
+  [self flush];
+
+  if (_size == self->readBufferSize)
+    return;
+
+  if (_size == 0) {
+    if (self->readBuffer != NULL) {
+      free(self->readBuffer);
+      self->readBuffer = NULL;
+    }
+    self->readBufferSize = _size;
+    self->readBufferPos  = NULL;
+  }
+  else {
+    if (self->readBuffer != NULL)
+      self->readBuffer = realloc(self->readBuffer, _size);
+    else
+      self->readBuffer = calloc(_size, 1);
+    
+    self->readBufferSize     = _size;
+    self->readBufferPos      = self->readBuffer;
+    self->readBufferFillSize = 0; // no bytes a read from source
+  }
+}
+- (unsigned)readBufferSize {
+  return self->readBufferSize;
+}
+
+- (void)setWriteBufferSize:(unsigned)_size {
+  [self flush];
+
+  if (_size == self->writeBufferSize)
+    return;
+
+  self->writeBuffer = realloc(self->writeBuffer, _size);
+  self->writeBufferSize = _size;
+}
+- (unsigned)writeBufferSize {
+  return self->writeBufferSize;
+}
+
+/* blocking .. */
+
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode {
+  BOOL canRead, canWrite;
+
+  if (self->readBufferSize == 0)
+    canRead = NO;
+  else
+    canRead = (numberOfAvailableReadBufferBytes(self) > 0);
+  
+  canWrite = (self->writeBufferSize == 0)
+    ? NO
+    : (self->writeBufferFillSize > 0);
+  
+  if ((_mode == NGStreamMode_readWrite) && canRead && canWrite)
+    return NO;
+  if ((_mode == NGStreamMode_readOnly) && canRead) {
+    return NO;
+  }
+  if ((_mode == NGStreamMode_writeOnly) && canWrite)
+    return NO;
+
+  return ([self->source respondsToSelector:@selector(wouldBlockInMode:)])
+    ? [(id)self->source wouldBlockInMode:_mode]
+    : YES;
+}
+
+/* primitives */
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  register unsigned availBytes = numberOfAvailableReadBufferBytes(self);
+  
+  if (self->readBufferSize == 0) { // no read buffering is done (buffersize==0)
+    return (readBytes != NULL)
+      ? readBytes(source, _cmd, _buf, _len)
+      : [source readBytes:_buf count:_len];
+  }
+    
+  if (availBytes >= _len) {
+    // there are enough bytes in the buffer to fulfill the request
+    if (_len == 1) {
+      *(unsigned char *)_buf = *(unsigned char *)self->readBufferPos;
+      self->readBufferPos++;
+    }
+    else {
+      memcpy(_buf, self->readBufferPos, _len);
+      self->readBufferPos += _len; // update read position (consumed-size)
+    }
+    checkReadBufferFillState(self); // check whether all bytes where consumed
+    return _len;
+  }
+  else if (availBytes > 0) {
+    // there are some bytes in the buffer, these are returned
+    
+    memcpy(_buf, self->readBufferPos, availBytes);// copy all bytes from buffer
+    self->readBufferPos      = self->readBuffer;  // reset position
+    self->readBufferFillSize = 0;   // no bytes available in buffer anymore
+    return availBytes;
+  }
+  else if (_len > self->readBufferSize) {
+    /*
+      requested _len is bigger than the buffersize, so we can bypass the
+      buffer (which is empty, as guaranteed by the previous 'ifs'
+    */
+
+    NSAssert(self->readBufferPos == self->readBuffer,
+             @"read buffer position is not reset");
+    NSAssert(self->readBufferFillSize == 0, @"there are bytes in the buffer");
+
+    availBytes = (readBytes != NULL)
+      ? (unsigned)readBytes(source, _cmd, _buf, _len)
+      : [source readBytes:_buf count:_len];
+    
+    if (availBytes == NGStreamError)
+      return NGStreamError;
+    
+    NSAssert(availBytes != 0, @"readBytes:count: may never return zero !");
+
+    return availBytes; // return the number of bytes which could be read
+  }
+  else {
+    /*
+      no bytes are available and the requested _len is smaller than the 
+      possible buffer size, we have to read the next block of input from the 
+      source
+    */
+    
+    NSAssert(self->readBufferPos == self->readBuffer,
+             @"read buffer position is not reset");
+    NSAssert(self->readBufferFillSize == 0, @"there are bytes in the buffer");
+    
+    self->readBufferFillSize = (readBytes != NULL)
+      ? (unsigned)readBytes(source,_cmd, self->readBuffer,self->readBufferSize)
+      : [source readBytes:self->readBuffer count:self->readBufferSize];
+    
+    if (self->readBufferFillSize == NGStreamError) {
+      self->readBufferFillSize = 0;
+      return NGStreamError;
+    }
+    
+    NSAssert(self->readBufferFillSize != 0,
+             @"readBytes:count: may never return zero !");
+    
+    /* 
+       now comes a section which is roughly the same like the first to 
+       conditionals in this method
+    */
+    if (self->readBufferFillSize >= _len) {
+      // there are enough bytes in the buffer to fulfill the request
+    
+      memcpy(_buf, self->readBufferPos, _len);
+      self->readBufferPos += _len;    // update read position (consumed-size)
+      checkReadBufferFillState(self); // check whether all bytes where consumed
+      return _len;
+    }
+    else { // (readBufferFillSize > 0) (this is ensured by the above assert)
+      // there are some bytes in the buffer, these are returned
+
+      availBytes = self->readBufferFillSize;
+      // copy all bytes from buffer
+      memcpy(_buf, self->readBufferPos, self->readBufferFillSize);
+      self->readBufferPos      = self->readBuffer; // reset position
+      self->readBufferFillSize = 0; // no bytes available in buffer anymore
+      return availBytes;
+    }
+  }
+}
+
+- (int)readByte {
+  if (self->readBufferSize == 0) // no read buffering is done (buffersize==0)
+    return [super readByte];
+  
+  if (numberOfAvailableReadBufferBytes(self) >= 1) {
+    unsigned char byte = *(unsigned char *)self->readBufferPos;
+    self->readBufferPos++;
+    checkReadBufferFillState(self); // check whether all bytes where consumed    
+    return byte;
+  }
+  return [super readByte];
+}
+
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  register unsigned tmp       = 0;
+  register unsigned remaining = _len;
+  register void     *track    = (void *)_buf;
+
+#if DEBUG
+  if (_len > WRITE_WARN_SIZE) {
+    NSLog(@"WARNING(%s): got passed in length %uMB (%u bytes, errcode=%u) ...",
+          __PRETTY_FUNCTION__, (_len / 1024 / 1024), _len, NGStreamError);
+  }
+#endif
+  
+  while (remaining > 0) {
+    // how much bytes available in buffer ?
+    tmp = self->writeBufferSize - self->writeBufferFillSize; 
+    tmp = (tmp > remaining) ? remaining : tmp;
+    
+    memcpy((self->writeBuffer + self->writeBufferFillSize), track, tmp);
+    track += tmp;
+    remaining -= tmp;
+    self->writeBufferFillSize += tmp;
+    
+    if (self->writeBufferFillSize == self->writeBufferSize) {
+      BOOL ok;
+      
+      ok = [self->source safeWriteBytes:self->writeBuffer
+                         count:self->writeBufferFillSize];
+      if (!ok) return NGStreamError;
+      
+      self->writeBufferFillSize = 0;
+    }
+  }
+  
+  if (self->flags._flushOnNewline == 1) {
+    // scan buffer for newlines, if one is found, flush buffer
+    
+    for (tmp = 0; tmp < _len; tmp++) {
+      if (tmp == NEWLINE_CHAR) {
+        if (![self flush])
+          return NGStreamError;
+        break;
+      }
+    }
+  }
+  
+  /* clean up for GC */
+  tmp       = 0;    
+  track     = NULL; // clean up for GC
+  remaining = 0;
+  
+  return _len;
+}
+
+- (BOOL)close {
+  if (![self flush])
+    return NO;
+  
+  if (self->readBuffer) {
+    free(self->readBuffer);
+    self->readBuffer = NULL;
+    self->readBufferPos = NULL;
+  }
+  self->readBufferFillSize = 0;
+  self->readBufferSize = 0;
+  
+  if (self->writeBuffer) {
+    free(self->writeBuffer);
+    self->writeBuffer = NULL;
+  }
+  self->writeBufferFillSize = 0;
+  self->writeBufferSize = 0;
+  
+  return [super close];
+}
+
+- (BOOL)flush {
+  if (self->writeBufferFillSize > 0) {
+    BOOL ok;
+    
+#if DEBUG
+    if (self->writeBufferFillSize > WRITE_WARN_SIZE) {
+      NSLog(@"WARNING(%s): shall flush %uMB (%u bytes, errcode=%u) ...",
+            __PRETTY_FUNCTION__, (self->writeBufferFillSize/1024/1024),
+            self->writeBufferFillSize, NGStreamError);
+      //abort();
+    }
+#endif
+    
+    ok = [self->source
+              safeWriteBytes:self->writeBuffer
+              count:self->writeBufferFillSize];
+    if (!ok) {
+      /* should check exception for fill size ? ... */
+      return NO;
+    }
+    
+    self->writeBufferFillSize = 0;
+  }
+  return YES;
+}
+
+@end /* NGBufferedStream */
+
+@implementation NGStream(NGBufferedStreamExtensions)
+
+- (NGBufferedStream *)bufferedStream {
+  return [NGBufferedStream filterWithSource:self];
+}
+
+@end /* NGStream(NGBufferedStreamExtensions) */
+
+@implementation NGBufferedStream(NGBufferedStreamExtensions)
+
+- (NGBufferedStream *)bufferedStream {
+  return self;
+}
+
+@end /* NGBufferedStream(NGBufferedStreamExtensions) */
diff --git a/skyrix-core/NGStreams/NGByteBuffer.m b/skyrix-core/NGStreams/NGByteBuffer.m
new file mode 100644 (file)
index 0000000..bec356a
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGByteBuffer.h"
+#include "common.h"
+#include <sys/time.h>
+
+#if LIB_FOUNDATION_LIBRARY
+#  include <extensions/exceptions/GeneralExceptions.h>
+#endif
+
+typedef struct NGByteBufferLA {
+  unsigned char byte;
+  char          isEOF:1;
+  char          isFetched:1;
+} LA_NGByteBuffer;
+
+@implementation NGByteBuffer
+
+static BOOL  ProfileByteBuffer = NO;
+static Class DataStreamClass = Nil;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  ProfileByteBuffer = [ud boolForKey:@"ProfileByteBufferEnabled"];
+  DataStreamClass   = NSClassFromString(@"NGDataStream");
+}
+
++ (int)version {
+  return [super version] + 1;
+}
+
++ (id)byteBufferWithSource:(id<NGStream>)_source la:(unsigned)_la {
+  if (_source            == nil)            return nil;
+  if (*(Class *)_source == DataStreamClass) return _source;
+  return [[[self alloc] initWithSource:_source la:_la] autorelease];
+}
+
+- (id)initWithSource:(id<NGStream>)_source la:(unsigned)_la {
+  if (_source == nil) {
+    [self release];
+    return nil;
+  }
+  if (*(Class *)_source == DataStreamClass) {
+    [self release];
+    return [_source retain];
+  }
+  if ((self = [super initWithSource:_source])) {
+    unsigned size = 0;
+    
+    if (_la < 1) {
+#if LIB_FOUNDATION_LIBRARY
+      [[[RangeException alloc]
+                        initWithReason:@"lookahead depth is less than one"
+                        size:1 index:_la]
+                        raise];
+#else
+      [NSException raise:NSRangeException
+                   format:@"lookahead depth is less than one (%d)", _la];
+#endif
+    }
+
+    // Find first power of 2 >= to requested size
+    for (size = 2; size < _la; size *=2);
+    
+    self->la = malloc(sizeof(LA_NGByteBuffer) * size + 4);
+    memset(self->la, 0, sizeof(LA_NGByteBuffer) * size);
+
+    self->bufLen      = size;
+    self->sizeLessOne = self->bufLen - 1;
+    self->headIdx     = 0;
+    self->wasEOF      = NO;
+    if ([self->source respondsToSelector:@selector(methodForSelector:)]) {
+      self->readByte = (int(*)(id, SEL))
+        [(NSObject *)self->source methodForSelector:@selector(readByte)];
+    }
+    if ([self respondsToSelector:@selector(methodForSelector:)]) {
+      self->laFunction = (int(*)(id, SEL, unsigned))
+        [(NSObject *)self methodForSelector:@selector(la:)];
+    }
+  }
+  return self;
+}
+
+- (id)init {
+  [self release];
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (id)initWithSource:(id<NGStream>)_source {
+  [self release];
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (id)initWithInputSource:(id<NGInputStream>)_source {
+  [self release];
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (id)initWithOutputSource:(id<NGOutputStream>)_source {
+  [self release];
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (void)dealloc {
+  if (self->la) free(self->la);
+  [super dealloc];
+}
+
+/* operations */
+
+- (int)readByte {
+  int byte = (self->laFunction == NULL)
+    ? [self la:0]
+    : self->laFunction(self, @selector(la:), 0);
+  [self consume];
+  return byte;
+}
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  if (_len == 0)
+    return 0;
+
+  if (!(self->la[(self->headIdx & self->sizeLessOne)].isFetched)) {
+    int byte = [self readByte];
+
+    if (byte == -1)
+      [NGEndOfStreamException raiseWithStream:self->source];
+
+    ((char *)_buf)[0] = byte;
+    return 1;
+  }
+  else {
+    unsigned      cnt    = 0;
+    int           idxCnt = self->headIdx & sizeLessOne;
+    unsigned char buffer[self->bufLen];
+    
+    while (self->la[idxCnt].isFetched && cnt < _len && cnt < bufLen) {
+      buffer[cnt] = self->la[idxCnt].byte;
+      cnt++;
+      idxCnt = (cnt + self->headIdx) & sizeLessOne;
+    }
+    memcpy(_buf, buffer, cnt);
+    [self consume:cnt];
+    return cnt;
+  }
+  return 0;
+}
+
+- (int)la:(unsigned)_la {
+  // TODO: huge method, should be split up
+  volatile unsigned result, idx;
+  unsigned i = 0;
+  
+  result = -1;
+  *(&idx) = (_la + self->headIdx) & self->sizeLessOne;
+  
+  if (_la > self->sizeLessOne) {
+#if LIB_FOUNDATION_LIBRARY
+    [[[RangeException alloc]
+                      initWithReason:@"tried to look ahead too far"
+                      size:self->bufLen
+                      index:_la]
+                      raise];
+#else
+    [NSException raise:NSRangeException
+                 format:@"tried to look ahead too far (la=%d, max=%d)", 
+                  _la, self->bufLen];
+#endif
+  }
+  
+  if (self->wasEOF) {
+    result = (!self->la[idx].isFetched || self->la[idx].isEOF)
+      ? -1 : self->la[idx].byte;
+    return result;
+  }
+  
+  if (self->la[idx].isFetched) {
+    result = (self->la[idx].isEOF) ? -1 : self->la[idx].byte;
+    return result;
+  }
+
+  *(&i) = 0;
+  for (i = 0;
+       i < _la &&
+         self->la[(self->headIdx + i) & self->sizeLessOne].isFetched;
+       i++);
+  
+  /* 
+     If we should read more than 5 bytes, we take the time costs of an
+     exception handler 
+  */
+  if ((_la - i + 1) <= 5) {
+    while (i <= _la) {
+#if DEBUG
+      struct timeval tv;
+      double         ti = 0.0;
+#endif
+          
+      int byte = 0;
+
+#if DEBUG
+      if (ProfileByteBuffer) {
+        gettimeofday(&tv, NULL);
+        ti =  (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0);
+      }
+#endif
+      byte = (self->readByte == NULL)
+        ? [self->source readByte]
+        : (int)self->readByte(self->source, @selector(readByte));
+
+#if DEBUG
+      if (ProfileByteBuffer) {
+        gettimeofday(&tv, NULL);
+        ti = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0) - ti;
+        if (ti > 0.01) {
+          fprintf(stderr, "[%s] <read bytes from stream> : time "
+                  "needed: %4.4fs\n",
+                  __PRETTY_FUNCTION__, ti < 0.0 ? -1.0 : ti);
+        }
+      }
+#endif
+    
+      if (byte == -1) {  // EOF was reached
+        self->wasEOF = YES;
+        break;
+      }
+      else {
+        int ix = (self->headIdx + i) & self->sizeLessOne;
+        self->la[ix].byte      = byte;
+        self->la[ix].isFetched = 1;
+      }
+      i++;
+    }
+  }
+  else {
+    BOOL readStream = YES;
+    NSException *exc = nil;
+    
+    while (readStream) {
+      int  cntReadBytes  = 0;
+      int  cnt           = 0;
+      int  desiredBytes  = _la - i+1;
+      char *tmpBuffer;
+
+      // TODO: check whether malloc is used for sufficiently large blocks!
+      tmpBuffer = malloc(desiredBytes + 2);
+
+      cntReadBytes = (self->readBytes == NULL)
+        ? [self->source readBytes:tmpBuffer count:desiredBytes]
+        : self->readBytes(self->source, @selector(readBytes:count:),
+                          tmpBuffer, desiredBytes);
+          
+      if (cntReadBytes == NGStreamError) {
+        exc = [[self->source lastException] retain];
+        break;
+      }
+      else {
+        if (cntReadBytes == desiredBytes)
+          readStream = NO;
+
+        cnt = 0;
+        while (cntReadBytes > 0) {
+          int ix = (self->headIdx + i) & self->sizeLessOne;
+          self->la[ix].byte      = tmpBuffer[cnt];
+          self->la[ix].isFetched = 1;
+          i++;
+          cnt++;
+          cntReadBytes--;
+        }
+      }
+          
+      if (tmpBuffer) free(tmpBuffer);
+    }
+    if (exc) {
+      if (![exc isKindOfClass:[NGEndOfStreamException class]]) {
+        [self setLastException:exc];
+        return NGStreamError;
+      }
+      self->wasEOF = YES;
+    }
+  }
+  
+  if (self->wasEOF) {
+    while (i <= _la) {
+      self->la[(self->headIdx + i) & self->sizeLessOne].isEOF = YES;
+      i++;
+    }
+  }
+  
+  result = (self->la[idx].isEOF) ? -1 : self->la[idx].byte;
+  return result;
+}
+
+- (void)consume {
+  int idx = self->headIdx & sizeLessOne;
+  
+  if (!(self->la[idx].isFetched)) {
+    (self->laFunction == NULL)
+      ? [self la:0]
+      : self->laFunction(self, @selector(la:), 0);
+  }
+  self->la[idx].isFetched = 0;
+  self->headIdx++;
+}
+
+- (void)consume:(unsigned)_cnt {
+  while (_cnt > 0) {
+    int idx = self->headIdx & sizeLessOne;
+    
+    if (!(self->la[idx].isFetched))
+      (self->laFunction == NULL)
+        ? [self la:0]
+        : self->laFunction(self, @selector(la:), 0);
+
+    self->la[idx].isFetched = 0;
+    self->headIdx++;
+    _cnt--;
+  }
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:128];
+
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->source) [ms appendFormat:@" source=%@", self->source];
+  [ms appendFormat:@" mode=%@", [self modeDescription]];
+  [ms appendFormat:@" la=%d", self->bufLen];
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* NGByteBuffer */
diff --git a/skyrix-core/NGStreams/NGByteCountStream.m b/skyrix-core/NGStreams/NGByteCountStream.m
new file mode 100644 (file)
index 0000000..23df212
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGByteCountStream.h"
+
+@implementation NGByteCountStream
+
++ (id)byteCounterForStream:(id<NGStream>)_stream byte:(unsigned char)_byte {
+  return [[[self alloc] initWithSource:_stream byte:_byte] autorelease];
+}
+
+- (id)initWithSource:(id<NGStream>)_source byte:(unsigned char)_byte {
+  if ((self = [super initWithSource:_source])) {
+    [self setByteToCount:_byte];
+  }
+  return self;
+}
+- (id)initWithSource:(id<NGStream>)_source {
+  return [self initWithSource:_source byte:'\n'];
+}
+
+// accessors
+
+- (void)setByteToCount:(unsigned char)_byte {
+  if (_byte != byteToCount) {
+    byteReadCount  = 0;
+    byteWriteCount = 0;
+    byteToCount    = _byte;
+  }
+}
+- (unsigned char)byteToCount {
+  return byteToCount;
+}
+
+- (unsigned)readCount {
+  return byteReadCount;
+}
+- (unsigned)writeCount {
+  return byteWriteCount;
+}
+
+- (unsigned)totalReadCount {
+  return totalReadCount;
+}
+- (unsigned)totalWriteCount {
+  return totalWriteCount;
+}
+
+// operations
+
+- (void)resetCounters {
+  totalReadCount  = 0;
+  totalWriteCount = 0;
+  byteReadCount   = 0;
+  byteWriteCount  = 0;
+}
+
+// primitives
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  unsigned result;
+
+  result = (readBytes != NULL)
+    ? readBytes(source, _cmd, _buf, _len)
+    : [source readBytes:_buf count:_len];
+
+  totalReadCount += result;
+  {
+    register unsigned char *byteBuffer = _buf;
+
+    for (_len = result - 1; _len >= 0; _len--, byteBuffer++) {
+      if (*byteBuffer == byteToCount)
+        byteReadCount++;
+    }
+  }
+  return result;
+}
+
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  unsigned result;
+
+  result = (writeBytes != NULL)
+    ? writeBytes(source, _cmd, _buf, _len)
+    : [source writeBytes:_buf count:_len];
+
+  totalWriteCount += result;
+  {
+    register unsigned char *byteBuffer = (unsigned char *)_buf;
+
+    for (_len = result - 1; _len >= 0; _len--, byteBuffer++) {
+      if (*byteBuffer == byteToCount)
+        byteWriteCount++;
+    }
+  }
+  return result;
+}
+
+@end
diff --git a/skyrix-core/NGStreams/NGCTextStream.m b/skyrix-core/NGStreams/NGCTextStream.m
new file mode 100644 (file)
index 0000000..6afe8fb
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGExtensions/NGCharBuffers.h>
+#include "common.h"
+#include "NGCTextStream.h"
+#include "NGStreamExceptions.h"
+#include "NGFileStream.h"
+
+static NSString *NGNewLineString = @"\n";
+
+@interface _NGCTextStreamLineEnumerator : NSEnumerator
+{
+  NGCTextStream *stream;
+}
+- (id)initWithTextStream:(NGCTextStream *)_stream;
+- (id)nextObject;
+@end
+
+NGStreams_DECLARE id<NGExtendedTextInputStream>  NGTextIn  = nil;
+NGStreams_DECLARE id<NGExtendedTextOutputStream> NGTextOut = nil;
+NGStreams_DECLARE id<NGExtendedTextOutputStream> NGTextErr = nil;
+
+@implementation NGCTextStream
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
+
+// stdio
+
+NGStreams_DECLARE void NGInitTextStdio(void) {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+    
+    NGInitStdio();
+    
+    NGTextIn  = [(NGCTextStream *)[NGCTextStream alloc]
+                    initWithSource:(id<NGStream>)NGIn];
+    NGTextOut = [(NGCTextStream *)[NGCTextStream alloc]
+                    initWithSource:(id<NGStream>)NGOut];
+    NGTextErr = [(NGCTextStream *)[NGCTextStream alloc]
+                    initWithSource:(id<NGStream>)NGErr];
+  }
+}
+
++ (void)_flushForExit:(NSNotification *)_notification {
+  [NGTextIn  flush]; [NGTextIn  release]; NGTextIn  = nil;
+  [NGTextOut flush]; [NGTextOut release]; NGTextOut = nil;
+  [NGTextErr flush]; [NGTextErr release]; NGTextErr = nil;
+}
+
+static void _flushAtExit(void) {
+  [NGTextIn  flush]; [NGTextIn  release]; NGTextIn  = nil;
+  [NGTextOut flush]; [NGTextOut release]; NGTextOut = nil;
+  [NGTextErr flush]; [NGTextErr release]; NGTextErr = nil;
+}
+
++ (void)initialize {
+  BOOL isInitialized = NO;
+  if (!isInitialized) {
+    NSAssert2([super version] == 2,
+              @"invalid superclass (%@) version %i !",
+              NSStringFromClass([self superclass]), [super version]);
+    isInitialized = YES;
+
+    atexit(_flushAtExit);
+  }
+}
+
+// system text stream
+
++ (id)textStreamWithInputSource:(id<NGInputStream>)_s {
+  if (_s == nil) return nil;
+  return [[(NGCTextStream *)[self alloc] initWithInputSource:_s] autorelease];
+}
++ (id)textStreamWithOutputSource:(id<NGOutputStream>)_s {
+  if (_s == nil) return nil;
+  return [[(NGCTextStream *)[self alloc] initWithOutputSource:_s] autorelease];
+}
++ (id)textStreamWithSource:(id<NGStream>)_stream {
+  if (_stream == nil) return nil;
+  return [[(NGCTextStream *)[self alloc] initWithSource:_stream] autorelease];
+}
+
+- (id)initWithSource:(id<NGStream>)_stream {
+  if (_stream == nil) {
+    [self release];
+    return nil;
+  }
+  if ((self = [super init])) {
+    self->source = [_stream retain];
+
+#ifdef __APPLE__
+    //#  warning no selector caching on MacOSX ...
+#else
+    /* check whether we are dealing with a proxy .. */
+    if ([source isKindOfClass:[NSObject class]]) {
+      self->readBytes   = (NGIOReadMethodType)
+        [(NSObject *)source methodForSelector:@selector(readBytes:count:)];
+      self->writeBytes  = (NGIOWriteMethodType)
+        [(NSObject *)source methodForSelector:@selector(writeBytes:count:)];
+      self->flushBuffer = (BOOL (*)(id,SEL))
+        [(NSObject *)source methodForSelector:@selector(flush)];
+    }
+#endif
+  }
+  return self;
+}
+- (id)initWithInputSource:(id<NGInputStream>)_source {
+  return [self initWithSource:(id)_source];
+}
+- (id)initWithOutputSource:(id<NGOutputStream>)_source {
+  return [self initWithSource:(id)_source];
+}
+
+- (void)dealloc {
+  [self->source release];
+  self->readBytes   = NULL;
+  self->writeBytes  = NULL;
+  self->flushBuffer = NULL;
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id<NGStream>)source {
+  return self->source;
+}
+- (int)fileDescriptor {
+  return [(id)[self source] fileDescriptor];
+}
+
+- (BOOL)isOpen {
+  return [(id)[self source] isOpen];
+}
+
+/* operations */
+
+- (BOOL)close {
+  return [self->source close];
+}
+
+/* NGTextInputStream */
+
+- (unichar)readCharacter {
+  return [self readChar];
+}
+
+- (unsigned char)readChar {
+  unsigned char c;
+  unsigned res;
+  
+  if (readBytes) {
+    res = readBytes(self->source, @selector(readBytes:count:),
+                    &c, sizeof(unsigned char));
+  }
+  else
+    res = [self->source readBytes:&c count:sizeof(unsigned char)];
+  
+  if (res == NGStreamError) {
+    [self setLastException:[self->source lastException]];
+    return -1;
+  }
+  
+  return c;
+}
+
+/* TODO: fix exception handling */
+
+- (NSString *)readLineAsString {
+  NGCharBuffer8   buffer = NULL;
+  unsigned char   c;
+
+  *(&buffer) = NGCharBuffer8_new(128);
+
+  NS_DURING {
+    unsigned int res;
+    
+    if (readBytes) {
+      do {
+        res = self->readBytes(source, @selector(readBytes:count:),
+                        &c, sizeof(unsigned char));
+        if (res != 1) [[self->source lastException] raise];
+        
+        if (c == '\r') {
+          res = readBytes(source, @selector(readBytes:count:),
+                          &c, sizeof(unsigned char));
+          if (res != 1) [[self->source lastException] raise];
+        }
+        
+        if ((c != '\n') && (c != 0)) {
+          NSAssert1(c != 0, @"tried to add '0' character to buffer '%s' ..",
+                    buffer->buffer);
+          NGCharBuffer8_addChar(buffer, c);
+        }
+      }
+      while ((c != '\n') && (c != 0));
+    }
+    else {
+      do {
+        res = [self->source readBytes:&c count:sizeof(unsigned char)];
+       /* TODO: raises exception */
+        if (res != 1) [[self->source lastException] raise];
+        if (c == '\r') {
+          res = [self->source readBytes:&c count:sizeof(unsigned char)];
+          if (res != 1) [[self->source lastException] raise];
+        }
+        
+        if ((c != '\n') && (c != 0))
+          NGCharBuffer8_addChar(buffer, c);
+      }
+      while ((c != '\n') && (c != 0));
+    }
+  }
+  NS_HANDLER {
+    if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
+      if (buffer->length == 0) {
+        NGCharBuffer8_dealloc(buffer);
+        buffer = NULL;
+      }
+    }
+    else
+      [localException raise];
+  }
+  NS_ENDHANDLER;
+  
+  return buffer ? NGCharBuffer8_makeStringAndDealloc(buffer) : nil;
+}
+
+- (NSEnumerator *)lineEnumerator {
+  return [[[_NGCTextStreamLineEnumerator alloc]
+                                         initWithTextStream:self]
+                                         autorelease];
+}
+
+// NGTextOutputStream
+
+- (BOOL)writeCharacter:(unichar)_character {
+  unsigned char c;
+  unsigned res;
+  
+  if (_character > ((sizeof(unsigned char) * 256) - 1)) {
+    // character is not in range of maximum system encoding
+    [NSException raise:@"NGCTextStreamEncodingException"
+                 format:
+                   @"called writeCharacter: with character code (0x%X) exceeding"
+                   @" the maximum system character code (0x%X)",
+                   _character, ((sizeof(unsigned char) * 256) - 1)];
+  }
+
+  c = _character;
+
+  if (writeBytes) {
+    res = writeBytes(self->source, @selector(writeBytes:count:),
+                     &c, sizeof(unsigned char));
+  }
+  else
+    res = [self->source writeBytes:&c count:sizeof(unsigned char)];
+
+  if (res == NGStreamError) {
+    [self setLastException:[self->source lastException]];
+    return NO;
+  }
+  
+  return YES;
+}
+
+- (BOOL)writeString:(NSString *)_string {
+  unsigned char *str, *buf;
+  unsigned toGo;
+  
+  if ((toGo = [_string cStringLength]) == 0)
+    return YES;
+  
+  buf = str = calloc(toGo + 1, sizeof(unsigned char));
+  [_string getCString:str]; str[toGo] = '\0';
+  
+  NS_DURING {
+    while (toGo > 0) {
+      unsigned writeCount;
+      
+      writeCount = writeBytes
+        ? writeBytes(source, @selector(writeBytes:count:), str, toGo)
+        : [source writeBytes:str count:toGo];
+      
+      if (writeCount == NGStreamError)
+        [[self->source lastException] raise];
+      
+      toGo -= writeCount;
+      str  += writeCount;
+    }
+  }
+  NS_HANDLER {
+    if (buf) { free(buf); buf = NULL; };
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+  
+  if (buf) { free(buf); buf = NULL; }
+  return YES;
+}
+
+- (BOOL)flush {
+  if (flushBuffer)
+    return flushBuffer(self->source, @selector(flush));
+  else
+    return [self->source flush];
+}
+
+- (BOOL)writeNewline {
+  if (![self writeString:NGNewLineString]) return NO;
+  if (![self flush]) return NO;
+  return YES;
+}
+
+@end /* NGCTextStream */
+
+@implementation _NGCTextStreamLineEnumerator
+
+- (id)initWithTextStream:(NGCTextStream *)_stream {
+  self->stream = [_stream retain];
+  return self;
+}
+
+- (void)dealloc {
+  [self->stream release];
+  [super dealloc];
+}
+
+- (id)nextObject {
+  id result;
+
+  *(&result) = nil;
+  
+  NS_DURING {
+    result = [self->stream readLineAsString];
+  }
+  NS_HANDLER {
+    if ([localException isKindOfClass:[NGEndOfStreamException class]])
+      result = nil;
+    else
+      [localException raise];
+  }
+  NS_ENDHANDLER;
+  
+  return result;
+}
+
+@end /* _NGCTextStreamLineEnumerator */
diff --git a/skyrix-core/NGStreams/NGCharBuffer.m b/skyrix-core/NGStreams/NGCharBuffer.m
new file mode 100644 (file)
index 0000000..6db0023
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGCharBuffer.h"
+#include "common.h"
+
+#if LIB_FOUNDATION_LIBRARY
+#  include <extensions/exceptions/GeneralExceptions.h>
+#endif
+
+typedef struct NGCharBufferLA {
+  unichar character;
+  char    isEOF:1;
+  char    isFetched:1;
+} LA_NGCharBuffer;
+
+@implementation NGCharBuffer
+
++ (id)charBufferWithSource:(id<NGTextStream>)_source la:(int)_la {
+  return [[[self alloc] initWithSource:_source la:_la] autorelease];
+}
+
+- (id)initWithSource:(id<NGTextStream>)_source la:(int)_la {
+  if ((self = [super initWithSource:_source])) {
+    int size = 0;
+
+    if (_la < 1) {
+#if LIB_FOUNDATION_LIBRARY
+      [[[RangeException alloc]
+                        initWithReason:@"LA is less than one"
+                        size:1 index:_la]
+                        raise];
+#else
+      [NSException raise:NSRangeException
+                   format:@"lookahead depth is less than one (%d)", _la];
+#endif
+    }
+
+    // Find first power of 2 >= to requested size
+    for (size = 2; size < _la; size *=2);
+    
+#if NeXT_Foundation_LIBRARY
+    self->la = NSZoneMalloc([self zone], sizeof(LA_NGCharBuffer) * size);
+#else
+    self->la = NSZoneMallocAtomic([self zone],
+                                  sizeof(LA_NGCharBuffer) * size);
+#endif
+    memset(self->la, 0, sizeof(LA_NGCharBuffer) * size);
+
+    self->bufLen      = size;
+    self->sizeLessOne = self->bufLen - 1;
+    self->headIdx     = 0;
+    self->wasEOF      = NO;
+
+    if ([self->source respondsToSelector:@selector(methodForSelector:)]) {
+      self->readCharacter =
+        [(NSObject *)self->source methodForSelector:@selector(readCharacter)];
+    }
+  }
+  return self;
+}
+
+- (id)initWithSource:(id<NGTextStream>)_source {
+  [self release];
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (id)init {
+  [self release];
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  NSZoneFree([self zone], self->la);
+  self->readCharacter = NULL;
+  [super dealloc];
+}
+#endif
+
+- (unichar)readCharacter {
+  int character = [self la:0];
+  if (character < 1)
+      [[[NGEndOfStreamException alloc] init] raise];
+  [self consume];
+  return character;
+}
+
+// LA
+
+- (int)la:(int)_la {
+  int result = -1;
+  int idx    = (_la + self->headIdx) & self->sizeLessOne;
+
+  idx = *(&idx);
+  
+  if (_la > self->sizeLessOne) {
+#if LIB_FOUNDATION_LIBRARY
+    [[[RangeException alloc]
+                      initWithReason:@"LA out of bounds"
+                      size:self->bufLen
+                      index:_la]
+                      raise];
+#else
+    [NSException raise:NSRangeException
+                 format:@"tried to look ahead too far (la=%d, max=%d)", 
+                  _la, self->bufLen];
+#endif
+  }
+  
+  if (self->wasEOF) {
+    result = (!self->la[idx].isFetched || self->la[idx].isEOF)
+      ? -1
+      : self->la[idx].character;
+  }
+  else {
+    if (!self->la[idx].isFetched) {
+      int i;
+
+      *(&i) = 0;
+      while ((i < _la) &&
+             (self->la[(self->headIdx + i) & self->sizeLessOne].isFetched))
+        i++;
+
+      NS_DURING {
+        while (i <= _la) {
+          int     ix        = 0;
+          unichar character = 0;
+
+          if (self->readCharacter == NULL) 
+            character = [self->source readCharacter];
+          else
+            character = (int)self->readCharacter(self->source,
+                                                 @selector(readCharacter));
+          ix = (self->headIdx + i) & self->sizeLessOne;      
+          self->la[ix].character = character;
+          self->la[ix].isFetched = 1;
+          i++;
+        }
+      }
+      NS_HANDLER {
+        if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
+          while (i <= _la) {
+            self->la[(self->headIdx + i) & self->sizeLessOne].isEOF = YES;
+            i++;
+            self->wasEOF = YES;        
+          }
+        }
+        else {
+          [localException raise];
+        }
+      }
+      NS_ENDHANDLER;
+    }
+    result = (self->la[idx].isEOF) ? -1 : self->la[idx].character;
+  }
+  return result;
+}
+
+- (void)consume {
+  int idx = self->headIdx & sizeLessOne;
+  
+  if (!(self->la[idx].isFetched))
+    [self la:0];
+
+  self->la[idx].isFetched = 0;
+  self->headIdx++;
+}
+
+- (void)consume:(int)_cnt {
+  while (_cnt > 0) {
+    int idx = self->headIdx & sizeLessOne;
+    
+    if (!(self->la[idx].isFetched))
+      [self la:0];
+
+    self->la[idx].isFetched = 0;
+    self->headIdx++;
+    _cnt--;
+  }
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X] source=%@ la=%d",
+                     NSStringFromClass([self class]),
+                     (unsigned)self,
+                     self->source,
+                     self->bufLen
+                   ];
+}
+
+@end
diff --git a/skyrix-core/NGStreams/NGConcreteStreamFileHandle.m b/skyrix-core/NGStreams/NGConcreteStreamFileHandle.m
new file mode 100644 (file)
index 0000000..90430f0
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <objc/objc-api.h>
+#include "common.h"
+#include "NGConcreteStreamFileHandle.h"
+#include "NGStreamProtocols.h"
+#include "NGStreamExceptions.h"
+#include "NGBufferedStream.h"
+
+@interface NGStream(FileHandleReset)
+
+- (void)resetFileHandle;
+
+@end
+
+@implementation NGConcreteStreamFileHandle
+
+- (id)initWithStream:(id<NGStream>)_stream {
+  if ((self = [super init])) {
+    self->stream = [_stream retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if ([stream respondsToSelector:@selector(resetFileHandle)])
+    [(NGStream *)self->stream resetFileHandle];
+  [self->stream release];
+  [super dealloc];
+}
+
+// accessors
+
+- (id<NGStream>)stream {
+  return self->stream;
+}
+
+/* NSFileHandle operations */
+
+- (void)closeFile {
+  [self->stream close];
+}
+
+- (int)fileDescriptor {
+  if ([self->stream respondsToSelector:@selector(fileDescriptor)])
+    return [(id)self->stream fileDescriptor];
+  else {
+    [self subclassResponsibility:_cmd];
+    return -1;
+  }
+}
+
+/* buffering */
+
+- (void)synchronizeFile {
+  [self->stream flush];
+}
+
+/* reading */
+
+- (NSData *)readDataOfLength:(unsigned int)_length {
+  char   *buffer;
+  NSData *data;
+
+  *(&buffer) = NGMallocAtomic(_length);
+  *(&data)   = nil;
+  
+  NS_DURING {
+    [stream safeReadBytes:buffer count:_length];
+    data = [[NSData alloc] initWithBytes:buffer length:_length];
+  }
+  NS_HANDLER {
+    if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
+      data = [(NGEndOfStreamException *)localException readBytes];
+
+      data = data ? [data retain] : [[NSData alloc] init];
+    }
+    else {
+      if (buffer) {
+        NGFree(buffer);
+        buffer = NULL;
+      }
+      [localException raise];
+    }
+  }
+  NS_ENDHANDLER;
+  
+  if (buffer) {
+    NGFree(buffer);
+    buffer = NULL;
+  }
+
+  return [data autorelease];
+}
+
+- (NSData *)readDataToEndOfFile {
+  NGBufferedStream *bs;
+  NSMutableData    *data;
+  char buf[2048];
+
+  *(&data) = [NSMutableData dataWithCapacity:2048];
+  *(&bs) = [self->stream isKindOfClass:[NGBufferedStream class]]
+    ? [self->stream retain]
+    : [(NGBufferedStream *)[NGBufferedStream alloc] 
+          initWithSource:self->stream];
+
+  NS_DURING {
+    while (1 == 1) {
+      unsigned got = [bs readBytes:buf count:2048];
+      [data appendBytes:buf length:got];
+    }
+  }
+  NS_HANDLER {
+    if (![localException isKindOfClass:[NGEndOfStreamException class]]) {
+      [bs release];
+      bs = nil;
+      [localException raise];
+    }
+  }
+  NS_ENDHANDLER;
+  [bs release]; bs = nil;
+
+  return data;
+}
+
+- (NSData *)availableData {
+  NSLog(@"NGConcreteStreamFileHandle(availableData) not implemented");
+  [self notImplemented:_cmd];
+  return nil;
+}
+
+/* writing */
+
+- (void)writeData:(NSData *)_data {
+  [self->stream safeWriteBytes:[_data bytes] count:[_data length]];
+}
+
+/* seeking */
+
+- (unsigned long long)seekToEndOfFile {
+  NSLog(@"NGConcreteStreamFileHandle(seekToEndOfFile) not implemented");
+  [self notImplemented:_cmd];
+  return 0;
+}
+- (void)seekToFileOffset:(unsigned long long)_offset {
+  [(id<NGPositionableStream>)stream moveToLocation:_offset];
+}
+
+- (unsigned long long)offsetInFile {
+  NSLog(@"_NGConcreteFileStreamFileHandle(offsetInFile:) not implemented, abort");
+  [self notImplemented:_cmd];
+  return 0;
+}
+
+/* asynchronous operations */
+
+- (void)acceptConnectionInBackgroundAndNotify {
+  NSLog(@"NGConcreteStreamFileHandle(acceptConnectionInBackgroundAndNotify) "
+        @"not implemented");
+  [self notImplemented:_cmd];
+}
+- (void)acceptConnectionInBackgroundAndNotifyForModes:(NSArray *)_modes {
+  NSLog(@"NGConcreteStreamFileHandle(acceptConnectionInBackgroundAndNotifyForModes:) "
+        @"not implemented");
+  [self notImplemented:_cmd];
+}
+
+- (void)readInBackgroundAndNotify {
+  NSLog(@"NGConcreteStreamFileHandle(readInBackgroundAndNotify) not implemented");
+  [self notImplemented:_cmd];
+}
+- (void)readInBackgroundAndNotifyForModes:(NSArray *)_modes {
+  NSLog(@"NGConcreteStreamFileHandle(readInBackgroundAndNotifyForModes:) "
+        @"not implemented");
+  [self notImplemented:_cmd];
+}
+- (void)readToEndOfFileInBackgroundAndNotify {
+  NSLog(@"NGConcreteStreamFileHandle(readToEndOfFileInBackgroundAndNotify)"
+        @"not implemented");
+  [self notImplemented:_cmd];
+}
+- (void)readToEndOfFileInBackgroundAndNotifyForModes:(NSArray *)_modes {
+  NSLog(@"NGConcreteStreamFileHandle("
+        @"readToEndOfFileInBackgroundAndNotifyForModes:)"
+        @"not implemented");
+  [self notImplemented:_cmd];
+}
+
+- (void)waitForDataInBackgroundAndNotify {
+  NSLog(@"NGConcreteStreamFileHandle("
+        @"waitForDataInBackgroundAndNotify)"
+        @"not implemented");
+  [self notImplemented:_cmd];
+}
+- (void)waitForDataInBackgroundAndNotifyForModes:(NSArray *)_modes {
+  NSLog(@"NGConcreteStreamFileHandle("
+        @"waitForDataInBackgroundAndNotifyForModes:)"
+        @"not implemented");
+  [self notImplemented:_cmd];
+}
+
+@end /* NGConcreteStreamFileHandle */
diff --git a/skyrix-core/NGStreams/NGDataStream.m b/skyrix-core/NGStreams/NGDataStream.m
new file mode 100644 (file)
index 0000000..6b6032e
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGDataStream.h"
+#include "NGStreamExceptions.h"
+#include "common.h"
+
+// TODO: cache -bytes and -length of NSData for immutable data!
+
+@implementation NGDataStream
+
++ (int)version {
+  return [super version] + 2;
+}
+
++ (id)dataStream {
+  return [self streamWithData:[NSMutableData dataWithCapacity:1024]];
+}
++ (id)dataStreamWithCapacity:(int)_capacity {
+  return [self streamWithData:[NSMutableData dataWithCapacity:_capacity]];
+}
+
++ (id)streamWithData:(NSData *)_data {
+  return [[[self alloc] initWithData:_data] autorelease];
+}
+- (id)initWithData:(NSData *)_data mode:(NGStreamMode)_mode {
+  if ((self = [super init])) {
+    self->data     = [_data retain];
+    self->position = 0;
+
+    if ([self->data respondsToSelector:@selector(methodForSelector:)] == YES) {
+      self->dataLength = (unsigned int(*)(id, SEL))
+                         [self->data methodForSelector:@selector(length)];
+      self->dataBytes  = (const void*(*)(id, SEL))
+                         [self->data methodForSelector:@selector(bytes)];
+    }
+    else {
+      self->dataLength = NULL;
+      self->dataBytes  = NULL;
+    }
+    
+    self->streamMode = _mode;
+
+    /* for read-only streams */
+    if (self->streamMode == NGStreamMode_readOnly) {
+      self->bytes  = [self->data bytes];
+      self->length = [self->data length];
+    }
+  }
+  return self;
+}
+- (id)initWithData:(NSData *)_data {
+  NGStreamMode smode;
+  
+  smode = [data isKindOfClass:[NSMutableData class]]
+    ? NGStreamMode_readWrite
+    : NGStreamMode_readOnly;
+  return [self initWithData:_data mode:smode];
+}
+
+- (void)dealloc {
+  [self->data          release];
+  [self->lastException release];
+  [super dealloc];
+}
+
+/* accessors */
+
+/* NGTextInputStream */
+
+- (NSException *)lastException {
+  return self->lastException;
+}
+- (void)setLastException:(NSException *)_exception {
+  ASSIGN(self->lastException, _exception);
+}
+- (void)resetLastException {
+  [self->lastException release];
+  self->lastException = nil;
+}
+
+- (NSData *)data {
+  return self->data;
+}
+
+- (unsigned)availableBytes {
+  // returns number of available bytes
+  register unsigned currentLength = 0;
+  
+  if (self->bytes == NULL) {
+    currentLength = (self->dataLength == NULL)
+      ? [self->data length]
+      : self->dataLength(self->data, @selector(length));
+  }
+  else
+    currentLength = self->length;
+  
+  return (currentLength == position)
+    ? 0
+    : (currentLength - position);
+}
+
+/* primitives */
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  // throws
+  //   NGStreamNotOpenException   when the stream is not open
+  //   NGEndOfStreamException     when the end of the stream is reached
+  register unsigned currentLength = 0;
+  
+  if (self->bytes == NULL) {
+    currentLength = (self->dataLength == NULL)
+      ? [self->data length]
+      : self->dataLength(self->data, @selector(length));
+  }
+  else
+    currentLength = self->length;
+
+  if (self->data == nil) {
+    NSException *e;
+    
+    e = [NGStreamNotOpenException exceptionWithStream:self reason:
+                                   @"tried to read from a data stream "
+                                   @"which was closed"];
+    [self setLastException:e];
+    return NGStreamError;
+  }
+
+  if (currentLength == position) {
+    [self setLastException:
+           [NGEndOfStreamException exceptionWithStream:self]];
+    return NGStreamError;
+  }
+  {
+    NSRange range;
+    range.location = position;
+
+    if ((position + _len) > currentLength)
+      range.length = currentLength - position;
+    else
+      range.length = _len;
+
+    [self->data getBytes:_buf range:range];
+
+    position += range.length;
+    return range.length;
+  }
+}
+
+- (int)readByte {
+  register const unsigned char *p;
+  register unsigned int currentLength = 0;
+  int result = 0;
+  
+  if (self->bytes == NULL) {
+    currentLength = (self->dataLength == NULL)
+      ? [self->data length]
+      : self->dataLength(self->data, @selector(length));
+  }
+  else
+    currentLength = self->length;
+  
+  if (currentLength == position)
+    return -1;
+  
+  if (self->bytes == NULL) {
+    p = (self->dataBytes == NULL)
+      ? [self->data bytes]
+      : self->dataBytes(self->data, @selector(bytes));
+  }
+  else
+    p = self->bytes;
+  result = p[self->position];
+  self->position++;
+  return result;
+}
+
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  // throws
+  //   NGReadOnlyStreamException when the stream is not writeable
+  //   NGStreamNotOpenException  when the stream is not open
+  
+  if (self->data == nil) {
+    NSException *e;
+
+    e = [NGStreamNotOpenException exceptionWithStream:self reason:
+                                    @"tried to write to a data stream "
+                                   @"which was closed"];
+    [self setLastException:e];
+    return NGStreamError;
+  }
+  if (!NGCanWriteInStreamMode(streamMode)) {
+    NSException *e;
+    
+    e = [NGReadOnlyStreamException exceptionWithStream:self];
+    [self setLastException:e];
+    return NGStreamError;
+  }
+  [(NSMutableData *)self->data appendBytes:_buf length:_len];
+
+  return _len;
+}
+
+- (BOOL)close {
+  ASSIGN(self->lastException, (id)nil);
+  [self->data release]; self->data = nil;
+  position   = 0;
+  streamMode = NGStreamMode_undefined;
+  return YES;
+}
+
+- (NGStreamMode)mode {
+  return streamMode;
+}
+- (BOOL)isRootStream {
+  return YES;
+}
+
+// NGPositionableStream
+
+- (BOOL)moveToLocation:(unsigned)_location {
+  position = _location;
+  return YES;
+}
+- (BOOL)moveByOffset:(int)_delta {
+  position += _delta;
+  return YES;
+}
+
+/* blocking .. */
+
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode {
+  return NO;
+}
+
+- (id)retain {
+  return [super retain];
+}
+
+/* bytebuffer / lookahead API */
+
+- (int)la:(unsigned)_la {
+  register unsigned int currentLength, newpos;
+  register const unsigned char *p;
+  int result = 0;
+  
+  if (self->bytes == NULL) {
+    currentLength = (self->dataLength == NULL)
+      ? [self->data length]
+      : self->dataLength(self->data, @selector(length));
+  }
+  else
+    currentLength = self->length;
+  
+  if (currentLength == self->position) // already at EOF
+    return -1;
+  
+  newpos = (self->position + _la);
+  if (newpos >= currentLength)
+    return -1; /* a look into EOF */
+  
+  if (self->bytes == NULL) {
+    p = (self->dataBytes == NULL)
+      ? [self->data bytes]
+      : self->dataBytes(self->data, @selector(bytes));
+  }
+  else
+    p = self->bytes;
+  
+  result = p[newpos];
+  return result;
+}
+
+- (void)consume { // consume one byte
+  register unsigned int currentLength = 0;
+  
+  if (self->bytes == NULL) {
+    currentLength = (self->dataLength == NULL)
+      ? [self->data length]
+      : self->dataLength(self->data, @selector(length));
+  }
+  else
+    currentLength = self->length;
+  
+  if (currentLength == self->position)
+    return;
+  
+  self->position++; // consume
+}
+- (void)consume:(unsigned)_cnt { // consume _cnt bytes
+  register unsigned int currentLength = 0;
+
+  if (self->bytes == NULL) {
+    currentLength = (self->dataLength == NULL)
+      ? [self->data length]
+      : self->dataLength(self->data, @selector(length));
+  }
+  else
+    currentLength = self->length;
+  
+  if (currentLength == self->position)
+    return;
+  
+  self->position += _cnt; // consume
+  
+  if (self->position > currentLength)
+    self->position = currentLength;
+}
+
+@end /* NGDataStream */
diff --git a/skyrix-core/NGStreams/NGDatagramPacket.m b/skyrix-core/NGStreams/NGDatagramPacket.m
new file mode 100644 (file)
index 0000000..2f5a53e
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGDatagramPacket.h"
+#include "common.h"
+
+@implementation NGDatagramPacket
+
++ (id)packetWithData:(NSData *)_data {
+  return [[[self alloc] initWithData:_data] autorelease];
+}
++ (id)packetWithBytes:(const void *)_bytes size:(int)_packetSize {
+  return [[[self alloc] initWithBytes:_bytes size:_packetSize] autorelease];
+}
+
+- (id)initWithBytes:(const void *)_bytes size:(int)_packetSize {
+  return [self initWithData:[NSData dataWithBytes:_bytes length:_packetSize]];
+}
+- (id)initWithData:(NSData *)_data {
+  if ((self = [self init])) {
+    self->packet = [_data copyWithZone:[self zone]];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->packet   release];
+  [self->sender   release];
+  [self->receiver release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setSender:(id<NGSocketAddress>)_address {
+  ASSIGN(self->sender, _address);
+}
+- (id<NGSocketAddress>)sender {
+  return self->sender;
+}
+
+- (void)setReceiver:(id<NGSocketAddress>)_address {
+  ASSIGN(self->receiver, _address);
+}
+- (id<NGSocketAddress>)receiver {
+  return self->receiver;
+}
+
+- (void)setData:(NSData *)_data {
+  ASSIGN(self->packet, _data);
+}
+- (NSData *)data {
+  return self->packet;
+}
+
+- (int)packetSize {
+  return [self->packet length];
+}
+
+/* operations */
+
+- (void)reverseAddresses {
+  id oldSender = [[self sender] retain];
+  [self setSender:[self receiver]];
+  [self setReceiver:oldSender];
+  [oldSender release]; oldSender = nil;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: from=%@ to=%@ size=%i>",
+                     NSStringFromClass([self class]), (unsigned)self,
+                     [self sender], [self receiver], [self packetSize]];
+}
+
+@end /* NGDatagramPacket */
diff --git a/skyrix-core/NGStreams/NGDatagramSocket.m b/skyrix-core/NGStreams/NGDatagramSocket.m
new file mode 100644 (file)
index 0000000..6d1b1c8
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+  Copyright (C) 2000-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$
+
+#if defined(__APPLE__)
+#  include <sys/types.h>
+#  include <sys/socket.h>
+#endif
+
+#include <NGStreams/NGDescriptorFunctions.h>
+#include "NGDatagramSocket.h"
+#include "NGDatagramPacket.h"
+#include "NGSocketExceptions.h"
+#include "NGSocket+private.h"
+#include "common.h"
+
+#if !defined(POLLRDNORM)
+#  define POLLRDNORM POLLIN
+#endif
+
+NSString *NGSocketTimedOutNotificationName = @"NGSocketTimedOutNotification";
+
+@interface NGSocket(privateMethods)
+
+- (void)_createSocketInDomain:(int)_domain;
+
+- (void)setOption:(int)_option level:(int)_level value:(void *)_value len:(int)_len;
+- (void)setOption:(int)_option value:(void *)_value len:(int)_len;
+- (void)getOption:(int)_option level:(int)_level value:(void *)_val len:(int *)_len;
+- (void)getOption:(int)_option value:(void *)_value len:(int *)_len;
+
+@end
+
+//static const int NGMaxTimeout = (int)-1;
+static const NSTimeInterval NGNoTimeout = 0.0;
+
+@implementation NGDatagramSocket
+
+#if !defined(WIN32) || defined(__CYGWIN32__)
+
++ (BOOL)socketPair:(id<NGSocket>[2])_pair inDomain:(id<NGSocketDomain>)_domain {
+  int fds[2];
+
+  _pair[0] = nil;
+  _pair[1] = nil;
+
+  if (socketpair([_domain socketDomain], SOCK_DGRAM, [_domain protocol],
+                 fds) == 0) {
+    NGDatagramSocket *s1 = nil;
+    NGDatagramSocket *s2 = nil;
+    
+    s1 = [[self alloc] _initWithDomain:_domain descriptor:fds[0]];
+    s2 = [[self alloc] _initWithDomain:_domain descriptor:fds[1]];
+    s1 = AUTORELEASE(s1);
+    s2 = AUTORELEASE(s2);
+
+    if ((s1 != nil) && (s2 != nil)) {
+      _pair[0] = s1;
+      _pair[1] = s2;
+
+      return YES;
+    }
+    else
+      return NO;
+  }
+  else {
+    int      e       = errno;
+    NSString *reason = nil;
+
+    switch (e) {
+      case EACCES:
+        reason = @"Not allowed to create socket of this type";
+        break;
+      case ENOMEM:
+        reason = @"Could not create socket: Insufficient user memory available";
+        break;
+      case EPROTONOSUPPORT:
+        reason = @"The protocol is not supported by the address family or "
+                 @"implementation";
+        break;
+      case EPROTOTYPE:
+        reason = @"The socket type is not supported by the protocol";
+        break;
+      case EMFILE:
+        reason = @"Could not create socket: descriptor table is full";
+        break;
+      case EOPNOTSUPP:
+        reason = @"The specified protocol does not permit creation of socket "
+                 @"pairs";
+        break;
+
+      default:
+        reason = [NSString stringWithFormat:@"Could not create socketpair: %s",
+                             strerror(e)];
+        break;
+    }
+    [[[NGCouldNotCreateSocketException alloc]
+              initWithReason:reason domain:_domain] raise];
+    return NO;
+  }
+}
+
+#endif
+
++ (id)socketBoundToAddress:(id<NGSocketAddress>)_address {
+  volatile id sock = [[self alloc] initWithDomain:[_address domain]];
+
+  if (sock != nil) {
+    sock = AUTORELEASE(sock);
+    [sock bindToAddress:_address];
+  }
+  return sock;
+}
+
+- (id)initWithDomain:(id<NGSocketDomain>)_domain { // designated initializer
+  if ((self = [super initWithDomain:_domain])) {
+    [self setMaxPacketSize:2048];
+    [self setPacketFactory:(id)[NGDatagramPacket class]];
+    self->udpFlags.isConnected = NO;
+  }
+  return self;
+}
+
+// accessors
+
+- (void)setMaxPacketSize:(int)_maxPacketSize {
+  self->maxPacketSize = _maxPacketSize;
+}
+- (int)maxPacketSize {
+  return self->maxPacketSize;
+}
+
+- (void)setPacketFactory:(id<NGDatagramPacketFactory>)_factory {
+  ASSIGN(self->packetFactory, _factory);
+}
+- (id<NGDatagramPacketFactory>)packetFactory {
+  return self->packetFactory;
+}
+
+- (int)socketType {
+  return SOCK_DGRAM;
+}
+
+- (BOOL)isConnected {
+  return self->udpFlags.isConnected;
+}
+
+// polling
+
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode {
+  short events = 0;
+
+  if (fd == NGInvalidSocketDescriptor)
+    return NO;
+
+  if (NGCanReadInStreamMode(_mode))  events |= POLLRDNORM;
+  if (NGCanWriteInStreamMode(_mode)) events |= POLLWRNORM;
+
+  // timeout of 0 means return immediatly
+  return (NGPollDescriptor([self fileDescriptor], events, 0) == 1 ? NO : YES);
+}
+
+// sending
+
+- (void)primarySendPacket:(id<NGDatagramPacket>)_packet {
+  int bytesWritten;
+
+  NSAssert([_packet receiver], @"packet has no destination !");
+
+  bytesWritten = sendto(self->fd, // socket
+                        [[_packet data] bytes], [[_packet data] length],
+                        0, // flags
+                        [[_packet receiver] internalAddressRepresentation],
+                        [[_packet receiver] addressRepresentationSize]);
+
+  if (!self->flags.isBound) // was not explictly bound, so get local address
+    [self kernelBoundAddress];
+
+  [_packet setSender:[self localAddress]];
+}
+
+- (BOOL)sendPacket:(id<NGDatagramPacket>)_packet timeout:(NSTimeInterval)_to {
+  if (_to > NGNoTimeout) {
+    int result = NGPollDescriptor([self fileDescriptor],
+                                  POLLWRNORM,
+                                  (int)(_to * 1000.0));
+
+    if (result == 0) {
+      // timeout
+      [[NSNotificationCenter defaultCenter]
+                             postNotificationName:NGSocketTimedOutNotificationName
+                             object:self];
+      return NO;
+    }
+    else if (result < 0) {
+      [[[NGSocketException alloc]
+           initWithReason:@"error during poll on UDP socket"] raise];
+      return NO;
+    }
+
+    // else receive packet ..
+  }
+  [self primarySendPacket:_packet];
+  return YES;
+}
+
+- (BOOL)sendPacket:(id<NGDatagramPacket>)_packet {
+  return [self sendPacket:_packet timeout:NGNoTimeout];
+}
+
+// receiving
+
+- (id<NGDatagramPacket>)primaryReceivePacketWithMaxSize:(int)_maxSize {
+  id<NGSocketAddress>  remote  = nil;
+  id<NGDatagramPacket> packet = nil;
+  char    buffer[_maxSize];
+  size_t  size;
+  int     len   = [[self domain] addressRepresentationSize];
+  char    data[len];
+
+  size = recvfrom(self->fd, buffer, _maxSize,
+                  0, // flags
+                  (void *)data, &len);
+  remote = [[self domain] addressWithRepresentation:(void *)data size:len];
+
+  if (!self->flags.isBound) // was not explictly bound, so get local address
+    [self kernelBoundAddress];
+
+  packet = [[self packetFactory] packetWithBytes:buffer size:size];
+  [packet setReceiver:[self localAddress]];
+  [packet setSender:remote];
+
+  return packet;
+}
+- (id<NGDatagramPacket>)receivePacketWithMaxSize:(int)_size
+  timeout:(NSTimeInterval)_to {
+  
+  if (_to > NGNoTimeout) {
+    int result = NGPollDescriptor([self fileDescriptor],
+                                  POLLRDNORM,
+                                  (int)(_to * 1000.0));
+
+    if (result == 0) {
+      // timeout
+      [[NSNotificationCenter defaultCenter]
+                             postNotificationName:NGSocketTimedOutNotificationName
+                             object:self];
+      return nil;
+    }
+    else if (result < 0) {
+      [[[NGSocketException alloc]
+           initWithReason:@"error during poll on UDP socket"] raise];
+    }
+
+    // else receive packet ..
+  }
+  return [self primaryReceivePacketWithMaxSize:_size];
+}
+
+- (id<NGDatagramPacket>)receivePacketWithTimeout:(NSTimeInterval)_timeout {
+  return [self receivePacketWithMaxSize:[self maxPacketSize] timeout:_timeout];
+}
+
+- (id<NGDatagramPacket>)receivePacketWithMaxSize:(int)_maxPacketSize {
+  return [self receivePacketWithMaxSize:_maxPacketSize timeout:NGNoTimeout];
+}
+- (id<NGDatagramPacket>)receivePacket {
+  return [self receivePacketWithMaxSize:[self maxPacketSize] timeout:NGNoTimeout];
+}
+
+// ************************* options *************************
+
+static int i_yes = 1;
+static int i_no  = 0;
+
+static inline void setBoolOption(id self, int _option, BOOL _flag) {
+  [self setOption:_option level:SOL_SOCKET
+        value:(_flag ? &i_yes : &i_no) len:4];
+}
+static inline BOOL getBoolOption(id self, int _option) {
+  int value, len;
+  [self getOption:_option level:SOL_SOCKET value:&value len:&len];
+  return (value ? YES : NO);
+}
+
+- (void)setBroadcast:(BOOL)_flag {
+  setBoolOption(self, SO_BROADCAST, _flag);
+}
+- (BOOL)doesBroadcast {
+  return getBoolOption(self, SO_BROADCAST);
+}
+
+// aborts, only supported for TCP
+
+- (void)setDebug:(BOOL)_flag {
+  [self doesNotRecognizeSelector:_cmd];
+}
+- (BOOL)doesDebug {
+  [self doesNotRecognizeSelector:_cmd];
+  return NO;
+}
+
+@end
diff --git a/skyrix-core/NGStreams/NGDescriptorFunctions.m b/skyrix-core/NGStreams/NGDescriptorFunctions.m
new file mode 100644 (file)
index 0000000..cae3470
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+  Copyright (C) 2000-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$
+
+#if !defined(WIN32) || defined(__CYGWIN32__)
+
+// similiar functions for Windows can be found in NGSocket.[hm]
+
+#include "NGDescriptorFunctions.h"
+#include "NGStreamExceptions.h"
+#include "common.h"
+#include "config.h"
+
+#ifdef HAVE_POLL
+#  ifdef HAVE_POLL_H
+#    include <poll.h>
+#  endif
+#  ifdef HAVE_SYS_POLL_H
+#    include <sys/poll.h>
+#  endif
+#  ifndef POLLRDNORM
+#    define POLLRDNORM POLLIN /* needed on Linux */
+#  endif
+#else
+#  ifdef HAVE_SELECT_H
+#    include <select.h>
+#  endif
+#endif
+
+#if defined(HAVE_SYS_SOCKET_H) || defined(__APPLE__)
+#  include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_FCNTL_H
+#  include <sys/fcntl.h>
+#endif
+#if defined(HAVE_FCNTL_H) || defined(__APPLE__)
+#  include <fcntl.h>
+#endif
+
+#if HAVE_UNISTD_H || defined(__APPLE__)
+#  include <unistd.h>
+#endif
+#if HAVE_LIMITS_H
+#  include <limits.h>
+#endif
+#if HAVE_SYS_TIME_H || defined(__APPLE__)
+#  include <sys/time.h>
+#endif
+#if HAVE_SYS_TYPES_H || defined(__APPLE__)
+#  include <sys/types.h>
+#endif
+
+#if !HAVE_TTYNAME_R
+#  if LIB_FOUNDATION_LIBRARY
+extern NSRecursiveLock *libFoundationLock = nil;
+#    define systemLock libFoundationLock
+#  else
+#    ifndef __APPLE__
+#      warning "No locking support for ttyname on this platform"
+#    endif
+#    define systemLock (id)nil
+#  endif
+#endif
+
+// ******************** Poll *********************
+
+int NGPollDescriptor(int _fd, short _events, int _timeout) {
+#ifdef HAVE_POLL
+  struct pollfd pfd;
+  int           result;
+
+  pfd.fd      = _fd;
+  pfd.events  = _events;
+  pfd.revents = 0;
+
+  do {
+    result = poll(&pfd, 1, _timeout);
+
+    if (result < 0) { // error
+      int e = errno;
+
+      if (e == 0) {
+        NSLog(@"%s: errno is 0, but return value of poll is <0 (%i) (retry) ?!",
+              __PRETTY_FUNCTION__, result);
+        continue;
+      }
+
+      if ((e != EAGAIN) && (e != EINTR)) 
+        // only retry of interrupted or repeatable
+        break;
+    }
+  }
+  while (result < 0);
+
+  /* revents: POLLERR POLLHUP POLLNVAL */
+
+  return (result < 0) ? -1 : result;
+#else
+  struct timeval timeout;
+  fd_set rSet;
+  fd_set wSet;
+  fd_set eSet;
+  int    result;
+  FD_ZERO(&rSet);
+  FD_ZERO(&wSet);
+  FD_ZERO(&eSet);
+
+  if (_events & POLLIN)  FD_SET(_fd, &rSet);
+  if (_events & POLLOUT) FD_SET(_fd, &wSet);
+  if (_events & POLLERR) FD_SET(_fd, &eSet);
+
+  timeout.tv_sec  = _timeout / 1000;
+  timeout.tv_usec = _timeout * 1000 - timeout.tv_sec * 1000000;
+
+  do {
+    result = select(FD_SETSIZE, &rSet, &wSet, &eSet, &timeout);
+    if (result == -1) { // error
+      int e = errno;
+      if ((e != EAGAIN) && (e != EINTR)) 
+        // only retry of interrupted or repeatable
+        break;
+    }
+  }
+  while (result == -1);
+
+  return (result < 0) ? -1 : result;
+#endif
+}
+
+// ******************** Flags ********************
+
+int NGGetDescriptorFlags(int _fd) {
+  int val;
+
+  val = fcntl(_fd, F_GETFL, 0);
+  if (val < 0)
+    [NGIOException raiseWithReason:@"could not get descriptor flags"];
+  return val;
+}
+void NGSetDescriptorFlags(int _fd, int _flags) {
+  if (fcntl(_fd, F_SETFL, _flags) == -1)
+    [NGIOException raiseWithReason:@"could not set descriptor flags"];
+}
+
+void NGAddDescriptorFlag(int _fd, int _flag) {
+  int val = NGGetDescriptorFlags(_fd);
+  NGSetDescriptorFlags(_fd, val | _flag);
+}
+
+// ******************** NonBlocking IO ************
+
+static int enableDescLogging = -1;
+
+int NGDescriptorRecv(int _fd, char *_buf, int _len, int _flags, int _timeout /* in ms */) {
+  int errorCode;
+  int result;
+
+  if (enableDescLogging == -1) {
+    enableDescLogging = 
+      [[[NSUserDefaults standardUserDefaults] 
+        objectForKey:@"NGLogDescriptorRecv"] boolValue] ? YES : NO;
+  }
+  
+  if (enableDescLogging) {
+    NSLog(@"%s(fd=%i,buf=0x%08X,len=%i,flags=%i,timeout=%i)", 
+         __PRETTY_FUNCTION__, _fd,_buf,_len,_flags,_timeout);
+  }
+  
+  if (_timeout == -1)
+    _timeout = 1000 * 60 * 60; /* default timeout: 1 hour */
+  
+  result = recv(_fd, _buf, _len, _flags);
+  errorCode = errno;
+  if (result == 0) return 0; // EOF
+  
+  if (enableDescLogging) {
+    if ((result < 0) && (errorCode == EINVAL)) {
+      NSLog(@"%s: invalid argument in recv(%i, 0x%08X, %i, %i)",
+           __PRETTY_FUNCTION__, _fd, _buf, _len, _flags);
+    }
+  }
+  
+  if (enableDescLogging) {
+    NSLog(@"result=%i, error=%i(%s)", result, errorCode, strerror(errorCode));
+  }
+  
+  if ((result == -1) && (errorCode == EWOULDBLOCK)) { // retry
+#if HAVE_POLL
+    struct pollfd pfd;
+    pfd.fd      = _fd;
+    pfd.events  = POLLRDNORM;
+    pfd.revents = 0;
+    
+    do {
+      if (enableDescLogging) NSLog(@"starting poll, loop (to=%i)", _timeout);
+      
+      if ((result = poll(&pfd, 1, _timeout)) < 0) {
+        errorCode = errno;
+        
+       if (enableDescLogging) {
+         if (errno == EINVAL)
+           NSLog(@"%s: invalid argument to poll(...)", __PRETTY_FUNCTION__);
+       }
+        
+        if (errorCode == 0) {
+          NSLog(@"%s: errno is 0, but return value of poll is <0 (%i) (retry) ?!",
+                __PRETTY_FUNCTION__, result);
+          continue;
+        }
+        
+        // retry if interrupted
+        if ((errorCode != EINTR) && (errorCode != EAGAIN)) 
+          break;
+      }
+    }
+    while (result < 0);
+#else
+    struct timeval timeout;
+    fd_set rSet;
+    fd_set wSet;
+    fd_set eSet;
+    FD_ZERO(&rSet);
+    FD_ZERO(&wSet);
+    FD_ZERO(&eSet);
+
+    FD_SET(_fd, &rSet);
+    
+    timeout.tv_sec  = _timeout / 1000;
+    timeout.tv_usec = _timeout * 1000 - timeout.tv_sec * 1000000;
+    
+    do {
+      result = select(FD_SETSIZE, &rSet, &wSet, &eSet, &timeout);
+      if (enableDescLogging) {
+       if ((result < 0) && (errno == EINVAL))
+         NSLog(@"%s: invalid argument in select(...)", __PRETTY_FUNCTION__);
+      }
+      
+      if (result == -1) { // error
+        int e = errno;
+        if ((e != EAGAIN) && (e != EINTR)) 
+          // only retry of interrupted or repeatable
+          break;
+      }
+    }
+    while (result == -1);
+#endif
+    
+    if (result == 1) { // data waiting, try to read
+      if (enableDescLogging) NSLog(@"receiving data ...");
+      
+      result = recv(_fd, _buf, _len, _flags);
+      if (result == 0)
+        return 0; // EOF
+      else if (result == -1) {
+        errorCode = errno;
+
+        if (errorCode == EWOULDBLOCK)
+          NSLog(@"WARNING: would block although descriptor was polled ..");
+      }
+    }
+    else if (result == 0) {
+      if (enableDescLogging) {
+       NSLog(@"nonblock: recv on %i timed out after %i milliseconds ..",
+             _fd, _timeout);
+      }
+      result = -2;
+    }
+    else
+      result = -1;
+  }
+
+  return result;
+}
+
+int NGDescriptorSend
+(int _fd, const char *_buf, int _len, int _flags, int _timeout) 
+{
+  int errorCode;
+  int result;
+
+  result = send(_fd, _buf, _len, _flags);
+  if (result == 0) return 0; // EOF
+
+  errorCode = errno;
+
+  if ((result == -1) && (errorCode == EWOULDBLOCK)) { // retry
+#if HAVE_POLL
+    struct pollfd pfd;
+    pfd.fd      = _fd;
+    pfd.events  = POLLWRNORM;
+    pfd.revents = 0;
+    
+    do {
+      if ((result = poll(&pfd, 1, _timeout)) < 0) {
+        errorCode = errno;
+
+        if (errorCode == 0) {
+          NSLog(@"%s: errno is 0, but return value of poll is <0 (%i) (retry) ?!",
+                __PRETTY_FUNCTION__, result);
+          continue;
+        }
+        
+        if (errorCode != EINTR) // retry only if interrupted
+          break;
+      }
+    }
+    while (result < 0);
+#else
+    struct timeval timeout;
+    fd_set rSet;
+    fd_set wSet;
+    fd_set eSet;
+    FD_ZERO(&rSet);
+    FD_ZERO(&wSet);
+    FD_ZERO(&eSet);
+
+    FD_SET(_fd, &wSet);
+    
+    timeout.tv_sec  = _timeout / 1000;
+    timeout.tv_usec = _timeout * 1000 - timeout.tv_sec * 1000000;
+
+    do {
+      result = select(FD_SETSIZE, &rSet, &wSet, &eSet, &timeout);
+      if (result == -1) { // error
+        int e = errno;
+        if ((e != EAGAIN) && (e != EINTR)) 
+          // only retry of interrupted or repeatable
+          break;
+      }
+    }
+    while (result == -1);
+#endif
+
+    if (result == 1) { // data waiting, try to read
+      result = send(_fd, _buf, _len, _flags);
+      if (result == 0) return 0; // EOF
+    }
+    else if (result == 0) {
+      NSLog(@"nonblock: send on %i timed out after %i milliseconds ..",
+             _fd, _timeout);
+      result = -2;
+    }
+    else
+      result = -1;
+  }
+
+  return result;
+}
+
+// ******************** TTY *********************
+
+/*
+  Check whether the descriptor is associated to a terminal device.
+  Get the name of the associated terminal device.
+*/
+
+BOOL NGDescriptorIsAtty(int _fd) {
+#if HAVE_ISATTY
+  return isatty(_fd) == 1 ? YES : NO;
+#else
+  return NO;
+#endif
+}
+
+NSString *NGDescriptorGetTtyName(int _fd) {
+#if HAVE_ISATTY
+  if (isatty(_fd) != 1) // not connected to a terminal device ?
+    return nil;
+#endif
+  {
+#if HAVE_TTYNAME_R
+#  ifndef sparc
+   extern int ttyname_r(int, char*, size_t);
+#  endif
+#  ifdef _POSIX_PATH_MAX
+    char namebuffer[_POSIX_PATH_MAX + 128];
+#  else
+    char namebuffer[4096];
+#  endif
+
+    if (ttyname_r(_fd, namebuffer, sizeof(namebuffer)))
+      return [NSString stringWithCString:namebuffer];
+    
+#elif HAVE_TTYNAME
+    char     *result = NULL;
+    NSString *str    = nil;
+    int      errCode = 0;
+
+    [systemLock lock];
+    {
+      result  = ttyname(_fd);
+      errCode = errno;
+      if (result) str = [NSString stringWithCString:result];
+    }
+    [systemLock unlock];
+    
+    if (str) return str;
+#endif
+  }
+  return nil;
+}
+
+#endif // WIN32
diff --git a/skyrix-core/NGStreams/NGFileStream.m b/skyrix-core/NGStreams/NGFileStream.m
new file mode 100644 (file)
index 0000000..521ae74
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "config.h"
+
+#if HAVE_UNISTD_H || __APPLE__
+#  include <unistd.h>
+#endif
+#if HAVE_SYS_STAT_H
+#  include <sys/stat.h>
+#endif
+#if HAVE_SYS_FCNTL_H
+#  include <sys/fcntl.h>
+#endif
+#if HAVE_FCNTL_H || __APPLE__
+#  include <fcntl.h>
+#endif
+
+#include "common.h"
+#import <Foundation/NSThread.h>
+#include "NGFileStream.h"
+#include "NGBufferedStream.h"
+#include "NGConcreteStreamFileHandle.h"
+#include "NGLockingStream.h"
+#include "NGStreamExceptions.h"
+#include "NGDescriptorFunctions.h"
+
+#if !defined(POLLRDNORM)
+#  define POLLRDNORM POLLIN
+#endif
+
+// TODO: NGFileStream needs to be changed to operate without throwing 
+//       exceptions
+
+NGStreams_DECLARE NSString *NGFileReadOnly    = @"r";
+NGStreams_DECLARE NSString *NGFileWriteOnly   = @"w";
+NGStreams_DECLARE NSString *NGFileReadWrite   = @"rw";
+NGStreams_DECLARE NSString *NGFileAppend      = @"a";
+NGStreams_DECLARE NSString *NGFileReadAppend  = @"ra";
+
+static const int NGInvalidUnixDescriptor = -1;
+static const int NGFileCreationMask      = 0666; // rw-rw-rw-
+
+@interface _NGConcreteFileStreamFileHandle : NGConcreteStreamFileHandle
+@end
+
+NGStreams_DECLARE id<NGInputStream>  NGIn  = nil;
+NGStreams_DECLARE id<NGOutputStream> NGOut = nil;
+NGStreams_DECLARE id<NGOutputStream> NGErr = nil;
+
+@implementation NGFileStream
+
+// stdio stream
+
+#if defined(__MINGW32__)
+- (id)__initWithInConsole {
+  if ((self = [self init])) {
+    self->systemPath = @"CONIN$";
+    self->streamMode = NGStreamMode_readWrite;
+    self->fh = GetStdHandle(STD_INPUT_HANDLE);
+    /*
+    self->fh = CreateFile("CONIN$", GENERIC_READ, FILE_SHARE_READ,
+                          NULL,
+                          OPEN_EXISTING,
+                          0,
+                          NULL);
+     */
+  }
+  return self;
+}
+- (id)__initWithOutConsole {
+  if ((self = [self init])) {
+    DWORD written;
+    self->systemPath = @"CONOUT$";
+    self->streamMode = NGStreamMode_readWrite;
+    self->fh         = GetStdHandle(STD_OUTPUT_HANDLE);
+    /*
+    self->fh = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
+                          NULL,
+                          OPEN_EXISTING,
+                          0,
+                          NULL);
+     */
+    FlushFileBuffers(self->fh);
+  }
+  return self;
+}
+#else
+- (id)__initWithDescriptor:(int)_fd mode:(NGStreamMode)_mode {
+  if ((self = [self init])) {
+    self->fd         = _fd;
+    self->streamMode = _mode;
+  }
+  return self;
+}
+#endif
+
+void NGInitStdio(void) {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    NGFileStream *ti = nil, *to = nil, *te = nil;
+    
+    isInitialized = YES;
+
+#if defined(__MINGW32__)
+    ti = [[NGFileStream alloc] __initWithInConsole];
+    to = [[NGFileStream alloc] __initWithOutConsole];
+    te = [to retain];
+#else
+    ti = [[NGFileStream alloc] __initWithDescriptor:0 mode:NGStreamMode_readOnly];
+    to = [[NGFileStream alloc] __initWithDescriptor:1 mode:NGStreamMode_writeOnly];
+    te = [[NGFileStream alloc] __initWithDescriptor:2 mode:NGStreamMode_writeOnly];
+#endif
+
+    NGIn  = [[NGBufferedStream alloc] initWithSource:(id)ti];
+    NGOut = [[NGBufferedStream alloc] initWithSource:(id)to];
+    NGErr = [[NGBufferedStream alloc] initWithSource:(id)te];
+
+    [ti release]; ti = nil;
+    [to release]; to = nil;
+    [te release]; te = nil;
+  }
+}
+
++ (void)_makeThreadSafe:(NSNotification *)_notification {
+  NGLockingStream *li = nil, *lo = nil, *le = nil;
+  
+  if ([NGIn isKindOfClass:[NGLockingStream class]])
+    return;
+
+  li = [[NGLockingStream alloc] initWithSource:NGIn];  [NGIn  release]; NGIn  = li;
+  lo = [[NGLockingStream alloc] initWithSource:NGOut]; [NGOut release]; NGOut = lo;
+  le = [[NGLockingStream alloc] initWithSource:NGErr]; [NGErr release]; NGErr = le;
+}
+
++ (void)_flushForExit:(NSNotification *)_notification {
+  [NGIn  flush];
+  [NGOut flush];
+  [NGErr flush];
+}
+
+static void _flushForExit(void) {
+  [NGIn  flush];
+  [NGOut flush];
+  [NGErr flush];
+}
+
++ (void)initialize {
+  BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+
+    if ([NSThread isMultiThreaded])
+      [self _makeThreadSafe:nil];
+    else {
+      [[NSNotificationCenter defaultCenter]
+                             addObserver:self
+                             selector:@selector(_makeThreadSafe:)
+                             name:NSWillBecomeMultiThreadedNotification
+                             object:nil];
+    }
+    atexit(_flushForExit);
+  }
+}
+
+/* normal file stream */
+
+- (id)init {
+  if ((self = [super init])) {
+    self->streamMode = NGStreamMode_undefined;
+    self->systemPath = nil;
+    self->markDelta  = -1;
+    self->handle     = nil;
+#if defined(__MINGW32__)
+    self->fh         = INVALID_HANDLE_VALUE;
+#else
+    self->fd         = NGInvalidUnixDescriptor;
+#endif
+  }
+  return self;
+}
+
+- (id)initWithPath:(NSString *)_path {
+  if ((self = [self init])) {
+    self->systemPath = [_path copy];
+  }
+  return self;
+}
+
+- (id)initWithFileHandle:(NSFileHandle *)_handle {
+  if ((self = [self init])) {
+#if defined(__MINGW32__)
+    self->fh = [_handle nativeHandle];
+#else
+    self->fd = [_handle fileDescriptor];
+#endif
+  }
+  return self;
+}
+
+- (void)gcFinalize {
+  if ([self isOpen]) {
+#if DEBUG && 0
+    NSLog(@"NGFileStream(gcFinalize): closing %@", self);
+#endif
+    [self close];
+  }
+}
+- (void)dealloc {
+  [self gcFinalize];
+  self->streamMode = NGStreamMode_undefined;
+  [self->systemPath release]; self->systemPath = nil;
+  self->handle = nil;
+  [super dealloc];
+}
+
+// opening
+
+- (BOOL)openInMode:(NSString *)_mode {
+  // throws
+  //   NGUnknownStreamModeException  when _mode is invalid
+  //   NGCouldNotOpenStreamException when the file could not be opened
+#if defined(__MINGW32__)
+  DWORD openFlags;
+  DWORD shareMode;
+
+  if (self->fh != INVALID_HANDLE_VALUE)
+    [self close]; // if stream is open, close and reopen
+
+  if ([_mode isEqualToString:NGFileReadOnly]) {
+    self->streamMode = NGStreamMode_readOnly;
+    openFlags = GENERIC_READ;
+    shareMode = FILE_SHARE_READ;
+  }
+  else if ([_mode isEqualToString:NGFileWriteOnly]) {
+    self->streamMode = NGStreamMode_writeOnly;
+    openFlags = GENERIC_WRITE;
+    shareMode = FILE_SHARE_WRITE;
+  }
+  else if ([_mode isEqualToString:NGFileReadWrite]) {
+    self->streamMode = NGStreamMode_readWrite;
+    openFlags = GENERIC_READ | GENERIC_WRITE;
+    shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+  }
+  else {
+    [[[NGUnknownStreamModeException alloc]
+                                    initWithStream:self mode:_mode] raise];
+    return NO;
+  }
+
+  self->fh = CreateFile([self->systemPath fileSystemRepresentation],
+                        openFlags, shareMode, NULL,
+                        OPEN_ALWAYS, // same as the Unix O_CREAT flag
+                        0,           // security flags ?
+                        NULL);
+
+  if (self->fh == INVALID_HANDLE_VALUE)
+    [NGCouldNotOpenStreamException raiseWithStream:self];
+
+#else
+  int openFlags; // flags passed to open() call
+
+  if (self->fd != NGInvalidUnixDescriptor)
+    [self close]; // if stream is open, close and reopen
+
+  if ([_mode isEqualToString:NGFileReadOnly]) {
+    self->streamMode = NGStreamMode_readOnly;
+    openFlags = O_RDONLY;
+  }
+  else if ([_mode isEqualToString:NGFileWriteOnly]) {
+    self->streamMode = NGStreamMode_writeOnly;
+    openFlags = O_WRONLY | O_CREAT;
+  }
+  else if ([_mode isEqualToString:NGFileReadWrite]) {
+    self->streamMode = NGStreamMode_readWrite;
+    openFlags = O_RDWR | O_CREAT;
+  }
+  else if ([_mode isEqualToString:NGFileAppend]) {
+    self->streamMode = NGStreamMode_writeOnly;
+    openFlags = O_WRONLY | O_CREAT | O_APPEND;
+  }
+  else if ([_mode isEqualToString:NGFileReadAppend]) {
+    self->streamMode = NGStreamMode_readWrite;
+    openFlags = O_RDWR | O_CREAT | O_APPEND;
+  }
+  else {
+    [[[NGUnknownStreamModeException alloc]
+              initWithStream:self mode:_mode] raise];
+    return NO;
+  }
+
+  self->fd = open([self->systemPath fileSystemRepresentation],
+                  openFlags,
+                  NGFileCreationMask);
+
+  if (self->fd == -1) {
+    self->fd = NGInvalidUnixDescriptor;
+
+    [NGCouldNotOpenStreamException raiseWithStream:self];
+    return NO;
+  }
+#endif
+  
+  self->markDelta = -1; // not marked
+  return YES;
+}
+
+- (BOOL)isOpen {
+#if defined(__MINGW32__)
+  return (self->fh != INVALID_HANDLE_VALUE) ? YES : NO;
+#else
+  return (self->fd != NGInvalidUnixDescriptor) ? YES : NO;
+#endif
+}
+
+// Foundation file handles
+
+- (void)resetFileHandle { // called by NSFileHandle on dealloc
+  self->handle = nil;
+}
+- (NSFileHandle *)fileHandle {
+  if (self->handle == nil)
+    self->handle = [[_NGConcreteFileStreamFileHandle allocWithZone:[self zone]]
+                                                     initWithStream:self];
+  return [self->handle autorelease];
+}
+
+#if defined(__MINGW32__)
+- (HANDLE)windowsFileHandle {
+  return self->fh;
+}
+#endif
+
+- (int)fileDescriptor {
+#if defined(__MINGW32__)
+  return (int)[self fileHandle];
+#else
+  return self->fd;
+#endif
+}
+
+// primitives
+
+static void _checkOpen(NGFileStream *self, NSString *_reason) {
+#if defined(__MINGW32__)
+  if (self->fh == INVALID_HANDLE_VALUE)
+    [NGStreamNotOpenException raiseWithStream:self reason:_reason];
+#else
+  if (self->fd == NGInvalidUnixDescriptor)
+    [NGStreamNotOpenException raiseWithStream:self reason:_reason];
+#endif
+}
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  // throws
+  //   NGWriteOnlyStreamException  when the stream is not readable
+  //   NGStreamNotOpenException    when the stream is not open
+  //   NGEndOfStreamException      when the end of the stream is reached
+  //   NGStreamReadErrorException  when the read call failed
+
+  _checkOpen(self, @"tried to read from a file stream which is closed");
+
+  if (!NGCanReadInStreamMode(streamMode))
+    [NGWriteOnlyStreamException raiseWithStream:self];
+
+  {
+#if defined(__MINGW32__)
+    DWORD readResult = 0;
+
+    if (ReadFile(self->fh, _buf, _len, &readResult, NULL) == FALSE) {
+      DWORD lastErr = GetLastError();
+
+      if (lastErr == ERROR_HANDLE_EOF)
+        [NGEndOfStreamException raiseWithStream:self];
+      else
+        [NGStreamReadErrorException raiseWithStream:self errorCode:lastErr];
+    }
+    if (readResult == 0)
+      [NGEndOfStreamException raiseWithStream:self];
+#else
+    int readResult;
+    int retryCount = 0;
+    
+    do {
+      readResult = read(self->fd, _buf, _len);
+      
+      if (readResult == 0)
+        [NGEndOfStreamException raiseWithStream:self];
+      else if (readResult == -1) {
+        int errCode = errno;
+
+        if (errCode == EINTR)
+          // system call was interrupted
+          retryCount++;
+        else
+          [NGStreamReadErrorException raiseWithStream:self errorCode:errCode];
+      }
+    }
+    while ((readResult <= 0) && (retryCount < 10));
+
+    if (retryCount >= 10)
+      [NGStreamReadErrorException raiseWithStream:self errorCode:EINTR];
+#endif
+    
+    NSAssert(readResult > 0, @"invalid read method state");
+
+    // adjust mark
+    if (self->markDelta != -1)
+      self->markDelta += readResult; // increase delta
+    
+    return readResult;
+  }
+}
+
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  // throws
+  //   NGReadOnlyStreamException   when the stream is not writeable
+  //   NGStreamNotOpenException    when the stream is not open
+  //   NGStreamWriteErrorException when the write call failed
+  
+  _checkOpen(self, @"tried to write to a file stream which is closed");
+  
+  if (!NGCanWriteInStreamMode(streamMode))
+    [NGReadOnlyStreamException raiseWithStream:self];
+
+  {
+#if defined(__MINGW32__)
+    DWORD writeResult = 0;
+
+    if (WriteFile(self->fh, _buf, _len, &writeResult, NULL) == FALSE) {
+      DWORD errorCode = GetLastError();
+
+      switch (errorCode) {
+        case ERROR_INVALID_HANDLE:
+          [NGStreamWriteErrorException raiseWithStream:self
+                                       reason:@"incorrect file handle"];
+          break;
+        case ERROR_WRITE_PROTECT:
+          [NGStreamWriteErrorException raiseWithStream:self
+                                       reason:@"disk write protected"];
+          break;
+        case ERROR_NOT_READY:
+          [NGStreamWriteErrorException raiseWithStream:self
+                                       reason:@"the drive is not ready"];
+          break;
+        case ERROR_HANDLE_EOF:
+          [NGStreamWriteErrorException raiseWithStream:self
+                                       reason:@"reached end of file"];
+          break;
+        case ERROR_DISK_FULL:
+          [NGStreamWriteErrorException raiseWithStream:self
+                                       reason:@"disk is full"];
+          break;
+        
+        default:
+          [NGStreamWriteErrorException raiseWithStream:self
+                                       errorCode:GetLastError()];
+      }
+      
+      NSLog(@"invalid program state, aborting");
+      abort();
+    }
+#else
+    int writeResult;
+    int retryCount = 0;
+
+    do {
+      writeResult = write(self->fd, _buf, _len);
+
+      if (writeResult == -1) {
+        int errCode = errno;
+
+        if (errCode == EINTR)
+          // system call was interrupted
+          retryCount++;
+        else
+          [NGStreamWriteErrorException raiseWithStream:self errorCode:errno];
+      }
+    }
+    while ((writeResult == -1) && (retryCount < 10));
+
+    if (retryCount >= 10)
+      [NGStreamWriteErrorException raiseWithStream:self errorCode:EINTR];
+#endif
+    
+    return writeResult;
+  }
+}
+
+- (BOOL)close {
+#if defined(__MINGW32__)
+  if (self->fh == INVALID_HANDLE_VALUE) {
+    NSLog(@"tried to close already closed stream %@", self);
+    return YES; /* not signaled as an error .. */
+  }
+
+  if (CloseHandle(self->fh) == FALSE) {
+    [NGCouldNotCloseStreamException raiseWithStream:self];
+    return NO;
+  }
+  
+  self->fh = INVALID_HANDLE_VALUE;
+#else
+  if (self->fd == NGInvalidUnixDescriptor) {
+    NSLog(@"tried to close already closed stream %@", self);
+    return YES; /* not signaled as an error .. */
+  }
+
+  if (close(self->fd) != 0) {
+    [NGCouldNotCloseStreamException raiseWithStream:self];
+    return NO;
+  }
+  
+  self->fd = NGInvalidUnixDescriptor;
+#endif
+  self->markDelta = -1;
+  return YES;
+}
+
+- (NGStreamMode)mode {
+  return self->streamMode;
+}
+- (BOOL)isRootStream {
+  return YES;
+}
+
+#if defined(__MINGW32__)
+- (BOOL)flush {
+  if (self->fh != INVALID_HANDLE_VALUE)
+    FlushFileBuffers(self->fh);
+  return YES;
+}
+#endif
+
+// blocking
+
+#if defined(__MINGW32__)
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode {
+  NSLog(@"%@ not supported in Windows environment !",
+        NSStringFromSelector(_cmd));
+  return YES;
+}
+#else
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode {
+  short events = 0;
+
+  if (self->fd == NGInvalidUnixDescriptor)
+    return NO;
+
+  if (NGCanReadInStreamMode(_mode))  events |= POLLRDNORM;
+  if (NGCanWriteInStreamMode(_mode)) events |= POLLWRNORM;
+
+  // timeout of 0 means return immediatly
+  return (NGPollDescriptor(self->fd, events, 0) == 1 ? NO : YES);
+}
+#endif
+
+// marking
+
+- (BOOL)mark {
+  self->markDelta = 0;
+  return YES;
+}
+- (BOOL)rewind {
+  if (![self moveByOffset:-(self->markDelta)])
+    return NO;
+  self->markDelta = -1;
+  return YES;
+}
+- (BOOL)markSupported {
+  return YES;
+}
+
+// NGPositionableStream
+
+- (BOOL)moveToLocation:(unsigned)_location {
+  self->markDelta = -1;
+
+#if defined(__MINGW32__)
+  if (SetFilePointer(self->fh, _location, NULL, FILE_BEGIN) == -1) {
+    [NGStreamSeekErrorException raiseWithStream:self errorCode:GetLastError()];
+    return NO;
+  }
+#else
+  if (lseek(self->fd, _location, SEEK_SET) == -1) {
+    [NGStreamSeekErrorException raiseWithStream:self errorCode:errno];
+    return NO;
+  }
+#endif
+  return YES;
+}
+- (BOOL)moveByOffset:(int)_delta {
+  self->markDelta += _delta;
+  
+#if defined(__MINGW32__)
+  if (SetFilePointer(self->fh, _delta, NULL, FILE_CURRENT) == -1) {
+    [NGStreamSeekErrorException raiseWithStream:self errorCode:GetLastError()];
+    return NO;
+  }
+#else
+  if (lseek(self->fd, _delta, SEEK_CUR) == -1) {
+    [NGStreamSeekErrorException raiseWithStream:self errorCode:errno];
+    return NO;
+  }
+#endif
+  return YES;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<%@[0x%08X] path=%@ mode=%@>",
+                     NSStringFromClass([self class]), (unsigned)self,
+                     self->systemPath ? self->systemPath : @"nil",
+                     [self modeDescription]];
+}
+
+@end
+
+@implementation _NGConcreteFileStreamFileHandle
+
+// accessors
+
+#if defined(__MINGW32__)
+- (HANDLE)fileHandle {
+  return [(NGFileStream *)stream windowsFileHandle];
+}
+#endif
+
+- (int)fileDescriptor {
+  return [(NGFileStream *)stream fileDescriptor];
+}
+
+@end
diff --git a/skyrix-core/NGStreams/NGFilterStream.m b/skyrix-core/NGStreams/NGFilterStream.m
new file mode 100644 (file)
index 0000000..06f52a6
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGFilterStream.h"
+
+@implementation NGFilterStream
+
++ (id)filterWithInputSource:(id<NGInputStream>)_s {
+  return [[(NGFilterStream *)[self alloc] initWithInputSource:_s] autorelease];
+}
++ (id)filterWithOutputSource:(id<NGOutputStream>)_s {
+  return [[(NGFilterStream *)[self alloc] initWithOutputSource:_s] autorelease];
+}
++ (id)filterWithSource:(id<NGStream>)_s {
+  return [[(NGFilterStream *)[self alloc] initWithSource:_s] autorelease];
+}
+
+- (id)init {
+  return [self initWithSource:nil];
+}
+
+- (id)initWithSource:(id<NGStream>)_source {
+  if ((self = [super init])) {
+    self->source = [_source retain];
+
+    if ([source isKindOfClass:[NSObject class]]) {
+      self->readBytes  = (NGIOReadMethodType)
+        [(NSObject *)self->source methodForSelector:@selector(readBytes:count:)];
+      self->writeBytes = (NGIOWriteMethodType)
+        [(NSObject *)self->source methodForSelector:@selector(writeBytes:count:)];
+    }
+  }
+  return self;
+}
+
+- (id)initWithInputSource:(id<NGInputStream>)_source {
+  if ((self = [super init])) {
+    self->source = [_source retain];
+
+    if ([source isKindOfClass:[NSObject class]]) {
+      self->readBytes  = (NGIOReadMethodType)
+        [(NSObject *)self->source methodForSelector:@selector(readBytes:count:)];
+    }
+  }
+  return self;
+}
+- (id)initWithOutputSource:(id<NGOutputStream>)_source {
+  if ((self = [super init])) {
+    self->source = [_source retain];
+
+    if ([source isKindOfClass:[NSObject class]]) {
+      self->writeBytes  = (NGIOWriteMethodType)
+        [(NSObject *)self->source methodForSelector:@selector(writeBytes:count:)];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->source release];
+  self->readBytes  = NULL;
+  self->writeBytes = NULL;
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id<NGInputStream>)inputStream {
+  return [self source];
+}
+- (id<NGOutputStream>)outputStream {
+  return [self source];
+}
+- (id<NGStream>)source {
+  return self->source;
+}
+
+/* primitives */
+
+- (NSException *)lastException {
+  return [self->source lastException];
+}
+- (void)resetLastException {
+  [self->source resetLastException];
+}
+- (void)setLastException:(NSException *)_exception {
+  [self->source setLastException:_exception];
+}
+
+- (BOOL)isOpen {
+  return [self->source isOpen];
+}
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  if (self->readBytes)
+    return (unsigned)readBytes(self->source, _cmd, _buf, _len);
+  else
+    return [self->source readBytes:_buf count:_len];
+}
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  if (self->writeBytes)
+    return (unsigned)writeBytes(self->source, _cmd, _buf, _len);
+  else
+    return [self->source writeBytes:_buf count:_len];
+}
+
+- (BOOL)flush {
+  return [self->source flush];
+}
+- (BOOL)close {
+  return [((NGStream *)self->source) close];
+}
+
+- (NGStreamMode)mode {
+  return [(NGStream *)self->source mode];
+}
+- (BOOL)isRootStream {
+  return NO;
+}
+
+// all other things are forward
+
+- (void)forwardInvocation:(NSInvocation *)_invocation {
+  if ([self->source respondsToSelector:[_invocation selector]]) {
+    [_invocation setTarget:self->source];
+    [_invocation invoke];
+  }
+  else
+    [self doesNotRecognizeSelector:[_invocation selector]];
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<%@[0x%08X] source=%@ mode=%@>",
+                     NSStringFromClass([self class]), (unsigned)self,
+                     self->source ? (id)self->source : (id)@"nil",
+                     [self modeDescription]];
+}
+
+@end /* NGFilterStream */
diff --git a/skyrix-core/NGStreams/NGFilterTextStream.m b/skyrix-core/NGStreams/NGFilterTextStream.m
new file mode 100644 (file)
index 0000000..ae1b76b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGFilterTextStream.h"
+
+@implementation NGFilterTextStream
+
++ (id)textFilterWithSource:(id<NGTextStream>)_s {
+  return [[(NGFilterTextStream *)[self alloc] initWithSource:_s] autorelease];
+}
+
+- (id)initWithSource:(id<NGTextStream>)_source {
+  if ((self = [super init])) {
+    self->source = [_source retain];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithSource:nil];
+}
+
+- (void)dealloc {
+  [self->source release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id<NGTextStream>)source {
+  return self->source;
+}
+
+@end /* NGFilterTextStream */
diff --git a/skyrix-core/NGStreams/NGGZipStream.m b/skyrix-core/NGStreams/NGGZipStream.m
new file mode 100644 (file)
index 0000000..396cda8
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGStreams/NGStreamExceptions.h>
+#include <NGStreams/NGGZipStream.h>
+#include <NGExtensions/NSData+gzip.h>
+#include "common.h"
+
+#ifdef Assert
+#undef Assert
+#endif
+
+#include <zlib.h>
+#ifndef DEF_MEM_LEVEL /* zutil.h */
+#  if MAX_MEM_LEVEL >= 8
+#    define DEF_MEM_LEVEL 8
+#  else
+#    define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#  endif
+#  define OS_CODE  0x07 /* TODO: probably need to adjust that ... */
+#endif
+
+#undef Assert
+
+@implementation NGGZipStream
+
+- (id)initWithSource:(id<NGStream>)_source level:(int)_level {
+  if ((self = [super initWithSource:_source])) {
+    z_stream *zout;
+    
+    NSAssert1((_level >= NGGZipMinimalCompression &&
+               _level <= NGGZipMaximalCompression)
+              || (_level == Z_DEFAULT_COMPRESSION),
+              @"invalid compression level %i (0-9)", _level);
+
+    self->outBufLen = 2048;
+#if GNU_RUNTIME
+    self->outBuf    = NSZoneMallocAtomic([self zone], self->outBufLen);
+    self->outp       = NSZoneMallocAtomic([self zone], sizeof(z_stream));
+#else
+    self->outBuf    = NSZoneMalloc([self zone], self->outBufLen);
+    self->outp       = NSZoneMalloc([self zone], sizeof(z_stream));
+#endif
+    zout = self->outp;
+    zout->zalloc    = (alloc_func)NULL;
+    zout->zfree     = (free_func)NULL;
+    zout->opaque    = (voidpf)NULL;
+    zout->next_out  = self->outBuf;
+    zout->avail_out = self->outBufLen;
+    zout->next_in   = Z_NULL;
+    zout->avail_in  = 0;
+    self->crc       = crc32(0L, Z_NULL, 0);
+
+    if (deflateInit2(zout, _level, Z_DEFLATED, -MAX_WBITS,
+                     DEF_MEM_LEVEL, 0) != Z_OK) {
+      NSLog(@"Could not init deflate ..");
+      self = [self autorelease];
+      return nil;
+    }
+  }
+  return self;
+}
+
+- (void)gcFinalize {
+  [self close];
+}
+
+- (void)dealloc {
+  if (self->outBuf) NSZoneFree([self zone], self->outBuf);
+  if (self->outp)    NSZoneFree([self zone], self->outp);
+  [self gcFinalize];
+  [super dealloc];
+}
+
+/* headers */
+
+- (void)writeGZipHeader {
+  // gzip header
+  char buf[10] = {
+    0x1f, 0x8b,    // magic
+    Z_DEFLATED, 0, // flags
+    0, 0, 0, 0,    // time
+    0, OS_CODE     // flags
+  };
+
+  [self safeWriteBytes:buf count:10];
+}
+
+static inline void putLong(NGGZipStream *self, uLong x) {
+  int n;
+  for (n = 0; n < 4; n++) {
+    unsigned char c = (int)(x & 0xff);
+    [self safeWriteBytes:&c count:1];
+    x >>= 8;
+  }
+}
+- (void)writeGZipTrailer {
+  putLong(self, self->crc);
+  putLong(self, ((z_stream *)self->outp)->total_in);
+}
+
+/* primitives */
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len { // decoder
+  [self notImplemented:_cmd];
+  return -1;
+}
+
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len { // encoder
+  z_stream *zout = self->outp;
+  
+  if (!self->headerIsWritten) [self writeGZipHeader];
+
+  { // gz_write
+    zout->next_in   = (void*)_buf;
+    zout->avail_in  = _len;
+    
+    while (zout->avail_in > 0) {
+      int errorCode;
+      
+      if (zout->avail_out == 0) {
+        [self safeWriteBytes:self->outBuf count:self->outBufLen];
+        zout->next_out  = self->outBuf; // reset buffer position
+        zout->avail_out = self->outBufLen;
+      }
+      errorCode = deflate(self->outp, Z_NO_FLUSH);
+      if (errorCode != Z_OK) {
+        if (zout->state) deflateEnd(self->outp);
+        [NGStreamException raiseWithStream:self
+                           format:@"could not deflate chunk !"];
+      }
+    }
+    self->crc = crc32(self->crc, _buf, _len);
+  }
+  return _len;
+}
+- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len { // encoder
+  // gzip writes are safe
+  if ([self writeBytes:_buf count:_len] == NGStreamError)
+    return NO;
+  else
+    return YES;
+}
+
+- (void)close {
+  [self flush];
+  [self writeGZipTrailer];
+  if (((z_stream *)self->outp)->state) deflateEnd(self->outp);
+  [super close];
+}
+
+- (void)flush {
+  int      errorCode = Z_OK;
+  z_stream *zout     = self->outp;
+  BOOL     done      = NO;
+    
+  zout->next_in  = NULL;
+  zout->avail_in = 0; // should be zero already anyway
+    
+  while (1) {
+    int len = self->outBufLen - zout->avail_out;
+
+    if (len > 0) {
+      [self safeWriteBytes:self->outBuf count:len];
+      zout->next_out  = self->outBuf;
+      zout->avail_out = self->outBufLen;
+    }
+    if (done)
+      break;
+    errorCode = deflate(zout, Z_FINISH);
+
+    // deflate has finished flushing only when it hasn't used up
+    // all the available space in the output buffer: 
+    done = (zout->avail_out != 0 || errorCode == Z_STREAM_END);
+
+    if (errorCode != Z_OK && errorCode != Z_STREAM_END)
+      break;
+  }
+  if (errorCode != Z_STREAM_END) {
+    if (zout->state) deflateEnd(zout);
+    [NGStreamException raiseWithStream:self format:@"flush failed"];
+  }
+
+  [super flush];
+}
+
+@end
diff --git a/skyrix-core/NGStreams/NGInternetSocketAddress.m b/skyrix-core/NGStreams/NGInternetSocketAddress.m
new file mode 100644 (file)
index 0000000..31e9013
--- /dev/null
@@ -0,0 +1,661 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+
+#if HAVE_SYS_TYPES_H || defined(__APPLE__)
+#  include <sys/types.h>
+#endif
+#if HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+#endif
+#if HAVE_UNISTD_H || defined(__APPLE__)
+#  include <unistd.h>
+#endif
+#if defined(__APPLE__)
+#  include <netdb.h>
+#endif
+
+#if !defined(__CYGWIN32__)
+#  if HAVE_WINDOWS_H
+#    include <windows.h>
+#  endif
+#  if HAVE_WINSOCK_H
+#    include <winsock.h>
+#  endif
+#endif
+
+#include "NGSocketExceptions.h"
+#include "NGInternetSocketAddress.h"
+#include "NGInternetSocketDomain.h"
+#include "common.h"
+
+#if defined(HAVE_GETHOSTBYNAME_R) && !defined(linux)
+#define USE_GETHOSTBYNAME_R 1
+#endif
+
+@implementation NGInternetSocketAddress
+
+#if LIB_FOUNDATION_LIBRARY
+extern NSRecursiveLock *libFoundationLock;
+#define systemLock libFoundationLock
+#else
+static NSRecursiveLock *systemLock = nil;
+#endif
+
+static NSMapTable *nameCache = NULL;
+
++ (void)initialize {
+  [NGSocket initialize];
+  
+  if (nameCache == NULL) {
+    nameCache = NSCreateMapTable(NSIntMapKeyCallBacks,
+                                 NSObjectMapValueCallBacks,
+                                 128);
+  }
+  
+#if !LIB_FOUNDATION_LIBRARY
+  [[NSNotificationCenter defaultCenter]
+                         addObserver:self selector:@selector(taskNowMultiThreaded:)
+                         name:NSWillBecomeMultiThreadedNotification
+                         object:nil];
+#endif
+}
+
++ (void)taskNowMultiThreaded:(NSNotification *)_notification {
+  if (systemLock == nil) systemLock = [[NSRecursiveLock alloc] init];
+}
+
+static inline NSString *_nameOfLocalhost(void) {
+#if 1
+  return [[NSHost currentHost] name];
+#else
+  NSString *hostName = nil;
+
+  [systemLock lock];
+  {
+    char buffer[1024];
+    gethostname(buffer, sizeof(buffer));
+    hostName = [[NSString alloc] initWithCString:buffer];
+  }
+  [systemLock unlock];
+
+  return [hostName autorelease];
+#endif
+}
+
+- (void)_fillHost {
+  /*
+    Fill up the host and port ivars based on the INET address.
+    
+    TODO: cache some information, takes quite some time (11% of execution
+    time on MacOSX proftest) to get the hostname of an address.
+  */
+  struct hostent *hostEntity = NULL; // only valid during lock
+  NSString       *newHost  = nil;
+  int            errorCode = 0;
+  struct sockaddr_in *sockAddr = self->address;
+  
+  if (self->isHostFilled)
+    /* host is already filled .. */
+    return;
+
+#if DEBUG
+  NSAssert(self->isAddressFilled, @"either host or address must be filled ...");
+#endif
+  
+  if (sockAddr->sin_addr.s_addr != 0) { // not a wildcard address
+#if !defined(HAVE_GETHOSTBYADDR_R)
+    [systemLock lock];
+    newHost = NSMapGet(nameCache, (void *)sockAddr->sin_addr.s_addr);
+#else
+    [systemLock lock];
+    newHost = NSMapGet(nameCache, (void *)sockAddr->sin_addr.s_addr);
+    [systemLock unlock];
+#endif
+    if (newHost == nil) { 
+      BOOL done = NO;
+      
+      while (!done) {
+#if USE_GETHOSTBYNAME_R
+        struct hostent hostEntityBuffer;
+        char buffer[8200];
+       
+        hostEntity = gethostbyaddr_r((char *)&(sockAddr->sin_addr.s_addr),
+                                     4,
+                                     [[self domain] socketDomain],
+                                     &hostEntityBuffer,
+                                     buffer, 8200,
+                                     &errorCode);
+#else
+# ifdef __MINGW32__
+#   warning "doesn't resolve host name on mingw32 !"
+       hostEntity = NULL;
+       errorCode  = -1;
+# else
+        hostEntity = gethostbyaddr((char *)&(sockAddr->sin_addr.s_addr),
+                                   4,
+                                   [[self domain] socketDomain]);
+#  if defined(WIN32) && !defined(__CYGWIN32__)
+        errorCode = WSAGetLastError();
+#  else
+        errorCode = h_errno;
+#  endif
+# endif
+#endif
+        if (hostEntity == NULL) {
+          done = YES;
+          
+          switch (errorCode) {
+#ifdef __MINGW32__
+           case -1:
+             break;
+#endif
+            case HOST_NOT_FOUND:
+              NSLog(@"%s: host not found ..", __PRETTY_FUNCTION__);
+              break;
+              
+            case TRY_AGAIN:
+#ifndef __linux
+              NSLog(@"%s:\n  couldn't lookup host, retry ..",
+                    __PRETTY_FUNCTION__);
+              done = NO;
+#else
+              NSLog(@"%s: couldn't lookup host ..", __PRETTY_FUNCTION__);
+#endif
+              break;
+            
+            case NO_RECOVERY:
+              NSLog(@"%s: no recovery", __PRETTY_FUNCTION__);
+              break;
+            
+            case NO_DATA:
+              NSLog(@"%s: no data", __PRETTY_FUNCTION__);
+              break;
+            
+            default:
+              NSLog(@"%s: unknown error: h_errno=%i errno=%s",
+                    __PRETTY_FUNCTION__,
+                    errorCode, strerror(errno));
+              break;
+          }
+          
+          newHost = [NSString stringWithCString:inet_ntoa(sockAddr->sin_addr)];
+        }
+        else {
+          newHost = [NSString stringWithCString:hostEntity->h_name];
+          done = YES;
+        }
+      }
+
+      if (hostEntity == NULL) {
+        // throw could not get address ..
+        NSLog(@"could not get DNS name of address %@ in domain %@: %i",
+              newHost, [self domain], errorCode);
+      }
+      else if (newHost) {
+        /* add to cache */
+        NSMapInsert(nameCache, (void *)sockAddr->sin_addr.s_addr, newHost);
+      }
+      /* TODO: should also cache unknown IPs ! */
+    }
+    
+    //else printf("%s: CACHE HIT !\n", __PRETTY_FUNCTION__);
+    
+#if !defined(HAVE_GETHOSTBYADDR_R)
+    [systemLock unlock];
+#endif
+  }
+  else {
+    /* wildcard address */
+    newHost = nil;
+  }
+
+  ASSIGNCOPY(self->hostName, newHost);
+  self->isHostFilled = YES;
+}
+
+- (void)_fillAddress {
+  /*
+    Fill up the INET address based on the host and port ivars.
+  */
+  // throws
+  //   NGCouldNotResolveHostNameException  when a DNS lookup fails
+  
+#if defined(WIN32) && !defined(__CYGWIN32__)
+  u_long *ia = &(((struct sockaddr_in *)self->address)->sin_addr.s_addr);
+#else
+  unsigned int *ia = &(((struct sockaddr_in *)self->address)->sin_addr.s_addr);
+#endif
+  
+  if (self->isAddressFilled)
+    /* address is already filled .. */
+    return;
+  
+#if DEBUG
+  NSAssert(self->isHostFilled, @"either host or address must be filled ...");
+#endif
+  
+  if (self->hostName == nil) {
+    //  if ([self isWildcardAddress])
+    *ia = htonl(INADDR_ANY); // wildcard (0)
+    self->isAddressFilled = YES;
+  }
+  else {
+    const unsigned char *chost;
+    
+    chost = [[self hostName] cString];
+    
+    // try to interpret hostname as INET dotted address (eg 122.133.44.87)
+    *ia = inet_addr(chost);
+    
+    if ((int)*ia != -1) { // succeeded
+      self->isAddressFilled = YES;
+    }
+    else { // failed, try to interpret hostname as DNS hostname
+      BOOL didFail   = NO;
+      int  errorCode = 0;
+      int  addrType  = AF_INET;
+#if defined(HAVE_GETHOSTBYNAME_R) && !defined(linux)
+      char buffer[4096];
+      struct hostent hostEntity;
+#else
+      struct hostent *hostEntity; // only valid during lock
+#endif
+
+#if defined(HAVE_GETHOSTBYNAME_R) && !defined(linux)
+      if (gethostbyname_r(chost, &hostEntity,
+                          buffer, sizeof(buffer), &errorCode) == NULL) {
+        didFail = YES;
+      }
+      else {
+        addrType = hostEntity.h_addrtype;
+
+        if (addrType == AF_INET)
+          *ia = ((struct in_addr *)(hostEntity.h_addr_list[0]))->s_addr;
+        else
+          didFail = YES; // invalid domain (eg AF_INET6)
+      }
+#else
+      [systemLock lock];
+      {
+        if ((hostEntity = gethostbyname(chost)) == NULL) {
+          didFail = YES;
+#if defined(WIN32) && !defined(__CYGWIN32__)
+          errorCode = WSAGetLastError();
+#else
+          errorCode = h_errno;
+#endif
+        }
+        else {
+          addrType = hostEntity->h_addrtype;
+          
+          if (addrType == AF_INET)
+            *ia = ((struct in_addr *)(hostEntity->h_addr_list[0]))->s_addr;
+          else
+            didFail = YES; // invalid domain (eg AF_INET6)
+        }
+      }
+      [systemLock unlock];
+#endif
+
+      if (didFail) { // could not resolve hostname
+        // did not find host
+        NSString *reason = nil;
+
+        if (addrType != AF_INET) {
+          // invalid domain (eg AF_INET6)
+          reason = @"resolved address is in invalid domain";
+        }
+        else {
+          switch (errorCode) {
+            case HOST_NOT_FOUND: reason = @"host not found"; break;
+            case TRY_AGAIN:      reason = @"try again";      break;
+            case NO_RECOVERY:    reason = @"no recovery";    break;
+            case NO_DATA:        reason = @"no address available"; break;
+            default:
+              reason = [NSString stringWithFormat:@"error code %i", errorCode];
+              break;
+          }
+        }
+        [[[NGCouldNotResolveHostNameException alloc]
+                  initWithHostName:[self hostName] reason:reason] raise];
+      }
+
+      self->isAddressFilled = YES;
+    }
+  }
+}
+
+/* constructors */
+
++ (id)addressWithPort:(int)_port onHost:(id)_host {
+  return [[[self alloc] initWithPort:_port onHost:_host] autorelease];
+}
++ (id)addressWithPort:(int)_port {
+  return [[[self alloc] initWithPort:_port] autorelease];
+}
+
++ (id)addressWithService:(NSString *)_sname onHost:(id)_host
+  protocol:(NSString *)_protocol
+{
+  return [[[self alloc] initWithService:_sname
+                        onHost:_host
+                        protocol:_protocol]
+                        autorelease];
+}
++ (id)addressWithService:(NSString *)_sname protocol:(NSString *)_protocol {
+  return [[[self alloc] initWithService:_sname protocol:_protocol] autorelease];
+}
+
++ (id)wildcardAddress {
+  return [[[self alloc] initWithPort:0 onHost:@"*"] autorelease];
+}
++ (id)wildcardAddressWithPort:(int)_port {
+  return [[[self alloc] initWithPort:_port onHost:@"*"] autorelease];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->address = malloc(sizeof(struct sockaddr_in));
+  }
+  return self;
+}
+
+- (id)initWithPort:(int)_port onHost:(id)_host { /* designated initializer */
+  if ((self = [self init])) {
+    self->isAddressFilled = NO;
+    self->isHostFilled    = YES;
+    
+    if (_host != nil) {
+      if ([_host isKindOfClass:[NSHost class]])
+        _host = [(NSHost *)_host address];
+      
+      if ([_host isEqualToString:@"*"]) {
+        self->hostName = nil; /* wildcard host */
+      }
+      else {
+        self->hostName = [_host copy];
+        self->isWildcardHost = NO;
+      }
+    }
+    else {
+      /* wildcard host */
+      self->isWildcardHost = YES;
+    }
+    
+    ((struct sockaddr_in *)self->address)->sin_family =
+      [[self domain] socketDomain];
+    ((struct sockaddr_in *)self->address)->sin_port =
+      htons((short)(_port & 0xffff));
+  }
+  return self;
+}
+
+- (id)initWithService:(NSString *)_serviceName onHost:(id)_host
+  protocol:(NSString *)_protocol
+{
+  NSException *exc = nil;
+  int port = -1;
+#if defined(HAVE_GETSERVBYNAME_R)
+  char   buffer[2048];
+  struct servent entry;
+#else
+  struct servent *entry;
+#endif
+  
+#if defined(HAVE_GETSERVBYNAME_R)
+  if (getservbyname_r((char *)[_serviceName cString], [_protocol cString],
+                      &entry, buffer, sizeof(buffer)) == NULL) {
+    exc = [[NGDidNotFindServiceException alloc] initWithServiceName:_serviceName];
+  }
+  else
+    port = entry.s_port;
+#else
+  [systemLock lock];
+  {
+    entry = getservbyname((char *)[_serviceName cString], [_protocol cString]);
+    if (entry == NULL)
+      exc = [[NGDidNotFindServiceException alloc] initWithServiceName:_serviceName];
+    else
+      port = entry->s_port;
+  }
+  [systemLock unlock];
+#endif
+
+  if (exc) {
+    self = [self autorelease];
+    [exc raise];
+    return nil;
+  }
+  return [self initWithPort:port onHost:_host];
+}
+
+- (id)initWithPort:(int)_port {
+  return [self initWithPort:_port onHost:_nameOfLocalhost()];
+}
+
+- (id)initWithService:(NSString *)_serviceName protocol:(NSString *)_protocol {
+  return [self initWithService:_serviceName
+               onHost:_nameOfLocalhost()
+               protocol:_protocol];
+}
+
+- (id)initWithDomain:(id)_domain
+  internalRepresentation:(void *)_representation
+  size:(int)_length
+{
+  struct sockaddr_in *sockAddr = _representation;
+#if DEBUG
+  NSAssert(_length == sizeof(struct sockaddr_in),
+           @"invalid socket address length");
+#else
+  if (_length != sizeof(struct sockaddr_in)) {
+    NSLog(@"%s: got invalid sockaddr_in size ...", __PRETTY_FUNCTION__);
+    [self release];
+    return nil;
+  }
+#endif
+  
+  if ((self = [self init]) == nil)
+    return nil;
+  
+  self->isHostFilled = NO; /* need to lookup DNS */
+  
+  /* fill address */
+  
+  self->isAddressFilled = YES;
+  memcpy(self->address, _representation, sizeof(struct sockaddr_in));
+  
+  if (sockAddr->sin_addr.s_addr != 0) {
+    /* not a wildcard address */
+    self->isWildcardHost = NO;
+  }
+  else {
+    /* wildcard address */
+    self->hostName       = nil;
+    self->isWildcardHost = YES;
+    self->isHostFilled   = YES; /* wildcard host, no DNS lookup ... */
+  }
+  
+  return self;
+}
+
+- (void)dealloc {
+  [self->hostName release];
+  if (self->address) free(self->address);
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)hostName {
+  if (!self->isHostFilled) [self _fillHost];
+  return [[self->hostName copy] autorelease];
+}
+- (NSString *)address {
+#if defined(WIN32) && !defined(__CYGWIN32__)
+  u_long *ia;
+  ia = (u_long *)&(((struct sockaddr_in *)self->address)->sin_addr.s_addr);
+#else
+  unsigned int ia;
+  ia = (unsigned int)&(((struct sockaddr_in *)self->address)->sin_addr.s_addr);
+#endif
+
+  if (self->hostName == nil) /* wildcard */
+    return nil;
+  
+  if (!self->isAddressFilled)
+    [self _fillAddress];
+
+  {
+    char     *ptr = NULL;
+    NSString *str = nil;
+    
+    [systemLock lock];
+    {
+      ptr = inet_ntoa(*((struct in_addr *)ia));
+      str = [NSString stringWithCString:ptr];
+    }
+    [systemLock unlock];
+
+    return str;
+  }
+}
+
+- (int)port {
+  /* how to do ? */
+  if (!self->isAddressFilled)
+    [self _fillAddress];
+  return ntohs(((struct sockaddr_in *)self->address)->sin_port);
+}
+
+- (BOOL)isWildcardAddress {
+  if (self->isWildcardHost) return YES;
+  return ([self hostName] == nil) || ([self port] == 0);
+}
+
+/* NGSocketAddress protocol */
+
+- (void *)internalAddressRepresentation {
+  // throws
+  //   NGCouldNotResolveHostNameException  when a DNS lookup fails
+  
+  if (!self->isAddressFilled)
+    [self _fillAddress];
+  
+  return self->address;
+}
+
+- (int)addressRepresentationSize {
+  return [[self domain] addressRepresentationSize];
+}
+- (id)domain {
+  static id domain = nil;
+  if (domain == nil) domain = [[NGInternetSocketDomain domain] retain];
+  return domain;
+}
+
+/* comparing */
+
+- (unsigned)hash {
+  return [self port];
+}
+
+- (BOOL)isEqualToAddress:(NGInternetSocketAddress *)_otherAddress {
+  if (self == _otherAddress)
+    return YES;
+  if (![[_otherAddress hostName] isEqualToString:[self hostName]])
+    return NO;
+  if ([_otherAddress port] != [self port])
+    return NO;
+  return YES;
+}
+
+- (BOOL)isEqual:(id)_object {
+  if (_object == self) return YES;
+  if ([_object class] != [self class]) return NO;
+  return [self isEqualToAddress:_object];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  // socket addresses are immutable, therefore just retain self
+  return [self retain];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_encoder {
+  int aPort = [self port];
+  
+  [_encoder encodeValueOfObjCType:@encode(int) at:&aPort];
+  [_encoder encodeObject:[self hostName]];
+}
+- (id)initWithCoder:(NSCoder *)_decoder {
+  int aPort;
+  id  aHost;
+
+  [_decoder decodeValueOfObjCType:@encode(int) at:&aPort];
+  aHost = [_decoder decodeObject];
+
+  return [self initWithPort:aPort onHost:aHost];
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  NSString *name = [self hostName];
+  if (name == nil) name = @"*";
+  return [NSString stringWithFormat:@"%@:%i", name, [self port]];
+}
+
+- (NSString *)description {
+  NSString *name = [self hostName];
+
+  if (name == nil) name = @"*";
+  
+  return [NSString stringWithFormat:@"<InetSocketAddress: %@:%i>",
+                     name, [self port]];
+}
+
+@end /* NGInternetSocketAddress */
+
+@implementation NGActiveSocket(NGInternetActiveSocket)
+
++ (id)socketConnectedToPort:(int)_port onHost:(id)_host {
+  // this method calls +socketConnectedToAddress: with an 
+  // NGInternetSocketAddress
+  
+  return [self socketConnectedToAddress:
+                 [NGInternetSocketAddress addressWithPort:_port onHost:_host]];
+}
+
+- (BOOL)connectToPort:(int)_port onHost:(id)_host {
+  // this method calls -connectToAddress: with an NGInternetSocketAddress
+  
+  return [self connectToAddress:
+                 [NGInternetSocketAddress addressWithPort:_port onHost:_host]];
+}
+
+@end /* NGActiveSocket(NGInternetActiveSocket) */
diff --git a/skyrix-core/NGStreams/NGInternetSocketDomain.m b/skyrix-core/NGStreams/NGInternetSocketDomain.m
new file mode 100644 (file)
index 0000000..dd7d1c9
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGInternetSocketDomain.h"
+#include "NGInternetSocketAddress.h"
+#include "common.h"
+
+#ifndef __MINGW32__
+#  include <netinet/in.h>
+#endif
+
+@implementation NGInternetSocketDomain
+
+static NGInternetSocketDomain *domain = nil;
+
++ (int)version {
+  return 1;
+}
++ (void)initialize {
+  if (domain == nil) domain = [[NGInternetSocketDomain alloc] init];
+}
++ (id)domain {
+  return domain;
+}
+
+/* NGSocketDomain */
+
+- (id<NGSocketAddress>)addressWithRepresentation:(void *)_data
+  size:(unsigned int)_size
+{
+  NGInternetSocketAddress *address = nil;
+  
+  if ((unsigned int)[self addressRepresentationSize] != _size) {
+    NSLog(@"%@: invalid address size %i ..", NSStringFromSelector(_cmd), _size);
+    return nil;
+  }
+  
+  address = [[NGInternetSocketAddress allocWithZone:[self zone]]
+                                      initWithDomain:self
+                                      internalRepresentation:_data
+                                      size:_size];
+  return [address autorelease];
+}
+
+- (BOOL)prepareAddress:(id<NGSocketAddress>)_address
+  forBindWithSocket:(id<NGSocket>)_socket
+{
+  // nothing to prepare
+  return YES;
+}
+- (BOOL)cleanupAddress:(id<NGSocketAddress>)_address
+  afterCloseOfSocket:(id<NGSocket>)_socket
+{
+  // nothing to cleanup
+  return YES;
+}
+
+- (int)socketDomain {
+  return AF_INET;
+}
+
+- (int)addressRepresentationSize {
+  return sizeof(struct sockaddr_in);
+}
+
+- (int)protocol {
+  return 0;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  /* domain objects are immutable, just retain on copy */
+  return [self retain];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_encoder {
+}
+- (id)initWithCoder:(NSCoder *)_decoder {
+  [self release]; self = nil;
+  return [domain retain];
+}
+
+- (id)awakeAfterUsingCoder:(NSCoder *)_decoder {
+  if (self != domain) {
+    [self release]; self = nil;
+    return [domain retain];
+  }
+  else
+    return self;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<InternetDomain[0x%08X]>", (unsigned)self];
+}
+
+@end /* NGInternetSocketDomain */
diff --git a/skyrix-core/NGStreams/NGLocalSocketAddress.m b/skyrix-core/NGStreams/NGLocalSocketAddress.m
new file mode 100644 (file)
index 0000000..3b92b3a
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+  Copyright (C) 2000-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$
+
+#if !defined(WIN32) || defined(__CYGWIN32__)
+
+#include "NGSocketExceptions.h"
+#include "NGLocalSocketAddress.h"
+#include "NGLocalSocketDomain.h"
+#import <Foundation/NSString.h>
+
+#if LIB_FOUNDATION_LIBRARY
+#  include <extensions/exceptions/GeneralExceptions.h>
+#endif
+
+#include "config.h"
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#  include <sys/types.h>
+#else
+#  include <sys/un.h>
+#endif
+
+#if defined(HAVE_UNISTD_H) || defined(__APPLE__)
+#  include <unistd.h>
+#endif
+
+#ifndef SUN_LEN
+#define SUN_LEN(su) \
+        (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
+
+#include "common.h"
+
+#ifndef AF_LOCAL
+#  define AF_LOCAL AF_UNIX
+#endif
+
+#if defined(__WIN32__) && !defined(__CYGWIN32__)
+static NSString *socketDirectoryPath = @"\\\\.\\pipe\\";
+#else
+static NSString *socketDirectoryPath = @"/tmp";
+#endif
+
+@implementation NGLocalSocketAddress
+
++ (id)addressWithPath:(NSString *)_p {
+  return [[(NGLocalSocketAddress *)[self alloc] initWithPath:_p] autorelease];
+}
++ (id)address {
+  return [[[self alloc] init] autorelease];
+}
+
+- (id)initWithPath:(NSString *)_path {
+  if ((self = [super init])) {
+    self->address = calloc(1, sizeof(struct sockaddr_un));
+    
+    memset(self->address, 0, sizeof(struct sockaddr_un));
+    
+#if defined(__WIN32__) && !defined(__CYGWIN32__)
+    self->path = [_path copyWithZone:[self zone]];
+#else
+    if ([_path cStringLength] >=
+        sizeof(((struct sockaddr_un *)self->address)->sun_path)) {
+      
+      NSLog(@"LocalDomain name too long: maxlen=%i, len=%i, path=%@",
+            sizeof(((struct sockaddr_un *)self->address)->sun_path),
+            [_path cStringLength],
+            _path);
+#if LIB_FOUNDATION_LIBRARY      
+      [[[InvalidArgumentException alloc] initWithReason:
+           @"path to long as local domain socket address !"] raise];
+#else
+      [NSException raise:NSInvalidArgumentException
+                   format:@"path to long as local domain socket address !"];
+#endif
+      [self release];
+      return nil;
+    }
+    
+    ((struct sockaddr_un *)self->address)->sun_family =
+      [[self domain] socketDomain];
+
+    [_path getCString:((struct sockaddr_un *)self->address)->sun_path
+           maxLength:sizeof(((struct sockaddr_un *)self->address)->sun_path)];
+#endif
+  }
+  return self;
+}
+
+- (id)init {
+  int      addressCounter = 0;
+  NSString *newPath;
+  
+  newPath = [NSString stringWithFormat:@"_ngsocket_%08X_%08X_%03d",
+                        getpid(), [NSThread currentThread], addressCounter];
+  newPath = [socketDirectoryPath stringByAppendingPathComponent:newPath];
+
+  return [self initWithPath:newPath];
+}
+
+- (id)initWithDomain:(id)_domain
+  internalRepresentation:(void *)_representation
+  size:(int)_length
+{
+  // this method is used by the address factory
+  struct sockaddr_un *nun = _representation;
+  NSString *path;
+
+  path = (_length < 3)
+    ? @""
+    : [NSString stringWithCString:nun->sun_path];
+  
+  return [self initWithPath:path];
+}
+
+- (void)dealloc {
+  if (self->address) free(self->address);
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)path {
+  const char *sp;
+
+  sp = ((struct sockaddr_un *)self->address)->sun_path;
+  if (strlen(sp) == 0)
+    return @"";
+  
+  return [NSString stringWithCString:sp];
+}
+
+/* operations */
+
+- (void)deletePath {
+  const char *sp;
+  
+  sp = ((struct sockaddr_un *)self->address)->sun_path;
+  if (strlen(sp) == 0)
+    return;
+  
+  unlink(sp);
+}
+
+// NGSocketAddress protocol
+
+- (void *)internalAddressRepresentation {
+  return self->address;
+}
+- (int)addressRepresentationSize { // varies in length
+  return SUN_LEN(((struct sockaddr_un *)self->address));
+}
+- (id)domain {
+  return [NGLocalSocketDomain domain];
+}
+
+/* test for accessibility */
+
+- (BOOL)canSendOnAddress {
+  return (access(((struct sockaddr_un *)self->address)->sun_path, W_OK) == 0)
+    ? YES : NO;
+}
+- (BOOL)canReceiveOnAddress {
+  return (access(((struct sockaddr_un *)self->address)->sun_path, R_OK) == 0)
+    ? YES : NO;
+}
+
+/* testing for equality */
+
+- (BOOL)isEqualToAddress:(NGLocalSocketAddress *)_addr {
+  return [[_addr path] isEqualToString:[self path]];
+}
+
+- (BOOL)isEqual:(id)_object {
+  if (_object == self) return YES;
+  if ([_object class] != [self class]) return NO;
+  return [self isEqualToAddress:_object];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  /* socket addresses are immutable, just retain on copy ... */
+  return [self retain];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_encoder {
+  [_encoder encodeObject:[[NSHost currentHost] name]];
+  [_encoder encodeObject:[self path]];
+}
+
+- (id)initWithCoder:(NSCoder *)_decoder {
+  NSString *hostName = [_decoder decodeObject];
+  NSString *path     = [_decoder decodeObject];
+
+  NSAssert([path isKindOfClass:[NSString class]], @"path must be a string ..");
+
+  if (![hostName isEqualToString:[[NSHost currentHost] name]]) {
+    NSLog(@"unarchived local socket address on a different host, "
+          @"encoded on %@, decoded on %@ (path=%@)",
+          hostName, [[NSHost currentHost] name], path);
+  }
+
+  return [self initWithPath:path];
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  NSString *p = [self path];
+  return [p length] == 0 ? @"*" : (id)p;
+}
+
+- (NSString *)description {
+  NSString *p = [self path];
+  
+  if ([p length] == 0)
+    p = @"[no path]";
+
+  return [NSString stringWithFormat:@"<0x%08X[%@]: %@>",
+                     self, NSStringFromClass([self class]),
+                     p];
+}
+
+@end
+
+#endif /* !WIN32 */
diff --git a/skyrix-core/NGStreams/NGLocalSocketDomain.m b/skyrix-core/NGStreams/NGLocalSocketDomain.m
new file mode 100644 (file)
index 0000000..9d54b54
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#if !defined(WIN32)
+
+#include "NGLocalSocketDomain.h"
+#include "NGLocalSocketAddress.h"
+#include "NGSocket.h"
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#  include <sys/types.h>
+#  include <sys/socket.h>
+#else
+#  include <sys/un.h>
+#endif
+
+#include "common.h"
+
+@implementation NGLocalSocketDomain
+
+static NGLocalSocketDomain *domain = nil;
+
++ (void)initialize {
+  BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+    [NGSocket initialize];
+    domain = [[NGLocalSocketDomain alloc] init];
+  }
+}
+  
++ (id)domain {
+  return domain;
+}
+
+// NGSocketDomain
+
+- (id<NGSocketAddress>)addressWithRepresentation:(void *)_data
+  size:(unsigned int)_size
+{
+  NGLocalSocketAddress *address = nil;
+
+  address = [[NGLocalSocketAddress alloc] initWithDomain:self
+                                          internalRepresentation:_data
+                                          size:_size];
+  return AUTORELEASE(address);
+}
+
+- (BOOL)prepareAddress:(id<NGSocketAddress>)_address
+  forBindWithSocket:(id<NGSocket>)_socket
+{
+  if ([_socket conformsToProtocol:@protocol(NGPassiveSocket)]) {
+    NSString *path = [(NGLocalSocketAddress *)_address path];
+
+    // ignore errors ..
+    [[NSFileManager defaultManager] removeFileAtPath:path handler:nil];
+  }
+  return YES;
+}
+- (BOOL)cleanupAddress:(id<NGSocketAddress>)_address
+  afterCloseOfSocket:(id<NGSocket>)_socket
+{
+  if ([_socket conformsToProtocol:@protocol(NGPassiveSocket)]) {
+#if 0
+    NSString *path = [(NGLocalSocketAddress *)_address path];
+
+    // ignore errors ..
+    [[NSFileManager defaultManager] removeFileAtPath:path handler:nil];
+#endif
+  }
+  return YES;
+}
+
+- (int)socketDomain {
+  return AF_LOCAL;
+}
+
+- (int)addressRepresentationSize { // maximum size
+  return sizeof(struct sockaddr_un);
+}
+
+- (int)protocol {
+  return 0;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  /* domains are immutable, just return self on copy .. */
+  return [self retain];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_encoder {
+}
+- (id)initWithCoder:(NSCoder *)_decoder {
+  [self release]; self = nil;
+  return [domain retain]; /* replace with singleton */
+}
+
+- (id)awakeAfterUsingCoder:(NSCoder *)_decoder {
+  if (self != domain) {
+    [self release]; self = nil;
+    return [domain retain]; /* replace with singleton */
+  }
+  else
+    return self;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<UnixDomain: self=0x%08X>", (unsigned)self];
+}
+
+@end /* NGLocalSocketDomain */
+
+#endif // !WIN32
diff --git a/skyrix-core/NGStreams/NGLockingStream.m b/skyrix-core/NGStreams/NGLockingStream.m
new file mode 100644 (file)
index 0000000..d5f0cc4
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGLockingStream.h"
+
+@implementation NGLockingStream
+
++ (id)filterWithSource:(id<NGStream>)_source lock:(id<NSObject,NSLocking>)_lock {
+  return [[[self alloc] initWithSource:_source lock:_lock] autorelease];
+}
+
+- (id)initWithSource:(id<NGStream>)_source lock:(id<NSObject,NSLocking>)_lock {
+  if ((self = [super initWithSource:_source])) {
+    if (_lock == nil) {
+      readLock  = [[NSRecursiveLock allocWithZone:[self zone]] init];
+      writeLock = [readLock retain];
+    }
+    else {
+      readLock  = [_lock    retain];
+      writeLock = [readLock retain];
+    }
+  }
+  return self;
+}
+
+- (id)initWithSource:(id<NGStream>)_source {
+  return [self initWithSource:_source lock:nil];
+}
+
+- (void)dealloc {
+  [self->readLock  release];
+  [self->writeLock release];
+  [super dealloc];
+}
+
+// primitives
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  volatile unsigned result = 0;
+
+  [readLock lock];
+
+  NS_DURING {
+    result = (readBytes != NULL)
+      ? (unsigned)readBytes(source, _cmd, _buf, _len)
+      : [source readBytes:_buf count:_len];
+  }
+  NS_HANDLER {
+    [readLock unlock];
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+  [readLock unlock];
+
+  return result;
+}
+
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  volatile unsigned result = 0;
+
+  [writeLock lock];
+
+  NS_DURING {
+    result = (writeBytes != NULL)
+      ? (unsigned)writeBytes(source, _cmd, _buf, _len)
+      : [source writeBytes:_buf count:_len];
+  }
+  NS_HANDLER {
+    [writeLock unlock];
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+  [writeLock unlock];
+
+  return result;
+}
+
+- (BOOL)flush {
+  BOOL res = NO;
+  
+  [writeLock lock];
+
+  NS_DURING {
+    res = [super flush];
+  }
+  NS_HANDLER {
+    [writeLock unlock];
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+  [writeLock unlock];
+  return res;
+}
+
+- (BOOL)safeReadBytes:(void *)_buf  count:(unsigned)_len {
+  BOOL res;
+  
+  [readLock lock];
+
+  NS_DURING {
+    *(&res) = [super safeReadBytes:_buf count:_len];
+  }
+  NS_HANDLER {
+    [readLock unlock];
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+  [readLock unlock];
+
+  return res;
+}
+
+- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len {
+  BOOL res = NO;
+  
+  [writeLock lock];
+
+  NS_DURING {
+    res = [super safeWriteBytes:_buf count:_len];
+  }
+  NS_HANDLER {
+    [writeLock unlock];
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+  [writeLock unlock];
+  return res;
+}
+
+@end /* NGLockingStream */
diff --git a/skyrix-core/NGStreams/NGNetUtilities.m b/skyrix-core/NGStreams/NGNetUtilities.m
new file mode 100644 (file)
index 0000000..330ef0f
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGNetUtilities.h"
+#include "NGInternetSocketAddress.h"
+#include "NGLocalSocketAddress.h"
+#include "common.h"
+
+id<NGSocketAddress> NGSocketAddressFromString(NSString *_string) {
+  const unsigned char *cstr = [_string cString];
+  if (cstr == NULL)         return nil;
+  if ([_string length] < 1) return nil;
+
+  {
+    const unsigned char *tmp = index(cstr, ':');
+    
+    if (tmp) { // INET socket
+      NSString *hostName = nil;
+
+      if (((tmp - cstr) == 1) && (*cstr == '*'))
+        hostName = nil; // wildcard host
+      else
+        hostName = [NSString stringWithCString:cstr length:(tmp - cstr)];
+
+      // check what comes after colon
+      if (isdigit(tmp[1])) {
+        // a port
+        int port = atoi(tmp + 1);
+        return [NGInternetSocketAddress addressWithPort:port onHost:hostName];
+      }
+      else {
+        // a service or 'auto' for auto-assigned ports
+        const unsigned char *tmp2 = index((tmp + 1), '/');
+        NSString *protocol = @"tcp";
+        NSString *service;
+
+        tmp++;
+
+        if (tmp2 == NULL)
+          service  = [NSString stringWithCString:tmp];
+        else {
+          service  = [NSString stringWithCString:tmp length:(tmp2 - tmp)];
+          protocol = [NSString stringWithCString:(tmp2 + 1)];
+        }
+
+        if ([service isEqualToString:@"auto"])
+          return [NGInternetSocketAddress addressWithPort:0
+                                          onHost:hostName];
+        
+        return [NGInternetSocketAddress addressWithService:service
+                                        onHost:hostName
+                                        protocol:protocol];
+      }
+    }
+
+#if !defined(WIN32)
+    if ([_string isAbsolutePath])
+      return [NGLocalSocketAddress addressWithPath:_string];
+#endif
+  }
+  return nil;
+}
diff --git a/skyrix-core/NGStreams/NGPassiveSocket.m b/skyrix-core/NGStreams/NGPassiveSocket.m
new file mode 100644 (file)
index 0000000..bee820d
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGPassiveSocket.h"
+#include "NGSocketExceptions.h"
+#include "NGActiveSocket.h"
+#include "NGSocket+private.h"
+
+#if defined(__APPLE__)
+#  include <sys/types.h>
+#  include <sys/socket.h>
+#endif
+
+#if HAVE_SYS_ERRNO_H || defined(__APPLE__)
+#  include <sys/errno.h>
+#endif
+
+#include "common.h"
+
+@interface NGActiveSocket(privateMethods)
+
+- (id)_initWithDescriptor:(int)_fd
+  localAddress:(id<NGSocketAddress>)_local
+  remoteAddress:(id<NGSocketAddress>)_remote;
+
+@end
+
+@implementation NGPassiveSocket
+
++ (id)socketBoundToAddress:(id<NGSocketAddress>)_address {
+  volatile id sock;
+  
+  sock = [[[self alloc] initWithDomain:[_address domain]] autorelease];
+  [sock bindToAddress:_address];
+  return sock;
+}
+
+- (id)initWithDomain:(id<NGSocketDomain>)_domain { // designated initializer
+  if ((self = [super initWithDomain:_domain])) {
+    backlogSize = -1; // -1 means 'not listening'
+    
+    if ([NSThread isMultiThreaded])
+      acceptLock = [[NSLock allocWithZone:[self zone]] init];
+    else {
+      acceptLock = nil;
+      [[NSNotificationCenter defaultCenter]
+                             addObserver:self
+                             selector:@selector(taskNowMultiThreaded:)
+                             name:NSWillBecomeMultiThreadedNotification
+                             object:nil];
+    }
+
+    if (self->fd != NGInvalidSocketDescriptor) {
+      int i_yes = 1;
+      
+      if (setsockopt(self->fd, SOL_SOCKET, SO_REUSEADDR,
+                     (void *)&i_yes, sizeof(int)) != 0) {
+        NSLog(@"WARNING: could not set SO_REUSEADDR option for socket %@: %s",
+              self, strerror(errno));
+      }
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter]
+                         removeObserver:self
+                         name:NSWillBecomeMultiThreadedNotification
+                         object:nil];
+  
+  [self->acceptLock release];
+  [super dealloc];
+}
+
+- (void)taskNowMultiThreaded:(NSNotification *)_notification {
+  if (acceptLock == nil) acceptLock = [[NSLock alloc] init];
+}
+
+// accessors
+
+- (BOOL)isListening {
+  return (backlogSize != -1);
+}
+- (BOOL)isOpen {
+  return [self isListening];
+}
+
+- (id<NGSocketAddress>)localAddress {
+  return localAddress;
+}
+
+- (int)socketType {
+  return SOCK_STREAM;
+}
+
+/* operations */
+
+#if defined(WIN32) && !defined(__CYGWIN32__)
+- (NSString *)reasonForLastError {
+  int errorCode = WSAGetLastError();
+
+  switch (errorCode) {
+    case WSAEBADF:
+      return @"not a valid socket descriptor";
+    case WSAENOTSOCK:
+      return @"descriptor is not a socket descriptor";
+    case WSAEOPNOTSUPP:
+      return @"socket does not support listen";
+    case WSAEINTR:
+      return\a @"interrupted by signal";
+    case WSAEMFILE:
+      return @"descriptor table is full";
+
+    default:
+      return [NSString stringWithCString:strerror(errorCode)];
+  }
+}
+#else
+- (NSString *)reasonForLastError {
+  int errorCode = errno;
+  
+  switch (errorCode) {
+    case EBADF:
+      return @"not a valid socket descriptor";
+    case ENOTSOCK:
+      return @"descriptor is not a socket descriptor";
+    case EOPNOTSUPP:
+      return @"socket does not support listen";
+    case EINTR:
+      return @"interrupted by signal";
+    case EMFILE:
+      return @"descriptor table is full";
+    case EPROTONOSUPPORT:
+      return @"The protocol is not supported by the address family or "
+             @"implementation";
+    case EPROTOTYPE:
+      return @"The socket type is not supported by the protocol";
+
+    default:
+      return [NSString stringWithCString:strerror(errorCode)];
+  }
+}
+#endif
+
+- (BOOL)listenWithBacklog:(int)_backlogSize {
+  // throws
+  //   NGSocketIsAlreadyListeningException  when the socket is in the listen state
+  //   NGCouldNotListenException            when the listen call failed
+  
+  if ([self isListening]) {
+    [[[NGSocketIsAlreadyListeningException alloc]
+              initWithReason:@"already called listen" socket:self] raise];
+    return NO;
+  }
+
+  if (listen([self fileDescriptor], _backlogSize) != 0) {
+    NSString *reason;
+    reason = [self reasonForLastError];
+    reason = [@"Could not listen: %@" stringByAppendingString:reason];
+    
+    [[[NGCouldNotListenException alloc]
+              initWithReason:reason socket:self] raise];
+    return NO;
+  }
+
+  /* set backlog size (and mark socket as 'listening') */
+  self->backlogSize = _backlogSize;
+  return YES;
+}
+
+- (id<NGActiveSocket>)accept {
+  // throws
+  //   NGCouldNotAcceptException  when the socket is not listening
+  //   NGCouldNotAcceptException  when the accept call failed
+
+  id<NGActiveSocket> socket;
+  *(&socket) = nil;
+  
+  if (![self isListening]) {
+    [[[NGCouldNotAcceptException alloc]
+              initWithReason:@"socket is not listening" socket:self] raise];
+  }
+  
+  SYNCHRONIZED(self->acceptLock) {
+    id<NGSocketAddress> local  = nil;
+    id<NGSocketAddress> remote = nil;
+    int  len;
+    char *data;
+    int  newFd = NGInvalidSocketDescriptor;
+
+    len   = [[self domain] addressRepresentationSize];
+    data = calloc(1, len + 1);
+    
+    if ((newFd = accept(fd, (void *)data, &len)) == -1) {
+      // call failed
+      NSString *reason = nil;
+      reason = [self reasonForLastError];
+      reason = [@"Could not accept: " stringByAppendingString:reason];
+
+      [[[NGCouldNotAcceptException alloc]
+                initWithReason:reason socket:self] raise];
+    }
+
+    /* produce remote socket address object */
+    remote = [[self domain] addressWithRepresentation:(void *)data
+                            size:len];
+    
+    // getsockname if wildcard-IP-bind to get local IP address assigned
+    // to the connection
+    len = [[self domain] addressRepresentationSize];
+    if (getsockname(newFd, (void *)data, &len) != 0) { // function is MT-safe
+      [[[NGSocketException alloc]
+                initWithReason:@"could not get local socket name" socket:self]
+                raise];
+    }
+    local = [[self domain] addressWithRepresentation:(void *)data size:len];
+
+    if (data) {
+      free(data);
+      data = NULL;
+    }
+    
+    socket = [[NGActiveSocket alloc]
+                              _initWithDescriptor:newFd
+                              localAddress:local
+                              remoteAddress:remote];
+    socket = [socket autorelease];
+  }
+  END_SYNCHRONIZED;
+  return socket;
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<PassiveSocket: address=%@>",
+                     [self localAddress]];
+}
+
+@end /* NGPassiveSocket */
diff --git a/skyrix-core/NGStreams/NGSocket+private.h b/skyrix-core/NGStreams/NGSocket+private.h
new file mode 100644 (file)
index 0000000..13b394e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGSocket.h"
+
+@interface NGSocket(PrivateMethods)
+
+#if defined(WIN32)
+- (id)_initWithDomain:(id<NGSocketDomain>)_domain descriptor:(SOCKET)_fd;
+#else
+- (id)_initWithDomain:(id<NGSocketDomain>)_domain descriptor:(int)_fd;
+#endif
+
+- (void)setOption:(int)_option value:(void *)_value len:(int)_len;
+- (void)getOption:(int)_option value:(void *)_value len:(int *)_len;
+- (void)setOption:(int)_option level:(int)_level value:(void *)_value len:(int)_len;
+- (void)getOption:(int)_option level:(int)_level value:(void *)_val len:(int *)_len;
+
+@end
diff --git a/skyrix-core/NGStreams/NGSocket.m b/skyrix-core/NGStreams/NGSocket.m
new file mode 100644 (file)
index 0000000..ec8931c
--- /dev/null
@@ -0,0 +1,784 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGStreams/NGConcreteStreamFileHandle.h>
+#include "NGSocketExceptions.h"
+#include "NGSocket.h"
+#include "NGSocket+private.h"
+#include "NGInternetSocketDomain.h"
+
+#include "config.h"
+#if defined(__APPLE__)
+#  include <sys/types.h>
+#  include <sys/socket.h>
+#endif
+
+#if defined(HAVE_UNISTD_H) || defined(__APPLE__)
+#  include <unistd.h>
+#endif
+
+#include "common.h"
+
+@interface _NGConcreteSocketFileHandle : NGConcreteStreamFileHandle
+{
+}
+
+- (id)initWithSocket:(id<NGSocket>)_socket;
+
+@end
+
+@interface NSObject(WildcardAddresses)
+- (BOOL)isWildcardAddress;
+@end
+
+#ifdef __s390__
+#  define SockAddrLenType socklen_t
+#elif __APPLE__
+#  define SockAddrLenType int
+#else
+#  define SockAddrLenType size_t
+#endif
+
+@implementation NGSocket
+
+#if defined(WIN32) && !defined(__CYGWIN32__)
+
+static BOOL    isInitialized = NO;
+static WSADATA wsaData;
+
++ (int)version {
+  return 2;
+}
+
++ (void)initialize {
+  if (!isInitialized) {
+    isInitialized = YES;
+
+    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
+      NSLog(@"WARNING: Could not start Windows sockets !");
+
+    NSLog(@"WinSock version %i.%i.",
+          LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
+  }
+}
+
+static void _killWinSock(void) __attribute__((destructor));
+static void _killWinSock(void) {
+  fprintf(stderr, "killing Windows sockets ..\n");
+  if (isInitialized) {
+    WSACleanup();
+    isInitialized = NO;
+  }
+}
+
+#endif /* WIN32 */
+
++ (id)socketInDomain:(id<NGSocketDomain>)_domain {
+  return [[[self alloc] initWithDomain:_domain] autorelease];
+}
+
+- (id)init {
+  return [self initWithDomain:[NGInternetSocketDomain domain]];
+}
+
+#if defined(WIN32) && !defined(__CYGWIN32__)
+- (id)_initWithDomain:(id<NGSocketDomain>)_domain descriptor:(SOCKET)_fd {
+#else
+- (id)_initWithDomain:(id<NGSocketDomain>)_domain descriptor:(int)_fd {
+#endif
+  if ((self = [super init])) {
+    self->fd                = _fd;
+    self->flags.closeOnFree = YES;
+    self->flags.isBound     = (_fd == NGInvalidSocketDescriptor) ? NO : YES;
+    self->domain            = [_domain retain];
+
+    if (_fd == NGInvalidSocketDescriptor)
+      [self primaryCreateSocket];
+  }
+  return self;
+}
+- (id)initWithDomain:(id<NGSocketDomain>)_domain {
+  return [self _initWithDomain:_domain descriptor:NGInvalidSocketDescriptor];
+}
+
+- (void)gcFinalize {
+  if (self->flags.closeOnFree)
+    [self close];
+  else
+    NSLog(@"WARNING: socket was not 'closeOnFree' !");
+}
+
+- (void)dealloc {
+  [self gcFinalize];
+
+  [self->lastException release];
+  [self->localAddress  release];
+  [self->domain  release];
+  self->fileHandle = nil;
+  [super dealloc];
+}
+
+/* creation */
+
+- (BOOL)primaryCreateSocket {
+  // throws
+  //   NGCouldNotCreateSocketException  if the socket creation failed
+  
+  fd = socket([domain socketDomain], [self socketType], [domain protocol]);
+
+#if defined(WIN32) && !defined(__CYGWIN32__)
+  if (fd == SOCKET_ERROR) { // error
+    int e = WSAGetLastError();
+    NSString *reason = nil;
+    
+    switch (e) {
+      case WSAEACCES:
+        reason = @"Not allowed to create socket of this type";
+        break;
+      case WSAEMFILE:
+        reason = @"Could not create socket: descriptor table is full";
+        break;
+      case WSAEPROTONOSUPPORT:
+        reason = @"Could not create socket: The protocol type or the specified "
+                 @"protocol  is  not  supported within this domain";
+        break;
+      default:
+        reason = [NSString stringWithFormat:@"Could not create socket: %s",
+                             strerror(e)];
+        break;
+    }
+#else
+  if (fd == -1) { // error
+    int      e       = errno;
+    NSString *reason = nil;
+    
+    switch (e) {
+      case EACCES:
+        reason = @"Not allowed to create socket of this type";
+        break;
+      case EMFILE:
+        reason = @"Could not create socket: descriptor table is full";
+        break;
+      case ENOMEM:
+        reason = @"Could not create socket: Insufficient user memory available";
+        break;
+      case EPROTONOSUPPORT:
+        reason = @"Could not create socket: The protocol type or the specified "
+                 @"protocol  is  not  supported within this domain";
+        break;
+      default:
+        reason = [NSString stringWithFormat:@"Could not create socket: %s",
+                             strerror(e)];
+        break;
+    }
+#endif
+
+    [[[NGCouldNotCreateSocketException alloc]
+              initWithReason:reason domain:domain] raise];
+    return NO;
+  }
+  return YES;
+}
+
+- (BOOL)close {
+  if (self->fd != NGInvalidSocketDescriptor) {
+#if DEBUG && 0
+    NSLog(@"%@: closing socket fd %i", self, self->fd);
+#endif
+#if defined(WIN32) && !defined(__CYGWIN32__)
+    closesocket(self->fd);
+#else
+    close(self->fd);
+#endif
+    self->fd = NGInvalidSocketDescriptor;
+
+    if (self->flags.isBound) {
+      self->flags.isBound = NO;
+      [[self domain] cleanupAddress:self->localAddress
+                     afterCloseOfSocket:self];
+    }
+    else
+      self->flags.isBound = NO;
+  }
+  return YES;
+}
+
+/* operations */
+
+- (void)setLastException:(NSException *)_exception {
+  /* NOTE: watch out for cycles !!! */
+  // THREAD
+  ASSIGN(self->lastException, _exception);
+}
+- (NSException *)lastException {
+  // THREAD
+  return self->lastException;
+}
+- (void)resetLastException {
+  // THREAD
+  ASSIGN(self->lastException,(id)nil);
+}
+- (BOOL)primaryBindToAddress:(id<NGSocketAddress>)_address {
+  // throws
+  //   NGCouldNotBindSocketException    if the bind failed
+
+  [[self domain] prepareAddress:_address
+                 forBindWithSocket:self];
+
+  if (bind(fd,
+           (struct sockaddr *)[_address internalAddressRepresentation],
+           [_address addressRepresentationSize]) != 0) {
+    NSString *reason = nil;
+#if defined(WIN32) && !defined(__CYGWIN32__)
+    int errorCode = WSAGetLastError();
+#else    
+    int errorCode = errno;
+#endif
+
+    switch (errorCode) {
+      default:
+        reason = [NSString stringWithCString:strerror(errorCode)];
+        break;
+    }
+
+    reason = [NSString stringWithFormat:@"Could not bind to address %@: %@",
+                         _address, reason];
+    
+    [[[NGCouldNotBindSocketException alloc]
+              initWithReason:reason socket:self address:_address] raise];
+    return NO;
+  }
+
+  /* bind was successful */
+  
+  ASSIGN(self->localAddress, _address);
+  self->flags.isBound = YES;
+  return YES;
+}
+
+- (BOOL)bindToAddress:(id<NGSocketAddress>)_address {
+  // throws
+  //   NGSocketAlreadyBoundException    if the socket is already bound
+  //   NGCouldNotCreateSocketException  if the socket creation failed
+  //   NGCouldNotBindSocketException    if the bind failed
+
+  // check whether socket is already bound (either manually or by the kernel)
+  if (flags.isBound) {
+    [[[NGSocketAlreadyBoundException alloc]
+              initWithReason:@"socket is already bound." socket:self] raise];
+  }
+
+  if (_address == nil) {
+    /* let kernel bind address */
+    return [self kernelBoundAddress];
+  }
+  
+  // perform bind
+  if (![self primaryBindToAddress:_address])
+    return NO;
+  
+  /* check for wildcard port */
+  
+  if ([_address respondsToSelector:@selector(isWildcardAddress)]) {
+    if ([(id)_address isWildcardAddress]) {
+      SockAddrLenType len = [[_address domain] addressRepresentationSize];
+      char data[len]; // struct sockaddr
+      
+      if (getsockname(fd, (void *)&data, &len) == 0) { // function is MT-safe
+        id<NGSocketAddress> boundAddr;
+        
+        boundAddr = [[_address domain]
+                               addressWithRepresentation:&(data[0])
+                               size:len];
+#if 0
+        NSLog(@"got sock name (addr-len=%d, %s, %d) %@ ..",
+              len,
+              inet_ntoa( (((struct sockaddr_in *)(&data[0]))->sin_addr)),
+              ntohs(((struct sockaddr_in *)(&data[0]))->sin_port),
+              boundAddr);
+#endif   
+        ASSIGN(self->localAddress, boundAddr);
+      }
+      else {
+        // could not get local socket name, THROW
+        NSLog(@"ERROR: couldn't resolve wildcard address %@", _address);
+      }
+    }
+  }
+  return YES;
+}
+
+- (BOOL)kernelBoundAddress {
+  SockAddrLenType len = [[self domain] addressRepresentationSize];
+  char   data[len];
+  
+  // check whether socket is already bound (either manually or by the kernel)
+  if (flags.isBound) {
+    [[[NGSocketAlreadyBoundException alloc]
+              initWithReason:@"socket is already bound." socket:self] raise];
+    return NO;
+  }
+  
+#if 0
+  NSLog(@"socket: kernel bound address of %i in domain %@",
+        self->fd, [self domain]);
+#endif
+  
+  if (getsockname(self->fd, (void *)&data, &len) != 0) { // function is MT-safe
+    // could not get local socket name, THROW
+    [[[NGSocketException alloc]
+         initWithReason:@"could not get local socket name" socket:self] raise];
+    return NO;
+  }
+
+  if (self->localAddress) { // release old address
+    [self->localAddress release];
+    self->localAddress = nil;
+  }
+  self->localAddress = [[self domain] addressWithRepresentation:(void *)data
+                                      size:len];
+  self->localAddress  = [self->localAddress retain];
+  self->flags.isBound = YES;
+  return YES;
+}
+
+/* accessors */
+
+- (id<NGSocketAddress>)localAddress {
+  return self->localAddress;
+}
+
+- (BOOL)isBound {
+  return self->flags.isBound;
+}
+
+- (int)socketType {
+  [self subclassResponsibility:_cmd];
+  return -1;
+}
+
+- (id<NGSocketDomain>)domain {
+  return self->domain;
+}
+
+#if defined(WIN32) && !defined(__CYGWIN32__)
+- (SOCKET)fileDescriptor {
+#else 
+- (int)fileDescriptor {
+#endif
+  return self->fd;
+}
+
+- (void)resetFileHandle { // called by the NSFileHandle on dealloc
+  self->fileHandle = nil;
+}
+- (NSFileHandle *)fileHandle {
+  /* the filehandle will reset itself from the stream when being deallocated */
+  if (self->fileHandle == nil) {
+    self->fileHandle =
+      [(_NGConcreteSocketFileHandle *)[_NGConcreteSocketFileHandle alloc]
+                                          initWithSocket:self];
+  }
+  return [self->fileHandle autorelease];
+}
+
+/* options */
+
+- (void)setOption:(int)_option level:(int)_level value:(void *)_value len:(int)_len {
+  if (setsockopt(fd, _level, _option, _value, _len) != 0) {
+    NSString *reason = nil;
+#if defined(WIN32) && !defined(__CYGWIN32__)
+    int e = WSAGetLastError();
+
+   switch (e) {
+     case WSAEBADF:
+       reason = @"Could not set socket option, invalid file descriptor";
+       break;
+     case WSAEINVAL:
+       reason =
+         @"Could not set socket option, option is invalid or socket has been"
+         @"shut down";
+       break;
+     case WSAENOPROTOOPT:
+       reason = @"Could not set socket option, option is not supported by protocol";
+       break;
+     case WSAENOTSOCK:
+       reason = @"Could not set socket option, descriptor isn't a socket";
+       break;
+     default:
+       reason = [NSString stringWithFormat:@"Could not set socket option: %s",
+                            strerror(e)];
+       break;
+   }
+#else
+    int e = errno;
+    
+    switch (e) {
+      case EBADF:
+        reason = @"Could not set socket option, invalid file descriptor";
+        break;
+      case EINVAL:
+        reason =
+          @"Could not set socket option, option is invalid or socket has been"
+          @"shut down";
+        break;
+      case ENOPROTOOPT:
+        reason = @"Could not set socket option, option is not supported by protocol";
+        break;
+      case ENOTSOCK:
+        reason = @"Could not set socket option, descriptor isn't a socket";
+        break;
+      default:
+        reason = [NSString stringWithFormat:@"Could not set socket option: %s",
+                             strerror(e)];
+        break;
+    }
+#endif
+    [[[NGCouldNotSetSocketOptionException alloc]
+         initWithReason:reason option:_option level:_level] raise];
+  }
+}
+- (void)setOption:(int)_option value:(void *)_value len:(int)_len {
+  [self setOption:_option level:SOL_SOCKET value:_value len:_len];
+}
+
+- (void)getOption:(int)_option level:(int)_level value:(void *)_value
+  len:(int *)_len {
+  
+  if (getsockopt(fd, _level, _option, _value, _len) != 0) {
+    NSString *reason = nil;
+#if defined(WIN32) && !defined(__CYGWIN32__)
+    int e = WSAGetLastError();
+    
+    switch (e) {
+      case WSAEBADF:
+        reason = @"Could not get socket option, invalid file descriptor";
+        break;
+      case WSAEINVAL:
+        reason =
+          @"Could not get socket option, option is invalid at the specified level";
+        break;
+      case WSAENOPROTOOPT:
+        reason = @"Could not get socket option, option is not supported by protocol";
+        break;
+      case WSAENOTSOCK:
+        reason = @"Could not get socket option, descriptor isn't a socket";
+        break;
+      case WSAEOPNOTSUPP:
+        reason =
+          @"Could not get socket option, operation is not supported by protocol";
+        break;
+      default:
+        reason = [NSString stringWithFormat:@"Could not get socket option: %s",
+                             strerror(e)];
+        break;
+    }
+#else
+    int e = errno;
+    
+    switch (e) {
+      case EBADF:
+        reason = @"Could not get socket option, invalid file descriptor";
+        break;
+      case EINVAL:
+        reason =
+          @"Could not get socket option, option is invalid at the specified level";
+        break;
+      case ENOPROTOOPT:
+        reason = @"Could not get socket option, option is not supported by protocol";
+        break;
+      case ENOTSOCK:
+        reason = @"Could not get socket option, descriptor isn't a socket";
+        break;
+      case EOPNOTSUPP:
+        reason =
+          @"Could not get socket option, operation is not supported by protocol";
+        break;
+      default:
+        reason = [NSString stringWithFormat:@"Could not get socket option: %s",
+                             strerror(e)];
+        break;
+    }
+#endif
+    [[[NGCouldNotGetSocketOptionException alloc]
+         initWithReason:reason option:_option level:_level] raise];
+  }
+}
+- (void)getOption:(int)_option value:(void *)_value len:(int *)_len {
+  [self getOption:_option level:SOL_SOCKET value:_value len:_len];
+}
+
+static int i_yes = 1;
+static int i_no  = 0;
+
+static inline void setBoolOption(id self, int _option, BOOL _flag) {
+  [self setOption:_option level:SOL_SOCKET
+        value:(_flag ? &i_yes : &i_no) len:4];
+}
+static inline BOOL getBoolOption(id self, int _option) {
+  int value, len;
+  [self getOption:_option level:SOL_SOCKET value:&value len:&len];
+  return (value ? YES : NO);
+}
+
+- (void)setDebug:(BOOL)_flag {
+  setBoolOption(self, SO_DEBUG, _flag);
+}
+- (BOOL)doesDebug {
+  return getBoolOption(self, SO_DEBUG);
+}
+
+- (void)setReuseAddress:(BOOL)_flag {
+  setBoolOption(self, SO_REUSEADDR, _flag);
+}
+- (BOOL)doesReuseAddress {
+  return getBoolOption(self, SO_REUSEADDR);
+}
+
+- (void)setKeepAlive:(BOOL)_flag {
+  setBoolOption(self, SO_KEEPALIVE, _flag);
+}
+- (BOOL)doesKeepAlive {
+  return getBoolOption(self, SO_KEEPALIVE);
+}
+
+- (void)setDontRoute:(BOOL)_flag {
+  setBoolOption(self, SO_DONTROUTE, _flag);
+}
+- (BOOL)doesNotRoute {
+  return getBoolOption(self, SO_DONTROUTE);
+}
+
+- (void)setSendBufferSize:(int)_size {
+  [self setOption:SO_SNDBUF level:SOL_SOCKET value:&_size len:sizeof(_size)];
+}
+- (int)sendBufferSize {
+  int size, len;
+  [self getOption:SO_SNDBUF level:SOL_SOCKET value:&size len:&len];
+  return size;
+}
+
+- (void)setReceiveBufferSize:(int)_size {
+  [self setOption:SO_RCVBUF level:SOL_SOCKET value:&_size len:sizeof(_size)];
+}
+- (int)receiveBufferSize {
+  int size, len;
+  [self getOption:SO_RCVBUF level:SOL_SOCKET value:&size len:&len];
+  return size;
+}
+
+- (int)getSocketError {
+  int error, len;
+  [self getOption:SO_ERROR level:SOL_SOCKET value:&error len:&len];
+  return error;
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<%@[0x%08X]: fd=%i type=%i bound=%@ domain=%@>",
+                     NSStringFromClass([self class]), (unsigned)self,
+                     [self fileDescriptor],
+                     [self socketType],
+                     [self localAddress] ? [self localAddress] : (id)@"no",
+                     [self domain]
+                   ];
+}
+
+@end /* NGSocket */
+
+
+@implementation _NGConcreteSocketFileHandle
+
+- (id)initWithSocket:(id<NGSocket>)_socket {
+  return [super initWithStream:(id<NGStream>)_socket];
+}
+
+// accessors
+
+- (int)fileDescriptor {
+  return [(NGSocket *)stream fileDescriptor];
+}
+
+@end /* _NGConcreteSocketFileHandle */
+
+#if defined(WIN32) && !defined(__CYGWIN32__)
+
+// Windows Descriptor functions
+
+// ******************** Poll *********************
+
+int NGPollDescriptor(SOCKET _fd, short _events, int _timeout) {
+  struct timeval timeout;
+  fd_set rSet;
+  fd_set wSet;
+  fd_set eSet;
+  int    result;
+  FD_ZERO(&rSet);
+  FD_ZERO(&wSet);
+  FD_ZERO(&eSet);
+
+  if (_events & POLLIN)  FD_SET(_fd, &rSet);
+  if (_events & POLLOUT) FD_SET(_fd, &wSet);
+  if (_events & POLLERR) FD_SET(_fd, &eSet);
+
+  timeout.tv_sec  = _timeout / 1000;
+  timeout.tv_usec = _timeout * 1000 - timeout.tv_sec * 1000000;
+
+  do {
+    result = select(FD_SETSIZE, &rSet, &wSet, &eSet, &timeout);
+    if (result == -1) { // error
+      int e = WSAGetLastError();
+      if (e != WSAEINTR)
+        // only retry of interrupted or repeatable
+        break;
+    }
+  }
+  while (result == -1);
+
+  return (result < 0) ? -1 : result;
+}
+
+// ******************** Flags ********************
+
+#if 0 
+int NGGetDescriptorFlags(int _fd) {
+  int val;
+
+  val = fcntl(_fd, F_GETFL, 0);
+  if (val < 0)
+    [NGIOException raiseWithReason:@"could not get descriptor flags"];
+  return val;
+}
+void NGSetDescriptorFlags(int _fd, int _flags) {
+  if (fcntl(_fd, F_SETFL, _flags) == -1)
+    [NGIOException raiseWithReason:@"could not set descriptor flags"];
+}
+
+void NGAddDescriptorFlag (int _fd, int _flag) {
+  int val = NGGetDescriptorFlags(_fd);
+  NGSetDescriptorFlags(_fd, val | _flag);
+}
+#endif 
+
+// ******************** NonBlocking IO ************
+
+int NGDescriptorRecv(SOCKET _fd, char *_buf, int _len, int _flags, int _timeout) {
+  int errorCode;
+  int result;
+
+  result = recv(_fd, _buf, _len, _flags);
+  if (result == 0) return 0; // EOF
+
+  errorCode = errno;
+
+  if ((result == -1) && (errorCode == WSAEWOULDBLOCK)) { // retry
+#if 0
+    struct pollfd pfd;
+    pfd.fd      = _fd;
+    pfd.events  = POLLRDNORM;
+    pfd.revents = 0;
+
+    do {
+      if ((result = poll(&pfd, 1, _timeout)) < 0) {
+        errorCode = errno;
+
+        // retry if interrupted
+        if ((errorCode != EINTR) && (errorCode != EAGAIN)) 
+          break;
+      }
+    }
+    while (result < 0);
+#endif
+    result = 1;
+
+    if (result == 1) { // data waiting, try to read
+      result = recv(_fd, _buf, _len, _flags);
+      if (result == 0)
+        return 0; // EOF
+      else if (result == -1) {
+        errorCode = errno;
+
+        if (errorCode == WSAEWOULDBLOCK)
+          NSLog(@"WARNING: would block although descriptor was polled ..");
+      }
+    }
+    else if (result == 0) {
+      result = -2;
+    }
+    else
+      result = -1;
+  }
+
+  return result;
+}
+
+int NGDescriptorSend(SOCKET _fd, const char *_buf, int _len, int _flags,
+                     int _timeout) {
+  int errorCode;
+  int result;
+
+  result = send(_fd, _buf, _len, _flags);
+  if (result == 0) return 0; // EOF
+
+  errorCode = errno;
+
+  if ((result == -1) && (errorCode == WSAEWOULDBLOCK)) { // retry
+#if 0
+    struct pollfd pfd;
+    pfd.fd      = _fd;
+    pfd.events  = POLLWRNORM;
+    pfd.revents = 0;
+
+    do {
+      if ((result = poll(&pfd, 1, _timeout)) < 0) {
+        errorCode = errno;
+
+        if (errorCode != WSAEINTR) // retry only if interrupted
+          break;
+      }
+    }
+    while (result < 0);
+#endif
+    result = 1; // block ..
+
+    if (result == 1) { // data waiting, try to read
+      result = send(_fd, _buf, _len, _flags);
+      if (result == 0) return 0; // EOF
+    }
+    else if (result == 0) {
+#if 0
+      NSLog(@"nonblock: send on %i timed out after %i milliseconds ..",
+             _fd, _timeout);
+#endif
+      result = -2;
+    }
+    else
+      result = -1;
+  }
+
+  return result;
+}
+
+#endif /* WIN32 */
diff --git a/skyrix-core/NGStreams/NGSocketExceptions.m b/skyrix-core/NGStreams/NGSocketExceptions.m
new file mode 100644 (file)
index 0000000..c01002e
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+#import <NGExtensions/NGExtensions.h>
+#import <NGExtensions/NSException+misc.h>
+#include "NGSocketExceptions.h"
+
+@implementation NGSocketException
+
+- (id)init {
+  return [self initWithReason:@"a socket exception occured" socket:nil];
+}
+- (id)initWithReason:(NSString *)_reason {
+  return [self initWithReason:_reason socket:nil];
+}
+
+- (id)initWithReason:(NSString *)_reason socket:(id<NGSocket>)_socket {
+  self = [super initWithName:NSStringFromClass([self class])
+                reason:_reason
+                userInfo:nil];
+  if (self) {
+    self->socket = [_socket retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->socket release];
+  [super dealloc];
+}
+
+- (id<NGSocket>)socket {
+  return self->socket;
+}
+
+@end /* NGSocketException */
+
+@implementation NGCouldNotResolveHostNameException
+
+- (id)init {
+  return [self initWithHostName:@"<noname>" reason:nil];
+}
+
+- (id)initWithHostName:(NSString *)_name reason:(NSString *)_reason {
+  self = [super initWithReason:
+                  [NSString stringWithFormat:
+                              @"Could not resolve host %@: %@",
+                            _name, _reason ? _reason : @"error"]
+                socket:nil];
+  if (self) {
+    self->hostName = [_name copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->hostName  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)hostName {
+  return self->hostName;
+}
+
+@end /* NGCouldNotResolveHostNameException */
+
+@implementation NGDidNotFindServiceException
+
+- (id)init {
+  return [self initWithServiceName:nil];
+}
+- (id)initWithServiceName:(NSString *)_service {
+  self = [super initWithReason:
+                  [NSString stringWithFormat:@"did not find service %@", _service]
+                socket:nil];
+  if (self) {
+    self->serviceName = [_service copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->serviceName release];
+  [super dealloc];
+}
+
+- (NSString *)serviceName {
+  return self->serviceName;
+}
+
+@end /* NGDidNotFindServiceException */
+
+@implementation NGInvalidSocketDomainException
+
+- (id)initWithReason:(NSString *)_reason
+  socket:(id<NGSocket>)_socket
+  domain:(id<NGSocketDomain>)_domain {
+
+  if ((self = [super initWithReason:_reason socket:nil])) {
+    self->domain = [_domain retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->domain release];
+  [super dealloc];
+}
+
+- (id<NGSocketDomain>)domain {
+  return self->domain;
+}
+
+@end /* NGInvalidSocketDomainException */
+
+@implementation NGCouldNotCreateSocketException
+
+- (id)init {
+  return [self initWithReason:@"Could not create socket" domain:nil];
+}
+- (id)initWithReason:(NSString *)_reason domain:(id<NGSocketDomain>)_domain {
+  if ((self = [super initWithReason:_reason socket:nil])) {
+    self->domain = [_domain retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->domain release];
+  [super dealloc];
+}
+
+- (id<NGSocketDomain>)domain {
+  return self->domain;
+}
+
+@end /* NGCouldNotCreateSocketException */
+
+// ******************** bind ***********************
+
+@implementation NGSocketBindException
+@end /* NGSocketBindException */
+
+@implementation NGSocketAlreadyBoundException
+
+- (id)init {
+  return [self initWithReason:@"Socket is already bound"];
+}
+
+@end /* NGSocketAlreadyBoundException */
+
+@implementation NGCouldNotBindSocketException
+
+- (id)init {
+  return [self initWithReason:@"could not bind socket" socket:nil address:nil];
+}
+
+- (id)initWithReason:(NSString *)_reason
+  socket:(id<NGSocket>)_socket
+  address:(id<NGSocketAddress>)_address {
+
+  if ((self = [super initWithReason:_reason socket:_socket])) {
+    self->address = [_address retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->address release];
+  [super dealloc];
+}
+
+- (id<NGSocketAddress>)address {
+  return self->address;
+}
+
+@end /* NGCouldNotBindSocketException */
+
+// ******************** connect ********************
+
+@implementation NGSocketConnectException
+@end /* NGSocketConnectException */
+
+@implementation NGSocketNotConnectedException
+
+- (id)init {
+  return [self initWithReason:@"Socket is not connected"];
+}
+
+@end /* NGSocketNotConnectedException */
+
+@implementation NGSocketAlreadyConnectedException
+
+- (id)init {
+  return [self initWithReason:@"Socket is already connected"];
+}
+
+@end /* NGSocketAlreadyConnectedException */
+
+@implementation NGCouldNotConnectException
+
+- (id)init {
+  return [self initWithReason:@"could not connect socket" socket:nil address:nil];
+}
+
+- (id)initWithReason:(NSString *)_reason
+  socket:(id<NGActiveSocket>)_socket
+  address:(id<NGSocketAddress>)_address {
+
+  if ((self = [super initWithReason:_reason socket:_socket])) {
+    self->address = [_address retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->address release];
+  [super dealloc];
+}
+
+- (id<NGSocketAddress>)address {
+  return self->address;
+}
+
+@end /* NGCouldNotConnectException */
+
+// ******************** listen ********************
+
+@implementation NGSocketIsAlreadyListeningException
+
+- (id)init {
+  return [self initWithReason:@"Socket is already listening"];
+}
+
+@end /* NGSocketIsAlreadyListeningException */
+
+@implementation NGCouldNotListenException
+@end /* NGCouldNotListenException */
+
+// ******************** accept ********************
+
+@implementation NGCouldNotAcceptException
+@end /* NGCouldNotAcceptException */
+
+// ******************** options ********************
+
+@implementation NGSocketOptionException
+
+- (id)init {
+  return [self initWithReason:@"Could not get/set socket option" option:-1 level:-1];
+}
+- (id)initWithReason:(NSString *)_reason option:(int)_option level:(int)_level {
+  if ((self = [super initWithReason:_reason])) {
+    option = _option;
+    level  = _level;
+  }
+  return self;
+}
+
+- (int)option {
+  return option;
+}
+- (int)level {
+  return level;
+}
+
+@end /* NGSocketOptionException */
+
+@implementation NGCouldNotSetSocketOptionException
+@end /* NGCouldNotSetSocketOptionException */
+
+@implementation NGCouldNotGetSocketOptionException
+@end /* NGCouldNotGetSocketOptionException */
+
+// ******************** socket closed **************
+
+@implementation NGSocketShutdownException
+
+- (id)init {
+  return [self initWithStream:nil reason:@"the socket was shutdown"];
+}
+- (id)initWithReason:(NSString *)_reason {
+  return [self initWithStream:nil reason:_reason];
+}
+- (id)initWithReason:(NSString *)_reason socket:(id<NGActiveSocket>)_socket {
+  return [self initWithStream:_socket reason:_reason];
+}
+
+- (id)initWithSocket:(id<NGActiveSocket>)_socket {
+  return [self initWithStream:_socket reason:@"the socket was shutdown"];
+}
+
+/* accessors */
+
+- (id<NGActiveSocket>)socket {
+  return [self->streamPointer nonretainedObjectValue];
+}
+
+@end /* NGSocketShutdownException */
+
+@implementation NGSocketShutdownDuringReadException
+@end
+
+@implementation NGSocketShutdownDuringWriteException
+@end
+
+@implementation NGSocketTimedOutException
+@end
+
+@implementation NGSocketConnectionResetException
+@end
diff --git a/skyrix-core/NGStreams/NGStream+serialization.m b/skyrix-core/NGStreams/NGStream+serialization.m
new file mode 100644 (file)
index 0000000..61b0aa9
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "config.h"
+
+#if !defined(WIN32)
+# if HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+# endif
+# if HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+# endif
+# if HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+# endif
+#  include <arpa/inet.h>
+#endif
+
+#include "common.h"
+#include "NGStream+serialization.h"
+
+#if NeXT_RUNTIME
+#  include <objc/objc-class.h>
+#endif
+
+@implementation NGStream(serialization)
+
+// serialization
+
+- (void)serializeChar:(char)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(char), nil);
+}
+- (void)serializeShort:(short)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(short), nil);
+}
+- (void)serializeInt:(int)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(int), nil);
+}
+- (void)serializeLong:(long)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(long), nil);
+}
+
+- (void)serializeFloat:(float)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(float), nil);
+}
+- (void)serializeDouble:(double)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(double), nil);
+}
+- (void)serializeLongLong:(long long)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(long long), nil);
+}
+
+- (void)serializeCString:(const char *)_value {
+  NGStreamSerializeObjC(self, &_value, @encode(char *), nil);
+}
+
+#if USE_SERIALIZER
+- (void)serializeDataAt:(const void*)_value ofObjCType:(const char*)_type
+  context:(id<NSObjCTypeSerializationCallBack>)_callback
+{
+  NGStreamSerializeObjC(self, _value, _type, _callback);
+}
+#endif
+
+// deserialization
+
+- (char)deserializeChar {
+  char c;
+  NGStreamDeserializeObjC(self, &c, @encode(char), nil);
+  return c;
+}
+- (short)deserializeShort {
+  short s;
+  NGStreamDeserializeObjC(self, &s, @encode(short), nil);
+  return s;
+}
+- (int)deserializeInt {
+  int i;
+  NGStreamDeserializeObjC(self, &i, @encode(int), nil);
+  return i;
+}
+- (long)deserializeLong {
+  long l;
+  NGStreamDeserializeObjC(self, &l, @encode(long), nil);
+  return l;
+}
+- (float)deserializeFloat {
+  float f;
+  NGStreamDeserializeObjC(self, &f, @encode(float), nil);
+  return f;
+}
+
+- (double)deserializeDouble {
+  double d;
+  NGStreamDeserializeObjC(self, &d, @encode(double), nil);
+  return d;
+}
+- (long long)deserializeLongLong {
+  long long l;
+  NGStreamDeserializeObjC(self, &l, @encode(long long), nil);
+  return l;
+}
+
+- (char *)deserializeCString {
+  char *result = NULL;
+  NGStreamDeserializeObjC(self, &result, @encode(char *), nil);
+  return result;
+}
+
+#if USE_SERIALIZER
+- (void)deserializeDataAt:(void *)_value ofObjCType:(const char *)_type
+  context:(id<NSObjCTypeSerializationCallBack>)_callback
+{
+  NGStreamDeserializeObjC(self, _value, _type, _callback);
+}
+#endif
+
+@end
+
+void NGStreamSerializeObjC(id<NGStream> self,
+                           const void *_value, const char *_type,
+#if USE_SERIALIZER
+                           id<NSObjCTypeSerializationCallBack> _callback
+#else
+                           id _callback
+#endif
+                           )
+{
+  switch (*_type) {
+    case _C_ID:
+    case _C_CLASS:
+      [_callback serializeObjectAt:(id *)_value
+                 ofObjCType:_type
+                 intoData:(NSMutableData *)self];
+      break;
+
+    case _C_CHARPTR: {
+      const char *cstr = *(char **)_value;
+      int        len   = cstr ? (int)strlen(cstr) : -1;
+
+      NGStreamSerializeObjC(self, &len, @encode(int), _callback);
+      if (cstr)
+        [self safeWriteBytes:cstr count:len];
+
+      break;
+    }
+
+    case _C_ARY_B: {
+      int i, offset, itemSize, count;
+
+      count = atoi(_type + 1); // skip '[' and get dimension
+
+      while (isdigit((int)*++_type)) ; // skip '[' and dimension
+      itemSize = objc_sizeof_type(_type);
+
+      for (i = offset = 0; i < count; i++, offset += itemSize)
+        NGStreamSerializeObjC(self, (char *)_value + offset, _type, _callback);
+      break;
+    }
+    
+    case _C_STRUCT_B: {
+      int offset = 0;
+
+      while ((*_type != _C_STRUCT_E) && (*_type++ != '=')) ; // skip '<name>='
+
+      while (YES) {
+        NGStreamSerializeObjC(self, (char *)_value + offset, _type, _callback);
+
+        offset += objc_sizeof_type(_type);
+        _type  =  objc_skip_typespec(_type);
+    
+        if (*_type != _C_STRUCT_E) {
+          int align, remainder;
+
+          align = objc_alignof_type(_type);
+          if ((remainder = offset % align))
+            offset += align - remainder;
+        }
+        else // done with structure
+          break;
+      }
+      break;
+    }
+
+    case _C_PTR:
+      NGStreamSerializeObjC(self, *(char **)_value, _type + 1, _callback);
+      break;
+
+    case _C_CHR:
+    case _C_UCHR:
+      [self safeWriteBytes:_value count:1];
+      break;
+
+    case _C_SHT:
+    case _C_USHT: {
+      short netValue = htons(*(short *)_value);
+      [self safeWriteBytes:&netValue count:2];
+      break;
+    }
+        
+    case _C_INT:
+    case _C_UINT: {
+      int netValue = htonl(*(int *)_value);
+      [self safeWriteBytes:&netValue count:4];
+      break;
+    }
+
+    case _C_LNG:
+    case _C_ULNG: {
+      long netValue = htonl(*(long *)_value);
+      [self safeWriteBytes:&netValue count:sizeof(long)];
+      break;
+    }
+
+    case _C_FLT: {
+      union fconv {
+        float         value;
+        unsigned long ul;
+      } fc;
+      fc.value = *(float *)_value;
+      fc.ul    = htonl(fc.ul);
+      [self safeWriteBytes:&fc count:sizeof(unsigned long)];
+      break;
+    }
+    case _C_DBL: {
+      [self safeWriteBytes:_value count:8];
+      break;
+    }
+
+    default:
+      NSCAssert1(0, @"unsupported C type %s ..", _type);
+      break;
+  }
+}
+
+void NGStreamDeserializeObjC(id<NGStream> self,
+                             void *_value, const char *_type,
+#if USE_SERIALIZER
+                             id<NSObjCTypeSerializationCallBack> _callback
+#else
+                             id _callback
+#endif
+                             ) 
+{
+  if ((_value == NULL) || (_type == NULL))
+    return;
+
+  switch (*_type) {
+    case _C_ID:
+    case _C_CLASS:
+      [_callback deserializeObjectAt:(id *)_value
+                 ofObjCType:_type
+                 fromData:(NSData *)self
+                 atCursor:0];
+      break;
+
+    case _C_CHARPTR: { // malloced C-string
+      int len = -1;
+
+      NGStreamDeserializeObjC(self, &len, @encode(int), _callback);
+
+      if (len == -1) // NULL-string
+        *(char **)_value = NULL;
+      else {
+        char *result = NULL;
+    
+#if NeXT_Foundation_LIBRARY
+        result = NSZoneMalloc(NULL, len + 1);
+#else
+        result = NSZoneMallocAtomic(NULL, len + 1);
+#endif
+        result[len] = '\0';
+    
+        if (len > 0) [self safeReadBytes:result count:len];
+        *(char **)_value = result;
+      }
+      break;
+    }
+
+    case _C_ARY_B: {
+      int i, offset, itemSize, count;
+
+      count = atoi(_type + 1); // skip '[' and get dimension
+
+      while (isdigit((int)*++_type)) ; // skip '[' and dimension
+      itemSize = objc_sizeof_type(_type);
+
+      for (i = offset = 0; i < count; i++, offset += itemSize)
+        NGStreamDeserializeObjC(self, (char *)_value + offset, _type, _callback);
+      
+      break;
+    }
+    
+    case _C_STRUCT_B: {
+      int offset = 0;
+
+      while ((*_type != _C_STRUCT_E) && (*_type++ != '=')) ; // skip '<name>='
+
+      while (YES) {
+        NGStreamDeserializeObjC(self, (char *)_value + offset, _type, _callback);
+
+        offset += objc_sizeof_type(_type);
+        _type  =  objc_skip_typespec(_type);
+    
+        if (*_type != _C_STRUCT_E) {
+          int align, remainder;
+
+          align = objc_alignof_type(_type);
+          if ((remainder = offset % align))
+            offset += align - remainder;
+        }
+        else // done with structure
+          break;
+      }
+      break;
+    }
+
+    case _C_PTR: {
+       // skip '^', type of the value the ptr points to
+      void *result = NULL;
+  
+      result = NSZoneMalloc(NULL, objc_sizeof_type(_type + 1));
+
+      NGStreamDeserializeObjC(self, result, _type + 1, _callback);
+
+      *(char **)_value = result;
+      result = NULL;
+
+      break;
+    }
+
+    case _C_CHR:
+    case _C_UCHR:
+      [self safeReadBytes:_value count:1];
+      break;
+
+    case _C_SHT:
+    case _C_USHT:
+      [self safeReadBytes:_value count:2];
+      *(short *)_value = ntohs(*(short *)_value);
+      break;
+
+    case _C_INT:
+    case _C_UINT:
+      [self safeReadBytes:_value count:4];
+      *(int *)_value = ntohl(*(int *)_value);
+      break;
+
+    case _C_LNG:
+    case _C_ULNG:
+      [self safeReadBytes:_value count:4];
+      *(long *)_value = ntohl(*(long *)_value);
+      break;
+
+    case _C_FLT: {
+      [self safeReadBytes:_value count:4];
+      *(long *)_value = ntohl(*(long *)_value);
+      break;
+    }
+    case _C_DBL: {
+      [self safeReadBytes:_value count:8];
+      break;
+    }
+
+    default:
+      NSLog(@"unsupported C type %s ..", _type);
+      break;
+  }
+}
+
+void __link_NGStream_serialization(void) {
+  __link_NGStream_serialization();
+}
diff --git a/skyrix-core/NGStreams/NGStream.m b/skyrix-core/NGStreams/NGStream.m
new file mode 100644 (file)
index 0000000..ca259ea
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "common.h"
+#include "NGStreamExceptions.h"
+#include "NGStream.h"
+#include "NGFilterStream.h"
+
+@implementation NGStream
+
+/* primitives */
+
+- (void)setLastException:(NSException *)_exception {
+  [_exception raise];
+}
+- (NSException *)lastException {
+  return nil;
+}
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  [self subclassResponsibility:_cmd];
+  return 0;
+}
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  [self subclassResponsibility:_cmd];
+  return 0;
+}
+
+- (BOOL)flush {
+  return YES;
+}
+- (BOOL)close {
+  return YES;
+}
+
+- (NGStreamMode)mode {
+  [self subclassResponsibility:_cmd];
+  return 0;
+}
+- (BOOL)isRootStream {
+  [self subclassResponsibility:_cmd];
+  return NO;
+}
+
+// methods method which write exactly _len bytes
+
+- (BOOL)safeReadBytes:(void *)_buf count:(unsigned)_len {
+  return NGSafeReadBytesFromStream(self, _buf, _len);
+}
+
+- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len {
+  return NGSafeWriteBytesToStream(self, _buf, _len);
+}
+
+/* marking */
+
+- (BOOL)mark {
+  NSLog(@"WARNING: called mark on a stream which doesn't support marking !");
+  return NO;
+}
+- (BOOL)rewind {
+  [NGStreamException raiseWithStream:self reason:@"marking not supported"];
+  return NO;
+}
+- (BOOL)markSupported {
+  return NO;
+}
+
+/* convenience methods */
+
+- (int)readByte {
+  return NGReadByteFromStream(self);
+}
+
+/* description */
+
+- (NSString *)modeDescription {
+  NSString *result = @"unknown";
+  
+  switch ([self mode]) {
+    case NGStreamMode_undefined: result = @"undefined"; break;
+    case NGStreamMode_readOnly:  result = @"r";         break;
+    case NGStreamMode_writeOnly: result = @"w";         break;
+    case NGStreamMode_readWrite: result = @"rw";        break;
+    default:
+      [NGUnknownStreamModeException raiseWithStream:self];
+      break;
+  }
+  return result;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<%@[0x%08X] mode=%@>",
+                     NSStringFromClass([self class]), (unsigned)self,
+                     [self modeDescription]];
+}
+
+@end /* NGStream */
+
+@implementation NGStream(DataMethods)
+
+- (NSData *)readDataOfLength:(unsigned int)_length {
+  unsigned readCount;
+  char buf[_length];
+  
+  if (_length == 0) return [NSData data];
+  
+  readCount = [self readBytes:buf count:_length];
+  if (readCount == NGStreamError)
+    return nil;
+  
+  return [NSData dataWithBytes:buf length:readCount];
+}
+
+- (NSData *)safeReadDataOfLength:(unsigned int)_length {
+  char buf[_length];
+  
+  if (_length == 0) return [NSData data];
+  if (![self safeReadBytes:buf count:_length])
+    return nil;
+  return [NSData dataWithBytes:buf length:_length];
+}
+
+- (unsigned int)writeData:(NSData *)_data {
+  return [self writeBytes:[_data bytes] count:[_data length]];
+}
+- (BOOL)safeWriteData:(NSData *)_data {
+  return [self safeWriteBytes:[_data bytes] count:[_data length]];
+}
+
+@end /* NGStream(DataMethods) */
+
+// concrete implementations as functions
+
+int NGReadByteFromStream(id<NGInputStream> _stream) {
+  volatile int  result = -1;
+  unsigned char c;
+
+  NS_DURING {
+    int l;
+    l = [_stream readBytes:&c count:sizeof(unsigned char)];
+    if (l == NGStreamError) {
+      NSException *e = [(id)_stream lastException];
+      if ([e isKindOfClass:[NGEndOfStreamException class]])
+        *(&result) = -1;
+      else
+        [e raise];
+    }
+    else
+      *(&result) = c;
+  }
+  NS_HANDLER {
+    if ([localException isKindOfClass:[NGEndOfStreamException class]])
+      *(&result) = -1;
+    else
+      [localException raise];
+  }
+  NS_ENDHANDLER;
+  
+  return result;
+}
+
+BOOL NGSafeReadBytesFromStream(id<NGInputStream> _in, void *_buf, unsigned _len){
+  volatile int toBeRead;
+  volatile int readResult;
+  volatile NGIOReadMethodType readBytes;
+
+  *(&toBeRead) = _len;
+  readBytes = (NGIOReadMethodType)
+    [(NSObject *)_in methodForSelector:@selector(readBytes:count:)];
+
+  NS_DURING {
+    void *pos = _buf;
+    
+    while (YES) {
+      *(&readResult) = (unsigned)readBytes(_in, @selector(readBytes:count:),
+                                           pos, toBeRead);
+
+      if (readResult == NGStreamError) {
+       /* TODO: improve exception handling ... */
+        [[(id)_in lastException] raise];
+      }
+      else if (readResult == toBeRead) {
+        // all bytes were read successfully, return
+        break;
+      }
+      
+      if (readResult < 1) {
+        [NSException raise:NSInternalInconsistencyException
+                     format:@"readBytes:count: returned a value < 1"];
+      }
+
+      toBeRead -= readResult;
+      pos += readResult;
+    }
+  }
+  NS_HANDLER {
+    if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
+      [[[NGEndOfStreamException alloc]
+                                initWithStream:(id)_in
+                                readCount:(_len - toBeRead)
+                                safeCount:_len
+                                data:[NSData dataWithBytes:_buf
+                                             length:(_len - toBeRead)]]
+                                raise];
+    }
+    else {
+      [localException raise];
+    }
+  }
+  NS_ENDHANDLER;
+  return YES;
+}
+
+BOOL NGSafeWriteBytesToStream(id<NGOutputStream> _o,const void *_b,unsigned _l) {
+  int  toBeWritten = _l;
+  int  writeResult;
+  void *pos = (void *)_b;
+  NGIOWriteMethodType writeBytes;
+  
+  writeBytes = (NGIOWriteMethodType)
+    [(NSObject *)_o methodForSelector:@selector(writeBytes:count:)];
+  
+  while (YES) {
+    writeResult =
+      (int)writeBytes(_o, @selector(writeBytes:count:), pos, toBeWritten);
+    
+    if (writeResult == NGStreamError) {
+      /* remember number of written bytes ??? */
+      return NO;
+    }
+    else if (writeResult == toBeWritten) {
+      // all bytes were written successfully, return
+      break;
+    }
+    
+    if (writeResult < 1) {
+      [NSException raise:NSInternalInconsistencyException
+                   format:@"writeBytes:count: returned a value<1 in %@", _o];
+    }
+
+    toBeWritten -= writeResult;
+    pos += writeResult;
+  }
+  return YES;
+}
diff --git a/skyrix-core/NGStreams/NGStreamCoder.m b/skyrix-core/NGStreams/NGStreamCoder.m
new file mode 100644 (file)
index 0000000..4c47dd6
--- /dev/null
@@ -0,0 +1,1180 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "config.h"
+#include "common.h"
+#include "NGStreamCoder.h"
+#include "NGStream+serialization.h"
+
+#if APPLE_RUNTIME || NeXT_RUNTIME
+#  include <objc/objc-class.h>
+#endif
+
+#define FINAL static inline
+
+extern id nil_method(id, SEL, ...);
+
+/*
+  Debugging topics:
+    encoder
+    decoder
+*/
+
+typedef unsigned char NGTagType;
+
+#define REFERENCE 128
+#define VALUE     127
+
+static unsigned __NGHashPointer(void *table, const void *anObject)
+{
+    return (unsigned)((long)anObject / 4);
+}
+static BOOL __NGComparePointers(void *table, 
+       const void *anObject1, const void *anObject2)
+{
+    return anObject1 == anObject2 ? YES : NO;
+}
+static void __NGRetainObjects(void *table, const void *anObject)
+{
+    (void)[(NSObject*)anObject retain];
+}
+static void __NGReleaseObjects(void *table, void *anObject)
+{
+    [(NSObject*)anObject release];
+}
+static NSString* __NGDescribePointers(void *table, const void *anObject)
+{
+    return [NSString stringWithFormat:@"%p", anObject];
+}
+
+static NSMapTableKeyCallBacks NGIdentityObjectMapKeyCallbacks = {
+  (unsigned(*)(NSMapTable *, const void *))          __NGHashPointer,
+  (BOOL(*)(NSMapTable *, const void *, const void *))__NGComparePointers,
+  (void (*)(NSMapTable *, const void *anObject))     __NGRetainObjects,
+  (void (*)(NSMapTable *, void *anObject))           __NGReleaseObjects,
+  (NSString *(*)(NSMapTable *, const void *))        __NGDescribePointers,
+  (const void *)NULL
+};
+
+static const char *NGCoderSignature = "MDlink NGStreamCoder";
+static int        NGCoderVersion    = 1100;
+
+@implementation NGStreamCoder
+
+static NSMapTable *classToAliasMappings = NULL; // archive name => decoded name
+
++ (void)initialize {
+  BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+
+    classToAliasMappings = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                            NSObjectMapValueCallBacks,
+                                            19);
+  }
+}
+
++ (id)coderWithStream:(id<NGStream>)_stream {
+  return AUTORELEASE([[self alloc] initWithStream:_stream]);
+}
+
+- (id)initWithStream:(id<NGStream>)_stream mode:(NGStreamMode)_mode {
+  if ((self = [super init])) {
+    self->stream = [_stream retain];
+
+    self->classForCoder      = @selector(classForCoder);
+    self->replObjectForCoder = @selector(replacementObjectForCoder:);
+
+    if ([self->stream isKindOfClass:[NSObject class]]) {
+      self->readIMP = (NGIOSafeReadMethodType)
+        [(NSObject*)self->stream methodForSelector:@selector(safeReadBytes:count:)];
+      self->writeIMP = (NGIOSafeWriteMethodType)
+        [(NSObject*)self->stream methodForSelector:@selector(safeWriteBytes:count:)];
+    }
+
+    if (NGCanReadInStreamMode(_mode)) { // setup decoder
+      self->inObjects       = NSCreateMapTable(NSIntMapKeyCallBacks,
+                                               NSObjectMapValueCallBacks,
+                                               119);
+      self->inClasses       = NSCreateMapTable(NSIntMapKeyCallBacks,
+                                               NSObjectMapValueCallBacks,
+                                               19);
+      self->inPointers      = NSCreateMapTable(NSIntMapKeyCallBacks,
+                                               NSIntMapValueCallBacks,
+                                               19);
+      self->inClassAlias    = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                               NSObjectMapValueCallBacks,
+                                               19);
+      self->inClassVersions = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                               NSObjectMapValueCallBacks,
+                                               19);
+    }
+
+    if (NGCanWriteInStreamMode(_mode)) { // setup encoder
+      self->outObjects      = NSCreateHashTable(NSNonOwnedPointerHashCallBacks, 119);
+      self->outConditionals = NSCreateHashTable(NSNonOwnedPointerHashCallBacks, 119);
+      self->outPointers     = NSCreateHashTable(NSNonOwnedPointerHashCallBacks, 0);
+      self->replacements    = NSCreateMapTable(NGIdentityObjectMapKeyCallbacks,
+                                               NSObjectMapValueCallBacks,
+                                               19);
+    }
+  }
+  return self;
+}
+
+- (id)init {
+  return [self initWithStream:nil mode:NGStreamMode_undefined];
+}
+- (id)initWithStream:(id<NGStream>)_stream {
+  return [self initWithStream:_stream mode:[_stream mode]];
+}
+
+- (void)dealloc {
+  // release encoding restreams
+  if (self->outObjects) {
+    NSFreeHashTable(self->outObjects); self->outObjects = NULL; }
+  if (self->outConditionals) {
+    NSFreeHashTable(self->outConditionals); self->outConditionals = NULL; }
+  if (self->outPointers) {
+    NSFreeHashTable(self->outPointers); self->outPointers = NULL; }
+  if (self->replacements) {
+    NSFreeMapTable(self->replacements); self->replacements = NULL; }
+
+  // release decoding restreams
+  if (self->inObjects) {
+    NSFreeMapTable(self->inObjects); self->inObjects = NULL; }
+  if (self->inClasses) {
+    NSFreeMapTable(self->inClasses); self->inClasses = NULL; }
+  if (self->inPointers) {
+    NSFreeMapTable(self->inPointers); self->inPointers = NULL; }
+  if (self->inClassAlias) {
+    NSFreeMapTable(self->inClassAlias); self->inClassAlias = NULL; }
+  if (self->inClassVersions) {
+    NSFreeMapTable(self->inClassVersions); self->inClassVersions = NULL; }
+
+  [self->stream release]; self->stream = nil;
+  
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id<NGStream>)stream {
+  return self->stream;
+}
+
+- (NSString *)coderSignature {
+  return [NSString stringWithCString:NGCoderSignature];
+}
+- (int)coderVersion {
+  return NGCoderVersion;
+}
+
+- (unsigned int)systemVersion {
+  return self->inArchiverVersion;
+}
+
+// misc
+
+FINAL BOOL isBaseType(const char *_type) {
+  switch (*_type) {
+    case _C_CHR: case _C_UCHR:
+    case _C_SHT: case _C_USHT:
+    case _C_INT: case _C_UINT:
+    case _C_LNG: case _C_ULNG:
+    case _C_FLT: case _C_DBL:
+      return YES;
+
+    default:
+      return NO;
+  }
+}
+
+FINAL BOOL isReferenceTag(NGTagType _tag) {
+  return (_tag & REFERENCE) ? YES : NO;
+}
+
+FINAL NGTagType tagValue(NGTagType _tag) {
+  return _tag & VALUE; // mask out bit 8
+}
+
+FINAL int _archiveIdOfObject(NGStreamCoder *self, id _object) {
+  return (_object == nil)
+    ? 0
+    : (int)_object;
+}
+FINAL int _archiveIdOfClass(NGStreamCoder *self, Class _class) {
+  return _archiveIdOfObject(self, _class);
+}
+
+
+// primitive encoding
+
+FINAL void _writeBytes(NGStreamCoder *self, const void *_bytes, unsigned _len);
+
+FINAL void _writeTag  (NGStreamCoder *self, NGTagType _tag);
+
+FINAL void _writeChar (NGStreamCoder *self, char _value);
+FINAL void _writeShort(NGStreamCoder *self, short _value);
+FINAL void _writeInt  (NGStreamCoder *self, int _value);
+FINAL void _writeLong (NGStreamCoder *self, long _value);
+FINAL void _writeFloat(NGStreamCoder *self, float _value);
+
+FINAL void _writeCString(NGStreamCoder *self, const char *_value);
+FINAL void _writeObjC(NGStreamCoder *self, const void *_value, const char *_type);
+
+// primitive decoding
+
+FINAL void _readBytes(NGStreamCoder *self, void *_bytes, unsigned _len);
+
+FINAL NGTagType _readTag(NGStreamCoder *self);
+
+FINAL char  _readChar (NGStreamCoder *self);
+FINAL short _readShort(NGStreamCoder *self);
+FINAL int   _readInt  (NGStreamCoder *self);
+FINAL long  _readLong (NGStreamCoder *self);
+FINAL float _readFloat(NGStreamCoder *self);
+
+FINAL char *_readCString(NGStreamCoder *self);
+FINAL void _readObjC(NGStreamCoder *self, void *_value, const char *_type);
+
+// -------------------- encoding --------------------
+
+- (void)beginEncoding {
+  self->traceMode       = NO;
+  self->encodingRoot    = YES;
+}
+- (void)endEncoding {
+  NSResetHashTable(self->outObjects);
+  NSResetHashTable(self->outConditionals);
+  NSResetHashTable(self->outPointers);
+  NSResetMapTable(self->replacements);
+  self->traceMode      = NO;
+  self->encodingRoot   = NO;
+}
+
+- (void)writeArchiveHeader {
+  if (self->didWriteHeader == NO) {
+    _writeCString(self, [[self coderSignature] cString]);
+    _writeInt(self, [self coderVersion]);
+    self->didWriteHeader = YES;
+  }
+}
+- (void)writeArchiveTrailer {
+}
+
+- (void)traceObjectsWithRoot:(id)_root {
+  // encoding pass 1
+
+  NS_DURING {
+    self->traceMode = YES;
+
+    [self encodeObject:_root];
+  }
+  NS_HANDLER {
+    self->traceMode = NO;
+    NSResetHashTable(self->outObjects);
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+  self->traceMode = NO;
+  NSResetHashTable(self->outObjects);
+}
+
+- (void)encodeObjectsWithRoot:(id)_root {
+  // encoding pass 2
+  [self encodeObject:_root];
+}
+
+- (void)encodeRootObject:(id)_object {
+  NSAutoreleasePool *pool = [[NSAutoreleasePool allocWithZone:[self zone]] init];
+  
+  [self beginEncoding];
+
+  NS_DURING {
+    /*
+     * Prepare for writing the graph objects for which `rootObject' is the root
+     * node. The algorithm consists from two passes. In the first pass it
+     * determines the nodes so-called 'conditionals' - the nodes encoded *only*
+     * with -encodeConditionalObject:. They represent nodes that are not
+     * related directly to the graph. In the second pass objects are encoded
+     * normally, except for the conditional objects which are encoded as nil.
+     */
+
+    // pass1: start tracing for conditionals
+    [self traceObjectsWithRoot:_object];
+
+    // pass2: start writing
+    [self writeArchiveHeader];
+    [self encodeObjectsWithRoot:_object];
+    [self writeArchiveTrailer];
+  }
+  NS_HANDLER {
+    [self endEncoding]; // release resources
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+  [self endEncoding]; // release resources
+
+  [pool release]; pool = nil;
+}
+
+- (void)encodeConditionalObject:(id)_object {
+  if (self->traceMode) { // pass 1
+    /*
+     * This is the first pass of the determining the conditionals
+     * algorithm. We traverse the graph and insert into the `conditionals'
+     * set. In the second pass all objects that are still in this set will
+     * be encoded as nil when they receive -encodeConditionalObject:. An
+     * object is removed from this set when it receives -encodeObject:.
+     */
+
+    if (_object) {
+      if (NSHashGet(self->outObjects, _object))
+        // object isn't conditional any more .. (was stored using encodeObject:)
+        ;
+      else if (NSHashGet(self->outConditionals, _object))
+        // object is already stored as conditional
+        ;
+      else
+        // insert object in conditionals set
+        NSHashInsert(self->outConditionals, _object);
+    }
+  }
+  else { // pass 2
+    BOOL isConditional;
+
+    isConditional = (NSHashGet(self->outConditionals, _object) != nil);
+
+    // If anObject is still in the `conditionals' set, it is encoded as nil.
+    [self encodeObject:isConditional ? nil : _object];
+  }
+}
+
+- (void)_traceObject:(id)_object {
+  if (_object == nil) // don't trace nil objects ..
+    return;
+
+  if (NSHashGet(self->outObjects, _object) == nil) { // object wasn't traced yet
+    // Look-up the object in the `conditionals' set. If the object is
+    // there, then remove it because it is no longer a conditional one.
+    if (NSHashGet(self->outConditionals, _object)) {
+      // object was marked conditional ..
+      NSHashRemove(self->outConditionals, _object);
+    }
+
+    // mark object as traced
+    NSHashInsert(self->outObjects, _object);
+      
+    if (object_is_instance(_object)) {
+      Class archiveClass = Nil;
+      id    replacement  = nil;
+
+      replacement = [_object performSelector:self->replObjectForCoder
+                             withObject:self];
+
+      if (replacement != _object) {
+        NSMapInsert(self->replacements, _object, replacement);
+        _object = replacement;
+      }
+      
+      if (object_is_instance(_object)) {
+        archiveClass = [_object performSelector:self->classForCoder
+                                withObject:self];
+      }
+        
+      [self encodeObject:archiveClass];
+      [_object encodeWithCoder:self];
+    }
+    else {
+      // there are no class-variables ..
+    }
+  }
+}
+- (void)_encodeObject:(id)_object {
+  NGTagType tag;
+  int       archiveId = _archiveIdOfObject(self, _object);
+
+  tag = object_is_instance(_object) ? _C_ID : _C_CLASS;
+    
+  if (_object == nil) { // nil object
+#if 0
+    NSLog(@"encoding nil reference ..");
+#endif
+    _writeTag(self, tag | REFERENCE);
+    _writeInt(self, archiveId);
+  }
+  else if (NSHashGet(self->outObjects, _object)) { // object was already written
+#if 0
+    if (tag == _C_CLASS) {
+      NSLog(@"encoding reference to class <%s> ..",
+             class_get_class_name(_object));
+    }
+    else {
+      NSLog(@"encoding reference to object 0x%08X<%s> ..",
+             _object, class_get_class_name(*(Class *)_object));
+    }
+#endif
+
+    _writeTag(self, tag | REFERENCE);
+    _writeInt(self, archiveId);
+  }
+  else {
+    // mark object as written
+    NSHashInsert(self->outObjects, _object);
+
+#if 0
+    if (tag == _C_CLASS) { // a class object
+      NSLog( @"encoding class %s:%i ..",
+             class_get_class_name(_object), [_object version]);
+    }
+    else {
+      NSLog(@"encoding object 0x%08X<%s> ..",
+             _object, class_get_class_name(*(Class *)_object));
+    }
+#endif
+    
+    _writeTag(self, tag);
+    _writeInt(self, archiveId);
+
+    if (tag == _C_CLASS) { // a class object
+      _writeCString(self, class_get_class_name(_object));
+      _writeInt(self, [_object version]);
+    }
+    else {
+      Class archiveClass = Nil;
+      id    replacement  = nil;
+
+      replacement = NSMapGet(self->replacements, _object);
+      if (replacement) _object = replacement;
+
+      /*
+      _object      = [_object performSelector:self->replObjectForCoder
+                              withObject:self];
+      */
+      archiveClass = [_object performSelector:self->classForCoder
+                              withObject:self]; // class of replacement
+
+      NSAssert(archiveClass, @"no archive class found ..");
+
+      [self encodeObject:archiveClass];
+      [_object encodeWithCoder:self];
+    }
+  }
+}
+
+- (void)encodeObject:(id)_object {
+  if (self->encodingRoot) {
+    [self encodeValueOfObjCType:object_is_instance(_object) ? "@" : "#"
+          at:&_object];
+  }
+  else {
+    [self encodeRootObject:_object];
+  }
+}
+
+- (void)_traceValueOfObjCType:(const char *)_type at:(const void *)_value {
+#if 0
+  NSLog(@"tracing value of ObjC-type '%s'", _type);
+#endif
+
+  switch (*_type) {
+    case _C_ID:
+    case _C_CLASS:
+      [self _traceObject:*(id *)_value];
+      break;
+
+    case _C_ARY_B: {
+      int        count     = atoi(_type + 1); // eg '[15I' => count = 15
+      const char *itemType = _type;
+      while(isdigit((int)*(++itemType))) ; // skip dimension
+      [self encodeArrayOfObjCType:itemType count:count at:_value];
+      break;
+    }
+
+    case _C_STRUCT_B: { // C-structure begin '{'
+      int offset = 0;
+
+      while ((*_type != _C_STRUCT_E) && (*_type++ != '=')); // skip "<name>="
+        
+      while (YES) {
+        [self encodeValueOfObjCType:_type at:((char *)_value) + offset];
+            
+        offset += objc_sizeof_type(_type);
+        _type  =  objc_skip_typespec(_type);
+            
+        if(*_type != _C_STRUCT_E) { // C-structure end '}'
+          int align, remainder;
+                    
+          align = objc_alignof_type(_type);
+          if((remainder = offset % align))
+            offset += (align - remainder);
+        }
+        else
+          break;
+      }
+      break;
+    }
+  }
+}
+
+- (void)_encodeValueOfObjCType:(const char *)_type at:(const void *)_value {
+  switch (*_type) {
+    case _C_ID:
+    case _C_CLASS:
+      // ?? Write another tag just to be possible to read using the
+      // ?? decodeObject method. (Otherwise a lookahead would be required)
+      // ?? _writeTag(self, *_type);
+      [self _encodeObject:*(id *)_value];
+      break;
+
+    case _C_ARY_B: {
+      int        count     = atoi(_type + 1); // eg '[15I' => count = 15
+      const char *itemType = _type;
+
+      while(isdigit((int)*(++itemType))) ; // skip dimension
+
+      // Write another tag just to be possible to read using the
+      // decodeArrayOfObjCType:count:at: method.
+      _writeTag(self, _C_ARY_B);
+      [self encodeArrayOfObjCType:itemType count:count at:_value];
+      break;
+    }
+
+    case _C_STRUCT_B: { // C-structure begin '{'
+      int offset = 0;
+
+      _writeTag(self, '{');
+
+      while ((*_type != _C_STRUCT_E) && (*_type++ != '=')); // skip "<name>="
+        
+      while (YES) {
+        [self encodeValueOfObjCType:_type at:((char *)_value) + offset];
+            
+        offset += objc_sizeof_type(_type);
+        _type  =  objc_skip_typespec(_type);
+            
+        if(*_type != _C_STRUCT_E) { // C-structure end '}'
+          int align, remainder;
+                    
+          align = objc_alignof_type(_type);
+          if((remainder = offset % align))
+            offset += (align - remainder);
+        }
+        else
+          break;
+      }
+      break;
+    }
+
+    case _C_SEL:
+      _writeTag(self, _C_SEL);
+      _writeCString(self, (*(SEL *)_value) ? sel_get_name(*(SEL *)_value) : NULL);
+      break;
+      
+    case _C_PTR:
+      _writeTag(self, *_type);
+      _writeObjC(self, *(char **)_value, _type + 1);
+      break;
+    case _C_CHARPTR:
+      _writeTag(self, *_type);
+      _writeObjC(self, _value, _type);
+      break;
+      
+    case _C_CHR:    case _C_UCHR:
+    case _C_SHT:    case _C_USHT:
+    case _C_INT:    case _C_UINT:
+    case _C_LNG:    case _C_ULNG:
+    case _C_FLT:    case _C_DBL:
+      _writeTag(self, *_type);
+      _writeObjC(self, _value, _type);
+      break;
+      
+    default:
+      NSLog(@"unsupported C type '%s' ..", _type);
+      break;
+  }
+}
+
+- (void)encodeValueOfObjCType:(const char *)_type at:(const void *)_value {
+  if (self->traceMode)
+    [self _traceValueOfObjCType:_type at:_value];
+  else {
+    if (self->didWriteHeader == NO)
+      [self writeArchiveHeader];
+  
+    [self _encodeValueOfObjCType:_type at:_value];
+  }
+}
+
+- (void)encodeArrayOfObjCType:(const char *)_type count:(unsigned int)_count
+  at:(const void *)_array {
+
+  if ((self->didWriteHeader == NO) && (self->traceMode == NO))
+    [self writeArchiveHeader];
+
+  // array header
+  if (self->traceMode == NO) { // nothing is written during trace-mode
+    _writeTag(self, _C_ARY_B);
+    _writeInt(self, _count);
+  }
+
+  // Optimize writing arrays of elementary types. If such an array has to
+  // be written, write the type and then the elements of array.
+
+  if ((*_type == _C_ID) || (*_type == _C_CLASS)) { // object array
+    int i;
+
+    if (self->traceMode == NO)
+      _writeTag(self, *_type); // object array
+
+    for (i = 0; i < _count; i++)
+      [self encodeObject:((id *)_array)[i]];
+  }
+  else if ((*_type == _C_CHR) || (*_type == _C_UCHR)) { // byte array
+    if (self->traceMode == NO) {
+
+      // write base type tag
+      _writeTag(self, *_type);
+
+      // write buffer
+      _writeBytes(self, _array, _count);
+    }
+  }
+  else if (isBaseType(_type)) {
+    if (self->traceMode == NO) {
+      unsigned offset, itemSize = objc_sizeof_type(_type);
+      int      i;
+
+      // write base type tag
+      _writeTag(self, *_type);
+
+      // write contents
+      for (i = offset = 0; i < _count; i++, offset += itemSize)
+        _writeObjC(self, (char *)_array + offset, _type);
+    }
+  }
+  else { // encoded using normal method
+    IMP      encodeValue = NULL;
+    unsigned offset, itemSize = objc_sizeof_type(_type);
+    int      i;
+
+    encodeValue = [self methodForSelector:@selector(encodeValueOfObjCType:at:)];
+
+    for (i = offset = 0; i < _count; i++, offset += itemSize) {
+      encodeValue(self, @selector(encodeValueOfObjCType:at:),
+                  (char *)_array + offset, _type);
+    }
+  }
+}
+
+// -------------------- decoding --------------------
+
+- (void)decodeArchiveHeader {
+  if (self->didReadHeader == NO) {
+    char *archiver = _readCString(self);
+
+    self->inArchiverVersion = _readInt(self);
+
+    if (strcmp(archiver, [[self coderSignature] cString])) {
+      NSLog(@"WARNING: used a different archiver (signature %s:%i)",
+            archiver, [self systemVersion]);
+    }
+    else if ([self systemVersion] != [self coderVersion]) {
+      NSLog(@"WARNING: used a different archiver version "
+            @"(archiver=%i, unarchiver=%i)",
+            [self systemVersion], [self coderVersion]);
+    }
+
+    if (archiver) {
+      NGFree(archiver);
+      archiver = NULL;
+    }
+    self->didReadHeader = YES;
+  }
+}
+
+- (void)beginDecoding {
+#if 0
+  NSLog(@"start decoding ..");
+#endif
+  [self decodeArchiveHeader];
+}
+- (void)endDecoding {
+#if 0
+  NSLog(@"finish decoding ..");
+#endif
+  NSResetMapTable(self->inObjects);
+  NSResetMapTable(self->inClasses);
+  NSResetMapTable(self->inPointers);
+  NSResetMapTable(self->inClassAlias);
+  NSResetMapTable(self->inClassVersions);
+}
+
+- (Class)_decodeClass:(BOOL)_isReference {
+  int   archiveId = _readInt(self);
+  Class result    = Nil;
+  
+  if (_isReference) {
+    result = (Class)NSMapGet(self->inClasses, (void *)archiveId);
+    if (result == Nil) {
+      NSLog(@"did not find class for archive-id %i", archiveId);
+    }
+  }
+  else {
+    NSString *name   = NULL;
+    int      version = 0;
+
+    name    = [NSString stringWithCString:_readCString(self)];
+    version = _readInt(self);
+
+    if (name == nil) {
+      [NSException raise:NSInconsistentArchiveException
+                   format:@"did not find class name"];
+    }
+
+    { // check whether the class is to be replaced
+      NSString *newName = NSMapGet(self->inClassAlias, name);
+      
+      if (newName)
+        name = newName;
+      else {
+        newName = NSMapGet(classToAliasMappings, name);
+        if (newName)
+          name = newName;
+      }
+    }
+    
+    result = NSClassFromString(name);
+#if 0
+    NSLog(@"decoded class %@:%i (result=%@).", name, version, result);
+#endif
+    
+    NSAssert([result version] == version, @"class versions do not match ..");
+
+    NSMapInsert(self->inClasses, (void *)archiveId, result);
+  }
+  
+  NSAssert(result, @"class may not be Nil ..");
+  
+  return result;
+}
+- (id)_decodeObject:(BOOL)_isReference {
+  // this method returns a retained object !
+  int archiveId = _readInt(self);
+  id  result    = nil;
+
+  if (archiveId == 0) // nil object or unused conditional object
+    return nil;
+  
+  if (_isReference) {
+    result = [(id)NSMapGet(self->inObjects, (void *)archiveId) retain];
+  }
+  else {
+    Class class       = Nil;
+    id    replacement = nil;
+
+    // decode class info
+    [self decodeValueOfObjCType:"#" at:&class];
+    NSAssert(class, @"invalid class ..");
+    
+    result = [class allocWithZone:self->objectZone];
+    NSMapInsert(self->inObjects, (void *)archiveId, result);
+
+    replacement = [result initWithCoder:self];
+    if (replacement != result) {
+
+      replacement = [replacement retain];
+      NSMapRemove(self->inObjects, result);
+      result = replacement;
+      NSMapInsert(self->inObjects, (void *)archiveId, result);
+      [replacement release];
+    }
+
+    replacement = [result awakeAfterUsingCoder:self];
+    if (replacement != result) {
+      replacement = [replacement retain];
+      NSMapRemove(self->inObjects, result);
+      result = replacement;
+      NSMapInsert(self->inObjects, (void *)archiveId, result);
+      [replacement release];
+    }
+  }
+  NSAssert([result retainCount] > 0, @"invalid retain count ..");
+  return result;
+}
+
+- (id)decodeObject {
+  id result = nil;
+
+  [self decodeValueOfObjCType:"@" at:&result];
+  
+  // result is retained
+  return [result autorelease];
+}
+
+- (void)decodeValueOfObjCType:(const char *)_type at:(void *)_value {
+  BOOL      startedDecoding = NO;
+  NGTagType tag             = 0;
+  BOOL      isReference     = NO;
+
+  if (self->decodingRoot == NO) {
+    self->decodingRoot = YES;
+    startedDecoding = YES;
+    [self beginDecoding];
+  }
+
+  tag         = _readTag(self);
+  isReference = isReferenceTag(tag);
+  tag         = tagValue(tag);
+
+  switch (tag) {
+    case _C_ID:
+      NSAssert((*_type == _C_ID) || (*_type == _C_CLASS), @"invalid type ..");
+      *(id *)_value = [self _decodeObject:isReference];
+      break;
+    case _C_CLASS:
+      NSAssert((*_type == _C_ID) || (*_type == _C_CLASS), @"invalid type ..");
+      *(Class *)_value = [self _decodeClass:isReference];
+      break;
+
+    case _C_ARY_B: {
+      int        count     = atoi(_type + 1); // eg '[15I' => count = 15
+      const char *itemType = _type;
+
+      NSAssert(*_type == _C_ARY_B, @"invalid type ..");
+
+      while(isdigit((int)*(++itemType))) ; // skip dimension
+
+      [self decodeArrayOfObjCType:itemType count:count at:_value];
+      break;
+    }
+
+    case _C_STRUCT_B: {
+      int offset = 0;
+
+      NSAssert(*_type == _C_STRUCT_B, @"invalid type ..");
+      
+      while ((*_type != _C_STRUCT_E) && (*_type++ != '=')); // skip "<name>="
+        
+      while (YES) {
+        [self decodeValueOfObjCType:_type at:((char *)_value) + offset];
+            
+        offset += objc_sizeof_type(_type);
+        _type  =  objc_skip_typespec(_type);
+            
+        if(*_type != _C_STRUCT_E) { // C-structure end '}'
+          int align, remainder;
+                    
+          align = objc_alignof_type(_type);
+          if((remainder = offset % align))
+            offset += (align - remainder);
+        }
+        else
+          break;
+      }
+      break;
+    }
+
+    case _C_SEL: {
+      char *name = NULL;
+      
+      NSAssert(*_type == tag, @"invalid type ..");
+      _readObjC(self, &name, @encode(char *));
+      *(SEL *)_value = name ? sel_get_any_uid(name) : NULL;
+      NGFree(name); name = NULL;
+    }
+
+    case _C_PTR:
+      _readObjC(self, *(char **)_value, _type + 1); // skip '^'
+      break;
+      
+    case _C_CHARPTR:
+    case _C_CHR:    case _C_UCHR:
+    case _C_SHT:    case _C_USHT:
+    case _C_INT:    case _C_UINT:
+    case _C_LNG:    case _C_ULNG:
+    case _C_FLT:    case _C_DBL:
+      NSAssert(*_type == tag, @"invalid type ..");
+      _readObjC(self, _value, _type);
+      break;
+      
+    default:
+      NSAssert2(0, @"unsupported tag '%c', type %s ..", tag, _type);
+      break;
+  }
+
+  if (startedDecoding) {
+    [self endDecoding];
+    self->decodingRoot = NO;
+  }
+}
+
+- (void)decodeArrayOfObjCType:(const char *)_type count:(unsigned int)_count
+  at:(void *)_array {
+
+  BOOL      startedDecoding = NO;
+  NGTagType tag   = _readTag(self);
+  int       count = _readInt(self);
+
+  if (self->decodingRoot == NO) {
+    self->decodingRoot = YES;
+    startedDecoding = YES;
+    [self beginDecoding];
+  }
+
+#if 0
+  NSLog(@"decoding array[%i/%i] of ObjC-type '%s' array-tag='%c'",
+         _count, count, _type, tag);
+#endif
+  
+  NSAssert(tag == _C_ARY_B, @"invalid type ..");
+  NSAssert(count == _count, @"invalid array size ..");
+
+  // Arrays of elementary types are written optimized: the type is written
+  // then the elements of array follow.
+  if ((*_type == _C_ID) || (*_type == _C_CLASS)) { // object array
+    int i;
+
+#if 0
+    NSLog(@"decoding object-array[%i] type='%s'", _count, _type);
+#endif
+
+    tag = _readTag(self); // object array
+    NSAssert(tag == *_type, @"invalid array element type ..");
+      
+    for (i = 0; i < _count; i++)
+      ((id *)_array)[i] = [self decodeObject];
+  }
+  else if ((*_type == _C_CHR) || (*_type == _C_UCHR)) { // byte array
+    tag = _readTag(self);
+    NSAssert((tag == _C_CHR) || (tag == _C_UCHR), @"invalid byte array type ..");
+
+#if 0
+    NSLog(@"decoding byte-array[%i] type='%s' tag='%c'",
+           _count, _type, tag);
+#endif
+
+    // read buffer
+    _readBytes(self, _array, _count);
+  }
+  else if (isBaseType(_type)) {
+    unsigned offset, itemSize = objc_sizeof_type(_type);
+    int      i;
+      
+    tag = _readTag(self);
+    NSAssert(tag == *_type, @"invalid array base type ..");
+
+    for (i = offset = 0; i < _count; i++, offset += itemSize)
+      _readObjC(self, (char *)_array + offset, _type);
+  }
+  else {
+    IMP      decodeValue = NULL;
+    unsigned offset, itemSize = objc_sizeof_type(_type);
+    int      i;
+
+    decodeValue = [self methodForSelector:@selector(decodeValueOfObjCType:at:)];
+    
+    for (i = offset = 0; i < count; i++, offset += itemSize) {
+      decodeValue(self, @selector(decodeValueOfObjCType:at:),
+                  (char *)_array + offset, _type);
+    }
+  }
+
+  if (startedDecoding) {
+    [self endDecoding];
+    self->decodingRoot = NO;
+  }
+}
+
+// Substituting One Class for Another
+
++ (NSString *)classNameDecodedForArchiveClassName:(NSString *)nameInArchive {
+  NSString *className = NSMapGet(classToAliasMappings, nameInArchive);
+  return className ? className : nameInArchive;
+}
++ (void)decodeClassName:(NSString *)nameInArchive asClassName:(NSString *)trueName {
+  NSMapInsert(classToAliasMappings, nameInArchive, trueName);
+}
+
+- (NSString *)classNameDecodedForArchiveClassName:(NSString *)_nameInArchive {
+  NSString *className = NSMapGet(self->inClassAlias, _nameInArchive);
+  return className ? className : _nameInArchive;
+}
+- (void)decodeClassName:(NSString *)nameInArchive asClassName:(NSString *)trueName {
+  NSMapInsert(self->inClassAlias, nameInArchive, trueName);
+}
+
+// ******************** primitives ********************
+
+// encoding
+
+FINAL void _writeBytes(NGStreamCoder *self, const void *_bytes, unsigned _len) {
+  NSCAssert(self->traceMode == NO, @"nothing can be written during trace-mode ..");
+  
+  self->writeIMP
+    ? self->writeIMP(self->stream, @selector(safeWriteBytes:count:), _bytes, _len)
+    : [self->stream safeWriteBytes:_bytes count:_len];
+}
+
+FINAL void _writeTag(NGStreamCoder *self, NGTagType _tag) {
+  NSCAssert(self, @"invalid self ..");
+#if 0
+  NSLog(@"write tag '%s%c'",
+        isReferenceTag(_tag) ? "&" : "", tagValue(_tag));
+#endif
+  
+  [self->stream serializeChar:_tag];
+}
+
+FINAL void _writeChar(NGStreamCoder *self, char _value) {
+  [self->stream serializeChar:_value];
+}
+FINAL void _writeShort(NGStreamCoder *self, short _value) {
+  [self->stream serializeShort:_value];
+}
+FINAL void _writeInt(NGStreamCoder *self, int _value) {
+  [self->stream serializeInt:_value];
+}
+FINAL void _writeLong(NGStreamCoder *self, long _value) {
+  [self->stream serializeLong:_value];
+}
+FINAL void _writeFloat(NGStreamCoder *self, float _value) {
+  [self->stream serializeFloat:_value];
+}
+
+FINAL void _writeCString(NGStreamCoder *self, const char *_value) {
+  [(id)self->stream serializeDataAt:&_value ofObjCType:@encode(char *) context:self];
+}
+
+FINAL void _writeObjC(NGStreamCoder *self,
+                              const void *_value, const char *_type) {
+  if ((_value == NULL) || (_type == NULL))
+    return;
+
+  if (self->traceMode) {
+    // no need to track base-types in trace-mode
+    
+    switch (*_type) {
+      case _C_ID:
+      case _C_CLASS:
+      case _C_CHARPTR:
+      case _C_ARY_B:
+      case _C_STRUCT_B:
+      case _C_PTR:
+        [(id)self->stream serializeDataAt:_value ofObjCType:_type context:self];
+        break;
+
+      default:
+        break;
+    }
+  }
+  else {
+    [(id)self->stream serializeDataAt:_value ofObjCType:_type context:self];
+  }
+}
+
+// decoding
+
+FINAL void _readBytes(NGStreamCoder *self, void *_bytes, unsigned _len) {
+  self->readIMP
+    ? self->readIMP(self->stream, @selector(safeReadBytes:count:), _bytes, _len)
+    : [self->stream safeReadBytes:_bytes count:_len];
+}
+
+FINAL NGTagType _readTag(NGStreamCoder *self) {
+  return [self->stream deserializeChar];
+}
+FINAL char _readChar(NGStreamCoder *self) {
+  return [self->stream deserializeChar];
+}
+FINAL short _readShort(NGStreamCoder *self) {
+  return [self->stream deserializeShort];
+}
+FINAL int _readInt(NGStreamCoder *self) {
+  return [self->stream deserializeInt];
+}
+FINAL long _readLong (NGStreamCoder *self) {
+  return [self->stream deserializeLong];
+}
+FINAL float _readFloat(NGStreamCoder *self) {
+  return [self->stream deserializeFloat];
+}
+
+FINAL char *_readCString(NGStreamCoder *self) {
+  char *result = NULL;
+  [(id)self->stream deserializeDataAt:&result ofObjCType:@encode(char *) context:self];
+  return result;
+}
+
+FINAL void _readObjC(NGStreamCoder *self, void *_value, const char *_type) {
+  [(id)self->stream deserializeDataAt:_value ofObjCType:_type context:(id)self];
+}
+
+// NSObjCTypeSerializationCallBack
+
+- (void)serializeObjectAt:(id *)_object ofObjCType:(const char *)_type
+  intoData:(NSMutableData *)_data {
+
+  switch (*_type) {
+    case _C_ID:
+    case _C_CLASS:
+      if (self->traceMode)
+        [self _traceObject:*_object];
+      else
+        [self _encodeObject:*_object];
+      break;
+        
+    default:
+      abort();
+      break;
+  }
+}
+
+- (void)deserializeObjectAt:(id *)_object ofObjCType:(const char *)_type
+  fromData:(NSData *)_data atCursor:(unsigned int *)_cursor {
+
+  NGTagType tag             = 0;
+  BOOL      isReference     = NO;
+
+  tag         = _readTag(self);
+  isReference = isReferenceTag(tag);
+  tag         = tagValue(tag);
+  
+  switch (*_type) {
+    case _C_ID:
+      NSAssert((*_type == _C_ID) || (*_type == _C_CLASS), @"invalid type ..");
+      break;
+      *_object = [self _decodeObject:isReference];
+      break;
+    case _C_CLASS:
+      NSAssert((*_type == _C_ID) || (*_type == _C_CLASS), @"invalid type ..");
+      *_object = [self _decodeClass:isReference];
+      break;
+      
+    default:
+      abort();
+      break;
+  }
+}
+
+@end
diff --git a/skyrix-core/NGStreams/NGStreamExceptions.m b/skyrix-core/NGStreams/NGStreamExceptions.m
new file mode 100644 (file)
index 0000000..91ab9b8
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGStreamExceptions.h"
+
+@interface NSObject(setLastException)
+- (void)setLastException:(NSException *)_exception;
+@end
+
+@implementation NGIOException
+
+- (id)init {
+  self = [super initWithName:NSStringFromClass([self class])
+                reason:@"an IO exception occured"
+                userInfo:nil];
+  return self;
+}
+- (id)initWithReason:(NSString *)_reason {
+  self = [super initWithName:NSStringFromClass([self class])
+                reason:_reason
+                userInfo:nil];
+  return self;
+}
+
++ (void)raiseWithReason:(NSString *)_reason {
+  [[[self alloc] initWithReason:_reason] raise];
+}
+
++ (void)raiseOnStream:(id)_stream reason:(NSString *)_reason {
+  NGIOException *e;
+
+  e = [[self alloc] initWithReason:_reason];
+  
+  if (_stream) {
+    if ([_stream respondsToSelector:@selector(setLastException:)]) {
+      [_stream setLastException:e];
+      [e release];
+      return;
+    }
+  }
+  [e raise];
+}
++ (void)raiseOnStream:(id)_stream {
+  [self raiseOnStream:_stream reason:nil];
+}
+
+@end /* NGIOException */
+
+@implementation NGStreamException
+
+- (NSString *)defaultReason {
+  return @"a stream exception occured";
+}
+
+- (id)init {
+  return [self initWithStream:nil reason:[self defaultReason]];
+}
+- (id)initWithStream:(id<NGStream>)_stream {
+  return [self initWithStream:_stream reason:[self defaultReason]];
+}
+
+- (id)initWithStream:(id<NGStream>)_stream format:(NSString *)_format,... {
+  NSString *tmp = nil;
+  va_list  ap;
+  
+  va_start(ap, _format);
+  tmp = [[NSString alloc] initWithFormat:_format arguments:ap];
+  va_end(ap);
+
+  self = [self initWithStream:_stream reason:tmp];
+  [tmp release];
+  return self;
+}
+
+- (id)initWithStream:(id<NGStream>)_stream reason:(NSString *)_reason {
+  NSDictionary *ui = nil;
+  
+  ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                       [NSNumber numberWithInt:errno], @"errno",
+                       [NSString stringWithCString:strerror(errno)], @"error",
+                       [NSValue valueWithNonretainedObject:_stream], @"stream",
+                       nil];
+  
+  self = [super initWithName:NSStringFromClass([self class])
+                reason:_reason
+                userInfo:ui];
+  if (self) {
+    self->streamPointer = 
+      [[NSValue valueWithNonretainedObject:_stream] retain];
+  }
+  return self;
+}
+
++ (id)exceptionWithStream:(id<NGStream>)_stream {
+  return [[self alloc] initWithStream:_stream];
+}
++ (id)exceptionWithStream:(id<NGStream>)_stream reason:(NSString *)_reason {
+  return [[self alloc] initWithStream:_stream reason:_reason];
+}
++ (void)raiseWithStream:(id<NGStream>)_stream {
+  [[[self alloc] initWithStream:_stream] raise];
+}
++ (void)raiseWithStream:(id<NGStream>)_stream reason:(NSString *)_reason {
+  [[[self alloc] initWithStream:_stream reason:_reason] raise];
+}
++ (void)raiseWithStream:(id<NGStream>)_stream format:(NSString *)_format,... {
+  NSString *tmp = nil;
+  va_list  ap;
+  
+  va_start(ap, _format);
+  tmp = [[NSString alloc] initWithFormat:_format arguments:ap];
+  va_end(ap);
+  tmp = [tmp autorelease];
+
+  [[[self alloc] initWithStream:_stream reason:tmp] raise];
+}
+
+- (void)dealloc {
+  [self->streamPointer release];
+  [super dealloc];
+}
+
+@end /* NGStreamException */
+
+// ******************** NGEndOfStreamException ********************
+
+@implementation NGEndOfStreamException
+
+- (id)initWithStream:(id<NGStream>)_stream {
+  return [self initWithStream:_stream
+               readCount:0
+               safeCount:0
+               data:nil];
+}
+
+- (id)initWithStream:(id<NGStream>)_stream
+  readCount:(unsigned)_readCount
+  safeCount:(unsigned)_safeCount
+  data:(NSData *)_data {
+
+  NSString *tmp;
+
+  tmp = [NSString stringWithFormat:@"reached end of stream %@", _stream];
+
+  if ((self = [super initWithStream:_stream reason:tmp])) {
+    self->readCount = _readCount;
+    self->safeCount = _safeCount;
+    self->data      = [_data retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->data release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSData *)readBytes {
+  return self->data;
+}
+
+@end /* NGEndOfStreamException */
+
+// ******************** open state exceptions *********************
+
+@implementation NGCouldNotOpenStreamException
+
+- (NSString *)defaultReason {
+  return @"could not open stream";
+}
+
+@end
+
+@implementation NGCouldNotCloseStreamException
+
+- (NSString *)defaultReason {
+  return @"could not close stream";
+}
+
+@end
+
+@implementation NGStreamNotOpenException
+
+- (NSString *)defaultReason {
+  return @"stream is not open";
+}
+
+@end
+
+// ******************** NGStreamErrors ****************************
+
+@implementation NGStreamErrorException
+
+- (id)initWithStream:(id<NGStream>)_stream errorCode:(int)_code {
+  NSString *tmp = nil;
+
+  tmp = [NSString stringWithFormat:@"stream error occured, errno=%i error=%s",
+                    _code, strerror(_code)];
+  if ((self = [self initWithStream:_stream reason:tmp])) {
+    osErrorCode = _code;
+  }
+  tmp = nil;
+  return self;
+}
+
++ (void)raiseWithStream:(id<NGStream>)_stream errorCode:(int)_code {
+  [[[self alloc] initWithStream:_stream errorCode:_code] raise];
+}
+
+- (int)operationSystemErrorCode {
+  return osErrorCode;
+}
+- (NSString *)operatingSystemError {
+  return [NSString stringWithCString:strerror(osErrorCode)];
+}
+
+@end /* NGStreamErrorException */
+
+@implementation NGStreamReadErrorException
+
+- (NSString *)defaultReason {
+  return @"read error on stream";
+}
+
+@end /* NGStreamReadErrorException */
+
+@implementation NGStreamWriteErrorException
+
+- (NSString *)defaultReason {
+  return @"write error on stream";
+}
+
+@end /* NGStreamWriteErrorException */
+
+@implementation NGStreamSeekErrorException
+
+- (NSString *)defaultReason {
+  return @"seek error on stream";
+}
+
+@end
+
+// ******************** NGStreamModeExceptions ********************
+
+@implementation NGStreamModeException
+
+- (NSString *)defaultReason {
+  return @"stream mode failure";
+}
+
+@end
+
+@implementation NGUnknownStreamModeException
+
+- (NSString *)defaultReason {
+  return @"unknow stream mode";
+}
+
+- (id)initWithStream:(id<NGStream>)_stream mode:(NSString *)_streamMode {
+  if ((self = [super initWithStream:_stream
+                     format:@"unknown stream mode: %@", _streamMode])) {
+    streamMode = [_streamMode copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->streamMode release];
+  [super dealloc];
+}
+
+@end /* NGUnknownStreamModeException */
+
+@implementation NGReadOnlyStreamException
+
+- (NSString *)defaultReason {
+  return @"stream is read only";
+}
+
+@end /* NGReadOnlyStreamException */
+
+@implementation NGWriteOnlyStreamException
+
+- (NSString *)defaultReason {
+  return @"stream is write only";
+}
+
+@end /* NGWriteOnlyStreamException */
+
+// ******************** NGIOAccessException ******************
+
+@implementation NGIOAccessException
+@end
+
+@implementation NGIOSearchAccessException
+@end
diff --git a/skyrix-core/NGStreams/NGStreamPipe.m b/skyrix-core/NGStreams/NGStreamPipe.m
new file mode 100644 (file)
index 0000000..91c0ca5
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "config.h"
+#include "common.h"
+#include "NGStreamPipe.h"
+#include "NGFileStream.h"
+#include "NGBufferedStream.h"
+
+#if defined(WIN32)
+
+@implementation NGStreamPipe
+@end
+
+#else
+
+static const int NGInvalidUnixDescriptor = -1;
+
+@interface _NGConcretePipeFileHandle : NSFileHandle
+{
+@public
+  int *fd;
+}
+
+- (id)initWithDescriptor:(int *)_fd;
+
+@end
+
+@interface NGFileStream(PrivateMethods)
+- (id)__initWithDescriptor:(int)_fd mode:(NGStreamMode)_mode;
+@end
+
+@implementation NGStreamPipe
+
++ (id)pipe {
+  return [[[self alloc] init] autorelease];
+}
+
+- (id)init {
+  if (pipe(self->fildes) == -1) {
+    NSLog (@"pipe() system call failed: %s", strerror (errno));
+    self = [self autorelease];
+    return nil;
+  }
+  return self;
+}
+
+- (void)gcFinalize {
+  [self close];
+}
+
+- (void)dealloc {
+  [self gcFinalize];
+  [self->fhIn  release];
+  [self->fhOut release];
+  [super dealloc];
+}
+
+- (NSFileHandle *)fileHandleForReading {
+  if (self->fhIn == nil) {
+    self->fhIn = [[_NGConcretePipeFileHandle alloc]
+                      initWithDescriptor:&(self->fildes[0])];
+  }
+  return self->fhIn;
+}
+- (NSFileHandle *)fileHandleForWriting {
+  if (self->fhOut == nil) {
+    self->fhOut = [[_NGConcretePipeFileHandle alloc]
+                       initWithDescriptor:&(self->fildes[1])];
+  }
+  return self->fhOut;
+}
+
+- (id<NGByteSequenceStream>)streamForReading {
+  return self;
+}
+- (id<NGOutputStream>)streamForWriting {
+  return self;
+}
+
+- (NSException *)lastException {
+  return nil;
+}
+
+/* NGInputStream */
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  int readResult;
+
+  if (self->fildes[0] == NGInvalidUnixDescriptor) {
+    [NGStreamReadErrorException raiseWithStream:self
+                                reason:@"read end of pipe is closed"];
+  }
+  
+  readResult = read(self->fildes[0], _buf, _len);
+
+  if (readResult == 0)
+    [NGEndOfStreamException raiseWithStream:self];
+  else if (readResult == -1)
+    [NGStreamReadErrorException raiseWithStream:self errorCode:errno];
+
+  return readResult;
+}
+- (BOOL)safeReadBytes:(void *)_buf count:(unsigned)_len {
+  return NGSafeReadBytesFromStream(self, _buf, _len);
+}
+
+/* marks */
+
+- (BOOL)mark {
+  NSLog(@"WARNING: called mark on a stream which doesn't support marking !");
+  return NO;
+}
+- (BOOL)rewind {
+  [NGStreamException raiseWithStream:self reason:@"marking not supported"];
+  return NO;
+}
+- (BOOL)markSupported {
+  return NO;
+}
+
+/* NGOutputStream */
+
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  int writeResult;
+
+  if (self->fildes[1] == NGInvalidUnixDescriptor) {
+    [NGStreamWriteErrorException raiseWithStream:self
+                                 reason:@"write end of pipe is closed"];
+  }
+  
+  writeResult = write(self->fildes[1], _buf, _len);
+
+  if (writeResult == -1)
+    [NGStreamWriteErrorException raiseWithStream:self errorCode:errno];
+  return writeResult;
+}
+- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len {
+  return NGSafeWriteBytesToStream(self, _buf, _len);
+}
+
+- (BOOL)flush {
+  return YES;
+}
+
+/* NGStream */
+
+- (BOOL)close {
+  if (self->fildes[0] != NGInvalidUnixDescriptor) close(self->fildes[0]);
+  if (self->fildes[1] != NGInvalidUnixDescriptor) close(self->fildes[1]);
+  return YES;
+}
+
+- (NGStreamMode)mode {
+  NGStreamMode mode = NGStreamMode_undefined;
+
+  if (self->fildes[0] != NGInvalidUnixDescriptor)
+    mode |= NGStreamMode_readOnly;
+  if (self->fildes[1] != NGInvalidUnixDescriptor)
+    mode |= NGStreamMode_writeOnly;
+
+  return mode;
+}
+
+// NGByteSequenceStream
+
+- (int)readByte {
+  return NGReadByteFromStream(self);
+}
+
+// Extensions
+
+- (BOOL)isOpen {
+  return (self->fildes[0] == NGInvalidUnixDescriptor) &&
+         (self->fildes[1] == NGInvalidUnixDescriptor) ? NO : YES;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X[%@]: in=%i out=%i>",
+                     self, NSStringFromClass([self class]),
+                     self->fildes[0], self->fildes[1]];
+}
+
+@end /* NGStreamPipe */
+
+@implementation _NGConcretePipeFileHandle
+
+- (id)initWithDescriptor:(int *)_fd {
+  self->fd = _fd;
+  return self;
+}
+
+- (int)fileDescriptor {
+  return *(self->fd);
+}
+
+- (void)closeFile {
+  close(*(self->fd));
+  *(self->fd) = NGInvalidUnixDescriptor;
+}
+
+@end
+
+#endif /* WIN32 */
diff --git a/skyrix-core/NGStreams/NGStreams-Info.plist b/skyrix-core/NGStreams/NGStreams-Info.plist
new file mode 100644 (file)
index 0000000..b6d085d
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGStreams</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.core.NGStreams</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-core/NGStreams/NGStreams.m b/skyrix-core/NGStreams/NGStreams.m
new file mode 100644 (file)
index 0000000..a26ac74
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGStreams.h"
+
+@implementation NGStreams
+
+- (void)_staticLinkClasses {
+}
+
+- (void)_staticLinkModules {
+}
+
+@end /* NGStreams */
diff --git a/skyrix-core/NGStreams/NGStreams/NGActiveSSLSocket.h b/skyrix-core/NGStreams/NGStreams/NGActiveSSLSocket.h
new file mode 100644 (file)
index 0000000..308a068
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+#ifndef __NGNet_NGActiveSSLSocket_H__
+#define __NGNet_NGActiveSSLSocket_H__
+
+#include <NGStreams/NGActiveSocket.h>
+
+@interface NGActiveSSLSocket : NGActiveSocket
+{
+  void *ctx;   /* real type: SSL_CTX */
+  void *ssl;   /* real type: SSL */
+  void *sbio;  /* real type: BIO (basic input/output) */
+}
+
+@end
+
+#endif /* __NGNet_NGActiveSSLSocket_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGActiveSocket+serialization.h b/skyrix-core/NGStreams/NGStreams/NGActiveSocket+serialization.h
new file mode 100644 (file)
index 0000000..47d06e6
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGActiveSocket_serialization_H__
+#define __NGNet_NGActiveSocket_serialization_H__
+
+#if !(MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED)
+#  define USE_SERIALIZER 1
+#endif
+
+#import <Foundation/NSObject.h>
+#if USE_SERIALIZER
+#  import <Foundation/NSSerialization.h>
+#endif
+#include <NGStreams/NGStream+serialization.h>
+#include <NGStreams/NGActiveSocket.h>
+
+@interface NGActiveSocket(serialization)
+#if USE_SERIALIZER
+  < NGSerializer >
+#endif
+
+- (void)serializeChar:(char)_value;
+- (void)serializeShort:(short)_value;
+- (void)serializeInt:(int)_value;
+- (void)serializeLong:(long)_value;
+- (void)serializeFloat:(float)_value;
+- (void)serializeDouble:(double)_value;
+- (void)serializeLongLong:(long long)_value;
+
+- (char)deserializeChar;
+- (short)deserializeShort;
+- (int)deserializeInt;
+- (long)deserializeLong;
+- (float)deserializeFloat;
+- (double)deserializeDouble;
+- (long long)deserializeLongLong;
+
+- (void)serializeCString:(const char *)_value;
+- (char *)deserializeCString;
+
+#if USE_SERIALIZER
+- (void)serializeDataAt:(const void*)data ofObjCType:(const char*)type
+  context:(id<NSObjCTypeSerializationCallBack>)_callback;
+- (void)deserializeDataAt:(void *)data ofObjCType:(const char*)type
+  context:(id<NSObjCTypeSerializationCallBack>)_callback;
+#endif
+
+@end
+
+#endif /* __NGNet_NGActiveSocket_serialization_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGActiveSocket.h b/skyrix-core/NGStreams/NGStreams/NGActiveSocket.h
new file mode 100644 (file)
index 0000000..b80808a
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGActiveSocket_H__
+#define __NGNet_NGActiveSocket_H__
+
+#import <Foundation/NSDate.h>
+#include <NGStreams/NGSocket.h>
+#include <NGStreams/NGSocketProtocols.h>
+#include <NGStreams/NGStreamProtocols.h>
+
+@class NSData, NSFileHandle;
+
+/*
+  Represents an active STREAM socket based on the standard Unix sockets library.
+
+  An active socket can be either a socket gained by calling accept with an
+  passive socket or by explicitly connecting one to an address (a client socket).
+  Therefore an active socket has two addresses, the local and the remote one.
+
+  There are three methods to perform a close, this is rooted in the fact that
+  a socket actually is full-duplex, it provides a send and a receive channel.
+  The stream-mode is updated according to what channels are open/closed.
+  Initially the socket is full-duplex and you cannot reopen a channel that was
+  shutdown. If you have shutdown both channels the socket can be considered
+  closed.
+*/
+
+@interface NGActiveSocket : NGSocket < NGActiveSocket >
+{
+@private
+  id<NGSocketAddress> remoteAddress;
+  NGStreamMode        mode;
+  
+  NSTimeInterval receiveTimeout;
+  NSTimeInterval sendTimeout;
+}
+
++ (id)socketConnectedToAddress:(id<NGSocketAddress>)_address;
+- (id)initWithDomain:(id<NGSocketDomain>)_domain; // designated initializer
+
+#if !defined(WIN32)
++ (BOOL)socketPair:(id<NGSocket>[2])_pair inDomain:(id<NGSocketDomain>)_domain;
+#endif
+
+// ******************** operations ********************
+
+// throws
+//   NGSocketAlreadyConnectedException  when the socket is already connected
+//   NGInvalidSocketDomainException     when the remote domain != local domain
+//   NGCouldNotCreateSocketException    if the socket creation failed
+- (BOOL)connectToAddress:(id<NGSocketAddress>)_address;
+
+- (BOOL)shutdown; // do a complete shutdown
+- (BOOL)shutdownSendChannel;
+- (BOOL)shutdownReceiveChannel;
+
+// ******************** accessors *********************
+
+- (id<NGSocketAddress>)remoteAddress;
+- (BOOL)isConnected;
+- (BOOL)isOpen;
+
+- (void)setSendTimeout:(NSTimeInterval)_timeout;
+- (NSTimeInterval)sendTimeout;
+- (void)setReceiveTimeout:(NSTimeInterval)_timeout;
+- (NSTimeInterval)receiveTimeout;
+
+// test whether a read, a write or both would block the thread (using select)
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode;
+- (int)waitForMode:(NGStreamMode)_mode timeout:(NSTimeInterval)_timeout;
+- (unsigned)numberOfAvailableBytesForReading;
+- (BOOL)isAlive;
+
+// ******************** NGStream **********************
+
+// throws
+//   NGStreamReadErrorException    when the read call failed
+//   NGSocketNotConnectedException when the socket is not connected
+//   NGEndOfStreamException        when the end of the stream is reached
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;
+
+// throws
+//   NGStreamWriteErrorException   when the write call failed
+//   NGSocketNotConnectedException when the socket is not connected
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len;
+
+- (BOOL)flush;                  // does nothing, sockets are unbuffered
+- (NGStreamMode)mode;           // returns read/write
+
+- (BOOL)safeReadBytes:(void *)_buf count:(unsigned)_len;
+- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len;
+
+@end
+
+@interface NGActiveSocket(DataMethods)
+
+- (NSData *)readDataOfLength:(unsigned int)_length;
+- (NSData *)safeReadDataOfLength:(unsigned int)_length;
+- (unsigned int)writeData:(NSData *)_data;
+- (BOOL)safeWriteData:(NSData *)_data;
+
+@end
+
+#endif /* __NGNet_NGActiveSocket_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGBase64Stream.h b/skyrix-core/NGStreams/NGStreams/NGBase64Stream.h
new file mode 100644 (file)
index 0000000..c3441ad
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGBase64Stream_H__
+#define __NGStreams_NGBase64Stream_H__
+
+#include <NGStreams/NGFilterStream.h>
+
+/*
+  NGBase64Stream
+  
+  A filter stream which either decodes or encodes Base64 entities on the fly.
+*/
+
+@interface NGBase64Stream : NGFilterStream
+{
+@protected
+  /* decoding */
+  unsigned char decBuffer[3]; // output buffer
+  unsigned char decBufferLen; // number of bytes in buffer
+
+  /* encoding */
+  unsigned int  buf;          // a 24-bit quantity
+  unsigned int  bufBytes;     // how many octets are set in it
+  unsigned char line[74];     // output buffer
+  unsigned char lineLength;   // output buffer fill pointer
+}
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len; // decoder
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len; // encoder
+
+- (BOOL)close;
+- (BOOL)flush;
+
+@end
+
+#endif /* __NGStreams_NGBase64Stream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGBufferedStream.h b/skyrix-core/NGStreams/NGStreams/NGBufferedStream.h
new file mode 100644 (file)
index 0000000..0e7a511
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGBufferedStream_H__
+#define __NGStreams_NGBufferedStream_H__
+
+#include <NGStreams/NGFilterStream.h>
+
+@interface NGBufferedStream : NGFilterStream
+{
+@private
+  void     *readBuffer;
+  void     *readBufferPos;     // current position (ptr) in buffer
+  unsigned readBufferFillSize; // number of 'read' bytes in the buffer
+  unsigned readBufferSize;     // maximum capacity in bytes
+
+  void     *writeBuffer;
+  unsigned writeBufferFillSize;
+  unsigned writeBufferSize;
+
+  struct {
+    unsigned int _flushOnNewline:1;
+  } flags;
+}
+
++ (id)filterWithSource:(id<NGStream>)_source bufferSize:(unsigned)_size;
+- (id)initWithSource:(id<NGStream>)_source bufferSize:(unsigned)_size;
+- (id)initWithSource:(id<NGStream>)_source;
+
+/* accessors */
+
+- (void)setReadBufferSize:(unsigned)_size;
+- (unsigned)readBufferSize;
+
+- (void)setWriteBufferSize:(unsigned)_size;
+- (unsigned)writeBufferSize;
+
+/* blocking .. */
+
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode;
+
+/* primitives */
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len;
+- (BOOL)flush;
+
+@end
+
+@interface NGStream(NGBufferedStreamExtensions)
+
+- (NGBufferedStream *)bufferedStream;
+
+@end
+
+#endif /* __NGStreams_NGBufferedStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGByteBuffer.h b/skyrix-core/NGStreams/NGStreams/NGByteBuffer.h
new file mode 100644 (file)
index 0000000..5d3295f
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGByteBuffer_H__
+#define __NGStreams_NGByteBuffer_H__
+
+#include <NGStreams/NGFilterStream.h>
+#include <NGStreams/NGStreamProtocols.h>
+
+struct NGByteBufferLA;
+
+/*
+  Although NGByteBuffer is defined to be a stream, it is usually not used as
+  such. Instead most parsers implemented using NGByteBuffer will only call
+  -la: and -consume.
+
+  The stream interface is provided to read large blocks with a known length. Eg
+  if you have a structure that prefixes some data with the data's length, you
+  can first parse the length and then call -safeReadBytes:count: to read the
+  content.
+  
+  Note that -readByte and -la: return -1 on EOF.
+*/
+
+@interface NGByteBuffer : NGFilterStream
+{
+@protected
+  struct NGByteBufferLA *la;
+
+  unsigned bufLen;
+  BOOL     wasEOF;
+  unsigned headIdx;
+  unsigned sizeLessOne;
+
+  int (*readByte)(id, SEL);
+  int (*laFunction)(id, SEL, unsigned);
+}
+
+/*
+  Initialize a byte buffer with a lookahead depth of _la bytes.
+*/
++ (id)byteBufferWithSource:(id<NGStream>)_stream la:(unsigned)_la;
+- (id)initWithSource:(id<NGStream>)_stream la:(unsigned)_la;
+
+// LA
+- (int)la:(unsigned)_lookaheadPosition;
+
+- (void)consume;                // consume one byte
+- (void)consume:(unsigned)_cnt; // consume _cnt bytes
+
+// NGStream
+- (int)readByte;
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;
+
+@end
+
+#endif /* __NGStreams_NGByteBuffer_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGByteCountStream.h b/skyrix-core/NGStreams/NGStreams/NGByteCountStream.h
new file mode 100644 (file)
index 0000000..3a2b00b
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGByteCountStream_H__
+#define __NGStreams_NGByteCountStream_H__
+
+#include <NGStreams/NGFilterStream.h>
+
+@interface NGByteCountStream : NGFilterStream
+{
+@protected
+  unsigned      totalReadCount;
+  unsigned      totalWriteCount;
+  unsigned char byteToCount;
+  unsigned      byteReadCount;
+  unsigned      byteWriteCount;
+}
+
++ (id)byteCounterForStream:(id<NGStream>)_stream byte:(unsigned char)_byte;
+- (id)initWithSource:(id<NGStream>)_source byte:(unsigned char)_byte;
+
+// accessors
+
+- (void)setByteToCount:(unsigned char)_byte;
+- (unsigned char)byteToCount;
+
+- (unsigned)readCount;
+- (unsigned)writeCount;
+
+- (unsigned)totalReadCount;
+- (unsigned)totalWriteCount;
+
+// operations
+
+- (void)resetCounters;
+
+@end
+
+#endif /* __NGStreams_NGByteCountStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGCTextStream.h b/skyrix-core/NGStreams/NGStreams/NGCTextStream.h
new file mode 100644 (file)
index 0000000..f611ddc
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGCTextStream_H__
+#define __NGStreams_NGCTextStream_H__
+
+#include <NGStreams/NGStreamsDecls.h>
+#include <NGStreams/NGStream.h>
+#include <NGStreams/NGTextStream.h>
+#include <NGStreams/NGTextStreamProtocols.h>
+#include <NGStreams/NGFilterStream.h>
+
+@class NSEnumerator;
+
+NGStreams_EXPORT id<NGExtendedTextInputStream>  NGTextIn;
+NGStreams_EXPORT id<NGExtendedTextOutputStream> NGTextOut;
+NGStreams_EXPORT id<NGExtendedTextOutputStream> NGTextErr;
+NGStreams_EXPORT void NGInitTextStdio(void);
+
+/*
+  NGCTextStream
+
+  NGCTextStream is a text stream which operates in the operation systems
+  default encoding (it returns the bytes read from the source as characters).
+  Note that the results of the unicode-methods do not necessarily represent a
+  valid unicode character. This is only the case for character codes in the
+  7bit ASCII set.
+  NGCTextStream never returns a character value above 255.
+  
+  To retrieve correctly converted unicode characters use the NGTextStream class.
+*/
+
+@interface NGCTextStream : NGTextStream
+{
+@private
+  id<NGStream>        source; // retained
+  NGIOReadMethodType  readBytes;
+  NGIOWriteMethodType writeBytes;
+  BOOL                (*flushBuffer)(id, SEL);
+}
+
++ (id)textStreamWithInputSource:(id<NGInputStream>)_source;
++ (id)textStreamWithOutputSource:(id<NGOutputStream>)_source;
++ (id)textStreamWithSource:(id<NGStream>)_stream;
+- (id)initWithSource:(id<NGStream>)_stream;
+- (id)initWithInputSource:(id<NGInputStream>)_source;
+- (id)initWithOutputSource:(id<NGOutputStream>)_source;
+
+// accessors
+
+- (id<NGStream>)source;
+
+// operations
+
+- (BOOL)close; // forwarded to source
+
+// NGTextInputStream, NGExtendedTextInputStream
+
+- (unichar)readCharacter;
+- (unsigned char)readChar;
+
+- (NSString *)readLineAsString;
+
+// Enumeration
+
+- (NSEnumerator *)lineEnumerator;
+
+// NGTextOutputStream, NGExtendedTextOutputStream
+
+- (BOOL)writeCharacter:(unichar)_character;
+- (BOOL)writeString:(NSString *)_string;
+- (BOOL)flush;
+
+- (BOOL)writeNewline;
+
+@end
+
+#endif /* __NGStreams_NGCTextStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGCharBuffer.h b/skyrix-core/NGStreams/NGStreams/NGCharBuffer.h
new file mode 100644 (file)
index 0000000..1737f25
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGCharBuffer_H__
+#define __NGStreams_NGCharBuffer_H__
+
+#include <NGStreams/NGFilterTextStream.h>
+#include <NGStreams/NGTextStreamProtocols.h>
+#include <NGStreams/NGStreamProtocols.h>
+
+struct NGCharBufferLA;
+
+/*
+  Although NGCharBuffer is defined to be a stream, it is usually not used as
+  such. Instead most parsers implemented using NGCharBuffer will only call
+  -la: and -consume.
+
+  Note that -la: return -1 on EOF and -readCharacter throws an
+  NGEndOfStreamException. -readCharacter is basically a -la:0 followed by a
+  -consume.
+*/
+
+@interface NGCharBuffer : NGFilterTextStream
+{
+@protected
+  struct NGCharBufferLA *la;
+
+  int  bufLen;
+  BOOL wasEOF;
+  int  headIdx;
+  int  sizeLessOne;
+
+  IMP readCharacter;
+}
+
++ (id)charBufferWithSource:(id<NGTextStream>)_source la:(int)_la;
+- (id)initWithSource:(id<NGTextStream>)_source la:(int)_la;
+
+// LA
+- (int)la:(int)_ls;
+
+- (void)consume;           // consume one character
+- (void)consume:(int)_cnt; // consume _cnt characters
+
+// NGTextStream
+- (unichar)readCharacter;
+
+@end
+
+#endif /* __NGStreams_NGCharBuffer_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGConcreteStreamFileHandle.h b/skyrix-core/NGStreams/NGStreams/NGConcreteStreamFileHandle.h
new file mode 100644 (file)
index 0000000..738e988
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGConcreteStreamFileHandle_H__
+#define __NGStreams_NGConcreteStreamFileHandle_H__
+
+#import <Foundation/NSFileHandle.h>
+#include <NGStreams/NGStream.h>
+
+@class NSData;
+
+@interface NGConcreteStreamFileHandle : NSFileHandle
+{
+  id<NGStream> stream;
+}
+
+- (id)initWithStream:(id<NGStream>)_stream;
+
+// accessors
+
+- (id<NGStream>)stream;
+
+// ops
+
+- (void)closeFile;
+- (int)fileDescriptor; // abstract
+
+// buffering
+
+- (void)synchronizeFile;
+
+// reading
+
+- (NSData *)readDataOfLength:(unsigned int)_length;
+- (NSData *)readDataToEndOfFile;
+
+// writing
+
+- (void)writeData:(NSData *)_data;
+
+// seeking
+
+- (void)seekToFileOffset:(unsigned long long)_offset;
+
+@end
+
+#endif /* __NGStreams_NGConcreteStreamFileHandle_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGDataStream.h b/skyrix-core/NGStreams/NGStreams/NGDataStream.h
new file mode 100644 (file)
index 0000000..cf4bfc3
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGDataStream_H__
+#define __NGStreams_NGDataStream_H__
+
+#include <NGStreams/NGStream.h>
+#include <NGStreams/NGStreamProtocols.h>
+
+@class NSData;
+
+@interface NGDataStream : NGStream < NGPositionableStream >
+{
+@private
+  NSException  *lastException;
+  NGStreamMode streamMode;
+  NSData       *data;
+  unsigned     position;
+  
+  unsigned int (*dataLength)(id, SEL);
+  const void   *(*dataBytes)(id, SEL);  
+  
+  /* for read-only streams */
+  unsigned int length;
+  const void   *bytes;
+}
+
++ (id)dataStream;
++ (id)dataStreamWithCapacity:(int)_capacity;
++ (id)streamWithData:(NSData *)_data;
+- (id)initWithData:(NSData *)_data mode:(NGStreamMode)_mode;
+- (id)initWithData:(NSData *)_data;
+
+- (NSException *)lastException;
+- (void)setLastException:(NSException *)_exception;
+- (void)resetLastException;
+
+// accessors
+
+- (NSData *)data;
+
+- (unsigned)availableBytes; // returns number of available bytes
+
+// primitives
+
+// throws
+//   NGStreamNotOpenException   when the stream is not open
+//   NGEndOfStreamException     when the end of the stream is reached
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;
+
+// throws
+//   NGReadOnlyStreamException when the stream is not writeable
+//   NGStreamNotOpenException  when the stream is not open
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len;
+
+- (BOOL)close;
+
+- (NGStreamMode)mode;
+- (BOOL)isRootStream;
+
+// NGPositionableStream
+
+- (BOOL)moveToLocation:(unsigned)_location;
+- (BOOL)moveByOffset:(int)_delta;
+
+// blocking ..
+
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode; // always NO ..
+
+@end
+
+#endif /* __NGStreams_NGDataStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGDatagramPacket.h b/skyrix-core/NGStreams/NGStreams/NGDatagramPacket.h
new file mode 100644 (file)
index 0000000..830aac6
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGDatagramPacket_H__
+#define __NGNet_NGDatagramPacket_H__
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGSocketProtocols.h>
+
+@class NSData;
+
+/*
+  This class represents an UDP datagram. It contains the addresses of it's sender
+  and it's receiver.
+*/
+
+@interface NGDatagramPacket : NSObject < NGDatagramPacket >
+{
+@protected
+  id<NGSocketAddress> sender;
+  id<NGSocketAddress> receiver;
+  NSData              *packet;
+}
+
+// packet factory
+
++ (id)packetWithData:(NSData *)_data;
++ (id)packetWithBytes:(const void *)_bytes size:(int)_packetSize;
+
+- (id)initWithBytes:(const void *)_bytes size:(int)_size;
+- (id)initWithData:(NSData *)_data;
+
+// accessors
+
+- (void)setSender:(id<NGSocketAddress>)_address;
+- (id<NGSocketAddress>)sender;
+- (void)setReceiver:(id<NGSocketAddress>)_address;
+- (id<NGSocketAddress>)receiver;
+
+- (void)setData:(NSData *)_data;
+- (NSData *)data;
+
+- (int)packetSize;
+
+// operations
+
+- (void)reverseAddresses;
+
+@end
+
+#endif /* __NGNet_NGDatagramPacket_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGDatagramSocket.h b/skyrix-core/NGStreams/NGStreams/NGDatagramSocket.h
new file mode 100644 (file)
index 0000000..d8ef2d0
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGDatagramSocket_H__
+#define __NGNet_NGDatagramSocket_H__
+
+#import <Foundation/NSDate.h>
+#include <NGStreams/NGSocket.h>
+#include <NGStreams/NGSocketProtocols.h>
+
+/*
+  Represents an UDP socket. UDP is a protocol based on IP, it's major 
+  difference to TCP is that UDP is connectionless and unreliable (UDP
+  datagrams send are not guaranteed to reach their destination).
+  
+  Note that you can connect an UDP socket. However, this only sets a 'default'
+  target address, an UDP socket can be connected multiple times, therefore
+  changing the default target. You can still use the send methods which take
+  a target when the socket is connected.
+
+  With UDP you do not have a distinction between active and passive sockets 
+  (you cannot put an UDP socket in the listen-state). A socket becomes a 
+  server socket by calling receive, which blocks the thread until a datagram 
+  is available and it becomes a client socket by calling send. However to send
+  datagrams you have to know the target address of the server-socket. This is
+  usually acomplished by binding the socket to a well-known address.
+
+  The receive packet methods take a timeout argument. The timeout is 
+  accomplished by using a poll call that waits for read and timeout. A timeout 
+  of 0 specifies that no timeout is used, that means the thread will block if 
+  no data is available.
+  When receiving a packet the socket needs to know the maximum packet size. 
+  While packets may be bigger than the maximum size, the additional bytes are
+  discarded.
+  If the packet size is known you should use receivePacketWithMaxSize: instead
+  of receivePacket. If the packet size is always the same, set the maximum
+  packet size and use receivePacket.
+*/
+
+extern NSString *NGSocketTimedOutNotificationName;
+
+@interface NGDatagramSocket : NGSocket
+{
+  id<NGDatagramPacketFactory> packetFactory;
+  int maxPacketSize; // default = 2048
+  struct {
+    BOOL isConnected:1;
+  } udpFlags;
+}
+
++ (id)socketBoundToAddress:(id<NGSocketAddress>)_address;
+
+#if !defined(WIN32)
++ (BOOL)socketPair:(id<NGSocket>[2])_pair inDomain:(id<NGSocketDomain>)_domain;
+#endif
+
+// accessors
+
+- (void)setMaxPacketSize:(int)_maxPacketSize;
+- (int)maxPacketSize;
+
+- (void)setPacketFactory:(id<NGDatagramPacketFactory>)_factory;
+- (id<NGDatagramPacketFactory>)packetFactory;
+
+- (int)socketType; // returns SOCK_DGRAM
+
+// polling
+
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode;
+
+// sending
+
+// returns NO on timeout
+- (BOOL)sendPacket:(id<NGDatagramPacket>)_packet timeout:(NSTimeInterval)_timeout;
+// blocks until data can be send
+- (BOOL)sendPacket:(id<NGDatagramPacket>)_packet;
+
+// receiving
+
+- (id<NGDatagramPacket>)receivePacketWithMaxSize:(int)_maxPacketSize
+  timeout:(NSTimeInterval)_timeout;
+- (id<NGDatagramPacket>)receivePacketWithTimeout:(NSTimeInterval)_timeout;
+
+- (id<NGDatagramPacket>)receivePacketWithMaxSize:(int)_maxPacketSize;
+- (id<NGDatagramPacket>)receivePacket;
+
+// ************************* options *************************
+//
+//   set methods throw NGCouldNotSetSocketOptionException
+//   get methods throw NGCouldNotGetSocketOptionException
+
+- (void)setBroadcast:(BOOL)_flag;
+- (BOOL)doesBroadcast;
+
+// aborts, only supported for TCP
+- (void)setDebug:(BOOL)_flag; 
+- (BOOL)doesDebug;
+
+@end
+
+#endif /* __NGNet_NGDatagramSocket_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGDescriptorFunctions.h b/skyrix-core/NGStreams/NGStreams/NGDescriptorFunctions.h
new file mode 100644 (file)
index 0000000..b120b3c
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGDescriptorFunctions_H__
+#define __NGStreams_NGDescriptorFunctions_H__
+
+#import <Foundation/NSObject.h>
+
+#if !defined(WIN32)
+
+/*
+  Polls a descriptor. Returns 1 if events occurred, 0 if a timeout occured
+  and -1 if an error other than EINTR or EAGAIN occured.
+*/
+extern int NGPollDescriptor(int _fd, short _events, int _timeout);
+
+/*
+  Set/Get descriptor flags
+*/
+extern int  NGGetDescriptorFlags(int _fd);
+extern void NGSetDescriptorFlags(int _fd, int _flags);
+extern void NGAddDescriptorFlag (int _fd, int _flag);
+
+/*
+  Reading and writing with non-blocking IO support.
+  The functions return
+    -1  on error, with errno set to either recv's or poll's errno
+    0   on the end of file condition
+    -2  if the operation timed out
+
+  Enable login topic 'nonblock' to find out about timeouts.
+*/
+extern int NGDescriptorRecv(int _fd, char *_buf, int _len,
+                            int _flags, int _timeout);
+extern int NGDescriptorSend(int _fd, const char *_buf, int _len,
+                            int _flags, int _timeout);
+
+/*
+  Check whether the descriptor is associated to a terminal device.
+  Get the name of the associated terminal device.
+*/
+extern BOOL     NGDescriptorIsAtty(int _fd);
+extern NSString *NGDescriptorGetTtyName(int _fd);
+
+#endif /* !WIN32 */
+
+#endif /* __NGStreams_NGDescriptorFunctions_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGFileStream.h b/skyrix-core/NGStreams/NGStreams/NGFileStream.h
new file mode 100644 (file)
index 0000000..353c35e
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGFileStream_H__
+#define __NGStreams_NGFileStream_H__
+
+/*
+  NGFileStream
+  
+  NGFileStream is a stream which allows reading/writing local files.
+*/
+
+#if defined(__MINGW32__) && defined(HAVE_WINDOWS_H)
+#  include <windows.h>
+#endif
+#ifdef HAVE_POLL_H
+#  include <poll.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+#  include <sys/poll.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#if defined(__MINGW32__)
+#  include <winsock.h>
+#endif
+
+#include <NGStreams/NGStreamsDecls.h>
+#include <NGStreams/NGStream.h>
+#include <NGStreams/NGStreamProtocols.h>
+
+@class NSFileHandle;
+
+NGStreams_EXPORT NSString *NGFileReadOnly;
+NGStreams_EXPORT NSString *NGFileWriteOnly;
+NGStreams_EXPORT NSString *NGFileReadWrite;
+NGStreams_EXPORT NSString *NGFileAppend;
+NGStreams_EXPORT NSString *NGFileReadAppend;
+
+NGStreams_EXPORT id<NGInputStream>  NGIn;
+NGStreams_EXPORT id<NGOutputStream> NGOut;
+NGStreams_EXPORT id<NGOutputStream> NGErr;
+NGStreams_EXPORT void NGInitStdio(void);
+
+@interface NGFileStream : NGStream < NGPositionableStream >
+{
+@private
+#if defined(__MINGW32__)
+  HANDLE fh; // Windows file handle
+#else
+  int    fd; // Unix file descriptor
+#endif
+  
+  NGStreamMode streamMode;
+  NSString     *systemPath;
+  NSFileHandle *handle;     // not retained !
+  
+  int markDelta; // tracks mark, for marking (special value -1)
+}
+
+- (id)initWithPath:(NSString *)_path;
+- (id)initWithFileHandle:(NSFileHandle *)_handle; // use with care !
+
+// throws
+//   NGUnknownStreamModeException  when _mode is invalid
+//   NGCouldNotOpenStreamException when the file could not be opened
+- (BOOL)openInMode:(NSString *)_mode;
+
+- (BOOL)isOpen;
+
+// Foundation file handles
+
+- (NSFileHandle *)fileHandle;
+- (int)fileDescriptor;
+
+#if defined(__MINGW32__)
+- (HANDLE)windowsFileHandle;
+#endif
+
+// primitives
+
+// throws
+//   NGWriteOnlyStreamException when the stream is not readable
+//   NGStreamNotOpenException   when the stream is not open
+//   NGEndOfStreamException     when the end of the stream is reached
+//   NGReadErrorException       when the read call failed
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;
+
+// throws
+//   NGReadOnlyStreamException when the stream is not writeable
+//   NGStreamNotOpenException  when the stream is not open
+//   NGWriteErrorException     when the write call failed
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len;
+
+// throws NGCouldNotCloseStreamException when the close call failed
+- (BOOL)close;
+
+- (NGStreamMode)mode;
+- (BOOL)isRootStream;
+
+// blocking
+
+- (BOOL)wouldBlockInMode:(NGStreamMode)_mode; // not supported with Windows
+
+// marking
+
+- (BOOL)mark;
+- (BOOL)rewind;
+- (BOOL)markSupported; // returns YES
+
+// NGPositionableStream
+
+// throws
+//   NGStreamSeekErrorException
+- (BOOL)moveToLocation:(unsigned)_location; // note that absolute moves delete marks
+
+// throws
+//   NGStreamSeekErrorException
+- (BOOL)moveByOffset:(int)_delta;
+
+@end
+
+#endif /* __NGStreams_NGFileStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGFilterStream.h b/skyrix-core/NGStreams/NGStreams/NGFilterStream.h
new file mode 100644 (file)
index 0000000..ef92ced
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGFilterStream_H__
+#define __NGStreams_NGFilterStream_H__
+
+#include <NGStreams/NGStream.h>
+
+@interface NGFilterStream : NGStream
+{
+@protected
+  id                  source;
+  NGIOReadMethodType  readBytes;
+  NGIOWriteMethodType writeBytes;
+}
+
++ (id)filterWithInputSource:(id<NGInputStream>)_source;
++ (id)filterWithOutputSource:(id<NGOutputStream>)_source;
++ (id)filterWithSource:(id<NGStream>)_source;
+- (id)initWithInputSource:(id<NGInputStream>)_source;
+- (id)initWithOutputSource:(id<NGOutputStream>)_source;
+- (id)initWithSource:(id<NGStream>)_source;
+
+/* accessors */
+
+- (id<NGInputStream>)inputStream;
+- (id<NGOutputStream>)outputStream;
+- (id<NGStream>)source;
+
+/* primitives */
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len;
+- (BOOL)flush;
+- (BOOL)close;
+
+- (NGStreamMode)mode;
+- (BOOL)isRootStream;
+
+@end
+
+#endif /* __NGStreams_NGFilterStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGFilterTextStream.h b/skyrix-core/NGStreams/NGStreams/NGFilterTextStream.h
new file mode 100644 (file)
index 0000000..a1205cd
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGFilterTextStream_H__
+#define __NGStreams_NGFilterTextStream_H__
+
+#include <NGStreams/NGTextStream.h>
+
+@interface NGFilterTextStream : NGTextStream
+{
+  id<NGTextStream> source;
+}
+
++ (id)textFilterWithSource:(id<NGTextStream>)_source;
+- (id)initWithSource:(id<NGTextStream>)_source;
+
+// accessors
+
+- (id<NGTextStream>)source;
+
+@end
+
+#endif /* __NGStreams_NGFilterTextStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGGZipStream.h b/skyrix-core/NGStreams/NGStreams/NGGZipStream.h
new file mode 100644 (file)
index 0000000..4a4dad1
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGZlib_NGGZipStream_H__
+#define __NGZlib_NGGZipStream_H__
+
+#include <NGStreams/NGFilterStream.h>
+
+@interface NGGZipStream : NGFilterStream
+{
+@private
+  void          *outp;
+  void          *outBuf;
+  unsigned      outBufLen;
+  unsigned long crc;
+  BOOL          headerIsWritten;
+}
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;        // decoder
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len; // encoder
+
+- (void)close;
+- (void)flush;
+
+@end
+
+#endif /* __NGZlib_NGGZipStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGInternetSocketAddress.h b/skyrix-core/NGStreams/NGStreams/NGInternetSocketAddress.h
new file mode 100644 (file)
index 0000000..730476f
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGInternetSocketAddress_H__
+#define __NGNet_NGInternetSocketAddress_H__
+
+#include <NGStreams/NGSocketProtocols.h>
+#include <NGStreams/NGActiveSocket.h>
+
+/*
+  Represents an Internet socket address (AF_INET).
+  
+  Socket addresses are immutable. -copy therefore returns a retained self.
+
+  The host arguments are id because they are allowed to be either NSString
+  or NSHost objects (although NSString's are preferred). If the host is nil,
+  then a wildcard (INADDR_ANY) is used.
+
+  Note that the hostName is resolved when the internalAddressRepresentation
+  is requested.
+ */
+
+@interface NGInternetSocketAddress : NSObject < NSCopying, NSCoding, NGSocketAddress >
+{
+@private
+  void     *address; /* ptr to struct sockaddr_in */
+  NSString *hostName;
+  BOOL     isAddressFilled;
+  BOOL     isHostFilled;
+  BOOL     isWildcardHost;
+}
+
++ (id)addressWithPort:(int)_port onHost:(id)_host;
++ (id)addressWithPort:(int)_port; // localhost
+- (id)initWithPort:(int)_port onHost:(id)_host; // designated init
+- (id)initWithPort:(int)_port;    // localhost
+
+// these throw NGDidNotFindServiceException if the service is not found
++ (id)addressWithService:(NSString *)_serviceName
+  onHost:(id)_host protocol:(NSString *)_protocol;
++ (id)addressWithService:(NSString *)_serviceName protocol:(NSString *)_proto;
+- (id)initWithService:(NSString *)_serviceName onHost:(id)_host
+  protocol:(NSString *)_protocol;
+- (id)initWithService:(NSString *)_serviceName protocol:(NSString *)_protocol;
+
++ (id)wildcardAddress;
++ (id)wildcardAddressWithPort:(int)_port;
+
+/* accessors */
+
+- (NSString *)hostName;
+- (NSString *)address;
+- (int)port;
+
+- (BOOL)isWildcardAddress;
+
+/* testing for equality */
+
+- (BOOL)isEqualToAddress:(NGInternetSocketAddress *)_addr;
+- (BOOL)isEqual:(id)_obj;
+
+/* description */
+
+- (NSString *)stringValue; // returns 'hostname:port' as used in URLs
+- (NSString *)description;
+
+/* NGSocketAddress */
+
+// throws NGCouldNotResolveHostNameException
+- (void *)internalAddressRepresentation;
+
+- (int)addressRepresentationSize;
+- (id)domain;
+
+@end
+
+@interface NGActiveSocket(NGInternetActiveSocket)
+
+// this method calls +socketConnectedToAddress: with an NGInternetSocketAddress
++ (id)socketConnectedToPort:(int)_port onHost:(id)_host;
+
+// this method calls -connectToAddress: with an NGInternetSocketAddress
+- (BOOL)connectToPort:(int)_port onHost:(id)_host;
+
+@end
+
+#endif /* __NGNet_NGInternetSocketAddress_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGInternetSocketDomain.h b/skyrix-core/NGStreams/NGStreams/NGInternetSocketDomain.h
new file mode 100644 (file)
index 0000000..7cc60a8
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGInternetSocketDomain_H__
+#define __NGNet_NGInternetSocketDomain_H__
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGSocketProtocols.h>
+
+/*
+  Represents the AF_INET socket domain.
+
+  NGInternetSocketDomain is a singleton, therefore on copy it returns itself
+  and on unarchiving it replaces the unarchived instance with the singleton.
+*/
+
+@interface NGInternetSocketDomain : NSObject < NSCoding, NSCopying, NGSocketDomain >
+
++ (id)domain;
+
+// NGSocketDomain
+
+- (id<NGSocketAddress>)addressWithRepresentation:(void *)_data
+  size:(unsigned int)_size;
+
+- (int)socketDomain;
+- (int)protocol;
+
+@end
+
+#define NGDefaultInternetSocketDomain [NGInternetSocketDomain domain]
+
+#endif /* __NGNet_NGInternetSocketDomain_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGLocalSocketAddress.h b/skyrix-core/NGStreams/NGStreams/NGLocalSocketAddress.h
new file mode 100644 (file)
index 0000000..4ed5528
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGLocalSocketAddress_H__
+#define __NGNet_NGLocalSocketAddress_H__
+
+#if !defined(WIN32) || defined(__CYGWIN32__)
+
+/*
+  UNIX domain sockets, currently not available on Windows
+
+  The Win32 local sockets are done using so called 'named pipes'.
+*/
+
+#include <NGStreams/NGSocketProtocols.h>
+
+/*
+  Represents a UNIX domain socket address (AF_LOCAL) or a named pipe (Win32).
+
+  Socket addresses are immutable. -copy therefore returns a retained self.
+
+  Note that when a local socket address is archived it stores the host together
+  with the path. This ensures that the address-space will be the same on
+  unarchiving, otherwise it will return an error.
+*/
+
+@interface NGLocalSocketAddress : NSObject < NSCopying, NGSocketAddress >
+{
+@private
+#if defined(__WIN32__) && !defined(__CYGWIN32__)
+  NSString *path;
+#else
+  void *address; /* ptr to struct sockaddr_un */
+#endif
+}
+
++ (id)addressWithPath:(NSString *)_path;
++ (id)address;
+- (id)initWithPath:(NSString *)_path; // designated initializer
+- (id)init;                           // creates unique path (pid,thread-id,cnt)
+
+/* accessors */
+
+- (NSString *)path;
+
+/* testing for equality */
+
+- (BOOL)isEqualToAddress:(NGLocalSocketAddress *)_addr;
+- (BOOL)isEqual:(id)_obj;
+
+/* test for accessibility */
+
+- (BOOL)canSendOnAddress;
+- (BOOL)canReceiveOnAddress;
+
+@end
+
+#endif /* !WIN32 */
+
+#endif /* __NGNet_NGLocalSocketAddress_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGLocalSocketDomain.h b/skyrix-core/NGStreams/NGStreams/NGLocalSocketDomain.h
new file mode 100644 (file)
index 0000000..7d5d777
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGLocalSocketDomain_H__
+#define __NGNet_NGLocalSocketDomain_H__
+
+#if !defined(WIN32)
+// UNIX domain, not available on WIN32
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGSocketProtocols.h>
+
+/*
+  Represents the AF_LOCAL (AF_UNIX) socket domain.
+
+  NGLocalSocketDomain is a singleton, therefore on copy it returns itself and on
+  unarchiving it replaces the unarchived instance with the singleton.
+*/
+
+@interface NGLocalSocketDomain : NSObject < NSCopying, NSCoding, NGSocketDomain >
+
++ (id)domain;
+
+// NGSocketDomain
+
+- (id<NGSocketAddress>)addressWithRepresentation:(void *)_data
+  size:(unsigned int)_size;
+
+- (int)socketDomain;
+- (int)protocol;
+
+@end
+
+#define NGDefaultLocalSocketDomain [NGLocalSocketDomain domain]
+
+#endif /* !WIN32 */
+
+#endif /* __NGNet_NGLocalSocketDomain_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGLockingStream.h b/skyrix-core/NGStreams/NGStreams/NGLockingStream.h
new file mode 100644 (file)
index 0000000..0363c61
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGLockingStream_H__
+#define __NGStreams_NGLockingStream_H__
+
+#import <Foundation/NSLock.h>
+#include <NGStreams/NGFilterStream.h>
+
+@interface NGLockingStream : NGFilterStream
+{
+@private
+  id<NSObject,NSLocking> readLock;
+  id<NSObject,NSLocking> writeLock;
+
+  void (*_lockMethod)(id, SEL);
+  void (*_unlockMethod)(id, SEL);
+}
+
++ (id)filterWithSource:(id<NGStream>)_source lock:(id<NSObject,NSLocking>)_lock;
+- (id)initWithSource:(id<NGStream>)_source   lock:(id<NSObject,NSLocking>)_lock;
+
+// primitives
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len;
+- (BOOL)flush;
+
+@end
+
+#endif /* __NGStreams_NGLockingStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGNet.h b/skyrix-core/NGStreams/NGStreams/NGNet.h
new file mode 100644 (file)
index 0000000..7910c44
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_H__
+#define __NGNet_H__
+
+#include <NGStreams/NGActiveSocket.h>
+#include <NGStreams/NGInternetSocketAddress.h>
+#include <NGStreams/NGInternetSocketDomain.h>
+#include <NGStreams/NGPassiveSocket.h>
+#include <NGStreams/NGSocket.h>
+#include <NGStreams/NGSocketExceptions.h>
+#include <NGStreams/NGSocketProtocols.h>
+#include <NGStreams/NGDatagramPacket.h>
+#include <NGStreams/NGDatagramSocket.h>
+#include <NGStreams/NGNetUtilities.h>
+
+#if !defined(WIN32)
+#  include <NGStreams/NGLocalSocketAddress.h>
+#  include <NGStreams/NGLocalSocketDomain.h>
+#endif
+
+// kit class
+
+@interface NGNet : NSObject
+@end
+
+#define LINK_NGNet void __link_NGNet() { [NGNet class]; }
+
+#endif /* __NGNet_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGNetDecls.h b/skyrix-core/NGStreams/NGStreams/NGNetDecls.h
new file mode 100644 (file)
index 0000000..08779c4
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGNetDecls_H__
+#define __NGNet_NGNetDecls_H__
+
+#if BUILD_libNGStreams_DLL
+#  define NGNet_EXPORT  __declspec(dllexport)
+#  define NGNet_DECLARE __declspec(dllexport)
+#elif libNGStreams_ISDLL
+#  define NGNet_EXPORT  extern __declspec(dllimport)
+#  define NGNet_DECLARE extern __declspec(dllimport)
+#else
+#  define NGNet_EXPORT  extern
+#  define NGNet_DECLARE 
+#endif
+
+#endif /* __NGNet_NGNetDecls_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGNetUtilities.h b/skyrix-core/NGStreams/NGStreams/NGNetUtilities.h
new file mode 100644 (file)
index 0000000..d282f83
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGNetUtilities_H__
+#define __NGNet_NGNetUtilities_H__
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGSocketProtocols.h>
+
+/*
+  Some supporting functions
+*/
+
+/*
+  This function tried to 'guess' the appropriate socket address from _string.
+  It currently creates an internet domain address if a ':' is encountered and
+  a local domain address if the string returns true on -isAbsolutePath.
+  The function returns nil if the string argument is nil or empty.
+
+  Examples are:
+
+    INET:   "*:20000"           // wildcard IP, port 20000
+            "localhost:1000"    // localhost, port 1000
+            "*:echo/udp"        // wildcard IP, echo service on UDP
+            "*:echo"            // wildcard IP, echo service on TCP (TCP=default)
+            
+    LOCAL:  "/tmp/mySocket"
+*/
+id<NGSocketAddress> NGSocketAddressFromString(NSString *_string);
+
+#endif /* __NGNet_NGNetUtilities_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGPassiveSocket.h b/skyrix-core/NGStreams/NGStreams/NGPassiveSocket.h
new file mode 100644 (file)
index 0000000..36b3753
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGPassiveSocket_H__
+#define __NGNet_NGPassiveSocket_H__
+
+#import <Foundation/NSLock.h>
+#include <NGStreams/NGSocket.h>
+#include <NGStreams/NGSocketProtocols.h>
+
+/*
+  Represents a STREAM server socket based on the standard Unix sockets library.
+
+  A passive socket has exactly one address, the address the socket is bound to.
+  If you do not bind the socket, the address is determined after the listen()
+  call was executed through the getsockname() call.
+
+  Note that if the socket is bound it's still an active socket in the
+  system's view, it becomes an passive one when the listen call is executed.
+
+  NOTE: Currently the passive _must_ be bound. This is because during the
+        creation of the socket the domain is needed. The domain is encapsulated
+        in the socket-address.
+        Therefore the method of letting the kernel determine a socket address,
+        as described above, currently does not work.
+*/
+
+@interface NGPassiveSocket : NGSocket < NGPassiveSocket >
+{
+@protected
+  id<NSObject,NSLocking> acceptLock; // prevents file-locking
+  int backlogSize;
+}
+
++ (id)socketBoundToAddress:(id<NGSocketAddress>)_address;
+
+/* accessors */
+
+- (BOOL)isListening;
+- (BOOL)isOpen;
+
+/* operations */
+
+// throws
+//   NGSocketIsAlreadyListeningException  when the socket is in the listen state
+//   NGCouldNotListenException            when the listen call failed
+- (BOOL)listenWithBacklog:(int)_backlogSize;
+
+// accept blocks when multiple threads try to accept (using acceptLock)
+// throws
+//   NGCouldNotAcceptException  when the socket is not listening
+//   NGCouldNotAcceptException  when the accept call failed
+- (id<NGActiveSocket>)accept;
+
+@end
+
+#endif /* __NGNet_NGPassiveSocket_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGSocket.h b/skyrix-core/NGStreams/NGStreams/NGSocket.h
new file mode 100644 (file)
index 0000000..6024e50
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGSocket_H__
+#define __NGNet_NGSocket_H__
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGSocketProtocols.h>
+
+#if defined(WIN32)
+#  include <winsock.h>
+#endif
+
+@class NSFileHandle, NSException;
+
+/*
+  Represents the sockets accessible through the standard Unix sockets library.
+  The socket class itself is abstract and has two concrete subclasses,
+  NGActiveSocket and NGPassiveSocket. The terminology may be confusing
+  at first, but I choose to use these instead of Client/ServerSocket
+  because the NGPassiveSocket accept method returns a socket which isn't
+  one of these. It's an active socket which is already connected.
+  NGActiveSocket represents a connection while NGPassiveSocket only accepts
+  connections (it can't be read or written).
+
+  Each socket has a local address. The socket can be bound to an address
+  by using the bind() call or the address can be assigned by the operating
+  system kernel.
+  Passive sockets are normally bound to a well-known port (or service),
+  active sockets receive in most cases their address from the kernel.
+
+  fd is the file descriptor gained through the socket() call. closeOnFree
+  specifies whether the socket is closed when the memory for the
+  socket object is reclaimed.
+
+  Note that the creation of the actual socket has to wait until it is
+  bound or a connect or listen call has been initiated. This is because
+  the socket() call needs the socket-domain, which is encapsulated in the
+  NGSocketAddress objects.
+  Until the socket is created the fd variable contains the value
+  NGInvalidSocketDescriptor.
+*/
+
+#if defined(WIN32)
+#  define NGInvalidSocketDescriptor INVALID_SOCKET
+#else
+#  define NGInvalidSocketDescriptor ((int)-1)
+#endif
+
+@interface NGSocket : NSObject < NGSocket >
+{
+@protected
+#if defined(WIN32)
+  SOCKET              fd;
+#else
+  int                 fd;           // socket descriptor
+#endif
+  id<NGSocketDomain>  domain;
+  id<NGSocketAddress> localAddress;
+  NSFileHandle        *fileHandle;  // not retained !
+
+  struct {
+    int closeOnFree:1; // close socket on collect/dealloc ?
+    int isBound:1;     // was a bind issued (either by the kernel or explicitly)
+  } flags;
+  
+  NSException *lastException;
+}
+
++ (id)socketInDomain:(id<NGSocketDomain>)_domain;
+- (id)initWithDomain:(id<NGSocketDomain>)_domain; // designated initializer
+
+// ************************* create a socket *****************
+
+- (BOOL)primaryCreateSocket;
+- (BOOL)close;
+
+// ************************* bind a socket *******************
+
+// throws
+//   NGSocketAlreadyBoundException    if the socket is already bound
+- (BOOL)bindToAddress:(id<NGSocketAddress>)_address;
+
+// throws
+//   NGSocketAlreadyBoundException    if the socket is already bound
+- (BOOL)kernelBoundAddress;
+
+// ************************* accessors ***********************
+
+- (id<NGSocketAddress>)localAddress;
+- (BOOL)isBound;
+
+- (void)setLastException:(NSException *)_exception;
+- (NSException *)lastException;
+- (void)resetLastException;
+
+- (int)socketType;       // abstract
+- (id<NGSocketDomain>)domain;
+
+- (NSFileHandle *)fileHandle;
+#if defined(WIN32)
+- (SOCKET)fileDescriptor;
+#else
+- (int)fileDescriptor;
+#endif
+
+// ************************* options *************************
+//
+//   set methods throw NGCouldNotSetSocketOptionException
+//   get methods throw NGCouldNotGetSocketOptionException
+
+- (void)setDebug:(BOOL)_flag;
+- (void)setReuseAddress:(BOOL)_flag;
+- (void)setKeepAlive:(BOOL)_flag;
+- (void)setDontRoute:(BOOL)_flag;
+- (BOOL)doesDebug;
+- (BOOL)doesReuseAddress;
+- (BOOL)doesKeepAlive;
+- (BOOL)doesNotRoute;
+
+- (void)setSendBufferSize:(int)_size;
+- (void)setReceiveBufferSize:(int)_size;
+- (int)sendBufferSize;
+- (int)receiveBufferSize;
+
+@end
+
+#if defined(WIN32)
+
+// Windows Descriptor Functions
+
+// events
+#  ifndef POLLIN
+#    define POLLRDNORM 1
+#    define POLLIN     POLLRDNORM
+#    define POLLWRNORM 2
+#    define POLLOUT    POLLWRNORM
+#    define POLLERR    4
+#    define POLLHUP    4
+#  endif
+
+/*
+  Polls a descriptor. Returns 1 if events occurred, 0 if a timeout occured
+  and -1 if an error other than EINTR or EAGAIN occured.
+*/
+int NGPollDescriptor(SOCKET _fd, short _events, int _timeout);
+
+/*
+  Reading and writing with non-blocking IO support.
+  The functions return
+    -1  on error, with errno set to either recv's or poll's errno
+    0   on the end of file condition
+    -2  if the operation timed out
+
+  Enable login topic 'nonblock' to find out about timeouts.
+*/
+int NGDescriptorRecv(SOCKET _fd, char *_buf, int _len, int _flags, int _timeout);
+int NGDescriptorSend(SOCKET _fd, const char *_buf, int _len, int _flags, int _timeout);
+
+#endif /* WIN32 */
+
+#endif /* __NGNet_NGSocket_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGSocketExceptions.h b/skyrix-core/NGStreams/NGStreams/NGSocketExceptions.h
new file mode 100644 (file)
index 0000000..d045e30
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGSocketExceptions_H__
+#define __NGNet_NGSocketExceptions_H__
+
+#import <Foundation/NSException.h>
+#include <NGStreams/NGStreamExceptions.h>
+#include <NGStreams/NGSocketProtocols.h>
+
+/*
+  Exceptions:
+
+    NGIOException
+      NGSocketException
+        NGSocketBindException
+          NGSocketAlreadyBoundException
+          NGCouldNotBindSocketException
+        NGSocketConnectionException
+          NGSocketNotConnectedException
+          NGSocketAlreadyConnectedException
+          NGCouldNotConnectException
+        NGSocketOptionException
+          NGCouldNotSetSocketOptionException
+          NGCouldNotGetSocketOptionException
+        NGCouldNotResolveHostNameException
+        NGDidNotFindServiceException
+        NGSocketIsAlreadyListeningException
+        NGCouldNotListenException
+        NGCouldNotAcceptException
+        NGInvalidSocketDomainException
+        NGCouldNotCreateSocketException
+      NGStreamException
+        NGEndOfStreamException
+          NGSocketShutdownException
+            NGSocketShutdownDuringReadException
+            NGSocketShutdownDuringWriteException
+            NGSocketConnectionResetException
+            NGSocketTimedOutException
+*/
+
+@interface NGSocketException : NGIOException
+{
+@protected
+  id<NGSocket> socket;
+}
+
+- (id)init;
+- (id)initWithReason:(NSString *)_reason;
+- (id)initWithReason:(NSString *)_reason socket:(id<NGSocket>)_socket;
+
+- (id<NGSocket>)socket;
+
+@end
+
+@interface NGCouldNotResolveHostNameException : NGSocketException
+{
+@protected
+  NSString *hostName;
+}
+
+- (id)initWithHostName:(NSString *)_name reason:(NSString *)_reason;
+
+- (NSString *)hostName;
+
+@end
+
+@interface NGDidNotFindServiceException : NGSocketException
+{
+@protected
+  NSString *serviceName;
+}
+
+- (id)init;
+- (id)initWithServiceName:(NSString *)_service;
+
+- (NSString *)serviceName;
+
+@end
+
+@interface NGInvalidSocketDomainException : NGSocketException
+{
+@protected
+  id<NGSocketDomain> domain;
+}
+
+- (id)initWithReason:(NSString *)_reason
+  socket:(id<NGSocket>)_socket domain:(id<NGSocketDomain>)_domain;
+
+@end
+
+@interface NGCouldNotCreateSocketException : NGSocketException
+{
+@protected
+  id<NGSocketDomain> domain;
+}
+
+- (id)init;
+- (id)initWithReason:(NSString *)_reason domain:(id<NGSocketDomain>)_domain;
+
+@end
+
+// ******************** bind ***********************
+
+@interface NGSocketBindException : NGSocketException
+@end
+
+@interface NGSocketAlreadyBoundException : NGSocketBindException
+@end
+
+@interface NGCouldNotBindSocketException : NGSocketBindException
+{
+@protected
+  id<NGSocketAddress> address;
+}
+
+- (id)initWithReason:(NSString *)_reason
+  socket:(id<NGSocket>)_socket address:(id<NGSocketAddress>)address;
+
+- (id<NGSocketAddress>)address;
+
+@end
+
+// ******************** connect ********************
+
+@interface NGSocketConnectException : NGSocketException
+@end
+
+@interface NGSocketNotConnectedException : NGSocketConnectException
+@end
+
+@interface NGSocketAlreadyConnectedException : NGSocketConnectException
+@end
+
+@interface NGCouldNotConnectException : NGSocketConnectException
+{
+@protected
+  id<NGSocketAddress> address;
+}
+
+- (id)initWithReason:(NSString *)_reason
+  socket:(id<NGActiveSocket>)_socket
+  address:(id<NGSocketAddress>)address;
+
+- (id<NGSocketAddress>)address;
+
+@end
+
+// ******************** listen ********************
+
+@interface NGSocketIsAlreadyListeningException : NGSocketException
+@end
+
+@interface NGCouldNotListenException : NGSocketException
+@end
+
+// ******************** accept ********************
+
+@interface NGCouldNotAcceptException : NGSocketException
+@end
+
+// ******************** options ********************
+
+@interface NGSocketOptionException : NGSocketException
+{
+@protected
+  int option;
+  int level;
+}
+
+- (id)init;
+- (id)initWithReason:(NSString *)_reason option:(int)_option level:(int)_level;
+
+@end
+
+@interface NGCouldNotSetSocketOptionException : NGSocketOptionException
+@end
+
+@interface NGCouldNotGetSocketOptionException : NGSocketOptionException
+@end
+
+// ******************** socket closed **************
+
+@interface NGSocketShutdownException : NGEndOfStreamException
+
+- (id)initWithReason:(NSString *)_reason;
+- (id)initWithReason:(NSString *)_reason socket:(id<NGActiveSocket>)_socket;
+- (id)initWithSocket:(id<NGActiveSocket>)_socket;
+
+/* Note: this only returns a valid ptr, if the socket is still retained ! */
+- (id<NGActiveSocket>)socket;
+
+@end
+
+@interface NGSocketShutdownDuringReadException : NGSocketShutdownException
+@end
+
+@interface NGSocketShutdownDuringWriteException : NGSocketShutdownException
+@end
+
+@interface NGSocketTimedOutException : NGSocketShutdownException
+@end
+
+@interface NGSocketConnectionResetException : NGSocketShutdownException
+@end
+
+#endif /* __NGNet_NGSocketExceptions_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGSocketProtocols.h b/skyrix-core/NGStreams/NGStreams/NGSocketProtocols.h
new file mode 100644 (file)
index 0000000..e3f9796
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGNet_NGSocketProtocols_H__
+#define __NGNet_NGSocketProtocols_H__
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGStreamProtocols.h>
+
+@class NSException;
+
+// addresses
+
+@protocol NGSocketAddress < NSObject >
+
+- (void *)internalAddressRepresentation;
+- (int)addressRepresentationSize;
+- (id)domain; // (a NGSocketDomain)
+
+// needed by socket address factory:
+- (id)initWithDomain:(id)_domain
+  internalRepresentation:(void *)_representation
+  size:(int)_length;
+
+@end
+
+// sockets
+
+@protocol NGSocket < NSObject >
+
+- (id<NGSocketAddress>)localAddress;
+- (BOOL)bindToAddress:(id<NGSocketAddress>)_localAddress;
+- (BOOL)close;
+
+- (NSException *)lastException;
+
+@end
+
+// domains
+
+@protocol NGSocketDomain < NSObject >
+
+- (id<NGSocketAddress>)addressWithRepresentation:(void *)_data
+  size:(unsigned int)_size;
+
+- (int)socketDomain;
+- (int)addressRepresentationSize;
+- (int)protocol;
+
+// these two methods manage resources associated with addresses
+// (primarily the files used for AF_LOCAL sockets)
+- (BOOL)prepareAddress:(id<NGSocketAddress>)_address
+  forBindWithSocket:(id<NGSocket>)_socket;
+- (BOOL)cleanupAddress:(id<NGSocketAddress>)_address
+  afterCloseOfSocket:(id<NGSocket>)_socket;
+
+@end
+
+// concrete sockets
+
+@protocol NGActiveSocket < NGSocket, NGStream, NGByteSequenceStream >
+
+- (BOOL)connectToAddress:(id<NGSocketAddress>)_address;
+- (BOOL)shutdown;
+
+- (BOOL)isConnected;
+
+- (id<NGSocketAddress>)remoteAddress;
+
+@end
+
+@protocol NGPassiveSocket < NGSocket >
+
+- (BOOL)listenWithBacklog:(int)_backlogSize;
+- (id<NGActiveSocket>)accept;
+
+@end
+
+// packets
+
+@protocol NGDatagramPacket < NSObject >
+
+- (void)setSender:(id<NGSocketAddress>)_address;
+- (id<NGSocketAddress>)sender;
+- (void)setReceiver:(id<NGSocketAddress>)_address;
+- (id<NGSocketAddress>)receiver;
+
+- (NSData *)data;
+
+@end
+
+@protocol NGDatagramPacketFactory < NSObject >
+
+- (id<NGDatagramPacket>)packetWithData:(NSData *)_data;
+
+- (id<NGDatagramPacket>)
+  packetWithBytes:(const void *)_bytes
+  size:(int)_packetSize;
+
+@end
+
+#endif /* __NGNet_NGSocketProtocols_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGStream+serialization.h b/skyrix-core/NGStreams/NGStreams/NGStream+serialization.h
new file mode 100644 (file)
index 0000000..1bfb94e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGStream_serialization_H__
+#define __NGStreams_NGStream_serialization_H__
+
+#include <NGStreams/NGStreamsDecls.h>
+#include <NGStreams/NGStream.h>
+#include <NGStreams/NGStreamProtocols.h>
+
+#if !(MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED)
+#  define USE_SERIALIZER 1
+#  import <Foundation/NSSerialization.h>
+#endif
+
+/*
+  Serialization is implemented as a category because of it's importance. From
+  a design point of view it would be better placed in an extra class, so that
+  the serialization scheme could be replaced.
+*/
+
+@interface NGStream(serialization) < NGSerializer >
+
+- (void)serializeChar:(char)_value;
+- (void)serializeShort:(short)_value;
+- (void)serializeInt:(int)_value;
+- (void)serializeLong:(long)_value;
+- (void)serializeFloat:(float)_value;
+- (void)serializeDouble:(double)_value;
+- (void)serializeLongLong:(long long)_value;
+
+- (char)deserializeChar;
+- (short)deserializeShort;
+- (int)deserializeInt;
+- (long)deserializeLong;
+- (float)deserializeFloat;
+- (double)deserializeDouble;
+- (long long)deserializeLongLong;
+
+- (void)serializeCString:(const char *)_value;
+- (char *)deserializeCString;
+
+#if USE_SERIALIZER
+- (void)serializeDataAt:(const void*)data ofObjCType:(const char*)type
+  context:(id<NSObjCTypeSerializationCallBack>)_callback;
+- (void)deserializeDataAt:(void *)data ofObjCType:(const char*)type
+  context:(id<NSObjCTypeSerializationCallBack>)_callback;
+#endif
+
+@end
+
+NGStreams_EXPORT void
+NGStreamSerializeObjC(id<NGStream> self,
+                      const void *_data, const char *_type,
+#if USE_SERIALIZER
+                      id<NSObjCTypeSerializationCallBack> _callback
+#else
+                      id _callback
+#endif
+                      );
+
+NGStreams_EXPORT void
+NGStreamDeserializeObjC(id<NGStream> self,
+                       void *_data, const char *_type,
+#if USE_SERIALIZER
+                       id<NSObjCTypeSerializationCallBack> _callback
+#else
+                        id _callback
+#endif
+                        );
+
+#endif /* __NGStreams_NGStream_serialization_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGStream.h b/skyrix-core/NGStreams/NGStreams/NGStream.h
new file mode 100644 (file)
index 0000000..b4afec5
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGStream_H__
+#define __NGStreams_NGStream_H__
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGStreamsDecls.h>
+#include <NGStreams/NGStreamProtocols.h>
+
+@class NSData, NSException;
+
+static inline BOOL NGCanReadInStreamMode(NGStreamMode _mode) {
+  return ((_mode == NGStreamMode_readOnly) ||
+          (_mode == NGStreamMode_readWrite));
+}
+static inline BOOL NGCanWriteInStreamMode(NGStreamMode _mode) {
+  return ((_mode == NGStreamMode_writeOnly) ||
+          (_mode == NGStreamMode_readWrite));
+}
+
+@interface NGStream : NSObject < NGStream, NGByteSequenceStream >
+
+// ******************** primitives ********************
+
+// Never returns 0. If an EOF like condition occures, NGEndOfStreamException
+// is thrown.
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;       // abstract
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len; // abstract
+
+- (void)setLastException:(NSException *)_exception;
+
+- (BOOL)flush; // empty
+- (BOOL)close; // empty
+
+- (NGStreamMode)mode; // abstract
+- (BOOL)isRootStream; // abstract
+
+/* methods which read/write exactly _len bytes */
+
+- (BOOL)safeReadBytes:(void *)_buf count:(unsigned)_len;
+- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len;
+
+/* marking */
+
+- (BOOL)mark;           // does nothing
+- (BOOL)rewind;         // does nothing
+- (BOOL)markSupported;  // returns NO
+
+/* convenience methods */
+
+- (int)readByte; // java semantics (-1 returned on EOF)
+
+// description
+
+- (NSString *)modeDescription;
+
+@end
+
+@interface NGStream(DataMethods)
+
+- (NSData *)readDataOfLength:(unsigned int)_length;
+- (NSData *)safeReadDataOfLength:(unsigned int)_length;
+- (unsigned int)writeData:(NSData *)_data;
+- (BOOL)safeWriteData:(NSData *)_data;
+
+@end
+
+// concrete implementations as functions (to be used in non-subclasses)
+
+NGStreams_EXPORT int NGReadByteFromStream(id<NGInputStream> _stream);
+
+NGStreams_EXPORT BOOL
+NGSafeReadBytesFromStream(id<NGInputStream> _in, void *_buf, unsigned _len);
+
+NGStreams_EXPORT BOOL
+NGSafeWriteBytesToStream(id<NGOutputStream> _out,const void *_buf,unsigned _len);
+
+#endif /* __NGStreams_NGStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGStreamCoder.h b/skyrix-core/NGStreams/NGStreams/NGStreamCoder.h
new file mode 100644 (file)
index 0000000..875ad3f
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGStreamCoder_H__
+#define __NGStreams_NGStreamCoder_H__
+
+#import <Foundation/NSCoder.h>
+
+#if !(MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED)
+#  define USE_SERIALIZER 1
+#  import <Foundation/NSSerialization.h>
+#endif
+
+#import <Foundation/NSMapTable.h>
+#import <Foundation/NSHashTable.h>
+#include <NGStreams/NGStreamProtocols.h>
+
+@interface NGStreamCoder : NSCoder 
+#if USE_SERIALIZER
+  < NSObjCTypeSerializationCallBack >
+#endif
+{
+@protected
+  id<NGSerializer,NGStream> stream;   // destination/source stream
+  NGIOSafeReadMethodType    readIMP;  // safe read method
+  NGIOSafeWriteMethodType   writeIMP; // safe write method
+
+  // used during encoding
+  NSHashTable *outObjects;          // objects written so far
+  NSHashTable *outConditionals;     // conditional objects
+  NSHashTable *outPointers;         // set of pointers
+  NSMapTable  *replacements;        // src-object to replacement
+  BOOL        traceMode;            // YES if finding conditionals
+  BOOL        didWriteHeader;
+  SEL         classForCoder;        // default: classForCoder:
+  SEL         replObjectForCoder;   // default: replacementObjectForCoder:
+  BOOL        encodingRoot;
+
+  // used during decoding
+  unsigned    inArchiverVersion;    // archiver's version that wrote the data
+  NSMapTable  *inObjects;           // decoded objects: key -> object
+  NSMapTable  *inClasses;           // decoded classes: key -> class info
+  NSMapTable  *inPointers;          // decoded pointers: key -> pointer
+  NSMapTable  *inClassAlias;        // archive name -> decoded name
+  NSMapTable  *inClassVersions;     // archive name -> class info
+  NSZone      *objectZone;
+  BOOL        decodingRoot;
+  BOOL        didReadHeader;
+}
+
++ (id)coderWithStream:(id<NGSerializer,NGStream>)_stream;
+- (id)initWithStream:(id<NGSerializer,NGStream>)_stream;
+
+// accessors
+
+- (id<NGStream>)stream;
+- (NSString *)coderSignature; // ID of the coder used
+- (int)coderVersion;          // Version of the coder used
+
+// encoding
+
+- (void)encodeConditionalObject:(id)_object;
+- (void)encodeRootObject:(id)_object;
+
+// decoding
+
+- (unsigned int)systemVersion;
+- (id)decodeObject;
+
+// Substituting One Class for Another
+
++ (NSString *)classNameDecodedForArchiveClassName:(NSString *)nameInArchive;
++ (void)decodeClassName:(NSString *)nameInArch asClassName:(NSString *)trueName;
+- (NSString *)classNameDecodedForArchiveClassName:(NSString *)nameInArchive;
+- (void)decodeClassName:(NSString *)nameInArch asClassName:(NSString *)trueName;
+
+@end
+
+#endif /* __NGStreams_NGStreamCoder_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGStreamExceptions.h b/skyrix-core/NGStreams/NGStreams/NGStreamExceptions.h
new file mode 100644 (file)
index 0000000..6719b4f
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGStreamExceptions_H__
+#define __NGStreams_NGStreamExceptions_H__
+
+#import <Foundation/NSException.h>
+#include <NGStreams/NGStream.h>
+
+@class NSData;
+
+@interface NGIOException : NSException
+
+- (id)init;
+- (id)initWithReason:(NSString *)_reason;
++ (void)raiseWithReason:(NSString *)_reason;
++ (void)raiseOnStream:(id)_stream reason:(NSString *)_reason;
++ (void)raiseOnStream:(id)_stream;
+
+@end
+
+static inline BOOL NGIsIOException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGIOException class]];
+}
+
+// ******************** NGStreamException *************************
+
+@class NSValue;
+
+@interface NGStreamException : NGIOException
+{
+@protected
+  NSValue *streamPointer; /* only valid if stream is not deallocated */
+}
+
+- (id)init;
+- (id)initWithStream:(id<NGStream>)_stream;
+- (id)initWithStream:(id<NGStream>)_stream reason:(NSString *)_reason;
+- (id)initWithStream:(id<NGStream>)_stream format:(NSString *)_format,...;
++ (id)exceptionWithStream:(id<NGStream>)_stream;
++ (id)exceptionWithStream:(id<NGStream>)_stream reason:(NSString *)_reason;
++ (void)raiseWithStream:(id<NGStream>)_stream;
++ (void)raiseWithStream:(id<NGStream>)_stream format:(NSString *)_format,...;
++ (void)raiseWithStream:(id<NGStream>)_stream reason:(NSString *)_reason;
+
+@end
+
+static inline BOOL NGIsStreamException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGStreamException class]];
+}
+
+// ******************** NGEndOfStreamException ********************
+
+@interface NGEndOfStreamException : NGStreamException
+{
+@protected
+  unsigned readCount; // number of bytes that could be read in
+  unsigned safeCount; // number of bytes that were requested
+  NSData   *data;
+}
+
+- (id)initWithStream:(id<NGStream>)_stream;
+
+- (id)initWithStream:(id<NGStream>)_stream
+  readCount:(unsigned)_readCount
+  safeCount:(unsigned)_safeCount
+  data:(NSData *)_data;
+
+- (NSData *)readBytes; // the bytes read before EOF
+
+@end
+
+static inline BOOL NGIsEndOfStreamException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGEndOfStreamException class]];
+}
+
+// ******************** open state exceptions *********************
+
+@interface NGCouldNotOpenStreamException : NGStreamException
+@end
+
+@interface NGCouldNotCloseStreamException : NGStreamException
+@end
+
+@interface NGStreamNotOpenException : NGStreamException
+@end
+
+static inline BOOL NGIsCouldNotOpenStreamException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGCouldNotOpenStreamException class]];
+}
+static inline BOOL NGIsCouldNotCloseStreamException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGCouldNotCloseStreamException class]];
+}
+static inline BOOL NGIsStreamNotOpenException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGStreamNotOpenException class]];
+}
+
+// ******************** NGStreamErrors ****************************
+
+@interface NGStreamErrorException : NGStreamException
+{
+@protected
+  int osErrorCode;
+}
+
+- (id)initWithStream:(id<NGStream>)_stream errorCode:(int)_code;
++ (void)raiseWithStream:(id<NGStream>)_stream errorCode:(int)_code;
+
+- (int)operationSystemErrorCode;
+- (NSString *)operatingSystemError;
+
+@end
+
+static inline BOOL NGIsStreamErrorException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGStreamErrorException class]];
+}
+
+@interface NGStreamReadErrorException : NGStreamErrorException
+@end
+
+@interface NGStreamWriteErrorException : NGStreamErrorException
+@end
+
+@interface NGStreamSeekErrorException : NGStreamErrorException
+@end
+
+static inline BOOL NGIsStreamReadErrorException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGStreamReadErrorException class]];
+}
+static inline BOOL NGIsStreamWriteErrorException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGStreamWriteErrorException class]];
+}
+static inline BOOL NGIsStreamSeekErrorException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGStreamSeekErrorException class]];
+}
+
+// ******************** NGStreamModeExceptions ********************
+
+@interface NGStreamModeException : NGStreamException
+@end
+
+@interface NGUnknownStreamModeException : NGStreamModeException
+{
+@protected
+  NSString *streamMode;
+}
+
+- (id)initWithStream:(id<NGStream>)_stream mode:(NSString *)_streamMode;
+
+@end
+
+@interface NGReadOnlyStreamException : NGStreamModeException
+@end
+
+@interface NGWriteOnlyStreamException : NGStreamModeException
+@end
+
+static inline BOOL NGIsStreamModeException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGStreamModeException class]];
+}
+static inline BOOL NGIsUnknownStreamModeException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGUnknownStreamModeException class]];
+}
+static inline BOOL NGIsReadOnlyStreamException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGReadOnlyStreamException class]];
+}
+static inline BOOL NGIsWriteOnlyStreamException(NSException *_exception) {
+  return [_exception isKindOfClass:[NGWriteOnlyStreamException class]];
+}
+
+// ******************** NGIOAccessException ***********************
+
+@interface NGIOAccessException : NGIOException
+@end
+
+@interface NGIOSearchAccessException : NGIOAccessException
+@end
+
+#endif /* __NGStreams_NGStreamExceptions_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGStreamPipe.h b/skyrix-core/NGStreams/NGStreams/NGStreamPipe.h
new file mode 100644 (file)
index 0000000..bced5bf
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGStreamPipe_H__
+#define __NGStreams_NGStreamPipe_H__
+
+#import <Foundation/NSFileHandle.h>
+
+@interface NGStreamPipe : NSPipe < NGStream, NGByteSequenceStream >
+{
+@private
+  int          fildes[2];
+  NSFileHandle *fhIn;
+  NSFileHandle *fhOut;
+}
+
++ (id)pipe;
+- (id)init;
+
+- (NSFileHandle *)fileHandleForReading;
+- (NSFileHandle *)fileHandleForWriting;
+
+- (id<NGByteSequenceStream>)streamForReading;
+- (id<NGOutputStream>)streamForWriting;
+
+// NGInputStream
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;
+- (BOOL)safeReadBytes:(void *)_buf count:(unsigned)_len;
+
+- (BOOL)mark;
+- (BOOL)rewind;
+- (BOOL)markSupported;
+
+// NGOutputStream
+
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len;
+- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len;
+- (BOOL)flush;
+
+// NGStream
+
+- (BOOL)close;
+- (NGStreamMode)mode;
+
+// Extensions
+
+- (BOOL)isOpen;
+
+@end
+
+#endif /* __NGStreams_NGStreamPipe_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGStreamProtocols.h b/skyrix-core/NGStreams/NGStreams/NGStreamProtocols.h
new file mode 100644 (file)
index 0000000..4cbd8ff
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGStreamProtocols_H__
+#define __NGStreams_NGStreamProtocols_H__
+
+#import <Foundation/NSObject.h>
+
+#if !(MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED)
+#  define USE_SERIALIZER 1
+#  import <Foundation/NSSerialization.h>
+#endif
+
+@class NSException;
+
+typedef enum {
+  NGStreamMode_undefined = 0,
+  NGStreamMode_readOnly  = 1,
+  NGStreamMode_writeOnly = 2,
+  NGStreamMode_readWrite = 4
+} NGStreamMode;
+
+/* if this value is returned by -read, -lastException is set ... */
+enum {NGStreamError = 0x7fffffff};
+
+typedef unsigned (*NGIOReadMethodType )(id, SEL, void *, unsigned);
+typedef unsigned (*NGIOWriteMethodType)(id, SEL, const void *, unsigned);
+typedef BOOL (*NGIOSafeReadMethodType )(id, SEL, void *, unsigned);
+typedef BOOL (*NGIOSafeWriteMethodType)(id, SEL, const void *, unsigned);
+
+@protocol NGInputStream < NSObject >
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len;
+- (BOOL)safeReadBytes:(void *)_buf count:(unsigned)_len;
+- (BOOL)close;
+
+// marks
+
+- (BOOL)mark;
+- (BOOL)rewind;
+- (BOOL)markSupported;
+
+@end
+
+@protocol NGOutputStream < NSObject >
+
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len;
+- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len;
+
+- (BOOL)flush;
+- (BOOL)close;
+
+@end
+
+@protocol NGPositionableStream < NSObject >
+
+- (BOOL)moveToLocation:(unsigned)_location;
+- (BOOL)moveByOffset:(int)_delta;
+
+@end
+
+@protocol NGStream < NGInputStream, NGOutputStream >
+
+- (BOOL)close;
+- (NGStreamMode)mode;
+- (NSException *)lastException;
+
+@end
+
+@protocol NGByteSequenceStream < NGInputStream >
+
+- (int)readByte; // Java semantics (-1 on EOF)
+  
+@end
+
+typedef int (*NGSequenceReadByteMethod)(id<NGByteSequenceStream> self, SEL _cmd);
+
+// push streams
+
+@class NSData;
+
+@protocol NGPushStream < NSObject >
+
+- (void)pushChar:(char)_c;
+- (void)pushCString:(const char *)_cstr;
+- (void)pushData:(NSData *)_block;
+- (void)pushBytes:(const void *)_buffer count:(unsigned)_len;
+- (void)abort;
+
+@end
+
+// serializer
+
+@protocol NGSerializer < NSObject >
+
+- (void)serializeChar:(char)_value;
+- (void)serializeShort:(short)_value;
+- (void)serializeInt:(int)_value;
+- (void)serializeLong:(long)_value;
+- (void)serializeFloat:(float)_value;
+- (void)serializeDouble:(double)_value;
+- (void)serializeLongLong:(long long)_value;
+
+- (char)deserializeChar;
+- (short)deserializeShort;
+- (int)deserializeInt;
+- (long)deserializeLong;
+- (float)deserializeFloat;
+- (double)deserializeDouble;
+- (long long)deserializeLongLong;
+
+- (void)serializeCString:(const char *)_value;
+- (char *)deserializeCString;
+
+#if USE_SERIALIZER
+- (void)serializeDataAt:(const void*)data ofObjCType:(const char*)type
+  context:(id<NSObjCTypeSerializationCallBack>)_callback;
+- (void)deserializeDataAt:(const void*)data ofObjCType:(const char*)type
+  context:(id<NSObjCTypeSerializationCallBack>)_callback;
+#endif
+
+@end
+
+#endif /* __NGStreams_NGStreamProtocols_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGStreams.h b/skyrix-core/NGStreams/NGStreams/NGStreams.h
new file mode 100644 (file)
index 0000000..21e4023
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_H__
+#define __NGStreams_H__
+
+#include <NGStreams/NGStreamsDecls.h>
+
+#include <NGStreams/NGStreamProtocols.h>
+#include <NGStreams/NGTextStreamProtocols.h>
+
+#include <NGStreams/NGBase64Stream.h>
+#include <NGStreams/NGBufferedStream.h>
+#include <NGStreams/NGByteCountStream.h>
+#include <NGStreams/NGConcreteStreamFileHandle.h>
+#include <NGStreams/NGDataStream.h>
+#include <NGStreams/NGFileStream.h>
+#include <NGStreams/NGFilterStream.h>
+#include <NGStreams/NGLockingStream.h>
+#include <NGStreams/NGStream.h>
+#include <NGStreams/NGStreamExceptions.h>
+#include <NGStreams/NGStringTextStream.h>
+#include <NGStreams/NGCTextStream.h>
+#include <NGStreams/NGTextStream.h>
+#include <NGStreams/NGByteBuffer.h>
+#include <NGStreams/NGCharBuffer.h>
+
+#include <NGStreams/NGStreamPipe.h>
+#include <NGStreams/NGTerminalSupport.h>
+
+// kit class
+
+@interface NGStreams : NSObject
+@end
+
+// static linking
+
+#define LINK_NGStreams \
+  void __link_NGStreams(void) { \
+    [NGStreams class];  \
+    __link_NGStreams(); \
+  }
+
+#endif /* __NGStreams_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGStreamsDecls.h b/skyrix-core/NGStreams/NGStreams/NGStreamsDecls.h
new file mode 100644 (file)
index 0000000..52f040a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGStreamDecls_H__
+#define __NGStreams_NGStreamDecls_H__
+
+#if BUILD_libNGStreams_DLL
+#  define NGStreams_EXPORT  __declspec(dllexport)
+#  define NGStreams_DECLARE __declspec(dllexport)
+#elif libNGStreams_ISDLL
+#  define NGStreams_EXPORT  extern __declspec(dllimport)
+#  define NGStreams_DECLARE __declspec(dllimport)
+#else
+#  define NGStreams_EXPORT  extern
+#  define NGStreams_DECLARE
+#endif
+
+#endif /* __NGStreams_NGStreamDecls_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGStringTextStream.h b/skyrix-core/NGStreams/NGStreams/NGStringTextStream.h
new file mode 100644 (file)
index 0000000..556890f
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGStringTextStream_H__
+#define __NGStreams_NGStringTextStream_H__
+
+#include <NGStreams/NGTextStream.h>
+#include <NGStreams/NGTextStreamProtocols.h>
+
+@interface NGStringTextStream : NGTextStream
+{
+@private
+  NSString *string; // retained
+  unsigned index;   // position
+  BOOL     isMutable;
+}
+
++ (id)textStreamWithString:(NSString *)_string;
+- (id)initWithString:(NSString *)_string;
+
+// accessors
+
+- (NSString *)string;
+
+// operations
+
+- (BOOL)close; // releases string
+
+// NGTextInputStream, NGExtendedTextInputStream
+
+- (unichar)readCharacter;
+
+- (NSString *)readLineAsString; // inefficient implementation
+
+// NGTextOutputStream, NGExtendedTextOutputStream
+
+// throws
+//   NGReadOnlyStreamException when the stream is not writeable
+//   NGStreamNotOpenException  when the stream is not open
+- (BOOL)writeCharacter:(unichar)_character;
+
+// throws
+//   NGReadOnlyStreamException when the stream is not writeable
+//   NGStreamNotOpenException  when the stream is not open
+- (BOOL)writeString:(NSString *)_string;
+
+- (BOOL)flush;
+
+@end
+
+#endif /* __NGStreams_NGStringTextStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGTaskStream.h b/skyrix-core/NGStreams/NGStreams/NGTaskStream.h
new file mode 100644 (file)
index 0000000..fcb07d7
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGTaskStream_H__
+#define __NGStreams_NGTaskStream_H__
+
+#include <NGStreams/NGStream.h>
+
+@class NSTask;
+
+@interface NGTaskStream : NGStream
+{
+@private
+  NSTask *task;
+  int    stdinHandle;
+  int    stdoutHandle;
+}
+
+@end
+
+#endif /* __NGStreams_NGTaskStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGTerminalSupport.h b/skyrix-core/NGStreams/NGStreams/NGTerminalSupport.h
new file mode 100644 (file)
index 0000000..19f445f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGTerminalSupport_H__
+#define __NGStreams_NGTerminalSupport_H__
+
+#include <NGStreams/NGStream.h>
+#include <NGStreams/NGTextStream.h>
+
+@interface NGStream(NGTerminalSupport)
+
+- (BOOL)isAssociatedWithTerminalDevice;
+- (NSString *)nameOfAssociatedTerminalDevice;
+
+@end
+
+@interface NGTextStream(NGTerminalSupport)
+
+- (BOOL)isAssociatedWithTerminalDevice;
+- (NSString *)nameOfAssociatedTerminalDevice;
+
+@end
+
+#endif /* __NGStreams_NGTerminalSupport_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGTextStream.h b/skyrix-core/NGStreams/NGStreams/NGTextStream.h
new file mode 100644 (file)
index 0000000..7a5b4f2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGTextStream_H__
+#define __NGStreams_NGTextStream_H__
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGTextStreamProtocols.h>
+
+@class NSException;
+
+@interface NGTextStream : NSObject < NGExtendedTextStream >
+{
+@private
+  NSException *lastException;
+}
+
+// NGTextInputStream
+
+- (unichar)readCharacter;       // abstract
+- (NSException *)lastException;
+- (void)setLastException:(NSException *)_exception;
+- (void)resetLastException;
+
+// NGExtendedTextInputStream
+
+- (NSString *)readLineAsString; // inefficient
+- (unsigned)readCharacters:(unichar *)_chars count:(unsigned)_count;
+- (BOOL)safeReadCharacters:(unichar *)_chars count:(unsigned)_count;
+
+// NGTextOutputStream
+
+- (BOOL)writeCharacter:(unichar)_character; // abstract
+- (BOOL)writeString:(NSString *)_string;    // writeCharacter: based
+- (BOOL)flush; // does nothing
+
+// NGExtendedTextOutputStream
+
+- (BOOL)writeFormat:(NSString *)_format arguments:(va_list)_ap;
+- (BOOL)writeFormat:(NSString *)_format, ...;
+- (BOOL)writeNewline;
+
+- (unsigned)writeCharacters:(const unichar *)_chars count:(unsigned)_count;
+- (BOOL)safeWriteCharacters:(const unichar *)_chars count:(unsigned)_count;
+
+@end
+
+#endif /* __NGStreams_NGTextStream_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGTextStreamProtocols.h b/skyrix-core/NGStreams/NGStreams/NGTextStreamProtocols.h
new file mode 100644 (file)
index 0000000..10f962f
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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
+
+#ifndef __NGStreams_NGTextStreamProtocols_H__
+#define __NGStreams_NGTextStreamProtocols_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+
+@class NSString, NSException;
+
+@protocol NGTextInputStream < NSObject >
+
+- (unichar)readCharacter;
+
+@end
+
+@protocol NGTextOutputStream < NSObject >
+
+- (BOOL)writeCharacter:(unichar)_character;
+- (BOOL)writeString:(NSString *)_string;
+
+- (BOOL)flush;
+
+@end
+
+@protocol NGTextStream < NGTextInputStream, NGTextOutputStream >
+
+- (NSException *)lastException;
+
+@end
+
+// extended text streams
+
+@protocol NGExtendedTextInputStream < NGTextInputStream >
+
+- (NSString *)readLineAsString;
+
+@end
+
+@protocol NGExtendedTextOutputStream < NGTextOutputStream >
+
+- (BOOL)writeFormat:(NSString *)_format, ...;
+- (BOOL)writeNewline;
+
+@end
+
+@protocol NGExtendedTextStream < NGExtendedTextInputStream, NGExtendedTextOutputStream >
+@end
+
+#endif /* __NGStreams_NGTextStreamProtocols_H__ */
diff --git a/skyrix-core/NGStreams/NGStreams/NGUrlChars.h b/skyrix-core/NGStreams/NGStreams/NGUrlChars.h
new file mode 100644 (file)
index 0000000..38903f0
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_NGUrlChars_H__
+#define __NGStreams_NGUrlChars_H__
+
+static inline BOOL isUrlAlpha(unsigned char _c) {
+  return
+    (((_c >= 'a') && (_c <= 'z')) ||
+     ((_c >= 'A') && (_c <= 'Z')))
+    ? YES : NO;
+}
+static inline BOOL isUrlDigit(unsigned char _c) {
+  return ((_c >= '0') && (_c <= '9')) ? YES : NO;
+}
+static inline BOOL isUrlSafeChar(unsigned char _c) {
+  switch (_c) {
+    case '$': case '-': case '_': case '@':
+    case '.': case '&': case '+':
+      return YES;
+
+    default:
+      return NO;
+  }
+}
+static inline BOOL isUrlExtraChar(unsigned char _c) {
+  switch (_c) {
+    case '!': case '*': case '"': case '\'':
+    case '|': case ',':
+      return YES;
+  }
+  return NO;
+}
+static inline BOOL isUrlEscapeChar(unsigned char _c) {
+  return (_c == '%') ? YES : NO;
+}
+static inline BOOL isUrlReservedChar(unsigned char _c) {
+  switch (_c) {
+    case '=': case ';': case '/':
+    case '#': case '?': case ':':
+    case ' ':
+      return YES;
+  }
+  return NO;
+}
+
+static inline BOOL isUrlXalpha(unsigned char _c) {
+  if (isUrlAlpha(_c))      return YES;
+  if (isUrlDigit(_c))      return YES;
+  if (isUrlSafeChar(_c))   return YES;
+  if (isUrlExtraChar(_c))  return YES;
+  if (isUrlEscapeChar(_c)) return YES;
+  return NO;
+}
+
+static inline BOOL isUrlHexChar(unsigned char _c) {
+  if (isUrlDigit(_c))
+    return YES;
+  if ((_c >= 'a') && (_c <= 'f'))
+    return YES;
+  if ((_c >= 'A') && (_c <= 'F'))
+    return YES;
+  return NO;
+}
+
+static inline BOOL isUrlAlphaNum(unsigned char _c) {
+  return (isUrlAlpha(_c) || isUrlDigit(_c)) ? YES : NO;
+}
+
+#endif /* __NGStreams_NGUrlChars_H__ */
diff --git a/skyrix-core/NGStreams/NGStringTextStream.m b/skyrix-core/NGStreams/NGStringTextStream.m
new file mode 100644 (file)
index 0000000..7df2cdf
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGStringTextStream.h"
+#include "NGStreamExceptions.h"
+
+@implementation NGStringTextStream
+
++ (id)textStreamWithString:(NSString *)_string {
+  return [[[self alloc] initWithString:_string] autorelease];
+}
+- (id)initWithString:(NSString *)_string {
+  if ((self = [super init])) {
+    self->string    = [_string retain];
+    self->index     = 0;
+    self->isMutable = [_string isKindOfClass:[NSMutableString class]];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->string release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)string {
+  return string;
+}
+
+/* operations */
+
+- (BOOL)close {
+  // releases string
+  [self->string release]; self->string = nil;
+  return YES;
+}
+
+// NGTextInputStream
+
+- (unichar)readCharacter {
+  // throws
+  //   NGStreamNotOpenException  when the stream is not open
+  unsigned currentLength = [string length];
+  unichar  result;
+
+  if (string == nil) {
+    [NGStreamNotOpenException raiseWithReason:
+       @"tried to read from a string text stream which was closed"];
+  }
+  
+  if (currentLength == index)
+    [[[NGEndOfStreamException alloc] init] raise];
+
+  result = [string characterAtIndex:index];
+  index++;
+  return result;
+}
+
+// NGExtendedTextInputStream
+
+- (NSString *)readLineAsString {
+  // throws
+  //   NGStreamNotOpenException  when the stream is not open
+  
+  unsigned currentLength = [string length];
+  NSRange  range;
+  
+  if (string == nil) {
+    [NGStreamNotOpenException raiseWithReason:
+            @"tried to read from a string text stream which was closed"];
+  }
+  
+  if (currentLength == index)
+    //[[[NGEndOfStreamException alloc] init] raise]
+    return nil;
+  
+  range.location = index;
+  range.length   = (currentLength - index);
+
+  range = [string rangeOfString:@"\n" options:NSLiteralSearch range:range];
+  if (range.length == 0) { // did not found newline
+    NSString *result = [string substringFromIndex:index];
+    index = currentLength;
+    return result;
+  }
+  else {
+    NSString *result = nil;
+
+    range.length   = (range.location - index);
+    range.location = index;
+
+    result = [string substringWithRange:range];
+
+    index += range.length + 1;
+
+    return result;
+  }
+}
+
+// NGTextOutputStream
+
+- (BOOL)writeCharacter:(unichar)_character {
+  // throws
+  //   NGReadOnlyStreamException when the stream is not writeable
+  //   NGStreamNotOpenException  when the stream is not open
+  
+  if (string == nil) {
+    [NGStreamNotOpenException raiseWithReason:
+            @"tried to write to a string text stream which was closed"];
+    return NO;
+  }
+  if (!isMutable) {
+    [[[NGReadOnlyStreamException alloc] init] raise];
+    return NO;
+  }
+  
+  [(NSMutableString *)string appendString:
+    [NSString stringWithCharacters:&_character length:1]];
+  return YES;
+}
+
+- (BOOL)writeString:(NSString *)_string {
+  // throws
+  //   NGReadOnlyStreamException when the stream is not writeable
+  //   NGStreamNotOpenException  when the stream is not open
+  
+  if (string == nil) {
+    [NGStreamNotOpenException raiseWithReason:
+            @"tried to write to a string text stream which was closed"];
+    return NO;
+  }
+  if (!isMutable) {
+    [[[NGReadOnlyStreamException alloc] init] raise];
+    return NO;
+  }
+  
+  [(NSMutableString *)string appendString:_string];
+  return YES;
+}
+
+- (BOOL)flush {
+  return YES;
+}
+
+@end /* NGStringTextStream */
diff --git a/skyrix-core/NGStreams/NGTaskStream.m b/skyrix-core/NGStreams/NGTaskStream.m
new file mode 100644 (file)
index 0000000..a62d3fd
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "config.h"
+#include "common.h"
+#include "NGTaskStream.h"
+
+@implementation NGTaskStream
+
+- (id)initWithPath:(NSString *)_executable
+  arguments:(NSArray *)_args
+  environment:(NSDictionary *)_env
+{
+  return nil;
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* state */
+
+- (BOOL)isOpen {
+  return [self->task isRunning];
+}
+
+/* primitives */
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  return NGStreamError;
+}
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  return NGStreamError;
+}
+
+- (BOOL)close {
+  if (![self isOpen]) {
+    NSLog(@"tried to close already closed stream %@", self);
+    return NO;
+  }
+  [self->task terminate];
+  return YES;
+}
+
+- (NGStreamMode)mode {
+  return NGStreamMode_readWrite;
+}
+- (BOOL)isRootStream {
+  return YES;
+}
+
+/* marking */
+
+- (BOOL)mark {
+  NSLog(@"WARNING: called mark on a stream which doesn't support marking !");
+  return NO;
+}
+- (BOOL)rewind {
+  [[[NGStreamException alloc] initWithStream:self
+                              reason:@"marking not supported"] raise];
+  return NO;
+}
+- (BOOL)markSupported {
+  return -1;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<%@[0x%08X] task=%@ mode=%@>",
+                     NSStringFromClass([self class]), (unsigned)self,
+                     self->task,
+                     [self modeDescription]];
+}
+
+@end /* NGTaskStream */
diff --git a/skyrix-core/NGStreams/NGTerminalSupport.m b/skyrix-core/NGStreams/NGTerminalSupport.m
new file mode 100644 (file)
index 0000000..184ca67
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGTerminalSupport.h"
+#include "NGFileStream.h"
+#include "NGFilterStream.h"
+#include "NGCTextStream.h"
+#include "NGDescriptorFunctions.h"
+
+@implementation NGStream(NGTerminalSupport)
+
+- (BOOL)isAssociatedWithTerminalDevice {
+  return NO;
+}
+
+- (NSString *)nameOfAssociatedTerminalDevice {
+  return nil;
+}
+
+@end
+
+@implementation NGFileStream(NGTerminalSupport)
+
+- (BOOL)isAssociatedWithTerminalDevice {
+#if defined(WIN32)
+  return NO;
+#else
+  return [self isOpen] ? NGDescriptorIsAtty(self->fd) : NO;
+#endif
+}
+
+- (NSString *)nameOfAssociatedTerminalDevice {
+#if defined(WIN32)
+  return nil;
+#else
+  return [self isOpen] ? NGDescriptorGetTtyName(self->fd) : nil;
+#endif
+}
+
+@end
+
+@implementation NGFilterStream(NGTerminalSupport)
+
+- (BOOL)isAssociatedWithTerminalDevice {
+  id src = [self source];
+  
+  return [src respondsToSelector:_cmd]
+    ? [src isAssociatedWithTerminalDevice]
+    : NO;
+}
+
+- (NSString *)nameOfAssociatedTerminalDevice {
+  id src = [self source];
+  
+  return [src respondsToSelector:_cmd]
+    ? [src nameOfAssociatedTerminalDevice]
+    : NO;
+}
+
+@end
+
+@implementation NGTextStream(NGTerminalSupport)
+
+- (BOOL)isAssociatedWithTerminalDevice {
+  return NO;
+}
+- (NSString *)nameOfAssociatedTerminalDevice {
+  return nil;
+}
+
+@end
+
+@implementation NGCTextStream(NGTerminalSupport)
+
+- (BOOL)isAssociatedWithTerminalDevice {
+  id src = [self source];
+  
+  return [src respondsToSelector:_cmd]
+    ? [src isAssociatedWithTerminalDevice]
+    : NO;
+}
+
+- (NSString *)nameOfAssociatedTerminalDevice {
+  id src = [self source];
+  
+  return [src respondsToSelector:_cmd]
+    ? [src nameOfAssociatedTerminalDevice]
+    : NO;
+}
+
+@end
+
+void __link_NGStreams_NGTerminalSupport(void) {
+  __link_NGStreams_NGTerminalSupport();
+}
diff --git a/skyrix-core/NGStreams/NGTextStream.m b/skyrix-core/NGStreams/NGTextStream.m
new file mode 100644 (file)
index 0000000..037aa67
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGTextStream.h"
+
+@implementation NGTextStream
+
++ (int)version {
+  return 2;
+}
+
+- (void)dealloc {
+  [self->lastException release];
+  [super dealloc];
+}
+
+/* NGTextInputStream */
+
+- (NSException *)lastException {
+  return nil;
+}
+- (void)setLastException:(NSException *)_exception {
+  ASSIGN(self->lastException, _exception);
+}
+- (void)resetLastException {
+  [self->lastException release];
+  self->lastException = nil;
+}
+
+- (unichar)readCharacter {
+  [self subclassResponsibility:_cmd];
+  return 0;
+}
+
+- (BOOL)isOpen {
+  return YES;
+}
+
+/* NGExtendedTextInputStream */
+
+- (NSString *)readLineAsString {
+  NSMutableString *str;
+  unichar c;
+
+  *(&str) = (id)[NSMutableString string];
+
+  NS_DURING {
+    while ((c = [self readCharacter]) != '\n')
+      [str appendString:[NSString stringWithCharacters:&c length:1]];
+  }
+  NS_HANDLER {
+    if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
+      if ([str length] == 0) str = nil;
+    }
+    else
+      [localException raise];
+  }
+  NS_ENDHANDLER;
+  
+  return str;
+}
+
+- (unsigned)readCharacters:(unichar *)_chars count:(unsigned)_count {
+  /*
+    Read up to _count characters, but one at the minimum.
+  */
+  volatile unsigned pos;
+
+  NS_DURING {
+    for (pos = 0; pos < _count; pos++)
+      _chars[pos] = [self readCharacter];
+  }
+  NS_HANDLER {
+    if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
+      if (pos == 0)
+        [localException raise];
+    }
+    else
+      [localException raise];
+  }
+  NS_ENDHANDLER;
+
+  NSAssert1(pos > 0, @"invalid character count to be returned: %i", pos);
+  return pos;
+}
+
+- (BOOL)safeReadCharacters:(unichar *)_chars count:(unsigned)_count {
+  volatile unsigned pos;
+  
+  for (pos = 0; pos < _count; pos++)
+    _chars[pos] = [self readCharacter];
+  
+  return YES;
+}
+
+/* NGTextOutputStream */
+
+- (BOOL)writeCharacter:(unichar)_character {
+  [self subclassResponsibility:_cmd];
+  return NO;
+}
+
+- (BOOL)writeString:(NSString *)_string {
+  unsigned length = [_string length], cnt = 0;
+  unichar  buffer[length];
+  void     (*writeChar)(id, SEL, unichar);
+
+  writeChar = (void (*)(id,SEL,unichar))
+    [self methodForSelector:@selector(writeCharacter:)];
+  
+  [_string getCharacters:buffer];
+  for (cnt = 0; cnt < length; cnt++)
+    writeChar(self, @selector(writeCharacter:), buffer[cnt]);
+  
+  return YES;
+}
+
+- (BOOL)flush {
+  return YES;
+}
+
+/* NGExtendedTextOutputStream */
+
+- (BOOL)writeFormat:(NSString *)_format arguments:(va_list)_ap {
+  NSString *tmp;
+  
+  tmp = [[[NSString alloc] initWithFormat:_format arguments:_ap] autorelease];
+  [self writeString:tmp];
+  return YES;
+}
+- (BOOL)writeFormat:(NSString *)_format, ... {
+  va_list ap;
+  BOOL res = NO;
+
+  va_start(ap, _format);
+
+  NS_DURING {
+    res = [self writeFormat:_format arguments:ap];
+  }
+  NS_HANDLER {
+    va_end(ap);
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+  va_end(ap);
+
+  return res;
+}
+
+- (BOOL)writeNewline {
+  if (![self writeString:@"\n"]) return NO;
+  return [self flush];
+}
+
+- (unsigned)writeCharacters:(const unichar *)_chars count:(unsigned)_count {
+  /*
+    Write up to _count characters, but one at the minimum.
+  */
+  volatile unsigned pos;
+
+  NS_DURING {
+    for (pos = 0; pos < _count; pos++)
+      [self writeCharacter:_chars[pos]];
+  }
+  NS_HANDLER {
+    if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
+      if (pos == 0)
+        [localException raise];
+    }
+    else
+      [localException raise];
+  }
+  NS_ENDHANDLER;
+
+  NSAssert1(pos > 0, @"invalid character count to be returned: %i", pos);
+  return pos;
+}
+
+- (BOOL)safeWriteCharacters:(const unichar *)_chars count:(unsigned)_count {
+  unsigned pos;
+
+  for (pos = 0; pos < _count; pos++) {
+    if (![self writeCharacter:_chars[pos]])
+      return NO;
+  }
+  
+  return YES;
+}
+
+@end /* NGTextStream */
diff --git a/skyrix-core/NGStreams/README b/skyrix-core/NGStreams/README
new file mode 100644 (file)
index 0000000..fc00e33
--- /dev/null
@@ -0,0 +1,121 @@
+# $Id$
+
+SKYRiX IO Streaming Library
+===========================
+
+Introduction
+============
+
+This library contains Objective-C classes to access files and
+network sockets using a java.io like streaming mechanism.
+It also abstracts the Unix socket API (that is, we have extensible
+classes for socket domains, addresses etc)
+
+TODO
+====
+
+Should we remove serialization ? It's not available with Jaguar
+(MacOSX 10.2) anymore. Currently is turned off on Jaguar.
+
+Removed functionality
+=====================
+
+Removed in 4.1, available in MOF3:
+
+  NGUrl related things
+
+... idn't make much sense anymore, now that Foundation has NSURL
+
+Defaults:
+=========
+
+  ProfileByteBufferEnabled = NO;
+
+Protocols
+=========
+
+  NGSerializer
+  NGActiveSocket
+  NGPositionableStream
+  NGDatagramPacket
+  NGSocketAddress
+  NGSocketDomain
+
+Class Hierachy
+==============
+  
+  NSObject
+    NGStream < NGStream, NGByteSequenceStream > (serialization) <NGSerializer>
+      NGFileStream          < NGPositionableStream >
+      NGDataStream          < NGPositionableStream >
+      NGTaskStream
+      NGFilterStream
+        NGBase64Stream
+        NGBufferedStream
+        NGByteBuffer
+        NGByteCountStream
+        NGLockingStream
+    NGSocket                < NGSocket >
+      NGActiveSocket        < NGActiveSocket > (serialization) < NGSerializer >
+      NGPassiveSocket       < NGPassiveSocket >
+      NGDatagramSocket
+    NGTextStream            < NGExtendedTextStream >
+      NGStringTextStream
+      NGCTextStream
+      NGFilterTextStream
+        NGCharBuffer
+    NGDatagramPacket        < NGDatagramPacket >
+    NGInternetSocketAddress < NSCopying, NSCoding, NGSocketAddress >
+    NGInternetSocketDomain  < NSCoding, NSCopying, NGSocketDomain >
+    NGLocalSocketAddress    < NSCopying, NGSocketAddress >
+    NGLocalSocketDomain     < NSCopying, NSCoding, NGSocketDomain >
+    NSFileHandle
+      NGConcreteStreamFileHandle
+    NSCoder
+      NGStreamCoder         < NSObjCTypeSerializationCallBack >
+    NSPipe
+      NGStreamPipe          < NGStream, NGByteSequenceStream >
+
+Exceptions
+==========
+
+  NSException
+    NGIOException
+      NGStreamException
+        NGEndOfStreamException
+          NGSocketShutdownException
+            NGSocketShutdownDuringReadException
+            NGSocketShutdownDuringWriteException
+            NGSocketTimedOutException
+            NGSocketConnectionResetException
+        NGCouldNotOpenStreamException
+        NGCouldNotCloseStreamException
+        NGStreamNotOpenException
+        NGStreamErrorException
+          NGStreamReadErrorException
+          NGStreamWriteErrorException
+          NGStreamSeekErrorException
+        NGStreamModeException
+          NGUnknownStreamModeException
+          NGReadOnlyStreamException
+          NGWriteOnlyStreamException
+      NGIOAccessException
+        NGIOSearchAccessException
+      NGSocketException
+        NGCouldNotResolveHostNameException
+        NGDidNotFindServiceException
+        NGInvalidSocketDomainException
+        NGCouldNotCreateSocketException
+        NGSocketBindException
+          NGSocketAlreadyBoundException
+          NGCouldNotBindSocketException
+        NGSocketConnectException
+          NGSocketNotConnectedException
+          NGSocketAlreadyConnectedException
+          NGCouldNotConnectException
+        NGSocketIsAlreadyListeningException
+        NGCouldNotListenException
+        NGCouldNotAcceptException
+        NGSocketOptionException
+          NGCouldNotSetSocketOptionException
+          NGCouldNotGetSocketOptionException
diff --git a/skyrix-core/NGStreams/SxCore-NGStreams.graffle b/skyrix-core/NGStreams/SxCore-NGStreams.graffle
new file mode 100644 (file)
index 0000000..f0daa7c
--- /dev/null
@@ -0,0 +1,4989 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+       <key>CanvasColor</key>
+       <dict>
+               <key>w</key>
+               <real>1.000000e+00</real>
+       </dict>
+       <key>ColumnAlign</key>
+       <integer>0</integer>
+       <key>ColumnSpacing</key>
+       <real>5.400000e+01</real>
+       <key>GraphDocumentVersion</key>
+       <integer>2</integer>
+       <key>GraphicsList</key>
+       <array>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{639, 1332}, {225, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8385</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCouldNotGetSocketOptionException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{720, 1359}, {225, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8386</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCouldNotSetSocketOptionException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{702, 1296}, {171, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8387</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketOptionException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8385</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8388</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{778.5, 1314}</string>
+                                               <string>{760.5, 1332}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8387</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8386</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8389</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{793.929, 1314}</string>
+                                               <string>{826.071, 1359}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8387</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8384</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{567, 999}, {234, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8383</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCouldNotResolveHostNameException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{324, 315}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8368</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGBase64Stream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGBase64Stream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{396, 279}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8369</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGLockingStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGLockingStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{252, 279}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8370</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGMD5Stream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGMD5Stream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{396, 252}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8371</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGByteBuffer.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGByteBuffer}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{396, 225}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8372</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGByteCountStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGByteCountStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{252, 252}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8373</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGBufferedStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGBufferedStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{252, 225}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8374</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGGZipStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGGZipStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{324, 189}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8375</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGFilterStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGFilterStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8368</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8376</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{387, 207}</string>
+                                               <string>{387, 315}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8375</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8369</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8377</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{394.2, 207}</string>
+                                               <string>{451.8, 279}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8375</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8370</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8378</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{379.8, 207}</string>
+                                               <string>{322.2, 279}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8375</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8371</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8379</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{397.286, 207}</string>
+                                               <string>{448.714, 252}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8375</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8372</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8380</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{405, 207}</string>
+                                               <string>{441, 225}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8375</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8373</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8381</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{376.714, 207}</string>
+                                               <string>{325.286, 252}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8375</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8374</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8382</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{369, 207}</string>
+                                               <string>{333, 225}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8375</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8367</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{36, 981}, {207, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8366</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCouldNotCloseStreamException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{117, 1404}, {243, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8357</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketShutdownDuringReadException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{18, 1377}, {243, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8358</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketConnectionResetException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{117, 1350}, {243, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8359</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketTimedOutException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{54, 1287}, {279, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8360</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketShutdownException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{18, 1323}, {243, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8361</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketShutdownDuringWriteException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8357</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8362</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{196.962, 1305}</string>
+                                               <string>{235.038, 1404}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8360</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8358</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8363</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{188.1, 1305}</string>
+                                               <string>{144.9, 1377}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8360</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8359</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8364</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{199.929, 1305}</string>
+                                               <string>{232.071, 1350}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8360</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8361</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8365</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{180, 1305}</string>
+                                               <string>{153, 1323}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8360</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8356</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{567, 972}, {234, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8355</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketIsAlreadyListeningException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{225, 1089}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8348</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStreamSeekErrorException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{333, 1062}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8349</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStreamWriteErrorException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{225, 1035}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8350</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStreamReadErrorException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{279, 999}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8351</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStreamErrorException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8348</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8352</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{351.45, 1017}</string>
+                                               <string>{319.05, 1089}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8351</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8349</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8353</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{365.143, 1017}</string>
+                                               <string>{413.357, 1062}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8351</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8350</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8354</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{345.375, 1017}</string>
+                                               <string>{325.125, 1035}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8351</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8347</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{171, 540}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8334</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGDatagramSocket.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGDatagramSocket}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{315, 567}, {117, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8335</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGActiveSocket}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{171, 567}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8336</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGActiveSocket.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGActiveSocket}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{315, 513}, {117, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8337</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGPassiveSocket}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{171, 513}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8338</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGPassiveSocket.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGPassiveSocket}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{45, 576}, {81, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8339</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGSocket}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{45, 540}, {81, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8340</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocket.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocket}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8334</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8341</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{126, 549}</string>
+                                               <string>{171, 549}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8340</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8336</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8342</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{315, 576}</string>
+                                               <string>{297, 576}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8335</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8336</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8343</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{124.876, 556.159}</string>
+                                               <string>{184.5, 567}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8340</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8338</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8344</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{315, 522}</string>
+                                               <string>{297, 522}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8337</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8338</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8345</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{124.876, 541.841}</string>
+                                               <string>{184.5, 531}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8340</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8340</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8346</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{85.5, 576}</string>
+                                               <string>{85.5, 558}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8339</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8333</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{558, 1179}, {198, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8329</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketAlreadyBoundException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{585, 1143}, {171, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8330</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketBindException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{603, 1206}, {198, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8331</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCouldNotBindSocketException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8331</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8332</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{675, 1161}</string>
+                                               <string>{697.5, 1206}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8330</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8328</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{567, 945}, {234, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8327</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGInvalidSocketDomainException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{99, 684}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8316</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGCharBuffer.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCharBuffer}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{243, 684}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8317</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStringTextStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStringTextStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{99, 648}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8318</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGFilterTextStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGFilterTextStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{306, 648}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8319</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGCTextStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCTextStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{297, 612}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8320</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGTextStreamProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGExtendedTextStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{153, 612}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8321</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGTextStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGTextStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8316</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8322</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{162, 666}</string>
+                                               <string>{162, 684}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8318</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8317</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8323</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{227.25, 630}</string>
+                                               <string>{294.75, 684}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8321</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8318</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8324</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{202.5, 630}</string>
+                                               <string>{175.5, 648}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8321</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8319</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8325</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{254.25, 630}</string>
+                                               <string>{330.75, 648}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8321</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8321</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8326</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{297, 621}</string>
+                                               <string>{279, 621}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8320</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8315</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{234, 1233}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8308</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGWriteOnlyStreamException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{234, 1179}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8309</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGReadOnlyStreamException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{270, 1134}, {207, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8310</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStreamModeException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{306, 1206}, {207, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8311</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGUnknownStreamModeException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8308</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8312</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{369, 1152}</string>
+                                               <string>{328.5, 1233}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8310</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8309</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8313</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{363.6, 1152}</string>
+                                               <string>{333.9, 1179}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8310</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8311</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8314</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{378, 1152}</string>
+                                               <string>{405, 1206}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8310</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8307</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{567, 918}, {234, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8306</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGDidNotFindServiceException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{351, 837}, {171, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8305</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGIOSearchAccessException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{99, 234}, {90, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8302</integer>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSFileHandle}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{54, 270}, {180, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8303</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGConcreteStreamFileHandle.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGConcreteStreamFileHandle}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8303</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8304</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{144, 252}</string>
+                                               <string>{144, 270}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8302</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8301</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{567, 891}, {234, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8300</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCouldNotListenException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{189, 837}, {144, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8299</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGIOAccessException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{837, 1116}, {225, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8292</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketAlreadyConnectedException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{801, 1143}, {198, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8293</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketNotConnectedException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{837, 1053}, {171, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8294</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketConnectException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{801, 1089}, {198, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8295</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCouldNotConnectException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8292</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8296</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{926.357, 1071}</string>
+                                               <string>{945.643, 1116}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8294</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8293</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8297</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{920.25, 1071}</string>
+                                               <string>{902.25, 1143}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8294</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8295</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8298</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{916.875, 1071}</string>
+                                               <string>{905.625, 1089}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8294</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8291</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{45, 306}, {207, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8289</integer>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NSObjCTypeSerializationCallBack}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{45, 342}, {207, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8290</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamCoder.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStreamCoder}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8288</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{45, 477}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8283</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGInternetSocketDomain.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGInternetSocketDomain}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{216, 468}, {117, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8284</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGSocketDomain}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{45, 450}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8285</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGLocalSocketDomain.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGLocalSocketDomain}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8283</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8286</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{216, 480.441}</string>
+                                               <string>{197.975, 481.501}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8284</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8285</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8287</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{216, 470.118}</string>
+                                               <string>{194.883, 467.633}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8284</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8282</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{252, 72}, {99, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8277</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGDataStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGDataStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{369, 45}, {135, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8278</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGPositionableStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{252, 27}, {99, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8279</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGFileStream.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGFileStream}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8277</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8280</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{391.5, 63}</string>
+                                               <string>{346.415, 72.017}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8278</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8279</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8281</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{369, 45}</string>
+                                               <string>{350.325, 42.51}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8278</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8276</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{72, 27}, {99, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8273</integer>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSPipe}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{72, 63}, {99, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8274</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamPipe.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStreamPipe}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8274</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>8275</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{121.5, 45}</string>
+                                               <string>{121.5, 63}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>8273</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8272</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{306, 936}, {207, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8271</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStreamNotOpenException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{27, 1197}, {162, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8270</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGEndOfStreamException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{207, 774}, {108, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8269</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGIOException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{567, 864}, {234, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8268</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCouldNotCreateSocketException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{198, 900}, {126, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8267</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStreamException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{18, 945}, {207, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8266</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCouldNotOpenStreamException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{729, 774}, {126, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8265</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGSocketException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{567, 837}, {234, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8264</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGCouldNotAcceptException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{351, 459}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8261</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGInternetSocketAddress.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGInternetSocketAddress}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{216, 441}, {117, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8262</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGSocketAddress}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{351, 432}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8263</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGLocalSocketAddress.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGLocalSocketAddress}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8260</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8261</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8259</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{333, 456.882}</string>
+                               <string>{354.117, 459.367}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8262</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8263</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8258</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{333, 446.559}</string>
+                               <string>{351.025, 445.499}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8262</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{342, 108}, {99, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8257</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGTaskStream.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGTaskStream}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{216, 387}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8255</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGDatagramPacket}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{45, 387}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>8256</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGDatagramPacket.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>RoundedRectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGDatagramPacket}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>8254</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8256</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8253</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{216, 396}</string>
+                               <string>{198, 396}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8255</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{207, 738}, {108, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8252</integer>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>5.000000e-01</real>
+                                               <key>g</key>
+                                               <real>1.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSException}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{45, 189}, {81, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8251</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamProtocols.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGStream}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{117, 117}, {153, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8250</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamProtocols.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 NGByteSequenceStream}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{153, 189}, {81, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>8249</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStream.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>RoundedRectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NGStream}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8383</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8248</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{787.68, 792}</string>
+                               <string>{688.32, 999}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8366</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8247</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{247.5, 918}</string>
+                               <string>{153, 981}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8267</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8269</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8246</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{261, 756}</string>
+                               <string>{261, 774}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8252</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8355</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8245</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{787.091, 792}</string>
+                               <string>{688.909, 972}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8329</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8244</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{667.125, 1161}</string>
+                               <string>{660.375, 1179}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8330</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8294</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8243</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{796.21, 792}</string>
+                               <string>{918.29, 1053}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8360</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8242</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{116.55, 1215}</string>
+                               <string>{184.95, 1287}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8270</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8327</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8241</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{786.316, 792}</string>
+                               <string>{689.684, 945}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8387</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8240</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{791.922, 792}</string>
+                               <string>{787.578, 1296}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8330</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8239</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{789.037, 792}</string>
+                               <string>{673.463, 1143}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8306</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8238</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{785.25, 792}</string>
+                               <string>{690.75, 918}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8305</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8237</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{333, 846}</string>
+                               <string>{351, 846}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8299</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8300</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8236</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{783.692, 792}</string>
+                               <string>{692.308, 891}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8299</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8235</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{261, 792}</string>
+                               <string>{261, 837}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8269</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8290</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8234</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{148.5, 324}</string>
+                               <string>{148.5, 342}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8289</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8277</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8233</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{201.808, 189}</string>
+                               <string>{293.192, 90}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8249</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8274</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8232</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{88.0714, 189}</string>
+                               <string>{118.929, 81}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8251</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8274</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8231</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{181.5, 117}</string>
+                               <string>{133.5, 81}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8250</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8279</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8230</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{199.5, 189}</string>
+                               <string>{295.5, 45}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8249</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8271</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8229</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{298.125, 918}</string>
+                               <string>{372.375, 936}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8267</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8351</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8228</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{269.591, 918}</string>
+                               <string>{346.909, 999}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8267</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8310</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8227</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{265.327, 918}</string>
+                               <string>{369.173, 1134}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8267</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8267</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8226</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{261, 792}</string>
+                               <string>{261, 900}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8269</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8375</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8225</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{234, 198}</string>
+                               <string>{324, 198}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8249</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8270</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8224</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{256.364, 918}</string>
+                               <string>{112.636, 1197}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8267</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8223</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{315, 783}</string>
+                               <string>{729, 783}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8269</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8268</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8222</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{781.2, 792}</string>
+                               <string>{694.8, 864}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8266</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8221</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{233.1, 918}</string>
+                               <string>{149.4, 945}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8267</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8264</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8220</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{776.571, 792}</string>
+                               <string>{699.429, 837}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8265</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8257</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8219</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{215.5, 189}</string>
+                               <string>{369.5, 126}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8249</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8249</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8218</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{126, 198}</string>
+                               <string>{153, 198}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8251</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8249</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8217</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{193.5, 135}</string>
+                               <string>{193.5, 189}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8250</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8251</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>8216</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{85.5, 576}</string>
+                               <string>{85.5, 207}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledDiamond</string>
+                                       <key>LineType</key>
+                                       <integer>1</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>8339</integer>
+                       </dict>
+               </dict>
+       </array>
+       <key>GridInfo</key>
+       <dict/>
+       <key>HPages</key>
+       <integer>4</integer>
+       <key>ImageCounter</key>
+       <integer>1</integer>
+       <key>IsPalette</key>
+       <string>NO</string>
+       <key>Layers</key>
+       <array>
+               <dict>
+                       <key>Lock</key>
+                       <string>NO</string>
+                       <key>Name</key>
+                       <string>Layer 1</string>
+                       <key>Print</key>
+                       <string>YES</string>
+                       <key>View</key>
+                       <string>YES</string>
+               </dict>
+       </array>
+       <key>LayoutInfo</key>
+       <dict>
+               <key>AutoAdjust</key>
+               <string>YES</string>
+               <key>HierarchicalOrientation</key>
+               <integer>0</integer>
+               <key>MagneticFieldCenter</key>
+               <string>{0, 0}</string>
+       </dict>
+       <key>MagnetsEnabled</key>
+       <string>YES</string>
+       <key>PageBreakColor</key>
+       <dict>
+               <key>w</key>
+               <real>3.333333e-01</real>
+       </dict>
+       <key>PageBreaks</key>
+       <string>YES</string>
+       <key>PageSetup</key>
+       <data>
+       BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE
+       hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpEpKEhIQITlNT
+       dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE
+       mZkOTlNCb3R0b21NYXJnaW6GkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVlAJSEASqEhAFm
+       nSSGkoSZmQtOU1BhcGVyTmFtZYaShJmZBkxldHRlcoaShJmZD05TUHJpbnRBbGxQYWdl
+       c4aShJ2chIQBc54AhpKEmZkNTlNSaWdodE1hcmdpboaShJ2cn50khpKEmZkITlNDb3Bp
+       ZXOGkoSdnISEAVOfAYaShJmZD05TU2NhbGluZ0ZhY3RvcoaShJ2chIQBZKABhpKEmZkL
+       TlNGaXJzdFBhZ2WGkoSdnKmfAYaShJmZFE5TVmVydGljYWxQYWdpbmF0aW9uhpKEnZyk
+       ngCGkoSZmRVOU0hvcml6b25hbFBhZ2luYXRpb26GkoSdnKSeAIaShJmZFk5TSG9yaXpv
+       bnRhbGx5Q2VudGVyZWSGkoSdnKSeAYaShJmZDE5TTGVmdE1hcmdpboaShJ2cn50khpKE
+       mZkNTlNPcmllbnRhdGlvboaShJ2cpJ4AhpKEmZkZTlNQcmludFJldmVyc2VPcmllbnRh
+       dGlvboaSo5KEmZkKTlNMYXN0UGFnZYaShJ2chJeXgn////+GkoSZmQtOU1RvcE1hcmdp
+       boaShJ2cn50khpKEmZkUTlNWZXJ0aWNhbGx5Q2VudGVyZWSGkrSShJmZC05TUGFwZXJT
+       aXplhpKEnpyEhAx7X05TU2l6ZT1mZn2hgQJkgQMYhoaG
+       </data>
+       <key>RowAlign</key>
+       <integer>0</integer>
+       <key>RowSpacing</key>
+       <real>9.000000e+00</real>
+       <key>VPages</key>
+       <integer>2</integer>
+       <key>WindowInfo</key>
+       <dict>
+               <key>Frame</key>
+               <string>{{185, 90}, {794, 751}}</string>
+               <key>VisibleRegion</key>
+               <string>{{0, 0}, {1038.67, 898.667}}</string>
+               <key>Zoom</key>
+               <string>0.75</string>
+       </dict>
+</dict>
+</plist>
diff --git a/skyrix-core/NGStreams/TODO b/skyrix-core/NGStreams/TODO
new file mode 100644 (file)
index 0000000..a81847f
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id: TODO,v 1.1 2004/06/09 21:09:54 helge Exp $
+
+TODO for NGStreams
+==================
+
+- can we support NSxxStreams?
+- do we really need the dependency to:
+  - NGStreams
+  - NGExtensions
+  ?
diff --git a/skyrix-core/NGStreams/Version b/skyrix-core/NGStreams/Version
new file mode 100644 (file)
index 0000000..b64cd58
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=41
diff --git a/skyrix-core/NGStreams/common.h b/skyrix-core/NGStreams/common.h
new file mode 100644 (file)
index 0000000..b7fd849
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGStreams_common_H__
+#define __NGStreams_common_H__
+
+// common include files
+
+#include  <Foundation/Foundation.h>
+
+// configuration
+
+#include "config.h"
+
+#if defined(WIN32)
+#  include <windows.h>
+#  include <winsock.h>
+#endif
+
+#if LIB_FOUNDATION_BOEHM_GC
+#  include <gc.h>
+#endif
+
+#ifdef GNU_RUNTIME
+#  include <objc/objc-api.h>
+#  include <objc/objc.h>
+#  include <objc/encoding.h>
+#endif
+
+#if WITH_FOUNDATION_EXT
+#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY
+#  import <FoundationExt/objc-runtime.h>
+#  import <FoundationExt/DefaultScannerHandler.h>
+#  import <FoundationExt/PrintfFormatScanner.h>
+#  import <FoundationExt/GeneralExceptions.h>
+#  import <FoundationExt/MissingMethods.h>
+#  import <FoundationExt/NSException.h>
+#  import <FoundationExt/NSObjectMacros.h>
+#endif
+#endif
+
+#if !LIB_FOUNDATION_LIBRARY && !NeXT_Foundation_LIBRARY
+#  define NSWillBecomeMultiThreadedNotification NSBecomingMultiThreaded
+#endif
+
+#ifndef ASSIGN
+#  define ASSIGN(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) [__value retain]; \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+
+#include <NGExtensions/NGExtensions.h>
+
+/* system config */
+
+#if !defined(__CYGWIN32__)
+#  ifdef HAVE_WINDOWS_H
+#    include <windows.h>
+#  endif
+#  ifdef HAVE_WINSOCK_H
+#    include <winsock.h>
+#  endif
+#endif
+
+#ifdef HAVE_STRING_H
+#  include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#  include <strings.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+
+#ifndef __MINGW32__
+#  include <netinet/in.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#  include <netdb.h>
+#endif
+
+#if !defined(WIN32) || defined(__CYGWIN32__)
+#  include <arpa/inet.h>
+#  include <sys/un.h>
+#endif
+
+#ifndef AF_LOCAL
+#  define AF_LOCAL AF_UNIX
+#endif
+
+#if !defined(SHUT_RD)
+#  define SHUT_RD   0
+#endif
+#if !defined(SHUT_WR)
+#  define SHUT_WR   1
+#endif
+#if !defined(SHUT_RDWR)
+#  define SHUT_RDWR 2
+#endif
+
+// local common's
+
+#include "NGStreamExceptions.h"
+
+@interface NSObject(OSXHacks)
+- (void)subclassResponsibility:(SEL)_acmd;
+- (void)notImplemented:(SEL)_acmd;
+@end
+
+#endif /* __NGStreams_common_H__ */
diff --git a/skyrix-core/NGStreams/config.guess b/skyrix-core/NGStreams/config.guess
new file mode 100755 (executable)
index 0000000..378eab8
--- /dev/null
@@ -0,0 +1,1368 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+#   Free Software Foundation, Inc.
+
+timestamp='2001-03-30'
+
+# 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script.
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int dummy(){}" > $dummy.c
+       for c in cc gcc c89 ; do
+         ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1
+         if test $? = 0 ; then
+            CC_FOR_BUILD="$c"; break
+         fi
+       done
+       rm -f $dummy.c $dummy.o $dummy.rel
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # Netbsd (nbsd) targets should (where applicable) match one or
+       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       # Determine the machine/vendor (is the vendor relevant).
+       case "${UNAME_MACHINE}" in
+           amiga) machine=m68k-unknown ;;
+           arm32) machine=arm-unknown ;;
+           atari*) machine=m68k-atari ;;
+           sun3*) machine=m68k-sun ;;
+           mac68k) machine=m68k-apple ;;
+           macppc) machine=powerpc-apple ;;
+           hp3[0-9][05]) machine=m68k-hp ;;
+           ibmrt|romp-ibm) machine=romp-ibm ;;
+           *) machine=${UNAME_MACHINE}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE}" in
+           i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k)
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep __ELF__ >/dev/null
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # The OS release
+       release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit 0 ;;
+    alpha:OSF1:*:*)
+       if test $UNAME_RELEASE = "V4.0"; then
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+       fi
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       cat <<EOF >$dummy.s
+       .data
+\$Lformat:
+       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+
+       .text
+       .globl main
+       .align 4
+       .ent main
+main:
+       .frame \$30,16,\$26,0
+       ldgp \$29,0(\$27)
+       .prologue 1
+       .long 0x47e03d80 # implver \$0
+       lda \$2,-1
+       .long 0x47e20c21 # amask \$2,\$1
+       lda \$16,\$Lformat
+       mov \$0,\$17
+       not \$1,\$18
+       jsr \$26,printf
+       ldgp \$29,0(\$26)
+       mov 0,\$16
+       jsr \$26,exit
+       .end main
+EOF
+       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               case `./$dummy` in
+                       0-0)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       1-0)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       1-1)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       1-101)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       2-303)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       2-307)
+                               UNAME_MACHINE="alphaev67"
+                               ;;
+               esac
+       fi
+       rm -f $dummy.s $dummy
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit 0;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit 0 ;;
+    arc64:OpenBSD:*:*)
+       echo mips64el-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hkmips:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    pmax:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    sun3*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy \
+         && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i?86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+               rm -f $dummy.c $dummy
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:[45])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+              case "${HPUX_REV}" in
+                11.[0-9][0-9])
+                  if [ -x /usr/bin/getconf ]; then
+                    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+                        esac ;;
+                    esac
+                  fi ;;
+              esac
+              if [ "${HP_ARCH}" = "" ]; then
+              sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+       (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+       if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+       rm -f $dummy.c $dummy
+       fi ;;
+       esac
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    *9??*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i?86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    hppa*:OpenBSD:*:*)
+       echo hppa-unknown-openbsd
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:*:*:*)
+       echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3D:*:*:*)
+       echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY-2:*:*:*)
+       echo cray2-cray-unicos
+        exit 0 ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit 0 ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit 0 ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i386-pc-interix
+       exit 0 ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit 0 ;;
+    arm*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux
+       exit 0 ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    mips:Linux:*:*)
+       cat >$dummy.c <<EOF
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+int main (int argc, char *argv[]) {
+#else
+int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __MIPSEB__
+  printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+  printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       ;;
+    ppc:Linux:*:*)
+       # Determine Lib Version
+       cat >$dummy.c <<EOF
+#include <features.h>
+#if defined(__GLIBC__)
+extern char __libc_version[];
+extern char __libc_release[];
+#endif
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+#if defined(__GLIBC__)
+  printf("%s %s\n", __libc_version, __libc_release);
+#else
+  printf("unknown\n");
+#endif
+  return 0;
+}
+EOF
+       LIBC=""
+       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               ./$dummy | grep 1\.99 > /dev/null
+               if test "$?" = 0 ; then LIBC="libc1" ; fi
+       fi
+       rm -f $dummy.c $dummy
+       echo powerpc-unknown-linux-gnu${LIBC}
+       exit 0 ;;
+    alpha:Linux:*:*)
+       cat <<EOF >$dummy.s
+         .data
+         \$Lformat:
+               .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+          .text
+               .globl main
+               .align 4
+               .ent main
+           main:
+               .frame \$30,16,\$26,0
+               ldgp \$29,0(\$27)
+               .prologue 1
+               .long 0x47e03d80 # implver \$0
+               lda \$2,-1
+               .long 0x47e20c21 # amask \$2,\$1
+               lda \$16,\$Lformat
+               mov \$0,\$17
+               not \$1,\$18
+               jsr \$26,printf
+               ldgp \$29,0(\$26)
+               mov 0,\$16
+               jsr \$26,exit
+               .end main
+EOF
+       LIBC=""
+       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               case `./$dummy` in
+               0-0)    UNAME_MACHINE="alpha" ;;
+               1-0)    UNAME_MACHINE="alphaev5" ;;
+               1-1)    UNAME_MACHINE="alphaev56" ;;
+               1-101)  UNAME_MACHINE="alphapca56" ;;
+               2-303)  UNAME_MACHINE="alphaev6" ;;
+               2-307)  UNAME_MACHINE="alphaev67" ;;
+               esac
+               objdump --private-headers $dummy | \
+                 grep ld.so.1 > /dev/null
+               if test "$?" = 0 ; then
+                       LIBC="libc1"
+               fi
+       fi
+       rm -f $dummy.s $dummy
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit 0 ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-gnu ;;
+         PA8*) echo hppa2.0-unknown-linux-gnu ;;
+         *)    echo hppa-unknown-linux-gnu ;;
+       esac
+       exit 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux
+       exit 0 ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    x86_64:Linux:*:*)
+       echo x86_64-unknown-linux-gnu
+       exit 0 ;;
+    i?86:Linux:*:*)
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       ld_supported_emulations=`cd /; ld --help 2>&1 \
+                        | sed -ne '/supported emulations:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported emulations: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_emulations" in
+         i?86linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit 0
+               ;;
+         elf_i?86)
+               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+               ;;
+         i?86coff)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit 0
+               ;;
+       esac
+       # Either a pre-BFD a.out linker (linux-gnuoldld)
+       # or one that does not give us useful --help.
+       # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+       # If ld does not provide *any* "supported emulations:"
+       # that means it is gnuoldld.
+       test -z "$ld_supported_emulations" && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+       case "${UNAME_MACHINE}" in
+       i?86)
+         VENDOR=pc;
+         ;;
+       *)
+         VENDOR=unknown;
+         ;;
+       esac
+       # Determine whether the default compiler is a.out or elf
+       cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+#  if __GLIBC__ >= 2
+    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+#  else
+    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+#  endif
+# else
+   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+       ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i?86:DYNIX/ptx:4*:*)
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i?86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit 0 ;;
+    i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit 0 ;;
+    i?86:*:5:7*)
+        # Fixed at (any) Pentium or better
+        UNAME_MACHINE=i586
+        if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
+           echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
+       else
+           echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    i?86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    i?86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit 0 ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:* | i?86:LynxOS:4.0*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                           # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit 0 ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit 0 ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Darwin:*:*)
+       echo `uname -p`-apple-darwin${UNAME_RELEASE}
+       exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       if test "${UNAME_MACHINE}" = "x86pc"; then
+               UNAME_MACHINE=pc
+       fi
+       echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+       exit 0 ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit 0 ;;
+    NSR-[KW]:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit 0 ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit 0 ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit 0 ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit 0 ;;
+    i?86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit 0 ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit 0 ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit 0 ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit 0 ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/skyrix-core/NGStreams/config.h.in b/skyrix-core/NGStreams/config.h.in
new file mode 100644 (file)
index 0000000..7e88a57
--- /dev/null
@@ -0,0 +1,253 @@
+#ifndef __config_h__
+#define __config_h__
+
+/* Define if system calls automatically restart after interruption
+   by a signal.  */
+#undef HAVE_RESTARTABLE_SYSCALLS
+
+/* Define if you have the gethostbyname_r function. */
+#undef HAVE_GETHOSTBYNAME_R
+
+/* Define if you have the gethostbyaddr_r function. */
+#undef HAVE_GETHOSTBYADDR_R
+
+/* Define if you have the gethostent_r function. */
+#undef HAVE_GETHOSTENT_R
+
+/* Define if you have posix mmap function.  */
+#undef HAVE_MMAP
+
+/* Define if you have the getcwd function */
+#undef HAVE_GETCWD
+
+/* Define if you have the getuid function */
+#undef HAVE_GETUID
+
+/* Define if you have the getpwnam function */
+#undef HAVE_GETPWNAM
+
+/* Define if you have the getpwuid function */
+#undef HAVE_GETPWUID
+
+/* Define if you have the kill function */
+#undef HAVE_KILL
+
+/* Define if you have the statvfs function */
+#undef HAVE_STATVFS
+
+/* Define if you have the poll function */
+#undef HAVE_POLL
+
+/* Define if you have the chown function */
+#undef HAVE_CHOWN
+
+/* Define if you have the symlink function */
+#undef HAVE_SYMLINK
+
+/* Define if you have the readlink function */
+#undef HAVE_READLINK
+
+/* Define if you have the fsync function */
+#undef HAVE_FSYNC
+
+/* Define if you have the opendir family of functions */
+#undef HAVE_OPENDIR
+
+/* Define if you have the isatty function */
+#undef HAVE_ISATTY
+
+/* Define if you have the ttyname function */
+#undef HAVE_TTYNAME
+
+/* Define if you have the ttyname_r function */
+#undef HAVE_TTYNAME_R
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <strings.h> header file.  */
+#undef HAVE_STRINGS_H
+
+/* Define if you have the <memory.h> header file */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <stdlib.h> header file.  */
+#undef HAVE_STDLIB_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <libc.h> header file.  */
+#undef HAVE_LIBC_H
+
+/* Define if you have the <sys/stat.h> header file */
+#undef HAVE_SYS_STAT_H
+
+/* Define if you have the <sys/fcntl.h> header file */
+#undef HAVE_SYS_FCNTL_H
+
+/* Define if you have the <fcntl.h> header file */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <sys/vfs.h> header file */
+#undef HAVE_SYS_VFS_H
+
+/* Define if you have the <sys/statfs.h> header file */
+#undef HAVE_SYS_STATFS_H
+
+/* Define if you have the <sys/statvfs.h> header file */
+#undef HAVE_SYS_STATVFS_H
+
+/* Define if you have the <poll.h> header file */
+#undef HAVE_POLL_H
+
+/* Define if you have the <sys/poll.h> header file */
+#undef HAVE_SYS_POLL_H
+
+/* Define if you have the <sys/socket.h> header file */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define if you have the <unistd.h> header file */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the <sys/ioctl.h> header file */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define if you have the <sys/filio.h> header file */
+#undef HAVE_SYS_FILIO_H
+
+/* Define if you have the <netinet/in.h> header file */
+#undef HAVE_NETINET_IN_H
+
+/* Define if you have the <netdb.h> header file */
+#undef HAVE_NETDB_H
+
+/* Define if you have the <windows.h> header file */
+#undef HAVE_WINDOWS_H
+
+/* Define if you have the <winsock.h> header file */
+#undef HAVE_WINSOCK_H
+
+/* Define if you have the <Windows32/Sockets.h> header file */
+#undef HAVE_WINDOWS32_SOCKETS_H
+
+/* Define if you have the <pwd.h> header file */
+#undef HAVE_PWD_H
+
+/* Define if you have the <process.h> header file */
+#undef HAVE_PROCESS_H
+
+/* Define if you have the <grp.h> header file */
+#undef HAVE_GRP_H
+
+/* Define if you have the <sys/file.h> header file */
+#undef HAVE_SYS_FILE_H
+
+/* Define if you have the <sys/select.h> header file */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <time.h> header file */
+#undef HAVE_TIME_H
+
+/* Define if you have the <sys/time.h> header file */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/types.h> header file */
+#undef HAVE_SYS_TYPES_H
+
+/* Define if you have the <utime.h> header file */
+#undef HAVE_UTIME_H
+
+/* Define if you have the <sys/errno.h> header file */
+#undef HAVE_SYS_ERRNO_H
+
+/* Define if sys/wait.h is POSIX compatible */
+#undef HAVE_SYS_WAIT_H
+
+/* Define this if you have the <vfork.h> header file */
+#undef HAVE_VFORK_H
+
+/* Define for vfork in case it's not defined */
+#undef vfork
+
+/* Define for pid_t in case it's not defined */
+#undef pid_t
+
+/* The following macros deal with directory entries. */
+#undef HAVE_DIRENT_H
+#undef HAVE_SYS_NDIR_H
+#undef HAVE_SYS_DIR_H
+#undef HAVE_NDIR_H
+#undef HAVE_DIR_H
+
+/* The structure alignment as determined by configure */
+#define STRUCT_ALIGNMENT @STRUCT_ALIGNMENT@
+
+/* The name of the target platform, obtained by configure */
+#define TARGET_PLATFORM                "@host@"
+
+/* define POLL constants */
+
+#if HAVE_POLL_H
+#  include <poll.h>
+#endif
+#if HAVE_SYS_POLL_H
+#  include <sys/poll.h>
+#endif
+
+#ifndef POLLIN
+# ifdef HAVE_POLL
+#  warning "manually declared POLLIN=1 .."
+# endif
+#  define POLLIN     1
+#endif
+#ifndef POLLOUT
+# ifdef HAVE_POLL
+#  warning "manually declared POLLOUT=2 .."
+# endif
+#  define POLLOUT    2
+#endif
+#ifndef POLLERR
+# ifdef HAVE_POLL
+#  warning "manually declared POLLERR=4 .."
+# endif
+#  define POLLERR    4
+#endif
+
+#ifndef POLLRDNORM
+#  ifdef linux
+#    define POLLRDNORM POLLIN
+#  else /* !linux */
+#    ifdef POLLIN
+#     ifdef HAVE_POLL
+#      warning "manually declared POLLRDNORM=POLLIN .."
+#     endif
+#      define POLLRDNORM POLLIN
+#    else
+#     ifdef HAVE_POLL
+#      warning "manually declared POLLRDNORM .."
+#     endif
+#      define POLLRDNORM 1
+#    endif
+#  endif /* !linux */
+#endif
+
+#ifndef POLLWRNORM
+#  ifdef linux
+#    define POLLWRNORM POLLOUT
+#  else /* !linux */
+#    ifdef POLLOUT
+#     ifdef HAVE_POLL
+#      warning "manually declared POLLWRNORM=POLLOUT .."
+#     endif
+#      define POLLWRNORM POLLOUT
+#    else
+#     ifdef HAVE_POLL
+#      warning "manually declared POLLWRNORM .."
+#     endif
+#      define POLLWRNORM 2
+#    endif
+#  endif /* !linux */
+#endif
+
+#endif /* __config_h__ */
diff --git a/skyrix-core/NGStreams/config.sub b/skyrix-core/NGStreams/config.sub
new file mode 100755 (executable)
index 0000000..4ac0c8b
--- /dev/null
@@ -0,0 +1,1360 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+#   Free Software Foundation, Inc.
+
+timestamp='2001-03-30'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | storm-chaos* | os2-emx*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis)
+               os=
+               basic_machine=$1
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc \
+               | arm | arme[lb] | arm[bl]e | armv[2345] | armv[345][lb] | strongarm | xscale \
+               | pyramid | mn10200 | mn10300 | tron | a29k \
+               | 580 | i960 | h8300 \
+               | x86 | ppcbe | mipsbe | mipsle | shbe | shle \
+               | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+               | hppa64 \
+               | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
+               | alphaev6[78] \
+               | we32k | ns16k | clipper | i370 | sh | sh[34] \
+               | powerpc | powerpcle \
+               | 1750a | dsp16xx | pdp10 | pdp11 \
+               | mips16 | mips64 | mipsel | mips64el \
+               | mips64orion | mips64orionel | mipstx39 | mipstx39el \
+               | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
+               | mips64vr5000 | miprs64vr5000el | mcore | s390 | s390x \
+               | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
+               | thumb | d10v | d30v | fr30 | avr | openrisc | tic80 \
+               | pj | pjl | h8500)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12)
+               # Motorola 68HC11/12.
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | w65)
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i[234567]86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       # FIXME: clean up the formatting here.
+       vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
+             | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | c[123]* \
+             | arm-*  | armbe-* | armle-* | armv*-* | strongarm-* | xscale-* \
+             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+             | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
+             | xmp-* | ymp-* \
+             | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* \
+             | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
+             | hppa2.0n-* | hppa64-* \
+             | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
+             | alphaev6[78]-* \
+             | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
+             | clipper-* | orion-* \
+             | sparclite-* | pdp10-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+             | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
+             | mips64el-* | mips64orion-* | mips64orionel-* \
+             | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
+             | mipstx39-* | mipstx39el-* | mcore-* \
+             | f30[01]-* | f700-* | s390-* | s390x-* | sv1-* | t3e-* \
+             | [cjt]90-* \
+             | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
+             | thumb-* | v850-* | d30v-* | tic30-* | tic80-* | c30-* | fr30-* \
+             | bs2000-* | tic54x-* | c54x-* | x86_64-* | pj-* | pjl-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       cray2)
+               basic_machine=cray2-cray
+               os=-unicos
+               ;;
+       [cjt]90)
+               basic_machine=${basic_machine}-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i[34567]86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i[34567]86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i[34567]86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i[34567]86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       mingw32)
+               basic_machine=i386-pc
+               os=-mingw32
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mipsel*-linux*)
+               basic_machine=mipsel-unknown
+               os=-linux-gnu
+               ;;
+       mips*-linux*)
+               basic_machine=mips-unknown
+               os=-linux-gnu
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       mmix*)
+               basic_machine=mmix-knuth
+               os=-mmixware
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+        pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5 | k5 | k6 | nexgen)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2)
+               basic_machine=i686-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sparclite-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=t3e-cray
+               os=-unicos
+               ;;
+       tic54x | c54x*)
+               basic_machine=tic54x-unknown
+               os=-coff
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xmp)
+               basic_machine=xmp-cray
+               os=-unicos
+               ;;
+        xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       mips)
+               if [ x$os = x-linux-gnu ]; then
+                       basic_machine=mips-unknown
+               else
+                       basic_machine=mips-mips
+               fi
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh3 | sh4)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv9)
+               basic_machine=sparc-sun
+               ;;
+        cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       c4x*)
+               basic_machine=c4x-none
+               os=-coff
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -os2*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i[34567]86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto*)
+               os=-nto-qnx
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+        -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+       pdp10-*)
+               os=-tops20
+               ;;
+        pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+        *-gould)
+               os=-sysv
+               ;;
+        *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+        *-sgi)
+               os=-irix
+               ;;
+        *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/skyrix-core/NGStreams/configure b/skyrix-core/NGStreams/configure
new file mode 100755 (executable)
index 0000000..454727c
--- /dev/null
@@ -0,0 +1,2502 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_default_prefix=/usr/local
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=NGStream.m
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+# Determine the host, build, and target systems
+CC_TARGET=$target # use --target value for CC, not the canonical form
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Do some error checking and defaulting for the host and target type.
+# The inputs are:
+#    configure --host=HOST --target=TARGET --build=BUILD NONOPT
+#
+# The rules are:
+# 1. You are not allowed to specify --host, --target, and nonopt at the
+#    same time.
+# 2. Host defaults to nonopt.
+# 3. If nonopt is not specified, then host defaults to the current host,
+#    as determined by config.guess.
+# 4. Target and build default to nonopt.
+# 5. If nonopt is not specified, then target and build default to host.
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+case $host---$target---$nonopt in
+NONE---*---* | *---NONE---* | *---*---NONE) ;;
+*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
+esac
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:576: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+  case $nonopt in
+  NONE)
+    if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+    else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+    fi ;;
+  *) host_alias=$nonopt ;;
+  esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+echo "configure:597: checking target system type" >&5
+
+target_alias=$target
+case "$target_alias" in
+NONE)
+  case $nonopt in
+  NONE) target_alias=$host_alias ;;
+  *) target_alias=$nonopt ;;
+  esac ;;
+esac
+
+target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
+target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$target" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:615: checking build system type" >&5
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+  case $nonopt in
+  NONE) build_alias=$host_alias ;;
+  *) build_alias=$nonopt ;;
+  esac ;;
+esac
+
+build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+test "$host_alias" != "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+
+
+
+
+
+# check for cross compilation
+
+if test "x$target" = "xNONE"; then
+  set target $host
+fi
+
+if test "x$host" != "x$target"; then
+       cross_defines="CROSS=-DCROSS_COMPILE"
+        cross_compiling="yes"
+        echo "cross compiling from $host to $target .."
+# Extract the first word of ""${CC_TARGET}-gcc"", so it can be a program name with args.
+set dummy "${CC_TARGET}-gcc"; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:654: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC=""${CC_TARGET}-gcc""
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="gcc"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of ""${CC_TARGET}-ranlib"", so it can be a program name with args.
+set dummy "${CC_TARGET}-ranlib"; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:684: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB=""${CC_TARGET}-ranlib""
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB="ranlib"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of ""${CC_TARGET}-ar"", so it can be a program name with args.
+set dummy "${CC_TARGET}-ar"; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:714: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_AR=""${CC_TARGET}-ar""
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar"
+fi
+fi
+AR="$ac_cv_prog_AR"
+if test -n "$AR"; then
+  echo "$ac_t""$AR" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of ""${CC_TARGET}-dlltool"", so it can be a program name with args.
+set dummy "${CC_TARGET}-dlltool"; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:744: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_DLLTOOL=""${CC_TARGET}-dlltool""
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_DLLTOOL" && ac_cv_prog_DLLTOOL="dlltool"
+fi
+fi
+DLLTOOL="$ac_cv_prog_DLLTOOL"
+if test -n "$DLLTOOL"; then
+  echo "$ac_t""$DLLTOOL" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+        CC=${CC_TARGET}-gcc
+        LD=${CC_TARGET}-ld
+        AR=${CC_TARGET}-ar
+        RANLIB=${CC_TARGET}-ranlib
+else
+# Extract the first word of ""gcc"", so it can be a program name with args.
+set dummy "gcc"; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:779: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC=""gcc""
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="gcc"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of ""ranlib"", so it can be a program name with args.
+set dummy "ranlib"; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:809: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB=""ranlib""
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB="ranlib"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of ""ar"", so it can be a program name with args.
+set dummy "ar"; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:839: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_AR=""ar""
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar"
+fi
+fi
+AR="$ac_cv_prog_AR"
+if test -n "$AR"; then
+  echo "$ac_t""$AR" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of ""dlltool"", so it can be a program name with args.
+set dummy "dlltool"; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:869: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_DLLTOOL=""dlltool""
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_DLLTOOL" && ac_cv_prog_DLLTOOL="dlltool"
+fi
+fi
+DLLTOOL="$ac_cv_prog_DLLTOOL"
+if test -n "$DLLTOOL"; then
+  echo "$ac_t""$DLLTOOL" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+case "${host_cpu}" in
+    i[45]86*)  host_cpu=i386;;
+    hppa1.1)   host_cpu=hppa;;
+esac
+if test "x$cross_compiling" = "xyes"; then
+  case "${target_cpu}" in
+    i[45]86*)  target_cpu=i386;;
+    hppa1.1)   target_cpu=hppa;;
+  esac
+else
+  target_cpu=${host_cpu}
+  target_os=${host_os}
+  target_vendor=${host_vendor}
+fi
+case "x${target_os}" in
+  xfreebsd*) target_os=freebsd;;
+esac
+
+# Assign the HOST variables for sharedlib.mak
+HOST=$host
+HOST_CPU=$host_cpu
+HOST_VENDOR=$host_vendor
+HOST_OS=$host_os
+TARGET=$target
+TARGET_CPU=$target_cpu
+TARGET_VENDOR=$target_vendor
+TARGET_OS=$target_os
+
+echo $ac_n "checking for chown in -lnsl""... $ac_c" 1>&6
+echo "configure:927: checking for chown in -lnsl" >&5
+ac_lib_var=`echo nsl'_'chown | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lnsl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 935 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char chown();
+
+int main() {
+chown()
+; return 0; }
+EOF
+if { (eval echo configure:946: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lnsl $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for accept in -lsocket""... $ac_c" 1>&6
+echo "configure:974: checking for accept in -lsocket" >&5
+ac_lib_var=`echo socket'_'accept | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 982 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char accept();
+
+int main() {
+accept()
+; return 0; }
+EOF
+if { (eval echo configure:993: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for  in -lwsock32""... $ac_c" 1>&6
+echo "configure:1021: checking for  in -lwsock32" >&5
+ac_lib_var=`echo wsock32'_' | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lwsock32  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1029 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char ();
+
+int main() {
+()
+; return 0; }
+EOF
+if { (eval echo configure:1040: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo wsock32 | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lwsock32 $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for  in -ladvapi32""... $ac_c" 1>&6
+echo "configure:1068: checking for  in -ladvapi32" >&5
+ac_lib_var=`echo advapi32'_' | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ladvapi32  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1076 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char ();
+
+int main() {
+()
+; return 0; }
+EOF
+if { (eval echo configure:1087: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo advapi32 | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-ladvapi32 $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+transformed_target_cpu=`${GNUSTEP_MAKEFILES}/clean_cpu.sh ${TARGET_CPU}`
+ac_cv_file_output_prefix=${transformed_target_cpu}/${TARGET_OS}
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1123: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1128 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1136: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1161: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1169 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1180: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1202: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1210 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1221: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1244: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1259 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1265: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1276 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1282: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1293 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1299: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+for ac_hdr in dir.h libc.h time.h stdlib.h memory.h string.h           strings.h sys/stat.h sys/fcntl.h fcntl.h                 sys/vfs.h sys/statfs.h sys/statvfs.h           netinet/in.h windows.h winsock.h sys/socket.h           Windows32/Sockets.h pwd.h process.h grp.h sys/param.h           sys/file.h sys/errno.h sys/select.h sys/poll.h poll.h                 sys/time.h sys/types.h                 sys/ioctl.h sys/filio.h                 netdb.h unistd.h unistd.h limits.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1327: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1332 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1337: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:1364: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1369 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:1385: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_sys_wait_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+
+for ac_func in memcpy getcwd kill poll isatty ttyname ttyname_r                gethostbyname_r gethostbyaddr_r gethostent_r
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1409: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1414 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1437: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1465: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1470 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1475: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in getpagesize
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1504: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1509 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1532: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking for working mmap""... $ac_c" 1>&6
+echo "configure:1557: checking for working mmap" >&5
+if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_func_mmap_fixed_mapped=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1565 "configure"
+#include "confdefs.h"
+
+/* Thanks to Mike Haertel and Jim Avera for this test.
+   Here is a matrix of mmap possibilities:
+       mmap private not fixed
+       mmap private fixed at somewhere currently unmapped
+       mmap private fixed at somewhere already mapped
+       mmap shared not fixed
+       mmap shared fixed at somewhere currently unmapped
+       mmap shared fixed at somewhere already mapped
+   For private mappings, we should verify that changes cannot be read()
+   back from the file, nor mmap's back from the file at a different
+   address.  (There have been systems where private was not correctly
+   implemented like the infamous i386 svr4.0, and systems where the
+   VM page cache was not coherent with the filesystem buffer cache
+   like early versions of FreeBSD and possibly contemporary NetBSD.)
+   For shared mappings, we should conversely verify that changes get
+   propogated back to all the places they're supposed to be.
+
+   Grep wants private fixed already mapped.
+   The main things grep needs to know about mmap are:
+   * does it exist and is it safe to write into the mmap'd area
+   * how to use it (BSD variants)  */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+/* This mess was copied from the GNU getpagesize.h.  */
+#ifndef HAVE_GETPAGESIZE
+# ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+# endif
+
+/* Assume that all systems that can run configure have sys/param.h.  */
+# ifndef HAVE_SYS_PARAM_H
+#  define HAVE_SYS_PARAM_H 1
+# endif
+
+# ifdef _SC_PAGESIZE
+#  define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+#  ifdef HAVE_SYS_PARAM_H
+#   include <sys/param.h>
+#   ifdef EXEC_PAGESIZE
+#    define getpagesize() EXEC_PAGESIZE
+#   else /* no EXEC_PAGESIZE */
+#    ifdef NBPG
+#     define getpagesize() NBPG * CLSIZE
+#     ifndef CLSIZE
+#      define CLSIZE 1
+#     endif /* no CLSIZE */
+#    else /* no NBPG */
+#     ifdef NBPC
+#      define getpagesize() NBPC
+#     else /* no NBPC */
+#      ifdef PAGESIZE
+#       define getpagesize() PAGESIZE
+#      endif /* PAGESIZE */
+#     endif /* no NBPC */
+#    endif /* no NBPG */
+#   endif /* no EXEC_PAGESIZE */
+#  else /* no HAVE_SYS_PARAM_H */
+#   define getpagesize() 8192  /* punt totally */
+#  endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
+
+#endif /* no HAVE_GETPAGESIZE */
+
+#ifdef __cplusplus
+extern "C" { void *malloc(unsigned); }
+#else
+char *malloc();
+#endif
+
+int
+main()
+{
+       char *data, *data2, *data3;
+       int i, pagesize;
+       int fd;
+
+       pagesize = getpagesize();
+
+       /*
+        * First, make a file with some known garbage in it.
+        */
+       data = malloc(pagesize);
+       if (!data)
+               exit(1);
+       for (i = 0; i < pagesize; ++i)
+               *(data + i) = rand();
+       umask(0);
+       fd = creat("conftestmmap", 0600);
+       if (fd < 0)
+               exit(1);
+       if (write(fd, data, pagesize) != pagesize)
+               exit(1);
+       close(fd);
+
+       /*
+        * Next, try to mmap the file at a fixed address which
+        * already has something else allocated at it.  If we can,
+        * also make sure that we see the same garbage.
+        */
+       fd = open("conftestmmap", O_RDWR);
+       if (fd < 0)
+               exit(1);
+       data2 = malloc(2 * pagesize);
+       if (!data2)
+               exit(1);
+       data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1);
+       if (data2 != mmap(data2, pagesize, PROT_READ | PROT_WRITE,
+           MAP_PRIVATE | MAP_FIXED, fd, 0L))
+               exit(1);
+       for (i = 0; i < pagesize; ++i)
+               if (*(data + i) != *(data2 + i))
+                       exit(1);
+
+       /*
+        * Finally, make sure that changes to the mapped area
+        * do not percolate back to the file as seen by read().
+        * (This is a bug on some variants of i386 svr4.0.)
+        */
+       for (i = 0; i < pagesize; ++i)
+               *(data2 + i) = *(data2 + i) + 1;
+       data3 = malloc(pagesize);
+       if (!data3)
+               exit(1);
+       if (read(fd, data3, pagesize) != pagesize)
+               exit(1);
+       for (i = 0; i < pagesize; ++i)
+               if (*(data + i) != *(data3 + i))
+                       exit(1);
+       close(fd);
+       unlink("conftestmmap");
+       exit(0);
+}
+
+EOF
+if { (eval echo configure:1705: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_mmap_fixed_mapped=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_mmap_fixed_mapped=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_mmap_fixed_mapped" 1>&6
+if test $ac_cv_func_mmap_fixed_mapped = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_MMAP 1
+EOF
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1728: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1733 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1741: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1758 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1776 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1797 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1808: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:1832: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1837 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_pid_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+  cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+ac_safe=`echo "vfork.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for vfork.h""... $ac_c" 1>&6
+echo "configure:1866: checking for vfork.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1871 "configure"
+#include "confdefs.h"
+#include <vfork.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1876: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VFORK_H 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for working vfork""... $ac_c" 1>&6
+echo "configure:1901: checking for working vfork" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vfork_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  echo $ac_n "checking for vfork""... $ac_c" 1>&6
+echo "configure:1907: checking for vfork" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1912 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vfork(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vfork();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vfork) || defined (__stub___vfork)
+choke me
+#else
+vfork();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_vfork=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vfork=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vfork`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+ac_cv_func_vfork_works=$ac_cv_func_vfork
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1957 "configure"
+#include "confdefs.h"
+/* Thanks to Paul Eggert for this test.  */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+/* On some sparc systems, changes by the child to local and incoming
+   argument registers are propagated back to the parent.
+   The compiler is told about this with #include <vfork.h>,
+   but some compilers (e.g. gcc -O) don't grok <vfork.h>.
+   Test for this by using a static variable whose address
+   is put into a register that is clobbered by the vfork.  */
+static
+#ifdef __cplusplus
+sparc_address_test (int arg)
+#else
+sparc_address_test (arg) int arg;
+#endif
+{
+  static pid_t child;
+  if (!child) {
+    child = vfork ();
+    if (child < 0) {
+      perror ("vfork");
+      _exit(2);
+    }
+    if (!child) {
+      arg = getpid();
+      write(-1, "", 0);
+      _exit (arg);
+    }
+  }
+}
+main() {
+  pid_t parent = getpid ();
+  pid_t child;
+
+  sparc_address_test ();
+
+  child = vfork ();
+
+  if (child == 0) {
+    /* Here is another test for sparc vfork register problems.
+       This test uses lots of local variables, at least
+       as many local variables as main has allocated so far
+       including compiler temporaries.  4 locals are enough for
+       gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe.
+       A buggy compiler should reuse the register of parent
+       for one of the local variables, since it will think that
+       parent can't possibly be used any more in this routine.
+       Assigning to the local variable will thus munge parent
+       in the parent process.  */
+    pid_t
+      p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(),
+      p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid();
+    /* Convince the compiler that p..p7 are live; otherwise, it might
+       use the same hardware register for all 8 local variables.  */
+    if (p != p1 || p != p2 || p != p3 || p != p4
+       || p != p5 || p != p6 || p != p7)
+      _exit(1);
+
+    /* On some systems (e.g. IRIX 3.3),
+       vfork doesn't separate parent from child file descriptors.
+       If the child closes a descriptor before it execs or exits,
+       this munges the parent's descriptor as well.
+       Test for this by closing stdout in the child.  */
+    _exit(close(fileno(stdout)) != 0);
+  } else {
+    int status;
+    struct stat st;
+
+    while (wait(&status) != child)
+      ;
+    exit(
+        /* Was there some problem with vforking?  */
+        child < 0
+
+        /* Did the child fail?  (This shouldn't happen.)  */
+        || status
+
+        /* Did the vfork/compiler bug occur?  */
+        || parent != getpid()
+
+        /* Did the file descriptor bug occur?  */
+        || fstat(fileno(stdout), &st) != 0
+        );
+  }
+}
+EOF
+if { (eval echo configure:2052: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_vfork_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_vfork_works=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_vfork_works" 1>&6
+if test $ac_cv_func_vfork_works = no; then
+  cat >> confdefs.h <<\EOF
+#define vfork fork
+EOF
+
+fi
+
+
+# uses AC_TRY_RUN
+if test "$cross_compiling" = yes; then
+echo "WARNING: cannot check for restartable system calls during cross compilation."
+else
+echo $ac_n "checking for restartable system calls""... $ac_c" 1>&6
+echo "configure:2080: checking for restartable system calls" >&5
+if eval "test \"`echo '$''{'ac_cv_sys_restartable_syscalls'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2088 "configure"
+#include "confdefs.h"
+/* Exit 0 (true) if wait returns something other than -1,
+   i.e. the pid of the child, which means that wait was restarted
+   after getting the signal.  */
+#include <sys/types.h>
+#include <signal.h>
+ucatch (isig) { }
+main () {
+  int i = fork (), status;
+  if (i == 0) { sleep (3); kill (getppid (), SIGINT); sleep (3); exit (0); }
+  signal (SIGINT, ucatch);
+  status = wait(&i);
+  if (status == -1) wait(&i);
+  exit (status == -1);
+}
+
+EOF
+if { (eval echo configure:2106: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sys_restartable_syscalls=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sys_restartable_syscalls=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_sys_restartable_syscalls" 1>&6
+if test $ac_cv_sys_restartable_syscalls = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_RESTARTABLE_SYSCALLS 1
+EOF
+
+fi
+
+fi
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[        ]*VPATH[        ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo " config.h:config.h.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@CC@%$CC%g
+s%@RANLIB@%$RANLIB%g
+s%@AR@%$AR%g
+s%@DLLTOOL@%$DLLTOOL%g
+s%@CPP@%$CPP%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-""}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([  ]*\)#\([        ]*define[       ][      ]*\)'
+ac_dB='\([     ][      ]*\)[^  ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_uB='\([     ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h:config.h.in"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[   ]*#[    ]*undef[        ][      ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+. ./config.cache
+
+if test ! -d ${ac_cv_file_output_prefix}; then
+  ${GNUSTEP_MAKEFILES}/mkinstalldirs ${ac_cv_file_output_prefix}
+fi
+cp config.h ${ac_cv_file_output_prefix}
+rm -f config.h
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/skyrix-core/NGStreams/configure.in b/skyrix-core/NGStreams/configure.in
new file mode 100644 (file)
index 0000000..98dddf4
--- /dev/null
@@ -0,0 +1,108 @@
+AC_PREREQ(2.4)
+
+AC_INIT(NGStream.m)
+
+# Determine the host, build, and target systems
+CC_TARGET=$target # use --target value for CC, not the canonical form
+AC_CANONICAL_SYSTEM
+
+AC_CONFIG_HEADER(config.h:config.h.in)
+AC_PREFIX_DEFAULT(/usr/local)
+
+# check for cross compilation
+
+if test "x$target" = "xNONE"; then
+  set target $host
+fi
+
+if test "x$host" != "x$target"; then
+       cross_defines="CROSS=-DCROSS_COMPILE"
+        cross_compiling="yes"
+        echo "cross compiling from $host to $target .."
+AC_CHECK_PROG(CC,      "${CC_TARGET}-gcc",     "${CC_TARGET}-gcc",     gcc)
+AC_CHECK_PROG(RANLIB,  "${CC_TARGET}-ranlib",  "${CC_TARGET}-ranlib",  ranlib)
+AC_CHECK_PROG(AR,      "${CC_TARGET}-ar",      "${CC_TARGET}-ar",      ar)
+AC_CHECK_PROG(DLLTOOL, "${CC_TARGET}-dlltool", "${CC_TARGET}-dlltool", dlltool)
+        CC=${CC_TARGET}-gcc
+        LD=${CC_TARGET}-ld
+        AR=${CC_TARGET}-ar
+        RANLIB=${CC_TARGET}-ranlib
+else
+AC_CHECK_PROG(CC,      "gcc",     "gcc",     gcc)
+AC_CHECK_PROG(RANLIB,  "ranlib",  "ranlib",  ranlib)
+AC_CHECK_PROG(AR,      "ar",      "ar",      ar)
+AC_CHECK_PROG(DLLTOOL, "dlltool", "dlltool", dlltool)
+fi
+
+changequote(,)dnl
+case "${host_cpu}" in
+    i[45]86*)  host_cpu=i386;;
+    hppa1.1)   host_cpu=hppa;;
+esac
+if test "x$cross_compiling" = "xyes"; then
+  case "${target_cpu}" in
+    i[45]86*)  target_cpu=i386;;
+    hppa1.1)   target_cpu=hppa;;
+  esac
+else
+  target_cpu=${host_cpu}
+  target_os=${host_os}
+  target_vendor=${host_vendor}
+fi
+case "x${target_os}" in
+  xfreebsd*) target_os=freebsd;;
+esac
+changequote([,])dnl
+
+# Assign the HOST variables for sharedlib.mak
+HOST=$host
+HOST_CPU=$host_cpu
+HOST_VENDOR=$host_vendor
+HOST_OS=$host_os
+TARGET=$target
+TARGET_CPU=$target_cpu
+TARGET_VENDOR=$target_vendor
+TARGET_OS=$target_os
+
+AC_CHECK_LIB(nsl, chown)
+AC_CHECK_LIB(socket, accept)
+AC_CHECK_LIB(wsock32)
+AC_CHECK_LIB(advapi32)
+
+transformed_target_cpu=`${GNUSTEP_MAKEFILES}/clean_cpu.sh ${TARGET_CPU}`
+ac_cv_file_output_prefix=${transformed_target_cpu}/${TARGET_OS}
+
+AC_HEADER_DIRENT
+AC_HAVE_HEADERS(dir.h libc.h time.h stdlib.h memory.h string.h dnl
+               strings.h sys/stat.h sys/fcntl.h fcntl.h dnl
+                sys/vfs.h sys/statfs.h sys/statvfs.h dnl
+               netinet/in.h windows.h winsock.h sys/socket.h dnl
+               Windows32/Sockets.h pwd.h process.h grp.h sys/param.h dnl
+               sys/file.h sys/errno.h sys/select.h sys/poll.h poll.h dnl
+                sys/time.h sys/types.h dnl
+                sys/ioctl.h sys/filio.h dnl
+                netdb.h unistd.h unistd.h limits.h)
+AC_HEADER_SYS_WAIT
+
+AC_CHECK_FUNCS(memcpy getcwd kill poll isatty ttyname ttyname_r dnl
+               gethostbyname_r gethostbyaddr_r gethostent_r)
+AC_FUNC_MMAP
+AC_FUNC_VFORK
+
+# uses AC_TRY_RUN
+if test "$cross_compiling" = yes; then
+echo "WARNING: cannot check for restartable system calls during cross compilation."
+else
+AC_SYS_RESTARTABLE_SYSCALLS
+fi
+
+AC_OUTPUT(,
+[
+. ./config.cache
+
+if test ! -d ${ac_cv_file_output_prefix}; then
+  ${GNUSTEP_MAKEFILES}/mkinstalldirs ${ac_cv_file_output_prefix}
+fi
+cp config.h ${ac_cv_file_output_prefix}
+rm -f config.h
+])
diff --git a/skyrix-core/NGStreams/install-sh b/skyrix-core/NGStreams/install-sh
new file mode 100755 (executable)
index 0000000..5871924
--- /dev/null
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       true
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+       else
+               instcmd=mkdir
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               true
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               true
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               true
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               true
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               true
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/skyrix-core/NGStreams/libNGStreams.def b/skyrix-core/NGStreams/libNGStreams.def
new file mode 100644 (file)
index 0000000..36f9d5a
--- /dev/null
@@ -0,0 +1,67 @@
+EXPORTS
+       NGPollDescriptor;
+       NGGetDescriptorFlags;
+       NGSetDescriptorFlags;
+       NGAddDescriptorFlag;
+       NGDescriptorSend;
+       NGDescriptorRecv;
+       NGDescriptorIsAtty;
+       NGDescriptorGetTtyName;
+       __objc_class_name_NGBase64Stream;
+       __objc_class_name_NGBufferedStream;
+       __objc_class_name_NGByteBuffer;
+       __objc_class_name_NGByteCountStream;
+       __objc_class_name_NGCTextStream;
+       __objc_class_name_NGCharBuffer;
+       __objc_class_name_NGConcreteStreamFileHandle;
+       __objc_class_name_NGCouldNotCloseStreamException;
+       __objc_class_name_NGCouldNotOpenStreamException;
+       __objc_class_name_NGDataStream;
+       __objc_class_name_NGEndOfStreamException;
+       __objc_class_name_NGFileStream;
+       __objc_class_name_NGFilterStream;
+       __objc_class_name_NGFilterTextStream;
+       __objc_class_name_NGIOAccessException;
+       __objc_class_name_NGIOException;
+       __objc_class_name_NGIOSearchAccessException;
+       __objc_class_name_NGLockingStream;
+       __objc_class_name_NGReadOnlyStreamException;
+       __objc_class_name_NGStream;
+       __objc_class_name_NGStreamCoder;
+       __objc_class_name_NGStreamErrorException;
+       __objc_class_name_NGStreamException;
+       __objc_class_name_NGStreamModeException;
+       __objc_class_name_NGStreamNotOpenException;
+       __objc_class_name_NGStreamPipe;
+       __objc_class_name_NGStreamPipe;
+       __objc_class_name_NGStreamReadErrorException;
+       __objc_class_name_NGStreamSeekErrorException;
+       __objc_class_name_NGStreamWriteErrorException;
+       __objc_class_name_NGStreams;
+       __objc_class_name_NGStringTextStream;
+       __objc_class_name_NGTextStream;
+       __objc_class_name_NGUnknownStreamModeException;
+       __objc_class_name_NGWriteOnlyStreamException;
+       __objc_class_name__NGCTextStreamLineEnumerator;
+       __objc_class_name__NGConcreteFileStreamFileHandle;
+       NGStreamSerializeObjC
+       NGStreamDeserializeObjC
+       NGReadByteFromStream
+       NGSafeReadBytesFromStream
+       NGSafeWriteBytesToStream
+       NGFileReadOnly
+       NGFileWriteOnly
+       NGFileReadWrite
+       NGFileAppend
+       NGFileReadAppend
+       NGIn
+       NGOut
+       NGErr
+       NGTextIn
+       NGTextOut
+       NGTextErr
+       NGInitStdio
+       NGInitTextStdio
+
+;__objc_class_name__NGConcretePipeFileHandle;
+;__objc_class_name_NGTaskStream;
diff --git a/skyrix-core/NGStreams/macosx/config.h b/skyrix-core/NGStreams/macosx/config.h
new file mode 100644 (file)
index 0000000..4ad6ec4
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+#ifndef __config_h__
+#define __config_h__
+
+/* Define if system calls automatically restart after interruption
+   by a signal.  */
+#undef HAVE_RESTARTABLE_SYSCALLS
+
+/* Define if you have the gethostbyname_r function. */
+#undef HAVE_GETHOSTBYNAME_R
+
+/* Define if you have the gethostbyaddr_r function. */
+#undef HAVE_GETHOSTBYADDR_R
+
+/* Define if you have the gethostent_r function. */
+#undef HAVE_GETHOSTENT_R
+
+/* Define if you have posix mmap function.  */
+#define HAVE_MMAP 1
+
+/* Define if you have the getcwd function */
+#define HAVE_GETCWD 1
+
+/* Define if you have the getuid function */
+#define HAVE_GETUID 1
+
+/* Define if you have the getpwnam function */
+#undef HAVE_GETPWNAM
+
+/* Define if you have the getpwuid function */
+#undef HAVE_GETPWUID
+
+/* Define if you have the kill function */
+#undef HAVE_KILL
+
+/* Define if you have the statvfs function */
+#undef HAVE_STATVFS
+
+/* Define if you have the poll function */
+//#define HAVE_POLL 1
+
+/* Define if you have the chown function */
+#define HAVE_CHOWN 1
+
+/* Define if you have the symlink function */
+#define HAVE_SYMLINK 1
+
+/* Define if you have the readlink function */
+#define HAVE_READLINK 1
+
+/* Define if you have the fsync function */
+#define HAVE_FSYNC 1
+
+/* Define if you have the opendir family of functions */
+#undef HAVE_OPENDIR
+
+/* Define if you have the isatty function */
+#define HAVE_ISATTY 1
+
+/* Define if you have the ttyname function */
+#define HAVE_TTYNAME 1
+
+/* Define if you have the ttyname_r function */
+#undef HAVE_TTYNAME_R
+
+/* Define if you have the <string.h> header file.  */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <strings.h> header file.  */
+#define HAVE_STRINGS_H 1
+
+/* Define if you have the <memory.h> header file */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <stdlib.h> header file.  */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <limits.h> header file.  */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <libc.h> header file.  */
+#define HAVE_LIBC_H 1
+
+/* Define if you have the <sys/stat.h> header file */
+#define HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/fcntl.h> header file */
+#define HAVE_SYS_FCNTL_H 1
+
+/* Define if you have the <fcntl.h> header file */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <sys/vfs.h> header file */
+#undef HAVE_SYS_VFS_H
+
+/* Define if you have the <sys/statfs.h> header file */
+#undef HAVE_SYS_STATFS_H
+
+/* Define if you have the <sys/statvfs.h> header file */
+#undef HAVE_SYS_STATVFS_H
+
+/* Define if you have the <poll.h> header file */
+#undef HAVE_POLL_H
+
+/* Define if you have the <sys/poll.h> header file */
+#undef HAVE_SYS_POLL_H
+
+/* Define if you have the <sys/socket.h> header file */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define if you have the <unistd.h> header file */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <sys/ioctl.h> header file */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define if you have the <sys/filio.h> header file */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define if you have the <netinet/in.h> header file */
+#define HAVE_NETINET_IN_H 1
+
+/* Define if you have the <netdb.h> header file */
+#define HAVE_NETDB_H 1
+
+/* Define if you have the <windows.h> header file */
+#undef HAVE_WINDOWS_H
+
+/* Define if you have the <winsock.h> header file */
+#undef HAVE_WINSOCK_H
+
+/* Define if you have the <Windows32/Sockets.h> header file */
+#undef HAVE_WINDOWS32_SOCKETS_H
+
+/* Define if you have the <pwd.h> header file */
+#define HAVE_PWD_H 1
+
+/* Define if you have the <process.h> header file */
+#undef HAVE_PROCESS_H
+
+/* Define if you have the <grp.h> header file */
+#define HAVE_GRP_H 1
+
+/* Define if you have the <sys/file.h> header file */
+#define HAVE_SYS_FILE_H 1
+
+/* Define if you have the <sys/select.h> header file */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define if you have the <time.h> header file */
+#define HAVE_TIME_H 1
+
+/* Define if you have the <sys/time.h> header file */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <sys/types.h> header file */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have the <utime.h> header file */
+#define HAVE_UTIME_H 1
+
+/* Define if you have the <sys/errno.h> header file */
+#define HAVE_SYS_ERRNO_H 1
+
+/* Define if sys/wait.h is POSIX compatible */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define this if you have the <vfork.h> header file */
+#undef HAVE_VFORK_H
+
+/* Define for vfork in case it's not defined */
+#undef vfork
+
+/* Define for pid_t in case it's not defined */
+#define HAVE_pid_t 1
+
+/* The following macros deal with directory entries. */
+#define HAVE_DIRENT_H 1
+#undef HAVE_SYS_NDIR_H
+#define HAVE_SYS_DIR_H 1
+#undef HAVE_NDIR_H
+#undef HAVE_DIR_H
+
+/* The structure alignment as determined by configure */
+#define STRUCT_ALIGNMENT @STRUCT_ALIGNMENT@
+
+/* The name of the target platform, obtained by configure */
+#define TARGET_PLATFORM                "@host@"
+
+/* define POLL constants */
+
+#if HAVE_POLL_H
+#  include <poll.h>
+#endif
+#if HAVE_SYS_POLL_H
+#  include <sys/poll.h>
+#endif
+
+#ifndef POLLIN
+# ifdef HAVE_POLL
+#  warning "manually declared POLLIN=1 .."
+# endif
+#  define POLLIN     1
+#endif
+#ifndef POLLOUT
+# ifdef HAVE_POLL
+#  warning "manually declared POLLOUT=2 .."
+# endif
+#  define POLLOUT    2
+#endif
+#ifndef POLLERR
+# ifdef HAVE_POLL
+#  warning "manually declared POLLERR=4 .."
+# endif
+#  define POLLERR    4
+#endif
+
+#ifndef POLLRDNORM
+#  ifdef linux
+#    define POLLRDNORM POLLIN
+#  else /* !linux */
+#    ifdef POLLIN
+#     ifdef HAVE_POLL
+#      warning "manually declared POLLRDNORM=POLLIN .."
+#     endif
+#      define POLLRDNORM POLLIN
+#    else
+#     ifdef HAVE_POLL
+#      warning "manually declared POLLRDNORM .."
+#     endif
+#      define POLLRDNORM 1
+#    endif
+#  endif /* !linux */
+#endif
+
+#ifndef POLLWRNORM
+#  ifdef linux
+#    define POLLWRNORM POLLOUT
+#  else /* !linux */
+#    ifdef POLLOUT
+#     ifdef HAVE_POLL
+#      warning "manually declared POLLWRNORM=POLLOUT .."
+#     endif
+#      define POLLWRNORM POLLOUT
+#    else
+#     ifdef HAVE_POLL
+#      warning "manually declared POLLWRNORM .."
+#     endif
+#      define POLLWRNORM 2
+#    endif
+#  endif /* !linux */
+#endif
+
+#endif /* __config_h__ */
diff --git a/skyrix-core/NGiCal/.cvsignore b/skyrix-core/NGiCal/.cvsignore
new file mode 100644 (file)
index 0000000..49a10b1
--- /dev/null
@@ -0,0 +1,2 @@
+shared_debug_obj
+shared_obj
diff --git a/skyrix-core/NGiCal/COPYING b/skyrix-core/NGiCal/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-core/NGiCal/COPYRIGHT b/skyrix-core/NGiCal/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-core/NGiCal/ChangeLog b/skyrix-core/NGiCal/ChangeLog
new file mode 100644 (file)
index 0000000..c78f643
--- /dev/null
@@ -0,0 +1,129 @@
+2004-08-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * iCalEntityObject.m: changed "sequence" attribute from NSString to
+         NSNumber (this might break some code, though some care was taken to
+         accept NSString parameters) (v4.2.24)
+
+2004-07-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * iCalEvent.h: moved 'status' field to iCalEntityObject, because it is
+         also available in todo objects (v4.2.23)
+
+2004-06-30  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * iCalEntityObject.m: added -removeAllAttendees and -removeAllAlarms.
+         These are necessary in case you want to remake the contents of these
+         collections, but keep all other attributes otherwise. (v4.2.22)
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.21
+
+       * GNUmakefile.preamble: added prebinding
+
+       * GNUmakefile: create GNUmakefile.preamble, GNUmakefile.postamble
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.20)
+
+2004-01-23  Helge Hess  <helge.hess@opengroupware.org>
+
+       * iCalDataSource.m: added some sanity checks, improved to work better
+         with Mozilla generated iCal files (v4.2.19)
+
+2003-12-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * iCalDateHolder.m: small fix not to print a warning for "YYYYMMDD"
+         style dates (which are supported) (v4.2.18)
+
+2003-12-21  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.17
+
+       * iCalEvent.m: added parsing of duration values and calculation of 
+         end-dates based on that (eg required for Panther iCal.app)
+       
+       * iCalEvent.m: added support for 'status' and 'duration' fields 
+
+Thu Nov 20 16:31:15 2003  Martin Hoerning  <martin@opengroupware.org>
+
+       * iCalDateHolder.m: added timeless date format: YYYYMMDD
+         (solves ogo bug 424) (v4.2.16)
+
+Wed Oct 29 22:04:32 2003  Martin Hoerning  <martin@opengroupware.org>
+
+       * iCalDateHolder.m, iCalObject.[m|h]: added iCalDefaultTimeZone to 
+         create date from iCalDates without timeZone. (solves OGoo bug 257) 
+         (v4.2.15)
+
+2003-10-12  Helge Hess  <helge@opengroupware.org>
+
+       * GNUmakefile (libNGiCal_LIBRARIES_DEPEND_UPON): link against
+         libSaxObjC on MacOSX (v4.2.14)
+
+Fri Jul 18 17:04:55 2003  Martin Hoerning  <mh@skyrix.com>
+
+       * iCalToDo.h, iCalPerson.h, iCalEvent.h, iCalEntityObject.h: added 
+         accessor-methods to interface (v4.2.13)
+
+2003-07-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * iCalDateHolder.m: replaces and indexOfString with rangeOfString,
+         thanks to Filip Van Raemdonck for pointing that out (v4.2.12)
+
+2003-03-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * added some method prototypes
+
+2003-03-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved iCalEntityObject to a separate file (v4.2.11)
+
+Mon Mar 10 18:41:10 2003  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * NGiCal.xmap: added missing attendee attributes (as dictated by
+         mh on the phone)
+
+2003-03-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * iCalPerson.h: added some method prototypes
+
+2003-02-24  Helge Hess  <helge.hess@skyrix.com>
+
+       * iCalObject.h: added some accessors (v4.2.10)
+
+2003-02-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved to skyrix-core (v4.2.9)
+
+2003-01-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * added some support for timezones to be able to parse Evolution
+         apt creation requests (v4.2.7)
+
+2002-10-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * added iCalDateHolder for decoding xCal date values with timezone
+         attributes to a NSCalendarDate
+
+       * iCalObject.m: ignore X- keys
+
+       * removed all the old stuff (v4.2.4)
+
+       * ICalVEvent.m: renamed -class to -eventClass since -class conflicts
+         with the NSObject method
+
+       * started XML based iCal (v4.2.3)
+
+2002-10-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * ICalParser.m: small cleanups (v4.2.2)
+
+2002-10-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * created ChangeLog, created NGiCal library into SkyCore
+
+
diff --git a/skyrix-core/NGiCal/GNUmakefile b/skyrix-core/NGiCal/GNUmakefile
new file mode 100644 (file)
index 0000000..3b536f0
--- /dev/null
@@ -0,0 +1,53 @@
+# $Id$
+
+include ../common.make
+
+LIBRARY_NAME = libNGiCal
+
+libNGiCal_HEADER_FILES_DIR         = .
+libNGiCal_HEADER_FILES_INSTALL_DIR = /NGiCal
+libNGiCal_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libNGiCal_HEADER_FILES =       \
+       NGiCal.h                \
+       iCalAttachment.h        \
+       iCalObject.h            \
+       iCalEntityObject.h      \
+       iCalCalendar.h          \
+       iCalToDo.h              \
+       iCalJournal.h           \
+       iCalEvent.h             \
+       iCalFreeBusy.h          \
+       iCalPerson.h            \
+       iCalAlarm.h             \
+       iCalDuration.h          \
+       iCalTrigger.h           \
+       iCalDataSource.h        \
+
+#      IcalResponse.h          \
+
+libNGiCal_OBJC_FILES =         \
+       NSCalendarDate+ICal.m   \
+       iCalDateHolder.m        \
+       \
+       iCalAttachment.m        \
+       iCalObject.m            \
+       iCalEntityObject.m      \
+       iCalCalendar.m          \
+       iCalToDo.m              \
+       iCalJournal.m           \
+       iCalEvent.m             \
+       iCalFreeBusy.m          \
+       iCalPerson.m            \
+       iCalAlarm.m             \
+       iCalDuration.m          \
+       iCalTrigger.m           \
+       iCalDataSource.m        \
+
+#      NSString+ICal.m         \
+#IcalElements.m
+#IcalResponse.m
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/NGiCal/GNUmakefile.postamble b/skyrix-core/NGiCal/GNUmakefile.postamble
new file mode 100644 (file)
index 0000000..8a7e159
--- /dev/null
@@ -0,0 +1,7 @@
+# $Id$
+
+MAPDIR="$(GNUSTEP_INSTALLATION_DIR)/Library/SaxMappings/"
+
+after-install ::
+       $(MKDIRS) $(MAPDIR)
+       cp NGiCal.xmap $(MAPDIR)
diff --git a/skyrix-core/NGiCal/GNUmakefile.preamble b/skyrix-core/NGiCal/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..b255f0f
--- /dev/null
@@ -0,0 +1,31 @@
+# $Id$
+
+libNGiCal_LIBRARIES_DEPEND_UPON = \
+       -lSaxObjC -lEOControl
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+libNGiCal_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                                            \
+       -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+libNGiCal_LIB_DIRS += \
+       -L./$(GNUSTEP_OBJ_DIR)                          \
+       -L../../skyrix-xml/SaxObjC/$(GNUSTEP_OBJ_DIR)   \
+       -L../EOControl/$(GNUSTEP_OBJ_DIR)
+endif
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I. -I..        \
+       -I../NGExtensions/
+
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libNGiCal_PREBIND_ADDR="0xC1E00000"
+libNGiCal_LDFLAGS += -seg1addr $(libNGiCal_PREBIND_ADDR)
+endif
diff --git a/skyrix-core/NGiCal/IcalElements.m b/skyrix-core/NGiCal/IcalElements.m
new file mode 100644 (file)
index 0000000..c5c17a8
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface IcalComponent : WODynamicElement
+{
+  WOAssociation *cname;
+  WOElement     *template;
+}
+@end
+
+@interface IcalProperty : WODynamicElement
+{
+  WOAssociation *pname;
+  WOElement     *template;
+  NSDictionary  *parameters;
+  WOAssociation *value;
+  WOAssociation *valueType;
+}
+@end
+
+#include "common.h"
+
+static inline NSDictionary *ExtractParameters(NSDictionary *_set) {
+  /* extracts ? parameters */
+  NSMutableDictionary *paras = nil;
+  NSMutableArray      *paraKeys = nil;
+  NSEnumerator        *keys;
+  NSString            *key;
+  
+  // locate query parameters
+  keys = [_set keyEnumerator];
+  while ((key = [keys nextObject])) {
+    if ([key hasPrefix:@"?"]) {
+      WOAssociation *value;
+
+      if ([key isEqualToString:@"?wosid"])
+        continue;
+
+      value = [_set objectForKey:key];
+          
+      if (paraKeys == nil)
+        paraKeys = [NSMutableArray arrayWithCapacity:8];
+      if (paras == nil)
+        paras = [NSMutableDictionary dictionaryWithCapacity:8];
+          
+      [paraKeys addObject:key];
+      [paras setObject:value forKey:[key substringFromIndex:1]];
+    }
+  }
+
+  // remove query parameters
+  if (paraKeys) {
+    unsigned cnt, count;
+    for (cnt = 0, count = [paraKeys count]; cnt < count; cnt++) {
+      [(NSMutableDictionary *)_set removeObjectForKey:
+                                     [paraKeys objectAtIndex:cnt]];
+    }
+  }
+
+  // assign parameters
+  return [paras copy];
+}
+
+static inline id GetProperty(NSDictionary *_set, NSString *_name) {
+  id propValue = [_set objectForKey:_name];
+
+  if (propValue) {
+    propValue = RETAIN(propValue);
+    [(id)_set removeObjectForKey:_name];
+  }
+  return propValue;
+}
+
+@implementation IcalComponent
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->cname = GetProperty(_config, @"name");
+    self->template = RETAIN(_t);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->template);
+  RELEASE(self->cname);
+  [super dealloc];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *n;
+  
+  n = [self->cname stringValueInComponent:[_ctx component]];
+  
+  [_response appendContentString:@"BEGIN:"];
+  [_response appendContentString:n];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_response appendContentString:@"END:"];
+  [_response appendContentString:n];
+}
+
+@end /* IcalComponent */
+
+@implementation IcalProperty
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->pname      = GetProperty(_config, @"name");
+    self->value      = GetProperty(_config, @"value");
+    self->valueType  = GetProperty(_config, @"valueType");
+    self->template   = RETAIN(_t);
+    self->parameters = ExtractParameters(_config);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->value);
+  RELEASE(self->valueType);
+  RELEASE(self->parameters);
+  RELEASE(self->template);
+  RELEASE(self->pname);
+  [super dealloc];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent  *sComponent;
+  NSString     *n;
+  NSEnumerator *keys;
+  NSString     *key;
+  id           val;
+  NSString     *valType;
+
+  sComponent = [_ctx component];
+  n       = [self->pname     stringValueInComponent:sComponent];
+  val     = [self->value     valueInComponent:sComponent];
+  valType = [self->valueType stringValueInComponent:sComponent];
+
+  /* add name */
+  [_response appendContentString:n];
+
+  /* add parameters */
+  keys = [self->parameters keyEnumerator];
+  while ((key = [keys nextObject])) {
+    WOAssociation *val;
+    NSString *s;
+    
+    val = [self->parameters objectForKey:key];
+    s   = [val stringValueInComponent:sComponent];
+    
+    if ([s length] > 0) {
+      [_response appendContentString:@";"];
+      [_response appendContentString:key];
+      [_response appendContentString:@"="];
+      [_response appendContentString:s];
+    }
+  }
+  
+  /* add value */
+  [_response appendContentString:@":"];
+
+  if ([valType length] == 0) {
+    val = [val stringValue];
+  }
+  else if ([valType isEqualToString:@"datetime"]) {
+    static NSString *calfmt = @"%Y%m%dT%H%M00Z";
+    
+    if ([val respondsToSelector:@selector(descriptionWithCalendarFormat:)]) {
+      static NSTimeZone *gmt = nil;
+      if (gmt == nil) gmt = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
+      [val setTimeZone:gmt];
+      val = [val descriptionWithCalendarFormat:calfmt];
+    }
+    else
+      val = [val stringValue];
+  }
+  else
+    val = [val stringValue];
+  
+  [_response appendContentString:val];
+  [self->template appendToResponse:_response inContext:_ctx];
+}
+
+@end /* IcalProperty */
diff --git a/skyrix-core/NGiCal/IcalResponse.h b/skyrix-core/NGiCal/IcalResponse.h
new file mode 100644 (file)
index 0000000..f414ecd
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SkyDaemon_skyaptd_IcalResponse_H__
+#define __SkyDaemon_skyaptd_IcalResponse_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSMutableString, NSData;
+
+@interface IcalResponse : NSObject
+{
+  NSMutableString *content;
+  BOOL            isFinished;
+}
+
+- (id)initWithCapacity:(unsigned)_capacity;
+
+- (void)finish;
+- (NSString *)asString;
+- (BOOL)appendLine:(NSString *)_line;
+
+// _attr:_line
+- (BOOL)appendLine:(NSString *)_line forAttribute:(NSString *)_attr;
+
+@end /* IcalResponse */
+
+#endif /* __SkyDaemon_skyaptd_IcalResponse_H__ */
diff --git a/skyrix-core/NGiCal/IcalResponse.m b/skyrix-core/NGiCal/IcalResponse.m
new file mode 100644 (file)
index 0000000..fcc5991
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "IcalResponse.h"
+#import <Foundation/Foundation.h>
+
+@implementation IcalResponse
+
+- (void)_initContent {
+  [self appendLine:@"BEGIN:VCALENDAR"];
+  [self appendLine:@"VERSION:2.0"];
+  [self appendLine:@"PRODID:-//skyrix42/scheduler/skyaptd v.1.0//"];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->content    = [[NSMutableString alloc] initWithCapacity:0xFFFF];
+    self->isFinished = NO;
+    [self _initContent];
+  }
+  return self;
+}
+- (id)initWithCapacity:(unsigned)_capacity {
+  if ((self = [super init])) {
+    self->content    = [[NSMutableString alloc] initWithCapacity:_capacity];
+    self->isFinished = NO;
+    [self _initContent];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->content release];
+  [super dealloc];
+}
+
+
+- (BOOL)appendLine:(NSString *)_line {
+  if (self->isFinished) {
+    NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
+    return NO;
+  }
+  // limit length to 75 chars
+  while ([_line length] > 75) {
+    [self appendLine:[_line substringToIndex:75]];
+    _line = [@" " stringByAppendingString:[_line substringFromIndex:75]];
+  }
+
+  [self->content appendString:_line];
+  [self->content appendString:@"\r\n"];
+  
+  return YES;
+}
+
+- (BOOL)appendLine:(NSString *)_line forAttribute:(NSString *)_attr {
+  _line = [NSString stringWithFormat:@"%@:%@", _attr, _line];
+  return [self appendLine:_line];
+}
+
+
+- (void)finish {
+  if (self->isFinished) return;
+  [self appendLine:@"END:VCALENDAR"];
+  self->isFinished = YES;
+}
+
+- (NSString *)asString {
+  [self finish];
+  return [[self->content copy] autorelease];
+}
+
+@end /* IcalResponse */
diff --git a/skyrix-core/NGiCal/NGiCal-Info.plist b/skyrix-core/NGiCal/NGiCal-Info.plist
new file mode 100644 (file)
index 0000000..7839cf9
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGiCal</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.core.NGiCal</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-core/NGiCal/NGiCal.h b/skyrix-core/NGiCal/NGiCal.h
new file mode 100644 (file)
index 0000000..5d4e21c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGiCal_H__
+#define __NGiCal_H__
+
+#include <NGiCal/iCalAttachment.h>
+#include <NGiCal/iCalObject.h>
+#include <NGiCal/iCalCalendar.h>
+#include <NGiCal/iCalToDo.h>
+#include <NGiCal/iCalJournal.h>
+#include <NGiCal/iCalEvent.h>
+#include <NGiCal/iCalFreeBusy.h>
+#include <NGiCal/iCalPerson.h>
+#include <NGiCal/iCalAlarm.h>
+#include <NGiCal/iCalDuration.h>
+#include <NGiCal/iCalTrigger.h>
+
+#endif /* __NGiCal_H__ */
diff --git a/skyrix-core/NGiCal/NGiCal.xmap b/skyrix-core/NGiCal/NGiCal.xmap
new file mode 100644 (file)
index 0000000..8e7a454
--- /dev/null
@@ -0,0 +1,268 @@
+{
+  "http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt" = {
+
+    // components
+    
+    iCalendar = {
+      class  = NSMutableDictionary; // "ICalXRoot";
+      tagKey = "tag";
+      
+      ToManyRelationships = {
+       "subcomponents" = ( vcalendar );
+      };
+    };
+    
+    vcalendar = {
+      class  = iCalCalendar; // ICalVCalendar;
+
+      attributes = {
+        prodid   = prodId;
+        version  = version;
+        calscale = calscale;
+      };
+      
+      ToManyRelationships = {
+       events    = ( vevent    );
+       todos     = ( vtodo     );
+       journals  = ( journals  );
+       freeBusys = ( vfreebusy );
+       timezones = ( vtimezone );
+      };
+    };
+    
+    vevent = {
+      class  = iCalEvent;
+      
+      ToManyRelationships = {
+       "alarms"    = ( valarm   );
+       "attendees" = ( attendee );
+      };
+    };
+    
+    vtodo = {
+      class = "iCalToDo";
+      
+      ToManyRelationships = {
+       "alarms"    = ( valarm   );
+       "attendees" = ( attendee );
+      };
+    };
+    
+    valarm = {
+      class = "iCalAlarm";
+    };
+    
+    vfreebusy = {
+      class = "iCalFreeBusy";
+      
+      ToManyRelationships = {
+       "entries" = ( freebusy );
+      };
+    };
+    
+    vtimezone = {
+      class = NSMutableDictionary;
+      
+      attributes = {
+       tzid             = timeZoneID;
+        "X-LIC-LOCATION" = location;
+        daylight         = daylightInfo;
+        standard         = standardInfo;
+      };
+    };
+    daylight = {
+      class = NSMutableDictionary;
+      
+      attributes = {
+       tzoffsetfrom = tzOffsetFrom;
+       tzoffsetto   = tzOffsetTo;
+       tzname       = tzName;
+       dtstart      = startDate;
+       rrule        = recurrenceRule;
+      };
+    };
+    standard = {
+      class = NSMutableDictionary;
+      
+      attributes = {
+       tzoffsetfrom = tzOffsetFrom;
+       tzoffsetto   = tzOffsetTo;
+       tzname       = tzName;
+       dtstart      = startDate;
+       rrule        = recurrenceRule;
+      };
+    };
+    
+    // attributes
+    
+    dtstamp = {
+      class      = iCalDateHolder;
+      key        = "timeStampAsDate";
+      tagKey     = "tag";
+      contentKey = "string";
+    };
+    created = {
+      class      = iCalDateHolder;
+      key        = "created";
+      tagKey     = "tag";
+      contentKey = "string";
+    };
+    "last-modified" = {
+      class      = iCalDateHolder;
+      key        = "lastModified";
+      tagKey     = "tag";
+      contentKey = "string";
+    };
+    
+    dtstart = {
+      class = iCalDateHolder;
+      key   = "startDate";
+      attributes = {
+        tzid = tzid;
+      };
+      tagKey     = "tag";
+      contentKey = "string";
+    };
+    dtend = {
+      class = iCalDateHolder;
+      key   = "endDate";
+      attributes = {
+        tzid = tzid;
+      };
+      tagKey     = "tag";
+      contentKey = "string";
+    };
+    due = {
+      class = iCalDateHolder;
+      attributes = {
+        tzid = tzid;
+      };
+      tagKey     = "tag";
+      contentKey = "string";
+    };
+    completed = {
+      class = iCalDateHolder;
+      attributes = {
+        tzid = tzid;
+      };
+      tagKey     = "tag";
+      contentKey = "string";
+    };
+    
+    duration = {
+      class = NSString;
+    };
+    
+    summary     = { class = NSString; };
+    description = { class = NSString; key = comment; };
+    uid         = { class = NSString; };
+    action      = { class = NSString; };
+    priority    = { class = NSString; };
+    status      = { class = NSString; };
+    transp      = { class = NSString; };
+    sequence    = { class = NSString; };
+    class       = { class = NSString; key = accessClass; };
+    percent-complete = { class = NSString; key = "percentComplete"; };
+    
+    attendee = {
+      class = iCalPerson;
+      attributes = {
+        cn = cn;
+        rsvp = rsvp;
+        role = role;
+        partstat = partStat;
+      };
+      contentKey = "email";
+    };
+    organizer = {
+      class      = iCalPerson;
+      attributes = {
+        cn = cn;
+      };
+      contentKey = "email";
+    };
+    
+    freebusy = {
+      class = NSString;
+    };
+    url = {
+      class = NSString;
+    };
+    
+    trigger = {
+      class = iCalTrigger;
+      attributes = {
+        value = valueType;
+      };
+      contentKey = "value";
+    };
+    attach = {
+      class = iCalAttachment;
+      attributes = {
+        value = valueType;
+      };
+      contentKey = "value";
+    };
+
+    tzid = {
+      class = NSString;
+    };
+    tzname = {
+      class = NSString;
+    };
+    tzoffsetfrom = {
+      class = NSString;
+    };
+    tzoffsetto = {
+      class = NSString;
+    };
+    rrule = {
+      class = NSString;
+    };
+    location = {
+      class = NSString;
+    };
+    
+    // extra tags
+
+    "X-LIC-LOCATION" = {
+      class = NSString;
+    };
+    
+    "X-WR-TIMEZONE" = {
+      rejectWithContent = YES;
+    };
+    "X-WR-CALNAME" = {
+      rejectWithContent = YES;
+    };
+    "X-WR-RELCALID" = {
+      rejectWithContent = YES;
+    };
+
+    "X-MICROSOFT-CDO-TZID" = {
+      rejectWithContent = YES;
+    };
+    "X-MICROSOFT-CDO-BUSYSTATUS" = {
+      rejectWithContent = YES;
+    };
+    "X-MICROSOFT-CDO-INSTTYPE" = {
+      rejectWithContent = YES;
+    };
+    "X-MICROSOFT-CDO-INTENDEDSTATUS" = {
+      rejectWithContent = YES;
+    };
+    "X-MICROSOFT-CDO-ALLDAYEVENT" = {
+      rejectWithContent = YES;
+    };
+    "X-MICROSOFT-CDO-IMPORTANCE" = {
+      rejectWithContent = YES;
+    };
+
+    "X-PILOTID" = {
+      rejectWithContent = YES;
+    };
+    "X-PILOTSTAT" = {
+      rejectWithContent = YES;
+    };
+  };
+}
diff --git a/skyrix-core/NGiCal/NSCalendarDate+ICal.h b/skyrix-core/NGiCal/NSCalendarDate+ICal.h
new file mode 100644 (file)
index 0000000..fc95cc6
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ICal2_NSCalendarDate_ICal_H__
+#define __ICal2_NSCalendarDate_ICal_H__
+
+#import <Foundation/NSCalendarDate.h>
+
+@class NSTimeZone;
+
+@interface NSCalendarDate(ICalValue)
+
+/* represention */
+
+- (NSString *)icalStringWithTimeZone:(NSTimeZone *)_tz;
+- (NSString *)icalString;
+
+@end
+
+#endif /* __ICal2_NSCalendarDate_ICal_H__ */
diff --git a/skyrix-core/NGiCal/NSCalendarDate+ICal.m b/skyrix-core/NGiCal/NSCalendarDate+ICal.m
new file mode 100644 (file)
index 0000000..dabe0f0
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+
+static NSTimeZone *gmt = nil;
+static inline void _setupGMT(void) {
+  if (gmt == nil)
+    gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+}
+
+@implementation NSCalendarDate(ICalValue)
+
+/* represention */
+
+static NSString *gmtcalfmt = @"%Y%m%dT%H%M00Z";
+
+- (NSString *)icalStringInGMT {
+  NSTimeZone *oldtz;
+  NSString   *s;
+  _setupGMT();
+  
+  /* set GMT as timezone */
+  oldtz = [[self timeZone] retain];
+  if (oldtz == gmt) {
+    [oldtz release];
+    oldtz = nil;
+  }
+  else {
+    [self setTimeZone:gmt];
+  }
+  
+  /* calc string */
+  s = [self descriptionWithCalendarFormat:gmtcalfmt];
+  
+  /* restore old timezone */
+  if (oldtz) {
+    [self setTimeZone:oldtz];
+    [oldtz release];
+  }
+  
+  return s;
+}
+
+- (NSString *)icalStringWithTimeZone:(NSTimeZone *)_tz {
+  _setupGMT();
+  
+  if (_tz == gmt || _tz == nil)
+    return [self icalStringInGMT];
+  else if ([_tz isEqual:gmt])
+    return [self icalStringInGMT];
+  else {
+    /* not in GMT */
+    NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
+          __PRETTY_FUNCTION__, _tz);
+    return [self icalStringInGMT];
+  }
+}
+
+- (NSString *)icalString {
+  _setupGMT();
+  return [self icalStringWithTimeZone:gmt];
+}
+
+@end /* NSDate(ICalValue) */
diff --git a/skyrix-core/NGiCal/NSString+ICal.h b/skyrix-core/NGiCal/NSString+ICal.h
new file mode 100644 (file)
index 0000000..f65cf17
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGiCal_NSString_ICal_H__
+#define __NGiCal_NSString_ICal_H__
+
+#import <Foundation/NSString.h>
+
+@interface NSString(ICalValue)
+
+/* libical internal C-strings */
+
+- (id)initWithICalCString:(const char *)_cstr;
+- (const char *)icalCString;
+- (NSString *)icalString;
+
+/* libical values */
+
+- (id)initWithICalValueHandle:(icalvalue *)_handle;
+- (id)initWithICalValueOfProperty:(icalproperty *)_prop;
+
+@end /* NSString(ICalValue) */
+
+#endif /* __NGiCal_NSString_ICal_H__ */
diff --git a/skyrix-core/NGiCal/NSString+ICal.m b/skyrix-core/NGiCal/NSString+ICal.m
new file mode 100644 (file)
index 0000000..b56593d
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSString+ICal.h"
+#include "common.h"
+#include <ical.h>
+
+@implementation NSString(ICalCString)
+
+- (const char *)icalCString {
+  NSStringEncoding enc;
+  
+  enc = [[self class] libicalStringEncoding];
+  
+  if (enc == NSUTF8StringEncoding)
+    return [self UTF8String];
+  else if (enc == [NSString defaultCStringEncoding])
+    return [self cString];
+  else
+    return [[self dataUsingEncoding:enc] bytes];
+}
+
+- (NSString *)icalString {
+  return self;
+}
+
+@end /* NSString(ICalCString) */
+
+@implementation NSObject(TemporaryStringInit)
+
++ (NSStringEncoding)libicalStringEncoding {
+  return NSUTF8StringEncoding;
+}
+
+- (id)initWithICalCString:(const char *)_cstr {
+  NSStringEncoding enc;
+
+  if (_cstr == NULL) {
+    RELEASE(self);
+    return nil;
+  }
+  
+  enc = [[self class] libicalStringEncoding];
+  
+  if (enc == NSUTF8StringEncoding)
+    return [(NSString *)self initWithUTF8String:_cstr];
+  else if (enc == [[self class] defaultCStringEncoding])
+    return [(NSString *)self initWithCString:_cstr];
+  else {
+    NSData *d;
+    
+    d = [[NSData alloc] initWithBytes:_cstr length:strlen(_cstr)];
+    self = [(NSString *)self initWithData:d encoding:enc];
+    RELEASE(d);
+    
+    return self;
+  }
+  
+  return nil;
+}
+
+- (id)initWithICalValueHandle:(icalvalue *)_handle {
+  const char *s;
+  
+  if (_handle == NULL) {
+    RELEASE(self);
+    return nil;
+  }
+  if ((s = icalvalue_as_ical_string(_handle)) == NULL) {
+    RELEASE(self);
+    return nil;
+  }
+  return [self initWithICalCString:s];
+}
+
+- (id)initWithICalValueOfProperty:(icalproperty *)_prop {
+  icalvalue *val;
+
+  if (_prop == nil) {
+    RELEASE(self);
+    return nil;
+  }
+  
+  if ((val = icalproperty_get_value(_prop)) == NULL) {
+    NSLog(@"%s: ical property has no value ??", __PRETTY_FUNCTION__);
+    RELEASE(self);
+    return nil;
+  }
+  
+  return [self initWithICalValueHandle:val];
+}
+
+@end /* NSObject(TemporaryStringInit) */
+
diff --git a/skyrix-core/NGiCal/README b/skyrix-core/NGiCal/README
new file mode 100644 (file)
index 0000000..df050b7
--- /dev/null
@@ -0,0 +1,27 @@
+# $Id$
+
+TODO: update text
+
+Objective-C classes for representing iCalendar entities as objects. To
+actually parse iCalendar entities the skyrix-xml iCalSaxDriver is used.
+Note that this library doesn't directly link against libical but rather
+relies on the SAX interface (SaxObjectDecoder is used).
+
+OPEN: should we add the "ical" generation tags to this library or to
+NGObjWeb or to ... ?? => iCal rendering should probably be a separate 
+product-bundle for SOPE
+
+Class Hierarchy
+
+  NSObject
+    ICalComponent
+      ICalVCalendar
+      ICalVEvent
+      ICalVFreeBusy
+      ICalXRoot
+    ICalProperty
+      ICalFreeBusy
+    ICalParser
+
+  EODataSource
+    iCalDataSource
diff --git a/skyrix-core/NGiCal/Version b/skyrix-core/NGiCal/Version
new file mode 100644 (file)
index 0000000..a281cca
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=24
diff --git a/skyrix-core/NGiCal/common.h b/skyrix-core/NGiCal/common.h
new file mode 100644 (file)
index 0000000..1633aa1
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ICal_common_H__
+#define __ICal_common_H__
+
+#import <Foundation/Foundation.h>
+#include <EOControl/EOControl.h>
+#include <NGExtensions/NGExtensions.h>
+
+#endif /* __ICal_common_H__ */
diff --git a/skyrix-core/NGiCal/iCalAlarm.h b/skyrix-core/NGiCal/iCalAlarm.h
new file mode 100644 (file)
index 0000000..766b021
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGiCal_iCalAlarm_H__
+#define __NGiCal_iCalAlarm_H__
+
+#include <NGiCal/iCalObject.h>
+
+@class NSString;
+
+@interface iCalAlarm : iCalObject
+{
+  id       trigger;
+  NSString *comment;
+  NSString *action;
+  id       attach;
+}
+
+/* accessors */
+
+- (id)trigger;
+- (id)attach;
+- (NSString *)comment;
+- (NSString *)action;
+
+@end
+
+#endif /* __NGiCal_iCalAlarm_H__ */
diff --git a/skyrix-core/NGiCal/iCalAlarm.m b/skyrix-core/NGiCal/iCalAlarm.m
new file mode 100644 (file)
index 0000000..6cf095b
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalAlarm.h"
+#include "common.h"
+
+@implementation iCalAlarm
+
+- (void)dealloc {
+  [self->trigger release];
+  [self->comment release];
+  [self->action  release];
+  [self->attach  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setTrigger:(id)_value {
+  ASSIGN(self->trigger, _value);
+}
+- (id)trigger {
+  return self->trigger;
+}
+
+- (void)setAttach:(id)_value {
+  ASSIGN(self->attach, _value);
+}
+- (id)attach {
+  return self->attach;
+}
+
+- (void)setComment:(NSString *)_value {
+  ASSIGNCOPY(self->comment, _value);
+}
+- (NSString *)comment {
+  return self->comment;
+}
+
+- (void)setAction:(NSString *)_value {
+  ASSIGNCOPY(self->action, _value);
+}
+- (NSString *)action {
+  return self->action;
+}
+
+/* descriptions */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->action)
+    [ms appendFormat:@" action=%@", self->action];
+  if (self->comment)
+    [ms appendFormat:@" comment=%@", self->comment];
+  if (self->trigger)
+    [ms appendFormat:@" trigger=%@", self->trigger];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* iCalAlarm */
diff --git a/skyrix-core/NGiCal/iCalAttachment.h b/skyrix-core/NGiCal/iCalAttachment.h
new file mode 100644 (file)
index 0000000..5b6a371
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGiCal_iCalAttachment_H__
+#define __NGiCal_iCalAttachment_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+
+@interface iCalAttachment : NSObject
+{
+  NSString *valueType;
+  NSString *value;
+}
+
+/* accessors */
+
+- (NSString *)valueType;
+- (NSString *)value;
+
+@end
+
+#endif /* __NGiCal_iCalAttachment_H__ */
diff --git a/skyrix-core/NGiCal/iCalAttachment.m b/skyrix-core/NGiCal/iCalAttachment.m
new file mode 100644 (file)
index 0000000..9a3edaf
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalAttachment.h"
+#include "common.h"
+
+@implementation iCalAttachment
+
+- (void)dealloc {
+  [self->value     release];
+  [self->valueType release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setValue:(NSString *)_value {
+  ASSIGNCOPY(self->value, _value);
+}
+- (NSString *)value {
+  return self->value;
+}
+
+- (void)setValueType:(NSString *)_value {
+  ASSIGNCOPY(self->valueType, _value);
+}
+- (NSString *)valueType {
+  return self->valueType;
+}
+
+/* descriptions */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->valueType)
+    [ms appendFormat:@" type=%@", self->valueType];
+  if (self->value)
+    [ms appendFormat:@" value=%@", self->value];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* iCalAttachment */
diff --git a/skyrix-core/NGiCal/iCalCalendar.h b/skyrix-core/NGiCal/iCalCalendar.h
new file mode 100644 (file)
index 0000000..38c6746
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGiCal_iCalCalendar_H__
+#define __NGiCal_iCalCalendar_H__
+
+#include <NGiCal/iCalObject.h>
+
+@class NSString, NSMutableArray, NSArray, NSEnumerator, NSMutableDictionary;
+@class iCalEvent, iCalToDo, iCalJournal, iCalFreeBusy;
+
+@interface iCalCalendar : iCalObject
+{
+  NSString *version;
+  NSString *calscale;
+  NSString *prodId;
+
+  NSMutableArray *todos;
+  NSMutableArray *events;
+  NSMutableArray *journals;
+  NSMutableArray *freeBusys;
+  NSMutableDictionary *timezones;
+}
+
+/* accessors */
+
+- (NSString *)calscale;
+- (NSString *)version;
+- (NSString *)prodId;
+
+- (NSArray *)events;
+- (NSArray *)todos;
+- (NSArray *)journals;
+- (NSArray *)freeBusys;
+
+/* collection */
+
+- (NSArray *)allObjects;
+- (NSEnumerator *)objectEnumerator;
+
+@end
+
+#endif /* __NGiCal_iCalCalendar_H__ */
diff --git a/skyrix-core/NGiCal/iCalCalendar.m b/skyrix-core/NGiCal/iCalCalendar.m
new file mode 100644 (file)
index 0000000..af41f39
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalCalendar.h"
+#include "common.h"
+
+@implementation iCalCalendar
+
+- (void)dealloc {
+  [self->todos     release];
+  [self->timezones release];
+  [self->events    release];
+  [self->freeBusys release];
+  [self->journals  release];
+  [self->version   release];
+  [self->calscale  release];
+  [self->prodId    release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setCalscale:(NSString *)_value {
+  ASSIGN(self->calscale, _value);
+}
+- (NSString *)calscale {
+  return self->calscale;
+}
+- (void)setVersion:(NSString *)_value {
+  ASSIGN(self->version, _value);
+}
+- (NSString *)version {
+  return self->version;
+}
+- (void)setProdId:(NSString *)_value {
+  ASSIGN(self->prodId, _value);
+}
+- (NSString *)prodId {
+  return self->prodId;
+}
+
+- (void)addToEvents:(iCalEvent *)_event {
+  if (_event == nil) return;
+  if (self->events == nil)
+    self->events = [[NSMutableArray alloc] initWithCapacity:4];
+  [self->events addObject:_event];
+}
+- (NSArray *)events {
+  return self->events;
+}
+
+- (void)addToTimezones:(id)_tz {
+  NSString *tzid;
+  
+  if (_tz == nil) return;
+  if (self->timezones == nil)
+    self->timezones = [[NSMutableDictionary alloc] initWithCapacity:4];
+  
+  if ((tzid = [_tz valueForKey:@"tzid"]) == nil) {
+    [self logWithFormat:@"ERROR: missing timezone-id in timezone: %@", _tz];
+    return;
+  }
+  [self->timezones setObject:_tz forKey:tzid];
+}
+- (NSArray *)timezones {
+  return [self->timezones allValues];
+}
+
+- (void)addToTodos:(iCalToDo *)_todo {
+  if (_todo == nil) return;
+  if (self->todos == nil)
+    self->todos = [[NSMutableArray alloc] initWithCapacity:4];
+  [self->todos addObject:_todo];
+}
+- (NSArray *)todos {
+  return self->todos;
+}
+
+- (void)addToJournals:(iCalJournal *)_obj {
+  if (_obj == nil) return;
+  if (self->journals == nil)
+    self->journals = [[NSMutableArray alloc] initWithCapacity:4];
+  [self->journals addObject:_obj];
+}
+- (NSArray *)journals {
+  return self->journals;
+}
+
+- (void)addToFreeBusys:(iCalJournal *)_obj {
+  if (_obj == nil) return;
+  if (self->freeBusys == nil)
+    self->freeBusys = [[NSMutableArray alloc] initWithCapacity:4];
+  [self->freeBusys addObject:_obj];
+}
+- (NSArray *)freeBusys {
+  return self->freeBusys;
+}
+
+/* collection */
+
+- (NSArray *)allObjects {
+  NSMutableArray *ma;
+  
+  ma = [NSMutableArray arrayWithCapacity:32];
+  if (self->events)    [ma addObjectsFromArray:self->events];
+  if (self->todos)     [ma addObjectsFromArray:self->todos];
+  if (self->freeBusys) [ma addObjectsFromArray:self->freeBusys];
+  if (self->journals)  [ma addObjectsFromArray:self->journals];
+  return ma;
+}
+- (NSEnumerator *)objectEnumerator {
+  return [[self allObjects] objectEnumerator];
+}
+
+/* ical typing */
+
+- (NSString *)entityName {
+  return @"vcalendar";
+}
+
+/* descriptions */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->version)  [ms appendFormat:@" v%@",         self->version];
+  if (self->prodId)   [ms appendFormat:@" product=%@",  self->prodId];
+  if (self->calscale) [ms appendFormat:@" calscale=%@", self->calscale];
+
+  if ([self->events count] > 0)
+    [ms appendFormat:@" events=%@", self->events];
+  if ([self->todos count] > 0)
+    [ms appendFormat:@" todos=%@", self->todos];
+  if ([self->freeBusys count] > 0)
+    [ms appendFormat:@" fb=%@", self->freeBusys];
+  if ([self->journals count] > 0)
+    [ms appendFormat:@" journals=%@", self->journals];
+
+  if ([self->timezones count] > 0)
+    [ms appendFormat:@" tzs=%@", [self->timezones allKeys]];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* iCalCalendar */
diff --git a/skyrix-core/NGiCal/iCalDataSource.h b/skyrix-core/NGiCal/iCalDataSource.h
new file mode 100644 (file)
index 0000000..f82f3aa
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGiCal_iCalDataSource_H__
+#define __NGiCal_iCalDataSource_H__
+
+#include <EOControl/EODataSource.h>
+
+@class NSString, NSURL;
+@class EOFetchSpecification;
+
+@interface iCalDataSource : EODataSource
+{
+  EOFetchSpecification *fetchSpecification;
+  NSURL    *url;
+  NSString *entityName;
+}
+
+- (id)initWithURL:(NSURL *)_url      entityName:(NSString *)_ename;
+- (id)initWithPath:(NSString *)_file entityName:(NSString *)_ename;
+- (id)initWithURL:(NSURL *)_url;
+- (id)initWithPath:(NSString *)_file;
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec;
+- (EOFetchSpecification *)fetchSpecification;
+
+/* fetching */
+
+- (NSArray *)fetchObjects;
+
+@end
+
+#endif /* __NGiCal_iCalDataSource_H__ */
diff --git a/skyrix-core/NGiCal/iCalDataSource.m b/skyrix-core/NGiCal/iCalDataSource.m
new file mode 100644 (file)
index 0000000..9257e41
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalDataSource.h"
+#include "iCalObject.h"
+#include "iCalCalendar.h"
+#include <SaxObjC/SaxObjC.h>
+#include "common.h"
+
+@interface NSObject(suppressCapitalizedKeyWarning)
++ (void)suppressCapitalizedKeyWarning;
+@end
+
+@implementation iCalDataSource
+
+// THREAD
+static id<NSObject,SaxXMLReader> parser = nil;
+static SaxObjectDecoder *sax = nil;
+
+- (void)_setupGlobals {
+  if (parser == nil ) {
+    SaxXMLReaderFactory *factory = 
+      [SaxXMLReaderFactory standardXMLReaderFactory];
+    parser = [[factory createXMLReaderForMimeType:@"text/calendar"] retain];
+    if (parser == nil)
+      [self logWithFormat:@"ERROR: found no SAX driver for 'text/calendar'!"];
+  }
+  if (sax == nil && parser != nil) {
+    NSBundle *bundle;
+    NSString *p;
+    
+#if COCOA_Foundation_LIBRARY
+    /* otherwise we get warning on "X-WR-TIMEZONE" etc */
+    [NSClassFromString(@"NSKeyBinding") suppressCapitalizedKeyWarning];
+#endif
+    
+    bundle = [NSBundle bundleForClass:[self class]];
+    if ((p = [bundle pathForResource:@"NGiCal" ofType:@"xmap"]))
+      sax = [[SaxObjectDecoder alloc] initWithMappingAtPath:p];
+    else
+      sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGiCal"];
+    
+    [parser setContentHandler:sax];
+    [parser setErrorHandler:sax];
+  }
+}
+
+
+- (id)initWithURL:(NSURL *)_url entityName:(NSString *)_ename {
+  [self _setupGlobals];
+  if ((self = [super init])) {
+    self->url        = [_url copy];
+    self->entityName = [_ename copy];
+  }
+  return self;
+}
+- (id)initWithPath:(NSString *)_path entityName:(NSString *)_ename {
+  NSURL *lurl;
+  
+  lurl = [[[NSURL alloc] initFileURLWithPath:_path] autorelease];
+  return [self initWithURL:lurl entityName:_ename];
+}
+
+- (id)initWithURL:(NSURL *)_url {
+  return [self initWithURL:_url entityName:nil];
+}
+- (id)initWithPath:(NSString *)_path {
+  return [self initWithPath:_path entityName:nil];
+}
+- (id)init {
+  return [self initWithURL:nil];
+}
+
+- (void)dealloc {
+  [self->fetchSpecification release];
+  [self->entityName release];
+  [self->url release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec {
+  if ([self->fetchSpecification isEqual:_fspec])
+    return;
+  
+  ASSIGNCOPY(self->fetchSpecification, _fspec);
+
+  [self postDataSourceChangedNotification];
+}
+- (EOFetchSpecification *)fetchSpecification {
+  return self->fetchSpecification;
+}
+
+/* fetching */
+
+- (id)_parseCalendar {
+  id cal;
+  
+  if (parser == nil) {
+    [self logWithFormat:@"ERROR: missing iCalendar parser!"];
+    return nil;
+  }
+  if (sax == nil) {
+    [self logWithFormat:@"ERROR: missing SAX handler!"];
+    return nil;
+  }
+  
+  [parser parseFromSource:self->url];
+  cal = [sax rootObject];
+  
+  return cal;
+}
+
+- (NSArray *)objectsForEntityNamed:(NSString *)ename inCalendar:(id)_cal {
+  if ([ename isEqualToString:@"vevent"])
+    return [_cal events];
+  if ([ename isEqualToString:@"vtodo"])
+    return [_cal todos];
+  if ([ename isEqualToString:@"vjournal"])
+    return [_cal journals];
+  if ([ename isEqualToString:@"vfreebusy"])
+    return [_cal freeBusys];
+  
+  [self logWithFormat:@"unknown calendar entity '%@'", ename];
+  return nil;
+}
+
+- (NSArray *)objectsFromCalendar:(id)_cal {
+  NSString *ename;
+  
+  ename = [self->fetchSpecification entityName];
+  if ([ename length] == 0)
+    ename = self->entityName;
+
+  if ([ename length] == 0)
+    return [_cal allObjects];
+  
+  if ([_cal isKindOfClass:[NSDictionary class]]) {
+    /*
+      This happens with Mozilla Calendar which posts one vcalendar
+      entry (with method 'PUBLISH') per event.
+    */
+    NSMutableArray *ma;
+    NSArray  *calendars;
+    unsigned i, count;
+    
+    if (![[_cal objectForKey:@"tag"] isEqualToString:@"iCalendar"]) {
+      [self logWithFormat:
+             @"ERROR: calendar (entity=%@) passed in as a dictionary: %@", 
+             _cal];
+    }
+    
+    if ((calendars = [_cal objectForKey:@"subcomponents"]) == nil)
+      return nil;
+
+    count = [calendars count];
+    ma = [NSMutableArray arrayWithCapacity:(count + 1)];
+    
+    for (i = 0; i < count; i++) {
+      NSArray *objects;
+      
+      objects = [self objectsForEntityNamed:ename 
+                     inCalendar:[calendars objectAtIndex:i]];
+      if ([objects count] == 0)
+       continue;
+      
+      [ma addObjectsFromArray:objects];
+    }
+    return ma;
+  }
+  
+  return [self objectsForEntityNamed:ename inCalendar:_cal];
+}
+
+- (NSArray *)fetchObjects {
+  NSAutoreleasePool *pool;
+  NSArray *result;
+  id calendar;
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  if ((calendar = [self _parseCalendar]) == nil)
+    return nil;
+  
+  if (self->fetchSpecification == nil) {
+    result = [[self objectsFromCalendar:calendar] shallowCopy];
+  }
+  else {
+    NSMutableArray *ma;
+    NSEnumerator   *e;
+    EOQualifier *q;
+    NSArray     *sort;
+    NSArray     *objects;
+    iCalObject  *object;
+    
+    /* get objects */
+    
+    objects = [self objectsFromCalendar:calendar];
+    
+    /* first filter using qualifier */
+    
+    ma = [NSMutableArray arrayWithCapacity:[objects count]];
+    q  = [self->fetchSpecification qualifier];
+    e  = [objects objectEnumerator];
+    while ((object = [e nextObject])) {
+      if (q) {
+       if (![(id<EOQualifierEvaluation>)q evaluateWithObject:object])
+         continue;
+      }
+      
+      [ma addObject:object];
+    }
+    
+    /* now sort */
+    
+    if ((sort = [self->fetchSpecification sortOrderings]))
+      [ma sortUsingKeyOrderArray:sort];
+
+    result = [ma shallowCopy];
+  }
+  
+  [pool release];
+  
+  return [result autorelease];
+}
+
+@end /* iCalDataSource */
diff --git a/skyrix-core/NGiCal/iCalDateHolder.h b/skyrix-core/NGiCal/iCalDateHolder.h
new file mode 100644 (file)
index 0000000..d333c3e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGiCal_iCalDateHolder_H__
+#define __NGiCal_iCalDateHolder_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+
+@interface iCalDateHolder : NSObject
+{
+  NSString *tzid;
+  NSString *string;
+  NSString *tag;
+}
+
+@end
+
+#endif /* __NGiCal_iCalDateHolder_H__ */
diff --git a/skyrix-core/NGiCal/iCalDateHolder.m b/skyrix-core/NGiCal/iCalDateHolder.m
new file mode 100644 (file)
index 0000000..540e8e5
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalDateHolder.h"
+#include "iCalObject.h"
+#include "common.h"
+
+@interface NSTimeZone(iCalTimeZone)
+
++ (NSTimeZone *)timeZoneWithICalId:(NSString *)_tz;
+
+@end
+
+@implementation iCalDateHolder
+
+static NSTimeZone *gmt = nil;
+
++ (void)initialize {
+  if (gmt == nil)
+    gmt = [[NSTimeZone timeZoneWithName:@"GMT"] retain];
+}
+
+- (void)dealloc {
+  [self->string release];
+  [self->tzid   release];
+  [self->tag    release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setString:(NSString *)_value {
+  ASSIGNCOPY(self->string, _value);
+}
+- (NSString *)string {
+  return self->string;
+}
+
+- (void)setTag:(NSString *)_value {
+  ASSIGNCOPY(self->tag, _value);
+}
+- (NSString *)tag {
+  return self->tag;
+}
+
+- (void)setTzid:(NSString *)_value {
+  ASSIGNCOPY(self->tzid, _value);
+}
+- (NSString *)tzid {
+  return self->tzid;
+}
+
+/* mapping to Foundation */
+
+- (NSTimeZone *)timeZone {
+  // TODO: lookup tzid in iCalCalendar !
+  NSString *s;
+
+  s = [self tzid];
+  
+  /* a hack */
+  if ([s hasPrefix:@"/softwarestudio.org"]) {
+    NSRange r;
+    
+    r = [s rangeOfString:@"Europe/"];
+    if (r.length > 0)
+      s = [s substringFromIndex:r.location];
+  }
+  return [NSTimeZone timeZoneWithICalId:s];
+}
+
+/* decoding */
+
+- (id)awakeAfterUsingSaxDecoder:(id)_decoder {
+  NSCalendarDate *date = nil;
+  NSString   *s;
+  NSTimeZone *tz;
+  
+  s = self->string;
+  if ([s length] < 5) {
+    [self logWithFormat:@"tag %@: got an weird date string '%@' ?!", 
+           self->tag, s];
+    return s;
+  }
+  
+  /* calculate timezone */
+  
+  if ([self->string hasSuffix:@"Z"]) {
+    /* zulu time, eg 20021009T094500Z */
+    tz = gmt;
+    s = [s substringToIndex:([s length] - 1)];
+  }
+  else
+    tz = [self timeZone];
+  
+  /* 
+     012345678901234
+     20021009T094500 - 15 chars 
+     20021009T0945   - 13 chars 
+     991009T0945     - 11 chars
+     
+     20031111        - 8 chars
+  */
+  if ([s rangeOfString:@"T"].length == 0 && [s length] == 8) {
+    /* hm, maybe a date without a time? like an allday event! */
+    int year, month, day;
+    unsigned char buf[16];
+    [s getCString:&(buf[0])];
+    
+    buf[9] = '\0';
+    day    = atoi(&(buf[6]));  buf[6] = '\0';
+    month  = atoi(&(buf[4]));  buf[4] = '\0';
+    year   = atoi(&(buf[0]));
+    
+    date = [NSCalendarDate dateWithYear:year month:month day:day
+                           hour:0 minute:0 second:0
+                           timeZone:tz];
+  }
+  else if ([s length] == 15) {
+    int year, month, day, hour, minute, second;
+    unsigned char buf[24];
+    [s getCString:&(buf[0])];
+      
+    second = atoi(&(buf[13])); buf[13] = '\0';
+    minute = atoi(&(buf[11])); buf[11] = '\0';
+    hour   = atoi(&(buf[9]));  buf[9] = '\0';
+    day    = atoi(&(buf[6]));  buf[6] = '\0';
+    month  = atoi(&(buf[4]));  buf[4] = '\0';
+    year   = atoi(&(buf[0]));
+      
+    date = [NSCalendarDate dateWithYear:year month:month day:day
+                           hour:hour minute:minute second:second
+                           timeZone:tz];
+  }
+  else
+    NSLog(@"%s: unknown date format (%@) ???", __PRETTY_FUNCTION__, s);
+    
+  if (date == nil)
+    NSLog(@"couldn't convert string '%@' to date (format '%@') ..", s);
+
+  return date;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->tag)    [ms appendFormat:@" %@",  self->tag];
+  if (self->string) [ms appendFormat:@" '%@'",  self->string];
+  if (self->tzid)   [ms appendFormat:@" tz=%@", self->tzid];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* iCalDateHolder */
+
+@implementation NSTimeZone(iCalTimeZone)
+
+static NSMutableDictionary *idToTz = nil; // THREAD
+
++ (NSTimeZone *)timeZoneWithICalId:(NSString *)_tzid {
+  static NSString *iCalDefaultTZ = nil;
+  NSTimeZone *tz;
+  
+  if (idToTz == nil)
+    idToTz = [[NSMutableDictionary alloc] initWithCapacity:16];
+  
+  if ([_tzid length] == 0) {
+    
+    tz = [iCalObject iCalDefaultTimeZone];
+    if (tz != nil) return tz;
+
+    if (iCalDefaultTZ == nil) {
+      NSString *defTz;
+      NSUserDefaults *ud;
+      // TODO: take a default timeZone
+      ud = [NSUserDefaults standardUserDefaults];
+      defTz = [ud stringForKey:@"iCalTimeZoneName"];
+      if ([defTz length] == 0)
+        defTz = [ud stringForKey:@"TimeZoneName"];
+      if ([defTz length] == 0)
+        defTz = [ud stringForKey:@"TimeZone"];
+      if ([defTz length] == 0)
+        defTz = @"GMT";
+      iCalDefaultTZ = [defTz retain];
+    }
+    
+    _tzid = iCalDefaultTZ;
+    
+  }
+  
+  if ([_tzid length] == 0)
+    _tzid = @"GMT";
+  
+  tz = [idToTz objectForKey:_tzid];
+  if (tz == nil) tz = [NSTimeZone timeZoneWithName:_tzid];
+  if (tz == nil) tz = [NSTimeZone timeZoneWithAbbreviation:_tzid];
+  
+  if (tz == nil) {
+    NSLog(@"couldn't map timezone id %@", _tzid);
+  }
+  
+  if (tz) [idToTz setObject:tz forKey:_tzid];
+  return tz;
+}
+
+@end /* NSTimeZone(iCalTimeZone) */
diff --git a/skyrix-core/NGiCal/iCalDuration.h b/skyrix-core/NGiCal/iCalDuration.h
new file mode 100644 (file)
index 0000000..7efa775
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGiCal_iCalDuration_H__
+#define __NGiCal_iCalDuration_H__
+
+#import <Foundation/NSObject.h>
+
+@interface iCalDuration : NSObject
+{
+}
+
+@end
+
+#endif /* __NGiCal_iCalDuration_H__ */
diff --git a/skyrix-core/NGiCal/iCalDuration.m b/skyrix-core/NGiCal/iCalDuration.m
new file mode 100644 (file)
index 0000000..fd1e0d4
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalDuration.h"
+#include "common.h"
+
+@implementation iCalDuration
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+@end /* iCalDuration */
diff --git a/skyrix-core/NGiCal/iCalEntityObject.h b/skyrix-core/NGiCal/iCalEntityObject.h
new file mode 100644 (file)
index 0000000..fa30b25
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGiCal_iCalEntityObject_H__
+#define __NGiCal_iCalEntityObject_H__
+
+#include <NGiCal/iCalObject.h>
+
+/*
+  iCalEntityObject
+  
+  This is a common base class for tasks and appointments which share a lot of
+  attributes.
+*/
+
+@class NSCalendarDate, NSMutableArray, NSString, NSArray, NSNumber;
+@class iCalPerson;
+
+@interface iCalEntityObject : iCalObject
+{
+  NSString       *uid;
+  NSString       *summary;
+  NSTimeInterval timestamp;
+  NSCalendarDate *created;
+  NSCalendarDate *lastModified;
+  NSCalendarDate *startDate;
+  NSString       *accessClass;
+  NSString       *priority;
+  NSMutableArray *alarms;
+  iCalPerson     *organizer;
+  NSMutableArray *attendees;
+  NSString       *comment;
+  NSNumber       *sequence;
+  NSString       *location;
+  NSString       *status;
+}
+
+/* accessors */
+
+- (void)setUid:(NSString *)_value;
+- (NSString *)uid;
+
+- (void)setSummary:(NSString *)_value;
+- (NSString *)summary;
+
+- (void)setLocation:(NSString *)_value;
+- (NSString *)location;
+
+- (void)setComment:(NSString *)_value;
+- (NSString *)comment;
+
+- (void)setTimeStampAsDate:(NSCalendarDate *)_date;
+- (NSCalendarDate *)timeStampAsDate;
+
+- (void)setStartDate:(NSCalendarDate *)_date;
+- (NSCalendarDate *)startDate;
+
+- (void)setLastModified:(NSCalendarDate *)_value;
+- (NSCalendarDate *)lastModified;
+
+- (void)setCreated:(NSCalendarDate *)_value;
+- (NSCalendarDate *)created;
+
+- (void)setAccessClass:(NSString *)_value;
+- (NSString *)accessClass;
+
+- (void)setPriority:(NSString *)_value;
+- (NSString *)priority;
+
+- (void)setSequence:(NSNumber *)_value; /* this is an int */
+- (NSNumber *)sequence;
+
+- (void)setOrganizer:(iCalPerson *)_organizer;
+- (iCalPerson *)organizer;
+
+- (void)setStatus:(NSString *)_value;
+- (NSString *)status;
+
+- (void)removeAllAttendees;
+- (void)addToAttendees:(iCalPerson *)_person;
+- (NSArray *)attendees;
+
+- (void)removeAllAlarms;
+- (void)addToAlarms:(id)_alarm;
+- (NSArray *)alarms;
+- (BOOL)hasAlarms;
+
+@end
+
+#endif /* __NGiCal_iCalEntityObject_H__ */
diff --git a/skyrix-core/NGiCal/iCalEntityObject.m b/skyrix-core/NGiCal/iCalEntityObject.m
new file mode 100644 (file)
index 0000000..297b8a1
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalEntityObject.h"
+#include "iCalPerson.h"
+#include "common.h"
+
+
+@implementation iCalEntityObject
+
+- (void)dealloc {
+  [self->status       release];
+  [self->location     release];
+  [self->sequence     release];
+  [self->startDate    release];
+  [self->comment      release];
+  [self->uid          release];
+  [self->summary      release];
+  [self->created      release];
+  [self->lastModified release];
+  [self->startDate    release];
+  [self->accessClass  release];
+  [self->priority     release];
+  [self->alarms       release];
+  [self->organizer    release];
+  [self->attendees    release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setUid:(NSString *)_value {
+  if (self->uid != _value) {
+    [self->uid autorelease];
+    self->uid = [_value retain];
+  }
+}
+- (NSString *)uid {
+  return self->uid;
+}
+
+- (void)setSummary:(NSString *)_value {
+  if (self->summary != _value) {
+    [self->summary autorelease];
+    self->summary = [_value retain];
+  }
+}
+- (NSString *)summary {
+  return self->summary;
+}
+
+- (void)setLocation:(NSString *)_value {
+  if (self->location != _value) {
+    [self->location autorelease];
+    self->location = [_value retain];
+  }
+}
+- (NSString *)location {
+  return self->location;
+}
+
+- (void)setComment:(NSString *)_value {
+  if (self->comment != _value) {
+    [self->comment autorelease];
+    self->comment = [_value retain];
+  }
+}
+- (NSString *)comment {
+  return self->comment;
+}
+
+- (void)setAccessClass:(NSString *)_value {
+  if (self->accessClass != _value) {
+    [self->accessClass autorelease];
+    self->accessClass = [_value retain];
+  }
+}
+- (NSString *)accessClass {
+  return self->accessClass;
+}
+- (void)setPriority:(NSString *)_value {
+  if (self->priority != _value) {
+    [self->priority autorelease];
+    self->priority = [_value retain];
+  }
+}
+- (NSString *)priority {
+  return self->priority;
+}
+
+- (void)setSequence:(NSNumber *)_value {
+  if (![_value isNotNull]) _value = nil;
+  if (self->sequence != _value) {
+    if (_value != nil && ![_value isKindOfClass:[NSNumber class]])
+      _value = [NSNumber numberWithInt:[_value intValue]];
+    [self->sequence autorelease];
+    self->sequence = [_value retain];
+  }
+}
+- (NSNumber *)sequence {
+  return self->sequence;
+}
+
+- (void)setStatus:(NSString *)_value {
+  ASSIGNCOPY(self->status, _value);
+}
+- (NSString *)status {
+  // eg: STATUS:CONFIRMED
+  return self->status;
+}
+
+- (void)setCreated:(NSCalendarDate *)_value {
+  if (self->created != _value) {
+    [self->created autorelease];
+    self->created = [_value retain];
+  }
+}
+- (NSCalendarDate *)created {
+  return self->created;
+}
+- (void)setLastModified:(NSCalendarDate *)_value {
+  if (self->lastModified != _value) {
+    [self->lastModified autorelease];
+    self->lastModified = [_value retain];
+  }
+}
+- (NSCalendarDate *)lastModified {
+  return self->lastModified;
+}
+
+- (void)setTimeStampAsDate:(NSCalendarDate *)_date {
+  /* TODO: too be completed */
+}
+- (NSCalendarDate *)timeStampAsDate {
+  return [NSDate dateWithTimeIntervalSince1970:self->timestamp];
+}
+
+- (void)setStartDate:(NSCalendarDate *)_date {
+  if (self->startDate != _date) {
+    [self->startDate autorelease];
+    self->startDate = [_date retain];
+  }
+}
+- (NSCalendarDate *)startDate {
+  return self->startDate;
+}
+
+- (void)setOrganizer:(iCalPerson *)_organizer {
+  if (self->organizer != _organizer) {
+    [self->organizer autorelease];
+    self->organizer = [_organizer retain];
+  }
+}
+- (iCalPerson *)organizer {
+  return self->organizer;
+}
+
+- (void)removeAllAttendees {
+    [self->attendees removeAllObjects];
+}
+- (void)addToAttendees:(iCalPerson *)_person {
+  if (_person == nil) return;
+  if (self->attendees == nil)
+    self->attendees = [[NSMutableArray alloc] initWithCapacity:4];
+  [self->attendees addObject:_person];
+}
+- (NSArray *)attendees {
+  return self->attendees;
+}
+
+- (void)removeAllAlarms {
+    [self->alarms removeAllObjects];
+}
+- (void)addToAlarms:(id)_alarm {
+  if (_alarm == nil) return;
+  if (self->alarms == nil)
+    self->alarms = [[NSMutableArray alloc] initWithCapacity:1];
+  [self->alarms addObject:_alarm];
+}
+- (BOOL)hasAlarms {
+  return [self->alarms count] > 0 ? YES : NO;
+}
+- (NSArray *)alarms {
+  return self->alarms;
+}
+
+@end /* iCalEntityObject */
diff --git a/skyrix-core/NGiCal/iCalEvent.h b/skyrix-core/NGiCal/iCalEvent.h
new file mode 100644 (file)
index 0000000..1559038
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGiCal_iCalEvent_H__
+#define __NGiCal_iCalEvent_H__
+
+#include <NGiCal/iCalEntityObject.h>
+#import <Foundation/NSDate.h>
+
+/*
+  iCalEvent
+  
+  This class keeps the attributes of an iCalendar event record, that is,
+  an appointment.
+*/
+
+@class NSString, NSMutableArray, NSCalendarDate;
+@class iCalPerson;
+
+@interface iCalEvent : iCalEntityObject
+{
+  NSCalendarDate *endDate;
+  NSString       *duration;
+}
+
+/* accessors */
+
+- (void)setEndDate:(NSCalendarDate *)_date;
+- (NSCalendarDate *)endDate;
+- (BOOL)hasEndDate;
+
+- (void)setDuration:(NSString *)_value;
+- (NSString *)duration;
+- (BOOL)hasDuration;
+- (NSTimeInterval)durationAsTimeInterval;
+
+@end 
+
+#endif /* __NGiCal_iCalEvent_H__ */
diff --git a/skyrix-core/NGiCal/iCalEvent.m b/skyrix-core/NGiCal/iCalEvent.m
new file mode 100644 (file)
index 0000000..b97cbc1
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalEvent.h"
+#include "iCalPerson.h"
+#include "common.h"
+
+@interface NSString(DurationTimeInterval)
+- (NSTimeInterval)durationAsTimeInterval;
+@end
+
+@implementation iCalEvent
+
+- (void)dealloc {
+  [self->duration release];
+  [self->endDate  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setEndDate:(NSCalendarDate *)_date {
+  id tmp;
+  if (self->endDate == _date) return;
+  tmp = self->endDate;
+  self->endDate = [_date retain];
+  [tmp release];
+}
+- (NSCalendarDate *)endDate {
+  if ([self hasEndDate])
+    return self->endDate;
+  
+  if ([self hasDuration] && (self->startDate != nil)) {
+    return [[self startDate] dateByAddingYears:0 months:0 days:0
+                            hours:0 minutes:0 
+                            seconds:[self durationAsTimeInterval]];
+  }
+  return nil;
+}
+- (BOOL)hasEndDate {
+  return self->endDate ? YES : NO;
+}
+
+- (void)setTransp:(NSString *)_transp {
+  /* ignore transp ... (used by Evo 'TRANSP:OPAQUE') */
+}
+
+- (void)setDuration:(NSString *)_value {
+  ASSIGNCOPY(self->duration, _value);
+}
+- (NSString *)duration {
+  // eg: "DURATION:PT1H"
+  if ([self hasDuration])
+    return self->duration;
+  
+  // TODO: calculate
+  return nil;
+}
+- (BOOL)hasDuration {
+  return self->duration ? YES : NO;
+}
+- (NSTimeInterval)durationAsTimeInterval {
+  /*
+    eg: DURATION:PT1H
+    P      - "period"
+    P2H30M - "2 hours 30 minutes"
+
+     dur-value  = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
+
+     dur-date   = dur-day [dur-time]
+     dur-time   = "T" (dur-hour / dur-minute / dur-second)
+     dur-week   = 1*DIGIT "W"
+     dur-hour   = 1*DIGIT "H" [dur-minute]
+     dur-minute = 1*DIGIT "M" [dur-second]
+     dur-second = 1*DIGIT "S"
+     dur-day    = 1*DIGIT "D"
+  */
+  
+  if (self->duration)
+    return [self->duration durationAsTimeInterval];
+  
+  if (self->endDate != nil && self->startDate != nil)
+    /* calculate duration using enddate */
+    return [[self endDate] timeIntervalSinceDate:[self startDate]];
+  
+  return 0.0;
+}
+
+/* ical typing */
+
+- (NSString *)entityName {
+  return @"vevent";
+}
+
+/* descriptions */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->uid)       [ms appendFormat:@" uid=%@", self->uid];
+  if (self->startDate) [ms appendFormat:@" from=%@", self->startDate];
+  if (self->endDate)   [ms appendFormat:@" to=%@", self->endDate];
+  if (self->summary)   [ms appendFormat:@" summary=%@", self->summary];
+  
+  if (self->organizer)
+    [ms appendFormat:@" organizer=%@", self->organizer];
+  if (self->attendees)
+    [ms appendFormat:@" attendees=%@", self->attendees];
+  
+  if ([self hasAlarms])
+    [ms appendFormat:@" alarms=%@", self->alarms];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* iCalEvent */
+
+@implementation NSString(DurationTimeInterval)
+
+- (NSTimeInterval)durationAsTimeInterval {
+  /*
+    eg: DURATION:PT1H
+    P      - "period"
+    P2H30M - "2 hours 30 minutes"
+
+     dur-value  = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
+
+     dur-date   = dur-day [dur-time]
+     dur-time   = "T" (dur-hour / dur-minute / dur-second)
+     dur-week   = 1*DIGIT "W"
+     dur-hour   = 1*DIGIT "H" [dur-minute]
+     dur-minute = 1*DIGIT "M" [dur-second]
+     dur-second = 1*DIGIT "S"
+     dur-day    = 1*DIGIT "D"
+  */
+  unsigned       i, len;
+  NSTimeInterval ti;
+  BOOL           isTime;
+  int            val;
+    
+  if (![self hasPrefix:@"P"]) {
+    NSLog(@"Cannot parse iCal duration value: '%@'", self);
+    return 0.0;
+  }
+    
+  ti  = 0.0;
+  val = 0;
+  for (i = 1, len = [self length], isTime = NO; i < len; i++) {
+    unichar c;
+      
+    c = [self characterAtIndex:i];
+    if (c == 't' || c == 'T') {
+      isTime = YES;
+      val = 0;
+      continue;
+    }
+      
+    if (isdigit(c)) {
+      val = (val * 10) + (c - 48);
+      continue;
+    }
+      
+    switch (c) {
+    case 'W': /* week */
+      ti += (val * 7 * 24 * 60 * 60);
+      break;
+    case 'D': /* day  */
+      ti += (val * 24 * 60 * 60);
+      break;
+    case 'H': /* hour */
+      ti += (val * 60 * 60);
+      break;
+    case 'M': /* min  */
+      ti += (val * 60);
+      break;
+    case 'S': /* sec  */
+      ti += val;
+      break;
+    default:
+      [self logWithFormat:@"cannot process duration unit: '%c'", c];
+      break;
+    }
+    val = 0;
+  }
+  return ti;
+}
+
+@end /* NSString(DurationTimeInterval) */
diff --git a/skyrix-core/NGiCal/iCalFreeBusy.h b/skyrix-core/NGiCal/iCalFreeBusy.h
new file mode 100644 (file)
index 0000000..06f9679
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGiCal_iCalFreeBusy_H__
+#define __NGiCal_iCalFreeBusy_H__
+
+#include <NGiCal/iCalObject.h>
+
+@class NSString, NSMutableArray, NSCalendarDate;
+@class iCalPerson;
+
+@interface iCalFreeBusy : iCalObject
+{
+  NSCalendarDate *startDate;
+  NSCalendarDate *endDate;
+  iCalPerson     *organizer;
+  NSString       *url;
+  
+  NSMutableArray *entries;
+}
+
+@end
+
+#endif /* __NGiCal_iCalFreeBusy_H__ */
diff --git a/skyrix-core/NGiCal/iCalFreeBusy.m b/skyrix-core/NGiCal/iCalFreeBusy.m
new file mode 100644 (file)
index 0000000..1c8b330
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalFreeBusy.h"
+#include "iCalPerson.h"
+#include "common.h"
+
+@implementation iCalFreeBusy
+
+- (void)dealloc {
+  [self->entries   release];
+  [self->organizer release];
+  [self->startDate release];
+  [self->endDate   release];
+  [self->url       release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setUrl:(NSString *)_url {
+  ASSIGN(self->url, _url);
+}
+- (NSString *)url {
+  return self->url;
+}
+
+- (void)setStartDate:(NSCalendarDate *)_date {
+  ASSIGN(self->startDate, _date);
+}
+- (NSCalendarDate *)startDate {
+  return self->startDate;
+}
+
+- (void)setEndDate:(NSCalendarDate *)_date {
+  ASSIGN(self->endDate, _date);
+}
+- (NSCalendarDate *)endDate {
+  return self->endDate;
+}
+
+- (void)setOrganizer:(iCalPerson *)_organizer {
+  ASSIGN(self->organizer, _organizer);
+}
+- (iCalPerson *)organizer {
+  return self->organizer;
+}
+
+- (void)addToEntries:(id)_obj {
+  if (_obj == nil) return;
+  if (self->entries == nil)
+    self->entries = [[NSMutableArray alloc] initWithCapacity:1];
+  [self->entries addObject:_obj];
+}
+
+/* ical typing */
+
+- (NSString *)entityName {
+  return @"vfreebusy";
+}
+
+/* descriptions */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->startDate) [ms appendFormat:@" from=%@", self->startDate];
+  if (self->endDate)   [ms appendFormat:@" to=%@", self->endDate];
+  
+  if (self->organizer)
+    [ms appendFormat:@" organizer=%@", self->organizer];
+  
+  if ([self->entries count] > 0)
+    [ms appendFormat:@" %@", self->entries];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* iCalFreeBusy */
diff --git a/skyrix-core/NGiCal/iCalJournal.h b/skyrix-core/NGiCal/iCalJournal.h
new file mode 100644 (file)
index 0000000..007380c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGiCal_iCalJournal_H__
+#define __NGiCal_iCalJournal_H__
+
+#include <NGiCal/iCalObject.h>
+
+@interface iCalJournal : iCalObject
+{
+}
+
+@end
+
+#endif /* __NGiCal_iCalJournal_H__ */
diff --git a/skyrix-core/NGiCal/iCalJournal.m b/skyrix-core/NGiCal/iCalJournal.m
new file mode 100644 (file)
index 0000000..b81b647
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalJournal.h"
+#include "common.h"
+
+@implementation iCalJournal
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* ical typing */
+
+- (NSString *)entityName {
+  return @"vjournal";
+}
+
+/* descriptions */
+
+@end /* iCalJournal */
diff --git a/skyrix-core/NGiCal/iCalObject.h b/skyrix-core/NGiCal/iCalObject.h
new file mode 100644 (file)
index 0000000..0ed2228
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGiCal_iCalObject_H__
+#define __NGiCal_iCalObject_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSDate.h>
+
+/*
+  iCalObject
+
+  A common base class for all iCal objects. Does some patches on key-value
+  coding.
+*/
+
+@class NSTimeZone;
+
+@interface iCalObject : NSObject
+{
+}
+
+// what shall we take, if no timeZone is specified in dateValues
++ (void)setICalDefaultTimeZone:(NSTimeZone *)_timeZone;
++ (NSTimeZone *)iCalDefaultTimeZone;
+
+@end
+
+
+
+#endif /* __NGiCal_iCalObject_H__ */
diff --git a/skyrix-core/NGiCal/iCalObject.m b/skyrix-core/NGiCal/iCalObject.m
new file mode 100644 (file)
index 0000000..f31ac09
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalObject.h"
+#include "common.h"
+
+@implementation iCalObject
+
+// what shall we take, if no timeZone is specified in dateValues
+static NSTimeZone *defTZ = nil;
++ (void)setICalDefaultTimeZone:(NSTimeZone *)_timeZone {
+  ASSIGNCOPY(defTZ,_timeZone);
+}
++ (NSTimeZone *)iCalDefaultTimeZone {
+  return defTZ;
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* KVC */
+
+- (void)takeValue:(id)_value forXKey:(id)_key {
+  /* extended keys are ignored by default */
+}
+
+- (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
+  if ([_key hasPrefix:@"X-"]) {
+    [self takeValue:_value forXKey:_key];
+  }
+  else {
+    NSLog(@"0x%08x[%@]: ignoring attempt to set unbound key '%@'",
+         self, NSStringFromClass([self class]), _key);
+  }
+}
+
+@end /* iCalObject */
diff --git a/skyrix-core/NGiCal/iCalPerson.h b/skyrix-core/NGiCal/iCalPerson.h
new file mode 100644 (file)
index 0000000..7b670c7
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGiCal_iCalPerson_H__
+#define __NGiCal_iCalPerson_H__
+
+#include <NGiCal/iCalObject.h>
+
+@interface iCalPerson : iCalObject
+{
+  NSString *cn;
+  NSString *email;
+  NSString *rsvp;     /* FALSE           */
+  NSString *partStat; /* ACCEPTED        */
+  NSString *role;     /* REQ-PARTICIPANT */
+  NSString *xuid;     /* x22sAAHFf       */
+}
+
+/* accessors */
+
+- (void)setCn:(NSString *)_s;
+- (NSString *)cn;
+
+- (void)setEmail:(NSString *)_s;
+- (NSString *)email;
+
+- (void)setRsvp:(NSString *)_s;
+- (NSString *)rsvp;
+
+- (void)setXuid:(NSString *)_s;
+- (NSString *)xuid;
+
+- (void)setRole:(NSString *)_s;
+- (NSString *)role;
+
+- (void)setPartStat:(NSString *)_s;
+- (NSString *)partStat;
+
+@end
+
+#endif /* __NGiCal_iCalPerson_H__ */
diff --git a/skyrix-core/NGiCal/iCalPerson.m b/skyrix-core/NGiCal/iCalPerson.m
new file mode 100644 (file)
index 0000000..a537156
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalPerson.h"
+#include "common.h"
+
+@implementation iCalPerson
+
+- (void)dealloc {
+  [self->rsvp     release];
+  [self->partStat release];
+  [self->role     release];
+  [self->xuid     release];
+  [self->email release];
+  [self->cn    release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setCn:(NSString *)_s {
+  ASSIGNCOPY(self->cn, _s);
+}
+- (NSString *)cn {
+  return self->cn;
+}
+
+- (void)setEmail:(NSString *)_s {
+  ASSIGNCOPY(self->email, _s);
+}
+- (NSString *)email {
+  return self->email;
+}
+
+- (void)setRsvp:(NSString *)_s {
+  ASSIGNCOPY(self->rsvp, _s);
+}
+- (NSString *)rsvp {
+  return self->rsvp;
+}
+
+- (void)setXuid:(NSString *)_s {
+  ASSIGNCOPY(self->xuid, _s);
+}
+- (NSString *)xuid {
+  return self->xuid;
+}
+
+- (void)setRole:(NSString *)_s {
+  ASSIGNCOPY(self->role, _s);
+}
+- (NSString *)role {
+  return self->role;
+}
+
+- (void)setPartStat:(NSString *)_s {
+  ASSIGNCOPY(self->partStat, _s);
+}
+- (NSString *)partStat {
+  return self->partStat;
+}
+
+/* descriptions */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->cn)       [ms appendFormat:@" cn=%@",     self->cn];
+  if (self->email)    [ms appendFormat:@" email=%@",  self->email];
+  if (self->role)     [ms appendFormat:@" role=%@",   self->role];
+  if (self->xuid)     [ms appendFormat:@" uid=%@",    self->xuid];
+  if (self->partStat) [ms appendFormat:@" status=%@", self->partStat];
+  if (self->rsvp)     [ms appendFormat:@" rsvp=%@",   self->rsvp];
+
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* iCalPerson */
diff --git a/skyrix-core/NGiCal/iCalToDo.h b/skyrix-core/NGiCal/iCalToDo.h
new file mode 100644 (file)
index 0000000..8d54e11
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGiCal_iCalToDo_H__
+#define __NGiCal_iCalToDo_H__
+
+#include <NGiCal/iCalEntityObject.h>
+
+/*
+  iCalToDo
+  
+  This class keeps the attributes of an iCalendar todo record (a task).
+*/
+
+@class NSString, NSCalendarDate;
+
+@interface iCalToDo : iCalEntityObject
+{
+  NSCalendarDate *due;
+  NSString       *percentComplete;
+  NSCalendarDate *completed;
+}
+
+- (void)setPercentComplete:(NSString *)_value;
+- (NSString *)percentComplete;
+
+- (void)setDue:(NSCalendarDate *)_date;
+- (NSCalendarDate *)due;
+
+- (void)setCompleted:(NSCalendarDate *)_date;
+- (NSCalendarDate *)completed;
+
+@end
+
+#endif /* __NGiCal_iCalToDo_H__ */
diff --git a/skyrix-core/NGiCal/iCalToDo.m b/skyrix-core/NGiCal/iCalToDo.m
new file mode 100644 (file)
index 0000000..7fb58bb
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalToDo.h"
+#include "common.h"
+
+@implementation iCalToDo
+
+- (void)dealloc {
+  [self->accessClass     release];
+  [self->percentComplete release];
+  [self->completed release];
+  [self->sequence  release];
+  [self->uid       release];
+  [self->summary   release];
+  [self->startDate release];
+  [self->due       release];
+  [self->priority  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setPercentComplete:(NSString *)_value {
+  ASSIGN(self->percentComplete, _value);
+}
+- (NSString *)percentComplete {
+  return self->percentComplete;
+}
+
+- (void)setDue:(NSCalendarDate *)_date {
+  ASSIGN(self->due, _date);
+}
+- (NSCalendarDate *)due {
+  return self->due;
+}
+
+- (void)setCompleted:(NSCalendarDate *)_date {
+  ASSIGN(self->completed, _date);
+}
+- (NSCalendarDate *)completed {
+  return self->completed;
+}
+
+/* ical typing */
+
+- (NSString *)entityName {
+  return @"vtodo";
+}
+
+/* descriptions */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->uid)       [ms appendFormat:@" uid=%@", self->uid];
+  if (self->startDate) [ms appendFormat:@" start=%@", self->startDate];
+  if (self->due)       [ms appendFormat:@" due=%@", self->due];
+  if (self->priority)  [ms appendFormat:@" pri=%@", self->priority];
+
+  if (self->completed) 
+    [ms appendFormat:@" completed=%@", self->completed];
+  if (self->percentComplete) 
+    [ms appendFormat:@" complete=%@", self->percentComplete];
+  if (self->accessClass) 
+    [ms appendFormat:@" class=%@", self->accessClass];
+  
+  if (self->summary)
+    [ms appendFormat:@" summary=%@", self->summary];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* iCalToDo */
diff --git a/skyrix-core/NGiCal/iCalTrigger.h b/skyrix-core/NGiCal/iCalTrigger.h
new file mode 100644 (file)
index 0000000..7479a02
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGiCal_iCalTrigger_H__
+#define __NGiCal_iCalTrigger_H__
+
+#include <NGiCal/iCalObject.h>
+
+@interface iCalTrigger : iCalObject
+{
+  NSString *valueType; /* value type, eg "duration" */
+  NSString *value;
+}
+
+- (NSString *)valueType;
+- (NSString *)value;
+
+@end
+
+#endif /* __NGiCal_iCalTrigger_H__ */
diff --git a/skyrix-core/NGiCal/iCalTrigger.m b/skyrix-core/NGiCal/iCalTrigger.m
new file mode 100644 (file)
index 0000000..32b3d4d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "iCalTrigger.h"
+#include "common.h"
+
+@implementation iCalTrigger
+
+- (void)dealloc {
+  [self->value     release];
+  [self->valueType release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setValue:(NSString *)_value {
+  ASSIGNCOPY(self->value, _value);
+}
+- (NSString *)value {
+  return self->value;
+}
+
+- (void)setValueType:(NSString *)_value {
+  ASSIGNCOPY(self->valueType, _value);
+}
+- (NSString *)valueType {
+  return self->valueType;
+}
+
+/* descriptions */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->valueType)
+    [ms appendFormat:@" type=%@", self->valueType];
+  if (self->value)
+    [ms appendFormat:@" value=%@", self->value];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* iCalTrigger */
diff --git a/skyrix-core/PROJECTLEAD b/skyrix-core/PROJECTLEAD
new file mode 100644 (file)
index 0000000..ab0c70a
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+PROJECTLEAD=helge.hess@opengroupware.org
diff --git a/skyrix-core/README b/skyrix-core/README
new file mode 100644 (file)
index 0000000..05c3ee2
--- /dev/null
@@ -0,0 +1,27 @@
+# $Id$
+
+This repository contains the core libraries of the SKYRiX application
+server, that is, extensions to the Foundation library (NGExtensions),
+streaming IO and network classes (NGStreams), libraries for datastore
+abstractions (EOControl), library for MIME and mail processing (NGMime).
+
+
+MacOSX Notes
+============
+Locations:
+currently some fixed pathes to /Users/helge/build might be used in the
+project. those need to be fixed to use variables.
+
+Precompiled Headers:
+I did not find out how to setup precompiled headers to support a
+MACOSX_DEPLOYMENT_TARGET=10.2, if this option is set, compilation
+throws a mass of warnings about __CONSTANT_CFSTRINGS__ and cannot
+use precompiled Foundation headers.
+Something like this:
+  fixPrecomps -force \
+    -precompFlags "-D__CONSTANT_CFSTRINGS__" \
+    -all
+did not work out. Suggestions are welcome ...
+
+Prebinding:
+doesn't work yet, needs to be checked
diff --git a/skyrix-core/README-OSX.txt b/skyrix-core/README-OSX.txt
new file mode 100644 (file)
index 0000000..c722ff3
--- /dev/null
@@ -0,0 +1,140 @@
+# $Id$
+
+Building Notes
+==============
+
+Prerequisites:
+- Apple Developer Tools
+- skyrix-xml
+
+There are two ways to build SOPE on MacOSX, either using the gnustep-make
+package or as native Xcode projects. The first option is usually used when
+you build SOPE for use with OGo, while the latter is more appropriate for
+SOPE:X applications.
+
+Building using gstep-make:
+==========================
+
+First install gnustep-make (eg v1.8), then ensure that GNUstep.sh is properly
+sources. For the build just enter:
+  make -s install
+or
+  make -s debug=yes install
+if you build with debug informations.
+
+Building using Xcode:
+=====================
+
+The Xcode build comes in two variants, one for development and the other for
+deployment.
+
+
+Development
+-----------
+Development usually means you're happily hacking away at your pet
+projects and sometimes want to update the SOPE frameworks. For this purpose
+use the "all" target and the accompanied "Development" build style. Later,
+you can narrow the target down to something more specific. For development we
+assume the destination for frameworks to be /Library/Frameworks. Once you are
+done building all the frameworks the loader commands of the frameworks will
+have that destination path built in. In order to use the frameworks you either
+have to install them (by copying them manually to their destination) or to
+prepare symlinks from /Library/Frameworks to the place where the built products
+are. I usually build everything in a central place (i.e. /Local/BuildArea) and
+have symlinks from /Library/Frameworks to /Local/BuildArea for each of the
+products.
+
+Also the following products are expected to be in the following locations:
+*.sax -> /Library/SaxDrivers
+*.sxp -> /Library/SoProducts
+
+Either copy them to the appropriate places or symlink them (my suggestion).
+
+
+Deployment
+----------
+Deployment in our terms means you want to copy all required SOPE products into
+an application's app wrapper. For this step all frameworks need to be built in
+a special fashion, as the "install_name" of the frameworks needs to be prepared
+to point to a relative path in the app wrapper. The situation is even more
+complicated as all frameworks during linking store the "install names" of other
+frameworks in their mach loader commands. In order for this step not to break
+we need to set up an environment which is clearly separated from the
+Development environment. I chose to use $(USER_LIBRARY_DIR)/EmbeddedFrameworks
+as the default destination for these builds. In order for your application to
+easily pick up the built products and copy them into its app wrapper this
+location needs to be fixed and easily accessible. Note that on my system
+~/Library/EmbeddedFrameworks is a symlink to /Library/EmbeddedFrameworks so
+even if you don't like the location at all it's very easy to point it to 
+somewhere else. As soon as you have set this up you can use the
+"Wrapper Contents" target with the accompanied "Wrapper" build style to build
+all wrapper contents in the appropriate fashion. When you're done you can copy
+all the wrapper products into your application's wrapper. The expected
+destination is the "Frameworks" directory in the wrappers "Contents" directory.
+For a complete list of what you need to copy into your application's wrapper
+see the "Direct Dependencies" of all "Wrapper Contents" targets in all SOPE
+related projects. At the time of this writing the complete list for SOPE
+consisted of the following:
+
+SxXML
+  SaxObjC.framework
+  DOM.framework
+  XmlRpc.framework
+
+SxCore
+  EOControl.framework
+  NGExtensions.framework
+  NGStreams.framework
+  NGMime.framework
+  NGImap4.framework
+  NGLdap.framework
+  NGMail.framework
+  NGiCal.framework
+
+
+Note: "A word on umbrellas"
+      The general idea of umbrellas is to make life easier by providing a cover
+      for linking. In an ideal world we would provide a SOPE umbrella (we 
+      actually do that) and you just link against that and forget about the
+      complete list. However, with the "Wrapper" style things do not work that
+      way. Because the "install name"s of all frameworks are relative paths,
+      during linking the mach dyld cannot find the dependend frameworks
+      (because the path isn't absolute) and thus symbol checking fails. This
+      directly leads to prebinding to fail which we really don't want since we
+      have such a huge dependency tree and prebinding escpecially in our case
+      speeds up loading significantly. So, umbrellas do not really help with
+      "Wrapper" products - in fact they just add to the overall dependency
+      graph without providing any benefit. With the notable exception of the
+      "Development" build style umbrellas are totally useless. If you're
+      not planning to do a "Wrapper" deployment you might be happy to have
+      the umbrellas, however, that's why they are still here.
+
+Note: You cannot use the -buildAllTargets commandline argument for Xcode,
+      because the Xcode projects also contain a target to build in the
+      gstep-make environment (called GSM:all)
+
+
+Prebinding Notes
+================
+
+General technical information about prebinding is available from Apple at
+http://developer.apple.com/documentation/Performance/Conceptual/LaunchTime/Tasks/Prebinding.html#//apple_ref/doc/uid/20001858.
+
+OGo frameworks currently use the range from 0xC0000000 to 0xCFFFFFFF.
+
+Any questions and feedback regarding our use of this range should go to
+Marcus Müller <znek@mulle-kybernetik.com>.
+
+
+SxCore: 0xC1000000 - 0xC2FFFFFF
+===============================
+
+0xC1000000 EOControl
+0xC1200000 NGExtensions
+0xC1400000 NGStreams
+0xC1600000 NGImap4 [not available with gstep-make]
+0xC1800000 NGMail  [not available with gstep-make]
+0xC1A00000 NGMime  [used as base in gstep-make]
+0xC1C00000 NGLdap
+0xC1E00000 NGiCal
+0xC2FF0000 SxCore
diff --git a/skyrix-core/SxCore-Info.plist b/skyrix-core/SxCore-Info.plist
new file mode 100644 (file)
index 0000000..d90ae9f
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SxCore</string>
+       <key>CFBundleIdentifier</key>
+       <string>org.OpenGroupware.SOPE.SxCore</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-core/SxCore.xcode/project.pbxproj b/skyrix-core/SxCore.xcode/project.pbxproj
new file mode 100644 (file)
index 0000000..12a7a16
--- /dev/null
@@ -0,0 +1,12995 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 39;
+       objects = {
+               AD0CE00A05D950D9004D9B87 = {
+                       fileEncoding = 5;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       tabWidth = 4;
+                       usesTabs = 1;
+               };
+               AD16270E05D91F6300A7368D = {
+                       fileEncoding = 5;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = "README-OSX.txt";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD16271C05D934F700A7368D = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       name = Foundation.framework;
+                       path = /System/Library/Frameworks/Foundation.framework;
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               AD16271D05D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16271E05D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16271F05D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272005D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272105D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272205D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272305D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272405D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272505D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272605D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272705D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272805D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272905D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD16272A05D934F700A7368D = {
+                       fileRef = AD16271C05D934F700A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1802550611DB7C00ED723F = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = "compiled.mach-o.dylib";
+                       name = libz.dylib;
+                       path = /usr/lib/libz.1.dylib;
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               AD1802560611DB7C00ED723F = {
+                       fileRef = AD1802550611DB7C00ED723F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1802570611DBD300ED723F = {
+                       fileRef = AD1802550611DB7C00ED723F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1803260611DE9B00ED723F = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+German.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1803270611DE9B00ED723F = {
+                       fileRef = AD1803260611DE9B00ED723F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1803280611DEFE00ED723F = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSString+German.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1803290611DEFE00ED723F = {
+                       fileRef = AD1803280611DEFE00ED723F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD5221D706A7E07400B24132 = {
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "all Frameworks";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       dependencies = (
+                               AD5221D906A7E0CF00B24132,
+                               AD5221DB06A7E0CF00B24132,
+                               AD5221DD06A7E0CF00B24132,
+                               AD5221DF06A7E0CF00B24132,
+                               AD5221E106A7E0CF00B24132,
+                               AD5221E306A7E0CF00B24132,
+                               AD5221E506A7E0CF00B24132,
+                               AD5221E706A7E0CF00B24132,
+                       );
+                       isa = PBXAggregateTarget;
+                       name = "Wrapper Contents";
+                       productName = "all Frameworks";
+               };
+               AD5221D806A7E0CF00B24132 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF629055DCB17006FE529;
+                       remoteInfo = EOControl;
+               };
+               AD5221D906A7E0CF00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF629055DCB17006FE529;
+                       targetProxy = AD5221D806A7E0CF00B24132;
+               };
+               AD5221DA06A7E0CF00B24132 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF632055DCB38006FE529;
+                       remoteInfo = NGExtensions;
+               };
+               AD5221DB06A7E0CF00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF632055DCB38006FE529;
+                       targetProxy = AD5221DA06A7E0CF00B24132;
+               };
+               AD5221DC06A7E0CF00B24132 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF63A055DCB43006FE529;
+                       remoteInfo = NGStreams;
+               };
+               AD5221DD06A7E0CF00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF63A055DCB43006FE529;
+                       targetProxy = AD5221DC06A7E0CF00B24132;
+               };
+               AD5221DE06A7E0CF00B24132 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8BA2119055F032600AD687B;
+                       remoteInfo = NGImap4;
+               };
+               AD5221DF06A7E0CF00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E8BA2119055F032600AD687B;
+                       targetProxy = AD5221DE06A7E0CF00B24132;
+               };
+               AD5221E006A7E0CF00B24132 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8BA2121055F033F00AD687B;
+                       remoteInfo = NGMail;
+               };
+               AD5221E106A7E0CF00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E8BA2121055F033F00AD687B;
+                       targetProxy = AD5221E006A7E0CF00B24132;
+               };
+               AD5221E206A7E0CF00B24132 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF642055DCB4D006FE529;
+                       remoteInfo = NGMime;
+               };
+               AD5221E306A7E0CF00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF642055DCB4D006FE529;
+                       targetProxy = AD5221E206A7E0CF00B24132;
+               };
+               AD5221E406A7E0CF00B24132 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81E06A4055E6E35006FE529;
+                       remoteInfo = NGLdap;
+               };
+               AD5221E506A7E0CF00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E81E06A4055E6E35006FE529;
+                       targetProxy = AD5221E406A7E0CF00B24132;
+               };
+               AD5221E606A7E0CF00B24132 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF653055DCB62006FE529;
+                       remoteInfo = NGiCal;
+               };
+               AD5221E706A7E0CF00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF653055DCB62006FE529;
+                       targetProxy = AD5221E606A7E0CF00B24132;
+               };
+               AD5226CB06A7F0C200B24132 = {
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               DEPLOYMENT_LOCATION = NO;
+                               DEPLOYMENT_POSTPROCESSING = YES;
+                               DSTROOT = /;
+                               DYLIB_INSTALL_NAME_BASE = "@executable_path/../Frameworks/";
+                               FRAMEWORK_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_OPTIMIZATION_LEVEL = 3;
+                               GCC_PREPROCESSOR_DEFINITIONS = "APPLE_RUNTIME=1 NeXT_Foundation_LIBRARY=1 COCOA_Foundation_LIBRARY=1 NeXT_RUNTIME=1 COMPILE_AS_FRAMEWORK=1";
+                               SKIP_INSTALL = YES;
+                               SYMROOT = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+                               TEMP_DIR = "$(SYMROOT)/$(PROJECT_NAME).build";
+                               UNSTRIPPED_PRODUCT = NO;
+                               ZERO_LINK = NO;
+                       };
+                       isa = PBXBuildStyle;
+                       name = Wrapper;
+               };
+               AD52282A06A7F3AE00B24132 = {
+                       children = (
+                               AD52283306A7F42E00B24132,
+                               AD52283206A7F42E00B24132,
+                               AD52283406A7F42E00B24132,
+                       );
+                       isa = PBXGroup;
+                       name = SxXML;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD52283206A7F42E00B24132 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = DOM.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               AD52283306A7F42E00B24132 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = SaxObjC.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               AD52283406A7F42E00B24132 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = XmlRpc.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               AD52283506A7F42E00B24132 = {
+                       fileRef = AD52283206A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD52283606A7F42E00B24132 = {
+                       fileRef = AD52283306A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD52283706A7F42E00B24132 = {
+                       fileRef = AD52283406A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD52285F06A7F47500B24132 = {
+                       fileRef = AD52283206A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD52286006A7F48F00B24132 = {
+                       fileRef = AD52283306A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD52287806A7F5B400B24132 = {
+                       fileRef = AD52283206A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD52287906A7F5B400B24132 = {
+                       fileRef = AD52283306A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD52287A06A7F62000B24132 = {
+                       fileRef = AD52283206A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD52287B06A7F62000B24132 = {
+                       fileRef = AD52283306A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD70A4EA06A8B20100D4CE98 = {
+                       fileRef = AD52283306A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD73C3F906D10BAD00226A2D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGCalendarDateRange.m;
+                       path = NGExtensions/NGCalendarDateRange.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD73C3FA06D10BAD00226A2D = {
+                       fileRef = AD73C3F906D10BAD00226A2D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD73C3FB06D10BDF00226A2D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGCalendarDateRange.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD73C3FC06D10BDF00226A2D = {
+                       fileRef = AD73C3FB06D10BDF00226A2D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD853AA506A7F7F300727CA0 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       name = LDAP.framework;
+                       path = /System/Library/Frameworks/LDAP.framework;
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               AD853AA706A7F7F300727CA0 = {
+                       fileRef = AD853AA506A7F7F300727CA0;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD853AAB06A7F84400727CA0 = {
+                       fileRef = AD52283306A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD853AAC06A7F86E00727CA0 = {
+                       fileRef = AD52283206A7F42E00B24132;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB6FBF05C05BC8009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB6FC005C05BC8009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB6FC105C05BC8009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADDB70D605C05DC1009DBFB4,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB6FC205C05BC8009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD16272505D934F700A7368D,
+                               ADDB70C405C05C27009DBFB4,
+                               ADDB70C505C05C27009DBFB4,
+                               ADDB70C605C05C27009DBFB4,
+                               ADDB70C705C05C27009DBFB4,
+                               ADDB70C805C05C27009DBFB4,
+                               ADDB70C905C05C27009DBFB4,
+                               ADDB70CA05C05C27009DBFB4,
+                               ADDB70CB05C05C27009DBFB4,
+                               AD52283506A7F42E00B24132,
+                               AD52283606A7F42E00B24132,
+                               AD52283706A7F42E00B24132,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB6FC305C05BC8009DBFB4 = {
+                       buildPhases = (
+                               ADDB6FBF05C05BC8009DBFB4,
+                               ADDB6FC005C05BC8009DBFB4,
+                               ADDB6FC105C05BC8009DBFB4,
+                               ADDB6FC205C05BC8009DBFB4,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "SxCore-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC2FF0000 -sub_umbrella EOControl -sub_umbrella NGExtensions -sub_umbrella NGStreams -sub_umbrella NGImap4 -sub_umbrella NGMail -sub_umbrella NGMime -sub_umbrella NGLdap -sub_umbrella NGiCal -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = SxCore;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                               ADDB6FC705C05BE0009DBFB4,
+                               ADDB6FC905C05BE0009DBFB4,
+                               ADDB6FCB05C05BE0009DBFB4,
+                               ADDB6FCD05C05BE0009DBFB4,
+                               ADDB6FCF05C05BE0009DBFB4,
+                               ADDB6FD105C05BE0009DBFB4,
+                               ADDB6FD305C05BE0009DBFB4,
+                               ADDB6FD505C05BE0009DBFB4,
+                       );
+                       isa = PBXNativeTarget;
+                       name = "SxCore (Umbrella)";
+                       productName = SxCore;
+                       productReference = ADDB6FC405C05BC8009DBFB4;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SxCore</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.SxCore</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               ADDB6FC405C05BC8009DBFB4 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = SxCore.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               ADDB6FC505C05BC9009DBFB4 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       path = "SxCore-Info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADDB6FC605C05BE0009DBFB4 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF629055DCB17006FE529;
+                       remoteInfo = EOControl;
+               };
+               ADDB6FC705C05BE0009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF629055DCB17006FE529;
+                       targetProxy = ADDB6FC605C05BE0009DBFB4;
+               };
+               ADDB6FC805C05BE0009DBFB4 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF632055DCB38006FE529;
+                       remoteInfo = NGExtensions;
+               };
+               ADDB6FC905C05BE0009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF632055DCB38006FE529;
+                       targetProxy = ADDB6FC805C05BE0009DBFB4;
+               };
+               ADDB6FCA05C05BE0009DBFB4 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF63A055DCB43006FE529;
+                       remoteInfo = NGStreams;
+               };
+               ADDB6FCB05C05BE0009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF63A055DCB43006FE529;
+                       targetProxy = ADDB6FCA05C05BE0009DBFB4;
+               };
+               ADDB6FCC05C05BE0009DBFB4 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8BA2119055F032600AD687B;
+                       remoteInfo = NGImap4;
+               };
+               ADDB6FCD05C05BE0009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E8BA2119055F032600AD687B;
+                       targetProxy = ADDB6FCC05C05BE0009DBFB4;
+               };
+               ADDB6FCE05C05BE0009DBFB4 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8BA2121055F033F00AD687B;
+                       remoteInfo = NGMail;
+               };
+               ADDB6FCF05C05BE0009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E8BA2121055F033F00AD687B;
+                       targetProxy = ADDB6FCE05C05BE0009DBFB4;
+               };
+               ADDB6FD005C05BE0009DBFB4 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF642055DCB4D006FE529;
+                       remoteInfo = NGMime;
+               };
+               ADDB6FD105C05BE0009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF642055DCB4D006FE529;
+                       targetProxy = ADDB6FD005C05BE0009DBFB4;
+               };
+               ADDB6FD205C05BE0009DBFB4 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81E06A4055E6E35006FE529;
+                       remoteInfo = NGLdap;
+               };
+               ADDB6FD305C05BE0009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81E06A4055E6E35006FE529;
+                       targetProxy = ADDB6FD205C05BE0009DBFB4;
+               };
+               ADDB6FD405C05BE0009DBFB4 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF653055DCB62006FE529;
+                       remoteInfo = NGiCal;
+               };
+               ADDB6FD505C05BE0009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF653055DCB62006FE529;
+                       targetProxy = ADDB6FD405C05BE0009DBFB4;
+               };
+               ADDB70C405C05C27009DBFB4 = {
+                       fileRef = E81EF62A055DCB17006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB70C505C05C27009DBFB4 = {
+                       fileRef = E81EF633055DCB38006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB70C605C05C27009DBFB4 = {
+                       fileRef = E81EF63B055DCB43006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB70C705C05C27009DBFB4 = {
+                       fileRef = E81EF643055DCB4D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB70C805C05C27009DBFB4 = {
+                       fileRef = E81EF654055DCB62006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB70C905C05C27009DBFB4 = {
+                       fileRef = E81E06A5055E6E35006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB70CA05C05C27009DBFB4 = {
+                       fileRef = E8BA211A055F032600AD687B;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB70CB05C05C27009DBFB4 = {
+                       fileRef = E8BA2122055F033F00AD687B;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB70D305C05CE5009DBFB4 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = ADDB6FC305C05BC8009DBFB4;
+                       remoteInfo = SxCore;
+               };
+               ADDB70D405C05CE5009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = ADDB6FC305C05BC8009DBFB4;
+                       targetProxy = ADDB70D305C05CE5009DBFB4;
+               };
+               ADDB70D605C05DC1009DBFB4 = {
+                       fileRef = E82093D605B0D70B0088B931;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB75C805C0981B009DBFB4 = {
+                       children = (
+                               E82093D605B0D70B0088B931,
+                               ADDB6FC505C05BC9009DBFB4,
+                       );
+                       isa = PBXGroup;
+                       name = SxCore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+//AD0
+//AD1
+//AD2
+//AD3
+//AD4
+//E80
+//E81
+//E82
+//E83
+//E84
+               E80D72AB05D6BA6E0050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMimeMessageBodyGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72AC05D6BA6E0050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMimeMessageMultipartBodyGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72AD05D6BA6E0050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMimeMessageRfc822BodyGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72AE05D6BA6E0050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMimeMessageTextBodyGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72AF05D6BA6E0050931F = {
+                       fileRef = E80D72AB05D6BA6E0050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D72B005D6BA6E0050931F = {
+                       fileRef = E80D72AC05D6BA6E0050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D72B105D6BA6E0050931F = {
+                       fileRef = E80D72AD05D6BA6E0050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D72B205D6BA6E0050931F = {
+                       fileRef = E80D72AE05D6BA6E0050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D72C805D6BAB10050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeAddressHeaderFieldGenerator.m;
+                       path = NGMime/NGMimeAddressHeaderFieldGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72C905D6BAB10050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeContentDispositionHeaderFieldGenerator.m;
+                       path = NGMime/NGMimeContentDispositionHeaderFieldGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72CA05D6BAB10050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeContentLengthHeaderFieldGenerator.m;
+                       path = NGMime/NGMimeContentLengthHeaderFieldGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72CB05D6BAB10050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeContentTypeHeaderFieldGenerator.m;
+                       path = NGMime/NGMimeContentTypeHeaderFieldGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72CC05D6BAB10050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeHeaderFieldGeneratorSet.m;
+                       path = NGMime/NGMimeHeaderFieldGeneratorSet.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72CD05D6BAB10050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeRFC822DateHeaderFieldGenerator.m;
+                       path = NGMime/NGMimeRFC822DateHeaderFieldGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72CE05D6BAB10050931F = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeStringHeaderFieldGenerator.m;
+                       path = NGMime/NGMimeStringHeaderFieldGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D72CF05D6BAB10050931F = {
+                       fileRef = E80D72C805D6BAB10050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D72D005D6BAB10050931F = {
+                       fileRef = E80D72C905D6BAB10050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D72D105D6BAB10050931F = {
+                       fileRef = E80D72CA05D6BAB10050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D72D205D6BAB10050931F = {
+                       fileRef = E80D72CB05D6BAB10050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D72D305D6BAB10050931F = {
+                       fileRef = E80D72CC05D6BAB10050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D72D405D6BAB10050931F = {
+                       fileRef = E80D72CD05D6BAB10050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D72D505D6BAB10050931F = {
+                       fileRef = E80D72CE05D6BAB10050931F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE219055EDA6700B28141 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF629055DCB17006FE529;
+                       remoteInfo = EOControl;
+               };
+               E81BE21A055EDA6700B28141 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF629055DCB17006FE529;
+                       targetProxy = E81BE219055EDA6700B28141;
+               };
+               E81BE21B055EDA6700B28141 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF632055DCB38006FE529;
+                       remoteInfo = NGExtensions;
+               };
+               E81BE21C055EDA6700B28141 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF632055DCB38006FE529;
+                       targetProxy = E81BE21B055EDA6700B28141;
+               };
+               E81BE21D055EDA6700B28141 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF63A055DCB43006FE529;
+                       remoteInfo = NGStreams;
+               };
+               E81BE21E055EDA6700B28141 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF63A055DCB43006FE529;
+                       targetProxy = E81BE21D055EDA6700B28141;
+               };
+               E81BE21F055EDA6700B28141 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF642055DCB4D006FE529;
+                       remoteInfo = NGMime;
+               };
+               E81BE220055EDA6700B28141 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF642055DCB4D006FE529;
+                       targetProxy = E81BE21F055EDA6700B28141;
+               };
+               E81BE221055EDA6700B28141 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81E06A4055E6E35006FE529;
+                       remoteInfo = NGLdap;
+               };
+               E81BE222055EDA6700B28141 = {
+                       isa = PBXTargetDependency;
+                       target = E81E06A4055E6E35006FE529;
+                       targetProxy = E81BE221055EDA6700B28141;
+               };
+               E81BE223055EDA6700B28141 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF653055DCB62006FE529;
+                       remoteInfo = NGiCal;
+               };
+               E81BE224055EDA6700B28141 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF653055DCB62006FE529;
+                       targetProxy = E81BE223055EDA6700B28141;
+               };
+               E81BE23A055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = NGMime/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE23B055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = NGMime/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE23C055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = NGMime/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE23D055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = NGMime/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE23E055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = NGMime/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE23F055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = NGMime/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE240055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = libNGMime.def;
+                       path = NGMime/libNGMime.def;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE241055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGConcreteMimeType.h;
+                       path = NGMime/NGConcreteMimeType.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE242055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGConcreteMimeType.m;
+                       path = NGMime/NGConcreteMimeType.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE243055EDACF00B28141 = {
+                       children = (
+                               E81BE280055EDAD100B28141,
+                               E81BE247055EDACF00B28141,
+                               E81BE244055EDACF00B28141,
+                               E81BE245055EDACF00B28141,
+                               E81BE4C0055EDC3600B28141,
+                               E81BE4C3055EDC5B00B28141,
+                               E81BE4C6055EDC6C00B28141,
+                       );
+                       isa = PBXGroup;
+                       name = NGImap4;
+                       path = NGMime/NGImap4;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE244055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE245055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE247055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE248055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE249055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE24A055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE24B055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4Client.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE24C055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4Client.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE24D055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4Context.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE24E055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4Context.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE24F055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4DataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE250055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4DataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE251055EDACF00B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4FileManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE252055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4FileManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE253055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4Folder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE254055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4Folder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE255055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4Functions.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE256055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4Functions.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE257055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NGImap4Message+BodyStructure.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE258055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4Message.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE259055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4Message.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE25A055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4ResponseParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE25B055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4ResponseParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE25C055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4ServerRoot.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE25D055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4ServerRoot.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE25E055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4Support.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE25F055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4Support.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE260055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGSieveClient.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE261055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGSieveClient.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE262055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSString+Imap4.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE263055EDAD000B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+Imap4.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE280055EDAD100B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE29E055EDAD200B28141 = {
+                       children = (
+                               E81BE2D9055EDAD300B28141,
+                               E81BE2A2055EDAD200B28141,
+                               E81BE2A0055EDAD200B28141,
+                               E81BE29F055EDAD200B28141,
+                               E81BE4C9055EDC7A00B28141,
+                               E81BE4CC055EDCA000B28141,
+                               E81BE4CF055EDCAC00B28141,
+                       );
+                       isa = PBXGroup;
+                       name = NGMail;
+                       path = NGMime/NGMail;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE29F055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2A0055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2A1055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2A2055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2A3055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2A4055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = libNGMail.def;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2A5055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMail.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2A6055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMail.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2A7055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMailAddress.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2A8055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMailAddress.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2A9055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMailAddressList.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2AA055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMailAddressList.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2AB055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMailAddressParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2AC055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMailAddressParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2AD055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMailDecls.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2AE055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMBoxReader.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2AF055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMBoxReader.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2B0055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMimeMessage.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2B1055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMimeMessage.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2B2055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMimeMessageGenerator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2B3055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMimeMessageGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2B4055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMimeMessageParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2B5055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGMimeMessageParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2B6055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGPop3Client.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2B7055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGPop3Client.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2B8055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGPop3Support.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2B9055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGPop3Support.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2BA055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGSmtpClient.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2BB055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGSmtpClient.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2BC055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGSmtpReplyCodes.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2BD055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGSmtpSupport.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2BE055EDAD200B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGSmtpSupport.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2D9055EDAD300B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2F4055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = "NGMime-Info.plist";
+                       path = "NGMime/NGMime-Info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2F5055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMime.h;
+                       path = NGMime/NGMime.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2F6055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMime.m;
+                       path = NGMime/NGMime.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2F7055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeBodyGenerator.h;
+                       path = NGMime/NGMimeBodyGenerator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2F8055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeBodyGenerator.m;
+                       path = NGMime/NGMimeBodyGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2F9055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeBodyParser.h;
+                       path = NGMime/NGMimeBodyParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2FA055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeBodyParser.m;
+                       path = NGMime/NGMimeBodyParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2FB055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeBodyPart.h;
+                       path = NGMime/NGMimeBodyPart.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2FC055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeBodyPart.m;
+                       path = NGMime/NGMimeBodyPart.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2FD055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeBodyPartParser.h;
+                       path = NGMime/NGMimeBodyPartParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2FE055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeBodyPartParser.m;
+                       path = NGMime/NGMimeBodyPartParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE2FF055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeDecls.h;
+                       path = NGMime/NGMimeDecls.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE300055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeExceptions.h;
+                       path = NGMime/NGMimeExceptions.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE301055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeExceptions.m;
+                       path = NGMime/NGMimeExceptions.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE302055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeFileData.h;
+                       path = NGMime/NGMimeFileData.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE303055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeFileData.m;
+                       path = NGMime/NGMimeFileData.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE304055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeGeneratorProtocols.h;
+                       path = NGMime/NGMimeGeneratorProtocols.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE305055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeHeaderFieldGenerator.h;
+                       path = NGMime/NGMimeHeaderFieldGenerator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE306055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeHeaderFieldGenerator.m;
+                       path = NGMime/NGMimeHeaderFieldGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE307055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeHeaderFieldParser.h;
+                       path = NGMime/NGMimeHeaderFieldParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE308055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeHeaderFieldParser.m;
+                       path = NGMime/NGMimeHeaderFieldParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE309055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeHeaderFields.h;
+                       path = NGMime/NGMimeHeaderFields.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE30A055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeHeaderFields.m;
+                       path = NGMime/NGMimeHeaderFields.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE30B055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeJoinedData.h;
+                       path = NGMime/NGMimeJoinedData.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE30C055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeJoinedData.m;
+                       path = NGMime/NGMimeJoinedData.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE30D055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeMultipartBody.h;
+                       path = NGMime/NGMimeMultipartBody.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE30E055EDAD400B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeMultipartBody.m;
+                       path = NGMime/NGMimeMultipartBody.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE30F055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeMultipartBodyParser.m;
+                       path = NGMime/NGMimeMultipartBodyParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE310055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimePartGenerator.h;
+                       path = NGMime/NGMimePartGenerator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE311055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimePartGenerator.m;
+                       path = NGMime/NGMimePartGenerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE312055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimePartParser.h;
+                       path = NGMime/NGMimePartParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE313055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimePartParser.m;
+                       path = NGMime/NGMimePartParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE314055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeType.h;
+                       path = NGMime/NGMimeType.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE315055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeType.m;
+                       path = NGMime/NGMimeType.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE316055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGMimeUtilities.h;
+                       path = NGMime/NGMimeUtilities.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE317055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeUtilities.m;
+                       path = NGMime/NGMimeUtilities.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE318055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGPart.h;
+                       path = NGMime/NGPart.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE319055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGPart.m;
+                       path = NGMime/NGPart.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE31A055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = NGMime/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE31B055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       name = "SxCore-NGMime.graffle";
+                       path = "NGMime/SxCore-NGMime.graffle";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE31C055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = timeMacros.h;
+                       path = NGMime/timeMacros.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE31D055EDAD500B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = NGMime/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE31E055EDAD500B28141 = {
+                       fileRef = E81BE23A055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE31F055EDAD500B28141 = {
+                       fileRef = E81BE23B055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE320055EDAD500B28141 = {
+                       fileRef = E81BE23C055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE321055EDAD500B28141 = {
+                       fileRef = E81BE23D055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE322055EDAD500B28141 = {
+                       fileRef = E81BE23E055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE323055EDAD500B28141 = {
+                       fileRef = E81BE23F055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE324055EDAD500B28141 = {
+                       fileRef = E81BE240055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE325055EDAD500B28141 = {
+                       fileRef = E81BE241055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE326055EDAD500B28141 = {
+                       fileRef = E81BE242055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE327055EDAD500B28141 = {
+                       fileRef = E81BE244055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE328055EDAD500B28141 = {
+                       fileRef = E81BE245055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE32A055EDAD500B28141 = {
+                       fileRef = E81BE247055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE32B055EDAD500B28141 = {
+                       fileRef = E81BE248055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE32C055EDAD500B28141 = {
+                       fileRef = E81BE249055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE32D055EDAD500B28141 = {
+                       fileRef = E81BE24A055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE32E055EDAD500B28141 = {
+                       fileRef = E81BE24B055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE32F055EDAD500B28141 = {
+                       fileRef = E81BE24C055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE330055EDAD500B28141 = {
+                       fileRef = E81BE24D055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE331055EDAD500B28141 = {
+                       fileRef = E81BE24E055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE332055EDAD500B28141 = {
+                       fileRef = E81BE24F055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE333055EDAD500B28141 = {
+                       fileRef = E81BE250055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE334055EDAD500B28141 = {
+                       fileRef = E81BE251055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE335055EDAD600B28141 = {
+                       fileRef = E81BE252055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE336055EDAD600B28141 = {
+                       fileRef = E81BE253055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE337055EDAD600B28141 = {
+                       fileRef = E81BE254055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE338055EDAD600B28141 = {
+                       fileRef = E81BE255055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE339055EDAD600B28141 = {
+                       fileRef = E81BE256055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE33A055EDAD600B28141 = {
+                       fileRef = E81BE257055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE33B055EDAD600B28141 = {
+                       fileRef = E81BE258055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE33C055EDAD600B28141 = {
+                       fileRef = E81BE259055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE33D055EDAD600B28141 = {
+                       fileRef = E81BE25A055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE33E055EDAD600B28141 = {
+                       fileRef = E81BE25B055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE33F055EDAD600B28141 = {
+                       fileRef = E81BE25C055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE340055EDAD600B28141 = {
+                       fileRef = E81BE25D055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE341055EDAD600B28141 = {
+                       fileRef = E81BE25E055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE342055EDAD600B28141 = {
+                       fileRef = E81BE25F055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE343055EDAD600B28141 = {
+                       fileRef = E81BE260055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE344055EDAD600B28141 = {
+                       fileRef = E81BE261055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE345055EDAD600B28141 = {
+                       fileRef = E81BE262055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE346055EDAD600B28141 = {
+                       fileRef = E81BE263055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE362055EDAD600B28141 = {
+                       fileRef = E81BE280055EDAD100B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE37F055EDAD600B28141 = {
+                       fileRef = E81BE29F055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE380055EDAD600B28141 = {
+                       fileRef = E81BE2A0055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE381055EDAD600B28141 = {
+                       fileRef = E81BE2A1055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE382055EDAD600B28141 = {
+                       fileRef = E81BE2A2055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE383055EDAD600B28141 = {
+                       fileRef = E81BE2A3055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE384055EDAD600B28141 = {
+                       fileRef = E81BE2A4055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE385055EDAD600B28141 = {
+                       fileRef = E81BE2A5055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE386055EDAD600B28141 = {
+                       fileRef = E81BE2A6055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE387055EDAD600B28141 = {
+                       fileRef = E81BE2A7055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE388055EDAD600B28141 = {
+                       fileRef = E81BE2A8055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE389055EDAD600B28141 = {
+                       fileRef = E81BE2A9055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE38A055EDAD600B28141 = {
+                       fileRef = E81BE2AA055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE38B055EDAD600B28141 = {
+                       fileRef = E81BE2AB055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE38C055EDAD600B28141 = {
+                       fileRef = E81BE2AC055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE38D055EDAD600B28141 = {
+                       fileRef = E81BE2AD055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE38E055EDAD600B28141 = {
+                       fileRef = E81BE2AE055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE38F055EDAD600B28141 = {
+                       fileRef = E81BE2AF055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE390055EDAD600B28141 = {
+                       fileRef = E81BE2B0055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE391055EDAD600B28141 = {
+                       fileRef = E81BE2B1055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE392055EDAD600B28141 = {
+                       fileRef = E81BE2B2055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE393055EDAD600B28141 = {
+                       fileRef = E81BE2B3055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE394055EDAD600B28141 = {
+                       fileRef = E81BE2B4055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE395055EDAD600B28141 = {
+                       fileRef = E81BE2B5055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE396055EDAD600B28141 = {
+                       fileRef = E81BE2B6055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE397055EDAD600B28141 = {
+                       fileRef = E81BE2B7055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE398055EDAD600B28141 = {
+                       fileRef = E81BE2B8055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE399055EDAD600B28141 = {
+                       fileRef = E81BE2B9055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE39A055EDAD600B28141 = {
+                       fileRef = E81BE2BA055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE39B055EDAD600B28141 = {
+                       fileRef = E81BE2BB055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE39C055EDAD600B28141 = {
+                       fileRef = E81BE2BC055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE39D055EDAD600B28141 = {
+                       fileRef = E81BE2BD055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE39E055EDAD600B28141 = {
+                       fileRef = E81BE2BE055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3B8055EDAD600B28141 = {
+                       fileRef = E81BE2D9055EDAD300B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3D2055EDAD600B28141 = {
+                       fileRef = E81BE2F4055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3D3055EDAD600B28141 = {
+                       fileRef = E81BE2F5055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3D4055EDAD600B28141 = {
+                       fileRef = E81BE2F6055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3D5055EDAD600B28141 = {
+                       fileRef = E81BE2F7055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3D6055EDAD600B28141 = {
+                       fileRef = E81BE2F8055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3D7055EDAD600B28141 = {
+                       fileRef = E81BE2F9055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3D8055EDAD600B28141 = {
+                       fileRef = E81BE2FA055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3D9055EDAD600B28141 = {
+                       fileRef = E81BE2FB055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3DA055EDAD600B28141 = {
+                       fileRef = E81BE2FC055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3DB055EDAD600B28141 = {
+                       fileRef = E81BE2FD055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3DC055EDAD600B28141 = {
+                       fileRef = E81BE2FE055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3DD055EDAD600B28141 = {
+                       fileRef = E81BE2FF055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3DE055EDAD600B28141 = {
+                       fileRef = E81BE300055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3DF055EDAD600B28141 = {
+                       fileRef = E81BE301055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3E0055EDAD600B28141 = {
+                       fileRef = E81BE302055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3E1055EDAD600B28141 = {
+                       fileRef = E81BE303055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3E2055EDAD600B28141 = {
+                       fileRef = E81BE304055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3E3055EDAD600B28141 = {
+                       fileRef = E81BE305055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3E4055EDAD600B28141 = {
+                       fileRef = E81BE306055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3E5055EDAD600B28141 = {
+                       fileRef = E81BE307055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3E6055EDAD600B28141 = {
+                       fileRef = E81BE308055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3E7055EDAD600B28141 = {
+                       fileRef = E81BE309055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3E8055EDAD600B28141 = {
+                       fileRef = E81BE30A055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3E9055EDAD600B28141 = {
+                       fileRef = E81BE30B055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3EA055EDAD600B28141 = {
+                       fileRef = E81BE30C055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3EB055EDAD600B28141 = {
+                       fileRef = E81BE30D055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3EC055EDAD600B28141 = {
+                       fileRef = E81BE30E055EDAD400B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3ED055EDAD600B28141 = {
+                       fileRef = E81BE30F055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3EE055EDAD600B28141 = {
+                       fileRef = E81BE310055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3EF055EDAD600B28141 = {
+                       fileRef = E81BE311055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3F0055EDAD600B28141 = {
+                       fileRef = E81BE312055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3F1055EDAD600B28141 = {
+                       fileRef = E81BE313055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3F2055EDAD600B28141 = {
+                       fileRef = E81BE314055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3F3055EDAD600B28141 = {
+                       fileRef = E81BE315055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3F4055EDAD600B28141 = {
+                       fileRef = E81BE316055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3F5055EDAD600B28141 = {
+                       fileRef = E81BE317055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3F6055EDAD600B28141 = {
+                       fileRef = E81BE318055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE3F7055EDAD600B28141 = {
+                       fileRef = E81BE319055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3F8055EDAD600B28141 = {
+                       fileRef = E81BE31A055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3F9055EDAD600B28141 = {
+                       fileRef = E81BE31B055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3FA055EDAD600B28141 = {
+                       fileRef = E81BE31C055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3FB055EDAD600B28141 = {
+                       fileRef = E81BE31D055EDAD500B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE3FE055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = NGLdap/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE3FF055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = NGLdap/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE400055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = NGLdap/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE401055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = NGLdap/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE402055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "EOQualifier+LDAP.h";
+                       path = "NGLdap/EOQualifier+LDAP.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE403055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "EOQualifier+LDAP.m";
+                       path = "NGLdap/EOQualifier+LDAP.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE404055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = NGLdap/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE405055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.postamble;
+                       path = NGLdap/GNUmakefile.postamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE406055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = NGLdap/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE407055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = "NGLdap-Info.plist";
+                       path = "NGLdap/NGLdap-Info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE408055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGLdap.h;
+                       path = NGLdap/NGLdap.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE409055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGLdapAttribute.h;
+                       path = NGLdap/NGLdapAttribute.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE40A055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLdapAttribute.m;
+                       path = NGLdap/NGLdapAttribute.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE40B055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGLdapConnection.h;
+                       path = NGLdap/NGLdapConnection.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE40C055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLdapConnection.m;
+                       path = NGLdap/NGLdapConnection.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE40D055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NGLdapConnection+Private.h";
+                       path = "NGLdap/NGLdapConnection+Private.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE40E055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGLdapDataSource.h;
+                       path = NGLdap/NGLdapDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE40F055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLdapDataSource.m;
+                       path = NGLdap/NGLdapDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE410055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGLdapEntry.h;
+                       path = NGLdap/NGLdapEntry.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE411055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLdapEntry.m;
+                       path = NGLdap/NGLdapEntry.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE412055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGLdapFileManager.h;
+                       path = NGLdap/NGLdapFileManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE413055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLdapFileManager.m;
+                       path = NGLdap/NGLdapFileManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE414055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGLdapGlobalID.h;
+                       path = NGLdap/NGLdapGlobalID.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE415055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLdapGlobalID.m;
+                       path = NGLdap/NGLdapGlobalID.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE416055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGLdapModification.h;
+                       path = NGLdap/NGLdapModification.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE417055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLdapModification.m;
+                       path = NGLdap/NGLdapModification.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE418055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGLdapSearchResultEnumerator.h;
+                       path = NGLdap/NGLdapSearchResultEnumerator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE419055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLdapSearchResultEnumerator.m;
+                       path = NGLdap/NGLdapSearchResultEnumerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE41A055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGLdapURL.h;
+                       path = NGLdap/NGLdapURL.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE41B055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLdapURL.m;
+                       path = NGLdap/NGLdapURL.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE41C055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NSString+DN.h";
+                       path = "NGLdap/NSString+DN.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE41D055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSString+DN.m";
+                       path = "NGLdap/NSString+DN.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE41E055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = NGLdap/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE41F055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README.macosx;
+                       path = NGLdap/README.macosx;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE420055EDAF900B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = NGLdap/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE421055EDAFA00B28141 = {
+                       fileRef = E81BE3FE055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE422055EDAFA00B28141 = {
+                       fileRef = E81BE3FF055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE423055EDAFA00B28141 = {
+                       fileRef = E81BE400055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE424055EDAFA00B28141 = {
+                       fileRef = E81BE401055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE425055EDAFA00B28141 = {
+                       fileRef = E81BE402055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE426055EDAFA00B28141 = {
+                       fileRef = E81BE403055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE427055EDAFA00B28141 = {
+                       fileRef = E81BE404055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE428055EDAFA00B28141 = {
+                       fileRef = E81BE405055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE429055EDAFA00B28141 = {
+                       fileRef = E81BE406055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE42A055EDAFA00B28141 = {
+                       fileRef = E81BE407055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE42B055EDAFA00B28141 = {
+                       fileRef = E81BE408055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE42C055EDAFA00B28141 = {
+                       fileRef = E81BE409055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE42D055EDAFA00B28141 = {
+                       fileRef = E81BE40A055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE42E055EDAFA00B28141 = {
+                       fileRef = E81BE40B055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE42F055EDAFA00B28141 = {
+                       fileRef = E81BE40C055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE430055EDAFA00B28141 = {
+                       fileRef = E81BE40D055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                               );
+                       };
+               };
+               E81BE431055EDAFA00B28141 = {
+                       fileRef = E81BE40E055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE432055EDAFA00B28141 = {
+                       fileRef = E81BE40F055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE433055EDAFA00B28141 = {
+                       fileRef = E81BE410055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE434055EDAFA00B28141 = {
+                       fileRef = E81BE411055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE435055EDAFA00B28141 = {
+                       fileRef = E81BE412055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE436055EDAFA00B28141 = {
+                       fileRef = E81BE413055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE437055EDAFA00B28141 = {
+                       fileRef = E81BE414055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE438055EDAFA00B28141 = {
+                       fileRef = E81BE415055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE439055EDAFA00B28141 = {
+                       fileRef = E81BE416055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE43A055EDAFA00B28141 = {
+                       fileRef = E81BE417055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE43B055EDAFA00B28141 = {
+                       fileRef = E81BE418055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE43C055EDAFA00B28141 = {
+                       fileRef = E81BE419055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE43D055EDAFA00B28141 = {
+                       fileRef = E81BE41A055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE43E055EDAFA00B28141 = {
+                       fileRef = E81BE41B055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE43F055EDAFA00B28141 = {
+                       fileRef = E81BE41C055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE440055EDAFA00B28141 = {
+                       fileRef = E81BE41D055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE441055EDAFA00B28141 = {
+                       fileRef = E81BE41E055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE442055EDAFA00B28141 = {
+                       fileRef = E81BE41F055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE443055EDAFA00B28141 = {
+                       fileRef = E81BE420055EDAF900B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE446055EDB0100B28141 = {
+                       children = (
+                               E81BE404055EDAF900B28141,
+                               E81BE405055EDAF900B28141,
+                               E81BE406055EDAF900B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE449055EDB1E00B28141 = {
+                       children = (
+                               E81BE402055EDAF900B28141,
+                               E81BE408055EDAF900B28141,
+                               E81BE409055EDAF900B28141,
+                               E81BE40B055EDAF900B28141,
+                               E81BE40D055EDAF900B28141,
+                               E81BE40E055EDAF900B28141,
+                               E81BE410055EDAF900B28141,
+                               E81BE412055EDAF900B28141,
+                               E81BE414055EDAF900B28141,
+                               E81BE416055EDAF900B28141,
+                               E81BE418055EDAF900B28141,
+                               E81BE41A055EDAF900B28141,
+                               E81BE41C055EDAF900B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE44C055EDB2A00B28141 = {
+                       children = (
+                               E81BE3FF055EDAF900B28141,
+                               E81BE403055EDAF900B28141,
+                               E81BE40A055EDAF900B28141,
+                               E81BE40C055EDAF900B28141,
+                               E81BE40F055EDAF900B28141,
+                               E81BE411055EDAF900B28141,
+                               E81BE413055EDAF900B28141,
+                               E81BE415055EDAF900B28141,
+                               E81BE417055EDAF900B28141,
+                               E81BE419055EDAF900B28141,
+                               E81BE41B055EDAF900B28141,
+                               E81BE41D055EDAF900B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE44F055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = NGiCal/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE450055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = NGiCal/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE451055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = NGiCal/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE452055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = NGiCal/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE453055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = NGiCal/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE454055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalAlarm.h;
+                       path = NGiCal/iCalAlarm.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE455055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalAlarm.m;
+                       path = NGiCal/iCalAlarm.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE456055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalAttachment.h;
+                       path = NGiCal/iCalAttachment.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE457055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalAttachment.m;
+                       path = NGiCal/iCalAttachment.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE458055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalCalendar.h;
+                       path = NGiCal/iCalCalendar.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE459055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalCalendar.m;
+                       path = NGiCal/iCalCalendar.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE45A055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalDataSource.h;
+                       path = NGiCal/iCalDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE45B055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalDataSource.m;
+                       path = NGiCal/iCalDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE45C055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalDateHolder.h;
+                       path = NGiCal/iCalDateHolder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE45D055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalDateHolder.m;
+                       path = NGiCal/iCalDateHolder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE45E055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalDuration.h;
+                       path = NGiCal/iCalDuration.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE45F055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalDuration.m;
+                       path = NGiCal/iCalDuration.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE460055EDB5600B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = IcalElements.m;
+                       path = NGiCal/IcalElements.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE461055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalEntityObject.h;
+                       path = NGiCal/iCalEntityObject.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE462055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalEntityObject.m;
+                       path = NGiCal/iCalEntityObject.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE463055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalEvent.h;
+                       path = NGiCal/iCalEvent.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE464055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalEvent.m;
+                       path = NGiCal/iCalEvent.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE465055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalFreeBusy.h;
+                       path = NGiCal/iCalFreeBusy.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE466055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalFreeBusy.m;
+                       path = NGiCal/iCalFreeBusy.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE467055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalJournal.h;
+                       path = NGiCal/iCalJournal.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE468055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalJournal.m;
+                       path = NGiCal/iCalJournal.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE469055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalObject.h;
+                       path = NGiCal/iCalObject.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE46A055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalObject.m;
+                       path = NGiCal/iCalObject.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE46B055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalPerson.h;
+                       path = NGiCal/iCalPerson.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE46C055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalPerson.m;
+                       path = NGiCal/iCalPerson.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE46D055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = IcalResponse.h;
+                       path = NGiCal/IcalResponse.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE46E055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = IcalResponse.m;
+                       path = NGiCal/IcalResponse.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE46F055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalToDo.h;
+                       path = NGiCal/iCalToDo.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE470055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalToDo.m;
+                       path = NGiCal/iCalToDo.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE471055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = iCalTrigger.h;
+                       path = NGiCal/iCalTrigger.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE472055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = iCalTrigger.m;
+                       path = NGiCal/iCalTrigger.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE473055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = "NGiCal-Info.plist";
+                       path = "NGiCal/NGiCal-Info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE474055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGiCal.h;
+                       path = NGiCal/NGiCal.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE475055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       name = NGiCal.xmap;
+                       path = NGiCal/NGiCal.xmap;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE476055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NSCalendarDate+ICal.h";
+                       path = "NGiCal/NSCalendarDate+ICal.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE477055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSCalendarDate+ICal.m";
+                       path = "NGiCal/NSCalendarDate+ICal.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE478055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NSString+ICal.h";
+                       path = "NGiCal/NSString+ICal.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE479055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSString+ICal.m";
+                       path = "NGiCal/NSString+ICal.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE47A055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = NGiCal/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE47B055EDB5700B28141 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = NGiCal/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE47C055EDB5700B28141 = {
+                       fileRef = E81BE44F055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE47E055EDB5700B28141 = {
+                       fileRef = E81BE451055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE47F055EDB5700B28141 = {
+                       fileRef = E81BE452055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE480055EDB5700B28141 = {
+                       fileRef = E81BE453055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE481055EDB5700B28141 = {
+                       fileRef = E81BE454055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE482055EDB5700B28141 = {
+                       fileRef = E81BE455055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE483055EDB5700B28141 = {
+                       fileRef = E81BE456055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE484055EDB5700B28141 = {
+                       fileRef = E81BE457055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE485055EDB5700B28141 = {
+                       fileRef = E81BE458055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE486055EDB5700B28141 = {
+                       fileRef = E81BE459055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE487055EDB5700B28141 = {
+                       fileRef = E81BE45A055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE488055EDB5700B28141 = {
+                       fileRef = E81BE45B055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE489055EDB5700B28141 = {
+                       fileRef = E81BE45C055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE48A055EDB5700B28141 = {
+                       fileRef = E81BE45D055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE48B055EDB5700B28141 = {
+                       fileRef = E81BE45E055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE48C055EDB5700B28141 = {
+                       fileRef = E81BE45F055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE48E055EDB5700B28141 = {
+                       fileRef = E81BE461055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE48F055EDB5700B28141 = {
+                       fileRef = E81BE462055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE490055EDB5700B28141 = {
+                       fileRef = E81BE463055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE491055EDB5700B28141 = {
+                       fileRef = E81BE464055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE492055EDB5700B28141 = {
+                       fileRef = E81BE465055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE493055EDB5700B28141 = {
+                       fileRef = E81BE466055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE494055EDB5700B28141 = {
+                       fileRef = E81BE467055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE495055EDB5700B28141 = {
+                       fileRef = E81BE468055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE496055EDB5700B28141 = {
+                       fileRef = E81BE469055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE497055EDB5700B28141 = {
+                       fileRef = E81BE46A055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE498055EDB5700B28141 = {
+                       fileRef = E81BE46B055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE499055EDB5700B28141 = {
+                       fileRef = E81BE46C055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE49A055EDB5700B28141 = {
+                       fileRef = E81BE46D055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE49B055EDB5700B28141 = {
+                       fileRef = E81BE46E055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE49C055EDB5700B28141 = {
+                       fileRef = E81BE46F055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE49D055EDB5700B28141 = {
+                       fileRef = E81BE470055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE49E055EDB5700B28141 = {
+                       fileRef = E81BE471055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE49F055EDB5700B28141 = {
+                       fileRef = E81BE472055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4A0055EDB5700B28141 = {
+                       fileRef = E81BE473055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4A1055EDB5700B28141 = {
+                       fileRef = E81BE474055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE4A2055EDB5700B28141 = {
+                       fileRef = E81BE475055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4A3055EDB5700B28141 = {
+                       fileRef = E81BE476055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81BE4A4055EDB5700B28141 = {
+                       fileRef = E81BE477055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4A7055EDB5700B28141 = {
+                       fileRef = E81BE47A055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4A8055EDB5700B28141 = {
+                       fileRef = E81BE47B055EDB5700B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4AB055EDB7E00B28141 = {
+                       children = (
+                               E81BE453055EDB5600B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4AE055EDB9900B28141 = {
+                       children = (
+                               E81BE454055EDB5600B28141,
+                               E81BE456055EDB5600B28141,
+                               E81BE458055EDB5600B28141,
+                               E81BE45A055EDB5600B28141,
+                               E81BE45C055EDB5600B28141,
+                               E81BE45E055EDB5600B28141,
+                               E81BE461055EDB5700B28141,
+                               E81BE463055EDB5700B28141,
+                               E81BE465055EDB5700B28141,
+                               E81BE467055EDB5700B28141,
+                               E81BE469055EDB5700B28141,
+                               E81BE46B055EDB5700B28141,
+                               E81BE46D055EDB5700B28141,
+                               E81BE46F055EDB5700B28141,
+                               E81BE471055EDB5700B28141,
+                               E81BE474055EDB5700B28141,
+                               E81BE476055EDB5700B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4B1055EDBA800B28141 = {
+                       children = (
+                               E81BE450055EDB5600B28141,
+                               E81BE455055EDB5600B28141,
+                               E81BE457055EDB5600B28141,
+                               E81BE459055EDB5600B28141,
+                               E81BE45B055EDB5600B28141,
+                               E81BE45D055EDB5600B28141,
+                               E81BE45F055EDB5600B28141,
+                               E81BE462055EDB5700B28141,
+                               E81BE464055EDB5700B28141,
+                               E81BE466055EDB5700B28141,
+                               E81BE468055EDB5700B28141,
+                               E81BE46A055EDB5700B28141,
+                               E81BE46C055EDB5700B28141,
+                               E81BE46E055EDB5700B28141,
+                               E81BE470055EDB5700B28141,
+                               E81BE472055EDB5700B28141,
+                               E81BE477055EDB5700B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4B4055EDBCB00B28141 = {
+                       children = (
+                               E81BE23E055EDACF00B28141,
+                               E81BE23F055EDACF00B28141,
+                               E81BE240055EDACF00B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4B7055EDBF100B28141 = {
+                       children = (
+                               E81BE241055EDACF00B28141,
+                               E81BE2F5055EDAD400B28141,
+                               E81BE2F7055EDAD400B28141,
+                               E81BE2F9055EDAD400B28141,
+                               E81BE2FB055EDAD400B28141,
+                               E81BE2FD055EDAD400B28141,
+                               E81BE2FF055EDAD400B28141,
+                               E81BE300055EDAD400B28141,
+                               E81BE302055EDAD400B28141,
+                               E81BE304055EDAD400B28141,
+                               E81BE305055EDAD400B28141,
+                               E81BE307055EDAD400B28141,
+                               E81BE309055EDAD400B28141,
+                               E81BE30B055EDAD400B28141,
+                               E81BE30D055EDAD400B28141,
+                               E81BE310055EDAD500B28141,
+                               E81BE312055EDAD500B28141,
+                               E81BE314055EDAD500B28141,
+                               E81BE316055EDAD500B28141,
+                               E81BE318055EDAD500B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4BA055EDC0200B28141 = {
+                       children = (
+                               E81BE31B055EDAD500B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Documentation;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4BD055EDC2400B28141 = {
+                       children = (
+                               E81BE23B055EDACF00B28141,
+                               E81BE31C055EDAD500B28141,
+                               E81BE2F6055EDAD400B28141,
+                               E897B36605B84D6000B708BC,
+                               E897B36705B84D7800B708BC,
+                               E81BE242055EDACF00B28141,
+                               E81BE2FA055EDAD400B28141,
+                               E81BE2FC055EDAD400B28141,
+                               E81BE2FE055EDAD400B28141,
+                               E81BE301055EDAD400B28141,
+                               E81BE303055EDAD400B28141,
+                               E81BE308055EDAD400B28141,
+                               E81BE30A055EDAD400B28141,
+                               E81BE30C055EDAD400B28141,
+                               E81BE30E055EDAD400B28141,
+                               E81BE30F055EDAD500B28141,
+                               E81BE313055EDAD500B28141,
+                               E81BE315055EDAD500B28141,
+                               E81BE317055EDAD500B28141,
+                               E81BE319055EDAD500B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4C0055EDC3600B28141 = {
+                       children = (
+                               E81BE248055EDACF00B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4C3055EDC5B00B28141 = {
+                       children = (
+                               E81BE249055EDACF00B28141,
+                               E81BE24B055EDACF00B28141,
+                               E81BE24D055EDACF00B28141,
+                               E81BE24F055EDACF00B28141,
+                               E81BE251055EDACF00B28141,
+                               E81BE253055EDAD000B28141,
+                               E84E826205C14F81005792AF,
+                               E84E826405C14F81005792AF,
+                               E81BE255055EDAD000B28141,
+                               E81BE257055EDAD000B28141,
+                               E81BE258055EDAD000B28141,
+                               E81BE25A055EDAD000B28141,
+                               E81BE25C055EDAD000B28141,
+                               E81BE25E055EDAD000B28141,
+                               E81BE260055EDAD000B28141,
+                               E81BE262055EDAD000B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4C6055EDC6C00B28141 = {
+                       children = (
+                               E824CFF305BD7CA00081A110,
+                               E820934105B0D30B0088B931,
+                               E820934205B0D30B0088B931,
+                               E81BE24A055EDACF00B28141,
+                               E81BE24C055EDACF00B28141,
+                               E81BE24E055EDACF00B28141,
+                               E81BE250055EDACF00B28141,
+                               E81BE252055EDAD000B28141,
+                               E81BE254055EDAD000B28141,
+                               E84E826305C14F81005792AF,
+                               E84E826505C14F81005792AF,
+                               E81BE256055EDAD000B28141,
+                               E81BE259055EDAD000B28141,
+                               E81BE25B055EDAD000B28141,
+                               E8ACC6BE05CED366005ADB68,
+                               E8ACC6BF05CED366005ADB68,
+                               E81BE25D055EDAD000B28141,
+                               E81BE25F055EDAD000B28141,
+                               E81BE261055EDAD000B28141,
+                               E81BE263055EDAD000B28141,
+                               E897B36805B84DAA00B708BC,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4C9055EDC7A00B28141 = {
+                       children = (
+                               E81BE2A3055EDAD200B28141,
+                               E81BE2A4055EDAD200B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4CC055EDCA000B28141 = {
+                       children = (
+                               E81BE2A5055EDAD200B28141,
+                               E81BE2A7055EDAD200B28141,
+                               E81BE2A9055EDAD200B28141,
+                               E81BE2AB055EDAD200B28141,
+                               E81BE2AD055EDAD200B28141,
+                               E81BE2AE055EDAD200B28141,
+                               E81BE2B0055EDAD200B28141,
+                               E81BE2B2055EDAD200B28141,
+                               E81BE2B4055EDAD200B28141,
+                               E81BE2B6055EDAD200B28141,
+                               E81BE2B8055EDAD200B28141,
+                               E81BE2BA055EDAD200B28141,
+                               E81BE2BC055EDAD200B28141,
+                               E81BE2BD055EDAD200B28141,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4CF055EDCAC00B28141 = {
+                       children = (
+                               E81BE2A1055EDAD200B28141,
+                               E81BE2A6055EDAD200B28141,
+                               E81BE2A8055EDAD200B28141,
+                               E81BE2AA055EDAD200B28141,
+                               E81BE2AC055EDAD200B28141,
+                               E81BE2AF055EDAD200B28141,
+                               E81BE2B1055EDAD200B28141,
+                               E81BE2B3055EDAD200B28141,
+                               E81BE2B5055EDAD200B28141,
+                               E81BE2B7055EDAD200B28141,
+                               E81BE2B9055EDAD200B28141,
+                               E81BE2BB055EDAD200B28141,
+                               E81BE2BE055EDAD200B28141,
+                               E80D72AB05D6BA6E0050931F,
+                               E80D72AC05D6BA6E0050931F,
+                               E80D72AD05D6BA6E0050931F,
+                               E80D72AE05D6BA6E0050931F,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81BE4D1055EDD8C00B28141 = {
+                       fileRef = E81EF62A055DCB17006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4D2055EDD8D00B28141 = {
+                       fileRef = E81EF633055DCB38006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4D3055EDD8F00B28141 = {
+                       fileRef = E81EF63B055DCB43006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4D4055EDD9700B28141 = {
+                       fileRef = E81EF62A055DCB17006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4D5055EDD9800B28141 = {
+                       fileRef = E81EF633055DCB38006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4D6055EDD9B00B28141 = {
+                       fileRef = E81EF62A055DCB17006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81BE4D7055EDD9B00B28141 = {
+                       fileRef = E81EF633055DCB38006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03E5055DDCA0006FE529 = {
+                       fileRef = E81EF62A055DCB17006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0450055DE791006FE529 = {
+                       children = (
+                               AD16271C05D934F700A7368D,
+                               AD853AA506A7F7F300727CA0,
+                               AD1802550611DB7C00ED723F,
+                               AD52282A06A7F3AE00B24132,
+                       );
+                       isa = PBXGroup;
+                       name = "Linked Frameworks & Libraries";
+                       path = "";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04B2055DE7E2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = NGStreams/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04B3055DE7E2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = NGStreams/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04B4055DE7E2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.script.sh;
+                       name = config.guess;
+                       path = NGStreams/config.guess;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04B5055DE7E2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = config.h.in;
+                       path = NGStreams/config.h.in;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04B6055DE7E2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.script.sh;
+                       name = config.sub;
+                       path = NGStreams/config.sub;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04B7055DE7E2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.script.sh;
+                       name = configure;
+                       path = NGStreams/configure;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04B8055DE7E2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = configure.in;
+                       path = NGStreams/configure.in;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04B9055DE7E2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = NGStreams/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04BA055DE7E2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = NGStreams/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04BB055DE7E2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = DESIGN;
+                       path = NGStreams/DESIGN;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04BC055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = NGStreams/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04BD055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.postamble;
+                       path = NGStreams/GNUmakefile.postamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04BE055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = NGStreams/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04BF055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.script.sh;
+                       name = "install-sh";
+                       path = "NGStreams/install-sh";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04C0055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = libNGStreams.def;
+                       path = NGStreams/libNGStreams.def;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04C1055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGActiveSocket.m;
+                       path = NGStreams/NGActiveSocket.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04C2055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NGActiveSocket+serialization.m";
+                       path = "NGStreams/NGActiveSocket+serialization.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04C3055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGActiveSSLSocket.m;
+                       path = NGStreams/NGActiveSSLSocket.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04C4055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGBase64Stream.m;
+                       path = NGStreams/NGBase64Stream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04C5055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGBufferedStream.m;
+                       path = NGStreams/NGBufferedStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04C6055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGByteBuffer.m;
+                       path = NGStreams/NGByteBuffer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04C7055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGByteCountStream.m;
+                       path = NGStreams/NGByteCountStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04C8055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGCharBuffer.m;
+                       path = NGStreams/NGCharBuffer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04C9055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGConcreteStreamFileHandle.m;
+                       path = NGStreams/NGConcreteStreamFileHandle.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04CA055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGCTextStream.m;
+                       path = NGStreams/NGCTextStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04CB055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGDatagramPacket.m;
+                       path = NGStreams/NGDatagramPacket.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04CC055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGDatagramSocket.m;
+                       path = NGStreams/NGDatagramSocket.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04CD055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGDataStream.m;
+                       path = NGStreams/NGDataStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04CE055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGDescriptorFunctions.m;
+                       path = NGStreams/NGDescriptorFunctions.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04CF055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGFileStream.m;
+                       path = NGStreams/NGFileStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04D0055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGFilterStream.m;
+                       path = NGStreams/NGFilterStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04D1055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGFilterTextStream.m;
+                       path = NGStreams/NGFilterTextStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04D2055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGGZipStream.m;
+                       path = NGStreams/NGGZipStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04D3055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGInternetSocketAddress.m;
+                       path = NGStreams/NGInternetSocketAddress.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04D4055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGInternetSocketDomain.m;
+                       path = NGStreams/NGInternetSocketDomain.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04D5055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLocalSocketAddress.m;
+                       path = NGStreams/NGLocalSocketAddress.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04D6055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLocalSocketDomain.m;
+                       path = NGStreams/NGLocalSocketDomain.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04D7055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGLockingStream.m;
+                       path = NGStreams/NGLockingStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04D8055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGNetUtilities.m;
+                       path = NGStreams/NGNetUtilities.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04D9055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGPassiveSocket.m;
+                       path = NGStreams/NGPassiveSocket.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04DA055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGSocket.m;
+                       path = NGStreams/NGSocket.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04DB055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NGSocket+private.h";
+                       path = "NGStreams/NGSocket+private.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04DC055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGSocketExceptions.m;
+                       path = NGStreams/NGSocketExceptions.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04DD055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGStream.m;
+                       path = NGStreams/NGStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04DE055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NGStream+serialization.m";
+                       path = "NGStreams/NGStream+serialization.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04DF055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGStreamCoder.m;
+                       path = NGStreams/NGStreamCoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04E0055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGStreamExceptions.m;
+                       path = NGStreams/NGStreamExceptions.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04E1055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGStreamPipe.m;
+                       path = NGStreams/NGStreamPipe.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04E2055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGStreams.m;
+                       path = NGStreams/NGStreams.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04E3055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGStringTextStream.m;
+                       path = NGStreams/NGStringTextStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04E4055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGTaskStream.m;
+                       path = NGStreams/NGTaskStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04E5055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGTerminalSupport.m;
+                       path = NGStreams/NGTerminalSupport.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04E6055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGTextStream.m;
+                       path = NGStreams/NGTextStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04E7055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = NGStreams/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04E8055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       name = "SxCore-NGStreams.graffle";
+                       path = "NGStreams/SxCore-NGStreams.graffle";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04E9055DE7E3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = NGStreams/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E04EA055DE7E4006FE529 = {
+                       fileRef = E81E04B2055DE7E2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E04EB055DE7E4006FE529 = {
+                       fileRef = E81E04B3055DE7E2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E04F1055DE7E4006FE529 = {
+                       fileRef = E81E04B9055DE7E2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E04F2055DE7E4006FE529 = {
+                       fileRef = E81E04BA055DE7E2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E04F9055DE7E4006FE529 = {
+                       fileRef = E81E04C1055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E04FC055DE7E4006FE529 = {
+                       fileRef = E81E04C4055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E04FD055DE7E4006FE529 = {
+                       fileRef = E81E04C5055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E04FE055DE7E4006FE529 = {
+                       fileRef = E81E04C6055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E04FF055DE7E4006FE529 = {
+                       fileRef = E81E04C7055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0500055DE7E4006FE529 = {
+                       fileRef = E81E04C8055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0501055DE7E4006FE529 = {
+                       fileRef = E81E04C9055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0502055DE7E4006FE529 = {
+                       fileRef = E81E04CA055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0503055DE7E4006FE529 = {
+                       fileRef = E81E04CB055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0504055DE7E4006FE529 = {
+                       fileRef = E81E04CC055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0505055DE7E4006FE529 = {
+                       fileRef = E81E04CD055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0506055DE7E4006FE529 = {
+                       fileRef = E81E04CE055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0507055DE7E4006FE529 = {
+                       fileRef = E81E04CF055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0508055DE7E4006FE529 = {
+                       fileRef = E81E04D0055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0509055DE7E4006FE529 = {
+                       fileRef = E81E04D1055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E050A055DE7E4006FE529 = {
+                       fileRef = E81E04D2055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E050B055DE7E4006FE529 = {
+                       fileRef = E81E04D3055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E050C055DE7E4006FE529 = {
+                       fileRef = E81E04D4055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E050D055DE7E4006FE529 = {
+                       fileRef = E81E04D5055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E050E055DE7E4006FE529 = {
+                       fileRef = E81E04D6055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E050F055DE7E4006FE529 = {
+                       fileRef = E81E04D7055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0510055DE7E4006FE529 = {
+                       fileRef = E81E04D8055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0511055DE7E4006FE529 = {
+                       fileRef = E81E04D9055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0512055DE7E4006FE529 = {
+                       fileRef = E81E04DA055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0513055DE7E4006FE529 = {
+                       fileRef = E81E04DB055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0514055DE7E4006FE529 = {
+                       fileRef = E81E04DC055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0515055DE7E4006FE529 = {
+                       fileRef = E81E04DD055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0518055DE7E4006FE529 = {
+                       fileRef = E81E04E0055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0519055DE7E4006FE529 = {
+                       fileRef = E81E04E1055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E051A055DE7E4006FE529 = {
+                       fileRef = E81E04E2055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E051B055DE7E4006FE529 = {
+                       fileRef = E81E04E3055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E051C055DE7E4006FE529 = {
+                       fileRef = E81E04E4055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E051D055DE7E4006FE529 = {
+                       fileRef = E81E04E5055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E051E055DE7E4006FE529 = {
+                       fileRef = E81E04E6055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E051F055DE7E4006FE529 = {
+                       fileRef = E81E04E7055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0521055DE7E4006FE529 = {
+                       fileRef = E81E04E9055DE7E3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0524055DE7F2006FE529 = {
+                       children = (
+                               E81E04B4055DE7E2006FE529,
+                               E81E04B5055DE7E2006FE529,
+                               E81E04B6055DE7E2006FE529,
+                               E81E04B7055DE7E2006FE529,
+                               E81E04B8055DE7E2006FE529,
+                               E81E04BC055DE7E3006FE529,
+                               E81E04BD055DE7E3006FE529,
+                               E81E04BE055DE7E3006FE529,
+                               E81E04BF055DE7E3006FE529,
+                               E81E04C0055DE7E3006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E0527055DE816006FE529 = {
+                       children = (
+                               E81E04B3055DE7E2006FE529,
+                               E81E04C4055DE7E3006FE529,
+                               E81E04C5055DE7E3006FE529,
+                               E81E04C6055DE7E3006FE529,
+                               E81E04C7055DE7E3006FE529,
+                               E81E04C8055DE7E3006FE529,
+                               E81E04C9055DE7E3006FE529,
+                               E81E04CA055DE7E3006FE529,
+                               E81E04CD055DE7E3006FE529,
+                               E81E04CE055DE7E3006FE529,
+                               E81E04CF055DE7E3006FE529,
+                               E81E04D0055DE7E3006FE529,
+                               E81E04D1055DE7E3006FE529,
+                               E81E04D2055DE7E3006FE529,
+                               E81E04D7055DE7E3006FE529,
+                               E81E04DD055DE7E3006FE529,
+                               E81E04E0055DE7E3006FE529,
+                               E81E04E1055DE7E3006FE529,
+                               E81E04E2055DE7E3006FE529,
+                               E81E04E3055DE7E3006FE529,
+                               E81E04E4055DE7E3006FE529,
+                               E81E04E5055DE7E3006FE529,
+                               E81E04E6055DE7E3006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Streams;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E052A055DE833006FE529 = {
+                       children = (
+                               E81E04BB055DE7E2006FE529,
+                               E81E04E8055DE7E3006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Documentation;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05C9055DE8B2006FE529 = {
+                       children = (
+                               E81E05CA055DE8B2006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = macosx;
+                       path = NGStreams/macosx;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05CA055DE8B2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = config.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05CB055DE8B2006FE529 = {
+                       children = (
+                               E81E05CC055DE8B2006FE529,
+                               E81E05CD055DE8B2006FE529,
+                               E81E05CE055DE8B2006FE529,
+                               E81E05CF055DE8B2006FE529,
+                               E81E05D0055DE8B2006FE529,
+                               E81E05D1055DE8B3006FE529,
+                               E81E05D2055DE8B3006FE529,
+                               E81E05D3055DE8B3006FE529,
+                               E81E05D4055DE8B3006FE529,
+                               E81E05D5055DE8B3006FE529,
+                               E81E05D6055DE8B3006FE529,
+                               E81E05D7055DE8B3006FE529,
+                               E81E05D8055DE8B3006FE529,
+                               E81E05D9055DE8B3006FE529,
+                               E81E05DA055DE8B3006FE529,
+                               E81E05DB055DE8B3006FE529,
+                               E81E05DC055DE8B3006FE529,
+                               E81E05DD055DE8B3006FE529,
+                               E81E05DE055DE8B3006FE529,
+                               E81E05DF055DE8B3006FE529,
+                               E81E05E0055DE8B3006FE529,
+                               E81E05E1055DE8B3006FE529,
+                               E81E05E2055DE8B3006FE529,
+                               E81E05E3055DE8B3006FE529,
+                               E81E05E4055DE8B3006FE529,
+                               E81E05E5055DE8B3006FE529,
+                               E81E05E6055DE8B3006FE529,
+                               E81E05E7055DE8B3006FE529,
+                               E81E05E8055DE8B3006FE529,
+                               E81E05E9055DE8B3006FE529,
+                               E81E05EA055DE8B3006FE529,
+                               E81E05EB055DE8B3006FE529,
+                               E81E05EC055DE8B3006FE529,
+                               E81E05ED055DE8B3006FE529,
+                               E81E05EE055DE8B3006FE529,
+                               E81E05EF055DE8B3006FE529,
+                               E81E05F0055DE8B3006FE529,
+                               E81E05F1055DE8B3006FE529,
+                               E81E05F2055DE8B3006FE529,
+                               E81E05F3055DE8B3006FE529,
+                               E81E05F4055DE8B3006FE529,
+                               E81E05F5055DE8B4006FE529,
+                               E81E05F6055DE8B4006FE529,
+                               E81E05F7055DE8B4006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       path = NGStreams/NGStreams;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05CC055DE8B2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NGActiveSocket+serialization.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05CD055DE8B2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGActiveSocket.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05CE055DE8B2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGActiveSSLSocket.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05CF055DE8B2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGBase64Stream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05D0055DE8B2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGBufferedStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05D1055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGByteBuffer.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05D2055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGByteCountStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05D3055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGCharBuffer.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05D4055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGConcreteStreamFileHandle.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05D5055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGCTextStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05D6055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGDatagramPacket.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05D7055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGDatagramSocket.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05D8055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGDataStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05D9055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGDescriptorFunctions.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05DA055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGFileStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05DB055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGFilterStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05DC055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGFilterTextStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05DD055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGGZipStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05DE055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGInternetSocketAddress.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05DF055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGInternetSocketDomain.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05E0055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGLocalSocketAddress.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05E1055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGLocalSocketDomain.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05E2055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGLockingStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05E3055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGNet.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05E4055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGNetDecls.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05E5055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGNetUtilities.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05E6055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGPassiveSocket.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05E7055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGSocket.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05E8055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGSocketExceptions.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05E9055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGSocketProtocols.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05EA055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NGStream+serialization.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05EB055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05EC055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGStreamCoder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05ED055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGStreamExceptions.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05EE055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGStreamPipe.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05EF055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGStreamProtocols.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05F0055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGStreams.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05F1055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGStreamsDecls.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05F2055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGStringTextStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05F3055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGTaskStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05F4055DE8B3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGTerminalSupport.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05F5055DE8B4006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGTextStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05F6055DE8B4006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGTextStreamProtocols.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05F7055DE8B4006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGUrlChars.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E05F8055DE8B4006FE529 = {
+                       fileRef = E81E05CA055DE8B2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E05F9055DE8B4006FE529 = {
+                       fileRef = E81E05CC055DE8B2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E05FA055DE8B4006FE529 = {
+                       fileRef = E81E05CD055DE8B2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E05FB055DE8B4006FE529 = {
+                       fileRef = E81E05CE055DE8B2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E05FC055DE8B4006FE529 = {
+                       fileRef = E81E05CF055DE8B2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E05FD055DE8B4006FE529 = {
+                       fileRef = E81E05D0055DE8B2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E05FE055DE8B4006FE529 = {
+                       fileRef = E81E05D1055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E05FF055DE8B4006FE529 = {
+                       fileRef = E81E05D2055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0600055DE8B4006FE529 = {
+                       fileRef = E81E05D3055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0601055DE8B4006FE529 = {
+                       fileRef = E81E05D4055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0602055DE8B4006FE529 = {
+                       fileRef = E81E05D5055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0603055DE8B4006FE529 = {
+                       fileRef = E81E05D6055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0604055DE8B4006FE529 = {
+                       fileRef = E81E05D7055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0605055DE8B4006FE529 = {
+                       fileRef = E81E05D8055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0606055DE8B4006FE529 = {
+                       fileRef = E81E05D9055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0607055DE8B4006FE529 = {
+                       fileRef = E81E05DA055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0608055DE8B4006FE529 = {
+                       fileRef = E81E05DB055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0609055DE8B4006FE529 = {
+                       fileRef = E81E05DC055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E060A055DE8B4006FE529 = {
+                       fileRef = E81E05DD055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E060B055DE8B4006FE529 = {
+                       fileRef = E81E05DE055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E060C055DE8B4006FE529 = {
+                       fileRef = E81E05DF055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E060D055DE8B4006FE529 = {
+                       fileRef = E81E05E0055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E060E055DE8B4006FE529 = {
+                       fileRef = E81E05E1055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E060F055DE8B4006FE529 = {
+                       fileRef = E81E05E2055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0610055DE8B4006FE529 = {
+                       fileRef = E81E05E3055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0611055DE8B4006FE529 = {
+                       fileRef = E81E05E4055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0612055DE8B4006FE529 = {
+                       fileRef = E81E05E5055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0613055DE8B4006FE529 = {
+                       fileRef = E81E05E6055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0614055DE8B4006FE529 = {
+                       fileRef = E81E05E7055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0615055DE8B4006FE529 = {
+                       fileRef = E81E05E8055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0616055DE8B4006FE529 = {
+                       fileRef = E81E05E9055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0617055DE8B4006FE529 = {
+                       fileRef = E81E05EA055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0618055DE8B4006FE529 = {
+                       fileRef = E81E05EB055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0619055DE8B4006FE529 = {
+                       fileRef = E81E05EC055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E061A055DE8B4006FE529 = {
+                       fileRef = E81E05ED055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E061B055DE8B4006FE529 = {
+                       fileRef = E81E05EE055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E061C055DE8B4006FE529 = {
+                       fileRef = E81E05EF055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E061D055DE8B4006FE529 = {
+                       fileRef = E81E05F0055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E061E055DE8B4006FE529 = {
+                       fileRef = E81E05F1055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E061F055DE8B4006FE529 = {
+                       fileRef = E81E05F2055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0620055DE8B4006FE529 = {
+                       fileRef = E81E05F3055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0621055DE8B4006FE529 = {
+                       fileRef = E81E05F4055DE8B3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0622055DE8B4006FE529 = {
+                       fileRef = E81E05F5055DE8B4006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0623055DE8B4006FE529 = {
+                       fileRef = E81E05F6055DE8B4006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0624055DE8B4006FE529 = {
+                       fileRef = E81E05F7055DE8B4006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E06A0055E6E35006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81BE422055EDAFA00B28141,
+                               E81BE425055EDAFA00B28141,
+                               E81BE42B055EDAFA00B28141,
+                               E81BE42C055EDAFA00B28141,
+                               E81BE42E055EDAFA00B28141,
+                               E81BE430055EDAFA00B28141,
+                               E81BE431055EDAFA00B28141,
+                               E81BE433055EDAFA00B28141,
+                               E81BE435055EDAFA00B28141,
+                               E81BE437055EDAFA00B28141,
+                               E81BE439055EDAFA00B28141,
+                               E81BE43B055EDAFA00B28141,
+                               E81BE43D055EDAFA00B28141,
+                               E81BE43F055EDAFA00B28141,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81E06A1055E6E35006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81BE421055EDAFA00B28141,
+                               E81BE423055EDAFA00B28141,
+                               E81BE424055EDAFA00B28141,
+                               E81BE427055EDAFA00B28141,
+                               E81BE428055EDAFA00B28141,
+                               E81BE429055EDAFA00B28141,
+                               E81BE42A055EDAFA00B28141,
+                               E81BE441055EDAFA00B28141,
+                               E81BE442055EDAFA00B28141,
+                               E81BE443055EDAFA00B28141,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81E06A2055E6E35006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81BE426055EDAFA00B28141,
+                               E81BE42D055EDAFA00B28141,
+                               E81BE42F055EDAFA00B28141,
+                               E81BE432055EDAFA00B28141,
+                               E81BE434055EDAFA00B28141,
+                               E81BE436055EDAFA00B28141,
+                               E81BE438055EDAFA00B28141,
+                               E81BE43A055EDAFA00B28141,
+                               E81BE43C055EDAFA00B28141,
+                               E81BE43E055EDAFA00B28141,
+                               E81BE440055EDAFA00B28141,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81E06A3055E6E35006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD16272305D934F700A7368D,
+                               E81BE4D5055EDD9800B28141,
+                               E81BE4D4055EDD9700B28141,
+                               AD52287B06A7F62000B24132,
+                               AD52287A06A7F62000B24132,
+                               AD853AA706A7F7F300727CA0,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81E06A4055E6E35006FE529 = {
+                       buildPhases = (
+                               E81E06A0055E6E35006FE529,
+                               E81E06A1055E6E35006FE529,
+                               E81E06A2055E6E35006FE529,
+                               E81E06A3055E6E35006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGLdap/NGLdap-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC1C00000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGLdap;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGLdap;
+                       productName = NGLdap;
+                       productReference = E81E06A5055E6E35006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGLdap</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGLdap</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81E06A5055E6E35006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGLdap.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81E06C0055E6E71006FE529 = {
+                       children = (
+                               E81E04DF055DE7E3006FE529,
+                               E81E04C2055DE7E3006FE529,
+                               E81E04DE055DE7E3006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Unused;
+                       path = "";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E06C3055E6EC6006FE529 = {
+                       children = (
+                               E81E04C1055DE7E3006FE529,
+                               E81E04C3055DE7E3006FE529,
+                               E81E04CB055DE7E3006FE529,
+                               E81E04CC055DE7E3006FE529,
+                               E81E04D3055DE7E3006FE529,
+                               E81E04D4055DE7E3006FE529,
+                               E81E04D5055DE7E3006FE529,
+                               E81E04D6055DE7E3006FE529,
+                               E81E04D8055DE7E3006FE529,
+                               E81E04D9055DE7E3006FE529,
+                               E81E04DA055DE7E3006FE529,
+                               E81E04DB055DE7E3006FE529,
+                               E81E04DC055DE7E3006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Network;
+                       path = "";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5C3055DC9BE006FE529 = {
+                       children = (
+                               E81EF61F055DCA6C006FE529,
+                               AD16270E05D91F6300A7368D,
+                               E81EF61B055DCA6C006FE529,
+                               E81EF61C055DCA6C006FE529,
+                               E81EF61E055DCA6C006FE529,
+                               AD0CE00A05D950D9004D9B87,
+                               E81EF620055DCA6C006FE529,
+                               E81EFB2F055DD862006FE529,
+                               E81EF5D7055DC9F3006FE529,
+                               E81EF5D6055DC9F0006FE529,
+                               E81EF5D5055DC9E9006FE529,
+                               E81EF5D3055DC9E0006FE529,
+                               E81EF5D4055DC9E6006FE529,
+                               E81EF5D2055DC9D9006FE529,
+                               ADDB75C805C0981B009DBFB4,
+                               E8F255DA05769CE60049F554,
+                               E81EF62B055DCB17006FE529,
+                               E81E0450055DE791006FE529,
+                       );
+                       isa = PBXGroup;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5C5055DC9BE006FE529 = {
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = "APPLE_RUNTIME=1 NeXT_Foundation_LIBRARY=1 COCOA_Foundation_LIBRARY=1 NeXT_RUNTIME=1 COMPILE_AS_FRAMEWORK=1 DEBUG=1";
+                       };
+                       isa = PBXBuildStyle;
+                       name = Development;
+               };
+               E81EF5C7055DC9BE006FE529 = {
+                       buildSettings = {
+                       };
+                       buildStyles = (
+                               E81EF5C5055DC9BE006FE529,
+                               AD5226CB06A7F0C200B24132,
+                       );
+                       hasScannedForEncodings = 1;
+                       isa = PBXProject;
+                       mainGroup = E81EF5C3055DC9BE006FE529;
+                       productRefGroup = E81EF62B055DCB17006FE529;
+                       projectDirPath = "";
+                       targets = (
+                               E81EF629055DCB17006FE529,
+                               E81EF632055DCB38006FE529,
+                               E81EF63A055DCB43006FE529,
+                               E8BA2119055F032600AD687B,
+                               E8BA2121055F033F00AD687B,
+                               E81EF642055DCB4D006FE529,
+                               E81E06A4055E6E35006FE529,
+                               E81EF653055DCB62006FE529,
+                               ADDB6FC305C05BC8009DBFB4,
+                               AD5221D706A7E07400B24132,
+                               E8F2562F05769D7F0049F554,
+                               E8F2562505769D720049F554,
+                               E8F2561305769D5C0049F554,
+                               E8F2561B05769D660049F554,
+                               E8F2560B05769D500049F554,
+                               E83DAE27064D381800D50E72,
+                               E81EF657055DCB6D006FE529,
+                               E81EF65F055DCB8D006FE529,
+                       );
+               };
+               E81EF5D2055DC9D9006FE529 = {
+                       children = (
+                               E81BE47A055EDB5700B28141,
+                               E81BE451055EDB5600B28141,
+                               E81BE452055EDB5600B28141,
+                               E81BE44F055EDB5600B28141,
+                               E81BE47B055EDB5700B28141,
+                               E81BE473055EDB5700B28141,
+                               E81BE475055EDB5700B28141,
+                               E81BE4AB055EDB7E00B28141,
+                               E81BE4AE055EDB9900B28141,
+                               E81BE4B1055EDBA800B28141,
+                               E8BA21C1055F0CD600AD687B,
+                       );
+                       isa = PBXGroup;
+                       name = NGiCal;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5D3055DC9E0006FE529 = {
+                       children = (
+                               E81BE31A055EDAD500B28141,
+                               E81BE23A055EDACF00B28141,
+                               E81BE23C055EDACF00B28141,
+                               E81BE23D055EDACF00B28141,
+                               E81BE31D055EDAD500B28141,
+                               E81BE2F4055EDAD400B28141,
+                               E81BE4BA055EDC0200B28141,
+                               E81BE4B4055EDBCB00B28141,
+                               E81BE4B7055EDBF100B28141,
+                               E81BE4BD055EDC2400B28141,
+                               E81BE243055EDACF00B28141,
+                               E81BE29E055EDAD200B28141,
+                       );
+                       isa = PBXGroup;
+                       name = NGMime;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5D4055DC9E6006FE529 = {
+                       children = (
+                               E81BE41E055EDAF900B28141,
+                               E81BE41F055EDAF900B28141,
+                               E81BE3FE055EDAF900B28141,
+                               E81BE400055EDAF900B28141,
+                               E81BE401055EDAF900B28141,
+                               E81BE420055EDAF900B28141,
+                               E81BE407055EDAF900B28141,
+                               E81BE446055EDB0100B28141,
+                               E81BE449055EDB1E00B28141,
+                               E81BE44C055EDB2A00B28141,
+                       );
+                       isa = PBXGroup;
+                       name = NGLdap;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5D5055DC9E9006FE529 = {
+                       children = (
+                               E81E04E7055DE7E3006FE529,
+                               E81E04B2055DE7E2006FE529,
+                               E81E04B9055DE7E2006FE529,
+                               E81E04BA055DE7E2006FE529,
+                               E81E04E9055DE7E3006FE529,
+                               E81E052A055DE833006FE529,
+                               E81E0524055DE7F2006FE529,
+                               E81E05C9055DE8B2006FE529,
+                               E81E05CB055DE8B2006FE529,
+                               E81E0527055DE816006FE529,
+                               E81E06C3055E6EC6006FE529,
+                               E81E06C0055E6E71006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = NGStreams;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5D6055DC9F0006FE529 = {
+                       children = (
+                               E81EF6A3055DD414006FE529,
+                               E81EF6A5055DD414006FE529,
+                               E81EF6A6055DD414006FE529,
+                               E81EF7D7055DD41B006FE529,
+                               E81EF7D8055DD41B006FE529,
+                               E81EF92E055DD4DF006FE529,
+                               E81EF925055DD4A7006FE529,
+                               E81EF769055DD418006FE529,
+                               E81EF922055DD49C006FE529,
+                               E81EF6A7055DD414006FE529,
+                               E81EF6EA055DD416006FE529,
+                               E81EF7D9055DD41B006FE529,
+                               E81EF7B2055DD41A006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = NGExtensions;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5D7055DC9F3006FE529 = {
+                       children = (
+                               E81EF610055DCA42006FE529,
+                               E81EF5DC055DCA42006FE529,
+                               E81EF5DE055DCA42006FE529,
+                               E81EF5DF055DCA42006FE529,
+                               E81EF613055DCA42006FE529,
+                               E81EF612055DCA42006FE529,
+                               E81EF621055DCABB006FE529,
+                               E81EF622055DCAC2006FE529,
+                               E81EF616055DCA4B006FE529,
+                               E81EF617055DCA52006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = EOControl;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5DC055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = EOControl/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5DD055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = EOControl/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5DE055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = EOControl/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5DF055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = EOControl/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5E0055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOAndQualifier.m;
+                       path = EOControl/EOAndQualifier.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5E1055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOArrayDataSource.h;
+                       path = EOControl/EOArrayDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5E2055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOArrayDataSource.m;
+                       path = EOControl/EOArrayDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5E3055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOClassDescription.h;
+                       path = EOControl/EOClassDescription.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5E4055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOClassDescription.m;
+                       path = EOControl/EOClassDescription.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5E5055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOControl.h;
+                       path = EOControl/EOControl.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5E6055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOControlDecls.h;
+                       path = EOControl/EOControlDecls.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5E7055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EODataSource.h;
+                       path = EOControl/EODataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5E8055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EODataSource.m;
+                       path = EOControl/EODataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5E9055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EODetailDataSource.h;
+                       path = EOControl/EODetailDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5EA055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EODetailDataSource.m;
+                       path = EOControl/EODetailDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5EF055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOFetchSpecification.h;
+                       path = EOControl/EOFetchSpecification.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5F0055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOFetchSpecification.m;
+                       path = EOControl/EOFetchSpecification.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5F1055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOGenericRecord.h;
+                       path = EOControl/EOGenericRecord.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5F2055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOGenericRecord.m;
+                       path = EOControl/EOGenericRecord.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5F3055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOGlobalID.h;
+                       path = EOControl/EOGlobalID.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5F4055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOGlobalID.m;
+                       path = EOControl/EOGlobalID.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5F5055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOKeyComparisonQualifier.m;
+                       path = EOControl/EOKeyComparisonQualifier.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5F6055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOKeyGlobalID.h;
+                       path = EOControl/EOKeyGlobalID.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5F7055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOKeyGlobalID.m;
+                       path = EOControl/EOKeyGlobalID.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5F8055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOKeyValueArchiver.h;
+                       path = EOControl/EOKeyValueArchiver.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5F9055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOKeyValueArchiver.m;
+                       path = EOControl/EOKeyValueArchiver.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5FA055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOKeyValueCoding.h;
+                       path = EOControl/EOKeyValueCoding.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5FB055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOKeyValueCoding.m;
+                       path = EOControl/EOKeyValueCoding.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5FC055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOKeyValueQualifier.m;
+                       path = EOControl/EOKeyValueQualifier.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5FD055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EONotQualifier.m;
+                       path = EOControl/EONotQualifier.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5FE055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EONull.h;
+                       path = EOControl/EONull.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF5FF055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EONull.m;
+                       path = EOControl/EONull.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF600055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOObserver.h;
+                       path = EOControl/EOObserver.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF601055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOObserver.m;
+                       path = EOControl/EOObserver.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF602055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOOrQualifier.m;
+                       path = EOControl/EOOrQualifier.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF603055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOQualifier.h;
+                       path = EOControl/EOQualifier.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF604055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOQualifier.m;
+                       path = EOControl/EOQualifier.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF605055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOQualifierParser.m;
+                       path = EOControl/EOQualifierParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF606055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOSortOrdering.h;
+                       path = EOControl/EOSortOrdering.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF607055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOSortOrdering.m;
+                       path = EOControl/EOSortOrdering.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF608055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOSQLParser.h;
+                       path = EOControl/EOSQLParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF609055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOSQLParser.m;
+                       path = EOControl/EOSQLParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF60A055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOValidation.m;
+                       path = EOControl/EOValidation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF60B055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = EOControl/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF60C055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = EOControl/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF60D055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = libEOControl.def;
+                       path = EOControl/libEOControl.def;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF60E055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSArray+EOQualifier.m";
+                       path = "EOControl/NSArray+EOQualifier.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF60F055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSObject+EOQualifierOps.m";
+                       path = "EOControl/NSObject+EOQualifierOps.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF610055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = EOControl/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF611055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       name = "SxCore-EOControl.graffle";
+                       path = "EOControl/SxCore-EOControl.graffle";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF612055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = TODO;
+                       path = EOControl/TODO;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF613055DCA42006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = EOControl/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF616055DCA4B006FE529 = {
+                       children = (
+                               E81EF5E1055DCA42006FE529,
+                               E81EF5E3055DCA42006FE529,
+                               E81EF5E5055DCA42006FE529,
+                               E81EF5E6055DCA42006FE529,
+                               E81EF5E7055DCA42006FE529,
+                               E81EF5E9055DCA42006FE529,
+                               E81EF5EF055DCA42006FE529,
+                               E81EF5F1055DCA42006FE529,
+                               E81EF5F3055DCA42006FE529,
+                               E81EF5F6055DCA42006FE529,
+                               E81EF5F8055DCA42006FE529,
+                               E81EF5FA055DCA42006FE529,
+                               E81EF5FE055DCA42006FE529,
+                               E81EF600055DCA42006FE529,
+                               E81EF603055DCA42006FE529,
+                               E81EF606055DCA42006FE529,
+                               E81EF608055DCA42006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF617055DCA52006FE529 = {
+                       children = (
+                               E81EF5DD055DCA42006FE529,
+                               E81EF5E0055DCA42006FE529,
+                               E81EF5E2055DCA42006FE529,
+                               E81EF5E4055DCA42006FE529,
+                               E81EF5E8055DCA42006FE529,
+                               E81EF5EA055DCA42006FE529,
+                               E81EF5F0055DCA42006FE529,
+                               E81EF5F2055DCA42006FE529,
+                               E81EF5F4055DCA42006FE529,
+                               E81EF5F5055DCA42006FE529,
+                               E81EF5F7055DCA42006FE529,
+                               E81EF5F9055DCA42006FE529,
+                               E81EF5FB055DCA42006FE529,
+                               E81EF5FC055DCA42006FE529,
+                               E81EF5FD055DCA42006FE529,
+                               E81EF5FF055DCA42006FE529,
+                               E81EF601055DCA42006FE529,
+                               E81EF602055DCA42006FE529,
+                               E81EF604055DCA42006FE529,
+                               E81EF605055DCA42006FE529,
+                               E860D21B05FC97020074B7B0,
+                               E81EF607055DCA42006FE529,
+                               E81EF609055DCA42006FE529,
+                               E81EF60A055DCA42006FE529,
+                               E81EF60E055DCA42006FE529,
+                               E81EF60F055DCA42006FE529,
+                               E860D22A05FC97260074B7B0,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF61A055DCA6C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = common.make;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF61B055DCA6C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF61C055DCA6C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF61D055DCA6C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF61E055DCA6C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = PROJECTLEAD;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF61F055DCA6C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF620055DCA6C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF621055DCABB006FE529 = {
+                       children = (
+                               E81EF60B055DCA42006FE529,
+                               E81EF60C055DCA42006FE529,
+                               E81EF60D055DCA42006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF622055DCAC2006FE529 = {
+                       children = (
+                               E81EF611055DCA42006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Documentation;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF625055DCB17006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EF661055DCBA0006FE529,
+                               E81EF665055DCBA4006FE529,
+                               E81EF667055DCBA5006FE529,
+                               E81EF669055DCBA8006FE529,
+                               E81EF66A055DCBA9006FE529,
+                               E81EF66B055DCBA9006FE529,
+                               E81EF66D055DCBAB006FE529,
+                               E81EF673055DCBB3006FE529,
+                               E81EF675055DCBB6006FE529,
+                               E81EF677055DCBB7006FE529,
+                               E81EF67A055DCBBA006FE529,
+                               E81EF67C055DCBBB006FE529,
+                               E81EF67E055DCBBC006FE529,
+                               E81EF682055DCBC5006FE529,
+                               E81EF684055DCBC6006FE529,
+                               E81EF687055DCBC8006FE529,
+                               E81EF68A055DCBD0006FE529,
+                               E81EF68C055DCBD2006FE529,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF626055DCB17006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EF660055DCB9F006FE529,
+                               E81EF662055DCBA2006FE529,
+                               E81EF663055DCBA2006FE529,
+                               E81EF68F055DCBD3006FE529,
+                               E81EF690055DCBD4006FE529,
+                               E81EF691055DCBD7006FE529,
+                               E81EF697055DCBDE006FE529,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF627055DCB17006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EF664055DCBA3006FE529,
+                               E81EF666055DCBA5006FE529,
+                               E81EF668055DCBA6006FE529,
+                               E81EF66C055DCBAB006FE529,
+                               E81EF66E055DCBAC006FE529,
+                               E81EF674055DCBB4006FE529,
+                               E81EF676055DCBB7006FE529,
+                               E81EF678055DCBB9006FE529,
+                               E81EF679055DCBBA006FE529,
+                               E81EF67B055DCBBB006FE529,
+                               E81EF67D055DCBBC006FE529,
+                               E81EF67F055DCBBD006FE529,
+                               E81EF680055DCBBD006FE529,
+                               E81EF681055DCBC4006FE529,
+                               E81EF683055DCBC5006FE529,
+                               E81EF685055DCBC7006FE529,
+                               E81EF686055DCBC7006FE529,
+                               E81EF688055DCBC8006FE529,
+                               E81EF689055DCBCC006FE529,
+                               E81EF68B055DCBD1006FE529,
+                               E81EF68D055DCBD2006FE529,
+                               E81EF68E055DCBD3006FE529,
+                               E81EF692055DCBD7006FE529,
+                               E81EF693055DCBD9006FE529,
+                               E860D21C05FC97020074B7B0,
+                               E860D22B05FC97260074B7B0,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF628055DCB17006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD16271D05D934F700A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF629055DCB17006FE529 = {
+                       buildPhases = (
+                               E81EF625055DCB17006FE529,
+                               E81EF626055DCB17006FE529,
+                               E81EF627055DCB17006FE529,
+                               E81EF628055DCB17006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "EOControl/EOControl-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC1000000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = EOControl;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = EOControl;
+                       productName = EOControl;
+                       productReference = E81EF62A055DCB17006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>EOControl</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.EOControl</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF62A055DCB17006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = EOControl.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF62B055DCB17006FE529 = {
+                       children = (
+                               E81EF62A055DCB17006FE529,
+                               E81EF633055DCB38006FE529,
+                               E81EF63B055DCB43006FE529,
+                               E81EF643055DCB4D006FE529,
+                               E81EF654055DCB62006FE529,
+                               E81E06A5055E6E35006FE529,
+                               E8BA211A055F032600AD687B,
+                               E8BA2122055F033F00AD687B,
+                               ADDB6FC405C05BC8009DBFB4,
+                               E8F2560C05769D500049F554,
+                               E8F2561405769D5C0049F554,
+                               E8F2561C05769D660049F554,
+                               E8F2562605769D720049F554,
+                               E8F2563005769D7F0049F554,
+                               E83DAE28064D381800D50E72,
+                       );
+                       isa = PBXGroup;
+                       name = Products;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF62E055DCB38006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EF7E6055DD41B006FE529,
+                               E81EF8A5055DD41C006FE529,
+                               E81EF8A6055DD41C006FE529,
+                               E81EF8A7055DD41C006FE529,
+                               E81EF8A8055DD41C006FE529,
+                               E81EF8A9055DD41C006FE529,
+                               E81EF8AA055DD41C006FE529,
+                               E81EF8AB055DD41C006FE529,
+                               E81EF8AC055DD41C006FE529,
+                               E81EF8AD055DD41C006FE529,
+                               E81EF8AE055DD41C006FE529,
+                               E81EF8AF055DD41C006FE529,
+                               E81EF8B0055DD41C006FE529,
+                               E81EF8B1055DD41C006FE529,
+                               E81EF8B2055DD41C006FE529,
+                               E81EF8B3055DD41C006FE529,
+                               E81EF8B4055DD41C006FE529,
+                               E81EF8B5055DD41C006FE529,
+                               E81EF8B6055DD41C006FE529,
+                               E81EF8B7055DD41C006FE529,
+                               E81EF8B8055DD41C006FE529,
+                               E81EF8BA055DD41C006FE529,
+                               E81EF8BB055DD41C006FE529,
+                               E81EF8BC055DD41C006FE529,
+                               E81EF8BD055DD41C006FE529,
+                               E81EF8BE055DD41C006FE529,
+                               E81EF8BF055DD41C006FE529,
+                               E81EF8C0055DD41C006FE529,
+                               E81EF8C1055DD41C006FE529,
+                               E81EF8C2055DD41C006FE529,
+                               E81EF8C3055DD41C006FE529,
+                               E81EF8C4055DD41C006FE529,
+                               E81EF8C5055DD41C006FE529,
+                               E81EF8C6055DD41C006FE529,
+                               E81EF8C7055DD41C006FE529,
+                               E81EF8C8055DD41C006FE529,
+                               E81EF8C9055DD41C006FE529,
+                               E81EF8CA055DD41C006FE529,
+                               E81EF8CB055DD41C006FE529,
+                               E81EF8CC055DD41C006FE529,
+                               E81EF8CD055DD41C006FE529,
+                               E81EF8CE055DD41C006FE529,
+                               E81EF8CF055DD41C006FE529,
+                               E81EF8D0055DD41C006FE529,
+                               E81EF8D1055DD41C006FE529,
+                               E81EF8D2055DD41C006FE529,
+                               E81EF8D3055DD41C006FE529,
+                               E81EF8D4055DD41C006FE529,
+                               E81EF8D5055DD41C006FE529,
+                               E81EF8D6055DD41C006FE529,
+                               E81EF8D7055DD41C006FE529,
+                               E81EF8D8055DD41C006FE529,
+                               E81EF8D9055DD41C006FE529,
+                               E81EF8DA055DD41C006FE529,
+                               E81EF8DB055DD41C006FE529,
+                               E81EF8DC055DD41C006FE529,
+                               E81EF8DD055DD41C006FE529,
+                               E81EF8DE055DD41C006FE529,
+                               E81EF8DF055DD41C006FE529,
+                               E81EF8E0055DD41C006FE529,
+                               E81EF8E1055DD41C006FE529,
+                               E81EF8E2055DD41C006FE529,
+                               E81EF8E3055DD41C006FE529,
+                               E81EF8F3055DD41C006FE529,
+                               E8CA85000605CC0F006366AB,
+                               E8CA85050605CC10006366AB,
+                               E8CA85070605CC11006366AB,
+                               AD1803290611DEFE00ED723F,
+                               AD73C3FC06D10BDF00226A2D,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF62F055DCB38006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EF7E5055DD41B006FE529,
+                               E81EF7E7055DD41B006FE529,
+                               E81EF7E8055DD41B006FE529,
+                               E81EF7E9055DD41B006FE529,
+                               E81EF7F5055DD41B006FE529,
+                               E81EF829055DD41C006FE529,
+                               E81EF82A055DD41C006FE529,
+                               E81EF89C055DD41C006FE529,
+                               E81EF89D055DD41C006FE529,
+                               E81EF89E055DD41C006FE529,
+                               E81EF8ED055DD41C006FE529,
+                               E81EF8EE055DD41C006FE529,
+                               E81EF900055DD41C006FE529,
+                               E81EF90E055DD41C006FE529,
+                               E81EF90F055DD41C006FE529,
+                               E81EF910055DD41C006FE529,
+                               E81EF911055DD41C006FE529,
+                               E81EF913055DD41C006FE529,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF630055DCB38006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EF7EA055DD41B006FE529,
+                               E81EF7EB055DD41B006FE529,
+                               E81EF7EC055DD41B006FE529,
+                               E81EF7ED055DD41B006FE529,
+                               E81EF7EE055DD41B006FE529,
+                               E81EF7EF055DD41B006FE529,
+                               E81EF7F0055DD41B006FE529,
+                               E81EF7F1055DD41B006FE529,
+                               E81EF7F2055DD41B006FE529,
+                               E81EF7F3055DD41B006FE529,
+                               E81EF7F4055DD41B006FE529,
+                               E81EF7F6055DD41B006FE529,
+                               E81EF82B055DD41C006FE529,
+                               E81EF82C055DD41C006FE529,
+                               E81EF82D055DD41C006FE529,
+                               E81EF82E055DD41C006FE529,
+                               E81EF82F055DD41C006FE529,
+                               E81EF830055DD41C006FE529,
+                               E81EF831055DD41C006FE529,
+                               E81EF832055DD41C006FE529,
+                               E81EF833055DD41C006FE529,
+                               E81EF834055DD41C006FE529,
+                               E81EF835055DD41C006FE529,
+                               E81EF836055DD41C006FE529,
+                               E81EF837055DD41C006FE529,
+                               E81EF838055DD41C006FE529,
+                               E81EF839055DD41C006FE529,
+                               E81EF83A055DD41C006FE529,
+                               E81EF83B055DD41C006FE529,
+                               E81EF83C055DD41C006FE529,
+                               E81EF83D055DD41C006FE529,
+                               E81EF83E055DD41C006FE529,
+                               E81EF83F055DD41C006FE529,
+                               E81EF840055DD41C006FE529,
+                               E81EF89B055DD41C006FE529,
+                               E81EF89F055DD41C006FE529,
+                               E81EF8A0055DD41C006FE529,
+                               E81EF8A1055DD41C006FE529,
+                               E81EF8A3055DD41C006FE529,
+                               E81EF8A4055DD41C006FE529,
+                               E81EF8E4055DD41C006FE529,
+                               E81EF8E5055DD41C006FE529,
+                               E81EF8E6055DD41C006FE529,
+                               E81EF8E7055DD41C006FE529,
+                               E81EF8E8055DD41C006FE529,
+                               E81EF8E9055DD41C006FE529,
+                               E81EF8EA055DD41C006FE529,
+                               E81EF8EB055DD41C006FE529,
+                               E81EF8EC055DD41C006FE529,
+                               E81EF8EF055DD41C006FE529,
+                               E81EF8F0055DD41C006FE529,
+                               E81EF8F1055DD41C006FE529,
+                               E81EF8F2055DD41C006FE529,
+                               E81EF8F4055DD41C006FE529,
+                               E81EF90C055DD41C006FE529,
+                               E81EF912055DD41C006FE529,
+                               E8FDB0CD056C297A002DFB9D,
+                               E8FDB0CE056C297A002DFB9D,
+                               E8FDB0CF056C297A002DFB9D,
+                               E8CA85170605CC1F006366AB,
+                               E8CA851A0605CC21006366AB,
+                               E8CA851C0605CC22006366AB,
+                               AD1803270611DE9B00ED723F,
+                               AD73C3FA06D10BAD00226A2D,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF631055DCB38006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD16271E05D934F700A7368D,
+                               E81E03E5055DDCA0006FE529,
+                               AD52286006A7F48F00B24132,
+                               AD52285F06A7F47500B24132,
+                               AD1802560611DB7C00ED723F,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF632055DCB38006FE529 = {
+                       buildPhases = (
+                               E81EF62E055DCB38006FE529,
+                               E81EF62F055DCB38006FE529,
+                               E81EF630055DCB38006FE529,
+                               E81EF631055DCB38006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGExtensions/NGExtensions-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC1200000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGExtensions;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGExtensions;
+                       productName = NGExtensions;
+                       productReference = E81EF633055DCB38006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGExtensions</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGExtensions</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF633055DCB38006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGExtensions.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF636055DCB43006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81E04EB055DE7E4006FE529,
+                               E81E0513055DE7E4006FE529,
+                               E81E05F8055DE8B4006FE529,
+                               E81E05F9055DE8B4006FE529,
+                               E81E05FA055DE8B4006FE529,
+                               E81E05FB055DE8B4006FE529,
+                               E81E05FC055DE8B4006FE529,
+                               E81E05FD055DE8B4006FE529,
+                               E81E05FE055DE8B4006FE529,
+                               E81E05FF055DE8B4006FE529,
+                               E81E0600055DE8B4006FE529,
+                               E81E0601055DE8B4006FE529,
+                               E81E0602055DE8B4006FE529,
+                               E81E0603055DE8B4006FE529,
+                               E81E0604055DE8B4006FE529,
+                               E81E0605055DE8B4006FE529,
+                               E81E0606055DE8B4006FE529,
+                               E81E0607055DE8B4006FE529,
+                               E81E0608055DE8B4006FE529,
+                               E81E0609055DE8B4006FE529,
+                               E81E060A055DE8B4006FE529,
+                               E81E060B055DE8B4006FE529,
+                               E81E060C055DE8B4006FE529,
+                               E81E060D055DE8B4006FE529,
+                               E81E060E055DE8B4006FE529,
+                               E81E060F055DE8B4006FE529,
+                               E81E0610055DE8B4006FE529,
+                               E81E0611055DE8B4006FE529,
+                               E81E0612055DE8B4006FE529,
+                               E81E0613055DE8B4006FE529,
+                               E81E0614055DE8B4006FE529,
+                               E81E0615055DE8B4006FE529,
+                               E81E0616055DE8B4006FE529,
+                               E81E0617055DE8B4006FE529,
+                               E81E0618055DE8B4006FE529,
+                               E81E0619055DE8B4006FE529,
+                               E81E061A055DE8B4006FE529,
+                               E81E061B055DE8B4006FE529,
+                               E81E061C055DE8B4006FE529,
+                               E81E061D055DE8B4006FE529,
+                               E81E061E055DE8B4006FE529,
+                               E81E061F055DE8B4006FE529,
+                               E81E0620055DE8B4006FE529,
+                               E81E0621055DE8B4006FE529,
+                               E81E0622055DE8B4006FE529,
+                               E81E0623055DE8B4006FE529,
+                               E81E0624055DE8B4006FE529,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF637055DCB43006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81E04EA055DE7E4006FE529,
+                               E81E04F1055DE7E4006FE529,
+                               E81E04F2055DE7E4006FE529,
+                               E81E051F055DE7E4006FE529,
+                               E81E0521055DE7E4006FE529,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF638055DCB43006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81E04F9055DE7E4006FE529,
+                               E81E04FC055DE7E4006FE529,
+                               E81E04FD055DE7E4006FE529,
+                               E81E04FE055DE7E4006FE529,
+                               E81E04FF055DE7E4006FE529,
+                               E81E0500055DE7E4006FE529,
+                               E81E0501055DE7E4006FE529,
+                               E81E0502055DE7E4006FE529,
+                               E81E0503055DE7E4006FE529,
+                               E81E0504055DE7E4006FE529,
+                               E81E0505055DE7E4006FE529,
+                               E81E0506055DE7E4006FE529,
+                               E81E0507055DE7E4006FE529,
+                               E81E0508055DE7E4006FE529,
+                               E81E0509055DE7E4006FE529,
+                               E81E050A055DE7E4006FE529,
+                               E81E050B055DE7E4006FE529,
+                               E81E050C055DE7E4006FE529,
+                               E81E050D055DE7E4006FE529,
+                               E81E050E055DE7E4006FE529,
+                               E81E050F055DE7E4006FE529,
+                               E81E0510055DE7E4006FE529,
+                               E81E0511055DE7E4006FE529,
+                               E81E0512055DE7E4006FE529,
+                               E81E0514055DE7E4006FE529,
+                               E81E0515055DE7E4006FE529,
+                               E81E0518055DE7E4006FE529,
+                               E81E0519055DE7E4006FE529,
+                               E81E051A055DE7E4006FE529,
+                               E81E051B055DE7E4006FE529,
+                               E81E051C055DE7E4006FE529,
+                               E81E051D055DE7E4006FE529,
+                               E81E051E055DE7E4006FE529,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF639055DCB43006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD16271F05D934F700A7368D,
+                               AD1802570611DBD300ED723F,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF63A055DCB43006FE529 = {
+                       buildPhases = (
+                               E81EF636055DCB43006FE529,
+                               E81EF637055DCB43006FE529,
+                               E81EF638055DCB43006FE529,
+                               E81EF639055DCB43006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = YES;
+                               INFOPLIST_FILE = "NGStreams/NGStreams-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC1400000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGStreams;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGStreams;
+                       productName = NGStreams;
+                       productReference = E81EF63B055DCB43006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGStreams</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGStreams</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF63B055DCB43006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGStreams.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF63E055DCB4D006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81BE31F055EDAD500B28141,
+                               E81BE325055EDAD500B28141,
+                               E81BE32C055EDAD500B28141,
+                               E81BE32E055EDAD500B28141,
+                               E81BE330055EDAD500B28141,
+                               E81BE332055EDAD500B28141,
+                               E81BE334055EDAD500B28141,
+                               E81BE336055EDAD600B28141,
+                               E81BE338055EDAD600B28141,
+                               E81BE33A055EDAD600B28141,
+                               E81BE33B055EDAD600B28141,
+                               E81BE33D055EDAD600B28141,
+                               E81BE33F055EDAD600B28141,
+                               E81BE341055EDAD600B28141,
+                               E81BE343055EDAD600B28141,
+                               E81BE345055EDAD600B28141,
+                               E81BE381055EDAD600B28141,
+                               E81BE385055EDAD600B28141,
+                               E81BE387055EDAD600B28141,
+                               E81BE389055EDAD600B28141,
+                               E81BE38B055EDAD600B28141,
+                               E81BE38D055EDAD600B28141,
+                               E81BE38E055EDAD600B28141,
+                               E81BE390055EDAD600B28141,
+                               E81BE392055EDAD600B28141,
+                               E81BE394055EDAD600B28141,
+                               E81BE396055EDAD600B28141,
+                               E81BE398055EDAD600B28141,
+                               E81BE39A055EDAD600B28141,
+                               E81BE39C055EDAD600B28141,
+                               E81BE39D055EDAD600B28141,
+                               E81BE3D3055EDAD600B28141,
+                               E81BE3D5055EDAD600B28141,
+                               E81BE3D7055EDAD600B28141,
+                               E81BE3D9055EDAD600B28141,
+                               E81BE3DB055EDAD600B28141,
+                               E81BE3DD055EDAD600B28141,
+                               E81BE3DE055EDAD600B28141,
+                               E81BE3E0055EDAD600B28141,
+                               E81BE3E2055EDAD600B28141,
+                               E81BE3E3055EDAD600B28141,
+                               E81BE3E5055EDAD600B28141,
+                               E81BE3E7055EDAD600B28141,
+                               E81BE3E9055EDAD600B28141,
+                               E81BE3EB055EDAD600B28141,
+                               E81BE3EE055EDAD600B28141,
+                               E81BE3F0055EDAD600B28141,
+                               E81BE3F2055EDAD600B28141,
+                               E81BE3F4055EDAD600B28141,
+                               E81BE3F6055EDAD600B28141,
+                               E81BE3FA055EDAD600B28141,
+                               E820934305B0D30B0088B931,
+                               E820934405B0D30B0088B931,
+                               E824CFED05BD7C9C0081A110,
+                               E824CFEF05BD7C9C0081A110,
+                               E824CFF105BD7C9C0081A110,
+                               E84E826605C14F81005792AF,
+                               E84E826805C14F81005792AF,
+                               E8ACC6C005CED366005ADB68,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF63F055DCB4D006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81BE31E055EDAD500B28141,
+                               E81BE320055EDAD500B28141,
+                               E81BE321055EDAD500B28141,
+                               E81BE322055EDAD500B28141,
+                               E81BE323055EDAD500B28141,
+                               E81BE324055EDAD500B28141,
+                               E81BE327055EDAD500B28141,
+                               E81BE328055EDAD500B28141,
+                               E81BE32A055EDAD500B28141,
+                               E81BE32B055EDAD500B28141,
+                               E81BE362055EDAD600B28141,
+                               E81BE37F055EDAD600B28141,
+                               E81BE380055EDAD600B28141,
+                               E81BE382055EDAD600B28141,
+                               E81BE383055EDAD600B28141,
+                               E81BE384055EDAD600B28141,
+                               E81BE3B8055EDAD600B28141,
+                               E81BE3D2055EDAD600B28141,
+                               E81BE3F8055EDAD600B28141,
+                               E81BE3F9055EDAD600B28141,
+                               E81BE3FB055EDAD600B28141,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF640055DCB4D006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81BE326055EDAD500B28141,
+                               E81BE32D055EDAD500B28141,
+                               E81BE32F055EDAD500B28141,
+                               E81BE331055EDAD500B28141,
+                               E81BE333055EDAD500B28141,
+                               E81BE335055EDAD600B28141,
+                               E81BE337055EDAD600B28141,
+                               E81BE339055EDAD600B28141,
+                               E81BE33C055EDAD600B28141,
+                               E81BE33E055EDAD600B28141,
+                               E81BE340055EDAD600B28141,
+                               E81BE342055EDAD600B28141,
+                               E81BE344055EDAD600B28141,
+                               E81BE346055EDAD600B28141,
+                               E81BE386055EDAD600B28141,
+                               E81BE388055EDAD600B28141,
+                               E81BE38A055EDAD600B28141,
+                               E81BE38C055EDAD600B28141,
+                               E81BE38F055EDAD600B28141,
+                               E81BE391055EDAD600B28141,
+                               E81BE393055EDAD600B28141,
+                               E81BE395055EDAD600B28141,
+                               E81BE397055EDAD600B28141,
+                               E81BE399055EDAD600B28141,
+                               E81BE39B055EDAD600B28141,
+                               E81BE39E055EDAD600B28141,
+                               E81BE3D4055EDAD600B28141,
+                               E81BE3D6055EDAD600B28141,
+                               E81BE3D8055EDAD600B28141,
+                               E81BE3DA055EDAD600B28141,
+                               E81BE3DC055EDAD600B28141,
+                               E81BE3DF055EDAD600B28141,
+                               E81BE3E1055EDAD600B28141,
+                               E81BE3E4055EDAD600B28141,
+                               E81BE3E6055EDAD600B28141,
+                               E81BE3E8055EDAD600B28141,
+                               E81BE3EA055EDAD600B28141,
+                               E81BE3EC055EDAD600B28141,
+                               E81BE3ED055EDAD600B28141,
+                               E81BE3EF055EDAD600B28141,
+                               E81BE3F1055EDAD600B28141,
+                               E81BE3F3055EDAD600B28141,
+                               E81BE3F5055EDAD600B28141,
+                               E81BE3F7055EDAD600B28141,
+                               E897B38305B8519900B708BC,
+                               E897B38405B8519A00B708BC,
+                               E897B38505B8519B00B708BC,
+                               E897B38605B8519D00B708BC,
+                               E897B38705B8519E00B708BC,
+                               E897B38805B8519F00B708BC,
+                               E897B38D05B8523E00B708BC,
+                               E824CFEE05BD7C9C0081A110,
+                               E824CFF005BD7C9C0081A110,
+                               E824CFF205BD7C9C0081A110,
+                               E84E826705C14F81005792AF,
+                               E84E826905C14F81005792AF,
+                               E8ACC6C105CED366005ADB68,
+                               E80D72AF05D6BA6E0050931F,
+                               E80D72B005D6BA6E0050931F,
+                               E80D72B105D6BA6E0050931F,
+                               E80D72B205D6BA6E0050931F,
+                               E80D72CF05D6BAB10050931F,
+                               E80D72D005D6BAB10050931F,
+                               E80D72D105D6BAB10050931F,
+                               E80D72D205D6BAB10050931F,
+                               E80D72D305D6BAB10050931F,
+                               E80D72D405D6BAB10050931F,
+                               E80D72D505D6BAB10050931F,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF641055DCB4D006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD16272205D934F700A7368D,
+                               E81BE4D1055EDD8C00B28141,
+                               E81BE4D2055EDD8D00B28141,
+                               E81BE4D3055EDD8F00B28141,
+                               AD52287806A7F5B400B24132,
+                               AD52287906A7F5B400B24132,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF642055DCB4D006FE529 = {
+                       buildPhases = (
+                               E81EF63E055DCB4D006FE529,
+                               E81EF63F055DCB4D006FE529,
+                               E81EF640055DCB4D006FE529,
+                               E81EF641055DCB4D006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGMime/NGMime-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC1A00000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGMime;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                               E8BA2126055F035700AD687B,
+                               E8BA2128055F035700AD687B,
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGMime;
+                       productName = NGMime;
+                       productReference = E81EF643055DCB4D006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGMime</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGMime</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF643055DCB4D006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGMime.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF64F055DCB62006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81BE481055EDB5700B28141,
+                               E81BE483055EDB5700B28141,
+                               E81BE485055EDB5700B28141,
+                               E81BE487055EDB5700B28141,
+                               E81BE489055EDB5700B28141,
+                               E81BE48B055EDB5700B28141,
+                               E81BE48E055EDB5700B28141,
+                               E81BE490055EDB5700B28141,
+                               E81BE492055EDB5700B28141,
+                               E81BE494055EDB5700B28141,
+                               E81BE496055EDB5700B28141,
+                               E81BE498055EDB5700B28141,
+                               E81BE49A055EDB5700B28141,
+                               E81BE49C055EDB5700B28141,
+                               E81BE49E055EDB5700B28141,
+                               E81BE4A1055EDB5700B28141,
+                               E81BE4A3055EDB5700B28141,
+                               E8FDB0E9056C3DE4002DFB9D,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF650055DCB62006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81BE47C055EDB5700B28141,
+                               E81BE47E055EDB5700B28141,
+                               E81BE47F055EDB5700B28141,
+                               E81BE480055EDB5700B28141,
+                               E81BE4A0055EDB5700B28141,
+                               E81BE4A2055EDB5700B28141,
+                               E81BE4A7055EDB5700B28141,
+                               E81BE4A8055EDB5700B28141,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF651055DCB62006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81BE482055EDB5700B28141,
+                               E81BE484055EDB5700B28141,
+                               E81BE486055EDB5700B28141,
+                               E81BE488055EDB5700B28141,
+                               E81BE48A055EDB5700B28141,
+                               E81BE48C055EDB5700B28141,
+                               E81BE48F055EDB5700B28141,
+                               E81BE491055EDB5700B28141,
+                               E81BE493055EDB5700B28141,
+                               E81BE495055EDB5700B28141,
+                               E81BE497055EDB5700B28141,
+                               E81BE499055EDB5700B28141,
+                               E81BE49B055EDB5700B28141,
+                               E81BE49D055EDB5700B28141,
+                               E81BE49F055EDB5700B28141,
+                               E81BE4A4055EDB5700B28141,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF652055DCB62006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD16272405D934F700A7368D,
+                               E81BE4D6055EDD9B00B28141,
+                               E81BE4D7055EDD9B00B28141,
+                               AD853AAB06A7F84400727CA0,
+                               AD853AAC06A7F86E00727CA0,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF653055DCB62006FE529 = {
+                       buildPhases = (
+                               E81EF64F055DCB62006FE529,
+                               E81EF650055DCB62006FE529,
+                               E81EF651055DCB62006FE529,
+                               E81EF652055DCB62006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGiCal/NGiCal-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC1E00000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGiCal;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGiCal;
+                       productName = NGiCal;
+                       productReference = E81EF654055DCB62006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGiCal</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGiCal</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF654055DCB62006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGiCal.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF657055DCB6D006FE529 = {
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = all;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       dependencies = (
+                               E81BE21A055EDA6700B28141,
+                               E81BE21C055EDA6700B28141,
+                               E81BE21E055EDA6700B28141,
+                               E81BE220055EDA6700B28141,
+                               E81BE222055EDA6700B28141,
+                               E81BE224055EDA6700B28141,
+                               E82093AC05B0D5DD0088B931,
+                               E82093B105B0D6150088B931,
+                               E82093D305B0D6800088B931,
+                               E82093D505B0D6800088B931,
+                               E840BA8F05B0D86000F799A1,
+                               E83DB660064DA26000D50E72,
+                               ADDB70D405C05CE5009DBFB4,
+                       );
+                       isa = PBXAggregateTarget;
+                       name = all;
+                       productName = all;
+               };
+               E81EF65F055DCB8D006FE529 = {
+                       buildArgumentsString = /usr/bin/make;
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "GSM: all";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       buildToolPath = /usr/bin/make;
+                       dependencies = (
+                       );
+                       isa = PBXLegacyTarget;
+                       name = "GSM: all";
+                       passBuildSettingsInEnvironment = 1;
+                       productName = "GSM: all";
+               };
+               E81EF660055DCB9F006FE529 = {
+                       fileRef = E81EF5DC055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF661055DCBA0006FE529 = {
+                       fileRef = E81EF5DD055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF662055DCBA2006FE529 = {
+                       fileRef = E81EF5DE055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF663055DCBA2006FE529 = {
+                       fileRef = E81EF5DF055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF664055DCBA3006FE529 = {
+                       fileRef = E81EF5E0055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF665055DCBA4006FE529 = {
+                       fileRef = E81EF5E1055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF666055DCBA5006FE529 = {
+                       fileRef = E81EF5E2055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF667055DCBA5006FE529 = {
+                       fileRef = E81EF5E3055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF668055DCBA6006FE529 = {
+                       fileRef = E81EF5E4055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF669055DCBA8006FE529 = {
+                       fileRef = E81EF5E5055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF66A055DCBA9006FE529 = {
+                       fileRef = E81EF5E6055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF66B055DCBA9006FE529 = {
+                       fileRef = E81EF5E7055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF66C055DCBAB006FE529 = {
+                       fileRef = E81EF5E8055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF66D055DCBAB006FE529 = {
+                       fileRef = E81EF5E9055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF66E055DCBAC006FE529 = {
+                       fileRef = E81EF5EA055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF673055DCBB3006FE529 = {
+                       fileRef = E81EF5EF055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF674055DCBB4006FE529 = {
+                       fileRef = E81EF5F0055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF675055DCBB6006FE529 = {
+                       fileRef = E81EF5F1055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF676055DCBB7006FE529 = {
+                       fileRef = E81EF5F2055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF677055DCBB7006FE529 = {
+                       fileRef = E81EF5F3055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF678055DCBB9006FE529 = {
+                       fileRef = E81EF5F4055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF679055DCBBA006FE529 = {
+                       fileRef = E81EF5F5055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF67A055DCBBA006FE529 = {
+                       fileRef = E81EF5F6055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF67B055DCBBB006FE529 = {
+                       fileRef = E81EF5F7055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF67C055DCBBB006FE529 = {
+                       fileRef = E81EF5F8055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF67D055DCBBC006FE529 = {
+                       fileRef = E81EF5F9055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF67E055DCBBC006FE529 = {
+                       fileRef = E81EF5FA055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF67F055DCBBD006FE529 = {
+                       fileRef = E81EF5FB055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF680055DCBBD006FE529 = {
+                       fileRef = E81EF5FC055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF681055DCBC4006FE529 = {
+                       fileRef = E81EF5FD055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF682055DCBC5006FE529 = {
+                       fileRef = E81EF5FE055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF683055DCBC5006FE529 = {
+                       fileRef = E81EF5FF055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF684055DCBC6006FE529 = {
+                       fileRef = E81EF600055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF685055DCBC7006FE529 = {
+                       fileRef = E81EF601055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF686055DCBC7006FE529 = {
+                       fileRef = E81EF602055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF687055DCBC8006FE529 = {
+                       fileRef = E81EF603055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF688055DCBC8006FE529 = {
+                       fileRef = E81EF604055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF689055DCBCC006FE529 = {
+                       fileRef = E81EF605055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF68A055DCBD0006FE529 = {
+                       fileRef = E81EF606055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF68B055DCBD1006FE529 = {
+                       fileRef = E81EF607055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF68C055DCBD2006FE529 = {
+                       fileRef = E81EF608055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF68D055DCBD2006FE529 = {
+                       fileRef = E81EF609055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF68E055DCBD3006FE529 = {
+                       fileRef = E81EF60A055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF68F055DCBD3006FE529 = {
+                       fileRef = E81EF60B055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF690055DCBD4006FE529 = {
+                       fileRef = E81EF60C055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF691055DCBD7006FE529 = {
+                       fileRef = E81EF60D055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF692055DCBD7006FE529 = {
+                       fileRef = E81EF60E055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF693055DCBD9006FE529 = {
+                       fileRef = E81EF60F055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF697055DCBDE006FE529 = {
+                       fileRef = E81EF613055DCA42006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF6A3055DD414006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = NGExtensions/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6A4055DD414006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = NGExtensions/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6A5055DD414006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = NGExtensions/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6A6055DD414006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = NGExtensions/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6A7055DD414006FE529 = {
+                       children = (
+                               E8CA84950605CB6D006366AB,
+                               E81EF6A9055DD414006FE529,
+                               E81EF6AA055DD414006FE529,
+                               E81EF6AB055DD414006FE529,
+                               E81EF6AC055DD414006FE529,
+                               E81EF6AD055DD415006FE529,
+                               E81EF6AE055DD415006FE529,
+                               E81EF6AF055DD415006FE529,
+                               E81EF6B0055DD415006FE529,
+                               E81EF6B1055DD415006FE529,
+                               E81EF6B2055DD415006FE529,
+                               E81EF6B3055DD415006FE529,
+                               E81EF6B5055DD415006FE529,
+                               E8CA84890605CB64006366AB,
+                               E8CA848A0605CB64006366AB,
+                               E8CA848B0605CB64006366AB,
+                       );
+                       isa = PBXGroup;
+                       name = "EOControl Extensions";
+                       path = NGExtensions/EOExt.subproj;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6A8055DD414006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6A9055DD414006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = EOCacheDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6AA055DD414006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = EOCompoundDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6AB055DD414006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EODataSource+NGExtensions.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6AC055DD414006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = EOFilterDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6AD055DD415006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = EOGrouping.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6AE055DD415006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = EOGroupingSet.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6AF055DD415006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = EOKeyGrouping.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6B0055DD415006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = EOKeyMapDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6B1055DD415006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EOQualifier+CtxEval.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6B2055DD415006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = EOQualifierGrouping.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6B3055DD415006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = EOTrueQualifier.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6B4055DD415006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6B5055DD415006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSArray+EOGrouping.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6EA055DD416006FE529 = {
+                       children = (
+                               E81EF6EB055DD416006FE529,
+                               E81EF6EC055DD416006FE529,
+                               E81EF6ED055DD416006FE529,
+                               E81EF6EE055DD416006FE529,
+                               E81EF6EF055DD416006FE529,
+                               E81EF6F0055DD416006FE529,
+                               E81EF6F1055DD416006FE529,
+                               E81EF6F2055DD416006FE529,
+                               E81EF6F3055DD416006FE529,
+                               E81EF6F4055DD416006FE529,
+                               E81EF6F5055DD416006FE529,
+                               E81EF6F6055DD416006FE529,
+                               E81EF6F7055DD416006FE529,
+                               E81EF6F8055DD416006FE529,
+                               E81EF6F9055DD416006FE529,
+                               E81EF6FA055DD416006FE529,
+                               E81EF6FB055DD416006FE529,
+                               E81EF6FC055DD416006FE529,
+                               E81EF6FD055DD416006FE529,
+                               E8FDB0D2056C2988002DFB9D,
+                               E81EF702055DD416006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "Foundation Extensions";
+                       path = NGExtensions/FdExt.subproj;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6EB055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6EC055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6ED055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGPropertyListParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6EE055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSArray+enumerator.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6EF055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSAutoreleasePool+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6F0055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSCalendarDate+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6F1055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSData+gzip.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6F2055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSData+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6F3055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSDictionary+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6F4055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSEnumerator+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6F5055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSException+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6F6055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSFileManager+Extensions.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6F7055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSMethodSignature+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6F8055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSNull+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6F9055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSObject+Logs.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6FA055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSObject+Values.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6FB055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSProcessInfo+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6FC055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSRunLoop+FileObjects.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6FD055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSSet+enumerator.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6FE055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+Encoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF6FF055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+Ext.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF700055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+Formatting.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF701055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF702055DD416006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSURL+misc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF75F055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = FileObjectHolder.m;
+                       path = NGExtensions/FileObjectHolder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF760055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = NGExtensions/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF761055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = NGExtensions/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF762055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = libNGExtensions.def;
+                       path = NGExtensions/libNGExtensions.def;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF763055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGBase64Coding.m;
+                       path = NGExtensions/NGBase64Coding.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF764055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGBitSet.m;
+                       path = NGExtensions/NGBitSet.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF765055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGBundleManager.m;
+                       path = NGExtensions/NGBundleManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF767055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGCustomFileManager.m;
+                       path = NGExtensions/NGCustomFileManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF768055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGDirectoryEnumerator.m;
+                       path = NGExtensions/NGDirectoryEnumerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF769055DD418006FE529 = {
+                       children = (
+                               E81EF76A055DD418006FE529,
+                               E8CA84C40605CB89006366AB,
+                               E8CA84BB0605CB7E006366AB,
+                               E8CA84DC0605CBAD006366AB,
+                               E8CA84D20605CBA0006366AB,
+                               E81EF777055DD419006FE529,
+                               E81EF778055DD419006FE529,
+                               E81EF779055DD419006FE529,
+                               E81EF77A055DD419006FE529,
+                               E81EF77B055DD419006FE529,
+                               E81EF77C055DD419006FE529,
+                               E81EF77D055DD419006FE529,
+                               E81EF77F055DD419006FE529,
+                               E81EF780055DD419006FE529,
+                               E81EF781055DD419006FE529,
+                               E81EF782055DD419006FE529,
+                               E81EF783055DD419006FE529,
+                               E81EF784055DD419006FE529,
+                               E81EF785055DD419006FE529,
+                               E81EF786055DD419006FE529,
+                               E81EF787055DD419006FE529,
+                               E81EF788055DD419006FE529,
+                               E81EF789055DD419006FE529,
+                               E81EF78A055DD419006FE529,
+                               E81EF78B055DD419006FE529,
+                               E81EF78C055DD419006FE529,
+                               E81EF792055DD419006FE529,
+                               E81EF793055DD419006FE529,
+                               AD73C3FB06D10BDF00226A2D,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       path = NGExtensions/NGExtensions;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF76A055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = AutoDefines.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF76B055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "DOMNode+EOQualifier.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF76C055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = EOCacheDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF76D055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = EOCompoundDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF76E055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "EODataSource+NGExtensions.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF76F055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = EOFilterDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF770055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = EOGrouping.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF771055DD418006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = EOGroupingSet.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF772055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = EOKeyGrouping.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF773055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = EOKeyMapDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF774055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "EOQualifier+CtxEval.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF775055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = EOQualifierGrouping.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF776055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = EOTrueQualifier.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF777055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = FileObjectHolder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF778055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = IndexFunc.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF779055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGBase64Coding.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF77A055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGBaseTypes.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF77B055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGBitSet.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF77C055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGBundleManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF77D055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGCharBuffers.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF77F055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGCustomFileManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF780055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGDirectoryEnumerator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF781055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGExtensions.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF782055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGExtensionsDecls.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF783055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGFileFolderInfoDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF784055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGFileManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF785055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGFileManagerURL.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF786055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHashMap.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF787055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMemoryAllocation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF788055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGMerging.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF789055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGObjCRuntime.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF78A055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGObjectMacros.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF78B055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGPropertyListParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF78C055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGQuotedPrintableCoding.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF78D055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGRule.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF78E055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGRuleAssignment.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF78F055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGRuleContext.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF790055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGRuleEngine.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF791055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGRuleModel.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF792055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGStack.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF793055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGStringScanEnumerator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF794055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSArray+enumerator.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF795055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSAutoreleasePool+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF796055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSCalendarDate+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF797055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSData+gzip.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF798055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSData+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF799055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSDictionary+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF79A055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSEnumerator+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF79B055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSException+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF79C055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSFileManager+Extensions.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF79D055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSMethodSignature+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF79E055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSNull+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF79F055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSObject+Logs.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7A0055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSObject+Values.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7A1055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSProcessInfo+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7A2055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSRunLoop+FileObjects.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7A3055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSSet+enumerator.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7A4055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSString+Encoding.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7A5055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSString+Ext.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7A6055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSString+Formatting.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7A7055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSString+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7A8055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSURL+misc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7A9055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGExtensions.m;
+                       path = NGExtensions/NGExtensions.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7AA055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGFileFolderInfoDataSource.m;
+                       path = NGExtensions/NGFileFolderInfoDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7AB055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGFileManager.m;
+                       path = NGExtensions/NGFileManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7AC055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NGFileManager+JS.m";
+                       path = "NGExtensions/NGFileManager+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7AD055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGFileManagerURL.m;
+                       path = NGExtensions/NGFileManagerURL.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7AE055DD419006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGHashMap.m;
+                       path = NGExtensions/NGHashMap.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7AF055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMerging.m;
+                       path = NGExtensions/NGMerging.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7B0055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGObjCRuntime.m;
+                       path = NGExtensions/NGObjCRuntime.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7B1055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGQuotedPrintableCoding.m;
+                       path = NGExtensions/NGQuotedPrintableCoding.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7B2055DD41A006FE529 = {
+                       children = (
+                               E81EF7B3055DD41A006FE529,
+                               E81EF7C7055DD41A006FE529,
+                               E81EF7B4055DD41A006FE529,
+                               E81EF7B5055DD41A006FE529,
+                               E81EF7B6055DD41A006FE529,
+                               E81EF7B7055DD41A006FE529,
+                               E81EF7B8055DD41A006FE529,
+                               E81EF7B9055DD41A006FE529,
+                               E81EF7BA055DD41A006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = NGRuleEngine;
+                       path = NGExtensions/NGRuleEngine.subproj;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7B3055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7B4055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7B5055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGRule.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7B6055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGRuleAssignment.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7B7055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGRuleContext.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7B8055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGRuleModel.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7B9055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGRuleParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7BA055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGRuleParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7C7055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7D4055DD41A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGStack.m;
+                       path = NGExtensions/NGStack.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7D5055DD41B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGStringScanEnumerator.m;
+                       path = NGExtensions/NGStringScanEnumerator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7D6055DD41B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       name = "SxCore-NGExtensions.graffle";
+                       path = "NGExtensions/SxCore-NGExtensions.graffle";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7D7055DD41B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = TODO;
+                       path = NGExtensions/TODO;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7D8055DD41B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = NGExtensions/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7D9055DD41B006FE529 = {
+                       children = (
+                               E81EF7DA055DD41B006FE529,
+                               E81EF7DC055DD41B006FE529,
+                               E81EF7DB055DD41B006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "XML Extensions";
+                       path = NGExtensions/XmlExt.subproj;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7DA055DD41B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7DB055DD41B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "DOMNode+EOQualifier.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7DC055DD41B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF7E5055DD41B006FE529 = {
+                       fileRef = E81EF6A3055DD414006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7E6055DD41B006FE529 = {
+                       fileRef = E81EF6A4055DD414006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7E7055DD41B006FE529 = {
+                       fileRef = E81EF6A5055DD414006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7E8055DD41B006FE529 = {
+                       fileRef = E81EF6A6055DD414006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7E9055DD41B006FE529 = {
+                       fileRef = E81EF6A8055DD414006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7EA055DD41B006FE529 = {
+                       fileRef = E81EF6A9055DD414006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7EB055DD41B006FE529 = {
+                       fileRef = E81EF6AA055DD414006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7EC055DD41B006FE529 = {
+                       fileRef = E81EF6AB055DD414006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7ED055DD41B006FE529 = {
+                       fileRef = E81EF6AC055DD414006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7EE055DD41B006FE529 = {
+                       fileRef = E81EF6AD055DD415006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7EF055DD41B006FE529 = {
+                       fileRef = E81EF6AE055DD415006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7F0055DD41B006FE529 = {
+                       fileRef = E81EF6AF055DD415006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7F1055DD41B006FE529 = {
+                       fileRef = E81EF6B0055DD415006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7F2055DD41B006FE529 = {
+                       fileRef = E81EF6B1055DD415006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7F3055DD41B006FE529 = {
+                       fileRef = E81EF6B2055DD415006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7F4055DD41B006FE529 = {
+                       fileRef = E81EF6B3055DD415006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7F5055DD41B006FE529 = {
+                       fileRef = E81EF6B4055DD415006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF7F6055DD41B006FE529 = {
+                       fileRef = E81EF6B5055DD415006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF829055DD41C006FE529 = {
+                       fileRef = E81EF6EB055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF82A055DD41C006FE529 = {
+                       fileRef = E81EF6EC055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF82B055DD41C006FE529 = {
+                       fileRef = E81EF6ED055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF82C055DD41C006FE529 = {
+                       fileRef = E81EF6EE055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF82D055DD41C006FE529 = {
+                       fileRef = E81EF6EF055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF82E055DD41C006FE529 = {
+                       fileRef = E81EF6F0055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF82F055DD41C006FE529 = {
+                       fileRef = E81EF6F1055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF830055DD41C006FE529 = {
+                       fileRef = E81EF6F2055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF831055DD41C006FE529 = {
+                       fileRef = E81EF6F3055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF832055DD41C006FE529 = {
+                       fileRef = E81EF6F4055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF833055DD41C006FE529 = {
+                       fileRef = E81EF6F5055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF834055DD41C006FE529 = {
+                       fileRef = E81EF6F6055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF835055DD41C006FE529 = {
+                       fileRef = E81EF6F7055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF836055DD41C006FE529 = {
+                       fileRef = E81EF6F8055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF837055DD41C006FE529 = {
+                       fileRef = E81EF6F9055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF838055DD41C006FE529 = {
+                       fileRef = E81EF6FA055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF839055DD41C006FE529 = {
+                       fileRef = E81EF6FB055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF83A055DD41C006FE529 = {
+                       fileRef = E81EF6FC055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF83B055DD41C006FE529 = {
+                       fileRef = E81EF6FD055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF83C055DD41C006FE529 = {
+                       fileRef = E81EF6FE055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF83D055DD41C006FE529 = {
+                       fileRef = E81EF6FF055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF83E055DD41C006FE529 = {
+                       fileRef = E81EF700055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF83F055DD41C006FE529 = {
+                       fileRef = E81EF701055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF840055DD41C006FE529 = {
+                       fileRef = E81EF702055DD416006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF89B055DD41C006FE529 = {
+                       fileRef = E81EF75F055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF89C055DD41C006FE529 = {
+                       fileRef = E81EF760055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF89D055DD41C006FE529 = {
+                       fileRef = E81EF761055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF89E055DD41C006FE529 = {
+                       fileRef = E81EF762055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF89F055DD41C006FE529 = {
+                       fileRef = E81EF763055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8A0055DD41C006FE529 = {
+                       fileRef = E81EF764055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8A1055DD41C006FE529 = {
+                       fileRef = E81EF765055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8A3055DD41C006FE529 = {
+                       fileRef = E81EF767055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8A4055DD41C006FE529 = {
+                       fileRef = E81EF768055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8A5055DD41C006FE529 = {
+                       fileRef = E81EF76A055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8A6055DD41C006FE529 = {
+                       fileRef = E81EF76B055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8A7055DD41C006FE529 = {
+                       fileRef = E81EF76C055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8A8055DD41C006FE529 = {
+                       fileRef = E81EF76D055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8A9055DD41C006FE529 = {
+                       fileRef = E81EF76E055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8AA055DD41C006FE529 = {
+                       fileRef = E81EF76F055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8AB055DD41C006FE529 = {
+                       fileRef = E81EF770055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8AC055DD41C006FE529 = {
+                       fileRef = E81EF771055DD418006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8AD055DD41C006FE529 = {
+                       fileRef = E81EF772055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8AE055DD41C006FE529 = {
+                       fileRef = E81EF773055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8AF055DD41C006FE529 = {
+                       fileRef = E81EF774055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8B0055DD41C006FE529 = {
+                       fileRef = E81EF775055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8B1055DD41C006FE529 = {
+                       fileRef = E81EF776055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8B2055DD41C006FE529 = {
+                       fileRef = E81EF777055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8B3055DD41C006FE529 = {
+                       fileRef = E81EF778055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8B4055DD41C006FE529 = {
+                       fileRef = E81EF779055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8B5055DD41C006FE529 = {
+                       fileRef = E81EF77A055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8B6055DD41C006FE529 = {
+                       fileRef = E81EF77B055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8B7055DD41C006FE529 = {
+                       fileRef = E81EF77C055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8B8055DD41C006FE529 = {
+                       fileRef = E81EF77D055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8BA055DD41C006FE529 = {
+                       fileRef = E81EF77F055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8BB055DD41C006FE529 = {
+                       fileRef = E81EF780055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8BC055DD41C006FE529 = {
+                       fileRef = E81EF781055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8BD055DD41C006FE529 = {
+                       fileRef = E81EF782055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8BE055DD41C006FE529 = {
+                       fileRef = E81EF783055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8BF055DD41C006FE529 = {
+                       fileRef = E81EF784055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8C0055DD41C006FE529 = {
+                       fileRef = E81EF785055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8C1055DD41C006FE529 = {
+                       fileRef = E81EF786055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8C2055DD41C006FE529 = {
+                       fileRef = E81EF787055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8C3055DD41C006FE529 = {
+                       fileRef = E81EF788055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8C4055DD41C006FE529 = {
+                       fileRef = E81EF789055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8C5055DD41C006FE529 = {
+                       fileRef = E81EF78A055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8C6055DD41C006FE529 = {
+                       fileRef = E81EF78B055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8C7055DD41C006FE529 = {
+                       fileRef = E81EF78C055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8C8055DD41C006FE529 = {
+                       fileRef = E81EF78D055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8C9055DD41C006FE529 = {
+                       fileRef = E81EF78E055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8CA055DD41C006FE529 = {
+                       fileRef = E81EF78F055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8CB055DD41C006FE529 = {
+                       fileRef = E81EF790055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8CC055DD41C006FE529 = {
+                       fileRef = E81EF791055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8CD055DD41C006FE529 = {
+                       fileRef = E81EF792055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8CE055DD41C006FE529 = {
+                       fileRef = E81EF793055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8CF055DD41C006FE529 = {
+                       fileRef = E81EF794055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8D0055DD41C006FE529 = {
+                       fileRef = E81EF795055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8D1055DD41C006FE529 = {
+                       fileRef = E81EF796055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8D2055DD41C006FE529 = {
+                       fileRef = E81EF797055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8D3055DD41C006FE529 = {
+                       fileRef = E81EF798055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8D4055DD41C006FE529 = {
+                       fileRef = E81EF799055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8D5055DD41C006FE529 = {
+                       fileRef = E81EF79A055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8D6055DD41C006FE529 = {
+                       fileRef = E81EF79B055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8D7055DD41C006FE529 = {
+                       fileRef = E81EF79C055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8D8055DD41C006FE529 = {
+                       fileRef = E81EF79D055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8D9055DD41C006FE529 = {
+                       fileRef = E81EF79E055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8DA055DD41C006FE529 = {
+                       fileRef = E81EF79F055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8DB055DD41C006FE529 = {
+                       fileRef = E81EF7A0055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8DC055DD41C006FE529 = {
+                       fileRef = E81EF7A1055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8DD055DD41C006FE529 = {
+                       fileRef = E81EF7A2055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8DE055DD41C006FE529 = {
+                       fileRef = E81EF7A3055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8DF055DD41C006FE529 = {
+                       fileRef = E81EF7A4055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8E0055DD41C006FE529 = {
+                       fileRef = E81EF7A5055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8E1055DD41C006FE529 = {
+                       fileRef = E81EF7A6055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8E2055DD41C006FE529 = {
+                       fileRef = E81EF7A7055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8E3055DD41C006FE529 = {
+                       fileRef = E81EF7A8055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8E4055DD41C006FE529 = {
+                       fileRef = E81EF7A9055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8E5055DD41C006FE529 = {
+                       fileRef = E81EF7AA055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8E6055DD41C006FE529 = {
+                       fileRef = E81EF7AB055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8E7055DD41C006FE529 = {
+                       fileRef = E81EF7AC055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8E8055DD41C006FE529 = {
+                       fileRef = E81EF7AD055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8E9055DD41C006FE529 = {
+                       fileRef = E81EF7AE055DD419006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8EA055DD41C006FE529 = {
+                       fileRef = E81EF7AF055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8EB055DD41C006FE529 = {
+                       fileRef = E81EF7B0055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8EC055DD41C006FE529 = {
+                       fileRef = E81EF7B1055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8ED055DD41C006FE529 = {
+                       fileRef = E81EF7B3055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8EE055DD41C006FE529 = {
+                       fileRef = E81EF7B4055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8EF055DD41C006FE529 = {
+                       fileRef = E81EF7B5055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8F0055DD41C006FE529 = {
+                       fileRef = E81EF7B6055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8F1055DD41C006FE529 = {
+                       fileRef = E81EF7B7055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8F2055DD41C006FE529 = {
+                       fileRef = E81EF7B8055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF8F3055DD41C006FE529 = {
+                       fileRef = E81EF7B9055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF8F4055DD41C006FE529 = {
+                       fileRef = E81EF7BA055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF900055DD41C006FE529 = {
+                       fileRef = E81EF7C7055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF90C055DD41C006FE529 = {
+                       fileRef = E81EF7D4055DD41A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF90E055DD41C006FE529 = {
+                       fileRef = E81EF7D6055DD41B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF90F055DD41C006FE529 = {
+                       fileRef = E81EF7D7055DD41B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF910055DD41C006FE529 = {
+                       fileRef = E81EF7D8055DD41B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF911055DD41C006FE529 = {
+                       fileRef = E81EF7DA055DD41B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF912055DD41C006FE529 = {
+                       fileRef = E81EF7DB055DD41B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF913055DD41C006FE529 = {
+                       fileRef = E81EF7DC055DD41B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF922055DD49C006FE529 = {
+                       children = (
+                               E81EF6A4055DD414006FE529,
+                               E81EF75F055DD418006FE529,
+                               E81EF763055DD418006FE529,
+                               E81EF764055DD418006FE529,
+                               E81EF765055DD418006FE529,
+                               E81EF767055DD418006FE529,
+                               E81EF768055DD418006FE529,
+                               E81EF7A9055DD419006FE529,
+                               E81EF7AA055DD419006FE529,
+                               E81EF7AB055DD419006FE529,
+                               E81EF7AC055DD419006FE529,
+                               E81EF7AD055DD419006FE529,
+                               E81EF7AE055DD419006FE529,
+                               E81EF7AF055DD41A006FE529,
+                               E81EF7B0055DD41A006FE529,
+                               E81EF7B1055DD41A006FE529,
+                               E81EF7D4055DD41A006FE529,
+                               E81EF7D5055DD41B006FE529,
+                               AD73C3F906D10BAD00226A2D,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF925055DD4A7006FE529 = {
+                       children = (
+                               E81EF760055DD418006FE529,
+                               E81EF761055DD418006FE529,
+                               E81EF762055DD418006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF92E055DD4DF006FE529 = {
+                       children = (
+                               E81EF7D6055DD41B006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Documentation;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB2F055DD862006FE529 = {
+                       children = (
+                               E81EF61A055DCA6C006FE529,
+                               E81EF61D055DCA6C006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E820934105B0D30B0088B931 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = imCommon.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E820934205B0D30B0088B931 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = imTimeMacros.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E820934305B0D30B0088B931 = {
+                       fileRef = E820934105B0D30B0088B931;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E820934405B0D30B0088B931 = {
+                       fileRef = E820934205B0D30B0088B931;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E820934505B0D47D0088B931 = {
+                       children = (
+                               E8F255F905769D0B0049F554,
+                               E8F255FA05769D0B0049F554,
+                               E8F255FB05769D0B0049F554,
+                               E8F255ED05769D0B0049F554,
+                               E8F255EE05769D0B0049F554,
+                               E8F255EF05769D0B0049F554,
+                               E8F255F005769D0B0049F554,
+                               E8F255F105769D0B0049F554,
+                               E8F255F205769D0B0049F554,
+                               E8F255F305769D0B0049F554,
+                               E8F255F405769D0B0049F554,
+                               E8F255F505769D0B0049F554,
+                       );
+                       isa = PBXGroup;
+                       name = "MIME / IMAP4";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E820934605B0D4B00088B931 = {
+                       children = (
+                               E8F255DD05769D0B0049F554,
+                               E8F255E105769D0B0049F554,
+                               E8F255E205769D0B0049F554,
+                               E8F255E305769D0B0049F554,
+                               E8F255E405769D0B0049F554,
+                               E8F255E505769D0B0049F554,
+                               E8F255E605769D0B0049F554,
+                               E8F255E705769D0B0049F554,
+                               E8F255EA05769D0B0049F554,
+                               E8F255FC05769D0B0049F554,
+                               E8F2560005769D0B0049F554,
+                               E8F2560105769D0B0049F554,
+                               E8F2560205769D0B0049F554,
+                               E8F255FF05769D0B0049F554,
+                       );
+                       isa = PBXGroup;
+                       name = "Core Stuff";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E820934705B0D4BD0088B931 = {
+                       children = (
+                               E8F255F605769D0B0049F554,
+                               E8F255F705769D0B0049F554,
+                               E8F255F805769D0B0049F554,
+                               E8F255FD05769D0B0049F554,
+                       );
+                       isa = PBXGroup;
+                       name = LDAP;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E82093AA05B0D5CA0088B931 = {
+                       fileRef = E81EF633055DCB38006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E82093AB05B0D5DD0088B931 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8F2562F05769D7F0049F554;
+                       remoteInfo = bmlookup;
+               };
+               E82093AC05B0D5DD0088B931 = {
+                       isa = PBXTargetDependency;
+                       target = E8F2562F05769D7F0049F554;
+                       targetProxy = E82093AB05B0D5DD0088B931;
+               };
+               E82093AD05B0D5F60088B931 = {
+                       fileRef = E81EF633055DCB38006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E82093AE05B0D5F90088B931 = {
+                       fileRef = E81EF643055DCB4D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E82093AF05B0D6040088B931 = {
+                       fileRef = E81EF63B055DCB43006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E82093B005B0D6150088B931 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8F2562505769D720049F554;
+                       remoteInfo = mime2xml;
+               };
+               E82093B105B0D6150088B931 = {
+                       isa = PBXTargetDependency;
+                       target = E8F2562505769D720049F554;
+                       targetProxy = E82093B005B0D6150088B931;
+               };
+               E82093B205B0D63F0088B931 = {
+                       fileRef = E81E06A5055E6E35006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E82093D105B0D66E0088B931 = {
+                       fileRef = E81E06A5055E6E35006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E82093D205B0D6800088B931 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8F2561305769D5C0049F554;
+                       remoteInfo = ldapls;
+               };
+               E82093D305B0D6800088B931 = {
+                       isa = PBXTargetDependency;
+                       target = E8F2561305769D5C0049F554;
+                       targetProxy = E82093D205B0D6800088B931;
+               };
+               E82093D405B0D6800088B931 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8F2561B05769D660049F554;
+                       remoteInfo = ldap2dsml;
+               };
+               E82093D505B0D6800088B931 = {
+                       isa = PBXTargetDependency;
+                       target = E8F2561B05769D660049F554;
+                       targetProxy = E82093D405B0D6800088B931;
+               };
+               E82093D605B0D70B0088B931 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.c;
+                       path = dummy.c;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E82093D705B0D70B0088B931 = {
+                       fileRef = E82093D605B0D70B0088B931;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E82093D805B0D70B0088B931 = {
+                       fileRef = E82093D605B0D70B0088B931;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E824CFE705BD7C9C0081A110 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4FolderGlobalID.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E824CFE805BD7C9C0081A110 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4FolderGlobalID.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E824CFE905BD7C9C0081A110 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4MessageGlobalID.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E824CFEA05BD7C9C0081A110 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4MessageGlobalID.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E824CFEB05BD7C9C0081A110 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4ServerGlobalID.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E824CFEC05BD7C9C0081A110 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4ServerGlobalID.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E824CFED05BD7C9C0081A110 = {
+                       fileRef = E824CFE705BD7C9C0081A110;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E824CFEE05BD7C9C0081A110 = {
+                       fileRef = E824CFE805BD7C9C0081A110;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E824CFEF05BD7C9C0081A110 = {
+                       fileRef = E824CFE905BD7C9C0081A110;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E824CFF005BD7C9C0081A110 = {
+                       fileRef = E824CFEA05BD7C9C0081A110;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E824CFF105BD7C9C0081A110 = {
+                       fileRef = E824CFEB05BD7C9C0081A110;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E824CFF205BD7C9C0081A110 = {
+                       fileRef = E824CFEC05BD7C9C0081A110;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E824CFF305BD7CA00081A110 = {
+                       children = (
+                               E824CFE705BD7C9C0081A110,
+                               E824CFE805BD7C9C0081A110,
+                               E824CFE905BD7C9C0081A110,
+                               E824CFEA05BD7C9C0081A110,
+                               E824CFEB05BD7C9C0081A110,
+                               E824CFEC05BD7C9C0081A110,
+                       );
+                       isa = PBXGroup;
+                       name = GlobalIDs;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E83DAE24064D381800D50E72 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E83DAE25064D381800D50E72 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E83DAE30064D382900D50E72,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E83DAE26064D381800D50E72 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E83DAE3B064D383600D50E72,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E83DAE27064D381800D50E72 = {
+                       buildPhases = (
+                               E83DAE24064D381800D50E72,
+                               E83DAE25064D381800D50E72,
+                               E83DAE26064D381800D50E72,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-framework Foundation";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = subclassing;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                               E83DAE7C064D39FC00D50E72,
+                       );
+                       isa = PBXNativeTarget;
+                       name = subclassing;
+                       productName = subclassing;
+                       productReference = E83DAE28064D381800D50E72;
+                       productType = "com.apple.product-type.tool";
+               };
+               E83DAE28064D381800D50E72 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = subclassing;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E83DAE30064D382900D50E72 = {
+                       fileRef = E8F255FF05769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E83DAE3B064D383600D50E72 = {
+                       fileRef = E81EF633055DCB38006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E83DAE7B064D39FC00D50E72 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF632055DCB38006FE529;
+                       remoteInfo = NGExtensions;
+               };
+               E83DAE7C064D39FC00D50E72 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF632055DCB38006FE529;
+                       targetProxy = E83DAE7B064D39FC00D50E72;
+               };
+               E83DB65F064DA26000D50E72 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E83DAE27064D381800D50E72;
+                       remoteInfo = subclassing;
+               };
+               E83DB660064DA26000D50E72 = {
+                       isa = PBXTargetDependency;
+                       target = E83DAE27064D381800D50E72;
+                       targetProxy = E83DB65F064DA26000D50E72;
+               };
+               E840BA8805B0D82700F799A1 = {
+                       fileRef = E81EF633055DCB38006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E840BA8905B0D82A00F799A1 = {
+                       fileRef = E81EF63B055DCB43006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E840BA8A05B0D83E00F799A1 = {
+                       fileRef = E8F255F405769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E840BA8B05B0D83F00F799A1 = {
+                       fileRef = E8F255F505769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E840BA8E05B0D86000F799A1 = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8F2560B05769D500049F554;
+                       remoteInfo = imapls;
+               };
+               E840BA8F05B0D86000F799A1 = {
+                       isa = PBXTargetDependency;
+                       target = E8F2560B05769D500049F554;
+                       targetProxy = E840BA8E05B0D86000F799A1;
+               };
+               E84E826205C14F81005792AF = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4FolderFlags.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84E826305C14F81005792AF = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4FolderFlags.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84E826405C14F81005792AF = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4FolderMailRegistry.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84E826505C14F81005792AF = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4FolderMailRegistry.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84E826605C14F81005792AF = {
+                       fileRef = E84E826205C14F81005792AF;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84E826705C14F81005792AF = {
+                       fileRef = E84E826305C14F81005792AF;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84E826805C14F81005792AF = {
+                       fileRef = E84E826405C14F81005792AF;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84E826905C14F81005792AF = {
+                       fileRef = E84E826505C14F81005792AF;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E860D21B05FC97020074B7B0 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOQualifierVariable.m;
+                       path = EOControl/EOQualifierVariable.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E860D21C05FC97020074B7B0 = {
+                       fileRef = E860D21B05FC97020074B7B0;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E860D22A05FC97260074B7B0 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSObject+QualDesc.m";
+                       path = "EOControl/NSObject+QualDesc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E860D22B05FC97260074B7B0 = {
+                       fileRef = E860D22A05FC97260074B7B0;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E883CA75064686D600EAF53E = {
+                       fileRef = E81EF633055DCB38006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E883CA77064686E300EAF53E = {
+                       fileRef = E81EF633055DCB38006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897B35A05B84D5B00B708BC = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeContentDispositionHeaderFieldParser.m;
+                       path = NGMime/NGMimeContentDispositionHeaderFieldParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897B35B05B84D5B00B708BC = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeContentLengthHeaderFieldParser.m;
+                       path = NGMime/NGMimeContentLengthHeaderFieldParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897B35C05B84D5B00B708BC = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeContentTypeHeaderFieldParser.m;
+                       path = NGMime/NGMimeContentTypeHeaderFieldParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897B35D05B84D5B00B708BC = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeRFC822DateHeaderFieldParser.m;
+                       path = NGMime/NGMimeRFC822DateHeaderFieldParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897B35E05B84D5B00B708BC = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeStringHeaderFieldParser.m;
+                       path = NGMime/NGMimeStringHeaderFieldParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897B35F05B84D5B00B708BC = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSCalendarDate+RFC822.m";
+                       path = "NGMime/NSCalendarDate+RFC822.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897B36605B84D6000B708BC = {
+                       children = (
+                               E897B38C05B8523E00B708BC,
+                               E897B35A05B84D5B00B708BC,
+                               E897B35B05B84D5B00B708BC,
+                               E897B35C05B84D5B00B708BC,
+                               E897B35D05B84D5B00B708BC,
+                               E897B35E05B84D5B00B708BC,
+                               E897B35F05B84D5B00B708BC,
+                       );
+                       isa = PBXGroup;
+                       name = "Headerfield Parsers";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897B36705B84D7800B708BC = {
+                       children = (
+                               E81BE2F8055EDAD400B28141,
+                               E81BE306055EDAD400B28141,
+                               E81BE311055EDAD500B28141,
+                               E80D72C805D6BAB10050931F,
+                               E80D72C905D6BAB10050931F,
+                               E80D72CA05D6BAB10050931F,
+                               E80D72CB05D6BAB10050931F,
+                               E80D72CC05D6BAB10050931F,
+                               E80D72CD05D6BAB10050931F,
+                               E80D72CE05D6BAB10050931F,
+                       );
+                       isa = PBXGroup;
+                       name = Generators;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897B36805B84DAA00B708BC = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EOQualifier+IMAPAdditions.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897B38305B8519900B708BC = {
+                       fileRef = E897B35A05B84D5B00B708BC;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897B38405B8519A00B708BC = {
+                       fileRef = E897B35C05B84D5B00B708BC;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897B38505B8519B00B708BC = {
+                       fileRef = E897B35B05B84D5B00B708BC;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897B38605B8519D00B708BC = {
+                       fileRef = E897B35D05B84D5B00B708BC;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897B38705B8519E00B708BC = {
+                       fileRef = E897B35E05B84D5B00B708BC;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897B38805B8519F00B708BC = {
+                       fileRef = E897B35F05B84D5B00B708BC;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897B38C05B8523E00B708BC = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGMimeHeaderFieldParserSet.m;
+                       path = NGMime/NGMimeHeaderFieldParserSet.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897B38D05B8523E00B708BC = {
+                       fileRef = E897B38C05B8523E00B708BC;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8ACC6BE05CED366005ADB68 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGImap4ResponseNormalizer.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8ACC6BF05CED366005ADB68 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGImap4ResponseNormalizer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8ACC6C005CED366005ADB68 = {
+                       fileRef = E8ACC6BE05CED366005ADB68;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8ACC6C105CED366005ADB68 = {
+                       fileRef = E8ACC6BF05CED366005ADB68;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8BA2115055F032600AD687B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8BA2129055F037100AD687B,
+                               E8BA212A055F037200AD687B,
+                               E8BA212B055F037300AD687B,
+                               E8BA212C055F037300AD687B,
+                               E8BA212D055F037400AD687B,
+                               E8BA212E055F037500AD687B,
+                               E8BA212F055F037500AD687B,
+                               E8BA2130055F037600AD687B,
+                               E8BA2131055F037700AD687B,
+                               E8BA2132055F037800AD687B,
+                               E8BA2133055F037800AD687B,
+                               E8BA2134055F037900AD687B,
+                               E8BA2135055F037A00AD687B,
+                               E8BA2136055F037B00AD687B,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8BA2116055F032600AD687B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8BA2117055F032600AD687B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E82093D705B0D70B0088B931,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8BA2118055F032600AD687B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD16272005D934F700A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8BA2119055F032600AD687B = {
+                       buildPhases = (
+                               E8BA2115055F032600AD687B,
+                               E8BA2116055F032600AD687B,
+                               E8BA2117055F032600AD687B,
+                               E8BA2118055F032600AD687B,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               GCC_PREFIX_HEADER = "";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGMime/NGImap4/NGImap4-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC1600000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGImap4;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGImap4;
+                       productName = NGImap4;
+                       productReference = E8BA211A055F032600AD687B;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGImap4</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGImap4</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E8BA211A055F032600AD687B = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGImap4.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8BA211D055F033F00AD687B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8BA2137055F038500AD687B,
+                               E8BA2138055F038600AD687B,
+                               E8BA2139055F038700AD687B,
+                               E8BA213A055F038700AD687B,
+                               E8BA213B055F038800AD687B,
+                               E8BA213C055F038900AD687B,
+                               E8BA213D055F038A00AD687B,
+                               E8BA213E055F038B00AD687B,
+                               E8BA213F055F038B00AD687B,
+                               E8BA2140055F038C00AD687B,
+                               E8BA2141055F038D00AD687B,
+                               E8BA2142055F038E00AD687B,
+                               E8BA2143055F038F00AD687B,
+                               E8BA2144055F038F00AD687B,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8BA211E055F033F00AD687B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8BA211F055F033F00AD687B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E82093D805B0D70B0088B931,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8BA2120055F033F00AD687B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD16272105D934F700A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8BA2121055F033F00AD687B = {
+                       buildPhases = (
+                               E8BA211D055F033F00AD687B,
+                               E8BA211E055F033F00AD687B,
+                               E8BA211F055F033F00AD687B,
+                               E8BA2120055F033F00AD687B,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               GCC_PREFIX_HEADER = "";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGMime/NGMail/NGMail-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC1800000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGMail;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGMail;
+                       productName = NGMail;
+                       productReference = E8BA2122055F033F00AD687B;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGMail</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGMail</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E8BA2122055F033F00AD687B = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGMail.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8BA2125055F035700AD687B = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8BA2119055F032600AD687B;
+                       remoteInfo = NGImap4;
+               };
+               E8BA2126055F035700AD687B = {
+                       isa = PBXTargetDependency;
+                       target = E8BA2119055F032600AD687B;
+                       targetProxy = E8BA2125055F035700AD687B;
+               };
+               E8BA2127055F035700AD687B = {
+                       containerPortal = E81EF5C7055DC9BE006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8BA2121055F033F00AD687B;
+                       remoteInfo = NGMail;
+               };
+               E8BA2128055F035700AD687B = {
+                       isa = PBXTargetDependency;
+                       target = E8BA2121055F033F00AD687B;
+                       targetProxy = E8BA2127055F035700AD687B;
+               };
+               E8BA2129055F037100AD687B = {
+                       fileRef = E81BE249055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA212A055F037200AD687B = {
+                       fileRef = E81BE24B055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA212B055F037300AD687B = {
+                       fileRef = E81BE24D055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA212C055F037300AD687B = {
+                       fileRef = E81BE24F055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA212D055F037400AD687B = {
+                       fileRef = E81BE251055EDACF00B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA212E055F037500AD687B = {
+                       fileRef = E81BE253055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA212F055F037500AD687B = {
+                       fileRef = E81BE255055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2130055F037600AD687B = {
+                       fileRef = E81BE257055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2131055F037700AD687B = {
+                       fileRef = E81BE258055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2132055F037800AD687B = {
+                       fileRef = E81BE25A055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2133055F037800AD687B = {
+                       fileRef = E81BE25C055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2134055F037900AD687B = {
+                       fileRef = E81BE25E055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2135055F037A00AD687B = {
+                       fileRef = E81BE260055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2136055F037B00AD687B = {
+                       fileRef = E81BE262055EDAD000B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2137055F038500AD687B = {
+                       fileRef = E81BE2A5055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2138055F038600AD687B = {
+                       fileRef = E81BE2A7055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2139055F038700AD687B = {
+                       fileRef = E81BE2A9055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA213A055F038700AD687B = {
+                       fileRef = E81BE2AB055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA213B055F038800AD687B = {
+                       fileRef = E81BE2AD055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA213C055F038900AD687B = {
+                       fileRef = E81BE2AE055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA213D055F038A00AD687B = {
+                       fileRef = E81BE2B0055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA213E055F038B00AD687B = {
+                       fileRef = E81BE2B2055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA213F055F038B00AD687B = {
+                       fileRef = E81BE2B4055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2140055F038C00AD687B = {
+                       fileRef = E81BE2B6055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2141055F038D00AD687B = {
+                       fileRef = E81BE2B8055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2142055F038E00AD687B = {
+                       fileRef = E81BE2BA055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2143055F038F00AD687B = {
+                       fileRef = E81BE2BC055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA2144055F038F00AD687B = {
+                       fileRef = E81BE2BD055EDAD200B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8BA21C1055F0CD600AD687B = {
+                       children = (
+                               E81BE478055EDB5700B28141,
+                               E81BE460055EDB5600B28141,
+                               E81BE479055EDB5700B28141,
+                       );
+                       isa = PBXGroup;
+                       name = unused;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA84890605CB64006366AB = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EOFetchSpecification+plist.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA848A0605CB64006366AB = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EOQualifier+plist.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA848B0605CB64006366AB = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EOSortOrdering+plist.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA84950605CB6D006366AB = {
+                       children = (
+                               E81EF6A8055DD414006FE529,
+                               E81EF6B4055DD415006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA84BB0605CB7E006366AB = {
+                       children = (
+                               E8CA84E30605CBD5006366AB,
+                               E8CA84E40605CBD5006366AB,
+                               E8CA84E50605CBD5006366AB,
+                               E81EF76C055DD418006FE529,
+                               E81EF76D055DD418006FE529,
+                               E81EF76E055DD418006FE529,
+                               E81EF76F055DD418006FE529,
+                               E81EF770055DD418006FE529,
+                               E81EF771055DD418006FE529,
+                               E81EF772055DD419006FE529,
+                               E81EF773055DD419006FE529,
+                               E81EF774055DD419006FE529,
+                               E81EF775055DD419006FE529,
+                               E81EF776055DD419006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "EOControl Extensions";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA84C40605CB89006366AB = {
+                       children = (
+                               E81EF76B055DD418006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "XML Extensions";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA84D20605CBA0006366AB = {
+                       children = (
+                               E81EF794055DD419006FE529,
+                               E81EF795055DD419006FE529,
+                               E81EF796055DD419006FE529,
+                               E81EF797055DD419006FE529,
+                               E81EF798055DD419006FE529,
+                               E81EF799055DD419006FE529,
+                               E81EF79A055DD419006FE529,
+                               E81EF79B055DD419006FE529,
+                               E81EF79C055DD419006FE529,
+                               E81EF79D055DD419006FE529,
+                               E81EF79E055DD419006FE529,
+                               E81EF79F055DD419006FE529,
+                               E81EF7A0055DD419006FE529,
+                               E81EF7A1055DD419006FE529,
+                               E81EF7A2055DD419006FE529,
+                               E81EF7A3055DD419006FE529,
+                               E81EF7A4055DD419006FE529,
+                               E81EF7A5055DD419006FE529,
+                               E81EF7A6055DD419006FE529,
+                               AD1803280611DEFE00ED723F,
+                               E81EF7A7055DD419006FE529,
+                               E81EF7A8055DD419006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "Foundation Extensions";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA84DC0605CBAD006366AB = {
+                       children = (
+                               E81EF78D055DD419006FE529,
+                               E81EF78E055DD419006FE529,
+                               E81EF78F055DD419006FE529,
+                               E81EF790055DD419006FE529,
+                               E81EF791055DD419006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "Rule Engine";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA84E30605CBD5006366AB = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "EOFetchSpecification+plist.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA84E40605CBD5006366AB = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "EOQualifier+plist.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA84E50605CBD5006366AB = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "EOSortOrdering+plist.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8CA85000605CC0F006366AB = {
+                       fileRef = E8CA84E30605CBD5006366AB;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8CA85050605CC10006366AB = {
+                       fileRef = E8CA84E40605CBD5006366AB;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8CA85070605CC11006366AB = {
+                       fileRef = E8CA84E50605CBD5006366AB;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8CA85170605CC1F006366AB = {
+                       fileRef = E8CA84890605CB64006366AB;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8CA851A0605CC21006366AB = {
+                       fileRef = E8CA848A0605CB64006366AB;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8CA851C0605CC22006366AB = {
+                       fileRef = E8CA848B0605CB64006366AB;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F255DA05769CE60049F554 = {
+                       children = (
+                               E8F255DE05769D0B0049F554,
+                               E8F255FE05769D0B0049F554,
+                               E8F255E005769D0B0049F554,
+                               E8F255DF05769D0B0049F554,
+                               E8F2560505769D2F0049F554,
+                               E820934605B0D4B00088B931,
+                               E820934505B0D47D0088B931,
+                               E820934705B0D4BD0088B931,
+                               E8F255EB05769D0B0049F554,
+                               E8F255EC05769D0B0049F554,
+                       );
+                       isa = PBXGroup;
+                       name = Samples;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255DD05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = bmlookup.m;
+                       path = samples/bmlookup.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255DE05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = samples/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255DF05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = samples/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255E005769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = samples/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255E105769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = encoding.m;
+                       path = samples/encoding.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255E205769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EncodingTool.h;
+                       path = samples/EncodingTool.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255E305769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EncodingTool.m;
+                       path = samples/EncodingTool.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255E405769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = eoqual.m;
+                       path = samples/eoqual.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255E505769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EOQualTool.h;
+                       path = samples/EOQualTool.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255E605769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = EOQualTool.m;
+                       path = samples/EOQualTool.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255E705769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = fmdls.m;
+                       path = samples/fmdls.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255E805769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = samples/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255E905769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = samples/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255EA05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = httpu_notify.m;
+                       path = samples/httpu_notify.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255EB05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ical2.m;
+                       path = samples/ical2.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255EC05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ical3.m;
+                       path = samples/ical3.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255ED05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = imap_tool.m;
+                       path = samples/imap_tool.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255EE05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ImapListTool.h;
+                       path = samples/ImapListTool.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255EF05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ImapListTool.m;
+                       path = samples/ImapListTool.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255F005769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = imapls.m;
+                       path = samples/imapls.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255F105769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = imapquota.m;
+                       path = samples/imapquota.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255F205769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ImapQuotaTool.h;
+                       path = samples/ImapQuotaTool.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255F305769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ImapQuotaTool.m;
+                       path = samples/ImapQuotaTool.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255F405769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ImapTool.h;
+                       path = samples/ImapTool.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255F505769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ImapTool.m;
+                       path = samples/ImapTool.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255F605769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ldap2dsml.m;
+                       path = samples/ldap2dsml.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255F705769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ldapchkpwd.m;
+                       path = samples/ldapchkpwd.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255F805769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ldapls.m;
+                       path = samples/ldapls.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255F905769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = mime2xml.m;
+                       path = samples/mime2xml.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255FA05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = Mime2XmlTool.h;
+                       path = samples/Mime2XmlTool.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255FB05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = Mime2XmlTool.m;
+                       path = samples/Mime2XmlTool.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255FC05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = parserule.m;
+                       path = samples/parserule.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255FD05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "pwd-check.m";
+                       path = "samples/pwd-check.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255FE05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = samples/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F255FF05769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = subclassing.m;
+                       path = samples/subclassing.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F2560005769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = test_qpdecode.m;
+                       path = samples/test_qpdecode.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F2560105769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = testdirenum.m;
+                       path = samples/testdirenum.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F2560205769D0B0049F554 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = testsock.m;
+                       path = samples/testsock.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F2560505769D2F0049F554 = {
+                       children = (
+                               E8F255E805769D0B0049F554,
+                               E8F255E905769D0B0049F554,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8F2560805769D500049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8F2563405769D930049F554,
+                               E840BA8A05B0D83E00F799A1,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2560905769D500049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8F2563205769D910049F554,
+                               E8F2563305769D920049F554,
+                               E840BA8B05B0D83F00F799A1,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2560A05769D500049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8F2563B05769DC10049F554,
+                               E8F2563C05769DC30049F554,
+                               E840BA8805B0D82700F799A1,
+                               E840BA8905B0D82A00F799A1,
+                               AD16272A05D934F700A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2560B05769D500049F554 = {
+                       buildPhases = (
+                               E8F2560805769D500049F554,
+                               E8F2560905769D500049F554,
+                               E8F2560A05769D500049F554,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = imapls;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = imapls;
+                       productName = imapls;
+                       productReference = E8F2560C05769D500049F554;
+                       productType = "com.apple.product-type.tool";
+               };
+               E8F2560C05769D500049F554 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = imapls;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8F2561005769D5C0049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2561105769D5C0049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8F2563505769D9F0049F554,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2561205769D5C0049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E82093B205B0D63F0088B931,
+                               AD16272805D934F700A7368D,
+                               E883CA75064686D600EAF53E,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2561305769D5C0049F554 = {
+                       buildPhases = (
+                               E8F2561005769D5C0049F554,
+                               E8F2561105769D5C0049F554,
+                               E8F2561205769D5C0049F554,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = ldapls;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = ldapls;
+                       productName = ldapls;
+                       productReference = E8F2561405769D5C0049F554;
+                       productType = "com.apple.product-type.tool";
+               };
+               E8F2561405769D5C0049F554 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = ldapls;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8F2561805769D660049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2561905769D660049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8F2563605769DA50049F554,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2561A05769D660049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD16272905D934F700A7368D,
+                               AD70A4EA06A8B20100D4CE98,
+                               E82093D105B0D66E0088B931,
+                               E883CA77064686E300EAF53E,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2561B05769D660049F554 = {
+                       buildPhases = (
+                               E8F2561805769D660049F554,
+                               E8F2561905769D660049F554,
+                               E8F2561A05769D660049F554,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = ldap2dsml;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = ldap2dsml;
+                       productName = ldap2dsml;
+                       productReference = E8F2561C05769D660049F554;
+                       productType = "com.apple.product-type.tool";
+               };
+               E8F2561C05769D660049F554 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = ldap2dsml;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8F2562205769D720049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8F2563805769DAB0049F554,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2562305769D720049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8F2563705769DAA0049F554,
+                               E8F2563905769DAC0049F554,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2562405769D720049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E82093AD05B0D5F60088B931,
+                               E82093AE05B0D5F90088B931,
+                               E82093AF05B0D6040088B931,
+                               AD16272705D934F700A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2562505769D720049F554 = {
+                       buildPhases = (
+                               E8F2562205769D720049F554,
+                               E8F2562305769D720049F554,
+                               E8F2562405769D720049F554,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = mime2xml;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = mime2xml;
+                       productName = mime2xml;
+                       productReference = E8F2562605769D720049F554;
+                       productType = "com.apple.product-type.tool";
+               };
+               E8F2562605769D720049F554 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = mime2xml;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8F2562C05769D7F0049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2562D05769D7F0049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8F2563A05769DB20049F554,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2562E05769D7F0049F554 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E82093AA05B0D5CA0088B931,
+                               AD16272605D934F700A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8F2562F05769D7F0049F554 = {
+                       buildPhases = (
+                               E8F2562C05769D7F0049F554,
+                               E8F2562D05769D7F0049F554,
+                               E8F2562E05769D7F0049F554,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = bmlookup;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = bmlookup;
+                       productName = bmlookup;
+                       productReference = E8F2563005769D7F0049F554;
+                       productType = "com.apple.product-type.tool";
+               };
+               E8F2563005769D7F0049F554 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = bmlookup;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8F2563205769D910049F554 = {
+                       fileRef = E8F255F005769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F2563305769D920049F554 = {
+                       fileRef = E8F255EF05769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F2563405769D930049F554 = {
+                       fileRef = E8F255EE05769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F2563505769D9F0049F554 = {
+                       fileRef = E8F255F805769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F2563605769DA50049F554 = {
+                       fileRef = E8F255F605769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F2563705769DAA0049F554 = {
+                       fileRef = E8F255F905769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F2563805769DAB0049F554 = {
+                       fileRef = E8F255FA05769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F2563905769DAC0049F554 = {
+                       fileRef = E8F255FB05769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F2563A05769DB20049F554 = {
+                       fileRef = E8F255DD05769D0B0049F554;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F2563B05769DC10049F554 = {
+                       fileRef = E81EF643055DCB4D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8F2563C05769DC30049F554 = {
+                       fileRef = E8BA211A055F032600AD687B;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FDB0CA056C297A002DFB9D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+HTMLEscaping.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FDB0CB056C297A002DFB9D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+URLEscaping.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FDB0CC056C297A002DFB9D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+XMLEscaping.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FDB0CD056C297A002DFB9D = {
+                       fileRef = E8FDB0CA056C297A002DFB9D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FDB0CE056C297A002DFB9D = {
+                       fileRef = E8FDB0CB056C297A002DFB9D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FDB0CF056C297A002DFB9D = {
+                       fileRef = E8FDB0CC056C297A002DFB9D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FDB0D2056C2988002DFB9D = {
+                       children = (
+                               E81EF6FE055DD416006FE529,
+                               E81EF6FF055DD416006FE529,
+                               E81EF700055DD416006FE529,
+                               AD1803260611DE9B00ED723F,
+                               E81EF701055DD416006FE529,
+                               E8FDB0CA056C297A002DFB9D,
+                               E8FDB0CB056C297A002DFB9D,
+                               E8FDB0CC056C297A002DFB9D,
+                       );
+                       isa = PBXGroup;
+                       name = "NSString Extensions";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FDB0E9056C3DE4002DFB9D = {
+                       fileRef = E81BE450055EDB5600B28141;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+       };
+       rootObject = E81EF5C7055DC9BE006FE529;
+}
diff --git a/skyrix-core/Version b/skyrix-core/Version
new file mode 100644 (file)
index 0000000..2dfd0b9
--- /dev/null
@@ -0,0 +1,8 @@
+# $Id$
+#
+# This file is included by library makefiles to set the version information 
+# of the executable.
+
+MAJOR_VERSION=4
+MINOR_VERSION=2
+# subminor versions are set in the Version files contained in the library path
diff --git a/skyrix-core/common.make b/skyrix-core/common.make
new file mode 100644 (file)
index 0000000..c01b911
--- /dev/null
@@ -0,0 +1,43 @@
+# $Id: common.make,v 1.3 2004/06/09 21:04:42 helge Exp $
+
+SKYROOT=..
+
+include $(GNUSTEP_MAKEFILES)/common.make
+include $(SKYROOT)/Version
+-include ./Version
+
+GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT)
+
+ADDITIONAL_CPPFLAGS += -pipe -Wall -Wno-protocol
+ifeq ($(reentrant),yes)
+ADDITIONAL_CPPFLAGS += -D_REENTRANT=1
+endif
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I.. -I../NGStreams/    \
+       -I../../skyrix-xml
+
+ADDITIONAL_LIB_DIRS += \
+        -L./$(GNUSTEP_OBJ_DIR)                 \
+       \
+       -L../../skyrix-xml/SaxObjC/$(GNUSTEP_OBJ_DIR)   \
+       -L../../skyrix-xml/DOM/$(GNUSTEP_OBJ_DIR)       \
+       -L../../skyrix-xml/XmlRpc/$(GNUSTEP_OBJ_DIR)
+
+AUTODOC_COPYRIGHT = "SKYRIX Software AG"
+AUTODOC_SxVERSION = "4.2"
+AUTODOC_TEMPLATE  = "../Documentation/AutoDocTemplate.html"
+
+AUTODOC_FLAGS     = \
+       -copyright $(AUTODOC_COPYRIGHT) \
+       -format html                    \
+       -typedirs                       \
+       -copydocs                       \
+       -tree                           \
+       -allclasses                     \
+       -define-SxVersion $(AUTODOC_SxVERSION) \
+       -template $(AUTODOC_TEMPLATE)
+
+ifeq ($(FOUNDATION_LIB),nx)
+ADDITIONAL_LDFLAGS += -framework Foundation
+endif
diff --git a/skyrix-core/dummy.c b/skyrix-core/dummy.c
new file mode 100644 (file)
index 0000000..1f05c8b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  this is required by the "fake" frameworks NGImap4 and NGMail, otherwise
+  linking will fail with:
+  ---snip---
+  ld: /Users/helge/build/NGImap4.framework/NGImap4 tocoff in load command 7 extends past the end of the file
+  ld: /Users/helge/build/NGMail.framework/NGMail tocoff in load command 7 extends past the end of the file
+  ---snap---
+*/
+
diff --git a/skyrix-core/samples/.cvsignore b/skyrix-core/samples/.cvsignore
new file mode 100644 (file)
index 0000000..f6f5660
--- /dev/null
@@ -0,0 +1,11 @@
+*.gprof
+ImapGetTool.h
+ImapGetTool.m
+data
+imapget.m
+out.xml
+*.gprof
+out1.xml
+out2.xml
+cachegrind.out.*
+*.log
diff --git a/skyrix-core/samples/COPYING b/skyrix-core/samples/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-core/samples/ChangeLog b/skyrix-core/samples/ChangeLog
new file mode 100644 (file)
index 0000000..f78f6b5
--- /dev/null
@@ -0,0 +1,129 @@
+2004-08-17  Helge Hess  <helge.hess@opengroupware.org>
+
+       * subclassing.m: fixed a compiler warning
+
+2004-07-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * bmlookup.m: major code cleanups, improved output
+
+2004-06-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * ldap2dsml.m: fixed a compile warning
+
+2004-06-21  Helge Hess  <helge.hess@opengroupware.org>
+
+       * common.h: fixed compatibility with gstep-base
+
+2004-06-17  Helge Hess  <helge.hess@opengroupware.org>
+
+       * added 'testurl' to test NSURL for the Cocoa Foundation bug wrt the
+         trailing suffix in -path
+
+2004-05-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * subclassing.m: added support for Apple runtime
+
+2004-04-12  Helge Hess  <helge.hess@opengroupware.org>
+
+       * ImapListTool, ImapTool.m, imapls.m: minor code cleanups
+
+2004-01-19  Helge Hess  <helge.hess@opengroupware.org>
+
+       * ldapls.m: minor fixes (moved NSAutoreleasePool to correct place)
+
+2004-01-11  Helge Hess  <helge.hess@opengroupware.org>
+
+       * minor cleanups to log messages
+
+2003-10-12  Helge Hess  <helge@opengroupware.org>
+
+       * EOQualTool.m: fix: returned value in a void method
+
+       * GNUmakefile (TOOL_NAME): do not compile subclassing.m on
+         MacOSX
+
+       * EncodingTool.m: fixed compilation on MacOSX
+
+2003-05-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * added parserule for testing parsing of NGRule objects
+
+2003-05-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * some gcc 3.3 warnings fixed
+
+2003-04-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: added ldapchkpwd tool
+
+       * ldap2dsml.m: added autorelease-pool to main()
+
+2003-04-01  GNUstep User  <helge.hess@skyrix.com>
+
+       * ImapListTool.m: do not use NSFileIdentifier constant
+
+       * EncodingTool.m: removed some undeclared encodings when compiling for
+         GNUstep Base
+
+2003-02-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * added ical2.m, ical3.m - examples for NGiCal
+
+2003-01-30  Helge Hess  <helge.hess@skyrix.com>
+       
+       * added httpu_notify, a small tool to send out HTTP-over-UDP 
+         NOTIFY notifications
+
+2003-01-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * testsock.m: improved test code
+
+2003-01-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * subclassing.m, ImapQuotaTool.m, imapquota.m: fixed compilation 
+         warnings
+         
+       * moved in testsock.m from NGStreams
+
+       * changes for improved compilation on MacOSX, replaced RETAIN macros
+         with methods
+
+Fri Dec 27 10:54:40 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * Mime2XmlTool.m: fixed a protocol warning
+
+Mon Dec 23 15:36:01 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * ImapListTool.m: pass correct filemanager as a parameter
+
+2002-12-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * testdirenum.m: cleanups
+
+Tue Dec 17 15:07:40 2002    <jan@skyrix.com>
+
+       * imapquota.m: add quota test
+
+2002-11-21  Jan Reichmann <jr@skyrix.com>
+
+       * added Imap-Super class, improve imapls
+
+2002-11-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * added ldapls, ldap2dsml as examples for NGLdap
+
+2002-11-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOQualTool.m: added test for complex cast
+
+2002-10-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOQualTool.m: added support for parsing SQL using the new EOSQLParser
+
+2002-10-25  Helge Hess  <helge.hess@skyrix.com>
+
+       * added eoqual tool for parsing EOQualifier's (useful for syntax 
+         checks)
+
+       * created ChangeLog
+
diff --git a/skyrix-core/samples/EOQualTool.h b/skyrix-core/samples/EOQualTool.h
new file mode 100644 (file)
index 0000000..e8dedb4
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/NSObject.h>
+
+@class NSArray, EOQualifier;
+
+/*
+  Supported Args:
+*/
+
+@interface EOQualTool : NSObject
+{
+}
+
+- (void)indent:(int)_level;
+- (void)printQualifiers:(NSArray *)_qs nesting:(int)_level;
+- (void)printQualifier:(EOQualifier *)_q nesting:(int)_level;
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
diff --git a/skyrix-core/samples/EOQualTool.m b/skyrix-core/samples/EOQualTool.m
new file mode 100644 (file)
index 0000000..3d56f2b
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "EOQualTool.h"
+#import "common.h"
+#include <EOControl/EOControl.h>
+#include <EOControl/EOSQLParser.h>
+
+@interface dateTime : NSDate
+@end
+
+@implementation dateTime
+
+- (id)initWithString:(NSString *)_s {
+  NSCalendarDate *date;
+  NSString *fmt = @"%Y-%m-%dT%H:%M:%SZ";
+  [self release];
+  date = [NSCalendarDate dateWithString:_s calendarFormat:fmt];
+  [date setCalendarFormat:@"%Y-%m-%d %H:%M %Z"];
+  return [date retain];
+}
+
+@end
+
+@implementation EOQualTool
+
+/* ops */
+
+- (void)indent:(int)_level {
+  int i;
+  for (i = 0; i < _level; i++)
+    printf("  ");
+}
+
+- (void)printQualifiers:(NSArray *)_qs nesting:(int)_level {
+  NSEnumerator *e;
+  EOQualifier *q;
+
+  e = [_qs objectEnumerator];
+  while ((q = [e nextObject]))
+    [self printQualifier:q nesting:_level];
+}
+
+- (void)printQualifier:(id)_q nesting:(int)_level {
+  [self indent:_level];
+  
+  if ([_q isKindOfClass:[EOAndQualifier class]]) {
+    printf("AND\n");
+    [self printQualifiers:[_q qualifiers] nesting:_level + 1];
+  }
+  else if ([_q isKindOfClass:[EOOrQualifier class]]) {
+    printf("OR\n");
+    [self printQualifiers:[_q qualifiers] nesting:_level + 1];
+  }
+  else if ([_q isKindOfClass:[EONotQualifier class]]) {
+    printf("NOT\n");
+    [self printQualifier:[_q qualifier] nesting:_level + 1];
+  }
+  else if ([_q isKindOfClass:[EOKeyValueQualifier class]]) {
+    id v = [_q value];
+    printf("key OP value\n");
+    _level++;
+    [self indent:_level];
+    printf("key:   %s\n", [[_q key] cString]);
+    [self indent:_level];
+    printf("value: '%s' (class=%s)\n",
+          [[v stringValue] cString],
+          [NSStringFromClass([v class]) cString]);
+    [self indent:_level];
+    printf("OP:    %s\n", [NSStringFromSelector([_q selector]) cString]);
+    _level--;
+  }
+  else if ([_q isKindOfClass:[EOKeyComparisonQualifier class]]) {
+    printf("key1 OP key1\n");
+    _level++;
+    [self indent:_level];
+    printf("left:  %s\n", [[_q leftKey] cString]);
+    [self indent:_level];
+    printf("right: %s\n", [[_q rightKey] cString]);
+    [self indent:_level];
+    printf("OP:    %s\n", [NSStringFromSelector([_q selector]) cString]);
+    _level--;
+  }
+  else
+    printf("unknown: %s\n", [NSStringFromClass([_q class]) cString]);
+}
+
+- (void)processQualifier:(NSString *)_qs {
+  EOQualifier *q;
+  NSArray *args = nil;
+  
+  printf("qualifier: '%s'\n", [_qs cString]);
+  
+  if ((q = [EOQualifier qualifierWithQualifierFormat:_qs arguments:args])) {
+    printf("  parsed: %s\n", [[q description] cString]);
+
+    [self printQualifier:q nesting:1];
+  }
+  else
+    printf("  parsing failed !\n");
+}
+
+- (void)testExQualifier {
+  [self processQualifier:
+                @"\"DAV:iscollection\" = False     and "
+              @"\"http://schemas.microsoft.com/mapi/proptag/x0c1e001f\" = "
+              @"'SMTP'        and "
+              @"\"http://schemas.microsoft.com/mapi/proptag/x0e230003\" > 0"];
+}
+- (void)testComplexCastQualifier {
+  [self processQualifier:
+              @"\"DAV:getlastmodified\" < "
+              @"  cast(\"1970-01-01T00:00:00Z\" as 'dateTime')  "
+              @" and \"DAV:contentclass\" = 'urn:content-classes:appointment'"
+              @" and (\"urn:schemas:calendar:instancetype\" = 0 "
+              @" or \"urn:schemas:calendar:instancetype\" = 1)"];
+}
+
+- (void)testQualifiers {
+  [self testExQualifier];
+  [self testComplexCastQualifier];
+}
+
+- (void)testSQL:(NSString *)_sql {
+  EOSQLParser *parser;
+  EOFetchSpecification *fs;
+
+  if ([_sql hasPrefix:@"test"]) {
+    SEL s;
+    
+    s = NSSelectorFromString(_sql);
+    if ([EOSQLParser respondsToSelector:s]) {
+      [EOSQLParser performSelector:s];
+      return;
+    }
+  }
+  
+  parser = [EOSQLParser sharedSQLParser];
+  
+  [self logWithFormat:@"parse SQL: %@", _sql];
+  [self logWithFormat:@"parser: %@", parser];
+  
+  fs = [parser parseSQLSelectStatement:_sql];
+  [self logWithFormat:@"got fs: %@", fs];
+}
+
+/* tool operation */
+
+- (int)usage {
+  fprintf(stderr, "usage: eoqual <quals>\n");
+  return 1;
+}
+
+- (int)runWithArguments:(NSArray *)_args {
+  NSUserDefaults *ud;
+  unsigned i;
+  
+  _args = [_args subarrayWithRange:NSMakeRange(1, [_args count] - 1)];
+  if ([_args count] == 0)
+    return [self usage];
+  
+  ud = [NSUserDefaults standardUserDefaults];
+  
+  for (i = 0; i < [_args count]; i++) {
+    NSString *q;
+    
+    q = [_args objectAtIndex:i];
+    if ([q hasPrefix:@"sql:"])
+      [self testSQL:[q stringWithoutPrefix:@"sql:"]];
+    else if ([q isEqualToString:@"test"])
+      [self testQualifiers];
+    else
+      [self processQualifier:q];
+  }
+  
+  return 0;
+}
+
+@end /* EOQualTool */
diff --git a/skyrix-core/samples/EncodingTool.h b/skyrix-core/samples/EncodingTool.h
new file mode 100644 (file)
index 0000000..a658f7d
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+
+@class NSString;
+
+/*
+  Supported Args:
+    -from_encoding <string> (Default: defaultCStringEncoding)
+    -to_encoding   <string> (Default: defaultCStringEncoding)
+*/
+
+@interface EncodingTool : NSObject
+{
+  NSString *file;
+  NSStringEncoding fromEncoding;
+  NSStringEncoding toEncoding;
+}
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
diff --git a/skyrix-core/samples/EncodingTool.m b/skyrix-core/samples/EncodingTool.m
new file mode 100644 (file)
index 0000000..f9e17d9
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "EncodingTool.h"
+#import "common.h"
+#import <NGStreams/NGStreams.h>
+#import <NGMime/NGMime.h>
+#import <NGMail/NGMail.h>
+
+@implementation EncodingTool
+
+- (NSUserDefaults *)userDefaults {
+  return [NSUserDefaults standardUserDefaults];
+}
+
+
+- (BOOL)getEncoding:(NSString *)_encodingStr
+  encoding:(NSStringEncoding *)_encoding
+{
+  NSLog(@"_encoding %@", _encodingStr);
+  if ([_encodingStr isEqualToString:@"NSASCIIStringEncoding"])
+    *_encoding = NSASCIIStringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSNEXTSTEPStringEncoding"])
+    *_encoding = NSNEXTSTEPStringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSJapaneseEUCStringEncoding"])
+    *_encoding = NSJapaneseEUCStringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSUTF8StringEncoding"])
+    *_encoding = NSUTF8StringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSISOLatin1StringEncoding"])
+    *_encoding = NSISOLatin1StringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSSymbolStringEncoding"])
+    *_encoding = NSSymbolStringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSNonLossyASCIIStringEncoding"])
+    *_encoding = NSNonLossyASCIIStringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSShiftJISStringEncoding"])
+    *_encoding = NSShiftJISStringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSISOLatin2StringEncoding"])
+    *_encoding = NSISOLatin2StringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSUnicodeStringEncoding"])
+    *_encoding = NSUnicodeStringEncoding;
+#if LIB_FOUNDATION_LIBRARY
+  else if ([_encodingStr isEqualToString:@"NSISOLatin9StringEncoding"])
+    *_encoding = NSISOLatin9StringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSAdobeStandardCyrillicStringEncoding"])
+    *_encoding = NSAdobeStandardCyrillicStringEncoding;
+  else if ([_encodingStr isEqualToString:@"NSWinLatin1StringEncoding"])
+    *_encoding = NSWinLatin1StringEncoding;
+#endif
+  else {
+    NSLog(@"%s: could not find encoding: '%@'",
+          __PRETTY_FUNCTION__, _encodingStr);
+    return NO;
+  }
+  return YES;
+}
+
+- (void)processEncoding {
+  NSData   *data;
+  NSString *str;
+
+  data = [NSData dataWithContentsOfFile:self->file];
+
+  NSLog(@"%s: got data %s", __PRETTY_FUNCTION__, [data bytes]);
+
+  str = [[[NSString alloc] initWithData:data encoding:self->fromEncoding]
+                    autorelease];
+  NSLog(@"%s: str length %d str %s ", __PRETTY_FUNCTION__, [str length], [str cString]);
+  data = [str dataUsingEncoding:self->toEncoding];
+  NSLog(@"%s: data length %d str %s ", __PRETTY_FUNCTION__, [data length], [data bytes]);
+  
+}
+
+/* tool operation */
+
+- (int)usage {
+  fprintf(stderr, "usage: encoding <file>\n");
+  fprintf(stderr, "  -from_encoding  <s>\n");
+  fprintf(stderr, "  -to_encoding    <s>\n");
+  return 1;
+}
+
+- (int)runWithArguments:(NSArray *)_args {
+  NSUserDefaults *ud = [self userDefaults];
+  NSString *tmp;
+  
+  _args = [_args subarrayWithRange:NSMakeRange(1, [_args count] - 1)];
+  if ([_args count] == 0)
+    return [self usage];
+
+  self->file = [_args lastObject];
+
+  tmp = [ud stringForKey:@"from_encoding"];
+  if ([tmp length]) {
+    if (![self getEncoding:tmp encoding:&self->fromEncoding])
+      self->fromEncoding = [NSString defaultCStringEncoding];
+  }
+  else
+    self->fromEncoding = [NSString defaultCStringEncoding];
+
+  tmp = [ud stringForKey:@"to_encoding"];
+  if ([tmp length]) {
+    if (![self getEncoding:tmp encoding:&self->toEncoding])
+      self->toEncoding = [NSString defaultCStringEncoding];
+  }
+  else
+    self->toEncoding = [NSString defaultCStringEncoding];
+
+  NSLog(@"process file %@ with from-encoding %@ to encoding %@",
+        file, [NSString localizedNameOfStringEncoding:self->fromEncoding],
+        [NSString localizedNameOfStringEncoding:self->toEncoding]);
+
+  [self processEncoding];
+  
+  return 0;
+}
+
+@end /* Mime2XmlTool */
diff --git a/skyrix-core/samples/GNUmakefile b/skyrix-core/samples/GNUmakefile
new file mode 100644 (file)
index 0000000..d0af126
--- /dev/null
@@ -0,0 +1,63 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+TOOL_NAME = \
+       mime2xml        \
+       imapls          \
+       encoding        \
+       fmdls           \
+       testdirenum     \
+       bmlookup        \
+       test_qpdecode   \
+       eoqual          \
+       ldapls          \
+       ldap2dsml       \
+       ldapchkpwd      \
+       imapquota       \
+       testsock        \
+       httpu_notify    \
+       ical2           \
+       ical3           \
+       parserule       \
+       testurl         \
+
+ifneq ($(OBJC_RUNTIME_LIB),apple)
+TOOL_NAME += subclassing
+endif
+
+imapquota_OBJC_FILES       = ImapQuotaTool.m ImapTool.m imapquota.m
+imapget_OBJC_FILES       = ImapTool.m imapget.m
+mime2xml_OBJC_FILES      = Mime2XmlTool.m mime2xml.m
+imapls_OBJC_FILES        = ImapTool.m ImapListTool.m imapls.m
+encoding_OBJC_FILES      = EncodingTool.m encoding.m
+subclassing_OBJC_FILES   = subclassing.m
+fmdls_OBJC_FILES         = fmdls.m
+bmlookup_OBJC_FILES      = bmlookup.m
+testdirenum_OBJC_FILES   = testdirenum.m
+test_qpdecode_OBJC_FILES = test_qpdecode.m
+eoqual_OBJC_FILES        = eoqual.m EOQualTool.m
+ldapls_OBJC_FILES       = ldapls.m
+ldap2dsml_OBJC_FILES    = ldap2dsml.m
+ldapchkpwd_OBJC_FILES   = ldapchkpwd.m
+testsock_OBJC_FILES      = testsock.m
+parserule_OBJC_FILES     = parserule.m
+httpu_notify_OBJC_FILES  = httpu_notify.m
+testurl_OBJC_FILES       = testurl.m
+
+ical2_OBJC_FILES        = ical2.m
+ical3_OBJC_FILES        = ical3.m
+
+#TOOL_NAME = #pwd-check
+#pwd-check_OBJC_FILES = pwd-check.m
+
+ldapls_TOOL_LIBS     += -lNGLdap
+ldap2dsml_TOOL_LIBS  += -lNGLdap
+ldapchkpwd_TOOL_LIBS += -lNGLdap
+
+ical2_TOOL_LIBS += -lNGiCal -lSaxObjC
+ical3_TOOL_LIBS += -lNGiCal -lSaxObjC
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/tool.make
+-include GNUmakefile.postamble
diff --git a/skyrix-core/samples/GNUmakefile.preamble b/skyrix-core/samples/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..7bf8471
--- /dev/null
@@ -0,0 +1,21 @@
+# $Id$
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..                    \
+       -I../NGMime             \
+       -I../NGStreams          \
+       -I../NGExtensions       \
+
+ADDITIONAL_LIB_DIRS += \
+       -L../EOControl/$(GNUSTEP_OBJ_DIR)    \
+       -L../NGExtensions/$(GNUSTEP_OBJ_DIR) \
+       -L../NGStreams/$(GNUSTEP_OBJ_DIR)    \
+       -L../NGMime/$(GNUSTEP_OBJ_DIR)       \
+       -L../NGLdap/$(GNUSTEP_OBJ_DIR)       \
+       -L../NGiCal/$(GNUSTEP_OBJ_DIR)       \
+
+
+ADDITIONAL_TOOL_LIBS += \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lDOM -lSaxObjC
+
diff --git a/skyrix-core/samples/ImapListTool.h b/skyrix-core/samples/ImapListTool.h
new file mode 100644 (file)
index 0000000..4c37d8b
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __ImapListTool_H__
+#define __ImapListTool_H__
+
+#import "ImapTool.h"
+
+@class NSArray;
+
+/*
+  Supported Args:
+    -statistics YES|NO (print statistics, parsing time, memory)
+    -datasource YES|NO (use datasource or directoryContentsAtPath:)
+    -preloops   <int>  (loop n-times before running the actual fetch)
+*/
+
+@interface ImapListTool : ImapTool
+{
+  BOOL useDataSource;
+  int  preloops;
+  BOOL stats;
+}
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
+
+#endif /* __ImapListTool_H__ */
diff --git a/skyrix-core/samples/ImapListTool.m b/skyrix-core/samples/ImapListTool.m
new file mode 100644 (file)
index 0000000..ad2b7b6
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "ImapListTool.h"
+#include "common.h"
+#include <NGImap4/NGImap4.h>
+#include <EOControl/EOControl.h>
+#include <NGImap4/NGImap4FileManager.h>
+#include <NGImap4/NGImap4Message.h>
+
+@implementation ImapListTool
+
+/* output */
+
+- (BOOL)outputResultsAsList:(NSArray *)dirContents
+  fileManager:(NGImap4FileManager *)fm part:(NSString *)_part
+{
+  unsigned i, count;
+  NSString *path = [fm currentDirectoryPath];
+  
+  for (i = 0, count = [dirContents count]; i < count; i++) {
+    NSString     *cpath, *apath;
+    NSDictionary *info;
+    NSString     *mid;
+        
+    if (!self->useDataSource) {
+      cpath = [dirContents objectAtIndex:i];
+      apath = [path stringByAppendingPathComponent:cpath];
+        
+      info = [fm fileAttributesAtPath:apath
+                traverseLink:NO];
+    }
+    else {
+      info = [dirContents objectAtIndex:i];
+      cpath = [NSString stringWithFormat:@"%u", [(id)info uid]];
+      apath = [path stringByAppendingPathComponent:cpath];
+      //cpath = [info valueForKey:@"NSFileName"];
+      //apath = [info valueForKey:@"NSFilePath"];
+    }
+    
+    mid = [[info valueForKey:@"NSFileIdentifier"] description];
+    if ([mid length] > 39) {
+      mid = [mid substringToIndex:37];
+      mid = [mid stringByAppendingString:@"..."];
+    }
+        
+    /* id uid date name */
+    if (_part) {
+      printf("%10d ",
+             [[fm contentsAtPath:[info valueForKey:@"NSFilePath"]
+                  part:_part] length]);
+    }
+    printf("%-40s  %8s  %8i  %-32s %s",
+          [mid cString],
+          [[info valueForKey:NSFileOwnerAccountName]      cString],
+          [[info valueForKey:NSFileSize] intValue],
+          [[[info valueForKey:NSFileModificationDate]
+             description] cString],
+          [apath cString]);
+
+    if ([[info valueForKey:NSFileType]
+         isEqualToString:NSFileTypeDirectory])
+      printf("/\n");
+    else
+      printf("\n");
+
+    
+  }
+  return YES;
+}
+
+- (BOOL)outputResultsAsXML:(NSArray *)_dirContents
+  fileManager:(NGFileManager *)_fm 
+{
+  NSLog(@"XML output not implemented ...");
+  return NO;
+}
+
+- (BOOL)outputResults:(NSArray *)dirContents
+  fileManager:(NGImap4FileManager *)fm part:(NSString *)_part
+{
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  NSAutoreleasePool *pool;
+  NSString *out;
+  BOOL result;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  out = [ud stringForKey:@"out"];
+  if ([out length] == 0)
+    result = YES;
+  else if ([out isEqualToString:@"xml"])
+    result = [self outputResultsAsXML:dirContents fileManager:fm];
+  else if ([out isEqualToString:@"ls"]) 
+    result = [self outputResultsAsList:dirContents fileManager:fm part:_part];
+  else {
+    NSLog(@"unknown output module: %@", out);
+    result = NO;
+  }
+  [pool release];
+  return result;
+}
+
+/* ops */
+
+- (void)processFile:(NSString *)path fileManager:(NGImap4FileManager *)fm
+  part:(NSString *)_part
+{
+  /* a file */
+  NSData   *contents;
+  NSString *s;
+
+  if (_part) {
+    if ((contents = [fm contentsAtPath:path part:_part]) == nil) {
+      NSLog(@"could not get content of message: '%@'", path);
+    }
+    else {
+      s = [[NSString alloc] initWithData:contents
+                            encoding:[NSString defaultCStringEncoding]];
+      printf("%s\n", [s cString]);
+      [s release];
+    }
+  }
+  else {
+    NGImap4Message *contents;
+  
+    if ((contents = [fm messageAtPath:path]) == nil) {
+      NSLog(@"could not get message at path: '%@'", path);
+    }
+    else {
+#if 0
+      s = [[NSString alloc] initWithData:contents
+                            encoding:[NSString defaultCStringEncoding]];
+      printf("%s\n", [s cString]);
+      [s release];
+#else
+      printf("%s\n", [[contents description] cString]);
+      printf("%s\n", [[[contents bodyStructure] description] cString]);
+    
+#endif
+    }
+  }
+}
+
+- (void)processFolder:(NSString *)path fileManager:(NGImap4FileManager *)fm
+  part:(NSString *)_part
+{
+  NSAutoreleasePool *pool;
+  NSTimeInterval startTime, endTime;
+  unsigned int   startSize, endSize;
+  NSProcessInfo  *pi = [NSProcessInfo processInfo];
+  NSArray        *dirContents;
+  unsigned       i;
+  EODataSource   *ds;
+  
+  if (![fm changeCurrentDirectoryPath:path]) {
+    NSLog(@"%s: could not change to directory: '%@'", path);
+  }
+
+  ds = self->useDataSource
+    ? [(id<NGFileManagerDataSources>)fm dataSourceAtPath:path]
+    : nil;
+  
+  /* pre fetches */
+  
+  for (i = 0; i < self->preloops; i++ ) {
+    NSAutoreleasePool *pool;
+    
+    startTime = [[NSDate date] timeIntervalSince1970];
+    startSize = [pi virtualMemorySize];
+    
+    /* fetch */
+    
+    pool = [[NSAutoreleasePool alloc] init];
+    {
+      ds = self->useDataSource
+       ? [(id<NGFileManagerDataSources>)fm dataSourceAtPath:path]
+       : nil;
+  
+      dirContents = (!self->useDataSource)
+       ? [fm directoryContentsAtPath:path]
+       : [ds fetchObjects];
+    }
+    [pool release];
+    
+    /* statistics */
+    
+    endSize = [pi virtualMemorySize];
+    endTime = [[NSDate date] timeIntervalSince1970];
+    
+    if (self->stats) {
+      fprintf(stderr, 
+             "parsing time [%2i]: %.3fs, "
+             "vmem-diff: %8i (%4iK,%4iM), vmem: %8i (%4iK,%4iM))\n", 
+             i, (endTime-startTime), 
+             (endSize - startSize), 
+             (endSize - startSize) / 1024, 
+             (endSize - startSize) / 1024 / 1024, 
+             endSize, endSize/1024, endSize/1024/1024);
+    }
+  }
+  
+  /* actual fetch */
+
+  startTime = [[NSDate date] timeIntervalSince1970];
+  startSize = [pi virtualMemorySize];
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  ds = self->useDataSource
+    ? [(id<NGFileManagerDataSources>)fm dataSourceAtPath:path]
+    : nil;
+  
+  dirContents = (!self->useDataSource)
+    ? [fm directoryContentsAtPath:path]
+    : [ds fetchObjects];
+  
+  dirContents = [dirContents retain];
+  [pool release];
+  dirContents = [dirContents autorelease];
+  
+  /* statistics */
+      
+  endSize = [pi virtualMemorySize];
+  endTime = [[NSDate date] timeIntervalSince1970];
+  
+  if (self->stats) {
+    fprintf(stderr, 
+           "parsing time: %.3fs, "
+           "vmem-diff: %8i (%4iK,%4iM), vmem: %8i (%4iK,%4iM))\n", 
+           (endTime-startTime), 
+           (endSize - startSize), 
+           (endSize - startSize) / 1024, 
+           (endSize - startSize) / 1024 / 1024, 
+           endSize, endSize/1024, endSize/1024/1024);
+  }
+  
+  /* output */
+  [self outputResults:dirContents fileManager:fm part:_part];
+}
+
+/*
+  path /INBOX/1233?part=1.2
+*/
+
+
+- (void)processPath:(NSString *)path fileManager:(NGImap4FileManager *)fm {
+  BOOL    isDir;
+  NSArray *array;
+  NSString *part;
+
+  array = [path componentsSeparatedByString:@"?"];
+
+  if ([array count] > 1) {
+    path = [array objectAtIndex:0];
+    part = [[[array objectAtIndex:1] componentsSeparatedByString:@"="]
+                     lastObject]; 
+  }
+  else
+    part = nil;
+  
+  if (![fm fileExistsAtPath:path isDirectory:&isDir]) {
+    NSLog(@"file/directory does not exist: %@", path);
+    return;
+  }
+    
+  if (isDir) {
+    [self processFolder:path fileManager:fm part:part];
+  }
+  else {
+    [self processFile:path fileManager:fm part:part];
+  }
+}
+
+/* tool operation */
+- (int)usage {
+  fprintf(stderr, "usage: imapls <pathes>?part=<part>\n");
+  fprintf(stderr, "usage: imapls <pathes>\n");
+  fprintf(stderr, "  -url        <url>\n");
+  fprintf(stderr, "  -user       <login>\n");
+  fprintf(stderr, "  -password   <pwd>\n");
+  fprintf(stderr, "  -host       <host>\n");
+  fprintf(stderr, "  -datasource YES|NO\n");
+  fprintf(stderr, "  -out        ls|xml\n");
+  fprintf(stderr, "  -statistics YES|NO\n");
+  fprintf(stderr, "  -preloops   <n>\n");
+  return 1;
+}
+
+- (int)runWithArguments:(NSArray *)_args {
+  NGImap4FileManager *fm;
+  NSUserDefaults *ud;
+  int            i;
+  
+  _args = [_args subarrayWithRange:NSMakeRange(1, [_args count] - 1)];
+  if ([_args count] == 0)
+    return [self usage];
+  
+  ud = [NSUserDefaults standardUserDefaults];
+  
+  self->useDataSource = [ud boolForKey:@"datasource"];
+  self->stats         = [ud boolForKey:@"statistics"];
+  self->preloops      = [ud integerForKey:@"preloops"];
+  
+  if ((fm = [self fileManager]) == nil) {
+    NSLog(@"could not open IMAP connection (got no filemanager)");
+    return 2;
+  }
+  
+#if 1
+  NSLog(@"IMAP: %@", fm);
+#endif
+  
+  for (i = 0; i < [_args count]; i++) {
+    [self processPath:[_args objectAtIndex:i] fileManager:fm];
+  }
+  
+  return 0;
+}
+
+@end /* ImapListTool */
diff --git a/skyrix-core/samples/ImapQuotaTool.h b/skyrix-core/samples/ImapQuotaTool.h
new file mode 100644 (file)
index 0000000..ad9025d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+
+#include "ImapTool.h"
+
+@class NSString, NSDictionary;
+
+@interface ImapQuotaTool : ImapTool
+{
+}
+
+- (NSDictionary *)getQuotaRoot:(NSString *)_folder;
+
+@end
diff --git a/skyrix-core/samples/ImapQuotaTool.m b/skyrix-core/samples/ImapQuotaTool.m
new file mode 100644 (file)
index 0000000..cfcf608
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGImap4/NGImap4Client.h>
+#include <NGImap4/NGImap4FileManager.h>
+#include <NGImap4/NGImap4Context.h>
+#include "common.h"
+#include "ImapQuotaTool.h"
+
+@implementation ImapQuotaTool
+
+- (NSDictionary *)getQuotaRoot:(NSString *)_folder {
+  NGImap4FileManager *fm;
+  NGImap4Client      *client;
+
+  fm = [self fileManager];
+  client = [[fm imapContext] client];
+
+  return [[client getQuotaRoot:_folder] objectForKey:@"quotas"];
+  
+}
+
+@end /* ImapQuotaTool */
diff --git a/skyrix-core/samples/ImapTool.h b/skyrix-core/samples/ImapTool.h
new file mode 100644 (file)
index 0000000..33b86c3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ImapTool_H__
+#define __ImapTool_H__
+
+#import <Foundation/NSObject.h>
+
+@class NGImap4FileManager;
+
+@interface ImapTool : NSObject
+{
+  NGImap4FileManager *fileManager;
+}
+- (void)flush;
+- (NGImap4FileManager *)fileManager;
+
+@end
+
+#endif /* __ImapTool_H__ */
diff --git a/skyrix-core/samples/ImapTool.m b/skyrix-core/samples/ImapTool.m
new file mode 100644 (file)
index 0000000..df974ce
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "ImapTool.h"
+#include <NGImap4/NGImap4FileManager.h>
+#include "common.h"
+
+@implementation ImapTool
+
+- (void)flush {
+  [self->fileManager release]; self->fileManager = nil;
+}
+
+- (NGImap4FileManager *)fileManager {
+  NSUserDefaults *ud;
+  NSString       *pwd, *user, *host;
+  id             url;
+  
+  if (self->fileManager)
+    return self->fileManager;
+  
+  ud = [NSUserDefaults standardUserDefaults];
+  
+  if ((url = [ud stringForKey:@"url"]))
+    url = [NSURL URLWithString:url];
+  
+  if ((user = [ud stringForKey:@"user"]) == nil)
+    user = [url user];
+  if ((pwd = [ud stringForKey:@"password"]) == nil)
+    pwd = [url password];
+  if ((host = [ud stringForKey:@"host"]) == nil)
+    host = [(NSURL *)url host];
+  
+  self->fileManager = [[NGImap4FileManager alloc] initWithUser:user
+                                                 password:pwd
+                                                 host:host];
+  if (self->fileManager == nil) {
+    if (user == nil) NSLog(@"missing login.");
+    if (pwd  == nil) NSLog(@"missing password.");
+    if (host == nil) NSLog(@"missing host.");
+  }
+  
+  return self->fileManager;
+}
+
+@end /* ImapTool */ 
diff --git a/skyrix-core/samples/Mime2XmlTool.h b/skyrix-core/samples/Mime2XmlTool.h
new file mode 100644 (file)
index 0000000..30c8d11
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/NSObject.h>
+
+@class NSArray;
+
+/*
+  Supported Args:
+    -statistics YES|NO (print statistics, parsing time, memory)
+    -streams    YES|NO (either use streaming IO or memory mapped data)
+    -preloops   <int>  (loop n-times before running the actual parse)
+*/
+
+@interface Mime2XmlTool : NSObject
+{
+  int outIndent;
+
+  BOOL parseFields;
+  BOOL useDelegate;
+  BOOL rejectAllFields;
+  
+  int  preloops;
+}
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
diff --git a/skyrix-core/samples/Mime2XmlTool.m b/skyrix-core/samples/Mime2XmlTool.m
new file mode 100644 (file)
index 0000000..87569e2
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "Mime2XmlTool.h"
+#import "common.h"
+#import <NGStreams/NGStreams.h>
+#import <NGMime/NGMime.h>
+#import <NGMail/NGMail.h>
+
+@interface Mime2XmlTool(Privates)
+- (BOOL)_outputPartAsXML:(id<NGMimePart>)_part;
+@end
+
+@implementation Mime2XmlTool
+
+- (NSUserDefaults *)userDefaults {
+  return [NSUserDefaults standardUserDefaults];
+}
+
+/* part generation */
+
+- (void)indent {
+  unsigned i;
+  for (i = 0; i < self->outIndent; i++)
+    printf("  ");
+}
+
+- (BOOL)_outputMultipartBody:(NGMimeMultipartBody *)_body {
+  NSEnumerator *e;
+  id<NGMimePart> part;
+  
+  self->outIndent++;
+
+  e = [[_body parts] objectEnumerator];
+  while ((part = [e nextObject]))
+    [self _outputPartAsXML:part];
+  
+  self->outIndent--;
+  return YES;
+}
+
+- (BOOL)_outputStringBody:(NSString *)body {
+  [self indent];
+  printf("<body charlen='%i'>", [body length]);
+  if ([body length] > 256) {
+    body = [body substringToIndex:255];
+    printf("%s", [body cString]);
+  }
+  printf("</body>\n");
+  return YES;
+}
+- (BOOL)_outputDataBody:(NSData *)body {
+  [self indent];
+  printf("<body><data size='%i'>...</data></body>\n",
+        [body length]);
+  return YES;
+}
+- (BOOL)_outputPartBody:(id<NGMimePart>)body {
+  [self indent];
+  printf("<body>\n");
+  [self _outputPartAsXML:(id<NGMimePart>)body];
+  [self indent];
+  printf("</body>\n");
+  return YES;
+}
+- (BOOL)_outputMultiPartBody:(id<NGMimePart>)body {
+  [self indent];
+  printf("<body multipart='true'>\n");
+       
+  [self _outputMultipartBody:(id)body];
+       
+  [self indent];
+  printf("</body>\n");
+  return YES;
+}
+
+- (BOOL)_outputHeaderField:(NSString *)_field value:(id)_value {
+  Class    clazz;
+  NSString *s;
+  [self indent];
+  
+  clazz = [_value class];
+  printf("<h name=\"%s\"", [_field cString]);
+  printf(">");
+  
+  s = [_value stringValue];
+  s = [s stringByEscapingXMLString];
+  printf("%s", [s cString]);
+  
+  printf("</h>\n");
+  return YES;
+}
+- (BOOL)_outputPartHeaders:(id<NGMimePart>)_part {
+  NSEnumerator *headerFields;
+  NSString *headerField;
+  
+  headerFields = [_part headerFieldNames];
+  while ((headerField = [headerFields nextObject])) {
+    NSEnumerator *vals;
+    id value;
+    
+    vals = [_part valuesOfHeaderFieldWithName:headerField];
+    while ((value = [vals nextObject])) {
+      [self _outputHeaderField:headerField value:value];
+    }
+  }
+  return YES;
+}
+
+- (BOOL)_outputPartAsXML:(id<NGMimePart>)_part {
+  id tmp;
+  id body;
+  
+  if (_part == nil) {
+    NSLog(@"got no part ...");
+    return NO;
+  }
+  
+  [self indent];
+  printf("<part ptr='0x%08X'", (unsigned int)_part);
+  
+  if ([_part conformsToProtocol:@protocol(NGMimePart)]) {
+    if ((tmp = [_part contentType]))
+      printf(" content-type='%s'", [[tmp stringValue] cString]);
+    if ((tmp = [_part encoding]))
+      printf(" encoding='%s'", [[tmp stringValue] cString]);
+    if ((tmp = [_part contentId]))
+      printf(" content-id='%s'", [[tmp stringValue] cString]);
+    if ((tmp = [_part contentLanguage]))
+      printf(" content-language='%s'", [[tmp stringValue] cString]);
+    if ((tmp = [_part contentMd5]))
+      printf(" content-md5='%s'", [[tmp stringValue] cString]);
+  }  
+  printf(">\n");
+  self->outIndent++;
+  {
+    /* output header */
+    [self _outputPartHeaders:_part];
+    
+    /* output body */
+    
+    if ((body = [_part body])) {
+      if ([body isKindOfClass:[NSString class]])
+       [self _outputStringBody:body];
+      else if ([body isKindOfClass:[NSData class]])
+       [self _outputDataBody:body];
+      else if ([body conformsToProtocol:@protocol(NGMimePart)]) {
+       /*
+         Note: an NSData is also a MIME part, because of this
+         a check for NSData needs to be done first ! 
+       */
+       [self _outputPartBody:body];
+      }
+      else if ([body isKindOfClass:[NGMimeMultipartBody class]]) {
+       [self _outputMultiPartBody:body];
+      }
+      else
+       NSLog(@"unknown body class: %@", NSStringFromClass(body));
+    }
+  }
+  self->outIndent--;
+  [self indent];
+  printf("</part>\n");
+  return YES;
+}
+
+- (BOOL)outputPartAsXML:(id<NGMimePart>)_part {
+  self->outIndent = 0;
+  printf("<?xml version='1.0' encoding='ISO-8859-1'?>\n");
+  return [self _outputPartAsXML:_part];
+}
+
+- (BOOL)outputPartAsMime:(id<NGMimePart>)_part {
+  return NO;
+}
+
+- (BOOL)outputPart:(id<NGMimePart>)_part {
+  NSUserDefaults *ud = [self userDefaults];
+  NSAutoreleasePool *pool;
+  NSString *out;
+  BOOL result;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  out = [ud stringForKey:@"out"];
+  if ([out length] == 0)
+    result = YES;
+  else if ([out isEqualToString:@"xml"])
+    result = [self outputPartAsXML:_part];
+  else if ([out isEqualToString:@"mime"]) 
+    result = [self outputPartAsMime:_part];
+  else {
+    NSLog(@"unknown output module: %@", out);
+    result = NO;
+  }
+  [pool release];
+  return result;
+}
+
+/* MIME delegate */
+
+#if 0
+- (id)parser:(NGMimePartParser *)_parser
+  parseHeaderField:(NSString *)_name
+  data:(NSData *)_data
+{
+  if (self->rejectAllFields) {
+    if ([_name hasPrefix:@"content-"]) {
+      NSString *s;
+      
+      s = [[NSString alloc] initWithData:_data 
+                           encoding:NSISOLatin1StringEncoding];
+      return [s autorelease];
+    }
+    return nil;
+  }
+  
+  return _data;
+}
+#endif
+
+- (void)parser:(NGMimePartParser *)_parser
+  didParseHeader:(NGHashMap *)_header
+{
+  //NSLog(@"got header: %@", _header);
+}
+- (BOOL)parser:(NGMimePartParser *)_parser
+  keepHeaderField:(NSString *)_name
+  value:(id)_value
+{
+  if ([_name hasPrefix:@"content-"])
+    return YES;
+  
+  return self->rejectAllFields ? NO : YES;
+}
+
+/* MIME parsing */
+
+- (id<NGMimePart>)parseFile:(NSString *)_path useStreams:(BOOL)_streams {
+  NSAutoreleasePool *pool;
+  NGMimePartParser  *parser;
+  id<NGMimePart>    part;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    id  input;
+    SEL sel;
+    
+    parser = [[[NGMimeMessageParser alloc] init] autorelease];
+    
+    if (self->useDelegate)
+      [parser setDelegate:self];
+    
+    /* create input object */
+    
+    if (_streams) {
+      NGFileStream *stream;
+      
+      stream = [[[NGFileStream alloc] initWithPath:_path] autorelease];
+      if (![stream openInMode:@"r"]) {
+       NSLog(@"could not open stream for reading: '%@'\n  exception: %@", 
+             _path, [stream lastException]);
+       return NO;
+      }
+      
+      sel   = @selector(parsePartFromStream:);
+      input = stream;
+    }
+    else {
+      NSData *data;
+    
+      if ((data = [NSData dataWithContentsOfMappedFile:_path]) == nil) {
+       NSLog(@"could not get data for path: '%@'", _path);
+       return NO;
+      }
+      
+      sel   = @selector(parsePartFromData:);
+      input = data;
+    }
+
+    /* do parsing */
+    
+    if ([[self userDefaults] boolForKey:@"noparse"])
+      part = nil;
+    else
+      part = [parser performSelector:sel withObject:input];
+    
+    part = [part retain];
+  }
+  [pool release];
+  return [part autorelease];
+}
+
+- (BOOL)processFile:(NSString *)_path {
+  NSProcessInfo     *pi = [NSProcessInfo processInfo];
+  NSUserDefaults    *ud = [self userDefaults];
+  id<NGMimePart>    part;
+  NSAutoreleasePool *pool;
+  
+  NSLog(@"process: %@", _path);
+
+  /* parsing */
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    NSTimeInterval startTime, endTime;
+    unsigned int   startSize, endSize;
+    int i, preRepeatCount;
+    
+    /* first some useless parsing for profiling */
+    
+    preRepeatCount = self->preloops;
+    for (i = 0; i < preRepeatCount; i++) {
+      NSAutoreleasePool *pool;
+      
+      startTime = [[NSDate date] timeIntervalSince1970];
+      startSize = [pi virtualMemorySize];
+      
+      pool = [[NSAutoreleasePool alloc] init];
+      part = [self parseFile:_path useStreams:[ud boolForKey:@"streams"]];
+      [pool release];
+      
+      endSize = [pi virtualMemorySize];
+      endTime = [[NSDate date] timeIntervalSince1970];
+      
+      /* statistics */
+      
+      if ([ud boolForKey:@"statistics"]) {
+       fprintf(stderr, 
+               "parsing time [%2i]: %.3fs, "
+               "vmem-diff: %8i (%4iK,%4iM), vmem: %8i (%4iK,%4iM))\n", 
+               i, (endTime-startTime), 
+               (endSize - startSize), 
+               (endSize - startSize) / 1024, 
+               (endSize - startSize) / 1024 / 1024, 
+               endSize, endSize/1024, endSize/1024/1024);
+      }
+    }
+
+    /* the "real" parser (remembers the part ...) */
+    
+    startTime = [[NSDate date] timeIntervalSince1970];
+    startSize = [pi virtualMemorySize];
+    part = [self parseFile:_path useStreams:[ud boolForKey:@"streams"]];
+    endSize = [pi virtualMemorySize];
+    endTime = [[NSDate date] timeIntervalSince1970];
+    
+    /* statistics */
+    
+    if ([ud boolForKey:@"statistics"]) {
+      fprintf(stderr, 
+             "parsing time: %.3fs, vmem-diff: %8i, vmem: %8i\n", 
+             (endTime-startTime), (endSize - startSize), endSize);
+    }
+  }
+  part = [part retain];
+  [pool release];
+  part = [part autorelease];
+  
+  if (part == nil) {
+    NSLog(@"could not parse a part from path: '%@'", _path);
+    return NO;
+  }
+  
+  /* generating */
+  [self outputPart:part];
+  return YES;
+}
+
+/* tool operation */
+
+- (int)usage {
+  fprintf(stderr, "usage: mime2xml <file>*\n");
+  fprintf(stderr, "  -preloops    <n>\n");
+  fprintf(stderr, "  -statistics  YES|NO\n");
+  fprintf(stderr, "  -streams     YES|NO\n");
+  fprintf(stderr, "  -noparse     YES|NO\n");
+  fprintf(stderr, "  -delegate    YES|NO\n");
+  fprintf(stderr, "  -parsefields YES|NO\n");
+  return 1;
+}
+
+- (int)runWithArguments:(NSArray *)_args {
+  NSUserDefaults *ud = [self userDefaults];
+  NSEnumerator *e;
+  NSString *f;
+
+  self->parseFields     = [ud boolForKey:@"parsefields"];
+  self->useDelegate     = [ud boolForKey:@"delegate"];
+  self->preloops        = [ud integerForKey:@"preloops"];
+  self->rejectAllFields = [ud boolForKey:@"rejectAllFields"];
+  
+  _args = [_args subarrayWithRange:NSMakeRange(1, [_args count] - 1)];
+  if ([_args count] == 0)
+    return [self usage];
+  
+  e = [_args objectEnumerator];
+  while ((f = [e nextObject])) {
+    NSAutoreleasePool *pool;
+    
+    pool = [[NSAutoreleasePool alloc] init];
+    [self processFile:f];
+    [pool release];
+  }
+  
+  return 0;
+}
+
+@end /* Mime2XmlTool */
diff --git a/skyrix-core/samples/README b/skyrix-core/samples/README
new file mode 100644 (file)
index 0000000..692d2a6
--- /dev/null
@@ -0,0 +1,26 @@
+# $Id$
+
+This directory contains sample programs for the skyrix-core libraries.
+
+Tools
+=====
+
+mime2xml    - read a MIME file and output the structure as XML
+
+imapls      - list IMAP4 server directories, sample for NGImap4FileManager
+
+bmlookup    - perform resource lookups using the NGExtensions NGBundleManager
+              class
+
+fmdls       - list directories using the NGFileManager directory-datasource
+              implementation
+
+subclassing - test runtime subclassing in the Objective-C runtime 
+              (NGObjCRuntime in NGExtensions)
+
+testdirenum - test the NGDirectoryEnumerator
+
+ldapls     - an 'ls' for LDAP directories
+ldap2dsml   - return the output of an LDAP server as DSML (directory service
+              markup language)
+ldapchkpwd  - check whether a login/password combo would be authenticated
diff --git a/skyrix-core/samples/bmlookup.m b/skyrix-core/samples/bmlookup.m
new file mode 100644 (file)
index 0000000..d3a63dd
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "common.h"
+#include <EOControl/EOControl.h>
+#include <NGExtensions/NSFileManager+Extensions.h>
+#include <NGExtensions/NGFileFolderInfoDataSource.h>
+#include <NGExtensions/NGExtensions.h>
+
+@interface BMLookupTool : NSObject
+{
+  NGBundleManager *bm;
+}
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
+
+@implementation BMLookupTool
+
+- (id)init {
+  if ((self = [super init])) {
+    self->bm = [[NGBundleManager defaultBundleManager] retain];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->bm release];
+  [super dealloc];
+}
+
+- (void)listResourcesOfType:(NSString *)btype {
+  NSEnumerator *resources;
+  id resource;
+  
+  printf("lookup resources of type: '%s'\n", [btype cString]);
+
+  resources = [[bm providedResourcesOfType:btype] objectEnumerator];
+  while ((resource = [resources nextObject])) {
+    NSString *rname;
+      
+    if ((rname  = [resource objectForKey:@"name"]) != nil) {
+      NSBundle *bundle;
+      
+      bundle = [bm bundleProvidingResource:rname ofType:btype];
+      printf("  resource  '%s'\n",  [rname cString]);
+      printf("    bundle: '%s'\n", [[bundle bundlePath] cString]);
+      printf("    info:   %s\n", [[resource description] cString]);
+    }
+    else
+      printf("  resource info: %s\n", [[resource description] cString]);
+  }
+}
+
+- (void)lookupResourceWithName:(NSString *)bname ofType:(NSString *)btype {
+  NSBundle *bundle;
+    
+  printf("lookup resource '%s' of type: '%s'\n", 
+        [bname cString], [btype cString]);
+    
+  bundle = [self->bm bundleProvidingResource:bname ofType:btype];
+  printf("  bundle: '%s'\n", [[bundle bundlePath] cString]);
+  
+  if ([[NSUserDefaults standardUserDefaults] boolForKey:@"load"]) {
+    if (![bundle load])
+      NSLog(@"Could not load bundle: %@", bundle);
+    else
+      printf("  did load bundle: %s\n", [[bundle description] cString]);
+  }
+}
+
+- (int)runWithArguments:(NSArray *)_args {
+  if ([_args count] < 2) {
+    NSLog(@"usage: %@ type name", [[_args objectAtIndex:0] lastPathComponent]);
+    return 1;
+  }
+  
+  if ([_args count] == 2) {
+    [self listResourcesOfType:[_args objectAtIndex:1]];
+    return 0;
+  }
+  
+  [self lookupResourceWithName:[_args objectAtIndex:2]
+       ofType:[_args objectAtIndex:1]];
+  return 0;
+}
+
+@end /* BMLookupTool */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  int rc;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  rc = [[[[BMLookupTool alloc] init] autorelease]
+        runWithArguments:
+          [[NSProcessInfo processInfo] argumentsWithoutDefaults]];
+  
+  [pool release];
+  
+  exit(rc);
+  return rc;
+}
diff --git a/skyrix-core/samples/common.h b/skyrix-core/samples/common.h
new file mode 100644 (file)
index 0000000..408caa9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <Foundation/Foundation.h>
+
+#if LIB_FOUNDATION_LIBRARY
+#  include <Foundation/exceptions/GeneralExceptions.h>
+#else
+#  include <NGExtensions/NGObjectMacros.h>
+#  include <NGExtensions/NSString+Ext.h>
+#endif
+
+#include <NGExtensions/NGExtensions.h>
diff --git a/skyrix-core/samples/encoding.m b/skyrix-core/samples/encoding.m
new file mode 100644 (file)
index 0000000..1d73828
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  encode utf8
+*/
+
+#import "EncodingTool.h"
+#include "common.h"
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  EncodingTool      *tool;
+  int res;
+  
+  pool = [NSAutoreleasePool new];
+  
+#if LIB_FOUNDATION_LIBRARY  
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  tool = [[EncodingTool alloc] init];
+  res = [tool runWithArguments:
+               [[NSProcessInfo processInfo] argumentsWithoutDefaults]];
+  [tool release];
+  
+  [pool release];
+  exit(0);
+  /* static linking */
+  [NGExtensions class];
+  return 0;
+}
diff --git a/skyrix-core/samples/eoqual.m b/skyrix-core/samples/eoqual.m
new file mode 100644 (file)
index 0000000..922bea1
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "EOQualTool.h"
+#include "common.h"
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  EOQualTool *tool;
+  int res;
+  
+  pool = [NSAutoreleasePool new];
+  
+#if LIB_FOUNDATION_LIBRARY  
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  tool = [[EOQualTool alloc] init];
+  res = [tool runWithArguments:
+               [[NSProcessInfo processInfo] argumentsWithoutDefaults]];
+  [tool release];
+  
+  [pool release];
+  exit(0);
+  /* static linking */
+  [NGExtensions class];
+  return 0;
+}
diff --git a/skyrix-core/samples/fmdls.m b/skyrix-core/samples/fmdls.m
new file mode 100644 (file)
index 0000000..be3b4ee
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+#import <EOControl/EOControl.h>
+#include <NGExtensions/NSFileManager+Extensions.h>
+#include <NGExtensions/NGFileFolderInfoDataSource.h>
+#include <NGExtensions/NGExtensions.h>
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  NSArray       *args;
+  NSFileManager *fm;
+  int           i;
+  
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  args = [[NSProcessInfo processInfo] arguments];
+  if ([args count] < 1) {
+    NSLog(@"usage: %@ <files>", [args objectAtIndex:0]);
+    exit(1);
+  }
+  else if ([args count] == 1)
+    args = [args arrayByAddingObject:@"."];
+
+  fm = [NSFileManager defaultManager];
+
+  for (i = 1; i < [args count]; i++) {
+    NSString *path;
+    BOOL     isDir;
+    
+    path = [args objectAtIndex:i];
+
+    if ([path hasPrefix:@"-"]) {
+      i++;
+      continue;
+    }
+    
+    if (![fm fileExistsAtPath:path isDirectory:&isDir]) {
+      NSLog(@"file/directory does not exist: %@", path);
+      continue;
+    }
+    
+    if (isDir) {
+      EODataSource *ds;
+      NSEnumerator *records;
+      NSDictionary *record;
+      NSArray      *sortOrderings;
+      EOQualifier  *qualifier;
+      id tmp;
+      
+      if ((ds = [fm dataSourceAtPath:path]) == nil) {
+        NSLog(@"could not get datasource for path: '%@'", path);
+        continue;
+      }
+
+      /* build fetch specification */
+      
+      tmp = [[NSUserDefaults standardUserDefaults] stringForKey:@"qualifier"];
+      if ([tmp length] > 0) {
+        qualifier = [EOQualifier qualifierWithQualifierFormat:tmp];
+        if (qualifier == nil)
+          NSLog(@"could not parse qualifier: %@", tmp);
+      }
+      else
+        qualifier = nil;
+
+      tmp = [EOSortOrdering sortOrderingWithKey:@"NSFileName"
+                            selector:EOCompareAscending];
+      sortOrderings = [NSArray arrayWithObject:tmp];
+      
+      if ((qualifier != nil) || (sortOrderings != nil)) {
+        EOFetchSpecification *fs;
+        
+        fs = [[EOFetchSpecification alloc] init];
+        [fs setQualifier:qualifier];
+        [fs setSortOrderings:sortOrderings];
+
+        [(id)ds setFetchSpecification:fs];
+        [fs release]; fs = nil;
+      }
+      
+      /* perform fetch */
+      
+      records = [[ds fetchObjects] objectEnumerator];
+      
+      /* print out */
+
+      while ((record = [records nextObject])) {
+        /* id uid gid date name */
+        NSString *fileId;
+        NSString *owner;
+        int      gid;
+        unsigned size;
+        NSString *modDate;
+        NSString *fname;
+        NSString *ftype;
+        
+        fileId  = [[record objectForKey:@"NSFileIdentifier"] description];
+        owner   = [record  objectForKey:NSFileOwnerAccountName];
+        gid     = [[record objectForKey:@"NSFileGroupOwnerAccountNumber"] intValue];
+        size    = [[record  objectForKey:NSFileSize] intValue];
+        modDate = [[record objectForKey:NSFileModificationDate] description];
+        fname   = [record  objectForKey:@"NSFileName"];
+        ftype   = [record  objectForKey:NSFileType];
+
+        if ([ftype isEqualToString:NSFileTypeDirectory])
+          fname = [fname stringByAppendingString:@"/"];
+        else if ([ftype isEqualToString:NSFileTypeSocket])
+          fname = [fname stringByAppendingString:@"="];
+        else if ([ftype isEqualToString:NSFileTypeSymbolicLink])
+          fname = [fname stringByAppendingString:@"@"];
+        
+        //NSLog(@"record: %@", record);
+        
+        printf("%8s  %8s  %8i  %8i  %8s  %s\n",
+               [fileId cString],
+               [owner  cString],
+               gid,
+               size,
+               [modDate cString],
+               [fname cString]);
+      }
+    }
+    else {
+      /* a file */
+    }
+  }
+  [pool release];
+  
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-core/samples/httpu_notify.m b/skyrix-core/samples/httpu_notify.m
new file mode 100644 (file)
index 0000000..5c63a91
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+#include <NGStreams/NGDatagramPacket.h>
+#include <NGStreams/NGDatagramSocket.h>
+#include <NGStreams/NGInternetSocketAddress.h>
+#include <NGStreams/NGInternetSocketDomain.h>
+
+static void run(void) {
+  NSUserDefaults *ud;
+  NSString *sid;
+  NSURL    *observer;
+  NGDatagramSocket *socket = nil;
+  NGInternetSocketAddress *address;
+  NGDatagramPacket *packet;
+  NSMutableString  *ms;
+  NSData           *data;
+  
+  ud  = [NSUserDefaults standardUserDefaults];
+  sid      = [ud stringForKey:@"sid"];
+  observer = [NSURL URLWithString:[ud stringForKey:@"url"]];
+  
+  if (observer  == nil) {
+    NSLog(@"missing observer ! (use -url to specify one !)");
+    exit(2);
+  }
+  
+  /* construct HTTP-over-UDP request */
+  
+  ms = [NSMutableString stringWithCapacity:16];
+  [ms appendString:@"NOTIFY "];
+  [ms appendString:[observer absoluteString]];
+  [ms appendString:@" HTTP/1.1\r\n"];
+  
+  /* notifications without sid are "teardown's" */
+  if ([sid length] > 0) {
+    [ms appendString:@"Subscription-id: "];
+    [ms appendString:sid];
+    [ms appendString:@"\r\n"];
+  }
+  
+  /* send packet */
+  
+  data    = [ms dataUsingEncoding:NSUTF8StringEncoding];
+  packet  = [NGDatagramPacket packetWithData:data];
+  address = [NGInternetSocketAddress addressWithPort:
+                                       [[observer port] intValue]
+                                     onHost:
+                                       [observer host]];
+  
+  socket = [[NGDatagramSocket alloc] initWithDomain:
+                                       [NGInternetSocketDomain domain]];
+  [packet setReceiver:address];
+  
+  if (![socket sendPacket:packet timeout:3.0]) {
+    NSLog(@"could not send packet %@ on socket %@ !");
+    exit(1);
+  }
+}
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  run();
+  
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-core/samples/ical2.m b/skyrix-core/samples/ical2.m
new file mode 100644 (file)
index 0000000..e7c66dd
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+#include <SaxObjC/SaxObjC.h>
+
+@interface iCal2Tool : NSObject
+{
+  id<NSObject,SaxXMLReader> parser;
+  SaxObjectDecoder *sax;
+}
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
+
+@implementation iCal2Tool
+
+- (id)init {
+  if ((self = [super init])) {
+    self->parser =
+      [[[SaxXMLReaderFactory standardXMLReaderFactory] 
+                            createXMLReaderForMimeType:@"text/calendar"]
+                             retain];
+    if (self->parser == nil) {
+      NSLog(@"%s: did not find a parser for text/calendar !",
+           __PRETTY_FUNCTION__);
+      [self release];
+      return nil;
+    }
+    
+    /* ensure that NGiCal.xmap can be found ! (Library/SaxMappings) */
+    self->sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGiCal"];
+    if (self->sax == nil) {
+      NSLog(@"could not create the iCal SAX handler !");
+      [self release];
+      return nil;
+    }
+    
+    [self->parser setContentHandler:self->sax];
+    [self->parser setErrorHandler:self->sax];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->sax    release];
+  [self->parser release];
+  [super dealloc];
+}
+
+/* parsing */
+
+- (id)parseFile:(NSString *)_path {
+  if ([_path length] == 0) return nil;
+  
+  _path = [@"file://" stringByAppendingString:_path];
+  
+  [self->parser parseFromSystemId:_path];
+  
+  return [self->sax rootObject];
+}
+
+- (void)printParsedObject:(id)_object {
+  NSLog(@"component: %@",       _object);
+#if 0
+  NSLog(@"  subcomponents: %@", [_object subComponents]);
+  
+  printf("%s", [[_object icalString] cString]);
+#endif
+}
+
+/* run */
+
+- (int)runWithArguments:(NSArray *)_args {
+  NSEnumerator      *args;
+  NSString          *arg;
+  
+  args = [_args objectEnumerator];
+  [args nextObject]; // process name ...
+
+  while ((arg = [args nextObject])) {
+    NSAutoreleasePool *pool2;
+
+    if ([arg hasPrefix:@"-"]) { /* consume defaults */
+      [args nextObject];
+      continue;
+    }
+    
+    pool2 = [[NSAutoreleasePool alloc] init];
+    {    
+      id component;
+      
+      NS_DURING
+       component = [self parseFile:arg];
+      NS_HANDLER
+       abort();
+      NS_ENDHANDLER;
+      
+      if (component == nil)
+       NSLog(@"could not parse file: '%@'", arg);
+      else
+       [self printParsedObject:component];
+    }
+    [pool2 release];
+  }
+  return 0;
+}
+
+@end /* iCal2Tool */
+
+int main(int argc, char **argv, char **env)  {
+  NSAutoreleasePool *pool;
+  iCal2Tool *tool;
+  int rc;
+
+#if LIB_FOUNDATION_LIBRARY  
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  if ((tool = [[iCal2Tool alloc] init])) {
+    NS_DURING
+      rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]];
+    NS_HANDLER
+      abort();
+    NS_ENDHANDLER;
+    
+    [tool release];
+  }
+  else
+    rc = 1;
+  
+  [pool release];
+  return rc;
+}
diff --git a/skyrix-core/samples/ical3.m b/skyrix-core/samples/ical3.m
new file mode 100644 (file)
index 0000000..deccf79
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+
+@class EOQualifier, NSString, EOSortOrdering;
+
+@interface iCal3Tool : NSObject
+{
+  EOQualifier *qualifier;
+  NSString    *entityName;
+  NSArray     *sortOrderings;
+}
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
+
+#include <NGiCal/iCalDataSource.h>
+#include <NGiCal/iCalObject.h>
+#include <EOControl/EOQualifier.h>
+#include <EOControl/EOSortOrdering.h>
+#include "common.h"
+
+@implementation iCal3Tool
+
+- (id)init {
+  if ((self = [super init])) {
+    NSUserDefaults *ud;
+    id tmp;
+    
+    /* collect options */
+    ud = [NSUserDefaults standardUserDefaults];
+
+    self->entityName = [[ud stringForKey:@"entity"] copy];
+    
+    if ((tmp = [ud objectForKey:@"qualifier"]))
+      self->qualifier = [[EOQualifier alloc] initWithPropertyList:tmp];
+
+    if ((tmp = [ud objectForKey:@"sort"])) {
+      if ((tmp = [[EOSortOrdering alloc] initWithPropertyList:tmp])) {
+       self->sortOrderings = [[NSArray alloc] initWithObjects:tmp,nil];
+       [tmp release];
+      }
+    }
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->sortOrderings release];
+  [self->qualifier     release];
+  [self->entityName    release];
+  [super dealloc];
+}
+
+/* run */
+
+- (void)printObject:(id)_object {
+  printf("object: %s\n", [[_object description] cString]);
+}
+
+- (int)runWithArguments:(NSArray *)_args {
+  NSEnumerator *args;
+  NSString     *arg;
+  
+  /* begin processing */
+  
+  args = [_args objectEnumerator];
+  [args nextObject]; // process name ...
+  
+  while ((arg = [args nextObject])) {
+    NSAutoreleasePool *pool2;
+    
+    if ([arg hasPrefix:@"-"]) { /* consume defaults */
+      [args nextObject];
+      continue;
+    }
+    
+    pool2 = [[NSAutoreleasePool alloc] init];
+    {    
+      iCalDataSource       *ds;
+      EOFetchSpecification *fspec;
+      NSArray    *objs;
+      iCalObject *obj;
+      
+      /* setup fetch specification */
+      
+      fspec = [[[EOFetchSpecification alloc] init] autorelease];
+      [fspec setEntityName:self->entityName];
+      [fspec setQualifier:self->qualifier];
+      
+      /* setup datasource */
+      
+      ds = [[[iCalDataSource alloc] initWithPath:arg] autorelease];
+      [ds setFetchSpecification:fspec];
+
+      /* perform fetch */
+      
+      if ((objs = [ds fetchObjects]) == nil) {
+       /* fetch failed */
+       
+       NSLog(@"fetch on ical file failed: %@", arg);
+      }
+      else {
+       /* process results */
+       NSEnumerator *e;
+       
+       e = [objs objectEnumerator];
+       while ((obj = [e nextObject])) {
+         [self printObject:obj];
+       }
+      }
+    }
+    [pool2 release];
+  }
+  return 0;
+}
+
+@end /* iCal3Tool */
+
+int main(int argc, char **argv, char **env)  {
+  NSAutoreleasePool *pool;
+  iCal3Tool *tool;
+  int rc;
+
+#if LIB_FOUNDATION_LIBRARY  
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  if ((tool = [[iCal3Tool alloc] init])) {
+    NS_DURING
+      rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]];
+    NS_HANDLER
+      abort();
+    NS_ENDHANDLER;
+    
+    [tool release];
+  }
+  else
+    rc = 1;
+  
+  [pool release];
+  return rc;
+}
diff --git a/skyrix-core/samples/imap_tool.m b/skyrix-core/samples/imap_tool.m
new file mode 100644 (file)
index 0000000..397bf3a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+
+#include "common.h"
+#include "NGImap4.h"
+
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  {
+    NSString       *login, *pwd, *host;
+    NSUserDefaults *ud;
+    NGImap4Client  *client;
+
+    ud = [NSUserDefaults standardUserDefaults];
+
+    if (!(login = [ud stringForKey:@"login"])) {
+      login = @"j";
+    }
+    if (!(pwd = [ud stringForKey:@"pwd"])) {
+      pwd = @"system";
+    }
+    if (!(host = [ud stringForKey:@"host"])) {
+      host = @"defiant";
+    }
+
+    client = [NGImap4Client clientWithHost:host];
+
+    [client login:login password:pwd];
+    NSLog(@"client %@", client);
+
+    {
+      int cnt = 0;
+      
+      while (1) {
+        NSString *action;
+        NSString *arg;
+        id       result;
+
+        action = [ud stringForKey:
+                     [NSString stringWithFormat:@"action_%d", cnt]]; 
+        arg = [ud stringForKey:
+                  [NSString stringWithFormat:@"arg_%d", cnt]];
+
+        if (![action length])
+          break;
+        
+        if ([action isEqualToString:@"select"]) {
+          result = [client select:arg];
+        }
+        else if ([action isEqualToString:@"thread"]) {
+          result = [client threadBySubject:[arg boolValue] charset:nil];
+        }
+        else if ([action isEqualToString:@"list"]) {
+          result = [client list:arg pattern:@"*"];
+        }
+        else if ([action isEqualToString:@"fetch"]) {
+          NSArray *args;
+
+          args = [arg componentsSeparatedByString:@":"];
+          result = [client fetchFrom:[[args objectAtIndex:0] intValue]
+                           to:[[args objectAtIndex:1] intValue]
+                           parts:[args subarrayWithRange:
+                                       NSMakeRange(2,[args count] - 2)]];
+        }
+        NSLog(@"action %d: %@:%@ : %@", cnt, action, arg,
+              result);
+        cnt++;
+      }
+    }
+  }
+  [pool release];
+  return 0;
+}
+
diff --git a/skyrix-core/samples/imapls.m b/skyrix-core/samples/imapls.m
new file mode 100644 (file)
index 0000000..5e6e6f2
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-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$
+
+/*
+  scan through imap folders/messages using the NGImap4FileManager
+*/
+
+#include "ImapListTool.h"
+#include "common.h"
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  ImapListTool *tool;
+  int res;
+  
+  pool = [NSAutoreleasePool new];
+#if LIB_FOUNDATION_LIBRARY  
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  tool = [[ImapListTool alloc] init];
+  res = [tool runWithArguments:
+               [[NSProcessInfo processInfo] argumentsWithoutDefaults]];
+  [tool release];
+  
+  [pool release];
+  exit(0);
+  /* static linking */
+  [NGExtensions class];
+  return 0;
+}
diff --git a/skyrix-core/samples/imapquota.m b/skyrix-core/samples/imapquota.m
new file mode 100644 (file)
index 0000000..6c03673
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+
+#import "ImapQuotaTool.h"
+#include "common.h"
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  ImapTool *tool;
+  int res = 0;
+  
+  pool = [NSAutoreleasePool new];
+  
+#if LIB_FOUNDATION_LIBRARY  
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  tool = [[ImapQuotaTool alloc] init];
+
+  {
+    NSString *str;
+
+    str = [[NSUserDefaults standardUserDefaults] objectForKey:@"path"];
+    NSLog(@"quota for path: %@", str);
+    NSLog(@"result %@", [tool getQuotaRoot:str]);
+  }  
+  [tool release];
+  
+  [pool release];
+  exit(res);
+  /* static linking */
+  [NGExtensions class];
+  return res;
+}
diff --git a/skyrix-core/samples/ldap2dsml.m b/skyrix-core/samples/ldap2dsml.m
new file mode 100644 (file)
index 0000000..7733220
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/NSObject.h>
+#import <SaxObjC/SaxXMLReader.h>
+#import <NGLdap/NGLdapAttribute.h>
+#import <NGLdap/NGLdapEntry.h>
+#import <NGLdap/NGLdapConnection.h>
+#include "common.h"
+
+@interface DSMLSaxProducer : NSObject
+{
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+}
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler;
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler;
+
+- (void)produceOnConnection:(NGLdapConnection *)_con dn:(NSString *)_dn;
+
+@end
+
+static NSString *XMLNS_DSML = @"http://wwww.dsml.org/DSML";
+
+@implementation DSMLSaxProducer
+
+- (void)dealloc {
+  [self->errorHandler   release];
+  [self->contentHandler release];
+  [super dealloc];
+}
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  ASSIGN(self->contentHandler, _handler);
+}
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  ASSIGN(self->errorHandler, _handler);
+}
+
+- (void)_produceAttribute:(NGLdapAttribute *)_attribute
+  ofEntry:(NGLdapEntry *)_entry
+{
+  SaxAttributes *attrs;
+
+  attrs = [[SaxAttributes alloc] init];
+  
+  [attrs addAttribute:@"name" uri:XMLNS_DSML rawName:@"name"
+         type:@"CDATA"
+         value:[_attribute attributeName]];
+  
+  [self->contentHandler
+       startElement:@"attr"
+       namespace:XMLNS_DSML
+       rawName:@"attr"
+       attributes:attrs];
+  
+  [attrs release]; attrs = nil;
+  
+  /* encode values */
+  {
+    NSEnumerator *values;
+    NSString *value;
+  
+    values = [_attribute stringValueEnumerator];
+    while ((value = [values nextObject])) {
+      unsigned len;
+      unichar  *chars;
+
+      if ((len = [value length]) == 0)
+        continue;
+      
+      chars = calloc(len + 1, sizeof(unichar));
+      [value getCharacters:chars];
+      
+      [self->contentHandler
+           startElement:@"value"
+           namespace:XMLNS_DSML
+           rawName:@"value"
+           attributes:nil];
+      
+      [self->contentHandler characters:chars length:len];
+      
+      if (chars) free(chars);
+      
+      [self->contentHandler
+           endElement:@"value"
+           namespace:XMLNS_DSML
+           rawName:@"value"];
+    }
+  }
+  
+  [self->contentHandler
+       endElement:@"attr"
+       namespace:XMLNS_DSML
+       rawName:@"attr"];
+}
+
+- (void)_produceObjectClassOfEntry:(NGLdapEntry *)_entry {
+  NGLdapAttribute *attr;
+
+  if ((attr = [_entry attributeWithName:@"objectclass"]) == nil)
+    return;
+  
+  [self->contentHandler
+       startElement:@"objectclass"
+       namespace:XMLNS_DSML
+       rawName:@"objectclass"
+       attributes:nil];
+  
+  /* encode values */
+  {
+    NSEnumerator *values;
+    NSString *value;
+  
+    values = [attr stringValueEnumerator];
+    while ((value = [values nextObject])) {
+      unsigned len;
+      unichar  *chars;
+
+      if ((len = [value length]) == 0)
+        continue;
+      
+      chars = calloc(len + 1, sizeof(unichar));
+      [value getCharacters:chars];
+      
+      [self->contentHandler
+           startElement:@"objectclass"
+           namespace:XMLNS_DSML
+           rawName:@"objectclass"
+           attributes:nil];
+      
+      [self->contentHandler characters:chars length:len];
+      
+      if (chars) free(chars);
+      
+      [self->contentHandler
+           endElement:@"objectclass"
+           namespace:XMLNS_DSML
+           rawName:@"objectclass"];
+    }
+  }
+  
+  [self->contentHandler
+       endElement:@"objectclass"
+       namespace:XMLNS_DSML
+       rawName:@"objectclass"];
+}
+
+- (void)_produceEntry:(NGLdapEntry *)_entry {
+  SaxAttributes *attrs;
+  NSEnumerator  *names;
+  NSString      *cname;
+  
+  attrs = [[SaxAttributes alloc] init];
+  
+  [attrs addAttribute:@"dn" uri:XMLNS_DSML rawName:@"dn"
+         type:@"CDATA"
+         value:[_entry dn]];
+  
+  [self->contentHandler
+       startElement:@"entry"
+       namespace:XMLNS_DSML
+       rawName:@"entry"
+       attributes:attrs];
+
+  [attrs release]; attrs = nil;
+
+  /* attributes */
+
+  [self _produceObjectClassOfEntry:_entry];
+  
+  names = [[_entry attributeNames] objectEnumerator];
+  while ((cname = [names nextObject])) {
+    NGLdapAttribute *attr;
+
+    if ([cname isEqualToString:@"objectclass"])
+      continue;
+    
+    if ((attr = [_entry attributeWithName:cname]))
+      [self _produceAttribute:attr ofEntry:_entry];
+  }  
+  
+  [self->contentHandler
+       endElement:@"entry"
+       namespace:XMLNS_DSML
+       rawName:@"entry"];
+}
+
+- (void)_produceEntries:(NSEnumerator *)_entries {
+  NGLdapEntry *entry;
+
+  [self->contentHandler
+       startElement:@"directory-entries"
+       namespace:XMLNS_DSML
+       rawName:@"directory-entries"
+       attributes:nil];
+  
+  while ((entry = [_entries nextObject]))
+    [self _produceEntry:entry];
+  
+  [self->contentHandler
+       endElement:@"directory-entries"
+       namespace:XMLNS_DSML
+       rawName:@"directory-entries"];
+}
+
+- (void)produceOnConnection:(NGLdapConnection *)_con dn:(NSString *)_dn {
+  [self->contentHandler startDocument];
+  [self->contentHandler startPrefixMapping:@"" uri:XMLNS_DSML];
+  
+  [self->contentHandler
+       startElement:@"dsml"
+       namespace:XMLNS_DSML
+       rawName:@"dsml"
+       attributes:nil];
+
+  [self _produceEntries:[_con flatSearchAtBaseDN:_dn
+                              qualifier:nil
+                              attributes:nil]];
+  
+  [self->contentHandler endElement:@"dsml" namespace:XMLNS_DSML rawName:@"dsml"];
+  
+  [self->contentHandler endPrefixMapping:@""];
+  [self->contentHandler endDocument];
+}
+
+@end /* DSMLSaxProducer */
+
+#import <SaxObjC/SaxDefaultHandler.h>
+
+@interface DSMLSaxOutputter : SaxDefaultHandler
+{
+  int level;
+}
+@end
+
+@implementation DSMLSaxOutputter
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attrs
+{
+  int i, count;
+  
+  level++;
+  for (i = 0; i < level; i++)
+    printf("  ");
+  printf("<dsml:%s", [_localName cString]);
+  
+  if (level <= 1) {
+    printf(" xmlns:dsml='%s'", [_ns cString]);
+  }
+
+  for (i = 0, count = [_attrs count]; i < count; i++) {
+    printf(" %s='%s'",
+           [[_attrs nameAtIndex:i] cString],
+           [[_attrs valueAtIndex:i] cString]);
+  }
+  
+  printf(">\n");
+}
+
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  int i;
+  for (i = 0; i < level; i++)
+    printf("  ");
+  printf("</dsml:%s>\n", [_localName cString]);
+  level--;
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  int i;
+  NSString *s;
+  
+  for (i = 0; i < level + 1; i++)
+    printf("  ");
+
+  s = [[NSString alloc] initWithCharacters:_chars length:_len];
+  printf("%s\n", [s cString]);
+  [s release];
+}
+
+@end /* DSMLSaxOutputter */
+
+#import <Foundation/Foundation.h>
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  NSUserDefaults   *ud;
+  NSArray          *args;
+  DSMLSaxProducer  *cpu;
+  DSMLSaxOutputter *out;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  args = [[NSProcessInfo processInfo] arguments];
+  if ([args count] < 1) {
+    NSLog(@"usage: %@ <files>", [args objectAtIndex:0]);
+    exit(1);
+  }
+  else if ([args count] == 1)
+    args = [args arrayByAddingObject:@"."];
+
+  ud = [NSUserDefaults standardUserDefaults];
+
+  cpu = [[DSMLSaxProducer alloc] init];
+  out = [[DSMLSaxOutputter alloc] init];
+  [cpu setContentHandler:out];
+  [cpu setErrorHandler:out];
+
+#if 0
+  fm = [[NGLdapFileManager alloc]
+                           initWithHostName:[ud stringForKey:@"LDAPHost"]
+                           port:0
+                           bindDN:[ud stringForKey:@"LDAPBindDN"]
+                           credentials:[ud stringForKey:@"LDAPPassword"]
+                           rootDN:[ud stringForKey:@"LDAPRootDN"]];
+  fm = [fm autorelease];
+#endif
+
+  {
+    NGLdapConnection *con;
+
+    con = [[NGLdapConnection alloc]
+                             initWithHostName:[ud stringForKey:@"LDAPHost"]
+                             port:0];
+    [con bindWithMethod:@"simple"
+         binddn:[ud stringForKey:@"LDAPBindDN"]
+         credentials:[ud stringForKey:@"LDAPPassword"]];
+    
+    [cpu produceOnConnection:con
+         dn:[ud stringForKey:@"LDAPRootDN"]];
+    
+    [con release];
+  }
+  [pool release];
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-core/samples/ldapchkpwd.m b/skyrix-core/samples/ldapchkpwd.m
new file mode 100644 (file)
index 0000000..feaaa7c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <EOControl/EOControl.h>
+#import <NGLdap/NGLdapConnection.h>
+#include "common.h"
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  NSUserDefaults *ud;
+  NSArray        *args;
+  BOOL ok = NO;
+  
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  args = [[NSProcessInfo processInfo] arguments];
+  if ([args count] < 3) {
+    NSLog(@"usage: %@ <user> <password>", [args objectAtIndex:0]);
+    exit(1);
+  }
+  
+  ud = [NSUserDefaults standardUserDefaults];
+  
+  ok = [NGLdapConnection checkPassword:[args objectAtIndex:2]
+                         ofLogin:[args objectAtIndex:1]
+                         atBaseDN:[ud stringForKey:@"LDAPRootDN"]
+                         onHost:[ud stringForKey:@"LDAPHost"]
+                         port:0];
+  if (ok)
+    printf("authenticated successfully.\n");
+  else
+    printf("did not authenticate !\n");
+  
+  [pool release];
+  
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-core/samples/ldapls.m b/skyrix-core/samples/ldapls.m
new file mode 100644 (file)
index 0000000..9ae1ce6
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <EOControl/EOControl.h>
+#include <NGLdap/NGLdapFileManager.h>
+#include "common.h"
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  NSUserDefaults *ud;
+  NSArray        *args;
+  NSFileManager  *fm;
+  unsigned i;
+  BOOL     doDeep = NO;
+
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  args = [[NSProcessInfo processInfo] arguments];
+  if ([args count] < 1) {
+    NSLog(@"usage: %@ <files>", [args objectAtIndex:0]);
+    exit(1);
+  }
+  else if ([args count] == 1)
+    args = [args arrayByAddingObject:@"."];
+  
+  ud = [NSUserDefaults standardUserDefaults];
+
+  fm = [[NGLdapFileManager alloc]
+                           initWithHostName:[ud stringForKey:@"LDAPHost"]
+                           port:0
+                           bindDN:[ud stringForKey:@"LDAPBindDN"]
+                           credentials:[ud stringForKey:@"LDAPPassword"]
+                           rootDN:[ud stringForKey:@"LDAPRootDN"]];
+  fm = [fm autorelease];
+  
+  if (fm == nil) {
+    NSLog(@"could not open LDAP connection (got no filemanager).");
+    exit(2);
+  }
+  
+  // NSLog(@"LDAP: %@", fm);
+  
+  for (i = 1; i < [args count]; i++) {
+    NSString *path;
+    BOOL     isDir;
+    
+    path = [args objectAtIndex:i];
+
+    if ([path hasPrefix:@"-r"]) {
+      doDeep = YES;
+      continue;
+    }
+    
+    if ([path hasPrefix:@"-"]) {
+      i++;
+      continue;
+    }
+    
+    if (![fm fileExistsAtPath:path isDirectory:&isDir]) {
+      NSLog(@"file/directory does not exist: %@", path);
+      continue;
+    }
+    
+    if (isDir) {
+      NSArray  *dirContents;
+      unsigned i, count;
+      NSString *mid;
+      
+      dirContents = doDeep
+        ? [fm subpathsAtPath:path]
+        : [fm directoryContentsAtPath:path];
+      
+      for (i = 0, count = [dirContents count]; i < count; i++) {
+        NSString     *cpath, *apath;
+        NSDictionary *info;
+        NSString     *owner;
+        NSString     *date;
+        
+        cpath = [dirContents objectAtIndex:i];
+        apath = [path stringByAppendingPathComponent:cpath];
+        
+        info = [fm fileAttributesAtPath:apath
+                   traverseLink:NO];
+        
+        mid = [[info objectForKey:@"NSFileIdentifier"] description];
+        if ([mid length] > 39) {
+          mid = [mid substringToIndex:37];
+          mid = [mid stringByAppendingString:@"..."];
+        }
+
+        owner = [info objectForKey:NSFileOwnerAccountName];
+        date  = [[info objectForKey:NSFileModificationDate] description];
+
+        if (owner == nil)
+          owner = @"-";
+        if (date == nil)
+          date = @"-";
+        
+        /* id uid date name */
+        printf("%-34s  %20s  %-32s %s",
+               [mid   cString],
+               [owner cString],
+               [date  cString],
+               [apath cString]);
+
+        if ([[info objectForKey:NSFileType]
+                   isEqualToString:NSFileTypeDirectory])
+          printf("/\n");
+        else
+          printf("\n");
+      }
+    }
+    else {
+      /* a file */
+      NSData   *contents;
+      NSString *s;
+      
+      if ((contents = [fm contentsAtPath:path]) == nil) {
+        NSLog(@"could not get content of record: '%@'", path);
+      }
+      else {
+        s = [[NSString alloc] initWithData:contents
+                              encoding:[NSString defaultCStringEncoding]];
+        printf("%s\n", [s cString]);
+        [s release];
+      }
+    }
+  }
+
+  [pool release];
+  
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-core/samples/mime2xml.m b/skyrix-core/samples/mime2xml.m
new file mode 100644 (file)
index 0000000..67c1c09
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  read a MIME message file and output XML ...
+*/
+
+#import "Mime2XmlTool.h"
+#include "common.h"
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  Mime2XmlTool *tool;
+  int res;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+#if LIB_FOUNDATION_LIBRARY  
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  tool = [[Mime2XmlTool alloc] init];
+  res = [tool runWithArguments:
+               [[NSProcessInfo processInfo] argumentsWithoutDefaults]];
+  [tool release];
+  
+  [pool release];
+  exit(0);
+  /* static linking */
+  [NGExtensions class];
+  return 0;
+}
diff --git a/skyrix-core/samples/parserule.m b/skyrix-core/samples/parserule.m
new file mode 100644 (file)
index 0000000..2ebb207
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGExtensions/NGRule.h>
+#include "common.h"
+
+/*
+  eg:
+
+  ./obj/parserule \
+     "a > b => a = 1; 10"           \
+     "*true* => color = 'green'; 1" \
+     "a>'b' => bool=YES; high"
+*/
+
+static int runTest(NSArray *args) {
+  NSEnumerator *e;
+  NSString *arg;
+  
+  e = [args objectEnumerator];
+  [e nextObject];
+  
+  while ((arg = [e nextObject])) {
+    NGRule *rule;
+    
+    NSLog(@"Parse: '%@' (len=%i)", arg, [arg length]);
+    
+    if ((rule = [[NGRule alloc] initWithPropertyList:arg]) == nil) {
+      NSLog(@"  parsing failed.");
+      continue;
+    }
+    NSLog(@"  Rule:        %@", rule);
+    NSLog(@"    Qualifier: %@ (class=%@)", [rule qualifier],
+          NSStringFromClass([[rule qualifier] class]));
+    NSLog(@"    Action:    %@ (class=%@)", [rule action],
+          NSStringFromClass([[rule action] class]));
+    NSLog(@"    Priority:  %i", [rule priority]);
+    [rule release];
+  }
+  return 0;
+}
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  int res;
+  
+  pool = [NSAutoreleasePool new];
+  
+#if LIB_FOUNDATION_LIBRARY  
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  res = runTest([[NSProcessInfo processInfo] argumentsWithoutDefaults]);
+  
+  [pool release];
+  exit(0);
+  /* static linking */
+  [NGExtensions class];
+  return 0;
+}
diff --git a/skyrix-core/samples/pwd-check.m b/skyrix-core/samples/pwd-check.m
new file mode 100644 (file)
index 0000000..ea0be84
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+/* pwcheck_ldap.c -- check passwords using LDAP
+ *
+ * Author: Clayton Donley <donley@cig.mot.com>
+ *         http://www.wwa.com/~donley/
+ * Version: 1.01
+ *
+ * Note: This works by finding a DN that matches an entered UID and
+ * binding to the LDAP server using this UID.  This uses clear-text
+ * passwords.  A better approach with servers that support SSL and
+ * new LDAPv3 servers that support SASL bind methods like CRAM-MD5
+ * and TSL.
+ *
+ * This version should work with both University of Michigan and Netscape
+ * LDAP libraries.  It also gets rid of the requirement for userPassword
+ * attribute readability.
+ *
+ */
+
+//#include <lber.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <lber.h>
+#include <ldap.h>
+//#include <libio.h>
+
+/* Set These to your Local Environment */
+
+#define MY_LDAP_SERVER  "imap.mdlink.de"
+#define MY_LDAP_BASEDN  "ou=people,o=mdlink.de"
+#define MY_LDAP_UIDATTR "uid"
+
+char *pwcheck(char *userid, char *password) {
+    LDAP *ld;
+    LDAPMessage *result;
+    LDAPMessage *entry;
+    char *attrs[2];
+    char filter[200]; 
+    char *dn;
+    int ldbind_res;
+    char **vals;
+
+/* If the password is NULL, reject the login...Otherwise the bind will
+   succeed as a reference bind.  Not good... */
+
+    if (strcmp(password,"") == 0)
+    {
+       return "Null Password";
+    }
+    
+/* Open the LDAP connection.  Change the second argument if your LDAP
+   server is not on port 389. */
+
+    if ((ld = ldap_open(MY_LDAP_SERVER,LDAP_PORT)) == NULL)
+    {
+       return "Init Failed";
+    }
+
+/* Bind anonymously so that you can find the DN of the appropriate user. */
+
+    if (ldap_simple_bind_s(ld,"","") != LDAP_SUCCESS)
+    {
+        ldap_unbind(ld);
+        return "Bind Failed";
+    }
+
+/* Generate a filter that will return the entry with a matching UID */
+
+    sprintf(filter,"(%s=%s)",MY_LDAP_UIDATTR,userid);
+
+/* Just return country...This doesn't actually matter, since we will
+   not read the attributes and values, only the DN */
+
+    attrs[0] = "c";
+    attrs[1] = NULL;
+
+/* Perform the search... */
+
+    if (ldap_search_s(ld,MY_LDAP_BASEDN,LDAP_SCOPE_SUBTREE,filter,attrs,1,&result)
+!= LDAP_SUCCESS)
+    {
+       ldap_unbind(ld);
+       return "Search Failed";
+    }
+
+/* If the entry count is not equal to one, either the UID was not unique or
+   there was no match */
+
+    if ((ldap_count_entries(ld,result)) != 1)
+    {
+       ldap_unbind(ld);
+       return "UserID Unknown";
+    }
+
+/* Get the first entry */
+
+    if ((entry = ldap_first_entry(ld,result)) == NULL)
+    {
+       ldap_unbind(ld);
+       return "UserID Unknown";
+    }
+
+/* Get the DN of the entry */
+
+    if ((dn = ldap_get_dn(ld,entry)) == NULL)
+    {
+       ldap_unbind(ld);
+       return "DN Not Found";
+    }
+
+/* Now bind as the DN with the password supplied earlier...
+   Successful bind means the password was correct, otherwise the
+   password is invalid. */
+
+    printf("dn: %s\npassword: %s\n", dn, password);
+    
+    if (ldap_simple_bind_s(ld,dn,password) != LDAP_SUCCESS)
+    {
+       ldap_unbind(ld);
+       return "Invalid Login or Password";
+    }
+
+    ldap_unbind(ld);
+    return "OK";
+}
+
+#include <Foundation/Foundation.h>
+#include "NGLdapConnection.h"
+
+int main(int argc, char **argv, char **env) {
+  NSArray        *args;
+  NSUserDefaults *ud;
+  char *uid, *pwd;
+
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  args = [[NSProcessInfo processInfo] arguments];
+  ud   = [NSUserDefaults standardUserDefaults];
+  
+  if (argc < 3)
+    exit(10);
+
+#if 0
+  uid = argv[1];
+  pwd = argv[2];
+  
+  printf("pwcheck('%s', '%s'): %s\n", uid, pwd,
+         pwcheck(uid, pwd));
+#else
+  
+  if ([NGLdapConnection checkPassword:[ud stringForKey:@"LDAPPassword"]
+                        ofLogin:[ud stringForKey:@"LDAPBindDN"]
+                        atBaseDN:[ud stringForKey:@"LDAPRootDN"]
+                        onHost:[ud stringForKey:@"LDAPHost"]
+                        port:0]) {
+    NSLog(@"OK: user %@ is authorized.", [ud stringForKey:@"LDAPBindDN"]);
+  }
+  else {
+    NSLog(@"FAIL: user %@ is not authorized.", [ud stringForKey:@"LDAPBindDN"]);
+  }
+  
+#endif
+  return 0;
+}
diff --git a/skyrix-core/samples/subclassing.m b/skyrix-core/samples/subclassing.m
new file mode 100644 (file)
index 0000000..4a5ca61
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <Foundation/Foundation.h>
+#include <NGExtensions/NGObjCRuntime.h>
+#include <objc/objc.h>
+
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#endif
+
+#if APPLE_RUNTIME
+#  include <objc/objc-class.h>
+#  ifndef sel_get_name
+#    define sel_get_name sel_getName
+#  endif
+#endif
+
+static void myPrint(id self, SEL _cmd, int arg) {
+  NSLog(@"%s: self=%@, _cmd=%@, arg=%i", 
+       __PRETTY_FUNCTION__,
+       self, NSStringFromSelector(_cmd), arg);
+}
+
+@interface NSObject(MyPrint)
++ (void)myPrint:(int)i;
+- (void)myPrint:(int)i;
+@end
+
+@interface TestSubclassing : NSObject
++ (void)run;
+@end
+
+@implementation TestSubclassing
+
+- (void)printPreInfo {
+  NSLog(@"mt: %s", [NSWillBecomeMultiThreadedNotification cString]);
+
+  NSLog(@"class NSObject:  size=%d", [NSObject  instanceSize]);
+  NSLog(@"class NSString:  size=%d", [NSString  instanceSize]);
+  NSLog(@"class NSRunLoop: size=%d", [NSRunLoop instanceSize]);
+}
+
+- (void)testNSObjectSubclassing {
+  Class c;
+  id    o;
+
+  /* subclass NSObject */
+  
+  c = [NSObject subclass:@"MyObject"
+                ivars:@"blah", @"@", @"blub", @"c", @"blab", @"s", nil];
+  
+  printf("MyObject is 0x%08X\n", (unsigned)c);
+  printf("MyObject name is %s\n", c->name);
+  printf("MyObject super-name is %s\n", c->super_class->name);
+  
+  NSLog(@"MyObject: %@", c);
+  o = [[c alloc] init];
+  NSLog(@"MyObject-instance: %@", o);
+  [o release]; o = nil;
+}
+
+- (void)testInstanceAddMethods {
+  Class c;
+  id    o;
+  
+  c = NSClassFromString(@"MyObject");
+  o = [[c alloc] init];
+  NSLog(@"MyObject-instance: %@", o);
+
+  NSLog(@" new instance respondsto 'myPrint:': %s",
+        [o respondsToSelector:@selector(myPrint:)] ? "yes" : "no");
+
+  NSLog(@" adding selector 'myPrint:' ...");
+  
+  [c addMethods:@selector(myPrint:), @"v@:i", myPrint, nil];
+  NSLog(@" instance respondsto 'myPrint' after add: %s",
+        [o respondsToSelector:@selector(myPrint:)] ? "yes" : "no");
+
+  NSLog(@" call 'myPrint:14':");
+  [o myPrint:14];
+  
+  [o release]; o = nil;
+}
+
+- (void)testClassAddMethods {
+  Class c;
+  
+  c = NSClassFromString(@"MyObject");
+
+  NSLog(@" class respondsto 'myPrint': %s",
+        [c respondsToSelector:@selector(myPrint:)] ? "yes" : "no");
+  
+  NSLog(@" adding selector 'myPrint:' ...");
+  [c addClassMethods:@selector(myPrint:), @"v@:i", myPrint, nil];
+  
+  NSLog(@" class respondsto 'myPrint' after add: %s",
+        [c respondsToSelector:@selector(myPrint:)] ? "yes" : "no");
+
+  NSLog(@" call 'myPrint:42':");
+  [c myPrint:42];
+}
+
+- (void)testNSRunLoopSubclassing {
+  Class c;
+  
+  c = [NSRunLoop subclass:@"MyRunLoop"
+                 ivars:@"blah", @"@", @"blub", @"c", @"blab", @"s", nil];
+
+  printf("MyRunLoop is 0x%08X\n", (unsigned int)c);
+  printf("MyRunLoop name is %s\n", c->name);
+  printf("MyRunLoop super-name is %s\n", c->super_class->name);
+  
+  NSLog(@"MyRunLoop: %@", c);
+  NSLog(@"MyRunLoop-instance: %@", [[c alloc] init]);
+  NSLog(@"MyRunLoop ivars: class=%@ all=%@",
+        [c instanceVariableNames], [c allInstanceVariableNames]);
+  NSLog(@"  signature of blub: %@",
+        [c signatureOfInstanceVariableWithName:@"blub"]);
+}
+
+- (void)run {
+  [self printPreInfo];
+  [self testNSObjectSubclassing];
+  [self testInstanceAddMethods];
+  [self testClassAddMethods];
+  [self testNSRunLoopSubclassing];
+}
+
++ (void)run {
+  [[[[self alloc] init] autorelease] run];
+}
+
+@end /* TestSubclassing */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  [TestSubclassing run];
+  
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-core/samples/test_qpdecode.m b/skyrix-core/samples/test_qpdecode.m
new file mode 100644 (file)
index 0000000..3c8a431
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  check whether the quoted printable MIME decoding works ...
+*/
+
+#include "common.h"
+
+static void test(void) {
+  static unsigned char *fields[] = {
+    "attachment; filename=\"Mappe langerp=?iso-8859-15?q?=FC=E4=F6=20Name=F6=F6=F6=201234456=2Exls?=\"",
+    "Umlaute: =?iso-8859-15?q?=FC=E4=F6?=",
+    "keine Umlaute: =?iso-8859-15?q?keine Umlaute?=",
+    "=?iso-8859-15?q?keine Umlaute?=",
+    "=?iso-8859-15?q?=FC=E4=F6?=",
+    "",
+    "hello world !",
+    "??doit??",
+    NULL
+  };
+  unsigned char *field;
+  int i;
+  
+  for (i = 0; (field = fields[i]); i++) {
+    NSData *fieldData;
+    id result;
+    
+    NSLog(@"decoding field: '%s'", field);
+    fieldData = [NSData dataWithBytes:field length:strlen(field)];
+    NSLog(@"  length: %i", [fieldData length]);
+    
+    result = [fieldData decodeQuotedPrintableValueOfMIMEHeaderField:
+                         @"content-disposition"];
+    
+    if (result == nil) {
+      NSLog(@"  got no result for field data %@ !!!", fieldData);
+    }
+    else if ([result isKindOfClass:[NSData class]]) {
+      NSLog(@"  got a data, length %i: %@", [result length], result);
+    }
+    else if ([result isKindOfClass:[NSString class]]) {
+      NSLog(@"  got a string, length %i: '%@'", [result length], result);
+    }
+    else {
+      NSLog(@"  got an unexpected object, class %@: %@",
+           NSStringFromClass([result class]), result);
+    }
+  }
+}
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  
+  pool = [NSAutoreleasePool new];
+  
+#if LIB_FOUNDATION_LIBRARY  
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  test();
+  
+  [pool release];
+  exit(0);
+  /* static linking */
+  [NGExtensions class];
+  return 0;
+}
diff --git a/skyrix-core/samples/testdirenum.m b/skyrix-core/samples/testdirenum.m
new file mode 100644 (file)
index 0000000..88cddd7
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+#import <EOControl/EOControl.h>
+#include <NGExtensions/NSFileManager+Extensions.h>
+#include <NGExtensions/NGFileFolderInfoDataSource.h>
+#include <NGExtensions/NGDirectoryEnumerator.h>
+
+@interface TestDirEnumTool : NSObject
+@end
+
+@implementation TestDirEnumTool
+
+- (void)runWithArguments:(NSArray *)args {
+  NSFileManager *fm;
+  NGDirectoryEnumerator *e;
+  NSString      *cpath;
+
+  fm = [NSFileManager defaultManager];
+  
+  e = [[NGDirectoryEnumerator alloc] initWithFileManager:fm
+                                     directoryPath:[args objectAtIndex:1]];
+
+  NSLog(@"enum: %@", e);
+  
+  while ((cpath = [e nextObject])) {
+#if 1
+    printf("%s\n", [cpath cString]);
+#else
+    NSDictionary *record;
+
+    record = [e fileAttributes];
+    {
+      /* id uid gid date name */
+      NSString *fileId;
+      NSString *owner;
+      int      gid;
+      unsigned size;
+      NSString *modDate;
+      NSString *fname;
+      NSString *ftype;
+        
+      fileId  = [[record objectForKey:NSFileIdentifier] description];
+      owner   = [record  objectForKey:NSFileOwnerAccountName];
+      gid     = [[record objectForKey:NSFileGroupOwnerAccountNumber] intValue];
+      size    = [[record  objectForKey:NSFileSize] intValue];
+      modDate = [[record objectForKey:NSFileModificationDate] description];
+      fname   = [record  objectForKey:NSFileName];
+      ftype   = [record  objectForKey:NSFileType];
+      
+      if ([ftype isEqualToString:NSFileTypeDirectory])
+        fname = [fname stringByAppendingString:@"/"];
+      else if ([ftype isEqualToString:NSFileTypeSocket])
+        fname = [fname stringByAppendingString:@"="];
+      else if ([ftype isEqualToString:NSFileTypeSymbolicLink])
+        fname = [fname stringByAppendingString:@"@"];
+        
+      //NSLog(@"record: %@", record);
+        
+      printf("%8s  %8s  %8i  %8i  %8s  %s\n",
+             [fileId cString],
+             [owner  cString],
+             gid,
+             size,
+             [modDate cString],
+             [fname cString]);
+    }
+#endif
+  }
+}
+
+@end /* TestDirEnumTool */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  NSArray *args;
+  id tool;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  args = [[NSProcessInfo processInfo] arguments];
+  if ([args count] < 1) {
+    NSLog(@"usage: %@ dir", [args objectAtIndex:0]);
+    exit(1);
+  }
+  else if ([args count] == 1)
+    args = [args arrayByAddingObject:@"."];
+  
+  tool = [[TestDirEnumTool alloc] init];
+  [tool runWithArguments:args];
+  
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-core/samples/testsock.m b/skyrix-core/samples/testsock.m
new file mode 100644 (file)
index 0000000..96cb03a
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "common.h"
+#include <NGStreams/NGStreams.h>
+#include <NGStreams/NGNet.h>
+
+@interface TestSock : NSObject
+- (void)runSMTPTest:(NSString *)sockClassName:(NSString *)host:(int)port;
+- (void)runHTTPTest:(NSString *)sockClassName:(NSString *)host:(int)port;
+- (void)runIMAP4Test:(NSString *)sockClassName:(NSString *)host:(int)port;
+@end
+
+@interface SockTest : NSObject
+{
+  id    address;
+  Class socketClass;
+
+  NGActiveSocket *socket;
+  NGCTextStream  *txt;
+}
+
++ (id)test:(NSString *)sockClassName:(NSString *)host:(int)port;
+
+@end
+
+@implementation SockTest
+
+- (id)init:(NSString *)sockClassName:(NSString *)host:(int)port {
+  if ((self = [super init])) {
+    self->address = 
+      [[NGInternetSocketAddress addressWithPort:port onHost:host] retain];
+    NSLog(@"addr: %@", self->address);
+    
+    if ((self->socketClass = NSClassFromString(sockClassName)) == Nil) {
+      [self logWithFormat:@"did not find socket class %@", sockClassName];
+      [self release];
+    }
+  }
+  return self;
+}
+
++ (id)test:(NSString *)_s:(NSString *)host:(int)port {
+  return [[[self alloc] init:_s:host:port] autorelease];
+}
+
+- (void)dealloc {
+  [self->address release];
+  [super dealloc];
+}
+
+/* tests */
+
+- (void)runSMTPTest {
+  [self->txt writeString:@"HELO imap\r\n"];
+  NSLog(@"read: %@", [self->txt readLineAsString]);
+}
+
+- (void)_readHTTP {
+  NSString *s;
+  BOOL isRespLine = YES;
+  BOOL isHeader   = NO;
+  BOOL hasContent = YES;
+
+  while ((s = [txt readLineAsString])) {
+    if (isRespLine) {
+      isRespLine = NO;
+      isHeader   = YES;
+      NSLog(@"SR: %@", s);
+    }
+    else if (isHeader) {
+      if ([s length] == 0) {
+       isHeader = NO;
+       if (!hasContent) break;
+      }
+      else {
+       NSLog(@"SH: %@", s);
+       
+       s = [s lowercaseString];
+       if ([s hasPrefix:@"content-length:"]) {
+         s = [s substringFromIndex:[@"content-length:" length]];
+         s = [s stringByTrimmingSpaces];
+         //NSLog(@"content-length: %i", [s intValue]);
+         hasContent = [s intValue] != 0;
+       }
+      }
+    }
+    else {
+      NSLog(@"SB: %@ (len=%u)", s, [s length]);
+    }
+  }
+}
+
+- (void)runHTTPTest {
+  NSString *s;
+  
+  if ((s = [[NSUserDefaults standardUserDefaults] stringForKey:@"url"])==nil)
+    s = @"/";
+  
+  NSLog(@"C: GET %@ HTTP/1.0", s);
+  [txt writeFormat:@"GET %@ HTTP/1.0\r\n\r\n", s];
+  
+  [self _readHTTP];
+}
+
+- (void)runXmlRpcTest {
+  NSString *s;
+  
+  if ((s = [[NSUserDefaults standardUserDefaults] stringForKey:@"url"])==nil)
+    s = @"/RPC2";
+  
+  NSLog(@"C: GET %@ HTTP/1.0", s);
+  [txt writeFormat:@"POST %@ HTTP/1.0\r\n", s];
+  [txt writeString:@"content-type: text/xml\r\n"];
+  [txt writeString:@"\r\n"];
+  [txt writeString:@"<?xml version=\"1.0\"?>\n"];
+  [txt writeString:@"<methodCall>\n"];
+  [txt writeString:@"<methodName>system.listMethods</methodName>\n"];
+  [txt writeString:@"<params>\n"];
+  [txt writeString:@"</params>\n"];
+  [txt writeString:@"</methodCall>\n"];
+  
+  [self _readHTTP];
+}
+
+- (void)runIMAP4Test {
+  NSString *s;
+  
+  NSLog(@"reading IMAP server hello ...");
+  s = [self->txt readLineAsString];
+  NSLog(@"S: %@", s);
+}
+
+/* common stuff */
+
+- (void)setUp {
+  self->socket = 
+    [[self->socketClass socketConnectedToAddress:self->address] retain];
+  self->txt = 
+    [[NGCTextStream textStreamWithSource:self->socket] retain];
+}
+- (void)tearDown {
+  [self->txt    close];
+  [self->txt    release];
+  [self->socket release];
+}
+
+- (void)handleException:(NSException *)_e {
+  [self logWithFormat:@"FAIL: %@", _e];
+}
+
+- (void)runTest:(NSString *)_name {
+  NSAutoreleasePool *pool;
+  SEL s;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  NSLog(@"-------------------- RUN: %@", _name);
+  
+  s = NSSelectorFromString([NSString stringWithFormat:@"run%@Test", _name]);
+  
+  [self setUp];
+  
+  NS_DURING
+    [self performSelector:s];
+  NS_HANDLER
+    [self handleException:localException];
+  NS_ENDHANDLER;
+
+  NS_DURING
+    [self tearDown];
+  NS_HANDLER
+    ;
+  NS_ENDHANDLER;
+  
+  NSLog(@"-------------------- DONE: %@\n", _name);
+  [pool release];
+}
+
+@end /* SockTest */
+
+
+@implementation TestSock
+
+- (void)runSMTPTest:(NSString *)sockClassName:(NSString *)host:(int)port {
+  [[SockTest test:sockClassName:host:port] runTest:@"SMTP"];
+}
+
+- (void)runHTTPTest:(NSString *)sockClassName:(NSString *)host:(int)port {
+  [[SockTest test:sockClassName:host:port] runTest:@"HTTP"];
+}
+
+- (void)runIMAP4Test:(NSString *)sockClassName:(NSString *)host:(int)port {
+  [[SockTest test:sockClassName:host:port] runTest:@"IMAP4"];
+}
+
+@end /* TestSock */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  TestSock *sock;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  sock = [[TestSock alloc] init];
+  
+#if 0  
+  [sock runSMTPTest:@"NGActiveSocket":@"imap.mdlink.de":25];
+  [sock runSMTPTest:@"NGActiveSocket":@"skyrix.in.skyrix.com":25];
+
+  [sock runHTTPTest:@"NGActiveSocket":@"www.skyrix.de":80];
+  [sock runHTTPTest:@"NGActiveSSLSocket":@"skyrix.in.skyrix.com":443];
+
+  [sock runIMAP4Test:@"NGActiveSSLSocket":@"skyrix.in.skyrix.com":993];
+
+  [sock runHTTPTest:@"NGActiveSSLSocket":@"localhost":505];
+#endif
+  
+  [[SockTest test:@"NGActiveSSLSocket":@"localhost":505] runTest:@"XmlRpc"];
+  
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-core/samples/testurl.m b/skyrix-core/samples/testurl.m
new file mode 100644 (file)
index 0000000..f5a63e3
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+  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$
+
+#import <Foundation/NSObject.h>
+#include <NGExtensions/NSURL+misc.h>
+
+@class NSArray;
+
+@interface TestURL : NSObject
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
+
+#include "common.h"
+
+@implementation TestURL
+
+- (void)testUrlSlashSuffix:(NSString *)_url {
+  NSURL *url;
+  
+  url  = [NSURL URLWithString:_url];
+  [self logWithFormat:@"Url  URL:  %@", url];
+  [self logWithFormat:@"     Abs:  %@", [url absoluteString]];
+  [self logWithFormat:@"     Path: %@", [url path]];
+  [self logWithFormat:@"  RelPath: %@", [url relativePath]];
+
+  if ([[url absoluteString] hasSuffix:@"/"]
+      != [[url path] hasSuffix:@"/"]) {
+    [self logWithFormat:@"ERROR: path suffix different from URL suffix!"];
+  }
+  else
+    [self logWithFormat:@"OK: suffix seems to match."];
+}
+
+- (void)testStringValueRelativeToURL:(NSString *)_url base:(NSString *)_base 
+  expect:(NSString *)_result
+{
+  NSURL    *url, *base;
+  NSString *result;
+
+  base = [NSURL URLWithString:_base];
+  [self logWithFormat:@"Base URL:  %@", base];
+  [self logWithFormat:@"     Abs:  %@", [base absoluteString]];
+  [self logWithFormat:@"     Path: %@", [base path]];
+  
+  url  = [NSURL URLWithString:_url];
+  [self logWithFormat:@"Url  URL:  %@", url];
+  [self logWithFormat:@"     Abs:  %@", [url absoluteString]];
+  [self logWithFormat:@"     Path: %@", [url path]];
+  
+  result = [url stringValueRelativeToURL:base];
+  [self logWithFormat:@"Relative: %@", result];
+
+  if ([result isEqualToString:_result])
+    [self logWithFormat:@"OK matches expected result '%@'", _result];
+  else
+    [self logWithFormat:@"ERROR: does not meet expectation: '%@'", _result];
+}
+
+- (int)runWithArguments:(NSArray *)_args {
+  [self testUrlSlashSuffix:@"http://localhost:20000/dbd.woa/so/localhost/"];
+  
+  [self testStringValueRelativeToURL:
+         @"http://localhost:20000/dbd.woa/so/localhost/Databases/OGo"
+       base:@"http://localhost:20000/dbd.woa/so/localhost/"
+       expect:@"Databases/OGo"];
+  return 0;
+}
+
+@end /* TestURL */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  TestURL *tool;
+  int rc;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  tool = [[TestURL alloc] init];
+  rc = [tool runWithArguments:
+              [[NSProcessInfo processInfo] argumentsWithoutDefaults]];
+  [tool release];
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-sope/COPYING b/skyrix-sope/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/COPYRIGHT b/skyrix-sope/COPYRIGHT
new file mode 100644 (file)
index 0000000..8e76449
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2004 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-sope/ChangeLog b/skyrix-sope/ChangeLog
new file mode 100644 (file)
index 0000000..1dcd6aa
--- /dev/null
@@ -0,0 +1,83 @@
+2004-07-21  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: fixed an incorrect framework search path.
+
+2004-07-21  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * README-OSX.txt: Major overhaul for build description, especially the
+         Xcode section.
+
+       * SOPE.xcode: added WOKeyPathAssociationSystemKVC.m and
+         NSUserDefaults+KVC.m in NGObjWeb/Associations to the Xcode build
+         which were previously missing.
+
+2004-07-16  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: added 'Wrapper' build style and 'Wrapper Contents' target.
+         Use these to build the frameworks in an appropriate form to have them
+         embedded in an applications app wrapper's 'Frameworks' folder.
+
+2004-06-24  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: removed WOPopUpButton.h.
+
+2004-05-16  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: added new bundle products, SoCore.sxp and SoOFS.sxp -
+         both seemed to get lost in the transition from Project Builder to
+         Xcode. Please note that the names of the two products bear the (SXP)
+         specifier which is unfortunately necessary since there already is an
+         SoOFS target and Xcode seriously gets confused by this, despite the
+         fact that the product types are different.
+
+2004-05-07  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: added new WOMessage+Validation.m
+
+2004-04-28  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: added new WOXML framework for legacy applications.
+
+       * README-OSX.txt: updated prebinding info list for new WOXML target.
+
+2004-04-19  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: added WEPageLink in WEExtensions,
+         WOHyperlink cluster in NGObjWeb.
+
+2004-04-02  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: Added WETableView group and accompanied files in
+         WEExtensions.
+
+2004-03-31  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: added WERedirect.m to WEExtensions, added WORedirect.[hm]
+         and WOExtensions.h to WOExtensions.
+
+2004-03-24  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: added WEQualifierConditional in WEExtensions.
+         Also, added -headerpad_max_install_names link option where
+         appropriate.
+
+2004-03-08  Helge Hess  <helge@mac.in.skyrix.com>
+
+       * SOPE.xcode: added new source files in WebDAV
+
+       * README-OSX.txt: added some build notes
+
+2004-02-26  Helge Hess  <helge.hess@opengroupware.org>
+
+       * added WOResourceURLAssociation to Xcode project
+
+2004-02-10  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SOPE.xcode: Updated prebinding information according to
+         README-OSX.txt. Also, added Foundation.framework explicitly
+         to all subprojects.
+
+       * README-OSX.txt: New README currently describing prebinding
+         information for Mac OS X.
+
+       * ChangeLog: created.
diff --git a/skyrix-sope/GNUmakefile b/skyrix-sope/GNUmakefile
new file mode 100644 (file)
index 0000000..3dbef8b
--- /dev/null
@@ -0,0 +1,17 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECTS += \
+       NGScripting     \
+       NGJavaScript    \
+       NGObjWeb        \
+       SxComponents    \
+       WEExtensions    \
+       WOExtensions    \
+       NGObjDOM        \
+       WOXML           \
+
+-include $(GNUSTEP_MAKEFILES)/GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/aggregate.make
+-include $(GNUSTEP_MAKEFILES)/GNUmakefile.postamble
diff --git a/skyrix-sope/NGJavaScript/.cvsignore b/skyrix-sope/NGJavaScript/.cvsignore
new file mode 100644 (file)
index 0000000..d4a0b7c
--- /dev/null
@@ -0,0 +1,3 @@
+SpiderMonkey.sse
+shared_debug_obj
+strace.out
diff --git a/skyrix-sope/NGJavaScript/COPYING b/skyrix-sope/NGJavaScript/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/NGJavaScript/ChangeLog b/skyrix-sope/NGJavaScript/ChangeLog
new file mode 100644 (file)
index 0000000..1fe2672
--- /dev/null
@@ -0,0 +1,280 @@
+2004-08-17  Helge Hess  <helge.hess@opengroupware.org>
+
+       * Core+JS.subproj/NSNumber+JS.m: check whether bool NSNumbers are 
+         singletons on MacOSX - they are, so we could remove a compilation
+         warning (v4.2.30)
+
+2004-07-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * Core+JS.subproj/EODataSource+JS.m: fixed a gcc 3.4 warning (v4.2.29)
+
+2004-06-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * Core+JS.subproj/GNUmakefile (CoreJS_HEADER_FILES_DIR): added some
+         include pathes to allow "in-place" compilation of SOPE (v4.2.28)
+
+2004-06-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGJavaScriptObject.m: fixed some gcc 3.4 warning (v4.2.27)
+
+2004-06-10  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * GNUmakefile.preamble: added prebinding (v4.2.26)
+       
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile, GNUmakefile.preamble: added support for building
+         with GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.25)
+
+2004-03-03  Helge Hess  <helge.hess@opengroupware.org>
+
+       * Core+JS.subproj/EODataSource+JS.m: fixed not to use deprecated
+         EOControl API (v4.2.24)
+
+2003-12-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile (BUNDLE_INSTALL_DIR): use GNUSTEP_INSTALLATION_DIR
+         (v4.2.23)
+
+2003-11-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGJavaScriptObjectMappingContext.m: added minor patch provided by
+         chunsj@embian.com to use the gstep-base behaviour functions when
+         compiling for gstep-base (v4.2.22)
+
+2003-11-18  Helge Hess  <helge@groove.local>
+
+       * Core+JS.subproj/EODataSource+JS.m: replaces some retain macros with 
+         methods (v4.2.21)
+
+2003-10-14  Helge Hess  <helge@groove.local.>
+
+       * NGJavaScriptObjectHandler.m, NGJavaScriptObjCClassInfo.m, 
+         NGJavaScriptShadow.m: use proper ObjC runtime functions on
+         MacOSX (v4.2.20)
+
+2003-10-13  Helge Hess  <helge@opengroupware.org>
+
+       * EODataSource+JS.m, common.h: fixed compilation on MacOSX (v4.2.19)
+
+2003-09-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGJavaScriptContext.m: returned a value in a void function (v4.2.18)
+
+2003-09-06 Helge Hess  <helge.hess@skyrix.com>
+
+        * fixed some warnings on MacOSX (v4.2.17)
+
+2003-07-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * applied GNUstep patches provided by Filip Van Raemdonck for improved
+         compilation with gstep-base (v4.2.16)
+
+2003-06-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.15
+       
+       * NGJavaScriptObjectMappingContext.m: added even more logging
+
+       * Core+JS.subproj/NSString+JS.m: improved performance of ObjC->JS
+         conversion by using -getCString: instead of -cString
+
+2003-06-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.14
+       
+       * tests/JSBridgeTests.m: added a test for the string slice problem
+         (works in the test though), the dict test fails
+
+       * NGJavaScriptObjectHandler.m, NGJavaScriptShadow: print logs if 
+         errors occure during attaching of funcs
+
+       * NGJavaScriptObjCClassInfo.m: improved logging (print funcname)
+
+       * NGJavaScriptLanguage.m: load standard classes into JS-Context if a 
+         new mapping context is created
+
+       * NGJavaScriptContext.m: added NSLogs if loading of standard classes
+         fails
+
+       * added a lot of logging and notes to locate a weird bug (see TODO)
+         (v4.2.13)
+
+2003-05-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGJavaScriptObjectMappingContext.m: added a fix for MacOSX (v4.2.12)
+
+Mon Dec 23 15:42:16 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * Core+JS.subproj: includes ../common.h instead of common.h (v4.2.11)
+
+2002-12-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved to skyrix-sope-42 (v4.2.10)
+
+2002-10-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGJavaScriptArray.m: improved NSArray compatibility, added
+         - containsObject: and -subarrayWithRange: (v4.2.9)
+
+2002-08-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved NGJavaScriptError to separate file, fixed some gcc 3.2 warnings
+
+2002-08-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.7
+
+       * NGJavaScriptObject.h: added some declarations for NSJavaScriptArray
+       
+       * NGJavaScriptObject.m: 
+         - the JavaScript class is returned by a method now, so we can create
+           subclasses that override the class
+         - splitted NSCoding in a JavaScript encoding part and in an ObjC
+           encoding part. This way subclasses can decide which JS things to
+           archive (eg NSJavaScriptArray only archives values stored at
+           array indices, no properties)
+         - added "greedy archiving" which also archives parent and prototype
+           objects
+         - very much improved -objectForKey: etc, they worked for string
+           keys only. They still only work for string keys, but are prepared
+           for more ;-)
+       
+       * NGJavaScriptContext.m: improved JavaScript error handling (eg by
+         adding the NGJavaScriptError class)
+       
+       * NGJavaScriptArray.m:
+         - create array objects using JS_NewArrayObject instead of
+           JS_NewObject
+         - properly return the js_ArrayClass (added -jsObjectClass method)
+         - added -addObject: method to simulate NSMutableArray
+         - improved NSCoding (index based encoding/decoding)
+
+2002-08-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * testjs.m: cleanup test program, prepared for inclusion in OCUnit
+         like environments
+       
+       * v4.2.6 (major feature: first working NSCoding support)
+       
+       * Core+JS.subproj/NSNumber+JS.m: assume that YES/NO NSNumbers are
+         implemented as singletons in Foundation to map JS boolean values
+       
+       * NGJavaScriptShadow.m: added NSCoding
+
+       * NGJavaScriptObjectMappingContext: added some docu, changed back
+         to use _js_parentObject instead of -parentObject (sigh), properly
+         map JS functions to NGJavaScriptFunction objects
+
+       * NGJavaScriptObjectHandler: added some docu, initialize some 
+         local vars so that gcc doesn't complain
+
+       * NGJavaScriptObject: added new methods: -allKeys, -allValues,
+         -convertToNSDictionary, fixed NSCoding, improved -description
+
+       * NGJavaScriptObjCClassInfo: added some docu, cleanup of property
+         and function "apply" code
+
+       * NGJavaScriptFunction: NGJavaScriptFunction now inherits from
+         NGJavaScriptObject, fixed the ivars etc to match this fact
+
+2002-08-20  Helge Hess  <helge.hess@skyrix.com>
+       
+       * started implementation of NSCoding (v4.2.5)
+
+       * NGJavaScriptObjectMappingContext.m: use -parentObject instead of
+         -_js_parentObject
+
+2002-08-05  Helge Hess  <helge.hess@skyrix.com>
+
+       * Core+JS.subproj/NSDate+JS.m: added JavaScript function to create
+         NSCalendarDate objects ...
+
+2002-06-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGJavaScriptObjectHandler.m: fixed serious bug with incorrectly
+         defined JavaScript class flags
+
+Mon Jun 10 13:04:19 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved NGScripting to separate library
+
+2002-06-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * heavy reworks towards a pluggable scripting system
+
+Mon Dec 17 15:22:59 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGFileManager+JS.m: added trash() function for moving files to
+         trash
+
+Tue Nov 27 16:42:20 2001  Bjoern Stierand <bjoern@skyrix.com>
+
+       * NGFileManager+JS.m: fixed wrong destination path in _jsfunc_mv()
+
+Tue Sep 25 12:55:53 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * added bindings for NGFileManager ...
+
+       * NGJavaScriptArray.m: added -insertObject:atIndex:
+
+Fri Jul 13 17:19:18 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGJavaScriptObjCClassInfo.m: added support for JSPROP_SHARED instead
+         of JSPROP_NOSLOT
+
+Thu Jun 14 12:51:26 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSUserDefaults+JS.m: added JS docu
+
+Sat May  5 17:04:24 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSArray+JS.m: auto-transform NSArray's into JavaScript arrays (note 
+         that mutable array's are also transformed into a copy, too !!!)
+
+Wed May  2 17:06:04 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * disable abort's in non-debug mode
+
+Mon Apr 30 21:31:18 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGJavaScriptObjectHandler.m, NGJavaScriptShadow.m: better exception
+         handling
+
+Fri Apr 27 14:27:11 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * EODataSource+JS.m: improved error handling
+
+Thu Apr  5 15:40:11 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * EODataSource+JS.m ([EODataSource -_updateFetchSpecWithEntityName:qualifier:sortOrderings:]): 
+         added support for setting/getting hints
+
+Fri Mar  9 12:06:08 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NSNumber+JS.m: convert NSBoolNumber to JS bools
+
+Mon Mar  5 19:43:18 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGJavaScriptArray: add NSMutableArray as behaviour
+
+Thu Feb 22 18:56:47 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * detect JavaScript construction calls (eg 'new Blah()')
+
+Mon Feb 12 18:28:10 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGJavaScriptObjectHandler.m: fixed remove-root bug
+
+Mon Jan  8 16:22:49 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * fixed compilation
+
+Fri Oct 13 17:16:42 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * use hashtable to map ObjC context wrapper
+
+Tue Sep 12 18:51:47 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * created ChangeLog, modified to use MOF3 internal JS library
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/.cvsignore b/skyrix-sope/NGJavaScript/Core+JS.subproj/.cvsignore
new file mode 100644 (file)
index 0000000..6a53797
--- /dev/null
@@ -0,0 +1,2 @@
+Resources
+shared_debug_obj
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/EODataSource+JS.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/EODataSource+JS.m
new file mode 100644 (file)
index 0000000..bd325cc
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <EOControl/EOControl.h>
+#include <NGExtensions/EODataSource+NGExtensions.h>
+#include <NGExtensions/NSNull+misc.h>
+#include "../common.h"
+
+/*
+  EODataSource JavaScript object
+  
+  Methods
+    bool     setQualifier(string [,args...]) // Format: EOQualifier Format !
+    String   getQualifier()
+    bool     setEntity(string)
+    String   getEntity()
+    bool     setSortOrdering(string)  // Format: 'name' oder '-name'
+    String   getSortOrdering()
+    bool     setHint(string, value)
+    Object   getHint(string)
+    
+    Array    fetchObjects([qual][,orderings][,grouping])
+    
+    Document createObject()
+    bool     updateObject(document)
+    bool     insertObject(document)
+    bool     deleteObject(document)
+*/
+
+@implementation EODataSource(SkyJSDataSourceBehaviour)
+
+static id null = nil;
+
+static inline void _ensureNull(void) {
+  if (null == nil)
+    null = [[NSNull null] retain];
+}
+
+/* methods */
+
+- (void)_updateFetchSpecWithEntityName:(NSString *)_ename
+  qualifier:(EOQualifier *)_qual
+  sortOrderings:(NSArray *)_so
+{
+  EOFetchSpecification *fspec;
+
+  if (_ename == nil && _qual == nil && _so == nil)
+    /* nothing to update .. */
+    return;
+  
+  _ensureNull();
+  
+  if ((fspec = [self fetchSpecification]) == nil) {
+    if (_qual  == null) _qual  = nil;
+    if (_so    == null) _so    = nil;
+    if (_ename == null) _ename = nil;
+    
+    fspec = [[EOFetchSpecification alloc]
+                                   initWithEntityName:_ename
+                                   qualifier:_qual
+                                   sortOrderings:_so
+                                   usesDistinct:YES isDeep:NO hints:nil];
+    fspec = [fspec autorelease];
+    
+    [self setFetchSpecification:fspec];
+  }
+  else {
+    fspec = [[fspec copy] autorelease];
+    
+    if (_qual) {
+      if (_qual == null) _qual = nil;
+      [fspec setQualifier:_qual];
+    }
+    if (_ename) {
+      if (_ename == null) _ename = nil;
+      [fspec setEntityName:_ename];
+    }
+    if (_so) {
+      if (_so == null) _so = nil;
+      [fspec setSortOrderings:_so];
+    }
+    
+    [self setFetchSpecification:fspec];
+  }
+}
+
+- (id)_jsfunc_setEntity:(NSArray *)_args {
+  unsigned count;
+  NSString *entityName;
+
+  if ((count = [_args count]) == 0) {
+#if DEBUG && 0
+    NSLog(@"%s: missing qualifier argument ..", __PRETTY_FUNCTION__);
+#endif
+    entityName = nil;
+  }
+  else {
+    entityName = [[_args objectAtIndex:0] stringValue];
+  }
+
+  if (entityName == nil) entityName = null;
+  
+  [self _updateFetchSpecWithEntityName:entityName
+        qualifier:nil
+        sortOrderings:nil];
+  
+  return [NSNumber numberWithBool:YES];
+}
+- (id)_jsfunc_getEntity:(NSArray *)_args {
+  return [[self fetchSpecification] entityName];
+}
+
+- (id)_jsfunc_setSortOrdering:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) {
+    [self _updateFetchSpecWithEntityName:nil
+          qualifier:nil
+          sortOrderings:[NSArray array]];
+    
+    return [NSNumber numberWithBool:YES];
+  }
+  else if (count == 1) {
+    NSString       *key;
+    SEL            selector;
+    EOSortOrdering *ordering;
+
+    selector = EOCompareAscending;
+    
+    key = [[_args objectAtIndex:0] stringValue];
+    if ([key hasPrefix:@"-"]) {
+      selector = EOCompareDescending;
+      key = [key substringFromIndex:1];
+    }
+    
+    ordering = [EOSortOrdering sortOrderingWithKey:key selector:selector];
+    
+    [self _updateFetchSpecWithEntityName:nil
+          qualifier:nil
+          sortOrderings:[NSArray arrayWithObject:ordering]];
+    
+    return [NSNumber numberWithBool:YES];
+  }
+  
+  return [NSNumber numberWithBool:NO];
+}
+- (id)_jsfunc_getSortOrdering:(NSArray *)_args {
+  NSArray        *orderings;
+  unsigned       count;
+  EOSortOrdering *ordering;
+  
+  orderings = [[self fetchSpecification] sortOrderings];
+  if ((count = [orderings count]) == 0)
+    return nil;
+  
+  ordering = [orderings objectAtIndex:0];
+  
+#if APPLE_RUNTIME || NeXT_RUNTIME
+  if ([ordering selector] == EOCompareDescending)
+    return [@"-" stringByAppendingString:[ordering key]];
+  if ([ordering selector] == EOCompareDescending)
+    return [ordering key];
+#else
+  if (sel_eq([ordering selector], EOCompareDescending))
+    return [@"-" stringByAppendingString:[ordering key]];
+  if (sel_eq([ordering selector], EOCompareDescending))
+    return [ordering key];
+#endif
+  return @"<unknown>";
+}
+
+- (id)_jsfunc_setQualifier:(NSArray *)_args {
+  EOFetchSpecification *fspec;
+  unsigned    count;
+  EOQualifier *q;
+  NSArray     *args;
+
+  _ensureNull();
+  
+  fspec = [self fetchSpecification];
+  
+  if ((count = [_args count]) == 0) {
+#if DEBUG && 0
+    NSLog(@"%s: missing qualifier argument ..", __PRETTY_FUNCTION__);
+#endif
+    q = nil;
+  }
+  else {
+    id qq;
+    
+    qq = [_args objectAtIndex:0];
+    
+    args = (count > 1)
+      ? [_args subarrayWithRange:NSMakeRange(1, count - 1)]
+      : [NSArray array];
+    
+    if ([qq isKindOfClass:[EOQualifier class]]) {
+      q = qq;
+    }
+    else if ([[qq stringValue] length] == 0) {
+      q = nil;
+    }
+    else {
+      q = [EOQualifier qualifierWithQualifierFormat:[qq stringValue]
+                       arguments:args];
+      
+#if DEBUG
+      if (q == nil) {
+        NSLog(@"%s: couldn't parse qualifier '%@' ..",
+              __PRETTY_FUNCTION__, qq);
+        return [NSNumber numberWithBool:NO];
+      }
+#endif
+    }
+  }
+  
+  if (q == nil) q = null;
+  
+  [self _updateFetchSpecWithEntityName:nil qualifier:q sortOrderings:nil];
+  
+  return [NSNumber numberWithBool:YES];
+}
+- (id)_jsfunc_getQualifier:(NSArray *)_args {
+  return [(id)[[self fetchSpecification] qualifier] stringValue];
+}
+
+- (id)_jsfunc_setHint:(NSArray *)_args {
+  unsigned count;
+  NSString *key;
+  id       value;
+  EOFetchSpecification *fspec;
+  NSMutableDictionary  *hints;
+  
+  if ((count = [_args count]) == 0)
+    return [NSNumber numberWithBool:NO];
+  if (count == 1)
+    return [NSNumber numberWithBool:NO];
+
+  key   = [[_args objectAtIndex:0] stringValue];
+  value = [_args objectAtIndex:1];
+
+  if (key == nil)
+    return [NSNumber numberWithBool:NO];
+  
+  if ((fspec = [[self fetchSpecification] copy]) == nil) {
+    fspec = [[EOFetchSpecification alloc]
+                                   initWithEntityName:nil
+                                   qualifier:nil
+                                   sortOrderings:nil
+                                   usesDistinct:YES isDeep:NO hints:nil];
+  }
+  fspec = [fspec autorelease];
+  
+  hints = [[fspec hints] mutableCopy];
+  if (hints == nil)
+    hints = [[NSMutableDictionary alloc] initWithCapacity:4];
+  
+  if (![value isNotNull]) {
+    /* delete hint */
+    [hints removeObjectForKey:key];
+  }
+  else {
+    [hints setObject:value forKey:key];
+  }
+  
+  [fspec setHints:hints];
+  [hints release]; hints = nil;
+  
+  [self setFetchSpecification:fspec];
+  
+  return [NSNumber numberWithBool:YES];
+}
+- (id)_jsfunc_getHint:(NSArray *)_args {
+  unsigned     count;
+  NSDictionary *hints;
+  
+  if ((count = [_args count]) == 0)
+    return nil;
+  
+  hints = [[self fetchSpecification] hints];
+  return [hints objectForKey:[[_args objectAtIndex:0] stringValue]];
+}
+
+/* query operation */
+
+- (void)logException:(NSException *)_exception {
+  NSLog(@"%s: exception: %@", __PRETTY_FUNCTION__, _exception);
+}
+
+- (id)_jsfunc_fetchObjects:(NSArray *)_args {
+  EOFetchSpecification *fspec;
+  unsigned count;
+  id qualifier     = nil;
+  id sortOrderings = nil;
+  id groupings     = nil;
+  id results;
+  
+  count = [_args count];
+  fspec = nil;
+
+  NS_DURING {
+    if (count > 0) {
+      if ((fspec = [self fetchSpecification]) == nil) {
+        fspec = [EOFetchSpecification fetchSpecificationWithEntityName:nil
+                                      qualifier:nil
+                                      sortOrderings:nil];
+      }
+      else
+        fspec = [[fspec copy] autorelease];
+    }
+    
+    if (count > 0) {
+      NSString *qs;
+      
+      qualifier = [_args objectAtIndex:0];
+      if (![qualifier isKindOfClass:[EOQualifier class]]) {
+        qs = [qualifier stringValue];
+        qualifier = [EOQualifier qualifierWithQualifierFormat:qs];
+  #if DEBUG && 0
+        NSLog(@"%s: made q %@ for string '%@'",
+              __PRETTY_FUNCTION__, qualifier, qs);
+  #endif
+      }
+      
+      [fspec setQualifier:qualifier];
+    }
+    
+    if (count > 1) {
+      sortOrderings = [_args objectAtIndex:1];
+      [fspec setSortOrderings:sortOrderings];
+    }
+    
+    if (count > 2) {
+      groupings = [_args objectAtIndex:2];
+      // [fspec setGroupings:..];
+    }
+    
+    if (fspec)
+      [self setFetchSpecification:fspec];
+    
+    results = [self fetchObjects];
+  }
+  NS_HANDLER {
+    *(&results) = nil;
+    [self logException:localException];
+  }
+  NS_ENDHANDLER;
+  
+  return results;
+}
+
+/* modification operations */
+
+- (id)_jsfunc_createObject:(NSArray *)_args {
+  id obj;
+
+  NS_DURING
+    obj = [self createObject];
+  NS_HANDLER {
+    *(&obj) = nil;
+    [self logException:localException];
+  }
+  NS_ENDHANDLER;
+  
+  return obj;
+}
+
+- (id)_jsfunc_insertObject:(NSArray *)_args {
+  unsigned     count;
+  NSEnumerator *e;
+  id   obj;
+  BOOL ok;
+  
+  if ((count = [_args count]) == 0)
+    return [NSNumber numberWithBool:YES];
+
+  e = [_args objectEnumerator];
+  ok = YES;
+  while ((obj = [e nextObject]) && ok) {
+    NS_DURING
+      [self insertObject:obj];
+    NS_HANDLER {
+      ok = NO;
+      [self logException:localException];
+    }
+    NS_ENDHANDLER;
+  }
+  
+  return [NSNumber numberWithBool:ok];
+}
+
+- (id)_jsfunc_updateObject:(NSArray *)_args {
+  unsigned     count;
+  NSEnumerator *e;
+  id   obj;
+  BOOL ok;
+  
+  if ((count = [_args count]) == 0)
+    return [NSNumber numberWithBool:YES];
+
+  e = [_args objectEnumerator];
+  ok = YES;
+  while ((obj = [e nextObject]) && ok) {
+    NS_DURING
+      [self updateObject:obj];
+    NS_HANDLER
+      ok = NO;
+    NS_ENDHANDLER;
+  }
+  return [NSNumber numberWithBool:ok];
+}
+
+- (id)_jsfunc_deleteObject:(NSArray *)_args {
+  unsigned     count;
+  NSEnumerator *e;
+  id   obj;
+  BOOL ok;
+  
+  if ((count = [_args count]) == 0)
+    return [NSNumber numberWithBool:YES];
+
+  e = [_args objectEnumerator];
+  ok = YES;
+  while ((obj = [e nextObject]) && ok) {
+    NS_DURING
+      [self deleteObject:obj];
+    NS_HANDLER {
+      ok = NO;
+      [self logException:localException];
+    }
+    NS_ENDHANDLER;
+  }
+  return [NSNumber numberWithBool:ok];
+}
+
+@end /* EOControl(SkyJSDataSourceBehaviour) */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/EOJavaScriptGrouping.h b/skyrix-sope/NGJavaScript/Core+JS.subproj/EOJavaScriptGrouping.h
new file mode 100644 (file)
index 0000000..ddba6a8
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef _EOJavaScriptGrouping_h__
+#define _EOJavaScriptGrouping_h__
+
+#include <NGExtensions/EOGrouping.h>
+
+@class NSString;
+@class EOJavaScript;
+
+@interface EOJavaScriptGrouping : EOGrouping
+{
+  NSString *script;
+  NSString *language;
+  NSString *name;
+}
+
+- (id)initWithJavaScript:(NSString *)_script name:(NSString *)_name;
+
+- (void)setName:(NSString *)_name;
+- (NSString *)name;
+
+- (void)setJavaScript:(NSString *)_script;
+- (NSString *)script;
+
+@end
+
+#endif /* _EOJavaScriptGrouping_h__ */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/EOJavaScriptGrouping.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/EOJavaScriptGrouping.m
new file mode 100644 (file)
index 0000000..1b64e27
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOJavaScriptGrouping.h"
+#include <NGScripting/NSObject+Scripting.h>
+#include "../common.h"
+
+@implementation EOJavaScriptGrouping
+
+- (id)initWithJavaScript:(NSString *)_script name:(NSString *)_name {
+  if ((self = [super initWithDefaultName:nil])) {
+    self->name     = [_name copy];
+    self->language = @"javascript";
+    self->script   = [_script copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->language);
+  RELEASE(self->script);
+  RELEASE(self->name);
+  [super dealloc];
+}
+
+// accessors
+
+- (void)setName:(NSString *)_name {
+  NSAssert1(_name != nil, @"%s: name is nil", __PRETTY_FUNCTION__);
+  ASSIGNCOPY(self->name, _name);
+}
+- (NSString *)name {
+  return self->name;
+}
+
+- (void)setJavaScript:(NSString *)_script {
+  RELEASE(self->language);
+  self->language = @"javascript";
+  ASSIGNCOPY(self->script, _script);
+}
+- (NSString *)script {
+  return self->script;
+}
+
+// -----------------------------------
+
+- (NSString *)groupNameForObject:(id)_object {
+  if (self->script == nil)
+    return self->name;
+
+  if ([[_object evaluateScript:self->script language:self->language] boolValue])
+    return self->name;
+  
+  return self->defaultName;
+}
+
+- (NSArray *)orderedGroupNames {
+  return [NSArray arrayWithObjects:[self name], [self defaultName], nil];
+}
+
+@end /* EOJavaScriptGrouping */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/EONull+JS.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/EONull+JS.m
new file mode 100644 (file)
index 0000000..3c3f0c9
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <EOControl/EONull.h>
+#include "../common.h"
+
+@implementation EONull(JSSupport)
+
+- (BOOL)_jsGetValue:(jsval *)_value inJSContext:(id)_jsContext {
+  *_value = JSVAL_NULL;
+  return YES;
+}
+
+@end /* EONull(JSSupport) */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/GNUmakefile b/skyrix-sope/NGJavaScript/Core+JS.subproj/GNUmakefile
new file mode 100644 (file)
index 0000000..9baac8d
--- /dev/null
@@ -0,0 +1,30 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = CoreJS
+
+CoreJS_HEADER_FILES_DIR         = .
+CoreJS_HEADER_FILES_INSTALL_DIR = /NGJavaScript
+
+CoreJS_HEADER_FILES = \
+       NSObject+JS.h           \
+       NSString+JS.h           \
+       EOJavaScriptGrouping.h  \
+
+CoreJS_OBJC_FILES = \
+       EONull+JS.m             \
+       NSArray+JS.m            \
+       NSDictionary+JS.m       \
+       NSNumber+JS.m           \
+       NSObject+JS.m           \
+       NSString+JS.m           \
+       NSUserDefaults+JS.m     \
+       NSDate+JS.m             \
+       NGFileManager+JS.m      \
+       EODataSource+JS.m       \
+       EOJavaScriptGrouping.m  \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/GNUmakefile.preamble b/skyrix-sope/NGJavaScript/Core+JS.subproj/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..fb48890
--- /dev/null
@@ -0,0 +1,9 @@
+# $Id$
+
+# JavaScript config
+ADDITIONAL_CPPFLAGS += -DXP_UNIX=1
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I.. -I../..            \
+       -I../../../skyrix-core  \
+       -I../../../skyrix-core/NGExtensions
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/NGFileManager+JS.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/NGFileManager+JS.m
new file mode 100644 (file)
index 0000000..0cfea2b
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGExtensions/NGFileManager.h>
+#include <NGExtensions/NSFileManager+Extensions.h>
+#include "NGJavaScriptContext.h"
+#include "../common.h"
+#include <NGExtensions/EOCacheDataSource.h>
+
+/*
+  JavaScript
+  
+    Properties
+    
+      cwd - readonly - current working directory, string
+    
+    Methods
+    
+      bool   cd(path)
+      Object ls([path|paths])
+      bool   mkdir(path[,path..])
+      bool   rmdir(path[,path..])
+      bool   rm(path[,path..])
+      bool   trash(path[,path..])
+      bool   cp(frompath[,frompath..], topath)
+      bool   mv(frompath[,frompath..], topath)
+      bool   ln(frompath, topath)
+      
+      bool   exists(path[,path..])
+      bool   isdir(path[,path..])
+      bool   islink(path[,path..])
+      
+      Object getDataSource([String path, [bool cache]])
+*/
+
+@implementation NSFileManager(JSSupport)
+
+static NSNumber *boolYes = nil;
+static NSNumber *boolNo  = nil;
+
+static void _ensureBools(void) {
+  if (boolYes == nil) boolYes = [[NSNumber numberWithBool:YES] retain];
+  if (boolNo  == nil) boolNo  = [[NSNumber numberWithBool:NO]  retain];
+}
+
+/* properties */
+
+- (id)_jsprop_cwd {
+  return [self currentDirectoryPath];
+}
+
+/* methods */
+
+- (id)_jsfunc_cd:(NSArray *)_args {
+  _ensureBools();
+  return [self changeCurrentDirectoryPath:[_args objectAtIndex:0]]
+    ? boolYes
+    : boolNo;
+}
+
+- (id)_jsfunc_ls:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) {
+    return [self directoryContentsAtPath:@"."];
+  }
+  else if (count == 1) {
+    return [self directoryContentsAtPath:
+                   [[_args objectAtIndex:0] stringValue]];
+  }
+  else {
+    NSMutableDictionary *md;
+    unsigned i;
+    
+    md = [NSMutableDictionary dictionaryWithCapacity:count];
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      NSArray  *contents;
+
+      path     = [_args objectAtIndex:i];
+      contents = [self directoryContentsAtPath:path];
+
+      if (contents)
+        [md setObject:contents forKey:path];
+    }
+    
+    return md;
+  }
+}
+
+- (id)_jsfunc_mkdir:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+
+  if ((count = [_args count]) == 0) {
+    return boolNo;
+  }
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      
+      path = [_args objectAtIndex:i];
+      
+      if (![self createDirectoryAtPath:path attributes:nil])
+        return boolNo;
+    }
+    
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_rmdir:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+
+  if ((count = [_args count]) == 0) {
+    return boolNo;
+  }
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      BOOL isDir;
+      
+      path = [_args objectAtIndex:i];
+      
+      if (![self fileExistsAtPath:path isDirectory:&isDir])
+        return boolNo;
+      
+      if (!isDir)
+        /* not a directory ! */
+        return boolNo;
+      
+      if ([[self directoryContentsAtPath:path] count] > 0)
+        /* directory has contents */
+        return boolNo;
+
+      if (![self removeFileAtPath:path handler:nil])
+        /* remove failed */
+        return boolNo;
+    }
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_rm:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0) {
+    return boolNo;
+  }
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      BOOL isDir;
+      
+      path = [_args objectAtIndex:i];
+      
+      if (![self fileExistsAtPath:path isDirectory:&isDir])
+        return boolNo;
+
+      if (isDir) {
+        if ([[self directoryContentsAtPath:path] count] > 0)
+          /* directory has contents */
+          return boolNo;
+      }
+      
+      if (![self removeFileAtPath:path handler:nil])
+        /* remove failed */
+        return boolNo;
+    }
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_trash:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+
+  if ((count = [_args count]) == 0) {
+    return boolNo;
+  }
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      BOOL isDir;
+      
+      path = [_args objectAtIndex:i];
+      if (![self supportsTrashFolderAtPath:path])
+        return boolNo;
+      
+      if (![self fileExistsAtPath:path isDirectory:&isDir])
+        return boolNo;
+      
+      if (![self trashFileAtPath:path handler:nil])
+        /* remove failed */
+        return boolNo;
+    }
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_mv:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0)
+    return boolNo;
+  else if (count == 1)
+    /* missing target path */
+    return boolNo;
+  else {
+    NSString *destpath;
+    unsigned i;
+    BOOL isDir;
+    
+    destpath = [_args objectAtIndex:(count - 1)];
+
+    if (![self fileExistsAtPath:destpath isDirectory:&isDir])
+      isDir = NO;
+    
+    for (i = 0; i < (count - 1); i++) {
+      NSString *path, *dpath = nil;
+      
+      path = [_args objectAtIndex:i];
+      
+      dpath = isDir
+        ? [dpath stringByAppendingPathComponent:[path lastPathComponent]]
+        : destpath;
+      
+      if (![self movePath:path toPath:dpath handler:nil])
+        /* move failed */
+        return boolNo;
+    }
+    
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_cp:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+   
+  if ((count = [_args count]) == 0)
+    return boolNo;
+  else if (count == 1)
+    /* missing target path */
+    return boolNo;
+  else {
+    NSString *destpath;
+    unsigned i;
+    BOOL isDir;
+    
+    destpath = [_args objectAtIndex:(count - 1)];
+
+    if (![self fileExistsAtPath:destpath isDirectory:&isDir])
+      isDir = NO;
+    
+    for (i = 0; i < (count - 1); i++) {
+      NSString *path, *dpath = nil;
+      
+      path = [_args objectAtIndex:i];
+
+      dpath = isDir
+        ? [dpath stringByAppendingPathComponent:[path lastPathComponent]]
+        : destpath;
+      
+      if (![self copyPath:path toPath:dpath handler:nil])
+        /* copy failed */
+        return boolNo;
+    }
+    
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_ln:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0)
+    return boolNo;
+  else if (count == 1)
+    /* missing target path */
+    return boolNo;
+  else {
+    NSString *srcpath;
+    NSString *destpath;
+    
+    srcpath  = [_args objectAtIndex:0];
+    destpath = [_args objectAtIndex:1];
+    
+    if (![self createSymbolicLinkAtPath:destpath pathContent:srcpath])
+      return boolNo;
+    
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_exists:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0)
+    return boolYes;
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      
+      path = [_args objectAtIndex:i];
+      
+      if (![self fileExistsAtPath:path])
+        return boolNo;
+    }
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_isdir:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0) {
+    return boolYes;
+  }
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString *path;
+      BOOL isDir;
+      
+      path = [_args objectAtIndex:i];
+
+#if 0
+      NSLog(@"CHECK PATH: %@", path);
+#endif
+      
+      if (![self fileExistsAtPath:path isDirectory:&isDir]) {
+#if 0
+        NSLog(@"  does not exist ..");
+#endif
+        return boolNo;
+      }
+
+      if (!isDir) {
+#if 0
+        NSLog(@"  not a directory ..");
+#endif
+        return boolNo;
+      }
+    }
+
+#if 0
+    NSLog(@"%s: returning yes, %@ are directories",
+          __PRETTY_FUNCTION__, _args);
+#endif
+    return boolYes;
+  }
+}
+
+- (id)_jsfunc_islink:(NSArray *)_args {
+  unsigned count;
+  _ensureBools();
+  
+  if ((count = [_args count]) == 0)
+    return boolYes;
+  else {
+    unsigned i;
+    
+    for (i = 0; i < count; i++) {
+      NSString     *path;
+      BOOL         isDir;
+      NSDictionary *attrs;
+      
+      path = [_args objectAtIndex:i];
+      
+      if (![self fileExistsAtPath:path isDirectory:&isDir])
+        return boolNo;
+      
+      if (isDir)
+        return boolNo;
+
+      if ((attrs = [self fileAttributesAtPath:path traverseLink:NO])==nil)
+        return boolNo;
+
+      if (![[attrs objectForKey:NSFileType]
+                   isEqualToString:NSFileTypeSymbolicLink])
+        return boolNo;
+    }
+    return boolYes;
+  }
+}
+
+/* datasource */
+
+- (id)_jsfunc_getDataSource:(NSArray *)_args {
+  unsigned count;
+  NSString *path = nil;
+  BOOL     lcache;
+  id       ds;
+  _ensureBools();
+  
+  lcache = NO;
+  
+  if ((count = [_args count]) == 0) {
+    path = @".";
+  }
+  else if (count == 1) {
+    path = [[_args objectAtIndex:0] stringValue];
+  }
+  else if (count == 2) {
+    path  = [[_args objectAtIndex:0] stringValue];
+    lcache = [[_args objectAtIndex:1] boolValue];
+  }
+  
+  if (![self supportsFolderDataSourceAtPath:path])
+    return nil;
+  
+  if ((ds = [(id<NGFileManagerDataSources>)self dataSourceAtPath:path])==nil)
+    return nil;
+  
+  if (lcache) 
+    ds = [[[EOCacheDataSource alloc] initWithDataSource:ds] autorelease];
+  
+  return ds;
+}
+
+@end /* NGFileManager(JSSupport) */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/NSArray+JS.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSArray+JS.m
new file mode 100644 (file)
index 0000000..e77066b
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptContext.h"
+#include "../common.h"
+
+@interface _NGJSIndexEnumerator : NSEnumerator
+{
+  int i;
+  int toGo;
+}
++ (id)indexEnumeratorForCount:(int)_count;
+@end
+
+#include "NGJavaScriptObjectMappingContext.h"
+
+@implementation NSArray(NGJavaScript)
+
+- (BOOL)_jsGetValue:(jsval *)_value inJSContext:(NGJavaScriptContext *)_ctx {
+  /* transform to JavaScript Array ... */
+  unsigned    count;
+  JSObject    *jsarray;
+  JSContext   *cx;
+  BOOL        addedRoot;
+  void        *root;
+  NSException *exception;
+  BOOL        retcode;
+  
+  cx = [_ctx handle];
+  
+  if ((jsarray = JS_NewArrayObject(cx, 0, NULL)) == NULL) {
+    NSLog(@"ERROR(%s): couldn't create JavaScript array ...",
+          __PRETTY_FUNCTION__);
+    return NO;
+  }
+  *_value = OBJECT_TO_JSVAL(jsarray);
+  
+  count = [self count];
+  exception = nil;
+  retcode   = YES;
+
+  if (count > 0) {
+    NGJavaScriptObjectMappingContext *mapctx;
+    
+    mapctx = [NGJavaScriptObjectMappingContext activeObjectMappingContext];
+    
+    /* temporarily add as root */
+    addedRoot = JS_AddNamedRoot(cx, &root, __PRETTY_FUNCTION__);
+
+    NS_DURING {
+      unsigned i;
+    
+      for (i = 0; i < count; i++) {
+        id    item;
+        jsval v;
+      
+        item = [self objectAtIndex:i];
+        
+        if (![mapctx jsValue:&v forObject:item]) {
+          retcode = NO;
+          NSLog(@"%s: couldn't get JS value for item %@", __PRETTY_FUNCTION__,
+                item);
+          break;
+        }
+      
+        if (!JS_SetElement(cx, jsarray, i, &v)) {
+          retcode = NO;
+          NSLog(@"%s: couldn't set item at index %d in JS array",
+                __PRETTY_FUNCTION__, i);
+          break;
+        }
+      }
+    }
+    NS_HANDLER {
+      exception = [localException retain];
+      retcode = NO;
+    }
+    NS_ENDHANDLER;
+  
+    /* remove temporary root */
+    if (addedRoot) JS_RemoveRoot(cx, &root);
+    root = NULL;
+
+    if (exception) {
+      NSLog(@"%s: catched exception: %@", __PRETTY_FUNCTION__, exception);
+      RELEASE(exception);
+    }
+  }
+  
+  return retcode;
+}
+
+- (id)valueForJSPropertyAtIndex:(int)_idx {
+  return [self objectAtIndex:_idx];
+}
+
+/* searching */
+
+- (id)_jsfunc_objectAtIndex:(NSArray *)_args {
+  return [self objectAtIndex:[[_args objectAtIndex:0] intValue]];
+}
+- (id)_jsfunc_indexOfObject:(NSArray *)_args {
+  unsigned idx;
+  
+  idx = [self indexOfObject:[_args objectAtIndex:0]];
+  if (idx == NSNotFound)
+    return nil;
+
+  return [NSNumber numberWithInt:idx];
+}
+- (id)_jsfunc_indexOfObjectIdenticalTo:(NSArray *)_args {
+  unsigned idx;
+
+  idx = [self indexOfObjectIdenticalTo:[_args objectAtIndex:0]];
+  if (idx == NSNotFound)
+    return nil;
+  
+  return [NSNumber numberWithInt:idx];
+}
+- (id)_jsfunc_lastObject:(NSArray *)_args {
+  return [self lastObject];
+}
+
+/* strings */
+
+- (id)_jsfunc_componentsJoinedByString:(NSArray *)_args {
+  return [self componentsJoinedByString:[_args componentsJoinedByString:@""]];
+}
+
+/* IO */
+
+- (id)_jsfunc_writeToFile:(NSArray *)_args {
+  BOOL atomically;
+  
+  atomically =  ([_args count] > 1)
+    ? [[_args objectAtIndex:1] boolValue]
+    : YES;
+  
+   atomically = [self writeToFile:[[_args objectAtIndex:0] stringValue]
+                      atomically:atomically];
+   return [NSNumber numberWithBool:atomically];
+}
+
+/* properties */
+
+- (id)_jsprop_count {
+  return [NSNumber numberWithInt:[self count]];
+}
+- (id)_jsprop_length {
+  return [self _jsprop_count];
+}
+
+/* enumerator */
+
+- (NSEnumerator *)indexEnumerator {
+  return [_NGJSIndexEnumerator indexEnumeratorForCount:[self count]];
+}
+
+- (NSEnumerator *)jsObjectEnumerator {
+  return [self indexEnumerator];
+}
+
+@end /* NSArray(NGJavaScript) */
+
+@implementation NSMutableArray(NGJavaScript)
+
+- (BOOL)takeValue:(id)_value forJSPropertyAtIndex:(int)_idx {
+  if (_value == nil)
+      return NO;
+  
+  [self replaceObjectAtIndex:_idx withObject:_value];
+  return YES;
+}
+
+/* adding objects */
+
+- (id)_jsfunc_addObject:(NSArray *)_objs {
+  [self addObjectsFromArray:_objs];
+  return self;
+}
+- (id)_jsfunc_addObjectsFromArray:(NSArray *)_objs {
+  NSEnumerator *e;
+  NSArray *array;
+
+  e = [_objs objectEnumerator];
+  while ((array = [e nextObject]))
+    [self addObjectsFromArray:array];
+  return self;
+}
+
+/* inserting objects */
+
+- (id)_jsfunc_insertObjectAtIndex:(NSArray *)_objs {
+  [self insertObject:[_objs objectAtIndex:0]
+        atIndex:[[_objs objectAtIndex:1] intValue]];
+  return self;
+}
+
+/* removing objects */
+
+- (id)_jsfunc_removeObject:(NSArray *)_objs {
+  [self removeObjectsInArray:_objs];
+  return self;
+}
+- (id)_jsfunc_removeObjectsInArray:(NSArray *)_objs {
+  NSEnumerator *e;
+  NSArray *array;
+
+  e = [_objs objectEnumerator];
+  while ((array = [e nextObject]))
+    [self removeObjectsInArray:array];
+  return self;
+}
+- (id)_jsfunc_removeAllObjects:(NSArray *)_objs {
+  [self removeAllObjects];
+  return self;
+}
+- (id)_jsfunc_removeObjectAtIndex:(NSArray *)_objs {
+  NSEnumerator *e;
+  id idx;
+
+  e = [_objs objectEnumerator];
+  while ((idx = [e nextObject]))
+    [self removeObjectAtIndex:[idx intValue]];
+  return self;
+}
+
+@end /* NSMutableArray(NGJavaScript) */
+
+@implementation _NGJSIndexEnumerator
+
+static Class NSNumberClass = Nil;
+
++ (id)indexEnumeratorForCount:(int)_count {
+  _NGJSIndexEnumerator *e;
+  
+  if (_count == 0)
+    return nil;
+
+  if (NSNumberClass == Nil)
+    NSNumberClass = [NSNumber class];
+
+  e = [[self alloc] init];
+  e->toGo = _count;
+  return AUTORELEASE(e);
+}
+
+- (id)nextObject {
+  id o;
+  
+  if (self->i >= self->toGo)
+    return nil;
+  
+  o = [NSNumberClass numberWithInt:self->i];
+  
+  self->i++;
+  return o;
+}
+
+@end /* _NGJSIndexEnumerator */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/NSDate+JS.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSDate+JS.m
new file mode 100644 (file)
index 0000000..9775ede
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "../common.h"
+#include <NGExtensions/NSCalendarDate+misc.h>
+
+static NSString *JSDateFormat = @"%a, %d %b %Y %H:%M:%S %Z";
+
+@implementation NSDate(NGJavaScript)
+@end /* NSDate(NGJavaScript) */
+
+@implementation NSObject(DateCreation)
+
+- (NSTimeZone *)jsDateTimeZone {
+  return [NSTimeZone defaultTimeZone];
+}
+
+- (id)_jsfunc_SkyDate:(NSArray *)_args {
+  unsigned count;
+  NSCalendarDate *date;
+  NSTimeZone     *tz;
+  
+  tz = [self jsDateTimeZone];
+  
+  if ((count = [_args count]) == 0) {
+    date = [NSCalendarDate date];
+  }
+  else if (count == 1) {
+    // new Date( milliseconds)
+    // new Date( dateString)
+    id arg0;
+
+    arg0 = [_args objectAtIndex:0];
+    
+    if ([arg0 isKindOfClass:[NSNumber class]]) {
+      NSTimeInterval ti;
+
+      ti = [arg0 unsignedIntValue] * 1000.0;
+      date = [NSCalendarDate dateWithTimeIntervalSince1970:ti];
+    }
+    else {
+      /* 1. "Mon, 25 Dec 1995 13:30:00 GMT". */
+      /* 2. "2001-01-04 13:23:45 GMT" */
+
+      arg0 = [arg0 stringValue];
+      date = [NSCalendarDate dateWithString:arg0 calendarFormat:JSDateFormat];
+      if (date == nil) {
+        date = [NSCalendarDate dateWithString:arg0
+                               calendarFormat:@"%Y-%m-%d %H:%M:%S %Z"];
+      }
+    }
+  }
+  else {
+    // new Date( yr_num, mo_num, day_num[, hr_num, min_num, sec_num])
+    short year = 2000, month = 1, day = 1, hour = 0, minute = 0, second = 0;
+
+    if (count > 5) second = [[_args objectAtIndex:5] intValue];
+    if (count > 4) minute = [[_args objectAtIndex:4] intValue];
+    if (count > 3) hour   = [[_args objectAtIndex:3] intValue];
+    if (count > 2) day    = [[_args objectAtIndex:2] intValue];
+    if (count > 1) month  = ([[_args objectAtIndex:1] intValue] + 1);
+    if (count > 0) year   = [[_args objectAtIndex:0] intValue];
+    
+    if (year < 100) year += 1900;
+    
+    date = [[NSCalendarDate alloc] initWithYear:year month:month day:day
+                                   hour:hour minute:minute second:second
+                                   timeZone:tz];
+    AUTORELEASE(date);
+  }
+  
+  [date setTimeZone:tz];
+  [date setCalendarFormat:JSDateFormat];
+  return date;
+}
+
+@end /* NSObject(DateCreation) */
+
+@implementation NSCalendarDate(NGJavaScript)
+
+static NSNumber *shortNum(short num) {
+  static NSNumber *zero = nil;
+
+  switch (num) {
+    case 0:
+      if (zero == nil) zero = [[NSNumber numberWithShort:num] retain];
+      return zero;
+    default:
+      return [NSNumber numberWithShort:num];
+  }
+}
+
+- (id)_jsfunc_getDate:(NSArray *)_args {
+  return shortNum([self dayOfMonth]);
+}
+- (id)_jsfunc_getDay:(NSArray *)_args {
+  return shortNum([self dayOfWeek]);
+}
+- (id)_jsfunc_getFullYear:(NSArray *)_args {
+  return shortNum([self yearOfCommonEra]);
+}
+- (id)_jsfunc_getYear:(NSArray *)_args {
+  return shortNum([self yearOfCommonEra] - 1900);
+}
+- (id)_jsfunc_getHours:(NSArray *)_args {
+  return shortNum([self hourOfDay]);
+}
+- (id)_jsfunc_getMilliseconds:(NSArray *)_args {
+  return shortNum(0);
+}
+- (id)_jsfunc_getMinutes:(NSArray *)_args {
+  return shortNum([self minuteOfHour]);
+}
+- (id)_jsfunc_getMonth:(NSArray *)_args {
+  /* JS counts from 0 to 11 */
+  return shortNum([self monthOfYear] - 1);
+}
+- (id)_jsfunc_getSeconds:(NSArray *)_args {
+  return shortNum([self secondOfMinute]);
+}
+- (id)_jsfunc_getTime:(NSArray *)_args {
+  return [NSNumber numberWithInt:(int)[self timeIntervalSince1970]];
+}
+- (id)_jsfunc_getTimezoneOffset:(NSArray *)_args {
+  return shortNum([[self timeZone] secondsFromGMTForDate:self]);
+}
+
+/* UTC */
+
+- (NSCalendarDate *)_utcDate {
+  NSCalendarDate *d;
+  
+  d = [[self copy] autorelease];
+  [d setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
+  return d;
+}
+
+- (id)_jsfunc_getUTCDate:(NSArray *)_args {
+  return shortNum([[self _utcDate] dayOfMonth]);
+}
+- (id)_jsfunc_getUTCDay:(NSArray *)_args {
+  return shortNum([[self _utcDate] dayOfWeek]);
+}
+- (id)_jsfunc_getUTCFullYear:(NSArray *)_args {
+  return shortNum([[self _utcDate] yearOfCommonEra]);
+}
+- (id)_jsfunc_getUTCHours:(NSArray *)_args {
+  return shortNum([[self _utcDate] hourOfDay]);
+}
+- (id)_jsfunc_getUTCMilliseconds:(NSArray *)_args {
+  return shortNum(0);
+}
+- (id)_jsfunc_getUTCMinutes:(NSArray *)_args {
+  return shortNum([[self _utcDate] minuteOfHour]);
+}
+- (id)_jsfunc_getUTCMonth:(NSArray *)_args {
+  /* JS counts from 0 to 11 */
+  return shortNum([[self _utcDate] monthOfYear] - 1);
+}
+- (id)_jsfunc_getUTCSeconds:(NSArray *)_args {
+  return shortNum([[self _utcDate] secondOfMinute]);
+}
+
+/* descriptions */
+
+- (id)_jsfunc_toGMTString:(NSArray *)_args {
+  return [[self _utcDate] descriptionWithCalendarFormat:JSDateFormat];
+}
+- (id)_jsfunc_toUTCString:(NSArray *)_args {
+  return [[self _utcDate] descriptionWithCalendarFormat:JSDateFormat];
+}
+- (id)_jsfunc_toLocaleString:(NSArray *)_args {
+  return [self descriptionWithCalendarFormat:JSDateFormat];
+}
+
+- (id)_jsfunc_toString:(NSArray *)_args {
+  return [self _jsfunc_toGMTString:_args];
+}
+
+/* NGJavaScript additions */
+
+- (id)_jsfunc_getWeekOfMonth:(NSArray *)_args {
+  return shortNum([self weekOfMonth]);
+}
+- (id)_jsfunc_getWeekOfYear:(NSArray *)_args {
+  return shortNum([self weekOfYear]);
+}
+- (id)_jsfunc_getNumberOfWeeksInYear:(NSArray *)_args {
+  return shortNum([self numberOfWeeksInYear]);
+}
+- (id)_jsfunc_getNumberOfDaysInMonth:(NSArray *)_args {
+  return shortNum([self numberOfDaysInMonth]);
+}
+
+- (id)_jsfunc_getFirstDayOfMonth:(NSArray *)_args {
+  return [self firstDayOfMonth];
+}
+- (id)_jsfunc_getLastDayOfMonth:(NSArray *)_args {
+  return [self lastDayOfMonth];
+}
+- (id)_jsfunc_getMondayOfWeek:(NSArray *)_args {
+  return [self mondayOfWeek];
+}
+- (id)_jsfunc_getBeginOfDay:(NSArray *)_args {
+  return [self beginOfDay];
+}
+- (id)_jsfunc_getEndOfDay:(NSArray *)_args {
+  return [self endOfDay];
+}
+
+- (id)_jsfunc_isDateOnSameDay:(NSArray *)_args {
+  unsigned count;
+
+  if ((count = [_args count]) == 0)
+    return nil;
+
+  return [self isDateOnSameDay:[_args objectAtIndex:0]]
+    ? [NSNumber numberWithBool:YES]
+    : [NSNumber numberWithBool:NO];
+}
+- (id)_jsfunc_isDateInSameWeek:(NSArray *)_args {
+  unsigned count;
+
+  if ((count = [_args count]) == 0)
+    return nil;
+
+  return [self isDateInSameWeek:[_args objectAtIndex:0]]
+    ? [NSNumber numberWithBool:YES]
+    : [NSNumber numberWithBool:NO];
+}
+
+- (id)_jsfunc_isToday:(NSArray *)_args {
+  return [self isToday]
+    ? [NSNumber numberWithBool:YES]
+    : [NSNumber numberWithBool:NO];
+}
+- (id)_jsfunc_isForenoon:(NSArray *)_args {
+  return [self isForenoon]
+    ? [NSNumber numberWithBool:YES]
+    : [NSNumber numberWithBool:NO];
+}
+- (id)_jsfunc_isAfternoon:(NSArray *)_args {
+  return [self isAfternoon]
+    ? [NSNumber numberWithBool:YES]
+    : [NSNumber numberWithBool:NO];
+}
+
+- (id)_jsfunc_getYesterday:(NSArray *)_args {
+  return [self yesterday];
+}
+- (id)_jsfunc_getTomorrow:(NSArray *)_args {
+  return [self tomorrow];
+}
+
+- (id)_jsfunc_getNextYear:(NSArray *)_args {
+  return [self nextYear];
+}
+- (id)_jsfunc_getLastYear:(NSArray *)_args {
+  return [self lastYear];
+}
+
+- (id)_jsfunc_getDateByAdding:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0)
+    return [[self copy] autorelease];
+  
+  if (count <= 3) {
+    short year = 0, month = 0, day = 0;
+
+    if (count > 0) year  = [[_args objectAtIndex:0] intValue];
+    if (count > 1) month = [[_args objectAtIndex:1] intValue];
+    if (count > 2) day   = [[_args objectAtIndex:2] intValue];
+    
+    return [self dateByAddingYears:year months:month days:day];
+  }
+  
+  return nil;
+}
+
+@end /* NSCalendarDate(NGJavaScript) */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/NSDictionary+JS.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSDictionary+JS.m
new file mode 100644 (file)
index 0000000..b4d07ea
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptContext.h"
+#import <Foundation/Foundation.h>
+#import <EOControl/EONull.h>
+#include "../common.h"
+
+@implementation NSDictionary(NGJavaScript)
+
+- (id)valueForJSPropertyNamed:(NSString *)_key {
+  return [self objectForKey:_key];
+}
+
+- (id)_jsfunc_allKeys:(NSArray *)_args {
+  return [self allKeys];
+}
+- (id)_jsfunc_allKeysForObject:(NSArray *)_args {
+  return [self allKeysForObject:[_args objectAtIndex:0]];
+}
+- (id)_jsfunc_allValues:(NSArray *)_args {
+  return [self allValues];
+}
+
+- (id)_jsfunc_objectForKey:(NSArray *)_args {
+  return [self objectForKey:[_args objectAtIndex:0]];
+}
+- (id)_jsfunc_objectsForKeys:(NSArray *)_args {
+  unsigned count;
+  id notFound;
+  
+  notFound = ((count = [_args count]) > 1)
+    ? [_args objectAtIndex:1]
+    : [EONull null];
+
+  return [self objectsForKeys:[_args objectAtIndex:0] notFoundMarker:notFound];
+}
+
+/* IO */
+
+- (id)_jsfunc_writeToFile:(NSArray *)_args {
+  BOOL atomically;
+  
+  atomically =  ([_args count] > 1)
+    ? [[_args objectAtIndex:1] boolValue]
+    : YES;
+  
+   atomically = [self writeToFile:[[_args objectAtIndex:0] stringValue]
+                      atomically:atomically];
+   return [NSNumber numberWithBool:atomically];
+}
+
+@end /* NSDictionary(NGJavaScript) */
+
+@implementation NSMutableDictionary(NGJavaScript)
+
+- (BOOL)takeValue:(id)_value forJSPropertyNamed:(NSString *)_key {
+  if ((_value == nil) || (_key == nil))
+      return NO;
+  
+  [self setObject:_value forKey:_key];
+  return YES;
+}
+
+/* adding objects */
+
+- (id)_jsfunc_addEntriesFromDictionary:(NSArray *)_args {
+  NSEnumerator *e;
+  NSDictionary *d;
+
+  e = [_args objectEnumerator];
+  while ((d = [e nextObject]))
+    [self addEntriesFromDictionary:d];
+  return self;
+}
+- (id)_jsfunc_setObjectForKey:(NSArray *)_args {
+  [self setObject:[_args objectAtIndex:0] forKey:[_args objectAtIndex:1]];
+  return self;
+}
+- (id)_jsfunc_setDictionary:(NSArray *)_args {
+  [self setDictionary:[_args objectAtIndex:0]];
+  return self;
+}
+
+/* removing objects */
+
+- (id)_jsfunc_removeAllObjects:(NSArray *)_args {
+  [self removeAllObjects];
+  return self;
+}
+- (id)_jsfunc_removeObjectForKey:(NSArray *)_args {
+  NSEnumerator *e;
+  NSString *d;
+
+  e = [_args objectEnumerator];
+  while ((d = [e nextObject]))
+    [self removeObjectForKey:d];
+  return self;
+}
+- (id)_jsfunc_removeObjectsForKeys:(NSArray *)_args {
+  NSEnumerator *e;
+  NSArray *d;
+
+  e = [_args objectEnumerator];
+  while ((d = [e nextObject]))
+    [self removeObjectsForKeys:d];
+  return self;
+}
+
+@end /* NSMutableDictionary(NGJavaScript) */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/NSNumber+JS.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSNumber+JS.m
new file mode 100644 (file)
index 0000000..b0102ed
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptContext.h"
+#import <Foundation/Foundation.h>
+#include "../common.h"
+
+@implementation NSNumber(JS)
+
+- (BOOL)_jsGetValue:(jsval *)_value inJSContext:(NGJavaScriptContext *)_ctx {
+  static NSNumber *boolYes = nil;
+  static NSNumber *boolNo  = nil;
+  const char *type;
+
+  if (boolYes == nil) boolYes = [[NSNumber numberWithBool:YES] retain];
+  if (boolNo  == nil) boolNo  = [[NSNumber numberWithBool:NO]  retain];
+  
+  if (self == boolYes) {
+    *_value = BOOLEAN_TO_JSVAL(YES);
+    return YES;
+  }
+  if (self == boolNo) {
+    *_value = BOOLEAN_TO_JSVAL(NO);
+    return YES;
+  }
+#if LIB_FOUNDATION_LIBRARY
+  {
+    static Class BoolClass = Nil;
+    if (BoolClass == Nil) BoolClass = NSClassFromString(@"NSBoolNumber");
+    if (*(Class*)self == BoolClass) {
+      /* it's a bool number */
+
+      *_value = BOOLEAN_TO_JSVAL([self boolValue]);
+      return YES;
+    }
+  }
+#elif APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+  /* check that, at least on Panther bool NSNumbers are singletons */
+#else
+#  warning what about BOOLs on this platform ? (hopefully it uses singletons ...)
+#endif
+
+  type = [self objCType];
+  //NSLog(@"getval (%s) for number %@", type, self);
+  switch (*type) {
+    case _C_DBL:
+    case _C_FLT:
+      return JS_NewDoubleValue([_ctx handle], [self doubleValue], _value);
+
+    case _C_UINT:
+      return JS_NewDoubleValue([_ctx handle], [self doubleValue], _value);
+      
+    default:
+      if (INT_FITS_IN_JSVAL([self intValue]))
+        *_value = INT_TO_JSVAL([self intValue]);
+      else
+        return JS_NewDoubleValue([_ctx handle], [self doubleValue], _value);
+      break;
+  }
+  return YES;
+}
+
+@end /* NSNumber(JS) */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/NSObject+JS.h b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSObject+JS.h
new file mode 100644 (file)
index 0000000..5204f97
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NSObject_JS_H__
+#define __NSObject_JS_H__
+
+#import <Foundation/NSObject.h>
+
+@interface NSObject(JSSupport)
+
+/* named properties */
+
+- (BOOL)takeValue:(id)_value forJSPropertyNamed:(NSString *)_key;
+- (id)valueForJSPropertyNamed:(NSString *)_key;
+
+/* indexed properties */
+
+- (BOOL)takeValue:(id)_value forJSPropertyAtIndex:(int)_idx;
+- (id)valueForJSPropertyAtIndex:(int)_idx;
+
+/* JS */
+
+- (id)evaluateJavaScript:(NSString *)_script;
+- (id)callJavaScriptFunction:(NSString *)_func;
+- (id)callJavaScriptFunction:(NSString *)_func withObject:(id)_arg0;
+- (id)callJavaScriptFunction:(NSString *)_func
+  withObject:(id)_arg0
+  withObject:(id)_arg1;
+
+@end
+
+#endif /* __NSObject_JS_H__ */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/NSObject+JS.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSObject+JS.m
new file mode 100644 (file)
index 0000000..7c4e491
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGScripting/NGScriptLanguage.h>
+#include "NGJavaScriptContext.h"
+#include "NGJavaScriptObjectMappingContext.h"
+#include "../common.h"
+#import <EOControl/EOControl.h>
+
+@implementation NSObject(JSSupport)
+
+static NGScriptLanguage *js = nil;
+static inline NGScriptLanguage *_jsLang(void) {
+  if (js == nil)
+    js = [[NGScriptLanguage languageWithName:@"javascript"] retain];
+  return js;
+}
+
+#if 0 /* do not enable, would expose any ObjC KVC to JavaScript !!! */
+- (BOOL)takeValue:(id)_value forJSPropertyNamed:(NSString *)_key {
+  return [self takeValue:_value forKey:_key];
+}
+- (id)valueForJSPropertyNamed:(NSString *)_key {
+  return [self valueForKey:_key];
+}
+#endif
+
+/* parents */
+
+- (id)_js_parentObject {
+  return nil;
+}
+
+/* JS functions */
+
+- (id)_jsprop_objCClass {
+  return NSStringFromClass([self class]);
+}
+
+- (id)_jsfunc_print:(NSArray *)_args {
+  NSEnumerator *e;
+  id   o;
+  BOOL isFirst;
+
+  isFirst = YES;
+  e = [_args objectEnumerator];
+  while ((o = [e nextObject])) {
+    NSString *s;
+
+    if (!isFirst) fputc(' ', stdout);
+    else isFirst = NO;
+    
+    s = [o stringValue];
+    fputs(s ? [s cString] : "", stdout);
+  }
+  fputc('\n', stdout);
+  
+  return self;
+}
+
+/* evaluation */
+
+- (id)evaluateJavaScript:(NSString *)_script {
+  return [_jsLang() evaluateScript:_script onObject:self 
+                    source:@"<string>" 
+                   line:0];
+}
+
+/* JavaScript functions */
+
+- (id)callJavaScriptFunction:(NSString *)_func {
+  return [_jsLang() callFunction:_func onObject:self];
+}
+
+- (id)callJavaScriptFunction:(NSString *)_func withObject:(id)_arg0 {
+  return [_jsLang() callFunction:_func withArgument:_arg0 onObject:self];
+}
+
+- (id)callJavaScriptFunction:(NSString *)_func
+  withObject:(id)_arg0
+  withObject:(id)_arg1
+{
+  return [_jsLang() callFunction:_func
+                withArgument:_arg0
+                withArgument:_arg1
+                onObject:self];
+}
+
+@end /* NSObject(JSSupport) */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/NSString+JS.h b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSString+JS.h
new file mode 100644 (file)
index 0000000..9b3cd5d
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NSString_JS_H__
+#define __NSString_JS_H__
+
+#import <Foundation/NSString.h>
+
+#define id _id
+#include <js/jsapi.h>
+#undef id
+
+@class NGJavaScriptContext;
+
+@interface NSString(NGJavaScriptI)
+
++ (id)stringWithJavaScriptString:(JSString *)_jss;
+- (id)initWithJavaScriptString:(JSString *)_jss;
+
+@end
+
+#endif /* __NSString_JS_H__ */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/NSString+JS.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSString+JS.m
new file mode 100644 (file)
index 0000000..54d8eef
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSString+JS.h"
+#include "NGJavaScriptContext.h"
+#import <Foundation/Foundation.h>
+#include "../common.h"
+
+@implementation NSString(NGJavaScript)
+
++ (id)stringWithJavaScriptString:(JSString *)_jss {
+  unsigned charCount;
+  
+  if (_jss == NULL)
+    return nil;
+  if ((charCount = JS_GetStringLength(_jss)) == 0)
+    return @"";
+
+  return [[[self alloc] initWithJavaScriptString:_jss] autorelease];
+}
+
+#if !HANDLE_NSSTRINGS_AS_OBJECTS
+- (BOOL)_jsGetValue:(jsval *)_value inJSContext:(NGJavaScriptContext *)_ctx {
+  JSContext *cx;
+  JSString  *s;
+  unsigned  len;
+  char      *buf;
+  
+  len = [self cStringLength];
+  
+  //NSLog(@"%s: MORPH STRING (len=%i) ...", __PRETTY_FUNCTION__, len);
+  
+  cx = [_ctx handle];
+  //NSAssert1(cx, @"missing JS context handle (ctx=%@) ...", _ctx);
+  
+  // TODO: unicode
+  
+  if ((buf = JS_malloc(cx, len + 3)) == NULL) {
+    NSLog(@"%s: could not allocate string buffer (len=%i) ...", 
+         __PRETTY_FUNCTION__, len);
+    return NO;
+  }
+  [self getCString:buf]; buf[len] = '\0';
+  
+  s = JS_NewString(cx, buf, len);
+  *_value = STRING_TO_JSVAL(s);
+  
+  return YES;
+}
+#endif
+
+- (id)_jsprop_length {
+#if !HANDLE_NSSTRINGS_AS_OBJECTS
+  printf("CALLED NSString 'length' JS property "
+        "(should never happen since NSStrings convert themselves to"
+        " JSString values !)\n");
+#endif
+  return [NSNumber numberWithInt:[self length]];
+}
+
+@end /* NSString(NGJavaScript) */
+
+@implementation NSObject(NGJavaScript)
+/* category on NSObject, so that NSTemporaryString is included ! */
+
+- (id)initWithJavaScriptString:(JSString *)_jss {
+#if WITH_UNICODE
+  unsigned charCount, i;
+  unichar  *uchars;
+  jschar   *jchars;
+
+  if (_jss == NULL) {
+    [self release];
+    return nil;
+  }
+  
+  if ((charCount = JS_GetStringLength(_jss)) == 0) {
+    [self release];
+    return @"";
+  }
+
+  jchars = JS_GetStringChars(_jss);
+  NSAssert(jchars, @"couldn't get chars of JavaScript string !");
+  
+  uchars = calloc(charCount + 3, sizeof(unichar));
+  for (i = 0; i < charCount; i++)
+    uchars[i] = jchars[i];
+
+  self = [(NSString *)self initWithCharacters:uchars length:charCount];
+  free(uchars);
+  
+  return self;
+#else
+  unsigned char *cstr;
+
+  if ((cstr = JS_GetStringBytes(_jss)))
+    return [(NSString *)self initWithCString:cstr];
+  
+  NSLog(@"ERROR(%s): did not get bytes of JS string 0x%08X !",
+       __PRETTY_FUNCTION__, _jss);
+  [self release];
+  return nil;
+#endif
+}
+
+@end /* NSObject(NGJavaScript) */
diff --git a/skyrix-sope/NGJavaScript/Core+JS.subproj/NSUserDefaults+JS.m b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSUserDefaults+JS.m
new file mode 100644 (file)
index 0000000..e604038
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptContext.h"
+#import <Foundation/Foundation.h>
+#import <EOControl/EONull.h>
+#include "../common.h"
+
+/*
+  NSUserDefaults JavaScript object
+
+  Properties
+
+    Array searchList
+  
+  Methods
+
+    bool   synchronize()
+           setObjectForKey(obj, key)
+    Object objectForKey(key)
+           removeObjectForKey(key)
+    Array  arrayForKey(key)
+    Dict   dictionaryForKey(key)
+    Object dataForKey(key)
+    Array  stringArrayForKey(key)
+    String stringForKey(key)
+    bool   boolForKey(key)
+    Number floatForKey(key)
+    Number integerForKey(key)
+*/
+
+@implementation NSUserDefaults(NGJavaScript)
+
+- (id)valueForJSPropertyNamed:(NSString *)_key {
+  return [self objectForKey:_key];
+}
+
+#if !(NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY)
+- (void)_jsprop_searchList:(id)_array {
+  [self setSearchList:_array];
+}
+- (id)_jsprop_searchList {
+  return [self searchList];
+}
+#endif
+
+- (id)_jsfunc_synchronize:(NSArray *)_args {
+  return [NSNumber numberWithBool:[self synchronize]];
+}
+
+- (id)_jsfunc_setObjectForKey:(NSArray *)_args {
+  [self setObject:[_args objectAtIndex:0]
+        forKey:[_args objectAtIndex:1]];
+  return self;
+}
+- (id)_jsfunc_objectForKey:(NSArray *)_args {
+  return [self objectForKey:[_args objectAtIndex:0]];
+}
+- (id)_jsfunc_removeObjectForKey:(NSArray *)_args {
+  NSEnumerator *e;
+  NSString *key;
+  
+  e = [_args objectEnumerator];
+  while ((key = [e nextObject]))
+    [self removeObjectForKey:key];
+  return self;
+}
+
+- (id)_jsfunc_arrayForKey:(NSArray *)_args {
+  return [self arrayForKey:[_args objectAtIndex:0]];
+}
+- (id)_jsfunc_dictionaryForKey:(NSArray *)_args {
+  return [self dictionaryForKey:[_args objectAtIndex:0]];
+}
+- (id)_jsfunc_dataForKey:(NSArray *)_args {
+  return [self dataForKey:[_args objectAtIndex:0]];
+}
+- (id)_jsfunc_stringArrayForKey:(NSArray *)_args {
+  return [self stringArrayForKey:[_args objectAtIndex:0]];
+}
+- (id)_jsfunc_stringForKey:(NSArray *)_args {
+  return [self stringForKey:[_args objectAtIndex:0]];
+}
+- (id)_jsfunc_boolForKey:(NSArray *)_args {
+  return [NSNumber numberWithBool:[self boolForKey:[_args objectAtIndex:0]]];
+}
+- (id)_jsfunc_floatForKey:(NSArray *)_args {
+  return [NSNumber numberWithFloat:[self floatForKey:[_args objectAtIndex:0]]];
+}
+- (id)_jsfunc_integerForKey:(NSArray *)_args {
+  return [NSNumber numberWithInt:[self integerForKey:[_args objectAtIndex:0]]];
+}
+
+@end /* NSUserDefaults(NGJavaScript) */
diff --git a/skyrix-sope/NGJavaScript/GNUmakefile b/skyrix-sope/NGJavaScript/GNUmakefile
new file mode 100644 (file)
index 0000000..9f57a83
--- /dev/null
@@ -0,0 +1,86 @@
+# $Id$
+
+include ../common.make
+
+#ADDITIONAL_CPPFLAGS += -DTRACK_JSMEM=1 -DTRACK_JSMEM_RC=1
+
+LIBRARY_NAME       = libNGJavaScript
+BUNDLE_NAME        = SpiderMonkey
+BUNDLE_EXTENSION   := .sse
+ # SKYRiX script engine ;-)
+BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/ScriptEngines
+
+# NGJavaScript
+
+libNGJavaScript_SUBPROJECTS = Core+JS.subproj
+libNGJavaScript_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libNGJavaScript_HEADER_FILES = \
+       NGJavaScriptDecls.h                     \
+       NGJavaScript.h                          \
+       \
+       NGJavaScriptObject.h                    \
+       NGJavaScriptContext.h                   \
+       NGJavaScriptFunction.h                  \
+       NGJavaScriptCallable.h                  \
+       NGJavaScriptObjectHandler.h             \
+       NGJavaScriptRuntime.h                   \
+       NGJavaScriptObjectMappingContext.h      \
+       NGJavaScriptShadow.h                    \
+       NGJavaScriptError.h                     \
+
+libNGJavaScript_OBJC_FILES = globals.m \
+       NGJavaScriptArray.m                     \
+       NGJavaScriptContext.m                   \
+       NGJavaScriptFunction.m                  \
+       NGJavaScriptObjCClassInfo.m             \
+       NGJavaScriptObject.m                    \
+       NGJavaScriptCallable.m                  \
+       NGJavaScriptObjectHandler.m             \
+       NGJavaScriptRuntime.m                   \
+       NGJavaScriptShadow.m                    \
+       NGJavaScriptObjectMappingContext.m      \
+       NGJavaScriptLanguage.m                  \
+       NGJavaScriptError.m                     \
+
+SpiderMonkey_OBJC_FILES =  dummy.m
+SpiderMonkey_BUNDLE_LIBS += -lNGJavaScript
+SpiderMonkey_RESOURCE_FILES += ScriptLanguages.plist
+
+libNGJavaScript_HEADER_FILES_DIR         = .
+libNGJavaScript_HEADER_FILES_INSTALL_DIR = /NGJavaScript
+
+ADDITIONAL_INCLUDE_DIRS += -I.. -I./Core+JS.subproj
+
+libNGJavaScript_LIBRARIES_DEPEND_UPON += -lNGScripting
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+libNGJavaScript_LIB_DIRS += \
+       -L$(GNUSTEP_BUILD_DIR)/../NGScripting/$(GNUSTEP_OBJ_DIR_NAME)
+else
+libNGJavaScript_LIB_DIRS += -L../NGScripting/$(GNUSTEP_OBJ_DIR)
+endif
+
+#      -I../js/$(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS)\
+
+# test tool
+
+TOOL_NAME = testjs # jsobjops
+
+testjs_OBJC_FILES   += testjs.m $(libNGJavaScript_OBJC_FILES)
+testjs_SUBPROJECTS  = tests
+
+jsobjops_OBJC_FILES += jsobjops.m $(libNGJavaScript_OBJC_FILES)
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+include $(GNUSTEP_MAKEFILES)/bundle.make
+
+ifeq ($(tests),yes)
+  include $(GNUSTEP_MAKEFILES)/tool.make
+endif
+
+-include GNUmakefile.postamble
+
+autodoc :
+       autodoc $(AUTODOC_FLAGS) -dest $(AUTODOC_DESTPATH)/NGJavaScript/ -proj .
diff --git a/skyrix-sope/NGJavaScript/GNUmakefile.preamble b/skyrix-sope/NGJavaScript/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..c6750be
--- /dev/null
@@ -0,0 +1,95 @@
+# $Id$
+
+# JavaScript config
+
+ADDITIONAL_CPPFLAGS += -DXP_UNIX=1
+
+ifeq ($(NATIVEJS),yes)
+ADDITIONAL_INCLUDE_DIRS += \
+       -I/usr/local/src/js-1.5rc1/src  \
+       -I/usr/local/src/js-1.5rc1/src/Linux_All_DBG.OBJ
+
+ADDITIONAL_LIB_DIRS += -L/usr/local/src/js-1.5rc1/src/Linux_All_DBG.OBJ
+endif
+
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_JS=$(GNUSTEP_BUILD_DIR)/../../../ThirdParty/js-1.5
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/../../skyrix-core
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+RELBUILD_DIR_SOPE=$(GNUSTEP_BUILD_DIR)/..
+
+ADDITIONAL_LIB_DIRS += \
+       -L$(RELBUILD_DIR_SOPE)/NGJavaScript/$(GNUSTEP_OBJ_DIR_NAME)     \
+       -L$(RELBUILD_DIR_SOPE)/NGScripting/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+       -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)             \
+       -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)         \
+       -L$(RELBUILD_DIR_JS)/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                    \
+       -L../NGScripting/$(GNUSTEP_OBJ_DIR)     \
+       -L../NGJavaScript/$(GNUSTEP_OBJ_DIR)    \
+       -L../NGExtensions/$(GNUSTEP_OBJ_DIR)    \
+       -L../EOControl/$(GNUSTEP_OBJ_DIR)       \
+       -L../js/$(GNUSTEP_OBJ_DIR)
+endif
+
+# further config
+
+ADDITIONAL_CPPFLAGS += -Wall
+
+ifeq ($(GNUSTEP_TARGET_OS),darwin1.1)
+ADDITIONAL_LDFLAGS += -framework Foundation
+endif
+
+ifeq ($(GNUSTEP_TARGET_OS),darwin1.2)
+ADDITIONAL_LDFLAGS += \
+       -framework Foundation                   \
+       -L../js/$(GNUSTEP_OBJ_DIR)              \
+       -L../NGStreams/$(GNUSTEP_OBJ_DIR)       \
+
+libNGJavaScript_LIBRARIES_DEPEND_UPON += -ljs -lNGStreams
+endif
+
+# Windows
+
+ifeq ($(GNUSTEP_TARGET_OS),mingw32)
+libNGJavaScript_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+libNGJavaScript_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
+
+# dependencies
+
+libNGJavaScript_LIBRARIES_DEPEND_UPON += \
+       -lNGScripting                   \
+       -lNGExtensions -lEOControl      \
+       -lDOM -lSaxObjC                 \
+       -ljs
+
+testjs_CPP_FLAGS    += -DBUILD_libNGJavaScript_DLL=1
+testjs_INCLUDE_DIRS += -I. -I.. -I./tests/
+testjs_LIB_DIRS     += -L./$(GNUSTEP_OBJ_DIR)
+testjs_TOOL_LIBS    += -lNGJavaScript -lNGScripting -lNGExtensions -ljs
+
+jsobjops_CPP_FLAGS    += -DBUILD_libNGJavaScript_DLL=1 -Wall
+jsobjops_INCLUDE_DIRS += -I. -I..
+jsobjops_LIB_DIRS     += -L./$(GNUSTEP_OBJ_DIR)
+jsobjops_TOOL_LIBS    += -lNGExtensions -ljs
+
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libNGJavaScript_PREBIND_ADDR="0xC3200000"
+libNGJavaScript_LDFLAGS += -seg1addr $(libNGJavaScript_PREBIND_ADDR)
+endif
+
+ifeq ($(FOUNDATION_LIB),nx)
+libNGJavaScript_LIBRARIES_DEPEND_UPON += -lFoundationExt
+ADDITIONAL_LDFLAGS      += -framework Foundation
+endif
diff --git a/skyrix-sope/NGJavaScript/JSObjectOps.m b/skyrix-sope/NGJavaScript/JSObjectOps.m
new file mode 100644 (file)
index 0000000..42a257c
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+
+#include "common.h"
+
+#define LOG_OBJECT_OPS 1
+
+extern JS_IMPORT_DATA(JSObjectOps) js_ObjectOps;
+
+typedef struct {
+  JSObjectMap map;
+  void *backend;
+} jso_ObjectMap;
+
+static JSObjectMap *
+jop_newMap(JSContext *cx, jsrefcount nrefs,
+            JSObjectOps *ops, JSClass *clasp,
+            JSObject *obj)
+{
+  /*
+    The object map stores property information for the object, and is
+    created when the object is created. 
+  */
+  JSObjectMap *map;
+  jso_ObjectMap *emap;
+
+#if LOG_OBJECT_OPS
+  NSLog(@"new map: cx=0x%08X, nrefs=%i, ops=0x%08X, class=0x%08X, obj=0x%08X",
+       cx, nrefs, ops, clasp, obj);
+#endif
+  
+  map  = js_ObjectOps.newObjectMap(cx, nrefs, ops, clasp, obj);
+  emap = calloc(1, sizeof(jso_ObjectMap));
+  memcpy(emap, map, sizeof(JSObjectMap));
+  free(map);
+  return (JSObjectMap *)emap;
+}
+
+static void jop_delMap(JSContext *cx, JSObjectMap *map) {
+  /* the function that destroys the object map when it is no longer needed. */
+  js_ObjectOps.destroyObjectMap(cx, map);
+}
+
+static JSBool jop_lookup(JSContext *cx, JSObject *obj, jsid jid,
+                         JSObject **objp, JSProperty **propp
+#if defined JS_THREADSAFE && defined DEBUG
+                           , const char *file, uintN line
+#endif
+                         )
+{
+  /* custom property lookup method for the object. */
+}
+
+static JSBool jop_define(JSContext *cx, JSObject *obj, jsid jid, jsval value,
+                         JSPropertyOp getter, JSPropertyOp setter,
+                         uintN attrs, JSProperty **propp)
+{
+  /* custom property creation method for the object. */
+}
+
+static JSBool jop_get(JSContext *cx, JSObject *obj, jsid jid, jsval *vp) {
+}
+static JSBool jop_set(JSContext *cx, JSObject *obj, jsid jid, jsval *vp) {
+}
+static JSBool jop_del(JSContext *cx, JSObject *obj, jsid jid, jsval *vp) {
+}
+
+static JSBool jop_attrsget(JSContext *cx, JSObject *obj, jsid jid,
+                           JSProperty *prop, uintN *attrsp)
+{
+}
+static JSBool jop_attrsset(JSContext *cx, JSObject *obj, jsid jid,
+                           JSProperty *prop, uintN *attrsp)
+{
+}
+
+static JSBool 
+jop_defValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
+{
+}
+
+static JSBool jop_enum(JSContext *cx, JSObject *obj,
+                       JSIterateOp enum_op,
+                       jsval *statep, jsid *idp)
+{
+}
+
+static JSBool jop_chkaccess(JSContext *cx, JSObject *obj, jsid jid,
+                            JSAccessMode mode, jsval *vp, uintN *attrsp)
+{
+}
+
+struct JSObjectOps NGJavaScriptObjectHandler_JSObjectOps = {
+  /* Mandatory non-null function pointer members. */
+  jop_newMap,    /* JSNewObjectMapOp    newObjectMap; */
+  jop_delMap,    /* JSObjectMapOp       destroyObjectMap; */
+  jop_lookup,    /* JSLookupPropOp      lookupProperty; */
+  jop_define,    /* JSDefinePropOp      defineProperty; */
+  jop_get,       /* JSPropertyIdOp      getProperty; */
+  jop_set,       /* JSPropertyIdOp      setProperty; */
+  jop_attrsget,  /* JSAttributesOp      getAttributes; */
+  jop_attrsset,  /* JSAttributesOp      setAttributes; */
+  jop_del,       /* JSPropertyIdOp      deleteProperty; */
+  jop_defValue,  /* JSConvertOp         defaultValue; */
+  jop_enum,      /* JSNewEnumerateOp    enumerate; */
+  jop_chkaccess, /* JSCheckAccessIdOp   checkAccess; */
+  
+  /* Optionally non-null members start here. */
+  NULL, /* JSObjectOp          thisObject; */
+  NULL, /* JSPropertyRefOp     dropProperty; */
+  NULL, /* JSNative            call; */
+  NULL, /* JSNative            construct; */
+  NULL, /* JSXDRObjectOp       xdrObject; */
+  NULL, /* JSHasInstanceOp     hasInstance; */
+  NULL, /* JSSetObjectSlotOp   setProto; */
+  NULL, /* JSSetObjectSlotOp   setParent; */
+  0,    /* jsword              spare1; */
+  0,    /* jsword              spare2; */
+  0,    /* jsword              spare3; */
+  0,    /* jsword              spare4; */
+};
+
+/* JS class */
+
+static JSObjectOps *_getObjOps(JSContext *cx, JSClass *clazz) {
+  return &NGJavaScriptObjectHandler_JSObjectOps;
+}
+
+static JSBool _convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) {
+  return JS_TRUE;
+}
+
+static void _finalize(JSContext *cx, JSObject *obj) {
+}
+
+struct JSClass NGJavaScriptObjectHandler_JSObjectOpsClass = {
+  "ObjC",
+  JSCLASS_HAS_PRIVATE,
+  NULL, NULL, NULL, NULL,
+  NULL, NULL, 
+  _convert,
+  _finalize,
+  /* Optionally non-null members start here. */
+  _getObjOps, //JSGetObjectOps getObjectOps;
+  NULL, //JSCheckAccessOp checkAccess;
+  NULL, //JSNative call;
+  NULL, //JSNative construct;
+  NULL, //JSXDRObjectOp xdrObject;
+  NULL  //JSHasInstanceOp hasInstance;
+  //prword spare[2];
+};
diff --git a/skyrix-sope/NGJavaScript/NGJavaScript-Info.plist b/skyrix-sope/NGJavaScript/NGJavaScript-Info.plist
new file mode 100644 (file)
index 0000000..ed180f1
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGJavaScript</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.NGJavaScript</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/NGJavaScript/NGJavaScript.h b/skyrix-sope/NGJavaScript/NGJavaScript.h
new file mode 100644 (file)
index 0000000..a7dc551
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScript_H__
+#define __NGJavaScript_H__
+
+#include <NGJavaScript/NGJavaScriptContext.h>
+#include <NGJavaScript/NGJavaScriptFunction.h>
+#include <NGJavaScript/NGJavaScriptObject.h>
+#include <NGJavaScript/NGJavaScriptObjectHandler.h>
+#include <NGJavaScript/NGJavaScriptRuntime.h>
+
+#include <NGJavaScript/NSObject+JS.h>
+
+#include <NGJavaScript/NGJavaScriptObjectMappingContext.h>
+
+#endif /* __NGJavaScript_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptArray.m b/skyrix-sope/NGJavaScript/NGJavaScriptArray.m
new file mode 100644 (file)
index 0000000..d4bed9e
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptObject.h"
+#include "NGJavaScriptContext.h"
+#include "NGJavaScriptObjectMappingContext.h"
+#include "common.h"
+
+#define ARCHIVE_AS_NSARRAY 1
+
+@interface NGJavaScriptArray(Private)
+- (NSArray *)convertToNSArray;
+@end
+
+@implementation NGJavaScriptArray
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+#if NeXT_RUNTIME || APPLE_RUNTIME || GNUSTEP_BASE_LIBRARY
+    NSLog(@"WARNING(%s): adding NSMutableArray behaviour to "
+          @"NGJavaScriptArray is not supported with the current"
+          @"runtime!", __PRETTY_FUNCTION__);
+    /* TODO: port to MacOSX/GNUstep */
+#else
+    class_add_behavior(self, [NSMutableArray class]);
+#endif
+  }
+}
+
+- (void *)createJSObjectForJSClass:(void *)_class inJSContext:(void *)jsctx {
+  /* this is called by initWithClassHandle ... */
+  return JS_NewArrayObject(jsctx, 0 /* length */, NULL /* vector */);
+  //return JS_NewObject(jsctx, _class, NULL, NULL);
+}
+
++ (void *)jsObjectClass {
+  return &js_ArrayClass;
+}
+
+/* convert to array */
+
+- (NSArray *)convertToNSArray {
+  jsint   i, count;
+  id      *objs;
+  NSArray *array;
+  
+  if (!JS_GetArrayLength(self->jscx, self->handle, &count))
+    return nil;
+  
+  if (count <= 0)
+    return [NSArray array];
+
+  objs = calloc(count, sizeof(id));
+  for (i = 0; i < count; i++) {
+    static id null = nil;
+    jsval val;
+
+    if (null == nil)
+      null = [[NSClassFromString(@"EONull") alloc] init];
+
+    if (!JS_GetElement(self->jscx, self->handle, i, &val))
+      objs[i] = null;
+    else
+      objs[i] = [self->ctx objectForJSValue:&val];
+  }
+  array = [[NSArray alloc] initWithObjects:objs count:count];
+  free(objs);
+  return [array autorelease];
+}
+
+- (NSArray *)copyWithZone:(NSZone *)_zone {
+  return [[self convertToNSArray] copyWithZone:_zone];
+}
+- (NSMutableArray *)mutableCopyWithZone:(NSZone *)_zone {
+  return [[self convertToNSArray] mutableCopyWithZone:_zone];
+}
+
+/* NSCoding */
+
+#if ARCHIVE_AS_NSARRAY
+
+- (id)replacementObjectForCoder:(NSCoder*)anEncoder {
+  id array;
+  
+  array = [[[self convertToNSArray] mutableCopy] autorelease];
+  NSLog(@"%s: replace %@ with %@", __PRETTY_FUNCTION__, self, array);
+  return array;
+}
+#if 0
+- (Class)classForCoder {
+  return [NSMutableArray class];
+}
+#endif
+#endif
+
+- (void)decodeJavaScriptPropertiesWithCoder:(NSCoder *)_coder {
+  unsigned i, count;
+  
+  [_coder decodeValueOfObjCType:@encode(unsigned) at:&count];
+  for (i = 0; i < count; i++) {
+    id obj = [_coder decodeObject];
+    [self addObject:obj];
+  }
+}
+- (void)encodeJavaScriptPropertiesWithCoder:(NSCoder *)_coder {
+  unsigned i, count;
+  
+  count = [self count];
+  [_coder encodeValueOfObjCType:@encode(unsigned) at:&count];
+  
+  for (i = 0; i < count; i++)
+    [_coder encodeObject:[self objectAtIndex:i]];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [[self convertToNSArray] description];
+}
+
+@end /* NGJavaScriptArray */
+
+@implementation NGJavaScriptArray(NSArrayCompatibility)
+
+- (unsigned)count {
+  jsint v;
+  
+  if (JS_GetArrayLength(self->jscx, self->handle, &v))
+    return v;
+  
+  return 0;
+}
+
+- (id)objectAtIndex:(unsigned)_idx {
+  jsval obj;
+
+  if (JS_GetElement(self->jscx, self->handle, _idx, &obj))
+    return [self->ctx objectForJSValue:&obj];
+  
+  /* get failed */
+  return nil;
+}
+
+- (NSEnumerator *)objectEnumerator {
+  return [[self convertToNSArray] objectEnumerator];
+}
+
+- (id)lastObject {
+  jsint v;
+
+  if (JS_GetArrayLength(self->jscx, self->handle, &v)) {
+    jsval obj;
+
+    if (JS_GetElement(self->jscx, self->handle, v, &obj))
+      return [self->ctx objectForJSValue:&obj];
+  }
+  /* failed */
+  return nil;
+}
+
+- (BOOL)containsObject:(id)_obj {
+  // to be improved ...
+  return [[self convertToNSArray] containsObject:_obj];
+}
+
+/* Deriving New Array */
+
+- (NSArray *)arrayByAddingObject:(id)anObject {
+  return [[self convertToNSArray] arrayByAddingObject:anObject];
+}
+- (NSArray *)arrayByAddingObjectsFromArray:(NSArray *)anotherArray {
+  return [[self convertToNSArray] arrayByAddingObjectsFromArray:anotherArray];
+}
+
+- (NSArray *)sortedArrayUsingFunction:
+  (int(*)(id element1, id element2, void *userData))comparator
+  context:(void*)context
+{
+  return [[self convertToNSArray]
+                sortedArrayUsingFunction:comparator
+                context:context];
+}
+- (NSArray *)sortedArrayUsingSelector:(SEL)comparator {
+  return [[self convertToNSArray] sortedArrayUsingSelector:comparator];
+}
+
+- (NSArray *)subarrayWithRange:(NSRange)_range {
+  // to be improved ...
+  return [[self convertToNSArray] subarrayWithRange:_range];
+}
+
+@end /* NGJavaScriptArray(NSArrayCompatibility) */
+
+@implementation NGJavaScriptArray(NSMutableArrayCompatibility)
+
+- (void)setObject:(id)_obj atIndex:(unsigned)_idx {
+  jsval obj;
+  
+  if ([self->ctx jsValue:&obj forObject:_obj]) {
+    if (JS_SetElement(self->jscx, self->handle, _idx, &obj))
+      // ok
+      return;
+  }
+  
+  NSAssert2(NO, @"set element failed (%@ at idx %d) !", self, _idx);
+}
+
+static inline void
+_removeObjectsFrom(NGJavaScriptArray *self,
+                   unsigned int _idx, unsigned int _count)
+{
+  jsint i, itemsCount;
+
+#if 0
+  /* cannot use DeleteElement ! this doesn't adjust indizes !! */
+  NSAssert(JS_DeleteElement(self->jscx, self->handle, _idx),
+           @"delete-element failed in JS");
+#endif
+  
+  if (_count == 0)
+    return;
+  if (!JS_GetArrayLength(self->jscx, self->handle, &itemsCount))
+    goto failed;
+  if ((_idx + _count) > itemsCount)
+    goto failed;
+
+  /* move to front */
+  for (i = (_idx + _count); i < itemsCount; i++, _idx++) {
+    jsval val;
+    
+    if (!JS_GetElement(self->jscx, self->handle, i, &val))
+      goto failed;
+    
+    if (!JS_SetElement(self->jscx, self->handle, _idx, &val))
+      goto failed;
+  }
+  
+  /* shorten array */
+  if (JS_SetArrayLength(self->jscx, self->handle, itemsCount - _count)) {
+    /* ok */
+    return;
+  }
+  
+ failed:
+  NSCAssert3(NO, @"element remove failed (%@ at idx %d,%d) !",
+             self, _idx, _count);
+}
+
+- (void)removeObjectsInRange:(NSRange)aRange {
+  _removeObjectsFrom(self, aRange.location, aRange.length);
+}
+- (void)removeAllObjects {
+  _removeObjectsFrom(self, 0, [self count]);
+}
+- (void)removeLastObject {
+  unsigned itemsCount;
+  itemsCount = [self count];
+  if (itemsCount > 0) _removeObjectsFrom(self, (itemsCount - 1), 1);
+}
+- (void)removeObjectAtIndex:(unsigned)_idx {
+  _removeObjectsFrom(self, _idx, 1);
+}
+
+- (void)insertObject:(id)_object atIndex:(unsigned)_idx {
+  jsval obj;
+  jsint i, itemsCount;
+
+#if 0
+  NSLog(@"%s: before: %@", __PRETTY_FUNCTION__,
+        [[[self convertToNSArray]
+                valueForKey:@"description"]
+                componentsJoinedByString:@","]);
+#endif
+  
+  if (!JS_GetArrayLength(self->jscx, self->handle, &itemsCount))
+    goto failed;
+  
+  if (_idx > itemsCount)
+    /* range exception ... */
+    goto failed;
+  
+  /* move items up */
+  for (i = itemsCount; i > _idx; i--) {
+    jsval val;
+    
+    if (!JS_GetElement(self->jscx, self->handle, (i - 1), &val))
+      goto failed;
+    
+    if (!JS_SetElement(self->jscx, self->handle, i, &val))
+      goto failed;
+  }
+  
+  /* get JS value of new object */
+  if (![self->ctx jsValue:&obj forObject:_object])
+    goto failed;
+  
+  /* place new item */
+  if (JS_SetElement(self->jscx, self->handle, _idx, &obj)) {
+    /* ok */
+#if 0
+    NSLog(@"%s: after: %@", __PRETTY_FUNCTION__,
+          [[[self convertToNSArray]
+                  valueForKey:@"description"]
+                  componentsJoinedByString:@","]);
+#endif
+    return;
+  }
+  
+ failed:
+  NSAssert2(NO, @"element insert failed (%@ at idx %d) !", self, _idx);
+}
+- (void)addObject:(id)_object {
+  [self insertObject:_object atIndex:[self count]];
+}
+
+@end /* NGJavaScriptArray(NSMutableArrayCompatibility) */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptCallable.h b/skyrix-sope/NGJavaScript/NGJavaScriptCallable.h
new file mode 100644 (file)
index 0000000..09a9d0d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScriptCallable_H__
+#define __NGJavaScriptCallable_H__
+
+#include <NGJavaScript/NGJavaScriptObject.h>
+
+@interface NGJavaScriptCallable : NGJavaScriptObject
+@end
+
+#endif /* __NGJavaScriptCallable_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptCallable.m b/skyrix-sope/NGJavaScript/NGJavaScriptCallable.m
new file mode 100644 (file)
index 0000000..1a3f956
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptCallable.h"
+#include "common.h"
+
+@implementation NGJavaScriptCallable
+
+static void _finalize(JSContext *cx, JSObject *obj);
+
+JSClass NGJavaScriptCallable_JSClass = {
+  "NGJavaScriptCallable",
+  JSCLASS_HAS_PRIVATE /* flags */,
+  JS_PropertyStub,
+  JS_PropertyStub,
+  JS_PropertyStub,
+  JS_PropertyStub,
+  JS_EnumerateStub,
+  JS_ResolveStub,
+  JS_ConvertStub,
+  _finalize,
+  /* Optionally non-null members start here. */
+  NULL, //JSGetObjectOps getObjectOps;
+  NULL, //JSCheckAccessOp checkAccess;
+  NULL, //JSNative call;
+  NULL, //JSNative construct;
+  NULL, //JSXDRObjectOp xdrObject;
+  NULL, //JSHasInstanceOp hasInstance;
+  //prword spare[2];
+};
+
++ (void *)jsObjectClass {
+  return &NGJavaScriptCallable_JSClass;
+}
+
+static void _finalize(JSContext *cx, JSObject *obj) {
+  NGJavaScriptCallable *self;
+  
+  if ((self = JS_GetPrivate(cx, obj)) == nil) {
+    JS_FinalizeStub(cx, obj);
+  }
+  else if (self->handle == obj) {
+  }
+  else {
+#if DEBUG
+    fprintf(stderr, "%s: aborting ..\n", __PRETTY_FUNCTION__);
+    abort();
+#else
+    fprintf(stderr, "%s: invalid finalize ..\n", __PRETTY_FUNCTION__);
+#endif
+  }
+}
+
+@end /* NGJavaScriptCallable */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptContext.h b/skyrix-sope/NGJavaScript/NGJavaScriptContext.h
new file mode 100644 (file)
index 0000000..197c3a4
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScriptContext_H__
+#define __NGJavaScriptContext_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSException;
+@class NGJavaScriptRuntime;
+
+@interface NGJavaScriptContext : NSObject
+{
+  NGJavaScriptRuntime *rt;
+  void                *handle;
+
+  NSException *lastError;
+}
+
++ (NGJavaScriptContext *)jsContextForHandle:(void *)_handle;
+
+- (id)initWithRuntime:(NGJavaScriptRuntime *)_rt
+  maximumStackSize:(unsigned)_size;
+- (id)initWithRuntime:(NGJavaScriptRuntime *)_rt;
+- (id)init;
+
+- (BOOL)loadStandardClasses;
+
+/* private */
+
+- (void *)handle;
+
+/* accessors */
+
+- (NGJavaScriptRuntime *)runtime;
+
+- (BOOL)isRunning;
+- (BOOL)isConstructing;
+
+- (void)setJavaScriptVersion:(int)_version;
+- (int)javaScriptVersion;
+
+/* evaluation */
+
+- (id)evaluateScript:(NSString *)_script;
+
+/* invocation */
+
+- (id)callFunctionNamed:(NSString *)_funcName, ...;
+
+/* errors */
+
+- (void)reportException:(NSException *)_exc;
+- (void)reportError:(NSString *)_fmt, ...;
+- (void)reportOutOfMemory;
+
+- (void)reportError:(NSString *)_msg
+  inFile:(NSString *)_path inLine:(unsigned)_line
+  report:(void *)_report;
+- (NSException *)lastError;
+- (void)clearLastError;
+
+/* garbage collector */
+
+- (void)collectGarbage;
+- (void)maybeCollectGarbage;
+
+- (void *)malloc:(unsigned)_size;
+- (void *)realloc:(void *)_pointer size:(unsigned)_size;
+- (void)freePointer:(void *)_pointer;
+
+- (BOOL)addRootPointer:(void *)_root;
+- (BOOL)addRootPointer:(void *)_root name:(NSString *)_name;
+- (BOOL)removeRootPointer:(void *)_root;
+
+- (BOOL)lockGCThing:(void *)_ptr;
+- (BOOL)unlockGCThing:(void *)_ptr;
+
+- (BOOL)beginGarbageCollection;
+- (BOOL)endGarbageCollection;
+
+/* threads */
+
+- (void)beginRequest;
+- (void)endRequest;
+- (void)suspendRequest;
+- (void)resumeRequest;
+
+@end
+
+#endif /* __NGJavaScriptContext_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptContext.m b/skyrix-sope/NGJavaScript/NGJavaScriptContext.m
new file mode 100644 (file)
index 0000000..7a01796
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptContext.h"
+#include "NGJavaScriptRuntime.h"
+#include "NGJavaScriptObject.h"
+#include "NGJavaScriptFunction.h"
+#include "NGJavaScriptObjectHandler.h"
+#include "NGJavaScriptError.h"
+#include "NSString+JS.h"
+#include "common.h"
+
+
+@interface NGJavaScriptContext(PrivateMethods)
+
+@end
+
+static JSBool
+Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+
+@implementation NGJavaScriptContext
+
+static BOOL abortOnJSError = NO;
+static BOOL debugDealloc   = NO;
+NSMapTable *jsctxToObjC = NULL;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  abortOnJSError = [ud boolForKey:@"JSAbortOnError"];
+  debugDealloc   = [ud boolForKey:@"JSDebugContextDealloc"];
+}
+
+static JSFunctionSpec functions[] = {
+    {"print",           Print,          0},
+    {0}
+};
+
+
+static void jsErrorReporter(JSContext *cx, const char *msg, JSErrorReport *rp);
+static JSBool jsGCCallback(JSContext *cx, JSGCStatus status)
+     __attribute__((unused));
+
+
+static JSBool global_resolve(JSContext *cx, JSObject *obj, jsval _id)
+     __attribute__((unused));
+static JSBool global_resolve(JSContext *cx, JSObject *obj, jsval _id) {
+  NGJavaScriptContext *self;
+  
+  self = NSMapGet(jsctxToObjC, cx);
+  
+  NSLog(@"resolve called on %@.", self);
+  return JS_ResolveStub(cx, obj, _id);
+}
+
++ (NGJavaScriptContext *)jsContextForHandle:(void *)_handle {
+  NGJavaScriptContext *ctx;
+
+  ctx = NSMapGet(jsctxToObjC, _handle);
+  return ctx;
+}
+
+- (id)initWithRuntime:(NGJavaScriptRuntime *)_rt
+  maximumStackSize:(unsigned)_size
+{
+  self->handle = JS_NewContext([_rt handle], _size ? _size : 8192);
+  if (self->handle == NULL) {
+    NSLog(@"WARNING(%s): got no handle !", __PRETTY_FUNCTION__);
+    [self release];
+    return nil;
+  }
+  
+  if (jsctxToObjC == NULL) {
+    jsctxToObjC = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
+                                   NSNonRetainedObjectMapValueCallBacks,
+                                   200);
+  }
+  NSMapInsert(jsctxToObjC, self->handle, self);
+  JS_SetErrorReporter(self->handle, jsErrorReporter);
+  
+  // JSSetGCCallback(self->handle, jsGCCallback);
+  
+#if 0
+  /* setup initial global */
+  {
+    NGJavaScriptObject *oglob;
+    
+    oglob = [[NGJavaScriptObject alloc] initWithJSContext:self];
+    if (oglob == nil) {
+      [self release];
+      return nil;
+    }
+    [oglob makeGlobal];
+    
+    [oglob release]; oglob = nil;
+  }
+#endif
+  
+  ASSIGN(self->rt, _rt);
+  
+  return self;
+}
+- (id)initWithRuntime:(NGJavaScriptRuntime *)_rt {
+  return [self initWithRuntime:_rt maximumStackSize:0];
+}
+- (id)init {
+  return [self initWithRuntime:[NGJavaScriptRuntime standardJavaScriptRuntime]
+               maximumStackSize:0];
+}
+
+- (void)dealloc {
+  if (debugDealloc) NSLog(@"dealloc context: %@", self);
+  
+  [self collectGarbage];
+  
+  if (self->handle) {
+    JS_DestroyContext(self->handle);
+    NSMapRemove(jsctxToObjC, self->handle);
+  }
+
+  [self->rt release];
+  [super dealloc];
+  
+  if (debugDealloc) NSLog(@"did dealloc context: 0x%08X", self);
+}
+
+- (BOOL)loadStandardClasses {
+  JSObject *glob;
+  
+  if ((glob = JS_GetGlobalObject(self->handle)) == NULL) {
+    NSLog(@"NGJavaScriptContext: no global object set ..");
+    return NO;
+  }
+  
+  //NSLog(@"NGJavaScriptContext: loading std classes ..");
+  
+  if (!JS_InitStandardClasses(self->handle, glob)) {
+    NSLog(@"NGJavaScriptContext: could not init standard classes ...");
+    return NO;
+  }
+  if (!JS_DefineFunctions(self->handle, glob, functions)) {
+    NSLog(@"NGJavaScriptContext: could not define global funcs ...");
+    return NO;
+  }
+  
+  return YES;
+}
+
+- (void *)handle {
+  return self->handle;
+}
+
+/* accessors */
+
+- (NGJavaScriptRuntime *)runtime {
+  return self->rt;
+}
+
+- (BOOL)isRunning {
+  return JS_IsRunning(self->handle) ? YES : NO;
+}
+
+- (BOOL)isConstructing {
+  return JS_IsConstructing(self->handle) ? YES : NO;
+}
+
+- (void)setJavaScriptVersion:(int)_version {
+  JS_SetVersion(self->handle, _version);
+}
+- (int)javaScriptVersion {
+  return JS_GetVersion(self->handle);
+}
+
+/* global object */
+
+- (id)globalObject {
+  JSObject                  *global;
+  NGJavaScriptObjectHandler *oglobal;
+  
+  global = JS_GetGlobalObject(self->handle);
+  NSAssert(global, @"missing global object !");
+  
+  if ((oglobal = JS_GetPrivate(self->handle, global)) == nil)
+    return nil;
+  
+  return [[oglobal retain] autorelease];
+}
+
+/* evaluation */
+
+- (id)evaluateScript:(NSString *)_script {
+  return [[self globalObject] evaluateScript:_script];
+}
+
+/* invocation */
+
+- (id)callFunctionNamed:(NSString *)_funcName, ... {
+  return [[self globalObject] callFunctionNamed:_funcName, nil];
+}
+
+/* errors */
+
+- (void)reportException:(NSException *)_exc {
+  JS_ReportError(self->handle, "%s", [[_exc description] cString]);
+}
+
+- (void)reportError:(NSString *)_fmt, ... {
+  NSString *s;
+  va_list va;
+  
+  va_start(va, _fmt);
+
+#if NG_VARARGS_AS_REFERENCE /* in common.h */
+  s = [[[NSString alloc] initWithFormat:_fmt arguments:va] autorelease];
+#else
+  s = [NSString stringWithFormat:_fmt arguments:&va];
+#endif
+  va_end(va);
+  
+  JS_ReportError(self->handle, "%s", [s cString]);
+}
+
+- (void)reportOutOfMemory {
+  JS_ReportOutOfMemory(self->handle);
+}
+
+- (void)logReportedJavaScriptError:(NGJavaScriptError *)_error {
+  NSLog(@"JS ERROR(%@:%d): %@", [_error path], [_error line], [_error reason]);
+  if (abortOnJSError) abort();
+}
+
+- (void)reportError:(NSString *)_msg
+  inFile:(NSString *)_path inLine:(unsigned)_line
+  report:(void *)_report
+{
+  NGJavaScriptError *e;
+  
+  e = [[NGJavaScriptError alloc] initWithErrorReport:_report message:_msg context:self];
+  
+  [self logReportedJavaScriptError:e];
+  if ([[NSUserDefaults standardUserDefaults] boolForKey:@"AbortOnJSError"])
+    abort();
+    
+  ASSIGN(self->lastError, e);
+
+  if ([[NSUserDefaults standardUserDefaults] boolForKey:@"RaiseOnJSError"])
+    [self->lastError raise];
+}
+
+- (NSException *)lastError {
+  return self->lastError;
+}
+- (void)clearLastError {
+  [self->lastError release]; self->lastError = nil;
+}
+
+/* garbage collector */
+
+- (void)collectGarbage {
+  JS_GC(self->handle);
+}
+- (void)maybeCollectGarbage {
+  JS_MaybeGC(self->handle);
+}
+
+- (void *)malloc:(unsigned)_size {
+  return JS_malloc(self->handle, _size);
+}
+- (void *)realloc:(void *)_pointer size:(unsigned)_size {
+  return JS_realloc(self->handle, _pointer, _size);
+}
+- (void)freePointer:(void *)_pointer {
+  JS_free(self->handle, _pointer);
+}
+
+- (BOOL)addRootPointer:(void *)_root {
+  return JS_AddRoot(self->handle, _root) ? YES : NO;
+}
+- (BOOL)addRootPointer:(void *)_root name:(NSString *)_name {
+  return JS_AddNamedRoot(self->handle, _root, [_name cString]) ? YES : NO;
+}
+- (BOOL)removeRootPointer:(void *)_root {
+  return JS_RemoveRoot(self->handle, _root) ? YES : NO;
+}
+
+- (BOOL)lockGCThing:(void *)_ptr {
+  return JS_LockGCThing(self->handle, _ptr) ? YES : NO;
+}
+- (BOOL)unlockGCThing:(void *)_ptr {
+  return JS_UnlockGCThing(self->handle, _ptr) ? YES : NO;
+}
+
+- (BOOL)beginGarbageCollection {
+  return YES;
+}
+- (BOOL)endGarbageCollection {
+  return YES;
+}
+
+/* threads */
+
+#if JS_THREADSAFE
+- (void)beginRequest {
+  JS_BeginRequest(self->handle);
+}
+- (void)endRequest {
+  JS_EndRequest(self->handle);
+}
+- (void)suspendRequest {
+  JS_SuspendRequest(self->handle);
+}
+- (void)resumeRequest {
+  JS_ResumeRequest(self->handle);
+}
+#else
+- (void)beginRequest {
+#if LIB_FOUNDATION_LIBRARY
+  [self notImplemented:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+#endif
+}
+- (void)endRequest {
+#if LIB_FOUNDATION_LIBRARY
+  [self notImplemented:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+#endif
+}
+- (void)suspendRequest {
+#if LIB_FOUNDATION_LIBRARY
+  [self notImplemented:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+#endif
+}
+- (void)resumeRequest {
+#if LIB_FOUNDATION_LIBRARY
+  [self notImplemented:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+#endif
+}
+#endif
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<%@[0x%08X]: %@%@handle=0x%08X version=%i runtime=%@>",
+                     NSStringFromClass([self class]), self,
+                     [self isRunning]      ? @"running "      : @"",
+                     [self isConstructing] ? @"constructing " : @"",
+                     [self handle],
+                     [self javaScriptVersion],
+                     [self runtime]];
+}
+
+/* statics */
+
+static void jsErrorReporter(JSContext *cx, const char *msg, JSErrorReport *rp) {
+  NGJavaScriptContext *self;
+
+  self = NSMapGet(jsctxToObjC, cx);
+
+  if (self == NULL) {
+    fprintf(stderr, "ERROR(missing ObjC object): %s\n", msg);
+  }
+  
+  [self reportError:msg?[NSString stringWithCString:msg]:@"unknown JavaScript error"
+        inFile:rp->filename?[NSString stringWithCString:rp->filename]:@""
+        inLine:rp->lineno
+        report:rp];
+}
+
+static JSBool jsGCCallback(JSContext *cx, JSGCStatus status) {
+  NGJavaScriptContext *self;
+  
+  self = NSMapGet(jsctxToObjC, cx);
+
+  return (status == JSGC_BEGIN)
+    ? ([self beginGarbageCollection] ? JSVAL_TRUE : JSVAL_FALSE)
+    : ([self endGarbageCollection]   ? JSVAL_TRUE : JSVAL_FALSE);
+}
+
+@end /* NGJavaScriptContext */
+
+static JSBool
+Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+    uintN i, n;
+    JSString *str;
+
+    for (i = n = 0; i < argc; i++) {
+       str = JS_ValueToString(cx, argv[i]);
+       if (!str)
+           return JS_FALSE;
+       fprintf(stdout, "%s%s", i ? " " : "", JS_GetStringBytes(str));
+    }
+    n++;
+    if (n)
+        fputc('\n', stdout);
+    return JS_TRUE;
+}
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptDecls.h b/skyrix-sope/NGJavaScript/NGJavaScriptDecls.h
new file mode 100644 (file)
index 0000000..c64c16c
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScriptDecls_H__
+#define __NGJavaScriptDecls_H__
+
+#if BUILD_libNGJavaScript_DLL
+#  define NGJavaScript_EXPORT  __declspec(dllexport)
+#  define NGJavaScript_DECLARE __declspec(dllexport)
+#elif libNGJavaScript_ISDLL
+#  define NGJavaScript_EXPORT  extern __declspec(dllimport)
+#  define NGJavaScript_DECLARE extern __declspec(dllimport)
+#else
+#  define NGJavaScript_EXPORT  extern
+#  define NGJavaScript_DECLARE 
+#endif
+
+#endif /* __NGJavaScriptDecls_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptError.h b/skyrix-sope/NGJavaScript/NGJavaScriptError.h
new file mode 100644 (file)
index 0000000..c56a9f4
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScript_NGJavaScriptError_H__
+#define __NGJavaScript_NGJavaScriptError_H__
+
+#import <Foundation/NSException.h>
+
+@class NSString;
+@class NGJavaScriptContext;
+
+@interface NGJavaScriptError : NSException
+{
+  NGJavaScriptContext *cx;
+  unsigned int flags;
+}
+
+- (id)initWithErrorReport:(void *)_report
+  message:(NSString *)_msg 
+  context:(NGJavaScriptContext *)_ctx;
+  
+/* accessors */
+
+- (NSString *)path;
+- (int)line;
+- (NSString *)message;
+- (int)errorNumber;
+
+/* JS error flags */
+
+- (BOOL)isJSError;
+- (BOOL)isJSWarning;
+- (BOOL)isJSException;
+- (BOOL)isJSStrictViolation;
+
+@end
+
+#endif /* __NGJavaScript_NGJavaScriptError_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptError.m b/skyrix-sope/NGJavaScript/NGJavaScriptError.m
new file mode 100644 (file)
index 0000000..17df767
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptError.h"
+#include "NGJavaScriptContext.h"
+#include "common.h"
+
+@implementation NGJavaScriptError
+
+- (id)initWithErrorReport:(void *)_report
+  message:(NSString *)_msg 
+  context:(NGJavaScriptContext *)_ctx
+{
+#if 0 // JSErrorReport
+    const char      *filename;      /* source file name, URL, etc., or null */
+    uintN           lineno;         /* source line number */
+    const char      *linebuf;       /* offending source line without final \n */
+    const char      *tokenptr;      /* pointer to error token in linebuf */
+    const jschar    *uclinebuf;     /* unicode (original) line buffer */
+    const jschar    *uctokenptr;    /* unicode (original) token pointer */
+    uintN           flags;          /* error/warning, etc. */
+    uintN           errorNumber;    /* the error number, e.g. see js.msg */
+    const jschar    *ucmessage;     /* the (default) error message */
+    const jschar    **messageArgs;  /* arguments for the error message */
+#endif
+  JSErrorReport       *rp = _report;
+  NSMutableDictionary *ui;
+  NSString *lReason;
+  
+  ui = [NSMutableDictionary dictionaryWithCapacity:8];
+  
+  if (_msg) {
+    lReason = [[_msg copy] autorelease];
+    [ui setObject:lReason forKey:@"message"];
+  }
+  else
+    lReason = @"no JavaScript reason available";
+
+  if (rp->filename) 
+    [ui setObject:[NSString stringWithCString:rp->filename] forKey:@"path"];
+  if (rp->lineno > 0)
+    [ui setObject:[NSNumber numberWithUnsignedInt:rp->lineno] forKey:@"line"];
+  if (rp->errorNumber > 0)
+    [ui setObject:[NSNumber numberWithUnsignedInt:rp->errorNumber] forKey:@"faultCode"];
+    
+  if (rp->linebuf)
+    [ui setObject:[NSString stringWithCString:rp->linebuf] forKey:@"source"];
+  
+  self = [self initWithName:@"JavaScriptError"
+               reason:lReason
+               userInfo:ui];
+  self->cx    = [_ctx retain];
+  self->flags = rp->flags;
+  return self;
+}
+- (void)dealloc {
+  [self->cx release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)path {
+  return [[self userInfo] objectForKey:@"path"];
+}
+- (int)line {
+  return [[[self userInfo] objectForKey:@"line"] intValue];
+}
+- (NSString *)sourceLine {
+  return [[self userInfo] objectForKey:@"source"];
+}
+- (NSString *)message {
+  return [self reason];
+}
+- (int)errorNumber {
+  return [[[self userInfo] objectForKey:@"faultCode"] intValue];
+}
+
+- (BOOL)isJSError {
+  return (self->flags & JSREPORT_ERROR) == JSREPORT_ERROR ? YES : NO;
+}
+- (BOOL)isJSWarning {
+  return (self->flags & JSREPORT_WARNING) == JSREPORT_WARNING ? YES : NO;
+}
+- (BOOL)isJSException {
+  return (self->flags & JSREPORT_EXCEPTION) == JSREPORT_EXCEPTION ? YES : NO;
+}
+- (BOOL)isJSStrictViolation {
+  return (self->flags & JSREPORT_STRICT) == JSREPORT_STRICT ? YES : NO;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms = [NSMutableString stringWithCapacity:64];
+  id tmp;
+  
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  if (self->cx)
+    [ms appendFormat:@" cx=0x%08X", self->cx];
+  else
+    [ms appendString:@" no-cx"];
+  
+  if ([self isJSError])     [ms appendString:@" error"];
+  if ([self isJSWarning])   [ms appendString:@" warning"];
+  if ([self isJSException]) [ms appendString:@" exception"];
+  if ([self isJSStrictViolation]) [ms appendString:@" strict"];
+  
+  [ms appendFormat:@" code=%i", [self errorNumber]];
+  
+  if ((tmp = [self path]))
+    [ms appendFormat:@" path=%@:%i", tmp, [self line]];
+  if ((tmp = [self reason]))
+    [ms appendFormat:@" reason=%@", tmp];
+  if ((tmp = [self sourceLine]))
+    [ms appendFormat:@" source=%@", tmp];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* NGJavaScriptError */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptFunction.h b/skyrix-sope/NGJavaScript/NGJavaScriptFunction.h
new file mode 100644 (file)
index 0000000..2e0cfc6
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScriptFunction_H__
+#define __NGJavaScriptFunction_H__
+
+#include <NGJavaScript/NGJavaScriptObject.h>
+
+@class NGJavaScriptContext;
+
+@interface NGJavaScriptFunction : NGJavaScriptObject
+{
+  void *function;
+  id   mapCtx; /* non-retained */
+}
+
+#if 0
+- (id)initWithHandle:(void *)_handle mappingContext:(id)_mapCtx;
+
+/* private */
+
+- (void *)handle;
+#endif
+
+/* accessors */
+
+- (NSString *)functionName;
+
+/* typing */
+
+- (BOOL)isJavaScriptFunction;
+
+/* compilation */
+
+- (NSString *)decompileBodyWithIndent:(unsigned)_indent
+  inContext:(NGJavaScriptContext *)_ctx;
+- (NSString *)decompileWithIndent:(unsigned)_indent
+  inContext:(NGJavaScriptContext *)_ctx;
+
+@end
+
+@interface NSObject(JSFuncTyping)
+- (BOOL)isJavaScriptFunction;
+@end
+
+#endif /* __NGJavaScriptFunction_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptFunction.m b/skyrix-sope/NGJavaScript/NGJavaScriptFunction.m
new file mode 100644 (file)
index 0000000..0700aba
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptFunction.h"
+#include "NGJavaScriptContext.h"
+#include "NGJavaScriptObject.h"
+#include "NGJavaScriptObjectMappingContext.h"
+#include "NSString+JS.h"
+#include "common.h"
+
+@implementation NGJavaScriptFunction
+
+/* accessors */
+
+- (NSString *)functionName {
+  return [NSString stringWithCString:JS_GetFunctionName(self->handle)];
+}
+
+/* typing */
+
+- (BOOL)isJavaScriptFunction {
+  return YES;
+}
+- (BOOL)isScriptFunction {
+  return YES;
+}
+
+/* compilation */
+
+- (NSString *)decompileBodyWithIndent:(unsigned)_indent
+  inContext:(NGJavaScriptContext *)_ctx
+{
+  JSString *s;
+
+  s = JS_DecompileFunctionBody([_ctx handle], self->handle, _indent);
+  return [NSString stringWithJavaScriptString:s];
+}
+
+- (NSString *)decompileWithIndent:(unsigned)_indent
+  inContext:(NGJavaScriptContext *)_ctx
+{
+  JSString *s;
+
+  s = JS_DecompileFunction([_ctx handle], self->handle, _indent);
+  return [NSString stringWithJavaScriptString:s];
+}
+
+/* NSCoding */
+
+- (id)initWithCoder:(NSCoder *)_coder {
+  NSAssert(NO, @"decoding of functions not supported yet ...");
+  return nil;
+}
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  NSAssert(NO, @"encoding of functions not supported yet ...");
+}
+
+@end /* NGJavaScriptFunction */
+
+@implementation NSObject(JSFuncTyping)
+
+- (BOOL)isJavaScriptFunction {
+  return NO;
+}
+
+@end /* NSObject(JSFuncTyping) */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptLanguage.m b/skyrix-sope/NGJavaScript/NGJavaScriptLanguage.m
new file mode 100644 (file)
index 0000000..3e8519e
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGScripting/NGScriptLanguage.h>
+
+@interface NGJavaScriptLanguage : NGScriptLanguage
+{
+  id rootctx;
+} 
+
+@end
+
+#include "NGJavaScriptObjectMappingContext.h"
+#include "NGJavaScriptContext.h"
+#include "NGJavaScriptShadow.h"
+#include "NGJavaScriptRuntime.h"
+#include "NSObject+JS.h"
+#include "common.h"
+
+@implementation NGJavaScriptLanguage
+
+- (id)initWithLanguage:(NSString *)_language {
+  if ((self = [super initWithLanguage:_language])) {
+    NSLog(@"%@", [NGJavaScriptRuntime javaScriptImplementationVersion]);
+    
+    self->rootctx = [[NGJavaScriptObjectMappingContext alloc] init];
+    [[self->rootctx jsContext] loadStandardClasses];
+    [self->rootctx pushContext];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->rootctx popContext];
+  [self->rootctx release];
+  [super dealloc];
+}
+
+- (NSString *)language {
+  return @"javascript";
+}
+
+- (id)evaluateScript:(NSString *)_script onObject:(id)_object 
+  source:(NSString *)_source line:(unsigned)_line
+{
+  NGJavaScriptObjectMappingContext *mctx;
+  JSBool      res;
+  jsval       lastValue;
+  void        *jso;
+  void        *cx;
+  NSException *e;
+  const char *srcname = NULL;
+  
+  mctx = [NGJavaScriptObjectMappingContext activeObjectMappingContext];
+  NSAssert(mctx, @"no javascript mapping context is active !");
+  
+  jso = [mctx handleForObject:_object];
+  NSAssert(jso, @"missing JS object ..");
+  
+  cx = [[mctx jsContext] handle];
+  
+  if ([_source hasPrefix:@"file://"])
+    _source = [_source substringFromIndex:7];
+  // TODO: use buffer
+  srcname = [_source cString];
+  
+#if 0
+  NSLog(@"%s:%i eval script on objc=0x%08X js=0x%08X cx=0x%08X", 
+       [_source cString], _line,
+       _object, jso, cx);
+#endif
+  
+  res = JS_EvaluateScript(cx, jso,
+                          [_script cString],
+                          [_script cStringLength],
+                          srcname, /* source file */
+                          _line,   /* line number */
+                          &lastValue);
+  
+  if (res == JS_TRUE)
+    return [mctx objectForJSValue:&lastValue];
+  
+  if ([(e = [[mctx jsContext] lastError]) retain]) {
+    
+    [[mctx jsContext] clearLastError];
+    [[mctx jsContext] collectGarbage];
+    //[[mctx jsContext] collectGarbage];
+    //[[mctx jsContext] collectGarbage];
+    
+    [e raise];
+  }
+  
+  {
+    NSDictionary *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _script,             @"script",
+                         _object,             @"objectHandler",
+                         [NGJavaScriptContext jsContextForHandle:cx],
+                           @"jscontext",
+                         nil];
+    
+    e = [[NSException alloc] initWithName:@"JavaScriptEvalException"
+                             reason:@"couldn't evaluate script"
+                             userInfo:ui];
+    [e raise];
+  }
+  return nil;
+}
+
+/* functions */
+
+- (id)callFunction:(NSString *)_func onObject:(id)_object {
+  NGJavaScriptObjectMappingContext *mctx;
+  JSBool ret;
+  void   *jso;
+  jsval  result;
+  
+  mctx = [NGJavaScriptObjectMappingContext activeObjectMappingContext];
+  NSAssert(mctx, @"no javascript mapping context is active !");
+  
+  jso = [mctx handleForObject:_object];
+  NSAssert(jso, @"missing JS object ..");
+  
+  ret = JS_CallFunctionName([[mctx jsContext] handle],
+                            jso,
+                            [_func cString],
+                            0 /* argc */, NULL /* argv */,
+                            &result);
+  if (ret == JS_TRUE)
+    return [mctx objectForJSValue:&result];
+  
+  NSLog(@"%s: couldn't run function %@", __PRETTY_FUNCTION__, _func);
+  return nil;
+}
+
+- (id)callFunction:(NSString *)_func
+  withArgument:(id)_arg0
+  onObject:(id)_object 
+{
+  NGJavaScriptObjectMappingContext *mctx;
+  JSBool ret;
+  void   *jso;
+  jsval  result;
+  jsval  argv[1];
+  
+  mctx = [NGJavaScriptObjectMappingContext activeObjectMappingContext];
+  NSAssert(mctx, @"no javascript mapping context is active !");
+  
+  jso = [mctx handleForObject:_object];
+  NSAssert(jso, @"missing JS object ..");
+  
+  if (![mctx jsValue:&(argv[0]) forObject:_arg0]) {
+    NSLog(@"%s: couldn't get value for first function argument ..",
+          __PRETTY_FUNCTION__);
+    return nil;
+  }
+  
+  ret = JS_CallFunctionName([[mctx jsContext] handle],
+                            jso,
+                            [_func cString],
+                            1, argv,
+                            &result);
+  if (ret == JS_TRUE)
+    return [mctx objectForJSValue:&result];
+  
+  NSLog(@"%s: couldn't run function %@", __PRETTY_FUNCTION__, _func);
+  return nil;
+}
+- (id)callFunction:(NSString *)_func
+  withArgument:(id)_arg0
+  withArgument:(id)_arg1
+  onObject:(id)_object 
+{
+  NGJavaScriptObjectMappingContext *mctx;
+  JSBool ret;
+  void   *jso;
+  jsval  result;
+  jsval  argv[2];
+  
+  mctx = [NGJavaScriptObjectMappingContext activeObjectMappingContext];
+  NSAssert(mctx, @"no javascript mapping context is active !");
+  
+  jso = [mctx handleForObject:_object];
+  NSAssert(jso, @"missing JS object ..");
+  
+  if (![mctx jsValue:&(argv[0]) forObject:_arg0]) {
+    NSLog(@"%s: couldn't get value for first function argument ..",
+          __PRETTY_FUNCTION__);
+    return nil;
+  }
+  
+  if (![mctx jsValue:&(argv[1]) forObject:_arg1]) {
+    NSLog(@"%s: couldn't get value for second function argument ..",
+          __PRETTY_FUNCTION__);
+    return nil;
+  }
+  
+  ret = JS_CallFunctionName([[mctx jsContext] handle],
+                            jso,
+                            [_func cString],
+                            2, argv,
+                            &result);
+  if (ret == JS_TRUE)
+    return [mctx objectForJSValue:&result];
+  
+  NSLog(@"%s: couldn't run function %@", __PRETTY_FUNCTION__, _func);
+  return nil;
+}
+
+/* reflection */
+
+- (BOOL)object:(id)_object hasFunctionNamed:(NSString *)_name {
+  return [_object hasFunctionNamed:_name];
+}
+
+/* shadow objects */
+
+- (id)createShadowForMaster:(id)_master {
+  NGJavaScriptShadow *shadow;
+  
+  if (_master == nil)
+    /* no shadow without a master ... */
+    return nil;
+  
+  if ((shadow = [[NGJavaScriptShadow alloc] init]) == nil) {
+    NSLog(@"%s: could not create shadow for master %@", 
+         __PRETTY_FUNCTION__, _master);
+    return nil;
+  }
+  
+  [shadow setMasterObject:_master];
+  
+  return shadow; /* returns a retained object */
+}
+
+/* mapping ctx */
+
+- (NGObjectMappingContext *)createMappingContext {
+  NGJavaScriptObjectMappingContext *ctx;
+  
+  ctx = [[NGJavaScriptObjectMappingContext alloc] init];
+  [[ctx jsContext] loadStandardClasses];
+  return ctx;
+}
+
+@end /* NGJavaScriptLanguage */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptObjCClassInfo.h b/skyrix-sope/NGJavaScript/NGJavaScriptObjCClassInfo.h
new file mode 100644 (file)
index 0000000..e4bca0b
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScriptObjCClassInfo_H__
+#define __NGJavaScriptObjCClassInfo_H__
+
+#include "common.h"
+#import <Foundation/NSMapTable.h>
+
+@class NSString, NSArray, NSMutableDictionary;
+
+/*
+  This class determines and stores the mapping information for 
+  Objective-C objects, that is, the properties and selectors of
+  the class which are exposed to JavaScript.
+  It should be probably modified to mirror the AppleScript classes in
+  Foundation, that is, we should add a NGScriptClassDescription etc.
+  
+  Property Mapping: Objective-C classes export properties by
+  declaring get/set accessor methods that start with "_jsprop_":
+  
+    - (id)_jsprop_a;
+    
+  to retrieve a property named "a" and
+  
+    - (void)_jsprop_a:(id)_value
+    
+  to set a property named "a". If no set accessors can be found,
+  the property is registered as a read-only field.
+  
+  Function Mapping: functions are exported by declaring a single
+  argument selector that starts with "_jsfunc_", eg:
+  
+    - (id)_jsfunc_doIt:(NSArray *)_args;
+  
+  declares a JavaScript function named "doIt()".
+*/
+
+@interface NGJavaScriptObjCClassInfo : NSObject
+{
+  Class          clazz;
+  NSArray        *jsFuncNames;
+  NSArray        *jsPropNames;
+  NSArray        *jsReadOnlyPropNames;
+  JSFunctionSpec *funcSpecs;
+  unsigned char  tinyId;
+  NSMapTable     *idToKey;
+  JSPropertyOp   setter;
+  JSPropertyOp   getter;
+  JSNative       caller;
+}
+
+- (id)initWithClass:(Class)_clazz
+  setter:(JSPropertyOp)_setter
+  getter:(JSPropertyOp)_getter
+  caller:(JSNative)_caller;
+
+- (NSArray *)jsFuncNames;
+- (NSArray *)jsPropNames;
+- (NSArray *)jsReadOnlyPropNames;
+
+- (JSFunctionSpec *)functionSpecs;
+
+- (BOOL)isStaticProperty:(NSString *)_prop;
+
+/* resolving IDs */
+
+- (SEL)getSelectorForPropertyId:(void *)_idval inJSContext:(void *)_cx;
+- (SEL)setSelectorForPropertyId:(void *)_idval inJSContext:(void *)_cx;
+
+/* apply on JSObject */
+
+- (BOOL)applyOnJSObject:(void *)_jso inJSContext:(void *)_cx;
+
+@end
+
+#endif /* __NGJavaScriptObjCClassInfo_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptObjCClassInfo.m b/skyrix-sope/NGJavaScript/NGJavaScriptObjCClassInfo.m
new file mode 100644 (file)
index 0000000..53c6694
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptObjCClassInfo.h"
+#include "NGJavaScriptObjectHandler.h"
+#include <NGExtensions/NGObjCRuntime.h>
+#include "globals.h"
+#include "common.h"
+
+#if 0
+#  warning needs to be rewritten for tinyIds
+#endif
+
+@interface NGJavaScriptObjectHandler(Misc)
++ (void *)jsStaticFuncDispatcher;
+@end
+
+#ifndef JSPROP_NOSLOT
+// new in 1.5 rc3
+#  define PROP_READONLY_FLAGS  (JSPROP_READONLY | JSPROP_SHARED)
+#  define PROP_READWRITE_FLAGS (JSPROP_SHARED)
+#else
+// special version of 1.5 rc
+#  define PROP_READONLY_FLAGS  (JSPROP_READONLY | JSPROP_NOSLOT)
+#  define PROP_READWRITE_FLAGS (JSPROP_NOSLOT)
+#endif
+//#define PROP_READONLY_FLAGS  (JSPROP_READONLY | JSPROP_PERMANENT)
+
+@implementation NGJavaScriptObjCClassInfo
+
+- (id)initWithClass:(Class)_clazz
+  setter:(JSPropertyOp)_setter
+  getter:(JSPropertyOp)_getter
+  caller:(JSNative)_caller
+{
+  NSEnumerator   *e;
+  NSString       *mname;
+  NSMutableArray *funcs;
+  NSMutableArray *props;
+  NSMutableArray *roProps;
+  
+  self->clazz  = _clazz;
+  self->setter = _setter;
+  self->getter = _getter;
+  self->caller = _caller;
+  
+  funcs = props = roProps = nil;
+  
+  self->idToKey = NSCreateMapTable(NSIntMapKeyCallBacks,
+                                   NSOwnedPointerMapValueCallBacks,
+                                   64);
+  
+  e = [_clazz hierachyMethodNameEnumerator];
+  while ((mname = [e nextObject])) {
+    if ([mname hasPrefix:@"_jsfunc_"]) {
+      NSString *f;
+      
+      if (funcs == nil)
+        funcs = [NSMutableArray arrayWithCapacity:64];
+
+      f = [mname substringFromIndex:8];
+      f = [f substringToIndex:([f length] - 1)];
+      
+      [funcs addObject:f];
+    }
+    else if ([mname hasPrefix:@"_jsprop_"] && ![mname hasSuffix:@":"]) {
+      char     *buf;
+      unsigned len;
+      NSString *propName;
+      SEL      setSel;
+      
+      len = [mname length];
+      buf = malloc(len + 3);
+      [mname getCString:buf];
+      
+      propName = [NSString stringWithCString:&(buf[8])];
+
+      /* get set-selector */
+      buf[len] = ':';
+      buf[len + 1] = '\0';
+#if NeXT_RUNTIME || APPLE_RUNTIME
+      setSel = sel_getUid(buf);
+#else
+      setSel = sel_get_uid(buf);
+#endif
+
+      if ((setSel != NULL) && [_clazz instancesRespondToSelector:setSel]) {
+        if (props == nil)
+          props = [NSMutableArray arrayWithCapacity:64];
+        [props addObject:propName];
+      }
+      else {
+        if (roProps == nil)
+          roProps = [NSMutableArray arrayWithCapacity:64];
+        [roProps addObject:propName];
+      }
+    }
+  }
+  
+  self->jsFuncNames = [funcs copy];
+  self->jsPropNames = [props copy];
+  self->jsReadOnlyPropNames = [roProps copy];
+  
+  return self;
+}
+
+- (void)dealloc {
+  //NSLog(@"DEALLOC ClassInfo ..");
+
+#if 0 // BUGGY, need to leak
+  if (self->funcSpecs) {
+    unsigned i;
+    
+    while (self->funcSpecs[i].name)
+      free((void *)self->funcSpecs[i].name);
+    
+    free(self->funcSpecs);
+  }
+  if (self->idToKey) {
+    NSFreeMapTable(self->idToKey);
+    self->idToKey = NULL;
+  }
+#endif
+  [self->jsFuncNames         release];
+  [self->jsReadOnlyPropNames release];
+  [self->jsPropNames         release];
+  [super dealloc];
+}
+
+- (NSArray *)jsFuncNames {
+  return self->jsFuncNames;
+}
+- (NSArray *)jsPropNames {
+  return self->jsPropNames;
+}
+- (NSArray *)jsReadOnlyPropNames {
+  return self->jsReadOnlyPropNames;
+}
+
+- (JSFunctionSpec *)functionSpecs {
+  unsigned i, count;
+  
+  if (self->funcSpecs)
+    return self->funcSpecs;
+  
+  if ((count = [self->jsFuncNames count]) == 0)
+    return NULL;
+  
+  self->funcSpecs = calloc(count + 1, sizeof(JSFunctionSpec));
+  for (i = 0; i < count; i++) {
+    NSString *oname;
+    unsigned clen;
+    
+    oname = [self->jsFuncNames objectAtIndex:i];
+    clen  = [oname cStringLength];
+    
+    self->funcSpecs[i].name = malloc(clen + 4);
+    [oname getCString:(char *)self->funcSpecs[i].name];
+    
+    //NSLog(@"  def JS func '%s'\n", self->funcSpecs[i].name);
+    
+    self->tinyId++;
+    // TODO: explain the comment below
+    //***BUG: copy 'name'!
+    NSMapInsert(self->idToKey, (void*)(int)self->tinyId,
+                self->funcSpecs[i].name);
+    
+    self->funcSpecs[i].call  = self->caller;
+    self->funcSpecs[i].nargs = 0;
+    self->funcSpecs[i].flags = 0;
+    self->funcSpecs[i].extra = 0;
+  }
+  return self->funcSpecs;
+}
+
+- (BOOL)isStaticProperty:(NSString *)_prop {
+  if ([self->jsFuncNames containsObject:_prop])
+    return YES;
+  if ([self->jsReadOnlyPropNames containsObject:_prop])
+    return YES;
+  if ([self->jsPropNames containsObject:_prop])
+    return YES;
+  return NO;
+}
+
+/* resolving IDs */
+
+- (SEL)getSelectorForPropertyId:(void *)_idval inJSContext:(void *)_cx {
+  jsval      _id = *(jsval *)_idval;
+  const char *propName = NULL;
+  SEL        sel       = NULL;
+  
+  if (JSVAL_IS_STRING(_id)) {
+    if ((propName = JS_GetStringBytes(JS_ValueToString(_cx, _id))) == NULL)
+      NSLog(@"%s: got no string for string id val ..", __PRETTY_FUNCTION__);
+  }
+  else if (JSVAL_IS_INT(_id)) {
+    int ttid;
+    
+    ttid = JSVAL_TO_INT(_id);
+    if ((propName = NSMapGet(self->idToKey, (void*)(int)ttid)) == NULL)
+      NSLog(@"%s: got no INT id val %i ..", __PRETTY_FUNCTION__, ttid);
+  }
+  else {
+#if DEBUG
+    NSLog(@"%s: GOT invalid id value ..", __PRETTY_FUNCTION__);
+    abort();
+#else
+    NSLog(@"%s: GOT invalid id value ..", __PRETTY_FUNCTION__);
+    return NULL;
+#endif
+  }
+  
+  if (propName) {
+    char *msgname;
+    
+    msgname = malloc(strlen(propName) + 12);
+    strcpy(msgname, "_jsprop_");
+    strcat(msgname, propName);
+#if NeXT_RUNTIME
+    sel = sel_getUid(msgname);
+#else
+    sel = sel_get_any_uid(msgname);
+#endif
+    if (sel == NULL)
+      NSLog(@"%s: got no selector for msg '%s'", __PRETTY_FUNCTION__, msgname);
+    free(msgname);
+  }
+  return sel;
+}
+- (SEL)setSelectorForPropertyId:(void *)_idval inJSContext:(void *)_cx {
+  jsval      _id = *(jsval *)_idval;
+  const char *propName = NULL;
+  SEL        sel       = NULL;
+  
+  if (JSVAL_IS_STRING(_id)) {
+    if ((propName = JS_GetStringBytes(JS_ValueToString(_cx, _id))) == NULL)
+      NSLog(@"%s: got no string for string id val ..", __PRETTY_FUNCTION__);
+  }
+  else if (JSVAL_IS_INT(_id)) {
+    int ttid;
+    
+    ttid     = JSVAL_TO_INT(_id);
+    if ((propName = NSMapGet(self->idToKey, (void*)(int)ttid)) == NULL)
+      NSLog(@"%s: got no INT id val %i ..", __PRETTY_FUNCTION__, ttid);
+  }
+  else {
+#if DEBUG
+    NSLog(@"%s: GOT invalid id value ..", __PRETTY_FUNCTION__);
+    abort();
+#else
+    NSLog(@"%s: GOT invalid id value ..", __PRETTY_FUNCTION__);
+    return NULL;
+#endif
+  }
+
+  if (propName) {
+    char *msgname;
+    
+    msgname = malloc(strlen(propName) + 12);
+    strcpy(msgname, "_jsprop_");
+    strcat(msgname, propName);
+    strcat(msgname, ":");
+
+#if NeXT_RUNTIME
+    sel = sel_getUid(msgname);
+#else
+    sel = sel_get_any_uid(msgname);
+#endif
+    if (sel == NULL)
+      NSLog(@"%s: got no selector for msg '%s'", __PRETTY_FUNCTION__, msgname);
+    free(msgname);
+  }
+  
+  return sel;
+}
+
+/* apply on JSObject */
+
+- (unsigned char)tinyIdForKey:(NSString *)_key {
+  char *ckey;
+  
+  self->tinyId++;
+  ckey = malloc([_key cStringLength] + 1);
+  [_key getCString:ckey];
+  NSMapInsert(self->idToKey, (void*)(int)self->tinyId, ckey);
+  
+  return self->tinyId;
+}
+
+- (JSBool)defineProperty:(NSString *)mname readOnly:(BOOL)_ro
+  onObject:(void *)_jso inJSContext:(void *)_cx
+{
+  JSBool ret;
+  
+  if (NGJavaScriptBridge_LOG_PROP_DEFINITION) {
+    NSLog(@"%s: definition of %@ property '%@' on j0x%08X",
+          __PRETTY_FUNCTION__, _ro ? @"ro/noslot" : @"rw/noslot", 
+         mname, _jso);
+  }
+
+#if WITH_TINY_ID
+  ret = JS_DefinePropertyWithTinyId(_cx, _jso,
+                                    [mname cString],
+                                    [self tinyIdForKey:mname],
+                                    JSVAL_NULL,
+                                    self->getter, ro ? NULL : self->setter,
+                                    _ro ? PROP_READONLY_FLAGS : PROP_READWRITE_FLAGS);
+#else
+  ret = JS_DefineProperty(_cx, _jso,
+                          [mname cString],
+                          JSVAL_NULL,
+                          self->getter, _ro ? NULL : self->setter,
+                          _ro ? PROP_READONLY_FLAGS : PROP_READWRITE_FLAGS);
+#endif
+  return ret;
+}
+
+- (BOOL)applyOnJSObject:(void *)_jso inJSContext:(void *)_cx {
+  NSEnumerator *mnames;
+  NSString     *mname;
+  JSFunctionSpec *fspecs;
+  
+  if ((fspecs = [self functionSpecs])) {  
+    if (!JS_DefineFunctions(_cx, _jso, fspecs)) {
+      NSLog(@"ERROR(%s): couldn't define static JS functions (0x%08X) on "
+           @"JSObject 0x%08X in JSContext 0x%08X ..", 
+           __PRETTY_FUNCTION__, fspecs, _jso, _cx);
+      return NO;
+    }
+  }
+  
+  mnames = [[self jsPropNames] objectEnumerator];
+  while ((mname = [mnames nextObject])) {
+    JSBool ret;
+    
+    ret = [self defineProperty:mname readOnly:NO 
+                onObject:_jso inJSContext:_cx];
+    if (!ret) {
+      NSLog(@"ERROR(%s): couldn't define property '%@' on "
+           @"JSObject 0x%08X in JSContext 0x%08X", 
+           __PRETTY_FUNCTION__, mname, _jso, _cx);
+      continue;
+    }
+  }
+  
+  mnames = [[self jsReadOnlyPropNames] objectEnumerator];
+  while ((mname = [mnames nextObject])) {
+    JSBool ret;
+    
+    ret = [self defineProperty:mname readOnly:YES
+                onObject:_jso inJSContext:_cx];
+    if (!ret)
+      continue;
+  }
+
+  return YES;
+}
+
+@end /* NGJavaScriptObjCClassInfo */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptObject.h b/skyrix-sope/NGJavaScript/NGJavaScriptObject.h
new file mode 100644 (file)
index 0000000..8a303b4
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScriptObject_H__
+#define __NGJavaScriptObject_H__
+
+#import <Foundation/NSObject.h>
+#include "NSObject+JS.h"
+
+/*
+  NGJavaScriptObject
+  
+  Related: NGJavaScriptObjectHandler, see docu
+  
+  Hm, what is the difference between the handler and the object ?
+  => find out and document
+  
+  Note: this object keeps a retained reference to the context.
+*/
+
+@class NSEnumerator, NSArray, NSString, NSDictionary;
+@class NGObjectMappingContext;
+@class NGJavaScriptObjectMappingContext;
+
+@interface NGJavaScriptObject : NSObject < NSCoding >
+{
+  NGJavaScriptObjectMappingContext *ctx;
+  void *jscx;     /* cached JSContext handle         */
+  void *handle;   /* the handle of the object itself */
+  BOOL addedRoot; /* was a root-ref added            */
+}
+
+- (id)initWithHandle:(void *)_handle
+  inMappingContext:(NGObjectMappingContext *)_ctx;
+
+/* private */
+
+- (void *)handle;
+- (void)makeGlobal;
+- (void *)_jsHandleInMapContext:(NGObjectMappingContext *)_ctx;
+
+/* misc */
+
+- (void)applyStandardClasses;
+
+- (void)setParentObject:(id)_parent;
+- (id)parentObject;
+- (NSEnumerator *)parentObjectChain;
+
+- (void)setPrototypeObject:(id)_proto;
+- (id)prototypeObject;
+- (NSEnumerator *)prototypeObjectChain;
+
+- (BOOL)hasPropertyNamed:(NSString *)_key;
+- (BOOL)hasFunctionNamed:(NSString *)_key;
+
+/* a function object */
+
+- (BOOL)isJavaScriptFunction;
+- (id)callOn:(id)_this;
+- (id)callOn:(id)_this withObject:(id)_arg0;
+
+/* mimic an NSDictionary */
+
+- (void)setObject:(id)_value forKey:(id)_key;
+- (id)objectForKey:(id)_key;
+- (void)removeObjectForKey:(id)_key;
+- (NSEnumerator *)keyEnumerator;
+- (NSEnumerator *)objectEnumerator;
+- (NSArray *)allKeys;
+- (NSArray *)allValues;
+
+/* convert to dictionary */
+
+- (NSDictionary *)convertToNSDictionary;
+
+/* KVC */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key;
+- (id)valueForKey:(NSString *)_key;
+
+@end
+
+#import <Foundation/NSArray.h>
+
+/* this class gets the NSMutableArray behaviour added !!! */
+
+@interface NGJavaScriptArray : NGJavaScriptObject < NSCopying >
+
+/* convert to array */
+
+- (NSArray *)convertToNSArray;
+
+@end
+
+@interface NGJavaScriptArray(NSArrayCompatibility)
+
+- (unsigned)count;
+- (id)objectAtIndex:(unsigned)_idx;
+- (NSEnumerator *)objectEnumerator;
+- (id)lastObject;
+
+- (NSArray *)arrayByAddingObject:(id)anObject;
+- (NSArray *)arrayByAddingObjectsFromArray:(NSArray *)anotherArray;
+
+- (NSArray *)sortedArrayUsingFunction:
+  (int(*)(id element1, id element2, void *userData))comparator
+  context:(void*)context;
+
+@end
+
+@interface NGJavaScriptArray(NSMutableArrayCompatibility)
+
+- (void)setObject:(id)_obj atIndex:(unsigned)_idx;
+
+- (void)removeObjectsInRange:(NSRange)aRange;
+- (void)removeAllObjects;
+- (void)removeLastObject;
+- (void)removeObjectAtIndex:(unsigned)_idx;
+
+- (void)insertObject:(id)_object atIndex:(unsigned)_idx;
+- (void)addObject:(id)_object;
+
+@end
+
+#endif /* __NGJavaScriptObject_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptObject.m b/skyrix-sope/NGJavaScript/NGJavaScriptObject.m
new file mode 100644 (file)
index 0000000..5d5c674
--- /dev/null
@@ -0,0 +1,711 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGJavaScriptObject.h"
+#include "NGJavaScriptContext.h"
+#include <NGExtensions/NGExtensions.h>
+#include <NGScripting/NGObjectMappingContext.h>
+#include "NGJavaScriptObjectMappingContext.h"
+#include "common.h"
+#include "globals.h"
+
+//#define GREEDY_ARCHIVE 1
+
+@interface JSIDEnum : NSEnumerator
+{
+  NGJavaScriptObjectMappingContext *ctx;
+  JSContext *cx;
+  JSIdArray *idArray;
+  unsigned  pos;
+  id        object;
+}
+- (id)initWithIdArray:(JSIdArray *)_array 
+  mappingContext:(NGJavaScriptObjectMappingContext *)_ctx;
+- (id)initWithIdArray:(JSIdArray *)_array 
+  object:(id)_object
+  mappingContext:(NGJavaScriptObjectMappingContext *)_ctx;
+@end
+
+@interface JSObjChainEnum : NSEnumerator
+{
+  id  object;
+  SEL selector;
+}
+- (id)initWithObject:(id)_obj selector:(SEL)_sel;
+@end
+
+@implementation NGJavaScriptObject
+
+- (id)initWithHandle:(void *)_handle
+  inMappingContext:(NGObjectMappingContext *)_ctx
+{
+  NSAssert(_handle, @"Missing handle ..");
+  NSAssert(_ctx,    @"Missing context ..");
+
+  self->handle = _handle;
+  self->ctx    = [_ctx retain];
+  
+  self->jscx =
+    [[(NGJavaScriptObjectMappingContext *)self->ctx jsContext] handle];
+  
+  self->addedRoot =
+    JS_AddNamedRoot(self->jscx, &(self->handle), self->isa->name);
+  NSAssert(self->addedRoot, @"couldn't add root !");
+  
+  return self;
+}
+
++ (void *)jsObjectClass {
+  return NULL;
+}
+
+- (void *)createJSObjectForJSClass:(void *)_class inJSContext:(void *)jsctx {
+  return JS_NewObject(jsctx, _class, NULL, NULL);
+}
+
+- (id)initWithJSClass:(void *)_class {
+  NGJavaScriptObjectMappingContext *mctx;
+  
+  if ((mctx = [NGJavaScriptObjectMappingContext activeObjectMappingContext])) {
+    void *jsctx;
+    void *jso;
+    
+    jsctx = [[mctx jsContext] handle];
+    
+    if ((jso = [self createJSObjectForJSClass:_class inJSContext:jsctx])) {
+      self = [self initWithHandle:jso inMappingContext:mctx];
+      [mctx registerObject:self forImportedHandle:jso];
+      return self;
+    }
+    else {
+      [self release]; self = nil;
+      
+      [NSException raise:@"NGJavaScriptException"
+                   format:@"couldn't create JS object .."];
+      return nil;
+    }
+  }
+  [self release];
+  [NSException raise:@"NGJavaScriptException"
+               format:@"missing active mapping context !"];
+  return nil;
+}
+- (id)init {
+  return [self initWithJSClass:[[self class] jsObjectClass]];
+}
+
+- (void)dealloc {
+  if (NGJavaScriptBridge_TRACK_MEMORY) {
+    NSLog(@"%s: dealloc o0x%08X j0x%08X ctx=0x%08X jcx=0x%08X",
+          __PRETTY_FUNCTION__, self, self->handle,
+          self->ctx, self->jscx);
+  }
+  
+  if (self->handle) {
+    if (self->addedRoot)
+      JS_RemoveRoot(self->jscx, &self->handle);
+    [self->ctx forgetImportedHandle:self->handle];
+  }
+  else {
+    if (self->addedRoot)
+      NSLog(@"%s: missing handle !, couldn't remove root ..", __PRETTY_FUNCTION__);
+  }
+  
+  [self->ctx release];
+  [super dealloc];
+}
+
+/* transformation */
+
+- (BOOL)_jsGetValue:(void *)_value inJSContext:(NGJavaScriptContext *)_ctx {
+  *((jsval *)_value) = OBJECT_TO_JSVAL(self->handle);
+  return YES;
+}
+- (void *)_jsHandleInMapContext:(NGObjectMappingContext *)_ctx {
+  return self->handle;
+}
+
+/* misc */
+
+- (void)applyStandardClasses {
+  if (!JS_InitStandardClasses(self->jscx, self->handle)) {
+    NSLog(@"couldn't load standard classes into JS object %@", self);
+    return;
+  }
+}
+
+- (void)setParentObject:(id)_parent {
+  JSObject *p;
+  
+  p = [self->ctx handleForObject:_parent];
+  
+  if (JS_SetParent(self->jscx, self->handle, p) == JS_FALSE) {
+    NSLog(@"couldn't set parent of object %@", self);
+  }
+}
+- (id)parentObject {
+  JSObject *p;
+  
+  if ((p = JS_GetParent(self->jscx, self->handle)) == NULL)
+    return nil;
+  
+  return [self->ctx objectForHandle:p];
+}
+
+- (NSEnumerator *)parentObjectChain {
+  NSEnumerator *e;
+  
+  e = [[JSObjChainEnum alloc] 
+       initWithObject:self selector:@selector(parentObject)];
+  return [e autorelease];
+}
+
+- (void)setPrototypeObject:(id)_proto {
+  JSObject *p;
+  
+  p = [self->ctx handleForObject:_proto];
+  
+  if (JS_SetPrototype(self->jscx, self->handle, p) == JS_FALSE) {
+    NSLog(@"couldn't set prototype of object %@", self);
+  }
+}
+- (id)prototypeObject {
+  JSObject *p;
+  
+  if ((p = JS_GetPrototype(self->jscx, self->handle)) == NULL)
+    return nil;
+  
+  return [self->ctx objectForHandle:p];
+}
+
+- (NSEnumerator *)prototypeObjectChain {
+  NSEnumerator *e;
+  
+  e = [[JSObjChainEnum alloc] 
+       initWithObject:self selector:@selector(prototypeObject)];
+  return AUTORELEASE(e);
+}
+
+- (BOOL)hasPropertyNamed:(NSString *)_key {
+  JSBool ret;
+  jsval  val = JSVAL_VOID;
+  unsigned int  clen;
+  unsigned char *ckey;
+  
+  clen = [_key cStringLength];
+  ckey = malloc(clen + 1);
+  [_key getCString:ckey];
+  
+  ret = JS_LookupProperty(self->jscx, self->handle, ckey, &val);
+  if (ret == JS_FALSE) {
+    NSLog(@"%s: WARNING: couldn't lookup property '%@'",
+          __PRETTY_FUNCTION__, _key);
+    free(ckey);
+    return NO;
+  }
+  if (val == JSVAL_VOID)
+    return NO;
+
+  return YES;
+}
+
+- (BOOL)hasFunctionNamed:(NSString *)_key {
+  JSBool        ret;
+  jsval         val = JSVAL_VOID;
+  unsigned int  clen;
+  unsigned char *ckey;
+  JSType        jsType;
+  
+  clen = [_key cStringLength];
+  ckey = malloc(clen + 1);
+  [_key getCString:ckey];
+  
+  ret = JS_GetProperty(self->jscx, self->handle, ckey, &val);
+  if (ret == JS_FALSE) {
+    NSLog(@"WARNING: couldn't lookup property '%@'", _key);
+    free(ckey);
+    return NO;
+  }
+  if (val == JSVAL_VOID)
+    return NO;
+  
+  jsType = JS_TypeOfValue(self->jscx, val);
+
+  return jsType == JSTYPE_FUNCTION ? YES : NO;
+}
+
+/* functions */
+
+- (BOOL)isJavaScriptFunction {
+  jsval  val;
+  JSType jsType;
+  
+  val = OBJECT_TO_JSVAL(self->handle);
+  if (val == JSVAL_VOID)
+    return NO;
+  
+  jsType = JS_TypeOfValue(self->jscx, val);
+
+  return jsType == JSTYPE_FUNCTION ? YES : NO;
+}
+- (BOOL)isScriptFunction {
+  return [self isJavaScriptFunction];
+}
+
+- (id)_callOn:(id)_this argc:(int)_argc argv:(jsval *)_argv {
+  jsval    val;
+  JSBool   ret;
+  jsval    result;
+  JSObject *jso;
+  
+  val = OBJECT_TO_JSVAL(self->handle);
+  jso = [self->ctx handleForObject:_this];
+  
+  ret = JS_CallFunctionValue(self->jscx, jso, val,
+                             _argc, _argv,
+                             &result);
+  if (ret == JS_TRUE)
+    return [self->ctx objectForJSValue:&result];
+  
+  NSLog(@"%s: couldn't run function %@", __PRETTY_FUNCTION__, self);
+  return nil;
+}
+- (id)callOn:(id)_this {
+  return [self _callOn:_this argc:0 argv:NULL];
+}
+- (id)callOn:(id)_this withObject:(id)_arg0 {
+  jsval arg0;
+  
+  if ([self->ctx jsValue:&arg0 forObject:_arg0])
+    return [self _callOn:_this argc:1 argv:&arg0];
+  
+  NSLog(@"%s: couldn't convert arg0 %@ for function %@", __PRETTY_FUNCTION__,
+        _arg0, self);
+  return nil;
+}
+
+/* mimic dictionary */
+
+- (NSArray *)allKeys {
+  NSEnumerator   *e;
+  NSString       *key;
+  NSMutableArray *keys;
+  
+  if ((e = [self keyEnumerator]) == nil) return nil;
+  keys = [NSMutableArray arrayWithCapacity:8];
+  while ((key = [e nextObject]))
+    [keys addObject:key];
+  return keys;
+}
+- (NSArray *)allValues {
+  NSEnumerator   *e;
+  id object;
+  NSMutableArray *keys;
+  
+  if ((e = [self objectEnumerator]) == nil) return nil;
+  keys = [NSMutableArray arrayWithCapacity:8];
+  while ((object = [e nextObject]))
+    [keys addObject:object];
+  return keys;
+}
+
+- (NSEnumerator *)keyEnumerator {
+  JSIDEnum *e;
+  JSIdArray *idArray;
+  
+  if ((idArray = JS_Enumerate(self->jscx, self->handle)) == NULL) {
+    NSLog(@"couldn't enumerate object ..");
+    return nil;
+  }
+  
+  e = [[JSIDEnum alloc] initWithIdArray:idArray mappingContext:self->ctx];
+  return AUTORELEASE(e);
+}
+- (NSEnumerator *)objectEnumerator {
+  JSIDEnum *e;
+  JSIdArray *idArray;
+  
+  if ((idArray = JS_Enumerate(self->jscx, self->handle)) == NULL) {
+    NSLog(@"couldn't enumerate object ..");
+    return nil;
+  }
+  
+  e = [[JSIDEnum alloc] initWithIdArray:idArray 
+                       object:self
+                       mappingContext:self->ctx];
+  return AUTORELEASE(e);
+}
+
+- (void)setObject:(id)_obj forStringKey:(NSString *)_key {
+  jsval         v, lv;
+  JSBool        res;
+  unsigned int  clen;
+  unsigned char *ckey;
+  
+  if (![self->ctx jsValue:&v forObject:_obj]) {
+    NSLog(@"WARNING: couldn't convert ObjC value to JS: %@", _obj);
+    return;
+  }
+  
+  clen = [_key cStringLength];
+  ckey = malloc(clen + 1);
+  [_key getCString:ckey];
+  
+  res = JS_LookupProperty(self->jscx, self->handle, ckey, &lv);
+  if (res == JS_FALSE) {
+    NSLog(@"WARNING: couldn't lookup property '%@'", _key);
+    free(ckey);
+    return;
+  }
+  
+  if (lv == JSVAL_VOID) {
+    /* property does not exist */
+    res = JS_DefineProperty(self->jscx, self->handle, ckey, v,
+                            NULL /* getter */,
+                            NULL /* setter */,
+                            JSPROP_ENUMERATE|JSPROP_EXPORTED);
+  }
+  else {
+    /* property does exist */
+    res = JS_SetProperty(self->jscx, self->handle, ckey, &v);
+  }
+  
+  free(ckey); ckey = NULL;
+  
+  if (res == JS_FALSE) {
+    NSLog(@"WARNING: couldn't set ObjC value %@ to JS %@", _obj, _key);
+    return;
+  }
+}
+
+- (id)objectForStringKey:(NSString *)_key {
+  JSBool ret;
+  jsval  val = JSVAL_VOID;
+  unsigned int  clen;
+  unsigned char *ckey;
+  
+  clen = [_key cStringLength];
+  ckey = malloc(clen + 1);
+  [_key getCString:ckey];
+  
+  ret = JS_GetProperty(self->jscx, self->handle, ckey, &val);
+  if (ret == JS_FALSE) {
+    NSLog(@"WARNING(%s): couldn't get value of property %@ ",
+          __PRETTY_FUNCTION__, _key);
+    free(ckey);
+    return nil;
+  }
+  
+  free(ckey); ckey = NULL;
+  
+  if (val == JSVAL_VOID) {
+    /* property is not defined */
+#if 0
+    NSLog(@"%s: got void for key '%s' o0x%08X j0x%08X",
+          __PRETTY_FUNCTION__,
+          ckey, self, self->handle);
+#endif
+    return nil;
+  }
+  
+  return [self->ctx objectForJSValue:&val];
+}
+
+- (void)removeObjectForStringKey:(NSString *)_key {
+  JSBool ret;
+  
+  ret = JS_DeleteProperty(self->jscx, self->handle, [_key cString]);
+  if (ret == JS_FALSE) {
+    NSLog(@"WARNING: couldn't delete property %@ ", _key);
+    return;
+  }
+}
+
+- (BOOL)isStringKey:(id)_key {
+  return [_key isKindOfClass:[NSString class]];
+}
+- (id)unableToHandleKey:(id)_key {
+  NSLog(@"Unable to handle key: %@\n  key class: %@\n  object: %@\n  object class: %@",
+        _key, [_key class], self, [self class]);
+  return nil;
+}
+
+- (id)objectForKey:(id)_key {
+  if ([self isStringKey:_key])
+    return [self objectForStringKey:_key];
+  else
+    return [self unableToHandleKey:_key];
+}
+- (void)setObject:(id)_obj forKey:(id)_key {
+  if ([self isStringKey:_key]) {
+    [self setObject:_obj forStringKey:(id)_key];
+  }
+  else
+    [self unableToHandleKey:_key];
+}
+- (void)removeObjectForKey:(id)_key {
+  if ([self isStringKey:_key])
+    [self removeObjectForStringKey:_key];
+  else
+    [self unableToHandleKey:_key];
+}
+
+/* convert to dictionary */
+
+- (NSDictionary *)convertToNSDictionary {
+  /* could be made far more efficient ... */
+  NSEnumerator   *e;
+  NSString       *key;
+  NSMutableDictionary *dict;
+  
+  if ((e = [self keyEnumerator]) == nil) return nil;
+
+  dict = [NSMutableDictionary dictionaryWithCapacity:16];
+  while ((key = [e nextObject])) {
+    id value = [self objectForKey:key];
+    
+    [dict setObject:value?value:[NSNull null] forKey:key];
+  }
+  return dict;
+}
+
+/* KVC */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+#if 0
+  if (_value == nil)
+    ;
+#endif
+  [self setObject:_value forKey:_key];
+}
+- (id)valueForKey:(NSString *)_key {
+  return [self objectForKey:_key];
+}
+
+/* private */
+
+- (void *)handle {
+  return self->handle;
+}
+
+- (void)makeGlobal {
+  JS_SetGlobalObject(self->jscx, self->handle);
+}
+
+- (NSString *)javaScriptClassName {
+  if (self->handle == nil)
+    return nil;
+  return [NSString stringWithCString:JS_GetClass(self->handle)->name];
+}
+
+/* NSCoding */
+
+- (void)decodeJavaScriptPropertiesWithCoder:(NSCoder *)_coder {
+  NSDictionary *props;
+  NSEnumerator *keys;
+  NSString     *key;
+
+  props = [_coder decodeObject];
+    
+  keys = [props keyEnumerator];
+  while ((key = [keys nextObject])) {
+    id value = [props objectForKey:key];
+      
+    if ([value isNotNull])
+      [self setObject:value forKey:key];
+    else
+      [self setObject:nil forKey:key];
+  }
+}
+- (void)encodeJavaScriptPropertiesWithCoder:(NSCoder *)_coder {
+  NSMutableDictionary *props;
+  NSEnumerator        *keys;
+  NSString            *key;
+  
+  props = [NSMutableDictionary dictionaryWithCapacity:16];
+  keys = [self keyEnumerator];
+  while ((key = [keys nextObject])) {
+    id value;
+    
+    if ((value = [self objectForKey:key])) {
+      if ([value isJavaScriptFunction]) {
+        [self debugWithFormat:@"did not encode JS function object: %@", value];
+        continue;
+      }
+      
+      [props setObject:value forKey:key];
+    }
+    else
+      [props setObject:[NSNull null] forKey:key];
+  }
+  [_coder encodeObject:props];
+}
+
+- (id)initWithCoder:(NSCoder *)_coder {
+  if ((self = [self init])) {
+    NSString *jsClass;
+    id lParent, lPrototype;
+  
+    jsClass    = [_coder decodeObject];
+    lParent    = [_coder decodeObject];
+    lPrototype = [_coder decodeObject];
+  
+    [self setParentObject:lParent];
+    [self setPrototypeObject:lPrototype];
+
+    [self decodeJavaScriptPropertiesWithCoder:_coder];
+    
+    if (![[self javaScriptClassName] isEqualToString:jsClass]) {
+      [self logWithFormat:@"WARNING: decoded object is not JS class %@ !!", jsClass];
+    }
+  }
+  return self;
+}
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:[self javaScriptClassName]];
+#if GREEDY_ARCHIVE
+  [_coder encodeObject:[self parentObject]];
+  [_coder encodeObject:[self prototypeObject]];
+#else
+  [_coder encodeConditionalObject:[self parentObject]];
+  [_coder encodeConditionalObject:[self prototypeObject]];
+#endif
+  [self encodeJavaScriptPropertiesWithCoder:_coder];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  id tmp;
+  
+  ms = [NSMutableString stringWithCapacity:32];
+  [ms appendFormat:@"<%@[0x%08X]: handle=0x%08X>",
+                     NSStringFromClass([self class]), self,
+                     [self handle]];
+  if ((tmp = [self javaScriptClassName]))
+    [ms appendFormat:@" class=%@", tmp];
+  
+  if ([self isJavaScriptFunction])
+    [ms appendString:@" function"];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* NGJavaScriptObject */
+
+@implementation JSIDEnum
+
+- (id)initWithIdArray:(JSIdArray *)_array 
+  mappingContext:(NGJavaScriptObjectMappingContext *)_ctx
+{
+  if (_array == NULL) {
+    RELEASE(self);
+    return nil;
+  }
+  self->idArray = _array;
+  self->ctx = _ctx;
+  self->cx  = [[_ctx jsContext] handle];
+  return self;
+}
+- (id)initWithIdArray:(JSIdArray *)_array 
+  object:(id)_object
+  mappingContext:(NGJavaScriptObjectMappingContext *)_ctx
+{
+  if ((self = [self initWithIdArray:_array mappingContext:_ctx])) {
+    self->object = RETAIN(_object);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (self->idArray)
+    JS_DestroyIdArray(self->cx, self->idArray);
+  RELEASE(self->object);
+  [super dealloc];
+}
+
+- (id)nextObject {
+  jsid  jid;
+  jsval idv;
+  id    jobj = nil;
+  
+  if (self->idArray == NULL)
+    return nil;
+  
+  if (self->idArray->length <= self->pos) {
+    JS_DestroyIdArray(self->cx, self->idArray);
+    self->idArray = NULL;
+    return nil;
+  }
+  
+  jid = self->idArray->vector[self->pos];
+  
+  if (JS_IdToValue(self->cx, jid, &idv) == JS_FALSE) {
+    NSLog(@"couldn't convert id to value ..");
+    return nil;
+  }
+  
+  jobj = [self->ctx objectForJSValue:&idv];
+  
+  if (self->object)
+    jobj = [(NSDictionary *)self->object objectForKey:jobj];
+  
+  self->pos++;
+  
+  if (self->idArray->length <= self->pos) {
+    JS_DestroyIdArray(self->cx, self->idArray);
+    self->idArray = NULL;
+  }
+  
+  return jobj;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                    @"<0x%08X[%@]: len=%d>",
+                    self, NSStringFromClass([self class]),
+                    self->idArray ? self->idArray->length : 0];
+}
+
+@end /* JSIDEnum */
+
+@implementation JSObjChainEnum
+
+- (id)initWithObject:(id)_obj selector:(SEL)_sel {
+  self->object   = RETAIN(_obj);
+  self->selector = _sel;
+  return self;
+}
+- (void)dealloc {
+  RELEASE(self->object);
+  [super dealloc];
+}
+
+- (id)nextObject {
+  AUTORELEASE(self->object);
+  self->object = RETAIN([self->object performSelector:self->selector]);
+  return self->object;
+}
+
+@end /* JSObjChainEnum */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptObjectHandler.h b/skyrix-sope/NGJavaScript/NGJavaScriptObjectHandler.h
new file mode 100644 (file)
index 0000000..bda7ab3
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScriptObjectHandle_H__
+#define __NGJavaScriptObjectHandle_H__
+
+#import <Foundation/NSObject.h>
+
+@class NGJavaScriptContext;
+@class NGJavaScriptObjectMappingContext;
+@class NGObjectMappingContext;
+
+/*
+  This object manages the access to an JavaScript object
+  by the NGJavaScriptObject class (that is, it's more or
+  less the "private" implementation of NGJavaScriptObject)
+  
+  For example it manages the "retain count" of JavaScript
+  objects. To make JS objects survive a garbage collection,
+  the JS objects must be either stored as a value in a
+  another surviving object or it must be marked as a root
+  object. Almost all Objective-C objects are marked as
+  root objects since they exist completly independed from
+  their JS containers.
+  
+  Note: The object-handler is stored as in the private
+        field of the JS object structure.
+  
+  BTW: Maybe root objects aren't necessary anymore:
+  ---snip---
+  In point of fact, you do not need JS_AddRoot/JS_RemoveRoot to protect 
+  GC-thing strong references in private data nowadays: you should consider 
+  implementing your own JSClass.mark hook, which could call JS_MarkGCThing 
+  on each strong ref.  Then your getter could live only in the prototype, 
+  you would use JSPROP_SHARED, and memory use would be minimized.
+  ---snap---
+*/
+
+@interface NGJavaScriptObjectHandler : NSObject
+{
+  NGJavaScriptObjectMappingContext *ctx; // non-retained ?
+  void           *jsContext;    // JavaScript ctx handle
+  void           *jsObject;     // JavaScript object handle
+  id             managedObject; // non-ret. (is this the NGJavaScriptObject ?)
+@private
+  unsigned short jsRootRC;
+}
+
+- (id)initWithJSContext:(NGJavaScriptContext *)_ctx;
+
+- (id)initWithObject:(id)_object
+  inMappingContext:(NGObjectMappingContext *)_ctx;
+
+/* accessors */
+
+- (NGJavaScriptContext *)jsContext;
+- (void *)handle;
+- (id)managedObject;
+
+/* JS root references */
+
+- (id)jsRetain;
+- (void)jsRelease;
+- (unsigned)jsRootRetainCount;
+
+/* properties */
+
+- (BOOL)hasPropertyNamed:(NSString *)_propName;
+- (BOOL)hasElementAtIndex:(unsigned)_idx;
+
+- (void)setValue:(id)_value ofPropertyNamed:(NSString *)_propName;
+- (id)valueOfPropertyNamed:(NSString *)_propName;
+
+/* scripts */
+
+- (id)callFunctionNamed:(NSString *)_funcName, ...;
+- (id)evaluateScript:(NSString *)_script;
+
+/* misc */
+
+- (BOOL)loadStandardClasses;
+- (void)makeGlobal;
+
+@end
+
+#endif /* __NGJavaScriptObjectHandle_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptObjectHandler.m b/skyrix-sope/NGJavaScript/NGJavaScriptObjectHandler.m
new file mode 100644 (file)
index 0000000..49685ef
--- /dev/null
@@ -0,0 +1,1118 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptObjectHandler.h"
+#include "NGJavaScriptObjectMappingContext.h"
+#include "common.h"
+#include "NGJavaScriptContext.h"
+#include "NSString+JS.h"
+#include "NSObject+JS.h"
+#include "NGJavaScriptObjCClassInfo.h"
+#include "NGJavaScriptRuntime.h"
+#include <NGExtensions/NGObjCRuntime.h>
+#import <EOControl/EONull.h>
+
+//#define USE_ENUM 1
+//#define LOG_PROP_RESOLVE 1
+
+#define PROP_READONLY_FLAGS  0
+#define PROP_READWRITE_FLAGS 0
+//#define PROP_READONLY_FLAGS  (JSPROP_READONLY | JSPROP_PERMANENT)
+
+@interface NGJavaScriptObjectHandler(Privates)
+- (BOOL)_applyStaticDefs;
+- (NSString *)stringValue;
+@end
+
+static BOOL IsInPropDefMode = NO;
+
+@interface NSObject(JSFinalization)
+- (BOOL)isJSCombinedObject;
+- (NSEnumerator *)jsObjectEnumerator;
+@end
+
+#include "globals.h"
+
+@implementation NGJavaScriptObjectHandler
+
+static JSBool 
+staticFuncDispatcher
+(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool NGJavaScriptBridge_setStaticProp
+(JSContext *cx, JSObject *obj, jsval _id, jsval *vp);
+static JSBool NGJavaScriptBridge_getStaticProp
+(JSContext *cx, JSObject *obj, jsval _id, jsval *vp);
+
+static NSMutableDictionary *classToInfo = nil;
+
+static void relInfo(void) {
+  if (classToInfo)
+    [classToInfo release]; classToInfo = nil;
+}
+static NGJavaScriptObjCClassInfo *jsClassInfo(Class _class) {
+  NGJavaScriptObjCClassInfo  *ci;
+
+  if (_class == Nil)
+    return nil;
+
+  if (classToInfo == nil) {
+    classToInfo = [[NSMutableDictionary alloc] initWithCapacity:64];
+    atexit(relInfo);
+  }
+
+  if ((ci = [classToInfo objectForKey:_class]) == nil) {
+    ci = [[NGJavaScriptObjCClassInfo alloc]
+                                     initWithClass:_class
+                                     setter:NGJavaScriptBridge_setStaticProp
+                                     getter:NGJavaScriptBridge_getStaticProp
+                                     caller:&staticFuncDispatcher];
+    [classToInfo setObject:ci forKey:_class];
+    [ci autorelease];
+  }
+  
+  return ci;
+}
+
+static Class NSStringClass = Nil;
+static Class ObjInfoClass  = Nil;
+
+static JSBool _addProp(JSContext *cx, JSObject *obj, jsval _id, jsval *vp);
+static JSBool _delProp(JSContext *cx, JSObject *obj, jsval _id, jsval *vp);
+static JSBool _getProp(JSContext *cx, JSObject *obj, jsval _id, jsval *vp);
+static JSBool _setProp(JSContext *cx, JSObject *obj, jsval _id, jsval *vp);
+static JSBool _resolve(JSContext *cx, JSObject *obj, jsval _id);
+static JSBool _convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
+static void   _finalize(JSContext *cx, JSObject *obj);
+//static JSBool _construct
+//(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+
+#if USE_ENUM
+static JSBool
+_newEnumObj(JSContext *cx, JSObject *obj,
+            JSIterateOp op, jsval *statep, jsid *idp);
+#endif
+
+JSClass NGJavaScriptObjectHandler_JSClass = {
+  "NGJavaScriptObjectHandler",
+#if USE_ENUM
+  JSCLASS_HAS_PRIVATE | JSCLASS_NEW_ENUMERATE /* flags */,
+#else
+  JSCLASS_HAS_PRIVATE /* flags */,
+#endif
+  _addProp,
+  _delProp,
+  _getProp,
+  _setProp,
+#if USE_ENUM
+  (JSEnumerateOp)_newEnumObj,
+#else
+  JS_EnumerateStub,
+#endif
+  _resolve,
+  _convert,
+  _finalize,
+  /* Optionally non-null members start here. */
+  NULL, //JSGetObjectOps getObjectOps;
+  NULL, //JSCheckAccessOp checkAccess;
+  NULL, //JSNative call;
+  NULL,// _construct //JSNative construct;
+  NULL, //JSXDRObjectOp xdrObject;
+  NULL, //JSHasInstanceOp hasInstance;
+  //prword spare[2];
+};
+
++ (void)initialize {
+  if (NSStringClass == Nil) NSStringClass = [NSString class];
+  if (ObjInfoClass  == Nil) ObjInfoClass  = [NGJavaScriptObjCClassInfo class];
+}
+
++ (void *)defaultJSClassHandle {
+  return &NGJavaScriptObjectHandler_JSClass;
+}
+- (void *)jsclassHandle {
+  return [[self class] defaultJSClassHandle];
+}
+
+- (id)initWithJSContext:(NGJavaScriptContext *)_ctx {
+  /*
+    TODO: This *is* used. But where ? Document !
+    
+    -testSequence:
+      blah = [[Blah alloc] init];
+      [global setObject:blah forKey:@"blah"];
+    The setObject: triggers the initWithJSContext:.
+  */
+  JSContext *cx;
+  
+  cx = [_ctx handle];
+  
+  self->jsObject = JS_NewObject(cx,
+                                [self jsclassHandle],
+                                NULL /* prototype */,
+                                NULL /* parent    */);
+  if (self->jsObject == NULL) {
+    NSLog(@"WARNING(%s): got no JS object ...", __PRETTY_FUNCTION__);
+    [self release];
+    return nil;
+  }
+  
+  // TODO: is it correct that private is retained ?
+  JS_SetPrivate(cx, self->jsObject, [self retain]);
+  
+  self->jsContext = [_ctx handle];
+  
+  return self;
+}
+- (id)initWithJSContext:(NGJavaScriptContext *)_ctx handler:(id)_handler {
+  // TODO: is this actually used anywhere
+  if ((self = [self initWithJSContext:_ctx])) {
+    self->managedObject = _handler;
+    
+    if (![self _applyStaticDefs]) {
+      NSLog(@"ERROR(%s): rejecting creation of handler for %@ in ctx %@ "
+           @"because the static defs could not be applied !",
+           __PRETTY_FUNCTION__, _handler, _ctx);
+      [self release];
+      return nil;
+    }
+  }
+  return self;
+}
+
+- (id)initWithObject:(id)_object
+  inMappingContext:(NGObjectMappingContext *)_ctx
+{
+  /* 
+     this one is called by -proxyForObject: and makeObjectCombined: of 
+     NGJavaScriptObjectMappingContext
+  */
+  if ((self = [self initWithJSContext:[(id)_ctx jsContext]])) {
+    self->ctx           = (NGJavaScriptObjectMappingContext *)_ctx;
+    self->managedObject = _object;
+    
+    if (![self _applyStaticDefs]) {
+      NSLog(@"ERROR(%s): rejecting creation of handler for %@ in ctx %@ "
+           @"because the static defs could not be applied !",
+           __PRETTY_FUNCTION__, _object, _ctx);
+      [self release];
+      return nil;
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  JSContext *cx;
+  
+  /* 
+     Note: managedObject could already be deallocated at this stage ! 
+     BUT: if managedObject is deallocated, the "ctx" is not retained
+          by the managedObject and therefore possibly broken !
+  */
+  
+  if (NGJavaScriptBridge_TRACK_MEMORY) {
+    NSLog(@"%s: dealloc 0x%08X<%@> at 0x%08X on j0x%08X",
+          __PRETTY_FUNCTION__,
+          self, NSStringFromClass([self class]),
+          self->managedObject,
+          self->jsObject);
+  }
+  
+  cx = self->jsContext;
+  
+  if (self->jsObject) {
+    if (cx) {
+      id priv;
+      
+      while (self->jsRootRC > 0) 
+        JS_RemoveRoot(cx, self->jsObject);
+      self->jsRootRC = 0;
+      
+      priv = JS_GetPrivate(cx, self->jsObject);
+      if (priv == self) {
+        NSLog(@"ERROR(%s): object handler 0x%08X still has a private ???",
+              __PRETTY_FUNCTION__, self);
+        JS_SetPrivate(cx, self->jsObject, NULL);
+      }
+    }
+  }
+  else {
+    if (self->jsRootRC > 0) {
+      NSLog(@"WARNING(%s): jsRootRc > 0, but jsObject is missing 0x%08X",
+            __PRETTY_FUNCTION__, self);
+    }
+  }
+  
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NGJavaScriptContext *)jsContext {
+  return [NGJavaScriptContext jsContextForHandle:self->jsContext];
+}
+- (void *)handle {
+  return self->jsObject;
+}
+
+- (NSString *)javaScriptClassName {
+  JSClass *clazz;
+  
+  if (self->jsObject == nil)
+    return nil;
+  
+  if ((clazz = JS_GetClass(self->jsObject)))
+    return nil;
+  
+  return [NSStringClass stringWithCString:clazz->name];
+}
+
+- (id)managedObject {
+  return self->managedObject;
+}
+
+- (id)parentObject {
+  JSObject *pjso;
+
+  if ((pjso = JS_GetParent(self->jsContext, self->jsObject)) == NULL)
+    return nil;
+  
+  return [self->ctx objectForHandle:pjso];
+}
+
+/* JS root references */
+
+- (const char *)_jsRCName {
+#if DEBUG && 0
+  /* WATCH OUT: leaks memory ! */
+  char *buf;
+  buf = malloc(32);
+  sprintf(buf, "ObjC:0x%08X", (unsigned)self);
+  return buf;
+#else
+  return "ObjC root";
+#endif
+}
+
+- (id)jsRetain {
+  if (self->jsRootRC > 0) {
+    self->jsRootRC++;
+  }
+  else {
+    JSBool     ret;
+    const char *c;
+    JSContext  *cx;
+    
+    cx = self->jsContext;
+    
+    NSAssert(self->jsObject,  @"missing JS object !");
+    NSAssert(cx,              @"missing JS context !");
+    
+    c = [self _jsRCName];
+    ret = c != NULL
+      ? JS_AddNamedRoot(cx, &self->jsObject, c)
+      : JS_AddRoot(cx, &self->jsObject);
+    
+    NSAssert(ret, @"couldn't add JS root !");
+    self->jsRootRC = 1;
+  }
+  return self;
+}
+- (void)jsRelease {
+  if (self->jsRootRC < 1) {
+    NSLog(@"WARNING(%s): called jsRelease on JS object which is not retained !");
+    return;
+  }
+  self->jsRootRC--;
+  
+  if (self->jsRootRC == 0)
+    JS_RemoveRoot(self->jsContext, &self->jsObject);
+}
+- (unsigned)jsRootRetainCount {
+  return self->jsRootRC;
+}
+
+/* properties */
+
+- (BOOL)hasPropertyNamed:(NSString *)_propName {
+  JSBool r;
+  jsval  v;
+
+  r = JS_LookupProperty(self->jsContext,
+                       self->jsObject,
+                        [_propName cString],
+                       &v);
+  if (!r) {
+    NSLog(@"WARNING: JS_LookupProperty call failed !");
+    return NO;
+  }
+  return v == JSVAL_VOID ? NO : YES;
+}
+
+- (BOOL)hasElementAtIndex:(unsigned)_idx {
+  JSBool r;
+  jsval  v;
+  
+  r = JS_LookupElement(self->jsContext,
+                       self->jsObject,
+                       _idx,
+                       &v);
+  if (!r) return NO;
+  return v == JSVAL_VOID ? NO : YES;
+}
+
+- (void)setValue:(id)_value ofPropertyNamed:(NSString *)_propName {
+  JSBool ret;
+  jsval  val;
+
+  if (![self->ctx jsValue:&val forObject:_value]) {
+    NSLog(@"WARNING: couldn't convert ObjC value to JS: %@", _value);
+    return;
+  }
+  
+  ret = JS_SetProperty(self->jsContext,
+                       self->jsObject,
+                       [_propName cString],
+                       &val);
+  if (!ret) {
+    NSLog(@"WARNING: couldn't set value of property %@ ", _propName);
+    return;
+  }
+}
+- (id)valueOfPropertyNamed:(NSString *)_propName {
+  JSBool ret;
+  jsval  val;
+
+  ret = JS_GetProperty(self->jsContext,
+                       self->jsObject,
+                       [_propName cString],
+                       &val);
+  if (!ret) {
+    NSLog(@"WARNING: couldn't get value of property %@ ", _propName);
+    return nil;
+  }
+
+  if (val == JSVAL_VOID)
+    /* property is not defined */
+    return nil;
+
+  return [self->ctx objectForJSValue:&val];
+}
+
+/* scripts */
+
+- (id)callFunctionNamed:(NSString *)_funcName, ... {
+  va_list  va;
+  unsigned argc, i;
+  JSBool   res;
+  jsval    result;
+  jsval    *argv;
+  id       arg;
+  
+  argc = 0;
+  argv = NULL;
+  
+  va_start(va, _funcName);
+  for (arg = va_arg(va, id); arg; arg = va_arg(va, id))
+    argc++;
+  va_end(va);
+  
+  if (argc > 0) {
+    argv = calloc(argc, sizeof(jsval));
+    va_start(va, _funcName);
+    for (arg = va_arg(va, id), i = 0; arg; arg = va_arg(va, id), i++) {
+      if (![self->ctx jsValue:&(argv[i]) forObject:arg])
+        NSLog(@"couldn't convert func argument !");
+    }
+    va_end(va);
+  }
+  
+  res = JS_CallFunctionName(self->jsContext,
+                            self->jsObject,
+                            [_funcName cString],
+                            argc,
+                            argv,
+                            &result);
+  if (argv) free(argv);
+  
+  if (res)
+    return [self->ctx objectForJSValue:&result];
+  
+  [NSException raise:@"JavaScriptEvalException"
+               format:@"could not call function '%@' !", _funcName];
+  return nil;
+}
+
+- (id)evaluateScript:(NSString *)_script {
+  JSBool   res;
+  jsval    lastValue;
+  
+  NSAssert(self->jsObject, @"missing JS object ..");
+  
+  res = JS_EvaluateScript(self->jsContext,
+                          self->jsObject /* script obj */,
+                          [_script cString],
+                          [_script cStringLength],
+                          "<string>",  /* source file */
+                          0,           /* line number */
+                          &lastValue);
+  
+  if (res == JS_TRUE)
+    return [self->ctx objectForJSValue:&lastValue];
+  
+  {
+    NSException  *e;
+    NSDictionary *ui;
+
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _script,         @"script",
+                         self,            @"objectHandler",
+                         [NGJavaScriptContext jsContextForHandle:
+                                              self->jsContext], @"jscontext",
+                         nil];
+    
+    e = [[NSException alloc] initWithName:@"JavaScriptEvalException"
+                             reason:@"couldn't evaluate script"
+                             userInfo:ui];
+    [e raise];
+  }
+  return nil;
+}
+
+/* static definition declarations */
+
+static JSBool NGJavaScriptBridge_setStaticProp
+(JSContext *cx, JSObject *obj, jsval _id, jsval *vp)
+{
+  NGJavaScriptObjectHandler *self;
+  NGJavaScriptObjCClassInfo *ci;
+  SEL        sel;
+  id         value;
+  
+  if ((self = JS_GetPrivate(cx, obj)) == NULL)
+    return JS_FALSE;
+  
+  ci  = jsClassInfo([self->managedObject class]);
+  sel = [ci setSelectorForPropertyId:&_id inJSContext:cx];
+  
+  if (sel == NULL) {
+    NSLog(@"%s: did not find selector for id !", __PRETTY_FUNCTION__);
+    return JS_FALSE;
+  }
+  
+  value = [self->ctx objectForJSValue:vp];
+  [self->managedObject performSelector:sel withObject:value];
+  
+  return JS_TRUE;
+}
+static JSBool NGJavaScriptBridge_getStaticProp
+(JSContext *cx, JSObject *obj, jsval _id, jsval *vp)
+{
+  NGJavaScriptObjCClassInfo *ci;
+  NGJavaScriptObjectHandler *self;
+  SEL sel;
+  id  result;
+  
+  if ((self = JS_GetPrivate(cx, obj)) == NULL) {
+    NSLog(@"%s: did not get private of JS object !", __PRETTY_FUNCTION__);
+    return JS_FALSE;
+  }
+  
+  ci  = jsClassInfo([self->managedObject class]);
+  sel = [ci getSelectorForPropertyId:&_id inJSContext:cx];
+  
+  if (sel == NULL) {
+    NSLog(@"%s: did not find selector for id !", __PRETTY_FUNCTION__);
+    return JS_FALSE;
+  }
+  
+  result = [self->managedObject performSelector:sel];
+  //NSLog(@"result is %@", result);
+  
+  return [self->ctx jsValue:vp forObject:result]
+    ? JS_TRUE
+    : JS_FALSE;
+}
+
+static JSBool 
+staticFuncDispatcher
+(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+  NGJavaScriptObjectHandler *self;
+  NSException *exception;
+  JSFunction  *funobj;
+  const char  *funcName;
+  char        *msgname;
+  SEL         sel;
+  unsigned    i;
+  id          *args;
+  NSArray     *argArray;
+  id          result;
+  JSBool      retcode = 0;
+
+#if DEBUG && 0
+  {
+    JSClass *clazz;
+    const char *cname;
+
+    if ((clazz = JS_GetClass(obj)))
+      cname = clazz->name;
+    else
+      cname = "<no class>";
+    
+    printf("%s: cx=0x%08X, obj=0x%08X<%s>, argc=%d\n",
+           __PRETTY_FUNCTION__,
+           cx, obj, cname, argc);
+  }
+#endif
+  
+  if (JS_IsConstructing(cx))
+    obj = JS_GetParent(cx, obj);
+  
+#if DEBUG
+  if (JS_GetClass(obj) != &NGJavaScriptObjectHandler_JSClass) {
+    NSLog(@"%s: invoked on invalid object class (eg using 'new' ?) !",
+          __PRETTY_FUNCTION__);
+    return JS_FALSE;
+  }
+#endif
+  
+  if ((self = JS_GetPrivate(cx, obj)) == NULL)
+    return JS_FALSE;
+  
+#if DEBUG
+  NSCAssert(JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION,
+            @"expected function in argv[-2] !");
+#endif
+  
+  funobj   = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[-2]));
+  funcName = JS_GetFunctionName(funobj);
+  
+  msgname = malloc(strlen(funcName) + 10);
+  strcpy(msgname, "_jsfunc_");
+  strcat(msgname, funcName);
+  strcat(msgname, ":");
+#if APPLE_RUNTIME || NeXT_RUNTIME
+  sel = sel_getUid(msgname); /* TODO: should be registerName? */
+#else
+  sel = sel_get_any_uid(msgname);
+#endif
+  
+  if (argc > 0) {
+    args = calloc(argc, sizeof(id));
+    for (i = 0; i < argc; i++) {
+      args[i] =
+        [self->ctx objectForJSValue:&(argv[i])];
+      
+      if (args[i] == nil) args[i] = [EONull null];
+    }
+    argArray = [NSArray arrayWithObjects:args count:argc];
+    free(args);
+  }
+  else
+    argArray = [NSArray array];
+
+#if 0  
+  NSLog(@"calling function '%s'(%s), %d args %@\n",
+        funcName, msgname, argc, argArray);
+#endif
+  
+  exception = nil;
+  NS_DURING {
+    result  = [self->managedObject performSelector:sel withObject:argArray];
+    retcode = [self->ctx jsValue:rval forObject:result] ? JS_TRUE : JS_FALSE;
+  }
+  NS_HANDLER {
+    exception = [localException retain];
+  }
+  NS_ENDHANDLER;
+  
+  if (exception) {
+    jsval exval;
+    
+#if DEBUG
+    NSLog(@"%s: catched exception: %@", __PRETTY_FUNCTION__, exception);
+#endif
+    retcode   = JS_FALSE;
+    
+    if ([self->ctx jsValue:&exval forObject:exception]) {
+      JS_SetPendingException(cx, exval);
+    }
+    else {
+      NSLog(@"%s: couldn't get JS value for exception: %@",
+            __PRETTY_FUNCTION__, exception);
+    }
+  }
+  
+#if 0
+  NSLog(@"result is %@", result);
+#endif
+  
+  return retcode;
+}
+
++ (void *)jsStaticFuncDispatcher {
+  return &staticFuncDispatcher;
+}
+
+- (BOOL)_applyStaticDefs {
+  NGJavaScriptObjCClassInfo *ci;
+  BOOL ok;
+  
+  if (self->managedObject == nil) {
+    NSLog(@"WARNING(%s): cannot apply defs on nil ...", __PRETTY_FUNCTION__);
+    return NO;
+  }
+  
+  ci = jsClassInfo([self->managedObject class]);
+  
+  IsInPropDefMode = YES;
+  ok = [ci applyOnJSObject:self->jsObject inJSContext:self->jsContext];
+  if (!ok)
+    NSLog(@"ERROR(%s): couldn't apply static defs !", __PRETTY_FUNCTION__);
+  IsInPropDefMode = NO;
+  return ok;
+}
+
+- (BOOL)isStaticProperty:(NSString *)_name {
+  NGJavaScriptObjCClassInfo *ci;
+  ci = jsClassInfo([self->managedObject class]);
+  return [ci isStaticProperty:_name];
+}
+
+/* misc */
+
+- (BOOL)loadStandardClasses {
+  NSLog(@"NGJavaScriptObjectHandler: load std classes ...");
+  if (!JS_InitStandardClasses(self->jsContext, self->jsObject)) {
+    NSLog(@"NGJavaScriptObjectHandler: failed to load std classes ...");
+    return NO;
+  }
+  return YES;
+}
+
+- (void)makeGlobal {
+  JS_SetGlobalObject(self->jsContext, self->jsObject);
+}
+
+/* unknown id */
+
+- (void)failureUnknownIDType:(jsval)_id {
+#if DEBUG
+  abort();
+#else
+  NSLog(@"SERIOUS ERROR(%s:%i): unknown id type ..",
+        __PRETTY_FUNCTION__, __LINE__);
+#endif
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:256];
+  [ms appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
+  [ms appendFormat:@" handle=0x%08X", [self handle]];
+  [ms appendFormat:@" class=%@", [self javaScriptClassName]];
+  [ms appendFormat:@" parent=%@", [self parentObject]];
+  [ms appendString:@">"];
+  
+  return ms;
+}
+
+/* JS class methods */
+
+typedef enum {
+  NGPropOp_add,
+  NGPropOp_del,
+  NGPropOp_set,
+  NGPropOp_get,
+  NGPropOp_resolve
+} NGPropOp;
+
+static inline JSBool _propOp(JSContext *cx, NGPropOp op,
+                             JSObject *obj, jsval _id, jsval *vp)
+{
+  NGJavaScriptObjectHandler *self;
+  BOOL res = NO;
+  
+  if ((self = JS_GetPrivate(cx, obj)) == nil) {
+    NSLog(@"WARNING: missing private in NGJavaScriptObjectHandler JS object !");
+    return JS_PropertyStub(cx, obj, _id, vp);
+  }
+  
+  if (IsInPropDefMode)
+    return JS_PropertyStub(cx, obj, _id, vp);
+
+  NSCAssert2(self->managedObject,
+             @"missing managed object (handler=%@, j0x%08X) !",
+             self, obj);
+  
+  if (JSVAL_IS_INT(_id)) {
+    /* lookup by key */
+    int sel;
+    
+    sel = JSVAL_TO_INT(_id);
+    
+    switch (op) {
+      case NGPropOp_get: {
+        if (NGJavaScriptBridge_LOG_PROP_GET)
+          NSLog(@"JS: get by sel %i", sel);
+        
+        if (sel > 0) {
+          if ([self->managedObject respondsToSelector:
+                   @selector(valueForJSPropertyAtIndex:)]) {
+            id v;
+          
+            v   = [self->managedObject valueForJSPropertyAtIndex:sel];
+            res = [self->ctx jsValue:vp forObject:v];
+          }
+        }
+        break;
+      }
+
+      case NGPropOp_set: {
+        if (NGJavaScriptBridge_LOG_PROP_SET)
+          NSLog(@"JS: set by sel %i", sel);
+        
+        if (sel > 0) {
+          if ([self->managedObject respondsToSelector:
+                   @selector(takeValue:forJSPropertyAtIndex:)]) {
+            id v;
+          
+            v = [self->ctx objectForJSValue:vp];
+          
+            res = [self->managedObject takeValue:v forJSPropertyAtIndex:sel];
+          }
+        }
+        
+        break;
+      }
+      
+      case NGPropOp_resolve:
+#if LOG_PROP_RESOLVE
+        NSLog(@"RESOLVE '%i'", idx);
+#endif
+        break;
+        
+      case NGPropOp_del:
+      case NGPropOp_add:
+        NSLog(@"int keys are not supported for this operation (%i) !", op);
+        return JS_FALSE;
+    }
+  }
+  else if (JSVAL_IS_STRING(_id)) {
+    /* lookup by name */
+    NSString *name;
+    JSString *jsname;
+
+    res = YES;
+      
+    jsname = JS_ValueToString(cx, _id);
+    name   = [NSStringClass stringWithJavaScriptString:jsname];
+    
+    switch (op) {
+      case NGPropOp_resolve: {
+#if LOG_PROP_RESOLVE
+        NSLog(@"RESOLVE '%@'", name);
+#endif
+#if 0
+        res  = [self resolvePropertyByName:name];
+#endif
+        break;
+      }
+      
+      case NGPropOp_del: {
+        if ([self isStaticProperty:name])
+          break;
+        
+        if (NGJavaScriptBridge_LOG_PROP_DEL)
+          NSLog(@"JS: NOT REALLY SUPPORTED del by name %@", name);
+        
+        break;
+      }
+      
+      case NGPropOp_add: {
+        if (NGJavaScriptBridge_LOG_PROP_ADD) {
+          NSLog(@"JS: add by name '%@' type %s "
+                @"j0x%08X o0x%08X<%@> on o0x%08X<%@>",
+                name, JS_GetTypeName(cx, JS_TypeOfValue(cx, *vp)),
+                obj, self, NSStringFromClass([self class]),
+                self->managedObject,
+                NSStringFromClass([self->managedObject class]));
+        }
+
+        if ([self->managedObject respondsToSelector:
+                 @selector(takeValue:forJSPropertyNamed:)]) {
+          id v;
+        
+          if ((v = [self->ctx objectForJSValue:vp]) == nil)
+            v = [EONull null];
+        
+          res = [self->managedObject takeValue:v forJSPropertyNamed:name];
+        }
+        
+        break;
+      }
+      
+      case NGPropOp_get: {
+        if ([self isStaticProperty:name])
+          break;
+        
+        if (NGJavaScriptBridge_LOG_PROP_GET) {
+          NSLog(@"JS: get by name '%@' type %s "
+                @"j0x%08X o0x%08X<%@> on o0x%08X<%@>",
+                name, JS_GetTypeName(cx, JS_TypeOfValue(cx, *vp)),
+                obj, self, NSStringFromClass([self class]),
+                self->managedObject,
+                NSStringFromClass([self->managedObject class]));
+        }
+        
+        if ([self->managedObject respondsToSelector:
+                 @selector(valueForJSPropertyNamed:)]) {
+          NS_DURING {
+            id v;
+          
+            v   = [self->managedObject valueForJSPropertyNamed:name];
+            
+            if (NGJavaScriptBridge_LOG_PROP_GET) {
+              NSLog(@"  return value o0x%08X<%@>",
+                    v, NSStringFromClass([v class]));
+            }
+            
+            res = [self->ctx jsValue:vp forObject:v];
+          }
+          NS_HANDLER {
+            [[self->ctx jsContext] reportException:localException];
+            res = NO;
+          }
+          NS_ENDHANDLER;
+        }
+        break;
+      }
+      
+      case NGPropOp_set: {
+        if ([self isStaticProperty:name])
+          break;
+        
+        if (NGJavaScriptBridge_LOG_PROP_SET) {
+          NSLog(@"JSObjectHandler: set by name '%@' type %s "
+                @"j0x%08X o0x%08X<%@> on o0x%08X<%@>",
+                name, JS_GetTypeName(cx, JS_TypeOfValue(cx, *vp)),
+                obj, self, NSStringFromClass([self class]),
+                self->managedObject,
+                NSStringFromClass([self->managedObject class]));
+        }
+      
+        if ([self->managedObject respondsToSelector:
+                 @selector(takeValue:forJSPropertyNamed:)]) {
+          id v;
+        
+          v   = [self->ctx objectForJSValue:vp];
+          res = [self->managedObject takeValue:v forJSPropertyNamed:name];
+        }
+        break;
+      }
+    }
+  }
+  else {
+    [self failureUnknownIDType:_id];
+    res = NO;
+  }
+  
+  return res ? JS_TRUE : JS_FALSE;
+}
+
+static JSBool _addProp(JSContext *cx, JSObject *obj, jsval _id, jsval *vp) {
+  return _propOp(cx, NGPropOp_add, obj, _id, vp);
+}
+static JSBool _delProp(JSContext *cx, JSObject *obj, jsval _id, jsval *vp) {
+  return _propOp(cx, NGPropOp_del, obj, _id, vp);
+}
+static JSBool _getProp(JSContext *cx, JSObject *obj, jsval _id, jsval *vp) {
+  return _propOp(cx, NGPropOp_get, obj, _id, vp);
+}
+static JSBool _setProp(JSContext *cx, JSObject *obj, jsval _id, jsval *vp) {
+  return _propOp(cx, NGPropOp_set, obj, _id, vp);
+}
+
+#if USE_ENUM
+static JSBool
+_newEnumObj(JSContext *cx, JSObject *obj,
+            JSIterateOp op, jsval *statep, jsid *idp)
+{
+  NGJavaScriptObjectHandler *self;
+
+  if ((self = JS_GetPrivate(cx, obj)) == nil)
+    return JS_TRUE;
+  else {
+    NSEnumerator *e;
+    
+    NSCAssert(self->managedObject, @"missing managed object !");
+    
+    if (![self->managedObject respondsToSelector:@selector(jsObjectEnumerator)])
+      return JS_TRUE;
+    
+    switch (op) {
+      case JSENUMERATE_INIT:
+        e = [[self->managedObject jsObjectEnumerator] retain];
+        *statep = PRIVATE_TO_JSVAL(e);
+        if (idp) *idp = JSVAL_ZERO;
+        break;
+        
+      case JSENUMERATE_NEXT: {
+        id nextObj;
+        
+        e = JSVAL_TO_PRIVATE(*statep);
+        
+        if ((nextObj = [e nextObject])) {
+          jsval idval;
+          
+          // NSLog(@"next id %@ ..", nextObj);
+#if 0 // can someone explain that ?
+          if (![self->ctx jsValue:&idval forObject:nextObject])
+            return JS_FALSE;
+#else
+          idval = INT_TO_JSVAL([nextObj intValue]);
+#endif
+          
+          if (!JS_ValueToId(cx, idval, idp))
+            return JS_FALSE;
+          
+          break;
+        }
+        //NSLog(@"no more IDs ..");
+        /* else fall through */
+      }
+      case JSENUMERATE_DESTROY: {
+        //NSLog(@"destroying enum ..");
+        if (*statep != JSVAL_NULL) {
+          if ((e = JSVAL_TO_PRIVATE(*statep))) {
+            [e release];
+            e = nil;
+          }
+          *statep = JSVAL_NULL;
+        }
+        break;
+      }
+    }
+    return JS_TRUE;
+  }
+}
+#endif
+
+#if 0
+static JSBool _construct
+(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+  NSLog(@"construct called ..");
+  return JS_FALSE;
+}
+#endif
+
+static JSBool _resolve(JSContext *cx, JSObject *obj, jsval _id) {
+  return _propOp(cx, NGPropOp_resolve, obj, _id, NULL);
+}
+
+static JSBool _convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) {
+  NGJavaScriptObjectHandler *self;
+  
+  if ((self = JS_GetPrivate(cx, obj)) == nil)
+    return JS_ConvertStub(cx, obj, type, vp);
+  else {
+    NSCAssert(self->managedObject, @"missing managed object !");
+    
+    switch (type) {
+      case JSTYPE_VOID:
+      case JSTYPE_STRING: {
+        NSString *s;
+        
+        s = [self->managedObject stringValue];
+        return [self->ctx jsValue:vp forObject:s];
+      }
+      
+      case JSTYPE_NUMBER:
+        *vp = INT_TO_JSVAL([self->managedObject intValue]);
+        return JS_TRUE;
+        
+      case JSTYPE_BOOLEAN:
+        *vp = [self->managedObject boolValue] ? JSVAL_TRUE : JSVAL_FALSE;
+        return JS_TRUE;
+        
+      case JSTYPE_OBJECT:
+      case JSTYPE_FUNCTION:
+      default:
+        return JS_ConvertStub(cx, obj, type, vp);
+    }
+  }
+}
+
+static void _finalize(JSContext *cx, JSObject *obj) {
+  NGJavaScriptObjectHandler *self;
+  
+  if ((self = JS_GetPrivate(cx, obj)) == nil) {
+    JS_FinalizeStub(cx, obj);
+  }
+  else if (self->jsObject == obj) {
+    /* the managed JS object is the same as the finalizing object */
+    
+    NSCAssert(self->managedObject, @"missing managed object !");
+    
+    if (NGJavaScriptBridge_TRACK_FINALIZATION) {
+      NSLog(@"finalizing j0x%08X o0x%08X<%@>",
+            obj, 
+            self->managedObject, 
+           NSStringFromClass([self->managedObject class]));
+    }
+    
+    [self->ctx forgetObject:self->managedObject];
+    
+#if DEBUG && 0
+#warning RC watch is on !
+    if ([self retainCount] != 1) {
+      NSLog(@"WARNING: JS object %@ was collected, "
+            @"but handle is still live (rc=%d) "
+            @"(could be pending autorelease refs: pending: %d) !",
+            self, [self retainCount],
+            [NSAutoreleasePool autoreleaseCountForObject:self]);
+    }
+#endif
+    
+    JS_SetPrivate(self->jsContext, obj, NULL);
+    self->jsObject = NULL;
+    
+    /* release private ref */
+    NSCAssert(self, @"where got self ??");
+    [self release]; self = nil;
+  }
+  else {
+#if DEBUG
+    fprintf(stderr, "%s: finalization error ...\n", __PRETTY_FUNCTION__);
+    abort();
+#else
+    fprintf(stderr, "%s: finalization error ...\n", __PRETTY_FUNCTION__);
+#endif
+  }
+}
+
+@end /* NGJavaScriptObjectHandler */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptObjectMappingContext.h b/skyrix-sope/NGJavaScript/NGJavaScriptObjectMappingContext.h
new file mode 100644 (file)
index 0000000..68889d1
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScriptObjectMappingContext_H__
+#define __NGJavaScriptObjectMappingContext_H__
+
+#include <NGScripting/NGObjectMappingContext.h>
+#import <Foundation/NSMapTable.h>
+
+@class NGJavaScriptContext, NGJavaScriptObjectHandler;
+
+/*
+  A context which maps JavaScript objects to ObjC objects.
+  
+  Note: do *not* create a context manually, use NGScriptLanguage
+  -createMappingContext !
+  
+  Note: NSCoding is done by NGObjectMappingContext and either unarchives
+  into the active context if one is available or creates a new context
+  if no context is available yet (in other words, NSCoding is context
+  sensitive)
+*/
+
+@interface NGJavaScriptObjectMappingContext : NGObjectMappingContext
+{
+  NSMapTable          *objcToJS; // ObjC proxies
+  NSMapTable          *jsToObjC; // pure JS objects (others stored in private)
+  NGJavaScriptContext *jsContext;
+}
+
+- (NGJavaScriptContext *)jsContext;
+
+/* hierachy */
+
+- (void)setGlobalObject:(id)_object;
+- (id)globalObject;
+
+/* mappings */
+
+- (void)registerObject:(id)_object forImportedHandle:(void *)_handle;
+- (void)forgetImportedHandle:(void *)_handle;
+
+/* handler */
+
+- (NGJavaScriptObjectHandler *)handlerForObject:(id)_object;
+
+/* values */
+
+- (id)objectForJSValue:(void *)_value;
+- (BOOL)jsValue:(void *)_value forObject:(id)_obj;
+
+@end
+
+@interface NGJavaScriptObjectMappingContext(CombinedObjects)
+
+- (void)makeObjectCombined:(id)_object;
+- (BOOL)isCombinedObject:(id)_object;
+
+@end
+
+@interface JSCombinedObjectBehaviour : NSObject
+- (id)evaluateScript:(NSString *)_js language:(NSString *)_language;
+@end
+
+@interface NSObject(JSCombinedObjects)
++ (BOOL)isJSCombinedObjectClass;
+- (BOOL)isJSCombinedObject;
+- (NGJavaScriptObjectMappingContext *)jsObjectMappingContext;
+@end
+
+@interface NGJavaScriptObjectMappingContext(Debugging)
+- (void)_logExportedJavaScriptObjects;
+- (void)_logExportedObjCObjects;
+- (void)_logCombinedObjects;
+@end
+
+#endif /* __NGJavaScriptObjectMappingContext_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptObjectMappingContext.m b/skyrix-sope/NGJavaScript/NGJavaScriptObjectMappingContext.m
new file mode 100644 (file)
index 0000000..3490aea
--- /dev/null
@@ -0,0 +1,946 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptObjectMappingContext.h"
+#include "NGJavaScriptContext.h"
+#include "NGJavaScriptObjectHandler.h"
+#include "NGJavaScriptObject.h"
+#include "NGJavaScriptShadow.h"
+#include "NGJavaScriptFunction.h"
+#include "NSString+JS.h"
+#include "common.h"
+#include "globals.h"
+
+#if GNUSTEP_BASE_LIBRARY
+#  include <GNUstepBase/behavior.h>
+#endif
+
+@interface NSObject(CombinedObjects)
+- (void)jsObjectFinalized:(void *)_handle;
+- (BOOL)_jsGetValue:(void *)_value inJSContext:(NGJavaScriptContext *)_ctx;
+- (id)_js_parentObject;
+@end
+
+@interface NGJavaScriptObjectMappingContext(Privates)
+- (void)_jsFinalizeCombinedObject:(id)_object;
+@end
+
+typedef struct {
+  JSObject                         *jso;
+  NGJavaScriptObjectMappingContext *ctx;
+  NGJavaScriptObjectHandler        *handler;
+  BOOL                             rootRef;
+  unsigned short                   rc;
+} JSCombinedObjInfo;
+
+extern JSClass ObjCShadow_JSClass;
+
+@implementation NGJavaScriptObjectMappingContext
+
+static BOOL       logHandleForObject = NO;
+static BOOL       logValueConversion = NO;
+static NSMapTable *combinedToInfo = NULL; // combined objects
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  if (didInit) return;
+  
+  NGJavaScriptBridge_LOG_PROP_DEFINITION
+    = [[ud objectForKey:@"jsLogPropDef"] boolValue];
+  NGJavaScriptBridge_LOG_FUNC_DEFINITION
+    = [[ud objectForKey:@"jsLogFuncDef"] boolValue];
+
+  logHandleForObject = [ud boolForKey:@"JSLogHandleForObject"];
+  logValueConversion = [ud boolForKey:@"JSLogValueConversion"];
+  
+  didInit = YES;
+}
+
+- (id)initWithJSContext:(NGJavaScriptContext *)_ctx {
+  if ((self = [super init])) {
+    self->jsContext = [_ctx retain];
+    
+    /* 'combined' ObjC-JS objects */
+    if (combinedToInfo == NULL) {
+      combinedToInfo =
+        NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
+                         NSOwnedPointerMapValueCallBacks,
+                         200);
+    }
+    
+    /* 'pure' ObjC objects */
+    self->objcToJS =
+      NSCreateMapTable(NSObjectMapKeyCallBacks,
+                       NSNonOwnedPointerMapValueCallBacks,
+                       200);
+    
+    /* 'pure' JS objects */
+    self->jsToObjC =
+      NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
+                       NSNonRetainedObjectMapValueCallBacks,
+                       200);
+    
+    /* make default global */
+    
+    [self pushContext];
+    {
+      NGJavaScriptObject *glob;
+
+      glob = [[NGJavaScriptObject alloc] init];
+      [glob applyStandardClasses];
+      [self setGlobalObject:glob];
+      [glob release];
+    }
+    [self popContext];
+  }
+  return self;
+}
+- (id)init {
+  NGJavaScriptContext *ctx;
+  
+  ctx = [[NGJavaScriptContext alloc] init];
+  self = [self initWithJSContext:ctx];
+  [ctx release]; ctx = nil;
+  return self;
+}
+
+- (void)dealloc {
+  if (self->jsToObjC) NSFreeMapTable(self->jsToObjC);
+  if (self->objcToJS) NSFreeMapTable(self->objcToJS);
+  [self->jsContext release];
+  [super dealloc];
+}
+
+- (NGJavaScriptContext *)jsContext {
+  return self->jsContext;
+}
+
+/* hierachy */
+
+- (void)setGlobalObject:(id)_object {
+  JSObject *glob;
+  
+  glob = [self handleForObject:_object];
+  JS_SetGlobalObject([self->jsContext handle], glob);
+}
+- (id)globalObject {
+  JSObject *glob;
+  
+  if ((glob = JS_GetGlobalObject([self->jsContext handle])) == NULL)
+    return nil;
+  
+  return [self objectForHandle:glob];
+}
+
+/* proxy factory */
+
+- (void *)proxyForObject:(id)_object {
+  /* this is called by handleForObject: */
+  NGJavaScriptObjectHandler *jsHandler;
+  void *jso;
+  
+  jsHandler =
+    [[NGJavaScriptObjectHandler alloc] initWithObject:_object
+                                       inMappingContext:self];
+  
+  jso = [jsHandler handle];
+  
+  [jsHandler autorelease];
+  
+  return jso;
+}
+- (id)proxyForPureJSObject:(void *)_handle {
+  Class proxyClass;
+  id    proxy;
+  JSContext *cx;
+  void      *jsClazz;
+  
+  if (_handle == NULL)
+    return nil;
+  
+  /* create a proxy for a 'pure' JavaScript object */
+  
+  cx = [self->jsContext handle];
+  jsClazz = OBJ_GET_CLASS(cx, (JSObject *)_handle);
+  
+  /* use a configurable mapping of JS-class to ObjC class here ? */
+  if (jsClazz == &js_ArrayClass)
+    proxyClass = [NGJavaScriptArray class];
+  else if (jsClazz == &js_FunctionClass)
+    proxyClass = [NGJavaScriptFunction class];
+  else
+    proxyClass = [NGJavaScriptObject class];
+  
+  proxy = [[proxyClass alloc] initWithHandle:_handle inMappingContext:self];
+  return AUTORELEASE(proxy);
+}
+
+/* mappings */
+
+- (void *)handleForObject:(id)_object {
+  /*
+    What is the _object in this context ?
+    - I guess it's a NGJavaScriptObject
+      - often, but not always, see testjs: called with Blah and MyNum
+      - only "custom" objects, not NGJavaScriptObject are registered !
+    
+    - it checks whether the object itself can return handle 
+      (_jsHandleInMapContext:)
+      - this seems always true for NGJavaScriptObject's !
+    - checks, whether a proxy is already registered
+      - I guess a proxy is a JS-object with an attached JSObjectHandler ?
+    - otherwise create a new one
+    - register new one
+    - check parent object of new one
+  */
+  JSCombinedObjInfo *combinedObjInfo;
+  void *jso;
+  id   parent;
+  
+  if (logHandleForObject)
+    NSLog(@"-proxyForObject:0x%08X %@", _object, _object);
+  
+  if (_object == nil) {
+    jso = JSVAL_TO_OBJECT(JSVAL_NULL);
+    if (logHandleForObject) NSLog(@"  => is nil: 0x%08X", jso);
+    return jso;
+  }
+  
+  if ([_object respondsToSelector:@selector(_jsHandleInMapContext:)]) {
+    jso = [_object _jsHandleInMapContext:self];
+    if (logHandleForObject) {
+      NSLog(@"  obj (class %@) handles itself: 0x%08X", 
+           NSStringFromClass([_object class]), jso);
+    }
+    return jso;
+  }
+  
+  if ((jso = NSMapGet(self->objcToJS, _object))) {
+    /* a proxy is already registered */
+    if (logHandleForObject) NSLog(@"  proxy already registered: 0x%08X", jso);
+    return jso;
+  }
+  
+  if ((combinedObjInfo = NSMapGet(combinedToInfo, _object))) {
+    /* check for correct context */
+    if (combinedObjInfo->ctx != self) {
+      NSLog(@"%s: tried to access combined object 0x%08X<%@> in "
+            @"different mapping context (ctx=0x%08X, required=0x%08X)  !",
+            __PRETTY_FUNCTION__, _object, NSStringFromClass([_object class]),
+            self, combinedObjInfo->ctx);
+      return nil;
+    }
+    if (logHandleForObject) NSLog(@"  proxy is combined object: 0x%08X", jso);
+    return combinedObjInfo->jso;
+  }
+  
+  /* create a new proxy */
+  
+  if (logHandleForObject) NSLog(@"  creating proxy ...");
+  if ((jso = [self proxyForObject:_object])) {
+    /* register proxy */
+#if DEBUG
+    NSAssert1(NSMapGet(self->objcToJS, _object) == NULL,
+              @"already registered a proxy for object o0x%08X", _object);
+#endif
+    if (logHandleForObject) NSLog(@"  register handle 0x%08X ...", jso);
+    NSMapInsertKnownAbsent(self->objcToJS, _object, jso);
+  }
+  else {
+    NSLog(@"ERROR(%s): proxy creation failed: %@", 
+         __PRETTY_FUNCTION__, _object);
+    return NULL;
+  }
+  
+  /* look for parent of new proxy */
+  
+  if ((parent = [_object _js_parentObject])) {
+    void *pjso;
+    JSBool res;
+    
+    if (logHandleForObject) 
+      NSLog(@"register parent 0x%08X for object .."), parent;
+    
+    pjso = [self handleForObject:parent];
+    
+    res = JS_SetParent([self->jsContext handle], jso, pjso);
+    
+    if (res == JS_FALSE) {
+      NSLog(@"WARNING: ctx %@ couldn't register JS parent %@ on object %@",
+            self, parent, _object);
+    }
+  }
+  
+  return jso;
+}
+
+- (void)registerObject:(id)_object forImportedHandle:(void *)_handle {
+#if DEBUG
+  NSAssert(_object, @"missing object");
+  NSAssert(_handle, @"missing handle");
+#endif
+  NSMapInsertKnownAbsent(self->jsToObjC, _handle, _object);
+}
+
+- (id)objectForHandle:(void *)_handle {
+  /*
+    What does it do ? What is the return value ? TODO: Document !
+  */
+  extern JSClass NGJavaScriptObjectHandler_JSClass;
+  JSClass *handleClass;
+  id obj;
+  
+  if (_handle == NULL)
+    return nil;
+  
+  if ((handleClass = JS_GetClass(_handle)) == NULL) {
+    NSLog(@"couldn't get class of handle 0x%08X", (unsigned)_handle);
+    return nil;
+  }
+  
+  /* check for 'reflected' JavaScript objects (combined or ObjC exported) */
+  
+  if (handleClass == &NGJavaScriptObjectHandler_JSClass) {
+    NGJavaScriptObjectHandler *h;
+    
+    if ((h = JS_GetPrivate([self->jsContext handle], _handle)) == nil) {
+      NSLog(@"couldn't get private of JS object 0x%08X "
+            @"(NGJavaScriptObjectHandler)", _handle);
+      return nil;
+    }
+    
+    return AUTORELEASE(RETAIN([h managedObject]));
+  }
+  
+  if (handleClass == &ObjCShadow_JSClass) {
+    NGJavaScriptShadow *h;
+    
+    if ((h = JS_GetPrivate([self->jsContext handle], _handle)) == nil) {
+      NSLog(@"couldn't get private of JS shadow object 0x%08X "
+            @"(NGJavaScriptShadow)", _handle);
+      return nil;
+    }
+    
+    return AUTORELEASE(RETAIN([h masterObject]));
+  }
+  
+  /* check for 'pure' JavaScript objects */
+  
+  if ((obj = NSMapGet(self->jsToObjC, _handle)))
+    /* found */
+    return AUTORELEASE(RETAIN(obj));
+  
+  if ((obj = [self proxyForPureJSObject:_handle])) {
+    /* register proxy */
+    [self registerObject:obj forImportedHandle:_handle];
+    return obj;
+  }
+  
+  /* couldn't build a proxy */
+  return nil;
+}
+
+- (void)forgetObject:(id)_object {
+  JSCombinedObjInfo *combinedObjInfo;
+  
+  NSAssert(_object, @"missing object ..");
+  
+  if ((combinedObjInfo = NSMapGet(combinedToInfo, _object))) {
+    if (combinedObjInfo->ctx != self) {
+      NSLog(@"forget combined object 0x%08X in wrong context !", _object);
+    }
+    else
+      [self _jsFinalizeCombinedObject:_object];
+  }
+  else {
+    if (NGJavaScriptBridge_TRACK_FORGET) {
+      JSObject *jso;
+      
+      jso = NSMapGet(self->objcToJS, _object);
+      NSLog(@"forgetting non-combined object o0x%08X<%@> j0x%08X rc %d",
+            _object, NSStringFromClass([_object class]),
+            jso,
+            [_object retainCount]);
+    }
+    
+    NSMapRemove(self->objcToJS, _object);
+
+#if 0
+    [self->jsContext performSelector:@selector(collectGarbage)
+                     withObject:nil
+                     afterDelay:0.0];
+#endif
+  }
+}
+- (void)forgetImportedHandle:(void *)_handle {
+  NSMapRemove(self->jsToObjC, _handle);
+}
+
+/* handler */
+
+- (NGJavaScriptObjectHandler *)handlerForObject:(id)_object {
+  JSObject *jso;
+  
+  if ((jso = [self handleForObject:_object]) == NULL) {
+    NSLog(@"did not find handle for object 0x%08X", _object);
+    return nil;
+  }
+  
+  return JS_GetPrivate([self->jsContext handle], jso);
+}
+
+/* garbage collection */
+
+- (id)popContext {
+  [self->jsContext collectGarbage];
+  return [super popContext];
+}
+
+- (void)collectGarbage {
+  [self pushContext];
+  [self->jsContext collectGarbage];
+  [self popContext];
+}
+
+/* logging */
+
+- (void)_logExportedJavaScriptObjects {
+  NSMapEnumerator e;
+  JSObject *jso;
+  JSClass  *jsClass;
+  id       proxy;
+
+  if (NSCountMapTable(jsToObjC) < 1) {
+    printf("no imported JavaScript objects.\n");
+    return;
+  }
+  
+  e = NSEnumerateMapTable(jsToObjC);
+  printf("imported JavaScript objects:\n");
+  printf("  %-10s %-20s %-10s %-26s %-2s\n",
+        "JS",
+         "JS-Class",
+        "ObjC",
+        "ObjC-Class",
+        "rc");
+  while (NSNextMapEnumeratorPair(&e, (void*)&jso, (void*)&proxy)) {
+    jsClass = jso ? JS_GetClass(jso) : NULL;
+    
+    printf("  0x%08X %-20s 0x%08X %-26s %2d\n",
+          (unsigned)jso,
+           jsClass ? jsClass->name : "<null>",
+          (unsigned)proxy,
+          [NSStringFromClass([proxy class]) cString],
+          [proxy retainCount]);
+  }
+}
+
+- (void)_logExportedObjCObjects {
+  NSMapEnumerator e;
+  id       object;
+  JSObject *jsProxy;
+
+  if (NSCountMapTable(objcToJS) < 1) {
+    printf("no exported Objective-C objects.\n");
+    return;
+  }
+  
+  printf("exported Objective-C objects:\n");
+  printf("  %-10s %-20s %-10s %-26s %-2s\n",
+        "ObjC",
+        "ObjC-Class",
+        "JS",
+        "JS-Class",
+        "rc");
+  e = NSEnumerateMapTable(objcToJS);
+  while (NSNextMapEnumeratorPair(&e, (void*)&object, (void*)&jsProxy)) {
+    JSClass *jsClass;
+    
+    jsClass = jsProxy ? JS_GetClass(jsProxy) : NULL;
+    
+    printf("  0x%08X %-20s 0x%08X %-26s %2d\n",
+          (unsigned)object,
+          [NSStringFromClass([object class]) cString],
+          (unsigned)jsProxy,
+           jsClass ? jsClass->name : "<null>",
+          [object retainCount]);
+  }  
+}
+
+/* values */
+
+- (id)objectForJSValue:(void *)_value {
+  JSType    jsType;
+  JSBool    couldConvert;
+  JSContext *cx;
+  
+  couldConvert = JS_FALSE;
+  
+  if (JSVAL_IS_NULL(*(jsval *)_value))
+    return nil;
+  
+  cx = [self->jsContext handle];
+  jsType = JS_TypeOfValue(cx, *(jsval *)_value);
+  switch (jsType) {
+    case JSTYPE_VOID:
+      return nil;
+      
+    case JSTYPE_FUNCTION:
+    case JSTYPE_OBJECT: {
+      JSObject *obj;
+      
+      if (!(couldConvert = JS_ValueToObject(cx, *(jsval *)_value, &obj)))
+        break;
+      
+      return [self objectForHandle:obj];
+    }
+    
+#if 0
+    case JSTYPE_FUNCTION: {
+      JSFunction *func;
+      
+      if ((func = JS_ValueToFunction(cx, *(jsval *)_value))) {
+        static Class FuncClass = Nil;
+        
+        if (FuncClass == Nil)
+          FuncClass = NSClassFromString(@"NGJavaScriptFunction");
+
+        NSAssert(FuncClass, @"missing JS function class ..");
+        
+        return AUTORELEASE([[FuncClass alloc] initWithHandle:func
+                                              mappingContext:self]);
+      }
+      else {
+        NSLog(@"%s: couldn't get JS function ..", __PRETTY_FUNCTION__);
+        couldConvert = NO;
+      }
+      break;
+    }
+#endif
+      
+    case JSTYPE_STRING: {
+      JSString *s;
+
+      if ((s = JS_ValueToString(cx, *(jsval *)_value))) {
+        return [NSString stringWithJavaScriptString:s];
+      }
+      else
+        couldConvert = NO;
+      
+      break;
+    }
+    
+    case JSTYPE_NUMBER:
+      if (JSVAL_IS_INT(*(jsval *)_value)) {
+        int32 i;
+        
+        if ((couldConvert = JS_ValueToInt32(cx, *(jsval *)_value, &i)))
+          return [NSNumber numberWithInt:i];
+      }
+      else {
+        jsdouble d;
+
+        if ((couldConvert = JS_ValueToNumber(cx, *(jsval *)_value, &d)))
+          return [NSNumber numberWithDouble:d];
+      }
+      break;
+      
+    case JSTYPE_BOOLEAN: {
+      JSBool b;
+      
+      couldConvert = JS_ValueToBoolean(cx, *(jsval *)_value, &b);
+      if (couldConvert)
+        return [NSNumber numberWithBool:b ? YES : NO];
+      break;
+    }
+
+    default:
+      [NSException raise:@"InvalidJavaScriptTypeException"
+                   format:@"JavaScript value has unknown type %i !", jsType];
+  }
+  
+  if (!couldConvert) {
+      [NSException raise:@"JavaScriptTypeConvertException"
+                   format:@"Could not convert JavaScript value of type %i !",
+                     jsType];
+  }
+  
+  return nil;
+}
+
+- (BOOL)jsValue:(void *)_value forObject:(id)_obj {
+  /*
+    This is used to convert ObjC object _obj to a JSVAL.
+    
+    Cases:
+    - _obj is a proxy for a JavaScript object (eg NGJavaScriptObject),
+      the proxy will return the value itself
+    - _obj is a primitive Foundation object (eg NSString), the object
+      will convert itself to a primitiv JavaScript type using
+      _jsGetValue:inJSContext:
+    - _obj is a complex object, it will be mapped to a proxy JSObject
+    
+    Primitive types seem to be broken in certain cases right now.
+  */
+  if (_obj == nil) {
+    *(jsval *)_value = JSVAL_NULL;
+    return YES;
+  }
+  
+  if ([_obj respondsToSelector:@selector(_jsGetValue:inJSContext:)]) {
+    if (logValueConversion) {
+      NSLog(@"%s(0x%08X, 0x%08X<%@>) => own handling ..", 
+             __PRETTY_FUNCTION__,
+             _value, _obj, NSStringFromClass([_obj class]));
+    }
+    /* eg this is called on NSString */
+    return [_obj _jsGetValue:_value inJSContext:self->jsContext];
+  }
+  else if (_value) {
+    JSObject *jso;
+
+    if (logValueConversion) {
+      NSLog(@"%s(0x%08X, 0x%08X<%@>) => get handle ..", 
+             __PRETTY_FUNCTION__,
+             _value, _obj, NSStringFromClass([_obj class]));
+    }
+    
+    if ((jso = [self handleForObject:_obj]) == NULL)
+      return NO;
+    
+    *((jsval *)_value) = OBJECT_TO_JSVAL(jso);
+    return YES;
+  }
+  else {
+    if (logValueConversion) {
+      NSLog(@"%s(0x%08X, 0x%08X<%@>) => missing value store ?", 
+             __PRETTY_FUNCTION__,
+             _value, _obj, NSStringFromClass([_obj class]));
+    }
+    return NO;
+  }
+}
+
+@end /* NGJavaScriptObjectMappingContext */
+
+@implementation NGJavaScriptObjectMappingContext(CombinedObjects)
+
+/* combined objects */
+
+- (void)makeObjectCombined:(id)_object {
+  Class    clazz;
+  unsigned oldRC;
+  JSCombinedObjInfo *combinedObjInfo;
+  id handler;
+  
+  if (NSMapGet(combinedToInfo, _object))
+    /* object is already a combined one */
+    return;
+  
+  oldRC = [_object retainCount];
+  clazz = [_object class];
+  
+  handler = [[NGJavaScriptObjectHandler alloc]
+                                        initWithObject:_object
+                                        inMappingContext:self];
+  
+  if (![clazz isJSCombinedObjectClass]) {
+    // TODO: is this correct shouldn't we add combined behaviour only
+    //       *on* combined classes ??, explain !
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+    NSLog(@"ERROR(%s): combined objects not supported on this runtime!",
+          __PRETTY_FUNCTION__);
+    /* TODO: port to MacOSX */
+#else
+    static Class BehaviourClass = Nil;
+    BehaviourClass = NSClassFromString(@"JSCombinedObjectBehaviour");
+    NSAssert(BehaviourClass, @"did not find JSCombinedObjectBehaviour !");
+#if GNUSTEP_BASE_LIBRARY
+    behavior_class_add_class(clazz, BehaviourClass);
+#else
+    class_add_behavior(clazz, BehaviourClass);
+#endif
+#endif
+  }
+  
+  combinedObjInfo = calloc(1, sizeof(JSCombinedObjInfo));
+  combinedObjInfo->jso     = [handler handle];
+  combinedObjInfo->handler = handler;
+  combinedObjInfo->ctx     = self;
+  combinedObjInfo->rc      = oldRC; // -1 ???
+  
+  combinedObjInfo->rootRef = YES;
+  [handler jsRetain];
+  AUTORELEASE(handler);
+  
+  NSMapInsertKnownAbsent(combinedToInfo,  _object, combinedObjInfo);
+  
+  if (NGJavaScriptBridge_TRACK_MEMORY) {
+    NSLog(@"combine: o0x%08X<%@>->j0x%08X "
+          @"(handler=0x%08X, old-rc=%d, new-rc=%d)",
+          _object, NSStringFromClass([_object class]),
+          combinedObjInfo->jso, combinedObjInfo->handler, oldRC, [_object retainCount]);
+  }
+  
+#if DEBUG
+  NSAssert([_object isJSCombinedObject], @"still not a combined object !");
+#endif
+}
+
+- (BOOL)isCombinedObject:(id)_object {
+  return NSMapGet(combinedToInfo, _object) ? YES : NO;
+}
+
+- (void)_logCombinedObjects {
+  NSMapEnumerator e;
+  id                object;
+  JSCombinedObjInfo *combinedObjInfo;
+  
+  printf("Combined objects:\n");
+  printf("  %-10s %-16s %-2s %-10s %-10s %-10s %-2s %-2s\n",
+        "ObjC",
+        "Class",
+        "o#",
+        "JS",
+        "Ctx",
+        "Handler",
+        "/#",
+        "h#");
+  e = NSEnumerateMapTable(combinedToInfo);
+  while (NSNextMapEnumeratorPair(&e, (void*)&object, (void*)&combinedObjInfo)) {
+    printf("  0x%08X %-16s %2d 0x%08X 0x%08X 0x%08X %2d %2d\n", 
+          (unsigned)object, [NSStringFromClass([object class]) cString],
+          [object retainCount],
+          (unsigned)combinedObjInfo->jso,
+          (unsigned)combinedObjInfo->ctx,
+          (unsigned)combinedObjInfo->handler,
+          [combinedObjInfo->handler jsRootRetainCount],
+          [combinedObjInfo->handler retainCount]);
+  }
+}
+
+- (void)_jsFinalizeCombinedObject:(id)_object {
+  /*
+    This should never be called if ObjC RC > 0 !, since the ObjC object
+    keeps a root-ref to the JS object !
+  */
+  JSCombinedObjInfo *combinedObjInfo;
+  
+  if (_object == nil) return;
+  
+  if ((combinedObjInfo = NSMapGet(combinedToInfo, _object))) {
+    NSAssert(combinedObjInfo->ctx == self, @"invalid ctx for combined finalization !");
+    
+    if (combinedObjInfo->rc == 0) {
+      if (combinedObjInfo->rootRef) {
+        [combinedObjInfo->handler jsRelease];
+        combinedObjInfo->rootRef = NO;
+      }
+      
+      if (NGJavaScriptBridge_TRACK_MEMORY) {
+        NSLog(@"FREEING COMBINED OBJECT o%08X<%@>-j%08X (handler 0x%08X).",
+              _object, NSStringFromClass([_object class]),
+              combinedObjInfo->jso, combinedObjInfo->handler);
+      }
+      
+      NSMapRemove(combinedToInfo, _object);
+      combinedObjInfo = NULL;
+      
+      /* deallocate Objective-C memory of object */
+      [_object dealloc];
+    }
+    else {
+      NSLog(@"WARNING: finalized JS object, but handler RC > 0 !");
+    }
+  }
+}
+
+@end /* NGJavaScriptObjectMappingContext */
+
+@implementation NSObject(JSCombinedObjects)
+
++ (BOOL)isJSCombinedObjectClass {
+  return NO;
+}
+
+- (BOOL)isJSCombinedObject {
+  return NO;
+}
+- (NGJavaScriptObjectMappingContext *)jsObjectMappingContext {
+  return nil;
+}
+
+@end /* NSObject(JSCombinedObjects) */
+
+@implementation JSCombinedObjectBehaviour
+
+- (NGJavaScriptObjectMappingContext *)jsObjectMappingContext {
+  JSCombinedObjInfo *combinedObjInfo;
+  
+  if ((combinedObjInfo = NSMapGet(combinedToInfo, self)) == NULL)
+    return nil;
+  
+  return combinedObjInfo->ctx;
+}
+
++ (BOOL)isJSCombinedObjectClass {
+  return YES;
+}
+
+- (BOOL)isJSCombinedObject {
+  return NSMapGet(combinedToInfo, self) ? YES : NO;
+}
+
+/* retain-counting */
+
+- (id)retain {
+  JSCombinedObjInfo *combinedObjInfo;
+  
+  if ((combinedObjInfo = NSMapGet(combinedToInfo, self)) == NULL) {
+    if (NGJavaScriptBridge_TRACK_NOINFO_MEMORY) {
+      NSLog(@"CO: NO INFO retain: o%08X<%@>, rc=%d",
+            self, NSStringFromClass([self class]), [self retainCount]);
+    }
+    return [super retain];
+  }
+  
+  if (combinedObjInfo->handler == nil) {
+    if (NGJavaScriptBridge_TRACK_MEMORY) {
+      NSLog(@"CO: NO HANDLER retain: o%08X<%@>-j0x%08X, rc=%d",
+            self, NSStringFromClass([self class]),
+            combinedObjInfo->jso, [self retainCount]);
+    }
+    return [super retain];
+  }
+  
+  if (combinedObjInfo->rc == 0) {
+    /* life, but not specially retained (RC=1) */
+    
+    if (!combinedObjInfo->rootRef) {
+      /* ensure that the JS object is life */
+      [combinedObjInfo->handler jsRetain];
+      combinedObjInfo->rootRef = YES;
+    }
+  }
+  combinedObjInfo->rc++;
+  
+  if (NGJavaScriptBridge_TRACK_MEMORY_RC) {
+    NSLog(@"CO: retain: o%08X<%@>-j%08X (handler=0x%08X), rc=%d, root-rc=%d",
+          self, NSStringFromClass([self class]), combinedObjInfo->jso, combinedObjInfo->handler,
+          combinedObjInfo->rc, [combinedObjInfo->handler jsRootRetainCount]);
+  }
+  
+  return self;
+}
+
+- (oneway void)release {
+  JSCombinedObjInfo *combinedObjInfo;
+
+  if ((combinedObjInfo = NSMapGet(combinedToInfo, self)) == NULL) {
+    if (NGJavaScriptBridge_TRACK_NOINFO_MEMORY)
+      NSLog(@"CO: NO INFO release: o%08X, rc=%d", self, [self retainCount]);
+    
+    [super release];
+    return;
+  }
+  
+  if (combinedObjInfo->handler == nil) {
+    if (NGJavaScriptBridge_TRACK_MEMORY) {
+      NSLog(@"CO: NO HANDLER release: o%08X<%@>-j0x%08X, rc=%d",
+            self, NSStringFromClass([self class]),
+            combinedObjInfo->jso, [self retainCount]);
+    }
+    
+    [super release];
+    return;
+  }
+  
+  if (NGJavaScriptBridge_TRACK_MEMORY_RC) {
+    NSLog(@"CO: release: o%08X<%@>-j%08X (handler=0x%08X), rc=%d, root-rc=%d",
+          self, NSStringFromClass([self class]), combinedObjInfo->jso, combinedObjInfo->handler,
+          [self retainCount], [combinedObjInfo->handler jsRootRetainCount]);
+  }
+  NSAssert1(combinedObjInfo->handler,
+            @"missing handler for combined object 0x%08X ..", self);
+
+  
+  /*
+    this does never dealloc the ObjC object - the ObjC object is deallocated
+    in the JS destructor !
+  */
+
+  combinedObjInfo->rc--;
+  
+  if (combinedObjInfo->rc == 0) {
+    /* not specially retained in the ObjC side anymore */
+    
+    /* JS object is still live, release our root-ref .. */
+    NSAssert(combinedObjInfo->rootRef, @"missing JS root-reference");
+    [combinedObjInfo->handler jsRelease];
+    combinedObjInfo->rootRef = NO;
+    
+    if (NGJavaScriptBridge_TRACK_MEMORY) {
+      NSLog(@"%s: released last ObjC reference of o%08X-j%08X, %d root-refs ..",
+            __PRETTY_FUNCTION__,
+            self, combinedObjInfo->jso, [combinedObjInfo->handler jsRootRetainCount]);
+    }
+    
+    [combinedObjInfo->ctx performSelector:@selector(collectGarbage)
+                withObject:nil
+                afterDelay:0.0];
+  }
+}
+
+- (unsigned)retainCount {
+  JSCombinedObjInfo *combinedObjInfo;
+  
+  if ((combinedObjInfo = NSMapGet(combinedToInfo, self)) == NULL)
+    return [super retainCount];
+  
+  if (combinedObjInfo->handler == nil)
+    return [super retainCount];
+
+  return combinedObjInfo->rc;
+}
+
+/* evaluation */
+
+- (id)evaluateScript:(NSString *)_js language:(NSString *)_language {
+  JSCombinedObjInfo *combinedObjInfo;
+  
+  if ((combinedObjInfo = NSMapGet(combinedToInfo, self)) == NULL) {
+    /* what to do ? */
+    return [[[NGJavaScriptObjectMappingContext activeObjectMappingContext]
+                                               handlerForObject:self]
+                                               evaluateScript:_js];
+  }
+  
+  return [combinedObjInfo->handler evaluateScript:_js];
+}
+- (id)evaluateJavaScript:(NSString *)_js {
+  /* deprecated */
+  return [self evaluateScript:_js language:@"javascript"];
+}
+
+@end /* JSCombinedObjectBehaviour */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptRuntime.h b/skyrix-sope/NGJavaScript/NGJavaScriptRuntime.h
new file mode 100644 (file)
index 0000000..ff8d88b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScriptRuntime_H__
+#define __NGJavaScriptRuntime_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSArray;
+
+@interface NGJavaScriptRuntime : NSObject
+{
+  void *handle;
+}
+
++ (id)standardJavaScriptRuntime;
+- (id)initWithGCCollectSize:(unsigned)_size; /* designated initializer */
+- (id)init;
+
+/* private */
+
+- (void *)handle;
+
+/* contexts */
+
+- (NSArray *)contexts;
+
+/* globals */
+
++ (NSString *)javaScriptImplementationVersion;
+
+@end
+
+#endif /* __NGJavaScriptRuntime_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptRuntime.m b/skyrix-sope/NGJavaScript/NGJavaScriptRuntime.m
new file mode 100644 (file)
index 0000000..5bdf9b6
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptRuntime.h"
+#include "NGJavaScriptContext.h"
+#include "common.h"
+#include "globals.h"
+
+extern NSMapTable *jsctxToObjC;
+
+@implementation NGJavaScriptRuntime
+
+static JSBool jsGCCallback(JSContext *cx, JSGCStatus status)
+     __attribute__((unused));
+
++ (void)initialize {
+  static BOOL didInit = NO;
+
+  if (!didInit) {
+    NSUserDefaults *ud;
+    didInit = YES;
+    
+    ud = [NSUserDefaults standardUserDefaults];
+    
+    NGJavaScriptBridge_TRACK_FINALIZATION =
+      [ud boolForKey:@"JSTrackFinalization"];
+    NGJavaScriptBridge_TRACK_NOINFO_MEMORY =
+      [ud boolForKey:@"JSTrackNoInfoMemory"];
+    NGJavaScriptBridge_TRACK_MEMORY =
+      [ud boolForKey:@"JSTrackMemory"];
+    NGJavaScriptBridge_TRACK_MEMORY_RC =
+      [ud boolForKey:@"JSTrackMemoryRC"];
+    NGJavaScriptBridge_TRACK_FORGET =
+      [ud boolForKey:@"JSTrackForget"];
+
+    NGJavaScriptBridge_LOG_PROP_DEFINITION =
+      [ud boolForKey:@"JSTrackPropDefinition"];
+    NGJavaScriptBridge_LOG_FUNC_DEFINITION =
+      [ud boolForKey:@"JSTrackFuncDefinition"];
+
+    NGJavaScriptBridge_LOG_PROP_GET = [ud boolForKey:@"JSTrackPropGet"];
+    NGJavaScriptBridge_LOG_PROP_SET = [ud boolForKey:@"JSTrackPropSet"];
+    NGJavaScriptBridge_LOG_PROP_DEL = [ud boolForKey:@"JSTrackPropDel"];
+    NGJavaScriptBridge_LOG_PROP_ADD = [ud boolForKey:@"JSTrackPropAdd"];
+  }
+}
+
++ (id)standardJavaScriptRuntime {
+  static id stdrt = nil;
+
+  if (stdrt == nil) {
+    stdrt = [[self alloc] init];
+  }
+  return stdrt;
+}
+
+- (id)initWithGCCollectSize:(unsigned)_size {
+  self->handle = JS_NewRuntime(_size ? _size : 1024 * 1024 /* 1 MB default */);
+  if (self->handle == NULL) {
+    RELEASE(self);
+    return nil;
+  }
+
+  // JSSetGCCallbackRT(self->handle, jsGCCallback);
+  
+  return self;
+}
+- (id)init {
+  return [self initWithGCCollectSize:
+                 [[NSUserDefaults standardUserDefaults]
+                                  integerForKey:@"JSGCCollectSize"]];
+}
+
+- (void)dealloc {
+  if (self->handle)
+    JS_DestroyRuntime(self->handle);
+  [super dealloc];
+}
+
+- (void *)handle {
+  return self->handle;
+}
+
+/* named roots */
+
+static void rootDumper(const char *name, void *rp, void *data)
+     __attribute__((unused));
+
+static void rootDumper(const char *name, void *rp, void *data) {
+  printf("ROOT: %s rp=0x%08X rt=0x%08X\n", name, (unsigned)rp, (unsigned)data);
+}
+
+- (void)dumpNamedRoots {
+#if DEBUG && 0
+  JS_DumpNamedRoots(self->handle, rootDumper, self);
+#endif
+}
+
+/* garbage collector */
+
+- (BOOL)beginGarbageCollectionInContext:(NGJavaScriptContext *)_ctx {
+  return YES;
+}
+- (BOOL)endGarbageCollectionInContext:(NGJavaScriptContext *)_ctx {
+  return YES;
+}
+
+/* contexts */
+
+- (NSArray *)contexts {
+  JSContext *ctx, *iterp;
+  NSMutableArray *cts;
+
+  cts = [NSMutableArray array];
+  
+  for (iterp = NULL; (ctx = JS_ContextIterator(self->handle, &iterp)) != NULL;) {
+    NGJavaScriptContext *octx;
+
+    octx = NSMapGet(jsctxToObjC, ctx);
+    [cts addObject:octx];
+  }
+  return AUTORELEASE([cts copy]);
+}
+
+/* globals */
+
++ (NSString *)javaScriptImplementationVersion {
+  return [NSString stringWithCString:JS_GetImplementationVersion()];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<%@[0x%08X]: handle=0x%08X>",
+                     NSStringFromClass([self class]), self,
+                     [self handle]
+                   ];
+}
+
+/* statics */
+
+static JSBool jsGCCallback(JSContext *cx, JSGCStatus status) {
+  NGJavaScriptContext *ctx;
+  NGJavaScriptRuntime *rt;
+  
+  ctx = NSMapGet(jsctxToObjC, cx);
+  rt  = [ctx runtime];
+  
+  return (status == JSGC_BEGIN)
+    ? ([rt beginGarbageCollectionInContext:ctx] ? JSVAL_TRUE : JSVAL_FALSE)
+    : ([rt endGarbageCollectionInContext:ctx]   ? JSVAL_TRUE : JSVAL_FALSE);
+}
+
+@end /* NGJavaScriptRuntime */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptShadow.h b/skyrix-sope/NGJavaScript/NGJavaScriptShadow.h
new file mode 100644 (file)
index 0000000..f16cb5a
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGJavaScriptShadow_H__
+#define __NGJavaScriptShadow_H__
+
+#include <NGJavaScript/NGJavaScriptObject.h>
+#include <NGScripting/NGScriptLanguage.h>
+
+/*
+  A shadow state object for an ObjC real object. The ObjC object needs to
+  forward dynamic state changes to this object, but it's properties and
+  methods are exposed under 'this' in the state object (no back-reference
+  is required).
+  The shadow object forwards it's static property and functions calls to it's
+  master using the private.
+
+  A shadow is required to retain the state of the script object since
+  a normal ObjC object doesn't keep a reference to a script object ! The
+  shadow contains some kind of specialized "extra variables" for the ObjC 
+  object.
+*/
+
+@interface NGJavaScriptShadow : NGJavaScriptObject < NGScriptShadow >
+{
+  id masterObject; /* non-retained */
+}
+
+- (void)setMasterObject:(id)_master;
+- (id)masterObject;
+
+@end
+
+#endif /* __NGJavaScriptShadow_H__ */
diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptShadow.m b/skyrix-sope/NGJavaScript/NGJavaScriptShadow.m
new file mode 100644 (file)
index 0000000..1803a9e
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGJavaScriptShadow.h"
+#include "NGJavaScriptObjCClassInfo.h"
+#include "NGJavaScriptObjectMappingContext.h"
+#include <NGScripting/NGScriptLanguage.h>
+#include "common.h"
+#include "globals.h"
+
+static BOOL IsInPropDefMode = NO;
+
+@interface NGJavaScriptShadow(Privates)
+- (BOOL)_applyStaticDefs;
+@end
+
+@implementation NGJavaScriptShadow
+
+static NGScriptLanguage *jslang = nil;
+
+static inline NGScriptLanguage *_JS(void) {
+  if (jslang == nil)
+    jslang = [[NGScriptLanguage languageWithName:@"javascript"] retain];
+  return jslang;
+}
+
+static void _finalize(JSContext *cx, JSObject *obj) {
+  NGJavaScriptShadow *self;
+  
+  if ((self = JS_GetPrivate(cx, obj)) == NULL) {
+    //printf("finalized JS shadow ..\n");
+  }
+  else {
+    NSLog(@"ERROR(%s): finalizing JS shadow j0x%08X, "
+          @"still has a private o0x%08X !!!",
+          __PRETTY_FUNCTION__, obj, self);
+  }
+}
+
+JSClass ObjCShadow_JSClass = {
+  "NGObjCShadow",
+  JSCLASS_HAS_PRIVATE /* flags */,
+  JS_PropertyStub,
+  JS_PropertyStub,
+  JS_PropertyStub,
+  JS_PropertyStub,
+  JS_EnumerateStub,
+  JS_ResolveStub,
+  JS_ConvertStub,
+  _finalize,
+  /* Optionally non-null members start here. */
+  NULL, //JSGetObjectOps getObjectOps;
+  NULL, //JSCheckAccessOp checkAccess;
+  NULL, //JSNative call;
+  NULL, //JSNative construct;
+  NULL, //JSXDRObjectOp xdrObject;
+  NULL, //JSHasInstanceOp hasInstance;
+  //prword spare[2];
+};
+
++ (void *)jsObjectClass {
+  return &ObjCShadow_JSClass;
+}
+
+static JSBool shadow_FuncDispatcher
+(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool shadow_setStaticProp
+(JSContext *cx, JSObject *obj, jsval _id, jsval *vp);
+static JSBool shadow_getStaticProp
+(JSContext *cx, JSObject *obj, jsval _id, jsval *vp);
+
+static NSMutableDictionary *classToInfo = nil;
+
+static void relInfo(void) {
+  if (classToInfo)
+    RELEASE(classToInfo); classToInfo = nil;
+}
+
+static NGJavaScriptObjCClassInfo *jsClassInfo(Class _class) {
+  NGJavaScriptObjCClassInfo  *ci;
+
+  if (_class == Nil)
+    return nil;
+  
+  if (classToInfo == nil) {
+    classToInfo = [[NSMutableDictionary alloc] initWithCapacity:64];
+    atexit(relInfo);
+  }
+  
+  if ((ci = [classToInfo objectForKey:_class]) == nil) {
+    ci = [[NGJavaScriptObjCClassInfo alloc]
+                                     initWithClass:_class
+                                     setter:shadow_setStaticProp
+                                     getter:shadow_getStaticProp
+                                     caller:shadow_FuncDispatcher];
+    [classToInfo setObject:ci forKey:_class];
+    AUTORELEASE(ci);
+  }
+  
+  return ci;
+}
+
+- (id)initWithHandle:(void *)_handle
+  inMappingContext:(NGObjectMappingContext *)_ctx
+{
+  if ((self = [super initWithHandle:_handle inMappingContext:_ctx])) {
+    JS_SetPrivate(self->jscx, _handle, self);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (NGJavaScriptBridge_TRACK_MEMORY) {
+    NSLog(@"%s: dealloc shadow o0x%08X j0x%08X ctx=0x%08X jcx=0x%08X",
+          __PRETTY_FUNCTION__, self, self->handle,
+          self->ctx, self->jscx);
+  }
+  
+  if (self->handle)
+    JS_SetPrivate(self->jscx, self->handle, NULL);
+  
+  [super dealloc];
+}
+
+- (void)setMasterObject:(id)_master {
+  if ((self->masterObject = _master)) {
+    if (![self _applyStaticDefs]) {
+      self->masterObject = nil;
+      NSLog(@"%s: resetted master object, because static defs could "
+           @"not be applied: %@", __PRETTY_FUNCTION__, _master);
+    }
+  }
+  else {
+    if (NGJavaScriptBridge_TRACK_MEMORY) {
+      NSLog(@"%s: resetted shadow master (rc now %i)",
+            __PRETTY_FUNCTION__,
+            [self retainCount]);
+    }
+  }
+}
+- (id)masterObject {
+  return self->masterObject;
+}
+- (void)invalidateShadow {
+  [self setMasterObject:nil];
+}
+
+- (BOOL)_applyStaticDefs {
+  NGJavaScriptObjCClassInfo *ci;
+  BOOL ok;
+  
+  if (self->masterObject == nil)
+    return NO;
+  
+  ci = jsClassInfo([self->masterObject class]);
+  
+  IsInPropDefMode = YES;
+  ok = [ci applyOnJSObject:self->handle inJSContext:self->jscx];
+  if (!ok)
+    NSLog(@"ERROR(%s): couldn't apply static defs !", __PRETTY_FUNCTION__);
+  IsInPropDefMode = NO;
+  return ok;
+}
+
+/* static definition declarations */
+
+static JSBool shadow_setStaticProp
+(JSContext *cx, JSObject *obj, jsval _id, jsval *vp)
+{
+  NGJavaScriptObjCClassInfo *ci;
+  NGJavaScriptShadow *self;
+  SEL sel;
+  id  value;
+  
+  if ((self = JS_GetPrivate(cx, obj)) == NULL)
+    return JS_FALSE;
+  
+  if (self->masterObject == nil) {
+    NSLog(@"%s: master object was deallocated !", __PRETTY_FUNCTION__);
+    return JS_FALSE;
+  }
+  
+  ci = jsClassInfo([self->masterObject class]);
+  NSCAssert(ci, @"missing class info ..");
+  
+  sel = [ci setSelectorForPropertyId:&_id inJSContext:cx];
+  
+  if (sel == NULL) {
+    NSLog(@"%s: did not find selector for id !", __PRETTY_FUNCTION__);
+    return JS_FALSE;
+  }
+  
+  value = [self->ctx objectForJSValue:vp];
+  [self->masterObject performSelector:sel withObject:value];
+  
+  return JS_TRUE;
+}
+static JSBool shadow_getStaticProp
+(JSContext *cx, JSObject *obj, jsval _id, jsval *vp)
+{
+  NGJavaScriptObjCClassInfo *ci;
+  NGJavaScriptShadow *self;
+  SEL sel;
+  id  result;
+  
+  if ((self = JS_GetPrivate(cx, obj)) == NULL) {
+    NSLog(@"%s: did not find private of JS shadow object !",
+          __PRETTY_FUNCTION__);
+    return JS_FALSE;
+  }
+  
+  if (self->masterObject == nil) {
+    NSLog(@"%s: master object was deallocated !", __PRETTY_FUNCTION__);
+    return JS_FALSE;
+  }
+  
+  ci  = jsClassInfo([self->masterObject class]);
+  sel = [ci getSelectorForPropertyId:&_id inJSContext:cx];
+  
+  if (sel == NULL) {
+    NSLog(@"%s: did not find selector for id !", __PRETTY_FUNCTION__);
+    return JS_FALSE;
+  }
+  
+  result = [self->masterObject performSelector:sel];
+  //NSLog(@"result is %@", result);
+  
+  return [self->ctx jsValue:vp forObject:result]
+    ? JS_TRUE
+    : JS_FALSE;
+}
+
+static JSBool shadow_FuncDispatcher
+(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+  NGJavaScriptShadow *self;
+  JSFunction  *funobj;
+  const char  *funcName;
+  char        *msgname;
+  SEL         sel;
+  unsigned    i;
+  id          *args;
+  NSArray     *argArray;
+  id          result;
+  NSException *exception;
+  JSBool      retcode = 0;
+  
+  if (JS_IsConstructing(cx)) 
+    obj = JS_GetParent(cx, obj);
+  
+#if DEBUG
+  if (JS_GetClass(obj) != &ObjCShadow_JSClass) {
+    NSLog(@"%s: invoked on invalid object class (eg using 'new' ?) !",
+          __PRETTY_FUNCTION__);
+    return JS_FALSE;
+  }
+#endif
+  
+  if ((self = JS_GetPrivate(cx, obj)) == NULL)
+    return JS_FALSE;
+  
+#if DEBUG
+  NSCAssert(JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION,
+            @"expected function in argv[-2] !");
+#endif
+  
+  funobj   = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[-2]));
+  funcName = JS_GetFunctionName(funobj);
+  
+  msgname = malloc(strlen(funcName) + 10);
+  strcpy(msgname, "_jsfunc_");
+  strcat(msgname, funcName);
+  strcat(msgname, ":");
+#if APPLE_RUNTIME || NeXT_RUNTIME
+  sel = sel_getUid(msgname); /* TODO: should be registerName? */
+#else
+  sel = sel_get_any_uid(msgname);
+#endif
+  
+  if (argc > 0) {
+    args = calloc(argc, sizeof(id));
+    for (i = 0; i < argc; i++) {
+      args[i] =
+        [self->ctx objectForJSValue:&(argv[i])];
+      
+      if (args[i] == nil) args[i] = [EONull null];
+    }
+    argArray = [NSArray arrayWithObjects:args count:argc];
+    free(args);
+  }
+  else
+    argArray = [NSArray array];
+
+#if 0  
+  NSLog(@"calling function '%s'(%s), %d args %@\n",
+        funcName, msgname, argc, argArray);
+#endif
+  
+  exception = nil;
+  NS_DURING {
+    result  = [self->masterObject performSelector:sel withObject:argArray];
+    retcode = [self->ctx jsValue:rval forObject:result] ? JS_TRUE : JS_FALSE;
+  }
+  NS_HANDLER {
+    exception = RETAIN(localException);
+  }
+  NS_ENDHANDLER;
+  
+  if (exception) {
+    jsval exval;
+    
+#if DEBUG
+    NSLog(@"%s: catched exception: %@", __PRETTY_FUNCTION__, exception);
+#endif
+    
+    retcode = JS_FALSE;
+    
+    if ([self->ctx jsValue:&exval forObject:[exception description]]) {
+      JS_SetPendingException(cx, exval);
+    }
+    else {
+      NSLog(@"%s: couldn't get JS value for exception: %@",
+            __PRETTY_FUNCTION__, exception);
+    }
+  }
+  
+  return retcode;
+}
+
+/* specialized calls */
+
+- (id)callScriptFunction:(NSString *)_func {
+  return [_JS() callFunction:_func onObject:self];
+}
+- (id)callScriptFunction:(NSString *)_func withObject:(id)_obj {
+  return [_JS() callFunction:_func withArgument:_obj onObject:self];
+}
+- (BOOL)hasFunctionNamed:(NSString *)_func {
+  return [super hasFunctionNamed:_func];
+}
+
+- (id)evaluateScript:(NSString *)_script 
+  source:(NSString *)_src line:(unsigned)_line 
+{
+  return [_JS() evaluateScript:_script onObject:self source:_src line:_line];
+}
+- (id)evaluateScript:(NSString *)_script {
+  return [self evaluateScript:_script source:@"<string>" line:0];
+}
+
+/* NSCoding */
+
+- (id)initWithCoder:(NSCoder *)_coder {
+  if ((self = [super initWithCoder:_coder])) {
+    [self setMasterObject:[_coder decodeObject]];
+  }
+  return self;
+}
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [super encodeWithCoder:_coder];
+  [_coder encodeObject:[self masterObject]];
+}
+
+@end /* NGJavaScriptShadow */
diff --git a/skyrix-sope/NGJavaScript/README b/skyrix-sope/NGJavaScript/README
new file mode 100644 (file)
index 0000000..2a2ad7c
--- /dev/null
@@ -0,0 +1,132 @@
+# $Id$
+
+Objective-C / JavaScript bridge
+===============================
+
+This code implements an Objective-C/JavaScript bridge that uses the
+SpiderMonkey JavaScript engine from the Mozilla project. It's used
+for scripted NGObjWeb components and for SKYRiX forms.
+
+It works pretty well so far, but currently requires a bit of work 
+to expose functions and properties from ObjC to JavaScript. Note that
+it's by intention that not all selectors of an ObjC class are exposed
+automatically as JavaScript functions primarily for security reasons
+(we want to support JavaScript 'sandboxes').
+
+In later versions I would like to move to mapping code to a configuration
+file and maybe add some security assertions. Pretty much like the Zope
+security system ... I'm not sure yet how/whether we could use the builtin
+security principal objects of SpiderMoneky.
+Further the bridge could/should get more AppleScript API like, that is,
+it should build scriptClassDescriptions and maybe use the Foundation
+ValueCoercionHandler.
+
+The bridge is not thread safe in the moment. At least one thing: the
+current mapping context is stored in a global variable.
+
+TRAPS:
+======
+  - do never use things as properties which reference the property owner, since
+    properties are cached by SpiderMonkey, you are going to have a cycle. Eg:
+
+      dom.all['blah']
+
+    If the 'all' proxy retains the 'dom' object, we are going to have a cycle.
+    'all' may only have a weak reference to 'dom' !
+    => this could be improved now be using the new deallochack from 
+       MulleKybernetik
+    => Brendan Eich also added some kind of pass-through flag were a backend
+       class can be the only property store and therefore disable the
+       described caching ?
+
+Archiving
+=========
+
+See archiving in Rhino to understand the difficulties:
+
+  http://mozilla.org/rhino/serialization.html
+  
+NSArchiver makes some things easier by providing conditional
+archiving. Eg the prototype and parent object are encoded that
+way. Besides that the mapping context is never encoded - you need
+to create one before you unarchive JS objects.
+
+Currently function objects are never archived. To be fixed.
+
+BUGS
+====
+
+- objectForKey:functionName does not return a NGJavaScriptFunction ?
+- during large exports with SkyPublisher either the bridge or SpiderMonkey
+  sometimes dump core in some AddRootObject call
+- function objects are not archived
+
+TODO
+====
+
+- we should probably create one JS class for each Objective-C
+  class, so that we don't need to define all the hooks again
+  and again (but instead use the class prototype object) !
+  (needs to be recreated if bundles are loaded)
+- BUGS first ! ;-)
+- speed, NGJavaScript currently is not optimized at all
+- thread safety
+- better AppleScript class compatibility
+- improved mapping facilities (mapping rule files)
+- archiving of additional native objects (dates, functions, ...)
+- combined objects
+- add dealloc-hack to improve tracking of objects
+
+Internals
+=========
+
+NGJavaScript is based on the NGScripting library which already provides
+the high-level API to load and execute scripts in any language.
+
+Classes
+  NGJavaScriptObject
+  
+  NGJavaScriptArray
+  NGJavaScriptArray(NSArrayCompatibility)
+  NGJavaScriptArray(NSMutableArrayCompatibility)
+  - a JavaScript array. this class inherits from NGJavaScriptObject
+    and "aquires" the methods of NSMutableArray using add_behaviour,
+    which is unsupported on NeXT runtime
+  
+  NGJavaScriptCallable
+  - a JavaScript "callable", that is, a JavaScript function or method
+  
+  NGJavaScriptContext
+  NGJavaScriptFunction
+  NSObject(JSFuncTyping)
+  NGJavaScriptLanguage
+  NGJavaScriptObjCClassInfo
+  JSIDEnum
+  JSObjChainEnum
+  NGJavaScriptObjectHandler
+  NGJavaScriptObjectMappingContext
+  NGJavaScriptObjectMappingContext(CombinedObjects)
+  NSObject(JSCombinedObjects)
+  JSCombinedObjectBehaviour
+  NGJavaScriptRuntime
+  NGJavaScriptShadow
+
+Some JS Samples
+===============
+
+  Exception Handling:
+    throw myObject;
+    try {} catch (localException) { };
+    - localException is the exception itself, not a switch on 
+      it's class
+    - throw can take any object, eg: "throw 5"
+
+Defaults
+========
+
+  JSAbortOnError        (abort on "JS ERROR" logs)
+  JSDebugContextDealloc (enable some logs in -dealloc of the JS Context Wrap)
+  jsLogPropDef         bool
+  jsLogFuncDef         bool
+  JSLogHandleForObject bool  log calls to -handleForObject:
+  JSLogValueConversion bool  log calls to jsValue:forObject:
diff --git a/skyrix-sope/NGJavaScript/ScriptLanguages.plist b/skyrix-sope/NGJavaScript/ScriptLanguages.plist
new file mode 100644 (file)
index 0000000..2a59cf2
--- /dev/null
@@ -0,0 +1,6 @@
+(
+  "javascript",
+  "javascript1.0",
+  "javascript1.1",
+  "javascript1.2"
+)
diff --git a/skyrix-sope/NGJavaScript/TODO b/skyrix-sope/NGJavaScript/TODO
new file mode 100644 (file)
index 0000000..b07930e
--- /dev/null
@@ -0,0 +1,41 @@
+# $Id: TODO,v 1.1.1.1 2003/07/09 22:57:26 cvs Exp $
+
+in common.h, correctly detect NG_VARARGS_AS_REFERENCE for gcc 3
+  - how do we detect gcc3 ?
+
+
+- add a .jobs like file for mapping selectors to functions instead of
+  special _jsfunc_, _jsprop_ selectors
+
+
+Find out the difference between NGJavaScriptObject and 
+NGJavaScriptObjectHandler
+=> document NGJavaScriptObject
+- the handler seems to be stored in the JS private field ?
+
+NGJavaScriptObjectHandler
+- is attached to a SpiderMonkey finalizer
+  - the finalizer func gets the handler reference from the JS private
+  - the managedObject should be active there
+  - the finalizer calls forgetObject: on the context
+    - forgetObject: removes the object from the objcToJS hash
+    - objcToJS retains the object
+- is created in NGJavaScriptObjectMappingContext -proxyForObject:
+- is created in makeObjectCombined
+
+BUG
+- Note: do not mix up the mapping context and the JS context
+  - we are talking about the NGJavaScriptObjectMappingContext, not about
+    the JS context (which is retained by the mapping context)
+- sometimes a context is collected earlier than a NGJavaScriptObjectHandler,
+  AFAIK the handler is registered inside the context and therefore can't
+  retain it (otherwise we would have a retain cycle)
+  - so either the context does not invalidate the object handlers
+  - or we have some handler which does not properly unregisters
+  - or something else :-(
+  Result:
+  ---snip---
+  Reason: message 'forgetObject:' sent to freed object 0x811a4d4 \
+    (NGJavaScriptObjectMappingContext)
+  ---snap---
+  - hm, but NGJavaScriptObject retains the context ?
diff --git a/skyrix-sope/NGJavaScript/Version b/skyrix-sope/NGJavaScript/Version
new file mode 100644 (file)
index 0000000..1c8a2e7
--- /dev/null
@@ -0,0 +1,5 @@
+# $Id$
+
+SUBMINOR_VERSION:=30
+
+# v4.2.24 requires libEOControl v4.2.39
diff --git a/skyrix-sope/NGJavaScript/common.h b/skyrix-sope/NGJavaScript/common.h
new file mode 100644 (file)
index 0000000..3feeaab
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#define id _id
+#  include <js/jsapi.h>
+#  include <js/jsobj.h>
+#  include <js/jsutil.h>
+#  include <js/jsfun.h>
+#  include <js/jsarray.h>
+#undef id
+
+#import <Foundation/Foundation.h>
+#include <EOControl/EOControl.h>
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+#  include <objc/objc.h>
+#  include <objc/objc-class.h>
+#endif
+
+#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY || \
+    COCOA_Foundation_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#  if 0 // no FoundationExt
+#    include <FoundationExt/objc-runtime.h>
+#    include <FoundationExt/MissingMethods.h>
+#  endif
+#elif LIB_FOUNDATION_LIBRARY
+#  include <extensions/objc-runtime.h>
+#endif
+
+// TODO: this is true for any gcc 3 ?
+#if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY || GNUSTEP_BASE_LIBRARY
+#  define NG_VARARGS_AS_REFERENCE 1
+#endif
diff --git a/skyrix-sope/NGJavaScript/dummy.m b/skyrix-sope/NGJavaScript/dummy.m
new file mode 100644 (file)
index 0000000..90ae5c2
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/* required for linking bundles/frameworks without source files */
diff --git a/skyrix-sope/NGJavaScript/globals.h b/skyrix-sope/NGJavaScript/globals.h
new file mode 100644 (file)
index 0000000..561cc08
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __JSBridge_globals_H__
+#define __JSBridge_globals_H__
+
+extern BOOL NGJavaScriptBridge_TRACK_FINALIZATION;
+extern BOOL NGJavaScriptBridge_TRACK_NOINFO_MEMORY;
+extern BOOL NGJavaScriptBridge_TRACK_MEMORY;
+extern BOOL NGJavaScriptBridge_TRACK_MEMORY_RC;
+extern BOOL NGJavaScriptBridge_TRACK_FORGET;
+
+extern BOOL NGJavaScriptBridge_LOG_PROP_DEFINITION;
+extern BOOL NGJavaScriptBridge_LOG_FUNC_DEFINITION;
+
+extern BOOL NGJavaScriptBridge_LOG_PROP_GET;
+extern BOOL NGJavaScriptBridge_LOG_PROP_SET;
+extern BOOL NGJavaScriptBridge_LOG_PROP_DEL;
+extern BOOL NGJavaScriptBridge_LOG_PROP_ADD;
+
+#endif /* __JSBridge_globals_H__ */
diff --git a/skyrix-sope/NGJavaScript/globals.m b/skyrix-sope/NGJavaScript/globals.m
new file mode 100644 (file)
index 0000000..71b5767
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/NSObject.h>
+
+BOOL NGJavaScriptBridge_TRACK_FINALIZATION  = NO;
+BOOL NGJavaScriptBridge_TRACK_NOINFO_MEMORY = NO;
+BOOL NGJavaScriptBridge_TRACK_MEMORY        = NO;
+BOOL NGJavaScriptBridge_TRACK_MEMORY_RC     = NO;
+BOOL NGJavaScriptBridge_TRACK_FORGET        = NO;
+
+BOOL NGJavaScriptBridge_LOG_PROP_DEFINITION = NO;
+BOOL NGJavaScriptBridge_LOG_FUNC_DEFINITION = NO;
+
+BOOL NGJavaScriptBridge_LOG_PROP_GET = NO;
+BOOL NGJavaScriptBridge_LOG_PROP_SET = NO;
+BOOL NGJavaScriptBridge_LOG_PROP_DEL = NO;
+BOOL NGJavaScriptBridge_LOG_PROP_ADD = NO;
diff --git a/skyrix-sope/NGJavaScript/jsobjops.m b/skyrix-sope/NGJavaScript/jsobjops.m
new file mode 100644 (file)
index 0000000..76b9360
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+#import <NGJavaScript/NGJavaScript.h>
+#import <NGJavaScript/NGJavaScriptObjectMappingContext.h>
+
+#import "JSObjectOps.m"
+
+id mapCtx = nil;
+
+static char *cstr = "print('this is '+this);\n";
+
+static void testinctx(void) {
+  JSContext *cx;
+  JSObject  *jso;
+  JSBool    res;
+  jsval     lastValue;
+  
+  cx = [[mapCtx jsContext] handle];
+  
+  jso = JS_NewObject(cx,
+                    &NGJavaScriptObjectHandler_JSObjectOpsClass,
+                    NULL, NULL);
+  NSCAssert(jso, @"couldn't create JS object ..");
+
+  res = JS_EvaluateScript(cx, jso,
+                         cstr, strlen(cstr),
+                          "<string>",  /* source file */
+                          0,           /* line number */
+                          &lastValue);
+  NSCAssert(res == JS_TRUE, @"couldn't evaluate script ..");
+}
+
+#include <NGExtensions/NGExtensions.h>
+
+int main(int argc, char **argv, char **env) {
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  {
+    mapCtx = [[NGJavaScriptObjectMappingContext alloc] init];
+  
+    if (![[mapCtx jsContext] loadStandardClasses])
+      ;
+  
+    [mapCtx pushContext];
+    testinctx();
+    [mapCtx popContext];
+  
+    RELEASE(mapCtx);
+  }
+
+  [NGExtensions class];
+  return 0;
+}
diff --git a/skyrix-sope/NGJavaScript/testjs.m b/skyrix-sope/NGJavaScript/testjs.m
new file mode 100644 (file)
index 0000000..8718f72
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "JSBridgeTests.h"
+#include "JSArchivingTests.h"
+#include "common.h"
+#include <NGExtensions/NGExtensions.h>
+#include "globals.h"
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  NGJavaScriptBridge_TRACK_FINALIZATION = YES;
+  NGJavaScriptBridge_TRACK_MEMORY       = YES;
+  NGJavaScriptBridge_TRACK_FORGET       = YES;
+
+  NS_DURING {
+    [JSBridgeTests    runSuite];
+    //[JSArchivingTests runSuite];
+  }
+  NS_HANDLER
+    abort();
+  NS_ENDHANDLER;
+  
+  [pool release];
+  [NGExtensions class];
+  return 0;
+}
diff --git a/skyrix-sope/NGJavaScript/tests/.cvsignore b/skyrix-sope/NGJavaScript/tests/.cvsignore
new file mode 100644 (file)
index 0000000..4d46bf0
--- /dev/null
@@ -0,0 +1,2 @@
+Resources
+
diff --git a/skyrix-sope/NGJavaScript/tests/Blah.h b/skyrix-sope/NGJavaScript/tests/Blah.h
new file mode 100644 (file)
index 0000000..49c1149
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __Blah_H__
+#define __Blah_H__
+
+#import <Foundation/NSObject.h>
+
+@interface Blah : NSObject
+@end
+
+#endif /* __Blah_H__ */
diff --git a/skyrix-sope/NGJavaScript/tests/Blah.m b/skyrix-sope/NGJavaScript/tests/Blah.m
new file mode 100644 (file)
index 0000000..faaffa2
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "Blah.h"
+#include "MyNum.h"
+#include "common.h"
+
+@implementation Blah
+
+- (id)_jsprop_sequence {
+  static int i = 0;
+  i++;
+  return [MyNum numberWithInt:i];
+  //return [NSNumber numberWithInt:i];
+}
+- (id)_jsprop_title {
+  return @"My Title";
+}
+
+- (id)_jsfunc_MyType:(NSArray *)_args {
+  return [MyNum numberWithInt:10];
+}
+
+- (id)_jsfunc_getContent:(NSArray *)_args {
+  return [NSString stringWithFormat:@"My Content String ..."];
+}
+
+@end /* Blah */
diff --git a/skyrix-sope/NGJavaScript/tests/Combined.h b/skyrix-sope/NGJavaScript/tests/Combined.h
new file mode 100644 (file)
index 0000000..fe8d295
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __Combined_H__
+#define __Combined_H__
+
+#import <Foundation/NSObject.h>
+
+@interface Combined : NSObject
+@end
+
+#endif /* __Combined_H__ */
diff --git a/skyrix-sope/NGJavaScript/tests/Combined.m b/skyrix-sope/NGJavaScript/tests/Combined.m
new file mode 100644 (file)
index 0000000..2075f5a
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "Combined.h"
+#include "Blah.h"
+#include "common.h"
+
+@implementation Combined
+
+- (id)_jsprop_blah {
+  return AUTORELEASE([[Blah alloc] init]);
+}
+
+@end /* combined */
diff --git a/skyrix-sope/NGJavaScript/tests/GNUmakefile b/skyrix-sope/NGJavaScript/tests/GNUmakefile
new file mode 100644 (file)
index 0000000..3059371
--- /dev/null
@@ -0,0 +1,20 @@
+# $Id$
+
+include ../../common.make
+
+SUBPROJECT_NAME = JSTests
+
+JSTests_OBJC_FILES = \
+       Blah.m                  \
+       Combined.m              \
+       MyNum.m                 \
+       \
+       JSTest.m                \
+       JSArchivingTests.m      \
+       JSBridgeTests.m         \
+
+ADDITIONAL_CPPFLAGS += -DXP_UNIX=1
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGJavaScript/tests/JSArchivingTests.h b/skyrix-sope/NGJavaScript/tests/JSArchivingTests.h
new file mode 100644 (file)
index 0000000..2ba33d8
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __JSArchivingTests_H__
+#define __JSArchivingTests_H__
+
+#include "JSTest.h"
+
+@interface JSArchivingTests : JSTest
+{
+}
+
++ (void)runSuite;
+
+@end
+
+#endif /* __JSArchivingTests_H__ */
diff --git a/skyrix-sope/NGJavaScript/tests/JSArchivingTests.m b/skyrix-sope/NGJavaScript/tests/JSArchivingTests.m
new file mode 100644 (file)
index 0000000..d1f1f7b
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "JSArchivingTests.h"
+#include "Blah.h"
+#include "MyNum.h"
+#include "common.h"
+
+#import <NGJavaScript/NGJavaScript.h>
+#import <NGScripting/NGScriptLanguage.h>
+#import <NGExtensions/NGExtensions.h>
+
+@implementation JSArchivingTests
+
++ (void)runSuite {
+  [self runTest:@"Archiving"];
+  [self runTest:@"JSArrayArchiveEvalProblem"];
+}
+
+- (void)testArchiving {
+  static NSString *testScript = 
+    @"var c = 30;\n"
+    @"var myArray=[1,2,3];\n"
+    @"function doIt(sender) {\n"
+    @"  print('doIt, a='+a+', b='+b+', c='+c);\n"
+    @"}\n"
+    ;
+  id original, copy;
+  NSData *archive;
+  
+  original = [[NGJavaScriptObject alloc] init];
+  [original setObject:@"10" forKey:@"a"];
+  [original setObject:@"20" forKey:@"b"];
+  [original evaluateScript:testScript language:@"javascript"];
+  [self print:@"  a: %@", [original objectForKey:@"a"]];
+  [self print:@"  b: %@", [original objectForKey:@"b"]];
+  [self print:@"  doIt: %@", [original objectForKey:@"doIt"]];
+  
+  [self print:@"archive object %@ (keys=%@) ...", 
+          original, 
+          [[original allKeys] componentsJoinedByString:@","]];
+  
+  archive = [NSArchiver archivedDataWithRootObject:original];
+  [self print:@"archived to data, size %i", [archive length]];
+  
+  copy = [NSUnarchiver unarchiveObjectWithData:archive];
+  [self print:@"unarchived object %@ (keys=%@)", 
+          copy,
+          [[copy allKeys] componentsJoinedByString:@","]];
+  [self print:@"  a: %@", [copy objectForKey:@"a"]];
+  [self print:@"  b: %@", [copy objectForKey:@"b"]];
+  [self print:@"  doIt: %@", [copy objectForKey:@"doIt"]];
+  [self print:@"  myArray: %@ (%@)", 
+       [copy objectForKey:@"myArray"],
+       [[copy objectForKey:@"myArray"] class]];
+  
+  [original release];
+}
+
+
+- (void)testJSArrayArchiveEvalProblem {
+  static NSString *testScriptA =
+    @"try {\n"
+    @"var counter=0;\n"
+    @"var dataRec = [\n"
+    @"  { 'a': 5, 'b': 10 }\n"
+    @"];\n"
+    @"} catch (exc) {\n"
+    @"  print('JS CODE CATCHED: '+exc);\n"
+    @"}\n"
+    ;
+  id wrapper, copy;
+  NSData *archive;
+  
+  /* create an object */
+  
+  wrapper = [[[NGJavaScriptObject alloc] init] autorelease];
+  [self print:@"object: %@ (keys=%@)", wrapper, [wrapper allKeys]];
+  
+  [wrapper evaluateScript:testScriptA language:@"javascript"];
+  [self print:@"object: %@ (keys=%@)", wrapper, [wrapper allKeys]];
+  [self printJavaScriptObjectInfo:wrapper];
+  
+  /* do the archiving/unarchiving transaction to create a copy */
+  
+  archive = [NSArchiver archivedDataWithRootObject:wrapper];
+  NSAssert1([archive length] > 0, 
+            @"archiver didn't generate a proper archive: %@",
+            archive);
+  
+  copy = [NSUnarchiver unarchiveObjectWithData:archive];
+  NSAssert(copy != nil, @"couldn't unarchive the object at all");
+  NSAssert1([copy isKindOfClass:[NGJavaScriptObject class]],
+            @"unexpected object class: %@", [copy class]);
+  
+  [self print:@"copy: %@ (keys=%@)", copy, [copy allKeys]];
+  [self printJavaScriptObjectInfo:wrapper];
+  
+  /*
+    the following broke with: "JS ERROR(<string>:1): null" which is
+    why we have this test
+  */
+  [copy evaluateScript:testScriptA language:@"javascript"];
+}
+
+@end /* JSArchivingTests */
diff --git a/skyrix-sope/NGJavaScript/tests/JSBridgeTests.h b/skyrix-sope/NGJavaScript/tests/JSBridgeTests.h
new file mode 100644 (file)
index 0000000..aec825a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __JSBridgeTests_H__
+#define __JSBridgeTests_H__
+
+#include "JSTest.h"
+
+@interface JSBridgeTests : JSTest
+{
+}
+
++ (void)runSuite;
+
+@end
+
+#endif /* __JSBridgeTests_H__ */
diff --git a/skyrix-sope/NGJavaScript/tests/JSBridgeTests.m b/skyrix-sope/NGJavaScript/tests/JSBridgeTests.m
new file mode 100644 (file)
index 0000000..1588936
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "JSBridgeTests.h"
+#include "Combined.h"
+#include "Blah.h"
+#include "MyNum.h"
+#include "common.h"
+//#import <Foundation/Foundation.h>
+#import <NGJavaScript/NGJavaScript.h>
+#import <NGScripting/NGScriptLanguage.h>
+#import <NGExtensions/NGExtensions.h>
+
+#define SLANG @"javascript"
+
+@implementation JSBridgeTests
+
+NSString *testScript =
+@"print('blah: ' + this.blah);\n"
+@"print('blah: ' + this.blah);\n"
+@"print('  s1: ' + this.blah.sequence);\n"
+@"print('  s2: ' + this.blah.sequence);\n"
+@"print('  s3: ' + this.blah.sequence);\n"
+@"print('blah2:' + this.blah2);\n"
+;
+
+NSString *testScript2 =
+@"print('blah: ' + this);\n"
+@"print('  s1: ' + this.sequence);\n"
+@"print('  s2: ' + this.sequence);\n"
+;
+
+#define infoobj(__X__) [self printJavaScriptObjectInfo:__X__]
+
+- (void)testCreation {
+  NSAutoreleasePool *pool;
+  id jobj;
+  id result;
+  id global;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  global = [mapCtx globalObject];
+  [self print:@"global is 0x%08X %@", global, global];
+  
+  jobj = [[Blah alloc] init];
+  [self print:@"  blah: %@ -> j0x%08X", jobj, [mapCtx handleForObject:jobj]];
+
+  [self print:@"  do: MyType()"];
+  result = [jobj evaluateScript:@"MyType()" language:SLANG];
+  [self print:@"  => %@", result];
+  
+  [self print:@"  do: new MyType()"];
+  result = [jobj evaluateScript:@"new MyType()" language:SLANG];
+  [self print:@"  => %@", result];
+  
+  [jobj release];
+  [pool release];
+}
+
+- (void)testKeyValueCoding {
+  NSString *testScript_KVC =
+  @"print('jso:  ' + this);\n"
+  @"var b = 10;\n"
+  @"this.a = 100;\n"
+  @"print('jso.a: ' + this.a);\n"
+  @"this['a'] = 101;\n"
+  @"print('jso.a: ' + this.a);\n"
+  @"print('jso.b: ' + this.b);\n"
+  @"print('jso.c: ' + this.c);\n"
+  @"for (var i in this.a) { print('  ' + i); };\n"
+  ;
+  id jobj = nil;
+  
+  jobj = [[NGJavaScriptObject alloc] init];
+  
+  [jobj setObject:@"202" forKey:@"c"];
+  
+  [jobj evaluateScript:testScript_KVC language:SLANG];
+  [self print:@"  obj.a=%@", [jobj objectForKey:@"a"]];
+  [self print:@"  obj.b=%@", [jobj objectForKey:@"b"]];
+  [self print:@"  obj.c=%@", [jobj objectForKey:@"c"]];
+  
+  infoobj(jobj);
+  
+  //[c evaluateScript:testScript language:SLANG];
+  
+  [jobj release];
+}
+
+- (void)testJSStructure {
+  static NSString *testScript_struct =
+    @"var dataRec = [\n"
+    @" { 'a': 5,  'b': 10  },\n"
+    @" { 'a': 55, 'b': 105 },\n"
+    @"];\n"
+  ;
+  id jobj;
+  jobj = [[NGJavaScriptObject alloc] init];
+  [jobj evaluateScript:testScript_struct language:SLANG];
+  [self print:@"  obj: %@", jobj];
+  [self print:@"  obj.dataRec: %@", [jobj objectForKey:@"dataRec"]];
+  [self print:@"  obj.dataRec[0]: %@", [[jobj objectForKey:@"dataRec"] objectAtIndex:0]];
+  [self print:@"  obj.dataRec[0].a: %@", 
+          [[[jobj objectForKey:@"dataRec"] objectAtIndex:0] objectForKey:@"a"]];
+  [jobj release];
+}
+
+- (void)testDictionary {
+  static NSString *testScript_dict =
+    @"this.a=10;"
+    @"this.b=101;"
+  ;
+  id jobj = nil;
+  NSAutoreleasePool *pool;
+  
+  pool = [NSAutoreleasePool new];
+
+  jobj = [[NSMutableDictionary alloc] init];
+  
+  [jobj setObject:@"202" forKey:@"c"];
+  
+  [jobj evaluateScript:testScript_dict language:SLANG];
+  [self print:@"  obj.a=%@", [jobj objectForKey:@"a"]];
+  [self print:@"  obj.b=%@", [jobj objectForKey:@"b"]];
+  [self print:@"  obj.c=%@", [jobj objectForKey:@"c"]];
+  
+  [[mapCtx jsContext] collectGarbage];
+  [pool release];
+  
+  //[jobj evaluateScript:testScript language:SLANG];
+  
+  [jobj release]; // Note: the dict may contain JS objects !
+}
+
+- (void)testSequence {
+  id   blah;
+  void *jso;
+  int  i;
+  id   global;
+  
+  global = [mapCtx globalObject];
+  NSLog(@"global is 0x%08X %@", global, global);
+  
+  blah = [[Blah alloc] init];
+  [global setObject:blah forKey:@"blah"];
+  
+  jso = NGObjectMapping_GetHandleForObject(blah);
+  NSLog(@"obj o0x%08X j0x%08X", blah, jso);
+
+  for (i = 0; i < 3; i++) {
+    NSAutoreleasePool *pool;
+
+    pool = [[NSAutoreleasePool alloc] init];
+    
+    [blah evaluateScript:testScript2 language:SLANG];
+
+    NSLog(@"release pool %i", i);
+    [pool release];
+    
+    NSLog(@"GC %i", i);
+    [[mapCtx jsContext] collectGarbage];
+    [[mapCtx jsContext] collectGarbage];
+  }
+  
+  [global removeObjectForKey:@"blah"];
+  
+  [blah release];
+}
+
+- (void)testIncTx {
+  Combined *c = nil;
+  void *jso;
+  id   obj = nil, jobj = nil;
+
+#if 0
+  c = [[Combined alloc] init];
+  [[NGObjectMappingContext activeObjectMappingContext] makeObjectCombined:c];
+  
+  obj = [[Blah alloc] init];
+  jso = NGObjectMapping_GetHandleForObject(obj);
+  NSLog(@"obj o0x%08X j0x%08X", obj, jso);
+  [obj evaluateScript:testScript2 language:SLANG];
+#endif
+  
+  jobj = [[NGJavaScriptObject alloc] init];
+  jso = NGObjectMapping_GetHandleForObject(jobj);
+  //NSLog(@"obj o0x%08X j0x%08X", jobj, jso);
+
+#if 0
+  [[NGObjectMappingContext activeObjectMappingContext]
+                           setGlobalObject:jobj];
+#endif
+  
+  infoobj(jobj);
+  
+  //[c setObject:obj forKey:@"blah2"];
+  
+  //[c evaluateScript:testScript language:SLANG];
+  
+  [jobj release];
+  [c    release];
+  [obj  release];
+}
+
+- (void)testStringPropAvailability {
+  /* 
+     if evaluation doesn't run against a NGJavaScriptObject, string objects
+     do not find their properties and functions (eg .length in this case)
+     why-o-why ? :-(
+     
+     - the NSString seems to be propertly converted into a JSString
+     - maybe the object doesn't have a proper parent pointer ?
+     - or the prototype of the string is broken ?
+     - or the standard classes are not loaded ?
+
+     - if I uncomment _jsGetValue in NSString+JS, I get a proper call to it's
+       length property, but the typeof (obviously) is 'object' instead of
+       'string' and certainly can't be used in a string context
+     
+     what sequence actually happens when we call "title.length" ?
+     - we map 'self' to a JS object (create a JS proxy, add statics)
+     - we call JS_EvaluateScript with that JS Object => makes self to this
+     - control goes to SpiderMoneky
+     - SpiderMonkey needs to resolve "title", which is a static
+       property we defined when creating the JS proxy
+     - this calls the _jsprop_title method which returns an NSString object
+     - the NSString object is converted to a value using it's own method
+     - SpiderMonkey should have a JS String with all methods ?
+  */
+  id base;
+  
+  base = [[Blah alloc] init];
+  NSLog(@"base: %@", base);
+
+  // this makes it dump core in getprivate
+  // NSLog(@"global: %@", [[self->mapCtx jsContext] globalObject]);
+  
+  NSLog(@"this: %@", [base evaluateScript:@"this" language:SLANG]);
+  NSLog(@"typeof this: %@", 
+       [base evaluateScript:@"typeof this" language:SLANG]);
+  
+  NSLog(@"title: %@",        
+       [base evaluateScript:@"title" language:SLANG]);
+  NSLog(@"typeof title: %@",        
+       [base evaluateScript:@"typeof title" language:SLANG]);
+  NSLog(@"title.length: %@ (should be %i)",        
+       [base evaluateScript:@"title.length" language:SLANG],
+       [[base _jsprop_title] length]);
+  
+  NSLog(@"getContent(): %@",        
+       [base evaluateScript:@"getContent()" language:SLANG]);
+  NSLog(@"getContent().length: %@ (should be %i)", 
+       [base evaluateScript:@"getContent().length" language:SLANG],
+       [[base _jsfunc_getContent:nil] length]);
+  
+  NSLog(@"'hello': %@",        
+       [base evaluateScript:@"'hello'" language:SLANG]);
+  NSLog(@"typeof 'hello': %@",        
+       [base evaluateScript:@"typeof 'hello'" language:SLANG]);
+  NSLog(@"'hello'.length: %@",        
+       [base evaluateScript:@"'hello'.length" language:SLANG]);
+  NSLog(@"'hello'.length == null: %@",        
+       [base evaluateScript:@"'hello'.length==null" language:SLANG]);
+}
+
++ (void)runSuite {
+  [self runTest:@"IncTx"];
+  [self runTest:@"KeyValueCoding"];
+  [self runTest:@"Sequence"];
+  [self runTest:@"Creation"];
+  [self runTest:@"JSStructure"];
+  
+  [self runTest:@"StringPropAvailability"];
+  
+  // currently the Dictionary test makes it dump core
+  //[self runTest:@"Dictionary"];
+}
+
+@end /* JSBridgeTests */
diff --git a/skyrix-sope/NGJavaScript/tests/JSTest.h b/skyrix-sope/NGJavaScript/tests/JSTest.h
new file mode 100644 (file)
index 0000000..3a147fe
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __JSTest_H__
+#define __JSTest_H__
+
+#import <Foundation/NSObject.h>
+
+@interface JSTest : NSObject
+{
+  id mapCtx;
+}
+
++ (void)runTestSelector:(SEL)_sel;
++ (void)runTest:(NSString *)_name;
+
+- (void)print:(NSString *)_format, ...;
+- (void)printJavaScriptObjectInfo:(id)_info;
+
+@end
+
+#endif /* __JSTest_H__ */
diff --git a/skyrix-sope/NGJavaScript/tests/JSTest.m b/skyrix-sope/NGJavaScript/tests/JSTest.m
new file mode 100644 (file)
index 0000000..5f4ff3e
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "JSTest.h"
+#include "common.h"
+#import <NGScripting/NGScriptLanguage.h>
+#import <NGJavaScript/NGJavaScript.h>
+#import <NGExtensions/NGExtensions.h>
+
+@implementation JSTest
+
+- (void)setUp {
+  id language;
+  id global;
+  
+  language = [NGScriptLanguage languageWithName:@"javascript"];
+  
+  self->mapCtx = [language createMappingContext];
+    
+  if (![[self->mapCtx jsContext] loadStandardClasses])
+    ;
+    
+  [self->mapCtx pushContext];
+
+  global = [[[NGJavaScriptObject alloc] init] autorelease];
+  [global applyStandardClasses];
+  [self->mapCtx setGlobalObject:global];
+}
+- (void)tearDown {
+  [[self->mapCtx jsContext] collectGarbage];
+  [[self->mapCtx jsContext] collectGarbage];
+   
+  [self->mapCtx popContext];
+  [self->mapCtx release];
+}
+
+- (void)print:(NSString *)_format arguments:(va_list)ap {
+  NSString *value = nil;
+  
+  value = [[NSString alloc] initWithFormat:_format arguments:ap];
+  printf("%s\n", [value cString]);
+  [value release];
+}
+- (void)print:(NSString *)_format, ... {
+  va_list ap;
+  
+  va_start(ap, _format);
+  [self print:_format arguments:ap];
+  va_end(ap);
+}
+
+- (void)printJavaScriptObjectInfo:(id)obj {
+  NSEnumerator *e;
+  void *jso;
+  id o;
+
+  jso = [[NGObjectMappingContext activeObjectMappingContext]
+                                handleForObject:obj];
+  
+  [self print:@"info on o0x%08X j0x%08X", obj, jso];
+  [self print:@"  description: %@", obj];
+  
+  e = [obj keyEnumerator];
+  [self print:@"  keys: (%@)", e];
+  while ((o = [e nextObject]))
+    [self print:@"    - '%@' <%@>", o, [o class]];
+  
+  e = [obj objectEnumerator];
+  [self print:@"  values: (%@)", e];
+  while ((o = [e nextObject]))
+    [self print:@"    - '%@' <%@>", o, [o class]];
+  
+  e = [obj prototypeObjectChain];
+  [self print:@"  prototypes: %@", e];
+  while ((o = [e nextObject]))
+    [self print:@"    - %@ <%@>", o, [o class]];
+  
+  e = [obj parentObjectChain];
+  [self print:@"  parents: %@", e];
+  while ((o = [e nextObject]))
+    [self print:@"    - %@ <%@>", o, [o class]];
+}
+
++ (void)testSelector:(SEL)_sel failedWithException:(NSException *)_exception {
+  NSLog(@"EXCEPTION: %@", _exception);
+}
+
++ (void)runTestSelector:(SEL)_sel {
+  NSAutoreleasePool *pool;
+  id fixture;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  fixture = [[[self alloc] init] autorelease];
+  [fixture setUp];
+  
+  printf("\n--- RUN TEST: %s --------------------\n", 
+         [NSStringFromSelector(_sel) cString]);
+  NS_DURING
+    [fixture performSelector:_sel];
+  NS_HANDLER
+    [self testSelector:_sel failedWithException:localException];
+  NS_ENDHANDLER;
+  printf(">>> DONE\n");
+  
+  [fixture tearDown];
+  [pool release];
+}
++ (void)runTest:(NSString *)_name {
+  SEL sel;
+  
+  _name = [@"test" stringByAppendingString:_name];
+  sel = NSSelectorFromString(_name);
+  [self runTestSelector:sel];
+}
+
+@end /* JSTest */
diff --git a/skyrix-sope/NGJavaScript/tests/MyNum.h b/skyrix-sope/NGJavaScript/tests/MyNum.h
new file mode 100644 (file)
index 0000000..14b9b8a
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __MyNum_H__
+#define __MyNum_H__
+
+#import <Foundation/NSObject.h>
+
+@interface MyNum : NSObject
+{
+  int i;
+}
++ (id)numberWithInt:(int)_i;
+@end
+
+#endif /* __MyNum_H__ */
diff --git a/skyrix-sope/NGJavaScript/tests/MyNum.m b/skyrix-sope/NGJavaScript/tests/MyNum.m
new file mode 100644 (file)
index 0000000..4e20f40
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "MyNum.h"
+#include "common.h"
+
+@implementation MyNum
+
++ (id)numberWithInt:(int)_i {
+  MyNum *n = [[self alloc] init];
+  n->i = _i;
+  return AUTORELEASE(n);
+}
+
+- (void)dealloc {
+  NSLog(@"dealloc MyNum: 0x%08X %i", self, self->i);
+  [super dealloc];
+}
+
+- (int)intValue {
+  return self->i;
+}
+- (NSString *)stringValue {
+  return [NSString stringWithFormat:@"MyNum:%i", self->i];
+}
+
+@end /* MyNum */
diff --git a/skyrix-sope/NGObjDOM/.cvsignore b/skyrix-sope/NGObjDOM/.cvsignore
new file mode 100644 (file)
index 0000000..ed903c9
--- /dev/null
@@ -0,0 +1,3 @@
+NGObjDOM.odr
+shared_debug_obj
+shared_obj
diff --git a/skyrix-sope/NGObjDOM/COPYING b/skyrix-sope/NGObjDOM/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/NGObjDOM/COPYRIGHT b/skyrix-sope/NGObjDOM/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-sope/NGObjDOM/ChangeLog b/skyrix-sope/NGObjDOM/ChangeLog
new file mode 100644 (file)
index 0000000..528c773
--- /dev/null
@@ -0,0 +1,233 @@
+2004-07-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.24
+
+       * XUL.subproj/ODRDynamicXULTag.m: fixed a gcc 3.4 warning
+
+       * XHTML: fixed some gcc 3.4 warnings
+
+2004-06-11  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * XUL.subproj/GNUmakefile, XHTML.subproj/GNUmakefile: added support
+         for building with GNUSTEP_BUILD_DIR env (v4.2.23)
+
+2004-06-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.22
+
+       * GNUmakefile.preamble: added prebinding
+
+       * ODResourceManager.m: minor cleanups
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.21
+
+       * GNUmakefile: moved post section to GNUmakefile.postamble, various
+         cleanups
+
+       * GNUmakefile.preamble: fixed relative search pathes
+
+2004-06-02  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile: more support for building with GNUSTEP_BUILD_DIR
+         env set (v4.2.20)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile, GNUmakefile.preamble: added support for building
+         with GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.19)
+
+2004-05-04  Helge Hess  <helge.hess@opengroupware.org>
+
+       * fixed dependencies for Panther (v4.2.18)
+
+2004-04-07  Helge Hess  <helge.hess@opengroupware.org>
+
+       * ODResourceManager.m: fixed a compilation warning (v4.2.17)
+
+2004-03-09  Helgs Hess  <helge.hess@opengroupware.org>
+
+       * ODRWebObject.m, ODNodeRenderer+attributes.m, WORenderDOM.m,
+         ODRDynamicXHTMLTag.m, ODR_XHTML_input.m, ODRDynamicXULTag.m:
+         fixed warning when compiling against gstep-base (v4.2.16)
+
+2004-02-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * XUL.subproj/ODR_XUL_grid.m, XUL.subproj/ODR_XUL_tab.m, 
+         ODRWebObject.m: fixed minor compilation warnings on MacOSX (v4.2.15)
+
+2004-01-07  Helge Hess  <helge@groove.local>
+
+       * ODResourceManager.m: fixed an uninitialized variable (v4.2.14)
+
+2003-12-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile (BUNDLE_EXTENSION), XUL.subproj/GNUmakefile 
+         (BUNDLE_INSTALL_DIR): use GNUSTEP_INSTALLATION_DIR instead of 
+         GNUSTEP_USER_ROOT (v4.2.13)
+
+2003-11-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile: include makefiles from GNUSTEP_MAKEFILES (as suggested
+         by chunsj@embian.com) (v4.2.12)
+
+Wed Oct 22 15:19:18 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * GNUmakefile: add ADDITIONAL_LIB_DIRS NGScripting and NGObjWeb 
+         (v4.2.11)
+
+2003-10-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * some changes for compilation with gstep-make on MacOSX (v4.2.10)
+
+2003-07-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * applied GNUstep patches provided by Filip Van Raemdonck for improved
+         compilation with gstep-base (v4.2.9)
+
+2003-06-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved to skyrix-sope-42 (v4.2.8)
+
+2003-06-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer+attributes.m: added various debugging defaults and
+         logs, cleanups (v4.1.7)
+
+2002-11-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile (SUBPROJECTS): removed WML, not required fuer 4.1
+         (v4.1.6)
+
+2002-08-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * small tweaks to make gcc 3.1 happy
+
+2002-06-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOContext+Cursor.m (WOContext): moved cursor code to NGObjWeb
+
+2002-06-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * adopted to "new"/current NGJavaScript library
+
+Fri Jun  7 13:00:36 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * updated to new "scripting" access
+
+Mon Dec 17 17:01:59 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNamespaces.h: use SaxObjC namespace declarations
+
+Tue Nov 27 15:05:25 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * added support for HTML40 namespace (as generated by Word 2000)
+
+Wed Nov 21 17:54:26 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * ODR_bind_viewertitle.h: fixed vtitle and vbutton bug
+
+Wed Oct 17 17:04:12 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNamespaces.h: added XForms namespace
+
+Tue Aug 21 14:56:48 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer+attributes.m: also evaluate JavaScript against the
+         cursor
+
+Tue Aug 21 12:24:30 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer.m: cache parent
+
+Tue Aug 21 10:52:48 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer+attributes.m: changed to use cursor for bind-evals
+       
+       * ODNodeRenderer.m: moved 'cycle' objects as cursors to WOContext
+
+Thu Aug  9 20:22:42 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer.m: fixed ODProfileRendererMin
+
+Wed Aug  8 20:36:54 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer.h: added support for cycle object
+
+Thu Jul 26 16:43:36 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer.m: added unique ID generator
+
+Mon Jul 23 19:40:01 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer+attributes.m(-invokeValueForAttributeNode:): check
+         whether return value conforms to WOActionResults protocol, otherwise
+         return nil
+
+Mon Jul  9 18:59:05 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer.m: improved profiling
+
+Thu Jul  5 19:49:31 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer.m: added ifnot 'common' attribute
+
+Wed Jul  4 10:45:46 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODRGenericTag.m ([ODRGenericTag -_appendAttributesOfNode:toResponse:inContext:]): 
+         HTML escape attribute values
+
+Tue Jul  3 19:02:23 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * added WML ODR bundle
+
+       * ODNamespaces.h: added WML12 namespace
+
+       * ODNodeRenderer+attributes.m: look for attributes in all namespaces !
+
+Mon Jun 11 12:51:53 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile.preamble: fixed library dependencies
+
+Wed Jun  6 15:02:57 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * turned XHTML.subproj and XUL.subproj into bundles
+
+Mon May  7 12:29:38 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODNodeRenderer.m: added global 'if' attribute
+
+Sun May  6 16:03:57 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * XHTML.subproj/ODR_XHTML_input_text.m: added support for disabled
+
+Fri Mar 30 19:13:59 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * XHTML.subproj/ODR_XHTML_input.m: added formatting support
+
+Mon Mar 12 14:14:13 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * XHTML.subproj/ODRDynamicXHTMLTag.m: use component resource-manager
+
+Wed Mar  7 16:30:41 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * XHTML.subproj/ODXHTMLNodeRenderFactory.m: fixed cache handling
+
+       * ODNodeRenderer.m: added profiling
+
+       * ODNodeRenderer: put attribute methods into separate category
+
+       * WORenderDOM.m: added profiling
+
+Tue Mar  6 14:36:17 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * added versioning
+
+Mon Feb 26 20:21:19 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * ODNodeRenderer.m ([ODNodeRenderer -attributeNodeNamed:ofNode:inContext:]): 
+         recognize eval namespace
+
+       * created ChangeLog
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/.cvsignore b/skyrix-sope/NGObjDOM/Dynamic.subproj/.cvsignore
new file mode 100644 (file)
index 0000000..6a53797
--- /dev/null
@@ -0,0 +1,2 @@
+Resources
+shared_debug_obj
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/COPYING b/skyrix-sope/NGObjDOM/Dynamic.subproj/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ChangeLog b/skyrix-sope/NGObjDOM/Dynamic.subproj/ChangeLog
new file mode 100644 (file)
index 0000000..f965d7e
--- /dev/null
@@ -0,0 +1,98 @@
+Wed Oct 22 15:57:58 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * GNUmakefile: add ADDITIONAL_LIB_DIRS NGScripting 
+
+Fri Sep 21 18:13:33 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_bind_with.m ([ODR_bind_with -appendNode:toResponse:inContext:]): 
+         added special object keys (# for component, #S for session ...)
+
+Tue Aug 21 15:48:24 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_bind_foreach.m: added filtering and sorting
+
+Tue Aug 21 15:19:45 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_bind_if.m: added value1/value2 bindings
+
+       * ODR_bind_foreach.m: added cursor support (when no item is present,
+         the cursor is used)
+
+Thu Jul 26 16:24:42 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_bind_form.m ([ODR_bind_form -_childComponentForNode:inContext:]):
+         register child-forms as subcomponents
+
+Mon Jul  2 17:38:53 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_bind_popupbutton.m: use lowercase 'noselectionstring' instead of
+         noSelectionString
+
+Wed Jun  6 14:52:30 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * added ODR_bind_nbsp to generate HTML nbsp entities ...
+
+Wed May 16 11:59:18 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_bind_datefield.m: better support for calendar-dates, fixed bug
+
+Mon May  7 20:51:57 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * ODR_bind_tableview+Private.m: color was wrong, if no navigation
+
+Sun May  6 17:12:35 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * ODR_bind_tableview+Private.m: render '&nbsp;' if no ttitle
+
+Sun May  6 15:43:02 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_bind_tabview.m: removed underline of tab-link using CSS
+
+       * ODR_bind_tabview.m: added tab-deactivation
+
+Tue Apr 10 16:38:14 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * ODR_bind_tableview+Private.m fixed dataSource bug
+
+Wed Apr  4 17:16:31 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * ODR_bind_tableview+Private.m create copy of fetchSpecification 
+
+Mon Apr  2 18:49:47 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * ODR_bind_sortorderings.[h|m]: added
+
+       * ODR_bind_tableview[_private]: changed behaviour of sorting
+
+Mon Apr  2 11:41:01 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_bind_viewertitle.m ([ODR_bind_viewertitle -appendNode:toResponse:inContext:]): 
+         fixed various HTML generation bugs
+
+Fri Mar 30 18:51:20 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_bind_string.m: added support for dateformat, numberformat and nil
+
+Thu Mar 15 20:06:22 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * ODR_bind_tableview.m: added selector caching
+
+       * ODR_bind_tableview.m: added profiling
+
+Thu Mar  8 16:58:47 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * ODR_bind_tableview+Private.m ([ODR_bind_tableview -_appendNav:isBlind:toResponse:inContext:]):
+         made less sensible to index problems
+
+       * ODR_bind_tableview+Private.m: added selector caching
+
+       * ODR_bind_tableview.m: cleanups in tableview
+
+Wed Mar  7 18:44:51 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * ODR_bind_tabledata.m: fixed bug with formatter binding
+
+Fri Feb 23 10:38:08 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * ODR_bind_if.m: added ifnot, removed 'negate' binding
+
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/GNUmakefile b/skyrix-sope/NGObjDOM/Dynamic.subproj/GNUmakefile
new file mode 100644 (file)
index 0000000..9698871
--- /dev/null
@@ -0,0 +1,61 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = Dynamic
+
+ADDITIONAL_CPPFLAGS += -pipe -Wall
+
+Dynamic_OBJC_FILES = \
+       ODBindNodeRenderFactory.m       \
+       ODR_bind_checkbox.m             \
+       ODR_bind_collapsible.m          \
+       ODR_bind_datefield.m            \
+       ODR_bind_fieldset.m             \
+       ODR_bind_foreach.m              \
+       ODR_bind_form.m                 \
+       ODR_bind_groupings.m            \
+       ODR_bind_if.m                   \
+       ODR_bind_multiselection.m       \
+       ODR_bind_nbsp.m                 \
+       ODR_bind_popupbutton.m          \
+       ODR_bind_radiobutton.m          \
+       ODR_bind_sortorderings.m        \
+       ODR_bind_string.m               \
+       ODR_bind_switch.m               \
+       ODR_bind_tablecell.m            \
+       ODR_bind_tabledata.m            \
+       ODR_bind_tableheader.m          \
+       ODR_bind_tableview+Private.m    \
+       ODR_bind_tableview.m            \
+       ODR_bind_tabview.m              \
+       ODR_bind_viewertitle.m          \
+       ODR_bind_with.m                 \
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..                    \
+       -I../..                 \
+       -I../../NGObjWeb        \
+       -I../../NGStreams       \
+
+ifeq ($(FOUNDATION_LIB),nx)
+
+ADDITIONAL_LIB_DIRS +=                                 \
+       -L../$(GNUSTEP_OBJ_DIR)                 \
+       -L../../NGObjWeb/$(GNUSTEP_OBJ_DIR)     \
+
+XUL_BUNDLE_LIBS += \
+       -lNGObjDOM      \
+       -lNGMime        \
+       -lNGStreams     \
+       -lEOControl     \
+       -lNGExtensions  \
+       -lFoundationExt \
+
+ADDITIONAL_LDFLAGS += -framework Foundation
+
+endif
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODBindNodeRenderFactory.h b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODBindNodeRenderFactory.h
new file mode 100644 (file)
index 0000000..ee03b86
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODBindNodeRenderFactory_H__
+#define __ODBindNodeRenderFactory_H__
+
+#include <NGObjDOM/ODNodeRendererFactory.h>
+
+@interface ODBindNodeRenderFactory : NSObject < ODNodeRendererFactory >
+@end
+
+#endif /* __ODBindNodeRenderFactory_H__ */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODBindNodeRenderFactory.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODBindNodeRenderFactory.m
new file mode 100644 (file)
index 0000000..8199180
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODBindNodeRenderFactory.h"
+#include <NGObjDOM/ODNamespaces.h>
+#include <NGObjDOM/ODNodeRenderer.h>
+#include "common.h"
+
+@implementation ODBindNodeRenderFactory
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  static NSMutableDictionary *tagToRenderer = nil; /* cache, THREAD */
+  ODNodeRenderer *renderer;
+  NSString *rendererName;
+
+  if ((renderer = [tagToRenderer objectForKey:[_domNode tagName]]))
+    return renderer;
+  
+  if (![[_domNode namespaceURI] isEqualToString:XMLNS_OD_BIND])
+    return nil;
+  
+  rendererName = [@"ODR_bind_" stringByAppendingString:[_domNode tagName]];
+  
+  if ((renderer = [[NSClassFromString(rendererName) alloc] init])) {
+    if (tagToRenderer == nil)
+      tagToRenderer = [[NSMutableDictionary alloc] initWithCapacity:64];
+    [tagToRenderer setObject:renderer forKey:[_domNode tagName]];
+    AUTORELEASE(renderer);
+  }
+  else {
+    renderer = nil;
+  }
+  
+  return renderer;
+}
+
+@end /* ODBindNodeRenderFactory */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_checkbox.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_checkbox.m
new file mode 100644 (file)
index 0000000..ed560b0
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+   attributes:
+
+     name
+     checked
+     value
+
+   example:
+     <script>
+       var checked=true;
+     </script>
+     
+     <var:checkbox checked="checked"/>
+*/
+
+@interface ODR_bind_checkbox : ODNodeRenderer
+@end
+
+#include <DOM/DOM.h>
+#include "common.h"
+
+@implementation ODR_bind_checkbox
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  id       formValue;
+  NSString *name;
+
+  name = [self stringFor:@"name" node:_node ctx:_ctx];
+  name = (name) ? name : [_ctx elementID];
+
+  formValue = [_req formValueForKey:name];
+
+  if ([self isSettable:@"checked" node:_node ctx:_ctx])
+    [self setBool:(formValue) ? YES : NO for:@"checked" node:_node ctx:_ctx];
+
+  if ([self isSettable:@"value" node:_node ctx:_ctx] && (formValue != nil))
+    [self setString:formValue for:@"value" node:_node ctx:_ctx];
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *name;
+
+  name = [self stringFor:@"name" node:_node ctx:_ctx];
+  name = (name) ? name : [_ctx elementID];
+
+  if (![[_ctx request] isFromClientComponent]) {
+    NSString *v;
+    BOOL     isChecked;
+
+    v         = [self stringFor:@"value" node:_node ctx:_ctx];
+    isChecked = [self boolFor:@"checked" node:_node ctx:_ctx];
+    
+    [_response appendContentString:@"<input type=\"checkbox\" name=\""];
+    [_response appendContentHTMLAttributeValue:name];
+    [_response appendContentString:@"\" value=\""];
+    [_response appendContentHTMLAttributeValue:([v length] > 0) ? v : @"1"];
+    [_response appendContentString:@"\""];
+  
+    if (isChecked)
+      [_response appendContentString:@" checked"];
+
+    [_response appendContentString:@">\n"];
+  }
+}
+
+@end /* ODR_bind_checkbox */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_collapsible.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_collapsible.m
new file mode 100644 (file)
index 0000000..59d5852
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODR_bind_collapsible.h>
+#include "common.h"
+
+@implementation ODR_bind_collapsible
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *eid;
+
+  eid = [_ctx elementID];
+
+  if ([self boolFor:@"visible" node:_node ctx:_ctx]) {
+    [_ctx appendZeroElementIDComponent];
+    [self takeValuesForChildNodes:[_node childNodes]
+          fromRequest:_request
+          inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+  
+  if ([_request formValueForKey:[eid stringByAppendingString:@".c"]] ||
+      [_request formValueForKey:[eid stringByAppendingString:@".c.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:[[_ctx senderID] stringByAppendingString:@".c"]];
+  }
+  else if ([_request formValueForKey:[eid stringByAppendingString:@".e"]] ||
+           [_request formValueForKey:[eid stringByAppendingString:@".e.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:[[_ctx senderID] stringByAppendingString:@".e"]];
+  }
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *state;
+  NSString *eid;
+
+  state = [[_ctx currentElementID] stringValue];
+
+  eid = [_ctx elementID];
+
+  if (state) {
+    [_ctx consumeElementID]; // consume state-id (on or off)
+    
+    if ([state isEqualToString:@"e"]) {
+      [self forceSetBool:NO for:@"visible" node:_node ctx:_ctx];
+      if (NO)
+        ; //[self->submitActionName valueInComponent:[_ctx component]];
+    }
+    else if ([state isEqualToString:@"c"]) {
+      [self forceSetBool:YES for:@"visible" node:_node ctx:_ctx];
+      if (NO)
+        ; // [self->submitActionName valueInComponent:[_ctx component]];
+    }
+    else {
+      id result;
+      
+      [_ctx appendElementIDComponent:state];
+      result = [self invokeActionForChildNodes:[_node childNodes]
+                     fromRequest:_request
+                     inContext:_ctx];
+      
+      [_ctx deleteLastElementIDComponent];
+
+      return result;
+    }
+  }
+  return nil;
+}
+
+- (void)appendNode:(id)_node
+        toResponse:(WOResponse *)_response
+         inContext:(WOContext *)_ctx
+{
+  NSString *img;
+  NSString *label;
+  BOOL     isCollapsed;
+  BOOL     doForm;
+
+  if (![self hasAttribute:@"visible" node:_node ctx:_ctx])
+    [self forceSetBool:YES for:@"visible" node:_node ctx:_ctx];
+
+  doForm      = [_ctx isInForm];
+  isCollapsed = ![self boolFor:@"visible" node:_node ctx:_ctx];
+
+  img = (isCollapsed)
+    ? [self stringFor:@"closedicon" node:_node ctx:_ctx]
+    : [self stringFor:@"openedicon" node:_node ctx:_ctx];
+
+  label = (isCollapsed)
+    ? [self stringFor:@"closedlabel" node:_node ctx:_ctx]
+    : [self stringFor:@"openedlabel" node:_node ctx:_ctx];
+
+  if (label == nil)
+    label = [self stringFor:@"label" node:_node ctx:_ctx];
+
+  img = ODRUriOfResource(img, _ctx);
+
+  [_ctx appendElementIDComponent:(isCollapsed) ? @"c" : @"e"];
+
+  if (doForm) {
+    NSString *value;
+
+    value = (img == nil || label == nil)
+      ? (isCollapsed) ? @"+" : @"-"
+      : (id)label;
+    
+    ODRAppendButton(_response, [_ctx elementID], img, value);
+  }
+  else {
+    NSString *value;
+    
+    value = (img == nil || label == nil)
+      ? (isCollapsed) ? @"[+]" : @"[-]"
+      : (id)label;
+    
+    [_response appendContentString:@"<A HREF=\""];
+    [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentString:@"\">"];
+
+    ODRAppendImage(_response, nil, img, value);
+
+    [_response appendContentString:@"</A>"];
+  }
+
+  [_ctx deleteLastElementIDComponent];
+
+  if (label) {
+    [_response appendContentString:@"&nbsp;"];
+    [_response appendContentString:label];
+  }
+
+  if (!isCollapsed) {
+    [_response appendContentString:@"<br>"];
+    [_ctx appendZeroElementIDComponent];
+    [self appendChildNodes:[_node childNodes]
+          toResponse:_response
+          inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+  [_response appendContentString:@"<br>"];
+}
+
+@end /* ODR_bind_collapsible */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_datefield.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_datefield.m
new file mode 100644 (file)
index 0000000..2f832cb
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+  Attributes:
+
+    day    - int
+    month  - int
+    year   - int
+    value  - string in format %Y-%m-%d
+  
+  Usage:
+    <var:datefield value="fromDate"/><br/>
+    <var:datefield value="toDate"/><br/>
+*/
+
+@interface ODR_bind_datefield : ODNodeRenderer
+@end
+
+#include "common.h"
+
+@implementation ODR_bind_datefield
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  int d, m, y;
+  NSString *s;
+  
+  [_ctx appendElementIDComponent:@"d"];
+  d = [[_req formValueForKey:[_ctx elementID]] intValue];
+  [_ctx deleteLastElementIDComponent];
+  
+  [_ctx appendElementIDComponent:@"m"];
+  m = [[_req formValueForKey:[_ctx elementID]] intValue];
+  [_ctx deleteLastElementIDComponent];
+  
+  [_ctx appendElementIDComponent:@"y"];
+  y = [[_req formValueForKey:[_ctx elementID]] intValue];
+  [_ctx deleteLastElementIDComponent];
+  
+  if (y < 100) y += 2000;
+  
+  if ([self isSettable:@"value" node:_node ctx:_ctx]) {
+    s = [NSString stringWithFormat:@"%i-%02i-%02i", y, m, d];
+    [self setString:s for:@"value" node:_node ctx:_ctx];
+  }
+  
+  if ([self isSettable:@"day"   node:_node ctx:_ctx])
+    [self setInt:d for:@"day"   node:_node ctx:_ctx];
+  if ([self isSettable:@"month" node:_node ctx:_ctx])
+    [self setInt:m for:@"month" node:_node ctx:_ctx];
+  if ([self isSettable:@"year"  node:_node ctx:_ctx])
+    [self setInt:y for:@"year"  node:_node ctx:_ctx];
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  unsigned i;
+  NSCalendarDate *date;
+  NSString *s;
+  NSString *d,*m,*y;
+  
+  d = [self stringFor:@"day"   node:_node ctx:_ctx];
+  m = [self stringFor:@"month" node:_node ctx:_ctx];
+  y = [self stringFor:@"year"  node:_node ctx:_ctx];
+  
+  date = [self valueFor:@"value" node:_node ctx:_ctx];
+  
+  if ([date isKindOfClass:[NSCalendarDate class]]) {
+    s = [date descriptionWithCalendarFormat:@"%Y-%m-%s"];
+    
+    d = [NSString stringWithFormat:@"%i", [date dayOfMonth]];
+    m = [NSString stringWithFormat:@"%i", [date monthOfYear]];
+    y = [NSString stringWithFormat:@"%i", [date yearOfCommonEra]];
+  }
+  else {
+    s = [date stringValue];
+    date = nil;
+    
+    if ([s length] > 0) {
+      NSArray  *comps;
+      unsigned count;
+    
+      comps = [s componentsSeparatedByString:@"-"];
+      count = [comps count];
+
+      if (count > 0) y = [comps objectAtIndex:0];
+      if (count > 1) m = [comps objectAtIndex:1];
+      if (count > 2) d = [comps objectAtIndex:2];
+    }
+  }
+  
+  [_ctx appendElementIDComponent:@"d"];
+  {
+    [_response appendContentString:@"<select name=\""];
+    [_response appendContentHTMLAttributeValue:[_ctx elementID]];
+    [_response appendContentString:@"\" value=\""];
+    [_response appendContentHTMLAttributeValue:d];
+    [_response appendContentString:@"\">\n"];
+    
+    [_response appendContentString:@"<option value=\"\">-"];
+    
+    for (i = 1; i <= 31; i++) {
+      s = [NSString stringWithFormat:@"%d", i];
+      [_response appendContentString:@"<option value=\""];
+      [_response appendContentString:s];
+      if ((int)i == [d intValue])
+        [_response appendContentString:@"\" selected=\"selected\" />"];
+      else
+        [_response appendContentString:@"\" />"];
+      [_response appendContentString:s];
+      
+      /* XHTML */
+    }
+  
+    [_response appendContentString:@"</select>"];
+  }
+  [_ctx deleteLastElementIDComponent];
+  
+  [_ctx appendElementIDComponent:@"m"];
+  {
+    static NSString *months[12] = {
+      @"Jan", @"Feb", @"Mar", @"Apr", @"May", @"Jun",
+      @"Jul", @"Aug", @"Sep", @"Oct", @"Nov", @"Dec"
+    };
+    [_response appendContentString:@"<select name=\""];
+    [_response appendContentHTMLAttributeValue:[_ctx elementID]];
+    [_response appendContentString:@"\" value=\""];
+    [_response appendContentHTMLAttributeValue:m];
+    [_response appendContentString:@"\">\n"];
+
+    [_response appendContentString:@"<option value=\"\">-"];
+    
+    for (i = 1; i <= 12; i++) {
+      s = [NSString stringWithFormat:@"%d", i];
+      [_response appendContentString:@"<option value=\""];
+      [_response appendContentString:s];
+      if ((int)i == [m intValue])
+        [_response appendContentString:@"\" selected=\"selected\" />"];
+      else
+        [_response appendContentString:@"\" />"];
+      [_response appendContentString:months[i - 1]];
+      
+      /* XHTML */
+    }
+  
+    [_response appendContentString:@"</select>"];
+  }
+  [_ctx deleteLastElementIDComponent];
+  
+  [_ctx appendElementIDComponent:@"y"];
+  {
+    [_response appendContentString:@"<select name=\""];
+    [_response appendContentHTMLAttributeValue:[_ctx elementID]];
+    [_response appendContentString:@"\" value=\""];
+    [_response appendContentHTMLAttributeValue:y];
+    [_response appendContentString:@"\">\n"];
+    
+    [_response appendContentString:@"<option value=\"\">-"];
+    
+    for (i = 2001; i <= 2010; i++) {
+      s = [NSString stringWithFormat:@"%d", i];
+      [_response appendContentString:@"<option value=\""];
+      [_response appendContentString:s];
+      if ((int)i == [y intValue])
+        [_response appendContentString:@"\" selected=\"selected\" />"];
+      else
+        [_response appendContentString:@"\" />"];
+      [_response appendContentString:s];
+      
+      /* XHTML */
+    }
+    
+    [_response appendContentString:@"</select>"];
+  }
+  [_ctx deleteLastElementIDComponent];
+}
+
+@end /* ODR_bind_datefield */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_fieldset.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_fieldset.m
new file mode 100644 (file)
index 0000000..5878cde
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODR_bind_fieldset.h>
+#include "common.h"
+
+@implementation ODR_bind_fieldset
+
+- (void)_takeValuesFromField:(id)_field
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSMutableArray *fields;
+  NSArray        *labels;
+  
+  fields  = [NSMutableArray arrayWithArray:(NSArray *)[_field childNodes]];
+  labels  = ODRLookupQueryPath(_field, @"-label");
+
+  [fields removeObjectsInArray:labels];
+  
+  [_ctx appendElementIDComponent:@"t"];
+  [self takeValuesForChildNodes:labels fromRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent]; // delete "t"
+  
+  [_ctx appendElementIDComponent:@"c"];
+  [self takeValuesForChildNodes:fields fromRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent]; // delete "c"
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSArray *fields;
+  int     i, cnt;
+
+  fields = ODRLookupQueryPath(_node, @"field");
+  cnt    = [fields count];
+  
+  for (i = 0; i < cnt; i++) {
+    id field;
+    
+    field = [fields objectAtIndex:i];
+    
+    [_ctx appendElementIDComponent:[NSString stringWithFormat:@"%i", i]];
+    
+    [self _takeValuesFromField:field fromRequest:_request inContext:_ctx];
+    
+    [_ctx deleteLastElementIDComponent]; // delete index
+  }
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  id       result = nil;
+  NSArray  *fields;
+  NSString *idx;
+  int      i;
+    id             field;
+    NSString       *section;
+    NSArray        *labels;
+
+  fields = ODRLookupQueryPath(_node, @"field");
+  idx    = [_ctx currentElementID];
+  i      = [idx intValue];
+
+  if (i >= (int)[fields count]) {
+    NSLog(@"%s: Warning! Index out of range.", __PRETTY_FUNCTION__);
+    return nil;
+  }
+
+    field = [fields objectAtIndex:i];
+    
+    [_ctx appendElementIDComponent:idx];
+    [_ctx consumeElementID];
+
+    section = [_ctx currentElementID]; // "c" || "t"
+    
+    [_ctx appendElementIDComponent:section];
+    [_ctx consumeElementID];
+
+    labels = ODRLookupQueryPath(field, @"-label");
+
+    if ([section isEqualToString:@"t"]) {
+      result = [self invokeActionForChildNodes:labels
+                     fromRequest:_request
+                     inContext:_ctx];
+    }
+    else if ([section isEqualToString:@"c"]) {
+      NSMutableArray *childs;
+      
+      childs = [NSMutableArray arrayWithArray:(NSArray *)[field childNodes]];
+      [childs removeObjectsInArray:labels];
+      
+      result = [self invokeActionForChildNodes:childs
+                     fromRequest:_request
+                     inContext:_ctx];
+    }
+    
+    [_ctx deleteLastElementIDComponent]; // section
+    [_ctx deleteLastElementIDComponent]; // idx
+    
+  return result;
+}
+
+- (void)_appendField:(id)_field
+  node:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSMutableArray *fields;
+  NSArray        *labels;
+  NSString       *label;
+  NSString       *labelBgColor;
+  NSString       *contentBgColor;
+  NSString       *width;
+  NSString       *fc, *ff, *fs;
+  BOOL           hasFont;
+
+  fc      = [self stringFor:@"fontcolor" node:_node ctx:_ctx];
+  ff      = [self stringFor:@"fontface"  node:_node ctx:_ctx];
+  fs      = [self stringFor:@"fontsize"  node:_node ctx:_ctx];
+  hasFont = (fc !=nil || ff !=nil || fs != nil);
+
+  label   = [self stringFor:@"label" node:_field ctx:_ctx];
+  fields  = [NSMutableArray arrayWithArray:(NSArray *)[_field childNodes]];
+  labels  = ODRLookupQueryPath(_field, @"-label");
+  
+  labelBgColor   = [self stringFor:@"labelcolor"   node:_node ctx:_ctx];
+  contentBgColor = [self stringFor:@"contentcolor" node:_node ctx:_ctx];
+  width          = [self stringFor:@"labelwidth"   node:_node ctx:_ctx];
+
+  [fields removeObjectsInArray:labels];
+  
+  [_response appendContentString:@"<td valign=\"top\" align=\"right\""];
+  if (labelBgColor) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentString:labelBgColor];
+    [_response appendContentCharacter:'"'];
+  }
+  if (width) {
+    [_response appendContentString:@" width=\""];
+    [_response appendContentString:width];
+    [_response appendContentCharacter:'"'];
+  }
+  [_response appendContentCharacter:'>'];
+  [_ctx appendElementIDComponent:@"t"];
+
+  if (hasFont)
+    ODRAppendFont(_response, fc, ff, fs);
+  
+  [self appendChildNodes:labels toResponse:_response inContext:_ctx];
+  if (label) {
+    [_response appendContentString:label];
+    [_response appendContentString:@":"];
+  }
+  
+  if (hasFont)
+    [_response appendContentString:@"</font>"];
+
+  [_ctx deleteLastElementIDComponent]; // delete "t"
+  [_response appendContentString:@"</td>"];
+  
+  [_response appendContentString:@"<td valign=\"top\""];
+  if (contentBgColor) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentString:contentBgColor];
+    [_response appendContentCharacter:'"'];
+  }
+  [_response appendContentCharacter:'>'];
+  
+  [_ctx appendElementIDComponent:@"c"];
+  [self appendChildNodes:fields toResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent]; // delete "c"
+  [_response appendContentString:@"</td>"];
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSArray *fields;
+  int     i, cnt;
+
+  fields = ODRLookupQueryPath(_node, @"field");
+  cnt    = [fields count];
+  
+  [_response appendContentString:
+             @"<table border=\"0\" width=\"100%\""
+             @"cellspacing=\"0\" cellpadding=\"4\">"];
+  
+  for (i = 0; i < cnt; i++) {
+    id field;
+
+    field = [fields objectAtIndex:i];
+
+    [_ctx appendElementIDComponent:[NSString stringWithFormat:@"%i", i]];
+    
+    [_response appendContentString:@"<tr>"];
+    [self _appendField:field node:_node toResponse:_response inContext:_ctx];
+    [_response appendContentString:@"</tr>"];
+
+    [_ctx deleteLastElementIDComponent]; // delete index
+  }
+  [_response appendContentString:@"</table>"];
+}
+
+@end /* ODR_bind_fieldset */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_foreach.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_foreach.m
new file mode 100644 (file)
index 0000000..abb09ef
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  description:
+
+    Iterates over a list of objects. The current item is stored in the item
+    binding or, if the binding is not present, as the current cursor.
+  
+  attributes:
+
+    list       // array of objects to iterate through
+    item       // current item in the array
+    index      // current index
+    identifier // unique id for element
+    count      // number of times the contents will be repeated
+    startIndex // first index
+    qualifier  // limit set
+    sortkey    // sort array using this key
+    
+  example:
+
+     <var:foreach list="list" item="item">
+       <var:string value="item"/>
+     </var:foreach>
+*/
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+@interface ODR_bind_foreach : ODNodeRenderer
+@end
+
+#include "WOContext+Cursor.h"
+#include <DOM/DOM.h>
+#include <EOControl/EOQualifier.h>
+#include <EOControl/EOSortOrdering.h>
+#include "common.h"
+
+@implementation ODR_bind_foreach
+
+- (NSArray *)_listForNode:(id)_node inContext:(WOContext *)_ctx {
+  NSMutableArray *sortOrderings;
+  NSArray  *array;
+  id       query;
+  NSString *sortkey;
+
+  /* get list */
+  
+  array = [self valueFor:@"list" node:_node ctx:_ctx];
+  if ([array count] == 0)
+    return array;
+  
+  /* qualify list */
+  
+  if ((query = [self valueFor:@"qualifier" node:_node ctx:_ctx])) {
+    if (![query isKindOfClass:[EOQualifier class]]) {
+      query = [query stringValue];
+      if ([query length] > 0)
+        query = [EOQualifier qualifierWithQualifierFormat:[query stringValue]];
+      else
+        query = nil;
+    }
+  }
+  if (query) {
+    array = [array filteredArrayUsingQualifier:query];
+    if ([array count] == 0)
+      return array;
+  }
+  
+  /* sort list */
+
+  sortOrderings = nil;
+  if ((sortkey = [self valueFor:@"sortkey" node:_node ctx:_ctx])) {
+    NSEnumerator *keys;
+    NSString *key;
+
+    sortOrderings = [NSMutableArray arrayWithCapacity:4];
+    
+    keys = [[sortkey componentsSeparatedByString:@","] objectEnumerator];
+    while ((key = [keys nextObject])) {
+      EOSortOrdering *so;
+      SEL sel = EOCompareAscending;
+      
+      if ([key hasPrefix:@"-"]) {
+        key = [key substringFromIndex:1];
+        sel = EOCompareDescending;
+      }
+      
+      if ((so = [EOSortOrdering sortOrderingWithKey:key selector:sel]))
+        [sortOrderings addObject:so];
+    }
+    
+    if ([sortOrderings count] == 0)
+      sortOrderings = nil;
+  }
+  if (sortOrderings)
+    array = [array sortedArrayUsingKeyOrderArray:sortOrderings];
+
+  /* return filtered and sorted list ... */
+  
+  return array;
+}
+
+// OWResponder
+
+static inline void
+_applyIdentifier(ODR_bind_foreach *self, id _node, id _ctx, NSString *_idx)
+{
+  NSArray *array;
+  unsigned count;
+  
+  array = [self _listForNode:_node inContext:_ctx];
+  count = [array count];
+  
+  if (count > 0) {
+    unsigned i;
+    BOOL hasSettableIndex;
+    BOOL hasSettableItem;
+    BOOL hasItem;
+
+    if ((hasItem = [self hasAttribute:@"item" node:_node ctx:_ctx]))
+      hasSettableItem = [self isSettable:@"item" node:_node ctx:_ctx];
+    else
+      hasSettableItem = NO;
+    
+    hasSettableIndex = [self isSettable:@"index" node:_node ctx:_ctx];
+    
+    /* find subelement for unique id */
+    
+    for (i = 0; i < count; i++) {
+      NSString *ident;
+      
+      if (hasSettableIndex)
+        [self setInt:i for:@"index" node:_node ctx:_ctx];
+      
+      if (hasSettableItem) {
+        [self setValue:[array objectAtIndex:i]
+              for:@"item" node:_node ctx:_ctx];
+      }
+      else if (!hasItem)
+        /* push cursor */
+        [_ctx pushCursor:[array objectAtIndex:i]];
+      
+      ident = [self stringFor:@"identifier" node:_node ctx:_ctx];
+      
+      if ([ident isEqualToString:_idx]) {
+        /* found subelement with unique id */
+        return;
+      }
+    }
+    if (hasSettableItem)
+      [self setValue:nil for:@"item" node:_node ctx:_ctx];
+    if (hasSettableIndex)
+      [self setInt:0 for:@"index" node:_node ctx:_ctx];
+  }
+}
+
+static inline void
+_applyIndex(ODR_bind_foreach *self, id _node, id _ctx, unsigned _i)
+{
+  NSArray *array;
+  BOOL hasSettableItem;
+  BOOL hasItem;
+
+  if ((hasItem = [self hasAttribute:@"item" node:_node ctx:_ctx]))
+    hasSettableItem = [self isSettable:@"item" node:_node ctx:_ctx];
+  else
+    hasSettableItem = NO;
+
+  array = [self _listForNode:_node inContext:_ctx];
+  
+  if ([self isSettable:@"index" node:_node ctx:_ctx])
+    [self setInt:_i for:@"index" node:_node ctx:_ctx];
+  
+  if (hasSettableItem) {
+    unsigned count = [array count];
+    
+    if (_i < count)
+      [self setValue:[array objectAtIndex:_i]
+            for:@"item" node:_node ctx:_ctx];
+    else {
+      [[_ctx component] logWithFormat:
+                    @"ODR_bind_foreach: array did change, index is invalid."];
+      [self setValue:nil for:@"item" node:_node ctx:_ctx];
+    }
+  }
+  else if (!hasItem) {
+    /* push cursor */
+    unsigned count = [array count];
+    
+    if (_i < count)
+      [_ctx pushCursor:[array objectAtIndex:_i]];
+    else {
+      [[_ctx component] logWithFormat:
+                    @"ODR_bind_foreach: array did change, index is invalid."];
+      [_ctx pushCursor:nil];
+    }
+  }
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  NSArray  *array;
+  unsigned aCount;
+  unsigned goCount;
+
+  array  = [self _listForNode:_node inContext:_ctx];
+  aCount = [array count];
+  
+  goCount = [self hasAttribute:@"count" node:_node ctx:_ctx]
+    ? [self intFor:@"count" node:_node ctx:_ctx]
+    : (int)aCount;
+  
+  if (goCount > 0) {
+    unsigned startIdx, goUntil;
+    int i;
+    
+    startIdx = [self intFor:@"startIndex" node:_node ctx:_ctx];
+    
+    if (![self hasAttribute:@"identifier" node:_node ctx:_ctx]) {
+      if (startIdx == 0)
+        [_ctx appendZeroElementIDComponent];
+      else
+        [_ctx appendElementIDComponent:[self stringForInt:startIdx]];
+    }
+    
+    if ([self hasAttribute:@"list" node:_node ctx:_ctx]) {
+      goUntil = (aCount > (startIdx + goCount))
+        ? startIdx + goCount
+        : aCount;
+    }
+    else
+      goUntil = startIdx + goCount;
+
+    for (i = startIdx; i < (int)goUntil; i++) {
+      _applyIndex(self, _node, _ctx, i);
+      
+      if ([self hasAttribute:@"identifier" node:_node ctx:_ctx]) {
+        NSString *s;
+        
+        s = [self stringFor:@"identifier" node:_node ctx:_ctx];
+        [_ctx appendElementIDComponent:s];
+      }
+      
+      [super takeValuesForNode:_node
+             fromRequest:_req
+             inContext:_ctx];
+      
+      [_ctx popCursor];
+      
+      if (![self hasAttribute:@"identifier" node:_node ctx:_ctx])
+        [_ctx incrementLastElementIDComponent];
+      else
+        [_ctx deleteLastElementIDComponent];
+    }
+    
+    if (![self hasAttribute:@"identifier" node:_node ctx:_ctx])
+      [_ctx deleteLastElementIDComponent]; // Repetition Index
+  }
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  id result = nil;
+  id idxId;
+  
+  if ((idxId  = [_ctx currentElementID])) {
+    BOOL hasItem;
+    int idx;
+    
+    hasItem = [self hasAttribute:@"item" node:_node ctx:_ctx];
+    
+    idx = [idxId intValue];
+    [_ctx consumeElementID]; // consume index-id
+    
+    /* this updates the element-id path */
+    [_ctx appendElementIDComponent:idxId];
+    
+    if ([self hasAttribute:@"identifier" node:_node ctx:_ctx])
+      _applyIdentifier(self, _node, _ctx, idxId);
+    else
+      _applyIndex(self, _node, _ctx, idx);
+    
+    result = [super invokeActionForNode:_node
+                    fromRequest:_req
+                    inContext:_ctx];
+    
+    if (!hasItem) [_ctx popCursor];
+    
+    [_ctx deleteLastElementIDComponent];
+  }
+  else {
+    [[_ctx session]
+           logWithFormat:@"%s: %@: MISSING INDEX ID in URL !",
+             __PRETTY_FUNCTION__,
+             self];
+  }
+  return result;
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  static Class NSAutoreleasePoolClass = Nil;
+  NSArray     *array;
+  unsigned    aCount, goCount, startIdx;
+  NSAutoreleasePool *pool;
+  BOOL hasId;
+
+  if (NSAutoreleasePoolClass == Nil)
+    NSAutoreleasePoolClass = [NSAutoreleasePool class];
+  
+  pool = [[NSAutoreleasePoolClass alloc] init];
+
+  hasId = NO;
+  
+  startIdx = [self   intFor:@"startIndex" node:_node ctx:_ctx];
+  goCount  = [self   intFor:@"count"      node:_node ctx:_ctx];
+  array    = [self _listForNode:_node inContext:_ctx];
+  aCount   = [array count];
+  goCount  = (goCount) ? goCount : aCount;
+
+#if DEBUG_REPETITION
+  NSLog(@"%s: process %d items ...", __PRETTY_FUNCTION__, goCount);
+#endif
+  
+  hasId = [self hasAttribute:@"identifier" node:_node ctx:_ctx];
+  
+  if (goCount > 0) {
+    unsigned i, goUntil;
+    BOOL hasSettableIndex = NO;
+    BOOL hasSettableItem  = NO;
+    BOOL hasItem          = NO;
+
+    if (!hasId) {
+      if (startIdx == 0)
+        [_ctx appendZeroElementIDComponent];
+      else
+        [_ctx appendElementIDComponent:[self stringForInt:startIdx]];
+    }
+
+    if ([self hasAttribute:@"list" node:_node ctx:_ctx]) {
+      goUntil = (aCount > (startIdx + goCount))
+        ? startIdx + goCount
+        : aCount;
+    }
+    else
+      goUntil = startIdx + goCount;
+
+    hasItem          = [self hasAttribute:@"item" node:_node ctx:_ctx];
+    hasSettableIndex = [self isSettable:@"index"  node:_node ctx:_ctx];
+    hasSettableItem  = [self isSettable:@"item"   node:_node ctx:_ctx];
+    
+    for (i = startIdx; i < goUntil; i++) {
+      id ident = nil;
+      
+      if (hasSettableIndex)
+        [self setInt:i for:@"index" node:_node ctx:_ctx];
+
+      if (hasItem) {
+        if (hasSettableItem) {
+          id item;
+        
+          item = [array objectAtIndex:i];
+#if DEBUG_REPETITION
+          NSLog(@"%s: apply item: %@", __PRETTY_FUNCTION__, item);
+#endif
+        
+          [self setValue:item for:@"item"
+                node:_node ctx:_ctx];
+        }
+      }
+      else {
+        /* use cursor */
+        [_ctx pushCursor:[array objectAtIndex:i]];
+      }
+      
+      /* get identifier used for action-links */
+      if (hasId) {
+        /* use a unique id for subelement detection */
+        ident = [self stringFor:@"identifier" node:_node ctx:_ctx];
+        //  ident = [ident stringByEscapingURL]; ???
+        [_ctx appendElementIDComponent:ident];
+      }
+      else {
+        /* use repetition index fo subelement detection */
+        ident = [self stringForInt:i];
+      }
+      
+      /* append child elements */
+      
+      [super appendNode:(id)_node
+             toResponse:(WOResponse *)_response
+             inContext:(WOContext *)_ctx];
+      
+      /* cleanup */
+      
+      if (!hasItem)
+        [_ctx popCursor];
+      
+      if (hasId)
+        [_ctx deleteLastElementIDComponent];
+      else
+        [_ctx incrementLastElementIDComponent];
+    }
+
+    if (!hasId)
+      [_ctx deleteLastElementIDComponent]; /* repetition index */
+    
+    if (hasSettableIndex)
+      [self setInt:0 for:@"index" node:_node ctx:_ctx];
+    
+    if (hasSettableItem)
+      [self setValue:nil for:@"item" node:_node ctx:_ctx];
+  }
+  RELEASE(pool);
+}
+
+@end /* ODR_bind_foreach */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_form.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_form.m
new file mode 100644 (file)
index 0000000..0592c5c
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+#include <EOControl/EOKeyValueCoding.h>
+
+/*
+   attributes:
+
+   usage:
+
+     <var:form const:src="/blah.sfm">
+       <var:param const:name="color"    const:value="green"/>
+       <var:param const:name="document" value="document"/>
+     </var:form>
+
+   form attributes
+     src
+
+   param attributes
+     name
+     value
+     type
+
+   NOTE: currently the context is stacked to the parent during the
+   synchronizations !!!
+*/
+
+@interface ODR_bind_form : ODNodeRenderer
+@end
+
+//#define PROFILE 1
+
+#include "common.h"
+#include "used_privates.h"
+#include <NGObjDOM/ODNodeRendererFactory.h>
+#include <NGObjDOM/ODNamespaces.h>
+#include <DOM/EDOM.h>
+#include <NGObjWeb/NGObjWeb.h>
+
+@interface _ODRBindFormTemplateWrapper : WODynamicElement
+@end
+
+@interface WOComponent(BindFormSupport)
+- (void)_addChildForm:(WOComponent *)_form withId:(NSString *)_fid;
+- (void)setSubComponents:(NSDictionary *)_sc;
+- (NSDictionary *)_subComponents;
+- (WOComponent *)childComponentWithName:(NSString *)_name;
+@end
+
+@implementation WOComponent(ChildForms)
+
+- (void)_addChildForm:(WOComponent *)_form withId:(NSString *)_fid {
+  NSMutableDictionary *msc;
+  NSDictionary *sc;
+  
+  if (_form == nil)       return;
+  if ([_fid length] == 0) return;
+  
+  sc = [self _subComponents];
+  msc = sc
+    ? [sc mutableCopy]
+    : [[NSMutableDictionary alloc] initWithCapacity:4];
+  
+  [msc setObject:_form forKey:_fid];
+  
+  [self setSubComponents:msc];
+  RELEASE(msc); msc = nil;
+}
+
+@end /* WOComponent(ChildForms) */
+
+@implementation ODR_bind_form
+
+- (WOComponent *)_childComponentForNode:(id)_node
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *form, *parent;
+  NSString    *src;
+  NSString    *fid;
+  
+  BEGIN_PROFILE;
+  
+  form   = nil;
+  parent = [_ctx component];
+  
+  /* try to lookup in cache */
+
+  fid = [self stringFor:@"id" node:_node ctx:_ctx];
+  
+  if ([fid length] == 0)
+    fid = [self uniqueIDForNode:_node inContext:_ctx];
+  
+  if ([fid length] > 0) {
+    fid = [NSString stringWithFormat:@"ODR_bind_form:%@", fid];
+#if DEBUG && 0
+    NSLog(@"FID: %@", fid);
+#endif
+    
+    if ((form = [parent childComponentWithName:fid]))
+      return form;
+  }
+  
+  /* try to instantiate form */
+  
+  if ((src = [self stringFor:@"src" node:_node ctx:_ctx])) {
+    //NSLog(@"%s: embed form '%@'", __PRETTY_FUNCTION__, src);
+    
+    PROFILE_CHECKPOINT("begin loading ..");
+    
+    //    NSLog(@"loading '%@' ...", src);
+    form = [parent pageWithName:src];
+    
+    PROFILE_CHECKPOINT("and not a page form ..");
+    
+    if (form == nil) {
+      [parent logWithFormat:@"(%@): found no subform at src '%@'",
+                NSStringFromClass([parent class]), src];
+    }
+  }
+  
+  /* insert form in cache ... */
+  if (form) [[_ctx component] _addChildForm:form withId:fid];
+  
+  END_PROFILE;
+  
+  return form;
+}
+
+- (WOElement *)_childContentForNode:(id)_node inContext:(WOContext *)_ctx {
+  return nil;
+}
+
+- (void)_syncComponent:(WOComponent *)_form
+  parent:(WOComponent *)_parent
+  node:(id)_node
+  syncUp:(BOOL)_syncUp
+  inContext:(WOContext *)_ctx
+{
+  /* Watch out for correct context when calling this method ! */
+  static DOMQueryPathExpression *qpexpr = nil;
+  NSEnumerator *childNodes;
+  id           childNode;
+  
+  BEGIN_PROFILE;
+  
+  if (_node == nil)
+    return;
+  
+  if (qpexpr == nil)
+    qpexpr = [[DOMQueryPathExpression queryPathWithString:@"-param"] retain];
+  
+  childNodes = _syncUp
+    ? [(NSArray *)[_node childNodes] objectEnumerator]
+    : [(NSArray *)[_node childNodes] reverseObjectEnumerator];
+  
+  while ((childNode = [childNodes nextObject])) {
+    NSString *pname;
+    NSString *ptype;
+    id       pvalue;
+    
+    if ([childNode nodeType] != DOM_ELEMENT_NODE)
+      continue;
+    if (![[childNode tagName] isEqualToString:@"param"])
+      continue;
+    
+    pname = [self stringFor:@"name" node:childNode ctx:_ctx];
+    ptype = [self stringFor:@"type" node:childNode ctx:_ctx];
+    
+    if (_syncUp) {
+      id attrNode;
+      
+      if ([ptype isEqualToString:@"in"])
+        continue;
+      
+      attrNode = [[childNode attributes]
+                             namedItem:@"value"
+                             namespaceURI:XMLNS_OD_BIND];
+      if (attrNode == nil) {
+#if DEBUG && 0
+        NSLog(@"%s: no up sync possible, missing proper value attribute ..",
+              __PRETTY_FUNCTION__);
+#endif
+        continue;
+      }
+      
+      pvalue = [_form valueForKey:pname];
+      
+#if DEBUG && 0
+      [[_ctx component]
+             logWithFormat:@"sync up value %@ to %@", pvalue, [attrNode value]];
+#endif
+      
+      [_parent takeValue:pvalue forKeyPath:[attrNode value]];
+    }
+    else {
+      if ([ptype isEqualToString:@"out"])
+        continue;
+      
+      pvalue = [self valueFor:@"value" node:childNode ctx:_ctx];
+#if DEBUG && 0
+      [[_ctx component]
+             logWithFormat:
+               @"sync down value '%@' to '%@'", pvalue, pname];
+#endif
+
+      [_form takeValue:pvalue forKey:pname];
+    }
+  }
+  
+  END_PROFILE;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *childComponent;
+  WOComponent *parentComponent;
+  
+  childComponent = [self _childComponentForNode:_node inContext:_ctx];
+  if (childComponent == nil)
+    return;
+
+  parentComponent = [_ctx component];
+  
+  [self _syncComponent:childComponent
+        parent:parentComponent
+        node:_node
+        syncUp:NO
+        inContext:_ctx];
+  
+  [_ctx enterComponent:childComponent
+        content:[self _childContentForNode:_node inContext:_ctx]];
+  
+  [childComponent takeValuesFromRequest:_request inContext:_ctx];
+
+  [_ctx leaveComponent:childComponent];
+  
+  [self _syncComponent:childComponent
+        parent:parentComponent
+        node:_node
+        syncUp:YES
+        inContext:_ctx];
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *childComponent;
+  WOComponent *parentComponent;
+  id result;
+
+  BEGIN_PROFILE;
+
+  childComponent = [self _childComponentForNode:_node inContext:_ctx];
+  if (childComponent == nil) {
+#if DEBUG
+    [[_ctx component] debugWithFormat:@"missing child component .."];
+#endif
+    return nil;
+  }
+  
+  parentComponent = [_ctx component];
+  
+  [self _syncComponent:childComponent
+        parent:parentComponent
+        node:_node
+        syncUp:NO
+        inContext:_ctx];
+  
+  [_ctx enterComponent:childComponent
+        content:[self _childContentForNode:_node inContext:_ctx]];
+  
+#if DEBUG && 0
+  [[_ctx component] debugWithFormat:@" %s\nsid=%@\neid=%@",
+                      __PRETTY_FUNCTION__,
+                      [_ctx senderID], [_ctx elementID]];
+#endif
+  
+  result = [childComponent invokeActionForRequest:_request inContext:_ctx];
+  
+  [_ctx leaveComponent:childComponent];
+  
+  [self _syncComponent:childComponent
+        parent:parentComponent
+        node:_node
+        syncUp:YES
+        inContext:_ctx];
+
+  END_PROFILE;
+  
+  return result;
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *childComponent;
+  WOComponent *parentComponent;
+
+  BEGIN_PROFILE;
+  
+  childComponent = [self _childComponentForNode:_node inContext:_ctx];
+  if (childComponent == nil)
+    return;
+  
+  parentComponent = [_ctx component];
+
+  PROFILE_CHECKPOINT("sync down ..");
+  
+  [self _syncComponent:childComponent
+        parent:parentComponent
+        node:_node
+        syncUp:NO
+        inContext:_ctx];
+
+  PROFILE_CHECKPOINT("enter stack ..");
+  
+  [_ctx enterComponent:childComponent
+        content:[self _childContentForNode:_node inContext:_ctx]];
+
+  PROFILE_CHECKPOINT("append child ..");
+  
+  [childComponent appendToResponse:_response inContext:_ctx];
+  
+  PROFILE_CHECKPOINT("leave stack ..");
+  
+  [_ctx leaveComponent:childComponent];
+
+  PROFILE_CHECKPOINT("sync up ..");
+  
+  [self _syncComponent:childComponent
+        parent:parentComponent
+        node:_node
+        syncUp:YES
+        inContext:_ctx];
+
+  END_PROFILE;
+}
+
+@end /* ODR_bind_embed */
+
+@implementation _ODRBindFormTemplateWrapper
+
+- (id)_nodeInContext:(WOContext *)_ctx {
+  return nil;
+}
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  id<ODNodeRendererFactory> factory;
+  ODNodeRenderer *renderer = nil;
+
+  if ((factory = [_ctx objectForKey:@"domRenderFactory"]))
+    renderer = [factory rendererForNode:_domNode inContext:_ctx];
+
+  return renderer;
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  ODNodeRenderer *lrenderer = nil;
+  id dom;
+  
+  if ((dom = [self _nodeInContext:_ctx]) == nil)
+    return;
+
+  [lrenderer takeValuesForNode:dom
+             fromRequest:_request
+             inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  ODNodeRenderer *lrenderer = nil;
+  id dom;
+  
+  if ((dom = [self _nodeInContext:_ctx]) == nil)
+    return nil;
+  
+  return [lrenderer invokeActionForNode:dom
+                    fromRequest:_request
+                    inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  ODNodeRenderer *lrenderer;
+  id dom;
+  
+  if ((dom = [self _nodeInContext:_ctx]) == nil)
+    return;
+
+  if ((lrenderer = [self rendererForNode:dom inContext:_ctx]) == nil) {
+#if DEBUG_DOM
+    [cmp logWithFormat:@"did not find renderer for node %@", dom];
+    [_response appendContentString:@"<!-- missing dom renderer -->"];
+#endif
+    return;
+  }
+
+#if DEBUG_DOM
+  NSAssert(lrenderer, @"lost renderer ..");
+#endif
+
+  [lrenderer appendNode:dom
+             toResponse:_response
+             inContext:_ctx];
+
+#if DEBUG_DOM
+  NSAssert(_response, @"lost response ..");
+  [_response appendContentString:@"<!-- renderdom-end -->"];
+#endif
+}
+
+@end /* _ODRBindFormTemplateWrapper */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_groupings.h b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_groupings.h
new file mode 100644 (file)
index 0000000..fdb00da
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_ODR_bind_groupings_H__
+#define __NGObjDOM_ODR_bind_groupings_H__
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+#define ODR_GroupingContainer     @"ODR_GroupingContainer"
+#define ODR_GroupingContainerMode @"ODR_GroupingContainerMode"
+
+@interface ODR_bind_groupings : ODNodeRenderer
+@end
+
+@interface ODR_bind_groupingset : ODNodeRenderer
+@end
+
+@interface ODR_bind_groupby : ODNodeRenderer
+@end
+
+#endif /* __NGObjDOM_ODR_bind_groupings_H__ */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_groupings.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_groupings.m
new file mode 100644 (file)
index 0000000..e0a99e9
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODR_bind_groupings.h"
+
+#include <EOControl/EOControl.h>
+#include <NGObjDOM/ODNamespaces.h>
+#include <DOM/EDOM.h>
+#include "common.h"
+#include "NGJavaScript/Core+JS.subproj/EOJavaScriptGrouping.h"
+
+@implementation ODR_bind_groupings
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if (![[_ctx objectForKey:ODR_GroupingContainerMode] boolValue])
+    return;
+  
+  if ([self boolFor:@"disabled" node:_node ctx:_ctx])
+    return;
+  
+  [_ctx setObject:[NSArray array] forKey:ODR_GroupingContainer];
+  
+  [self appendChildNodes:[_node childNodes]
+        toResponse:_response
+        inContext:_ctx];
+}
+
+@end /* ODR_bind_groupings */
+
+@implementation ODR_bind_groupingset
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  EOGroupingSet *groupingSet = nil;
+  id            container    = nil;
+  NSString      *defaultName = nil;
+
+  if (![[_ctx objectForKey:ODR_GroupingContainerMode] boolValue])
+    return;
+
+  if (!(container = [_ctx objectForKey:ODR_GroupingContainer]))
+    return;
+
+  groupingSet = [[EOGroupingSet alloc] init];
+  if ((defaultName = [self stringFor:@"defaultName" node:_node ctx:_ctx]))
+    [groupingSet setDefaultName:defaultName];
+
+  if (([container isKindOfClass:[NSArray class]])) {
+    container = [container arrayByAddingObject:groupingSet];
+  }
+  else if (([container isKindOfClass:[EOGroupingSet class]])) {
+    NSArray *tmp;
+
+    tmp = [container groupings];
+    if (tmp == nil)
+      [container setGroupings:[NSArray arrayWithObject:groupingSet]];
+    else
+      [container setGroupings:[tmp arrayByAddingObject:groupingSet]];
+  }
+  
+  [_ctx setObject:groupingSet forKey:ODR_GroupingContainer];
+  [self appendChildNodes:[_node childNodes]
+        toResponse:_response
+        inContext:_ctx];
+  [_ctx setObject:container forKey:ODR_GroupingContainer];
+  
+  AUTORELEASE(groupingSet);
+}
+
+@end /* ODR_bind_groupingset */
+
+@implementation ODR_bind_groupby
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  EOGrouping *grouping = nil;
+  NSString   *name;
+  id         value;
+  id         container;
+
+  if (![[_ctx objectForKey:ODR_GroupingContainerMode] boolValue])
+    return;
+  
+  if (!(container = [_ctx objectForKey:ODR_GroupingContainer]))
+    return;
+
+  name = [self stringFor:@"name" node:_node ctx:_node];
+  name = (name) ? name : [_ctx elementID];
+
+  if ((value = [self stringFor:@"key" node:_node ctx:_ctx]))
+    grouping = [[EOKeyGrouping alloc] initWithKey:value];
+  else if ((value = [self stringFor:@"qualifier" node:_node ctx:_ctx])) {
+    grouping = [[EOQualifierGrouping alloc] initWithQualifier:
+                        [EOQualifier qualifierWithQualifierFormat:value]
+                                            name:name];
+  }
+  else if ((value = [self valueFor:@"bindings" node:_node ctx:_ctx])) {
+    grouping = [[EOQualifierGrouping alloc] initWithQualifier:
+                        [[[EOQualifier alloc] init]
+                                       qualifierWithBindings:value
+                                       requiresAllVariables:NO]
+                                            name:name];
+  }
+  else if ((value = [self valueFor:@"grouping" node:_node ctx:_ctx])) {
+    if ([value isKindOfClass:[EOGrouping class]])
+      ASSIGN(grouping, value);
+  }
+  else if ((value = [self stringFor:@"script" node:_node ctx:_ctx])) {
+    static Class GroupingClass = Nil;
+    
+    if (GroupingClass == Nil)
+      GroupingClass = NSClassFromString(@"EOJavaScriptGrouping");
+    
+    grouping = [[GroupingClass alloc] initWithJavaScript:value name:name];
+  }
+  
+  if (grouping == nil)
+    return;
+
+  if ((value = [self stringFor:@"defaultName" node:_node ctx:_ctx]))
+    [grouping setDefaultName:value];
+  
+  if ([container isKindOfClass:[EOGroupingSet class]]) {
+    NSArray *tmp;
+
+    tmp = [container groupings];
+    if (tmp == nil)
+      [container setGroupings:[NSArray arrayWithObject:grouping]];
+    else
+      [container setGroupings:[tmp arrayByAddingObject:grouping]];
+  }
+  else if ([container isKindOfClass:[NSArray class]]) {
+    [_ctx setObject:[container arrayByAddingObject:grouping]
+             forKey:ODR_GroupingContainer];
+  }
+
+  AUTORELEASE(grouping);
+}
+
+@end /* ODR_bind_groupby */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_if.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_if.m
new file mode 100644 (file)
index 0000000..e228a8d
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+   attributes:
+     condition
+     value1
+     value2
+     
+   usage:
+     <script>
+       var condition=true;
+     </script>
+     
+     <var:if condition="condition1">
+       content of if
+       <var:elseif condition="condition2"/>content of elseif</elseif>
+       <var:else>content of else</var:else>
+     </var:if>
+     
+     <var:ifnot condition="condition">
+       <content />
+     </var:ifnot>
+
+     <var:if const:value1="10" const:value2="20">
+       ..
+     </var:if>
+*/
+
+@interface ODR_bind_if : ODNodeRenderer
+@end
+
+@interface ODR_bind_ifnot : ODR_bind_if
+@end
+
+#include <DOM/DOM.h>
+#include "common.h"
+
+@implementation ODR_bind_if
+
+- (BOOL)doShow:(id)_node ctx:(WOContext *)_ctx {
+  BOOL doShow;
+
+  doShow = YES;
+  
+  if ([self hasAttribute:@"condition" node:_node ctx:_ctx]) {
+    BOOL flag;
+    flag = [self boolFor:@"condition" node:_node ctx:_ctx];
+    if (!flag) doShow = NO;
+  }
+  
+  if ([self hasAttribute:@"value1" node:_node ctx:_ctx]) {
+    if ([self hasAttribute:@"value2" node:_node ctx:_ctx]) {
+      id value1, value2;
+      BOOL flag;
+      
+      value1 = [self valueFor:@"value1" node:_node ctx:_ctx];
+      value2 = [self valueFor:@"value2" node:_node ctx:_ctx];
+      
+      if (value1 == nil && value2 == nil)
+        flag = YES;
+      else
+        flag = [value1 isEqual:value2];
+      
+      if (!flag) doShow = NO;
+    }
+  }
+  
+  return doShow;
+}
+
+- (NSArray *)_contentOfIfNode:(id)_node {
+  NSArray        *children;
+  NSMutableArray *result;
+  int            i, cnt;
+
+  children = (NSArray *)[_node childNodes];
+  //children = ODRLookupQueryPath(_node, @"-*");
+  cnt      = [children count];
+  result   = [NSMutableArray arrayWithCapacity:cnt];
+  
+  for (i=0; i<cnt; i++) {
+    NSString *tagName;
+    id       child;
+
+    child = [children objectAtIndex:i];
+    tagName = [child nodeName];
+    
+    if (![tagName isEqualToString:@"else"] &&
+        ![tagName isEqualToString:@"elseif"])
+      [result addObject:child];
+  }
+  return result;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if ([self doShow:_node ctx:_ctx]) {
+    [_ctx appendElementIDComponent:@"if"];
+    
+    [self takeValuesForChildNodes:[self _contentOfIfNode:_node]
+           fromRequest:_request
+           inContext:_ctx];
+    
+    [_ctx deleteLastElementIDComponent]; // delete "if"
+  }
+  else {
+    BOOL    didMatch = NO;
+    NSArray *children;
+    int     i, cnt;
+
+    children = ODRLookupQueryPath(_node, @"-elseif");
+    cnt      = [children count];
+    
+    for (i = 0; i < cnt; i++) {
+      id child;
+
+      child = [children objectAtIndex:i];
+      
+      if ([self doShow:child ctx:_ctx]) {
+        [_ctx appendElementIDComponent:@"elseif"];
+        [_ctx appendElementIDComponent:[NSString stringWithFormat:@"%d", i]];
+        [super takeValuesForNode:child fromRequest:_request inContext:_ctx];
+        [_ctx deleteLastElementIDComponent]; // i
+        [_ctx deleteLastElementIDComponent]; // "elseif"
+        didMatch = YES;
+        break;
+      }
+    }
+    if (!didMatch) {
+      [_ctx appendElementIDComponent:@"else"];
+      [self takeValuesForChildNodes:ODRLookupQueryPath(_node, @"-else")
+            fromRequest:_request
+            inContext:_ctx];
+      [_ctx deleteLastElementIDComponent]; // "else"
+    }
+  }
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *state;
+  id       result = nil;
+
+  state = [[_ctx currentElementID] stringValue];
+  
+  if (state) {
+    [_ctx consumeElementID]; // consume ("if" | "elseif" | "else")
+
+    if ([state isEqualToString:@"if"]) {
+      
+      [_ctx appendElementIDComponent:@"if"];
+      result = [self invokeActionForChildNodes:[self _contentOfIfNode:_node]
+                     fromRequest:_request
+                     inContext:_ctx];
+      [_ctx deleteLastElementIDComponent]; // if
+    }
+    else if ([state isEqualToString:@"elseif"]) {
+      NSArray  *children;
+      NSString *idx;
+      int      i;
+
+      children = ODRLookupQueryPath(_node, @"-elseif");
+      idx      = [[_ctx currentElementID] stringValue];
+      i        = [idx intValue];
+
+      if (i < (int)[children count]) {
+        [_ctx appendElementIDComponent:@"elseif"];
+        [_ctx appendElementIDComponent:idx];
+        result = [super invokeActionForNode:[children objectAtIndex:i]
+                        fromRequest:_request
+                        inContext:_ctx];
+        [_ctx deleteLastElementIDComponent]; // idx
+        [_ctx deleteLastElementIDComponent]; // "elseif"        
+      }
+      else
+        [[_ctx component] logWithFormat:@"index out of range"];
+    }
+    else if ([state isEqualToString:@"else"]) {
+      [_ctx appendElementIDComponent:@"else"];
+      result = 
+        [self invokeActionForChildNodes:ODRLookupQueryPath(_node, @"-else")
+              fromRequest:_request
+              inContext:_ctx];
+      [_ctx deleteLastElementIDComponent]; // "else"
+    }
+    else
+      [[_ctx component] logWithFormat:@"wrong section"]; 
+  }
+  return result;
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{ 
+  if ([self doShow:_node ctx:_ctx]) {
+    [_ctx appendElementIDComponent:@"if"];
+    
+    [self appendChildNodes:[self _contentOfIfNode:_node]
+           toResponse:_response
+           inContext:_ctx];
+    
+    [_ctx deleteLastElementIDComponent]; // delete "if"
+  }
+  else {
+    BOOL    didMatch = NO;
+    NSArray *children;
+    int     i, cnt;
+
+    children = ODRLookupQueryPath(_node, @"-elseif");
+    cnt      = [children count];
+    
+    for (i = 0; i < cnt; i++) {
+      id child;
+
+      child = [children objectAtIndex:i];
+      
+      if ([self doShow:child ctx:_ctx]) {
+        [_ctx appendElementIDComponent:@"elseif"];
+        [_ctx appendElementIDComponent:[NSString stringWithFormat:@"%d", i]];
+        [super appendNode:child toResponse:_response inContext:_ctx];
+        [_ctx deleteLastElementIDComponent]; // i
+        [_ctx deleteLastElementIDComponent]; // "elseif"
+        didMatch = YES;
+        break;
+      }
+    }
+
+    if (!didMatch) {
+      [_ctx appendElementIDComponent:@"else"];
+      [self appendChildNodes:ODRLookupQueryPath(_node, @"-else")
+            toResponse:_response
+            inContext:_ctx];
+      [_ctx deleteLastElementIDComponent]; // "else"
+    }
+  }
+}
+
+@end /* ODR_bind_if */
+
+@implementation ODR_bind_ifnot
+
+- (BOOL)doShow:(id)_node ctx:(WOContext *)_ctx {
+  return [self boolFor:@"condition" node:_node ctx:_ctx] ? NO : YES;
+}
+
+@end /* ODR_bind_ifnot */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_multiselection.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_multiselection.m
new file mode 100644 (file)
index 0000000..3746598
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+  attributes:
+  
+    list item selection
+    string
+    noSelectionString
+    size
+    name
+
+  example:
+    <script>
+      var list       = [ "1", "2", "3", "4" ];
+      var selections = [ "1", "4" ];
+      var selection  = "2"
+    </script>
+
+    <wo:multiselection  list="list" item="item" selection="selections"/>
+    <wo:singleselection list="list" item="item" selection="selection"/>
+*/
+
+@interface ODR_bind_multiselection : ODNodeRenderer
+@end
+
+@interface ODR_bind_singleselection : ODR_bind_multiselection
+@end
+
+#include <DOM/DOM.h>
+#include "common.h"
+
+@implementation ODR_bind_multiselection
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (BOOL)isMultiple {
+  return YES;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  id        formValue = nil;
+  NSString *name      = nil;
+
+  name = [self stringFor:@"name" node:_node ctx:_ctx];
+  name = (name) ? name : [_ctx elementID];
+
+  formValue = [_req formValuesForKey:name];
+    
+  if ([self isSettable:@"value" node:_node ctx:_ctx])
+    [self setValue:formValue for:@"value" node:_node ctx:_ctx];
+  
+  if ([formValue count] == 1) {
+    NSArray *objects;
+    id      object;
+      
+    objects = [self valueFor:@"list" node:_node ctx:_ctx];
+      
+    formValue = [formValue lastObject];
+    if ([[formValue stringValue] isEqualToString:@"$"])
+      object = nil; // nil item selected
+    else
+      object = [objects objectAtIndex:[formValue intValue]];
+
+    if ([self isSettable:@"selection" node:_node ctx:_ctx]) {
+      NSArray *sel;
+        
+      if ([self isSettable:@"item" node:_node ctx:_ctx])
+        [self setValue:object for:@"item" node:_node ctx:_ctx];
+
+      if (object) {
+        if (![self isMultiple])
+          sel = RETAIN(object);
+        else
+          sel = [[NSArray alloc] initWithObjects:object,nil];
+      }
+      else // nil item selected
+        sel = nil;
+
+      if ([self isSettable:@"selection" node:_node ctx:_ctx])
+        [self setValue:sel for:@"selection" node:_node ctx:_ctx];
+      RELEASE(sel); sel = nil;
+    }
+  }
+  else if (formValue) {
+    NSEnumerator   *values  = [formValue objectEnumerator];
+    NSString       *v;
+    NSArray        *objects = [self valueFor:@"list" node:_node ctx:_ctx];
+    id             object;
+
+    if ([self isSettable:@"selection" node:_node ctx:_ctx]) {
+      NSMutableArray *sel;
+      
+      sel = [[NSMutableArray allocWithZone:[self zone]]
+                             initWithCapacity:[formValue count]];
+
+      while ((v = [values nextObject])) {
+        object = [objects objectAtIndex:[v intValue]];
+
+        if ([self isSettable:@"item" node:_node ctx:_ctx])
+          [self setValue:object for:@"item" node:_node ctx:_ctx];
+          
+        if (object) [sel addObject:object];
+      }
+
+      [self setValue:sel for:@"selection" node:_node ctx:_ctx];
+      RELEASE(sel); sel = nil;
+    }
+  }
+  else {
+    // nothing selected
+    if ([self isSettable:@"item" node:_node ctx:_ctx])
+      [self setValue:nil for:@"item" node:_node ctx:_ctx];
+    if ([self isSettable:@"selection" node:_node ctx:_ctx])
+      [self setValue:nil for:@"selection" node:_node ctx:_ctx];
+  }
+}
+
+
+
+// ---------------------------------- ok --------------
+
+- (void)appendOptions:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *nilStr  = nil;
+  NSArray  *array   = nil;
+  id       selection = nil;
+  int      i, cnt;
+    
+  nilStr    = [self stringFor:@"noSelectionString" node:_node ctx:_ctx];
+  array     = [self  valueFor:@"list"              node:_node ctx:_ctx];
+  selection = [self  valueFor:@"selection"         node:_node ctx:_ctx];
+  cnt       = [array count];
+
+  if ([self isMultiple]) {
+    if (![selection isKindOfClass:[NSArray class]])
+      selection = [NSArray array];
+  }
+  
+  if (nilStr) {
+    [_response appendContentString:@"  <option value=\"$\">"];
+    [_response appendContentHTMLString:nilStr];
+    [_response appendContentString:@"\n"];
+  }
+    
+  for (i = 0; i < cnt; i++) {
+    NSString *v         = nil;
+    NSString *displayV  = nil;
+    id       object     = [array objectAtIndex:i];
+    BOOL     isSelected;
+
+    if ([self isSettable:@"item" node:_node ctx:_ctx])
+      [self setValue:object for:@"item" node:_node ctx:_ctx];
+
+    if (![self isMultiple])
+      isSelected = selection ? [selection isEqual:object] : NO;
+    else
+      isSelected = selection ? [selection containsObject:object] : NO;
+
+    v = ([self hasAttribute:@"value" node:_node ctx:_ctx])
+      ? [self stringFor:@"value" node:_node ctx:_ctx]
+      : [NSString stringWithFormat:@"%i", i];
+
+    displayV = ([self hasAttribute:@"string" node:_node ctx:_ctx])
+      ? [self stringFor:@"string" node:_node ctx:_ctx]
+      : [object stringValue];
+
+    if (displayV == nil) displayV = @"<nil>";
+
+    [_response appendContentString:@"  <option value=\""];
+    [_response appendContentString:v];
+    [_response appendContentString:(isSelected) ? @"\" selected>" : @"\">"];
+    [_response appendContentHTMLString:displayV];
+    [_response appendContentString:@"\n"];
+  }
+}
+
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if (![[_ctx request] isFromClientComponent]) {
+    unsigned size;
+    NSString *name;
+
+    size = [self    intFor:@"size" node:_node ctx:_ctx];
+    name = [self stringFor:@"name" node:_node ctx:_ctx];
+    name = (name) ? name : [_ctx elementID];
+
+    
+    [_response appendContentString:@"<select name=\""];
+    [_response appendContentHTMLAttributeValue:name];
+    [_response appendContentString:@"\""];
+
+    if (size > 0) {
+      [_response appendContentString:@" size=\""];
+      [_response appendContentString:[NSString stringWithFormat:@"%d", size]];
+      [_response appendContentCharacter:'"'];
+    }
+      
+    if ([self isMultiple])
+      [_response appendContentString:@" multiple"];
+  
+    [_response appendContentString: @">\n"];
+  
+    [self appendOptions:_node toResponse:_response inContext:_ctx];
+  
+    [_response appendContentString:@"</select>"];
+  }
+}
+
+@end /* ODR_bind_multiselection */
+
+@implementation ODR_bind_singleselection
+
+- (BOOL)isMultiple {
+  return NO;
+}
+
+@end /* ODR_bind_singleselection */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_nbsp.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_nbsp.m
new file mode 100644 (file)
index 0000000..bbe438a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+   attributes:
+     -
+
+   usage:
+     <nbsp/>
+*/
+
+@interface ODR_bind_nbsp : ODNodeRenderer
+@end
+
+#include <DOM/DOM.h>
+#include "common.h"
+
+@implementation ODR_bind_nbsp
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  [_response appendContentString:@"&nbsp;"];
+  [super appendNode:_node toResponse:_response inContext:_ctx];
+}
+
+@end /* ODR_bind_nsbp */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_popupbutton.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_popupbutton.m
new file mode 100644 (file)
index 0000000..4ccfe3d
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+  attributes:
+  
+    list
+    item
+    selection
+    string
+    noselectionstring
+    name
+
+  example:
+    <script>
+      var list = [ "1", "2", "3", "4" ];
+    </script>
+  
+    <wo:popupbutton list="list" item="item" selection="selection"/>
+>
+*/
+
+@interface ODR_bind_popupbutton : ODNodeRenderer
+@end
+
+#include <DOM/DOM.h>
+#include "common.h"
+
+@implementation ODR_bind_popupbutton
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  NSString *formValue;
+  NSString *name;
+
+  name = [self stringFor:@"name" node:_node ctx:_ctx];
+  name = (name) ? name : [_ctx elementID];
+  
+  formValue = [_req formValueForKey:name];
+    
+  if ([self isSettable:@"value" node:_node ctx:_ctx])
+    [self setValue:formValue for:@"value" node:_node ctx:_ctx];
+    
+  if (formValue) {
+    NSArray *objects;
+    id      object;
+      
+    objects = [self valueFor:@"list" node:_node ctx:_ctx];
+      
+    object = nil;
+    if ([self hasAttribute:@"value" node:_node ctx:_ctx]) {
+      /* has a value binding, walk list to find object */
+      unsigned i, toGo;
+
+      for (i = 0, toGo = [objects count]; i < toGo; i++) {
+        NSString *cv;
+          
+        object = [objects objectAtIndex:i];
+          
+        if ([self isSettable:@"item" node:_node ctx:_ctx])
+          [self setValue:object for:@"item" node:_node ctx:_ctx];
+
+        cv = [self stringFor:@"value" node:_node ctx:_ctx];
+          
+        if ([cv isEqualToString:formValue])
+          break;
+      }
+    }
+    else if (![formValue isEqualToString:@"$"]) {
+      /* an index binding */
+      int idx;
+        
+      idx = [formValue intValue];
+      if (idx >= (int)[objects count]) {
+        [[_ctx page] logWithFormat:@"popup-index %i out of range 0-%i",
+                     idx, [objects count] - 1];
+        object = nil;
+      }
+      else 
+        object = [objects objectAtIndex:idx];
+    }
+      
+    if ([self isSettable:@"selection" node:_node ctx:_ctx]) {
+      if ([self isSettable:@"item" node:_node ctx:_ctx])
+        [self setValue:object for:@"item" node:_node ctx:_ctx];
+
+      if ([self isSettable:@"selection" node:_node ctx:_ctx])
+        [self setValue:object for:@"selection" node:_node ctx:_ctx];
+    }
+  }
+  else {
+    // nothing selected
+    if ([self isSettable:@"item" node:_node ctx:_ctx])
+      [self setValue:nil for:@"item" node:_node ctx:_ctx];
+    if ([self isSettable:@"selection" node:_node ctx:_ctx])
+      [self setValue:nil for:@"selection" node:_node ctx:_ctx];
+  }
+}
+
+- (void)appendOptions:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *nilStr   = nil;
+  NSArray  *array    = nil;
+  id       selection = nil;
+  int      i, cnt;
+  
+  nilStr    = [self stringFor:@"noselectionstring" node:_node ctx:_ctx];
+  if (nilStr == nil)
+    nilStr = [self stringFor:@"noSelectionString" node:_node ctx:_ctx];
+  array     = [self  valueFor:@"list"              node:_node ctx:_ctx];
+  selection = [self  valueFor:@"selection"         node:_node ctx:_ctx];
+  cnt       = [array count];
+  
+  if (nilStr) {
+    [_response appendContentString:@"  <option value=\"$\">"];
+    [_response appendContentHTMLString:nilStr];
+    [_response appendContentString:@"\n"];
+  }
+    
+  for (i = 0; i < cnt; i++) {
+    NSString *v         = nil;
+    NSString *displayV  = nil;
+    id       object     = [array objectAtIndex:i];
+    BOOL     isSelected;
+
+    if ([self isSettable:@"item" node:_node ctx:_ctx])
+      [self setValue:object for:@"item" node:_node ctx:_ctx];
+
+    isSelected = (selection) ? [selection isEqual:object] : NO;
+
+    v = ([self hasAttribute:@"value" node:_node ctx:_ctx])
+      ? [self stringFor:@"value" node:_node ctx:_ctx]
+      : [NSString stringWithFormat:@"%i", i];
+
+    displayV = ([self hasAttribute:@"string" node:_node ctx:_ctx])
+      ? [self stringFor:@"string" node:_node ctx:_ctx]
+      : [object stringValue];
+
+    if (displayV == nil) displayV = @"<nil>";
+
+    [_response appendContentString:@"  <option value=\""];
+    [_response appendContentString:v];
+    [_response appendContentString:(isSelected) ? @"\" selected>" : @"\">"];
+    [_response appendContentHTMLString:displayV];
+    [_response appendContentString:@"\n"];
+  }
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *name;
+
+  name = [self stringFor:@"name" node:_node ctx:_ctx];
+  name = (name) ? name : [_ctx elementID];
+
+  [_response appendContentString:@"<select name=\""];
+  [_response appendContentHTMLAttributeValue:name];
+  [_response appendContentString:@"\">\n"];
+
+  [self appendOptions:_node toResponse:_response inContext:_ctx];
+
+  [_response appendContentString:@"</select>"];
+}
+
+@end /* ODR_bind_popupbutton */
+
+
+@interface ODR_bind_popup : ODR_bind_popupbutton
+@end
+
+@implementation ODR_bind_popup
+@end
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_radiobutton.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_radiobutton.m
new file mode 100644 (file)
index 0000000..7e765c0
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+  attributes:
+  
+    checked || value selection
+    name
+    
+  example:
+
+    <script>
+      var selection="2";
+    </script>
+    
+    <wo:radiobutton const:name="radio" const:value="1" selection="selection"/>
+    <wo:radiobutton const:name="radio" const:value="2" selection="selection"/>
+    <wo:radiobutton const:name="radio" const:value="3" selection="selection"/>
+    
+    or:
+    
+    <script>
+       var radio1Checked=false;
+       var radio2Checked=true;
+       var radio3Checked=false;
+    </script>
+    
+    <wo:radiobutton const:name="radio" checked="radio1Checked">
+    <wo:radiobutton const:name="radio" checked="radio2Checked">
+    <wo:radiobutton const:name="radio" checked="radio3Checked">
+*/
+
+@interface ODR_bind_radiobutton : ODNodeRenderer
+@end
+
+#include <DOM/DOM.h>
+#include "common.h"
+
+@implementation ODR_bind_radiobutton
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  id       formValue;
+  NSString *name;
+
+  name = [self stringFor:@"name" node:_node ctx:_ctx];
+  name = (name) ? name : [_ctx elementID];
+  
+  formValue = [_req formValueForKey:name];
+
+  if ([self hasAttribute:@"checked" node:_node ctx:_ctx]) {
+    if ([self isSettable:@"checked" node:_node ctx:_ctx]) {
+      [self setBool:[formValue isEqual:[_ctx elementID]]
+            for:@"checked"
+            node:_node
+            ctx:_ctx];
+    }
+  }
+  if ([self isSettable:@"selection" node:_node ctx:_ctx])
+    [self setValue:formValue for:@"selection" node:_node ctx:_ctx];
+}
+
+- (void)appendNode:(id)_node
+        toResponse:(WOResponse *)_response
+         inContext:(WOContext *)_ctx
+{
+  NSString *name;
+
+  name = [self stringFor:@"name" node:_node ctx:_ctx];
+
+  if (name == nil) {
+    NSLog(@"var:radiobutton no name is specified!");
+    name = [_ctx elementID];
+  }
+
+  [_response appendContentString: @"<input type=\"radio\" name=\""];
+  [_response appendContentHTMLAttributeValue:name];
+  [_response appendContentString:@"\" value=\""];
+  [_response appendContentHTMLAttributeValue:
+             ([self hasAttribute:@"checked" node:_node ctx:_ctx])
+             ? [_ctx elementID]
+             : [self stringFor:@"value" node:_node ctx:_ctx]];
+  [_response appendContentString:@"\""];
+
+  if ([self hasAttribute:@"checked" node:_node ctx:_ctx]) {
+    if ([self boolFor:@"checked" node:_node ctx:_ctx])
+      [_response appendContentString:@" checked"];
+  }
+  else {
+    id v   = [self valueFor:@"value" node:_node ctx:_ctx];
+    id sel = [self valueFor:@"selection" node:_node ctx:_ctx];
+
+    if ([v isEqual:sel])
+      [_response appendContentString:@" checked"];
+  }
+  [_response appendContentString:@">\n"];
+}
+
+@end /* ODR_bind_radiobutton */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_sortorderings.h b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_sortorderings.h
new file mode 100644 (file)
index 0000000..f62b884
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_ODR_bind_sortorderings_H__
+#define __NGObjDOM_ODR_bind_sortorderings_H__
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+#define ODR_SortOrderingContainer     @"ODR_SortOrderingContainer"
+#define ODR_SortOrderingContainerMode @"ODR_SortOrderingContainerMode"
+
+@interface ODR_bind_sortorderings : ODNodeRenderer
+@end
+
+@interface ODR_bind_sortordering : ODNodeRenderer
+@end
+
+#endif /* __NGObjDOM_ODR_bind_sortorderings_H__ */
+
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_sortorderings.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_sortorderings.m
new file mode 100644 (file)
index 0000000..d8812a3
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODR_bind_sortorderings.h"
+
+#import <EOControl/EOControl.h>
+#include <NGObjDOM/ODNamespaces.h>
+#include <DOM/EDOM.h>
+#include "common.h"
+
+
+@implementation ODR_bind_sortorderings
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if (![[_ctx objectForKey:ODR_SortOrderingContainerMode] boolValue])
+    return;
+  
+  if ([self boolFor:@"disabled" node:_node ctx:_ctx])
+    return;
+  
+  [_ctx setObject:[NSArray array] forKey:ODR_SortOrderingContainer];
+  
+  [self appendChildNodes:[_node childNodes]
+        toResponse:_response
+        inContext:_ctx];
+}
+
+@end
+
+@implementation ODR_bind_sortordering
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  EOSortOrdering *so        = nil;
+  NSArray        *orderings = nil;
+  NSString       *sortedKey = nil;
+  BOOL           isDesc;
+  SEL            sel;
+
+  if (![[_ctx objectForKey:ODR_SortOrderingContainerMode] boolValue])
+    return;
+
+  if (!(orderings = [_ctx objectForKey:ODR_SortOrderingContainer]))
+    return;
+
+  if (!(sortedKey = [self stringFor:@"key"  node:_node ctx:_ctx]))
+    return;
+
+  isDesc = [self boolFor:@"isdescending" node:_node ctx:_ctx];
+
+  sel       = (isDesc) ? EOCompareDescending : EOCompareAscending;
+  so        = [EOSortOrdering sortOrderingWithKey:sortedKey  selector:sel];
+  orderings = [orderings arrayByAddingObject:so];
+  
+  [_ctx setObject:orderings forKey:ODR_SortOrderingContainer];
+}
+
+@end
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_string.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_string.m
new file mode 100644 (file)
index 0000000..11e1820
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+  Attributes:
+  
+    value      - value to be generated
+    nilValue   - value to be generated if value is nil
+    dateformat - a date formatting spec
+    numberformat
+    escapehtml - bool (default: true)
+    insertbr   - bool (default: false)
+  
+  Usage:
+    <var:string value="name"/>
+*/
+
+@interface ODR_bind_string : ODNodeRenderer
+@end
+
+#include "common.h"
+#import <Foundation/NSDateFormatter.h>
+
+@implementation ODR_bind_string
+
+- (NSFormatter *)_formatterForNode:(id)_node inContext:(WOContext *)_ctx {
+  NSFormatter *formatter;
+  NSString    *fmt;
+  
+  if ((fmt = [self stringFor:@"dateformat" node:_node ctx:_ctx])) {
+    formatter = [[NSDateFormatter alloc]
+                                  initWithDateFormat:fmt
+                                  allowNaturalLanguage:NO];
+    AUTORELEASE(formatter);
+  }
+  else if ((fmt = [self stringFor:@"numberformat" node:_node ctx:_ctx])) {
+    formatter = [[NSNumberFormatter alloc] init];
+    AUTORELEASE(formatter);
+    [(NSNumberFormatter *)formatter setFormat:fmt];
+  }
+  else
+    formatter = nil;
+
+  return formatter;
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  id          value;
+  NSString    *string = nil;
+  BOOL        insertBR;
+  SEL         selector;
+  NSFormatter *formatter;
+  
+  if ((value = [self valueFor:@"value" node:_node ctx:_ctx]) == nil)
+    value = [self valueFor:@"nilValue" node:_node ctx:_ctx];
+  
+  formatter = [self _formatterForNode:_node inContext:_ctx];
+  
+  string = formatter
+    ? [formatter stringForObjectValue:value]
+    : [value stringValue];
+  
+  if (string == nil)
+    return;
+
+  string = [string stringValue];
+  
+  insertBR = [self boolFor:@"insertbr" node:_node ctx:_ctx];
+  
+  selector = ![self hasAttribute:@"escapehtml" node:_node ctx:_ctx]
+    ? @selector(appendContentHTMLString:)
+    : ([self boolFor:@"escapehtml" node:_node ctx:_ctx]
+       ? @selector(appendContentHTMLString:)
+       : @selector(appendContentString:));
+  
+  if (!insertBR) {
+    [_response performSelector:selector withObject:string];
+  }
+  else {
+    NSArray *lines;
+    unsigned i, count;
+    
+    lines = [string componentsSeparatedByString:@"\n"];
+    count = [lines count];
+    
+    for (i = 0; i < count; i++) {
+      NSString *line = [lines objectAtIndex:i];
+      
+      if (i != 0)
+        [_response appendContentString:@"<br />"];
+      
+      [_response performSelector:selector withObject:line];
+    }
+  }
+}
+
+@end /* ODR_bind_string */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_switch.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_switch.m
new file mode 100644 (file)
index 0000000..1c08819
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+*/
+
+@interface ODR_bind_switch : ODNodeRenderer
+@end
+
+#include <DOM/EDOM.h>
+#include "common.h"
+
+@implementation ODR_bind_switch
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+    [super takeValuesForNode:_node
+           fromRequest:_req
+           inContext:_ctx];
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  NSString *key;
+  id       node   = nil;
+  id       result = nil;
+
+  key = [[_ctx currentElementID] stringValue];
+
+  if (key) {
+    [_ctx consumeElementID]; // consume case-key
+    
+    if ([key isEqualToString:@"_default"]) {
+
+      node = [_node lookupQueryPath:@"-default"];
+      if ([node isKindOfClass:[NSArray class]])
+        node = [node lastObject];
+    }
+    else {
+      NSArray *children;
+      int     i, cnt;
+
+      children = (NSArray *)[_node childNodes];
+      cnt = [children count];
+      
+      for (i = 0; i < cnt; i++) {
+        NSString *childKey;
+        id       child;
+
+        child    = [children objectAtIndex:i];
+        childKey = [self stringFor:@"key" node:child ctx:_ctx];
+        if ([key isEqualToString:childKey]) {
+          node = child;
+          break;
+        }
+      }
+    }
+
+    if (node) {
+      result = [super invokeActionForNode:node
+                      fromRequest:_req
+                      inContext:_ctx];
+    }
+    else
+      NSLog(@"Warning! switch: couldn't find case element '%@'", key);
+
+    [_ctx deleteLastElementIDComponent]; // delete case-key
+
+  }
+  return nil;
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSArray        *selections = nil;
+  NSString       *selection  = nil;
+  NSArray        *cases      = nil;
+  NSMutableArray *children   = nil;
+  unsigned       i, cnt, j, cnt2;
+
+  if (![_node hasChildNodes])
+    return;
+
+  selections = [self  valueFor:@"selections" node:_node ctx:_ctx];
+  selection  = [self stringFor:@"selection"  node:_node ctx:_ctx];
+  cases      = [_node lookupQueryPath:@"-case"]; // case nodes
+  
+  if ((selection!=nil) && (selections == nil))
+    selections = [NSArray arrayWithObject:selection];
+
+  cnt  = [selections count]; // number of selections
+  cnt2 = [cases count];      // number of cases
+
+  children = [NSMutableArray arrayWithCapacity:cnt];
+  
+  for (i=0; i<cnt; i++) { // for all selections
+    NSString *key;
+
+    key = [selections objectAtIndex:i];
+    
+    for (j=0; j<cnt2; j++) { // and all cases
+      NSString *caseKey;
+      id       caseChild;
+
+      caseChild = [cases objectAtIndex:j];
+      caseKey   = [self stringFor:@"key" node:caseChild ctx:_ctx];
+      if ([caseKey isEqualToString:key]) {
+        [children addObject:caseChild];
+        break;
+      }
+    }
+  }
+
+  if ([children count] == 0) {
+    id tmp;
+
+    tmp = [_node lookupQueryPath:@"-default"];
+    if ([tmp isKindOfClass:[NSArray class]]) {
+      NSLog(@"Warning! switch: more than one 'default' section!");
+      tmp = [tmp lastObject];
+    }
+    [children addObject:tmp];
+  }
+  
+  for (i=0, cnt = [children count]; i<cnt; i++) {
+    NSString *key;
+    id       node;
+
+    node = [children objectAtIndex:i];
+    key = [self stringFor:@"key" node:node ctx:_ctx];
+    key = (key) ? key : @"_default";
+    
+    [_ctx appendElementIDComponent:key];
+    [super appendNode:node
+           toResponse:_response
+           inContext:_ctx];
+    
+    [_ctx deleteLastElementIDComponent]; // delete key
+  }
+}
+
+@end /* ODR_bind_switch */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tablecell.h b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tablecell.h
new file mode 100644 (file)
index 0000000..286cf79
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_Dynamic_tablecell_H__
+#define __NGObjDOM_Dynamic_tablecell_H__
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+@interface ODR_bind_tablecell : ODNodeRenderer
+{
+}
+- (void)appendSortIcon:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+- (void)appendTitle:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+@end
+
+#endif /* __NGObjDOM_Dynamic_tablecell_H__ */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tablecell.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tablecell.m
new file mode 100644 (file)
index 0000000..64f686b
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODR_bind_tablecell.h"
+#include "ODR_bind_tableview.h"
+
+#include <DOM/EDOM.h>
+#include "common.h"
+
+@implementation ODR_bind_tablecell
+
+static NSNumber *YesNumber = nil;
+static NSNumber *NoNumber  = nil;
+
++ (void)initialize {
+  if (YesNumber == nil) YesNumber = [[NSNumber numberWithBool:YES] retain];
+  if (NoNumber  == nil) NoNumber  = [[NSNumber numberWithBool:NO]  retain];
+}
+
+- (void)appendSortIcon:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString    *icon = nil;
+  NSString    *nav  = nil;
+  BOOL        doForm = [_ctx isInForm];
+  NSString    *sortedKey;
+  NSString    *label;
+  NSString    *sk;
+  int         sortDir;
+
+  sortedKey = [_ctx objectForKey:ODRTableView_SORTEDKEY];
+  sk        = [self stringFor:@"sortkey" node:_node ctx:_ctx];
+  
+  label     = [self stringFor:@"sortlabel" node:_node ctx:_ctx];
+  label     = (label) ? label : ODRTableLabelForKey(@"sort", _ctx);
+
+  if (sk == nil)
+    return;
+
+  if (![sk isEqualToString:sortedKey])
+    sortDir = 0;
+  else if ( [_ctx objectForKey:ODRTableView_ISDESCENDING] == nil ||
+           [[_ctx objectForKey:ODRTableView_ISDESCENDING] boolValue])
+    sortDir = -1;
+  else
+    sortDir = 1;
+  
+  switch (sortDir) {
+    case  1: nav = @"down"; break;
+    case  0: nav = @"non";  break;
+    case -1: nav = @"up";   break;
+  }
+  switch (sortDir) {
+    case  1:
+      icon = [self stringFor:@"downwardsorticon" node:_node ctx:_ctx];
+      if ([icon length] == 0)
+        icon = [_ctx objectForKey:ODRTableView_downwardIcon];
+      break;
+    case  0:
+      icon = [self stringFor:@"nonsorticon"      node:_node ctx:_ctx];
+      if ([icon length] == 0)
+        icon = [_ctx objectForKey:ODRTableView_nonSortIcon];
+      break;
+    case -1:
+      icon = [self stringFor:@"upwardsorticon"   node:_node ctx:_ctx];
+      if ([icon length] == 0)
+        icon = [_ctx objectForKey:ODRTableView_upwardIcon];
+      break;
+  }
+
+#if DEBUG && 0
+  if (icon == nil) {
+    NSLog(@"%s: DID NOT FIND SORTICON (%i), ctx is %@\n  vars: %@",
+          __PRETTY_FUNCTION__,
+          sortDir, _ctx, [_ctx variableDictionary]);
+  }
+#endif
+
+#if 0
+  if (!ODRUriOfResource(icon,_ctx)) {
+    switch (sortDir) {
+      case  1: icon = [_ctx objectForKey:ODRTableView_downwardIcon]; break;
+      case  0: icon = [_ctx objectForKey:ODRTableView_nonSortIcon];  break;
+      case -1: icon = [_ctx objectForKey:ODRTableView_upwardIcon];   break;
+    }
+  }
+#endif
+  
+  icon   = ODRUriOfResource(icon, _ctx);
+  doForm = doForm && (icon != nil);
+
+  // append something like that: sort.name.down
+  [_ctx appendElementIDComponent:@"sort"];
+  [_ctx appendElementIDComponent:sk];     // remember sortKey
+  [_ctx appendElementIDComponent:nav];    // remember sortDirection
+
+  // append as submit button
+  if (doForm)
+    ODRAppendButton(_response, [_ctx elementID], icon, label);
+
+  /* append as hyperlink */
+  else {
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentString:@"\">"];
+    
+    if (icon) {
+      ODRAppendImage(_response, nil, icon, label);
+    }
+    else {
+      switch (sortDir) {
+        case  1: [_response appendContentString:@"&uarr;"]; break;
+        case  0: [_response appendContentString:@"-"]; break;
+        case -1: [_response appendContentString:@"&darr;"]; break;
+      }
+    }
+    [_response appendContentString:@"</a>"];
+  }
+  [_ctx deleteLastElementIDComponent]; // delete sortDirection
+  [_ctx deleteLastElementIDComponent]; // delete sortKey
+  [_ctx deleteLastElementIDComponent]; // delete @"sort"
+
+  return;
+}
+
+- (void)appendTitle:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *title;
+  NSString *tC, *tF, *tS; // text font attrtibutes
+  BOOL     hasFont;
+
+  tC  = [_ctx objectForKey:ODRTableView_fontColor];
+  tF  = [_ctx objectForKey:ODRTableView_fontFace];
+  tS  = [_ctx objectForKey:ODRTableView_fontSize];
+
+  hasFont = (tC || tF || tS) ? YES : NO;
+  
+  title   = [self stringFor:@"title" node:_node ctx:_ctx];
+
+  if (title) {
+    if (hasFont)
+      ODRAppendFont(_response, tC, tF, tS);                      //   <FONT...>
+   
+    [_response appendContentString:@" <b>"];
+    [_response appendContentString:title];
+    [_response appendContentString:@"</b>"];
+
+    if (hasFont)
+      [_response appendContentString:@"</font>"];               //   </FONT>
+  }
+}
+
+/* --- responder --- */
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  NSString *k;
+  
+  k = [self stringFor:@"sortkey" node:_node ctx:_ctx];
+
+  if (k && [[_ctx objectForKey:ODRTableView_HeaderMode] boolValue]) {
+    NSString *tmp;
+    tmp = [[_ctx elementID] stringByAppendingFormat:@".sort.%@.", k];
+
+    if ([_req formValueForKey:[tmp stringByAppendingString:@"down.x"]]) {
+      [_ctx addActiveFormElement:self];
+      [_ctx setRequestSenderID:[tmp stringByAppendingString:@"down"]];
+    }
+    else if ([_req formValueForKey:[tmp stringByAppendingString:@"up.x"]]) {
+      [_ctx addActiveFormElement:self];
+      [_ctx setRequestSenderID:[tmp stringByAppendingString:@"up"]];
+    }
+    else if ([_req formValueForKey:[tmp stringByAppendingString:@"non.x"]]) {
+      [_ctx addActiveFormElement:self];
+      [_ctx setRequestSenderID:[tmp stringByAppendingString:@"non"]];
+    }
+    else
+      [super takeValuesForNode:_node  fromRequest:_req inContext:_ctx];
+  }
+  else
+    [super takeValuesForNode:_node  fromRequest:_req inContext:_ctx];
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  id          result = nil;
+  NSString    *k;
+
+#if DEBUG && 0
+  NSLog(@"%s:    invoke on tablecell %@ (eid=%@, sid=%@)", __PRETTY_FUNCTION__,
+        _node, [_ctx elementID], [_ctx senderID]);
+#endif
+
+  k   = [self stringFor:@"sortkey" node:_node ctx:_ctx];
+  if ([[_ctx currentElementID] isEqual:@"sort"] && k != nil) {
+    NSString *tmp;
+    
+    [_ctx consumeElementID];                 // consume "sort"
+    [_ctx appendElementIDComponent:@"sort"]; // append  "sort"
+    
+    tmp = [_ctx currentElementID];
+    if (tmp != nil && [tmp isEqualToString:k]) {
+      BOOL doNegate = [self boolFor:@"negatesort" node:_node ctx:_ctx];
+
+      [_ctx consumeElementID];               // consume sortKey
+      [_ctx appendElementIDComponent:k];     // append  sortKey
+      [_ctx setObject:k forKey:ODRTableView_SORTEDKEY];
+
+      tmp = [_ctx currentElementID];
+      
+      if ([tmp isEqualToString:@"down"])
+        [_ctx setObject:YesNumber forKey:ODRTableView_ISDESCENDING];
+      else if ([tmp isEqualToString:@"up"])
+        [_ctx setObject:NoNumber forKey:ODRTableView_ISDESCENDING];
+      else if ([tmp isEqualToString:@"non"])
+        [_ctx setObject:[NSNumber numberWithBool:doNegate]
+                 forKey:ODRTableView_ISDESCENDING];
+      else {
+        [_ctx removeObjectForKey:ODRTableView_ISDESCENDING];
+        [_ctx removeObjectForKey:ODRTableView_SORTEDKEY];
+      }
+      [_ctx deleteLastElementIDComponent];
+    }
+    [_ctx deleteLastElementIDComponent];
+  }
+  else
+    result = [self invokeActionForChildNodes:[_node childNodes]
+                   fromRequest:_req
+                   inContext:_ctx];
+  
+  return result;
+}
+
+@end /* ODR_bind_tablecell */
+
+
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tabledata.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tabledata.m
new file mode 100644 (file)
index 0000000..d265111
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODR_bind_tablecell.h"
+
+@interface ODR_bind_td : ODR_bind_tablecell
+{
+}
+@end /* ODR_bind_td */
+
+#include "ODR_bind_tableview.h"
+#include "common.h"
+
+@implementation ODR_bind_td
+
+- (void)_collectData:(id)_node inContext:(WOContext *)_ctx {
+  NSMutableArray   *infos;
+  ODRTableViewInfo *info;
+  NSString         *key;
+  NSString         *sortedKey;
+
+  infos     = [_ctx objectForKey:ODRTableView_INFOS];
+  key       = [self stringFor:@"sortkey" node:_node ctx:_ctx];
+  sortedKey = [_ctx objectForKey:ODRTableView_SORTEDKEY];
+
+  if (infos == nil) {
+    infos = [NSMutableArray array];
+    [_ctx setObject:infos forKey:ODRTableView_INFOS];
+  }
+  info = [[ODRTableViewInfo allocWithZone:[self zone]] init];
+  info->rowSpan  = 1;
+  info->isGroup  = [self boolFor:@"isgroup" node:_node ctx:_ctx];
+  info->isSorted = (key != nil && sortedKey != nil && [key isEqual:sortedKey]);
+
+  [infos addObject:info];
+  AUTORELEASE(info);
+}
+
+- (void)_appendHeader:(id)_node
+        toResponse:(WOResponse *)_response
+        inContext:(WOContext *)_ctx
+{
+  NSString    *bg; // bgcolor
+
+  bg = [_ctx objectForKey:ODRTableView_headerColor];
+
+  ODRAppendTD(_response, @"left", nil, bg, nil);                 // <TD...>
+  [_response appendContentString:@"<nobr>"];
+  
+  [self appendSortIcon:_node toResponse:_response inContext:_ctx];
+  
+  [self appendTitle:_node   toResponse:_response inContext:_ctx];
+
+  [_response appendContentString:@"</nobr>"];
+  [_response appendContentString:@"</td>\n"];                   // </TD>
+}
+
+- (void)_appendStringContent:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *s;
+  
+  /* add value */
+  
+  if ([self hasAttribute:@"value" node:_node ctx:_ctx]) {
+    NSFormatter *fmt;
+    id          obj;
+    
+    obj = [self valueFor:@"value" node:_node ctx:_ctx];
+
+    if ([self hasAttribute:@"numberformat" node:_node ctx:_ctx]) {
+      fmt = AUTORELEASE([[NSNumberFormatter alloc] init]);
+      [(NSNumberFormatter *)fmt setFormat:
+                    [self valueFor:@"numberformat" node:_node ctx:_ctx]];
+    }
+    else if ([self hasAttribute:@"dateformat" node:_node ctx:_ctx]) {
+      fmt = [[NSDateFormatter alloc]
+                          initWithDateFormat:
+                          [self valueFor:@"dateformat" node:_node ctx:_ctx]
+                          allowNaturalLanguage:NO];
+      fmt = AUTORELEASE(fmt);
+    }
+    else if ([self hasAttribute:@"formatter" node:_node ctx:_ctx]) {
+      fmt = [self valueFor:@"formatter" node:_node ctx:_ctx];
+#if DEBUG
+      if (fmt && ![fmt respondsToSelector:@selector(stringForObjectValue:)]) {
+        [[_ctx component] logWithFormat:
+                          @"invalid formatter determined by %@", fmt];
+      }
+#endif
+    }
+    else
+      fmt = nil;
+    
+    if (fmt)
+      obj = [fmt stringForObjectValue:obj];
+    
+    s = [obj stringValue];
+    
+    if (s) [_response appendContentHTMLString:s];
+  }
+  
+  /* add string */
+  
+  if ([self hasAttribute:@"string" node:_node ctx:_ctx]) {
+    s = [self stringFor:@"string" node:_node ctx:_ctx];
+    [_response appendContentHTMLString:s];
+  }
+}
+
+- (void)_appendData:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  info:(ODRTableViewInfo *)_info
+{
+  if (!_info->isGroup) {
+    NSString    *bg  = [self stringFor:@"bgcolor" node:_node ctx:_ctx];
+  
+    if (bg == nil) {
+      bg = (_info->isEven)
+        ? [_ctx objectForKey:ODRTableView_evenColor]
+        : [_ctx objectForKey:ODRTableView_oddColor];
+    }
+    [_response appendContentString:@"<td bgcolor=\""];          // <TD...>
+    [_response appendContentString:bg];
+    if (_info->rowSpan > 1) {
+      [_response appendContentString:@"\" rowspan=\""];
+      [_response appendContentString:
+                 [NSString stringWithFormat:@"%i", _info->rowSpan]];
+    }
+    [_response appendContentCharacter:'"'];
+    [_response appendContentCharacter:'>'];
+    
+    [super appendChildNodes:[_node childNodes]
+           toResponse:_response
+           inContext:_ctx];
+
+    [self _appendStringContent:_node toResponse:_response inContext:_ctx];
+
+    [_response appendContentString:@"</td>\n"];                  // </TD>
+  }
+}
+
+/* responder */
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if ([_ctx objectForKey:ODRTableView_CollectMode]) {
+    [self _collectData:_node inContext:_ctx];
+    return;
+  }
+  
+  if ([_ctx objectForKey:ODRTableView_HeaderMode] &&
+      [self hasAttribute:@"title" node:_node ctx:_ctx]) {
+    [self _appendHeader:_node toResponse:_response inContext:_ctx];
+  }
+  else if ([[_ctx objectForKey:ODRTableView_DataMode] boolValue]) {
+    NSMutableArray *infos = nil;
+
+    infos  = [_ctx objectForKey:ODRTableView_INFOS];
+
+    if (infos != nil && [infos count] > 0) {
+      [self _appendData:_node
+            toResponse:_response
+            inContext:_ctx
+            info:[infos objectAtIndex:0]];
+      [infos removeObjectAtIndex:0];
+    }
+  }
+}
+
+@end /* ODR_bind_td */
+
+
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableheader.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableheader.m
new file mode 100644 (file)
index 0000000..63dc915
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODR_bind_tablecell.h"
+
+@interface ODR_bind_th : ODR_bind_tablecell
+{
+}
+@end /* ODR_bind_th */
+
+#include "ODR_bind_tableview.h"
+#include "common.h"
+
+@implementation ODR_bind_th
+
+- (void)appendNode:(id)_node
+        toResponse:(WOResponse *)_response
+        inContext:(WOContext *)_ctx
+{
+  if ([[_ctx objectForKey:ODRTableView_HeaderMode] boolValue]) {
+    NSString *bg  = nil;
+
+    bg  = [self stringFor:@"bgColor" node:_node ctx:_ctx];
+
+    if (!bg)
+      bg = [_ctx objectForKey:ODRTableView_headerColor];
+  
+    [_response appendContentString:@"<td"];
+    if (bg) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:bg];
+      [_response appendContentCharacter:'"'];
+    }
+
+    [_response appendContentString:@"><nobr>"];
+    [self appendSortIcon:_node toResponse:_response inContext:_ctx];
+    [self appendTitle:_node toResponse:_response inContext:_ctx];
+    [self appendChildNodes:[_node childNodes]
+          toResponse:_response
+          inContext:_ctx];
+  
+    [_response appendContentString:@"</nobr>"];
+    [_response appendContentString:@"</td>\n"];
+  }
+}
+
+@end /* ODR_bind_th */
+
+
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableview+Private.h b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableview+Private.h
new file mode 100644 (file)
index 0000000..bdbc7e0
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_Dynamic_tableview_Private_H__
+#define __NGObjDOM_Dynamic_tableview_Private_H__
+
+#include "ODR_bind_tableview.h"
+
+@interface ODR_bind_tableview(Private_Rendering)
+- (void)_appendTitle:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+
+- (void)_appendFooter:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+
+- (void)_appendData:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+- (void)_appendHeader:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+
+- (void)_appendBatchResizeButtons:(id)_node
+  toResponse:(WOResponse *)_response
+  rowSpan:(unsigned int)_rowSpan
+  actionUrl:(NSString *)_actionUrl
+  inContext:(WOContext *)_ctx;
+
+- (void)_appendCheckboxToResponse:(WOResponse *)_response
+  ctx:(WOContext *)_ctx
+  value:(NSString *)_value
+  isChecked:(BOOL)_isChecked;
+
+- (void)_applyIdentifier:(NSString *)_id node:(id)_node ctx:(WOContext *)_ctx;
+- (void)_applyItemForIndex:(int)_i node:(id)_node ctx:(WOContext *)_ctx;
+@end
+
+@interface ODR_bind_tableview(Private_ActionHandling)
+
+- (NSArray *)_sortedArrayOfNode:(id)_node
+                      inContext:(WOContext *)_ctx
+                          fetch:(BOOL)_doFetch;
+
+- (void)_handleSortAction:(id)_node inContext:(WOContext *)_ctx;
+- (id)_handleFirstButton:(id)_node inContext:(WOContext *)_ctx;
+- (id)_handlePreviousButton:(id)_node inContext:(WOContext *)_ctx;
+- (id)_handleNextButton:(id)_node inContext:(WOContext *)_ctx;
+- (id)_handleLastButton:(id)_node inContext:(WOContext *)_ctx;
+
+- (id)increaseAutoScrollHeight:(id)_node inContext:(WOContext *)_ctx;
+- (id)decreaseAutoScrollHeight:(id)_node inContext:(WOContext *)_ctx;
+- (id)increaseBatchSize:(id)_node inContext:(WOContext *)_ctx;
+- (id)decreaseBatchSize:(id)_node inContext:(WOContext *)_ctx;
+
+- (void)takeValuesForNode:(id)_node
+              fromRequest:(WORequest *)_request
+                 forBatch:(int)_batch
+               selections:(NSMutableArray *)_selArray
+                inContext:(WOContext *)_ctx;
+@end
+
+@interface ODR_bind_tableview(Private_JavaScriptAdditions)
+
+- (void)_appendGroupCollapseScript:(WOResponse *)_resp
+  inContext:(WOContext *)_ctx;
+
+- (void)jsButton:(WOResponse *)_resp   ctx:(WOContext *)_ctx
+            name:(NSString *)_name  button:(NSString *)_button;
+
+- (void)appendJavaScript:(WOResponse *)_resp inContext:(WOContext *)_ctx;
+
+- (void)_appendTableContentAsScript:(id)_node
+  toResponse:(WOResponse *)_resp
+  inContext:(WOContext *)_ctx;
+
+- (void)_appendScriptLink:(WOResponse *)_response name:(NSString *)_name;
+
+@end /* ODR_bind_tableview(Private_JavaScriptAdditions) */
+
+@interface ODR_bind_tableview(Private_Grouping)
+
+- (BOOL)_showGroupAtIndex:(int)_idx node:(id)_node ctx:(WOContext *)_ctx;
+- (void)_setShowGroup:(BOOL)_flag
+              atIndex:(int)_idx
+                 node:(id)_node
+                  ctx:(WOContext *)_ctx;
+
+- (id)_invokeGrouping:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx;
+
+- (void)_appendGroupTitle:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  infos:(NSMutableArray *)_infos
+  actionUrl:(NSString *)_actionUrl
+  rowSpan:(unsigned)_rowSpan
+  groupId:(NSString *)_groupId
+  index:(int)_idx;
+
+@end /* ODR_bind_tableview(Private_Grouping) */
+
+
+
+#endif /* __NGObjDOM_Dynamic_tableview_Private_H__ */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableview+Private.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableview+Private.m
new file mode 100644 (file)
index 0000000..c1edb53
--- /dev/null
@@ -0,0 +1,1705 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+
+  elementID structure:
+
+  dataSection:
+
+    ["data"].[batchSize].[identifier|index]
+
+*/
+
+#include "ODR_bind_tableview+Private.h"
+
+//#define PROFILE 1
+
+#import <EOControl/EOControl.h>
+#include <NGObjDOM/ODNamespaces.h>
+#include <DOM/EDOM.h>
+#include "common.h"
+#include "ODR_bind_sortorderings.h"
+
+@implementation ODR_bind_tableview(Private_Rendering)
+
+static inline void _rawAdd(WOResponse *response, NSString *s) {
+  /* appendContentString: with selector caching */
+#define sel @selector(appendContentString:)
+  static IMP   add       = NULL;
+  static Class lastClass = Nil;
+  
+  if ((response == nil) || (s == nil)) return;
+  
+  if ((*(Class *)response) == lastClass) {
+    if (add)
+      add(response, sel, s);
+    else
+      [response appendContentString:s];
+  }
+  else {
+    lastClass = (*(Class *)response);
+    if ((add = [response methodForSelector:sel]))
+      add(response, sel, s);
+    else
+      [response appendContentString:s];
+  }
+#undef sel
+}
+
+- (void)_applyIdentifier:(NSString *)_id node:(id)_node ctx:(WOContext *)_ctx {
+  unsigned count;
+  BEGIN_PROFILE;
+  
+  count = [self->list count];
+
+  if (count > 0) {
+    unsigned i;
+
+    /* find subelement for unique id */
+    
+    for (i = 0; i < count; i++) {
+      NSString *ident;
+      
+      if ([self isSettable:@"index" node:_node ctx:_ctx])
+        [self setInt:i for:@"index" node:_node ctx:_ctx];
+
+      if ([self isSettable:@"item" node:_node ctx:_ctx]) {
+        [self setValue:[self->list objectAtIndex:i] for:@"item"
+                  node:_node                        ctx:_ctx];
+
+      }
+      if ([self isSettable:@"previousitem" node:_node ctx:_ctx]) {
+        [self setValue:(i > self->state.firstIndex)
+              ? [self->list objectAtIndex:i-1] : nil
+              for:@"previousitem" node:_node ctx:_ctx];
+      }
+      if ([self isSettable:@"previousindex" node:_node ctx:_ctx])
+        [self setInt:(i-1) for:@"previousindex" node:_node ctx:_ctx];
+
+      ident = [self stringFor:@"identifier" node:_node ctx:_ctx];
+
+      if ([ident isEqualToString:_id]) {
+        /* found subelement with unique id */
+        return;
+      }
+    }
+    
+    [[_ctx component] logWithFormat:
+          @"tableview: array did change, "
+          @"unique-id isn't contained."];
+    if ([self isSettable:@"item" node:_node ctx:_ctx])
+      [self setValue:nil for:@"item"  node:_node ctx:_ctx];
+    if ([self isSettable:@"index" node:_node ctx:_ctx])
+      [self setValue:0   for:@"index" node:_node ctx:_ctx];
+  }
+  
+  END_PROFILE;
+}
+
+- (void)_applyItemForIndex:(int)_i node:(id)_node ctx:(WOContext *)_ctx {
+  unsigned count;
+  BEGIN_PROFILE;
+  
+  count = [self->list count];
+  
+  if ([self isSettable:@"index" node:_node ctx:_ctx])
+    [self setInt:_i for:@"index" node:_node ctx:_ctx];
+  
+  if ([self isSettable:@"item" node:_node ctx:_ctx]) {
+    id obj;
+
+    obj = ((count > 0) && ((int)count > _i))
+      ? [self->list objectAtIndex:_i]
+      : nil;
+    
+    [self setValue:obj for:@"item" node:_node ctx:_ctx];
+  }
+  
+  if ([self isSettable:@"previousitem" node:_node ctx:_ctx]) {
+    id obj;
+    
+    if (_i > (int)self->state.firstIndex) {
+      obj = ((count > 0) && ((int)count > (_i - 1)))
+        ? [self->list objectAtIndex:(_i - 1)]
+        : nil;
+    }
+    else
+      obj = nil;
+    
+    [self setValue:obj for:@"previousitem" node:_node ctx:_ctx];
+  }
+  
+  if ([self isSettable:@"previousindex" node:_node ctx:_ctx])
+    [self setInt:(_i - 1) for:@"previousindex" node:_node ctx:_ctx];
+  
+  END_PROFILE;
+}
+
+- (NSString *)labelForKey:(NSString *)_key ctx:(WOContext *)_ctx {
+  NSString *key;
+  key = [NSString stringWithFormat:@"ODRTableView_%@Label", _key];
+  return [_ctx objectForKey:key];
+}
+
+- (void)_appendNav:(NSString *)_nav isBlind:(BOOL)_isBlind
+  toResponse:(WOResponse *)_response inContext:(WOContext *)_ctx
+{
+  NSString *imgUri = nil;
+  NSString *label  = nil;
+  BOOL     doForm;
+  BEGIN_PROFILE;
+
+  doForm  = [_ctx isInForm];
+  
+  imgUri = [ODRTableView_ stringByAppendingString:_nav];
+  imgUri = [imgUri stringByAppendingString:(_isBlind) ? @"_blind" : @""];
+  imgUri = [_ctx objectForKey:imgUri];
+  imgUri = ODRUriOfResource(imgUri,_ctx);
+
+  label  = [self labelForKey:_nav ctx:_ctx];
+  
+  _rawAdd(_response, @"<td valign='middle'>");
+  // append as submit button
+  if (doForm && !_isBlind && self->use.scriptScrolling && (imgUri != nil)) {
+    [_ctx appendElementIDComponent:_nav];
+    ODRAppendButton(_response, [_ctx elementID], imgUri, label);
+    [_ctx deleteLastElementIDComponent];
+  }
+  else {
+    /* open anker */
+    if (!_isBlind || self->use.scriptScrolling) {
+      [_ctx appendElementIDComponent:_nav];
+      _rawAdd(_response, @"<a href=\"");
+      if (self->use.scriptScrolling)
+        [self _appendScriptLink:_response name:_nav];
+      else
+        _rawAdd(_response, [_ctx componentActionURL]);
+      _rawAdd(_response, @"\">");
+    }
+    if (imgUri == nil) {
+      [_response appendContentCharacter:'['];
+      _rawAdd(_response, label);
+      [_response appendContentCharacter:']'];
+    }
+    else {
+      ODRAppendImage(_response,
+                     [NSString stringWithFormat:@"%@PageImg%@",
+                               _nav, self->scriptID], // ??? 
+                     imgUri,
+                     label);
+    }
+    /* close anker */
+    if (!_isBlind || self->use.scriptScrolling) {
+      _rawAdd(_response, @"</a>");
+      [_ctx deleteLastElementIDComponent];
+    }
+    _rawAdd(_response, @"</td>");
+  }
+  END_PROFILE;
+}
+
+- (void)_appendNavigation:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSArray *buttons;
+  int     batch, batchCount;
+  BOOL    isFirstBlind, isPreviousBlind, isNextBlind, isLastBlind, didTD;
+  
+  batch      = self->state.currentBatch;
+  batchCount = self->state.batchCount;
+  didTD      = NO;
+
+  isFirstBlind    = (batch < 2);
+  isPreviousBlind = (batch < 2);
+  isNextBlind     = ((batchCount-1) < batch);
+  isLastBlind     = ((batchCount-1) < batch);
+
+  _rawAdd(_response, 
+          @"<table border='0' cellspacing='0' cellpadding='0'><tr>");
+
+  if (!(isFirstBlind && isPreviousBlind && isNextBlind && isLastBlind)) {
+    [self _appendNav:@"first"    isBlind:isFirstBlind
+          toResponse:_response   inContext:_ctx];
+    [self _appendNav:@"previous" isBlind:isPreviousBlind
+          toResponse:_response   inContext:_ctx];
+    didTD = YES;
+  }
+
+  /* append extra buttons */
+  buttons = ODRLookupQueryPath(_node, @"-tbutton");
+  if ([buttons count]) {
+    _rawAdd(_response, @"<td valign='middle'>");
+    [_ctx appendElementIDComponent:@"button"];
+    [_ctx setObject:@"YES" forKey:ODRTableView_ButtonMode];
+    [super appendChildNodes:buttons toResponse:_response inContext:_ctx];
+    [_ctx removeObjectForKey:ODRTableView_ButtonMode];
+    [_ctx deleteLastElementIDComponent];
+    _rawAdd(_response, @"</td>");
+    didTD = YES;
+  }
+  
+  if (!(isFirstBlind && isPreviousBlind && isNextBlind && isLastBlind)) {
+    [self _appendNav:@"next"     isBlind:isNextBlind
+          toResponse:_response  inContext:_ctx];
+    [self _appendNav:@"last"     isBlind:isLastBlind
+          toResponse:_response  inContext:_ctx];
+    didTD = YES;
+  }
+
+  if (!didTD)
+    _rawAdd(_response, @"<td>&nbsp;</td>");
+  
+  _rawAdd(_response, @"</tr></table>");
+}
+
+- (void)_appendTitle:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *bg;
+  NSArray  *titles;
+
+  bg = [_ctx objectForKey:ODRTableView_titleColor];
+  titles = ODRLookupQueryPath(_node, @"-ttitle");
+  
+  _rawAdd(_response, @"<tr><td>");
+
+  /* open title bar*/
+  _rawAdd(_response, 
+             @"<table border='0' width='100%' cellpadding='0' cellspacing='0'>"
+             @"<tr>");
+
+  /* append title */
+  [_ctx appendElementIDComponent:@"title"];
+  [_ctx setObject:@"YES" forKey:ODRTableView_TitleMode];
+  ODRAppendTD(_response, @"left", @"middle", bg, nil);               // <TD..>
+  if ([titles count] > 0)
+    [super appendChildNodes:titles toResponse:_response inContext:_ctx];
+  else
+    _rawAdd(_response, @"&nbsp;");
+  
+  _rawAdd(_response, @"</td>");                        // </TD>
+  [_ctx deleteLastElementIDComponent]; // delete "title"
+  [_ctx removeObjectForKey:ODRTableView_TitleMode];
+
+  /* append navigation + extra buttons */
+  ODRAppendTD(_response, @"right", @"middle", bg, nil);              // <TD..>
+  [self _appendNavigation:_node toResponse:_response inContext:_ctx];
+  _rawAdd(_response, @"</td>");                        // </TD>
+  
+  /* close title bar*/
+  _rawAdd(_response, @"</tr></table>");
+  _rawAdd(_response, @"</td></tr>");
+}
+
+- (void)_appendHeader:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  [_ctx setObject:[self stringFor:@"sortedkey" node:_node ctx:_ctx]
+        forKey:ODRTableView_SORTEDKEY];
+  
+  [_ctx setObject:[NSNumber numberWithBool:
+                            [self boolFor:@"isdescending" node:_node ctx:_ctx]]
+        forKey:ODRTableView_ISDESCENDING];
+
+  [_ctx setObject:@"YES" forKey:ODRTableView_HeaderMode];
+  _rawAdd(_response, @"<tr>");
+
+  [_ctx appendElementIDComponent:@"header"];
+  // append batchNumber
+  {
+    NSString *bn;
+    bn = [self stringForInt:self->state.currentBatch];
+    //bn = [NSString stringWithFormat:@"%d", self->state.currentBatch];
+    [_ctx appendElementIDComponent:bn];
+  }
+  
+  if (self->use.checkBoxes) {
+    _rawAdd(_response, 
+               @"<td  width=\"1%\" align=\"center\" bgcolor=\"");
+    _rawAdd(_response, 
+               [_ctx objectForKey:ODRTableView_headerColor]);
+    _rawAdd(_response, @"\">");
+
+    [_ctx appendElementIDComponent:@"_sa"];
+    [self _appendCheckboxToResponse:_response
+          ctx:_ctx
+          value:@"selectAll"
+          isChecked:[self boolFor:@"selectall" node:_node ctx:_ctx]];
+
+    [_ctx deleteLastElementIDComponent]; // delete "_sa" ==> SelectAll
+
+    _rawAdd(_response, @"</td>");
+  }
+
+  [self appendChildNodes:[_node childNodes]
+        toResponse:_response
+        inContext:_ctx];
+  
+  [_ctx deleteLastElementIDComponent]; // delete batchNumber
+  [_ctx deleteLastElementIDComponent]; // delete "header"
+
+  if (self->use.batchResizeButtons) {
+    int cnt;
+
+    cnt = (self->state.lastIndex - self->state.firstIndex + 1);
+
+    if (cnt == (int)self->state.batchSize && !self->use.overflow) {
+      _rawAdd(_response, @"<td width='1%'");
+      if ([_ctx objectForKey:ODRTableView_headerColor]) {
+        _rawAdd(_response, @" bgcolor='");
+        _rawAdd(_response, 
+                   [_ctx objectForKey:ODRTableView_headerColor]);
+        _rawAdd(_response, @"'");
+      }
+      _rawAdd(_response, @"></td>");
+    }
+  }
+  
+  _rawAdd(_response, @"</tr>");
+  [_ctx removeObjectForKey:ODRTableView_HeaderMode];
+  [_ctx removeObjectForKey:ODRTableView_SORTEDKEY];
+  [_ctx removeObjectForKey:ODRTableView_ISDESCENDING];
+}
+
+
+- (NSArray *)_collectData:(id)_node inContext:(WOContext *)_ctx {
+  NSAutoreleasePool *pool;
+  NSArray           *children  = nil;
+  NSMutableArray    *matrix    = nil;
+  NSMutableArray    *headInfos = nil;
+  NSString          *k         = nil;
+  id                oldGroup   = nil;
+  int               i, first, last;
+  int               sortedHeadIndex = -2;
+  BEGIN_PROFILE;
+  
+  pool   = [[NSAutoreleasePool alloc] init];
+  k      = [self stringFor:@"sortedkey" node:_node ctx:_ctx];
+
+  first  = self->state.firstIndex;
+  last   = self->state.lastIndex;
+  matrix = [NSMutableArray arrayWithCapacity:last-first+1];
+
+  [_ctx setObject:k      forKey:ODRTableView_SORTEDKEY];
+  [_ctx setObject:@"YES" forKey:ODRTableView_CollectMode];
+
+  self->state.groupCount = 0;
+
+  children = (NSArray *)[_node childNodes];
+  
+  i = ([children count] > 0) ? first : last+1;
+  i = first;
+    
+  for (; i<=last; i++) {
+    NSMutableArray *infos = nil;
+    NSString       *tmp   = nil;
+
+    [self _applyItemForIndex:i node:_node ctx:_ctx];
+    
+    [_ctx removeObjectForKey:ODRTableView_INFOS];
+    [self appendChildNodes:children
+          toResponse:nil
+          inContext:_ctx];
+    infos = [_ctx objectForKey:ODRTableView_INFOS];
+
+    NSAssert(infos != nil, @"Infos is nil.");
+
+    if (headInfos == nil) {
+      unsigned j, cnt;
+      headInfos = [[NSMutableArray alloc] initWithArray:infos];
+
+      for (j=0, cnt=[headInfos count]; j<cnt; j++) {
+        ODRTableViewInfo *headInfo = [headInfos objectAtIndex:j];
+        
+        headInfo->isEven = (((i-first) % 2) == 0) ? YES : NO;
+      }
+    }
+    else {
+      unsigned j, cnt;
+      BOOL     isEven = NO;
+
+      cnt = [infos count];
+      
+      if (sortedHeadIndex == -2) { // first time
+        for (j=0; j < cnt; j++) {
+          ODRTableViewInfo *info;
+
+          info = [infos objectAtIndex:j];
+          if (info->isSorted) {
+            sortedHeadIndex = j;
+            break;
+          }
+        }
+        sortedHeadIndex = (sortedHeadIndex < 0) ? -1 : sortedHeadIndex;
+      }
+
+      if (cnt) {
+        ODRTableViewInfo *headInfo;
+        ODRTableViewInfo *info;
+
+        if (sortedHeadIndex >= 0) {
+          NSAssert(sortedHeadIndex < (int)cnt, 
+                   @"SortedHeadIndex out of range!!!");
+          headInfo = [headInfos objectAtIndex:sortedHeadIndex];
+          info     = [infos     objectAtIndex:sortedHeadIndex];
+          isEven = (!info->isGroup) ? !headInfo->isEven : headInfo->isEven;
+        }
+        else { // sortedHeadIndex == -1 --> no column is sorted
+          headInfo = [headInfos lastObject];
+          isEven = !headInfo->isEven;
+        }
+      }
+
+      for (j = 0; j < cnt; j++) {
+        ODRTableViewInfo *info     = [infos     objectAtIndex:j];
+        ODRTableViewInfo *headInfo = [headInfos objectAtIndex:j];
+
+        if (!info->isGroup || ((int)j != sortedHeadIndex)) {
+          info->isEven  = isEven;
+          info->isGroup = NO;
+          [headInfos replaceObjectAtIndex:j withObject:info];
+        }
+        else
+          headInfo->rowSpan++;
+      }
+    }
+
+    // ??? tmp = [self valueFor:@"currentGroup" node:_node ctx:_ctx];
+    if (self->indexToGrouppath) {
+      tmp = ((int)[self->indexToGrouppath count] > i)
+        ? [self->indexToGrouppath objectAtIndex:i]
+        : nil;
+    }
+    if ((tmp != nil) && ![oldGroup isEqual:tmp]) {
+      oldGroup = tmp;
+      self->state.groupCount++;
+      [infos addObject:tmp];
+      [infos addObject:ODRTableView_GroupMode];
+    }
+
+    [matrix addObject:infos];
+  }
+  [_ctx removeObjectForKey:ODRTableView_INFOS];
+  [_ctx removeObjectForKey:ODRTableView_SORTEDKEY];
+  [_ctx removeObjectForKey:ODRTableView_CollectMode];
+
+  RETAIN(matrix);
+  RELEASE(headInfos);
+  RELEASE(pool);
+
+  END_PROFILE;
+  return AUTORELEASE(matrix);
+}
+
+- (void)_appendResizeButtons:(id)_node
+  toResponse:(WOResponse *)_response
+  actionUrl:(NSString *)_actionUrl
+  inContext:(WOContext *)_ctx
+{
+  NSString *img;
+  NSString *uri;
+  BEGIN_PROFILE;
+
+  // append batchSize--Button  
+  img = [_ctx objectForKey:ODRTableView_minusIcon];
+  img = ODRUriOfResource(img, _ctx);
+  uri = [_actionUrl stringByAppendingString:@".mm"];
+  
+  if (img && [_ctx isInForm]) {
+    uri = [[uri componentsSeparatedByString:@"/"] lastObject];
+    _rawAdd(_response, @"<input type=\"image\" border=\"0\"");
+    _rawAdd(_response, @" name=\"");
+    _rawAdd(_response, uri);
+    _rawAdd(_response, @"\" src=\"");
+    _rawAdd(_response, img);
+    _rawAdd(_response, @"\">");
+  }
+  else {
+    _rawAdd(_response, @"<a href=\"");
+    _rawAdd(_response, uri);
+    _rawAdd(_response, @"\">");
+  }
+  
+  if (img && ![_ctx isInForm]) {
+    _rawAdd(_response, @"<img border=\"0\" src=\"");
+    _rawAdd(_response, img);
+    _rawAdd(_response, @"\" />");
+  }
+  else if (!img)
+    _rawAdd(_response, @"-");
+
+  if (!(img && [_ctx isInForm]))
+    _rawAdd(_response, @"</a>");
+
+  // append batchSize--Button
+  img = [_ctx objectForKey:ODRTableView_plusIcon];
+  img = ODRUriOfResource(img, _ctx);
+  uri = [_actionUrl stringByAppendingString:@".pp"];
+  
+  if (img && [_ctx isInForm]) {
+    uri = [[uri componentsSeparatedByString:@"/"] lastObject];
+    _rawAdd(_response, @"<input type=\"image\" border=\"0\"");
+    _rawAdd(_response, @" name=\"");
+    _rawAdd(_response, uri);
+    _rawAdd(_response, @"\" src=\"");
+    _rawAdd(_response, img);
+    _rawAdd(_response, @"\" />");
+  }
+  else {
+    _rawAdd(_response, @"<a href=\"");
+    _rawAdd(_response, uri);
+    _rawAdd(_response, @"\">");
+  }
+  
+  if (img && ![_ctx isInForm]) {
+    _rawAdd(_response, @"<img border=\"0\" src=\"");
+    _rawAdd(_response, img);
+    _rawAdd(_response, @"\" />");
+  }
+  else if (!img)
+    _rawAdd(_response, @"+");
+
+  if (!(img && [_ctx isInForm]))
+    _rawAdd(_response, @"</a>");
+  
+  END_PROFILE;
+}
+
+- (void)_appendBatchResizeButtons:(id)_node
+  toResponse:(WOResponse *)_response
+  rowSpan:(unsigned int)_rowSpan
+  actionUrl:(NSString *)_actionUrl
+  inContext:(WOContext *)_ctx
+{
+  BEGIN_PROFILE;
+  // open "td"
+  _rawAdd(_response, 
+              @"<td align='center' valign='bottom' width='5' rowspan='");
+  _rawAdd(_response, [self stringForInt:_rowSpan]);
+  [_response appendContentCharacter:'\''];
+#if 0
+  _rawAdd(_response, [NSString stringWithFormat:
+      @"<td align='center' valign='bottom' width='5' rowspan='%d'", _rowSpan]);
+#endif
+  
+  if ([_ctx objectForKey:ODRTableView_footerColor]) {
+    _rawAdd(_response, @" bgcolor='");
+    _rawAdd(_response, 
+               [_ctx objectForKey:ODRTableView_footerColor]);
+    [_response appendContentCharacter:'\''];
+  }
+  [_response appendContentCharacter:'>'];
+
+      // apppend resize buttons
+  [self _appendResizeButtons:_node
+        toResponse:_response
+        actionUrl:_actionUrl
+        inContext:_ctx];
+  // close "td"
+  _rawAdd(_response, @"</td>");
+  END_PROFILE;
+}
+
+- (void)_appendCheckboxToResponse:(WOResponse *)_response
+  ctx:(WOContext *)_ctx
+  value:(NSString *)_value
+  isChecked:(BOOL)_isChecked
+{
+  _rawAdd(_response, @"<input type=\"checkbox\" name=\"");
+  [_response appendContentHTMLAttributeValue:[_ctx elementID]];
+  _rawAdd(_response, @"\" value=\"");
+  _rawAdd(_response, _value);
+  [_response appendContentCharacter:'"'];
+
+  if (_isChecked)
+    _rawAdd(_response, @" checked");
+
+  _rawAdd(_response, @" />");
+}
+
+- (void)_appendData:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSArray     *matrix;
+  NSString    *batchSizeUrl = nil;
+  NSArray     *selArray     = nil;
+  NSString    *groupId      = nil;
+  BOOL        hideObject    = NO;
+  unsigned    i, cnt, first;
+  BEGIN_PROFILE;
+  
+  matrix   = [self _collectData:_node inContext:_ctx];
+  first    = self->state.firstIndex;
+  cnt      = [matrix count];
+
+  if (matrix == nil || cnt == 0)
+    return;
+
+  if (self->use.checkBoxes)
+    selArray = [self valueFor:@"selection" node:_node ctx:_ctx];
+
+  if (self->use.scriptCollapsing)
+    [self _appendGroupCollapseScript:_response inContext:_ctx];
+
+  [_ctx appendElementIDComponent:@"data"];
+  {
+    NSString *bn;
+    bn = [self stringForInt:self->state.currentBatch];
+    //bn = [NSString stringWithFormat:@"%d", self->state.currentBatch];
+    [_ctx appendElementIDComponent:bn]; // append batchNumber
+  }
+  
+  batchSizeUrl = [_ctx componentActionURL];
+
+  if (![self hasAttribute:@"identifier"node:_node ctx:_ctx])
+    [_ctx appendElementIDComponent:[NSString stringWithFormat:@"%i", first]];
+
+  [_ctx setObject:@"YES" forKey:ODRTableView_DataMode];
+  
+  for (i = 0; i < cnt; i++) {
+    NSMutableArray *infos = nil;
+
+    [self _applyItemForIndex:first+i node:_node ctx:_ctx];
+    if ([self hasAttribute:@"identifier" node:_node ctx:_ctx]) {
+      NSString *ident;
+
+      ident = [self stringFor:@"identifier" node:_node ctx:_ctx];
+      [_ctx appendElementIDComponent:ident];
+    }
+    
+    infos = [matrix objectAtIndex:i];
+
+    if ([[infos lastObject] isEqual:ODRTableView_GroupMode]) {
+      unsigned rowSpan;
+
+      groupId = [NSString stringWithFormat:@"group%d", i];
+
+      rowSpan = ((i==0) && self->use.batchResizeButtons)
+        ? cnt+self->state.groupCount
+        : 0;
+      [self _appendGroupTitle:_node
+            toResponse:_response
+            inContext:_ctx
+            infos:infos
+            actionUrl:batchSizeUrl
+            rowSpan:rowSpan
+            groupId:groupId
+            index:i+first];
+      
+      if ((self->state.groupCount > 0) && !self->use.scriptCollapsing)
+        hideObject = ![self _showGroupAtIndex:i+first node:_node ctx:_ctx];
+      else
+        hideObject = NO;
+    }
+        
+    [_ctx setObject:infos forKey:ODRTableView_INFOS];
+
+    if (hideObject) {
+      if (![self hasAttribute:@"identifier" node:_node ctx:_ctx])
+        [_ctx incrementLastElementIDComponent];
+      else
+        [_ctx deleteLastElementIDComponent]; // delete identifier
+      continue;
+    }
+    
+    _rawAdd(_response, @"<tr");
+    if (groupId) {
+      _rawAdd(_response, @" groupName=\"");
+      _rawAdd(_response, groupId);
+      [_response appendContentCharacter:'"'];
+      if (self->use.scriptCollapsing &&
+          ![self _showGroupAtIndex:i+first node:_node ctx:_ctx])
+        _rawAdd(_response, @" style=\"display:none;\"");
+    }
+    [_response appendContentCharacter:'>'];
+
+    if (self->use.checkBoxes) {
+      ODRTableViewInfo *info = nil;
+      NSString        *bg   = nil;
+
+      info = ([infos count]) ? [infos objectAtIndex:0] : nil;
+
+      bg = (info && info->isEven)
+        ? [_ctx objectForKey:ODRTableView_evenColor]
+        : [_ctx objectForKey:ODRTableView_oddColor];
+
+      [_ctx appendElementIDComponent:@"cb"];
+      _rawAdd(_response, @"<td width=\"1%\" align=\"left\"");
+      _rawAdd(_response, @" bgcolor=\"");
+      _rawAdd(_response, bg);
+      _rawAdd(_response, @"\">");
+
+      [self _appendCheckboxToResponse:_response
+            ctx:_ctx
+            value:[self stringForInt:(first + i)]
+            //value:[NSString stringWithFormat:@"%d", first+i]
+            isChecked:[selArray containsObject:
+                                [self->list objectAtIndex:first+i]]];
+      
+      _rawAdd(_response, @"</td>");
+      
+      [_ctx deleteLastElementIDComponent]; // delete "cb"
+    }
+
+    [self appendChildNodes:[_node childNodes]
+          toResponse:_response
+          inContext:_ctx];
+
+    if (!i && self->use.batchResizeButtons &&!self->state.groupCount) {
+      [self _appendBatchResizeButtons:_node
+            toResponse:_response
+            rowSpan:cnt+self->state.groupCount
+            actionUrl:batchSizeUrl
+            inContext:_ctx];
+    }
+    
+    _rawAdd(_response, @"</tr>");
+
+    if (![self hasAttribute:@"identifier" node:_node ctx:_ctx])
+      [_ctx incrementLastElementIDComponent];
+    else
+      [_ctx deleteLastElementIDComponent]; // delete identifier
+  }
+  if (![self hasAttribute:@"identifier" node:_node ctx:_ctx])
+    [_ctx deleteLastElementIDComponent]; // delete index
+  [_ctx deleteLastElementIDComponent];   // delete batchNumber
+  [_ctx deleteLastElementIDComponent];   // delete "data"
+  [_ctx removeObjectForKey:ODRTableView_DataMode];
+
+  END_PROFILE;
+}
+
+- (void)_appendFooter:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *bg      = nil;
+  unsigned first    = self->state.firstIndex + 1;
+  unsigned last     = self->state.lastIndex  + 1;
+  unsigned count    = [self->list count];
+  unsigned batch    = self->state.currentBatch;
+  unsigned batchCnt = self->state.batchCount;
+  BEGIN_PROFILE;
+
+  first    = (count)    ? first    : 0;
+  batchCnt = (batchCnt) ? batchCnt : 1;
+  bg       = [_ctx objectForKey:ODRTableView_footerColor];
+  
+  [_ctx appendElementIDComponent:@"footer"];
+
+  _rawAdd(_response, 
+         @"<table border='0' width='100%' cellpadding='0' cellspacing='0'>");
+  _rawAdd(_response, @"<tr>");                        // <TR>
+  ODRAppendTD(_response, @"left", nil, bg, nil);                  //   <TD...>
+
+  [_ctx setObject:@"YES" forKey:ODRTableView_FooterMode];
+  [self appendChildNodes:ODRLookupQueryPath(_node, @"-tfooter")
+        toResponse:_response
+        inContext:_ctx];
+  [_ctx removeObjectForKey:ODRTableView_FooterMode];
+  
+  _rawAdd(_response, @"<small>");
+  if (!self->use.overflow) {
+    _rawAdd(_response, [self stringForInt:first]);
+    //_rawAdd(_response, [NSString stringWithFormat:@"%d ", first]];
+    _rawAdd(_response, [self labelForKey:@"to" ctx:_ctx]);
+    _rawAdd(_response, [self stringForInt:last]);
+    //_rawAdd(_response, [NSString stringWithFormat:@" %d ", last]];
+    _rawAdd(_response, [self labelForKey:@"of" ctx:_ctx]);
+  }
+  _rawAdd(_response, [self stringForInt:count]);
+  //_rawAdd(_response, [NSString stringWithFormat:@" %d", count]];
+  _rawAdd(_response, @"</small>");
+  
+  _rawAdd(_response, @"</td>");                       // </TD>
+  
+  ODRAppendTD(_response, @"right", nil, bg, nil);                 // <TD...>
+  if (!self->use.overflow) {
+    NSString *tmp;
+
+    tmp = [self labelForKey:@"page" ctx:_ctx];
+    
+    _rawAdd(_response, @"<small>");
+    if (tmp) {
+      _rawAdd(_response, tmp);
+      [_response appendContentCharacter:':'];
+    }
+    _rawAdd(_response, [self stringForInt:batch]);
+    //               [NSString stringWithFormat:@" %d ", batch]];
+    _rawAdd(_response, [self labelForKey:@"of" ctx:_ctx]);
+    _rawAdd(_response, [self stringForInt:batchCnt]);
+    //               [NSString stringWithFormat:@" %d", batchCnt]];
+    _rawAdd(_response, @"</small>");
+  }
+  else {
+    [self _appendResizeButtons:_node
+          toResponse:_response
+          actionUrl:[_ctx componentActionURL]
+          inContext:_ctx];
+  }
+
+
+  _rawAdd(_response, @"</td></tr>");              // </TD><TR>
+  _rawAdd(_response, @"</table>");                  // </TABLE>
+
+  [_ctx deleteLastElementIDComponent];
+  END_PROFILE;
+}
+
+@end /* ODR_bind_tableview(Private_Rendering) */
+
+@implementation ODR_bind_tableview(Private_ActionHandling)
+
+
+- (NSArray *)_sortedArrayOfNode:(id)_node
+                      inContext:(WOContext *)_ctx
+                          fetch:(BOOL)_doFetch
+{
+  NSArray        *array     = nil;
+  EOSortOrdering *so        = nil;
+  NSArray        *orderings = nil;
+  NSString       *sortedKey = nil;
+  BOOL           isDesc     = NO;
+  SEL            sel;
+
+  if (![self hasAttribute:@"sortaction" node:_node ctx:_ctx]) {
+    isDesc    = [self boolFor:@"isdescending" node:_node ctx:_ctx];
+    sortedKey = [self stringFor:@"sortedkey"  node:_node ctx:_ctx];
+    
+    sel = (isDesc) ? EOCompareDescending : EOCompareAscending;
+    if (sortedKey)
+      so  = [EOSortOrdering sortOrderingWithKey:sortedKey  selector:sel];
+
+    // get sortOrderings
+    [_ctx setObject:@"YES" forKey:ODR_SortOrderingContainerMode];
+    [self appendChildNodes:ODRLookupQueryPath(_node, @"-sortorderings")
+          toResponse:nil
+          inContext:_ctx];
+    [_ctx removeObjectForKey:ODR_SortOrderingContainerMode];
+
+    if (so)
+      orderings = [NSArray arrayWithObject:so];
+
+    if (orderings)
+      orderings = [orderings arrayByAddingObjectsFromArray:
+                             [_ctx objectForKey:ODR_SortOrderingContainer]];
+    else
+      orderings = [_ctx objectForKey:ODR_SortOrderingContainer];
+
+    if ([self hasAttribute:@"datasource" node:_node ctx:_ctx]) {
+      EODataSource *ds = [self valueFor:@"datasource" node:_node ctx:_ctx];
+
+      if (orderings) {
+        EOFetchSpecification *fspec;
+          
+        fspec = [[ds fetchSpecification] copy];
+        
+        if (fspec == nil)
+          fspec = [[EOFetchSpecification alloc] init];
+
+        [fspec setSortOrderings:orderings];
+        
+        [ds setFetchSpecification:fspec];
+        RELEASE(fspec);
+      }
+      if (_doFetch)
+        array = [ds fetchObjects];
+    }
+    else if (_doFetch) {
+      array = [self valueFor:@"list" node:_node ctx:_ctx];
+      if (orderings)
+        array = [array sortedArrayUsingKeyOrderArray:orderings];
+    }
+  }
+  else {
+    // [self->sortAction valueInComponent:cmp];
+    if (_doFetch)
+      array = [self valueFor:@"list" node:_node ctx:_ctx];
+  }
+  return array;
+}
+
+- (void)_handleSortAction:(id)_node inContext:(WOContext *)_ctx {
+  NSString    *key;
+  NSString    *oldKey;
+  BOOL        isDesc;
+  BOOL        oldIsDesc;
+  BEGIN_PROFILE;
+
+  if ([_ctx objectForKey:ODRTableView_SORTEDKEY] == nil ||
+      [_ctx objectForKey:ODRTableView_ISDESCENDING] == nil)
+    return; // nothing to do
+
+  key    = [_ctx  objectForKey:ODRTableView_SORTEDKEY];
+  isDesc = [[_ctx objectForKey:ODRTableView_ISDESCENDING] boolValue];
+
+  oldIsDesc = [self boolFor:@"isdescending" node:_node ctx:_ctx];
+  oldKey    = [self stringFor:@"sortedkey"  node:_node ctx:_ctx];
+
+  if ([oldKey isEqual:key] && oldIsDesc == isDesc)
+    return; // nothing to do
+
+  [self forceSetBool:isDesc for:@"isdescending" node:_node ctx:_ctx];
+  [self forceSetString:key  for:@"sortedkey"    node:_node ctx:_ctx];
+
+  [self _sortedArrayOfNode:_node inContext:_ctx fetch:NO];
+  
+  END_PROFILE;
+  return;
+}
+
+- (id)_handleFirstButton:(id)_node inContext:(WOContext *)_ctx {
+  if ([self hasAttribute:@"firstaction" node:_node ctx:_ctx])
+    ; // ??? [self->firstAction valueInComponent:[_ctx component]];
+  else {
+    self->state.currentBatch = 1; // ???
+    [self forceSetInt:1 for:@"currentbatch" node:_node ctx:_ctx];
+  }
+  return nil;
+}
+
+- (id)_handlePreviousButton:(id)_node inContext:(WOContext *)_ctx {
+  if ([self hasAttribute:@"previousaction" node:_node ctx:_ctx])
+    ; // ??? [self->previousAction valueInComponent:[_ctx component]];
+  else {
+    unsigned batch = self->state.currentBatch;
+    
+    self->state.currentBatch = ((batch -1) > 0) ? batch - 1 : 1;
+    [self forceSetInt:self->state.currentBatch
+          for:@"currentbatch" node:_node ctx:_ctx];
+  }
+  return nil;
+}
+
+- (id)_handleNextButton:(id)_node inContext:(WOContext *)_ctx {
+  if ([self hasAttribute:@"nextaction" node:_node ctx:_ctx])
+    ; // ??? [self->nextAction valueInComponent:[_ctx component]];
+  else {
+    unsigned batch = self->state.currentBatch;
+    unsigned cnt   = self->state.batchCount;
+    
+    self->state.currentBatch = ((batch +1) < cnt) ? batch + 1 : cnt;
+    [self forceSetInt:self->state.currentBatch
+          for:@"currentbatch" node:_node ctx:_ctx];
+  }
+  return nil;
+}
+
+- (id)_handleLastButton:(id)_node inContext:(WOContext *)_ctx {
+  if ([self hasAttribute:@"lastaction" node:_node ctx:_ctx])
+    ; // ??? [self->lastAction valueInComponent:[_ctx component]];
+  else {
+    self->state.currentBatch = self->state.batchCount;
+    [self forceSetInt:self->state.currentBatch
+          for:@"currentbatch" node:_node ctx:_ctx];
+  }
+  return nil;
+}
+
+- (id)increaseAutoScrollHeight:(id)_node inContext:(WOContext *)_ctx {
+  if ([self isSettable:@"autoscroll" node:_node ctx:_ctx]) {
+    int sh; // scrollHeight
+
+    sh = [self intFor:@"autoscroll" node:_node ctx:_ctx] + 20;
+    [self setInt:sh for:@"autoscroll" node:_node ctx:_ctx];
+  }
+  return nil;
+}
+
+- (id)decreaseAutoScrollHeight:(id)_node inContext:(WOContext *)_ctx {
+  if ([self isSettable:@"autoscroll" node:_node ctx:_ctx]) {
+    int sh; // scrollHeight
+
+    sh = [self intFor:@"autoscroll" node:_node ctx:_ctx] - 20;
+    if (sh > 50)
+      [self setInt:sh for:@"autoscroll" node:_node ctx:_ctx];
+  }
+  return nil;
+}
+
+
+- (id)increaseBatchSize:(id)_node inContext:(WOContext *)_ctx {
+  if ([self isSettable:@"batchsize" node:_node ctx:_ctx]) {
+    int bs;
+
+    bs = [self intFor:@"batchsize" node:_node ctx:_ctx] + 1;
+    [self setInt:bs for:@"batchsize" node:_node ctx:_ctx];
+  }
+  return nil;
+}
+
+- (id)decreaseBatchSize:(id)_node inContext:(WOContext *)_ctx {
+  if ([self isSettable:@"batchsize" node:_node ctx:_ctx]) {
+    int bs;
+
+    bs = [self intFor:@"batchsize" node:_node ctx:_ctx] - 1;
+    if (bs > 1)
+      [self setInt:bs for:@"batchsize" node:_node ctx:_ctx];
+  }
+  return nil;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  forBatch:(int)_batch
+  selections:(NSMutableArray *)_selArray
+  inContext:(WOContext *)_ctx
+{
+  NSString *eid;
+  int      i, first, last;
+  BEGIN_PROFILE;
+  
+  first = self->state.firstIndex;
+  last  = self->state.lastIndex;
+  
+  {
+    NSString *bn;
+    bn = [self stringForInt:self->state.currentBatch];
+    //bn = [NSString stringWithFormat:@"%d", self->state.currentBatch];
+    [_ctx appendElementIDComponent:bn]; // append batchNumber
+  }
+
+  eid = [_ctx elementID];
+
+  if ([_request formValueForKey:[eid stringByAppendingString:@".pp.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".pp"]];
+  }
+  else if ([_request formValueForKey:[eid stringByAppendingString:@".mm.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".mm"]];
+  }
+  
+  if (![self hasAttribute:@"identifier" node:_node ctx:_ctx]) // append index
+    //[_ctx appendElementIDComponent:[NSString stringWithFormat:@"%d", first]];
+    [_ctx appendElementIDComponent:[self stringForInt:first]];
+  
+  for (i = first; i <=last; i++) {
+    [self _applyItemForIndex:i node:_node ctx:_ctx];
+    if ([self hasAttribute:@"identifier" node:_node ctx:_ctx]) {
+      NSString *s;
+        
+      s = [self stringFor:@"identifier" node:_node ctx:_ctx];
+      [_ctx appendElementIDComponent:s];
+    }
+
+    if (_selArray != nil) {
+      NSString *cbID; // checkBoxID
+      id       formValue;
+      id       obj;
+
+      cbID = [[_ctx elementID] stringByAppendingString:@".cb"];
+      obj  = [self valueFor:@"item" node:_node ctx:_ctx];
+
+      if (obj) {
+        if ((formValue = [_request formValueForKey:cbID])) {
+          if (![_selArray containsObject:obj])
+            [_selArray addObject:obj];
+        }
+        else if ([_selArray containsObject:obj])
+          [_selArray removeObject:obj];
+      }
+    }
+    [_ctx setObject:@"YES" forKey:ODRTableView_DataMode];
+    [self takeValuesForChildNodes:[_node childNodes]
+          fromRequest:_request
+          inContext:_ctx];
+    [_ctx removeObjectForKey:ODRTableView_DataMode];
+    
+    if (![self hasAttribute:@"identifier" node:_node ctx:_ctx])
+      [_ctx incrementLastElementIDComponent];
+    else
+      [_ctx deleteLastElementIDComponent]; // delete identifier
+  }
+  if (![self hasAttribute:@"identifier" node:_node ctx:_ctx])
+    [_ctx deleteLastElementIDComponent]; // delete index
+
+  [_ctx deleteLastElementIDComponent]; // delete batchNumber
+  END_PROFILE;
+}
+
+@end /* ODR_bind_tableview(Private_ActionHandling) */
+
+@implementation ODR_bind_tableview(Private_JavaScriptAdditions)
+
+- (void)_appendGroupCollapseScript:(WOResponse *)_resp
+  inContext:(WOContext *)_ctx
+{
+  if (![_ctx objectForKey:ODRTableView_HasCollapseScript]) {
+    [_resp appendContentString:
+           @"\n<script language=\"JavaScript\">\n"
+           @"<!--\n"
+           @"function toggleTableGroup()\n"
+           @"{\n"
+           @"   img = event.srcElement;\n"
+           @"   visibility = img.isGroupVisible;\n"
+           @"   visibility = (visibility != \"none\") ? \"none\" : \"\";\n"
+           @"   img.isGroupVisible = visibility;\n"
+           @"   img.src = (visibility == \"\") ? img.openImg : img.closeImg;\n"
+           @"   groupName  = img.group;\n"
+           @"   table  = img.parentNode.parentNode.parentNode;\n"
+           @"   trList = table.getElementsByTagName(\"TR\");\n"
+           @"   cnt    = trList.length;\n"
+           @"   for (i=0; i<cnt; i++) {\n"
+           @"     tr = trList[i];\n"
+           @"     if (tr.groupName == groupName)\n"
+           @"       tr.style.display = visibility;\n"
+           @"   }\n"
+           @"}\n"
+           @"//-->\n"
+           @"</script>\n"];
+    [_ctx setObject:@"YES" forKey:ODRTableView_HasCollapseScript];
+  }
+}
+
+- (void)jsButton:(WOResponse *)_resp ctx:(WOContext *)_ctx
+  name:(NSString *)_name button:(NSString *)_button
+{
+  NSString *imgUri;
+  NSString *n;
+  
+  _button = [_button stringByAppendingString:@".gif"];
+  imgUri  = ODRUriOfResource(_button, _ctx);
+  n       = [_name stringByAppendingString:self->scriptID];
+  
+  [_resp appendContentString:[NSString stringWithFormat:
+         @"var %@ = new Image(); %@.src = \"%@\";\n", n, n, imgUri]];
+}
+                                    
+- (void)appendJavaScript:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  [_resp appendContentString:@"<SCRIPT LANGUAGE=\"JavaScript\">\n<!--\n"];
+  
+  [self jsButton:_resp ctx:_ctx name:@"First"     button:@"first"];
+  [self jsButton:_resp ctx:_ctx name:@"First2"    button:@"first_blind"];
+  [self jsButton:_resp ctx:_ctx name:@"Previous"  button:@"previous"];
+  [self jsButton:_resp ctx:_ctx name:@"Previous2" button:@"previous_blind"];
+  [self jsButton:_resp ctx:_ctx name:@"Next"      button:@"next"];
+  [self jsButton:_resp ctx:_ctx name:@"Next2"     button:@"next_blind"];
+  [self jsButton:_resp ctx:_ctx name:@"Last"      button:@"last"];
+  [self jsButton:_resp ctx:_ctx name:@"Last2"     button:@"last_blind"];
+
+  [_resp appendContentString:[NSString stringWithFormat:
+    @"function showPage%@() {\n"
+    @"  for (var i=1; i< page%@.length; i++) {\n"
+       @"    if (i == actualPage%@) {\n"
+    @"      page%@[i][\"Div\"].style.display = \"\";\n"
+    @"      footer%@[i][\"Div\"].style.display = \"\";\n"
+    @"    }\n"
+       @"    else {\n"
+    @"      page%@[i][\"Div\"].style.display = \"none\";\n"
+    @"      footer%@[i][\"Div\"].style.display = \"none\";\n"
+    @"    }\n"
+       @"      }\n"
+       @"      flushImages%@();\n"
+       @"}\n",
+    self->scriptID, // showPage
+    self->scriptID, // page.length
+    self->scriptID, // actualPage
+    self->scriptID, // page
+    self->scriptID, // footer
+    self->scriptID, // page
+    self->scriptID, // footer
+    self->scriptID  // flushImages
+  ]];
+  
+  [_resp appendContentString:[NSString stringWithFormat:
+    @"function firstPage%@() {\n"
+    @"  actualPage%@ = 1;\n"
+    @"  showPage%@();\n"
+    @"}\n",
+    self->scriptID, // firstPage
+    self->scriptID, // actualPage
+    self->scriptID  // showPage
+  ]];
+
+  [_resp appendContentString:[NSString stringWithFormat:
+    @"function previousPage%@() {\n"
+    @" if (actualPage%@ > 1) {\n"
+    @"    actualPage%@--;\n"
+    @"    showPage%@();\n"
+    @"  }\n"
+       @"}\n",
+    self->scriptID, // previousPage
+    self->scriptID, // actualPage
+    self->scriptID, // actualPage
+    self->scriptID  // showPage
+  ]];
+
+  [_resp appendContentString:[NSString stringWithFormat:
+    @"function nextPage%@() {\n"
+    @"  if (actualPage%@ < page%@.length - 1) {\n"
+    @"    actualPage%@++;\n"
+    @"    showPage%@();\n"
+    @" }\n"
+       @"}\n",
+    self->scriptID, // nextPage
+    self->scriptID, // actualPage
+    self->scriptID, // page
+    self->scriptID, // actualPage
+    self->scriptID  // showPage
+  ]];
+
+  [_resp appendContentString:[NSString stringWithFormat:
+    @"function lastPage%@() {\n"
+    @"  actualPage%@ = page%@.length - 1;\n"
+    @"  showPage%@();\n"
+    @"}\n",
+    self->scriptID, // lastPage
+    self->scriptID, // actualPage
+    self->scriptID, // page
+    self->scriptID  // showPage
+  ]];
+
+  [_resp appendContentString:[NSString stringWithFormat:
+    @"function flushImages%@() {\n"
+    @"  document.images[\"firstPageImg%@\"].src    = First%@.src;\n"
+    @"  document.images[\"previousPageImg%@\"].src = Previous%@.src;\n"
+    @"  document.images[\"nextPageImg%@\"].src     = Next%@.src;\n"
+    @"  document.images[\"lastPageImg%@\"].src     = Last%@.src;\n"
+    @"  if (actualPage%@ == 1) {\n"
+    @"    document.images[\"firstPageImg%@\"].src    = First2%@.src;\n"
+    @"    document.images[\"previousPageImg%@\"].src = Previous2%@.src;\n"
+    @"  }\n"
+                                       
+    //    @"  if (actualPage%@ == 2) {\n"
+    //    @"    document.images[\"firstPageImg%@\"].src = First2%@.src;\n"
+    //    @"  }\n"
+    //    @"  if (actualPage%@ == page%@.length -2) {\n"
+    //    @"    document.images[\"lastPageImg%@\"].src = Last2%@.src;\n"
+    //    @"  }\n"
+                                       
+    @"  if (actualPage%@ == page%@.length - 1) {\n"
+    @"    document.images[\"nextPageImg%@\"].src = Next2%@.src;\n"
+    @"    document.images[\"lastPageImg%@\"].src = Last2%@.src;\n"
+    @"  }\n"
+    @"}\n",
+    self->scriptID, // flushImages
+    self->scriptID, // firstPageImg
+    self->scriptID, // First
+    self->scriptID, // previousPageImg
+    self->scriptID, // Previous
+    self->scriptID, // nextPageImg
+    self->scriptID, // Next
+    self->scriptID, // lastPageImg
+    self->scriptID, // Last
+    self->scriptID, // actualPage
+    self->scriptID, // firstPageImg
+    self->scriptID, // First2
+    self->scriptID, // previousPageImg
+    self->scriptID, // Previous2
+                                       
+/*                                       
+    self->scriptID, // actualPage
+    self->scriptID, // firstPageImg
+    self->scriptID, // First2
+                                       
+    self->scriptID, // actualPage
+    self->scriptID, // page
+    self->scriptID, // lastPageImg
+    self->scriptID, // Last2
+*/
+                                       
+    self->scriptID, // actualPage
+    self->scriptID, // page
+    self->scriptID, // nextPageImg,
+    self->scriptID, // Next2
+    self->scriptID, // lastPageImg
+    self->scriptID  // Last2
+  ]];
+  
+  [_resp appendContentString:[NSString stringWithFormat:
+    @"var page%@   = new Array();\n"
+    @"var footer%@ = new Array();\n"
+    @"var actualPage%@ = %d;",
+    self->scriptID, // page
+    self->scriptID, // footer
+    self->scriptID, //actualPage
+    self->state.currentBatch
+  ]];
+  {
+    unsigned i;
+
+    for (i = 1; i <= self->state.batchCount; i++) {
+      [_resp appendContentString:[NSString stringWithFormat:
+        @"page%@[%d] = new Array();\n"
+        @"page%@[%d][\"Div\"] = page%dDiv%@;\n\n"
+        @"footer%@[%d] = new Array();\n"
+        @"footer%@[%d][\"Div\"] = footer%dDiv%@;\n\n",
+        self->scriptID, // page
+        i,              // page[i]
+        self->scriptID, // page
+        i,              // page[i]
+        i,              // pageiDiv
+        self->scriptID, // pageDiv
+        self->scriptID, // footer
+        i,              // footer[i]
+        self->scriptID, // footer
+        i,              // footer[i]
+        i,              // footeriDiv
+        self->scriptID  // footerDiv
+       ]];
+    }
+  }
+  [_resp appendContentString:[NSString stringWithFormat:
+    @"showPage%@();", self->scriptID]];
+
+  [_resp appendContentString:@"//-->\n</SCRIPT>\n"];
+}
+
+- (void)_appendTableContentAsScript:(id)_node
+  toResponse:(WOResponse *)_resp
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *cmp;
+  unsigned i, savedBatchIndex;
+  BEGIN_PROFILE;
+
+  cmp = [_ctx component];
+  
+  savedBatchIndex = self->state.currentBatch;
+  /* open header + data area */
+  [_resp appendContentString:@"\n<tr><td>"];
+
+  for (i = 1; i <= self->state.batchCount; i++) {
+    self->state.currentBatch = i;
+    [self forceSetInt:i for:@"currentbatch" node:_node ctx:_ctx];
+    [self updateStateOfNode:_node inContext:_ctx];
+    [_resp appendContentString:[NSString stringWithFormat:         // <DIV...>
+      @"<div id=\"page%dDiv%@\" style=\"display: ; \">", i, self->scriptID]];
+
+    [_resp appendContentString:
+           @"<table border='0' width='100%' cellpadding='1' cellspacing='0'>"];
+    
+    [self _appendHeader:_node toResponse:_resp inContext:_ctx];
+    [self _appendData:_node   toResponse:_resp inContext:_ctx];
+    
+    [_resp appendContentString:@"</table>\n"];
+    [_resp appendContentString:@"</div>"];                        // </DIV>
+    
+
+    /* append footer */
+    [_resp appendContentString:[NSString stringWithFormat:        // <DIV...>
+      @"<div id=\"footer%dDiv%@\" style=\"display: ; \">", i, self->scriptID]];
+
+    [self _appendFooter:_node toResponse:_resp inContext:_ctx];
+    
+    [_resp appendContentString:@"</div>"];                        // </DIV>
+  }
+  
+  /* close header + data area */
+  [_resp appendContentString:@"</td></tr>\n"];
+
+  self->state.currentBatch = savedBatchIndex;
+  [self forceSetInt:self->state.currentBatch
+        for:@"currentbatch" node:_node ctx:_ctx];
+  [self updateStateOfNode:_node inContext:_ctx];
+
+  END_PROFILE;
+}
+
+- (void)_appendScriptLink:(WOResponse *)_response name:(NSString *)_name {
+  _rawAdd(_response, @"JavaScript:");
+  _rawAdd(_response, _name);
+  _rawAdd(_response, [NSString stringWithFormat:
+    @"Page%@();", self->scriptID]);
+}
+
+@end /* ODR_bind_tableview(Private_JavaScriptAdditions) */
+
+
+@implementation ODR_bind_tableview(Private_Grouping)
+
+/* structure of attribute "visibleGroups":
+
+   separator of groups is "&"
+
+   qualGroupName1.keyGroupName1&qualGroupName2.keyGroupName2&...
+   |__________________________| |__________________________|
+                |                             |
+         path of group                  path of group
+       (separator is ".")             (separator is ".")
+*/
+
+- (BOOL)_showGroupAtIndex:(int)_idx node:(id)_node ctx:(WOContext *)_ctx {
+  id visibleGroups; /* Array of strings  */
+  id group;         /* string */
+  
+  if ([self hasAttribute:@"showgroup" node:_node ctx:_ctx])
+    return [self boolFor:@"showgroup" node:_node ctx:_ctx];
+  
+  if (self->indexToGrouppath == nil)
+    return NO;
+  
+  NSAssert(((int)[self->indexToGrouppath count] > _idx), 
+           @"index is out of range");
+  
+  visibleGroups = [self stringFor:@"visiblegroups" node:_node ctx:_ctx];
+  visibleGroups = (NSString *)[visibleGroups componentsSeparatedByString:@"&"];
+
+  group = [self->indexToGrouppath objectAtIndex:_idx];
+  group = (NSArray *)[group componentsJoinedByString:@"."];
+
+  return [visibleGroups containsObject:group];
+}
+
+- (void)_setShowGroup:(BOOL)_flag
+  atIndex:(int)_idx
+  node:(id)_node
+  ctx:(WOContext *)_ctx
+{
+  id   visibleGroups; /* Array of strings  */
+  id   group;         /* string */
+  BOOL isMarked;
+  BEGIN_PROFILE;
+
+  if ([self isSettable:@"showgroup" node:_node ctx:_ctx]) {
+    [self setBool:_flag for:@"showgroup" node:_node ctx:_ctx];
+    return;
+  }
+  
+  if (self->indexToGrouppath == nil) return;
+  
+  NSAssert(((int)[self->indexToGrouppath count] > _idx), 
+           @"index is out of range");
+  
+  visibleGroups = [self stringFor:@"visiblegroups" node:_node ctx:_ctx];
+  visibleGroups = (NSString *)[visibleGroups componentsSeparatedByString:@"&"];
+
+  group = [self->indexToGrouppath objectAtIndex:_idx];
+  group = (NSArray *)[group componentsJoinedByString:@"."];
+
+  isMarked = [visibleGroups containsObject:group];
+  
+  if (_flag && !isMarked) {
+    visibleGroups = (visibleGroups)
+      ? [visibleGroups arrayByAddingObject:group]
+      : [NSArray arrayWithObject:group];
+    
+    [self forceSetString:[visibleGroups componentsJoinedByString:@"&"]
+          for:@"visiblegroups"
+          node:_node
+          ctx:_ctx];
+  }
+  else if (!_flag && isMarked) {
+    NSMutableArray *tmp;
+
+    tmp = [NSMutableArray arrayWithArray:visibleGroups];
+    [tmp removeObject:group];
+    
+    [self forceSetString:[tmp componentsJoinedByString:@"&"]
+          for:@"visiblegroups"
+          node:_node
+          ctx:_ctx];
+  }
+  END_PROFILE;
+}
+
+- (id)_invokeGrouping:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *stateId;
+
+  stateId = [[_ctx currentElementID] stringValue];
+
+  if (stateId) {
+    int idx;
+    id  obj;
+    
+    /* ??? */
+    obj = [self valueFor:@"item" node:_node ctx:_ctx];
+    idx = [self->list indexOfObject:obj];
+
+#if DEBUG && 0
+    NSLog(@"%s: (grouping=%@) idx is %d (eid=%@)", __PRETTY_FUNCTION__,
+          _node, idx, [_ctx elementID]);
+#endif
+    
+    if ([stateId isEqualToString:@"e"]) {
+      [self _setShowGroup:NO atIndex:idx node:_node ctx:_ctx];
+    }
+    else if ([stateId isEqualToString:@"c"]) {
+      [self _setShowGroup:YES atIndex:idx node:_node ctx:_ctx];
+    }
+    else {
+#if DEBUG && 0
+      NSLog(@"%s:   invoke on children idx is %d (eid=%@)",
+            __PRETTY_FUNCTION__, idx, [_ctx elementID]);
+#endif
+      [_ctx setObject:@"YES" forKey:ODRTableView_DataMode];
+      return [self invokeActionForChildNodes:[_node childNodes]
+                   fromRequest:_request
+                   inContext:_ctx];
+      [_ctx removeObjectForKey:ODRTableView_DataMode];
+    }
+  }
+  return nil;
+}
+
+- (void)_appendGroupTitle:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  infos:(NSMutableArray *)_infos
+  actionUrl:(NSString *)_actionUrl
+  rowSpan:(unsigned)_rowSpan
+  groupId:(NSString *)_groupId
+  index:(int)_idx
+{
+  NSString    *bgcolor;
+  BOOL        isCollapsed;
+  NSString    *img;
+  int         colspan;
+  BEGIN_PROFILE;
+  
+  [_ctx removeObjectForKey:ODRTableView_INFOS];
+  colspan  = [_infos count] - 2;
+  colspan += (self->use.checkBoxes) ? 1 : 0;
+
+  isCollapsed = ![self _showGroupAtIndex:_idx node:_node ctx:_ctx];
+  
+  _rawAdd(_response, 
+             [NSString stringWithFormat:@"<tr><td colspan='%d'", colspan]);
+  bgcolor = [self stringFor:@"groupcolor" node:_node ctx:_ctx];
+  if (!bgcolor)
+    bgcolor = [_ctx objectForKey:ODRTableView_groupColor];
+      
+  if (bgcolor != nil) {
+    _rawAdd(_response, @" bgcolor='");
+    _rawAdd(_response, bgcolor);
+    [_response appendContentCharacter:'\''];
+  }
+  _rawAdd(_response, @"width='1%'>");
+      
+  [_ctx setObject:@"YES" forKey:ODRTableView_GroupMode];
+  
+  img = (!isCollapsed)
+    ? [_ctx objectForKey:ODRTableView_openedIcon]
+    : [_ctx objectForKey:ODRTableView_closedIcon];
+  
+  img = ODRUriOfResource(img, _ctx);
+  
+  [_ctx appendElementIDComponent:(isCollapsed) ? @"c" : @"e"];
+  
+  if (!self->use.scriptCollapsing) {
+    _rawAdd(_response, @"<a href=\"");
+    _rawAdd(_response, [_ctx componentActionURL]);
+    _rawAdd(_response, @"\">");
+  }
+
+  if (img) {
+    _rawAdd(_response, @"<img border='0' src=\"");
+    _rawAdd(_response, img);
+    [_response appendContentCharacter:'"'];
+    if (self->use.scriptCollapsing) {
+      NSString *openImg;
+      NSString *closeImg;
+
+      openImg  = [_ctx objectForKey:ODRTableView_openedIcon];
+      closeImg = [_ctx objectForKey:ODRTableView_closedIcon];
+
+      openImg  = ODRUriOfResource(openImg, _ctx);
+      closeImg = ODRUriOfResource(closeImg, _ctx);
+
+      openImg  = (openImg) ? openImg : closeImg;
+      closeImg = (closeImg) ? closeImg : openImg;
+      
+      _rawAdd(_response, @" onclick=\"toggleTableGroup();\"");
+      _rawAdd(_response, @" group=\"");
+      _rawAdd(_response, _groupId);
+      _rawAdd(_response, @"\" openImg=\"");
+      _rawAdd(_response, openImg);
+      _rawAdd(_response, @"\" closeImg=\"");
+      _rawAdd(_response, closeImg);
+      [_response appendContentCharacter:'"'];
+      if (isCollapsed)
+        _rawAdd(_response, @" isGroupVisible=\"none\"");
+      else
+        _rawAdd(_response, @" isGroupVisible=\"\"");
+    }
+    _rawAdd(_response, @" />");
+  }
+  else
+    _rawAdd(_response, (isCollapsed) ? @"[+]" : @"[-]");
+  if (!self->use.scriptCollapsing)
+    _rawAdd(_response, @"</a>&nbsp;");
+
+  [_ctx deleteLastElementIDComponent];
+
+  if ([self isSettable:@"currentgroup" node:_node ctx:_ctx]) {
+    NSAssert(([_infos count] > 1), @"info count must be at least 2");
+
+    
+    
+    [self setValue:[_infos objectAtIndex:[_infos count]-1]
+          for:@"currentgroup"
+          node:_node ctx:_ctx];
+  }
+  
+  [_ctx setObject:@"YES" forKey:ODRTableView_GroupMode];
+  {
+    NSString *gName = nil;
+    NSArray  *gPath = nil;
+    NSString *gList = nil;
+    
+    gPath = [self->indexToGrouppath objectAtIndex:_idx];
+
+    if ((gName = [gPath lastObject]))
+      gList = [self->groupedList objectForKey:gName];
+    
+    [_ctx setObject:gName  forKey:ODRTableView_GroupName];
+    [_ctx setObject:gList  forKey:ODRTableView_GroupItems];
+    [_ctx setObject:@"YES" forKey:ODRTableView_GroupMode];
+
+    [self appendChildNodes:ODRLookupQueryPath(_node, @"-tgroup")
+          toResponse:_response
+          inContext:_ctx];
+
+    [_ctx removeObjectForKey:ODRTableView_GroupMode];
+    [_ctx removeObjectForKey:ODRTableView_GroupName];
+    [_ctx removeObjectForKey:ODRTableView_GroupItems];
+  }
+  [_ctx removeObjectForKey:ODRTableView_GroupMode];
+
+  _rawAdd(_response, @"</td>");
+
+  if (_rowSpan) {
+    [self _appendBatchResizeButtons:_node
+          toResponse:_response
+          rowSpan:_rowSpan
+          actionUrl:_actionUrl
+          inContext:_ctx];
+  }
+  _rawAdd(_response, @"</tr>");
+  [_infos removeLastObject]; // groups
+  [_infos removeLastObject]; // ODRTableView_GroupMode
+
+  END_PROFILE;
+}
+
+@end /* ODR_bind_tableview(Private_Grouping) */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableview.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tableview.m
new file mode 100644 (file)
index 0000000..1d87466
--- /dev/null
@@ -0,0 +1,985 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODR_bind_tableview.h"
+#include "ODR_bind_tableview+Private.h"
+#include "ODR_bind_groupings.h"
+
+//#define PROFILE 1
+
+#import <EOControl/EOControl.h>
+#ifdef __APPLE__
+#include <NGObjWeb/WEClientCapabilities.h>
+#else
+#include <WEExtensions/WEClientCapabilities.h>
+#endif
+#include <NGObjDOM/ODNamespaces.h>
+#include <DOM/EDOM.h>
+#include "common.h"
+#include "ODR_bind_groupings.h"
+#include "ODR_bind_sortorderings.h"
+
+@interface NSDictionary(ODR_bind_tableview)
+
+- (NSArray *)flattenedArrayWithHint:(unsigned int)_hint
+  andOrderedKeys:(NSArray *)_keys;
+
+/* attributesWithHint:... returns an array of arrays !!! */
+- (NSArray *)attributesWithHint:(unsigned int)_hint
+  andOrderedKeys:(NSArray *)_keys;
+- (NGBitSet *)bitSetWithHint:(unsigned int)_hint;
+
+@end
+
+@implementation ODR_bind_tableview
+
+/* selector caching for ctx */
+
+static Class lastCtxClass = Nil;
+static IMP   setObjForKey = NULL;
+static IMP   remObjForKey = NULL;
+
+static inline void _updateCtxCache(WOContext *_ctx) {
+  if (_ctx == nil) return;
+  if (lastCtxClass != *(Class *)_ctx) {
+    lastCtxClass = *(Class *)_ctx;
+    setObjForKey = [_ctx methodForSelector:@selector(setObject:forKey:)];
+    remObjForKey = [_ctx methodForSelector:@selector(removeObjectForKey:)];
+  }
+}
+static inline void ctxSet(WOContext *_ctx, NSString *_key, NSString *_value) {
+  if (_ctx == nil) return;
+  _updateCtxCache(_ctx);
+  if (setObjForKey)
+    setObjForKey(_ctx, @selector(setObject:forKey:), _value, _key);
+  else
+    [_ctx setObject:_value forKey:_key];
+}
+static inline void ctxDel(WOContext *_ctx, NSString *_key) {
+  if (_ctx == nil) return;
+  _updateCtxCache(_ctx);
+  if (remObjForKey)
+    remObjForKey(_ctx, @selector(removeObjectForKey:), _key);
+  else
+    [_ctx removeObjectForKey:_key];
+}
+
+/* initialization */
+
+- (id)init {
+  if ((self = [super init])) {
+    self->list                 = nil;
+    self->scriptID             = nil;
+    self->groupedList          = nil;
+    self->indexToGrouppath     = nil; // mapping index     -> group path
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->list);
+  RELEASE(self->scriptID);
+  RELEASE(self->indexToGrouppath);
+  RELEASE(self->groupedList);
+  
+  [super dealloc];
+}
+#endif
+
+- (BOOL)requiresFormForNode:(id)_node inContext:(WOContext *)_ctx {
+  if ([self hasAttribute:@"selection" node:_node ctx:_ctx])
+    return YES;
+
+  return [self requiresFormForChildNodes:[_node childNodes] inContext:_ctx];
+}
+
+- (void)updateStateOfNode:(id)_node inContext:(WOContext *)_ctx {
+  WEClientCapabilities *ccaps;
+  BOOL                 isAutoScroll;
+  NSArray              *array;
+  NSArray              *groupings = nil;
+  unsigned             batchIdx, size, cnt;
+  BEGIN_PROFILE;
+
+  //ccaps        = [[_ctx request] clientCapabilities];
+  ccaps = nil;
+  isAutoScroll = [ccaps doesSupportCSSOverflow];
+  self->use.scriptScrolling  = [ccaps isInternetExplorer];
+  self->use.scriptCollapsing = [ccaps isInternetExplorer];
+
+  if (self->use.scriptCollapsing) {
+    self->use.scriptCollapsing =
+      [self boolFor:@"collapseonclient" node:_node ctx:_ctx];
+  }
+  
+  if ([self intFor:@"overflowscroll" node:_node ctx:_ctx] < 10)
+    isAutoScroll = NO;
+  else if (isAutoScroll)
+    self->use.scriptScrolling = NO;
+  
+  /* use JavaScript on InternetExplorer only */
+  self->use.scriptScrolling = (self->use.scriptScrolling)
+    ? (self->state.batchCount > 1)
+    : NO;
+
+  self->use.scriptScrolling = (self->use.scriptScrolling)
+    ? [self boolFor:@"scrollonclient" node:_node ctx:_ctx]
+    : NO;
+
+  array = [self _sortedArrayOfNode:_node inContext:_ctx fetch:YES];
+
+  batchIdx = [self   intFor:@"currentbatch" node:_node ctx:_ctx];
+  size     = [self   intFor:@"batchsize"    node:_node ctx:_ctx];
+  cnt      = [array count];
+  size     = (isAutoScroll) ? cnt : size;
+  batchIdx = (batchIdx) ? batchIdx : 1;
+  batchIdx = ((batchIdx * size) < (cnt+size)) ? batchIdx : 1;
+
+  // get groupings
+  [_ctx setObject:@"YES" forKey:ODR_GroupingContainerMode];
+  [self appendChildNodes:ODRLookupQueryPath(_node, @"-groupings")
+        toResponse:nil
+        inContext:_ctx];
+  [_ctx removeObjectForKey:ODR_GroupingContainerMode];
+  
+  groupings = [_ctx objectForKey:ODR_GroupingContainer];
+  ctxDel(_ctx, ODR_GroupingContainer);
+
+  if ([groupings count] > 0) {
+    EOGrouping   *grouping;
+
+    grouping = [groupings lastObject];
+    [grouping setDefaultName:@"default"];
+    //    [grouping setSortOrderings:[fetchSpec sortOrderings]];
+
+    RELEASE(self->groupedList);
+    self->groupedList = [array arrayGroupedBy:grouping];
+    RETAIN(self->groupedList);
+   
+    RELEASE(self->indexToGrouppath);
+    self->indexToGrouppath =
+      [self->groupedList attributesWithHint:[array count]
+                         andOrderedKeys:[self->groupedList allKeys]];
+    RETAIN(self->indexToGrouppath);
+
+    array = [self->groupedList flattenedArrayWithHint:[array count]
+                               andOrderedKeys:[self->groupedList allKeys]];
+  }
+  else {
+    RELEASE(self->groupedList);      self->groupedList      = nil;
+    RELEASE(self->indexToGrouppath); self->indexToGrouppath = nil;
+  }
+
+  ASSIGN(self->list, array);
+  
+  self->state.currentBatch = batchIdx;
+  self->state.batchSize    = size;
+  
+  self->state.batchCount = (!size) ? 1 :(cnt / size) + ((cnt % size) ? 1 : 0);
+  self->state.firstIndex = (batchIdx - 1) * size;
+  self->state.lastIndex  = (size==0 || !((self->state.firstIndex+size) < cnt))
+    ? cnt-1
+    : self->state.firstIndex + size - 1;
+
+
+  self->use.checkBoxes = [self hasAttribute:@"selection" node:_node ctx:_ctx];
+  self->use.overflow   = isAutoScroll;
+  END_PROFILE;
+}
+
+
+- (void)_setConfigDefaults:(id)_node inContext:(WOContext *)_ctx {
+  BEGIN_PROFILE;
+  ctxSet(_ctx, ODRTableView_toLabel,       @"-" );
+  ctxSet(_ctx, ODRTableView_ofLabel,       @"/" );
+  ctxSet(_ctx, ODRTableView_firstLabel,    @"<<");
+  ctxSet(_ctx, ODRTableView_previousLabel, @"<" );
+  ctxSet(_ctx, ODRTableView_nextLabel,     @">" );
+  ctxSet(_ctx, ODRTableView_lastLabel,     @">>");
+  END_PROFILE;
+}
+
+static void
+_SetConfigInContext(ODR_bind_tableview *self, id _node, WOContext *_ctx,
+                    NSString *_attr_, NSString *_key_)
+{
+  register NSString *tmp;
+
+  if ((tmp = [self stringFor:_attr_ node:_node ctx:_ctx]))
+    ctxSet(_ctx, _key_, tmp);
+}
+
+- (void)updateConfig:(id)_node inContext:(WOContext *)_ctx {
+  BEGIN_PROFILE;
+
+  [self _setConfigDefaults:_node inContext:_ctx];
+  
+  PROFILE_CHECKPOINT("config defaults");
+  
+#define SetConfigInContext(_attr_,_key_) \
+  _SetConfigInContext(self,_node,_ctx,_attr_,_key_)
+  
+  SetConfigInContext(@"titleColor",      ODRTableView_titleColor);
+  SetConfigInContext(@"headerColor",     ODRTableView_headerColor);
+  SetConfigInContext(@"footerColor",     ODRTableView_footerColor);
+  SetConfigInContext(@"evenColor",       ODRTableView_evenColor);
+  SetConfigInContext(@"oddColor",        ODRTableView_oddColor);
+  SetConfigInContext(@"fontColor",       ODRTableView_fontColor);
+  SetConfigInContext(@"fontFace",        ODRTableView_fontFace);
+  SetConfigInContext(@"fontSize",        ODRTableView_fontSize);
+
+  PROFILE_CHECKPOINT("configs");
+  
+  SetConfigInContext(@"downwardIcon",    ODRTableView_downwardIcon);
+  SetConfigInContext(@"upwardIcon",      ODRTableView_upwardIcon);
+  SetConfigInContext(@"nonSortIcon",     ODRTableView_nonSortIcon);
+  
+  SetConfigInContext(@"firstIcon",       ODRTableView_first);
+  SetConfigInContext(@"firstBlind",      ODRTableView_first_blind);
+  SetConfigInContext(@"previousIcon",    ODRTableView_previous);
+  SetConfigInContext(@"previousBlind",   ODRTableView_previous_blind);
+  SetConfigInContext(@"nextIcon",        ODRTableView_next);
+  SetConfigInContext(@"nextBlind",       ODRTableView_next_blind);
+  SetConfigInContext(@"lastIcon",        ODRTableView_last);
+  SetConfigInContext(@"lastBlind",       ODRTableView_last_blind);
+
+  SetConfigInContext(@"openedIcon",      ODRTableView_openedIcon);
+  SetConfigInContext(@"closedIcon",      ODRTableView_closedIcon);
+
+  SetConfigInContext(@"minusResizeIcon", ODRTableView_minusIcon);
+  SetConfigInContext(@"plusResizeIcon",  ODRTableView_plusIcon);
+  
+  SetConfigInContext(@"selectAllIcon",   ODRTableView_select_all);
+  SetConfigInContext(@"deselectAllIcon", ODRTableView_deselect_all);
+
+  PROFILE_CHECKPOINT("icons");
+  
+  SetConfigInContext(@"ofLabel",         ODRTableView_ofLabel);
+  SetConfigInContext(@"toLabel",         ODRTableView_toLabel);
+  SetConfigInContext(@"firstLabel",      ODRTableView_firstLabel);
+  SetConfigInContext(@"previousLabel",   ODRTableView_previousLabel);
+  SetConfigInContext(@"nextLabel",       ODRTableView_nextLabel);
+  SetConfigInContext(@"lastLabel",       ODRTableView_lastLabel);
+  SetConfigInContext(@"pageLabel",       ODRTableView_pageLabel);
+  SetConfigInContext(@"sortLabel",       ODRTableView_sortLabel);
+  
+#undef SetConfigInContext
+  END_PROFILE;
+}
+
+- (void)updateScriptIdInContext:(WOContext *)_ctx {
+  NSArray  *tmp;
+  NSString *str;
+  
+  tmp = [[_ctx elementID] componentsSeparatedByString:@"."];
+  str = [tmp componentsJoinedByString:@"_"];
+  
+  ASSIGNCOPY(self->scriptID, str);
+}
+
+- (void)removeConfigInContext:(WOContext *)_ctx {
+  BEGIN_PROFILE;
+  ctxDel(_ctx,ODRTableView_titleColor);
+  ctxDel(_ctx,ODRTableView_headerColor);
+  ctxDel(_ctx,ODRTableView_footerColor);
+  ctxDel(_ctx,ODRTableView_evenColor);
+  ctxDel(_ctx,ODRTableView_oddColor);
+  ctxDel(_ctx,ODRTableView_fontColor);
+  ctxDel(_ctx,ODRTableView_fontFace);
+  ctxDel(_ctx,ODRTableView_fontSize);
+  
+  ctxDel(_ctx,ODRTableView_downwardIcon);
+  ctxDel(_ctx,ODRTableView_upwardIcon);
+  ctxDel(_ctx,ODRTableView_nonSortIcon);
+
+  ctxDel(_ctx,ODRTableView_first);
+  ctxDel(_ctx,ODRTableView_first_blind);
+  ctxDel(_ctx,ODRTableView_previous);
+  ctxDel(_ctx,ODRTableView_previous_blind);
+  ctxDel(_ctx,ODRTableView_next);
+  ctxDel(_ctx,ODRTableView_next_blind);
+  ctxDel(_ctx,ODRTableView_last);
+  ctxDel(_ctx,ODRTableView_last_blind);
+  ctxDel(_ctx,ODRTableView_select_all);
+  ctxDel(_ctx,ODRTableView_deselect_all);
+
+  ctxDel(_ctx,ODRTableView_ofLabel);
+  ctxDel(_ctx,ODRTableView_toLabel);
+  ctxDel(_ctx,ODRTableView_firstLabel);
+  ctxDel(_ctx,ODRTableView_previousLabel);
+  ctxDel(_ctx,ODRTableView_nextLabel);
+  ctxDel(_ctx,ODRTableView_lastLabel);
+  ctxDel(_ctx,ODRTableView_pageLabel);
+  ctxDel(_ctx,ODRTableView_sortLabel);
+  END_PROFILE;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  int            i, firstBatch, lastBatch;
+  NSString       *eid;
+  NSMutableArray *selArray = nil;
+  BEGIN_PROFILE;
+
+  [self updateStateOfNode:_node inContext:_ctx];
+
+  eid = [_ctx elementID];
+
+  // handle "data" section
+  if (self->use.checkBoxes) {
+    selArray = [self valueFor:@"selection" node:_node ctx:_ctx];
+    selArray = (selArray == nil)
+      ? [[NSMutableArray allocWithZone:[self zone]] init]
+      : [selArray mutableCopyWithZone:[self zone]];
+  }
+
+  firstBatch = (self->use.scriptScrolling) ? 1 : self->state.currentBatch;
+  
+  lastBatch  = (self->use.scriptScrolling)
+    ? self->state.batchCount
+    : self->state.currentBatch;
+
+  [_ctx appendElementIDComponent:@"data"];
+
+  for (i = firstBatch; i <= lastBatch; i++) {    
+    self->state.currentBatch = i;
+    [self forceSetInt:i for:@"currentbatch" node:_node ctx:_ctx];
+    [self updateStateOfNode:_node inContext:_ctx];
+
+    [self takeValuesForNode:_node
+          fromRequest:_request
+          forBatch:i
+          selections:selArray
+          inContext:_ctx];
+  }
+
+  [_ctx deleteLastElementIDComponent]; // delete "data"
+
+  if (self->use.checkBoxes) {
+    [self setValue:selArray for:@"selection" node:_node ctx:_ctx];
+    [selArray release];
+  }
+
+  {
+    // handle header (sort buttons, ...)
+    ctxSet(_ctx, ODRTableView_HeaderMode, @"YES");
+    [_ctx appendElementIDComponent:@"header"];
+  
+    for (i = 1; i <= (int)self->state.batchCount; i++) {
+      [_ctx appendElementIDComponent:[NSString stringWithFormat:@"%d", i]];
+      [self takeValuesForChildNodes:[_node childNodes]
+            fromRequest:_request
+            inContext:_ctx];
+      [_ctx deleteLastElementIDComponent]; // delete batchNumber
+    }
+
+    [_ctx deleteLastElementIDComponent]; // delete "header"
+    ctxDel(_ctx, ODRTableView_HeaderMode);
+  }
+
+  // handle title
+  ctxSet(_ctx, ODRTableView_TitleMode, @"YES");
+  [_ctx appendElementIDComponent:@"title"];
+  [self takeValuesForChildNodes:ODRLookupQueryPath(_node, @"-ttitle")
+        fromRequest:_request
+        inContext:_ctx];
+  [_ctx deleteLastElementIDComponent]; // delete "title"
+  ctxDel(_ctx, ODRTableView_TitleMode);
+  
+  // handle buttons
+  ctxSet(_ctx, ODRTableView_ButtonMode, @"YES");
+  [_ctx appendElementIDComponent:@"button"];
+  [self takeValuesForChildNodes:ODRLookupQueryPath(_node, @"-tbutton")
+        fromRequest:_request
+        inContext:_ctx];
+  [_ctx deleteLastElementIDComponent]; // delete "button"
+  ctxDel(_ctx, ODRTableView_ButtonMode);
+
+  // handle footer
+  [_ctx appendElementIDComponent:@"footer"];
+
+  // reset autoScrollHeight
+  if ([_request formValueForKey:
+                [eid stringByAppendingString:@".footer.pp.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".pp"]];
+  }
+  else if ([_request formValueForKey:
+                     [eid stringByAppendingString:@".footer.mm.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".mm"]];
+  }
+
+  ctxSet(_ctx, ODRTableView_FooterMode, @"YES");
+  [self takeValuesForChildNodes:ODRLookupQueryPath(_node, @"-tfooter")
+        fromRequest:_request
+        inContext:_ctx];
+  ctxDel(_ctx, ODRTableView_FooterMode);
+  [_ctx deleteLastElementIDComponent]; // delete "footer"
+
+  if ([_request formValueForKey:[eid stringByAppendingString:@".first.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".first"]];
+  }
+  if ([_request formValueForKey:[eid stringByAppendingString:@".next.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".next"]];
+  }
+  if ([_request formValueForKey:[eid stringByAppendingString:@".last.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".last"]];
+  }
+  if ([_request formValueForKey:[eid stringByAppendingString:@".previous.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".previous"]];
+  }
+
+  END_PROFILE;
+}
+
+- (id)invokeDataActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *idxId;
+  NSString *bn;
+  id result = nil;
+    
+#if DEBUG && 0
+  NSLog(@"%s:   data section eid=%@, sid=%@",
+        __PRETTY_FUNCTION__, [_ctx elementID], [_ctx senderID]);
+#endif
+    
+  bn = [_ctx currentElementID];
+  [self forceSetInt:[bn intValue] for:@"currentbatch" node:_node ctx:_ctx];
+  
+  [_ctx consumeElementID];            // consume batchNumber
+  [_ctx appendElementIDComponent:bn]; // append batch
+  
+#if DEBUG && 0
+  NSLog(@"%s:   did data-batch section eid=%@, sid=%@",
+        __PRETTY_FUNCTION__, [_ctx elementID], [_ctx senderID]);
+#endif
+  
+  if ((idxId = [_ctx currentElementID])) {
+    [_ctx consumeElementID];               // consume index-id
+    [_ctx appendElementIDComponent:idxId]; // append index-id
+
+#if DEBUG && 0
+    NSLog(@"%s:   did data-index section (idx=%@) eid=%@, sid=%@",
+          __PRETTY_FUNCTION__, idxId, [_ctx elementID], [_ctx senderID]);
+#endif
+    
+    /* reset batchSize */
+    if ([idxId isEqualToString:@"pp"])
+      result = [self increaseBatchSize:_node inContext:_ctx];
+    else if ([idxId isEqualToString:@"mm"])
+      result = [self decreaseBatchSize:_node inContext:_ctx];
+    else {
+      if (![self hasAttribute:@"identifier" node:_node ctx:_ctx]) {
+        unsigned idx;
+      
+        idx   = [idxId unsignedIntValue];
+        if (idx < [self->list count] && idx >= 0)
+          [self _applyItemForIndex:idx node:_node ctx:_ctx];
+        else
+          NSLog(@"%s: index is out of range!", __PRETTY_FUNCTION__);
+      }
+      else
+        [self _applyIdentifier:idxId node:_node ctx:_ctx];
+
+      result = [self _invokeGrouping:_node
+                     fromRequest:_request
+                     inContext:_ctx];
+    }
+    [_ctx deleteLastElementIDComponent]; // delete index-id
+  }
+#if DEBUG
+  else {
+    NSLog(@"%s:   missing idx section eid=%@, sid=%@",
+          __PRETTY_FUNCTION__, [_ctx elementID], [_ctx senderID]);
+  }
+#endif
+    
+  [_ctx deleteLastElementIDComponent]; // delete batchNumber
+
+  return result;
+}
+
+- (id)invokeHeaderActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  id  result = nil;
+  int bn;
+
+  if ([self isSettable:@"currentbatch" node:_node ctx:_ctx]) {
+    bn = [[_ctx currentElementID] intValue];
+    [self setInt:bn for:@"currentbatch" node:_node ctx:_ctx];
+  }
+  [_ctx appendElementIDComponent:[_ctx currentElementID]]; // batchNumber
+  [_ctx consumeElementID];                         // consume batchNumber
+
+  // handle selectAllCheckBoxes:
+  if ([[_ctx currentElementID] isEqualToString:@"_sa"]) {
+    NSMutableArray *selArray;
+        
+    selArray = [self->list mutableCopyWithZone:[self zone]];
+    // ??? [self->selection setValue:selArray inComponent:cmp];
+    RELEASE(selArray);
+  }
+  // handle deselectAllCheckBoxes:
+  else if ([[_ctx currentElementID] isEqualToString:@"_dsa"]) {
+    ; // ???[self->selection setValue:[NSMutableArray array] inComponent:cmp];
+  }
+  else {
+    ctxSet(_ctx, ODRTableView_HeaderMode, @"YES");
+    result = [self invokeActionForChildNodes:[_node childNodes]
+                   fromRequest:_request inContext:_ctx];
+    ctxDel(_ctx, ODRTableView_HeaderMode);
+  } 
+  [_ctx deleteLastElementIDComponent]; // delete batchNumber
+  
+  return result;
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *eid;
+  NSArray  *children;
+  id       result;
+
+#if DEBUG && 0
+  NSLog(@"%s: node=%@, eid=%@, sid=%@",
+        __PRETTY_FUNCTION__, _node, [_ctx elementID], [_ctx senderID]);
+#endif
+  
+  [self updateStateOfNode:_node inContext:_ctx];
+
+  eid = [_ctx currentElementID];
+
+  if ([eid isEqual:@"first"])
+    return [self _handleFirstButton:_node inContext:_ctx];
+  else if ([eid isEqual:@"previous"])
+    return [self _handlePreviousButton:_node inContext:_ctx];
+  else if ([eid isEqual:@"next"])
+    return [self _handleNextButton:_node inContext:_ctx];
+  else if ([eid isEqual:@"last"])
+    return [self _handleLastButton:_node inContext:_ctx];
+  else if ([eid isEqual:@"data"]) {
+    [_ctx consumeElementID];             // consume "data"
+    [_ctx appendElementIDComponent:eid]; // append  "data"
+    
+    result = [self invokeDataActionForNode:_node
+                   fromRequest:_request
+                   inContext:_ctx];
+    
+    [_ctx deleteLastElementIDComponent]; // delete "data"
+  }
+  else if ([eid isEqual:@"header"]) {
+    [_ctx consumeElementID];             // consume "header"
+    [_ctx appendElementIDComponent:eid]; // append  "header"
+    
+    result = [self invokeHeaderActionForNode:_node
+                   fromRequest:_request
+                   inContext:_ctx];
+    
+    [_ctx deleteLastElementIDComponent]; // delete "header"
+
+    [self _handleSortAction:_node inContext:_ctx];
+    
+    ctxDel(_ctx, ODRTableView_SORTEDKEY);
+    ctxDel(_ctx, ODRTableView_ISDESCENDING);
+  }
+  else if ([eid isEqual:@"title"]) {
+    children = ODRLookupQueryPath(_node, @"-ttitle");
+    
+    [_ctx consumeElementID];
+    [_ctx appendElementIDComponent:@"title"];
+
+    eid = [_ctx currentElementID];
+    ctxSet(_ctx, ODRTableView_TitleMode, @"YES");
+    result = [self invokeActionForChildNodes:children
+                   fromRequest:_request inContext:_ctx];
+    ctxDel(_ctx, ODRTableView_TitleMode);
+    
+    [_ctx deleteLastElementIDComponent];
+  }
+  else if ([eid isEqual:@"button"]) {
+    children = ODRLookupQueryPath(_node, @"-tbutton");
+    
+    [_ctx consumeElementID];
+    [_ctx appendElementIDComponent:@"button"];
+
+    eid = [_ctx currentElementID];
+    ctxSet(_ctx, ODRTableView_ButtonMode, @"YES");
+    result = [self invokeActionForChildNodes:children
+                   fromRequest:_request inContext:_ctx];
+    ctxDel(_ctx, ODRTableView_ButtonMode);
+    
+    [_ctx deleteLastElementIDComponent];
+  }
+  else if ([eid isEqual:@"footer"]) {
+    children = ODRLookupQueryPath(_node, @"-tfooter");
+    
+    [_ctx consumeElementID];
+    [_ctx appendElementIDComponent:@"footer"];
+
+    eid = [_ctx currentElementID];
+    
+    // reset autoScrollHeight
+    if ([eid isEqualToString:@"pp"])
+      result = [self increaseAutoScrollHeight:_node inContext:_ctx];
+    else if ([eid isEqualToString:@"mm"])
+      result = [self decreaseAutoScrollHeight:_node inContext:_ctx];
+    else {
+      ctxSet(_ctx, ODRTableView_FooterMode, @"YES");
+      result = [self invokeActionForChildNodes:children
+                     fromRequest:_request inContext:_ctx];
+      ctxDel(_ctx, ODRTableView_FooterMode);
+    }
+    
+    [_ctx deleteLastElementIDComponent];
+  }
+  else
+    result = [self invokeActionForChildNodes:[_node childNodes]
+                   fromRequest:_request inContext:_ctx];
+  
+  return result;
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  BEGIN_PROFILE;
+  
+  [self updateStateOfNode:_node inContext:_ctx];
+  [self updateScriptIdInContext:_ctx];
+  [self updateConfig:_node      inContext:_ctx];
+  
+  /* open tableView */
+  [_response appendContentString:
+          @"<table border='0' width='100%' cellpadding='0' cellspacing='0'>"];
+
+  /* append tableTitle + navigation */
+  [self _appendTitle:_node toResponse:_response inContext:_ctx];
+
+  [_response appendContentString:@"<tr><td></td></tr>\n"];
+  
+  if (self->use.scriptScrolling) {
+    [self _appendTableContentAsScript:_node
+          toResponse:_response
+          inContext:_ctx]; //close tables
+  }
+  else {
+    /* open header + data area */
+    [_response appendContentString:@"\n<tr><td>\n"];
+    
+    if (self->use.overflow) {
+      [_response appendContentString:
+                 @"<p style=\"width:100%; height: "];
+      [_response appendContentString:
+                   [self stringFor:@"overflowscroll" node:_node ctx:_ctx]];
+      [_response appendContentString:@"; overflow-y: auto\">"];
+    }
+    
+    [_response appendContentString:
+                 @"<table border='0' width='100%' "
+                 @"cellpadding='1' cellspacing='0'>"];
+
+    self->use.batchResizeButtons =
+      ([self boolFor:@"showbatchresizebuttons" node:_node ctx:_ctx] &&
+       (self->state.currentBatch < self->state.batchCount) &&
+       !self->use.overflow);
+    
+    [self _appendHeader:_node toResponse:_response inContext:_ctx];
+    [self _appendData:_node   toResponse:_response inContext:_ctx];
+  
+    [_response appendContentString:@"</table>\n"];
+    if (self->use.overflow)
+      [_response appendContentString:@"</p>"];
+    
+    /* close header + data area */
+    [_response appendContentString:@"</td></tr>\n"];
+    
+    [_response appendContentString:@"</table>\n"];                  // </TABLE>
+
+    /* append footer */
+    [self _appendFooter:_node toResponse:_response inContext:_ctx];
+  }
+  
+  // close tableView
+  
+  if (self->use.scriptScrolling)
+    [self appendJavaScript:_response inContext:_ctx];
+  
+  [self removeConfigInContext:_ctx];
+
+  END_PROFILE;
+}
+
+@end /* ODR_bind_tableview */
+
+@implementation ODR_bind_ttitle : ODNodeRenderer
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if ([[_ctx objectForKey:ODRTableView_TitleMode] boolValue])
+    [super takeValuesForNode:_node fromRequest:_request inContext:_ctx];
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  return ([[_ctx objectForKey:ODRTableView_TitleMode] boolValue])
+    ? [super invokeActionForNode:_node fromRequest:_request inContext:_ctx]
+    : nil;
+}
+
+- (void)appendNode:(id)_node
+        toResponse:(WOResponse *)_response
+         inContext:(WOContext *)_ctx
+{
+  if ([[_ctx objectForKey:ODRTableView_TitleMode] boolValue])
+    [super appendNode:_node toResponse:_response inContext:_ctx];
+}
+
+@end
+
+@implementation ODR_bind_tbutton : ODNodeRenderer
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if ([[_ctx objectForKey:ODRTableView_ButtonMode] boolValue])
+    [super takeValuesForNode:_node fromRequest:_request inContext:_ctx];
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  return ([[_ctx objectForKey:ODRTableView_ButtonMode] boolValue])
+    ? [super invokeActionForNode:_node fromRequest:_request inContext:_ctx]
+    : nil;
+}
+
+- (void)appendNode:(id)_node
+        toResponse:(WOResponse *)_response
+         inContext:(WOContext *)_ctx
+{
+  if ([[_ctx objectForKey:ODRTableView_ButtonMode] boolValue])
+    [super appendNode:_node toResponse:_response inContext:_ctx];
+}
+@end
+
+@implementation ODR_bind_tfooter : ODNodeRenderer
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if ([[_ctx objectForKey:ODRTableView_FooterMode] boolValue])
+    [super takeValuesForNode:_node fromRequest:_request inContext:_ctx];
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  return ([[_ctx objectForKey:ODRTableView_FooterMode] boolValue])
+    ? [super invokeActionForNode:_node fromRequest:_request inContext:_ctx]
+    : nil;
+}
+
+- (void)appendNode:(id)_node
+        toResponse:(WOResponse *)_response
+         inContext:(WOContext *)_ctx
+{
+  if ([[_ctx objectForKey:ODRTableView_FooterMode] boolValue])
+    [super appendNode:_node toResponse:_response inContext:_ctx];
+}
+@end
+
+@implementation ODR_bind_tgroup : ODNodeRenderer
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if ([[_ctx objectForKey:ODRTableView_GroupMode] boolValue])
+    [super takeValuesForNode:_node fromRequest:_request inContext:_ctx];
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  //  NSLog(@"tgroup ... invokeActionForNode ");
+  return nil;
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if (![[_ctx objectForKey:ODRTableView_GroupMode] boolValue])
+    return;
+  
+  if ([self isSettable:@"items" node:_node ctx:_ctx])
+    [self setValue:[_ctx objectForKey:ODRTableView_GroupItems]
+          for:@"items"
+          node:_node
+          ctx:_ctx];
+
+  if ([self isSettable:@"groupname" node:_node ctx:_ctx])
+    [self setString:[_ctx objectForKey:ODRTableView_GroupName]
+          for:@"groupname"
+          node:_node
+          ctx:_ctx];
+
+  [self appendChildNodes:[_node childNodes]
+        toResponse:_response
+        inContext:_ctx];
+}
+@end
+
+@implementation ODRTableViewInfo
+@end
+
+
+#define ProfileComponents NO
+
+@implementation NSDictionary(ODR_bind_tableview)
+
+- (NSArray *)flattenedArrayWithHint:(unsigned int)_hint
+                     andOrderedKeys:(NSArray *)_keys
+{
+  NSMutableArray *result  = nil;
+  unsigned int   i, cnt;
+  NSTimeInterval st     = 0.0;
+  
+  if (ProfileComponents)
+    st = [[NSDate date] timeIntervalSince1970];
+
+
+  result = [[NSMutableArray allocWithZone:[self zone]]
+                            initWithCapacity:_hint]; // should be improved
+
+  for (i = 0, cnt = [_keys count]; i < cnt; i++) {
+    NSString *key;
+    NSArray  *tmp;
+
+    key = [_keys objectAtIndex:i];
+    tmp = [self objectForKey:key];
+    [result addObjectsFromArray:tmp];
+  }
+
+  if (ProfileComponents) {
+    NSTimeInterval diff;
+    diff = [[NSDate date] timeIntervalSince1970] - st;
+    
+    printf("NSDictionary.flattenedArray: %0.4fs\n", diff);
+  }
+  
+  return result;
+}
+
+- (NSArray *)attributesWithHint:(unsigned int)_hint
+                        andOrderedKeys:(NSArray *)_keys
+{
+  NSMutableArray *result  = nil;
+  unsigned int   i, cnt;
+  NSTimeInterval st     = 0.0;
+  
+  if (ProfileComponents)
+    st = [[NSDate date] timeIntervalSince1970];
+
+  result = [[NSMutableArray allocWithZone:[self zone]]
+                            initWithCapacity:_hint+1];
+
+  for (i = 0, cnt = [_keys count]; i < cnt; i++) {
+    unsigned j, cnt2;
+    NSString *key;
+
+    key  = [_keys objectAtIndex:i];
+
+    cnt2 = [[self objectForKey:key] count];
+    for (j = 0; j < cnt2; j++)
+      /* ??? [result addObject:key]; */
+      [result addObject:[NSArray arrayWithObject:key]];
+  }
+
+  if (ProfileComponents) {
+    NSTimeInterval diff;
+    diff = [[NSDate date] timeIntervalSince1970] - st;
+    
+    printf("NSDictionary.attributes: %0.4fs\n", diff);
+  }
+  
+  return result;
+}
+
+- (NGBitSet *)bitSetWithHint:(unsigned int)_hint {
+  NGBitSet     *bitSet  = nil;
+  NSEnumerator *keyEnum = [self keyEnumerator];
+  NSString     *key     = nil;
+  unsigned int firstPos = 0;
+  NSTimeInterval st     = 0.0;
+  
+  if (ProfileComponents)
+    st = [[NSDate date] timeIntervalSince1970];
+  bitSet = [NGBitSet bitSetWithCapacity:_hint];
+  
+  while ((key = [keyEnum nextObject])) {
+    [bitSet addMember:firstPos];
+    firstPos += [[self objectForKey:key] count];
+  }
+
+  if (ProfileComponents) {
+    NSTimeInterval diff;
+    diff = [[NSDate date] timeIntervalSince1970] - st;
+    
+    printf("NSDictionary.bitSet: %0.4fs\n", diff);
+  }
+  
+  return bitSet;
+}
+
+@end /* NSDictionary(ODR_bind_tableview) */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tabview.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_tabview.m
new file mode 100644 (file)
index 0000000..15301cd
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODR_bind_tabview.h>
+#ifdef __APPLE__
+#include <NGObjWeb/WEClientCapabilities.h>
+#else
+#include <WEExtensions/WEClientCapabilities.h>
+#endif
+
+/*
+   <var:tabview selection="selection"
+                bgcolor="bgcolor"
+                inactivecolor="inactivecolor"
+                activecolor="activecolor"
+                bgiconleft="inactivebgiconleft"
+                bgicon="inactivebgicon"
+                activebgicon="activebgicon">
+
+     <tab const:title="tab 1" const:key="tab1">
+       content of tab 1
+     </tab>
+
+     <tab const:title="tab 2" const:key="tab2">
+       content of tab 2
+     </tab>
+   
+   </var:tabview>
+
+   tabview attributes:
+     selection
+     bgcolor
+     inactivecolor
+     activecolor
+     bgiconleft
+     bgicon
+     activebgicon
+     
+   tab attributes:
+     disabled - bool
+     title    - String
+     key      - String
+     fontcolor
+     fontface
+     fontsize
+*/
+
+/* context keys */
+
+#include "common.h"
+
+@implementation ODR_bind_tabview
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->activeKey);
+  [super dealloc];
+}
+#endif
+
+- (void)_setActiveKey:(NSString *)_activeKey {
+  ASSIGN(self->activeKey, _activeKey);
+}
+
+- (void)setActiveKey:(id)_node inContext:(WOContext *)_ctx {
+  NSArray        *tabNodes;
+  NSMutableArray *keys;
+  int            i, cnt;
+
+  [self _setActiveKey:[self stringFor:@"selection" node:_node ctx:_ctx]];
+  keys      = [[NSMutableArray allocWithZone:[self zone]] initWithCapacity:8];
+  tabNodes  = ODRLookupQueryPath(_node, @"-tab");
+  cnt       = [tabNodes count];
+
+  for (i=0; i < cnt; i++) {
+    NSString *key = nil;
+    id       tab;
+
+    tab = [tabNodes objectAtIndex:i];
+    key = [self stringFor:@"key" node:tab ctx:_ctx];
+    if (key == nil) {
+      key = [NSString stringWithFormat:@"%d", i];
+      [self forceSetString:key for:@"key" node:tab ctx:_ctx];
+    }
+    [keys addObject:key];
+  }
+  /* selection is not available in keys */
+  if (![keys containsObject:self->activeKey])
+    [self _setActiveKey:nil];
+  
+  /* no or invalid selection, use first key */
+  if ((self->activeKey == nil) && ([keys count] > 0))
+    [self _setActiveKey:[[keys objectAtIndex:0] stringValue]];
+
+  [self forceSetString:self->activeKey for:@"selection" node:_node ctx:_ctx];
+
+  RELEASE(keys);  
+}
+
+/* responder */
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSArray  *tabs;
+  unsigned i, cnt;
+  
+  /* set ODR_bind_tabview_ACTIVEKEY */
+  [self setActiveKey:_node inContext:_ctx];
+
+  tabs = ODRLookupQueryPath(_node, @"-tab");
+  cnt  = [tabs count];
+    
+  [_ctx appendElementIDComponent:@"b"];
+  [_ctx appendElementIDComponent:self->activeKey];
+  
+  for (i = 0; i < cnt; i++) {
+    NSString *key;
+    id       tab;
+
+    tab = [tabs objectAtIndex:i];
+    key = [self stringFor:@"key" node:tab ctx:_ctx];
+
+    if ([key isEqualToString:self->activeKey]) {
+      [super takeValuesForNode:tab fromRequest:_request inContext:_ctx];
+      break;
+    }
+  }
+  [_ctx deleteLastElementIDComponent]; // activeKey 
+  [_ctx deleteLastElementIDComponent]; /* 'b' */
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *section;
+  id       result = nil;
+  
+  if ((section = [_ctx currentElementID])) {
+    /* header action */    
+    if ([section isEqualToString:@"h"]) {
+      
+      [_ctx consumeElementID];
+      
+      [self forceSetString:[_ctx currentElementID]
+            for:@"selection"
+            node:_node
+            ctx:_ctx];
+      
+    }
+    /* body action */
+    else if ([section isEqualToString:@"b"]) {
+      NSString *selection;
+      NSArray  *tabs;
+      int      i, cnt;
+      
+      selection = [self stringFor:@"selection" node:_node ctx:_ctx];
+      tabs      = ODRLookupQueryPath(_node, @"-tab");
+      cnt       = [tabs count];
+      
+      [_ctx consumeElementID];
+      [_ctx appendElementIDComponent:section];
+
+      for (i = 0; i < cnt; i++) {
+        NSString *key;
+        id       tab;
+
+        tab = [tabs objectAtIndex:i];
+        key = [self stringFor:@"key" node:tab ctx:_ctx];
+
+        if ([key isEqualToString:selection]) {
+          [_ctx appendElementIDComponent:key];
+          [_ctx consumeElementID];
+          result = [super invokeActionForNode:tab
+                          fromRequest:_request
+                          inContext:_ctx];
+          [_ctx deleteLastElementIDComponent];
+          break;
+        }
+      }
+      [_ctx deleteLastElementIDComponent];
+    }
+  }
+  return result;
+}
+
+- (void)appendTab:(id)_tab
+  node:(id)_node
+  response:(WOResponse *)_response
+  ctx:(WOContext *)_ctx
+  left:(BOOL)_isLeft
+{
+  NSString *key       = nil;
+  NSString *title     = nil;
+  NSString *bgcolor   = nil;
+  NSString *width     = nil;
+  NSString *height    = nil;
+  NSString *bgIcon    = nil;
+  BOOL     isActive;
+  NSString *tC, *tF, *tS; // text font attrtibutes
+  BOOL     hasFont;
+
+
+  key       = [self stringFor:@"key"   node:_tab ctx:_ctx];
+  title     = [self stringFor:@"title" node:_tab ctx:_ctx];
+  isActive  = [key isEqualToString:self->activeKey];
+  
+  width     = [self stringFor:@"width"  node:_node ctx:_ctx];
+  height    = [self stringFor:@"height" node:_node ctx:_ctx];
+  bgIcon    = (isActive)
+    ? [self stringFor:@"activebgicon" node:_node ctx:_ctx]
+    : ((_isLeft) ? [self stringFor:@"bgiconleft" node:_node ctx:_ctx]
+                 : [self stringFor:@"bgicon"     node:_node ctx:_ctx]);
+  bgIcon    = ODRUriOfResource(bgIcon, _ctx);
+       
+  bgcolor   = (isActive)
+    ? [self stringFor:@"activecolor"   node:_node ctx:_ctx]
+    : [self stringFor:@"inactivecolor" node:_node ctx:_ctx];
+  
+  title = (title) ? title : key;
+  
+  [_ctx appendElementIDComponent:key]; // append tab-key
+  
+  // append <td ...>
+  [_response appendContentString:@"<td align=\"center\" valign=\"bottom\""];
+  if (bgcolor) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentString:bgcolor];
+    [_response appendContentCharacter:'"'];
+  }
+  if (width) {
+    [_response appendContentString:@" width=\""];
+    [_response appendContentString:width];
+    [_response appendContentCharacter:'"'];
+  }
+  if (height) {
+    [_response appendContentString:@" height=\""];
+    [_response appendContentString:height];
+    [_response appendContentCharacter:'"'];
+  }
+  if (bgIcon) {
+    [_response appendContentString:@" background=\""];
+    [_response appendContentString:bgIcon];
+    [_response appendContentCharacter:'"'];
+  }
+  [_response appendContentCharacter:'>'];
+  
+  [_response appendContentString:@"<a href='"];
+  [_response appendContentHTMLAttributeValue:[_ctx componentActionURL]];
+  [_response appendContentString:@"' style=\"text-decoration: none;\">"];
+  
+  tC  = [self stringFor:@"fontcolor" node:_node ctx:_ctx];
+  tF  = [self stringFor:@"fontface"  node:_node ctx:_ctx];
+  tS  = [self stringFor:@"fontsize"  node:_node ctx:_ctx];
+  
+  hasFont = (tC || tF || tS) ? YES : NO;
+  
+  if (hasFont)
+    ODRAppendFont(_response, tC, tF, tS);                      //   <font...>
+  
+  if (isActive)
+    [_response appendContentString:@"<b>"];
+
+  if (!(bgIcon || bgcolor))
+    [_response appendContentString:@"["];
+  
+  [_response appendContentString:title];
+  
+  if (!(bgIcon || bgcolor))
+    [_response appendContentString:@"]"];
+
+  if (isActive)
+    [_response appendContentString:@"</b>"];
+
+  if (hasFont)
+    [_response appendContentString:@"</font"];
+  
+  [_response appendContentString:@"</a>"];
+
+  [_response appendContentString:@"</td>"];
+  
+  [_ctx deleteLastElementIDComponent]; // delete tab-key
+}
+
+- (void)appendHeaderFootRow:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  isLeftActive:(BOOL)_isLeftActive
+{
+  NSString *bgcolor = nil;
+  
+  /* header foot row */
+  bgcolor = [self stringFor:@"bgcolor" node:_node ctx:_ctx];
+
+  [_response appendContentString:@"<tr"];
+  if (bgcolor) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentHTMLAttributeValue:bgcolor];
+    [_response appendContentString:@"\""];
+  }
+  [_response appendContentString:@">"];
+    
+    /* left corner */
+  [_response appendContentString:@"<td align=\"left\" width=\"10\">"];
+  
+  if (_isLeftActive)
+    [_response appendContentString:@"&nbsp;"];
+    
+  if (!_isLeftActive) {
+    NSString *uri;
+
+    uri = [self stringFor:@"leftcornericon" node:_node ctx:_ctx];
+    if ((uri = ODRUriOfResource(uri, _ctx))) {
+      [_response appendContentString:@"<img border=\"0\" alt=\"\" src=\""];
+      [_response appendContentString:uri];
+      [_response appendContentString:@"\" />"];
+    }
+    else
+      [_response appendContentString:@"&nbsp;"];
+  }
+  [_response appendContentString:@"</td>"];
+
+  /* right corner */
+  [_response appendContentString:@"<td align=\"right\">"];
+  {
+    NSString *uri;
+    
+    uri = [self stringFor:@"rightcornericon" node:_node ctx:_ctx];
+    if ((uri = ODRUriOfResource(uri, _ctx))) {
+      [_response appendContentString:@"<img border=\"0\" alt=\"\" src=\""];
+      [_response appendContentString:uri];
+      [_response appendContentString:@"\" />"];
+    }
+    else
+      [_response appendContentString:@"&nbsp;"];
+  }
+  [_response appendContentString:@"</td>"];
+    
+  [_response appendContentString:@"</tr>"];
+}
+
+- (void)appendTabs:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSArray  *tabNodes;
+  NSString *selection;
+  BOOL     isLeftActive = NO, isFirst;
+  unsigned i, count;
+  
+  [_ctx appendElementIDComponent:@"h"];
+
+  tabNodes  = ODRLookupQueryPath(_node, @"-tab");
+  selection = self->activeKey;
+  
+  /* generate header row */
+  
+  [_response appendContentString:@"<tr>"];
+  [_response appendContentString:
+               @"<td colspan='2'>"
+               @"<table border='0' cellpadding='0' "
+               @"cellspacing='0'><tr>"];
+  
+  for (i = 0, isFirst = YES, count = [tabNodes count]; i < count; i++) {
+    NSString *key;
+    id       tab;
+    
+    tab = [tabNodes objectAtIndex:i];
+    
+    if ([self boolFor:@"disabled" node:tab ctx:_ctx])
+      continue;
+    
+    key = [self stringFor:@"key" node:tab ctx:_ctx];
+    if (isFirst && [key isEqualToString:selection])
+      isLeftActive = YES;
+    
+    [self appendTab:tab node:_node response:_response ctx:_ctx left:isFirst];
+    isFirst = NO;
+  }
+  [_response appendContentString:@"</tr></table></td></tr>"];
+  
+  [_ctx deleteLastElementIDComponent];
+  
+  [self appendHeaderFootRow:_node
+        toResponse:_response
+        inContext:_ctx
+        isLeftActive:isLeftActive];
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString     *bgcolor;
+
+  [self setActiveKey:_node inContext:_ctx];
+
+  /* start appending */
+  [_response appendContentString:
+               @"<table border='0' width='100%'"
+               @" cellpadding='0' cellspacing='0'>"];
+  
+  /* appending tabs */
+
+  [self appendTabs:_node toResponse:_response inContext:_ctx];
+
+  bgcolor   = [self stringFor:@"bgcolor" node:_node ctx:_ctx];
+
+  /* append body row */
+  {
+    [_response appendContentString:@"<tr><td colspan='2'"];
+    if (bgcolor) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentHTMLAttributeValue:bgcolor];
+      [_response appendContentString:@"\""];
+    }
+    [_response appendContentString:@">"];
+    
+    if (/*indentContent*/ YES) {
+      /* start padding table */
+      [_response appendContentString:
+                   @"<table border='0' width='100%'"
+                   @" cellpadding='10' cellspacing='0'>"];
+      [_response appendContentString:@"<tr><td>"];
+    }
+    
+    [_ctx appendElementIDComponent:@"b"];
+    
+    /* generate currently active body */
+    {
+      NSArray *tabs;
+      int     i, cnt;
+      
+      tabs = ODRLookupQueryPath(_node, @"-tab");
+      cnt  = [tabs count];
+      
+      [_ctx appendElementIDComponent:self->activeKey];
+      for (i=0; i<cnt; i++) {
+        NSString *key;
+        id       tab;
+
+        tab = [tabs objectAtIndex:i];
+        key = [self stringFor:@"key" node:tab ctx:_ctx]; 
+        if ([key isEqualToString:self->activeKey]) {
+          [super appendNode:tab toResponse:_response inContext:_ctx];
+          break;
+        }
+      }
+      [_ctx deleteLastElementIDComponent];
+    }
+    
+    [_ctx deleteLastElementIDComponent];
+    
+    if (/*indentContent*/ YES)
+      /* close padding table */
+      [_response appendContentString:@"</td></tr></table>"];
+    
+    [_response appendContentString:@"</td></tr>"];
+  }
+  
+  [_response appendContentString:@"</table>"];
+}
+
+@end /* ODR_bind_tabview */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_viewertitle.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_viewertitle.m
new file mode 100644 (file)
index 0000000..781fdee
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+
+  <var:viewertitle title="t" textcolor="tc" textfont="tf" textsize="ts">
+    <var:vtitle>  title  content </var:vtitle>
+    <var:vbutton> button content </var:vbutton>
+  </var:viewertitle>
+
+*/
+
+#include <NGObjDOM/ODR_bind_viewertitle.h>
+#include "common.h"
+
+@implementation ODR_bind_viewertitle
+
+- (void)takeValuesFromNode:(id)_node
+             fromRequest:(WORequest *)_request
+               inContext:(WOContext *)_ctx
+{
+
+  [_ctx appendElementIDComponent:@"t"];
+  
+  [self takeValuesForChildNodes:ODRLookupQueryPath(_node, @"-vtitle")
+        fromRequest:_request
+        inContext:_ctx];
+
+  [_ctx deleteLastElementIDComponent];
+
+  [_ctx appendElementIDComponent:@"b"];
+  
+  [self takeValuesForChildNodes:ODRLookupQueryPath(_node, @"-vbutton")
+        fromRequest:_request
+        inContext:_ctx];
+
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)invokeActionForNode:(id)_node
+              fromRequest:(WORequest *)_request
+                inContext:(WOContext *)_ctx
+{
+  NSString *section;
+  id       result = nil;
+
+  section = [_ctx currentElementID];
+  
+  if ([section isEqualToString:@"t"]) {
+    [_ctx consumeElementID];
+    [_ctx appendElementIDComponent:@"t"];
+    
+    result = [self invokeActionForNode:ODRLookupQueryPath(_node, @"-vtitle")
+               fromRequest:_request
+               inContext:_ctx];
+
+    [_ctx deleteLastElementIDComponent];
+  }
+  else if ([section isEqualToString:@"b"]) {
+    [_ctx consumeElementID];
+    [_ctx appendElementIDComponent:@"b"];
+    
+    result = [self invokeActionForNode:ODRLookupQueryPath(_node, @"-vbutton")
+               fromRequest:_request
+               inContext:_ctx];
+
+    [_ctx deleteLastElementIDComponent];
+  }
+
+  return result;
+}
+
+- (void)appendNode:(id)_node
+        toResponse:(WOResponse *)_response
+         inContext:(WOContext *)_ctx
+{
+  NSString *sC, *sF, *sS;
+  NSString *bgcolor;
+  NSString *title;
+  BOOL     hasFont;
+
+  sC = [self stringFor:@"textcolor" node:_node ctx:_ctx];
+  sF = [self stringFor:@"textface"  node:_node ctx:_ctx];
+  sS = [self stringFor:@"textsize"  node:_node ctx:_ctx];
+  
+  hasFont = (sC || sF || sS) ? YES : NO;
+  bgcolor = [self stringFor:@"bgcolor" node:_node ctx:_ctx];
+  title   = [self stringFor:@"title"   node:_node ctx:_ctx];
+
+  [_response appendContentString:
+             @"<table cellpadding=\"5\" cellspacing=\"0\" "
+             @"width=\"100%\" border=\"0\""];
+  
+  if (bgcolor) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentHTMLAttributeValue:bgcolor];
+    [_response appendContentCharacter:'"'];
+  }
+  
+  [_response appendContentString:@"><tr><td>"];
+  ODRAppendFont(_response, sC,sF, sS);
+  
+  if (title != nil) {
+    [_response appendContentString:@"<b>"];
+    [_response appendContentString:title];
+    [_response appendContentString:@"</b>"];
+  }
+  
+  [_ctx appendElementIDComponent:@"t"];
+
+  [self appendChildNodes:ODRLookupQueryPath(_node, @"-vtitle")
+        toResponse:_response
+        inContext:_ctx];
+
+  [_ctx deleteLastElementIDComponent]; // delete "t" 
+
+  [_response appendContentString:@"&nbsp;</font></td><td>"];
+  ODRAppendFont(_response, sC,sF, sS);
+
+  [_ctx appendElementIDComponent:@"b"];
+  
+  [self appendChildNodes:ODRLookupQueryPath(_node, @"-vbutton")
+        toResponse:_response
+        inContext:_ctx];
+
+  [_ctx deleteLastElementIDComponent]; // delete "b"
+  
+  [_response appendContentString:@"&nbsp;</font></td></tr></table>"];
+}
+
+@end /* ODR_bind_viewertitle */
+
+
+@implementation ODR_bind_vtitle
+@end /* ODR_bind_vtitle */
+
+@implementation ODR_bind_vbutton
+@end /* ODR_bind_vbutton */
diff --git a/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_with.m b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_with.m
new file mode 100644 (file)
index 0000000..02da2f8
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  attributes:
+
+    object // object to focus on
+
+  Special objects (strings):
+  
+    #  - component
+    #A - application
+    #S - session
+  
+  example:
+    
+    <var:with js:object="FileManager().loadDocument('/blah.gif')">
+      Title: <var:string value="name"/>
+    </var:with>
+    
+    <var:with const:object="#">
+      <var:string value="name"/>
+    </var:with>
+*/
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+@interface ODR_bind_with : ODNodeRenderer
+@end
+
+#include "WOContext+Cursor.h"
+#include <DOM/DOM.h>
+#include "common.h"
+
+@implementation ODR_bind_with
+
+- (id)_objectFromNode:(id)_node inContext:(WOContext *)_ctx {
+  id obj;
+  
+  if (_node == nil)
+    return nil;
+  
+  obj = [self valueFor:@"object" node:_node ctx:_ctx];
+  
+  if ([obj isKindOfClass:[NSString class]]) {
+    if ([(NSString *)obj hasPrefix:@"#"]) {
+      if ([obj isEqualToString:@"#"])
+        obj = [_ctx component];
+      else if ([obj isEqualToString:@"#A"])
+        obj = [WOApplication application];
+      else if ([obj isEqualToString:@"#S"])
+        obj = [[_ctx component] session];
+    }
+  }
+  
+  return obj;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  if ([_node hasChildNodes]) {
+    [_ctx pushCursor:[self _objectFromNode:_node inContext:_ctx]];
+    
+    [self takeValuesForChildNodes:[_node childNodes]
+          fromRequest:_req
+          inContext:_ctx];
+    
+    [_ctx popCursor];
+  }
+}
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if ([_domNode hasChildNodes]) {
+    id result;
+
+    [_ctx pushCursor:[self _objectFromNode:_domNode inContext:_ctx]];
+    
+    result = [self invokeActionForChildNodes:[_domNode childNodes]
+                   fromRequest:_request
+                   inContext:_ctx];
+    
+    [_ctx popCursor];
+    
+    return result;
+  }
+  else
+    return nil;
+}
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if ([_domNode hasChildNodes]) {
+    id obj;
+    
+    obj = [self _objectFromNode:_domNode inContext:_ctx];
+#if DEBUG
+    if (obj == nil)
+      NSLog(@"WARNING(%s): missing cursor object ...", __PRETTY_FUNCTION__);
+
+    //NSLog(@"%s: using cursor %@", __PRETTY_FUNCTION__, obj);
+#endif
+    
+    [_ctx pushCursor:obj];
+#if DEBUG && 0
+    NSAssert([_ctx cursor] == obj, @"cursor push failed !!");
+#endif
+
+    [self appendChildNodes:[_domNode childNodes]
+          toResponse:_response
+          inContext:_ctx];
+    
+    [_ctx popCursor];
+  }
+}
+
+@end /* ODR_bind_with */
diff --git a/skyrix-sope/NGObjDOM/GNUmakefile b/skyrix-sope/NGObjDOM/GNUmakefile
new file mode 100644 (file)
index 0000000..85fa5e6
--- /dev/null
@@ -0,0 +1,63 @@
+# $Id$
+
+include ../common.make
+
+GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT)
+
+LIBRARY_NAME  = libNGObjDOM
+RESOURCES_DIR = $(GNUSTEP_LOCAL_ROOT)/Libraries/Resources/NGObjDOM
+
+libNGObjDOM_SUBPROJECTS = Dynamic.subproj
+
+SUBPROJECTS = XUL.subproj XHTML.subproj
+
+libNGObjDOM_HEADER_FILES_DIR         = .
+libNGObjDOM_HEADER_FILES_INSTALL_DIR = /NGObjDOM
+libNGObjDOM_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libNGObjDOM_HEADER_FILES = \
+       NGObjDOM.h                      \
+       ODNamespaces.h                  \
+       ODNodeRenderer.h                \
+       ODNodeRendererFactory.h         \
+       ODNodeRendererFactorySet.h      \
+       ODREmbedComponent.h             \
+       ODRGenericTag.h                 \
+       ODRNodeText.h                   \
+       ODRWebObject.h                  \
+       WORenderDOM.h                   \
+       ODNodeRenderer+attributes.h     \
+       WOContext+Cursor.h              \
+       \
+       ODR_bind_tableview.h            \
+       ODR_bind_tabview.h              \
+       ODR_bind_collapsible.h          \
+       ODR_bind_viewertitle.h          \
+       ODR_bind_fieldset.h             \
+
+libNGObjDOM_OBJC_FILES = \
+       ODNodeRenderer.m                \
+       ODNodeRendererFactory.m         \
+       ODNodeRendererFactorySet.m      \
+       ODREmbedComponent.m             \
+       ODRGenericTag.m                 \
+       ODRNodeText.m                   \
+       ODRWebObject.m                  \
+       ODWONodeRenderFactory.m         \
+       WORenderDOM.m                   \
+       ODNodeRenderer+attributes.m     \
+
+# bundle
+
+BUNDLE_NAME        = NGObjDOM
+BUNDLE_EXTENSION   = .odr
+BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/Bundles
+
+NGObjDOM_OBJC_FILES  = NGObjDOMModule.m
+
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+include $(GNUSTEP_MAKEFILES)/bundle.make
+include $(GNUSTEP_MAKEFILES)/aggregate.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjDOM/GNUmakefile.postamble b/skyrix-sope/NGObjDOM/GNUmakefile.postamble
new file mode 100644 (file)
index 0000000..1bc7684
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-NGObjDOM-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-NGObjDOM-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
diff --git a/skyrix-sope/NGObjDOM/GNUmakefile.preamble b/skyrix-sope/NGObjDOM/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..b00cfe1
--- /dev/null
@@ -0,0 +1,49 @@
+# $Id$
+
+libNGObjDOM_LIBRARIES_DEPEND_UPON += \
+        -lNGObjWeb -lNGScripting \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..            \
+       -I../XML        \
+       -I../NGObjWeb   \
+       -I../NGStreams  \
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_SOPE=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/../../skyrix-core
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                                            \
+        -L$(RELBUILD_DIR_SOPE)/NGObjWeb/$(GNUSTEP_OBJ_DIR_NAME)                \
+        -L$(RELBUILD_DIR_SOPE)/NGJavaScript/$(GNUSTEP_OBJ_DIR_NAME)    \
+        -L$(RELBUILD_DIR_SOPE)/NGScripting/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGMime/$(GNUSTEP_OBJ_DIR_NAME)        \
+        -L$(RELBUILD_DIR_SxCore)/NGStreams/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+        -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)             \
+        -L$(RELBUILD_DIR_SxXml)/XmlRpc/$(GNUSTEP_OBJ_DIR_NAME)         \
+        -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)            \
+        -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS +=                                 \
+       -L./$(GNUSTEP_OBJ_DIR)                  \
+       -L../NGScripting/$(GNUSTEP_OBJ_DIR)     \
+       -L../NGObjWeb/$(GNUSTEP_OBJ_DIR)
+endif
+
+ADDITIONAL_CPPFLAGS += -pipe -Wall
+
+
+NGObjDOM_BUNDLE_LIBS += -lNGObjDOM
+
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libNGObjDOM_PREBIND_ADDR="0xC4600000"
+libNGObjDOM_LDFLAGS += -seg1addr $(libNGObjDOM_PREBIND_ADDR)
+endif
diff --git a/skyrix-sope/NGObjDOM/NGObjDOM-Info.plist b/skyrix-sope/NGObjDOM/NGObjDOM-Info.plist
new file mode 100644 (file)
index 0000000..8bbe24b
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGObjDOM</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.NGObjDOM</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/NGObjDOM/NGObjDOM.h b/skyrix-sope/NGObjDOM/NGObjDOM.h
new file mode 100644 (file)
index 0000000..56bf6d5
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_H__
+#define __NGObjDOM_H__
+
+#include <NGObjDOM/ODNamespaces.h>
+#include <NGObjDOM/ODNodeRenderer.h>
+#include <NGObjDOM/ODNodeRendererFactory.h>
+#include <NGObjDOM/ODNodeRendererFactorySet.h>
+#include <NGObjDOM/ODREmbedComponent.h>
+#include <NGObjDOM/ODRGenericTag.h>
+#include <NGObjDOM/ODRNodeText.h>
+#include <NGObjDOM/ODRWebObject.h>
+#include <NGObjDOM/WORenderDOM.h>
+
+#endif /* __NGObjDOM_H__ */
diff --git a/skyrix-sope/NGObjDOM/NGObjDOMModule.m b/skyrix-sope/NGObjDOM/NGObjDOMModule.m
new file mode 100644 (file)
index 0000000..70c5359
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/NSObject.h>
+
+@interface NGObjDOMModule : NSObject
+@end
+
+@implementation NGObjDOMModule
+@end /* NGObjDOMModule */
diff --git a/skyrix-sope/NGObjDOM/ODNamespaces.h b/skyrix-sope/NGObjDOM/ODNamespaces.h
new file mode 100644 (file)
index 0000000..00103c8
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_ODNamespaces_H__
+#define __NGObjDOM_ODNamespaces_H__
+
+#include <SaxObjC/XMLNamespaces.h>
+
+#endif /* __NGObjDOM_ODNamespaces_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODNodeRenderer+attributes.h b/skyrix-sope/NGObjDOM/ODNodeRenderer+attributes.h
new file mode 100644 (file)
index 0000000..f4c7023
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODNodeRenderer_attributes_H__
+#define __ODNodeRenderer_attributes_H__
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+@interface ODNodeRenderer(attributes)
+
+/* evaluate attributes depending on the namespace */
+- (BOOL)boolFor:(NSString *)_attr         node:(id)_node ctx:(id)_ctx;
+- (int)intFor:(NSString *)_attr           node:(id)_node ctx:(id)_ctx;
+- (id)valueFor:(NSString *)_attr          node:(id)_node ctx:(id)_ctx;
+- (NSString *)stringFor:(NSString *)_attr node:(id)_node ctx:(id)_ctx;
+
+- (void)setBool:(BOOL)_value for:(NSString *)_attr node:(id)_node ctx:(id)_ctx;
+- (void)setInt:(int)_value   for:(NSString *)_attr node:(id)_node ctx:(id)_ctx;
+- (void)setValue:(id)_value  for:(NSString *)_attr node:(id)_node ctx:(id)_ctx;
+- (void)setString:(NSString *)_value
+  for:(NSString *)_attrName
+  node:(id)_node
+  ctx:(id)_ctx;
+
+- (void)forceSetValue:(id)_v  for:(NSString *)_attr node:(id)_n ctx:(id)_ctx;
+- (void)forceSetBool:(BOOL)_v for:(NSString *)_attr node:(id)_n ctx:(id)_ctx;
+- (void)forceSetInt:(int)_v   for:(NSString *)_attr node:(id)_n ctx:(id)_ctx;
+- (void)forceSetString:(NSString *)_v
+  for:(NSString *)_attrName
+  node:(id)_node
+  ctx:(id)_ctx;
+
+- (BOOL)isSettable:(NSString *)_attr node:(id)_node ctx:(id)_ctx;
+- (BOOL)hasAttribute:(NSString *)_attr node:(id)_node ctx:(id)_ctx;
+
+- (NSString *)stringForInt:(int)_int;
+
+/* evaluate associations (looks for 'special' namespaces) */
+
+- (id)valueForAttributeNode:(id)_attrNode inContext:(id)_ctx;
+- (id)invokeValueForAttributeNode:(id)_attrNode inContext:(id)_ctx;
+
+@end
+
+#endif /* __ODNodeRenderer_attributes_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODNodeRenderer+attributes.m b/skyrix-sope/NGObjDOM/ODNodeRenderer+attributes.m
new file mode 100644 (file)
index 0000000..61b05a8
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRenderer+attributes.h>
+#include <NGObjDOM/ODNodeRenderer.h>
+#include <NGObjDOM/ODNamespaces.h>
+#include <NGObjDOM/WOContext+Cursor.h>
+#include "common.h"
+
+@interface ODNodeRenderer(PrivateMethodes)
+- (id)attributeNodeNamed:(NSString *)_attr ofNode:(id)_node inContext:(id)_ctx;
+- (id)stringValueForAttributeNode:(id)_attrNode inContext:(id)_ctx;
+@end
+
+@interface NSObject(NGScriptEval)
+- (id)evaluateScript:(NSString *)_script language:(NSString *)_lang;
+@end
+
+@implementation ODNodeRenderer(attributes)
+
+static BOOL evalJSInHandler = NO;
+static BOOL debugJS         = NO;
+static BOOL logValues       = NO;
+
+static void _categoryInitialize(void) {
+  NSUserDefaults *ud;
+  static BOOL didInit = NO;
+  if (didInit) return;
+  
+  ud = [NSUserDefaults standardUserDefaults];
+  evalJSInHandler = [ud boolForKey:@"ODEvalAttrValuesInExceptionHandler"];
+  debugJS         = [ud boolForKey:@"ODDebugJSAttrEval"];
+  logValues       = [ud boolForKey:@"ODLogAttrValues"];
+  
+  didInit = YES;
+}
+
+/* attributes */
+
+- (BOOL)boolFor:(NSString *)_attr node:(id)_node ctx:(id)_ctx {
+  id       attrNode;
+  NSString *value;
+  
+  attrNode = [self attributeNodeNamed:_attr ofNode:_node inContext:_ctx];
+  value    = [[self valueForAttributeNode:attrNode inContext:_ctx] stringValue];
+
+  if (logValues)
+    NSLog(@"%s: bool for attr %@ => '%@'", __PRETTY_FUNCTION__, _attr, value);
+  
+  if ([value isEqualToString:@"true"])
+    return YES;
+  if ([value isEqualToString:@"false"])
+    return NO;
+  
+  return [value boolValue];
+}
+
+- (int)intFor:(NSString *)_attr node:(id)_node ctx:(id)_ctx {
+  id attrNode = [self attributeNodeNamed:_attr ofNode:_node inContext:_ctx];
+  
+  return [[self valueForAttributeNode:attrNode inContext:_ctx] intValue];
+}
+
+- (id)valueFor:(NSString *)_attr node:(id)_node ctx:(id)_ctx {
+  id attrNode;
+  
+  attrNode = [self attributeNodeNamed:_attr ofNode:_node inContext:_ctx];
+  
+  return [self valueForAttributeNode:attrNode inContext:_ctx];
+}
+
+- (NSString *)stringFor:(NSString *)_attr node:(id)_node ctx:(id)_ctx {
+  id attrNode;
+  
+  attrNode = [self attributeNodeNamed:_attr ofNode:_node inContext:_ctx];
+  
+  return [self stringValueForAttributeNode:attrNode inContext:_ctx];
+}
+
+- (void)setValue:(id)_value for:(NSString *)_attr node:(id)_node ctx:(id)_ctx {
+  id attrNode = nil;
+  id<DOMNamedNodeMap> attrs;
+
+  NSAssert2((_attr != nil),
+            @"%s: Cannot set '%@' (The attributeName is nil!)",
+            __PRETTY_FUNCTION__, _value);
+
+  NSAssert3(((attrs = [_node attributes]) != nil),
+           @"%s: Cannot set '%@' for '%@' (There are no attributes!)",
+           __PRETTY_FUNCTION__, _value, _attr);
+  
+  attrNode = [attrs namedItem:_attr namespaceURI:XMLNS_OD_BIND];
+  
+  NSAssert4((attrNode != nil),
+            @"%s: Cannot set '%@' for '%@:%@' (There is not such attribute!)",
+            __PRETTY_FUNCTION__, _value, XMLNS_OD_BIND, _attr);
+
+  [[(id<WOPageGenerationContext>)_ctx cursor] 
+    takeValue:_value forKeyPath:[attrNode value]];
+}
+
+- (void)setBool:(BOOL)_value for:(NSString *)_attr node:(id)_node ctx:(id)_ctx {
+  [self setValue:[NSNumber numberWithBool:_value]
+        for:_attr
+        node:_node
+        ctx:_ctx];
+}
+
+- (void)setInt:(int)_value for:(NSString *)_attr node:(id)_node ctx:(id)_ctx {
+  [self setValue:[NSNumber numberWithInt:_value]
+        for:_attr
+        node:_node
+        ctx:_ctx];  
+}
+
+- (void)setString:(NSString *)_value
+  for:(NSString *)_attr node:(id)_node ctx:(id)_ctx
+{
+  [self setValue:[_value stringValue] for:_attr node:_node ctx:_ctx];
+}
+
+- (void)forceSetValue:(id)_value
+  for:(NSString *)_attr node:(id)_node ctx:(id)_ctx
+{
+  if ([self isSettable:_attr node:_node ctx:_ctx])
+    [self setValue:_value for:_attr node:_node ctx:_ctx];
+  else
+    [_node setAttribute:_attr namespaceURI:XMLNS_OD_CONST value:_value];
+}
+
+- (void)forceSetBool:(BOOL)_value for:(NSString *)_attr node:(id)_node ctx:(id)_ctx {
+  [self forceSetValue:[NSNumber numberWithBool:_value]
+        for:_attr
+        node:_node
+        ctx:_ctx];
+}
+
+- (void)forceSetInt:(int)_value
+  for:(NSString *)_attr node:(id)_node ctx:(id)_ctx
+{
+  [self forceSetValue:[NSNumber numberWithInt:_value]
+        for:_attr
+        node:_node
+        ctx:_ctx];  
+}
+
+- (void)forceSetString:(NSString *)_value
+  for:(NSString *)_attr node:(id)_node ctx:(id)_ctx
+{
+  [self forceSetValue:[_value stringValue] for:_attr node:_node ctx:_ctx];
+}
+
+
+- (BOOL)hasAttribute:(NSString *)_attr node:(id)_node ctx:(id)_ctx {
+  return ([self attributeNodeNamed:_attr ofNode:_node inContext:_ctx] != nil)
+    ? YES
+    : NO;
+}
+
+- (BOOL)isSettable:(NSString *)_attr node:(id)_node ctx:(id)_ctx {
+  id attrNode = nil;
+  id<DOMNamedNodeMap> attrs;
+  
+  if ((attrs = [_node attributes]) == nil)
+    return NO;
+  
+  if (!(attrNode = [attrs namedItem:_attr namespaceURI:XMLNS_OD_BIND]))
+    return NO;
+
+  return ([[attrNode value] length] > 0) ? YES : NO;
+}
+
+- (NSString *)stringForInt:(int)_value {
+  static NSString *strs[10] = {
+    @"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9" };
+  
+  if (_value < 10 && _value >= 0)
+    return strs[_value];
+  
+  return [NSString stringWithFormat:@"%i", _value];
+}
+
+/* evaluate associations (looks for 'special' namespaces) */
+
+- (NSException *)handleEvalException:(NSException *)_exception
+  onNode:(id)_attrNode inContext:(id)_ctx 
+{
+  [self logWithFormat:@"Eval Node %@ catched: %@", _attrNode, _exception];
+  return nil;
+}
+
+- (id)valueForAttributeNode:(id)_attrNode inContext:(id)_ctx {
+  NSString *nsuri;
+  NSString *value;
+  
+  _categoryInitialize();
+  
+  if (_attrNode == nil) {
+    return nil;
+  }
+  
+  nsuri = [_attrNode namespaceURI];
+  value = [_attrNode value];
+  
+  if (logValues) {
+    [self logWithFormat:
+           @"%s:\n  value for attr %@\n  (ns=%@, value='%@', cursor=%@) ...",
+           __PRETTY_FUNCTION__, _attrNode, nsuri, value, 
+           [(id<WOPageGenerationContext>)_ctx cursor]];
+  }
+  
+  if ([nsuri isEqualToString:XMLNS_OD_CONST]) {
+    // do nothing ...
+    if (logValues) [self logWithFormat:@"    constant value, pass through"];
+  }
+  else if ([nsuri isEqualToString:XMLNS_OD_BIND]) {
+    if (logValues) {
+      [self logWithFormat:@"    cursor: %@\n    valueForKeyPath:'%@'", 
+             [(id<WOPageGenerationContext>)_ctx cursor], value];
+    }
+    value = [[(id<WOPageGenerationContext>)_ctx cursor] valueForKeyPath:value];
+  }
+  else if ([nsuri isEqualToString:XMLNS_OD_ACTION]) {
+    // TODO: is this ever used anywhere ? (hm, maybe in forms)
+    // Note: the node-value gets used in the dispatch phase !
+    if (logValues) [self logWithFormat:@"    componentAction: '%@'", value];
+    value = [_ctx componentActionURL];
+  }
+  else if ([nsuri isEqualToString:XMLNS_OD_EVALJS]) {
+    id cursor;
+    
+    if (logValues) [self logWithFormat:@"    JavaScript: '%@'", value];
+    
+    cursor = [(id<WOPageGenerationContext>)_ctx cursor];
+    if ([cursor respondsToSelector:@selector(evaluateScript:language:)]) {
+      if (debugJS)
+       [self logWithFormat:@"\n  cursor %@\n  eval: '%@'", cursor, value];
+      
+      if (!evalJSInHandler) {
+       value = [cursor evaluateScript:value language:@"javascript"];
+      }
+      else {
+       NS_DURING
+         value = [cursor evaluateScript:value language:@"javascript"];
+       NS_HANDLER
+         [[self handleEvalException:localException
+                onNode:_attrNode inContext:_ctx] raise];
+       NS_ENDHANDLER;
+      }
+      
+      if (debugJS) [self logWithFormat:@"  got: %@", value];
+    }
+    else {
+      [self logWithFormat:
+             @"%s:\n  object %@ cannot evaluate JavaScript\n'%@' !!",
+              __PRETTY_FUNCTION__, self, value];
+    }
+  }
+  
+  if (logValues) {
+    [self logWithFormat:@"  return value: %@ (%@,0x%08X)\n", 
+           value ? value: @"<nil>", NSStringFromClass([value class]), value];
+  }
+  return value;
+}
+
+- (id)invokeValueForAttributeNode:(id)_attrNode inContext:(id)_ctx {
+  NSString *nsuri;
+  id result;
+
+  result = nil;
+  
+  if ((nsuri = [_attrNode namespaceURI])) {
+    if ([nsuri isEqualToString:XMLNS_OD_ACTION])
+      result = [[_ctx component] valueForKeyPath:[_attrNode value]];
+  }
+  if (result == nil)
+    result = [self valueForAttributeNode:_attrNode inContext:_ctx];
+  
+  if (![result conformsToProtocol:@protocol(WOActionResults)])
+    return nil;
+  
+  return result;
+}
+
+@end /* ODNodeRenderer(attributes) */
+
+@implementation ODNodeRenderer(PrivateMethodes)
+
+- (id)attributeNodeNamed:(NSString *)_attr ofNode:(id)_node inContext:(id)_ctx{
+  id attrNode;
+  id<DOMNamedNodeMap> attrs;
+  
+  if ((attrs = [_node attributes]) == nil)
+    return nil;
+  
+  attrNode = [attrs namedItem:_attr namespaceURI:XMLNS_OD_CONST];
+  if (attrNode == nil)
+    attrNode = [attrs namedItem:_attr namespaceURI:XMLNS_OD_BIND];
+  if (attrNode == nil)
+    attrNode = [attrs namedItem:_attr namespaceURI:XMLNS_XUL];
+  if (attrNode == nil)
+    attrNode = [attrs namedItem:_attr namespaceURI:XMLNS_XHTML];
+  if (attrNode == nil)
+    attrNode = [attrs namedItem:_attr namespaceURI:XMLNS_HTML40];
+  if (attrNode == nil)
+    attrNode = [attrs namedItem:_attr namespaceURI:XMLNS_OD_EVALJS];
+
+  if (attrNode == nil)
+    attrNode = [_node attributeNode:_attr namespaceURI:@"*"];
+  
+#if DEBUG && 0
+  if (attrNode == nil) {
+    NSLog(@"%s: found no attribute named %@ in node %@", __PRETTY_FUNCTION__,
+          _attr, _node);
+  }
+#endif
+  return attrNode;
+}
+
+- (id)stringValueForAttributeNode:(id)_attrNode inContext:(id)_ctx {
+  if ([[_attrNode namespaceURI] isEqualToString:XMLNS_XUL]) {
+    if ([[(id<DOMAttr>)_attrNode name] isEqualToString:@"src"]) {
+      /* a URL */
+      NSURL *url;
+      id rm;
+      
+      if ((url = [NSURL URLWithString:[_attrNode value]])) {
+        /* valid, regular URL */
+        return [[_attrNode value] stringValue];
+      }
+      
+      /* consider it a resource name */
+      rm = [[_ctx component] resourceManager];
+      return [rm urlForResourceNamed:[_attrNode value]
+                inFramework:nil
+                languages:[[_ctx session] languages]
+                request:[(WOContext *)_ctx request]];
+    }
+
+    if ([(NSString *)[(id<DOMAttr>)_attrNode name] hasPrefix:@"on"])
+      return [[_ctx elementID] stringValue];
+  }
+  return [[self valueForAttributeNode:_attrNode inContext:_ctx] stringValue];
+}
+
+@end /* ODNodeRenderer(PrivateMethodes) */
diff --git a/skyrix-sope/NGObjDOM/ODNodeRenderer.h b/skyrix-sope/NGObjDOM/ODNodeRenderer.h
new file mode 100644 (file)
index 0000000..de93941
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODNodeRenderer_H__
+#define __ODNodeRenderer_H__
+
+#import <Foundation/NSObject.h>
+
+@class WOContext, WORequest, WOResponse;
+
+@interface ODNodeRenderer : NSObject
+
+/* renderer lookup (uses the ODNodeRendererFactory stored in the WOContext) */
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode
+  inContext:(WOContext *)_ctx;
+
+/* request phases */
+
+- (void)takeValuesForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context;
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context;
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+
+/* request phases for child nodes */
+
+- (void)takeValuesForChildNodes:(id)_nodeList
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context;
+- (id)invokeActionForChildNodes:(id)_nodeList
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context;
+- (void)appendChildNodes:(id)_nodeList
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+
+/* requires HTML form */
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx;
+- (BOOL)requiresFormForChildNodes:(id)_nodeList inContext:(WOContext *)_ctx;
+
+/* selecting children */
+
+- (BOOL)includeChildNode:(id)_childNode
+  ofNode:(id)_domNode
+  inContext:(WOContext *)_ctx;
+
+/* generating node ids unique in DOM tree */
+
+- (NSString *)uniqueIDForNode:(id)_node inContext:(WOContext *)_ctx;
+
+@end
+
+#include <NGObjDOM/ODNodeRenderer+attributes.h>
+
+#endif /* __ODNodeRenderer_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODNodeRenderer.m b/skyrix-sope/NGObjDOM/ODNodeRenderer.m
new file mode 100644 (file)
index 0000000..85bb199
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjDOM/ODNodeRenderer.h>
+#include <NGObjDOM/ODNodeRendererFactory.h>
+#include <NGObjDOM/ODNamespaces.h>
+#include "common.h"
+
+//#define WITH_EXCEPTION_HANDLER 1
+#if NeXT_RUNTIME || APPLE_RUNTIME
+#  define sel_get_name sel_getName
+#endif
+
+@implementation ODNodeRenderer
+
+static int    profileRenderers = -1;
+static double profRenderMin = 0.0009;
+static Class NSDateClass = Nil;
+
++ (void)initialize {
+  if (NSDateClass == Nil)
+    NSDateClass = [NSDate class];
+  
+  if (profileRenderers == -1) {
+    id tmp;
+    
+    profileRenderers = [[[NSUserDefaults standardUserDefaults]
+                                          objectForKey:@"ODProfileRenderer"]
+                                          boolValue] ? 1 : 0;
+    
+    if ((tmp = [[NSUserDefaults standardUserDefaults]
+                                objectForKey:@"ODProfileRendererMin"])) {
+      double d = [tmp doubleValue];
+      
+      if (d > profRenderMin) {
+        profRenderMin = d;
+        if (profileRenderers)
+          NSLog(@"profRenderMin: %0.3fs", profRenderMin);
+      }
+    }
+  }
+}
+
++ (int)version {
+  return 1;
+}
+
+- (NSString *)_idForNode:(id)_node {
+  if ([_node nodeType] == DOM_ELEMENT_NODE) {
+    NSString *s;
+
+    if ((s = [_node attribute:@"id" namespaceURI:@"*"]))
+      return s;
+    
+    return [_node tagName];
+  }
+  
+  return [_node nodeName];
+}
+
+/* renderer lookup */
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  id<ODNodeRendererFactory> factory;
+  ODNodeRenderer *renderer = nil;
+  NSTimeInterval st = 0.0;
+
+  if (profileRenderers)
+    st = [[NSDateClass date] timeIntervalSince1970];
+  
+  if ((factory = [_ctx objectForKey:@"domRenderFactory"]))
+    renderer = [factory rendererForNode:_domNode inContext:_ctx];
+  
+  if (profileRenderers) {
+    NSTimeInterval diff;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    if (diff > profRenderMin) {
+      printf("[renderer lookup: %s %s]: %0.3fs id='%s'\n",
+             [[_domNode nodeName] cString],
+             sel_get_name(_cmd), diff,
+             [[self _idForNode:_domNode] cString]);
+    }
+  }
+  
+  return renderer;
+}
+
+/* request phase operations on children */
+
+- (void)takeValuesForChildNodes:(id)_nodeList
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  id children;
+  id child;
+  NSTimeInterval st = 0.0;
+  static int profDepth = 0;
+
+  if (profileRenderers) {
+    st = [[NSDateClass date] timeIntervalSince1970];
+    profDepth++;
+  }
+  
+  if ([_nodeList count] == 0) {
+    profDepth--;
+    return;
+  }
+  
+  [_ctx appendZeroElementIDComponent];
+  
+  children = [_nodeList objectEnumerator];
+  while ((child = [children nextObject])) {
+    if ([self includeChildNode:child ofNode:[child parentNode] inContext:_ctx]) {
+      ODNodeRenderer *renderer;
+      
+      if ((renderer = [self rendererForNode:child inContext:_ctx])) {
+        [renderer takeValuesForNode:child
+                  fromRequest:_request
+                  inContext:_ctx];
+      }
+    }    
+    [_ctx incrementLastElementIDComponent];
+  }
+  
+  [_ctx deleteLastElementIDComponent];
+  
+  if (profileRenderers) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    if (diff > profRenderMin) {
+      id dn;
+
+      dn = [[_nodeList lastObject] parentNode];
+      
+      for (i = profDepth; i >= 0; i--)
+        printf("  ");
+      printf("[list: %s %s]: %0.3fs '%s'\n",
+             [[dn nodeName] cString],
+             sel_get_name(_cmd), diff,
+             [[self _idForNode:dn] cString]);
+    }
+    profDepth--;
+  }
+}
+
+- (id)invokeActionForChildNodes:(id)_nodeList
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *idxId;
+  id result;
+  NSTimeInterval st = 0.0;
+  static int profDepth = 0;
+
+  if (profileRenderers) {
+    st = [[NSDateClass date] timeIntervalSince1970];
+    profDepth++;
+  }
+  
+  if ([_nodeList count] == 0) {
+    profDepth--;
+#if DEBUG && 0
+    NSLog(@"%s: no child nodes to invoke upon ..", __PRETTY_FUNCTION__);
+#endif
+    return nil;
+  }
+  
+  if ((idxId  = [_ctx currentElementID])) {
+    id node;
+    unsigned count;
+    
+    count = [_nodeList count];
+    
+    if (isdigit([idxId characterAtIndex:0])) {
+      /* lookup by index */
+      int idx;
+      idx = [idxId intValue];
+      
+      if (idx >= count) {
+        NSLog(@"%s: ERROR, click index is out of range "
+              @"(idx=%i, count=%d, eid=%@, sid=%@)",
+              __PRETTY_FUNCTION__, idx, count,
+              [_ctx elementID], [_ctx senderID]);
+        node = nil;
+      }
+      else if ((node = [_nodeList objectAtIndex:idx]) == nil) {
+#if DEBUG
+        NSLog(@"%s: ERROR, did not find node at index %i (tag=%@, list=%@) ..",
+              __PRETTY_FUNCTION__, idx,
+              [[_nodeList parentNode] nodeName], _nodeList);
+#endif
+      }
+    }
+    else {
+      /* lookup by name */
+      NSLog(@"%s: ERROR, LOOK FOR NAME %@ ..", __PRETTY_FUNCTION__, idxId);
+      node = nil;
+    }
+    
+    [_ctx consumeElementID]; // consume index-id
+    
+    /* this updates the element-id path */
+    [_ctx appendElementIDComponent:idxId];
+
+#if DEBUG && 0
+    NSLog(@"%s: invoke action on node:\n  %@\n  id=%@", __PRETTY_FUNCTION__,
+          node, [_ctx currentElementID]);
+#endif
+    
+    result = [[self rendererForNode:node inContext:_ctx]
+                    invokeActionForNode:node
+                    fromRequest:_request
+                    inContext:_ctx];
+    
+    [_ctx deleteLastElementIDComponent];
+  }
+  else {
+    [[_ctx session]
+           logWithFormat:
+             @"%s: %@: \n"
+             @"    MISSING INDEX ID in URL\n    eid: %@\n    nodelist: %@ !",
+             __PRETTY_FUNCTION__,
+             self, [_ctx elementID], _nodeList];
+    result = nil;
+  }
+  
+  if (profileRenderers) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    if (diff > profRenderMin) {
+      for (i = profDepth; i >= 0; i--)
+        printf("  ");
+      printf("[list: %s %s]: %0.3fs\n",
+             [[[[_nodeList lastObject] parentNode] nodeName] cString],
+             sel_get_name(_cmd), diff);
+    }
+    profDepth--;
+  }
+  
+  return result;
+}
+
+- (void)appendChildNodes:(id)_nodeList
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  id children;
+  id child, parent;
+  static unsigned profDepth = 0;
+  NSTimeInterval st = 0.0;
+
+  if (profileRenderers) {
+    st = [[NSDateClass date] timeIntervalSince1970];
+    profDepth++;
+  }
+  
+  if ([_nodeList count] == 0) {
+    profDepth--;
+    return;
+  }
+  
+  [_ctx appendZeroElementIDComponent];
+
+  parent   = nil;
+  children = [_nodeList objectEnumerator];
+  while ((child = [children nextObject])) {
+    if (parent == nil) parent = [child parentNode];
+    
+    if ([self includeChildNode:child ofNode:parent inContext:_ctx]) {
+      ODNodeRenderer *renderer;
+      NSTimeInterval st = 0.0;
+
+      if (profileRenderers) {
+        st = [[NSDateClass date] timeIntervalSince1970];
+        profDepth++;
+      }
+      
+      renderer = [self rendererForNode:child inContext:_ctx];
+      
+      [renderer appendNode:child
+                toResponse:_response
+                inContext:_ctx];
+      
+      if (profileRenderers) {
+        NSTimeInterval diff;
+        int i;
+        diff = [[NSDateClass date] timeIntervalSince1970] - st;
+        if (diff > profRenderMin) {
+          for (i = profDepth; i >= 0; i--)
+            printf("  ");
+          printf("[child: %s %s]: %0.3fs '%s'\n",
+                 [[child nodeName] cString],
+                 sel_get_name(_cmd), diff,
+                 [[self _idForNode:child] cString]);
+        }
+        profDepth--;
+      }
+    }
+    [_ctx incrementLastElementIDComponent];
+  }
+  
+  [_ctx deleteLastElementIDComponent];
+
+  
+  if (profileRenderers) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    if (diff > profRenderMin) {
+      id dn;
+      
+      dn = [[_nodeList lastObject] parentNode];
+      
+      for (i = profDepth; i >= 0; i--)
+        printf("  ");
+      printf("[list: %s %s]: %0.3fs '%s'\n",
+             [[dn nodeName] cString],
+             sel_get_name(_cmd), diff,
+             [[self _idForNode:dn] cString]);
+    }
+    profDepth--;
+  }
+}
+
+/* the three WO request phase operations */
+
+- (void)takeValuesForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+#if DEBUG && 0
+  NSLog(@"take values for node: %@", _domNode);
+#endif
+
+#if WITH_EXCEPTION_HANDLER
+  NS_DURING {
+    if ([_domNode hasChildNodes]) {
+      [self takeValuesForChildNodes:[_domNode childNodes]
+            fromRequest:_request
+            inContext:_context];
+    }
+  }
+  NS_HANDLER {
+    fprintf(stderr, "%s\n", [[localException description] cString]);
+    abort();
+  }
+  NS_ENDHANDLER;
+#else
+  if ([_domNode hasChildNodes]) {
+    [self takeValuesForChildNodes:[_domNode childNodes]
+          fromRequest:_request
+          inContext:_context];
+  }
+#endif
+}
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  if ([_domNode hasChildNodes]) {
+    return [self invokeActionForChildNodes:[_domNode childNodes]
+                 fromRequest:_request
+                 inContext:_context];
+  }
+  else {
+#if DEBUG
+    NSLog(@"%s: node %@ has no child nodes:\n  sid=%@\n  eid=%@",
+          __PRETTY_FUNCTION__, _domNode,
+          [_context senderID], [_context elementID]);
+#endif
+    return nil;
+  }
+}
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  if ([_domNode hasChildNodes]) {
+    [self appendChildNodes:[_domNode childNodes]
+          toResponse:_response
+          inContext:_context];
+  }
+}
+
+/* requires HTML form */
+
+- (BOOL)requiresFormForChildNodes:(id)_nodeList inContext:(WOContext *)_ctx {
+  id children;
+  id child;
+  
+  if ([_nodeList count] == 0)
+    return NO;
+  
+  if ([_ctx isInForm])
+    return NO;
+  
+  children = [_nodeList objectEnumerator];
+  
+  while ((child = [children nextObject])) {
+    if ([self includeChildNode:child ofNode:[child parentNode] inContext:_ctx]) {
+      ODNodeRenderer *renderer;
+      
+      if ((renderer = [self rendererForNode:child inContext:_ctx])) {
+        if ([renderer requiresFormForNode:child inContext:_ctx])
+          return YES;
+      }
+    }
+  }
+  return NO;
+}
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  if ([_domNode hasChildNodes]) {
+    return [self requiresFormForChildNodes:[_domNode childNodes]
+                 inContext:_ctx];
+  }
+  else
+    return NO;
+}
+
+/* generating node ids unique in DOM tree */
+
+- (NSString *)uniqueIDForNode:(id)_node inContext:(WOContext *)_ctx {
+  NSMutableArray  *nodePath;
+  NSMutableString *uid;
+  NSEnumerator    *topDown;
+  id   node, parent;
+  BOOL isFirst;
+  
+  if (_node == nil) return nil;
+  
+  nodePath = [NSMutableArray arrayWithCapacity:16];
+  
+  /* collect all parent nodes in bottom-up form */
+  
+  for (node = _node; node; node = [node parentNode])
+    [nodePath addObject:node];
+  
+  /* generate ID */
+  
+  uid     = [NSMutableString stringWithCapacity:64];
+  topDown = [nodePath reverseObjectEnumerator];
+  isFirst = YES;
+  parent  = nil;
+
+  for (isFirst = YES; (node = [topDown nextObject]); parent = node) {
+    if (!isFirst) {
+      NSArray  *children;
+      unsigned i, count;
+      
+      [uid appendString:@"."];
+      
+      /* determine index of _node */
+
+      children = (NSArray *)[parent childNodes];
+      for (i = 0, count = [children count]; i < count; i++) {
+        if ([children objectAtIndex:i] == node)
+          break;
+      }
+      [uid appendFormat:@"%d", i];
+    }
+    else {
+      [uid appendString:@"R"];
+      isFirst = NO;
+    }
+  }
+  
+  return [[uid copy] autorelease];
+}
+
+/* selecting children */
+
+- (BOOL)includeChildNode:(id)_childNode
+  ofNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  /* check 'if' attribute .. */
+
+  if ([_childNode nodeType] != DOM_ELEMENT_NODE)
+     return YES;
+  
+  if ([_childNode hasAttribute:@"if" namespaceURI:@"*"])
+    return [self boolFor:@"if" node:_childNode ctx:_ctx];
+  
+  if ([_childNode hasAttribute:@"ifnot" namespaceURI:@"*"])
+    return [self boolFor:@"ifnot" node:_childNode ctx:_ctx] ? NO : YES;
+  
+  return YES;
+}
+
+@end /* ODNodeRenderer */
diff --git a/skyrix-sope/NGObjDOM/ODNodeRendererFactory.h b/skyrix-sope/NGObjDOM/ODNodeRendererFactory.h
new file mode 100644 (file)
index 0000000..e090a8d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_ODNodeRendererFactory_H__
+#define __NGObjDOM_ODNodeRendererFactory_H__
+
+#import <Foundation/NSObject.h>
+
+@class WOContext;
+@class ODNodeRenderer;
+
+@protocol ODNodeRendererFactory
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode
+  inContext:(WOContext *)_ctx;
+
+@end
+
+@interface ODNodeRendererFactory : NSObject < ODNodeRendererFactory >
+
+/* those are called by -rendererForNode:inContext: depending on the node-type */
+
+- (ODNodeRenderer *)rendererForTextNode:(id)_domNode 
+  inContext:(WOContext *)_ctx;
+- (ODNodeRenderer *)rendererForElementNode:(id)_domNode 
+  inContext:(WOContext *)_ctx;
+
+/* 'master' factory */
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode
+  inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __NGObjDOM_ODNodeRendererFactory_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODNodeRendererFactory.m b/skyrix-sope/NGObjDOM/ODNodeRendererFactory.m
new file mode 100644 (file)
index 0000000..7c36bc0
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRendererFactory.h>
+#include <NGObjDOM/ODRNodeText.h>
+#include <NGObjDOM/ODRGenericTag.h>
+#include "common.h"
+
+@implementation ODNodeRendererFactory
+
++ (int)version {
+  return 1;
+}
+
+- (ODNodeRenderer *)rendererForTextNode:(id)_domNode 
+  inContext:(WOContext *)_ctx
+{
+  static id r = nil;
+  if (r == nil) r = [[ODRNodeText alloc] init];
+  return r;
+}
+
+- (ODNodeRenderer *)rendererForElementNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  static id r = nil;
+  if (r == nil) r = [[ODRGenericTag alloc] init];
+  return r;
+}
+
+- (ODNodeRenderer *)rendererForDocumentNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  static id r = nil;
+  if (r == nil) r = [[ODNodeRenderer alloc] init];
+  return r;
+}
+- (ODNodeRenderer *)rendererForDocumentFragmentNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  static id r = nil;
+  if (r == nil) r = [[ODNodeRenderer alloc] init];
+  return r;
+}
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  ODNodeRenderer *renderer;
+  
+  switch ([_domNode nodeType]) {
+    case DOM_TEXT_NODE:
+    case DOM_CDATA_SECTION_NODE:
+      renderer = [self rendererForTextNode:_domNode inContext:_ctx];
+      break;
+      
+    case DOM_ELEMENT_NODE:
+      renderer = [self rendererForElementNode:_domNode inContext:_ctx];
+      break;
+
+    case DOM_DOCUMENT_NODE:
+      renderer = [self rendererForDocumentNode:_domNode inContext:_ctx];
+      break;
+      
+    case DOM_DOCUMENT_FRAGMENT_NODE:
+      renderer =
+        [self rendererForDocumentFragmentNode:_domNode inContext:_ctx];
+      break;
+      
+    default:
+      renderer = nil;
+      break;
+  }
+  return renderer;
+}
+
+@end /* ODNodeRendererFactory */
diff --git a/skyrix-sope/NGObjDOM/ODNodeRendererFactorySet.h b/skyrix-sope/NGObjDOM/ODNodeRendererFactorySet.h
new file mode 100644 (file)
index 0000000..fa9ede2
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_ODNodeRendererFactorySet_H__
+#define __NGObjDOM_ODNodeRendererFactorySet_H__
+
+#include <NGObjDOM/ODNodeRendererFactory.h>
+
+@class NSMutableDictionary, NSMutableArray;
+@class EOQualifier;
+
+/*
+  Attention:
+
+    The set caches renderers based on the tag/namespace of an element only !!
+
+    That is: you can't have two different renderers for eg "input type='text'"
+    and "input type='submit'" !
+*/
+
+@interface ODNodeRendererFactorySet : NSObject < ODNodeRendererFactory >
+{
+  NSMutableDictionary *cache;
+  NSMutableArray      *subfactories;
+}
+
+- (void)flushCache;
+
+- (void)registerFactory:(id<NSObject,ODNodeRendererFactory>)_factory
+  forNodeQualifier:(EOQualifier *)_qualifier;
+
+- (void)registerFactory:(id<NSObject,ODNodeRendererFactory>)_factory
+  forNamespaceURI:(NSString *)_namespaceURI;
+
+- (void)registerFactory:(id<NSObject,ODNodeRendererFactory>)_factory
+  forNamespaceURI:(NSString *)_namespaceURI
+  tagName:(NSString *)_tagName;
+
+@end
+
+#endif /* __NGObjDOM_ODNodeRendererFactorySet_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODNodeRendererFactorySet.m b/skyrix-sope/NGObjDOM/ODNodeRendererFactorySet.m
new file mode 100644 (file)
index 0000000..7f96350
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRendererFactorySet.h>
+
+@interface _ODNodeRendererFactorySetEntry : NSObject
+{
+@public
+  ODNodeRendererFactory *factory;
+  EOQualifier *qualifier;
+  NSString    *namespaceURI;
+  NSString    *tagName;
+}
+
+- (BOOL)matchesNode:(id)_node;
+- (ODNodeRendererFactory *)nodeRendererFactory;
+
+@end
+
+#include <NGObjDOM/ODRNodeText.h>
+#include <NGObjDOM/ODRGenericTag.h>
+#include "common.h"
+#include <EOControl/EOQualifier.h>
+
+@implementation ODNodeRendererFactorySet
+
++ (int)version {
+  return 1;
+}
+
+- (void)dealloc {
+  RELEASE(self->subfactories);
+  RELEASE(self->cache);
+  [super dealloc];
+}
+
+- (void)flushCache {
+  [self->cache removeAllObjects];
+}
+
+/* registry */
+
+- (void)registerFactory:(id<NSObject,ODNodeRendererFactory>)_factory
+  forNodeQualifier:(EOQualifier *)_qualifier
+{
+  _ODNodeRendererFactorySetEntry *entry;
+
+#if DEBUG
+  if (![_factory conformsToProtocol:@protocol(ODNodeRendererFactory)]) {
+    NSLog(@"WARNING(%s): node-factory %@ to be registered, doesn't implement "
+          @"the ODNodeRendererFactory protocol !",
+          __PRETTY_FUNCTION__, _factory);
+  }
+#endif
+  
+  [self flushCache];
+  
+  entry = [[_ODNodeRendererFactorySetEntry alloc] init];
+  entry->factory   = RETAIN(_factory);
+  entry->qualifier = RETAIN(_qualifier);
+
+  if (self->subfactories == nil)
+    self->subfactories = [[NSMutableArray alloc] initWithCapacity:4];
+  [self->subfactories addObject:entry];
+  RELEASE(entry);
+}
+
+- (void)registerFactory:(id<NSObject,ODNodeRendererFactory>)_factory
+  forNamespaceURI:(NSString *)_namespaceURI
+  tagName:(NSString *)_tagName
+{
+  _ODNodeRendererFactorySetEntry *entry;
+  
+#if DEBUG
+  if (![_factory conformsToProtocol:@protocol(ODNodeRendererFactory)]) {
+    NSLog(@"WARNING(%s): node-factory %@ to be registered, doesn't implement "
+          @"the ODNodeRendererFactory protocol !",
+          __PRETTY_FUNCTION__, _factory);
+  }
+#endif
+
+  [self flushCache];
+  
+  entry = [[_ODNodeRendererFactorySetEntry alloc] init];
+  entry->factory      = RETAIN(_factory);
+  entry->namespaceURI = [_namespaceURI copy];
+  entry->tagName      = [_tagName copy];
+  
+  if (self->subfactories == nil)
+    self->subfactories = [[NSMutableArray alloc] initWithCapacity:4];
+  [self->subfactories addObject:entry];
+  RELEASE(entry);
+}
+
+- (void)registerFactory:(id<NSObject,ODNodeRendererFactory>)_factory
+  forNamespaceURI:(NSString *)_namespaceURI
+{
+  [self registerFactory:_factory
+        forNamespaceURI:_namespaceURI
+        tagName:nil];
+}
+
+
+/* lookup */
+
+- (ODNodeRenderer *)rendererForTextNode:(id)_domNode 
+  inContext:(WOContext *)_ctx
+{
+  static id r = nil;
+  if (r == nil) r = [[ODRNodeText alloc] init];
+  return r;
+}
+
+- (ODNodeRenderer *)rendererForElementNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  ODNodeRenderer *renderer;
+  NSString *key;
+  unsigned i, count;
+
+  key = [NSString stringWithFormat:@"{%@}%@",
+                    [_domNode namespaceURI], [_domNode tagName]];
+
+  if ((renderer = [self->cache objectForKey:key]))
+    return renderer;
+
+#if DEBUG && 0
+  NSLog(@"1st lookup renderer: %@", key);
+#endif
+  
+  for (i = 0, count = [self->subfactories count]; i < count; i++) {
+    _ODNodeRendererFactorySetEntry *entry;
+    
+    entry = [self->subfactories objectAtIndex:i];
+
+    if ([entry matchesNode:_domNode]) {
+      renderer = [[entry nodeRendererFactory]
+                         rendererForNode:_domNode
+                         inContext:_ctx];
+      if (renderer) break;
+    }
+  }
+  
+  if (renderer == nil) {
+    /* default tag */
+    static id r = nil;
+    if (r == nil) r = [[ODRGenericTag alloc] init];
+    renderer = r;
+  }
+  
+  if (renderer) {
+    if (self->cache == nil)
+      self->cache = [[NSMutableDictionary alloc] initWithCapacity:64];
+    [self->cache setObject:renderer forKey:key];
+  }
+  
+  return renderer;
+}
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  ODNodeRenderer *renderer;
+  
+  switch ([_domNode nodeType]) {
+    case DOM_TEXT_NODE:
+    case DOM_CDATA_SECTION_NODE:
+      renderer = [self rendererForTextNode:_domNode inContext:_ctx];
+      break;
+      
+    case DOM_ELEMENT_NODE:
+      renderer = [self rendererForElementNode:_domNode inContext:_ctx];
+      break;
+      
+    default: {
+      static id compoundRenderer = nil;
+
+      if (compoundRenderer == nil)
+        compoundRenderer = [[ODNodeRenderer alloc] init];
+      
+      renderer = compoundRenderer;
+      break;
+    }
+  }
+  return renderer;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:32];
+  
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  [ms appendFormat:@" factories=#%d", [self->subfactories count]];
+  [ms appendFormat:@">"];
+  
+  return ms;
+}
+
+@end /* ODNodeRendererFactorySet */
+
+@implementation _ODNodeRendererFactorySetEntry
+
+- (void)dealloc {
+  RELEASE(self->factory);
+  RELEASE(self->namespaceURI);
+  RELEASE(self->tagName);
+  RELEASE(self->qualifier);
+  [super dealloc];
+}
+
+- (BOOL)matchesNode:(id)_node {
+  if (self->namespaceURI) {
+    if (![self->namespaceURI isEqualToString:[_node namespaceURI]])
+      return NO;
+  }
+  if (self->tagName) {
+    if (![self->tagName isEqualToString:[_node tagName]])
+      return NO;
+  }
+  if (self->qualifier) {
+    if (![(id<EOQualifierEvaluation>)self->qualifier evaluateWithObject:_node])
+      return NO;
+  }
+  
+  return YES;
+}
+
+- (ODNodeRendererFactory *)nodeRendererFactory {
+  return self->factory;
+}
+
+@end /* _ODNodeRendererFactorySetEntry */
diff --git a/skyrix-sope/NGObjDOM/ODREmbedComponent.h b/skyrix-sope/NGObjDOM/ODREmbedComponent.h
new file mode 100644 (file)
index 0000000..1c5c322
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_ODREmbedComponent_H__
+#define __NGObjDOM_ODREmbedComponent_H__
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+@interface ODREmbedComponent : ODNodeRenderer
+@end
+
+#endif /* __NGObjDOM_ODREmbedComponent_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODREmbedComponent.m b/skyrix-sope/NGObjDOM/ODREmbedComponent.m
new file mode 100644 (file)
index 0000000..6cb5bab
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODREmbedComponent.h>
+#include <NGObjDOM/ODNamespaces.h>
+#include "common.h"
+
+@interface WOComponent(PrivateMethods)
+- (WOComponent *)childComponentWithName:(NSString *)_cname;
+@end
+
+@interface NSObject(DOMPrivates)
+- (id)attributeNode:(NSString *)_key namespaceURI:(NSString *)_ns;
+@end
+
+extern void WOContext_enterComponent
+(WOContext *_ctx, WOComponent *_component, WOElement *element);
+extern void WOContext_leaveComponent(WOContext *_ctx, WOComponent *_component);
+
+@implementation ODREmbedComponent
+
+- (NSString *)_keyForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  NSString *key;
+  id attrNode;
+  
+  attrNode = [_domNode attributeNode:@"id" namespaceURI:XMLNS_OD_BIND];
+  key      = [attrNode textValue];
+  
+  if ([key length] == 0) {
+    attrNode = [_domNode attributeNode:@"name" namespaceURI:XMLNS_OD_BIND];
+    key      = [attrNode textValue];
+  }
+  
+  if ([key length] == 0)
+    key = [NSString stringWithFormat:@"key0%08X", _domNode];
+  
+  return key;
+}
+
+- (void)takeValuesForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *parent, *child;
+  NSString    *key;
+  
+  key = [self _keyForNode:_domNode inContext:_ctx];
+  
+  if ((parent = [_ctx component]) == nil) {
+    [[_ctx session]
+           logWithFormat:@"WARNING: did not find parent component of child %@",
+             key];
+    return;
+  }
+  if ((child = [parent childComponentWithName:key]) == nil) {
+    [[_ctx session]
+           logWithFormat:
+             @"WARNING: did not find child component %@ of parent %@",
+             key, [parent name]];
+    return;
+  }
+  
+  WOContext_enterComponent(_ctx, child, nil /*self->template*/);
+  [child takeValuesFromRequest:_request inContext:_ctx];
+  WOContext_leaveComponent(_ctx, child);
+}
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  id          result = nil;
+  WOComponent *parent, *child;
+  NSString    *key;
+  
+  key = [self _keyForNode:_domNode inContext:_ctx];
+  
+  if ((parent = [_ctx component]) == nil) {
+    [[_ctx session]
+           logWithFormat:@"WARNING: did not find parent component of child %@",
+             key];
+    return nil;
+  }
+  if ((child = [parent childComponentWithName:key]) == nil) {
+    [[_ctx session]
+           logWithFormat:
+             @"WARNING: did not find child component %@ of parent %@",
+             key, [parent name]];
+    return nil;
+  }
+  
+  WOContext_enterComponent(_ctx, child, nil /*self->template*/);
+  result = [child invokeActionForRequest:_request inContext:_ctx];
+  WOContext_leaveComponent(_ctx, child);
+  
+  return result;
+}
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *parent, *child;
+  NSString    *key;
+  
+  if ([_domNode nodeType] != DOM_ELEMENT_NODE) {
+    [super appendNode:_domNode toResponse:_response inContext:_ctx];
+    return;
+  }
+  
+  key = [self _keyForNode:_domNode inContext:_ctx];
+  
+  if ((parent = [_ctx component]) == nil) {
+    [[_ctx session]
+           logWithFormat:@"WARNING: did not find parent component of child %@",
+             key];
+    return;
+  }
+  
+  if ((child = [parent childComponentWithName:key]) == nil) {
+    [[_ctx session]
+           logWithFormat:
+             @"WARNING: did not find child component %@ of parent %@",
+             key, [parent name]];
+    [_response appendContentString:@"<pre>[missing component: "];
+    [_response appendContentHTMLString:key];
+    [_response appendContentString:@"]</pre>"];
+    return;
+  }
+  
+  WOContext_enterComponent(_ctx, child, nil /*self->template*/);
+  [child appendToResponse:_response inContext:_ctx];
+  WOContext_leaveComponent(_ctx, child);
+}
+
+@end /* ODREmbedComponent */
diff --git a/skyrix-sope/NGObjDOM/ODRGenericTag.h b/skyrix-sope/NGObjDOM/ODRGenericTag.h
new file mode 100644 (file)
index 0000000..8d54346
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODRGenericTag_H__
+#define __ODRGenericTag_H__
+
+#import <Foundation/NSObject.h>
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+  This node-renderer is for rendering ELEMENT_NODE nodes by passing them
+  through. All non-ELEMENT_NODE's are ignored and rendering continues at
+  their children.
+*/
+
+@interface ODRGenericTag : ODNodeRenderer
+{
+  BOOL ignoreTextNodes;
+}
+
+@end
+
+#endif /* __ODRGenericTag_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODRGenericTag.m b/skyrix-sope/NGObjDOM/ODRGenericTag.m
new file mode 100644 (file)
index 0000000..2cea7b4
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODRGenericTag.h>
+#include "common.h"
+
+@implementation ODRGenericTag
+
+- (void)_appendAttributesOfNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  id attrs;
+  id<DOMAttr> attr;
+  NSString *nsuri, *prefix;
+  
+  prefix = [_domNode prefix];
+  nsuri  = [_domNode namespaceURI];
+
+  if ([nsuri length] > 0) {
+    id parentNode;
+    BOOL doNS;
+
+    doNS = YES;
+    
+    if ((parentNode = [_domNode parentNode])) {
+      if ([parentNode nodeType] == DOM_ELEMENT_NODE) {
+        if ([[parentNode namespaceURI] isEqualToString:nsuri]) {
+          NSString *pp;
+          
+          pp = [parentNode prefix];
+          
+          if ((pp == nil) && (prefix == nil))
+            doNS = NO;
+          else if ([pp isEqualToString:prefix])
+            doNS = NO;
+        }
+      }
+    }
+
+    if (doNS) {
+      [_response appendContentString:@" xmlns"];
+      if ([prefix length] > 0) {
+        [_response appendContentString:@":"];
+        [_response appendContentString:prefix];
+      }
+      [_response appendContentString:@"='"];
+      [_response appendContentString:nsuri];
+      [_response appendContentString:@"'"];
+    }
+  }
+  
+  if ((attrs = [(id)[_domNode attributes] objectEnumerator]) == nil)
+    return;
+  
+  while ((attr = [attrs nextObject])) {
+    NSString *attrURI  = nil;
+    NSString *attrName = nil;
+    
+    attrURI = [attr namespaceURI];
+    if ([attrURI length] > 0) {
+      if ([attrURI isEqualToString:nsuri]) {
+        if ([prefix length] > 0)
+          attrName = [NSString stringWithFormat:@"%@:%@", prefix, [attr name]];
+        else
+          attrName = [attr name];
+      }
+      else {
+        /* different namespace */
+        NSLog(@"WARNING(%s): tag '%@'(ns=%@) different namespace %@ ..",
+              __PRETTY_FUNCTION__,
+              [_domNode tagName], [_domNode namespaceURI], attrURI);
+      }
+    }
+    else
+      attrName = [attr name];
+    
+    [_response appendContentString:@" "];
+    [_response appendContentString:attrName];
+    [_response appendContentString:@"='"];
+    [_response appendContentHTMLAttributeValue:[attr value]];
+    [_response appendContentString:@"'"];
+  }
+}
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  if ([_domNode nodeType] != DOM_ELEMENT_NODE) {
+    [super appendNode:_domNode toResponse:_response inContext:_context];
+    return;
+  }
+  
+  [_response appendContentString:@"<"];
+  if ([[_domNode prefix] length] > 0) {
+    [_response appendContentString:[_domNode prefix]];
+    [_response appendContentString:@":"];
+  }
+  [_response appendContentString:[_domNode tagName]];
+    
+  [self _appendAttributesOfNode:_domNode
+        toResponse:_response
+        inContext:_context];
+    
+  if (![_domNode hasChildNodes]) {
+    [_response appendContentString:@" />"];
+  }
+  else {
+    [_response appendContentString:@">"];
+
+    /* children */
+    [self appendChildNodes:[_domNode childNodes]
+          toResponse:_response
+          inContext:_context];
+    
+    [_response appendContentString:@"</"];
+    if ([[_domNode prefix] length] > 0) {
+      [_response appendContentString:[_domNode prefix]];
+      [_response appendContentString:@":"];
+    }
+    [_response appendContentString:[_domNode tagName]];
+    [_response appendContentString:@">"];
+  }
+}
+
+@end /* ODRGenericTag */
diff --git a/skyrix-sope/NGObjDOM/ODRNodeText.h b/skyrix-sope/NGObjDOM/ODRNodeText.h
new file mode 100644 (file)
index 0000000..518918f
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODRNodeText_H__
+#define __ODRNodeText_H__
+
+#import <Foundation/NSObject.h>
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+  This node-renderer renders the -textValue of the node and afterwards
+  the continues rendering at the nodes childnodes.
+*/
+
+@interface ODRNodeText : ODNodeRenderer
+@end
+
+#endif /* __ODRNodeText_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODRNodeText.m b/skyrix-sope/NGObjDOM/ODRNodeText.m
new file mode 100644 (file)
index 0000000..b5cedf8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRNodeText.h"
+#include "common.h"
+
+@implementation ODRNodeText
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  [_response appendContentHTMLString:[_domNode textValue]];
+}
+
+@end /* ODRNodeText */
diff --git a/skyrix-sope/NGObjDOM/ODRWebObject.h b/skyrix-sope/NGObjDOM/ODRWebObject.h
new file mode 100644 (file)
index 0000000..c7273c6
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODRWebObject_H__
+#define __ODRWebObject_H__
+
+#import <Foundation/NSObject.h>
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+  Embed nodes as NGObjWeb dynamic elements.
+*/
+
+@interface ODRWebObject : ODNodeRenderer
+@end
+
+#endif /* __ODRWebObject_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODRWebObject.m b/skyrix-sope/NGObjDOM/ODRWebObject.m
new file mode 100644 (file)
index 0000000..82ae297
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjDOM/ODRWebObject.h>
+#include <NGObjDOM/ODNamespaces.h>
+#include <NGObjWeb/WODynamicElement.h>
+#include "common.h"
+
+@interface NSObject(WOPrivates)
++ (BOOL)isDynamicElement;
+- (BOOL)isDynamicElement;
+@end
+
+@interface _WODRTemplateElement : WODynamicElement
+{
+@public
+  /* both non-retained */
+  ODNodeRenderer *renderer;
+  id domNode;
+}
+@end
+
+@implementation ODRWebObject
+
+- (NSMutableDictionary *)associationsForNodeAttributes:(id)_domNode {
+  NSMutableDictionary *md;
+  NSEnumerator *attrs;
+  id attrNode;
+  
+  md = [NSMutableDictionary dictionaryWithCapacity:16];
+  
+  attrs = [(id)[_domNode attributes] objectEnumerator];
+  while ((attrNode = [attrs nextObject])) {
+    NSString *nsuri;
+    
+    nsuri = [attrNode namespaceURI];
+    
+    if ([nsuri isEqualToString:XMLNS_OD_BIND]) {
+      [md setObject:[WOAssociation associationWithKeyPath:[attrNode textValue]]
+          forKey:[(id<DOMAttr>)attrNode name]];
+    }
+    else {
+      [md setObject:[WOAssociation associationWithValue:[attrNode textValue]]
+          forKey:[(id<DOMAttr>)attrNode name]];
+    }
+  }
+  
+  return md;
+}
+
+- (WOElement *)constructElementForElementNode:(id)_domNode {
+  Class clazz;
+  
+  clazz = NSClassFromString([_domNode tagName]);
+
+  if (clazz == Nil) {
+    NSLog(@"%s: Can't find class for node %@",
+          __PRETTY_FUNCTION__, _domNode);
+    return nil;
+  }
+  else if ([clazz isDynamicElement]) {
+    WODynamicElement     *elem;
+    NSString             *elemName;
+    NSMutableDictionary  *assocs;
+    _WODRTemplateElement *template;
+
+    elemName = [[[_domNode attributes] namedItem:@"id"] textValue];
+    assocs   = [self associationsForNodeAttributes:_domNode];
+    template = nil;
+
+    if ([_domNode hasChildNodes]) {
+      template = [[_WODRTemplateElement alloc] init];
+      template->renderer = self;
+      template->domNode  = _domNode;
+      AUTORELEASE(template);
+    }
+    
+    elem  = [clazz alloc];
+    elem  = [elem initWithName:elemName
+                  associations:assocs
+                  template:template];
+    
+    if ([assocs count] > 0)
+      [elem setExtraAttributes:assocs];
+    
+    [assocs removeAllObjects];
+    
+    return AUTORELEASE(elem);
+  }
+  else {
+    NSLog(@"%s: Can't handle element class %@ for node %@",
+          __PRETTY_FUNCTION__,
+          clazz, _domNode);
+    return nil;
+  }
+}
+
+- (void)takeValuesForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  WOElement *e;
+  
+  e = [self constructElementForElementNode:_domNode];
+  [e takeValuesFromRequest:_request inContext:_context];
+}
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  WOElement *e;
+  id result;
+  
+  e = [self constructElementForElementNode:_domNode];
+  result = [e invokeActionForRequest:_request inContext:_context];
+  
+  return result;
+}
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  WOElement *e;
+  
+  if ([_domNode nodeType] != DOM_ELEMENT_NODE) {
+    [super appendNode:_domNode toResponse:_response inContext:_context];
+    return;
+  }
+  
+  e = [self constructElementForElementNode:_domNode];
+  [e appendToResponse:_response inContext:_context];
+}
+
+@end /* ODRWebObject */
+
+@implementation _WODRTemplateElement
+
+- (id)_childRendererForNode:(id)_node {
+  static id childRenderer = nil;
+  if (childRenderer == nil)
+    childRenderer = [[NSClassFromString(@"WODRChildNodes") alloc] init];
+  return childRenderer;
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  if (![self->domNode hasChildNodes])
+    return;
+  
+  [self->renderer takeValuesForChildNodes:[self->domNode childNodes]
+       fromRequest:_request
+       inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  if (![self->domNode hasChildNodes])
+    return nil;
+  
+  return [self->renderer invokeActionForChildNodes:[self->domNode childNodes]
+              fromRequest:_request
+              inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if ([self->domNode hasChildNodes]) {
+    //NSLog(@"%s: %@ ..", __PRETTY_FUNCTION__, self->domNode);
+  
+    [self->renderer appendChildNodes:[self->domNode childNodes]
+         toResponse:_response
+         inContext:_ctx];
+  }
+}
+
+@end /* _WODRTemplateElement */
+
diff --git a/skyrix-sope/NGObjDOM/ODR_bind_collapsible.h b/skyrix-sope/NGObjDOM/ODR_bind_collapsible.h
new file mode 100644 (file)
index 0000000..037396c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+
+#ifndef __NGObjDOM_ODR_bind_collapsible_h__
+#define __NGObjDOM_ODR_bind_collapsible_h__
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+@interface ODR_bind_collapsible : ODNodeRenderer
+{
+}
+@end
+
+#endif /* __NGObjDOM_ODR_bind_collapsible_h__ */
diff --git a/skyrix-sope/NGObjDOM/ODR_bind_fieldset.h b/skyrix-sope/NGObjDOM/ODR_bind_fieldset.h
new file mode 100644 (file)
index 0000000..ed7e6dd
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  attributes:
+
+    <fieldset>:
+    
+       labelcolor   - bgColor of label-td
+       contentcolor - bgColor of content-td
+       labelwidth   - width   of label-td
+       fontcolor    - font color of labelstrings
+       fontsize     - font size  of labelstrings
+       fontface     - font face  of labelstrings
+
+    <field>:
+
+       label        - label string
+
+  structure:
+
+    <var:fieldset>
+    
+       <var:field label="label string">
+         <var:label>label content</var:label>
+         < ... some content ...>
+       </var:field>
+
+       ...
+       
+    </var:fieldset>
+
+*/
+
+#ifndef __NGObjDOM_ODR_bind_fieldset_h__
+#define __NGObjDOM_ODR_bind_fieldset_h__
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+@interface ODR_bind_fieldset : ODNodeRenderer
+@end
+
+#endif /* __NGObjDOM_ODR_bind_fieldset_h__ */
diff --git a/skyrix-sope/NGObjDOM/ODR_bind_tableview.h b/skyrix-sope/NGObjDOM/ODR_bind_tableview.h
new file mode 100644 (file)
index 0000000..ea0067f
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_Dynamic_tableview_H__
+#define __NGObjDOM_Dynamic_tableview_H__
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+
+*/
+
+#define ODRTableView_              @"ODRTableView_"
+#define ODRTableView_CollectMode   @"ODRTableView_CollectMode"
+#define ODRTableView_TitleMode     @"ODRTableView_TitleMode"
+#define ODRTableView_ButtonMode    @"ODRTableView_ButtonMode"
+#define ODRTableView_HeaderMode    @"ODRTableView_HeaderMode"
+#define ODRTableView_DataMode      @"ODRTableView_DataMode"
+#define ODRTableView_FooterMode    @"ODRTableView_FooterMode"
+#define ODRTableView_GroupMode     @"ODRTableView_GroupMode"
+
+#define ODRTableView_INFOS         @"ODRTableView_INFOS"
+#define ODRTableView_SORTEDKEY     @"ODRTableView_SORTEDKEY"
+#define ODRTableView_ISDESCENDING  @"ODRTableView_ISDESCENDING"
+
+#define ODRTableView_GroupItems    @"ODRTableView_GroupItems"
+#define ODRTableView_GroupName     @"ODRTableView_GroupName"
+
+#define ODRTableView_HasCollapseScript @"ODRTableView_HasCollapseScript"
+
+// config stuff:
+#define ODRTableView_titleColor    @"ODRTableView_titleColor"
+#define ODRTableView_headerColor   @"ODRTableView_headerColor"
+#define ODRTableView_footerColor   @"ODRTableView_footerColor"
+#define ODRTableView_groupColor    @"ODRTableView_groupColor"
+#define ODRTableView_evenColor     @"ODRTableView_evenColor"
+#define ODRTableView_oddColor      @"ODRTableView_oddColor"
+#define ODRTableView_fontColor     @"ODRTableView_fontColor"
+#define ODRTableView_fontFace      @"ODRTableView_fontFace"
+#define ODRTableView_fontSize      @"ODRTableView_fontSize"
+
+// sort icons:
+#define ODRTableView_upwardIcon    @"ODRTableView_upwardIcon"
+#define ODRTableView_downwardIcon  @"ODRTableView_downwardIcon"
+#define ODRTableView_nonSortIcon   @"ODRTableView_nonSortIcon"
+
+// navigation icons
+#define ODRTableView_first           @"ODRTableView_first"
+#define ODRTableView_first_blind     @"ODRTableView_first_blind"
+#define ODRTableView_previous        @"ODRTableView_previous"
+#define ODRTableView_previous_blind  @"ODRTableView_previous_blind"
+#define ODRTableView_next            @"ODRTableView_next"
+#define ODRTableView_next_blind      @"ODRTableView_next_blind"
+#define ODRTableView_last            @"ODRTableView_last"
+#define ODRTableView_last_blind      @"ODRTableView_last_blind"
+#define ODRTableView_openedIcon      @"ODRTableView_openedIcon"
+#define ODRTableView_closedIcon      @"ODRTableView_closedIcon"
+#define ODRTableView_minusIcon       @"ODRTableView_minusIcon"
+#define ODRTableView_plusIcon        @"ODRTableView_plusIcon"
+#define ODRTableView_select_all      @"ODRTableView_select_all"
+#define ODRTableView_deselect_all    @"ODRTableView_deselect_all"
+
+// labels
+#define ODRTableView_ofLabel         @"ODRTableView_ofLabel"
+#define ODRTableView_toLabel         @"ODRTableView_toLabel"
+#define ODRTableView_firstLabel      @"ODRTableView_firstLabel"
+#define ODRTableView_previousLabel   @"ODRTableView_previousLabel"
+#define ODRTableView_nextLabel       @"ODRTableView_nextLabel"
+#define ODRTableView_lastLabel       @"ODRTableView_lastLabel"
+#define ODRTableView_pageLabel       @"ODRTableView_pageLabel"
+#define ODRTableView_sortLabel       @"ODRTableView_sortLabel"
+
+@class NSArray, NSDictionary, NSString;
+
+@interface ODR_bind_tableview : ODNodeRenderer
+{
+  /* caching */
+  NSArray             *list;
+  NSString            *scriptID; // to unify the JavaScript
+  struct {
+    unsigned currentBatch;
+    unsigned batchSize;
+    unsigned firstIndex;
+    unsigned lastIndex;
+    unsigned batchCount;
+    unsigned groupCount;
+  } state;
+  
+  struct {
+    BOOL     checkBoxes;
+    BOOL     overflow;           // generate overflow-scrolling
+    BOOL     scriptScrolling;    // scroll pages per JavaScript
+    BOOL     scriptCollapsing;   // collapse groups per JavaScript
+    BOOL     batchResizeButtons;
+  } use;
+
+  NSDictionary *groupedList;
+  NSArray      *indexToGrouppath;
+}
+- (void)updateStateOfNode:(id)_node inContext:(WOContext *)_ctx;
+@end
+
+static inline NSString *ODRTableLabelForKey(NSString *_key, WOContext *_ctx)
+     __attribute__((unused));
+
+#include <NGObjWeb/WOContext.h>
+#import <Foundation/NSString.h>
+
+static NSString *ODRTableLabelForKey(NSString *_key, WOContext *_ctx) {
+  NSString *key;
+  key = [NSString stringWithFormat:@"ODRTableView_%@Label", _key];
+  return [_ctx objectForKey:key];
+}
+
+@interface ODRTableViewInfo: NSObject
+{
+@public
+  unsigned rowSpan;
+  BOOL     isGroup;
+  BOOL     isEven;
+  BOOL     isSorted;
+}
+@end
+
+@interface ODR_bind_ttitle : ODNodeRenderer
+@end
+
+@interface ODR_bind_tbutton : ODNodeRenderer
+@end
+
+@interface ODR_bind_tfooter : ODNodeRenderer
+@end
+
+@interface ODR_bind_tgroup : ODNodeRenderer
+@end
+
+
+#endif /* __NGObjDOM_Dynamic_tableview_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODR_bind_tabview.h b/skyrix-sope/NGObjDOM/ODR_bind_tabview.h
new file mode 100644 (file)
index 0000000..84706f7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_ODR_bind_tabview_h__
+#define __NGObjDOM_ODR_bind_tabview_h__
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+@interface ODR_bind_tabview : ODNodeRenderer
+{
+  NSString *activeKey;
+}
+@end
+
+#endif /* __NGObjDOM_ODR_bind_tabview_h__ */
+
diff --git a/skyrix-sope/NGObjDOM/ODR_bind_viewertitle.h b/skyrix-sope/NGObjDOM/ODR_bind_viewertitle.h
new file mode 100644 (file)
index 0000000..14c4c3d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_ODR_bin_viewertitle_H__
+#define __NGObjDOM_ODR_bin_viewertitle_H__
+
+#include <NGObjDOM/ODNodeRenderer.h>
+
+@interface ODR_bind_viewertitle : ODNodeRenderer
+@end
+
+@interface ODR_bind_vtitle : ODNodeRenderer
+@end
+
+@interface ODR_bind_vbutton : ODNodeRenderer
+@end
+
+#endif /* __NGObjDOM_ODR_bin_viewertitle_H__ */
+
diff --git a/skyrix-sope/NGObjDOM/ODResourceManager.h b/skyrix-sope/NGObjDOM/ODResourceManager.h
new file mode 100644 (file)
index 0000000..5b9a0d5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODResourceManager_H__
+#define __ODResourceManager_H__
+
+#import <NGObjWeb/WOResourceManager.h>
+
+/*
+  Extends the standard resource manager to look for XML components ...
+*/
+
+@class NSMutableDictionary;
+
+@interface ODResourceManager : WOResourceManager
+{
+  NSMutableDictionary *nameToCDef;
+}
+
+@end
+
+#endif /* __ODResourceManager_H__ */
diff --git a/skyrix-sope/NGObjDOM/ODResourceManager.m b/skyrix-sope/NGObjDOM/ODResourceManager.m
new file mode 100644 (file)
index 0000000..a8c2ab7
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "ODResourceManager.h"
+#include "common.h"
+
+@interface WOResourceManager(Privates)
+
+- (id)definitionForComponent:(NSString *)_name
+  languages:(NSArray *)_languages;
+- (NSString *)pathToComponentNamed:(NSString *)_name
+  inFramework:(NSString *)_fw;
+
+@end
+
+@implementation ODResourceManager
+
++ (int)version {
+  return [super version] + 0 /* v3 */;
+}
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  NSDictionary *defs;
+  
+  NSAssert2([super version] == 3,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  if (isInitialized) return;
+  isInitialized = YES;
+
+  defs = [NSDictionary dictionaryWithObjectsAndKeys:
+                           [NSArray arrayWithObjects:
+                                      @"xml", @"wml", @"xhtml", nil],
+                           @"ODXMLComponentExtensions",
+                           nil];
+  // .svg, ... can be added using the default
+    
+  [[NSUserDefaults standardUserDefaults] registerDefaults:defs];
+}
+
++ (NSArray *)xmlComponentExtensions {
+  static NSArray *exts = nil;
+
+  if (exts == nil) {
+    exts = [[[NSUserDefaults standardUserDefaults]
+                             arrayForKey:@"ODXMLComponentExtensions"]
+                             copy];
+  }
+  
+  return exts;
+}
+
+- (void)dealloc {
+  RELEASE(self->nameToCDef);
+  [super dealloc];
+}
+
+/* lookup */
+
+- (NSString *)pathToComponentNamed:(NSString *)_name
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_langs
+{
+  /* search for component template .. */
+  
+  if (_name == nil) {
+#ifdef DEBUG
+    NSLog(@"WARNING(%s): tried to get path to component with <nil> name !",
+          __PRETTY_FUNCTION__);
+#endif
+    return nil;
+  }
+  
+  /* scan for name.$ext resource ... */
+  {
+    NSEnumerator *e;
+    NSString *ext;
+    
+    e = [[[self class] xmlComponentExtensions] objectEnumerator];
+    
+    while ((ext = [e nextObject])) {
+      NSString *templateName;
+      NSString *path;
+      
+      templateName = [_name stringByAppendingPathExtension:ext];
+      
+      path = [self pathForResourceNamed:templateName
+                   inFramework:_framework
+                   languages:_langs];
+      if (path) return path;
+    }
+  }
+  
+  /* this resource manager does not search in WOProjectSearchPath ... */
+  
+  return [super pathToComponentNamed:_name inFramework:_framework];
+}
+
+- (id)definitionForComponent:(NSString *)_name
+  languages:(NSArray *)_languages
+{
+  id cdef;
+  id cacheKey = nil;
+  
+  if (_name == nil)
+    return nil;
+  
+  if (_languages == nil)
+    _languages = [NSArray array];
+  
+  /* look into cache */
+  
+  if ([[WOApplication application] isCachingEnabled]) {
+    cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
+    
+    if ((cdef = [self->nameToCDef objectForKey:cacheKey]))
+      return cdef;
+  }
+  else {
+    cdef     = nil;
+    cacheKey = nil;
+  }
+  
+  /* look for .wo component if no XML component could be found ... */
+  
+  if (cdef == nil)
+    cdef = [super definitionForComponent:_name languages:_languages];
+  
+  /* return result */
+  
+  return cdef;
+}
+
+@end /* ODResourceManager */
diff --git a/skyrix-sope/NGObjDOM/ODWONodeRenderFactory.m b/skyrix-sope/NGObjDOM/ODWONodeRenderFactory.m
new file mode 100644 (file)
index 0000000..ca325d8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/ODNodeRendererFactory.h>
+
+@interface ODWONodeRenderFactory : NSObject < ODNodeRendererFactory >
+@end
+
+#include "ODREmbedComponent.h"
+#include <NGObjDOM/ODRWebObject.h>
+#include <NGObjDOM/ODREmbedComponent.h>
+#include <NGObjDOM/ODNamespaces.h>
+#include <NGObjDOM/ODNodeRenderer.h>
+#include "common.h"
+
+@implementation ODWONodeRenderFactory
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  ODNodeRenderer *renderer;
+  
+  if (![[_domNode namespaceURI] isEqualToString:XMLNS_OD_BIND])
+    return nil;
+  
+  if ([[_domNode tagName] isEqualToString:@"embed"]) {
+    static ODREmbedComponent *wor = nil;
+    if (wor == nil)
+      wor = [[ODREmbedComponent alloc] init];;
+    renderer = wor;
+  }
+  else {
+    static ODRWebObject *wor = nil;
+    if (wor == nil)
+      wor = [[ODRWebObject alloc] init];;
+    renderer = wor;
+  }
+  
+  return renderer;
+}
+
+@end /* ODWONodeRenderFactory */
diff --git a/skyrix-sope/NGObjDOM/README b/skyrix-sope/NGObjDOM/README
new file mode 100644 (file)
index 0000000..0010a18
--- /dev/null
@@ -0,0 +1,60 @@
+
+NGObjDOM XML Rendering Framework
+================================
+
+Note: while NGObjDOM *is* useful it is more or less deprecated in the places
+      where it is currently used, which are: OGo forms and OGo publisher.
+      In both cases the NGObjDOM implementation of the templates should be
+      replaced using NGObjWeb XML DOM builders for a major speedup and far
+      better integration into the NGObjWeb server.
+
+NGObjDOM is a framework which works together with NGObjWeb to render
+XML content represented as DOM trees.
+It can be used to create templates (WODynamicElement's) represented
+as XML files instead of .wo components.
+
+To render a DOM tree you can use the WORenderDOM dynamic element, eg:
+
+  <#DOMContent />
+
+  DOMContent: WORenderDOM {
+    domDocument = domTree;
+    factory     = passThroughHTMLRenderer;
+  }
+
+The DOM is processed using so called 'node renderers', which are roughly
+identical to WODynamicElements but differ in that they only perform the
+operation and do not represent the template tree (WODynamic elements are
+tree nodes with behaviour, this is separated in NGObjDOM: the tree is the
+DOM, the behaviour are the renderers).
+
+The superclass for all node renderers is ODNodeRenderer and already provides
+some convinience methods for accessing attributes and such. The ODR class
+prefix stands in for 'ObjDOM Renderer'.
+
+A bridge to dynamic elements in the other direction (embedding 
+WODynamicElement's in DOM trees) is the ODRWebObject renderer.
+
+Profiling
+=========
+
+You can profile the renderer using the defaults
+
+  ODProfileRenderer    - bool
+and
+  ODProfileRendererMin - double
+
+Defaults
+========
+
+  ODNodeRendererDebugCursor - bool
+
+ODProfileRenderer - Bool - log render profiling information
+
+ODNodeRenderer Debug Defaults
+  ODEvalAttrValuesInExceptionHandler - bool
+  ODDebugJSAttrEval - bool
+  ODLogAttrValues   - bool
+
+---
+hh, 2001-05-30
diff --git a/skyrix-sope/NGObjDOM/Version b/skyrix-sope/NGObjDOM/Version
new file mode 100644 (file)
index 0000000..4345f38
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=24
\ No newline at end of file
diff --git a/skyrix-sope/NGObjDOM/WOContext+Cursor.h b/skyrix-sope/NGObjDOM/WOContext+Cursor.h
new file mode 100644 (file)
index 0000000..b7bfb99
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __WOContext_Cursor_H__
+#define __WOContext_Cursor_H__
+
+#include <NGObjWeb/WOContext.h>
+
+/*
+  Cursors are used by evaluating bindings. The default-cursor is always the
+  active context component, so the default behaviour is like in WO.
+  
+  Cursors are useful for reducing the need for those 'item' bindings.
+*/
+
+@interface WOContext(Cursor)
+
+- (void)pushCursor:(id)_cursor;
+- (id)popCursor;
+- (id)cursor;
+
+@end
+
+#endif /* __WOContext_Cursor_H__ */
diff --git a/skyrix-sope/NGObjDOM/WORenderDOM.h b/skyrix-sope/NGObjDOM/WORenderDOM.h
new file mode 100644 (file)
index 0000000..1d2e553
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_WORenderDOM_H__
+#define __NGObjDOM_WORenderDOM_H__
+
+#include <NGObjWeb/WODynamicElement.h>
+#include <NGObjDOM/ODNodeRendererFactory.h>
+
+/*
+  This is a NGObjWeb dynamic element for rendering a DOM tree.
+
+  Bindings:
+
+    domDocument [in]
+    node        [out]
+    factory     [in]
+    renderer    [in]
+
+  'Factory' and 'renderer' bindings are invoked with 'node' setup to the
+  currently processed DOM-node of 'domDocument'.
+
+  The dynamic element binds itself as the node renderer factory to the ctx,
+  and forwards any renderer creation request to either a factory, if
+  the factory binding is set, or to a component, if the 'node' binding is set.
+*/
+
+@interface WORenderDOM : WODynamicElement < ODNodeRendererFactory >
+{
+  WOAssociation *domDocument; /* the document object            */
+  WOAssociation *factory;     /* the renderer factory           */
+  WOAssociation *node;        /* the current node for callbacks */
+  WOAssociation *renderer;    /* the renderer to apply on node  */
+}
+
+- (id)domInContext:(WOContext *)_ctx; // used in SkyForm
+
+@end
+
+#endif /* __NGObjDOM_WORenderDOM_H__ */
diff --git a/skyrix-sope/NGObjDOM/WORenderDOM.m b/skyrix-sope/NGObjDOM/WORenderDOM.m
new file mode 100644 (file)
index 0000000..a1f7489
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjDOM/WORenderDOM.h>
+#include "ODNodeRenderer.h"
+#include "common.h"
+
+//#define DEBUG_DOM
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+#  define sel_get_name sel_getName
+#endif
+
+@interface WOContext(Privates)
+- (unsigned)componentStackCount;
+- (id)activeFormElement;
+@end
+
+@implementation WORenderDOM
+
+static int profileComponents = -1;
+static Class NSDateClass = Nil;
+
++ (void)initialize {
+  if (NSDateClass == Nil)
+    NSDateClass = [NSDate class];
+  if (profileComponents == -1) {
+    profileComponents = [[[NSUserDefaults standardUserDefaults]
+                                          objectForKey:@"WOProfileComponents"]
+                                          boolValue] ? 1 : 0;
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_assocs
+  template:(WOElement *)_templ
+{
+  if ((self = [super initWithName:_name associations:nil template:nil])){
+    if (_templ)
+      NSLog(@"WARNING(%s): contains template !", __PRETTY_FUNCTION__);
+    
+    self->domDocument = [[_assocs objectForKey:@"domDocument"] copy];
+    self->node        = [[_assocs objectForKey:@"node"]        copy];
+    self->renderer    = [[_assocs objectForKey:@"renderer"]    copy];
+    self->factory     = [[_assocs objectForKey:@"factory"]     copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->factory);
+  RELEASE(self->node);
+  RELEASE(self->renderer);
+  RELEASE(self->domDocument);
+  [super dealloc];
+}
+
+/* discovering renders */
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  ODNodeRenderer *lrenderer;
+  
+  if ([self->node isValueSettable])
+    [self->node setValue:_domNode inComponent:[_ctx component]];
+
+  if (self->factory) {
+    id<ODNodeRendererFactory> lfactory;
+
+    if ((lfactory = [self->factory valueInComponent:[_ctx component]])) {
+#if DEBUG && 0
+      NSLog(@"factory: %@", lfactory);
+#endif
+      lrenderer = [lfactory rendererForNode:_domNode inContext:_ctx];
+    }
+    else
+      lrenderer = nil;
+  }
+  else if (self->renderer)
+    lrenderer = [self->renderer valueInComponent:[_ctx component]];
+  else
+    lrenderer = nil;
+
+#if DEBUG && 0
+  NSLog(@"lrenderer: %@", lrenderer);
+#endif
+  
+  return lrenderer;
+}
+
+/* root level methods */
+
+- (id)pushToCtx:(WOContext *)_ctx {
+  id old;
+
+  old = [_ctx objectForKey:@"domRenderFactory"];
+  [_ctx setObject:self forKey:@"domRenderFactory"];
+  return old;
+}
+- (void)popFromCtx:(WOContext *)_ctx old:(id)_old {
+  if (_old)
+    [_ctx setObject:_old forKey:@"domRenderFactory"];
+  else
+    [_ctx removeObjectForKey:@"domRenderFactory"];
+}
+
+- (BOOL)_requiresFormInContext:(WOContext *)_ctx
+  node:(id)_domNode
+  renderer:(id)_renderer
+{
+  if ([_ctx isInForm])
+    return NO;
+  
+  return [_renderer requiresFormForNode:_domNode inContext:_ctx];
+}
+
+- (id)domInContext:(WOContext *)_ctx {
+  return [self->domDocument valueInComponent:[_ctx component]];
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  ODNodeRenderer *lrenderer;
+  id   edom;
+  id   old;
+  BOOL doForm;
+  NSTimeInterval st = 0.0;
+
+  if (profileComponents)
+    st = [[NSDateClass date] timeIntervalSince1970];
+  
+#if DEBUG
+  if ([_ctx isInForm]) {
+    NSLog(@"WARNING(%s): this element shouldn't be used in forms, it generates "
+          @"it's own one.", __PRETTY_FUNCTION__);
+  }
+#endif
+
+  if ((edom = [self domInContext:_ctx]) == nil)
+    return;
+  
+  old = [self pushToCtx:_ctx];
+  
+  lrenderer = [self rendererForNode:edom inContext:_ctx];
+  doForm = [self _requiresFormInContext:_ctx node:edom renderer:lrenderer];
+
+  if (doForm) {
+    [_ctx setInForm:YES];
+  }
+  
+  [lrenderer takeValuesForNode:edom
+             fromRequest:_request
+             inContext:_ctx];
+
+  if (doForm) {
+    [_ctx setInForm:NO];
+  }
+  
+  [self popFromCtx:_ctx old:old];
+  
+  if (profileComponents) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    for (i = [_ctx componentStackCount]; i >= 0; i--)
+      printf("  ");
+    printf("[%s %s]: %0.3fs\n",
+           "WORenderDOM", sel_get_name(_cmd), diff);
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  ODNodeRenderer *lrenderer;
+  id   result;
+  id   edom;
+  id   old;
+  BOOL doForm;
+  NSTimeInterval st = 0.0;
+
+  if (profileComponents)
+    st = [[NSDateClass date] timeIntervalSince1970];
+
+#if DEBUG
+  if ([_ctx isInForm]) {
+    NSLog(@"WARNING(%s): this element shouldn't be used in forms, it generates "
+          @"it's own one.", __PRETTY_FUNCTION__);
+  }
+#endif
+  
+  if ((edom = [self domInContext:_ctx]) == nil)
+    /* no DOM tree available */
+    return nil;
+  
+  old = [self pushToCtx:_ctx];
+  
+  lrenderer = [self rendererForNode:edom inContext:_ctx];
+  doForm    = [self _requiresFormInContext:_ctx node:edom renderer:lrenderer];
+  
+  if (doForm) {
+    [_ctx setInForm:YES];
+    
+    if ([_ctx currentElementID] == nil) {
+      id activeNode;
+      
+      activeNode = [_ctx activeFormElement];
+      
+      lrenderer = [self rendererForNode:activeNode inContext:_ctx];
+
+      result = [lrenderer invokeActionForNode:activeNode
+                          fromRequest:_request
+                          inContext:_ctx];
+    }
+    else {
+      result = [lrenderer invokeActionForNode:edom
+                          fromRequest:_request
+                          inContext:_ctx];
+    }
+    
+    [_ctx setInForm:NO];
+  }
+  else {
+    result = [lrenderer invokeActionForNode:edom
+                        fromRequest:_request
+                        inContext:_ctx];
+  }
+  
+  [self popFromCtx:_ctx old:old];
+  
+  if (profileComponents) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    for (i = [_ctx componentStackCount]; i >= 0; i--)
+      printf("  ");
+    printf("[%s %s]: %0.3fs\n",
+           "WORenderDOM", sel_get_name(_cmd), diff);
+  }
+
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  ODNodeRenderer *lrenderer;
+  WOComponent    *cmp;
+  id   edom;
+  id   old;
+  BOOL doForm;
+  NSTimeInterval st = 0.0;
+
+  if (profileComponents)
+    st = [[NSDateClass date] timeIntervalSince1970];
+
+#if DEBUG
+  if ([_ctx isInForm]) {
+    NSLog(@"WARNING(%s): this element shouldn't be used in forms, it generates "
+          @"it's own one.", __PRETTY_FUNCTION__);
+  }
+#endif
+  
+  cmp = [_ctx component];
+  
+#if DEBUG_DOM
+  NSAssert(_ctx,      @"missing context ..");
+  NSAssert(_response, @"missing response ..");
+  NSAssert(cmp,       @"missing component ..");
+  [_response appendContentString:@"<!-- renderdom-begin -->"];
+#endif
+  
+  if ((edom = [self domInContext:_ctx]) == nil) {
+#if DEBUG_DOM
+    [cmp logWithFormat:@"no DOM to render .."];
+    [_response appendContentString:@"<!-- missing dom -->"];
+#endif
+    return;
+  }
+  
+  old = [self pushToCtx:_ctx];
+  
+  if ((lrenderer = [self rendererForNode:edom inContext:_ctx]) == nil) {
+#if DEBUG_DOM
+    [cmp logWithFormat:@"did not find renderer for node %@", edom];
+    [_response appendContentString:@"<!-- missing dom renderer -->"];
+#endif
+    return;
+  }
+  
+  doForm = [self _requiresFormInContext:_ctx node:edom renderer:lrenderer];
+  
+  if (doForm) {
+    [_response appendContentString:@"<form method=\"post\" action=\""];
+    [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentString:@"\">"];
+    [_ctx setInForm:YES];
+  }
+  
+#if DEBUG_DOM
+  [cmp logWithFormat:@"render dom %@ using %@", edom, lrenderer];
+  NSAssert(lrenderer, @"lost renderer ..");
+#endif
+  
+  [lrenderer appendNode:edom
+             toResponse:_response
+             inContext:_ctx];
+  
+  if (doForm) {
+    [_ctx setInForm:NO];
+    [_response appendContentString:@"</form>"];
+  }
+
+#if DEBUG_DOM
+  NSAssert(_response, @"lost response ..");
+  [_response appendContentString:@"<!-- renderdom-end -->"];
+#endif
+  
+  [self popFromCtx:_ctx old:old];
+  
+  if (profileComponents) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    for (i = [_ctx componentStackCount]; i >= 0; i--)
+      printf("  ");
+    printf("[%s %s]: %0.3fs (component=%s)\n",
+           "WORenderDOM", sel_get_name(_cmd), diff,
+           [[(WOComponent *)[_ctx component] name] cString]);
+  }
+}
+
+@end /* WORenderDOM */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/.cvsignore b/skyrix-sope/NGObjDOM/XHTML.subproj/.cvsignore
new file mode 100644 (file)
index 0000000..623b626
--- /dev/null
@@ -0,0 +1,3 @@
+XHTML.odr
+shared_debug_obj
+shared_obj
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/COPYING b/skyrix-sope/NGObjDOM/XHTML.subproj/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ChangeLog b/skyrix-sope/NGObjDOM/XHTML.subproj/ChangeLog
new file mode 100644 (file)
index 0000000..5db30af
--- /dev/null
@@ -0,0 +1,38 @@
+2004-07-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODRDynamicXHTMLTag.m, ODR_XHTML_a.m: fixed some gcc 3.4 warnings 
+         (v4.2.24)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package.
+
+2003-12-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile (BUNDLE_INSTALL_DIR): use GNUSTEP_INSTALLATION_DIR 
+         instead of GNUSTEP_USER_ROOT
+
+Wed Oct 22 15:58:32 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * GNUmakefile.preamble: add ADDITIONAL_LIB_DIRS NGScripting 
+
+Tue Nov 20 12:12:45 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_XHTML_input.m (-takeValuesForNode:fromRequest:inContext:):
+         added selection attribute used for radio-buttons
+
+Tue Jul 17 17:38:55 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_XHTML_input.m (-takeValuesForNode:fromRequest:inContext:): 
+         set value for the active radio-button
+
+Thu Jul  5 18:12:15 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ODR_XHTML_a.m: added dynamic 'action' and 'page' bindings
+
+Thu Jul  5 18:11:30 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * created ChangeLog
+
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/GNUmakefile b/skyrix-sope/NGObjDOM/XHTML.subproj/GNUmakefile
new file mode 100644 (file)
index 0000000..0069282
--- /dev/null
@@ -0,0 +1,34 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+BUNDLE_NAME        = XHTML
+BUNDLE_EXTENSION   = .odr
+BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/Bundles
+
+XHTML_OBJC_FILES = \
+       ODRDynamicXHTMLTag.m            \
+       ODXHTMLNodeRenderFactory.m      \
+       \
+       ODR_XHTML_a.m           \
+       ODR_XHTML_button.m      \
+       ODR_XHTML_form.m        \
+       ODR_XHTML_img.m         \
+       ODR_XHTML_input.m       \
+       ODR_XHTML_option.m      \
+       ODR_XHTML_select.m      \
+       ODR_XHTML_textarea.m    \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/GNUmakefile.preamble b/skyrix-sope/NGObjDOM/XHTML.subproj/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..7bca8ed
--- /dev/null
@@ -0,0 +1,39 @@
+# $Id$
+
+ADDITIONAL_CPPFLAGS += -pipe -Wall
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..                    \
+       -I../..                 \
+       -I../../NGObjWeb
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_SOPE=$(GNUSTEP_BUILD_DIR)/../..
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/../../../skyrix-core
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../../skyrix-xml
+
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                                            \
+        -L$(RELBUILD_DIR_SOPE)/NGObjDOM/$(GNUSTEP_OBJ_DIR_NAME)                \
+        -L$(RELBUILD_DIR_SOPE)/NGObjWeb/$(GNUSTEP_OBJ_DIR_NAME)                \
+        -L$(RELBUILD_DIR_SOPE)/NGJavaScript/$(GNUSTEP_OBJ_DIR_NAME)    \
+        -L$(RELBUILD_DIR_SOPE)/NGScripting/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGMime/$(GNUSTEP_OBJ_DIR_NAME)        \
+        -L$(RELBUILD_DIR_SxCore)/NGStreams/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+        -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)             \
+        -L$(RELBUILD_DIR_SxXml)/XmlRpc/$(GNUSTEP_OBJ_DIR_NAME)         \
+        -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)            \
+        -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS +=                                 \
+        -L../$(GNUSTEP_OBJ_DIR)                        \
+        -L../../NGObjWeb/$(GNUSTEP_OBJ_DIR)    \
+        -L../../NGScripting/$(GNUSTEP_OBJ_DIR)
+endif
+
+XHTML_BUNDLE_LIBS += \
+        -lNGObjDOM -lNGObjWeb -lNGScripting     \
+       -lNGMime -lNGStreams            \
+       -lEOControl -lNGExtensions      \
+        -lXmlRpc -lDOM -lSaxObjC
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODRDynamicXHTMLTag.h b/skyrix-sope/NGObjDOM/XHTML.subproj/ODRDynamicXHTMLTag.h
new file mode 100644 (file)
index 0000000..ed86257
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODRDynamicXHTMLTag_H__
+#define __ODRDynamicXHTMLTag_H__
+
+#import <Foundation/NSObject.h>
+#include <NGObjDOM/ODNodeRenderer.h>
+
+/*
+  This node-renderer is for rendering ELEMENT_NODE nodes which reside in the
+  XHTML namespace.
+  All non-ELEMENT_NODE / XHTML nodes are ignored and rendering continues at
+  their children.
+*/
+
+@interface ODRDynamicXHTMLTag : ODNodeRenderer
+{
+}
+
+/* this generates names for elements (based on 'name' and elementID) */
+- (NSString *)_selectNameOfNode:(id)_node inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __ODRDynamicXHTMLTag_H__ */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODRDynamicXHTMLTag.m b/skyrix-sope/NGObjDOM/XHTML.subproj/ODRDynamicXHTMLTag.m
new file mode 100644 (file)
index 0000000..2e4ba95
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "ODRDynamicXHTMLTag.h"
+#include "common.h"
+#include <EOControl/EOKeyValueCoding.h>
+#include <NGScripting/NSObject+Scripting.h>
+#include <NGObjDOM/ODNamespaces.h>
+
+#if APPLE_RUNTIME || NeXT_RUNTIME
+#  define sel_get_name sel_getName
+#endif
+
+@implementation ODRDynamicXHTMLTag
+
+static NSMutableSet *nonTextTags  = nil;
+static NSMutableSet *nonChildTags = nil;
+static int profileRenderers = -1;
+static Class NSDateClass = Nil;
+
++ (void)initialize {
+  NSAssert2([super version] == 1,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  if (NSDateClass == Nil)
+    NSDateClass = [NSDate class];
+  if (profileRenderers == -1) {
+    profileRenderers = [[[NSUserDefaults standardUserDefaults]
+                                          objectForKey:@"ODProfileRenderer"]
+                                          boolValue] ? 1 : 0;
+  }
+
+  if (nonChildTags == nil) {
+    nonChildTags =
+      [[NSMutableSet alloc] initWithObjects:
+                              @"br", @"hr", @"input", nil];
+  }
+  if (nonTextTags == nil) {
+    nonTextTags =
+      [[NSMutableSet alloc] initWithObjects:
+                              @"tr", @"table", @"tbody", @"thead"
+                              @"head", @"html",
+                              nil];
+  }
+}
+
++ (int)version {
+  return [super version] + 0 /* v1 */;
+}
+
+- (NSString *)_selectNameOfNode:(id)_node inContext:(WOContext *)_ctx {
+  NSString *name;
+  
+  if ((name = [self stringFor:@"name" node:_node ctx:_ctx]))
+    return name;
+
+  return [_ctx elementID];
+}
+
+- (NSException *)logEvaluationException:(NSException *)_exc
+  inContext:(WOContext *)_ctx
+{
+  [[_ctx component] logWithFormat:@"JS exception: %@", _exc];
+  /* SKYRIX specific ... */
+  [[_ctx page] takeValue:[_exc reason] forKey:@"errorString"];
+  return nil;
+}
+
+- (id)invokeValueForAttributeNode:(id<DOMAttr>)_attrNode inContext:(id)_ctx {
+  NSString *nsuri;
+
+  nsuri = [_attrNode namespaceURI];
+  if ([nsuri isEqualToString:XMLNS_XHTML] ||
+      [nsuri isEqualToString:XMLNS_HTML40]) {
+    if ([[(id<DOMAttr>)_attrNode name] hasPrefix:@"on"]) {
+      /* a JS action, eg onclick */
+      id scriptResult;
+
+      NS_DURING {
+        scriptResult =
+          [[_ctx component] evaluateScript:[_attrNode value] language:nil];
+      }
+      NS_HANDLER {
+        [[self logEvaluationException:localException inContext:_ctx] raise];
+        scriptResult = nil;
+      }
+      NS_ENDHANDLER;
+      
+      if ([scriptResult conformsToProtocol:@protocol(WOActionResults)])
+        return scriptResult;
+      
+      return nil;
+    }
+  }
+  return [super invokeValueForAttributeNode:_attrNode inContext:_ctx];
+}
+
+- (id)valueForAttributeNode:(id<DOMAttr>)_attrNode inContext:(id)_ctx {
+  NSString *nsuri;
+
+  nsuri = [_attrNode namespaceURI];
+  
+  if ([nsuri isEqualToString:XMLNS_XHTML] ||
+      [nsuri isEqualToString:XMLNS_HTML40]) {
+    static NSMutableSet *hreftags = nil;
+
+    if (hreftags == nil) {
+      hreftags = [[NSMutableSet alloc] initWithCapacity:8];
+      [hreftags addObject:@"src"];
+      [hreftags addObject:@"href"];
+    }
+    
+    if ([hreftags containsObject:[(id<DOMAttr>)_attrNode name]]) {
+      /* a URL */
+      WOResourceManager *rm;
+      NSURL    *url;
+      NSString *src;
+      
+      if ((rm = [[_ctx component] resourceManager]) == nil)
+        rm = [[WOApplication application] resourceManager];
+
+      src = [_attrNode value];
+      //NSLog(@"check src: %@", src);
+      
+      src = [rm urlForResourceNamed:src inFramework:nil
+                languages:[[_ctx session] languages]
+                request:[(WOContext *)_ctx request]];
+      
+      //NSLog(@"  found resource: %@", src);
+      
+      if ([src length] == 0) {
+        if ((url = [NSURL URLWithString:[_attrNode value]])) {
+          /* valid, regular URL */
+          src = [_attrNode value];
+        }
+      }
+      
+      return src;
+    }
+  }
+  return [super valueForAttributeNode:_attrNode inContext:_ctx];
+}
+
+- (BOOL)includeChildNode:(id)_childNode
+  ofNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  BOOL stripTextNodes;
+  NSString *tagName;
+  
+  tagName = [_domNode tagName];
+  
+  if ([nonChildTags containsObject:tagName])
+    /* node is not allowed to have children */
+    return NO;
+  
+  stripTextNodes = [nonTextTags containsObject:tagName];
+  
+  if (stripTextNodes) {
+    if ([_childNode nodeType] == DOM_TEXT_NODE)
+      return NO;
+    if ([_childNode nodeType] == DOM_CDATA_SECTION_NODE)
+      return NO;
+  }
+  
+  return [super includeChildNode:_childNode ofNode:_domNode inContext:_ctx];
+}
+
+- (void)takeValuesForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  if ([[_domNode tagName] isEqualToString:@"input"]) {
+    id formValue = nil;
+    
+    formValue = [_request formValueForKey:[_context elementID]];
+    
+    if (formValue) {
+      if ([self isSettable:@"value" node:_domNode ctx:_context])
+        [self setString:formValue for:@"value" node:_domNode ctx:_context];
+    }
+  }
+  
+  if ([_domNode hasChildNodes]) {
+    [self takeValuesForChildNodes:[_domNode childNodes]
+          fromRequest:_request
+          inContext:_context];
+  }
+}
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  id       children;
+  NSString *cid;
+  id result;
+  
+  cid = [_context currentElementID];
+  if ([cid length] > 0) {
+    id<DOMAttr> attr;
+    
+    if ((attr = [_domNode attributeNode:cid namespaceURI:XMLNS_OD_ACTION])) {
+      /* found a proper action attribute */
+      return [[_context component] valueForKeyPath:[attr value]];
+    }
+  }
+  
+  /* pass down the hierachy */
+
+  children = [_domNode hasChildNodes] ? [_domNode childNodes] : nil;
+  
+  if ([children count] == 0)
+    return nil;
+  
+  result = [self invokeActionForChildNodes:children
+                 fromRequest:_request
+                 inContext:_context];
+  
+  return result;
+}
+
+- (void)_appendAttributesOfNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  id attrs;
+  id attr;
+  NSTimeInterval st = 0.0;
+
+  if ((attrs = [(id)[_domNode attributes] objectEnumerator]) == nil)
+    return;
+  
+  if (profileRenderers)
+    st = [[NSDateClass date] timeIntervalSince1970];
+  
+  while ((attr = [attrs nextObject])) {
+    NSString *value;
+    
+    value = [[self valueForAttributeNode:attr inContext:_ctx] stringValue];
+    
+    [_response appendContentString:@" "];
+    [_response appendContentString:[(id<DOMAttr>)attr name]];
+    [_response appendContentString:@"=\""];
+    [_response appendContentString:value];
+    [_response appendContentString:@"\""];
+  }
+
+  if (profileRenderers) {
+    NSTimeInterval diff;
+    //int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    if (diff > 0.0009) {
+      //for (i = profDepth; i >= 0; i--)
+      //  printf("  ");
+      printf("[XHTML attrs: %s %s]: %0.3fs\n",
+             [[_domNode tagName] cString],
+             sel_get_name(_cmd), diff);
+    }
+  }
+}
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  id       children;
+  NSString *tagName;
+  static unsigned profDepth = 0;
+  NSTimeInterval st = 0.0;
+  
+  if (profileRenderers) {
+    st = [[NSDateClass date] timeIntervalSince1970];
+    profDepth++;
+  }
+  
+  if ([_domNode nodeType] != DOM_ELEMENT_NODE) {
+    NSLog(@"%s: WARNING incorrect renderer (invalid nodetype) for node %@",
+          __PRETTY_FUNCTION__, _domNode);
+    profDepth--;
+    
+    [super appendNode:_domNode
+           toResponse:_response
+           inContext:_context];
+    return;
+  }
+  
+  if (!([[_domNode namespaceURI] isEqualToString:XMLNS_XHTML] ||
+        [[_domNode namespaceURI] isEqualToString:XMLNS_HTML40])) {
+    /* not a HTML node */
+    NSLog(@"%s: WARNING incorrect renderer (no XHTML node) for node %@",
+          __PRETTY_FUNCTION__, _domNode);
+    profDepth--;
+    
+    [super appendNode:_domNode
+           toResponse:_response
+           inContext:_context];
+    return;
+  }
+
+  tagName = [_domNode tagName];
+  
+  if ([tagName isEqualToString:@"script"]) {
+    NSString    *runat;
+    id<DOMAttr> attr;
+    
+    attr  = [[_domNode attributes] 
+                       namedItem:@"runat" namespaceURI:XMLNS_XHTML];
+    runat = [attr value];
+    if ([runat isEqualToString:@"server"]) {
+      profDepth--;
+      return;
+    }
+  }
+  
+  children = [_domNode hasChildNodes] ? [_domNode childNodes] : nil;
+  
+  [_response appendContentString:@"<"];
+  [_response appendContentString:tagName];
+  
+  [self _appendAttributesOfNode:_domNode
+        toResponse:_response
+        inContext:_context];
+  
+  if ([children count] == 0) {
+    [_response appendContentString:@" />"];
+  }
+  else {
+    [_response appendContentString:@">"];
+    
+    [self appendChildNodes:children
+          toResponse:_response
+          inContext:_context];
+    
+    [_response appendContentString:@"</"];
+    [_response appendContentString:tagName];
+    [_response appendContentString:@">"];
+  }
+
+  if (profileRenderers) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    if (diff > 0.0009) {
+      for (i = profDepth; i >= 0; i--)
+        printf("  ");
+      printf("[xhtml: %s %s]: %0.3fs\n",
+             [[_domNode tagName] cString],
+             sel_get_name(_cmd), diff);
+    }
+    profDepth--;
+  }
+}
+
+@end /* ODRDynamicXHTMLTag */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_a.m b/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_a.m
new file mode 100644 (file)
index 0000000..84e7d72
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXHTMLTag.h"
+
+/*
+  Usage:
+
+  Dynamic Serverside Attributes
+    action
+    page
+
+  HTML 4:
+    <!ELEMENT A - - (%inline;)* -(A)       -- anchor -->
+    <!ATTLIST A
+      %attrs;                              -- %coreattrs, %i18n, %events --
+      charset     %Charset;      #IMPLIED  -- char encoding of linked resource --
+      type        %ContentType;  #IMPLIED  -- advisory content type --
+      name        CDATA          #IMPLIED  -- named link end --
+      href        %URI;          #IMPLIED  -- URI for linked resource --
+      hreflang    %LanguageCode; #IMPLIED  -- language code --
+      rel         %LinkTypes;    #IMPLIED  -- forward link types --
+      rev         %LinkTypes;    #IMPLIED  -- reverse link types --
+      accesskey   %Character;    #IMPLIED  -- accessibility key character --
+      shape       %Shape;        rect      -- for use with client-side image maps
+      coords      %Coords;       #IMPLIED  -- for use with client-side image maps
+      tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
+      onfocus     %Script;       #IMPLIED  -- the element got the focus --
+      onblur      %Script;       #IMPLIED  -- the element lost the focus --
+      >
+*/
+
+@interface ODR_XHTML_a : ODRDynamicXHTMLTag
+@end
+
+#include "common.h"
+#include <NGScripting/NSObject+Scripting.h>
+#include <NGObjDOM/ODNamespaces.h>
+
+@interface WOComponent(ProcessHrefPageAction)
+
+- (id)gotoAnkerURL:(NSString *)_url;
+
+@end
+
+@implementation ODR_XHTML_a
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  id result = nil;
+  
+  if ([[_context elementID] isEqualToString:[_context senderID]]) {
+    id onClickNode;
+    id<DOMNamedNodeMap> attrs;
+
+    if ([_node hasAttribute:@"page"]) {
+      NSString *pageName;
+      
+      pageName = [self stringFor:@"page" node:_node ctx:_context];
+      
+      return [[_context component] pageWithName:pageName];
+    }
+    else if ([_node hasAttribute:@"action" namespaceURI:@"*"]) {
+      return [self valueFor:@"action" node:_node ctx:_context];
+    }
+    
+    if ((attrs = [_node attributes]) == nil) {
+#if DEBUG
+      NSLog(@"%s: 'a' node %@ has no attributes ..",
+            __PRETTY_FUNCTION__, _node);
+#endif
+      return nil;
+    }
+
+    if ((onClickNode = [_node attributeNode:@"onclick" namespaceURI:@"*"])) {
+#if 0 && DEBUG
+      NSLog(@"%s: invoke onclick node %@", __PRETTY_FUNCTION__, onClickNode);
+#endif
+      id o;
+      
+      o = [self invokeValueForAttributeNode:onClickNode inContext:_context];
+      
+      if (![o conformsToProtocol:@protocol(WOActionResults)])
+        o = nil;
+      
+      return o;
+    }
+    
+    if ([[_context component] respondsToSelector:@selector(gotoAnkerURL:)]) {
+      id<DOMAttr> hrefNode;
+      NSString    *href;
+      
+      if ((hrefNode = [_node attributeNode:@"href" namespaceURI:XMLNS_XHTML]))
+        href = [hrefNode value];
+      else if ((hrefNode = [_node attributeNode:@"href" 
+                                  namespaceURI:XMLNS_HTML40]))
+        href = [hrefNode value];
+      else if ((hrefNode = [_node attributeNode:@"href"
+                                     namespaceURI:XMLNS_OD_BIND]))
+        href = [[_context component] valueForKeyPath:[hrefNode value]];
+      else if ((hrefNode = [_node attributeNode:@"href"
+                                  namespaceURI:XMLNS_OD_EVALJS])) {
+        href = [[_context component]
+                          evaluateScript:[hrefNode value] language:nil];
+      }
+      else
+        href = nil;
+      
+      if (href)
+        return [[_context component] gotoAnkerURL:href];
+    }
+
+    NSLog(@"%s: did not active attribute in <a> node %@ !",
+          __PRETTY_FUNCTION__, _node);
+    return nil;
+  }
+#if DEBUG
+  else {
+    NSLog(@"%s: senderID and elementID differ:\nsid=%@\neid=%@",
+          __PRETTY_FUNCTION__, [_context senderID], [_context elementID]);
+  }
+#endif
+  
+  result = [super invokeActionForNode:_node
+                  fromRequest:_request
+                  inContext:_context];
+  
+  return result;
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *src;
+  NSString *tmp;
+  id hrefNode;
+  
+  if ([_node hasAttribute:@"page" namespaceURI:@"*"]) {
+    /* page action */
+    src = [_ctx componentActionURL];
+  }
+  else if ([_node hasAttribute:@"action" namespaceURI:@"*"]) {
+    /* component action */
+    src = [_ctx componentActionURL];
+  }
+  else if ([_node attributeNode:@"onclick" namespaceURI:@"*"] != nil) {
+    src = [_ctx componentActionURL];
+  }
+  else if ((hrefNode = [_node attributeNode:@"href" namespaceURI:@"*"])) {
+    if ([[_ctx component] respondsToSelector:@selector(gotoAnkerURL:)])
+      src = [_ctx componentActionURL];
+    else
+      src = [self valueForAttributeNode:hrefNode inContext:_ctx];
+  }
+  else
+    src = nil;
+  
+  [_response appendContentString:@"<a "];
+  
+  if ([src length] > 0) {
+    [_response appendContentString:@" href=\""];
+    [_response appendContentHTMLAttributeValue:src];
+    [_response appendContentCharacter:'"'];
+  }
+  
+  if ((tmp = [self stringFor:@"target" node:_node ctx:_ctx])) {
+    [_response appendContentString:@" target=\""];
+    [_response appendContentHTMLAttributeValue:tmp];
+    [_response appendContentCharacter:'"'];
+  }
+  if ((tmp = [self stringFor:@"name" node:_node ctx:_ctx])) {
+    [_response appendContentString:@" name=\""];
+    [_response appendContentHTMLAttributeValue:tmp];
+    [_response appendContentCharacter:'"'];
+  }
+  
+  [_response appendContentCharacter:'>'];
+  
+  /* add subelements */
+  [self appendChildNodes:[_node childNodes]
+        toResponse:_response
+        inContext:_ctx];
+  
+  /* close tag */
+  [_response appendContentString:@"</a>"];
+}
+
+@end /* ODR_XHTML_a */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_button.m b/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_button.m
new file mode 100644 (file)
index 0000000..a141391
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXHTMLTag.h"
+
+/*
+  Usage:
+
+  Additions:
+
+  HTML 4.01:
+    <!ELEMENT BUTTON - -
+         (%flow;)* -(A|%formctrl;|FORM|FIELDSET)
+         -- push button -->
+    <!ATTLIST BUTTON
+      %attrs;                              -- %coreattrs, %i18n, %events --
+      name        CDATA          #IMPLIED
+      value       CDATA          #IMPLIED  -- sent to server when submitted --
+      type        (button|submit|reset) submit -- for use as form button --
+      disabled    (disabled)     #IMPLIED  -- unavailable in this context --
+      tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
+      accesskey   %Character;    #IMPLIED  -- accessibility key character --
+      onfocus     %Script;       #IMPLIED  -- the element got the focus --
+      onblur      %Script;       #IMPLIED  -- the element lost the focus --
+      >
+*/
+
+@interface ODR_XHTML_button : ODRDynamicXHTMLTag
+@end
+
+#include "common.h"
+
+@implementation ODR_XHTML_button
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  NSString *atype;
+  
+  if ((atype = [self stringFor:@"type" node:_domNode ctx:_ctx]) == nil) {
+    if ([_ctx isInForm])
+      atype = @"submit";
+    else {
+      if ([_domNode attributeNode:@"onclick" namespaceURI:@"*"])
+        atype = @"button";
+      else
+        atype = @"submit";
+    }
+  }
+  
+  if ([atype isEqualToString:@"submit"])
+    return YES;
+  if ([atype isEqualToString:@"reset"])
+    return YES;
+  
+  return NO;
+}
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  if ([[_context elementID] isEqualToString:[_context senderID]]) {
+    id onClickNode;
+    id<DOMNamedNodeMap> attrs;
+    
+    if ((attrs = [_domNode attributes]) == nil)
+      return nil;
+    
+    if ((onClickNode = [_domNode attributeNode:@"onclick" namespaceURI:@"*"])) {
+      return [self invokeValueForAttributeNode:onClickNode inContext:_context];
+    }
+    else {
+      NSLog(@"%s: did not find 'onclick' attribute in a:href !",
+            __PRETTY_FUNCTION__);
+      return nil;
+    }
+  }
+  
+  return [super invokeActionForNode:_domNode
+                fromRequest:_request
+                inContext:_context];
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *value;
+    
+  value = [self stringFor:@"value" node:_node ctx:_ctx];
+  
+  if ([_ctx isInForm]) {
+    NSString *atype;
+    NSString *value = nil;
+    
+    atype = [self stringFor:@"type" node:_node ctx:_ctx];
+    if (atype == nil) atype = @"submit";
+
+    if ([atype isEqualToString:@"reset"]) {
+      [_response appendContentString:@"<input type=\"reset\""];
+    }
+    else {
+      [_response appendContentString:@"<input type=\"submit\""];
+    }
+    
+    if (value) {
+      [_response appendContentString:@" value=\""];
+      [_response appendContentHTMLAttributeValue:value];
+      [_response appendContentString:@"\""];
+    }
+    
+    [_response appendContentString:@" />"];
+  }
+  else {
+    if ([_node attributeNode:@"onclick" namespaceURI:@"*"]) {
+      [_response appendContentString:@"<a href=\""];
+      [_response appendContentHTMLAttributeValue:[_ctx componentActionURL]];
+      [_response appendContentString:@"\">"];
+      [_response appendContentHTMLString:value];
+      [_response appendContentString:@"</a>"];
+    }
+    else {
+      [_response appendContentString:(value ? value : @"[button]")];
+    }
+  }
+}
+
+@end /* ODR_XHTML_button */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_form.m b/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_form.m
new file mode 100644 (file)
index 0000000..d25e417
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXHTMLTag.h"
+
+/*
+  Usage:
+
+    <form [enctype="multipart/form-data"]>
+      ...
+    </form>
+
+  HTML 4:
+*/
+
+@interface ODR_XHTML_form : ODRDynamicXHTMLTag
+@end
+
+#include "common.h"
+
+@implementation ODR_XHTML_form
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return NO;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_request
+                inContext:(WOContext *)_ctx {
+  if ([_node hasChildNodes]) {
+    [_ctx setInForm:YES];
+    
+    [self takeValuesForChildNodes:[_node childNodes]
+          fromRequest:_request
+          inContext:_ctx];
+    
+    [_ctx setInForm:NO];
+  }
+
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  id result = nil;
+  
+  if ([_node hasChildNodes]) {
+    [_ctx setInForm:YES];
+    
+    result = [self invokeActionForChildNodes:[_node childNodes]
+                   fromRequest:_request
+                   inContext:_ctx];
+    
+    [_ctx setInForm:NO];
+  }
+  
+  return result;
+}
+
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *enctype = nil;
+
+  enctype = [self stringFor:@"enctype" node:_node ctx:_ctx];
+  
+  if ([_node hasChildNodes]) {
+    [_ctx setInForm:YES];
+    [_response appendContentString:@"<form method=\"post\" action=\""];
+    [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentCharacter:'"'];
+    if (enctype != nil) {
+      [_response appendContentString:@" enctype=\""];
+      [_response appendContentString:enctype];
+      [_response appendContentCharacter:'"'];
+    }
+    [_response appendContentCharacter:'>'];
+    [super appendChildNodes:[_node childNodes]
+           toResponse:_response
+           inContext:_ctx];
+    [_ctx setInForm:NO];
+    [_response appendContentString:@"</form>"];
+  }
+}
+
+@end /* ODR_XHTML_form */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_img.m b/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_img.m
new file mode 100644 (file)
index 0000000..abe0393
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXHTMLTag.h"
+
+/*
+  Usage:
+
+  Additions:
+
+  HTML 4:
+   <!ELEMENT IMG - O EMPTY                -- Embedded image -->
+   <!ATTLIST IMG
+     %attrs;                              -- %coreattrs, %i18n, %events --
+     src         %URI;          #REQUIRED -- URI of image to embed --
+     alt         %Text;         #REQUIRED -- short description --
+     longdesc    %URI;          #IMPLIED  -- link to long description
+                                             (complements alt) --
+     name        CDATA          #IMPLIED  -- name of image for scripting --
+     height      %Length;       #IMPLIED  -- override height --
+     width       %Length;       #IMPLIED  -- override width --
+     usemap      %URI;          #IMPLIED  -- use client-side image map --
+     ismap       (ismap)        #IMPLIED  -- use server-side image map --
+     >
+*/
+
+@interface ODR_XHTML_img : ODRDynamicXHTMLTag
+@end
+
+#include "common.h"
+
+@implementation ODR_XHTML_img
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  if ([[_context elementID] isEqualToString:[_context senderID]]) {
+    id onClickNode;
+    id<DOMNamedNodeMap> attrs;
+    
+    if ((attrs = [_domNode attributes]) == nil)
+      return nil;
+    
+    if ((onClickNode = [_domNode attributeNode:@"onclick" namespaceURI:@"*"])) {
+      return [self invokeValueForAttributeNode:onClickNode inContext:_context];
+    }
+    else {
+      NSLog(@"%s: did not find 'onclick' attribute in a:href !",
+            __PRETTY_FUNCTION__);
+      return nil;
+    }
+  }
+  
+  return [super invokeActionForNode:_domNode
+                fromRequest:_request
+                inContext:_context];
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *src, *href;
+  NSString *tmp;
+  id srcNode;
+  
+  if ([_node attributeNode:@"onclick" namespaceURI:@"*"])
+    href = [_ctx componentActionURL];
+  else
+    href = nil;
+  
+  if ((srcNode = [_node attributeNode:@"src" namespaceURI:@"*"]))
+    src = [[self valueForAttributeNode:srcNode inContext:_ctx] stringValue];
+  else
+    src = nil;
+  
+  /* open link tag */
+  if ([href length] > 0) {
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentHTMLAttributeValue:href];
+    [_response appendContentString:@"\">"];
+  }
+  
+  if ([src length] > 0) {
+    [_response appendContentString:@"<img src=\""];
+    [_response appendContentString:src];
+    [_response appendContentCharacter:'"'];
+  
+    if ((tmp = [self stringFor:@"alt" node:_node ctx:_ctx])) {
+      [_response appendContentString:@" alt=\""];
+      [_response appendContentHTMLAttributeValue:tmp];
+      [_response appendContentCharacter:'"'];
+    }
+    if ((tmp = [self stringFor:@"border" node:_node ctx:_ctx])) {
+      [_response appendContentString:@" border=\""];
+      [_response appendContentHTMLAttributeValue:tmp];
+      [_response appendContentCharacter:'"'];
+    }
+    if ((tmp = [self stringFor:@"height" node:_node ctx:_ctx])) {
+      [_response appendContentString:@" height=\""];
+      [_response appendContentHTMLAttributeValue:tmp];
+      [_response appendContentCharacter:'"'];
+    }
+    if ((tmp = [self stringFor:@"width" node:_node ctx:_ctx])) {
+      [_response appendContentString:@" width=\""];
+      [_response appendContentHTMLAttributeValue:tmp];
+      [_response appendContentCharacter:'"'];
+    }
+    
+    [_response appendContentString:@" />"];
+  }
+  else {
+    [_response appendContentString:@"[img: "];
+    
+    if ((tmp = [self stringFor:@"alt" node:_node ctx:_ctx]))
+      [_response appendContentHTMLString:tmp];
+    
+    [_response appendContentString:@"]"];
+  }
+  
+  /* close link tag */
+  if ([href length] > 0)
+    [_response appendContentString:@"</a>"];
+}
+
+@end /* ODR_XHTML_img */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_input.m b/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_input.m
new file mode 100644 (file)
index 0000000..27eca0f
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXHTMLTag.h"
+
+/*
+  Usage:
+
+  Additions:
+
+    dateformat   - NSDateFormatter spec
+    numberformat - NSNumberFormatter spec
+
+    filepath     - NSString              -- filename      (for file upload)
+    data         - NSData                -- uploaded data (for file upload)
+
+    selection    - selected radio-button value
+  
+  HTML 4.01:
+   <!ENTITY % InputType
+     "(TEXT | PASSWORD | CHECKBOX |
+       RADIO | SUBMIT | RESET |
+       FILE | HIDDEN | IMAGE | BUTTON)"
+      >
+   
+   <!-- attribute name required for all but submit and reset -->
+   <!ELEMENT INPUT - O EMPTY              -- form control -->
+   <!ATTLIST INPUT
+     %attrs;                              -- %coreattrs, %i18n, %events --
+     type        %InputType;    TEXT      -- what kind of widget is needed --
+     name        CDATA          #IMPLIED  -- submit as part of form --
+     value       CDATA          #IMPLIED  -- Specify for radio buttons and
+                                             checkboxes --
+     checked     (checked)      #IMPLIED  -- for radio buttons and check boxes --
+     disabled    (disabled)     #IMPLIED  -- unavailable in this context --
+     readonly    (readonly)     #IMPLIED  -- for text and passwd --
+     size        CDATA          #IMPLIED  -- specific to each type of field --
+     maxlength   NUMBER         #IMPLIED  -- max chars for text fields --
+     src         %URI;          #IMPLIED  -- for fields with images --
+     alt         CDATA          #IMPLIED  -- short description --
+     usemap      %URI;          #IMPLIED  -- use client-side image map --
+     ismap       (ismap)        #IMPLIED  -- use server-side image map --
+     tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
+     accesskey   %Character;    #IMPLIED  -- accessibility key character --
+     onfocus     %Script;       #IMPLIED  -- the element got the focus --
+     onblur      %Script;       #IMPLIED  -- the element lost the focus --
+     onselect    %Script;       #IMPLIED  -- some text was selected --
+     onchange    %Script;       #IMPLIED  -- the element value was changed --
+     accept      %ContentTypes; #IMPLIED  -- list of MIME types for file upload--
+     >
+*/
+
+@interface ODR_XHTML_input : ODRDynamicXHTMLTag
+@end
+
+#include "common.h"
+#import <NGMime/NGMime.h>
+#import <NGHttp/NGHttp.h>
+
+@interface WOContext(Privates)
+- (void)addActiveFormElement:(id)_element;
+@end
+
+@interface WORequest(HttpRequest)
+- (id)httpRequest;
+@end
+
+@implementation ODR_XHTML_input
+
+static NGMimeType *multipartFormData = nil;
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+
+    multipartFormData = [NGMimeType mimeType:@"multipart/form-data"];
+    multipartFormData = RETAIN(multipartFormData);
+  }
+}
+
+- (BOOL)requiresFormForNode:(id)_node inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (NSFormatter *)_formatterForNode:(id)_node inContext:(WOContext *)_ctx {
+  NSFormatter *formatter;
+  NSString    *fmt;
+  
+  if ((fmt = [self stringFor:@"dateformat" node:_node ctx:_ctx])) {
+    formatter = [[NSDateFormatter alloc]
+                                  initWithDateFormat:fmt
+                                  allowNaturalLanguage:NO];
+    AUTORELEASE(formatter);
+  }
+  else if ((fmt = [self stringFor:@"numberformat" node:_node ctx:_ctx])) {
+    formatter = [[NSNumberFormatter alloc] init];
+    AUTORELEASE(formatter);
+    [(NSNumberFormatter *)formatter setFormat:fmt];
+  }
+  else
+    formatter = nil;
+
+  return formatter;
+}
+
+- (void)_setStringValue:(NSString *)_value
+  onNode:(id)_node
+  inContext:(WOContext *)_ctx
+{
+  if ([self isSettable:@"value" node:_node ctx:_ctx]) {
+    NSFormatter *formatter;
+
+    if ((formatter = [self _formatterForNode:_node inContext:_ctx])) {
+      id       v;
+      NSString *err;
+      
+      if ([formatter getObjectValue:&v forString:_value errorDescription:&err]){
+        [self setValue:v for:@"value" node:_node ctx:_ctx];
+        
+        if ([self isSettable:@"formattingError" node:_node ctx:_ctx])
+          [self setValue:nil for:@"formattingError" node:_node ctx:_ctx];
+      }
+      else {
+        [self setValue:_value for:@"value" node:_node ctx:_ctx];
+        
+        if ([self isSettable:@"formattingError" node:_node ctx:_ctx])
+          [self setValue:err ? err : @"failed"
+                for:@"formattingError" node:_node ctx:_ctx];
+      }
+    }
+    else
+      [self setString:_value for:@"value" node:_node ctx:_ctx];
+  }
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  NSString *itype;
+  NSString *ename;
+  id formValue;
+  
+#if DEBUG
+  if (![_ctx isInForm])
+    NSLog(@"WARNING(%s): not in form !", __PRETTY_FUNCTION__);
+#endif
+
+  if ([self boolFor:@"disabled" node:_node ctx:_ctx]) {
+    return;
+  }
+  
+  itype     = [self stringFor:@"type" node:_node ctx:_ctx];
+  ename     = [self _selectNameOfNode:_node inContext:_ctx];
+  formValue = [_req formValueForKey:ename];
+  
+  if ([itype isEqualToString:@"radio"]) {
+    BOOL isActiveRadio;
+    
+    isActiveRadio = [formValue isEqual:[_ctx elementID]];
+    
+    if ([self isSettable:@"checked" node:_node ctx:_ctx]) {
+      [self forceSetBool:isActiveRadio for:@"checked" node:_node ctx:_ctx];
+    }
+    if (isActiveRadio) {
+      if ([self isSettable:@"selection" node:_node ctx:_ctx])
+        [self setValue:formValue for:@"selection" node:_node ctx:_ctx];
+    }
+  }
+  else if ([itype isEqualToString:@"image"]) {
+    /* does not take values yet .. ('value' isn't transmitted) */
+  }
+  else if ([itype isEqualToString:@"file"]) {
+    if (formValue) {
+      NGMimeType *contentType = [[_req httpRequest] contentType];
+      
+      if (![contentType hasSameType:multipartFormData]) {
+        NSLog(@"WARNING: tried to apply file-upload value of %@ from "
+              @"a non multipart-form request (value=%@) !",
+              [_ctx elementID], formValue);
+        return;
+      }
+
+      if ([self isSettable:@"data" node:_node ctx:_ctx])
+        [self setValue:formValue for:@"data" node:_node ctx:_ctx];
+
+      if ([self isSettable:@"filepath" node:_node ctx:_ctx]) {
+        NGMimeMultipartBody *body = [[_req httpRequest] body];
+
+        if ([body isKindOfClass:[NGMimeMultipartBody class]]) {
+          NSArray  *parts   = [body parts];
+          unsigned i, count = [parts count];
+
+          // search for part of current form element
+          
+          for (i = 0; i < count; i++) {
+            id disposition;
+            id<NGMimePart> bodyPart;
+            
+            bodyPart = [parts objectAtIndex:i];
+            disposition =
+              [[bodyPart valuesOfHeaderFieldWithName:@"content-disposition"]
+                         nextObject];
+            
+            if (disposition) {
+              static Class DispClass = Nil;
+              NSString *formName;
+              
+              if (DispClass == Nil)
+                DispClass = [NGMimeContentDispositionHeaderField class];
+              
+              if (![disposition isKindOfClass:DispClass]) {
+                disposition =
+                  [[DispClass alloc] initWithString:[disposition stringValue]];
+                [disposition autorelease];
+              }
+              
+              formName = [(NGMimeContentDispositionHeaderField *)disposition
+                                                                name];
+              
+              if ([formName isEqualToString:ename]) {
+                [self setValue:[disposition filename]
+                      for:@"filepath" node:_node ctx:_ctx];
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else {
+    [self _setStringValue:formValue onNode:_node inContext:_ctx];
+    
+    if ([self hasAttribute:@"checked" node:_node ctx:_ctx]) {
+      if ([self isSettable:@"checked" node:_node ctx:_ctx]) {
+        if ([itype isEqualToString:@"checkbox"]) {
+          [self setBool:(formValue ? YES : NO) for:@"checked"
+                node:_node ctx:_ctx];
+        }
+        else {
+          NSLog(@"WARNING(%s): cannot handle 'checked' attribute of node %@",
+                __PRETTY_FUNCTION__, _node);
+        }
+      }
+    }
+  }
+  
+  /* 'active' elements */
+  
+  if ([itype isEqualToString:@"submit"] || [itype isEqualToString:@"button"]) {
+    /* check action */
+    if (formValue)
+      /* yep, we are the active element (submit-button) */
+      [_ctx addActiveFormElement:_node];
+  }
+  else if ([itype isEqualToString:@"image"]) {
+    /* 'image' forms transmit two values: key.x and x.y containing the position*/
+    NSString *xId;
+    NSString *xValue;
+    
+    xId = [ename stringByAppendingString:@".x"];
+    
+    if ((xValue = [_req formValueForKey:xId]))
+      /* yep, we are the active element (image-button) */
+      [_ctx addActiveFormElement:_node];
+  }
+}
+
+- (id)invokeActionForNode:(id)_node
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  /* check whether this is the active form element (determined in take-values) */
+
+  if ([self boolFor:@"disabled" node:_node ctx:_ctx]) {
+    return nil;
+  }
+
+  if ([[_ctx elementID] isEqualToString:[_ctx senderID]]) {
+    id onClickNode;
+    id<DOMNamedNodeMap> attrs;
+    
+    if ((attrs = [_node attributes]) == nil)
+      return nil;
+    
+    if ((onClickNode = [_node attributeNode:@"onclick" namespaceURI:@"*"])) {
+      return [self invokeValueForAttributeNode:onClickNode inContext:_ctx];
+    }
+    else {
+      NSLog(@"%s: did not find 'onclick' attribute in input node %@ !",
+            __PRETTY_FUNCTION__, _node);
+      return nil;
+    }
+  }
+  else {
+    NSLog(@"input is not active (%@ vs %@) !",
+          [_ctx elementID], [_ctx senderID]);
+    return nil;
+  }
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if (![_ctx isInForm]) {
+    id value;
+    
+    value = [self valueFor:@"value" node:_node ctx:_ctx];
+    
+    [[_ctx component]
+           logWithFormat:@"WARNING: input-tag is not in a form !"];
+    [_response appendContentHTMLString:[value stringValue]];
+    return;
+  }
+  
+  if ([self boolFor:@"disabled" node:_node ctx:_ctx]) {
+    id value;
+    
+    value = [self valueFor:@"value" node:_node ctx:_ctx];
+    
+    [_response appendContentHTMLString:[value stringValue]];
+    return;
+  }
+  
+  /* ok, we are in a form and we are not disabled ... */
+  
+  {
+    NSString    *itype;
+    NSString    *ename;
+    NSFormatter *formatter;
+    int size, maxlen;
+    id  value;
+    
+    ename  = [self _selectNameOfNode:_node inContext:_ctx];
+    itype  = [self stringFor:@"type"   node:_node ctx:_ctx];
+    size   = [self intFor:@"size"      node:_node ctx:_ctx];
+    maxlen = [self intFor:@"maxlength" node:_node ctx:_ctx];
+    
+    value  = [self valueFor:@"value"  node:_node ctx:_ctx];
+    
+    formatter = [self _formatterForNode:_node inContext:_ctx];
+    
+    if (formatter) {
+#if DEBUG && 0
+      NSLog(@"%s: formatting '%@'<%@> ..",
+            __PRETTY_FUNCTION__, value, [value class]);
+#endif
+      value = [formatter editingStringForObjectValue:value];
+#if DEBUG && 0
+      NSLog(@"%s: formatted value: '%@'<%@> ..",
+            __PRETTY_FUNCTION__, value, [value class]);
+#endif
+    }
+    else
+      value = [value stringValue];
+    
+    [_response appendContentString:@"<input type=\""];
+    [_response appendContentHTMLAttributeValue:itype];
+    [_response appendContentString:@"\""];
+    
+    if (ename) {
+      [_response appendContentString:@" name=\""];
+      [_response appendContentHTMLAttributeValue:ename];
+      [_response appendContentString:@"\""];
+    }
+    
+    if (size > 0) {
+      [_response appendContentString:@" size=\""];
+      [_response appendContentString:[NSString stringWithFormat:@"%d", size]];
+      [_response appendContentCharacter:'"'];
+    }
+    if (maxlen > 0) {
+      [_response appendContentString:@" maxlength=\""];
+      [_response appendContentString:[NSString stringWithFormat:@"%d", size]];
+      [_response appendContentCharacter:'"'];
+    }
+    
+    if ([self hasAttribute:@"checked" node:_node ctx:_ctx]) {
+      if ([self boolFor:@"checked" node:_node ctx:_ctx])
+        /* XHTML !!! */
+        [_response appendContentString:@" checked"];
+    }
+    else {
+      if ([itype isEqualToString:@"radio"]) {
+        [_response appendContentString:@" value=\""];
+        [_response appendContentHTMLAttributeValue:[_ctx elementID]];
+        [_response appendContentString:@"\""];
+      }
+      else if (value) {
+        [_response appendContentString:@" value=\""];
+        [_response appendContentHTMLAttributeValue:value];
+        [_response appendContentString:@"\""];
+      }
+    }
+
+    /* image specialties */
+    
+    if ([itype isEqualToString:@"image"]) {
+      id       srcNode;
+      NSString *src;
+      NSString *tmp;
+      
+      if ((srcNode = [_node attributeNode:@"src" namespaceURI:@"*"]))
+        src = [[self valueForAttributeNode:srcNode inContext:_ctx] stringValue];
+      else
+        src = nil;
+
+      if ([src length] > 0) {
+        [_response appendContentString:@" src=\""];
+        [_response appendContentString:src];
+        [_response appendContentString:@"\""];
+      }
+      
+      if ((tmp = [self stringFor:@"alt" node:_node ctx:_ctx])) {
+        [_response appendContentString:@" alt=\""];
+        [_response appendContentHTMLAttributeValue:tmp];
+        [_response appendContentCharacter:'"'];
+      }
+    }
+    
+    [_response appendContentString:@" />"];
+  }
+}
+
+@end /* ODR_XHTML_input */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_option.m b/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_option.m
new file mode 100644 (file)
index 0000000..929f547
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXHTMLTag.h"
+
+/*
+  Usage:
+
+    <option>Text</option>
+
+  HTML 4:
+   <!ELEMENT OPTION - O (#PCDATA)         -- selectable choice -->
+   <!ATTLIST OPTION
+     %attrs;                              -- %coreattrs, %i18n, %events --
+     selected    (selected)     #IMPLIED
+     disabled    (disabled)     #IMPLIED  -- unavailable in this context --
+     label       %Text;         #IMPLIED  -- for use in hierarchical menus --
+     value       CDATA          #IMPLIED  -- defaults to element content --
+     >
+*/
+
+@interface ODR_XHTML_option : ODRDynamicXHTMLTag
+@end
+
+#include "common.h"
+
+@implementation ODR_XHTML_option
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *tmp;
+  NSString *value;
+  BOOL isSelected;
+
+  isSelected = NO;
+  
+  if ((value = [self stringFor:@"value" node:_node ctx:_ctx]) == nil)
+    value = [_ctx elementID];
+  
+  [_response appendContentString:@"<option"];
+  
+  if (value) {
+    [_response appendContentString:@" value=\""];
+    [_response appendContentHTMLAttributeValue:value];
+    [_response appendContentString:@"\""];
+  }
+  if ((tmp = [self stringFor:@"label" node:_node ctx:_ctx])) {
+    [_response appendContentString:@" label=\""];
+    [_response appendContentHTMLAttributeValue:tmp];
+    [_response appendContentString:@"\""];
+  }
+  
+  /* find out selected state */
+  {
+    id pnode;
+    
+    for (pnode = [_node parentNode];
+         (pnode != nil) && ([pnode nodeType] == DOM_ELEMENT_NODE);
+         pnode = [pnode parentNode]) {
+      
+      if ([[pnode tagName] isEqualToString:@"select"]) {
+        NSString *selectValue;
+        
+        selectValue = [self stringFor:@"value" node:pnode ctx:_ctx];
+        if ([selectValue isEqualToString:value])
+          isSelected = YES;
+        
+        break;
+      }
+    }
+  }
+  
+  if (isSelected) {
+    /* XHMTL !! */
+    [_response appendContentString:@" selected"];
+  }
+  
+  [_response appendContentCharacter:'>'];
+
+  /* append child elements */
+  
+  if ([_node hasChildNodes]) {
+    [super appendChildNodes:[_node childNodes]
+           toResponse:_response
+           inContext:_ctx];
+  }
+  
+  /* XHTML CloseTag !!! */
+}
+
+@end /* ODR_XHTML_option */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_select.m b/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_select.m
new file mode 100644 (file)
index 0000000..d14311b
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXHTMLTag.h"
+
+/*
+  Usage:
+
+    <select var:value="blah">
+      <option .../>
+    </select>
+
+  HTML 4:
+
+   <!ELEMENT SELECT - - (OPTGROUP|OPTION)+ -- option selector -->
+   <!ATTLIST SELECT
+    %attrs;                              -- %coreattrs, %i18n, %events --
+    name        CDATA          #IMPLIED  -- field name --
+    size        NUMBER         #IMPLIED  -- rows visible --
+    multiple    (multiple)     #IMPLIED  -- default is single selection --
+    disabled    (disabled)     #IMPLIED  -- unavailable in this context --
+    tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
+    onfocus     %Script;       #IMPLIED  -- the element got the focus --
+    onblur      %Script;       #IMPLIED  -- the element lost the focus --
+    onchange    %Script;       #IMPLIED  -- the element value was changed --
+    >
+*/
+
+@interface ODR_XHTML_select : ODRDynamicXHTMLTag
+@end
+
+#include "common.h"
+
+@implementation ODR_XHTML_select
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (BOOL)includeChildNode:(id)_childNode
+  ofNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  /* leave out text nodes */
+  
+  if ([_childNode nodeType] == DOM_TEXT_NODE)
+    return NO;
+  if ([_childNode nodeType] == DOM_CDATA_SECTION_NODE)
+    return NO;
+
+  return [super includeChildNode:_childNode ofNode:_domNode inContext:_ctx];
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  NSString *ename;
+  id       formValue;
+  
+  ename     = [self _selectNameOfNode:_node inContext:_ctx];
+  formValue = [_req formValueForKey:ename];
+  
+  if ([self isSettable:@"value" node:_node ctx:_ctx])
+    [self setString:formValue for:@"value" node:_node ctx:_ctx];
+  
+  /* take values on child elements */
+  
+  if ([_node hasChildNodes]) {
+    [self takeValuesForChildNodes:[_node childNodes]
+          fromRequest:_req
+          inContext:_ctx];
+  }
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *ename;
+  NSString *tmp;
+  
+  ename = [self _selectNameOfNode:_node inContext:_ctx];
+  
+  [_response appendContentString:@"<select name=\""];
+  [_response appendContentHTMLAttributeValue:ename];
+  [_response appendContentCharacter:'"'];
+  
+  if ((tmp = [self stringFor:@"value" node:_node ctx:_ctx])) {
+    [_response appendContentString:@" value=\""];
+    [_response appendContentHTMLAttributeValue:tmp];
+    [_response appendContentString:@"\""];
+  }
+  if ((tmp = [self stringFor:@"size" node:_node ctx:_ctx])) {
+    [_response appendContentString:@" size=\""];
+    [_response appendContentHTMLAttributeValue:tmp];
+    [_response appendContentString:@"\""];
+  }
+  if ([self boolFor:@"multiple" node:_node ctx:_ctx]) {
+    /* XHTML!!! */
+    [_response appendContentString:@" multiple"];
+  }
+  
+  [_response appendContentString:@">\n"];
+  
+  /* append child elements */
+  
+  if ([_node hasChildNodes]) {
+    [self appendChildNodes:[_node childNodes]
+          toResponse:_response
+          inContext:_ctx];
+  }
+
+  /* close select */
+  
+  [_response appendContentString:@"</select>"];
+}
+
+@end /* ODR_XHTML_select */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_textarea.m b/skyrix-sope/NGObjDOM/XHTML.subproj/ODR_XHTML_textarea.m
new file mode 100644 (file)
index 0000000..ff8ff0b
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXHTMLTag.h"
+
+/*
+  Usage:
+
+    <textarea var:value="blah/>
+
+  Additions:
+
+    value - stores value of textarea
+  
+  HTML 4:
+   <!ELEMENT TEXTAREA - - (#PCDATA)       -- multi-line text field -->
+   <!ATTLIST TEXTAREA
+     %attrs;                              -- %coreattrs, %i18n, %events --
+     name        CDATA          #IMPLIED
+     rows        NUMBER         #REQUIRED
+     cols        NUMBER         #REQUIRED
+     disabled    (disabled)     #IMPLIED  -- unavailable in this context --
+     readonly    (readonly)     #IMPLIED
+     tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
+     accesskey   %Character;    #IMPLIED  -- accessibility key character --
+     onfocus     %Script;       #IMPLIED  -- the element got the focus --
+     onblur      %Script;       #IMPLIED  -- the element lost the focus --
+     onselect    %Script;       #IMPLIED  -- some text was selected --
+     onchange    %Script;       #IMPLIED  -- the element value was changed --
+     >
+*/
+
+@interface ODR_XHTML_textarea : ODRDynamicXHTMLTag
+@end
+
+#include "common.h"
+
+@implementation ODR_XHTML_textarea
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  NSString *ename;
+  id formValue;
+  
+  ename     = [self _selectNameOfNode:_node inContext:_ctx];
+  formValue = [_req formValueForKey:ename];
+  
+  if ([self isSettable:@"value" node:_node ctx:_ctx])
+    [self setString:formValue for:@"value" node:_node ctx:_ctx];
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *ename;
+  int rows, cols;
+  id  value;
+  
+  ename = [self _selectNameOfNode:_node inContext:_ctx];
+  rows  = [self intFor:@"rows"    node:_node ctx:_ctx];
+  cols  = [self intFor:@"cols"    node:_node ctx:_ctx];
+  value = [self valueFor:@"value" node:_node ctx:_ctx];
+  
+  if ([_ctx isInForm]) {
+    [_response appendContentString:@"<textarea name=\""];
+    [_response appendContentHTMLAttributeValue:ename];
+    [_response appendContentCharacter:'"'];
+    
+    if (rows > 0) {
+      [_response appendContentString:@" rows=\""];
+      [_response appendContentString:[NSString stringWithFormat:@"%d", rows]];
+      [_response appendContentCharacter:'"'];
+    }
+    if (cols > 0) {
+      [_response appendContentString:@" cols=\""];
+      [_response appendContentString:[NSString stringWithFormat:@"%d", cols]];
+      [_response appendContentCharacter:'"'];
+    }
+    
+    [_response appendContentString:@">"];
+    
+    /* append content (value + element content) */
+    
+    if (value) {
+      [_response appendContentHTMLString:value];
+    }
+    else {
+      /* 'default' value */
+      [self appendChildNodes:[_node childNodes]
+            toResponse:_response
+            inContext:_ctx];
+    }
+    
+    /* close tag */
+    [_response appendContentString:@"</textarea>"];
+  }
+  else {
+    [[_ctx component]
+           logWithFormat:@"WARNING: textarea is not in a form !"];
+    [_response appendContentHTMLString:[value stringValue]];
+  }
+}
+
+@end /* ODR_XHTML_textarea */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODXHTMLNodeRenderFactory.h b/skyrix-sope/NGObjDOM/XHTML.subproj/ODXHTMLNodeRenderFactory.h
new file mode 100644 (file)
index 0000000..c9526d7
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODXHTMLNodeRenderFactory_H__
+#define __ODXHTMLNodeRenderFactory_H__
+
+#include <NGObjDOM/ODNodeRendererFactory.h>
+
+@interface ODXHTMLNodeRenderFactory : NSObject < ODNodeRendererFactory >
+@end
+
+#endif /* __ODXHTMLNodeRenderFactory_H__ */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/ODXHTMLNodeRenderFactory.m b/skyrix-sope/NGObjDOM/XHTML.subproj/ODXHTMLNodeRenderFactory.m
new file mode 100644 (file)
index 0000000..0d7d044
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODXHTMLNodeRenderFactory.h"
+#include "ODRDynamicXHTMLTag.h"
+#include <NGObjDOM/ODNamespaces.h>
+#include <NGObjDOM/ODNodeRenderer.h>
+#include "common.h"
+
+@implementation ODXHTMLNodeRenderFactory
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  static NSMutableDictionary *tagToRenderer = nil; /* cache, THREAD */
+  ODNodeRenderer *renderer;
+  NSString *rendererName;
+
+  /* check node-type */
+  
+  if (!([[_domNode namespaceURI] isEqualToString:XMLNS_XHTML] ||
+        [[_domNode namespaceURI] isEqualToString:XMLNS_HTML40]))
+    return nil;
+
+  /* lookup renderer in cache */
+
+  if ((renderer = [tagToRenderer objectForKey:[_domNode tagName]]))
+    return renderer;
+  
+  /* lookup renderer by classname */
+  
+  rendererName = [@"ODR_XHTML_" stringByAppendingString:[_domNode tagName]];
+
+  renderer = [[[NSClassFromString(rendererName) alloc] init] autorelease];
+
+  /* did not find special renderer, use default renderer */
+  
+  if (renderer == nil) {
+    static ODRDynamicXHTMLTag *defRenderer = nil;
+    if (defRenderer == nil)
+      defRenderer = [[ODRDynamicXHTMLTag alloc] init];
+    renderer = defRenderer;
+  }
+
+  /* place renderer in cache */
+
+  if (renderer) {
+    if (tagToRenderer == nil)
+      tagToRenderer = [[NSMutableDictionary alloc] initWithCapacity:64];
+    [tagToRenderer setObject:renderer forKey:[_domNode tagName]];
+  }
+  
+  return renderer;
+}
+
+@end /* ODXHTMLNodeRenderFactory */
diff --git a/skyrix-sope/NGObjDOM/XHTML.subproj/bundle-info.plist b/skyrix-sope/NGObjDOM/XHTML.subproj/bundle-info.plist
new file mode 100644 (file)
index 0000000..623a5e5
--- /dev/null
@@ -0,0 +1,52 @@
+{
+  CVSID = "$Id: bundle-info.plist,v 1.1.1.1 2003/07/09 22:57:26 cvs Exp $";
+  bundleHandler = "ODXHTMLNodeRenderFactory";
+
+  requires = {
+    bundleManagerVersion = 1;
+    
+    classes = (
+      { name = NSObject; }
+    );
+  };
+
+  provides = {
+    ODRendererFactory = (
+      { 
+        name = "XHTML"; 
+        class = "ODXHTMLNodeRenderFactory"; 
+      }
+    );
+    
+    ODRenderer = (
+      { name = "{http://www.w3.org/1999/xhtml}a";        },
+      { name = "{http://www.w3.org/1999/xhtml}button";   },
+      { name = "{http://www.w3.org/1999/xhtml}form";     },
+      { name = "{http://www.w3.org/1999/xhtml}img";      },
+      { name = "{http://www.w3.org/1999/xhtml}input";    },
+      { name = "{http://www.w3.org/1999/xhtml}option";   },
+      { name = "{http://www.w3.org/1999/xhtml}select";   },
+      { name = "{http://www.w3.org/1999/xhtml}textarea"; },
+      { name = "{http://www.w3.org/TR/REC-html40}a";        },
+      { name = "{http://www.w3.org/TR/REC-html40}button";   },
+      { name = "{http://www.w3.org/TR/REC-html40}form";     },
+      { name = "{http://www.w3.org/TR/REC-html40}img";      },
+      { name = "{http://www.w3.org/TR/REC-html40}input";    },
+      { name = "{http://www.w3.org/TR/REC-html40}option";   },
+      { name = "{http://www.w3.org/TR/REC-html40}select";   },
+      { name = "{http://www.w3.org/TR/REC-html40}textarea"; },
+    );
+    classes = (
+      { name = ODRDynamicXHTMLTag;       },
+      { name = ODR_XHTML_a;              },
+      { name = ODR_XHTML_button;         },
+      { name = ODR_XHTML_form;           },
+      { name = ODR_XHTML_img;            },
+      { name = ODR_XHTML_input;          },
+      { name = ODR_XHTML_option;         },
+      { name = ODR_XHTML_select;         },
+      { name = ODR_XHTML_textarea;       },
+      { name = ODXHTMLNodeRenderFactory; },
+    );
+  };
+}
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/.cvsignore b/skyrix-sope/NGObjDOM/XUL.subproj/.cvsignore
new file mode 100644 (file)
index 0000000..f8ad236
--- /dev/null
@@ -0,0 +1,3 @@
+XUL.odr
+shared_debug_obj
+shared_obj
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/COPYING b/skyrix-sope/NGObjDOM/XUL.subproj/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/GNUmakefile b/skyrix-sope/NGObjDOM/XUL.subproj/GNUmakefile
new file mode 100644 (file)
index 0000000..5020f51
--- /dev/null
@@ -0,0 +1,34 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+BUNDLE_NAME        = XUL
+BUNDLE_EXTENSION   = .odr
+BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/Bundles
+
+XUL_OBJC_FILES = \
+       ODXULNodeRenderFactory.m\
+       ODRDynamicXULTag.m              \
+       ODR_XUL_box.m                   \
+       ODR_XUL_button.m                \
+       ODR_XUL_title.m                 \
+       ODR_XUL_titledbox.m             \
+       ODR_XUL_spring.m                \
+       ODR_XUL_text.m                  \
+       ODR_XUL_textfield.m             \
+       ODR_XUL_window.m                \
+       ODR_XUL_image.m                 \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/GNUmakefile.preamble b/skyrix-sope/NGObjDOM/XUL.subproj/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..556c9b8
--- /dev/null
@@ -0,0 +1,57 @@
+# $Id$
+
+ADDITIONAL_CPPFLAGS += -pipe -Wall
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..                    \
+       -I../..                 \
+       -I../../XML             \
+       -I../../NGObjWeb        \
+       -I../../NGStreams       \
+
+ifeq ($(FOUNDATION_LIB),apple)
+
+RELBUILD_DIR_SOPE=../..
+RELBUILD_DIR_SxCore=../../../skyrix-core
+RELBUILD_DIR_SxXml=../../../skyrix-xml
+
+ADDITIONAL_LIB_DIRS += \
+        -L$(RELBUILD_DIR_SOPE)/NGObjDOM/$(GNUSTEP_OBJ_DIR_NAME)                \
+        -L$(RELBUILD_DIR_SOPE)/NGObjWeb/$(GNUSTEP_OBJ_DIR_NAME)                \
+        -L$(RELBUILD_DIR_SOPE)/NGJavaScript/$(GNUSTEP_OBJ_DIR_NAME)    \
+        -L$(RELBUILD_DIR_SOPE)/NGScripting/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGMime/$(GNUSTEP_OBJ_DIR_NAME)        \
+        -L$(RELBUILD_DIR_SxCore)/NGStreams/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+        -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)             \
+        -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)            \
+
+XUL_BUNDLE_LIBS += \
+       -lNGObjDOM -lNGObjWeb -lNGScripting \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC
+
+ADDITIONAL_LDFLAGS += -framework Foundation
+
+endif
+
+ifeq ($(FOUNDATION_LIB),nx)
+
+ADDITIONAL_LIB_DIRS += \
+        -L../$(GNUSTEP_OBJ_DIR)                        \
+        -L../../NGMime/$(GNUSTEP_OBJ_DIR)      \
+        -L../../NGStreams/$(GNUSTEP_OBJ_DIR)   \
+        -L../../EOControl/$(GNUSTEP_OBJ_DIR)   \
+        -L../../NGExtensions/$(GNUSTEP_OBJ_DIR)        \
+
+XUL_BUNDLE_LIBS += \
+       -lNGObjDOM      \
+       -lNGMime        \
+       -lNGStreams     \
+       -lEOControl     \
+       -lNGExtensions  \
+       -lFoundationExt \
+
+ADDITIONAL_LDFLAGS += -framework Foundation
+
+endif
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODRDynamicXULTag.h b/skyrix-sope/NGObjDOM/XUL.subproj/ODRDynamicXULTag.h
new file mode 100644 (file)
index 0000000..c886de5
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODRDynamicXULTag_H__
+#define __ODRDynamicXULTag_H__
+
+#import <Foundation/NSObject.h>
+#import <NGObjDOM/ODNodeRenderer.h>
+
+@class NSString;
+@class WOContext;
+
+@interface ODRDynamicXULTag : ODNodeRenderer
+
+/* whether to process a child, only element-nodes are processed by default */
+- (BOOL)addChildNode:(id)_node inContext:(WOContext *)_ctx;
+
+- (void)willAppendChildNode:(id)_child
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+- (void)didAppendChildNode:(id)_child
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+
+@end
+
+#endif /* __ODRDynamicXULTag_H__ */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODRDynamicXULTag.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODRDynamicXULTag.m
new file mode 100644 (file)
index 0000000..dfe8cbc
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXULTag.h"
+#include <NGObjDOM/ODNamespaces.h>
+#include <NGScripting/NSObject+Scripting.h>
+#include "common.h"
+
+@implementation ODRDynamicXULTag
+
+- (BOOL)addChildNode:(id)_node inContext:(WOContext *)_ctx {
+  return [_node nodeType] == DOM_ELEMENT_NODE ? YES : NO;
+}
+
+- (id)invokeValueForAttributeNode:(id<DOMAttr>)_attrNode inContext:(id)_ctx {
+  id scriptResult;
+  
+  if (![[_attrNode namespaceURI] isEqualToString:XMLNS_XUL])
+    return [super invokeValueForAttributeNode:_attrNode inContext:_ctx];
+
+  if (![(NSString *)[(id<DOMAttr>)_attrNode name] hasPrefix:@"on"]) 
+    return [super invokeValueForAttributeNode:_attrNode inContext:_ctx];
+  
+  /* a JS action, eg onclick */
+  
+  scriptResult =
+    [[_ctx component] evaluateScript:[_attrNode value] language:nil];
+  
+  return nil;
+}
+
+- (void)takeValuesForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  if ([_domNode hasChildNodes]) {
+    [self takeValuesForChildNodes:[_domNode childNodes]
+          fromRequest:_request
+          inContext:_context];
+  }
+}
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  if (![_domNode hasChildNodes])
+    return nil;
+  
+  return [self invokeActionForChildNodes:[_domNode childNodes]
+               fromRequest:_request
+               inContext:_context];
+}
+
+- (void)willAppendChildNode:(id)_child
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+}
+- (void)didAppendChildNode:(id)_child
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+}
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  id children;
+  id child;
+  
+  if (![_domNode hasChildNodes])
+    return;
+  
+  [_ctx appendZeroElementIDComponent];
+  
+  children = [(id)[_domNode childNodes] objectEnumerator];
+  while ((child = [children nextObject])) {
+    ODNodeRenderer *renderer;
+    
+    if ([self includeChildNode:child ofNode:_domNode inContext:_ctx]) {
+      if ((renderer = [self rendererForNode:child inContext:_ctx])) {
+        [self willAppendChildNode:child
+              toResponse:_response
+              inContext:_ctx];
+        
+        [renderer appendNode:child
+                  toResponse:_response
+                  inContext:_ctx];
+        
+        [self didAppendChildNode:child
+              toResponse:_response
+              inContext:_ctx];
+      }
+    }
+    [_ctx incrementLastElementIDComponent];
+  }
+  [_ctx deleteLastElementIDComponent];
+}
+
+@end /* ODRDynamicXULTag */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_box.h b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_box.h
new file mode 100644 (file)
index 0000000..4a56834
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODR_XUL_box_H__
+#define __ODR_XUL_box_H__
+
+#include "ODRDynamicXULTag.h"
+
+@class WOResponse, WOContext;
+
+@interface ODR_XUL_box : ODRDynamicXULTag
+
+- (void)verticalAppendChildList:(id)_nodeList ofNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+
+- (void)horizontalAppendChildList:(id)_nodeList ofNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+
+@end
+
+#endif /* __ODR_XUL_box_H__ */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_box.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_box.m
new file mode 100644 (file)
index 0000000..c4dee82
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "ODR_XUL_box.h"
+
+@interface ODR_XUL_hbox : ODR_XUL_box
+@end
+
+@interface ODR_XUL_vbox : ODR_XUL_box
+@end
+
+#include "common.h"
+
+@implementation ODR_XUL_box
+
+- (NSString *)borderWidthForNode:(id)_node inContext:(WOContext *)_ctx {
+  return @"0";
+}
+
+- (void)appendAfterTableOfNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+}
+
+- (void)_openTheBox:(id)_node
+           response:(WOResponse *)_response
+                ctx:(WOContext *)_ctx
+{
+  NSString *tmp;
+
+  [_response appendContentString:@"<table"];
+  
+  tmp = [self borderWidthForNode:_node inContext:_ctx];
+  if (tmp) {
+    [_response appendContentString:@" border=\""];
+    [_response appendContentString:tmp];
+    [_response appendContentString:@"\""];
+  }
+  
+  tmp = [self stringFor:@"width" node:_node ctx:_ctx];
+  tmp = (tmp) ? tmp : @"100%";
+  if (tmp) {
+    [_response appendContentString:@" width=\""];
+    [_response appendContentString:tmp];
+    [_response appendContentString:@"\""];
+  }
+
+  tmp = [self stringFor:@"height" node:_node ctx:_ctx];
+  if (tmp) {
+    [_response appendContentString:@" height=\""];
+    [_response appendContentString:tmp];
+    [_response appendContentString:@"\""];
+  }
+  [_response appendContentCharacter:'>'];
+}
+
+- (void)_openTheCell:(id)_node
+            response:(WOResponse *)_response
+                 ctx:(WOContext *)_ctx
+{
+  NSString *tmp;
+
+  [_response appendContentString:@"<td"];
+  
+  tmp = [self stringFor:@"align" node:_node ctx:_ctx];
+  tmp = (tmp) ? tmp : @"center";
+  if (tmp) {
+    [_response appendContentString:@" align=\""];
+    [_response appendContentString:tmp];
+    [_response appendContentString:@"\""];
+  }
+  tmp = [self stringFor:@"valign" node:_node ctx:_ctx];
+  if (tmp) {
+    [_response appendContentString:@" valign=\""];
+    [_response appendContentString:tmp];
+    [_response appendContentString:@"\""];
+  }
+  [_response appendContentCharacter:'>'];
+}
+
+- (void)verticalAppendChildList:(id)_nodeList ofNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  id children;
+  id child;
+  
+  if ([_nodeList count] == 0)
+    return;
+  
+  // append <table ....>
+  [self _openTheBox:_node response:_response ctx:_ctx];
+
+  [self appendAfterTableOfNode:_node
+        toResponse:_response
+        inContext:_ctx];
+  
+  [_ctx appendZeroElementIDComponent];
+  
+  children = [_nodeList objectEnumerator];
+  while ((child = [children nextObject])) {
+    ODNodeRenderer *renderer;
+
+    if ([self addChildNode:child inContext:_ctx]) {
+      renderer = [self rendererForNode:child inContext:_ctx];
+      if (renderer) {
+        [_response appendContentString:@"<tr>"];
+        // append <td ... >
+        [self _openTheCell:_node response:_response ctx:_ctx];
+      
+        [renderer appendNode:child
+                  toResponse:_response
+                  inContext:_ctx];
+        
+        [_response appendContentString:@"</td></tr>"];
+      }
+    }
+    
+    [_ctx incrementLastElementIDComponent];
+  }
+  
+  [_ctx deleteLastElementIDComponent];
+  
+  [_response appendContentString:@"</table>"];
+}
+
+- (void)horizontalAppendChildList:(id)_nodeList ofNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  id children;
+  id child;
+  
+  if ([_nodeList count] == 0)
+    return;
+
+  // append <table ...>
+  [self _openTheBox:_node response:_response ctx:_ctx];
+    
+  [self appendAfterTableOfNode:_node
+        toResponse:_response
+        inContext:_ctx];
+  
+  [_response appendContentString:@"<tr>"];
+  
+  [_ctx appendZeroElementIDComponent];
+  
+  children = [_nodeList objectEnumerator];
+  while ((child = [children nextObject])) {
+    ODNodeRenderer *renderer;
+    
+    if ([self addChildNode:child inContext:_ctx]) {
+      renderer = [self rendererForNode:child inContext:_ctx];
+      if (renderer) {
+        // append <td ... >
+        [self _openTheCell:_node response:_response ctx:_ctx];
+      
+        [renderer appendNode:child
+                  toResponse:_response
+                  inContext:_ctx];
+        
+        [_response appendContentString:@"</td>"];
+      }
+    }
+    
+    [_ctx incrementLastElementIDComponent];
+  }
+  
+  [_ctx deleteLastElementIDComponent];
+  
+  [_response appendContentString:@"</tr></table>"];
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *orient;
+
+  if (![_node hasChildNodes])
+    return;
+  
+  orient = [self stringFor:@"orient" node:_node ctx:_ctx];
+  
+  if ([orient isEqualToString:@"vertical"]) {
+    [self verticalAppendChildList:[_node childNodes] ofNode:_node
+          toResponse:_response
+          inContext:_ctx];
+  }
+  else {
+    [self horizontalAppendChildList:[_node childNodes] ofNode:_node
+          toResponse:_response
+          inContext:_ctx];
+  }
+}
+
+@end /* ODR_XUL_box */
+
+@implementation ODR_XUL_hbox
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  if (![_domNode hasChildNodes])
+    return;
+  
+  [self horizontalAppendChildList:[_domNode childNodes] ofNode:_domNode
+        toResponse:_response
+        inContext:_context];
+}
+
+@end /* ODR_XUL_hbox */
+
+@implementation ODR_XUL_vbox
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  if (![_domNode hasChildNodes])
+    return;
+  
+  [self verticalAppendChildList:[_domNode childNodes] ofNode:_domNode
+        toResponse:_response
+        inContext:_context];
+}
+
+@end /* ODR_XUL_vbox */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_button.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_button.m
new file mode 100644 (file)
index 0000000..2b5a45d
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXULTag.h"
+
+/*
+  http://www.xulplanet.com/tutorials/xultu/elemref/ref_button.html
+*/
+
+@interface ODR_XUL_button : ODRDynamicXULTag
+@end
+
+#include <DOM/DOM.h>
+#include "common.h"
+#include "ODNamespaces.h"
+
+@interface WOContext(Privates)
+- (void)addActiveFormElement:(id)_element;
+@end
+
+@implementation ODR_XUL_button
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (void)takeValuesForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  if ([_context isInForm]) {
+    NSString *formId;
+    id formValue;
+    
+    formId = [_context elementID];
+    
+    if ((formValue = [_request formValueForKey:formId])) {
+      /* yep, we are the active element (submit-button) */
+      [_context addActiveFormElement:_domNode];
+    }
+    else {
+      /* check for image button coordinates */
+      NSString *xId;
+      
+      xId = [formId stringByAppendingString:@".x"];
+      if ((formValue = [_request formValueForKey:xId]))
+        /* yep, we are the active element (image-button) */
+        [_context addActiveFormElement:_domNode];
+    }
+  }
+  
+  [super takeValuesForNode:_domNode
+         fromRequest:_request
+         inContext:_context];
+}
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  if ([[_context elementID] isEqualToString:[_context senderID]]) {
+    /* active element .. */
+    id onClickNode;
+    id<DOMNamedNodeMap> attrs;
+    
+    if ((attrs = [_domNode attributes]) == nil)
+      return nil;
+    
+    if ((onClickNode = [_domNode attributeNode:@"onclick" namespaceURI:@"*"])) {
+      return [self invokeValueForAttributeNode:onClickNode inContext:_context];
+    }
+    else {
+      NSLog(@"%s: did not find 'onclick' attribute in xul:button !",
+            __PRETTY_FUNCTION__);
+      return nil;
+    }
+  }
+  else {
+    return [super invokeActionForNode:_domNode
+                  fromRequest:_request
+                  inContext:_context];
+  }
+}
+
+
+- (void)appendAsFormButton:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *value, *ttip, *src, *onClick;
+
+  value   = [self stringFor:@"value"       node:_node ctx:_ctx];
+  ttip    = [self stringFor:@"tooltiptext" node:_node ctx:_ctx];
+  src     = [self stringFor:@"src"         node:_node ctx:_ctx];
+  onClick = [self stringFor:@"onclick"     node:_node ctx:_ctx];
+
+  if ([src length] == 0) {
+    [_response appendContentString:@"<input type=\"submit\" name=\""];
+    [_response appendContentString:[_ctx elementID]];
+    [_response appendContentString:@"\" value=\""];
+    [_response appendContentHTMLAttributeValue:value];
+    [_response appendContentString:@"\" />"];
+  }
+  else {
+    NSString *alt;
+      
+    [_response appendContentString:@"<input type=\"image\" name=\""];
+    [_response appendContentString:[_ctx elementID]];
+    [_response appendContentString:@"\" src=\""];
+    [_response appendContentString:src];
+    [_response appendContentCharacter:'"'];
+        
+    if ([ttip length] > 0)
+      alt = ttip;
+    else if ([value length] > 0)
+      alt = value;
+    else
+      alt = nil;
+    
+    if ([alt length] > 0) {
+      [_response appendContentString:@" alt=\""];
+      [_response appendContentHTMLAttributeValue:alt];
+      [_response appendContentString:@"\" title=\""];
+      [_response appendContentHTMLAttributeValue:alt];
+      [_response appendContentCharacter:'"'];
+    }
+    
+    [_response appendContentString:@" />"];
+  }
+  
+  [super appendNode:_node
+         toResponse:_response
+         inContext:_ctx];
+}
+
+- (void)appendAsHyperlink:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *value, *ttip, *src, *onClick;
+
+  value   = [self stringFor:@"value"       node:_node ctx:_ctx];
+  ttip    = [self stringFor:@"tooltiptext" node:_node ctx:_ctx];
+  src     = [self stringFor:@"src"         node:_node ctx:_ctx];
+  onClick = [self stringFor:@"onclick"     node:_node ctx:_ctx];
+  
+  if ([onClick length] > 0) {
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:onClick];
+    [_response appendContentString:@"\""];
+    
+    if ([ttip length] > 0) {
+      [_response appendContentString:@" title=\""];
+      [_response appendContentHTMLAttributeValue:ttip];
+      [_response appendContentString:@"\""];
+    }
+    
+    [_response appendContentString:@">"];
+  }
+  
+  if ([src length] > 0) {
+    NSString *alt;
+    
+    [_response appendContentString:@"<img border='0' src=\""];
+    [_response appendContentHTMLAttributeValue:src];
+    [_response appendContentString:@"\""];
+    
+    if ([ttip length] > 0)
+      alt = ttip;
+    else if ([value length] > 0)
+      alt = value;
+    else
+      alt = nil;
+    
+    if ([alt length] > 0) {
+      [_response appendContentString:@" alt=\""];
+      [_response appendContentHTMLAttributeValue:alt];
+      [_response appendContentString:@"\""];
+    }
+    
+    [_response appendContentString:@" />"];
+  }
+  else if ([value length] > 0)
+    [_response appendContentHTMLString:value];
+  
+  [super appendNode:_node
+         toResponse:_response
+         inContext:_ctx];
+  
+  if (onClick != nil)
+    [_response appendContentString:@"</a>"];
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if ([_ctx isInForm])
+    [self appendAsFormButton:_node toResponse:_response inContext:_ctx];
+  else
+    [self appendAsHyperlink:_node toResponse:_response inContext:_ctx];
+}
+
+
+@end /* ODR_XUL_button */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_column.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_column.m
new file mode 100644 (file)
index 0000000..14dba5a
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+// $
+
+#include "ODRDynamicXULTag.h"
+
+@interface ODR_XUL_column : ODRDynamicXULTag
+@end
+
+#include <NGObjDOM/ODNamespaces.h>
+#include "common.h"
+
+@implementation ODR_XUL_column
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+
+  [_response appendContentString:@"column"];
+  if ([_domNode hasChildNodes]) {
+    NSLog(@"_domNode childNodes is %@", [_domNode childNodes]);
+    [self appendChildNodes:[_domNode childNodes]
+          toResponse:_response
+          inContext:_context];
+  }
+}
+
+@end /* ODR_XUL_text */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_columns.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_columns.m
new file mode 100644 (file)
index 0000000..332f1e9
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+// $
+
+#include "ODRDynamicXULTag.h"
+
+@interface ODR_XUL_columns : ODRDynamicXULTag
+@end
+
+#include <NGObjDOM/ODNamespaces.h>
+#include "common.h"
+
+@implementation ODR_XUL_columns
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+
+  [_response appendContentString:@"columns"];
+  if ([_domNode hasChildNodes]) {
+    NSLog(@"_domNode childNodes is %@", [_domNode childNodes]);
+    [self appendChildNodes:[_domNode childNodes]
+          toResponse:_response
+          inContext:_context];
+  }
+}
+
+@end /* ODR_XUL_text */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_grid.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_grid.m
new file mode 100644 (file)
index 0000000..1ac5f74
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXULTag.h"
+
+@interface ODR_XUL_grid : ODRDynamicXULTag
+@end
+
+#include <NGObjDOM/ODNamespaces.h>
+#include "common.h"
+
+@implementation ODR_XUL_grid
+
+
+- (void)appendRows:(NSArray *)_rows
+           columns:(NSArray *)_columns
+       doRowsFirst:(BOOL)_doRowsFirst
+        toResponse:(WOResponse *)_response
+         inContext:(id)_context
+{
+  int i, j, cnt, cnt2;
+
+  for (i = 0, cnt = [_rows count]; i < cnt; i++) {
+    id row;
+
+    row = [_rows objectAtIndex:i];
+    if (![[row nodeName] isEqualToString:@"row"])
+      continue;
+      
+    NSLog(@"__row is %@", row);
+    [_response appendContentString:@"<tr>"];
+    for (j = 0, cnt2 = [_columns count]; j < cnt; j++) {
+      id col;
+
+      col = [_columns objectAtIndex:i];
+      if (![[col nodeName] isEqualToString:@"column"])
+        continue;
+        
+      [_response appendContentString:@"<td>"];
+      [self appendChildNodes:[(id)((_doRowsFirst) ? row : col) childNodes]
+            toResponse:_response
+            inContext:_context];
+      [self appendChildNodes:[(id)((_doRowsFirst) ? col : row) childNodes]
+            toResponse:_response
+            inContext:_context];
+      [_response appendContentString:@"</td>"];
+    }
+    [_response appendContentString:@"</tr>"];
+  }
+}
+
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+
+  NSArray  *childNodes;
+  BOOL     doRowsFirst = NO;
+  id       rows     = nil;
+  id       columns  = nil;
+  unsigned colCount = 0;
+  unsigned rowCount = 0;
+  unsigned i, cnt;
+
+  if (![_domNode hasChildNodes])
+    return;
+
+  childNodes = (NSArray *)[_domNode childNodes];
+
+  // get child rows and columns
+  for (i = 0, cnt = [childNodes count]; i < cnt; i++) {
+    id child;
+    
+    child = [childNodes objectAtIndex:i];
+    if ([[child nodeName] isEqualToString:@"columns"]) {
+      doRowsFirst = (rowCount == 0) ? NO : doRowsFirst;
+      columns = child;
+      colCount++;
+    }
+    else if ([[child nodeName] isEqualToString:@"rows"]) {
+      doRowsFirst = (colCount == 0) ? YES : doRowsFirst;
+      rows = child;
+      rowCount++;
+    }
+  }
+
+  if (colCount != 1 || rowCount != 1) {
+    NSLog(@"Warning: wrong row or column count");
+    return;
+  }
+  
+  [_response appendContentString:@"<table border=\"1\">"];
+  [self appendRows:(NSArray *)[rows childNodes]
+        columns:(NSArray *)[columns childNodes]
+        doRowsFirst:doRowsFirst
+        toResponse:_response
+        inContext:_context];
+  [_response appendContentString:@"</table>"];
+}
+
+@end /* ODR_XUL_grid */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_image.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_image.m
new file mode 100644 (file)
index 0000000..d872a05
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXULTag.h"
+
+/*
+  http://www.xulplanet.com/tutorials/xultu/elemref/ref_image.html
+*/
+
+@interface ODR_XUL_image : ODRDynamicXULTag
+@end
+
+#include <DOM/DOM.h>
+#include "common.h"
+#include "ODNamespaces.h"
+
+@interface WOContext(Privates)
+- (void)addActiveFormElement:(id)_element;
+@end
+
+@implementation ODR_XUL_image
+
+- (void)takeValuesForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  if ([_context isInForm]) {
+    NSString *formId;
+    id formValue;
+    
+    formId = [_context elementID];
+    
+    if ((formValue = [_request formValueForKey:formId])) {
+      /* yep, we are the active element (submit-image) */
+      [_context addActiveFormElement:_domNode];
+    }
+    else {
+      /* check for image image coordinates */
+      NSString *xId;
+      
+      xId = [formId stringByAppendingString:@".x"];
+      if ((formValue = [_request formValueForKey:xId]))
+        /* yep, we are the active element (image-image) */
+        [_context addActiveFormElement:_domNode];
+    }
+  }
+  
+  [super takeValuesForNode:_domNode
+         fromRequest:_request
+         inContext:_context];
+}
+
+- (id)invokeActionForNode:(id)_domNode
+  fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context
+{
+  if ([[_context elementID] isEqualToString:[_context senderID]]) {
+    /* active element .. */
+    id onClickNode;
+    id<DOMNamedNodeMap> attrs;
+    
+    if ((attrs = [_domNode attributes]) == nil)
+      return nil;
+    
+    if ((onClickNode = [_domNode attributeNode:@"onclick" namespaceURI:@"*"])) {
+      return [self invokeValueForAttributeNode:onClickNode inContext:_context];
+    }
+    else {
+      NSLog(@"%s: did not find 'onclick' attribute in xul:image !",
+            __PRETTY_FUNCTION__);
+      return nil;
+    }
+  }
+  else {
+    return [super invokeActionForNode:_domNode
+                  fromRequest:_request
+                  inContext:_context];
+  }
+}
+
+
+- (void)appendAsFormImage:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *ttip, *src, *onclick;
+
+  ttip    = [self stringFor:@"tooltiptext" node:_node ctx:_ctx];
+  src     = [self stringFor:@"src"         node:_node ctx:_ctx];
+  onclick = [self stringFor:@"onclick"     node:_node ctx:_ctx];
+  
+  if ([src length] == 0) {
+    [_response appendContentString:@"|missing 'src' attribute in xul:image|"];
+  }
+  else if ([onclick length] == 0) {
+    [_response appendContentString:@"<img src=\""];
+    [_response appendContentString:src];
+    [_response appendContentCharacter:'"'];
+    
+    if ([ttip length] > 0) {
+      [_response appendContentString:@" alt=\""];
+      [_response appendContentHTMLAttributeValue:ttip];
+      [_response appendContentString:@"\" title=\""];
+      [_response appendContentHTMLAttributeValue:ttip];
+      [_response appendContentCharacter:'"'];
+    }
+    
+    [_response appendContentString:@" />"];
+  }
+  else {
+    [_response appendContentString:@"<input type=\"image\" name=\""];
+    [_response appendContentString:[_ctx elementID]];
+    [_response appendContentString:@"\" src=\""];
+    [_response appendContentString:src];
+    [_response appendContentCharacter:'"'];
+    
+    if ([ttip length] > 0) {
+      [_response appendContentString:@" alt=\""];
+      [_response appendContentHTMLAttributeValue:ttip];
+      [_response appendContentString:@"\" title=\""];
+      [_response appendContentHTMLAttributeValue:ttip];
+      [_response appendContentCharacter:'"'];
+    }
+    
+    [_response appendContentString:@" />"];
+  }
+  
+  [super appendNode:_node
+         toResponse:_response
+         inContext:_ctx];
+}
+
+- (void)appendAsHyperlink:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *ttip, *src, *onClick;
+  
+  ttip    = [self stringFor:@"tooltiptext" node:_node ctx:_ctx];
+  src     = [self stringFor:@"src"         node:_node ctx:_ctx];
+  onClick = [self stringFor:@"onclick"     node:_node ctx:_ctx];
+  
+  if ([onClick length] > 0) {
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:onClick];
+    [_response appendContentString:@"\""];
+    
+    if ([ttip length] > 0) {
+      [_response appendContentString:@" title=\""];
+      [_response appendContentHTMLAttributeValue:ttip];
+      [_response appendContentString:@"\""];
+    }
+    
+    [_response appendContentString:@">"];
+  }
+
+  if ([src length] > 0) {
+    [_response appendContentString:@"<img border='0' src=\""];
+    [_response appendContentHTMLAttributeValue:src];
+    [_response appendContentString:@"\""];
+    
+    if ([ttip length] > 0) {
+      [_response appendContentString:@" alt=\""];
+      [_response appendContentHTMLAttributeValue:ttip];
+      [_response appendContentString:@"\""];
+    }
+    
+    [_response appendContentString:@" />"];
+  }
+  else {
+    [_response appendContentString:@"|missing 'src' attribute in xul:image|"];
+  }
+  
+  [super appendNode:_node
+         toResponse:_response
+         inContext:_ctx];
+  
+  if ([onClick length] > 0)
+    [_response appendContentString:@"</a>"];
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if ([_ctx isInForm])
+    [self appendAsFormImage:_node toResponse:_response inContext:_ctx];
+  else
+    [self appendAsHyperlink:_node toResponse:_response inContext:_ctx];
+}
+
+
+@end /* ODR_XUL_image */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_spring.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_spring.m
new file mode 100644 (file)
index 0000000..d928897
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXULTag.h"
+
+@interface ODR_XUL_spring : ODRDynamicXULTag
+@end
+
+#include "common.h"
+
+@implementation ODR_XUL_spring
+
+@end /* ODR_XUL_spring */
+
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_tab.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_tab.m
new file mode 100644 (file)
index 0000000..eed1f82
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "ODR_XUL_box.h"
+#include "common.h"
+#include <DOM/DOMNode+QueryPath.h>
+
+@interface ODR_XUL_tabbox : ODR_XUL_box
+@end
+
+@implementation ODR_XUL_tabbox
+
+- (NSString *)borderWidthForNode:(id)_node inContext:(WOContext *)_context {
+  return @"1";
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *align;
+  BOOL     selection;
+
+  if (![_node hasChildNodes])
+    return;
+  
+  align     = [self stringFor:@"align"     node:_node ctx:_ctx];
+  selection = [self   boolFor:@"selection" node:_node ctx:_ctx];
+  
+  if ([align isEqualToString:@"vertical"]) {
+    [self verticalAppendChildList:[_node childNodes] ofNode:_node
+          toResponse:_response
+          inContext:_ctx];
+  }
+  else {
+    [self horizontalAppendChildList:[_node childNodes] ofNode:_node
+          toResponse:_response
+          inContext:_ctx];
+  }
+}
+
+@end
+
+@interface ODR_XUL_tabpanel : ODR_XUL_box
+@end
+
+@implementation ODR_XUL_tabpanel
+- (NSString *)borderWidthForNode:(id)_node inContext:(WOContext *)_ctx {
+  return @"1";
+}
+
+- (BOOL)addChildNode:(id)_node inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  NSArray *childs;
+
+  childs = (NSArray *)[_domNode childNodes];
+
+  if ([childs count] == 0) return;
+}
+
+@end /* ODR_XUL_tabpanel */
+
+@interface ODR_XUL_tab : ODRDynamicXULTag
+@end
+
+@implementation ODR_XUL_tab
+
+- (BOOL)addChildNode:(id)_node inContext:(WOContext *)_ctx {
+  return NO;
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *value;
+  BOOL     isSelected = YES;;
+
+  value = [self stringFor:@"value" node:_node ctx:_ctx];
+  NSLog(@"__tab value is %@", value);
+  value = (value) ? value : @"tab";
+
+  NSLog(@"_________ stringValue is %@",
+        [self stringFor:@"selected" node:_node ctx:_ctx]);
+  
+  if (isSelected) [_response appendContentString:@"<B>"];
+  
+  [_response appendContentString:value];
+  
+  if (isSelected) [_response appendContentString:@"</B>"];
+}
+
+@end /* ODR_XUL_tab */
+
+
+@interface ODR_XUL_tabcontrol : ODR_XUL_box
+@end
+
+@implementation ODR_XUL_tabcontrol
+
+- (NSString *)borderWidthForNode:(id)_node inContext:(WOContext *)_ctx {
+  return @"1";
+}
+
+- (BOOL)addChildNode:(id)_node inContext:(WOContext *)_ctx {
+  return ([[_node nodeName] isEqualToString:@"tabbox"] ||
+          [[_node nodeName] isEqualToString:@"tabpanel"]);
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *align;
+
+  if (![_node hasChildNodes])
+    return;
+
+  align = [self stringFor:@"align" node:_node ctx:_ctx];
+  
+  if ([align isEqualToString:@"vertical"]) {
+    [self verticalAppendChildList:[_node childNodes] ofNode:_node
+          toResponse:_response
+          inContext:_ctx];
+  }
+  else {
+    [self horizontalAppendChildList:[_node childNodes] ofNode:_node
+          toResponse:_response
+          inContext:_ctx];
+  }
+}
+
+@end /* ODR_XUL_tabcontrol */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_text.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_text.m
new file mode 100644 (file)
index 0000000..245592e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXULTag.h"
+
+@interface ODR_XUL_text : ODRDynamicXULTag
+@end
+
+#include <NGObjDOM/ODNamespaces.h>
+#include "common.h"
+
+@implementation ODR_XUL_text
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *string;
+
+  string = [self stringFor:@"value" node:_node ctx:_ctx];
+  
+  if (![string isKindOfClass:[NSString class]])
+    string = [string stringValue];
+
+  if (string) {
+#if DEBUG
+    NSAssert2([string isKindOfClass:[NSString class]],
+              @"got non-string -stringValue... %@<%@>",
+              string, NSStringFromClass([string class]));
+#endif
+    [_response appendContentHTMLString:string];
+  }
+  
+  if ([_node hasChildNodes]) {
+    [self appendChildNodes:[_node childNodes]
+          toResponse:_response
+          inContext:_ctx];
+  }
+}
+
+@end /* ODR_XUL_text */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_textfield.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_textfield.m
new file mode 100644 (file)
index 0000000..703f482
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXULTag.h"
+
+@interface ODR_XUL_textfield : ODRDynamicXULTag
+@end
+
+#include "common.h"
+
+@implementation ODR_XUL_textfield
+
+- (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+- (void)takeValuesForNode:(id)_node
+  fromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+{
+  id formValue = nil;
+    
+  formValue = [_req formValueForKey:[_ctx elementID]];
+
+  if (formValue) {
+    if ([self isSettable:@"value" node:_node ctx:_ctx]) {
+      // formValue = [self parseFormValue:formValue inContext:_ctx]; ????
+      [self setString:formValue for:@"value" node:_node ctx:_ctx];
+    }
+  }
+}
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  int size;
+  id  value;
+
+  size  = [self   intFor:@"size"  node:_node ctx:_ctx];
+  value = [self valueFor:@"value" node:_node ctx:_ctx];
+
+  if ([_ctx isInForm]) {
+    [_response appendContentString:@"<input type=\"text\" name=\""];
+    [_response appendContentHTMLAttributeValue:[_ctx elementID]]; // ???
+    [_response appendContentString:@"\" value=\""];
+    [_response appendContentHTMLAttributeValue:[value stringValue]];
+    [_response appendContentCharacter:'"'];
+    
+    if (size > 0) {
+      [_response appendContentString:@" size=\""];
+      [_response appendContentString:[NSString stringWithFormat:@"%d", size]];
+      [_response appendContentCharacter:'"'];
+    }
+  
+    [_response appendContentString:@" />"];
+  }
+  else {
+    [[_ctx component]
+           logWithFormat:@"WARNING: xul:textfield is not in a form !"];
+    [_response appendContentHTMLString:[value stringValue]];
+  }
+}
+
+@end /* ODR_XUL_textfield */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_title.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_title.m
new file mode 100644 (file)
index 0000000..f8e7b0c
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODRDynamicXULTag.h"
+
+@interface ODR_XUL_title : ODRDynamicXULTag
+@end
+
+#include "common.h"
+
+@implementation ODR_XUL_title
+
+- (BOOL)addChildNode:(id)_node inContext:(WOContext *)_ctx {
+  /* allows text-content */
+  return YES;
+}
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  if ([_domNode hasChildNodes]) {
+    [_response appendContentString:@"<legend>"];
+
+    [super appendNode:_domNode
+           toResponse:_response
+           inContext:_context];
+    
+    [_response appendContentString:@"</legend>"];
+  }
+}
+
+@end /* ODR_XUL_title */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_titledbox.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_titledbox.m
new file mode 100644 (file)
index 0000000..c691e24
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODR_XUL_box.h"
+#include "common.h"
+#include <DOM/DOMNode+QueryPath.h>
+
+@interface ODR_XUL_titledbox : ODR_XUL_box
+@end
+
+@implementation ODR_XUL_titledbox
+
+- (BOOL)addChildNode:(id)_node inContext:(WOContext *)_ctx {
+  if ([_node nodeType] != DOM_ELEMENT_NODE)
+    return NO;
+  
+  if ([[_node tagName] isEqualToString:@"title"])
+    return NO;
+  
+  return YES;
+}
+
+- (void)appendNode:(id)_domNode
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  id titleNode;
+  
+  if (![_domNode hasChildNodes])
+    return;
+  
+  [_response appendContentString:@"<fieldset>"];
+  
+  if ((titleNode = [_domNode lookupQueryPath:@"-title"])) {
+    ODNodeRenderer *renderer;
+
+    if ((renderer = [self rendererForNode:titleNode inContext:_context])){
+      [renderer appendNode:titleNode
+                toResponse:_response
+                inContext:_context];
+    }
+  }
+  
+  [super appendNode:_domNode
+         toResponse:_response
+         inContext:_context];
+  
+  [_response appendContentString:@"</fieldset>"];
+}
+
+@end /* ODR_XUL_titledbox */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_window.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODR_XUL_window.m
new file mode 100644 (file)
index 0000000..3ebd75f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODR_XUL_box.h"
+
+/*
+  http://www.xulplanet.com/tutorials/xultu/elemref/ref_window.html
+*/
+
+@interface ODR_XUL_window : ODR_XUL_box
+@end
+
+#include <DOM/DOM.h>
+#include "common.h"
+#include "ODNamespaces.h"
+
+@implementation ODR_XUL_window
+
+- (void)appendNode:(id)_node
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *title;
+  
+  title = [self stringFor:@"title" node:_node ctx:_ctx];
+
+  if ([title length] > 0) {
+    [_response appendContentString:@"<table border='1' width='100%'>"];
+    [_response appendContentString:@"<tr><th>"];
+    [_response appendContentHTMLString:title];
+    [_response appendContentString:@"</th></tr>"];
+    [_response appendContentString:@"<tr><td width='100%'>"];
+  }
+  
+  [super appendNode:_node
+         toResponse:_response
+         inContext:_ctx];
+
+  if ([title length] > 0)
+    [_response appendContentString:@"&nbsp;</td></tr></table>"];
+}
+
+@end /* ODR_XUL_window */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODXULNodeRenderFactory.h b/skyrix-sope/NGObjDOM/XUL.subproj/ODXULNodeRenderFactory.h
new file mode 100644 (file)
index 0000000..7666748
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ODXULNodeRenderFactory_H__
+#define __ODXULNodeRenderFactory_H__
+
+#include <NGObjDOM/ODNodeRendererFactory.h>
+
+@interface ODXULNodeRenderFactory : NSObject < ODNodeRendererFactory >
+@end
+
+#endif /* __ODXULNodeRenderFactory_H__ */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/ODXULNodeRenderFactory.m b/skyrix-sope/NGObjDOM/XUL.subproj/ODXULNodeRenderFactory.m
new file mode 100644 (file)
index 0000000..ff14341
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "ODXULNodeRenderFactory.h"
+#include <NGObjDOM/ODNamespaces.h>
+#include <NGObjDOM/ODNodeRenderer.h>
+#include "common.h"
+
+@implementation ODXULNodeRenderFactory
+
+- (ODNodeRenderer *)rendererForNode:(id)_domNode
+  inContext:(WOContext *)_ctx
+{
+  static NSMutableDictionary *tagToRenderer = nil; /* cache, THREAD */
+  ODNodeRenderer *renderer;
+  NSString *rendererName;
+
+  if ((renderer = [tagToRenderer objectForKey:[_domNode tagName]]))
+    return renderer;
+  
+  if (![[_domNode namespaceURI] isEqualToString:XMLNS_XUL])
+    return nil;
+  
+  rendererName = [@"ODR_XUL_" stringByAppendingString:[_domNode tagName]];
+  
+  if ((renderer = [[NSClassFromString(rendererName) alloc] init])) {
+    if (tagToRenderer == nil)
+      tagToRenderer = [[NSMutableDictionary alloc] initWithCapacity:64];
+    [tagToRenderer setObject:renderer forKey:[_domNode tagName]];
+    AUTORELEASE(renderer);
+  }
+  
+  return renderer;
+}
+
+@end /* ODXULNodeRenderFactory */
diff --git a/skyrix-sope/NGObjDOM/XUL.subproj/bundle-info.plist b/skyrix-sope/NGObjDOM/XUL.subproj/bundle-info.plist
new file mode 100644 (file)
index 0000000..631da40
--- /dev/null
@@ -0,0 +1,64 @@
+{
+  CVSID = "$Id: bundle-info.plist,v 1.1.1.1 2003/07/09 22:57:26 cvs Exp $";
+  bundleHandler = "ODXULNodeRenderFactory";
+
+  requires = {
+    bundleManagerVersion = 1;
+    
+    classes = (
+      { name = NSObject; }
+    );
+  };
+
+  provides = {
+    ODRendererFactory = (
+      { 
+        name  = "XUL"; 
+        class = "ODXULNodeRenderFactory";
+      }
+    );
+    
+    ODRenderer = (
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}box"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}hbox"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}vbox"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}button"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}column"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}columns"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}grid"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}image"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}spring"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}tabbox"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}tabpanel"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}tab"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}tabcontrol"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}text"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}textfield"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}title"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}titledbox"; },
+      { name = "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}window"; },
+    );
+    classes = (
+      { name = ODRDynamicXULTag;       },
+      { name = ODR_XUL_box;            },
+      { name = ODR_XUL_hbox;           },
+      { name = ODR_XUL_vbox;           },
+      { name = ODR_XUL_button;         },
+      { name = ODR_XUL_column;         },
+      { name = ODR_XUL_columns;        },
+      { name = ODR_XUL_grid;           },
+      { name = ODR_XUL_image;          },
+      { name = ODR_XUL_spring;         },
+      { name = ODR_XUL_tabbox;         },
+      { name = ODR_XUL_tabpanel;       },
+      { name = ODR_XUL_tab;            },
+      { name = ODR_XUL_tabcontrol;     },
+      { name = ODR_XUL_text;           },
+      { name = ODR_XUL_textfield;      },
+      { name = ODR_XUL_title;          },
+      { name = ODR_XUL_titledbox;      },
+      { name = ODR_XUL_window;         },
+      { name = ODXULNodeRenderFactory; },
+    );
+  };
+}
diff --git a/skyrix-sope/NGObjDOM/bundle-info.plist b/skyrix-sope/NGObjDOM/bundle-info.plist
new file mode 100644 (file)
index 0000000..67e782f
--- /dev/null
@@ -0,0 +1,96 @@
+{
+  CVSID = "$Id: bundle-info.plist,v 1.1.1.1 2003/07/09 22:57:26 cvs Exp $";
+  bundleHandler = "NGObjDOMModule";
+
+  requires = {
+    bundleManagerVersion = 1;
+    
+    classes = (
+      { name = NSObject; }
+    );
+  };
+
+  provides = {
+    ODRendererFactory = (
+      { 
+        name  = "ODWONodeRenderFactory"; 
+        class = "ODWONodeRenderFactory"; 
+      },
+      { 
+        name  = "BIND"; 
+        class = "ODBindNodeRenderFactory"; 
+      },
+    );
+    
+    ODRenderer = (
+      { name = "{http://www.skyrix.com/od/binding}checkbox";    },
+      { name = "{http://www.skyrix.com/od/binding}collapsible"; },
+      { name = "{http://www.skyrix.com/od/binding}datefield";   },
+      { name = "{http://www.skyrix.com/od/binding}fieldset";    },
+      { name = "{http://www.skyrix.com/od/binding}foreach";     },
+      { name = "{http://www.skyrix.com/od/binding}form";        },
+      { name = "{http://www.skyrix.com/od/binding}if";          },
+      { name = "{http://www.skyrix.com/od/binding}nbsp";        },
+      { name = "{http://www.skyrix.com/od/binding}popupbutton"; },
+      { name = "{http://www.skyrix.com/od/binding}radiobutton"; },
+      { name = "{http://www.skyrix.com/od/binding}string";      },
+      { name = "{http://www.skyrix.com/od/binding}switch";      },
+      { name = "{http://www.skyrix.com/od/binding}td";          },
+      { name = "{http://www.skyrix.com/od/binding}th";          },
+      { name = "{http://www.skyrix.com/od/binding}tableview";   },
+      { name = "{http://www.skyrix.com/od/binding}tabview";     },
+      { name = "{http://www.skyrix.com/od/binding}viewertitle"; },
+      { name = "{http://www.skyrix.com/od/binding}with";        },
+    );
+    
+    WODynamicElements = (
+      { name = WORenderDOM; },
+    );
+    
+    classes = (
+      { name = NGObjDOMModule;           },
+      { name = ODNodeRenderer;           },
+      { name = ODNodeRendererFactory;    },
+      { name = ODNodeRendererFactorySet; },
+      { name = ODREmbedComponent;        },
+      { name = ODRGenericTag;            },
+      { name = ODRNodeText;              },
+      { name = ODRWebObject;             },
+      { name = ODWONodeRenderFactory;    },
+      { name = WORenderDOM;              },
+
+      { name = ODBindNodeRenderFactory;  },
+      { name = ODR_bind_checkbox;        },
+      { name = ODR_bind_collapsible;     },
+      { name = ODR_bind_datefield;       },
+      { name = ODR_bind_fieldset;        },
+      { name = ODR_bind_foreach;         },
+      { name = ODR_bind_form;            },
+      { name = ODR_bind_groupby;         },
+      { name = ODR_bind_groupings;       },
+      { name = ODR_bind_groupingset;     },
+      { name = ODR_bind_if;              },
+      { name = ODR_bind_ifnot;           },
+      { name = ODR_bind_multiselection;  },
+      { name = ODR_bind_nbsp;            },
+      { name = ODR_bind_popup;           },
+      { name = ODR_bind_popupbutton;     },
+      { name = ODR_bind_radiobutton;     },
+      { name = ODR_bind_singleselection; },
+      { name = ODR_bind_sortordering;    },
+      { name = ODR_bind_sortorderings;   },
+      { name = ODR_bind_string;          },
+      { name = ODR_bind_switch;          },
+      { name = ODR_bind_tablecell;       },
+      { name = ODR_bind_tableview;       },
+      { name = ODR_bind_tabview;         },
+      { name = ODR_bind_tbutton;         },
+      { name = ODR_bind_td;              },
+      { name = ODR_bind_tfooter;         },
+      { name = ODR_bind_tgroup;          },
+      { name = ODR_bind_th;              },
+      { name = ODR_bind_ttitle;          },
+      { name = ODR_bind_viewertitle;     },
+    );
+  };
+}
diff --git a/skyrix-sope/NGObjDOM/common.h b/skyrix-sope/NGObjDOM/common.h
new file mode 100644 (file)
index 0000000..7ee6583
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjDOM_common_H__
+#define __NGObjDOM_common_H__
+
+#import <Foundation/Foundation.h>
+
+#if NeXT_Foundation_LIBRARY || APPLE_FOUNDATION_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#endif
+
+#include <NGExtensions/NGExtensions.h>
+#include <NGObjWeb/NGObjWeb.h>
+#include <DOM/DOM.h>
+
+@class ODNodeRenderer;
+
+@interface WOContext(ODNodeRenderPrivate)
+- (void)addActiveFormElement:(ODNodeRenderer *)_element;
+@end
+
+@interface DOMElement(ODNodeRenderPrivate)
+- (id)lookupQueryPath:(NSString *)_queryPath;
+@end
+
+
+static inline void ODRAppendFont(WOResponse *_resp,
+                                 NSString   *_color,
+                                 NSString   *_face,
+                                 NSString   *_size)
+{
+  [_resp appendContentString:@"<font"];
+  if (_color) {
+    [_resp appendContentString:@" color=\""];
+    [_resp appendContentHTMLAttributeValue:_color];
+    [_resp appendContentCharacter:'"'];
+  }
+  if (_face) {
+    [_resp appendContentString:@" face=\""];
+    [_resp appendContentHTMLAttributeValue:_face];
+    [_resp appendContentCharacter:'"'];
+  }
+  if (_size) {
+    [_resp appendContentString:@" size=\""];
+    [_resp appendContentHTMLAttributeValue:_size];
+    [_resp appendContentCharacter:'"'];
+  }
+  [_resp appendContentCharacter:'>'];
+}
+
+static inline void ODRAppendTD(WOResponse *_resp,
+                               NSString   *_align,
+                               NSString   *_valign,
+                               NSString   *_bgColor,
+                               NSString   *_colspan)
+{
+  [_resp appendContentString:@"<td"];
+  if (_bgColor) {
+    [_resp appendContentString:@" bgcolor=\""];
+    [_resp appendContentHTMLAttributeValue:_bgColor];
+    [_resp appendContentCharacter:'"'];
+  }
+  if (_align) {
+    [_resp appendContentString:@" align=\""];
+    [_resp appendContentHTMLAttributeValue:_align];
+    [_resp appendContentCharacter:'"'];
+  }
+  if (_valign) {
+    [_resp appendContentString:@" valign=\""];
+    [_resp appendContentHTMLAttributeValue:_valign];
+    [_resp appendContentCharacter:'"'];
+  }
+  if (_colspan) {
+    [_resp appendContentString:@" colspan=\""];
+    [_resp appendContentHTMLAttributeValue:_colspan];
+    [_resp appendContentCharacter:'"'];
+  }
+  [_resp appendContentCharacter:'>'];
+}
+
+static inline void ODRAppendButton(WOResponse *_response,
+                                   NSString   *_name,
+                                   NSString   *_src,
+                                   NSString   *_alt)
+{
+  
+  if (_name == nil) {
+    [_response appendContentHTMLString:(_alt) ? _alt : @"[button]"];
+    return;
+  }
+  [_response appendContentString:@"<input border=\"0\" type=\""];
+  [_response appendContentString:(_src) ? @"image" : @"submit"];
+  [_response appendContentString:@"\" name=\""];
+  [_response appendContentString:_name];
+  [_response appendContentCharacter:'"'];
+  if (_src) {
+    [_response appendContentString:@" src=\""];
+    [_response appendContentString:_src];
+    [_response appendContentCharacter:'"'];
+    // append alt-text
+    if (_alt) {
+      [_response appendContentString:@" alt=\""];
+      [_response appendContentString:_alt];
+      [_response appendContentCharacter:'"'];
+    }
+  }
+  else {
+    [_response appendContentString:@" value=\""];
+    [_response appendContentString:(_alt) ? _alt : @"submit"];
+    [_response appendContentCharacter:'"'];
+  }
+  [_response appendContentString:@" />"];
+}
+
+static inline void ODRAppendImage(WOResponse *_response,
+                                   NSString   *_name,
+                                   NSString   *_src,
+                                   NSString   *_alt)
+{
+  if (_src == nil) {
+    [_response appendContentHTMLString:(_alt) ? _alt : @"[img]"];
+    return;
+  }
+
+  [_response appendContentString:@"<img border=\"0\" src=\""];
+  [_response appendContentString:_src];
+  if (_name) {
+    [_response appendContentString:@"\" name=\""];
+    [_response appendContentString:_name];
+  }
+  [_response appendContentString:@"\" alt=\""];
+  [_response appendContentString:_alt];
+  [_response appendContentString:@"\" />"];
+}
+
+
+static inline NSArray *ODRLookupQueryPath(id _node, NSString *_path) {
+  static Class arrayClass = Nil;
+  id     tmp;
+
+  if (arrayClass == Nil)
+    arrayClass = [NSArray class];
+
+  if (!(tmp = [_node lookupQueryPath:_path]))
+    return nil;
+  
+  return ([tmp isKindOfClass:arrayClass])
+    ? tmp
+    : [arrayClass arrayWithObject:tmp];
+}
+
+static inline NSString *ODRUriOfResource(NSString *_name, WOContext *_ctx) {
+  NSArray           *languages;
+  WOResourceManager *resourceManager;
+  NSString          *uri;
+
+  if (_name == nil)
+    return nil;
+
+  languages = [_ctx hasSession]
+    ? [[_ctx session] languages]
+    : [[_ctx request] browserLanguages];
+
+  if ((resourceManager = [[_ctx component] resourceManager]) == nil)
+    resourceManager = [[_ctx application] resourceManager];
+  
+  uri = [resourceManager urlForResourceNamed:_name
+                         inFramework:nil
+                         languages:languages
+                         request:[_ctx request]];
+  if ([uri rangeOfString:@"/missingresource?"].length > 0)
+    uri = nil;
+  
+  return uri;
+}
+
+#if PROFILE
+#  define BEGIN_PROFILE \
+     { NSTimeInterval __ti = [[NSDate date] timeIntervalSince1970];
+
+#  define END_PROFILE \
+     __ti = [[NSDate date] timeIntervalSince1970] - __ti;\
+     if (__ti > 0.05) \
+       printf("***PROF[%s]: %0.3fs\n", __PRETTY_FUNCTION__, __ti);\
+     else if (__ti > 0.005) \
+       printf("PROF[%s]: %0.3fs\n", __PRETTY_FUNCTION__, __ti);\
+     }
+
+#  define PROFILE_CHECKPOINT(__key__) \
+       printf("---PROF[%s] CP %s: %0.3fs\n", __PRETTY_FUNCTION__, __key__,\
+              [[NSDate date] timeIntervalSince1970] - __ti)
+
+#else
+#  define BEGIN_PROFILE {
+#  define END_PROFILE   }
+#  define PROFILE_CHECKPOINT(__key__)
+#endif
+
+@interface NSObject(AttrNodeNSURI)
+- (id)attributeNode:(NSString *)_name namespaceURI:(NSString *)_nsuri;
+@end
+
+#endif /* __NGObjDOM_common_H__ */
diff --git a/skyrix-sope/NGObjDOM/dummy.m b/skyrix-sope/NGObjDOM/dummy.m
new file mode 100644 (file)
index 0000000..bd0a9dd
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+
+// dummy
diff --git a/skyrix-sope/NGObjDOM/used_privates.h b/skyrix-sope/NGObjDOM/used_privates.h
new file mode 100644 (file)
index 0000000..c3b19af
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __WOContext_Stack_H__
+#define __WOContext_Stack_H__
+
+#import <NGObjWeb/WOContext.h>
+
+@interface WOContext(Stack)
+- (void)enterComponent:(WOComponent *)_component content:(WOElement *)_content;
+- (void)leaveComponent:(WOComponent *)_component;
+@end
+
+#endif /* __WOContext_Stack_H__ */
diff --git a/skyrix-sope/NGObjWeb/.cvsignore b/skyrix-sope/NGObjWeb/.cvsignore
new file mode 100644 (file)
index 0000000..3009a88
--- /dev/null
@@ -0,0 +1,6 @@
+*away
+SoCore.sxp
+SoOFS.sxp
+nohup.out
+shared_debug_obj
+*.patch
diff --git a/skyrix-sope/NGObjWeb/Associations/.cvsignore b/skyrix-sope/NGObjWeb/Associations/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-sope/NGObjWeb/Associations/GNUmakefile b/skyrix-sope/NGObjWeb/Associations/GNUmakefile
new file mode 100644 (file)
index 0000000..0ae0306
--- /dev/null
@@ -0,0 +1,20 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = Associations
+
+Associations_OBJC_FILES = \
+       WOAssociation.m                 \
+       WOValueAssociation.m            \
+       WOKeyPathAssociation.m          \
+       WOKeyPathAssociationSystemKVC.m \
+       WOScriptAssociation.m           \
+       WOResourceURLAssociation.m      \
+       WOLabelAssociation.m            \
+       \
+       NSUserDefaults+KVC.m
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjWeb/Associations/GNUmakefile.preamble b/skyrix-sope/NGObjWeb/Associations/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..0f9aea9
--- /dev/null
@@ -0,0 +1,15 @@
+# $Id$
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..    \
+       -I../../../skyrix-core                  \
+       -I../../../skyrix-core/NGStreams        \
+       -I../../../skyrix-core/NGExtensions     \
+
+ifeq ($(WOAssociationExceptionHandlers),yes)
+ADDITIONAL_CPPFLAGS += -DUSE_EXCEPTION_HANDLERS=1
+endif
+
+ifeq ($(heavydebug),yes)
+ADDITIONAL_CPPFLAGS += -DHEAVY_DEBUG=1
+endif
diff --git a/skyrix-sope/NGObjWeb/Associations/NSUserDefaults+KVC.m b/skyrix-sope/NGObjWeb/Associations/NSUserDefaults+KVC.m
new file mode 100644 (file)
index 0000000..881b6aa
--- /dev/null
@@ -0,0 +1,15 @@
+// $Id$
+
+#import <Foundation/NSUserDefaults.h>
+
+@implementation NSUserDefaults(KeyValueCoding)
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  [self setObject:_value forKey:_key];
+}
+
+- (id)valueForKey:(NSString *)_key {
+  return [self objectForKey:_key];
+}
+
+@end /* NSUserDefaults(KeyValueCoding) */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOAssociation.m b/skyrix-sope/NGObjWeb/Associations/WOAssociation.m
new file mode 100644 (file)
index 0000000..50fcfd7
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOAssociation.h>
+#include "WOValueAssociation.h"
+#include "WOKeyPathAssociation.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOContext.h>
+#include "common.h"
+
+@interface WOContext(Cursor)
+- (id)cursor;
+@end
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY || \
+    COCOA_Foundation_LIBRARY
+@interface NSObject(Missing)
+- (void)subclassResponsibility:(SEL)cmd;
+- (void)notImplemented:(SEL)cmd;
+@end
+#endif
+
+@implementation WOAssociation
+
+static Class WOKeyPathAssociationClass = Nil;
+
++ (int)version {
+  return 2;
+}
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  NSString *s;
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  s = [ud stringForKey:@"WOKeyPathAssociationClass"];
+  if ([s length] > 0) {
+#if DEBUG
+    NSLog(@"Note: using different class for keypath associations: %@", s);
+#endif
+    WOKeyPathAssociationClass = NSClassFromString(s);
+  }
+  if (WOKeyPathAssociationClass == Nil)
+    WOKeyPathAssociationClass = [WOKeyPathAssociation class];
+}
+
++ (WOAssociation *)associationWithKeyPath:(NSString *)_keyPath {
+  static int WOCacheKeyPathAssociations = -1;
+  static NSMapTable *cache = NULL;
+  static unsigned cacheHits   = 0;
+  static unsigned cacheMisses = 0;
+  WOAssociation *a;
+  
+  if (WOCacheKeyPathAssociations == -1) {
+    WOCacheKeyPathAssociations =
+      [[[NSUserDefaults standardUserDefaults]
+                        objectForKey:@"WOKeyPathAssociationsCacheSize"]
+                        intValue];
+    if (WOCacheKeyPathAssociations > 0) {
+      cache = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                               NSObjectMapValueCallBacks,
+                               WOCacheKeyPathAssociations);
+    }
+  }
+
+  if (cache) {
+    if ((a = NSMapGet(cache, _keyPath))) {
+      cacheHits++;
+#if 0 && DEBUG
+      printf("%s: cache hits: %d, misses: %d, size:%d\n",
+             __PRETTY_FUNCTION__,
+             cacheHits, cacheMisses, NSCountMapTable(cache));
+#endif
+      return [[a retain] autorelease];
+    }
+    
+    cacheMisses++;
+    
+    if (cacheMisses > 1000) {
+      if (cacheHits < cacheMisses) {
+        fprintf(stderr,
+                "%s: disabling association cache "
+                "(%d cache misses vs %d cache hits)\n",
+                __PRETTY_FUNCTION__, cacheMisses, cacheHits);
+        if (cache) NSFreeMapTable(cache);
+        cache = NULL;
+      }
+    }
+  }
+  
+  a = [[WOKeyPathAssociationClass alloc] initWithKeyPath:_keyPath];
+  
+  if (cache)
+    NSMapInsert(cache, _keyPath, a);
+  
+  return [a autorelease];
+}
++ (WOAssociation *)associationWithValue:(id)_value {
+  static int        WOCacheValueAssociations   = -1;
+  static NSMapTable *cache = NULL;
+  static unsigned   cacheHits   = 0;
+  static unsigned   cacheMisses = 0;
+  static NSNumber   *boolYes    = nil;
+  static NSNumber   *boolNo     = nil;
+  WOAssociation *a;
+  
+  if (_value == nil) return nil;
+  
+  if (boolYes == nil)
+    boolYes = [[NSNumber numberWithBool:YES] retain];
+  if (boolNo == nil)
+    boolNo = [[NSNumber numberWithBool:NO] retain];
+  
+  if (boolYes == _value) {
+    static WOAssociation *yesAssoc = nil;
+    
+    if (yesAssoc == nil)
+      yesAssoc = [[_WOBoolValueAssociation associationWithBool:YES] retain];
+    
+    return yesAssoc;
+  }
+  if (boolNo == _value) {
+    static WOAssociation *noAssoc = nil;
+    
+    if (noAssoc == nil)
+      noAssoc = [[_WOBoolValueAssociation associationWithBool:NO] retain];
+    
+    return noAssoc;
+  }
+  
+  if (![_value conformsToProtocol:@protocol(NSCopying)])
+    /* if the value can't be copied, it shouldn't be cached ! */
+    return [WOValueAssociation associationWithValue:_value];
+  
+  _value = [[_value copyWithZone:NULL] autorelease];
+  
+  if (WOCacheValueAssociations == -1) {
+    WOCacheValueAssociations =
+      [[[NSUserDefaults standardUserDefaults]
+                        objectForKey:@"WOValueAssociationsCacheSize"]
+                        intValue];
+    if (WOCacheValueAssociations > 0) {
+      cache = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                               NSObjectMapValueCallBacks,
+                               WOCacheValueAssociations);
+    }
+  }
+
+  if (cache) {
+    if ((a = NSMapGet(cache, _value))) {
+      cacheHits++;
+#if 0 && DEBUG
+      printf("%s: cache hits: %d, misses: %d, size:%d\n",
+             __PRETTY_FUNCTION__,
+             cacheHits, cacheMisses, NSCountMapTable(cache));
+#endif
+      return [[a retain] autorelease];
+    }
+    
+    cacheMisses++;
+    
+    if (cacheMisses > 1000) {
+      if (cacheHits < cacheMisses) {
+        fprintf(stderr,
+                "%s: disabling association cache "
+                "(%d cache misses vs %d cache hits)",
+                __PRETTY_FUNCTION__, cacheMisses, cacheHits);
+        if (cache) NSFreeMapTable(cache);
+        cache = NULL;
+      }
+    }
+  }
+  
+  a = [WOValueAssociation associationWithValue:_value];
+  
+  if (cache != NULL)
+    NSMapInsert(cache, _value, a);
+  
+  return a;
+}
+
+/* value */
+
+- (void)setValue:(id)_value {
+  IS_DEPRECATED;
+  [self setValue:_value
+        inComponent:[[[WOApplication application] context] component]];
+}
+- (id)value {
+  IS_DEPRECATED;
+  return [self valueInComponent:
+                 [[[WOApplication application] context] component]];
+}
+
+- (void)setValue:(id)_value inComponent:(WOComponent *)_component {
+  [self subclassResponsibility:_cmd];
+}
+- (id)valueInComponent:(WOComponent *)_component {
+  [self subclassResponsibility:_cmd];
+  return nil;
+}
+
+- (void)setValue:(id)_value inContext:(WOContext *)_ctx {
+  [self setValue:_value inComponent:(id)[_ctx cursor]];
+}
+- (id)valueInContext:(WOContext *)_ctx {
+  return [self valueInComponent:(id)[_ctx cursor]];
+}
+
+- (BOOL)isValueConstant {
+  [self subclassResponsibility:_cmd];
+  return NO;
+}
+- (BOOL)isValueSettable {
+  [self subclassResponsibility:_cmd];
+  return NO;
+}
+
+// convenience methods
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<WOAssociation[0x%08X]>", self];
+}
+
+@end /* WOAssociation */
+
+@implementation WOAssociation(SpecialsValues)
+
+/* special values */
+
+- (void)setUnsignedCharValue:(unsigned char)_v inComponent:(WOComponent *)_c {
+  [self setValue:[NSNumber numberWithUnsignedChar:_v] inComponent:_c];
+}
+- (void)setCharValue:(char)_value inComponent:(WOComponent *)_component {
+  [self setValue:[NSNumber numberWithChar:_value] inComponent:_component];
+}
+- (void)setUnsignedIntValue:(unsigned int)_v inComponent:(WOComponent *)_c {
+  [self setValue:[NSNumber numberWithUnsignedInt:_v] inComponent:_c];
+}
+- (void)setIntValue:(int)_value inComponent:(WOComponent *)_component {
+  [self setValue:[NSNumber numberWithInt:_value] inComponent:_component];
+}
+- (void)setBoolValue:(BOOL)_value inComponent:(WOComponent *)_component {
+  [self setValue:[NSNumber numberWithBool:_value] inComponent:_component];
+}
+
+- (unsigned char)unsignedCharValueInComponent:(WOComponent *)_component {
+  return [[self valueInComponent:_component] unsignedCharValue];
+}
+- (char)charValueInComponent:(WOComponent *)_component {
+  return [[self valueInComponent:_component] charValue];
+}
+- (unsigned int)unsignedIntValueInComponent:(WOComponent *)_component {
+  return [[self valueInComponent:_component] unsignedIntValue];
+}
+- (int)intValueInComponent:(WOComponent *)_component {
+  return [[self valueInComponent:_component] intValue];
+}
+- (BOOL)boolValueInComponent:(WOComponent *)_component {
+  return [[self valueInComponent:_component] boolValue];
+}
+
+- (void)setStringValue:(NSString *)_v inComponent:(WOComponent *)_component {
+  [self setValue:_v inComponent:_component];
+}
+- (NSString *)stringValueInComponent:(WOComponent *)_component {
+  return [[self valueInComponent:_component] stringValue];
+}
+
+/* special context values */
+
+- (void)setUnsignedCharValue:(unsigned char)_v inContext:(WOContext *)_c {
+  [self setUnsignedCharValue:_v inComponent:(id)[_c cursor]];
+}
+- (void)setCharValue:(char)_value inContext:(WOContext *)_ctx {
+  [self setCharValue:_value inComponent:(id)[_ctx cursor]];
+}
+- (void)setUnsignedIntValue:(unsigned int)_v inContext:(WOContext *)_c {
+  [self setUnsignedIntValue:_v inComponent:(id)[_c cursor]];
+}
+- (void)setIntValue:(int)_value inContext:(WOContext *)_ctx {
+  [self setIntValue:_value inComponent:(id)[_ctx cursor]];
+}
+- (void)setBoolValue:(BOOL)_value inContext:(WOContext *)_ctx {
+  [self setBoolValue:_value inComponent:(id)[_ctx cursor]];
+}
+
+- (unsigned char)unsignedCharValueInContext:(WOContext *)_ctx {
+  return [self unsignedCharValueInComponent:[_ctx cursor]];
+}
+- (char)charValueInContext:(WOContext *)_ctx {
+  return [self charValueInComponent:[_ctx cursor]];
+}
+- (unsigned int)unsignedIntValueInContext:(WOContext *)_ctx {
+  return [self unsignedIntValueInComponent:[_ctx cursor]];
+}
+- (int)intValueInContext:(WOContext *)_ctx {
+  return [self intValueInComponent:[_ctx cursor]];
+}
+- (BOOL)boolValueInContext:(WOContext *)_ctx {
+  return [self boolValueInComponent:[_ctx cursor]];
+}
+
+- (void)setStringValue:(NSString *)_v inContext:(WOContext *)_ctx {
+  [self setValue:_v inComponent:[_ctx cursor]];
+}
+- (NSString *)stringValueInContext:(WOContext *)_ctx {
+  return [[self valueInComponent:(id)[_ctx cursor]] stringValue];
+}
+
+/* copying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  // WOAssociations are immutable
+  return RETAIN(self);
+}
+
+@end /* WOAssociation(SpecialsValues) */
+
+@implementation WOAssociation(BugTrap)
+
+- (unsigned int)unsignedIntValue {
+  [self notImplemented:_cmd];
+  return 0;
+}
+- (int)intValue {
+  [self notImplemented:_cmd];
+  return 0;
+}
+- (float)floatValue {
+  [self notImplemented:_cmd];
+  return 0.0;
+}
+- (BOOL)boolValue {
+  [self notImplemented:_cmd];
+  return NO;
+}
+
+- (NSString *)stringValue {
+  [self notImplemented:_cmd];
+  return nil;
+}
+
+@end /* WOAssociation(BugTrap) */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOKeyPathAssociation.h b/skyrix-sope/NGObjWeb/Associations/WOKeyPathAssociation.h
new file mode 100644 (file)
index 0000000..7000acd
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOKeyPathAssociation_H__
+#define __NGObjWeb_WOKeyPathAssociation_H__
+
+#include <NGObjWeb/WOAssociation.h>
+
+@class NSString;
+
+@interface WOKeyPathAssociation : WOAssociation < NSCoding, NSCopying >
+{
+@private
+  void          *keyPath;
+  unsigned char size;
+}
+
+- (id)initWithKeyPath:(NSString *)_keyPath;
+
+/* accessors */
+
+- (NSString *)keyPath;
+
+/* value */
+
+- (BOOL)isValueConstant; // returns NO
+- (BOOL)isValueSettable;
+
+@end
+
+#endif /* __NGObjWeb_WOKeyPathAssociation_H__ */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOKeyPathAssociation.m b/skyrix-sope/NGObjWeb/Associations/WOKeyPathAssociation.m
new file mode 100644 (file)
index 0000000..d08cd24
--- /dev/null
@@ -0,0 +1,1334 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOKeyPathAssociation.h"
+#include <NGObjWeb/WOComponent.h>
+#include "NSObject+WO.h"
+#include "common.h"
+
+#if LIB_FOUNDATION_BOEHM_GC
+#  if LIB_FOUNDATION_LIBRARY
+#    include <extensions/GarbageCollector.h>
+#  else
+#    error no BoehmGC support on this Foundation!
+#  endif
+#endif
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+#  include <objc/objc.h>
+#  include <objc/objc-api.h>
+#  include <objc/objc-class.h>
+
+#  define METHOD_NULL NULL
+#  define object_is_instance(XXX) \
+     ((XXX != nil) && CLS_ISCLASS(*((Class *)XXX)))
+#  define sel_get_uid               sel_getUid
+#  define class_get_class_method    class_getClassMethod
+#  define class_get_instance_method class_getInstanceMethod
+
+#  define __CLS_INFO(cls)         ((cls)->info)
+#  ifndef __CLS_ISINFO
+#    define __CLS_ISINFO(cls, mask) ((__CLS_INFO(cls) & mask) == mask)
+#  endif
+#  ifndef CLS_ISCLASS
+#    define CLS_ISCLASS(cls) ((cls) && __CLS_ISINFO(cls, CLS_CLASS))
+#  endif
+#endif
+
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
+    APPLE_FOUNDATION_LIBRARY
+bool _CFDictionaryIsMutable(CFDictionaryRef dict);
+#endif
+
+
+/*
+  WOKeyPathAssociation
+
+  This is an association class for so called keypaths. It uses extensive 
+  caching to reuse calculated method pointers.
+
+  Note the -kvcIsPreferredInKeyPath method. It is used whether -valueForKey: 
+  and -takeValue:forKey: has preference or the objects methods. In usual cases
+  it can be assumed that -valueForKey has the preference, but not in the case 
+  of
+
+    WOSession, WOComponent, WOApplication, WOContext
+
+  which use -valueForKey: as a fallback. Since -valueForKey: is defined as a
+  category on NSObject it eliminates the caching scheme used.
+*/
+
+#if DEBUG
+// #define HEAVY_DEBUG 1
+// #define USE_EXCEPTION_HANDLERS 1
+#endif
+
+#if USE_EXCEPTION_HANDLERS
+#  warning using local exception handlers in associations, slows down templates
+#endif
+
+typedef enum {
+  WOKeyType_unknown = 0,
+  WOKeyType_kvc     = 1,
+  WOKeyType_method  = 2,
+  WOKeyType_ivar    = 3,
+  WOKeyType_binding = 4
+} WOKeyType;
+
+typedef union {
+  void           *ivar;
+  IMP            method; // real method or takeValue:ForKey:
+  char           (*cmethod) (id, SEL);
+  unsigned char  (*ucmethod)(id, SEL);
+  int            (*imethod) (id, SEL);
+  unsigned int   (*uimethod)(id, SEL);
+  short          (*smethod) (id, SEL);
+  unsigned short (*usmethod)(id, SEL);
+  const char *   (*strmethod)(id, SEL);
+  float          (*fmethod)(id, SEL);
+  double         (*dmethod)(id, SEL);
+} WOGetMethodType;
+
+typedef union {
+  IMP  method; // real method or takeValue:ForKey:
+  void (*omethod)  (id, SEL, id);
+  void (*cmethod)  (id, SEL, char);
+  void (*ucmethod) (id, SEL, unsigned char);
+  void (*imethod)  (id, SEL, int);
+  void (*uimethod) (id, SEL, unsigned int);
+  void (*smethod)  (id, SEL, short);
+  void (*usmethod) (id, SEL, unsigned short);
+  void (*strmethod)(id, SEL, const char *);
+  void (*fmethod)  (id, SEL, float);
+  void (*dmethod)  (id, SEL, double);
+} WOSetMethodType;
+
+typedef struct {
+  char            *ckey;
+  short           keyLen:12;
+  short           isFault:1;
+  WOKeyType       type:3;
+  id              object;
+  Class           isa;
+  WOGetMethodType access;
+  union {
+    NSString *key; // for valueForKey:
+    struct {
+      SEL get; // get method selector
+    } sel;
+  } extra;
+  unsigned char retType;
+} WOKeyPathComponent;
+
+typedef union {
+  id             object;
+  const char     *cstr;
+  int            sint;
+  unsigned int   uint;
+  short          ss;
+  unsigned short us;
+  unsigned char  c;
+  float          flt;
+  double         dbl;
+} WOReturnValueHolder;
+
+#define intNumObj(__VAL__) \
+  (__VAL__==0?inum0:(__VAL__==1?inum1:[NumberClass numberWithInt:__VAL__]))
+
+#define uintNumObj(__VAL__) \
+  (__VAL__ ==0 ? uinum0 : \
+  (__VAL__==1?uinum1:[NumberClass numberWithUnsignedInt:__VAL__]))
+
+@implementation WOKeyPathAssociation
+
++ (int)version {
+  return 2;
+}
+
+static Class NumberClass = Nil;
+static Class StringClass = Nil;
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
+    APPLE_FOUNDATION_LIBRARY
+static Class NSCFDictionaryClass = Nil;
+#endif
+static int debugOn = -1;
+
+#define IS_NUMSTR(__VAL__)  (__VAL__>=0 && __VAL__<50)
+#define IS_UNUMSTR(__VAL__) (__VAL__<50)
+static NSString *numStrings[] = {
+  @"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9",
+  @"10", @"11", @"12", @"13", @"14", @"15", @"16", @"17", @"18", @"19",
+  @"20", @"21", @"22", @"23", @"24", @"25", @"26", @"27", @"28", @"29",
+  @"30", @"31", @"32", @"33", @"34", @"35", @"36", @"37", @"38", @"39",
+  @"40", @"41", @"42", @"43", @"44", @"45", @"46", @"47", @"48", @"49"
+};
+static NSNumber *inum0  = nil, *inum1  = nil;
+static NSNumber *uinum0 = nil, *uinum1 = nil;
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+
+  if (isInitialized) return;
+  isInitialized = YES;
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+
+  
+  debugOn = [[[NSUserDefaults standardUserDefaults]
+                              objectForKey:@"WODebugKeyPathAssociation"]
+                              boolValue] ? 1 : 0;
+  
+  NumberClass = [NSNumber class];
+  StringClass = [NSString class];
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
+    APPLE_FOUNDATION_LIBRARY
+  NSCFDictionaryClass = NSClassFromString(@"NSCFDictionary");
+#endif
+
+  inum0  = [[NumberClass numberWithInt:0] retain];
+  inum1  = [[NumberClass numberWithInt:1] retain];
+  uinum0 = [[NumberClass numberWithUnsignedInt:0] retain];
+  uinum1 = [[NumberClass numberWithUnsignedInt:1] retain];
+}
+
+static inline WOKeyPathComponent *
+_getComponent(register WOKeyPathAssociation *self, register unsigned _idx)
+{
+  return (WOKeyPathComponent *)
+    (self->keyPath + (_idx * sizeof(WOKeyPathComponent)));
+}
+
+static inline void _freeKeyPathComponent(WOKeyPathComponent *info) {
+  if (info->ckey) {
+    free(info->ckey);
+    info->ckey = NULL;
+  }
+  if ((info->type == WOKeyType_kvc) || (info->type == WOKeyType_binding)) {
+    [info->extra.key release];
+    info->extra.key = nil;
+  }
+  info->object = nil;
+  info->isa    = Nil;
+}
+
+static inline void
+_parseKeyPath(WOKeyPathAssociation *self,NSString *_keyPath)
+{
+  unsigned keyLen = [_keyPath cStringLength];
+  char *buf;
+  char *cstr;
+  char *tmp;
+
+  buf = malloc(keyLen + 1);
+  cstr = buf;
+  tmp = (char *)cstr;
+  [_keyPath getCString:buf]; buf[keyLen] = '\0';
+  
+  // get number of components
+  self->size = 1;
+  while (*tmp) {
+    if (*tmp == '.') (self->size)++;
+    tmp++;
+  }
+  
+  self->keyPath = calloc(self->size, sizeof(WOKeyPathComponent));
+  
+  // transfer components
+  {
+    unsigned char pos;
+
+    tmp = (char *)cstr;
+    for (pos = 0; pos < self->size; pos++) {
+      WOKeyPathComponent *info = _getComponent(self, pos);
+      
+      // goto end or next '.'
+      while ((*tmp != '\0') && (*tmp != '.'))
+        tmp++;
+      
+      info->keyLen = (tmp - cstr);
+      info->ckey   = malloc(info->keyLen + 4);
+      memcpy(info->ckey, cstr, info->keyLen);
+      info->ckey[info->keyLen] = '\0';
+
+      NSCAssert(strlen(info->ckey) > 0, @"invalid ckey ..");
+      NSCAssert((int)strlen(info->ckey) == (int)info->keyLen, 
+                @"size and content differ");
+      
+      info->object = nil;
+      info->isa    = Nil;
+      info->type   = WOKeyType_unknown;
+      
+      cstr = tmp + 1;
+      tmp  = (char *)cstr;
+    }
+  }
+  free(buf);
+}
+  
+- (id)initWithKeyPath:(NSString *)_keyPath {
+  if ([_keyPath length] < 1) {
+    self = [self autorelease];
+    self = nil;
+    NSLog(@"ERROR: passed invalid keypath (%@) to association !", _keyPath);
+    return nil;
+  }
+  if ((self = [super init])) {
+    _parseKeyPath(self, _keyPath);
+  }
+  return self;
+}
+- (id)init {
+  NSLog(@"keypaths can not be created using 'init' ..");
+  [NSException raise:@"InvalidUseOfMethodException"
+               format:@"keypaths can not be created using 'init'"];
+  return nil;
+}
+
+- (void)dealloc {
+  if (self->keyPath) {
+    int cnt;
+    
+    for (cnt = 0; cnt < self->size; cnt++)
+      _freeKeyPathComponent(_getComponent(self, cnt));
+    
+    free(self->keyPath);
+  }
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)keyPath {
+  register unsigned char pos;
+  char     *buffer;
+  unsigned len;
+
+  // get size
+  len = self->size; // size-1 '.' chars and the '\0' char
+  for (pos = 0; pos < self->size; pos++) {
+    WOKeyPathComponent *info = _getComponent(self, pos);
+    len += info->keyLen;
+  }
+  buffer = malloc(len + 4);
+  
+  // transfer contents
+  for (pos = 0, len = 0; pos < self->size; pos++) {
+    WOKeyPathComponent *info = _getComponent(self, pos);
+
+    if (pos != 0) {
+      buffer[len] = '.';
+      len++;
+    }
+    memcpy(&(buffer[len]), info->ckey, info->keyLen);
+    len += info->keyLen;
+  }
+  buffer[len] = '\0';
+
+  return [[[StringClass alloc] initWithCStringNoCopy:buffer
+                              length:len
+                              freeWhenDone:YES]
+                              autorelease];
+}
+- (id)initWithString:(NSString *)_s {
+  return [self initWithKeyPath:_s];
+}
+
+/* value */
+
+static inline void _fillInfo(WOKeyPathAssociation *self, id object,
+                             WOKeyPathComponent *info) 
+{
+  Class clazz      = [object class];
+  BOOL  needRefill = NO;
+  
+  if (info->isFault)
+    needRefill = YES;
+  else if (info->type == WOKeyType_unknown) // first invocation of 'value'
+    needRefill = YES;
+  else if ((info->object == nil) || (object == nil))
+    needRefill = YES;
+  else if (info->isa != clazz)
+    needRefill = YES;
+  else if (info->object != object)
+    needRefill = YES;
+  
+  if (!needRefill)
+    // object is the same, can use cached representation
+    return;
+
+  {
+#if NeXT_RUNTIME
+    struct objc_method *method = NULL;
+#else
+    Method_t method = METHOD_NULL;
+#endif
+    
+    if ((info->type == WOKeyType_kvc) || (info->type == WOKeyType_binding)) {
+      /* release old key */
+      [info->extra.key release];
+      info->extra.key = nil;
+    }
+    
+    info->type    = WOKeyType_unknown;
+    info->retType = _C_ID;
+    
+    if (*(info->ckey) == '^') { /* a binding key */
+      method = class_get_instance_method(clazz, @selector(valueForBinding:));
+      info->type = WOKeyType_binding;
+      info->extra.key =
+        [[StringClass alloc] initWithCString:(info->ckey + 1)];
+    }
+    else {
+      if (object) {
+        if (object_is_instance(object)) {
+          if ([object kvcIsPreferredInKeyPath]) {
+            method = class_get_instance_method(clazz, @selector(valueForKey:));
+            
+            if (method != METHOD_NULL) {
+              info->type      = WOKeyType_kvc;
+              info->extra.key = 
+               [[StringClass alloc] initWithCString:info->ckey];
+            }
+            else {
+              info->extra.sel.get = sel_get_uid(info->ckey);
+              method = class_get_instance_method(clazz, info->extra.sel.get);
+              if (method != METHOD_NULL)
+                info->type = WOKeyType_method;
+            }
+          }
+          else {
+            info->extra.sel.get = sel_get_uid(info->ckey);
+            method = class_get_instance_method(clazz, info->extra.sel.get);
+            
+            if (method != METHOD_NULL)
+              info->type = WOKeyType_method;
+            else {
+              method =
+                class_get_instance_method(clazz, @selector(valueForKey:));
+              if (method != METHOD_NULL) {
+                info->type      = WOKeyType_kvc;
+                info->extra.key = 
+                 [[StringClass alloc] initWithCString:info->ckey];
+              }
+            }
+          }
+        }
+        else { /* object is a class */
+          method = class_get_class_method(object, @selector(valueForKey:));
+          if (method != METHOD_NULL) {
+            info->type      = WOKeyType_kvc;
+            info->extra.key = [[StringClass alloc] initWithCString:info->ckey];
+          }
+          else {
+            info->extra.sel.get = sel_get_uid(info->ckey);
+            method =
+              class_get_class_method(*(Class *)object, info->extra.sel.get);
+            if (method != METHOD_NULL) {
+              info->type = WOKeyType_method;
+            }
+          }
+        }
+      }
+    }
+    info->object  = object;
+    info->isa     = [object class];
+    info->isFault = [object isFault];
+    
+    if (method != METHOD_NULL) {
+#if NeXT_RUNTIME
+      info->access.method = method->method_imp;
+#else
+      info->access.method = method_get_imp(method);
+#endif
+      info->retType = *(method->method_types);
+    }
+
+#if HEAVY_DEBUG
+    NSLog(@"type is %i, key is '%s'", info->type, info->ckey);
+#endif
+  }
+}
+
+- (NSException *)handleGetException:(NSException *)_exception  {
+  static NSString *excKey    = @"exception";
+  static NSString *kpKey     = @"keyPath";
+  static NSString *assocKey  = @"association";
+  static NSString *excName   = @"WOKeyPathException";
+  static NSString *excReason = @"couldn't get value for a keypath component";
+  NSException  *e;
+  NSDictionary *ui;
+  
+  ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                       _exception,     excKey,
+                       [self keyPath], kpKey,
+                       self,           assocKey,
+                     nil];
+  
+  e = [[NSException alloc] initWithName:excName
+                           reason:excReason
+                           userInfo:ui];
+  return e;
+}
+
+static WOReturnValueHolder _getComponentValue(WOKeyPathAssociation *self,
+                                              id object,
+                                              WOKeyPathComponent *info)
+{
+  WOReturnValueHolder retValue;
+  
+#if DEBUG
+  NSCAssert1(info, @"%s: missing info !", __PRETTY_FUNCTION__);
+#endif
+  
+  _fillInfo(self, object, info);
+  
+  // execute
+  if (info->type == WOKeyType_method) {
+#if HEAVY_DEBUG
+    NSLog(@"get key %s of keyPath %@\n"
+         @"  from: 0x%08X[%@]\n"
+         @"  via method (ret %c)", 
+         info->ckey, [self keyPath], object, 
+         NSStringFromClass([object class]), info->retType);
+#endif
+#if USE_EXCEPTION_HANDLERS
+    NS_DURING {
+#endif
+      if ((info->retType == _C_ID) || (info->retType == _C_CLASS)) {
+        retValue.object = info->access.method(object, info->extra.sel.get);
+#if HEAVY_DEBUG
+       NSLog(@"  got result 0x%08X[%@]: %@", retValue.object,
+             NSStringFromClass([retValue.object class]),
+             retValue.object);
+#endif
+      }
+      else {
+        switch (info->retType) {
+          case _C_ID:
+          case _C_CLASS:
+            retValue.object = info->access.method(object, info->extra.sel.get);
+            break;
+          case _C_VOID:
+            retValue.object = object;
+            break;
+            
+          case _C_CHR:
+          case _C_UCHR:
+            retValue.c = info->access.ucmethod(object, info->extra.sel.get);
+            break;
+          
+          case _C_INT:
+            retValue.sint = info->access.imethod(object, info->extra.sel.get);
+            break;
+          case _C_UINT:
+            retValue.uint = info->access.uimethod(object, info->extra.sel.get);
+            break;
+
+          case _C_SHT:
+            retValue.ss = info->access.smethod(object, info->extra.sel.get);
+            break;
+          case _C_USHT:
+            retValue.us = info->access.usmethod(object, info->extra.sel.get);
+            break;
+
+          case _C_FLT:
+            retValue.flt = info->access.fmethod(object, info->extra.sel.get);
+            break;
+        
+          case _C_DBL:
+            retValue.dbl = info->access.dmethod(object, info->extra.sel.get);
+            break;
+
+          case _C_CHARPTR:
+            retValue.cstr = info->access.strmethod(object, info->extra.sel.get);
+            break;
+
+          default:
+            NSLog(@"%@: unsupported type '%c' !", self, info->retType);
+            [NSException raise:@"WORuntimeException"
+                         format:
+                         @"in WOKeyPathAssociation %@: unsupported type '%c'",
+                         self, info->retType];
+            break;
+        }
+      }
+#if USE_EXCEPTION_HANDLERS
+    }
+    NS_HANDLER
+      [[self handleGetException:localException] raise];
+    NS_ENDHANDLER;
+#endif
+  }
+  else if (info->type == WOKeyType_kvc) {
+#if HEAVY_DEBUG
+    NSLog(@"get keyPath %@ from %@ via KVC", [self keyPath], object);
+#endif
+#if 0
+    NSLog(@"ckey:      %s", info->ckey);
+    NSLog(@"key-class: %s", (*(Class *)info->extra.key)->name);
+    NSLog(@"key:       %@", info->extra.key);
+#endif
+
+#if LIB_FOUNDATION_BOEHM_GC
+    [GarbageCollector collectGarbages];
+#endif
+    
+    retValue.object =
+      info->access.method(object, @selector(valueForKey:), info->extra.key);
+  }
+  else if (info->type == WOKeyType_binding) {
+#if HEAVY_DEBUG
+    NSLog(@"get keyPath %@ from %@ via binding", [self keyPath], object);
+#endif
+    
+    retValue.object =
+      info->access.method(object, @selector(valueForBinding:), info->extra.key);
+  }
+  else { // unknown || ivar
+#if HEAVY_DEBUG
+    NSLog(@"unknown info type for keyPath %@ from %@ !!",
+          [self keyPath], object);
+#endif
+    retValue.object = nil;
+  }
+
+  return retValue;
+}
+
+static inline id _objectify(unsigned char _type, WOReturnValueHolder *_value) {
+  id result = nil;
+
+  //NSLog(@"shall convert value of type '%c'", _type);
+  
+  switch (_type) {
+    case _C_ID:
+    case _C_CLASS:
+      result = _value->object;
+      break;
+      
+    case _C_VOID:
+      result = _value->object;
+      break;
+      
+    case _C_CHR:
+    case _C_UCHR:
+      result = [NumberClass numberWithUnsignedChar:_value->c];
+      break;
+      
+    case _C_INT:
+      result = intNumObj(_value->sint);
+      break;
+    case _C_UINT:
+      result = uintNumObj(_value->uint);
+      break;
+    case _C_SHT:
+      result = [NumberClass numberWithShort:_value->ss];
+      break;
+    case _C_USHT:
+      result = [NumberClass numberWithUnsignedShort:_value->us];
+      break;
+    case _C_FLT:
+      result = [NumberClass numberWithFloat:_value->flt];
+      break;
+    case _C_DBL:
+      result = [NumberClass numberWithDouble:_value->dbl];
+      break;
+
+    case _C_CHARPTR:
+      result = _value->cstr
+        ? [StringClass stringWithCString:_value->cstr]
+        : nil;
+      break;
+            
+    default:
+      NSLog(@"unsupported type '%c' !", _type);
+      [NSException raise:@"WORuntimeException"
+                   format:@"in WOKeyPathAssociation: unsupported type '%c'",
+                     _type];
+      break;
+  }
+
+  //NSLog(@"made %@[0x%08X].", NSStringFromClass([result class]), result);
+  
+  return result;
+}
+
+static inline id
+_getValueN(WOKeyPathAssociation *self, unsigned _count, id root)
+{
+  register unsigned cnt;
+  id object = root;
+
+  for (cnt = 0; (cnt < _count) && (object != nil); cnt++) {
+    WOKeyPathComponent  *info;
+    WOReturnValueHolder retValue;
+    
+    info     = _getComponent(self, cnt);
+#if DEBUG
+    NSCAssert1(info, @"%s: missing info !", __PRETTY_FUNCTION__);
+#endif
+    retValue = _getComponentValue(self, object, info);
+    
+    object = (info->type == WOKeyType_method)
+      ? _objectify(info->retType, &retValue)
+      : retValue.object;
+  }
+
+  //NSLog(@"object %@ for keyPath %@", object, [self keyPath]);
+
+  return object;
+}
+
+static inline id _getValue(WOKeyPathAssociation *self, id root) {
+  return _getValueN(self, self->size, root);
+}
+
+static id _getOneValue(WOKeyPathAssociation *self, id root) {
+  WOKeyPathComponent  *info;
+  WOReturnValueHolder retValue;
+
+  info     = (WOKeyPathComponent *)self->keyPath;
+  retValue = _getComponentValue(self, root, info);
+  
+  return (info->type == WOKeyType_method)
+    ? _objectify(info->retType, &retValue)
+    : retValue.object;
+}
+
+static inline void _getSetSelName(register unsigned char *buf,
+                                  register const unsigned char *_key,
+                                  register unsigned _len) {
+  buf[0] = 's';
+  buf[1] = 'e';
+  buf[2] = 't';
+
+  switch (_len) {
+    case 0: break;
+
+    case 1:
+      buf[3] = _key[0];
+      break;
+    case 2:
+      buf[3] = _key[0]; buf[4] = _key[1];
+      break;
+    case 3:
+      buf[3] = _key[0]; buf[4] = _key[1]; buf[5] = _key[2];
+      break;
+    case 4:
+      buf[3] = _key[0]; buf[4] = _key[1]; buf[5] = _key[2];
+      buf[6] = _key[3]; break;
+    case 5:
+      buf[3] = _key[0]; buf[4] = _key[1]; buf[5] = _key[2];
+      buf[6] = _key[3]; buf[7] = _key[4];
+      break;
+    case 6:
+      buf[3] = _key[0]; buf[4] = _key[1]; buf[5] = _key[2];
+      buf[6] = _key[3]; buf[7] = _key[4]; buf[8] = _key[5];
+      break;
+      
+    default:
+      memcpy(&(buf[3]), _key, _len);
+      break;
+  }
+  buf[3] = toupper(buf[3]);
+  buf[_len + 3] = ':';
+  buf[_len + 4] = '\0';
+}
+static inline SEL _getSetSel(register const unsigned char *_key,
+                             register unsigned _len) {
+  char buf[259];
+  _getSetSelName(buf, _key, _len);
+  return sel_get_uid(buf);
+}
+
+static BOOL _setValue(WOKeyPathAssociation *self, id _value, id root) {
+  WOKeyPathComponent *info;
+  id object = root;
+  
+  if (self->size > 1)
+    object = _getValueN(self, self->size - 1, root);
+
+  if (object == nil) // nothing to set ..
+    return YES; // receiver == nil isn't an error condition
+
+  info = _getComponent(self, self->size - 1);
+  NSCAssert(info->keyLen < 255, @"keysize to big ..");
+
+  _fillInfo(self, object, info);
+  
+  if (info->type == WOKeyType_method) { // determine set-selector
+    SEL setSel = _getSetSel(info->ckey, info->keyLen);
+      
+    if (![object respondsToSelector:setSel]) {
+#if 0
+      NSLog(@"%@: Could not set value for key '%s', "
+            @"object %@ doesn't respond to %@.",
+            self, info->ckey, object,
+            setSel ? NSStringFromSelector(setSel) : @"<NULL>");
+#endif
+      return NO;
+    }
+    else {
+      WOSetMethodType sm;
+
+      if ((sm.method = [object methodForSelector:setSel])) {
+        switch (info->retType) {
+          case _C_CLASS:
+          case _C_ID:
+            sm.omethod(object, setSel, _value);
+            break;
+
+          case _C_CHR:
+            sm.cmethod(object, setSel, [_value charValue]);
+            break;
+          case _C_UCHR:
+            sm.ucmethod(object, setSel, [_value unsignedCharValue]);
+            break;
+
+          case _C_SHT:
+            sm.smethod(object, setSel, [_value shortValue]);
+            break;
+          case _C_USHT:
+            sm.usmethod(object, setSel, [_value unsignedShortValue]);
+            break;
+            
+          case _C_INT:
+            sm.imethod(object, setSel, [_value intValue]);
+            break;
+          case _C_UINT:
+            sm.uimethod(object, setSel, [_value unsignedIntValue]);
+            break;
+
+          case _C_FLT:
+            sm.fmethod(object, setSel, [_value floatValue]);
+            break;
+        
+          case _C_DBL:
+            sm.dmethod(object, setSel, [_value doubleValue]);
+            break;
+
+          case _C_CHARPTR:
+            if (_value == nil)
+              sm.strmethod(object, setSel, NULL);
+            else {
+              unsigned clen;
+              if ((clen = [_value cStringLength]) == 0)
+                sm.strmethod(object, setSel, "");
+              else {
+                unsigned char *buf;
+                buf = malloc(clen + 4);
+                [_value getCString:buf]; buf[clen] = '\0';
+                sm.strmethod(object, setSel, buf);
+               if (buf) free(buf);
+              }
+            }
+            break;
+            
+          default:
+            NSLog(@"%@: cannot set type '%c' yet (key=%s, method=%@) ..",
+                  self, info->retType, info->ckey,
+                  NSStringFromSelector(setSel));
+            [NSException raise:@"WORuntimeException"
+                         format:
+                           @"in WOKeyPathAssociation %@: "
+                           @"cannot set type '%c' yet (key=%s, method=%@)",
+                           self, info->retType, info->ckey,
+                           NSStringFromSelector(setSel)];
+            return NO;
+        }
+        return YES;
+      }
+      else {
+        NSLog(@"%@: did not find method %@ in object %@",
+              self, NSStringFromSelector(setSel), object);
+        return NO;
+      }
+    }
+  }
+  else if (info->type == WOKeyType_kvc) { // takeValue:forKey:..
+    NSCAssert(info->extra.key, @"no key object set ..");
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
+    APPLE_FOUNDATION_LIBRARY
+    if([object isKindOfClass:NSCFDictionaryClass] &&
+       !_CFDictionaryIsMutable((CFDictionaryRef)object))
+        return NO;
+#endif
+    [object takeValue:_value forKey:info->extra.key];
+    return YES;
+  }
+  else if (info->type == WOKeyType_binding) { // setValue:forBinding:
+    NSCAssert(info->extra.key, @"no key object set ..");
+    [object setValue:_value forBinding:info->extra.key];
+    return YES;
+  }
+  else {
+    NSLog(@"%@: Could not set value for key '%s'.", self, info->ckey);
+    return NO;
+  }
+}
+
+- (void)setValue:(id)_value inComponent:(WOComponent *)_component {
+  if (debugOn)
+    NSLog(@"%@: set value %@ component %@", self, _value, _component);
+  
+  _setValue(self, _value, _component);
+}
+- (id)valueInComponent:(WOComponent *)_component {
+#if DEBUG
+  volatile id result;
+  if (debugOn)
+    NSLog(@"%@: get value in component %@", self, _component);
+  
+#if USE_EXCEPTION_HANDLERS
+  NS_DURING {
+#endif
+    result = (self->size > 1)
+      ? _getValue(self, _component)
+      : _getOneValue(self, _component);
+#if USE_EXCEPTION_HANDLERS
+  }
+  NS_HANDLER {
+    fprintf(stderr, "during evaluation of keypath %s:\n  %s\n",
+            [[self description] cString],
+            [[localException description] cString]);
+    fflush(stderr);
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+#endif
+  return result;
+#else
+  if (debugOn)
+    NSLog(@"%@: get value in component %@", self, _component);
+  
+  return (self->size > 1)
+    ? _getValue(self, _component)
+    : _getOneValue(self, _component);
+#endif
+}
+
+- (BOOL)isValueConstant {
+  return NO;
+}
+- (BOOL)isValueSettable {
+  return YES;
+}
+
+/* special values */
+
+- (void)setUnsignedIntValue:(unsigned int)_value
+  inComponent:(WOComponent *)_wo
+{
+  WOKeyPathComponent *info;
+  
+  if (debugOn)
+    NSLog(@"%@: set uint value %i in component %@", self, _value, _wo);
+  
+  if (self->size > 1) {
+    _setValue(self, uintNumObj(_value), _wo);
+    return;
+  }
+
+  info = (WOKeyPathComponent *)self->keyPath;
+  NSCAssert(info->keyLen < 255, @"keysize to big ..");
+    
+  _fillInfo(self, _wo, info);
+    
+  if (info->type == WOKeyType_method) { /* determine set-selector */
+    if (info->retType == _C_CHR || info->retType == _C_UCHR ||
+       info->retType == _C_INT || info->retType == _C_UINT) {
+      SEL             setSel;
+      WOSetMethodType sm;
+        
+      setSel = _getSetSel(info->ckey, info->keyLen);
+      sm.method = [_wo methodForSelector:setSel];
+      NSAssert1(sm.method, @"didn't find method for key %s", info->ckey);
+        
+      switch (info->retType) {
+          case _C_CHR: {
+            if (((int)_value < -126) || ((int)_value > 127))
+              NSLog(@"%@: value (%i) out of range for char !", self, _value);
+            sm.cmethod(_wo, setSel, (char)_value);
+            break;
+          }
+          case _C_UCHR: {
+            if ((_value < 0) || (_value > 255))
+              NSLog(@"%@: value (%i) out of range for uchar !", self, _value);
+            sm.ucmethod(_wo, setSel, (unsigned char)_value);
+            break;
+          }
+          case _C_INT: {
+            sm.imethod(_wo, setSel, (int)_value);
+            break;
+          }
+          case _C_UINT: {
+            sm.uimethod(_wo, setSel, (unsigned int)_value);
+            break;
+          }
+
+          default:
+            [NSException raise:@"WORuntimeException"
+                         format:
+                           @"in WOKeyPathAssociation %@: "
+                           @"does not handle type %c",
+                           self, info->retType];
+            break;
+      }
+    }
+    else {
+      // usual setValue
+        _setValue(self, uintNumObj(_value), _wo);
+    }
+    return;
+  }
+
+  if (info->type == WOKeyType_kvc) { // takeValue:forKey:..
+    NSCAssert(info->extra.key, @"no key object set ..");
+    [_wo takeValue:uintNumObj(_value) forKey:info->extra.key];
+    return;
+  }
+  if (info->type == WOKeyType_binding) { // setValue:forBinding:
+    NSCAssert(info->extra.key, @"no key object set ..");
+    [_wo setValue:uintNumObj(_value) forBinding:info->extra.key];
+    return;
+  }
+  
+  NSLog(@"%@: Could not set value for key '%s'.", self, info->ckey);
+}
+- (unsigned int)unsignedIntValueInComponent:(WOComponent *)_component {
+  WOKeyPathComponent  *info;
+  WOReturnValueHolder retValue;
+    
+  if (debugOn)
+    NSLog(@"%@: get uint value in component %@", self, _component);
+  
+  if (self->size > 1)
+    return [_getValue(self, _component) unsignedIntValue];
+
+  info     = (WOKeyPathComponent *)self->keyPath;
+  retValue = _getComponentValue(self, _component, info);
+
+  if (info->type == WOKeyType_method) {
+    switch (info->retType) {
+      case _C_UINT: return retValue.uint;
+      case _C_INT:  return retValue.sint;
+      case _C_UCHR: return retValue.c;
+      case _C_CHR:  return retValue.c;
+      case _C_SHT:  return retValue.ss;
+      case _C_USHT: return retValue.us;
+    }
+    return [_objectify(info->retType, &retValue) unsignedIntValue];
+  }
+
+#if 0
+  NSLog(@"ret value object for key '%s' is 0x%08X",
+       info->ckey, retValue.object);
+  NSLog(@"ret value object class is %@", [retValue.object class]);
+#endif
+  return [retValue.object unsignedIntValue];
+}
+
+- (void)setIntValue:(int)_value inComponent:(WOComponent *)_wo {
+  WOKeyPathComponent *info;
+  
+  if (debugOn)
+    NSLog(@"%@: set int value %i in component %@", self, _value, _wo);
+  
+  if (self->size > 1) {
+    _setValue(self, intNumObj(_value), _wo);
+    return;
+  }
+
+  info = (WOKeyPathComponent *)self->keyPath;
+  NSCAssert(info->keyLen < 255, @"keysize to big ..");
+    
+  _fillInfo(self, _wo, info);
+    
+  if (info->type == WOKeyType_method) { // determine set-selector
+      if (info->retType == _C_CHR || info->retType == _C_UCHR ||
+          info->retType == _C_INT || info->retType == _C_UINT) {
+        SEL             setSel;
+        WOSetMethodType sm;
+        
+        setSel = _getSetSel(info->ckey, info->keyLen);
+        sm.method = [_wo methodForSelector:setSel];
+        NSAssert1(sm.method, @"didn't find method for key %s", info->ckey);
+        
+        switch (info->retType) {
+          case _C_CHR: {
+            if (((int)_value < -126) || ((int)_value > 127))
+              NSLog(@"%@: value (%i) out of range for char !", self, _value);
+            sm.cmethod(_wo, setSel, (char)_value);
+            break;
+          }
+          case _C_UCHR: {
+            if ((_value < 0) || (_value > 255))
+              NSLog(@"%@: value (%i) out of range for uchar !", self, _value);
+            sm.ucmethod(_wo, setSel, (unsigned char)_value);
+            break;
+          }
+          case _C_INT: {
+            sm.imethod(_wo, setSel, (int)_value);
+            break;
+          }
+          case _C_UINT: {
+            sm.uimethod(_wo, setSel, (unsigned int)_value);
+            break;
+          }
+
+          default:
+            [NSException raise:@"WORuntimeException"
+                         format:
+                           @"in WOKeyPathAssociation %@: "
+                           @"does not handle type %c",
+                           self, info->retType];
+            break;
+        }
+      }
+      else {
+        // usual setValue
+        _setValue(self, intNumObj(_value), _wo);
+      }
+      return;
+  }
+
+  if (info->type == WOKeyType_kvc) { // takeValue:forKey:
+    NSCAssert(info->extra.key, @"no key object set ..");
+    [_wo takeValue:intNumObj(_value) forKey:info->extra.key];
+    return;
+  }
+  
+  if (info->type == WOKeyType_binding) { // setValue:forBinding:
+    NSCAssert(info->extra.key, @"no key object set ..");
+    [_wo setValue:intNumObj(_value) forBinding:info->extra.key];
+    return;
+  }
+
+  NSLog(@"%@: Could not set value for key '%s'.", self, info->ckey);
+}
+- (int)intValueInComponent:(WOComponent *)_component {
+  WOKeyPathComponent  *info;
+  WOReturnValueHolder retValue;
+
+  if (debugOn)
+    NSLog(@"%@: get int value in component %@", self, _component);
+  
+  if (self->size > 1)
+    return [_getValue(self, _component) intValue];
+
+  info     = (WOKeyPathComponent *)self->keyPath;
+  retValue = _getComponentValue(self, _component, info);
+
+  if (info->type != WOKeyType_method)
+    return [retValue.object intValue];
+
+  switch (info->retType) {
+    case _C_UINT: return retValue.uint;
+    case _C_INT:  return retValue.sint;
+    case _C_UCHR: return retValue.c;
+    case _C_CHR:  return retValue.c;
+    case _C_SHT:  return retValue.ss;
+    case _C_USHT: return retValue.us;
+    default:      return [_objectify(info->retType, &retValue) intValue];
+  }
+}
+
+- (void)setBoolValue:(BOOL)_value inComponent:(WOComponent *)_wo {
+  WOKeyPathComponent *info;
+  
+  if (debugOn)
+    NSLog(@"%@: set bool value %i in component %@", self, _value, _wo);
+  
+  if (self->size > 1) {
+    _setValue(self, [NumberClass numberWithBool:_value], _wo);
+    return;
+  }
+
+  info = (WOKeyPathComponent *)self->keyPath;
+  NSCAssert(info->keyLen < 255, @"keysize to big ..");
+    
+  _fillInfo(self, _wo, info);
+    
+  if (info->type == WOKeyType_method) { // determine set-selector
+      if (info->retType == _C_CHR || info->retType == _C_UCHR ||
+          info->retType == _C_INT || info->retType == _C_UINT) {
+        SEL             setSel;
+        WOSetMethodType sm;
+        
+        setSel = _getSetSel(info->ckey, info->keyLen);
+        sm.method = [_wo methodForSelector:setSel];
+        NSAssert1(sm.method, @"didn't find method for key %s", info->ckey);
+        
+        switch (info->retType) {
+          case _C_CHR: {
+            sm.cmethod(_wo, setSel, (char)_value);
+            break;
+          }
+          case _C_UCHR: {
+            sm.ucmethod(_wo, setSel, (unsigned char)_value);
+            break;
+          }
+          case _C_INT: {
+            sm.imethod(_wo, setSel, (int)_value);
+            break;
+          }
+          case _C_UINT: {
+            sm.uimethod(_wo, setSel, (unsigned int)_value);
+            break;
+          }
+
+          default:
+            [NSException raise:@"WORuntimeException"
+                         format:
+                           @"in WOKeyPathAssociation %@: "
+                           @"does not handle type %c",
+                           self, info->retType];
+            break;
+        }
+      }
+      else {
+        // usual setValue
+        _setValue(self, [NumberClass numberWithBool:_value], _wo);
+      }
+  }
+  else if (info->type == WOKeyType_kvc) { // takeValue:forKey:
+      NSCAssert(info->extra.key, @"no key object set ..");
+      [_wo takeValue:[NumberClass numberWithBool:_value]
+           forKey:info->extra.key];
+  }
+  else if (info->type == WOKeyType_binding) { // setValue:forBinding:
+      NSCAssert(info->extra.key, @"no key object set ..");
+      [_wo setValue:[NumberClass numberWithBool:_value]
+           forBinding:info->extra.key];
+  }
+  else {
+      NSLog(@"%@: Could not set value for key '%s'.", self, info->ckey);
+  }
+}
+- (BOOL)boolValueInComponent:(WOComponent *)_component {
+  if (debugOn)
+    NSLog(@"%@: get bool value in component %@", self, _component);
+  
+  if (self->size > 1)
+    return [_getValue(self, _component) boolValue];
+  else {
+    WOKeyPathComponent  *info;
+    WOReturnValueHolder retValue;
+
+    info     = (WOKeyPathComponent *)self->keyPath;
+    retValue = _getComponentValue(self, _component, info);
+
+    if (info->type == WOKeyType_method) {
+      switch (info->retType) {
+        case _C_UINT: return retValue.uint;
+        case _C_INT:  return retValue.sint;
+        case _C_UCHR: return retValue.c;
+        case _C_CHR:  return retValue.c;
+        case _C_SHT:  return retValue.ss;
+        case _C_USHT: return retValue.us;
+
+        default:
+          return [_objectify(info->retType, &retValue) boolValue];
+      }
+    }
+    else
+      return [retValue.object boolValue];
+  }
+}
+
+- (void)setStringValue:(NSString *)_value inComponent:(WOComponent *)_wo {
+  if (debugOn)
+    NSLog(@"%@: set string value '%@' in component %@", self, _value, _wo);
+  
+  _setValue(self, _value, _wo);
+}
+- (NSString *)stringValueInComponent:(WOComponent *)_component {
+  WOKeyPathComponent  *info;
+  WOReturnValueHolder retValue;
+    
+  if (debugOn)
+    NSLog(@"%@: get string value in component %@", self, _component);
+  
+  if (self->size > 1)
+    return [_getValue(self, _component) stringValue];
+
+  info     = (WOKeyPathComponent *)self->keyPath;
+  retValue = _getComponentValue(self, _component, info);
+
+  if (info->type != WOKeyType_method)
+    return [retValue.object stringValue];
+
+  switch (info->retType) {
+    case _C_UINT:
+      if (IS_UNUMSTR(retValue.uint)) return numStrings[retValue.uint];
+      return [StringClass stringWithFormat:@"%u", retValue.uint];
+    case _C_INT:
+      if (IS_NUMSTR(retValue.sint)) return numStrings[retValue.sint];
+      return [StringClass stringWithFormat:@"%d", retValue.sint];
+    case _C_UCHR:
+      if (IS_UNUMSTR(retValue.c)) return numStrings[retValue.c];
+      return [StringClass stringWithFormat:@"%d", (int)retValue.c];
+    case _C_CHR:
+      if (IS_NUMSTR((char)retValue.c)) return numStrings[retValue.c];
+      return [StringClass stringWithFormat:@"%d", (int)retValue.c];
+    case _C_SHT:
+      if (IS_NUMSTR(retValue.ss)) return numStrings[retValue.ss];
+      return [StringClass stringWithFormat:@"%d", (int)retValue.ss];
+    case _C_USHT:
+      if (IS_UNUMSTR(retValue.us)) return numStrings[retValue.us];
+      return [StringClass stringWithFormat:@"%d", (int)retValue.us];
+    
+#if 0      
+    case _C_FLT:
+      return [StringClass stringWithFormat:@"%0.7g", retValue.flt];
+#endif
+    default:
+      return [_objectify(info->retType, &retValue) stringValue];
+  }
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:[self keyPath]];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  return [self initWithKeyPath:[_coder decodeObject]];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  /* keypath associations are immutable */
+  return [self retain];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [StringClass stringWithFormat:@"<%@[0x%08X]: keyPath=%@>",
+                        NSStringFromClass([self class]), self,
+                        [self keyPath]];
+}
+
+@end /* WOKeyPathAssociation */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOKeyPathAssociationSystemKVC.m b/skyrix-sope/NGObjWeb/Associations/WOKeyPathAssociationSystemKVC.m
new file mode 100644 (file)
index 0000000..a9c8402
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+  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$
+
+#include "WOKeyPathAssociation.h"
+#include <NGObjWeb/WOComponent.h>
+#include "NSObject+WO.h"
+#include "common.h"
+
+/*
+  WOKeyPathAssociationSystemKVC
+  
+  This is an WOKeyPathAssociation subclass which uses the KVC methods
+  provided in the Foundation library. This is much less performant, but
+  much more compatible with WebObjects.
+  
+  This could be further optimized by doing method caching, using shared
+  objects, etc. Yet if you need speed, you should use the default association.
+*/
+
+@interface WOKeyPathAssociationSystemKVC : WOKeyPathAssociation
+{
+  NSString *keyPathString;
+  BOOL     hasCaretPrefix;
+}
+
+@end
+
+@implementation WOKeyPathAssociationSystemKVC
+
+static NSNumber *yesNum = nil;
+static NSNumber *noNum  = nil;
+
++ (int)version {
+  return [super version] + 0; /* v2 */
+}
++ (void)initialize {
+  if (yesNum == nil) yesNum = [[NSNumber numberWithBool:YES] retain];
+  if (noNum  == nil) noNum  = [[NSNumber numberWithBool:NO]  retain];
+}
+
+- (id)initWithKeyPath:(NSString *)_keyPath {
+  if ((self = [super initWithKeyPath:_keyPath])) {
+    self->hasCaretPrefix = 
+      (([_keyPath length] > 1) && [_keyPath hasPrefix:@"^"]) ? YES : NO;
+    
+    if (self->hasCaretPrefix)
+      self->keyPathString = [[_keyPath substringFromIndex:1] copy];
+    else
+      self->keyPathString = [_keyPath copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->keyPathString release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)keyPath {
+  return self->keyPathString;
+}
+
+/* value */
+
+- (void)setValue:(id)_value inComponent:(WOComponent *)_component {
+  if (self->hasCaretPrefix)
+    [_component setValue:_value forBinding:self->keyPathString];
+  else
+    [_component takeValue:_value forKeyPath:self->keyPathString];
+}
+- (id)valueInComponent:(WOComponent *)_component {
+  return (self->hasCaretPrefix)
+    ? [_component valueForBinding:self->keyPathString]
+    : [_component valueForKeyPath:self->keyPathString];
+}
+
+- (BOOL)isValueConstant {
+  return NO;
+}
+- (BOOL)isValueSettable {
+  return YES;
+}
+
+/* special values */
+
+- (void)setUnsignedIntValue:(unsigned int)_v inComponent:(WOComponent *)_wo {
+  [self setValue:[NSNumber numberWithUnsignedInt:_v] inComponent:_wo];
+}
+- (unsigned int)unsignedIntValueInComponent:(WOComponent *)_component {
+  return [[self valueInComponent:_component] unsignedIntValue];
+}
+
+- (void)setIntValue:(int)_value inComponent:(WOComponent *)_wo {
+  [self setValue:[NSNumber numberWithInt:_value] inComponent:_wo];
+}
+- (int)intValueInComponent:(WOComponent *)_component {
+  return [[self valueInComponent:_component] intValue];
+}
+
+- (void)setBoolValue:(BOOL)_value inComponent:(WOComponent *)_wo {
+  [self setValue:(_value ? yesNum : noNum) inComponent:_wo];
+}
+- (BOOL)boolValueInComponent:(WOComponent *)_component {
+  /* some optimizations, very likely that same objects are used for YES|NO */
+  id o;
+  
+  if ((o = [self valueInComponent:_component]) == nil)
+    return NO;
+  if (o == yesNum) return YES;
+  if (o == noNum)  return NO;
+  return [o boolValue];
+}
+
+- (void)setStringValue:(NSString *)_value inComponent:(WOComponent *)_wo {
+  [self setValue:_value inComponent:_wo];
+}
+- (NSString *)stringValueInComponent:(WOComponent *)_component {
+  return [[self valueInComponent:_component] stringValue];
+}
+
+@end /* WOKeyPathAssociationSystemKVC */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOLabelAssociation.h b/skyrix-sope/NGObjWeb/Associations/WOLabelAssociation.h
new file mode 100644 (file)
index 0000000..ea0be8b
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOLabelAssociation_H__
+#define __NGObjWeb_WOLabelAssociation_H__
+
+#include <NGObjWeb/WOAssociation.h>
+
+/*
+  WOLabelAssociation
+
+  String value syntax:
+    "next"       - lookup key 'next' in table 'nil'   with default 'next'
+    "table/next" - lookup key 'next' in table 'table' with default 'next'
+  
+  This association performs a string lookup in the components 
+  WOResourceManager (or the app's manager if the component has none). It uses 
+  the session and browser languages for the key lookup.
+  
+  Note that this also supports keypathes by prefixing the values with an
+  "$", eg: "$currentDay" will first evaluate "currentDay" in the component
+  and then pipe the result through the label processor.
+  We consider that a bit hackish, but given that it is often required in
+  practice, a pragmatic implementation.
+*/
+
+@interface WOLabelAssociation : WOAssociation < NSCopying >
+{
+  NSString *key;
+  NSString *table;
+  NSString *defaultValue;
+  struct {
+    int isKeyKeyPath:1;
+    int isTableKeyPath:1;
+    int isValueKeyPath:1;
+    int reserved:29;
+  } flags;
+}
+
+- (id)initWithKey:(NSString *)_key inTable:(NSString *)_table
+  withDefaultValue:(NSString *)_default;
+
+- (id)initWithString:(NSString *)_str;
+
+/* value */
+
+- (BOOL)isValueConstant; // returns NO
+- (BOOL)isValueSettable; // returns NO
+
+@end
+
+#endif /* __NGObjWeb_WOLabelAssociation_H__ */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOLabelAssociation.m b/skyrix-sope/NGObjWeb/Associations/WOLabelAssociation.m
new file mode 100644 (file)
index 0000000..9ff2b12
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+  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$
+
+#include "WOLabelAssociation.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOSession.h>
+#include "common.h"
+
+@implementation WOLabelAssociation
+
++ (int)version {
+  return [super version] /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithKey:(NSString *)_key inTable:(NSString *)_table
+  withDefaultValue:(NSString *)_default
+{
+  if ([_key length] == 0) {
+    [self debugWithFormat:@"WARNING: missing label key!"];
+    [self release];
+    return nil;
+  }
+  if ((self = [super init])) {
+    if ([_key hasPrefix:@"$"]) {
+      self->flags.isKeyKeyPath = 1;
+      _key = [_key substringFromIndex:1];
+    }
+    if ([_table hasPrefix:@"$"]) {
+      self->flags.isTableKeyPath = 1;
+      _table = [_table substringFromIndex:1];
+    }
+    if ([_default hasPrefix:@"$"]) {
+      self->flags.isValueKeyPath = 1;
+      _default = [_default substringFromIndex:1];
+    }
+    
+    self->key          = [_key     copy];
+    self->table        = [_table   copy];
+    self->defaultValue = [_default copy];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithKey:nil inTable:nil withDefaultValue:nil];
+}
+
+- (id)initWithString:(NSString *)_str {
+  NSString *lKey, *lTable, *lVal;
+  NSRange r;
+  
+  if ([_str length] == 0) {
+    [self release];
+    return nil;
+  }
+  
+  r = [_str rangeOfString:@"/"];
+  if (r.length > 0) {
+    lTable = [_str substringToIndex:r.location];
+    lKey   = [_str substringFromIndex:(r.location + r.length)];
+  }
+  else {
+    lTable = nil;
+    lKey   = _str;
+  }
+  lVal = lKey;
+  
+  return [self initWithKey:lKey inTable:lTable withDefaultValue:lVal];
+}
+
+- (void)dealloc {
+  [self->table        release];
+  [self->defaultValue release];
+  [self->key          release];
+  [super dealloc];
+}
+
+/* value */
+
+- (void)setValue:(id)_value inComponent:(WOComponent *)_component {
+  // not settable
+  [NSException raise:@"AssociationException"
+               format:@"association value is not settable !"];
+}
+- (id)valueInComponent:(WOComponent *)_component {
+  WOResourceManager *rm;
+  NSArray           *languages;
+  WOContext         *ctx;
+  NSString          *label;
+  NSString          *lKey, *lTable, *lVal;
+
+  /* lookup languages */
+  
+  ctx = [_component context];
+  languages = [ctx hasSession]
+    ? [[ctx session] languages]
+    : [[ctx request] browserLanguages];
+
+  /* find resource manager */
+  
+  if ((rm = [_component resourceManager]) == nil)
+    rm = [[WOApplication application] resourceManager];
+  if (rm == nil)
+    [self debugWithFormat:@"WARNING: missing resource manager!"];
+
+  /* get parameters */
+  
+  lKey   = self->key;
+  lTable = self->table;
+  lVal   = self->defaultValue;
+  if (self->flags.isKeyKeyPath)   lKey   = [_component valueForKeyPath:lKey];
+  if (self->flags.isTableKeyPath) lTable = [_component valueForKeyPath:lTable];
+  if (self->flags.isValueKeyPath) lVal   = [_component valueForKeyPath:lVal];
+
+  /* lookup string */
+  
+  label = [rm stringForKey:lKey inTableNamed:lTable withDefaultValue:lVal
+              languages:languages];
+  return label;
+}
+
+- (BOOL)isValueConstant {
+  return NO;
+}
+- (BOOL)isValueSettable {
+  return NO;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:64];
+  [str appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->flags.isKeyKeyPath)
+    [str appendFormat:@" key=%@",   self->key];
+  else
+    [str appendFormat:@" key='%@'", self->key];
+
+  if (self->flags.isTableKeyPath)
+    [str appendFormat:@" table=%@",   self->table];
+  else
+    [str appendFormat:@" table='%@'", self->table];
+
+  if (self->flags.isValueKeyPath)
+    [str appendFormat:@" def=%@",   self->defaultValue];
+  else
+    [str appendFormat:@" def='%@'", self->defaultValue];
+  
+  [str appendString:@">"];
+  return str;
+}
+
+@end /* WOLabelAssociation */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOResourceURLAssociation.h b/skyrix-sope/NGObjWeb/Associations/WOResourceURLAssociation.h
new file mode 100644 (file)
index 0000000..2794ec0
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOResourceURLAssociation_H__
+#define __NGObjWeb_WOResourceURLAssociation_H__
+
+#include <NGObjWeb/WOAssociation.h>
+
+@class NSString;
+
+@interface WOResourceURLAssociation : WOAssociation < NSCopying >
+{
+@private
+  NSString *resourceName;
+}
+
+/* accessors */
+
+- (NSString *)resourceName;
+
+/* value */
+
+- (BOOL)isValueConstant;
+- (BOOL)isValueSettable;
+
+@end
+
+#endif /* __NGObjWeb_WOResourceURLAssociation_H__ */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOResourceURLAssociation.m b/skyrix-sope/NGObjWeb/Associations/WOResourceURLAssociation.m
new file mode 100644 (file)
index 0000000..3c7d69d
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOResourceURLAssociation.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOSession.h>
+#include "common.h"
+
+@implementation WOResourceURLAssociation
+
+static BOOL doDebug = NO;
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithString:(NSString *)_name {
+  if ([_name length] == 0) {
+    if (doDebug) {
+      NSLog(@"WARNING(%s): got passed no resource name!", 
+           __PRETTY_FUNCTION__);
+    }
+    [self release];
+    return nil;
+  }
+  if ((self = [super init])) {
+    self->resourceName = [_name copy];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithString:nil];
+}
+
+- (void)dealloc {
+  [self->resourceName release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)resourceName {
+  return self->resourceName;
+}
+- (NSString *)frameworkName {
+  return nil;
+}
+
+/* value */
+
+- (void)setValue:(id)_value inComponent:(WOComponent *)_component {
+  /* resource-url association values cannot be set */
+  [NSException raise:@"AssociationException"
+               format:@"association value is not settable !"];
+}
+- (id)valueInComponent:(WOComponent *)_component {
+  WOResourceManager *rm;
+  WOContext *ctx;
+  NSArray   *langs;
+  WORequest *rq;
+
+  if ((ctx = [_component context]) == nil)
+    ctx = [[WOApplication application] context];
+  rq    = [ctx request];
+  langs = [ctx hasSession]
+    ? [[ctx session] languages]
+    : [[ctx request] browserLanguages];
+  
+  if ((rm = [_component resourceManager]) == nil) {
+    WOApplication *app;
+    
+    if ((app = [ctx application]) == nil)
+      app = [WOApplication application];
+    
+    rm = [app resourceManager];
+  }
+  if (rm == nil) {
+    [self logWithFormat:@"WARNING: found no resource manager!"];
+    return nil;
+  }
+  
+  return [rm urlForResourceNamed:[self resourceName]
+            inFramework:[self frameworkName]
+            languages:langs
+            request:rq];
+}
+
+- (BOOL)isValueConstant {
+  return NO;
+}
+- (BOOL)isValueSettable {
+  return NO;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  /* rsrc-url associations are immutable and don't need to be copied */
+  return [self retain];
+}
+
+- (NSString *)description {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:64];
+  [str appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
+  [str appendFormat:@" rsrc='%@'", [self resourceName]];
+  [str appendString:@">"];
+  return str;
+}
+
+@end /* WOResourceURLAssociation */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOScriptAssociation.h b/skyrix-sope/NGObjWeb/Associations/WOScriptAssociation.h
new file mode 100644 (file)
index 0000000..c461210
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOScriptAssociation_H__
+#define __NGObjWeb_WOScriptAssociation_H__
+
+#include <NGObjWeb/WOAssociation.h>
+
+@class NSString;
+
+@interface WOScriptAssociation : WOAssociation < NSCopying >
+{
+@private
+  NSString *script;
+  NSString *language;
+}
+
+- (id)initWithScript:(NSString *)_script language:(NSString *)_language;
+
+/* accessors */
+
+- (NSString *)script;
+- (NSString *)language;
+
+/* value */
+
+- (BOOL)isValueConstant;
+- (BOOL)isValueSettable;
+
+@end
+
+#endif /* __NGObjWeb_WOScriptAssociation_H__ */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOScriptAssociation.m b/skyrix-sope/NGObjWeb/Associations/WOScriptAssociation.m
new file mode 100644 (file)
index 0000000..687a9c8
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOScriptAssociation.h"
+#include <NGObjWeb/WOComponent.h>
+#import "common.h"
+
+@interface NSObject(Scripting)
+
+- (id)evaluateScript:(NSString *)_script language:(NSString *)_language;
+
+@end
+
+@implementation WOScriptAssociation
+
+static BOOL doDebug = NO;
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
++ (NSString *)defaultScriptLanguage {
+  return @"javascript";
+}
+
+- (id)initWithScript:(NSString *)_script language:(NSString *)_language {
+  if ([_language length] == 0)
+    _language = [WOScriptAssociation defaultScriptLanguage];
+  
+  if ([_script length] == 0) {
+    if (doDebug) {
+      NSLog(@"WARNING(%s): got passed an empty script ...",
+           __PRETTY_FUNCTION__);
+    }
+    [self release];
+    return nil;
+  }
+  
+  if ((self = [super init])) {
+    /* should compile script if possible !!! */
+    self->script   = [_script   copy];
+    self->language = [_language copy];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithScript:nil language:nil];
+}
+- (id)initWithString:(NSString *)_s {
+  if ([_s length] == 0) {
+    if (doDebug) {
+      NSLog(@"WARNING(%s): got passed an empty script ...", 
+           __PRETTY_FUNCTION__);
+    }
+    [self release];
+    return nil;
+  }
+  return [self initWithScript:_s language:nil];
+}
+
+- (void)dealloc {
+  [self->script   release];
+  [self->language release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)script {
+  return self->script;
+}
+- (NSString *)language {
+  return self->language;
+}
+
+/* value */
+
+- (void)setValue:(id)_value inComponent:(WOComponent *)_component {
+  // not settable
+  [NSException raise:@"AssociationException"
+               format:@"association value is not settable !"];
+}
+- (id)valueInComponent:(WOComponent *)_component {
+  return [_component evaluateScript:self->script language:self->language];
+}
+
+- (BOOL)isValueConstant {
+  return NO;
+}
+- (BOOL)isValueSettable {
+  return NO;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  /* script associations are immutable and don't need to be copied */
+  return [self retain];
+}
+
+- (NSString *)description {
+  NSMutableString *str;
+  NSString *v;
+
+  str = [NSMutableString stringWithCapacity:64];
+  [str appendFormat:@"<%@[0x%08X]: script(%@)=",
+         NSStringFromClass([self class]), self, [self language]];
+  
+  v = self->script;
+  if ([v length] > 10) {
+      v = [v substringToIndex:9];
+      v = [v stringByApplyingCEscaping];
+      [str appendString:v];
+      [str appendFormat:@"...[len=%i]", [self->script length]];
+  }
+  else {
+      v = [v stringByApplyingCEscaping];
+      [str appendString:v];
+  }
+  
+  [str appendString:@">"];
+  return str;
+}
+
+@end /* WOScriptAssociation */
+
+#if 0
+@interface WOAssociation(Blah)
+- (id)initWithValue:(id)_value;
+@end
+
+@implementation WOAssociation(Overload)
+
++ (WOAssociation *)associationWithValue:(id)_value {
+  WOAssociation *a;
+  
+  if ([_value isKindOfClass:[NSString class]]) {
+    if ([(NSString *)_value hasPrefix:@"JS:"]) {
+      _value = [_value substringFromIndex:3];
+      a = [[WOScriptAssociation alloc] initWithJavaScript:_value];
+      return [a autorelease];
+    }
+  }
+  
+  return [[[NSClassFromString(@"WOValueAssociation")
+                            alloc] initWithValue:_value] autorelease];
+}
+
+@end /* WOAssociation(Overload) */
+#endif /* 0 */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOValueAssociation.h b/skyrix-sope/NGObjWeb/Associations/WOValueAssociation.h
new file mode 100644 (file)
index 0000000..e637463
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOValueAssociation_H__
+#define __NGObjWeb_WOValueAssociation_H__
+
+#include <NGObjWeb/WOAssociation.h>
+
+@interface WOValueAssociation : WOAssociation < NSCoding, NSCopying >
+{
+  id value;
+  struct {
+    unsigned int smallValue:16;
+    unsigned int boolValue:2; // 0 - not cache, 1 - true, 2 - false
+    unsigned int hasSmallValue:1;
+    unsigned int hasNoSmallValue:1;
+    unsigned int reserved:12;
+  } cacheFlags;
+}
+
++ (WOAssociation *)associationWithValue:(id)_value;
+- (id)initWithValue:(id)_value;
+
+/* value */
+
+- (BOOL)isValueConstant; // returns YES
+- (BOOL)isValueSettable; // returns NO
+
+@end
+
+@interface _WOBoolValueAssociation : WOAssociation < NSCopying >
+{
+  BOOL value;
+}
+
++ (WOAssociation *)associationWithValue:(id)_value;
++ (WOAssociation *)associationWithBool:(BOOL)_value;
+
+/* value */
+
+- (BOOL)isValueConstant; // returns YES
+- (BOOL)isValueSettable; // returns NO
+
+@end
+
+#endif /* __NGObjWeb_WOValueAssociation_H__ */
diff --git a/skyrix-sope/NGObjWeb/Associations/WOValueAssociation.m b/skyrix-sope/NGObjWeb/Associations/WOValueAssociation.m
new file mode 100644 (file)
index 0000000..f3caab5
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOValueAssociation.h"
+#include "common.h"
+
+// TODO: check whether it makes sense to precalculate int/bool/?? values
+//       from the object value (add counters on how often these are called)
+
+@implementation WOValueAssociation
+
++ (int)version {
+  return [super version] /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
++ (WOAssociation *)associationWithValue:(id)_value {
+  return [[[WOValueAssociation alloc] initWithValue:_value] autorelease];
+}
+
+- (id)init {
+  return [self initWithValue:nil];
+}
+- (id)initWithValue:(id)_value {
+  if ((self = [super init])) {
+    self->value = [_value retain]; /* do not use copy, can be full objects */
+  }
+  return self;
+}
+- (id)initWithString:(NSString *)_s {
+  return [self initWithValue:_s];
+}
+
+- (void)dealloc {
+  [self->value release];
+  [super dealloc];
+}
+
+/* value */
+
+- (void)setValue:(id)_value inComponent:(WOComponent *)_component {
+  // not settable
+  [NSException raise:@"AssociationException"
+               format:@"association value is not settable !"];
+}
+- (id)valueInComponent:(WOComponent *)_component {
+  return self->value;
+}
+
+- (BOOL)isValueConstant {
+  return YES;
+}
+- (BOOL)isValueSettable {
+  return NO;
+}
+
+/* special values */
+
+- (unsigned int)unsignedIntValueInComponent:(WOComponent *)_component {
+  register unsigned int val;
+  
+  if (self->cacheFlags.hasSmallValue)
+    return self->cacheFlags.smallValue;
+  
+  val = [self->value unsignedIntValue];
+  if (self->cacheFlags.hasNoSmallValue)
+    return val;
+  
+  if (val < 65536) {
+    self->cacheFlags.smallValue = val;
+    self->cacheFlags.hasSmallValue = 1;
+  }
+  else
+    self->cacheFlags.hasNoSmallValue = 1;
+  return val;
+}
+- (int)intValueInComponent:(WOComponent *)_component {
+  register int val;
+  
+  if (self->cacheFlags.hasSmallValue)
+    return self->cacheFlags.smallValue;
+  
+  val = [self->value intValue];
+  if (self->cacheFlags.hasNoSmallValue)
+    return val;
+  
+  if (val >= 0 && val < 65536) {
+    self->cacheFlags.smallValue = val;
+    self->cacheFlags.hasSmallValue = 1;
+  }
+  else
+    self->cacheFlags.hasNoSmallValue = 1;
+  return val;
+}
+- (BOOL)boolValueInComponent:(WOComponent *)_component {
+  switch (self->cacheFlags.boolValue) {
+  case 1: return YES;
+  case 2: return NO;
+  default:
+    self->cacheFlags.boolValue = [self->value boolValue] ? 1 : 2;
+    return self->cacheFlags.boolValue == 1 ? YES : NO;
+  }
+}
+- (NSString *)stringValueInComponent:(WOComponent *)_component {
+  return [self->value stringValue];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->value];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  if ((self = [super init])) {
+    self->value = [[_coder decodeObject] retain];
+  }
+  return self;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:64];
+  [str appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  [str appendString:@" value="];
+  if ([self->value isKindOfClass:[NSString class]]) {
+    NSString *v = self->value;
+    
+    [str appendString:@"\""];
+    if ([self->value length] > 10) {
+      v = [v substringToIndex:9];
+      v = [v stringByApplyingCEscaping];
+      [str appendString:v];
+      [str appendFormat:@"...[len=%i]", [self->value length]];
+    }
+    else {
+      v = [v stringByApplyingCEscaping];
+      [str appendString:v];
+    }
+    [str appendString:@"\""];
+  }
+  else {
+    [str appendString:[self->value description]];
+    [str appendFormat:@"(%@)", NSStringFromClass([self->value class])];
+  }
+  [str appendString:@">"];
+
+  return str;
+}
+
+@end /* WOValueAssociation */
+
+@implementation _WOBoolValueAssociation
+
+static _WOBoolValueAssociation *yesAssoc = nil;
+static _WOBoolValueAssociation *noAssoc  = nil;
+static NSNumber *yesNum = nil;
+static NSNumber *noNum  = nil;
+
++ (void)initialize {
+  if (yesNum == nil) yesNum = [[NSNumber numberWithBool:YES] retain];
+  if (noNum  == nil) noNum  = [[NSNumber numberWithBool:NO] retain];
+}
+
++ (WOAssociation *)associationWithBool:(BOOL)_value {
+  if (_value) {
+    if (yesAssoc == nil) {
+      yesAssoc = [[_WOBoolValueAssociation alloc] init];
+      yesAssoc->value = YES;
+    }
+    return yesAssoc;
+  }
+  else {
+    if (noAssoc == nil) {
+      noAssoc = [[_WOBoolValueAssociation alloc] init];
+      noAssoc->value = NO;
+    }
+    return noAssoc;
+  }
+}
++ (WOAssociation *)associationWithValue:(id)_value {
+  return [self associationWithBool:[_value boolValue]];
+}
+
+/* value */
+
+- (void)setValue:(id)_value inComponent:(WOComponent *)_component {
+  // not settable
+  [NSException raise:@"AssociationException"
+               format:@"association value is not settable !"];
+}
+- (id)valueInComponent:(WOComponent *)_component {
+  return self->value ? yesNum : noNum;
+}
+
+- (BOOL)isValueConstant {
+  return YES;
+}
+- (BOOL)isValueSettable {
+  return NO;
+}
+
+/* special values */
+
+- (unsigned int)unsignedIntValueInComponent:(WOComponent *)_component {
+  return self->value ? 1 : 0;
+}
+- (int)intValueInComponent:(WOComponent *)_component {
+  return self->value ? 1 : 0;
+}
+- (BOOL)boolValueInComponent:(WOComponent *)_component {
+  return self->value;
+}
+- (NSString *)stringValueInComponent:(WOComponent *)_component {
+  return self->value ? @"YES" : @"NO";
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: %s",
+                     NSStringFromClass([self class]), self,
+                     self->value ? "YES" : "NO"];
+}
+
+@end /* _WOBoolValueAssociation */
diff --git a/skyrix-sope/NGObjWeb/COPYING b/skyrix-sope/NGObjWeb/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/NGObjWeb/COPYRIGHT b/skyrix-sope/NGObjWeb/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-sope/NGObjWeb/ChangeLog b/skyrix-sope/NGObjWeb/ChangeLog
new file mode 100644 (file)
index 0000000..ae69a32
--- /dev/null
@@ -0,0 +1,2917 @@
+2004-08-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoProductResourceManager.m: added html, xml, txt and js as 
+         known product resource extensions (v4.2.431)
+
+2004-08-11  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SoObjects/SoObject.m: improved a debug log, improved root URL 
+         processing (v4.2.430)
+
+2004-08-05  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * v4.2.429
+       
+       * OWResourceManager.m: major changes to resource lookup. When scanning
+         language lproj directories contained inside .wo wrappers, the lproj
+         themselves will be checked whether they contain an component.html 
+         file.
+
+       * Templates/WOWrapperTemplateBuilder.m: minor improvement to logging
+         code
+       
+       * WOComponentDefinition.m: added WODebugComponentDefinition default to
+         enable debug logs
+       
+2004-08-04  Helge Hess  <helge.hess@opengroupware.org>
+
+       * added OWResourceManager as a copy of WOResourceManager so that we
+         can apply Stephane's patches without breaking OGo. OWResourceManager
+         will be kept as a legacy until its ensured that OGo is compatible
+         with the WO resource manager (v4.2.428)
+
+2004-08-03  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SoObjects/SoProductRegistry.m: register product bundles loaded by
+         other code sections (using the NSBundleDidLoadNotification)
+         (v4.2.427)
+
+2004-08-01  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.426
+
+       * WOHttpAdaptor/WOHttpTransaction.m: added some debug logs
+
+       * WOHttpAdaptor/WOHttpAdaptor.m: minor code cleanups
+
+2004-07-29  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SoObjects/SoObject.m(-baseURLInContext:): if the object implements 
+         -isFolderish and returns YES, a slash will be added to the baseURL
+         (v4.2.425)
+
+2004-07-26  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.424
+
+       * Templates/WOxComponentElemBuilder.m: improved debug logs
+
+       * Associations/WOValueAssociation.m: improved description
+
+2004-07-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOComponent.m: made "missing context in component" warning log a
+         debug log (v4.2.423)
+
+2004-07-21  Helge Hess  <helge.hess@opengroupware.org>
+
+       * Associations/WOValueAssociation.m: added a great premature 
+         optimization to speed up value access for objects as ints, unsigned
+         ints and bools ;-), added a small optimization to access bool
+         objects as strings (v4.2.422)
+
+2004-07-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.421
+
+       * WOValueAssociation.m: minor code cleanups
+
+       * Defaults.plist(WOxAssociationClassMapping): registered new 
+         WOLabelAssociation for 'OGo:label' namespace
+       
+       * added new WOLabelAssociation for resolving labels
+
+2004-07-17  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.420
+
+       * WebDAV/SoObjectWebDAVDispatcher.m: improved error handling if the
+         target object does not implement a specific method (returns 501,
+         not implemented)
+       
+       * DAVPropMap.plist: added some DAV properties which are new with 
+         OOo 1.9 UCB
+
+2004-07-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOCoreApplication.m: added ability to filter out some "expected"
+         validation issues (by overwriting the -hideValidationIssue: method)
+         (v4.2.419)
+
+2004-07-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * Languages.plist: added mapping from 'nb' code to NorwegianBokmaal
+         (v4.2.418)
+
+2004-07-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOContext.m, WOComponent.m, Defaults.plist: added new 
+         'WODebugComponentAwake' default to enable component -awake/-sleep 
+         logging (v4.2.417)
+
+2004-07-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.416
+       
+       * SoObjects/SoPageInvocation.m, SoObjects/SoProductClassInfo.m: added 
+         support for extracting SOAP parameters as KVC keys for the 
+         WOComponent (SOAP parameters will be extracted and applied using
+         KVC)
+
+       * SoObjects/SoObjectSOAPDispatcher.m, 
+         SoObjects/SoObjectXmlRpcDispatcher.m: added an own logging prefix
+
+2004-07-07  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.415
+       
+       * SoObjects/SoSelectorInvocation.m: added support for SOAP parameter
+         extractions
+
+       * SoObjects/SoObjectSOAPDispatcher.m: added SOAP envelope in context
+       
+       * SoObjects/SoProductClassInfo.m: added support for 'arguments' key
+         in selector invocation declarations to specify request type specific
+         argument extractions
+
+2004-07-07  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * DynamicElements/WOString.m: new attribute "style" appends
+         surrounding <span> tag bearing the styleclass. Doesn't get set if
+         no string value will be printed. (v4.2.414)
+
+2004-07-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.413
+       
+       * SoObjects: started SOAP dispatcher for SOPE objects
+       
+       * Defaults.plist: added SOAP configuration to SOPE dispatcher selection
+
+       * SoObjects/WORequest+So.m: added -isSoSOAPRequest to detect SOAP 
+         requests based on the SOAPAction HTTP header
+
+2004-07-05  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WEClientCapabilities.m: report Mozilla browsers starting with major
+         version 5 as <iframe/> capable browsers, this should fix OGo bug 
+         #634 (v4.2.412)
+
+2004-07-04  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.411
+
+       * DynamicElements/WOForm.m: print a debug log if a session ID is to be
+         embedded in a direct action form, but no session is active
+
+       * DynamicElements/WOPopUpButton.m: minor improvement to 
+         WONoSelectionString generation code
+
+       * Templates/WOxTemplateBuilder.m: added WOxLogBuilderQueue default to
+         log the builder queue setup being used by the application
+
+2004-06-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SoObjects/NSException+HTTP.m: subminor fix to 404 reason (v4.2.410)
+
+2004-06-29  Stephane Corthesy  <stephane@sente.ch>
+
+       * Associations/WOKeyPathAssociationSystemKVC.m: fixed bool value 
+         processing (return YES for NO NSNumber's) (v4.2.409)
+
+2004-06-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * various makefile fixes to allow in-place compilation of the whole
+         SOPE frameworks (v4.2.408)
+
+       * WOComponent.m: removed a superflous log on MacOSX (v4.2.407)
+
+2004-06-22  Helge Hess  <helge.hess@opengroupware.org>
+
+       * DynamicElements/_WOConstResourceImage.m: added some debugging code
+         (v4.2.406)
+
+2004-06-21  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOCoreApplication.m: fixed a gstep-base warning (v4.2.405)
+
+2004-06-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoClass.m: added slot access logging (v4.2.404)
+
+       * SoApplication.m, SoObject+Traversal.m, SoObject.m,
+         SoObjectMethodDispatcher.m, SoPageInvocation.m, SoProductClassInfo.m,
+         SoSecurityManager.m: fixed some gcc 3.4 warnings (v4.2.403)
+
+2004-06-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.402
+
+       * DynamicElements/WOPopUpButton.m: moved in .h file
+
+       * DynamicElements/WOBrowser.m: do not include WOPopUpButton.h (does not
+         inherit from that dynamic element anymore)
+       
+2004-06-20  Stephane Corthesy  <stephane@sente.ch>
+       
+       * DynamicElements/WOPopUpButton.[hm]: 
+         - removed the singleSelection binding (now is fixed to YES [Note: 
+           will break compatibility with very old WO versions])
+         - added 'displayString' as an alias for the 'string' binding
+         - added 'selectedValue' and 'escapeHTML' bindings
+         - 'value' is not longer set to selected value in 
+           -takeValuesFromRequest:inContext:. Use 'selectedValue' instead.
+         - uses WONoSelectionString variable instead of hardcoded "$" for 
+           empty selections
+         - 'item' binding is reset after use
+         - added missing space in generated HTML when 'otherTagString' is set
+         - 'value' is now escaped
+       
+2004-06-17  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.401
+
+       * SoObjects/SoObjectMethodDispatcher.m: only lookup HTTP methods in the
+         SoClass, not in the object itself to avoid clashes with contained
+         objects
+
+       * DynamicElements/_WOComplexHyperlink.m: added 
+         'WODebugStaticLinkProcessing' default to debug URL processing in
+         static hyperlinks
+
+2004-06-16  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.400
+
+       * WOContext.m ([WOContext -urlWithRequestHandlerKey:path:queryString:]):
+         fixed processing of application name for '/' request URLs
+
+       * SoObjectMethodDispatcher.m: minor code cleanups
+
+       * SoObjects/SoObject.h: exposed -defaultMethodNameInContext: method
+         (v4.2.399)
+
+       * SoObjects/SoHTTPAuthenticator.m: added +parseCredentials: method
+         to reuse the HTTP authorization parsing (v4.2.398)
+
+2004-06-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SoObjects/SoApplication.m: fixed lookup for appname.woa which is
+         generated since the changes in v4.2.385 (v4.2.397)
+
+       * WOPageRequestHandler.m: fixed a bug in the new request methods 
+         (v4.2.396)
+
+       * v4.2.395
+       
+       * NGObjWeb/WOComponent.h: added prototypes for direct action methods
+
+       * WOPageRequestHandler.m: added direct action like form-value methods
+         to WOComponent category (-takeFormValuesForKeys:)
+
+       * SoObjects/SoProductRegistry.m: improved bundle based product lookup
+         (first checks using the bundle path)
+       
+       * SoObjects/SoPageInvocation.m: use application context for page
+         instantiation if none was passed in
+
+       * SoObjects/SoObject.m: use application context when looking up the
+         default method
+
+2004-06-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * woapp-gs.make, wobundle-gs.make: patches to use Contents/Resources 
+         as the resources directory on MacOSX (v4.2.394)
+       
+       * v4.2.393
+       
+       * WOComponentRequestHandler.m: properly generate content-type if none
+         is set in the response
+
+       * ngobjweb.make: added static linking flags for Mach linker
+
+       * Templates/WODParser.m (_parseProperty): now correctly parses key
+         pathes starting with a boolean substring like "true" or "NO"
+         (eg 'trueFlag') (v4.2.392)
+
+       * WORequestHandler.m: added KVC support for MacOSX (v4.2.391)
+
+2004-06-11  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SoObjects/SoPageInvocation.m: added KVC support for MacOSX (v4.2.390)
+
+2004-06-10  Stephane Corthesy  <stephane@sente.ch>
+
+       * v4.2.389
+
+       * WOResourceURLAssociation.m, WOStats.m: explicitly use 
+         -browserLanguages for resource lookup if there is no session
+
+       * WOBody.m, WOEmbeddedObject.m, WOImageButton.m, WOJavaScript.m,
+          WOResourceURL.m, _WOConstResourceImage.m, _WOResourceImage.m:
+         [hm, what was the change here?]
+       
+2004-06-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SoObjects/SoObjectRequestHandler.m: improved handling of NSNull
+         objects in the traversal stack, avoids coredumps in some edge
+         condition (v4.2.388)
+
+2004-06-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOApplication.m, WORequest.m, WORequestHandler.m: fixed gcc 3.4
+         warnings (v4.2.387)
+
+2004-06-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.386
+
+       * GNUmakefile.preamble: added prebinding
+
+       * SoObjects/SoPageInvocation.m: fixed code formatting
+
+2004-06-09  Stephane Corthesy  <stephane@sente.ch>
+       
+       * v4.2.385
+       
+       * Defaults.plist: added "WONoSelectionString" default (defaults to
+         "WONoSelectionString")
+       
+       * WORequest.[hm]: fixed parsing of URIs without request handler pathes 
+         (like /x.woa/wr?abc), added WONoSelectionString variable and default
+
+       * WOContext.[hm]: added -queryStringFromDictionary: method, rewrote
+         -directActionURLForActionNamed:queryDictionary: to use that. Fixed
+         -urlWithRequestHandlerKey:path:queryString: to append to application
+         extension
+
+       * Templates/WODParser.m: allow keypath strings which contain a slash 
+         ('/') (eg "src = urlKVC/path/to/file.html;")
+
+2004-06-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * DynamicElements/WOString.m: fixed default (YES) for 'escapeHTML' 
+         binding in cluster subclasses (was correct in _WOComplexString, but
+         wrong in the other ones). This might fix OGo bug #625 (v4.2.384)
+       
+       * DynamicElements/WOString.m: never escape value of 'valueWhenEmpty'
+         binding as suggested by Stephane (v4.2.383)
+       
+       * DynamicElements/WOPopUpButton.m: some code cleanups, properly close
+         the <option> tag for the 'nilValue' (v4.2.382)
+
+       * v4.2.381
+               
+       * _WOStringTable.m: added -description method
+
+       * WOComponent.m: changed -description to be more consistent with the
+         rest of the system
+
+2004-06-09  Stephane Corthesy  <stephane@sente.ch>
+       
+       * _WOStringTable.m: support .strings files in NSDictionary plist format
+       
+       * Associations/WOKeyPathAssociationSystemKVC.m: now properly supports
+         caret (^) notation
+       
+       * WOCoreApplication.m: added -setPrintsHTMLParserDiagnostics: and
+         -printsHTMLParserDiagnostics for enabling/disabling the output
+         validation
+
+2004-06-08  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.380
+
+       * SoObjects/SoComponent.m: minor logging improvement
+
+       * SoObjects/SoProductResourceManager.m, Defaults.plist: added default 
+         SoProductResourceManagerDebugEnabled to enable logging
+
+       * WOResourceManager.m (RSRCDIR_CONTENTS): this was only defined for
+         Xcode builds, it is now also enabled for gstep-make on OSX (which
+         also places resources in Contents/Resources) (this change makes
+         UI-X work on OSX)
+
+       * v4.2.379
+       
+       * GNUmakefile.preamble (libNGObjWeb_LIB_DIRS): fixed relative search
+         pathes
+
+       * SoObjects/SoProductRegistry.m: use bundle manager to get bundle 
+         objects, fixed a bug which lead to duplicate product registration
+         (and a set of resulting other issues), on MacOSX. Apparently
+         bundle uniquing is broken on MacOSX
+       
+       * SoObjects/SoClassSecurityInfo.m: be more tolerant about NSNull 
+         values, improved error logging
+
+       * NGObjWeb/WOCoreApplication.h: fixed for MacOSX compilation 
+         (NSTimeInterval was missing)
+
+2004-06-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOResourceManager.m: fixed a gcc 3.4 warnings (v4.2.378)
+
+2004-06-05  Helge Hess  <helge.hess@opengroupware.org>
+
+       * DynamicElements/WOString.m: added 'valueWhenEmpty' as suggested by
+         Stephane, various code cleanups (v4.2.377)
+
+2004-06-04  Stephane Corthesy  <stephane@sente.ch>
+
+       * WODisplayGroup.m: added special KVC support for "queryMatch.",
+         "queryMax.", "queryMin." and "queryOperator." keys (v4.2.376)
+
+2004-06-02  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SoObjects/SoObjectRequestHandler.m: added support for
+         rapidTurnAround (v4.2.375)
+
+2004-06-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.374
+       
+       * DynamicElements/WOxHTMLElemBuilder.m: use WOGenericContainer for
+         generating <a name=""> anchors instead of silently dropping the 
+         element
+       
+       * DynamicElements/WOGenericElement.m: some code cleanups
+
+2004-06-01  Stephane Corthesy  <stephane@sente.ch>
+
+       * v4.2.373
+
+       * WOApplication.h, WODirectAction.h, WOComponent.h: added prototypes
+         for logging methods, so that those are available in case NGExtensions
+         is not included
+
+       * WOCoreApplication.[hm]: added implementation of 
+         -terminateAfterTimeInterval:
+
+       * WOApplication+defaults.m, Defaults.plist: added: 
+         WOApplicationBaseURL, WOAutoOpenInBrowser, WOCGIAdaptorURL, 
+         WOFrameworksBaseURL
+
+2004-05-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOResponse.m: minor code cleanups (v4.2.372)
+
+2004-05-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOMessage+Validation.m: do not trigger validation for text/plain
+         (v4.2.371)
+
+2004-05-16  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SoOFS/SoOFS-SXP-Info.plist, SoObjects/SoCore-SXP-Info.plist: new
+         entries for Xcode build (v4.2.370)
+
+2004-05-13  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOCoreApplication.m: fixed a typo (v4.2.369)
+
+2004-05-11  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SoObjects/SoObjectRequestHandler.m: minor tweak for MacOSX Foundation
+         (v4.2.368)
+
+2004-05-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.367
+       
+       * WOMessage+Validation.m: added validation functionality for XML and 
+         HTML
+       
+       * WOCoreApplication.m: validation of generated output can be turned on
+         using the WOOutputValidationEnabled default
+
+2004-05-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * DynamicElements/WOJavaScript.m: minor code cleanups (v4.2.366)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.365)
+
+2004-05-05  Helge Hess  <helge.hess@skyrix.com>
+
+       * WORequest.m: if a browser language region code (like de-ch) cannot be
+         found, retry the lookup with the major language code (in this case 
+         'de') (as suggested by Stephane Corthesy) (v4.2.364)
+
+       * WOApplication.m: removed old license check, added 
+         "WOLogDefaultsOnStartup" default to enable logging of the default
+         configuration on server startup (as suggested by Stephane Corthesy)
+         (v4.2.363)
+
+2004-05-04  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGObjWeb/NGObjWeb.h: include WOMailDelivery.h and WOStatisticsStore.h
+         as suggested by Stephane Corthesy (thanks!) (v4.2.362)
+
+2004-05-04  Helge Hess  <helge.hess@skyrix.com>
+       
+       * DynamicElements/_WOComplexHyperlink.m: added special handling for
+         mailto: and javascript: URLs in href links (not processed using
+         NSURL) (v4.2.361)
+
+2004-05-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * DynamicElements/WOString.m: fixed a typo (v4.2.360)
+
+2004-05-01  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.359
+       
+       * WOMessage: added +setDefaultEncoding:/+defaultEncoding class methods
+         as suggested by Stephane Corthesy (thanks!) and as available in 
+         WO 4.5.
+       
+       * WOCookie: added missing set accessors as suggested by Stephane
+         Corthesy (thanks!) and as available in WO 4.5. Deprecated -expireDate
+         methods in favor of the WO 4.5 -expires/-setExpires: methods,
+         since WOCookie objects are not immutable anymore, changed the
+         NSCopying implementation to return a real copy
+
+2004-04-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * some minor cleanups to log messages
+
+       * WOComponent.m, Defaults.plist: added debugging default
+         'WOCoreOnAwakeComponentInCtxDealloc'
+
+2004-04-30  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SoOFS/OFSFolderDataSource.m: didn't work at all when no qualifier
+         was set (v4.2.358)
+
+2004-04-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * DynamicElements/WOBrowser.m: improved XHTML compatibility for bool
+         attributes (v4.2.357)
+
+2004-04-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * DynamicElements/WORadioButton.m: code cleanups (v4.2.356)
+
+2004-04-20  Jean-Alexis Montignies <ja@sente.ch>
+       
+       * WOResourceManager: added
+         -stringForKey:inTableNamed:withDefaultValue:inFramework:languages:
+         method, simplified implementation (v4.2.355)
+       
+2004-04-19  Jean-Alexis Montignies <ja@sente.ch>
+        
+       * WOKeyPathAssociation.m: added support for float and double (v4.2.354)
+
+2004-04-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOHyperlink.m: moved the cluster subclasses to separate files 
+         (v4.2.353)
+
+       * v4.2.352
+
+       * DynamicElements/WOJavaScript.m: code cleanups
+
+       * Templates/WOWrapperTemplateBuilder.m: fixed for Linux compilation
+
+2004-04-17  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * v4.2.351
+
+       * WOApplication.m: fixed generated HTML in -handleException:inContext.
+         If application is in RAD mode, extracts templateURL from exception's
+         userInfo and sets "x-sope-template-path" header appropriately.
+        
+       * Templates/WOWrapperTemplateBuilder.m: exceptions during template
+         parsing are being caught now before being re-raised.
+         During exceptions some necessary cleanup will be performed and the
+         templateURL will be added to the exception's userInfo for later
+         extraction.
+
+       * WOApplication.m, WOCoreApplication.m, WOHTTPConnection.m,
+         WOSimpleHTTPParser.m, WOWatchDogApplicationMain.m,
+         WOHttpAdaptor/WOHttpAdaptor.m: replaced all occurrences of "catched"
+         with "caught" in log statements and comments.
+
+2004-04-16  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOComponent.m: print a warning if the component name is set to nil
+         (v4.2.350)
+
+2004-04-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * Templates/WOxTemplateBuilder.m: minor code cleanups (v4.2.349)
+
+2004-04-16  Jean-Alexis Montignies  <ja@sente.ch>
+
+       * v4.2.348
+       
+       * WOComponent.m: resolve plist unarchiver references using KVC pathes
+       
+       * WOComponentDefinition.m: set component as delegate for plist 
+         unarchiver
+       
+2004-04-15  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * WOComponentDefinition.m: fixed use of incorrect variable in .woo
+         initializer, as reported by Jean-Alexis (v4.2.347)
+
+       * WOComponent.m, WOComponentDefinition.m: .woo postprocessing is
+         now triggered by WOComponent -init, the component definition is 
+         passed in the wocVariables ivar (HACK CD!) (v4.2.346)
+
+2004-04-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.345
+       
+       * WOComponentDefinition.m: minor code cleanups, implement
+         -_finishInitializingComponent: which loads the .woo and does some
+         other postprocessing
+       
+       * WOComponent.m: added -_setContext: private method and use that
+         instead of assigning to self->context
+
+       * WOApplication.m: added -_pageWithName:inContext: private method
+         (which is wrapped by -pageWithName:inContext:)
+
+2004-04-12  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * WOContext.m: improved -applicationURL to handle empty adaptor
+         prefixes (v4.2.344)
+
+2004-04-11  Helge Hess  <helge.hess@opengroupware.org>
+
+       * Languages.plist: added de-lu, en-gb, fr-be and fr-lu mappings
+         (v4.2.343)
+
+2004-04-09  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * Templates/WOHTMLParser.m: -[NSException setUserInfo:] does
+         not exist on MacOSX (v4.2.342)
+
+2004-04-07  Jean-Alexis Montignies   <ja@sente.ch>
+
+       * v4.2.341 (requires libNGExtensions v4.2.77)
+
+       * WOApplication: Added +eoEditingContextClass and 
+          +implementsEditingContexts dependant on the
+          availability of EOEditingContext in EOControl.
+
+       * WOSession: Implemented -defaultEditingContext, bumped class version
+         because an ivar was added
+       
+       * WORequest: Implemented -formValues.
+
+2004-04-07  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * Templates/WOWrapperTemplateBuilder.m: use 
+         -stringEncodingForEncodingNamed: on Cocoa (v4.2.340)
+
+2004-04-06  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * WOHTMLParser.m, WODParser.m: fixed a missing return statement, 
+         introduced in v4.2.338 (thanks Jean-Alexis for reporting :-) 
+         (v4.2.339)
+       
+2004-04-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.338
+
+       * WODParser.m, WOHTMLParser.m, WOWrapperTemplateBuilder.m: added 
+         support for using UTF-8 as the parsing encoding, can be enabled 
+         using the WOParsersUseUTF8 bool default (Note: this slows the parser
+         down).
+       
+       * WODParser.m: added support for parsing 'true' and 'false'
+
+2004-04-05  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.337
+
+       * WOComponentDefinition.m: added support for woo variables stored in 
+         the template
+
+       * WOWrapperTemplateBuilder.m: parse .woo file, remember .woo variables
+         in template and add a hack to support .woo file encodings
+
+       * WOTemplate.m: added ability to store extra, KVC encoded, component
+         variables, as contained in .woo files
+
+       * WOComponentDefinition.m, WOComponent.m: moved .woo loading from
+         WOComponent to WOComponentDefinition as suggested by ja@sente.ch 
+         (v4.2.336)
+
+2004-04-04  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOComponent.m: use just the component name as the login prefix
+         (without <>), properly deal with components without a name
+         (v4.2.335)
+
+2004-04-01  Helge Hess  <helge.hess@opengroupware.org>
+
+       * Languages.plist: added mapping of fr-fr to French (v4.2.334)
+
+2004-03-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * Associations/WOAssociation.m: minor fix to cache log message 
+         (v4.2.333)
+
+2004-03-29  Helge Hess  <helge.hess@opengroupware.org>
+
+       * DynamicElements/WORadioButtonList.m: code cleanups (v4.2.332)
+
+2004-03-26  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOComponentDefinition.m: fixed support for components without 
+         classes, some related warnings can be disabled by setting the
+         WOEnableComponentsWithoutClasses default (v4.2.331)
+
+2004-03-24  Helge Hess  <helge.hess@skyrix.com>
+
+       * DynamicElements/WOConditional.m, WOTextField.m: subminor code 
+         cleanups (v4.2.330)
+
+2004-03-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoSelectorInvocation.m: fixed a typo (v4.2.329)
+
+2004-03-21  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.328
+       
+       * WEClientCapabilities.m: added Ecto as a known client (BLog, XML-RPC)
+       
+       * SoObjectXmlRpcDispatcher.m, Defaults.plist: added default to enable
+         debug logs 'SoObjectXmlRpcDispatcherDebugEnabled', implemented first
+         working version of SOPE XML-RPC invocation using positional 
+         parameters
+       
+       * SoProductClassInfo.m: enhanced manifests for selector invocations
+       
+       * SoSecurityManager.m: minor improvements on the debug logs
+       
+       * SoSelectorInvocation.m: added ability to call methods with 
+         positional parameters as submitted by the XML-RPC dispatcher
+       
+2004-03-18  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOComponent.m: added empty default implementation of 
+         -unableToSetNilForKey: to support Cocoa KVC (v4.2.327)
+
+2004-03-17  Helge Hess  <helge.hess@skyrix.com>
+
+       * Languages.plist: added "es-es" language mapping (v4.2.326)
+
+2004-03-11  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * v4.2.325
+
+       * WOApplication.m: If in RAD mode sets new HTTP header bearing the path
+         to the current page template.
+        
+       * WOComponent+private.h: Expose private method
+         - (WOElement *)_woComponentTemplate;
+        
+       * WOTemplate.[hm]: New accessor - (NSURL *)url
+
+2004-03-16  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOComponent: fixed (the new) KVC extravar handling on gstep-base and
+         MacOSX (v4.2.324)
+
+2004-03-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.323
+
+       * SoObjects/SoSelectorInvocation.m: minor improvement to response 
+         generation (if GET is called directly on the method object)
+
+       * v4.2.322
+
+       * WOComponent.m, WOSession.m: improved KVC handling on Cocoa and 
+         gstep-base, uses "-handleQueryWithUnboundKey:" for extra variables
+
+       * SoObjects/SoProductClassInfo.m, NGXmlRpc: fixed a warning
+
+       * WOApplicationMain.m, WOWatchDogApplicationMain.m, xmlrpc_call.m: use 
+         explicit NSProcessInfo initialization if GS_PASS_ARGUMENTS is defined
+         (for some gstep-base setups) (v4.2.321)
+
+2004-03-11  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * v4.2.320
+
+       * Associations/WOKeyPathAssociation.m: new approach for fixing the
+         CoreFoundation related issue of possible immutability of
+         NSMutableDictionary.
+
+       * DynamicElements/WOxHTMLElemBuilder.m: Do not create WOHyperlink
+         element if <a /> tag has a name attribute (anchor). Also, do not
+         create WOHtml element at all.
+       
+       * DynamicElements/WOHtml.m: Minor fixes for obvious copy/paste
+         mistakes.
+
+2004-03-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * DynamicElements/WOComponentReference.m: removed inclusion of
+         private WOKeyPathAssociation header file (no reason for that) 
+         (v4.2.319)
+
+2004-03-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.319
+
+       * WOComponent.m, WOSession.m: improved KVC handling on Cocoa and 
+         gstep-base
+
+2004-03-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.318
+
+       * NGObjWeb/WebDAV/SoWebDAVRenderer.m: fixed a minor compilation
+         warning with gstep-base
+
+       * SoObjects/SoObjCClass.m: changed not use -stringWithoutSuffix:
+
+2004-03-07  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.317
+
+       * NGXmlRpc/NGXmlRpcClient.m: generate capitalized "Basic" authorization
+         header, required by eGroupware, improved processing of HTML
+         responses to XML-RPC calls (usually webserver error pages)
+       
+       * WOHttpAdaptor/WOHttpTransaction.m, WOContext.m, SoObjects/SoObject.m:
+         check for :0 ports
+
+       * WORequest.m: make language codes lowercase prior mapping
+
+       * WOMessage.m(-setHeaders:): properly process array values
+
+       * Languages.plist: map de-at to German
+
+       * SoObjects/SoProductClassInfo.m: added support for "valueClass"
+         slots which do not have a value (an instance of the class is created
+         using just -init)
+
+2004-03-03  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WebDAV/SoObjectWebDAVDispatcher.m, WebDAV/SoDAVSQLParser.m: fixed 
+         not to use deprecated EOControl API (v4.2.316)
+
+2004-03-02  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.315
+
+       * Languages.plist: mapped "de-ch" to German, fixes OGo bug #666
+
+       * NGXmlRpc: improved NGXmlRpcClient class to allow more HTTP tweaking
+
+2004-03-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.314
+       
+       * Associations/WOAssociation.m: the association class used for 
+         keypathes can now be configured using the WOKeyPathAssociationClass
+         default
+
+       * Associations/WOKeyPathAssociation.m: moved KVC category on 
+         NSUserDefaults to a separate file
+       
+       * Associations: added WOKeyPathAssociationSystemKVC association, which
+         uses the Foundation KVC implementation for improved WO compatibility
+
+       * WebDAV: removed dependency on EOSQLParser, added own SoDAVSQLParser
+         classes (different SQL dialect anyway) - should help with GDL2
+         compatibility
+       
+2004-03-01  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOHTTPConnection.m: write default "accept" and "user-agent" HTTP 
+         headers in case none are specified in a WORequest. Improves 
+         compatibility with the Roxen HTTP server (v4.2.313)
+
+2004-03-01  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOComponent.m: components can now load .woo files as emitted by
+         WebObjects Builder - you need to set the default 
+         WOComponentLoadWOOFiles to enable that (v4.2.312)
+
+2004-03-01  Helge Hess  <helge.hess@opengroupware.org>
+
+       * Templates/WOHTMLParser.m: allow for lowercase WO tags (v4.2.311)
+
+2004-02-29  Helge Hess  <helge.hess@opengroupware.org>
+
+       * Templates/WOHTMLParser.m: added ability to parse templates containing
+         <WEBOBJECT> tags, as requested by ZNeK for rapid turnaround support
+         with WebObjects Builder (v4.2.310)
+
+2004-02-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.309
+
+       * WOSession.m: fixed a small issue in the content-type processing,
+         thanks chunsj for pointing that out!
+
+       * WOHTTPConnection.m: subminor code cleanup
+
+       * v4.2.308
+       
+       * Templates/WOxElemBuilder.m: log a note if debugging is turned on,
+         ensure that +initialize is only called once (on MacOSX)
+       
+       * WOResourceManager.m: fixed resource lookup in MacOSX rapid 
+         turnaround mode
+
+2004-02-25  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.307
+
+       * WOResourceManager.m: improved error logging (backport from SX5)
+
+       * Associations/WOKeyPathAssociation.m: do not protected keypath 
+         evaluation using exception handlers - major slowdown and only really
+         useful in debugging contexts. Exception handlers can be reactivated
+         by passing "WOAssociationExceptionHandlers=yes" to make when 
+         compiling NGObjWeb
+
+2004-02-23  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.306
+
+       * WOApplication.m(-shouldTerminate): subminor cleanups
+
+       * WebDAV/SaxDAVHandler.m: ensure that a local variable is initialized
+       
+2004-02-19  Helge Hess  <helge.hess@opengroupware.org>
+
+       * Associations/WOKeyPathAssociation.m: added a hack to workaround
+         to find out whether a dictionary is immutable - even immutable
+         dictionaries have a -setObject:forKey: on Cocoa (v4.2.305)
+
+       * WOComponent.m, WOApplication.m: added KVC default handlers for Cocoa
+         Foundation (avoids some exceptions, libFoundation is much more 
+         tolerant regarding missing KVC keys than Cocoa) (v4.2.304)
+
+2004-02-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * Languages.plist: map pt-br to ptBR instead of "Portuguese-Brazil" 
+         (the .lproj's are ptBR.lproj) (v4.2.303)
+
+2004-02-19  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.302
+
+       * SoObjects/SoObject.m: ensure that no port ":0" is attached to object
+         URLs
+
+       * SoObjects/SoHTTPAuthenticator.m: return a proper 401/www-authenticate
+         response if an empty password is passed in
+
+2004-02-18  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.301
+
+       * Defaults.plist: explicitly list some adaptor defaults
+
+       * Languages.plist: mapped bt-br browser lang-code to Portuguese-Brazil
+         (fixes OGo bug 631)
+
+2004-02-17  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.300
+
+       * WOSimpleHTTPParser.m: added very simple support for 100-continue to
+         make the Mono HTTP client happy
+
+       * WOSimpleHTTPParser.m: trims trailing spaces in header lines
+
+       * WOSimpleHTTPParser.m, Defaults.plist: added defaults to configure
+         the WOSimpleHTTPParser: WOSimpleHTTPParserDebugEnabled,
+         WOSimpleHTTPParserHeavyDebugEnabled, 
+         WOSimpleHTTPParserFileIOBoundary, WOSimpleHTTPParserMaxUploadSizeInKB
+
+2004-02-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.299
+
+       * WORequest.m: missing browser-mapping log is now a debug-level log
+
+       * Languages.plist: added "es-cl" to Spanish mapping
+
+2004-02-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * DAVPropMap.plist: added mappings for {DAV:} source, executable, 
+         supportedlock, lockdiscovery properties as submitted by Konqueror
+         (v4.2.298)
+
+       * Languages.plist: added "pt-pt" to Portuguese mapping (v4.2.297)
+
+2004-02-13  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * v4.2.296
+
+       * README: documented new -WOProjectDirectory default
+
+       * WOResourceManager.m, WOApplication.m: added support for new
+         -WOProjectDirectory default. If set, resources will be looked
+         up there instead of using the default mechanism.
+
+       * SNSConnection.m: wrapped all safeWrite: methods to raise exceptions.
+         Not doing so breaks the existing checks. At least on OSX this did
+         prevent SNSConnection from running as expected.
+
+2004-02-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * DynamicElements/WOImage.m: moved some cluster subclasses to separate
+         source files, properly create a _WOConstResourceImage for constant
+         'filename' bindings (v4.2.295)
+
+2004-02-12  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.294
+       
+       * Languages.plist: add some country/language codes (as submitted by
+         Safari)
+       
+       * WORequest: rewrote to parse the accept-language header on its own
+         (instead of relying on the deprecated NGHttpRequest methods), print
+         a warning if the browser language map could not be found
+       
+       * GNUmakefile: another fix to the Version for the MacOSX linker
+       
+       * WEClientCapabilities.m: added new -ignoresCSSOnFormElements probe
+         for detecting browsers like Safari which do not apply stylesheets
+         on form elements (v4.2.293)
+
+2004-02-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * Templates: minor code cleanups in various files (v4.2.292)
+
+2004-02-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.291
+
+       * SoOFS/OFSFileRenderer.m: do not use -initWithTimeIntervalSince1970:
+         on MacOSX (deprecated in Cocoa)
+
+       * Templates/WOWrapperTemplateBuilder.m, 
+         WOHttpAdaptor/WOHttpTransaction.m: fixed compilation warnings on
+         MacOSX
+
+2004-02-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * DynamicElements/WOString.m: added support for 'format' binding (used
+         in conjunction with the 'formatterClass' binding for creation of
+         custom formatters) (v4.2.290)
+
+2004-02-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGXmlRpc: deprecated some API in NGXmlRpcClient (v4.2.289)
+         (what happened to 4.2.288?)
+
+2004-02-01  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.287
+
+       * SoObjects/SoObject+Traversal.m: modified key traversal so that
+         path-info is correctly set if a key right *after* a callable could
+         not be found (eg /object/myMethod/junk)
+
+       * SoObjects/SoProductRegistry.m, SoProduct.m: generate a simple 
+         registry representation
+
+2004-01-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOHttpAdaptor/WOHttpAdaptor.m: minor cleanups (v4.2.287)
+
+       * v4.2.286
+       
+       * NGHttp: removed an unnecessary debug log
+       
+       * GNUmakefile, Version: moved the MacOSX version hack to GNUmakefile
+         since the SKYRiX 5 migration tool will break on that otherwise
+
+2004-01-25  Helge Hess  <helge.hess@opengroupware.org>
+
+       * DynamicElements/WOGenericElement.m: minor cleanups (v4.2.285)
+
+2004-01-22  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile, SoApplication.m: provided include of -I../WebDAV/
+         and removed #include "WebDAV/..." because this breaks stupid
+         Xcode.
+         (v4.2.284)
+
+2004-01-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttp+WO.m: fixed a log (always logged the _decodeMultiPart.. stuff)
+         (v4.2.283) 
+
+2004-01-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOComponent.m, SoApplication.m, SaxDAVHandler.m: fixed some 
+         compilation warnings (v4.2.282)
+
+2004-01-03  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.281
+
+       * WOHttpAdaptor/WOHttpTransaction.m: fixed logging of response zipping
+         information
+       
+       * WOStatisticsStore.m: minor speed improvements and cleanups
+
+       * WOResponse.m: added default to debug 'zipping' of response contents,
+         fixed detection of the clients ability to process zipped responses
+         (in other words: pages should now (again) be zipped automatically)
+
+2003-12-31  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.280
+
+       * DynamicElements/WOConditional.m: code cleanups
+
+       * WOElementID.m: subminor cleanups
+
+       * Associations/WOKeyPathAssociation.m: minor cleanups
+
+2003-12-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.279
+       
+       * WebDAV/SoWebDAVRenderer.m: fixed rendering of propertyname-only
+         WebDAV queries (fixes OGo bug 503), use appendContentXMLString
+       
+       * WOMessage.m: added default WOProfileResponse for collecting append 
+         statistics, make more use of cached selectors
+       
+2003-12-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * DAVPropMap.plist: added mappings for two OOo DAV properties 
+         (v4.2.278)
+
+2003-12-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: added Kung-Log as a known user-agent, added
+          new typing checks "isXmlRpcClient" and "isBLogClient" (v4.2.277)
+
+2003-12-11  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WebDAV/SoObjectWebDAVDispatcher.m: allow delete properties during
+         object creation for iSync (v4.2.276)
+
+       * SoObjects/SoObject.m: added methods to calculate containment pathes
+         (-pathArrayToSoObject, -reversedPathArrayToSoObject) and a method to
+         calculate the containment stack (objectContainmentStack) (v4.2.275)
+
+       * v4.2.274
+
+       * DynamicElements/WOxHTMLElemBuilder.m: only create WOMetaRefresh 
+         elements for "http-equiv=refresh" (was previously used for anything
+         which has a "http-equiv" attribute)
+
+       * added new "WOResourceURLAssociation", only available in XML templates
+       
+       * added new - shorter - namespace mappings. "OGo:bind", "OGo:value",
+         "OGo:script" and "OGo:url" (only for associations!)
+       
+       * Templates/WOxElemBuilder.m: made namespace->association mapping a
+         default
+
+2003-12-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOComponent.m: subminor cleanups to some logging messages (v4.2.273)
+
+2003-12-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SoObjects/SoObjectMethodDispatcher.m: ensure that the method-object 
+         which was looked-up, is indeed callable. If not, return the object
+         itself (relates to OGo Bug #480) (v4.2.272)
+
+       * WEClientCapabilities.m: added Apple CoreFoundation user-agent as a
+         known one (v4.2.271)
+
+2003-12-09  Helge Hess  <helge.hess@skyrix.com>
+       
+       * SoObjects/SoHTTPAuthenticator.m: fixed an authentication bug 
+         introduced in v4.2.268 (v4.2.270)
+       
+2003-12-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile.postamble: install woapp-gs.make and wobundle-gs.make
+         in all but gstep-make 1.3.0 (which is the local OGo version) 
+         (v4.2.269)
+
+2003-12-07  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.268
+
+       * SoObjects/SoObjectXmlRpcDispatcher.m: made a bit more tolerant
+         regarding invalid input
+
+       * SoObjects/SoHTTPAuthenticator.m: fixed parsing of basic auth 
+         credentials
+
+       * NGHttp+WO.m: major cleanups in form decoding code (v4.2.267)
+
+2003-12-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: marked Safari as CSS and fast-table browser
+         (v4.2.266)
+
+2003-11-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.265
+
+       * GNUmakefile: added principal classes to the product bundles
+
+       * Templates/GNUmakefile: include project makefile from 
+         GNUSTEP_MAKEFILES (as suggested by chunsj@embian.com)
+
+2003-11-29  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WEClientCapabilities.m: added Morgul as a known (WebDAV) user agent
+         (v4.2.264)
+
+2003-11-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.263
+
+       * WebDAV/SoWebDAVRenderer.m: subminor cleanups
+
+       * WebDAV/SoObjectWebDAVDispatcher.m: unescape destination URL pathes
+         for MOVE/COPY operations (related to bug 456)
+
+2003-11-25  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WODirectActionRequestHandler.m: check whether class being used for
+         direct action actually responds to -initWithContext: - if not, no
+         object will be activated (v4.2.262)
+
+2003-11-24  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOMessage.m(-setHTTPVersion:): log a message if the version passed in
+         doesn't start with "HTTP/" (fixes OGo Bug 434) (v4.2.261)
+
+2003-11-23  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.260
+       
+       * SoObjects/SoObject.m: added some tweaks to generate a proper URL
+         even if x-webobjects-server-url reports a wrong port (mismatch of
+         host port and URL port)
+
+       * WOContext.m: replaced some defines with regular BOOL configurations
+
+       * SoObjects/SoProduct.m: fixed -description
+
+2003-11-21  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WebDAV/SoWebDAVRenderer.m: generate a preliminary etag to keep
+         WebFolders happy (v4.2.259)
+
+       * v4.2.258
+       
+       * WebDAV/SoObjectWebDAVDispatcher.m: added proper depth generation for
+         IE WebFolders (do not use flat+self on IE and Evo)
+
+       * WebDAV/SoObject+SoDAVQuery.m: do not include self in resultsets when
+         accessing with IE webfolders
+
+       * WebDAV/SoWebDAVRenderer.m: do not deliver content in the DELETE
+         response if the status is set to 204 (no content) ...
+
+       * WOSimpleHTTPParser.m: added "destroy" as a known header (sent by
+         IE 6)
+       
+       * WebDAV/SoWebDAVRenderer.m: improved debug logging
+
+2003-11-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.257
+
+       * SoWebDAVRenderer.m: minor improvements to GET/HEAD rendering
+
+       * SoObjects/WORequest+So.m: added ability to detect "break-DAV"
+         (/servlet/webdav. URIs), small fix to login code
+
+       * DAVPropMap.plist: mapped seven new WebDAV properties submitted by
+         WebFolders (IE 6)
+
+2003-11-21  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.256
+
+       * WebDAV/SoObjectWebDAVDispatcher.m: more tweaks for MOVE/COPY
+
+       * SoObjects/SoObject+Traversal.m: properly differentiate between
+         MOVE/COPY source and target pathinfo handling
+       
+       * WebDAV/SoWebDAVRenderer.m: added ability to render MOVE and COPY
+         result codes
+
+2003-11-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.255
+
+       * SoObject+Traversal.m: necessary tweaks for MOVE/COPY
+       
+       * SoWebDAVDispatcher.m: added initial implementation for WebDAV
+         MOVE and COPY operations
+       
+       * SoObject+SoDAV.[hm]: added method prototypes for WebDAV move and
+         copy operations
+
+       * WOSimpleHTTPParser.m: added "overwrite" as a known header
+
+       * SoObjects/SoObject.m, SoObjects/SoProduct.m, 
+         WebDAV/SoObjectDataSource.m: properly URL escape object names prior
+         adding them to URLs! (v4.2.254)
+
+2003-11-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * WebDAV/SoWebDAVRenderer.m: properly XML escape URLs which are part 
+         of a WebDAV response (fixed SX 1896), added a default to trigger
+         the generation of "good looking" WebDAV (inserts newlines in the
+         output for debugging) (v4.2.253)
+
+2003-11-19  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOApplication+defaults.m: comment the use of some default (v4.2.252)
+
+2003-11-18  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.251
+
+       * NGAsyncResultProxy: fixed the header file, replaced some retain
+         macros with methods
+
+       * WOGenericContainer.m: fixed a minor bug with an edge case where the
+         tag may not be defined
+
+       * WOAssociation.m, WOActionURL.m: minor tweak for OSX
+
+2003-11-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.250
+
+       * WebDAV/SoWebDAVRenderer.m: be smart about PUTAction return values
+
+       * WOSimpleHTTPParser.m: added "timeout" as a known header
+
+       * v4.2.249
+       
+       * WebDAV/SoObjectWebDAVDispatcher.m: minor cleanups
+
+       * WOSimpleHTTPParser.m: added "lock-token", "if" and "destination" as 
+         known headers
+
+2003-11-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.248
+
+       * SoObjects/SoProductClassInfo.m: improved logging of SoClasses
+         incorrectly declared in product.plist files (eg a product bundle
+         exporting a class it does not contain ...)
+
+2003-11-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * xmlrpc_call.m: added ability to force authentication (intended for
+         services which do not return a 401 on a protected resource, like
+         Zope) (v4.2.247)
+
+2003-11-04  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.246
+       
+       * WEClientCapabilities.m: added new MacOSX davfs user agent
+       
+       * DAVPropMap.plist: added WebDAV mappings for {DAV:}quota, quotaused
+         and {...}appledoubleheader, which are submitted by the Apple davfs
+
+2003-11-02  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOResponse.m: always use HTTP/1.0 as the response HTTP version
+         (before we just copied the version used in the request which
+         obviously is nonsense ...) (v4.2.245)
+
+2003-11-01  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WOSimpleHTTPParser.m: added x-forwarded-host, x-forwarded-server
+         and max-forwards as known headers (v4.2.244)
+
+2003-10-31  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.243
+       
+       * DynamicElements/WOMetaRefresh.m: properly add the session-id to the
+         query-string
+       
+       * DynamicElements/WOForm.m: code cleanups
+
+       * v4.2.242
+
+       * DynamicElements/WOHyperlink.m: smaller cleanups
+
+       * WOFileSessionStore.m: small code cleanups
+
+       * SoOFS/OFSFolder+SoDAV.m: fixed a warning
+
+       * WOServerSessionStore.m: small code cleanups
+
+2003-10-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoApplication.m: fixed a bug in new lookup code (did not
+         work with ZideStore, sigh), added lookup logging code (triggered by
+         SoDebugKeyLookup) (v4.2.241)
+
+       * v4.2.240
+
+       * SoObjects/SoObject.m: added SoDebugBaseURL default to enable debug
+         logs for SoObject base-url processing
+
+       * SoOFS/OFSFolder+SoDAV.m: added capability to create collections
+
+       * WebDAV/SoWebDAVRenderer.m: added ability to render MKCOL results
+
+       * WebDAV/SoObject+SoDAV.m: added default implementations for DAV
+         creation methods (which just return 405 exceptions ..)
+
+       * SoObjects/SoApplication.m: now forwards WebDAV resource creation 
+         requests to root folder. Further the application is now able to
+         lookup its own name (for /MyApp style path resolution)
+
+       * SoObjects/WORequest+So.m, Defaults.plist: added 
+         SoDebugRequestClassification default to control logging of request
+         classification (as WebDAV, XML-RPC, etc)
+
+Mon Oct 27 15:05:13 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * WOHttpAdaptor/WOHttpTransaction.m: if x-webobjects-server-port < 1
+         set x-webobjects-server-port to the [woRequest host] port (Apache 
+         2.x adaptor returns empty x-webobjects-server-port) (v4.2.239)
+
+2003-10-27  Thomas Schild  <ts@skyrix.com>
+
+       * Defaults.plist: added Dutch to WODefaultLanguages (v4.2.238)
+
+2003-10-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOResourceManager.m: improved lookup logging (v4.2.237)
+
+       * WOContext.m: changed serverURL (the base for most other URLs)
+         generation. Sometimes the mod_ngobjweb seems to report wrong ports
+         - so, if a 'host' header is available, we consider *that* as being
+         primary (v4.2.236)
+
+2003-10-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: properly detect version of Safari 1.1 -
+         this is a bit weird (Safari 1.1 reports v100 as its version ...)
+         (v4.2.235)
+
+       * v4.2.234
+
+       * WOResourceManager.m (-urlForResourceNamed:): avoid generation of two
+         slashes in URL (was triggered when WOResourcePrefix is set)
+
+       * DynamicElements/WOInput.m, DynamicElements/WOText.m: smaller cleanups
+
+2003-10-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile.preamble: explicitly link tools against libNGJavaScript
+         (v4.2.233)
+
+2003-10-20  Thomas Schild  <ts@skyrix.com>
+
+       * Defaults.plist: added ptBR to WODefaultLanguages
+
+2003-10-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.232
+
+       * GNUmakefile.preamble: mark when doing a gstep-make environment
+         compilation ...
+
+       * WOResourceManager.m: some modifications to support gstep-make on
+         MacOSX, added debugging defaults
+
+2003-10-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOHTTPConnection.m: improved request logging (v4.2.231)
+
+2003-10-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile.postamble (after-install): properly install NGObjWeb 
+         makefiles with gstep-make 1.7.4 (this is currently a fix makefile 
+         version check)
+
+2003-10-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.230
+
+       * WOHTTPConnection.m: added -description, added a lot of debug logs
+       
+       * SoObjects/SoProductRegistry.m: fixed a warning (v4.2.229)
+       
+       * Associations/WOKeyPathAssociation.m: patches to compile on MacOSX
+         without FoundationExt (adopted for the Apple runtime) (v4.2.228)
+
+2003-10-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.227
+
+       * SoOFS/OFSFolder.m: generalized authenticator lookup
+
+       * SoOFS/OFSBaseObject.m: avoid endless recursions in 
+         -authenticatorInContext:
+
+       * lots of fixes for compilation using gstep-make on MacOSX 
+
+2003-10-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.226
+
+       * WOPageRequestHandler.m, Defaults.plist: some code cleanups, added 
+         the WOPageRequestHandlerDebugEnabled log default
+
+       * WODirectActionRequestHandler.m: when a WOComponent class is used as
+         a direct-action, the code now applies the request on the component 
+         if it responds YES to shouldTakeValuesFromRequest:..
+
+       * NGObjWeb/WODirectAction.h: added -context method to public interface
+
+2003-10-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * common.h, NGObjWeb.h: minor fixes for MacOSX compilation (the port
+         is not finished yet) (v4.2.225)
+
+       * v4.2.224
+
+       * SoOFS: added a folder datasource class for querying contents of an
+         OFS folder and a "contentDataSource" method
+       
+       * SoObjects/SoTemplateRenderer.m: name the wrapper component of custom
+         components like the custom objects themselves
+
+       * SoObjects/SoObject+Traversal.m: improved debug logs
+
+       * v4.2.223
+       
+       * SoObjects/SoTemplateRenderer.m: added ability to render *any* 
+         object, not just WOComponent results
+
+       * SoObjects/SoObject.m: added -soClassName method to any SoObject
+
+       * SoOFS/OFSFile.m: moved renderer selection to 
+         SoRequestDispatcherRules
+
+       * Defaults.plist: added some renderer selections to the 
+         SoRequestDispatcherRules
+
+       * SoOFS/product.plist: set default access of OFSImage and 
+         OFSPropertyListObject to allow, so that acquisition works when we
+         lookup a template on the object
+
+       * SoOFS/OFSResourceManager.m: improved debug logging in error cases
+
+       * SoObjects/SoSubContext.m: fixed a bug in the description (parent
+         ctx was not properly logged)
+       
+       * SoObjects/SoSecurityManager.m: improved private key access exception
+
+2003-10-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m (WEUA_xmlrpclib_py): added Python XML-RPC
+         library as a known user-agent, smaller cleanups (v4.2.222)
+
+2003-10-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: detect NetNewsWire as a user-agent 
+         (v4.2.221)
+
+2003-10-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: added a new iCal.app user-agent (reports 
+         DAVKit instead of DAVAccess) (v4.2.220)
+
+2003-09-06  Helge Hess  <helge.hess@skyrix.com>
+
+        * fixed some MacOSX warnings (v4.2.219)
+
+2003-09-06  Marcus Mueller <znek@mulle-kybernetik.com>
+
+       * v4.2.218
+
+       * SoOFS/OFSFolder.m, SoObjects/SoObject+Traversal.m,
+         SoObjects/SoPageInvocation.m, SoObjects/SoProductResourceManager.m,
+         WebDAV/SoObject+SoDAVQuery.m: Casts for _ctx because of multiple
+         definitions of - response.
+         NOTE: I probably should have changed the interface,
+         but didn't know exactly if that was appropriate. However it seems
+         likely that this SHOULD be changed
+
+       * SoOFS/OFSHttpPasswd.m: Include <unistd.h> for crypt if on Apple
+         or FreeBSD. A quick glimpse revealed that the system gcc (3.2) on
+         FreeBSD 5.x doesn't define __FreeBSD__ which is most likely a bug
+         and should be reported. On FreeBSD 4.x everything's as expected.
+
+       * SoObjects/SoClass.h: class forward declarations include NSArray now
+
+2003-08-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile (RESOURCES_DIR): use GNUSTEP_RESOURCES instead of hard-
+         coded $(GNUSTEP_LOCAL_ROOT)/Libraries/Resources, do not pass the
+         RESOURCES_DIR to sourcecode (v4.2.217)
+
+2003-08-26  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGXmlRpc: small cleanup to exception handling (v4.2.216)
+
+2003-08-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOComponent.m, WOResourceManager.m: added some comments on the
+         -initWithContext: issue (v4.2.215)
+
+2003-08-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.214
+
+       * WOSimpleHTTPParser.m: added 'content-class' and 'if-none-match'
+         as known headers, both submitted by Entourage/X
+
+       * SoObjects/SoHTTPAuthenticator.m: split off domain names in login
+         strings (separated by backslash)
+
+       * v4.2.213
+
+       * WEClientCapabilities.m: added Entourage as a known user agent
+
+       * WOSimpleHTTPParser.m: added 'extension', 'ua-cpu' and 'ua-os',
+         all submitted by Entourage/X
+
+2003-08-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.212
+               
+       * WebDAV/SoWebDAVRenderer.m: added some very basic support for 
+         Exchange row range headers
+
+       * WebDAV/SoWebDAVRenderer.m, SoWebDAVValue.m: do not format XML output 
+         with newlines, this is good for improving WebStore compatibility
+
+2003-08-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: added detection of SOUP WebDAV library
+         (v4.2.211)
+
+2003-08-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.210
+
+       * GNUmakefile.preamble: do not link against libcrypt on OpenBSD
+
+       * SoOFS/OFSHttpPasswd.m: include des.h instead of crypt.h on OpenBSD
+         (pointed out by Max Berger, thanks!)
+
+2003-07-31  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.209
+
+       * DynamicElements/WOMetaRefresh.m: small cleanups
+
+       * DynamicElements/WOHTMLDynamicElement.m: ensure that components
+         returned by actions are awake in the current context, added a
+         debugging default to track action execution
+
+2003-07-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoObject.m: added a log if the hard coded default for
+         the broken SOUP library is used (v4.2.208)
+
+2003-07-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * applied rangeOfString patches provided by Filip Van Raemdonck for 
+         improved compilation with gstep-base (v4.2.207)
+
+       * applied GNUstep patches provided by Filip Van Raemdonck for improved
+         compilation with gstep-base (v4.2.206)
+
+2003-07-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.205
+
+       * SoObjects: improved the debug output
+       
+       * Defaults.plist: added some more default languages
+
+2003-07-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * Defaults.plist, WORequest.m, WOSession.m: made default language array
+         configurable using the WODefaultLanguages array default (v4.2.204)
+
+Fri Jul  4 17:55:15 2003  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved to OpenGroupware.org CVS repository
+
+       * removed old (pre-SOPE) ChangeLogs, uninteresting for OGo development
+
+2003-06-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * fixed some gcc 3.3 signed/unsigned warnings (v4.2.203)
+
+       * v4.2.202
+       
+       * WOResourceManager.m: major change in template lookup: consider the
+         bundle-path of a component class (shouldn't break anything, but who
+         knows ...)
+       
+       * SoObjects/SoProductRegistry.m: added a product lookup based on the
+         bundle (to be completed, right now only the last path component is
+         checked as the name ...)
+       
+       * WOResourceManager.m: replaced some RELEASE macros with methods
+       
+       * WOComponent.m: small cleanups, +initialize did not properly use the
+         didInit flag
+       
+       * SoObjects: added SoComponent, a WOComponent subclass which uses the
+         SoProductResourceManager for resource lookup (useful with product
+         bundles)
+       
+2003-06-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.201
+       
+       * SoObjects/SoObjects.h: included WORequest+So
+       
+       * SoObjects/product.plist: add SoApplication definition
+       
+       * SoObjects/SoProductClassInfo.m, SoObjects/SoProduct.m: improved 
+         handling of SoObject categories
+       
+       * SoObjects/SoClass.m: added -allKeys and -slotNames reflection methods
+       
+       * WOSimpleHTTPParser.m: added ms-webstorage as a known HTTP header
+         (v4.2.200)
+
+2003-06-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOContext.m: moved cursor tracking to WOComponent category, so that
+         custom subclasses (SkyPubComponent) can override it (v4.2.199)
+       
+2003-06-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOComponent.m: added a method which can be replaced to decide whether
+         extra variables are created (intendend for components which rely on
+         extra vars, like SkyPubComponent [News: not true, SkyPubComponent 
+         uses a JS shadow !]) (v4.2.198)
+
+2003-06-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: added -doesSupportUTF8Encoding to check for
+         UTF-8 capable browsers, properly recognize Apple's Safari browser
+         (previously detected as Mozilla) (v4.2.197)
+
+2003-06-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/WORequest+So.m: added -isSoWCAPRequest (v4.2.196)
+
+2003-05-31  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoOFS/OFSFolder.m: fixed calculation of default-method URI when
+         given a URI with a query-string (v4.2.195)
+
+2003-05-30  Helge Hess  <helge.hess@skyrix.com>
+       
+       * v4.2.194
+               
+       * SoOFS/OFSWebMethod.m: added support for POSTs (calls takeValues on
+         the component before returning it)
+       
+       * DynamicElements/WOComponentReference.m, Defaults.plist: added a
+         default (WOCoreOnRecursiveSubcomponents) to produce a coredump if
+         a component embeds itself (which is not necessarily an error, but
+         often it is)
+       
+       * SoObjects/SoObjectRequestHandler.m: added support for "XXX:method"
+         form values which are used with submit-buttons
+
+       * WOElementID.m: ensure element-id size constraints
+       
+       * v4.2.193
+       
+       * sope.m: modified to work with SMI
+
+       * SoObjects/product.plist: updated permissions
+
+2003-05-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.192
+
+       * Templates: improved error handling for WOx templates
+
+       * WOApplication.m ([WOApplication -handleException:inContext:]): fixed
+         a bug, the -handleException: method triggered a session creation in
+         session-less sites (when trying to output to session-id)
+       
+       * more fixes to compile and run on MacOSX
+
+2003-05-28  Helge Hess  <helge.hess@skyrix.com>
+       
+       * v4.2.191
+       
+       * SoObjects/WOContext+SoObjects.m: added -parentContext and 
+         -rootContext methods
+
+       * added UnixSignalHandler for compilation without FoundationExt on 
+         MacOSX
+
+2003-05-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * various fixes to compile on MacOSX (v4.2.190)
+
+2003-05-26  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoObject+Traversal.m: do not stop at executable objects
+         during traversal, so that we can call methods on methods (eg manage)
+         (v4.2.189)
+
+       * v4.2.188
+
+       * WOComponent+JS.m: fixed -initialize ... (the category also
+         declared an own +initialize method
+
+       * SoObjects/SoSubContext.m: fixed a bug with the SubContext's ID being
+         the same like the parent ctx-id, causing problems with the awake
+         state of a component
+
+       * SoObjects/SoOFS: major fixes to "clientObject" handling
+       
+       * WOComponent.m: only log extra-variable creation if we have a 
+         WOComponent subclass (since with components without an own class we
+         can only use extra variables ...)
+       
+       * SoOFS: added OFSWebDocument, map 'xhtml' extension to OFSWebDocument
+       
+       * SoOFS: prepared classes for ChangeLog files and htpasswd files
+
+       * SoObjects/SoClassRegistry.m: added support for exact names
+
+       * SoOFS/OFSFactoryRegistry.m: allow file extensions to determine 
+         folder factory, added exact-name support
+
+       * SoObjects: moved SoSecurityException to own file
+
+       * SoObjects/SoSecurityManager.m: various cleanups
+
+2003-05-23  Helge Hess  <helge.hess@skyrix.com>
+       
+       * SoOFS: added methods to detect version control systems (v4.2.187)
+       
+       * v4.2.186
+               
+       * WOComponentDefinition.m: small cleanups
+
+       * Templates/WOTemplateBuilder.m: select WOxTemplateBuilder based on
+         the WOxFileExtensions default (default: wox, xtmpl, xhtml)
+
+       * SoOFS: added OFSWebTemplate handler for xtmpl templates
+
+       * SoOFS/OFSResourceManager.m: uses -traverseKey with a subcontext to
+         acquire resources, added logging (SoOFSResourceManagerDebugEnabled)
+       
+       * SoObjects/SoObject.m(-lookupName:): added capability to acquire from
+         the container (should we add context-acquisition ?, see NOTES)
+       
+       * SoTemplateRenderer.m: allows selection of template using the 
+         "template" query parameter
+
+       * SoSubContext.m: copy traversal stack, keep clientObject,
+         set request-type to "INTERNAL" - all this is required to keep the
+         context
+       
+2003-05-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.185
+
+       * Defaults.plist: used template-renderer for OFSWebMethod's
+
+       * SoObjects/SoTemplateRenderer.m: first working version ! locates
+         templates with name "Main"
+
+       * WOxComponentElemBuilder.m: added support for <var:component value="">
+         to embed components by value instead of reference (eg if you keep
+         a WOComponent object in an ivar)
+       
+       * WOContext.m: explicitly ensure that the page is put to sleep, even
+         if the page is not marked as awake in the context. Also ensure that
+         the page is awaked in the context if it's set via -setPage:.
+       
+       * WOComponent.m: fixed a bug in _contextWillDealloc, a context mismatch
+         was reported even though the context was correct (the context-*id*
+         references was compared to the context object ...)
+       
+       * SoObjects: added SoSubContext for nested SOPE lookups (v4.2.184)
+
+2003-05-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.183
+
+       * SoOFS/OFSFileRenderer.m: changed to be a fully compliant renderer,
+         now also does the actual rendering (moved in code from OFSFile)
+       
+       * SoOFS/OFSWebMethod.m: moved OFSWebMethodRenderer to separate file
+       
+       * v4.2.182
+       
+       * SoOFS/OFSWebMethod.m: added specialized renderer for OFSWebMethod
+       
+       * modified renderer API to return an NSException instead of just a
+         bool (so that not all renderers need to implement NSException
+         rendering)
+       
+       * started SoTemplateRenderer
+       
+       * WebDAV/SoWebDAVRenderer.m: do not crash when a SOPE app is called
+         on a root URI '/', fixes bug 1592 (v4.2.181)
+       
+       * v4.2.180
+       
+       * SoObjects/SoObjectRequestHandler.m: 
+         - do not add empty path components to traversal path
+         - use default renderer if a renderer rejected an object (important 
+           for rendering exceptions)
+
+       * SoObjects/SoObjectRequestHandler.m: fixed a bug, SoRequestType was
+         not properly set in context resulting in wrong renderer for WebDAV
+         requests (v4.2.179)
+
+2003-05-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.178
+
+       * SoObjects: improved logging
+
+       * WORequest.m: added debug-logging
+
+       * SoObjectRequestHandler.m: use new NGExtension rules system to select
+         dispatcher, renderer and acquisition - requires NGExtension 4.2.33 !
+         (v4.2.177)
+
+2003-05-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.176
+
+       * SoObjects/SoProduct.m: added -description
+
+       * SoObjects/SoObjectRequestHandler.m: moved request classification into
+         category of WORequest (new files WORequest+So)
+
+       * GNUmakefile: added Version file to SoOFS and SoCore products
+
+2003-05-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * sope.m: the tool can now load a site-local defaults file located in
+         ".sope.plist". the defaults are loaded into the registration domain
+         (should become an own domain)
+
+       * WOSimpleHTTPParser.m, OFSFolder.m: fixed signed/unsigned warning 
+         (v4.2.175)
+
+2003-05-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.174
+
+       * SoOFS/OFSFile.m: return self on GET, use a renderer
+
+       * SoObjects/SoObjectRequestHandler.m: use traversal stack to find the
+         renderer for an object
+       
+       * v4.2.173
+
+       * SoOFS/OFSFile.m: added support for HEAD, cleaned up rendering (still
+         needs more work ...)
+
+       * NGHttp: smaller cleanups
+
+       * SoObjects/SoObjectRequestHandler.m: some cleanups, does consider the
+         appname part of the URI traversal path if the request handler key is
+         not detected as a registered one
+
+       * v4.2.172
+
+       * WOApplication.m: cleaned up login
+
+       * SoOFS/OFSWebMethod.m: added OFSWebMethodDebugEnabled default to
+         trigger debug logging, fixed a bug in component caching
+
+2003-04-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * Templates/WOHTMLParser.m: fixed a gcc 3.3 warning
+
+       * WOHTMLParser: added support for "hash tags" (eg <#name/>) (v4.2.171)
+
+2003-04-24  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoSecurityManager.m: disabled buggy permission cache, needs
+         to be fixed (v4.2.170)
+
+       * WOWatchDogApplicationMain.m: do not log signal code for SIGCHLD
+         (v4.2.169)
+
+2003-04-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * WebDAV: added support for MKCOL for creating collections (v4.2.168)
+
+2003-04-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: recognize ZideLook 0.9.5 plugin (changed user
+         agent identifier) (v4.2.167)
+
+2003-04-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.166
+       
+       * SoObjectRequestHandler.m: does request path aquisition per default,
+         fixed a retain bug (the path traversal array), added a facility to
+         put objects to sleep (they must implement either _sleepWithContext:
+         or just sleep and will be called after all processing is done)
+       
+       * SoObject+Traversal.m: fixed a bug in the name of the logging default
+       
+       * OFSFolder.m: added code to some negotiation of the object to be
+         located (eg you can lookup 'index.html' by looking up 'index')
+       
+       * OFSWebMethod.m: smaller cleanups
+       
+       * WOApplication.m: smaller cleanups
+       
+       * SoClassSecurityInfo, SoClass: added more logging, keeps associated 
+         class name
+       
+       * added 'sope' tool for hosting SoOFS based SOPE applications
+       
+       * DAVPropMap.plist: added {DAV:}status (v4.2.165)
+       
+2003-04-11  Helge Hess  <helge.hess@skyrix.com>
+        
+       * SoObjects/SoObjectRequestHandler.m: made WebDAV methods to check
+         for determining the SOPE handler a userdefault (v4.2.164)
+          
+2003-04-01  GNUstep User  <helge.hess@skyrix.com>
+
+       * DynamicElements/WOText.m: use -rangeOfString: instead of 
+         -indexOfString: (v4.2.163)
+
+Fri Mar 28 17:19:33 2003  Martin Hoerning  <mh@skyrix.com>
+
+       * WebDAV/SoObjectWebDAVDispatcher.m: fixed bulk target pathes where 
+         the base uri path was not properly unescaped (v4.2.162)
+
+2003-03-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * WebDAV/GNUmakefile: export SoObjectResultEntry.h as a public header
+
+2003-03-19  Helge Hess  <helge.hess@skyrix.com>
+       
+       * WebDAV/SoObjectWebDAVDispatcher.m: fixed a bug with _range queries
+         (an empty ID was added for the first _) (v4.2.161)
+
+       * v4.2.160
+
+       * WOHttpTransaction.m, WOResponse.m: moved body zipping code to 
+         response, so that it can be used in different adaptors
+
+       * WOHttpTransaction.m: removed unused (#if 0) code
+
+       * WOSimpleHTTPParser.m: added if-match as a known header (v4.2.159)
+
+2003-03-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.158
+
+       * SoObjects/SoControlPanel.m: added -appendToResponse:inContext:
+         for rendering a HTML representation (a GET should be bound by SMI)
+       
+       * SoObjects/SoSecurityManager.m: add support for special "<public>"
+         permission
+
+2003-03-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.157
+
+       * WebDAV/SoObject+SoDAVQuery.m: caught traversal exceptions in
+         bulk-path queries
+         
+       * SoObjects/SoSecurityManager.m: initialize security exceptions with
+         name and reason
+       
+2003-03-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * WebDAV/SoObject+SoDAVQuery.m: use traversePath for bulk targets that
+         contain slashes
+
+       * SoObjects/SoObjectRequestHandler.m, 
+         WebDAV/SoObjectWebDAVDispatcher.m: handle empty range queries
+         (v4.2.156)
+
+2003-03-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * WebDAV/SoObject+SoDAVQuery.m: always query davURL (v4.2.155)
+
+       * Defaults.plist: added {DAV:}href as default property
+
+2003-03-11  Helge Hess  <helge.hess@skyrix.com>
+       
+       * WebDAV/SoObjectWebDAVDispatcher.m: added support for ZideLook range
+         queries (transformed into bulk-queries) (v4.2.153)
+       
+2003-03-07  Helge Hess  <helge.hess@skyrix.com>
+       
+       * WebDAV/SaxDAVHandler.m: hopefully fixed the <prop> set vs <prop>
+         response the last time (v4.2.152)
+
+2003-03-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOSimpleHTTPParser.m: added "x-forwarded-for" as a known header
+         (v4.2.151)
+
+2003-03-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoObjectRequestHandler.m: fixed bug, query parameters were
+         not properly cut off when doing the URI processing in the handler,
+         added support for ASP ?Cmd style methods (v4.2.150)
+
+       * WebDAV/SaxDAVHandler.m: added a DAVParserDebugProp and 
+         DAVParserHeavyLog defaults for improved debugging, fixed yet another
+         bug in the property "set" handler (if each property was enclosed in
+         an individual "set" tag, only the last was delivered) (v4.2.149)
+
+2003-03-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxDAVHandler: fixed another bug in prop-patch parsing (if the prop-
+         patch contained a "delete" section, no values were returned 
+         (v4.2.148)
+
+2003-02-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.147
+
+       * SaxDAVHandler: fixed a bug in property-patch parsing
+
+       * SoObjects/SoSecurityManager.m: allow operations on objects which
+         are not owned
+
+       * SoObjects/SoObjectRequestHandler.m: set a HTTP header for the
+         SxNewObjectID context variable
+
+       * WOSimpleHTTPParser.m: added x-zidestore-name as known header
+
+2003-02-24  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOSimpleHTTPParser.m: added 'if-modified-since' as a known header
+         (v4.2.146)
+
+2003-02-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * WebDAV/SaxDAVHandler.m: fixed a bug with properties in the DAV: 
+         namespaces not being parsed in property-update and prop tags,
+         added a delegate for parsing results (v4.2.145)
+         
+2003-02-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoObject.m(lookupName:inContext:acquire:): if a key
+         is contained in the toOneRelationshipKeys array, lookupName will
+         now use -valueForKey: to find a name
+       
+       * WebDAV/SoObject+SoDAV.m: an object now becomes a DAV collection
+         marker if it the toOneRelationshipKeys array is not empty
+
+       * SoObjects/SoApplication.m(hasName:inContext:): fixed a bug with
+         name-lookup when the root object is the application itself
+
+2003-02-17  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGObjWeb/WOComponent.h: added missing declaration of NSException
+
+       * NGObjWeb/WODynamicElement.h: removed unnecessary declaration of
+         NSMutableArray and WOComponent
+
+       * NGObjWeb/WOElement.h: removed unnecessary declaration of NSException
+
+2003-02-14  Helge Hess  <helge.hess@skyrix.com>
+       
+       * WebDAV/SaxDAVHandler.m: added basic DASL query capabilities,
+         orderings still missing (v4.2.144)
+
+       * WOSimpleHTTPParser.m: added version control HTTP methods as known
+         methods (v4.2.143)
+
+2003-02-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoClass.m: added -copyWithZone: for OSX (v4.2.142)
+
+2003-01-31  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: added ZideLook detection (v4.2.141)
+
+2003-01-30  Helge Hess  <helge.hess@skyrix.com>
+       
+       * WebDAV: subscription manager almost complete (v4.2.140)
+       
+       * v4.2.139
+       
+       * WOSimpleHTTPParser.m: added UNSUBSCRIBE as a known HTTP method
+       
+       * WebDAV: started subscription manager
+       
+       * NGXmlRpc: added reflection support on MacOSX (v4.2.138)
+
+2003-01-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGXmlRpc bugfix by bs@skyrix.com (v4.2.137)
+
+2003-01-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGXmlRpcClient.m: abstracted HTTP connection and request in abstract
+         class factories (-connectionClass and -requestClass), removed 
+         dependency on XmlRpcMethodResponse+WO and XmlRpcMethodCall+WO
+         (v4.2.136)
+
+2003-01-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOSimpleHTTPParser.m: added 'p3p', 'set-cookie' and 'x-powered-by' 
+         as known headers (v4.2.135)
+
+2003-01-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.134
+       
+       * WOProxyRequestHandler.m: added facility to log to files
+       
+       * WOMessage.m: added -headersAsString method (useful for debugging)
+       
+       * WOSimpleHTTPParser.m: added 'server', 'x-cache', 'proxy-connection'
+         and 'subscription-id' as known headers
+       
+       * SoObjects/SoObjectRequestHandler.m: if the request-handler-key in the
+         request does not match a registered one, process the request URI
+         in this class (v4.2.133)
+       
+       * NGHttp: check superclass version (v4.2.132)
+       
+2003-01-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.131
+
+       * NGXmlRpc: bugfix with parameter counts
+
+       * Templates/WOHTMLParser.m (_isWOCloseTag): fixed a bug with parsing
+         tags (in files were the ">" of the close tag is the
+         last char of the file)
+
+2003-01-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * WebDAV/SoObjectWebDAVDispatcher.m: fixed an Evo bug with unsafe
+         chars in BPROPFIND target URLs (v4.2.130)
+
+       * v4.2.129
+       
+       * SoOFS/OFSPropertyListObject.m: improved factory and -saveObject to be
+         able to deal with new objects
+       
+       * SoOFS/OFSFactoryContext, OFSFolder: added a context creation method
+         for objects that do not yet exist in the store
+
+       * WebDAV: added handling for bulk queries to NSObject+SoDAV (v4.2.128)
+
+       * v4.2.127
+
+       * WebDAV: changed implementation of BPROPFIND. BPROPFIND doesn't use
+         individual queries for each target anymore, but passes relative
+         target names in the "bulkTargetKeys" fetch hint, this way it can be
+         processed by a SQL based datasource much faster.
+       
+       * WOSimpleHTTPParser.m: improved processing of content-length
+
+2003-01-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * WebDAV/SoObjectWebDAVDispatcher.m: fixed a bug in the BPROPFIND
+         implementation (v4.2.126)
+
+       * WORequest.m: added parsing of query parameters and form content in
+         query-parameter format (v4.2.125), multipart-formdata is not yet
+         processed
+
+       * WORequest.m: print a warning if the form parameters could not be
+         calculated (eg if you use the current WOSimpleHTTPParser)
+
+       * NGHttp+WO.m: replaced some RETAIN macros
+
+       * WOSimpleHTTPParser.m: added support for streamed uploads (large 
+         HTTP request bodies are streamed into a temporary file which is 
+         mapped into memory) (v4.2.124)
+
+       * v4.2.123
+
+       * WOHttpAdaptor/WOHttpTransaction.m: use request logging method for
+         WOSimpleHTTPParser (method became independed from NGHttpRequest)
+
+       * WOHttpAdaptor/WOHttpAdaptor.m: replaced RETAIN macros with methods
+
+       * WOSimpleHTTPParser.m: added some missing headers, added parsing of
+         content-length
+
+       * WebDAV fixes (v4.2.122)
+
+       * v4.2.121
+
+       * WebDAV/SoObject+SoDAVQuery.m: fixed typo
+
+       * WebDAV/SoObject+SoDAV.m: added default -dav* methods for 
+         WOCoreApplication, WOApplication and WORequestHandler
+
+       * SoObjects/SoApplication.m: added -toOneRelationshipKeys
+
+       * DynamicElements/WOPopUpButton.m: properly close option tag (v4.2.120)
+
+       * v4.2.119
+       
+       * WOHttpAdaptor/WOHttpTransaction.m: added a faster logging (does not
+         use -descriptionWithCalendarFormat:), replaced some RETAIN macros,
+         use gettimeofday() for calculating request-duration, use char* 
+         instead of NSString for reason, added a deliverResponse that uses
+         less NGTextStream operations and more direct buffer writes
+       
+       * WOSimpleHTTPParser.m: added "cookie" as a known header
+       
+       * v4.2.118 (results of NGObjWeb raw-performance "weekend", after
+         profiling on OSX
+       
+       * Templates/WOxElemBuilder.m: created WOSimpleStaticASCIIString for
+         ASCII strings (ASCII detection speed needs to be improved !)
+       
+       * DynamicElements/WOGenericElement.m, WOGenericContainer.m: added code
+         to handle constant tag-names efficiently
+
+       * DynamicElements: use WOResponse_AddCString if possible
+       
+       * DynamicElements/WOCompoundElement.m: replaced some RETAIN macros
+       
+       * DynamicElements/WOString.m: added WOSimpleStaticASCIIString subclass
+         (this class uses -appendContentCString: for a quick addition), 
+         replaced some RETAIN macros
+       
+       * WORequestHandler.m: return 404 on calls to /favicon.ico
+       
+       * WOHTTPConnection.m: fixed an OSX compiler warning
+
+       * SoObjects/SoApplication.m: fixed a bug, lookup always returned a
+         WORequestHandler (since requestHandlerForKey: returns the default
+         handler if the key did not match)
+
+       * WOElementTrackingContext.h: added -appendIntElementIDComponet:
+
+       * WOResponse+private.h: use macros for direct WOMessage access, added
+         macros for adding integers
+
+       * WOSession.m: replaced some RETAIN macros
+
+       * WOResponse.m: improved speed of -disableClientCaching, caches
+         GMT timezone, does not use -descriptionWithCalendarFormat: for
+         speed and locale-indepedence
+
+       * WODynamicElement.m: use -appendContentCString:
+
+       * WOCoreApplication.m: replaced some retain macros, cache some defaults
+
+       * WOCookie.m: cache GMT timezone during generation, replaced some
+         RETAIN macros
+
+       * WOApplication.m: generate session-id using sprintf for speed, 
+         replaced some RETAIN macros
+
+       * WOApplication+defaults.m: cache request-handler key defaults
+
+       * added WOElementID class for fast element-id tracking and
+         generation (more than twice as fast)
+       
+       * WOMessage.m: added -appendContentCString: for adding ASCII strings
+         (much faster than using -dataUsingEncoding: if we know that a string
+         is ASCII since most other encodings are "ASCII-compatible")
+       
+       * WOContext.m: caches URL prefixes (faster URL generation), moved 
+         element-id processing to WOElementID, several minor changes for speed
+
+2003-01-10  Helge Hess  <helge.hess@skyrix.com>
+        
+       * added generation of SoProduct bundles for SoCore and SoOFS (v4.2.117)
+
+2003-01-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOHttpAdaptor/WOHttpTransaction.m: cleaned up default initialization,
+         added default to enable WOSimpleHTTPParser (v4.2.116)
+
+       * Templates/WOHTMLParser.m (_makeHtmlException): only add parser to
+         exception userinfo if the parser is passed to _makeHtmlException
+         (v4.2.115)
+
+       * NGXmlRpc, xmlrpc_call: completed Unix domain sockets (v4.2.114)
+
+       * WOHTTPConnection.m: rewrote to base connections on NSURL (in 
+         preparation for HTTP-over-Unix-Domain-Sockets) (v4.2.113)
+
+       * NGXmlRpcClient, xmlrpc_call: started support for HTTP digest auth
+
+       * WOSimpleHTTPParser.m: added request parsing (v4.2.112)
+
+2003-01-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.111
+
+       * WOHTTPConnection.m: added support for WOSimpleHTTPParser (must be 
+         turned on using a default)
+
+       * started WOSimpleHTTPParser
+
+2003-01-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOHTTPConnection, NGXmlRpcClient, xmlrpc_call: added SSL support 
+         (v4.2.109)
+       
+       * v4.2.108
+
+       * SoOFS/OFSFactoryRegistry.m: added some code to allow SoClass'es 
+         behave as factories (located using the extension manifest key)
+
+       * SoOFS/OFSFolder.m: move factory method to a separate category
+
+       * WOHttpAdaptor/WORecordRequestStream.m: use defines for buffer sizes
+
+       * SoObjects/SoSecurityManager.m: some little code cleanups
+
+       * SoObjects/SoProductClassInfo.m: some code cleanups, process the
+         SoClass->extension mapping of the manifest
+
+       * SoObjects/SoObjCClass.m: added the -objcClass method to find the
+         implementation of a SoClass
+
+       * SoObjects/SoApplication.m: allow lookup of request-handlers
+
+       * replaced RETAIN macros with method calls in several places
+
+       * WOApplication.m: fixed a bug in the -path method, if the app wrapper
+         could not be found, the application retain count was broken
+
+2003-01-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoProductClassInfo.h: fixed header (NSArray was missing)
+         (v4.2.107)
+
+2003-01-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoProductClassInfo.m: parse extensions code from manifest
+         (v4.2.106)
+
+Thu Jan  2 11:07:43 2003  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.105
+       
+       * Templates/WOxComponentElemBuilder.m: fixed a compiler warning (added
+         a informal protocol for -line)
+       
+       * WOApplication.m: now reports a missing app-path (.woa wrapper) only
+         once
+
+Fri Dec 27 11:18:34 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.104
+
+       * WOMessage.m: some modifications to -appendContentCharacter: which
+         breaks if optimization is turned on in MacOSX Dec2002 devtools !,
+         also prints a warning if NSString is ever used to add a character
+         (performance warning ...)
+       
+       * WOPageRequestHandler.m: fixed a warning
+
+       * WOCoreApplication.m: allow capitalized keys on MacOSX (this usually
+         prints warnings on OSX), check for "COMPILE_AS_FRAMEWORK" instead of
+         "NGOBJWEB_AS_FRAMEWORK"
+       
+       * WOComponentRequestHandler.m: fixed a warning
+
+       * Templates/WOxElemBuilder.m: small code cleanups
+
+       * Templates/WOxTemplateBuilder.m: disabled logging on OSX too
+
+       * Templates/WOxComponentElemBuilder.m: fixed a bug, 'className' was
+         passed to the created component as a binding
+
+       * SoOFS/OFSResourceManager.m: fixed some compilation warnings
+       
+       * SoOFS/OFSBaseObject.m: return nil for unbound keys (OSX)
+
+       * NGXmlRpc: small code cleanups
+       
+       * SoObjects/WOContext+SoObjects.m: do not use -removeObjectForKey: on
+         WOContext anymore (use -setObject:nil forKey: instead)
+       
+       * SoObjects/SoSecurityManager.m: small logging improvement
+       
+       * SoObjects/SoProductRegistry.m: check for COCOA_Foundation_LIBRARY
+         instead of APPLE_Foundation_LIBRARY, do not fail product loading
+         of the MAIN bundle (eg if the main program is a tool)
+
+       * SoObjects/SoPageInvocation.m: fixed a warning
+
+       * SoObject.m, SoProduct.m, SoProductResourceManager.m: use basic
+         string methods for URL construction since 
+         -stringByAppendingPathComponent: doesn't work for URLs on
+         MacOSX
+
+       * SoObjects/SoHTTPAuthenticator.m: removed empty -dealloc
+
+       * SoObjects/NSException+HTTP.m: return nil for unbound keys (OSX)
+       
+       * WebDAV/SoObjectDataSource.m: check whether lookupName: returned an
+         exception
+       
+       * WebDAV/SoObject+SoDAV.m: added an exception handler for some key 
+         lookup on OSX, since OSX throws unbound key exceptions per default
+         (to be changed, OSX behaviour should be standard in libFoundation)
+       
+       * WOTextField.m, WOText.m, WOQuickTime.m: fixed a warning
+       
+Mon Dec 23 15:57:27 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.103 (results of OSX compilation)
+
+       * SoObjects/WODirectActionRequestHandler+SoObjects.m: fixed a bug, if
+         no context was available the lookup sent -context to the 
+         WOApplication class instead of the instance
+
+       * SoObjects/SoSelectorInvocation.m: does not rebind bound invocations
+
+       * SoObjects/SoSecurityManager.m, WOContext+SoObjects.m: fixed some
+         warnings
+
+       * SoObjects/SoProductRegistry.m: print log if main-bundle could not be
+         determined
+
+       * SoObjects/SoObjectRequestHandler.m: improved handling of root object
+
+       * SoObjects/SoObject.m: removed lookupKey completly (was still
+         available for compatibility reasons), added _initialize for 
+         initialization of category globals
+
+       * SoObjects/SoObjCClass.m: fixed invalid number of args in NSAssert
+
+       * SoClassSecurityInfo.h, SoObject.h, SoProductRegistry.h, 
+         WOContext+SoObjects.h: added NSArray which was missing in the header
+         file (for MacOSX)
+       
+       * SoObjects/SoApplication.m: only check for EnableDoubleReleaseCheck
+         on libFoundation
+
+       * Templates/WOWrapperTemplateBuilder.m: fixed a bug, when no root 
+         element was available the parsing result was undefined
+
+       * WODisplayGroup.m: fixed a bug, used -objectForKey: with the wrong
+         variable
+       
+       * OWViewRequestHandler.m, WOComponent.m, WOCoreApplication.m, 
+         WOHTTPURLHandle.m, WORequestHandler.m, WORepetition.m, 
+         SaxDAVHandler.m, SoObjectDataSource.m, SoProductClassInfo.m:
+         fixed gcc 3.2 warnings
+       
+2002-12-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects/SoClassRegistry.m: added a file-extension=>SoClass registry
+         (v4.2.102)
+
+2002-12-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoOFS/OFSFolder.m: fixed a typo
+
+       * WebDAV/SoObject+SoDAVQuery.m: fixed a bug with WebDAV deep queries
+         (v4.2.101)
+
+       * Defaults.plist: added a preferred WebDAV prefix for the Cadaver
+         namespace
+
+2002-12-11  Helge Hess  <helge.hess@skyrix.com>
+       
+       * SoOFS/OFSFile.m: added a generic "writeState:" method
+
+2002-12-08  Helge Hess  <helge.hess@skyrix.com>
+       
+       * WOComponent.m: improved -description
+
+       * WOComponentFault.m: reenabled usage of parent-resourcemanager, this
+         was #ifdef'ed out, why (problems with SKYRiX Forms) ?
+       
+       * WOResourceManager.m: added a -resourceNameForComponentNamed: to map
+         component names to resource names (previously this was fixed to .wox
+         files)
+       
+       * WOComponentDefinition.m: do not search for classes if the component
+         name contains a "."
+
+       * SoObjects: - fixed a problem with the default renderer returning an
+         empty result when the SoHTTPAuthenticator refused to render a 
+         security exception 
+         - added a GETAction: to OFSFolder which does a redirect to uri+/view
+         (v4.2.100)
+
+2002-12-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved to skyrix-sope-42 (v4.2.99)
+         - removed WOExtensions, WEExtensions (moved to Skyrix41e/WebUI)
+
+2002-11-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects: renamed -lookupKey:inContext: to 
+         -lookupName:inContext:acquire: (v4.2.98)
+
+2002-11-28  Helge Hess  <helge.hess@skyrix.com>
+       
+       * WebDAV.subproj: pass a context into DAV PROPPATCH methods (v4.2.97)
+       
+2002-11-25  Helge Hess  <helge.hess@skyrix.com>
+       
+       * WebDAV.subproj: fixed a bug in SoObjectDataSource,
+         -toOneRelationshipKeys of the object is checked, if the brief header
+         is set, no null properties are encoded (correct ???)
+         (v4.2.96)
+       
+       * SoObjects.subproj/SoHTTPAuthenticator.h: added public API (v4.2.95)
+
+       * Defaults.plist (WOxBuilderClasses): added WOxXULElemBuilder
+
+       * DynamicElements.subproj/WOxXULElemBuilder.m: started XULElemBuilder
+
+2002-11-22  Helge Hess  <helge.hess@skyrix.com>
+       
+       * SoOFS: cleanup of OFS storage system (v4.2.94)
+       
+2002-11-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * DynamicElements.subproj/WOForm.m, WOComponent.m: added a 
+         -shouldTakeValuesFromRequest:inContext: to check whether a form
+         should take the values even though it's href or element-id doesn't
+         match the request (v4.2.93)
+       
+       * WOComponent.m: added -redirectToLocation: for easy redirection in
+         response to an action of any kind (v4.2.92)
+       
+       * SoObjects.subproj/SoProductClassInfo.m: added support for non-method
+         slots (v4.2.91)
+
+2002-11-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * Associations.subproj/WOKeyPathAssociation.m: added faster number to
+         string conversions by using static strings for numbers < 50,
+         added a HEAVY_DEBUG define (v4.2.90)
+
+       * WebDAV: improved object datasource and DAV datasource handling
+         (v4.2.89)
+       
+       * Templates.subproj/WOxElemBuilder.m: added association for so-lookup
+         namespace (v4.2.88)
+
+       * SoObjects: added a SoApplication (v4.2.87)
+
+2002-11-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOResourceManager.m: added more bundle sensitivity (v4.2.86)
+       
+       * SoObjects: added product management system (v4.2.85)
+       
+2002-11-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOHttpAdaptor.subproj/WOHttpTransaction.m: ensure that 
+         x-webobjects-server-name and x-webobjects-server-port are always
+         set (v4.2.84)
+
+       * WebDAV.subproj/SoObjectWebDAVDispatcher.m: properly check permissions
+         of WebDAV methods (previously only WebDAV access was checked) 
+         (v4.2.83)
+
+       * SoObjects: added SoHTTPAuthenticator (v4.2.82)
+
+2002-11-17  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects, SoOFS: authenticator object is now local to the object and
+         acquired using the container (v4.2.81)
+
+2002-11-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * WebDAV.subproj/SoWebDAVRenderer.m: added SoWebDAVValue for rendering
+         complex WebDAV properties (v4.2.80)
+
+       * WOHTTPConnection.m: added -initWithURL:
+
+       * GNUmakefile: fixed includes (v4.2.79)
+
+       * WebDAV.subproj/SoObjectWebDAVDispatcher.m: added support for 
+         BPROPFIND (v4.2.78)
+
+       * WOContext: moved protocols from WOContext.h into separate header
+         files, added ivars for SOPE (clientObject, traversalStack),
+         increased version (v4.2.77)
+
+2002-11-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOMessage.m: prepared for content streaming, increased class version
+         (v4.2.76)
+               
+       * added first version of SoOFS (v4.2.75)
+
+2002-11-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * Associations.subproj/WOAssociation.m: support objects as values
+         which do not implement NSCopying (previously disallowed because
+         associations were cached) (v4.2.74)
+
+       * SoObjects: moved traversal code from SoObjectRequestHandler to
+         SoObject category (traversal is required in several environments)
+         (v4.2.73)
+       
+2002-11-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObject: fixed validation, added debugkey for SoObjectDataSource
+         (v4.2.72)
+
+       * WOComponentDefinition.m ([WOComponent -instantiateChildComponentsInTemplate:languages:]):
+         fixed a bug with components not passing down languages to child
+         components (v4.2.71)
+
+       * WOContext.m: fixed a small bug with the cursor debugging (cursor
+         pops were not reported correctly) (v4.2.70)
+
+2002-11-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * WebDAV.subproj/SaxDAVHandler.m: started support for DASL (SQL 
+         with XML syntax)
+
+       * added special SoClass subclass for ObjC classes (v4.2.69)
+
+2002-11-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttp: do not parse requests without clen in HTTP/1.1 (v4.2.68)
+
+       * started a new HTTP parser in NGHttpAdaptor (not used yet)
+       
+       * WebDAV: moved the query methods to a SoObjectDataSource class, which
+         is retrieved from the object using -davDataSourceInContext: (v4.2.67)
+
+2002-11-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects: first version supporting components as SoClass methods
+         (SoPageInvocation) (v4.2.66)
+
+2002-11-05  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects.subproj/SoSecurityManager.m: first version that actually
+         denies access to objects ;-) (v4.2.65)
+
+       * WEClientCapabilities.m: detect the GNOME-VFS (Nautilus) and mark
+         it as a WebDAV client (v4.2.64)
+
+2002-11-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.63
+
+       * WebDAV: added parsing of PROPPATCH queries, mapped some additional
+         DAV standard properties and provide a default implementation, added
+         PROPPATCH processing, use exceptions for most error responses, 
+
+       * SoObjects.subproj/SoSelectorInvocation.m: added a description and
+         -appendToResponse:inContext: in case the object is to be delivered
+         to the browser instead of being called
+
+       * SoObjects.subproj/SoObjectRequestHandler.m: added PROPPATCH as an
+         object creation method, create a PATH_INFO
+
+       * DAVPropMap.plist: added some classes
+
+2002-11-01  Helge Hess  <helge.hess@skyrix.com>
+       
+       * WebDAV.subproj: DAV property name->key mapping is now done in
+         NGObjWeb (v4.2.62)
+       
+       * WOComponentFault.m: added -setParent:, this fixes a bug introduced
+         in v4.2.57.
+
+       * started support for "renderer" objects, added SoDefaultRenderer and
+         SoWebDAVRenderer (v4.2.61)
+       
+       * moved WebDAV related SoObject stuff into a separate subproject,
+         WebDAV.subproj
+
+2002-10-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects.subproj/SoObjectWebDAVDispatcher.m: started subscribe/
+         unsubscribe support, uses attributes for search result generation
+         if available (v4.2.60)
+
+       * Defaults.plist: added SoPreferredNamespacePrefixes defaults to
+         configure default-prefixes for XML namespace generation
+
+       * NGHttp: added SUBSCRIBE/UNSCRIBE to the request methods were no body
+         parsing is performed (v4.2.59)
+
+2002-10-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: fixed Outlook detection (was recognized as
+         IE, not as Outlook ...).
+       
+       * SoObjects.subproj/EOFetchSpecification+SoDAV.m: changed to use the
+         new EOControl/EOSQLParser (v4.2.58)
+
+2002-10-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOComponent.m(-dealloc): reset parent pointers of subcomponents 
+         (v4.2.57)
+
+       * SoObjects: started security infrastructure (v4.2.56)
+
+       * Defaults.plist: added SoSecurityManagerDebugEnabled, 
+         SoLogSecurityDeclarations
+
+2002-10-25  Helge Hess  <helge.hess@skyrix.com>
+       
+       * SoObjects: abstracted DAV queries (PROPFIND, SEARCH) in
+         EOFetchSpecification (v4.2.55)
+       
+       * SoObjects: working dispatcher selection based on request (v4.2.54)
+
+2002-10-24  Helge Hess  <helge.hess@skyrix.com>
+
+       * SoObjects: started to add dispatcher and WebDAV support (v4.2.53)
+
+2002-10-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttp: added some WebDAV/HTTP methods (v4.2.52)
+
+       * WEClientCapabilities.m (WEUA_IE): recognizes Microsoft Outlook 
+         Express when used to access mailboxes over HTTP (v4.2.51)
+
+       * WOProxyRequestHandler.m: can act as a (non-transparent) HTTP proxy
+         (v4.2.50)
+
+       * WORequest.m: added -isProxyRequest to check whether we got a
+         proxy request ;-) (whether the URI passed is a full URL)
+
+       * WOHTTPConnection.m: filter out host headers during sending of request
+         headers (because host: is set by WOHTTPConnection itself)
+
+       * added the WOProxyRequestHandler for forwarding requests to other
+         HTTP servers (v4.2.49)
+       
+       * WEClientCapabilities.m: recognizes Microsoft Outlook 2002 when used
+         to access mailboxes over HTTP (v4.2.48)
+
+2002-10-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: added the Evolution WebDAV connector as a
+         known host (v4.2.47)
+
+2002-10-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOContext.m: disabled the new context-URL style (DnD should work 
+         again) (v4.2.47)
+
+       * some SoObject fixes (v4.2.46)
+
+       * v4.2.45
+
+       * a lot of work on the SoObject system (added classes, registry, 
+         selector invocation)
+
+       * WOHttpAdaptor.subproj/WOHttpTransaction.m: some code cleanup, added
+         some status-code=>reason mapping
+
+       * WEClientCapabilities.m: recognizes the curl program
+
+Fri Oct 18 10:59:16 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added SoObject support for WODirectActionRequestHandler and
+         WODirectAction (v4.2.44)
+       
+       * started SoObject support (object based request handling) (v4.2.43)
+
+1998-10-09  Helge Hess  <helge@trex.mdlink.de>
+
+       * added OWContext
+
+       * OWApplication.m: session cookie added
+
+       * created ChangeLog
diff --git a/skyrix-sope/NGObjWeb/DAVPropMap.plist b/skyrix-sope/NGObjWeb/DAVPropMap.plist
new file mode 100644 (file)
index 0000000..79ba954
--- /dev/null
@@ -0,0 +1,107 @@
+{
+  NGObjWeb_doc_   = "default WebDAV property mappings for NGObjWeb";
+  NGObjWeb_cvs_id = "$Id: DAVPropMap.plist,v 1.6 2004/07/17 16:28:23 helge Exp $";
+
+  /* DAV */
+  "{DAV:}iscollection"         = "davIsCollection";
+  "{DAV:}ishidden"             = "davIsHidden";
+  "{DAV:}uid"                  = "davUid";
+  "{DAV:}href"                 = "davURL";
+  "{DAV:}getlastmodified"      = "davLastModified";
+  "{DAV:}creationdate"         = "davCreationDate";
+  "{DAV:}getcontentlength"     = "davContentLength";
+  "{DAV:}getcontenttype"       = "davContentType";
+  "{DAV:}getetag"              = "davEntityTag";
+  "{DAV:}displayname"          = "davDisplayName";
+  "{DAV:}hassubs"              = "davHasSubFolders";
+  "{DAV:}nosubs "              = "davDenySubFolders";
+  "{DAV:}childcount"           = "davChildCount";
+  "{DAV:}objectcount"          = "davObjectCount";
+  "{DAV:}visiblecount"         = "davVisibleCount";
+  "{DAV:}isfolder"             = "davIsFolder";
+  "{DAV:}resourcetype"         = "davResourceType";
+  "{DAV:}contentclass"         = "davContentClass";
+  "{DAV:}isstructureddocument" = "davIsStructuredDocument";
+  "{DAV:}status"               = "davStatus";
+  "{http://apache.org/dav/props/}executable" = "davIsExecutable";
+
+  /* used with Apple WebDAV */
+  "{DAV:}quota"       = davQuota;
+  "{DAV:}quotaused"   = davQuotaUsed;
+  "{http://www.apple.com/webdav_fs/props/}appledoubleheader" = appleDoubleHeader;
+
+  /* new in current WebFolders */
+  "{DAV:}defaultdocument"    = davDefaultDocument;
+  "{DAV:}getcontentlanguage" = davContentLanguage;
+  "{DAV:}isreadonly"         = davIsReadOnly;
+  "{DAV:}isroot"             = davIsRoot;
+  "{DAV:}lastaccessed"       = davLastAccessed;
+  "{DAV:}name"               = davName;
+  "{DAV:}parentname"         = davParentName;
+  
+  /* new in Cadaver 0.21.0 */
+  "{DAV:}checked-in"  = davCheckedIn;
+  "{DAV:}checked-out" = davCheckedOut;
+  
+  /* Nautilus DAV support */
+  "{http://services.eazel.com/namespaces}nautilus-treat-as-directory" = 
+    "davIsFolder";
+
+  /* Konqueror */
+  "{DAV:}source"        = davSourceURL;
+  "{DAV:}executable"    = davIsExecutable;
+  "{DAV:}supportedlock" = davSupportedLock;
+  "{DAV:}lockdiscovery" = davLockDiscovery;
+  
+  /* HotMail (TM) */
+  "{http://schemas.microsoft.com/hotmail/}adbar"   = "hotmailAdbarInfo";
+  "{http://schemas.microsoft.com/hotmail/}maxpoll" = "hotmailMaxPollInterval";
+  "{http://schemas.microsoft.com/hotmail/}sig"     = "hotmailSignature";
+  
+  /* HTTP-Mail folders */
+  "{urn:schemas:httpmail:}calendar"        = "calendarFolderURL";
+  "{urn:schemas:httpmail:}contacts"        = "contactsFolderURL";
+  "{urn:schemas:httpmail:}deleteditems"    = "trashFolderURL";
+  "{urn:schemas:httpmail:}msgfolderroot"   = "accountRootURL";
+  "{urn:schemas:httpmail:}drafts"          = "draftsFolderURL";
+  "{urn:schemas:httpmail:}inbox"           = "inboxFolderURL";
+  "{urn:schemas:httpmail:}journal"         = "journalFolderURL";
+  "{urn:schemas:httpmail:}notes"           = "notesFolderURL";
+  "{urn:schemas:httpmail:}outbox"          = "outboxFolderURL";
+  "{urn:schemas:httpmail:}sendmsg"         = "mtaURL";
+  "{urn:schemas:httpmail:}sentitems"       = "sentFolderURL";
+  "{urn:schemas:httpmail:}tasks"           = "tasksFolderURL";
+  
+  /* HTTP-Mail fields */
+  "{urn:schemas:httpmail:}date"            = "date";
+  "{urn:schemas:httpmail:}hasattachment"   = "hasAttachment";
+  "{urn:schemas:httpmail:}read"            = "read";
+  "{urn:schemas:httpmail:}textdescription" = "textDescription";
+  "{urn:schemas:httpmail:}unreadcount"     = "unreadCount";
+  "{urn:schemas:mailheader:}cc"            = "cc";
+  "{urn:schemas:mailheader:}date"          = "date";
+  "{urn:schemas:mailheader:}from"          = "from";
+  "{urn:schemas:mailheader:}in-reply-to"   = "inReplyTo";
+  "{urn:schemas:mailheader:}message-id"    = "messageId";
+  "{urn:schemas:mailheader:}received"      = "received";
+  "{urn:schemas:mailheader:}references"    = "references";
+  "{urn:schemas:mailheader:}subject"       = "davDisplayName";
+  "{urn:schemas:mailheader:}to"            = "to";
+  
+  /* Exchange 2000 (TM) */
+  "{http://schemas.microsoft.com/exchange/}outlookfolderclass" = 
+    "outlookFolderClass";
+  "{http://schemas.microsoft.com/exchange/}outlookmessageclass" =
+    "outlookMessageClass";
+
+  /* OpenOffice.org */
+  "{http://ucb.openoffice.org/dav/props/}IsReadOnly"    = davIsReadOnly;
+  "{http://ucb.openoffice.org/dav/props/}BaseURI"       = davBaseURI; // TODO
+  "{http://ucb.openoffice.org/dav/props/}IsCompactDisc" = isOOoCompactDisc;
+  "{http://ucb.openoffice.org/dav/props/}IsFloppy"      = isOOoFloppy;
+  "{http://ucb.openoffice.org/dav/props/}IsHidden"      = davIsHidden;
+  "{http://ucb.openoffice.org/dav/props/}IsRemote"      = isOOoRemote;
+  "{http://ucb.openoffice.org/dav/props/}IsRemoveable"  = isOOoRemoveable;
+  "{http://ucb.openoffice.org/dav/props/}IsVolume"      = isOOoVolume;
+  "{http://ucb.openoffice.org/dav/props/}TargetURL"     = davOOoTargetURL;
+}
diff --git a/skyrix-sope/NGObjWeb/Defaults.plist b/skyrix-sope/NGObjWeb/Defaults.plist
new file mode 100644 (file)
index 0000000..d8fee7e
--- /dev/null
@@ -0,0 +1,253 @@
+{
+  NGObjWeb_doc_   = "NSUserDefaults for NGObjWeb";
+  NGObjWeb_cvs_id = "$Id: Defaults.plist,v 1.33 2004/08/05 01:46:23 helge Exp $";
+
+  WOAdaptor                             = "WOHttpAdaptor";
+  WOAdaptorLogPath                     = "";
+  WOAdditionalAdaptors                  = ( );
+  WOApplicationSuffix                   = ".woa";
+  WOApplicationBaseURL                  = "/WebObjects";
+  WOAutoOpenInBrowser                   = NO;
+  WOCachingEnabled                      = YES;
+  WOCGIAdaptorURL                       = "http://localhost/cgi-bin/WebObjects";
+  WOComponentExtensions                 = ( wo );
+  WOComponentLoadWOOFiles               = NO;
+  WOComponentRequestHandlerKey          = "wo";
+  WOCompoundElementPool                 = NO;
+  WOContactSNS                          = NO;
+  WOCoreOnApplicationException          = NO;
+  WOCoreOnHTTPAdaptorException          = NO;
+  WOCoreOnXmlRpcFault                   = NO;
+  WOCoreOnRecursiveSubcomponents       = NO;
+  WOCoreOnAwakeComponentInCtxDealloc    = NO;
+  WODebugCursor                         = NO;
+  WODebugComponentAwake                        = NO;
+  WODebugComponentDefinition            = NO;
+  WODebugComponentLookup               = NO;
+  WODebugKeyPathAssociation             = NO;
+  WODebugHttpTransaction                = NO;
+  WODebugResourceLookup                 = NO;
+  WODebugTakeValues                    = NO;
+  WODebugStaticLinkProcessing           = NO;
+  WODebuggingEnabled                    = YES;
+  WODefaultSessionTimeOut               = 3600;
+  WODefaultLanguages = ( 
+    English, 
+    German, 
+    Danish, 
+    Dutch,
+    French, 
+    Spanish, 
+    Italian, 
+    Portuguese, 
+    ptBR
+  );
+  WODescriptiveElementIDs               = NO;
+  WODebugActions                        = NO;
+  WODirectActionRequestHandlerKey       = "x";
+  WODontZipResponse                     = NO;
+  WODebugZipResponse                    = NO;
+  WOEnableComponentsWithoutClasses      = NO;
+  WOExpirationTimeInterval              = 120;
+  WOFormAlwaysPassDown                  = YES;
+  WOFrameworksBaseURL                   = "/WebObjects/Frameworks";
+  WOGenerateMissingResourceLinks        = NO;
+  WOHttpAdaptor_LogStream               = NO;
+  WOHttpAdaptorReceiveTimeout           = 120;
+  WOHttpAdaptorSendTimeout              = 120;
+  WOHttpAllowHost                       = "localhost";
+  WOHttpTransactionUseSimpleParser      = NO;
+  WOIncludeCommentsInResponse           = YES;
+  WOIsRedirectionEnabled                = NO;
+  WOKeyPathAssociationsCacheSize        = 200;
+  WOListenQueueSize                     = 5;
+  WOLogDefaultsOnStartup                = NO;
+  WOLogScriptKVC                        = NO;
+  WOLogScriptInit                       = NO;
+  WOLogScriptDealloc                    = NO;
+  WOLogComponents                       = NO;
+  WOLogPageCache                        = NO;
+  WOLogXmlRpcSelectorMapping            = NO;
+  WONoProxySuffixes                     = ( );
+  WONoSelectionString                   = "WONoSelectionString";
+  WOOutputValidationEnabled             = NO;
+  WOPageCacheSize                       = 30;
+  WOPageRefreshOnBacktrack              = YES;
+  WOPageRequestHandlerDebugEnabled      = NO;
+  WOParsersUseUTF8                      = NO;
+  WOPermanentPageCacheSize              = 30;
+  WOPort                                = "*:20000";
+  WOProfileApplication                  = NO;
+  WOProfileComponents                   = NO;
+  WOProfileDirectActionRequestHandler   = NO;
+  WOProfileElements                     = NO;
+  WOProfileHttpAdaptor                  = NO;
+  WOProfileLoading                      = NO;
+  WOProfileResponse                     = NO;
+  WOProjectSearchPath                   = ();
+  WOResourceRequestHandlerKey           = "y";
+  WORunMultithreaded                    = NO;
+  WOSMTPHost                            = "mail";
+  WOSimpleHTTPParserDebugEnabled        = NO;
+  WOSimpleHTTPParserHeavyDebugEnabled   = NO;
+  WOSimpleHTTPParserFileIOBoundary      = 16384;
+  WOSimpleHTTPParserMaxUploadSizeInKB   = 262144;
+  WOSendMail                            = "/usr/lib/sendmail";
+  WOSessionStore                        = "WOServerSessionStore";
+  WOStatsStylesheetName                 = "WOStats.xsl";
+  WOUseRelativeURLs                     = YES;
+  WOValueAssociationsCacheSize          = 200;
+  WOWorkerThreadCount                   = 0;
+  WOxFileExtensions                     = ( wox, xtmpl, xhtml );
+  WOxElemBuilder_LogAssociationMapping  = NO;
+  WOxElemBuilder_LogAssociationCreation = NO;
+  WOxComponentElemBuilderDebugEnabled  = NO;
+  WOxLogBuilderQueue                    = NO;
+  WOxBuilderClasses = ( 
+    WOxControlElemBuilder,
+    WOxMiscElemBuilder,
+    WOxHTMLElemBuilder,
+    WOxXULElemBuilder,
+    WExCalElemBuilder,
+    WExDnDElemBuilder,
+    WExExtElemBuilder,
+    WOxExtElemBuilder,
+    WOxComponentElemBuilder
+  );
+  WOxAssociationClassMapping = {
+    "http://www.skyrix.com/od/binding"    = WOKeyPathAssociation;
+    "http://www.skyrix.com/od/constant"   = WOValueAssociation;
+    "http://www.skyrix.com/od/javascript" = WOScriptAssociation;
+    "http://www.skyrix.com/od/so-lookup"  = SoLookupAssociation;
+    "OGo:bind"                            = WOKeyPathAssociation;
+    "OGo:value"                           = WOValueAssociation;
+    "OGo:script"                          = WOScriptAssociation;
+    "OGo:url"                             = WOResourceURLAssociation;
+    "OGo:label"                           = WOLabelAssociation;
+    "OGo:path"                            = SoLookupAssociation;
+  };
+  SoClassRegistryDebugEnabled          = NO;
+  SoDebugKeyLookup                     = NO;
+  SoDebugTraversal                     = NO;
+  SoDebugProductLoading                = NO;
+  SoDebugProductRegistry               = NO;
+  SoDebugRequestClassification         = NO;
+  SoLogSecurityDeclarations            = NO;
+  SoOFSDebugFactory                    = NO;
+  SoOFSDebugPlistObject                = NO;
+  SoOFSDebugRestore                    = NO;
+  SoOFSDebugNegotiate                  = NO;
+  SoOFSDebugAuthLookup                 = NO;
+  SoOFSWebMethodDebugEnabled           = NO;
+  SoOFSResourceManagerDebugEnabled     = NO;
+  SoObjCClassDebugEnabled              = NO;
+  SoObjectDAVDispatcherDebugEnabled    = NO;
+  SoObjectXmlRpcDispatcherDebugEnabled = NO;
+  SoObjectSOAPDispatcherDebugEnabled   = NO;
+  SoObjectDataSourceDebugEnabled       = NO;
+  SoObjectRequestHandlerDebugEnabled   = NO;
+  SoObjectMethodDispatcherDebugEnabled = NO;
+  SoPageInvocationDebugEnabled         = NO;
+  SoProductResourceManagerDebugEnabled = NO;
+  SoRendererDebugEnabled               = NO;
+  SoSecurityManagerDebugEnabled        = NO;
+  SoPreferredNamespacePrefixes = {
+    "DAV:" = "D";
+    "http://www.skyrix.com/od/binding"            = "var";
+    "http://www.skyrix.com/od/constant"           = "const";
+    "http://www.skyrix.com/od/javascript"         = "js";
+    "http://www.w3.org/1999/xhtml"                = "html";
+    "http://www.w3.org/TR/REC-html40"             = "html4";
+    "http://www.w3.org/1999/xlink"                = "xlink";
+    "http://www.w3.org/1999/XSL/Transform"        = "xsl";
+    "http://www.w3.org/1999/02/22-rdf-syntax-ns#" = "RDF";
+    "http://www.wapforum.org/DTD/wml_1.2.xml"     = "wml";
+    "http://schemas.microsoft.com/hotmail/"       = "hm";
+    "http://schemas.microsoft.com/exchange/"      = "ex";
+    "urn:schemas:contacts:"                       = "exab";
+    "urn:schemas:calendar:"                       = "excal";
+    "http://schemas.microsoft.com/mapi/proptag/"  = "pt";
+    "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" = "xul";
+    "http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt" =
+      "xcal";
+    "http://apache.org/dav/props/" = "ap";
+    "http://webdav.org/cadaver/custom-properties/" = "cdv";
+  };
+  SoDefaultWebDAVPropertyNames = (
+    "{DAV:}creationdate",
+    "{DAV:}getcontentlength",
+    "{DAV:}getlastmodified",
+    "{DAV:}getetag",
+    "{DAV:}resourcetype",
+    "{DAV:}getcontenttype",
+    "{DAV:}displayname",
+    "{DAV:}href",
+    "{http://apache.org/dav/props/}executable"
+  );
+  SoWebDAVFormatOutput = NO;
+  DAVParserDebugProp = NO;
+
+  SoWebDAVDefaultAllowMethods = (
+    GET, HEAD, POST, OPTIONS, MKCOL, DELETE, PUT,
+    LOCK, UNLOCK, COPY, MOVE
+    /* , NOTIFY, POLL, SUBSCRIBE, UNSUBSCRIBE */
+  );
+
+  SoWebDAVDetectionMethods = (
+    OPTIONS,
+    MKCOL,
+    PROPFIND,
+    PROPPATCH,
+    DELETE,
+    PUT,
+    LOCK,
+    UNLOCK,
+    COPY,
+    MOVE,
+    
+    /* WebStore specialties */
+    SEARCH,
+    NOTIFY,
+    POLL,
+    SUBSCRIBE,
+    UNSUBSCRIBE,
+    BCOPY,
+    BDELETE,
+    BMOVE,
+    BPROPFIND,
+    BPROPPATCH
+  );
+  
+  SoRequestDispatcherRules = (
+    "result.isOFSWebMethod=1 => renderer = 'OFSWebMethodRenderer' ; very high",
+    "object.isOFSWebMethod=1 => renderer = 'SoTemplateRenderer' ; high",
+
+    "object.soClassName='OFSPropertyListObject' => renderer = 'SoTemplateRenderer' ; very high",
+
+    "object.soClassName='OFSFile'  => renderer = 'OFSFileRenderer'",
+    "object.soClassName='OFSImage' => renderer = 'OFSFileRenderer'",
+
+    "context.soRequestType='WebDAV'  => renderer = 'SoWebDAVRenderer' ; high",
+    "context.soRequestType='XML-RPC' => renderer = 'SoXmlRpcRenderer' ; high",
+    "context.soRequestType='SOAP'    => renderer = 'SoSOAPRenderer' ;   high",
+    "context.soRequestType='WCAP'    => renderer = 'SoWCAPRenderer' ;   high",
+    "*true* => renderer = 'SoDefaultRenderer' ; fallback",
+    
+    "request.isSoSOAPRequest=YES   => dispatcher = 'SoObjectSOAPDispatcher'",
+    "request.isSoWebDAVRequest=YES => dispatcher = 'SoObjectWebDAVDispatcher'",
+    "request.isSoXmlRpcRequest=YES => dispatcher = 'SoObjectXmlRpcDispatcher'",
+    "*true* => dispatcher = 'SoObjectMethodDispatcher'; fallback",
+    
+    "request.isSoSOAPRequest=YES   => requestType = 'SOAP'",
+    "request.isSoWebDAVRequest=YES => requestType = 'WebDAV'",
+    "request.isSoXmlRpcRequest=YES => requestType = 'XML-RPC'",
+    "*true*                        => requestType = 'METHOD'; fallback",
+    
+    "request.isSoWebDAVRequest=YES => useAcquisition = NO",
+    "headers.translate='f'         => useAcquisition = NO; high",
+    "method='GET'                  => useAcquisition = YES; low",
+    "method='HEAD'                 => useAcquisition = YES; low",
+    "method='POST'                 => useAcquisition = YES; low",
+    "*true*                        => useAcquisition = NO; fallback",
+  );
+}
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/.cvsignore b/skyrix-sope/NGObjWeb/DynamicElements/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/GNUmakefile b/skyrix-sope/NGObjWeb/DynamicElements/GNUmakefile
new file mode 100644 (file)
index 0000000..295a9a2
--- /dev/null
@@ -0,0 +1,70 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = DynamicElements
+
+DynamicElements_OBJC_FILES = \
+        WOxHTMLElemBuilder.m   \
+        WOxControlElemBuilder.m        \
+       WOxMiscElemBuilder.m    \
+       WOxXULElemBuilder.m     \
+        \
+       WOActionURL.m           \
+       WOBody.m                \
+       WOBrowser.m             \
+       WOCheckBox.m            \
+       WOCheckBoxList.m        \
+       WOComponentContent.m    \
+       WOComponentReference.m  \
+       WOCompoundElement.m     \
+       WOConditional.m         \
+       WOEmbeddedObject.m      \
+       WOFileUpload.m          \
+       WOForm.m                \
+       WOFrame.m               \
+       WOGenericContainer.m    \
+       WOGenericElement.m      \
+       WOHtml.m                \
+       WOHTMLDynamicElement.m  \
+       WOHiddenField.m         \
+       WOHyperlink.m           \
+       WOHyperlinkInfo.m       \
+       WOImage.m               \
+       WOImageButton.m         \
+       WOInput.m               \
+       WOIFrame.m              \
+       WOJavaScript.m          \
+       WOMetaRefresh.m         \
+       WONestedList.m          \
+       WOPasswordField.m       \
+       WOPopUpButton.m         \
+       WORadioButton.m         \
+       WORadioButtonList.m     \
+       WORepetition.m          \
+       WOResetButton.m         \
+       WOResourceURL.m         \
+       WOString.m              \
+       WOSubmitButton.m        \
+       WOSwitchComponent.m     \
+       WOText.m                \
+       WOTextField.m           \
+       WOVBScript.m            \
+       WOEntity.m              \
+       WOSetCursor.m           \
+
+DynamicElements_OBJC_FILES += \
+       _WOConstResourceImage.m \
+       _WOResourceImage.m
+
+DynamicElements_OBJC_FILES += \
+       _WOComplexHyperlink.m           \
+       _WOTemporaryHyperlink.m         \
+       _WOCommonStaticDAHyperlink.m    \
+       _WOSimpleActionHyperlink.m      \
+
+$(GNUSTEP_OBJ_DIR)/WOGenericContainer.o : WOGenericElement.h WOGenericElement.m WOGenericContainer.m
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/GNUmakefile.preamble b/skyrix-sope/NGObjWeb/DynamicElements/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..ff6a033
--- /dev/null
@@ -0,0 +1,15 @@
+# $Id$
+
+ADDITIONAL_CPPFLAGS += -pipe 
+# -DHTML_DEBUG=1
+# -DPROFILE_CLUSTERS=1
+
+ADDITIONAL_CPPFLAGS += -pipe -Wall
+ADDITIONAL_CPPFLAGS += -DCOMPILING_NGOBJWEB=1
+
+DynamicElements_INCLUDE_DIRS += \
+       -I.. -I. -I../..        \
+       -I../../../skyrix-core                  \
+       -I../../../skyrix-core/NGStreams        \
+       -I../../../skyrix-core/NGExtensions     \
+       -I../../../skyrix-xml
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/README b/skyrix-sope/NGObjWeb/DynamicElements/README
new file mode 100644 (file)
index 0000000..af10c66
--- /dev/null
@@ -0,0 +1,39 @@
+# $Id$
+
+  Class-Hierachy
+
+    WOElement
+      WODynamicElement
+        WOComponentContent
+        WOComponentReference
+        WOCompoundElement
+        WOConditional
+        WOHTMLDynamicElement
+          WOEntity
+          WOForm
+          WOInput
+            WOCheckBox
+            WOCheckBoxList
+            WOFileUpload
+            WOHiddenField
+            WOImageButton
+            WOPasswordField
+            WOPopUpButton
+              WOBrowser
+            WORadioButton
+            WORadioButtonList
+            WOResetButton
+            WOSubmitButton
+            WOText
+            WOTextField
+          WOHyperlink
+          WONestedList
+          WOBody
+          WOGenericElement
+            WOGenericContainer
+          WOImage
+          WOString
+        WORepetition
+
+--
+1999-03-30, hh
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOActionURL.m b/skyrix-sope/NGObjWeb/DynamicElements/WOActionURL.m
new file mode 100644 (file)
index 0000000..6083d18
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHTMLDynamicElement.h"
+#include "WOElement+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+
+/*
+  WOActionURL associations:
+
+    pageName | action | (directActionName & actionClass)
+    fragmentIdentifier
+    queryDictionary
+*/
+
+@interface WOActionURL : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *fragmentIdentifier;
+  WOElement     *template;
+
+  /* new in WO4: */
+  WOAssociation *queryDictionary;
+  NSDictionary  *queryParameters;  /* associations beginning with ? */
+}
+
+@end /* WOActionURL */
+
+@interface _WOActionActionURL : WOActionURL
+{
+  WOAssociation *action;
+}
+@end
+
+@interface _WOPageActionURL : WOActionURL
+{
+  WOAssociation *pageName;
+}
+@end
+
+@interface _WODirectActionActionURL : WOActionURL
+{
+  WOAssociation *actionClass;
+  WOAssociation *directActionName;
+  BOOL          sidInUrl;          /* include session-id in wa URL ? */
+}
+@end
+
+@interface WOActionURL(PrivateMethods)
+
+- (id)_initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t;
+
+- (NSString *)associationDescription;
+
+@end
+
+@implementation WOActionURL
+
++ (int)version {
+  return 1;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  Class linkClass = Nil;
+  
+  if ([_config objectForKey:@"action"])
+    linkClass = [_WOActionActionURL class];
+  else if ([_config objectForKey:@"pageName"])
+    linkClass = [_WOPageActionURL class];
+  else
+    linkClass = [_WODirectActionActionURL class];
+
+  [self release];
+  return
+    [[linkClass alloc] initWithName:_name associations:_config template:_t];
+}
+
+- (id)_initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->fragmentIdentifier = OWGetProperty(_config, @"fragmentIdentifier");
+    self->queryDictionary    = OWGetProperty(_config, @"queryDictionary");
+    self->queryParameters    = OWExtractQueryParameters(_config);
+    self->template           = [_t retain];
+    self->containsForm       = self->queryParameters ? YES : NO;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->template);
+  RELEASE(self->queryDictionary);
+  RELEASE(self->queryParameters);
+  RELEASE(self->fragmentIdentifier);
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOElement *)template {
+  return self->template;
+}
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  /* links can take form values !!!! (for query-parameters) */
+
+  if (self->queryParameters) {
+    /* apply values to ?style parameters */
+    WOComponent  *sComponent = [_ctx component];
+    NSEnumerator *keys;
+    NSString     *key;
+
+    keys = [self->queryParameters keyEnumerator];
+    while ((key = [keys nextObject])) {
+      id assoc, value;
+
+      assoc = [self->queryParameters objectForKey:key];
+      value = [_req formValueForKey:key];
+
+      [assoc setValue:value inComponent:sComponent];
+    }
+  }
+  
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  [[_ctx session] logWithFormat:@"%@[0x%08X]: no action/page set !",
+                    NSStringFromClass([self class]), self];
+  return nil;
+}
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY || \
+    COCOA_Foundation_LIBRARY
+  NSLog(@"subclass responsibility ...");
+#else
+  [self subclassResponsibility:_cmd];
+#endif
+  return NO;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![[_ctx request] isFromClientComponent]) {
+    WOComponent *sComponent = [_ctx component];
+    NSString *queryString = nil;
+  
+    if ([self _appendHrefToResponse:_response inContext:_ctx]) {
+      queryString = [self queryStringForQueryDictionary:
+                            [self->queryDictionary valueInComponent:sComponent]
+                          andQueryParameters:self->queryParameters
+                          inContext:_ctx];
+    }
+  
+    if (self->fragmentIdentifier) {
+      [_response appendContentCharacter:'#'];
+      WOResponse_AddString(_response,
+         [self->fragmentIdentifier stringValueInComponent:sComponent]);
+    }
+    if (queryString) {
+      [_response appendContentCharacter:'?'];
+      WOResponse_AddString(_response, queryString);
+    }
+    
+    /* content */
+    [self->template appendToResponse:_response inContext:_ctx];
+  }
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  if (self->fragmentIdentifier)
+    [str appendFormat:@" fragment=%@", self->fragmentIdentifier];
+
+  return str;
+}
+
+@end /* WOActionURL */
+
+@implementation _WOActionActionURL
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    self->action = OWGetProperty(_config, @"action");
+
+    if (self->action == nil) {
+      NSLog(@"missing action association for WOActionURL ..");
+      RELEASE(self);
+      return nil;
+    }
+
+#if DEBUG
+    if ([_config objectForKey:@"pageName"] ||
+        [_config objectForKey:@"href"]     ||
+        [_config objectForKey:@"directActionName"] ||
+        [_config objectForKey:@"actionClass"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOActionURL !"
+            @" (assign only one of pageName, href, "
+            @"directActionName or action)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->action release];
+  [super dealloc];
+}
+
+/* dynamic invocation */
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  /* link is active */
+  return [self executeAction:self->action inContext:_ctx];
+}
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOResponse_AddString(_response, [_ctx componentActionURL]);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" action=%@", self->action];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOActionActionURL */
+
+@implementation _WOPageActionURL
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    self->pageName = OWGetProperty(_config, @"pageName");
+
+    if (self->pageName == nil) {
+      NSLog(@"missing pageName association for WOActionURL ..");
+      RELEASE(self);
+      return nil;
+    }
+
+#if DEBUG
+    if ([_config objectForKey:@"action"] ||
+        [_config objectForKey:@"href"]     ||
+        [_config objectForKey:@"directActionName"] ||
+        [_config objectForKey:@"actionClass"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOActionURL !"
+            @" (assign only one of pageName, href, "
+            @"directActionName or action)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->pageName release];
+  [super dealloc];
+}
+
+/* actions */
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *page = nil;
+  NSString    *name = nil;
+
+  name = [self->pageName stringValueInComponent:[_ctx component]];
+  page = [[_ctx application] pageWithName:name inContext:_ctx];
+
+  if (page == nil) {
+    [[_ctx session] logWithFormat:
+                      @"%@[0x%08X]: did not find page with name %@ !",
+                      NSStringFromClass([self class]), self, name];
+  }
+  return page;
+}
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOResponse_AddString(_response, [_ctx componentActionURL]);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" pageName=%@", self->pageName];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOPageActionURL */
+
+@implementation _WODirectActionActionURL
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    WOAssociation *sidInUrlAssoc;
+    
+    sidInUrlAssoc          = OWGetProperty(_config, @"?wosid");
+    self->actionClass      = OWGetProperty(_config, @"actionClass");
+    self->directActionName = OWGetProperty(_config, @"directActionName");
+
+    self->sidInUrl = (sidInUrlAssoc)
+      ? [sidInUrlAssoc boolValueInComponent:nil]
+      : YES;
+    
+#if DEBUG
+    if ([_config objectForKey:@"action"] ||
+        [_config objectForKey:@"href"]     ||
+        [_config objectForKey:@"pageName"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOActionURL !"
+            @" (assign only one of pageName, href, "
+            @"directActionName or action)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->actionClass      release];
+  [self->directActionName release];
+  [super dealloc];
+}
+
+/* href */
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent         *sComponent;
+  NSString            *daClass;
+  NSString            *daName;
+  NSMutableDictionary *qd;
+  NSDictionary        *tmp;
+
+  sComponent = [_ctx component];
+  daClass = [self->actionClass stringValueInComponent:sComponent];
+  daName  = [self->directActionName stringValueInComponent:sComponent];
+
+  if (daClass) {
+    if (daName) {
+      if (![daClass isEqualToString:@"DirectAction"])
+        daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
+    }
+    else
+      daName = daClass;
+  }
+
+  qd = [NSMutableDictionary dictionaryWithCapacity:16];
+
+      /* add query dictionary */
+      
+  if (self->queryDictionary) {
+    if ((tmp = [self->queryDictionary valueInComponent:sComponent]))
+      [qd addEntriesFromDictionary:tmp];
+  }
+      
+  /* add ?style parameters */
+
+  if (self->queryParameters) {
+    NSEnumerator *keys;
+    NSString     *key;
+
+    keys = [self->queryParameters keyEnumerator];
+    while ((key = [keys nextObject])) {
+      id assoc, value;
+
+      assoc = [self->queryParameters objectForKey:key];
+      value = [assoc stringValueInComponent:sComponent];
+          
+      [qd setObject:(value ? value : @"") forKey:key];
+    }
+  }
+      
+  /* add session ID */
+
+  if (self->sidInUrl) {
+    if ([_ctx hasSession]) {
+      WOSession *sn = [_ctx session];
+          
+      [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
+          
+      if (![sn isDistributionEnabled]) {
+        [qd setObject:[[WOApplication application] number]
+            forKey:WORequestValueInstance];
+      }
+    }
+  }
+
+  WOResponse_AddString(_response,
+                       [_ctx directActionURLForActionNamed:daName
+                             queryDictionary:qd]);
+  return NO;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  if (self->actionClass)
+    [str appendFormat:@" actionClass=%@", self->actionClass];
+  if (self->directActionName)
+    [str appendFormat:@" directAction=%@", self->directActionName];
+  
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WODirectActionActionURL */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOActiveImage.m b/skyrix-sope/NGObjWeb/DynamicElements/WOActiveImage.m
new file mode 100644 (file)
index 0000000..d29dd41
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  Not implemented yet.
+
+  Sample (Client side):
+<MAP NAME="FrontPageMap0">
+     <AREA SHAPE="RECT" COORDS="0, 0, 779, 70" HREF="../index.html">
+     <AREA SHAPE="RECT" COORDS="632, 76, 732, 87" HREF="../stellen/index.html">
+     <AREA SHAPE="RECT" COORDS="544, 75, 595, 88" HREF="../kontakt/index.html">
+     <AREA SHAPE="RECT" COORDS="399, 74, 516, 87" HREF="../apotheker/index.html">
+     <AREA SHAPE="RECT" COORDS="288, 74, 368, 87" HREF="../aerzte/index.html">
+     <AREA SHAPE="RECT" COORDS="147, 74, 262, 87" HREF="../patienten/index.html">
+</MAP>
+<img src="images/banner.jpg" width="780" height="94" alt="Esparma" border="0" 
+      usemap="#FrontPageMap0">
+*/
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOBody.m b/skyrix-sope/NGObjWeb/DynamicElements/WOBody.m
new file mode 100644 (file)
index 0000000..bd0473c
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOElement+private.h"
+#include "WOHTMLDynamicElement.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+
+@class WOAssociation;
+
+@interface WOBody : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *filename;  // path relative to WebServerResources
+  WOAssociation *framework;
+  WOAssociation *src;       // absolute URL
+  WOAssociation *value;     // image data (eg from a database)
+
+  WOElement *template;
+}
+
+@end
+
+@implementation WOBody
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->filename  = OWGetProperty(_config, @"filename");
+    self->framework = OWGetProperty(_config, @"framework");
+    self->src       = OWGetProperty(_config, @"src");
+    self->value     = OWGetProperty(_config, @"value");
+    
+    self->template  = RETAIN(_c);
+    
+    if (self->value) NSLog(@"WARNING: value not yet supported !");
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->template);
+  RELEASE(self->framework);
+  RELEASE(self->filename);
+  RELEASE(self->src);
+  RELEASE(self->value);
+  [super dealloc];
+}
+#endif
+
+// accessors
+
+- (WOElement *)template {
+  return self->template;
+}
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+}
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_req inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *uUri;
+  NSString *uFi;
+  
+  if ([[_ctx request] isFromClientComponent]) {
+    [self->template appendToResponse:_response inContext:_ctx];
+    return;
+  }
+  
+  uUri = [self->src      stringValueInComponent:[_ctx component]];
+  uFi  = [self->filename stringValueInComponent:[_ctx component]];
+  
+  WOResponse_AddCString(_response, "<body");
+  
+  if ([uFi length] > 0) {
+    NSArray *languages;
+    WOResourceManager *rm;
+    NSString  *frameworkName;
+
+    WOResponse_AddCString(_response, " background=\"");
+      
+    languages = [_ctx hasSession]
+      ? [[_ctx session] languages]
+      : [[_ctx request] browserLanguages];
+      
+    if ((rm = [[_ctx component] resourceManager]) == nil)
+      rm = [[_ctx application] resourceManager];
+      
+    /* If 'framework' binding is not set, use parent component's framework */
+    if (self->framework){
+      frameworkName = [self->framework stringValueInComponent:[_ctx component]];
+      if (frameworkName != nil && [frameworkName isEqualToString:@"app"])
+        frameworkName = nil;
+    }
+    else
+      frameworkName = [[_ctx component] frameworkName];
+    
+    uFi = [rm urlForResourceNamed:uFi
+              inFramework:frameworkName
+              languages:languages
+              request:[_ctx request]];
+    if (uFi == nil) {
+      NSLog(@"%@: did not find resource '%@' (languages=%@)",
+            [_ctx component],
+            [self->filename stringValueInComponent:[_ctx component]],
+            [languages componentsJoinedByString:@","]);
+      uFi = uUri;
+    }
+    [_response appendContentHTMLAttributeValue:uFi];
+    WOResponse_AddChar(_response, '"');
+  }
+  else if ([uUri length] > 0) {
+    WOResponse_AddCString(_response, " background=\"");
+    [_response appendContentHTMLAttributeValue:uUri];
+    WOResponse_AddChar(_response, '"');
+  }
+  
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  WOResponse_AddChar(_response, '>');
+  
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  WOResponse_AddCString(_response, "</body>");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:128];
+
+  if (self->filename)  [str appendFormat:@" filename=%@",  self->filename];
+  if (self->framework) [str appendFormat:@" framework=%@", self->framework];
+  if (self->src)       [str appendFormat:@" src=%@",       self->src];
+  if (self->value)     [str appendFormat:@" value=%@",     self->value];
+  if (self->template)  [str appendFormat:@" template=%@",  self->template];
+  
+  return str;
+}
+
+@end /* WOBody */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOBrowser.m b/skyrix-sope/NGObjWeb/DynamicElements/WOBrowser.m
new file mode 100644 (file)
index 0000000..066c87c
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOInput.h"
+#include "common.h"
+
+@interface WOBrowser : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // inherited: name
+  // inherited: value
+  // inherited: disabled
+@protected
+  WOAssociation *list;
+  WOAssociation *item;
+  WOAssociation *selection;
+  WOAssociation *string;            // WO4
+  WOAssociation *noSelectionString; // WO4
+  
+  // non-WO:
+  WOAssociation *singleSelection; // selection contains an item, not an array
+  WOAssociation *multiple; // multiple selections allowed
+  WOAssociation *size;
+}
+
+@end /* WOBrowser */
+
+@implementation WOBrowser
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
+
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c {
+
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->list              = OWGetProperty(_config, @"list");
+    self->item              = OWGetProperty(_config, @"item");
+    self->selection         = OWGetProperty(_config, @"selection");
+    self->string            = OWGetProperty(_config, @"string");
+    self->singleSelection   = OWGetProperty(_config, @"singleSelection");
+    self->multiple          = OWGetProperty(_config, @"multiple");
+    self->size              = OWGetProperty(_config, @"size");
+    self->noSelectionString = OWGetProperty(_config, @"noSelectionString");
+
+    // compatiblity
+    if (self->noSelectionString == nil)
+      self->noSelectionString = OWGetProperty(_config, @"nilString");
+    
+    if (self->multiple == nil) {
+      self->multiple =
+        [WOAssociation associationWithValue:[NSNumber numberWithBool:YES]];
+      self->multiple = [self->multiple retain];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->noSelectionString);
+  RELEASE(self->singleSelection);
+  RELEASE(self->list);
+  RELEASE(self->item);
+  RELEASE(self->selection);
+  RELEASE(self->string);
+  RELEASE(self->size);
+  RELEASE(self->multiple);
+  [super dealloc];
+}
+
+/* handling request */
+
+- (void)_takeSingleFormValue:(id)formValue fromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent;
+  NSArray *objects;
+  id      object;
+      
+  sComponent = [_ctx component];
+  objects = [self->list valueInComponent:sComponent];
+      
+  if ([[formValue stringValue] isEqualToString:@"$"])
+    object = nil; // nil item selected
+  else {
+    int idx;
+      
+    object = nil;
+    if ((idx = [formValue intValue]) >= 0) {
+      if (idx < (int)[objects count])
+        object = [objects objectAtIndex:idx];
+      else {
+        [sComponent logWithFormat:
+                      @"WOBrowser got invalid index '%i' (formvalue='%@') "
+                    @"for list with count %i !",
+                    idx, formValue, [objects count]];
+      }
+    }
+    else
+      [sComponent logWithFormat:@"WOBrowser got invalid index '%i' !", idx];
+  }
+    
+  if ([self->selection isValueSettable]) {
+    NSArray *sel;
+        
+    if ([self->item isValueSettable])
+      [self->item setValue:object inComponent:sComponent];
+
+    if (object) {
+      sel = [self->singleSelection boolValueInComponent:sComponent]
+        ? [object retain]
+        : [[NSArray alloc] initWithObjects:object,nil];
+    }
+    else // nil item selected
+      sel = nil;
+          
+    [self->selection setValue:sel inComponent:sComponent];
+    [sel release]; sel = nil;
+  }
+}
+
+- (void)_takeMultiFormValue:(NSArray *)formValue fromRequest:(WORequest *)_rq
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent;
+  NSEnumerator   *values;
+  NSString       *v;
+  NSArray        *objects;
+  id             object;
+  
+  values     = [formValue objectEnumerator];
+  sComponent = [_ctx component];
+  objects    = [self->list valueInComponent:sComponent];
+    
+  if ([self->selection isValueSettable]) {
+    NSMutableArray *sel;
+    unsigned objCount;
+      
+    sel      = [[NSMutableArray alloc] initWithCapacity:[formValue count]];
+    objCount = [objects count];
+      
+    while ((v = [values nextObject])) {
+        int idx;
+
+        object = nil;
+        if ((idx = [v intValue]) >= 0) {
+          if (idx < (int)objCount)
+            object = [objects objectAtIndex:idx];
+          else {
+            [sComponent logWithFormat:
+                          @"WOBrowser got invalid index '%i'(formValue='%@' "
+                          @"for list with count %i !",
+                          idx, objCount, v];
+          }
+          
+          if ([self->item isValueSettable])
+            [self->item setValue:object inComponent:sComponent];
+        }
+        else {
+          [sComponent logWithFormat:@"WOBrowser got invalid index '%i' !",
+                        idx];
+        }
+        
+        if (object) [sel addObject:object];
+    }
+
+    if ([self->singleSelection boolValueInComponent:sComponent]) {
+        if ([sel count] > 1) {
+          NSLog(@"WARNING(%@): "
+                @"using singleSelection with multiple selected values",
+                self);
+        }
+        [self->selection setValue:[sel lastObject] inComponent:sComponent];
+    }
+    else
+      [self->selection setValue:sel inComponent:sComponent];
+    [sel release]; sel = nil;
+  }
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent;
+  id formValue = nil;
+  
+  sComponent = [_ctx component];
+  if ([self->disabled boolValueInComponent:sComponent])
+      return;
+  
+  formValue = [_request formValuesForKey:OWFormElementName(self, _ctx)];
+#if 0
+  [self logWithFormat:@"value=%@ ..", formValue];
+#endif
+  
+  if ([self->value isValueSettable])
+    // TODO: is this correct?
+    [self->value setValue:formValue inComponent:sComponent];
+  
+  if ([formValue count] == 1) {
+    [self _takeSingleFormValue:[formValue lastObject] fromRequest:_request
+          inContext:_ctx];
+  }
+  else if (formValue != nil) {
+    [self _takeMultiFormValue:formValue fromRequest:_request
+          inContext:_ctx];
+  }
+  else {
+    // nothing selected
+    if ([self->item isValueSettable])
+      [self->item setValue:nil inComponent:sComponent];
+    if ([self->selection isValueSettable])
+      [self->selection setValue:nil inComponent:sComponent];
+  }
+}
+
+- (void)appendOptionsToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent = [_ctx component];
+  BOOL     isSingle = NO;
+  NSString *nilStr  = nil;
+  NSArray  *array   = nil;
+  id       selArray = nil;
+  int      i, toGo;
+    
+
+  nilStr   = [self->noSelectionString stringValueInComponent:sComponent];
+  isSingle = [self->singleSelection boolValueInComponent:sComponent];
+  array    = [self->list            valueInComponent:sComponent];
+  selArray = [self->selection       valueInComponent:sComponent];
+  toGo     = [array count];
+
+  if (nilStr) {
+    WOResponse_AddCString(_response, "<option value=\"$\">");
+    WOResponse_AddHtmlString(_response, nilStr);
+    WOResponse_AddCString(_response, "</option>");
+  }
+    
+  for (i = 0; i < toGo; i++) {
+    NSString *v         = nil;
+    NSString *displayV  = nil;
+    id       object     = [array objectAtIndex:i];
+    BOOL     isSelected;
+
+    if ([self->item isValueSettable])
+      [self->item setValue:object inComponent:sComponent];
+
+    isSelected = NO;
+    if (selArray) {
+      isSelected = isSingle 
+        ? [selArray isEqual:object] : [selArray containsObject:object];
+    }
+    
+    v = self->value
+      ? [self->value stringValueInComponent:sComponent]
+      : [NSString stringWithFormat:@"%i", i];
+
+    displayV = self->string
+      ? [self->string stringValueInComponent:sComponent]
+      : [object stringValue];
+    
+    if (displayV == nil) displayV = @"";
+    
+    WOResponse_AddCString(_response, "<option value=\"");
+    WOResponse_AddString(_response, v);
+    WOResponse_AddString(_response,
+                         isSelected ? @"\" selected=\"selected\">" : @"\">");
+    WOResponse_AddHtmlString(_response, displayV);
+    WOResponse_AddCString(_response, "</option>");
+  }
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  BOOL     isMultiple;
+  unsigned s;
+  
+  if ([[_ctx request] isFromClientComponent])
+    return;
+
+  isMultiple = [self->multiple boolValueInComponent:[_ctx component]];
+  s          = [self->size unsignedIntValueInComponent:[_ctx component]];
+    
+  WOResponse_AddCString(_response, "<select name=\"");
+  [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+  if (self->otherTagString) {
+    NSString *os;
+
+    os = [self->otherTagString stringValueInComponent:[_ctx component]];
+    WOResponse_AddString(_response, os);
+  }
+  WOResponse_AddCString(_response, "\"");
+      
+  if (s > 0) {
+    WOResponse_AddCString(_response, " size=\"");
+    WOResponse_AddUInt(_response, s);
+    [_response appendContentCharacter:'"'];
+  }
+      
+  if (isMultiple)
+    WOResponse_AddCString(_response, " multiple=\"multiple\"");
+    
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  WOResponse_AddCString(_response, ">\n");
+  
+  [self appendOptionsToResponse:_response inContext:_ctx];
+  
+  WOResponse_AddCString(_response, "</select>");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+  
+  str = [NSMutableString stringWithCapacity:256];
+  [str appendString:[super associationDescription]];
+  
+  if (self->list)      [str appendFormat:@" list=%@",      self->list];
+  if (self->item)      [str appendFormat:@" item=%@",      self->item];
+  if (self->selection) [str appendFormat:@" selection=%@", self->selection];
+  if (self->string)    [str appendFormat:@" string=%@",    self->string];
+  if (self->noSelectionString)
+    [str appendFormat:@" noselection=%@", self->noSelectionString];
+  if (self->singleSelection)
+    [str appendFormat:@" singleSelection=%@", self->singleSelection];
+
+  if (self->size)     [str appendFormat:@" size=%@",     self->size];
+  if (self->multiple) [str appendFormat:@" multiple=%@", self->multiple];
+
+  return str;
+}
+
+@end /* WOBrowser */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOCheckBox.m b/skyrix-sope/NGObjWeb/DynamicElements/WOCheckBox.m
new file mode 100644 (file)
index 0000000..39db1a0
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOInput.h"
+#include "common.h"
+
+@interface WOCheckBox : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // inherited: name
+  // inherited: value
+  // inherited: disabled
+@protected
+  WOAssociation *selection;
+  WOAssociation *checked;
+}
+
+@end /* WOCheckBox */
+
+@implementation WOCheckBox
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->selection = OWGetProperty(_config, @"selection");
+    self->checked   = OWGetProperty(_config, @"checked");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->selection release];
+  [self->checked   release];
+  [super dealloc];
+}
+
+// ******************** OWResponder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  /*
+    Checkboxes are special in their form-value handling. If the form is
+    submitted and the checkbox is checked, a 'YES' value is transferred in the
+    request. If the checkbox is not-checked, no value is transferred at all !
+  */
+  if (![self->disabled boolValueInComponent:[_ctx component]]) {
+    id formValue;
+
+    formValue = [_request formValueForKey:OWFormElementName(self, _ctx)];
+    
+    if ([self->checked isValueSettable]) {
+      [self->checked setBoolValue:formValue ? YES : NO
+                     inComponent:[_ctx component]];
+    }
+
+    if ([self->value isValueSettable] && (formValue != nil))
+      [self->value setStringValue:formValue inComponent:[_ctx component]];
+  }
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![[_ctx request] isFromClientComponent]) {
+    NSString *v;
+    BOOL     isChecked;
+
+    v         = [self->value   stringValueInComponent:[_ctx component]];
+    isChecked = [self->checked boolValueInComponent:[_ctx component]];
+    
+    WOResponse_AddCString(_response, "<input type=\"checkbox\" name=\"");
+    [_response appendContentHTMLAttributeValue:
+                 OWFormElementName(self, _ctx)];
+    WOResponse_AddCString(_response, "\" value=\"");
+    [_response appendContentHTMLAttributeValue:([v length] > 0) ? v : @"1"];
+    WOResponse_AddCString(_response, "\"");
+  
+    if (isChecked)
+      WOResponse_AddCString(_response, " checked=\"checked\"");
+      
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  
+    if (self->otherTagString) {
+      WOResponse_AddString(_response,
+                           [self->otherTagString stringValueInComponent:
+                                                   [_ctx component]]);
+    }
+    WOResponse_AddCString(_response, " />\n");
+  }
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = nil;
+  str = [[NSMutableString alloc]
+                          initWithString:[super associationDescription]];
+
+  if (self->selection) [str appendFormat:@" selection=%@", self->selection];
+  if (self->checked)   [str appendFormat:@" checked=%@", self->checked];
+
+  return [str autorelease];
+}
+
+@end /* WOCheckBox */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOCheckBoxList.m b/skyrix-sope/NGObjWeb/DynamicElements/WOCheckBoxList.m
new file mode 100644 (file)
index 0000000..d5d3882
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOInput.h"
+#include "common.h"
+
+@interface WOCheckBoxList : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // inherited: name
+  // inherited: value
+  // inherited: disabled
+@protected
+  WOAssociation *list;
+  WOAssociation *item;
+  WOAssociation *index;
+  WOAssociation *selections;
+  WOAssociation *prefix;
+  WOAssociation *suffix;
+}
+
+@end /* WOCheckBoxList */
+
+@implementation WOCheckBoxList
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->list       = OWGetProperty(_config, @"list");
+    self->item       = OWGetProperty(_config, @"item");
+    self->index      = OWGetProperty(_config, @"index");
+    self->selections = OWGetProperty(_config, @"selections");
+    self->prefix     = OWGetProperty(_config, @"prefix");
+    self->suffix     = OWGetProperty(_config, @"suffix");
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->list);
+  RELEASE(self->item);
+  RELEASE(self->index);
+  RELEASE(self->selections);
+  RELEASE(self->prefix);
+  RELEASE(self->suffix);
+  [super dealloc];
+}
+#endif
+
+// OWResponder
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  /*
+    Checkboxes are special in their form-value handling. If the form is
+    submitted and the checkbox is checked, a 'YES' value is transferred in the
+    request. If the checkbox is not-checked, no value is transferred at all !
+
+    Remember, the 'value' of a checkbox list is _not_ the form value but the
+    string besides the checkbox.
+  */
+  if (![self->disabled boolValueInComponent:[_ctx component]]) {
+    // could be optimized to use a single NAME with multiple values ..
+    WOComponent *sComponent = [_ctx component];
+    NSArray     *array      = [self->list valueInComponent:sComponent];
+    NSArray     *selArray   = nil;
+    unsigned    goCount     = [array count];
+  
+    if (goCount > 0) {
+      NSMutableArray *newSelection = nil;
+      unsigned cnt;
+
+      if (self->selections)
+        newSelection = [[NSMutableArray alloc] initWithCapacity:goCount];
+
+      [_ctx appendZeroElementIDComponent];
+    
+      for (cnt = 0; cnt < goCount; cnt++) {
+        id formValue = nil;
+        id object    = [array objectAtIndex:cnt];
+
+        if (self->index)
+          [self->index setUnsignedIntValue:cnt inComponent:sComponent];
+
+        if (self->item)
+          [self->item setValue:object inComponent:sComponent];
+
+        formValue = [_request formValueForKey:OWFormElementName(self, _ctx)];
+        if ([formValue isEqualToString:[self stringForInt:cnt]]) {
+          if ((object != nil) && (self->selections != nil))
+            [newSelection addObject:object];
+        }
+        [_ctx incrementLastElementIDComponent];
+      }
+    
+      [_ctx deleteLastElementIDComponent]; // list index
+
+      if (self->selections) {
+        selArray = [newSelection copy];
+        [newSelection release];
+      }
+    }
+    else if (self->selections)
+      selArray = [[NSArray alloc] init];
+
+    if ([self->selections isValueSettable])
+      [self->selections setValue:selArray inComponent:sComponent];
+
+    RELEASE(selArray);
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![[_ctx request] isFromClientComponent]) {
+    WOComponent *sComponent = [_ctx component];
+    NSArray     *array      = [self->list valueInComponent:sComponent];
+    unsigned    goCount     = [array count];
+  
+    if (goCount > 0) {
+      NSArray  *selArray = [self->selections valueInComponent:sComponent];
+      unsigned cnt;
+  
+      [_ctx appendZeroElementIDComponent];
+  
+      for (cnt = 0; cnt < goCount; cnt++) {
+        id object = [array objectAtIndex:cnt];
+        
+        if ([self->index isValueSettable])
+          [self->index setUnsignedIntValue:cnt inComponent:sComponent];
+  
+        if ([self->item isValueSettable])
+          [self->item setValue:object inComponent:sComponent];
+  
+        if (self->prefix) {
+          NSString *ps;
+
+          ps = [self->prefix stringValueInComponent:sComponent];
+          WOResponse_AddString(_response, ps);
+        }
+  
+        /* add checkbox */
+        {
+          NSString *n = nil;
+  
+          n = self->name
+            ? [self->name stringValueInComponent:sComponent]
+            : OWFormElementName(self, _ctx);
+  
+          WOResponse_AddCString(_response, "<input type=\"checkbox\" name=\"");
+          [_response appendContentHTMLAttributeValue:n];
+          WOResponse_AddCString(_response, "\" value=\"");
+          WOResponse_AddInt(_response, cnt);
+          WOResponse_AddCString(_response, "\"");
+  
+          if ([selArray containsObject:object])
+            WOResponse_AddCString(_response, " checked=\"checked\"");
+          
+          [self appendExtraAttributesToResponse:_response inContext:_ctx];
+          
+          if (self->otherTagString) {
+            WOResponse_AddString(_response,
+                                 [self->otherTagString stringValueInComponent:
+                                                         [_ctx component]]);
+          }
+          WOResponse_AddCString(_response, " />");
+  
+          // the value in a checkbox list is the string besides the checkbox
+          if (self->value) {
+            WOResponse_AddHtmlString(_response,
+               [self->value stringValueInComponent:sComponent]);
+          }
+        }
+        
+        if (self->suffix) {
+          NSString *ss;
+
+          ss = [self->suffix stringValueInComponent:sComponent];
+          WOResponse_AddString(_response, ss);
+        }
+        [_ctx incrementLastElementIDComponent];
+      }
+      [_ctx deleteLastElementIDComponent]; // list index
+    }
+  }
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+
+  str = [[NSMutableString alloc] init];
+  [str appendString:[super associationDescription]];
+  if (self->list)       [str appendFormat:@" list=%@",       self->list];
+  if (self->item)       [str appendFormat:@" item=%@",       self->item];
+  if (self->index)      [str appendFormat:@" index=%@",      self->index];
+  if (self->prefix)     [str appendFormat:@" prefix=%@",     self->prefix];
+  if (self->suffix)     [str appendFormat:@" suffix=%@",     self->suffix];
+  if (self->selections) [str appendFormat:@" selections=%@", self->selections];
+
+  return AUTORELEASE(str);
+}
+
+@end /* WOCheckBoxList */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOComponentContent.h b/skyrix-sope/NGObjWeb/DynamicElements/WOComponentContent.h
new file mode 100644 (file)
index 0000000..d71bd0f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOComponentContent_H__
+#define __NGObjWeb_WOComponentContent_H__
+
+#include <NGObjWeb/WODynamicElement.h>
+
+/*
+  This element outputs content nested inside a 'container' component tag.
+  The element is new in WO4 and described in the WO4 delta doc.
+*/
+
+@interface WOComponentContent : WODynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+}
+
+@end
+
+#endif /* __NGObjWeb_WOComponentContent_H__ */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOComponentContent.m b/skyrix-sope/NGObjWeb/DynamicElements/WOComponentContent.m
new file mode 100644 (file)
index 0000000..8a3dfae
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOComponentContent.h"
+#include "WOContext+private.h"
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@interface WOContext(ComponentStackCount)
+- (unsigned)componentStackCount;
+@end
+
+@implementation WOComponentContent
+
+static int profileComponents = -1;
+static Class NSDateClass = Nil;
+
++ (void)initialize {
+  if (profileComponents == -1) {
+    profileComponents = [[[NSUserDefaults standardUserDefaults]
+                                          objectForKey:@"WOProfileComponents"]
+                                          boolValue] ? 1 : 0;
+  }
+  if (NSDateClass == Nil)
+    NSDateClass = [NSDate class];
+}
+
+// responder
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOElement *content;
+  
+  content = [_ctx componentContent]; // content (valid in parent)
+  
+  if (content) {
+    NSTimeInterval st = 0.0;
+    WOComponent *component = [_ctx component]; // reusable component
+    
+    component = RETAIN(component);
+    content   = RETAIN(content);
+    
+    if (profileComponents)
+      st = [[NSDateClass date] timeIntervalSince1970];
+    
+    [_ctx leaveComponent:component];
+    [content takeValuesFromRequest:_request inContext:_ctx];
+    [_ctx enterComponent:component content:content];
+    
+    if (profileComponents) {
+      NSTimeInterval diff;
+      int i;
+      diff = [[NSDateClass date] timeIntervalSince1970] - st;
+      for (i = [_ctx componentStackCount]; i >= 0; i--)
+        printf("  ");
+      printf("content: [%s %s]: %0.3fs\n",
+             [[component name] cString], 
+#if APPLE_RUNTIME || NeXT_RUNTIME
+            sel_getName(_cmd), 
+#else
+            sel_get_name(_cmd), 
+#endif
+            diff);
+    }
+    
+    [content   release];
+    [component release];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  WOElement *content = [_ctx componentContent]; // content (valid in parent)
+
+  if (content) {
+    NSTimeInterval st = 0.0;
+    WOComponent *component = [_ctx component]; // reusable component
+    id result;
+    
+    component = [component retain];
+    content   = [content   retain];
+
+    if (profileComponents)
+      st = [[NSDateClass date] timeIntervalSince1970];
+    
+    [_ctx leaveComponent:component];
+    result = [content invokeActionForRequest:_request inContext:_ctx];
+    result = [result retain];
+    [_ctx enterComponent:component content:content];
+    
+    if (profileComponents) {
+      NSTimeInterval diff;
+      int i;
+      diff = [[NSDateClass date] timeIntervalSince1970] - st;
+      for (i = [_ctx componentStackCount]; i >= 0; i--)
+        printf("  ");
+      printf("content: [%s %s]: %0.3fs\n",
+             [[component name] cString], 
+#if APPLE_RUNTIME || NeXT_RUNTIME
+            sel_getName(_cmd), 
+#else
+            sel_get_name(_cmd), 
+#endif
+            diff);
+    }
+    
+    [content   release];
+    [component release];
+    return [result autorelease];
+  }
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOElement *content;
+  
+  content = [_ctx componentContent]; // content (valid in parent)
+  
+  if (content) {
+    NSTimeInterval st = 0.0;
+    WOComponent *component;
+    
+    component = [_ctx component]; // reusable component
+    component = [component retain];
+    content   = [content   retain];
+
+#if DEBUG && 0
+    [_response appendContentHTMLString:@" Component:"];
+    [_response appendContentHTMLString:[component description]];
+    [_response appendContentHTMLString:@" Content:"];
+    [_response appendContentHTMLString:[content description]];
+#endif
+    
+    if (profileComponents)
+      st = [[NSDateClass date] timeIntervalSince1970];
+    
+    [_ctx leaveComponent:component];
+    [content appendToResponse:_response inContext:_ctx];
+    [_ctx enterComponent:component content:content];
+    
+    if (profileComponents) {
+      NSTimeInterval diff;
+      int i;
+      diff = [[NSDateClass date] timeIntervalSince1970] - st;
+      for (i = [_ctx componentStackCount]; i >= 0; i--)
+        printf("  ");
+      printf("content: [%s %s]: %0.3fs\n",
+             [[component name] cString], 
+#if APPLE_RUNTIME || NeXT_RUNTIME
+            sel_getName(_cmd), 
+#else
+            sel_get_name(_cmd), 
+#endif
+            diff);
+    }
+    
+    [content   release];
+    [component release];
+  }
+  else {
+#if DEBUG && 0
+    [_response appendContentHTMLString:@" Missing content in component: "];
+    [_response appendContentHTMLString:[[_ctx component] description]];
+#endif
+  }
+}
+
+@end /* WOComponentContent */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOComponentReference.h b/skyrix-sope/NGObjWeb/DynamicElements/WOComponentReference.h
new file mode 100644 (file)
index 0000000..f778827
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOComponentReference_H__
+#define __NGObjWeb_WOComponentReference_H__
+
+#include "WOHTMLDynamicElement.h"
+
+/*
+  This element can be used to dynamically embed other components.
+
+  It's very complicated and uses a lot of black magic ...
+  
+  Associations:
+
+    component   the component to embed
+*/
+
+@class WOComponent, WOAssociation;
+
+@interface WOComponentReference : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *activeComponent; // attribute 'component'
+  WOComponent   *child;           // child component
+  NSDictionary  *bindings;
+  WOElement     *template;
+}
+
+@end
+
+@interface WOComponentReference(PrivateMethods)
+
+- (void)setChildComponent:(WOComponent *)_component;
+- (WOComponent *)childComponent;
+
+@end
+
+#endif /* __NGObjWeb_WOComponentReference_H__ */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOComponentReference.m b/skyrix-sope/NGObjWeb/DynamicElements/WOComponentReference.m
new file mode 100644 (file)
index 0000000..0d7b9bf
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOComponentReference.h"
+#include "WOElement+private.h"
+#include "WOContext+private.h"
+#include "WOComponent+private.h"
+#include "common.h"
+
+@interface WOContext(ComponentStackCount)
+- (unsigned)componentStackCount;
+@end
+
+@implementation WOComponentReference
+
+static int   profileComponents = -1;
+static BOOL  coreOnRecursion   = NO;
+static BOOL  debugOn           = NO;
+static Class NSDateClass = Nil;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  profileComponents = [[ud objectForKey:@"WOProfileComponents"]
+                          boolValue] ? 1 : 0;
+  coreOnRecursion = [ud boolForKey:@"WOCoreOnRecursiveSubcomponents"];
+  NSDateClass = [NSDate class];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->containsForm    = YES;
+    self->activeComponent = OWGetProperty(_config, @"component");
+    self->bindings        = [_config copyWithZone:[self zone]];
+    [(NSMutableDictionary *)_config removeAllObjects];
+    
+    self->template = [_c retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template        release];
+  [self->bindings        release];
+  [self->activeComponent release];
+  [self->child           release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOComponent *)childComponent {
+  return self->child;
+}
+
+static inline void
+_updateComponent(WOComponentReference *self, WOContext *_ctx)
+{
+  if (self->activeComponent) {
+    WOComponent *newChild;
+
+    newChild = [self->activeComponent valueInComponent:[_ctx component]];
+
+#if 0
+    if (newChild == nil) {
+      [[_ctx component] logWithFormat:
+                          @"missing child (got nil) "
+                          @"(element=%@, association=%@, component=%@).",
+                          self, self->activeComponent,
+                          [[_ctx component] name]];
+    }
+#endif
+    
+    if (newChild != self->child) {
+      //NSLog(@"switched component %@ => %@ ...",
+      //      [self->child name], [newChild name]);
+      ASSIGN(self->child, newChild);
+      [newChild setParent:[_ctx component]];
+      [newChild setBindings:self->bindings];
+    }
+  }
+}
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *parent;
+
+  parent = [_ctx component];
+  
+  _updateComponent(self, _ctx);
+
+  if (self->child) {
+    [_ctx enterComponent:self->child content:self->template];
+    [self->child takeValuesFromRequest:_req inContext:_ctx];
+    [_ctx leaveComponent:self->child];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *parent;
+  id result    = nil;
+
+  parent = [_ctx component];
+
+  _updateComponent(self, _ctx);
+
+  if (self->child) {
+    [_ctx enterComponent:self->child content:self->template];
+    result = [self->child invokeActionForRequest:_req inContext:_ctx];
+    [_ctx leaveComponent:self->child];
+  }
+  
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *parent;
+
+  parent = [_ctx component];
+  
+  _updateComponent(self, _ctx);
+  
+  if (self->child == parent) {
+    [self debugWithFormat:@"WARNING: recursive call of component: %@", parent];
+    if (coreOnRecursion)
+      abort();
+  }
+  
+  if (self->child) {
+    NSTimeInterval st = 0.0;
+
+    if (profileComponents)
+      st = [[NSDateClass date] timeIntervalSince1970];
+    
+    [_ctx enterComponent:self->child content:self->template];
+    [self->child appendToResponse:_response inContext:_ctx];
+    [_ctx leaveComponent:self->child];
+
+    if (profileComponents) {
+      NSTimeInterval diff;
+      int i;
+      diff = [[NSDateClass date] timeIntervalSince1970] - st;
+      for (i = [_ctx componentStackCount]; i >= 0; i--)
+        printf("  ");
+      printf("[%s %s]: %0.3fs\n",
+             [[child name] cString], 
+#if APPLE_RUNTIME || NeXT_RUNTIME
+            sel_getName(_cmd), 
+#else
+            sel_get_name(_cmd), 
+#endif
+            diff);
+    }
+  }
+  else if (debugOn) {
+    [self debugWithFormat:@"missing component for reference: %@",
+           self->activeComponent];
+    [_response appendContentHTMLString:@"[missing component for reference: "];
+    [_response appendContentHTMLString:[self->activeComponent description]];
+    [_response appendContentHTMLString:@"]"];
+  }
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *desc = [NSMutableString stringWithCapacity:64];
+  
+  [desc appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
+  
+  if (self->child) {
+    [desc appendFormat:@" child=%@[0x%08X] childName=%@",
+            NSStringFromClass([self->child class]),
+            self->child, [self->child name]];
+  }
+  
+  [desc appendString:@">"];
+  return desc;
+}
+
+@end /* WOComponentReference */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOCompoundElement.h b/skyrix-sope/NGObjWeb/DynamicElements/WOCompoundElement.h
new file mode 100644 (file)
index 0000000..2fdd864
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_DynElm_WOCompoundElement_H__
+#define __NGObjWeb_DynElm_WOCompoundElement_H__
+
+#import <NGObjWeb/WODynamicElement.h>
+
+/*
+  This is a FINAL class, do not subclass !
+*/
+
+@class NSArray;
+
+@interface WOCompoundElement : WODynamicElement
+{
+@private
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  
+  unsigned short count;
+  id children[1];
+}
+
++ (id)allocForCount:(int)_count zone:(NSZone *)_zone;
+- (id)initWithContentElements:(NSArray *)_elements;
+- (id)initWithChildren:(NSArray *)_children; // deprecated
+
+@end
+
+@interface WOHTMLStaticGroup : WOCompoundElement
+
+/* this element was discovered in SSLContainer.h and may not be public */
+
+@end
+
+#endif /* __NGObjWeb_DynElm_WOCompoundElement_H__ */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOCompoundElement.m b/skyrix-sope/NGObjWeb/DynamicElements/WOCompoundElement.m
new file mode 100644 (file)
index 0000000..db2efc7
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOCompoundElement.h"
+#include "WOElement+private.h"
+#include <NGObjWeb/WOContext.h>
+#include "common.h"
+
+#if APPLE_RUNTIME || NeXT_RUNTIME
+#  include <objc/objc-class.h>
+#endif
+
+@interface WOContext(ComponentStackCount)
+- (unsigned)componentStackCount;
+@end
+
+@implementation WOCompoundElement
+
+#ifdef DEBUG
+static int profElements  = -1;
+static Class NSDateClass = Nil;
+#endif
+static int descriptiveIDs = -1;
+
++ (id)allocForCount:(int)_count zone:(NSZone *)_zone {
+  return NSAllocateObject(self, _count * sizeof(WOElement *), _zone);
+}
+
+- (id)initWithContentElements:(NSArray *)_children {
+  WOElement *(*objAtIdx)(id, SEL, int);
+  int i;
+  
+  if (_children == nil) {
+    NSLog(@"%@: invalid argument ..", self);
+    self = [self autorelease];
+    return nil;
+  }
+  
+  self = [super init];
+
+  if (descriptiveIDs == -1) {
+    descriptiveIDs =
+      [[[NSUserDefaults standardUserDefaults]
+                        objectForKey:@"WODescriptiveElementIDs"]
+                        boolValue] ? 1 : 0;
+  }
+  
+  objAtIdx = (void *)[_children methodForSelector:
+                                @selector(objectAtIndex:)];
+  NSAssert1(objAtIdx != NULL,
+            @"could not get -objectAtIndex: method of %@",
+            _children);
+  
+  self->count = [_children count];
+  for (i = (self->count - 1); i >= 0; i--) {
+    register WOElement *child;
+    
+    child = objAtIdx(_children, @selector(objectAtIndex:), i);
+    
+    self->children[i] = [child retain];
+  }
+  return self;
+}
+
+- (id)initWithChildren:(NSArray *)_children {
+  return [self initWithContentElements:_children];
+}
+- (id)init {
+  return [self initWithContentElements:nil];
+}
+
+- (void)dealloc {
+  int i;
+  for (i = 0; i < self->count; i++) {
+    [self->children[i] release];
+    self->children[i] = nil;
+  }
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSArray *)subelements {
+  if (self->count == 0)
+    return nil;
+
+  return [NSArray arrayWithObjects:self->children count:self->count];
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  void (*incId)(id, SEL);
+  unsigned short i;
+
+  incId = (void *)
+    [_ctx methodForSelector:@selector(incrementLastElementIDComponent)];
+
+  if (descriptiveIDs)
+    [_ctx appendElementIDComponent:@"c0"];
+  else
+    [_ctx appendZeroElementIDComponent];
+  
+  for (i = 0; i < self->count; i++) {
+    register WOElement *child = self->children[i];
+    
+    if (child->takeValues) {
+      child->takeValues(child,
+                        @selector(takeValuesFromRequest:inContext:),
+                        _rq, _ctx);
+    }
+    else
+      [child takeValuesFromRequest:_rq inContext:_ctx];
+    
+    if (descriptiveIDs) {
+      [_ctx deleteLastElementIDComponent];
+      [_ctx appendElementIDComponent:
+              [NSString stringWithFormat:@"c%i", i]];
+    }
+    else
+      incId(_ctx, @selector(incrementLastElementIDComponent));
+  }
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  id result = nil;
+  id idxId;
+  
+  if ((idxId = [_ctx currentElementID])) {
+    int idx = [idxId intValue];
+
+    idx = (descriptiveIDs)
+      ? [[idxId substringFromIndex:1] intValue]
+      : [idxId intValue];
+    
+    [_ctx consumeElementID]; // consume index-id
+    
+    if ((idx < 0) || (idx >= self->count)) {
+      [[_ctx session] logWithFormat:
+                        @"%s: invalid element id, %i is out of range (0-%i) !",
+                        __PRETTY_FUNCTION__,
+                        idx, (self->count - 1)];
+      return nil;
+    }
+    
+    [_ctx appendElementIDComponent:idxId];
+    result = [self->children[idx] invokeActionForRequest:_rq inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+  else {
+    [[_ctx session]
+           logWithFormat:@"%s: MISSING INDEX ID in URL: %@ !",
+             __PRETTY_FUNCTION__,
+             [_ctx senderID]];
+  }
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  static int depth = 0;
+  void (*incId)(id, SEL);
+  unsigned short i;
+#if DEBUG
+#if USE_EXCEPTION_HANDLER
+  static NSString *cName  = @"componentName";
+  static NSString *elemId = @"elementID";
+#endif
+  static int embedInPool = -1;
+  static int logId = -1;
+  NSTimeInterval st = 0.0;
+
+  if (NSDateClass == Nil)
+    NSDateClass = [NSDate class];
+  
+  if (profElements == -1) {
+    profElements = [[[NSUserDefaults standardUserDefaults]
+                                     objectForKey:@"WOProfileElements"]
+                                     boolValue] ? 1 : 0;
+  }
+  if (embedInPool == -1) {
+    embedInPool = [[[NSUserDefaults standardUserDefaults]
+                                    objectForKey:@"WOCompoundElementPool"]
+                                    boolValue] ? 1 : 0;
+    NSLog(@"WOCompoundElement: pool embedding is on.");
+  }
+  if (logId == -1) {
+    logId = [[[NSUserDefaults standardUserDefaults]
+                              objectForKey:@"WOCompoundElementLogID"]
+                              boolValue] ? 1 : 0;
+    NSLog(@"WOCompoundElement: id logging is on.");
+  }
+#endif
+
+  depth++;
+  
+#if defined(DEBUG) && USE_EXCEPTION_HANDLER
+  NS_DURING {
+#endif
+
+#ifdef DEBUG
+    if (profElements)
+      st = [[NSDateClass date] timeIntervalSince1970];
+#endif
+    
+    incId = (void *)
+      [_ctx methodForSelector:@selector(incrementLastElementIDComponent)];
+    
+    if (descriptiveIDs)
+      [_ctx appendElementIDComponent:@"c0"];
+    else
+      [_ctx appendZeroElementIDComponent];
+    
+    for (i = 0; i < self->count; i++) {
+      register WOElement *child = self->children[i];
+#if DEBUG
+      NSAutoreleasePool *pool = nil;
+      NSTimeInterval st = 0.0;
+      if (embedInPool) pool = [[NSAutoreleasePool alloc] init];
+      if (profElements)
+        st = [[NSDateClass date] timeIntervalSince1970];
+#endif
+      
+      if (child->appendResponse) {
+        child->appendResponse(child,
+                              @selector(appendToResponse:inContext:),
+                              _response, _ctx);
+      }
+      else
+        [child appendToResponse:_response inContext:_ctx];
+      
+#if DEBUG
+      if (profElements) {
+        NSTimeInterval diff;
+        int j;
+        diff = [[NSDateClass date] timeIntervalSince1970] - st;
+        if (diff > 0.0005) {
+#if 1
+          for (j = [_ctx componentStackCount] + depth; j >= 0; j--)
+            printf("  ");
+#endif
+          printf("  Child of 0x%08X: i[%i] %s <%s>: %0.3fs\n",
+                 (unsigned int)self,
+                 i, [[_ctx elementID] cString],
+                 [child class]->name,
+                 diff);
+        }
+      }
+      if (logId) {
+        NSLog(@"WOCompoundElement: pool will release ... (lastId=%@)",
+              [_ctx elementID]);
+      }
+      [pool release];
+#endif
+
+      if (descriptiveIDs) {
+        [_ctx deleteLastElementIDComponent];
+        [_ctx appendElementIDComponent:
+                [NSString stringWithFormat:@"c%i", i]];
+      }
+      else
+        incId(_ctx, @selector(incrementLastElementIDComponent));
+    }
+    [_ctx deleteLastElementIDComponent];
+
+#if DEBUG
+    if (profElements) {
+      NSTimeInterval diff;
+      int i;
+      diff = [[NSDateClass date] timeIntervalSince1970] - st;
+#if 1
+      for (i = [_ctx componentStackCount] + depth; i >= 0; i--)
+        printf("  ");
+#endif
+      printf("CompoundElem0x%08X(#%i) %s (component=%s): %0.3fs\n",
+             (unsigned int)self,
+             self->count,
+             [[_ctx elementID] cString],
+             [[(WOComponent *)[_ctx component] name] cString],
+             diff);
+    }
+#endif
+    
+#if defined(DEBUG) && USE_EXCEPTION_HANDLER
+  }
+  NS_HANDLER {
+    NSMutableDictionary *ui;
+    id tmp;
+    
+    ui = [[localException userInfo] mutableCopy];
+    if (ui == nil) ui = [[NSMutableDictionary alloc] init];
+    
+    if ((tmp = [ui objectForKey:cName]) == nil)
+      [ui setObject:[[_ctx component] name] forKey:cName];
+    if ((tmp = [ui objectForKey:elemId]) == nil)
+      [ui setObject:[_ctx elementID] forKey:elemId];
+
+    [localException setUserInfo:ui];
+    [ui release]; ui = nil;
+    
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+#endif
+
+  depth--;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+  int i;
+
+  [str appendString:@"children=\n"];
+  for (i = 0; i < self->count; i++) {
+    [str appendString:@"  "];
+    [str appendString:[self->children[i] description]];
+    [str appendString:@"\n"];
+  }
+  return str;
+}
+
+@end /* WOCompoundElement */
+
+@implementation WOHTMLStaticGroup
+
+/* this element was discovered in SSLContainer.h and may not be public */
+
+@end /* WOHTMLStaticGroup */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOConditional.m b/skyrix-sope/NGObjWeb/DynamicElements/WOConditional.m
new file mode 100644 (file)
index 0000000..619de10
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WOConditional : WODynamicElement
+{
+@protected
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  
+  WOAssociation *condition;
+  WOAssociation *negate;
+  WOElement     *template;
+
+  // non-WO
+  WOAssociation *value; // compare the condition with value
+
+#if DEBUG
+  NSString *condName;
+#endif
+}
+
+@end /* WOConditional */
+
+#include "common.h"
+#include "WOElement+private.h"
+
+// TODO: make that a class cluster for improved performance
+
+@implementation WOConditional
+
+static int descriptiveIDs = -1;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  descriptiveIDs = [ud boolForKey:@"WODescriptiveElementIDs"] ? 1 : 0;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+#if DEBUG
+  self->condName = _name ? [_name copy] : @"condYES";
+#endif
+  
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->condition = OWGetProperty(_config, @"condition");
+    self->negate    = OWGetProperty(_config, @"negate");
+    self->value     = OWGetProperty(_config, @"value");
+    self->template  = [_c retain];
+    
+    if (self->condition == nil) {
+      [self logWithFormat:
+              @"WARNING: missing 'condition' association in element: '%@'",
+              _name];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template  release];
+  [self->value     release];
+  [self->condition release];
+  [self->negate    release];
+#if DEBUG
+  [self->condName release];
+#endif
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOElement *)template {
+  return self->template;
+}
+
+/* state */
+
+static inline BOOL _doShow(WOConditional *self, WOContext *_ctx) {
+  WOComponent *cmp = [_ctx component];
+  BOOL doShow   = NO;
+  BOOL doNegate = [self->negate boolValueInComponent:cmp];
+
+  if (self->value) {
+    id v  = [self->value     valueInComponent:cmp];
+    id cv = [self->condition valueInComponent:cmp];
+    
+    doShow = [cv isEqual:v];
+  }
+  else
+    doShow = [self->condition boolValueInComponent:cmp];
+  
+  return doNegate ? !doShow : doShow;
+}
+
+/* processing requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  if (!_doShow(self, _ctx)) {
+#if 0
+    NSLog(@"didn't take value from request: %@\n  doShow=%@\n  doNegate=%@",
+          [self elementID],
+          self->condition, self->negate);
+#endif
+    return;
+  }
+  
+#if DEBUG
+  [_ctx appendElementIDComponent:descriptiveIDs ? self->condName : @"1"];
+#else
+  [_ctx appendElementIDComponent:@"1"];
+#endif
+  [self->template takeValuesFromRequest:_rq inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  NSString *state;
+  NSString *key;
+  id result;
+
+  state = [[_ctx currentElementID] stringValue];
+  
+  if (!state) 
+    return nil;
+    
+  [_ctx consumeElementID]; // consume state-id (on or off)
+    
+#if DEBUG
+  key = descriptiveIDs ? self->condName : @"1";
+#else
+  key = @"1";
+#endif
+    
+  if (![state isEqualToString:key])
+    return nil;
+      
+  [_ctx appendElementIDComponent:state];
+  result = [self->template invokeActionForRequest:_rq inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  return result;
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (!_doShow(self, _ctx))
+    return;
+#if DEBUG
+  [_ctx appendElementIDComponent:descriptiveIDs ? self->condName : @"1"];
+#else
+  [_ctx appendElementIDComponent:@"1"];
+#endif
+    
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:64];
+  if (self->condition) [str appendFormat:@" condition=%@", self->condition];
+  if (self->negate)    [str appendFormat:@" negate=%@",    self->negate];
+  if (self->template)  [str appendFormat:@" template=%@",  self->template];
+  return str;
+}
+
+@end /* WOConditional */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOEmbeddedObject.m b/skyrix-sope/NGObjWeb/DynamicElements/WOEmbeddedObject.m
new file mode 100644 (file)
index 0000000..ba37e16
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHTMLDynamicElement.h"
+#include "WOElement+private.h"
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@interface WOEmbeddedObject : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *filename;  // path relative to WebServerResources
+  WOAssociation *framework;
+  WOAssociation *src;       // absolute URL
+  WOAssociation *value;     // data (eg from a database)
+
+  /* new in WO4 */
+  WOAssociation *data;
+  WOAssociation *mimeType;
+  WOAssociation *key;
+}
+
+@end /* WOEmbeddedObject */
+
+@implementation WOEmbeddedObject
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmpl
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmpl])) {
+    self->filename  = OWGetProperty(_config, @"filename");
+    self->framework = OWGetProperty(_config, @"framework");
+    self->src       = OWGetProperty(_config, @"src");
+    self->value     = OWGetProperty(_config, @"value");
+
+    self->data      = OWGetProperty(_config, @"data");
+    self->mimeType  = OWGetProperty(_config, @"mimeType");
+    self->key       = OWGetProperty(_config, @"key");
+
+    if (self->key)
+      NSLog(@"WARNING: 'key' association in WOEmbeddedObject not supported !");
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->key);
+  RELEASE(self->data);
+  RELEASE(self->mimeType);
+  RELEASE(self->framework);
+  RELEASE(self->filename);
+  RELEASE(self->src);
+  RELEASE(self->value);
+  [super dealloc];
+}
+#endif
+
+// ******************** responder ********************
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  if (self->value) {
+    WOElement *element;
+
+    if ((element = [self->value valueInComponent:[_ctx component]]) == nil) {
+      [[_ctx session] debugWithFormat:
+          @"WARNING: missing element value for WOEmbeddedObject %@", self];
+      return nil;
+    }
+
+    [element appendToResponse:[_ctx response] inContext:_ctx];
+    return [_ctx response];
+  }
+  else if (self->data) {
+    WOComponent *sComponent;
+    NSData     *adata;
+    NSString   *atype;
+    WOResponse *response;
+    
+    sComponent = [_ctx component];
+    adata = [self->data     valueInComponent:sComponent];
+    atype = [self->mimeType stringValueInComponent:sComponent];
+    
+    response = [_ctx response];
+    
+    [response setContent:adata];
+    [response setHeader:atype ? atype : @"application/octet-stream"
+              forKey:@"content-type"];
+    
+    return response;
+  }
+  else {
+    [[_ctx session] debugWithFormat:
+                      @"no value configured for WOEmbeddedObject %@", self];
+    return nil;
+  }
+}
+
+#define StrVal(__x__) [self->__x__ stringValueInComponent:sComponent]
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![[_ctx request] isFromClientComponent]) {
+    WOComponent *sComponent = [_ctx component];
+    NSString *uUri = [self->src      stringValueInComponent:sComponent];
+    NSString *uFi  = [self->filename stringValueInComponent:sComponent];
+    NSArray  *languages;
+
+    sComponent = [_ctx component];
+    uUri = [self->src      stringValueInComponent:sComponent];
+    uFi  = [self->filename stringValueInComponent:sComponent];
+    
+    WOResponse_AddCString(_response, "<embed src=\"");
+    
+    if ((self->data != nil) || (self->value != nil)) {
+      /* a component action link */
+      uUri = [_ctx componentActionURL];
+      if (uFi) {
+        uUri = [uUri stringByAppendingString:@"/"];
+        uUri = [uUri stringByAppendingString:uFi];
+      }
+      WOResponse_AddString(_response, uUri);
+    }
+    else if (uFi) {
+      WOResourceManager *rm;
+      NSString  *frameworkName;
+      
+      if ((rm = [[_ctx component] resourceManager]) == nil)
+        rm = [[_ctx application] resourceManager];
+      
+      /* If 'framework' binding is not set, use parent component's framework */
+      if (self->framework){
+        frameworkName = [self->framework stringValueInComponent:[_ctx component]];
+        if (frameworkName != nil && [frameworkName isEqualToString:@"app"])
+          frameworkName = nil;
+      }
+      else
+        frameworkName = [[_ctx component] frameworkName];
+      
+      languages = [_ctx hasSession]
+        ? [[_ctx session] languages]
+        : [[_ctx request] browserLanguages];
+      uFi = [rm urlForResourceNamed:uFi
+                inFramework:frameworkName
+                languages:languages
+                request:[_ctx request]];
+      if (uFi == nil) {
+        NSLog(@"%@: did not find resource '%@'", sComponent,
+              [self->filename stringValueInComponent:sComponent]);
+        uFi = uUri;
+      }
+      [_response appendContentHTMLAttributeValue:uFi];
+    }
+    else if (uUri) {
+      [_response appendContentHTMLAttributeValue:uUri];
+    }
+    else {
+      [sComponent logWithFormat:@"missing resource URL for element %@", self];
+    }
+    
+    WOResponse_AddChar(_response, '"');
+  
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    if (self->otherTagString) {
+      WOResponse_AddString(_response,
+                           [self->otherTagString stringValueInComponent:
+                                                   [_ctx component]]);
+    }
+    WOResponse_AddCString(_response, " />");
+  }
+}
+
+// description
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [[NSMutableString alloc] init];
+
+  if (self->filename)  [str appendFormat:@" filename=%@",  self->filename];
+  if (self->framework) [str appendFormat:@" framework=%@", self->framework];
+  if (self->src)       [str appendFormat:@" src=%@",       self->src];
+  if (self->value)     [str appendFormat:@" value=%@",     self->value];
+  
+  return AUTORELEASE(str);
+}
+
+@end /* WOEmbeddedObject */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOEntity.m b/skyrix-sope/NGObjWeb/DynamicElements/WOEntity.m
new file mode 100644 (file)
index 0000000..dff0ae7
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOHTMLDynamicElement.h"
+#include "WOElement+private.h"
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOxElemBuilder.h>
+#include <DOM/DOMProtocols.h>
+#include "common.h"
+
+@interface WOEntity : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *name;
+}
+
+@end /* WOEntity */
+
+@implementation WOEntity
+
+- (id)initWithElement:(id<DOMElement>)_element
+  templateBuilder:(WOxElemBuilder *)_builder
+{
+  NSString            *tname;
+  NSMutableDictionary *assocs;
+  id<NSObject,DOMNamedNodeMap> attrs;
+  unsigned count;
+  
+  tname = [_element tagName];
+  
+  /* construct associations */
+  
+  assocs = nil;
+  attrs = [_element attributes];
+  if ((count = [attrs length]) > 0)
+    assocs = [_builder associationsForAttributes:attrs];
+
+  if ([tname isEqualToString:@"nbsp"]) {
+    WOAssociation *a;
+
+    a = [_builder associationForValue:@"nbsp"];
+    if (assocs)
+      [assocs setObject:a forKey:@"name"];
+    else
+      assocs = [NSMutableDictionary dictionaryWithObject:a forKey:@"name"];
+  }
+  
+  /* construct child elements */
+  
+  if ([_element hasChildNodes]) {
+    [_builder logWithFormat:@"WARNING: element %@ has child-nodes (ignored)",
+                _element];
+  }
+  
+  /* construct self ... */
+  self = [self initWithName:tname
+               associations:assocs 
+               contentElements:nil];
+  [(id)self setExtraAttributes:assocs];
+  return self;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmpl
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmpl])) {
+    if ((self->name = OWGetProperty(_config, @"name")) == nil) {
+      NSLog(@"%s: missing 'name' binding for entity element %@ (assocs=%@)...",
+            __PRETTY_FUNCTION__, _name, _config);
+      RELEASE(self);
+      return nil;
+    }
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->name);
+  [super dealloc];
+}
+#endif
+
+// ******************** responder ********************
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *s;
+  
+  if ([[_ctx request] isFromClientComponent])
+    return;
+
+  s = [self->name stringValueInComponent:[_ctx component]];
+  if ([s length] == 0)
+    return;
+
+  WOResponse_AddChar(_response, '&');
+  WOResponse_AddString(_response, s);
+  WOResponse_AddChar(_response, ';');
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  return [NSString stringWithFormat:@" name=%@",  self->name];
+}
+
+@end /* WOEntity */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOFileUpload.m b/skyrix-sope/NGObjWeb/DynamicElements/WOFileUpload.m
new file mode 100644 (file)
index 0000000..d52f5cd
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOInput.h"
+#include "common.h"
+#import <NGMime/NGMime.h>
+#import <NGHttp/NGHttp.h>
+
+@interface WOFileUpload : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // inherited: name
+  // inherited: value
+  // inherited: disabled
+@protected
+  WOAssociation *filePath; // dispostion 'filename'
+  WOAssociation *data;     // uploaded data
+}
+
+@end /* WOFileUpload */
+
+@interface WORequest(UsedPrivates)
+- (id)httpRequest;
+@end
+
+@implementation WOFileUpload
+
+static NGMimeType *multipartFormData = nil;
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+
+    multipartFormData = [NGMimeType mimeType:@"multipart/form-data"];
+    multipartFormData = RETAIN(multipartFormData);
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_root {
+
+  if ((self = [super initWithName:_name associations:_config template:_root])) {
+    self->filePath = OWGetProperty(_config, @"filePath");
+    self->data     = OWGetProperty(_config, @"data");
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->filePath); self->filePath = nil;
+  RELEASE(self->data);     self->data     = nil;
+  [super dealloc];
+}
+#endif
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if (![self->disabled boolValueInComponent:[_ctx component]]) {
+    NSString *currentId;
+    id       formValue  = nil;
+
+    currentId = OWFormElementName(self, _ctx);
+
+    formValue = [_request formValueForKey:currentId];
+    if (formValue) {
+      NGMimeType *contentType = [[_request httpRequest] contentType];
+      
+      if (![contentType hasSameType:multipartFormData]) {
+        NSLog(@"WARNING: tried to apply file-upload value of %@ from "
+              @"a non multipart-form request (value=%@) !",
+              [_ctx elementID], formValue);
+        return;
+      }
+  
+      //NSLog(@"%@: value=%@ ..", [self elementID], formValue);
+
+      if ([self->data isValueSettable])
+        [self->data setValue:formValue inComponent:[_ctx component]];
+
+      if ([self->filePath isValueSettable]) {
+        NGMimeMultipartBody *body = [[_request httpRequest] body];
+
+        if ([body isKindOfClass:[NGMimeMultipartBody class]]) {
+          NSArray  *parts   = [body parts];
+          unsigned i, count = [parts count];
+
+          // search for part of current form element
+          
+          for (i = 0; i < count; i++) {
+            id disposition;
+            id<NGMimePart> bodyPart;
+            
+            bodyPart = [parts objectAtIndex:i];
+            disposition =
+              [[bodyPart valuesOfHeaderFieldWithName:@"content-disposition"]
+                         nextObject];
+            
+            if (disposition) {
+              static Class DispClass = Nil;
+              NSString *formName;
+              
+              if (DispClass == Nil)
+                DispClass = [NGMimeContentDispositionHeaderField class];
+              
+              if (![disposition isKindOfClass:DispClass]) {
+                disposition =
+                  [[DispClass alloc] initWithString:[disposition stringValue]];
+                AUTORELEASE(disposition);
+              }
+              
+              formName =
+               [(NGMimeContentDispositionHeaderField *)disposition name];
+              
+              if ([formName isEqualToString:currentId]) {
+                [self->filePath
+                    setValue:[disposition filename]
+                     inComponent:[_ctx component]];
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![[_ctx request] isFromClientComponent]) {
+    NSString *v = [self->value stringValueInComponent:[_ctx component]];
+      
+    WOResponse_AddCString(_response, "<input type=\"file\" name=\"");
+    [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+    WOResponse_AddChar(_response, '"');
+    if (v) {
+      WOResponse_AddCString(_response, " value=\"");
+      [_response appendContentHTMLAttributeValue:v];
+      WOResponse_AddChar(_response, '"');
+    }
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  
+    if (self->otherTagString) {
+      WOResponse_AddString(_response,
+                           [self->otherTagString stringValueInComponent:
+                                [_ctx component]]);
+    }
+    WOResponse_AddCString(_response, " />");
+  }
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [[NSMutableString alloc] init];
+  [str appendString:[super associationDescription]];
+
+  if (self->filePath) [str appendFormat:@" path=%@", self->filePath];
+  if (self->data)     [str appendFormat:@" data=%@", self->data];
+
+  return AUTORELEASE(str);
+}
+
+@end /* WOFileUpload */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOForm.h b/skyrix-sope/NGObjWeb/DynamicElements/WOForm.h
new file mode 100644 (file)
index 0000000..7401fd6
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_DynElem_WOForm_H__
+#define __NGObjWeb_DynElem_WOForm_H__
+
+#include "WOHTMLDynamicElement.h"
+
+@class WOAssociation;
+
+@interface WOForm : WOHTMLDynamicElement
+{
+@protected
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  
+  WOAssociation *action;
+  WOAssociation *href;
+  WOAssociation *pageName;
+  WOElement     *template;
+
+  // new in WO4:
+  WOAssociation *queryDictionary;
+  NSDictionary  *queryParameters;  /* associations beginning with '?' */
+  WOAssociation *actionClass;
+  WOAssociation *directActionName;
+  BOOL          sidInUrl;          /* include session-id in wa URL ? */
+  
+  // skyrix
+  WOAssociation *method;
+}
+
+@end
+
+#endif /* __NGObjWeb_DynElem_WOForm_H__ */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOForm.m b/skyrix-sope/NGObjWeb/DynamicElements/WOForm.m
new file mode 100644 (file)
index 0000000..a1165e8
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOForm.h"
+#include "WOElement+private.h"
+#include "WOInput.h"
+#include "WOContext+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@implementation WOForm
+
+static int debugTakeValues = -1;
+
++ (int)version {
+  return 4;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if (debugTakeValues == -1) {
+    debugTakeValues = 
+      [[NSUserDefaults standardUserDefaults] boolForKey:@"WODebugTakeValues"]
+      ? 1 : 0;
+    if (debugTakeValues) NSLog(@"WOForm: WODebugTakeValues on.");
+  }
+  
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    WOAssociation *sidInUrlAssoc;
+
+    self->containsForm = YES;
+    
+    sidInUrlAssoc          = OWGetProperty(_config, @"?wosid");
+    self->action           = OWGetProperty(_config, @"action");
+    self->href             = OWGetProperty(_config, @"href");
+    self->pageName         = OWGetProperty(_config, @"pageName");
+    self->queryDictionary  = OWGetProperty(_config, @"queryDictionary");
+    self->queryParameters  = OWExtractQueryParameters(_config);
+    self->actionClass      = OWGetProperty(_config, @"actionClass");
+    self->directActionName = OWGetProperty(_config, @"directActionName");
+    self->method           = OWGetProperty(_config, @"method");
+    
+    self->sidInUrl = (sidInUrlAssoc != nil)
+      ? [sidInUrlAssoc boolValueInComponent:nil]
+      : YES;
+    
+    self->template = [_c retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->method           release];
+  [self->template         release];
+  [self->actionClass      release];
+  [self->directActionName release];
+  [self->queryDictionary  release];
+  [self->queryParameters  release];
+  [self->action           release];
+  [self->pageName         release];
+  [self->href             release];
+  [super dealloc];
+}
+
+/* handle active form elements */
+
+- (WOElement *)template {
+  return self->template;
+}
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  static int alwaysPassIn = -1;
+
+  if (alwaysPassIn == -1) {
+    alwaysPassIn = [[[NSUserDefaults standardUserDefaults]
+                                     objectForKey:@"WOFormAlwaysPassDown"]
+                                     boolValue] ? 1 : 0;
+  }
+  
+  if ([_ctx isInForm]) {
+    NSLog(@"ERROR(%s): another form is already active in context !",
+          __PRETTY_FUNCTION__);
+  }
+  
+  [_ctx setInForm:YES];
+  {
+    WOComponent *sComponent = [_ctx component];
+    BOOL doTakeValues = NO;
+    
+    if (self->queryParameters) {
+      /* apply values to ?style parameters */
+      NSEnumerator *keys;
+      NSString     *key;
+
+      keys = [self->queryParameters keyEnumerator];
+      while ((key = [keys nextObject])) {
+        WOAssociation *assoc;
+        id value;
+        
+        assoc = [self->queryParameters objectForKey:key];
+        value = [_request formValueForKey:key];
+
+        [assoc setValue:value inComponent:sComponent];
+      }
+    }
+    
+    if ([[self->href stringValueInComponent:sComponent] 
+         isEqualToString:[_request uri]]) {
+      if (debugTakeValues) {
+       NSArray *formValues = [_request formValueKeys];
+       NSLog(@"%s: we are uri active (uri=%@): %@ ..", __PRETTY_FUNCTION__,
+             [_request uri], formValues);
+      }
+      doTakeValues = YES;
+    }
+    else if ([[_ctx elementID] isEqualToString:[_ctx senderID]]) {
+      if (debugTakeValues) {
+       NSArray *formValues = [_request formValueKeys];
+       NSLog(@"%s: we are elem active (eid=%@): %@ ..", __PRETTY_FUNCTION__,
+             [_ctx elementID], formValues);
+      }
+      doTakeValues = YES;
+    }
+    else if (alwaysPassIn) {
+      if (debugTakeValues)
+       NSLog(@"%s: taking values from foreign request ",__PRETTY_FUNCTION__);
+      doTakeValues = YES;
+    }
+    else {
+      /* finally, let the component decide */
+      doTakeValues = [sComponent shouldTakeValuesFromRequest:_request 
+                                inContext:_ctx];
+      if (debugTakeValues) {
+       NSLog(@"%s: component should take values: %s ", __PRETTY_FUNCTION__,
+             doTakeValues ? "yes" : "no");
+      }
+    }
+    
+    if (doTakeValues) {
+      if (debugTakeValues) 
+       NSLog(@"%s: taking values ...", __PRETTY_FUNCTION__);
+      
+      [self->template takeValuesFromRequest:_request inContext:_ctx];
+
+      if (debugTakeValues) 
+       NSLog(@"%s: did take values.", __PRETTY_FUNCTION__);
+    }
+    else if (debugTakeValues) {
+      [sComponent
+             debugWithFormat:
+               @"WOForm: *not* taking values from foreign request "
+               @"(id='%@' vs sid='%@') ...",
+               [_ctx elementID], [_ctx senderID]];
+    }
+  }
+  
+  if (![_ctx isInForm]) {
+    [[_ctx component]
+           logWithFormat:@"ERROR(%s:%d): -isInForm is NO !!!",
+             __PRETTY_FUNCTION__, __LINE__];
+  }
+  else
+    [_ctx setInForm:NO];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  id result = nil;
+  
+  [_ctx setInForm:YES];
+
+  if ([_ctx currentElementID] == nil) {
+    WOElement *element;
+    
+    if ((element = [_ctx activeFormElement])) {
+#if 1
+      result = [self->template invokeActionForRequest:_request inContext:_ctx];
+      RETAIN(result);
+#else
+      /* wrong - need to setup correct component stack */
+      result = [[element invokeActionForRequest:_request
+                         inContext:_ctx]
+                         retain];
+#endif
+    }
+    else if (self->action) {
+      result = [self executeAction:self->action inContext:_ctx];
+    }
+    else if (self->pageName) {
+      NSString    *pname = nil;
+      WOComponent *page = nil;
+
+      pname = [self->pageName stringValueInComponent:[_ctx component]];
+      page  = [[_ctx application] pageWithName:pname inContext:_ctx];
+
+      if (page == nil) {
+        [[_ctx session] logWithFormat:
+                          @"%@[0x%08X]: did not find page with name %@ !",
+                          NSStringFromClass([self class]), self, pname];
+      }
+      NSLog(@"showing page %@", page);
+      result = page;
+    }
+  }
+  else
+    result = [self->template invokeActionForRequest:_request inContext:_ctx];
+
+  [_ctx setInForm:NO];
+
+  return result;
+}
+
+- (NSString *)_addHrefToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  /* post to a fixed hyperlink */
+  WOComponent *sComponent = [_ctx component];
+  NSString     *s;
+  NSDictionary *d;
+
+  s = [self->href stringValueInComponent:sComponent];
+  d = [self->queryDictionary valueInComponent:sComponent];
+  
+  WOResponse_AddString(_r, s);
+  
+  return [self queryStringForQueryDictionary:d
+              andQueryParameters:self->queryParameters
+              inContext:_ctx];
+}
+
+- (NSString *)_addActionToResponse:(WOResponse *)_r inContext:(WOContext *)_c {
+  /* post to a component action */
+  NSDictionary *d;
+        
+  WOResponse_AddString(_r, [_c componentActionURL]);
+
+  d = [self->queryDictionary valueInComponent:[_c component]];
+  return [self queryStringForQueryDictionary:d
+              andQueryParameters:self->queryParameters
+              inContext:_c];
+}
+
+- (void)_addDirectActionToResponse:(WOResponse *)_r inContext:(WOContext *)_c {
+  /* a direct action link */
+  WOComponent *sComponent;
+  NSString            *daClass = nil;
+  NSString            *daName  = nil;
+  NSMutableDictionary *qd;
+  NSDictionary        *tmp;
+  NSString            *uri;
+          
+  sComponent = [_c component];
+  daClass = [self->actionClass stringValueInComponent:sComponent];
+  daName  = [self->directActionName stringValueInComponent:sComponent];
+  
+  if (daClass) {
+    if (daName) {
+      if (![daClass isEqualToString:@"DirectAction"])
+       daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
+    }
+    else
+      daName = daClass;
+  }
+  
+  qd = [NSMutableDictionary dictionaryWithCapacity:16];
+  
+  /* add query dictionary */
+        
+  if (self->queryDictionary) {
+    if ((tmp = [self->queryDictionary valueInComponent:sComponent]))
+      [qd addEntriesFromDictionary:tmp];
+  }
+        
+  /* add ?style parameters */
+  
+  if (self->queryParameters) {
+    NSEnumerator *keys;
+    NSString     *key;
+  
+    keys = [self->queryParameters keyEnumerator];
+    while ((key = [keys nextObject])) {
+      id assoc, value;
+  
+      assoc = [self->queryParameters objectForKey:key];
+      value = [assoc stringValueInComponent:sComponent];
+            
+      [qd setObject:(value ? value : @"") forKey:key];
+    }
+  }
+        
+  /* add session ID */
+  if (self->sidInUrl && [_c hasSession]) {
+    WOSession *sn;
+
+    sn = [_c session];
+    [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
+            
+    if (![sn isDistributionEnabled]) {
+      [qd setObject:[[WOApplication application] number]
+         forKey:WORequestValueInstance];
+    }
+  }
+  else if (self->sidInUrl) {
+    [self debugWithFormat:
+           @"Note: session-id is requested, but no session is active?"];
+  }
+  
+  uri = [_c directActionURLForActionNamed:daName queryDictionary:qd];
+  WOResponse_AddString(_r, uri);
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSString    *queryString = nil;
+  
+  if ([[_ctx request] isFromClientComponent]) {
+    [self->template appendToResponse:_response inContext:_ctx];
+    return;
+  }
+  
+  [_ctx setInForm:YES];
+  sComponent  = [_ctx component];
+
+  WOResponse_AddCString(_response, "<form action=\"");
+      
+  if (self->href) 
+    queryString = [self _addHrefToResponse:_response inContext:_ctx];
+  else if (self->directActionName != nil || self->actionClass != nil)
+    [self _addDirectActionToResponse:_response inContext:_ctx];
+  else
+    queryString = [self _addActionToResponse:_response inContext:_ctx];
+  
+  if (queryString) {
+    [_response appendContentCharacter:'?'];
+    WOResponse_AddString(_response, queryString);
+  }
+  if (self->method) {
+    WOResponse_AddCString(_response, "\" method=\"");
+    WOResponse_AddString(_response, 
+                        [self->method stringValueInComponent:sComponent]);
+    WOResponse_AddCString(_response, "\"");
+  }
+  else
+    WOResponse_AddCString(_response, "\" method=\"post\"");
+      
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  
+  if (self->otherTagString) {
+    NSString *s;
+    
+    s = [self->otherTagString stringValueInComponent:sComponent];
+    if ([s length] > 0) WOResponse_AddString(_response, s);
+  }
+  WOResponse_AddChar(_response, '>');
+    
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  WOResponse_AddCString(_response, "</form>");
+  [_ctx setInForm:NO];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:64];
+  //[str appendString:[super associationDescription]];
+
+  if (self->action)   [str appendFormat:@" action=%@", self->action];
+  if (self->href)     [str appendFormat:@" href=%@", self->href];
+  if (self->pageName) [str appendFormat:@" page=%@", self->pageName];
+
+  if (self->actionClass)
+    [str appendFormat:@" actionClass=%@", self->actionClass];
+  if (self->directActionName)
+    [str appendFormat:@" directAction=%@", self->directActionName];
+  if (self->template)
+    [str appendFormat:@" template=%@", self->template];
+  
+  return str;
+}
+
+@end /* WOForm */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOFrame.m b/skyrix-sope/NGObjWeb/DynamicElements/WOFrame.m
new file mode 100644 (file)
index 0000000..899ad67
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOElement+private.h"
+#include "WOHTMLDynamicElement.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WODynamicElement.h>
+#include "common.h"
+
+#define FRAME_TYPE_None  0
+#define FRAME_TYPE_Page  1
+#define FRAME_TYPE_Href  2
+#define FRAME_TYPE_Value 3
+#define FRAME_TYPE_DA    4
+
+@interface WOFrame : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  /* new in WO4 */
+  WOAssociation *queryDictionary;
+  NSDictionary  *queryParameters;  /* associations beginning with ? */
+}
+
+@end
+
+@interface _WOPageFrame : WOFrame
+{
+  WOAssociation *pageName;
+}
+@end
+
+@interface _WOHrefFrame : WOFrame
+{
+  WOAssociation *src;
+}
+@end
+
+@interface _WOValueFrame : WOFrame
+{
+  WOAssociation *value;
+}
+@end
+
+@interface _WODirectActionFrame : WOFrame
+{
+  WOAssociation *actionClass;
+  WOAssociation *directActionName;
+  BOOL          sidInUrl;          /* include session-id in wa URL ? */
+}
+@end
+
+@interface WOFrame(PrivateMethods)
+
+- (id)_initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t;
+
+- (NSString *)associationDescription;
+
+@end
+
+#if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (void)subclassResponsibility:(SEL)_cmd;
+@end
+#endif
+
+@implementation WOFrame
+
++ (int)version {
+  return 1;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  Class frameClass = Nil;
+  
+  if ([_config objectForKey:@"value"])
+    frameClass = [_WOValueFrame class];
+  else if ([_config objectForKey:@"pageName"])
+    frameClass = [_WOPageFrame class];
+  else if ([_config objectForKey:@"src"])
+    frameClass = [_WOHrefFrame class];
+  else
+    frameClass = [_WODirectActionFrame class];
+
+  [self release];
+  return [[frameClass alloc]
+                      initWithName:_name associations:_config template:_t];
+}
+
+- (id)_initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmpl
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmpl])) {
+    self->queryDictionary = OWGetProperty(_config, @"queryDictionary");
+    self->queryParameters = OWExtractQueryParameters(_config);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->queryDictionary);
+  RELEASE(self->queryParameters);
+  [super dealloc];
+}
+
+// ******************** responder ********************
+
+#define StrVal(__x__) [self->__x__ stringValueInComponent:sComponent]
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  [self subclassResponsibility:_cmd];
+  return NO;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent = [_ctx component];
+  NSString *queryString = nil;
+  if ([[_ctx request] isFromClientComponent])
+    return;
+
+  WOResponse_AddCString(_response, "<frame src=\"");
+    
+  if ([self _appendHrefToResponse:_response inContext:_ctx]) {
+    queryString = [self queryStringForQueryDictionary:
+                        [self->queryDictionary valueInComponent:sComponent]
+                        andQueryParameters:self->queryParameters
+                        inContext:_ctx];
+  }
+
+  if (queryString) {
+    [_response appendContentCharacter:'?'];
+    WOResponse_AddString(_response, queryString);
+  }
+  WOResponse_AddChar(_response, '"');
+  
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  WOResponse_AddCString(_response, " />");
+}
+
+// description
+
+- (NSString *)associationDescription {
+  return @"";
+}
+
+@end /* WOFrame */
+
+@implementation _WOPageFrame
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    self->pageName = OWGetProperty(_config, @"pageName");
+
+    if (self->pageName == nil) {
+      NSLog(@"missing pageName association for WOFrame ..");
+      RELEASE(self);
+      return nil;
+    }
+
+#if DEBUG
+    if ([_config objectForKey:@"value"] ||
+        [_config objectForKey:@"src"]     ||
+        [_config objectForKey:@"directActionName"] ||
+        [_config objectForKey:@"actionClass"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOFrame !"
+            @" (assign only one of pageName, href, "
+            @"directActionName or action)");
+    }
+#endif
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->pageName);
+  [super dealloc];
+}
+#endif
+
+/* value generation */
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString    *name;
+  WOComponent *page;
+
+  name = [self->pageName stringValueInComponent:[_ctx component]];
+  page = [[WOApplication application] pageWithName:name inContext:_ctx];
+
+  [[_ctx component] debugWithFormat:@"deliver page %@", [page name]];
+
+  return page;
+}
+
+/* href generation */
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOResponse_AddString(_response, [_ctx componentActionURL]);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" pageName=%@", self->pageName];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOPageFrame */
+
+@implementation _WOHrefFrame
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    self->src = OWGetProperty(_config, @"src");
+
+    if (self->src == nil) {
+      NSLog(@"missing src association for WOFrame ..");
+      RELEASE(self);
+      return nil;
+    }
+
+#if DEBUG
+    if ([_config objectForKey:@"value"] ||
+        [_config objectForKey:@"pageName"]     ||
+        [_config objectForKey:@"directActionName"] ||
+        [_config objectForKey:@"actionClass"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOFrame !"
+            @" (assign only one of pageName, src, directActionName or value)");
+    }
+#endif
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->src);
+  [super dealloc];
+}
+#endif
+
+/* URI generation */
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  WOResponse_AddString(_r, [self->src stringValueInComponent:[_ctx component]]);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" src=%@", self->src];
+  [str appendString:[super associationDescription]];
+
+  return str;
+}
+
+@end /* _WOHrefFrame */
+
+@implementation _WODirectActionFrame
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    WOAssociation *sidInUrlAssoc;
+
+    sidInUrlAssoc          = OWGetProperty(_config, @"?wosid");
+    self->actionClass      = OWGetProperty(_config, @"actionClass");
+    self->directActionName = OWGetProperty(_config, @"directActionName");
+
+    self->sidInUrl = (sidInUrlAssoc)
+      ? [sidInUrlAssoc boolValueInComponent:nil]
+      : YES;
+    
+#if DEBUG
+    if ([_config objectForKey:@"value"] ||
+        [_config objectForKey:@"src"]     ||
+        [_config objectForKey:@"pageName"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOFrame !"
+            @" (assign only one of value, src, directActionName or pageName)");
+    }
+#endif
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->actionClass);
+  RELEASE(self->directActionName);
+  [super dealloc];
+}
+#endif
+
+/* href */
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent         *sComponent;
+  NSString            *daClass;
+  NSString            *daName;
+  NSMutableDictionary *qd;
+  NSDictionary        *tmp;
+
+  sComponent = [_ctx component];
+  daClass = [self->actionClass stringValueInComponent:sComponent];
+  daName  = [self->directActionName stringValueInComponent:sComponent];
+
+  if (daClass) {
+    if (daName) {
+      if (![daClass isEqualToString:@"DirectAction"])
+        daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
+    }
+    else
+      daName = daClass;
+  }
+
+  qd = [NSMutableDictionary dictionaryWithCapacity:16];
+
+      /* add query dictionary */
+      
+  if (self->queryDictionary) {
+    if ((tmp = [self->queryDictionary valueInComponent:sComponent]))
+      [qd addEntriesFromDictionary:tmp];
+  }
+      
+  /* add ?style parameters */
+
+  if (self->queryParameters) {
+    NSEnumerator *keys;
+    NSString     *key;
+
+    keys = [self->queryParameters keyEnumerator];
+    while ((key = [keys nextObject])) {
+      id assoc, value;
+
+      assoc = [self->queryParameters objectForKey:key];
+      value = [assoc stringValueInComponent:sComponent];
+          
+      [qd setObject:(value ? value : @"") forKey:key];
+    }
+  }
+      
+  /* add session ID */
+
+  if (self->sidInUrl) {
+    if ([_ctx hasSession]) {
+      WOSession *sn = [_ctx session];
+          
+      [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
+          
+      if (![sn isDistributionEnabled]) {
+        [qd setObject:[[WOApplication application] number]
+            forKey:WORequestValueInstance];
+      }
+    }
+  }
+
+  WOResponse_AddString(_response,
+                       [_ctx directActionURLForActionNamed:daName
+                             queryDictionary:qd]);
+  return NO;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  if (self->actionClass)
+    [str appendFormat:@" actionClass=%@", self->actionClass];
+  if (self->directActionName)
+    [str appendFormat:@" directAction=%@", self->directActionName];
+  
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WODirectActionFrame */
+
+@implementation _WOValueFrame
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    self->value = OWGetProperty(_config, @"value");
+
+    if (self->value == nil) {
+      NSLog(@"missing value association for WOFrame ..");
+      RELEASE(self);
+      return nil;
+    }
+
+#if DEBUG
+    if ([_config objectForKey:@"pageName"] ||
+        [_config objectForKey:@"href"]     ||
+        [_config objectForKey:@"directActionName"] ||
+        [_config objectForKey:@"actionClass"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOFrame !"
+            @" (assign only one of pageName, href, directActionName or value)");
+    }
+#endif
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->value);
+  [super dealloc];
+}
+#endif
+
+/* dynamic invocation */
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  return [self->value valueInComponent:[_ctx component]];
+}
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOResponse_AddString(_response, [_ctx componentActionURL]);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" value=%@", self->value];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOValueFrame */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOGenericContainer.m b/skyrix-sope/NGObjWeb/DynamicElements/WOGenericContainer.m
new file mode 100644 (file)
index 0000000..cf859fb
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOGenericElement.h"
+
+@interface WOGenericContainer : WOGenericElement
+{
+  // WODynamicElement:   extraAttributes
+  // WODynamicElement:   otherTagString
+  // WOGenericContainer: tagName
+@protected
+  WOElement *template;
+}
+
+@end
+
+#import "WOElement+private.h"
+#import "common.h"
+
+// TODO(perf): ASCII Tags (appendContentCString)
+// TODO(perf): constant tags
+
+#define TagNameType_Assoc  0
+#define TagNameType_String 1
+#define TagNameType_ASCII  2
+
+@implementation WOGenericContainer
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->template = [_c retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOElement *)template {
+  return self->template;
+}
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+}
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_req inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSString    *tag;
+  
+  if ([[_ctx request] isFromClientComponent])
+    return;
+  
+  sComponent = [_ctx component];
+  switch (self->tagNameType) {
+    case TagNameType_Assoc:
+      if ((tag = [(id)self->tagName stringValueInComponent:sComponent]) == nil)
+        tag = @"p";
+      break;
+    case TagNameType_String:
+      if ((tag = self->tagName) == nil) tag = @"p";
+      break;
+    case TagNameType_ASCII:
+    default:
+      tag = nil;
+      break;
+  }
+  
+  WOResponse_AddChar(_response, '<');
+  if (tag) {
+    WOResponse_AddString(_response, tag);
+  }
+  else if (self->tagNameType == TagNameType_ASCII) {
+    WOResponse_AddCString(_response, self->tagName);
+  }
+  
+  [self _appendAttributesToResponse:_response inContext:_ctx];
+  
+  if (self->otherTagString) {
+    NSString *s;
+
+    s = [self->otherTagString stringValueInComponent:sComponent];
+    
+    WOResponse_AddString(_response, s);
+  }
+  WOResponse_AddChar(_response, '>');
+  
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  WOResponse_AddCString(_response, "</");
+  if (tag) {
+    WOResponse_AddString(_response, tag);
+  }
+  else if (self->tagNameType == TagNameType_ASCII) {
+    WOResponse_AddCString(_response, self->tagName);
+  }
+  WOResponse_AddChar(_response, '>');
+}
+
+@end /* WOGenericContainer */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOGenericElement.h b/skyrix-sope/NGObjWeb/DynamicElements/WOGenericElement.h
new file mode 100644 (file)
index 0000000..cb9794d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_DynElem_WOGenericElement_H__
+#define __NGObjWeb_DynElem_WOGenericElement_H__
+
+#include "WOHTMLDynamicElement.h"
+
+/*
+  WOGenericElement / WOGenericContainer
+  
+  Generate any tag with dynamic bindings.
+*/
+
+@class WOAssociation;
+
+@interface WOGenericElement : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  void     *tagName; // (elementName attribute)
+  unsigned tagNameType;
+@private
+  void     *mappings;
+  unsigned count;
+}
+
+- (void)_appendAttributesToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __NGObjWeb_DynElem_WOGenericElement_H__ */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOGenericElement.m b/skyrix-sope/NGObjWeb/DynamicElements/WOGenericElement.m
new file mode 100644 (file)
index 0000000..b091143
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOGenericElement.h"
+#include "WOElement+private.h"
+#include "common.h"
+#include <NGObjWeb/WOxElemBuilder.h>
+#include <DOM/DOMProtocols.h>
+
+// TODO: we should be able to store the key as ASCII ?
+// TODO: does it make sense to resolve constant associations ?
+//       all constant assocs could be joined at init time ?
+
+#define TagNameType_Assoc  0
+#define TagNameType_String 1
+#define TagNameType_ASCII  2
+
+typedef struct {
+  NSString      *key;
+  WOAssociation *value;
+} OWAttribute;
+
+@implementation WOGenericElement
+
+- (id)initWithElement:(id<DOMElement>)_element
+  templateBuilder:(WOxElemBuilder *)_builder
+{
+  NSString            *name;
+  NSMutableDictionary *assocs;
+  NSArray             *children;
+  id<NSObject,DOMNamedNodeMap> attrs;
+  unsigned lcount;
+  
+  name  = [_element tagName];
+  
+  /* construct associations */
+
+  assocs = nil;
+  attrs = [_element attributes];
+  if ((lcount = [attrs length]) > 0)
+    assocs = [_builder associationsForAttributes:attrs];
+
+  if (assocs == nil) {
+    assocs = 
+      [NSMutableDictionary dictionaryWithObject:
+                             [_builder associationForValue:[_element tagName]]
+                           forKey:@"elementName"];
+  }
+  else {
+    [assocs setObject:[_builder associationForValue:[_element tagName]]
+            forKey:@"elementName"];
+  }
+  
+  /* construct child elements */
+
+  children = [_element hasChildNodes]
+    ? [_builder buildNodes:[_element childNodes] templateBuilder:_builder]
+    : nil;
+  
+  /* construct self ... */
+  self = [(WODynamicElement *)self initWithName:name 
+                                   associations:assocs 
+                                   contentElements:children];
+  return self;
+}
+
+- (BOOL)_isASCIIString:(NSString *)_s {
+  /* TODO: not a very fast check for an ASCII string ... */
+  return [_s dataUsingEncoding:NSASCIIStringEncoding 
+             allowLossyConversion:NO] != nil ? YES : NO;
+}
+
+- (void)_setupAssociations:(NSMutableDictionary *)_associations {
+  NSEnumerator *keys;
+  NSString     *key     = nil;
+  OWAttribute  *mapping = NULL;
+  
+  if (self->count == 0)
+    return;
+  
+  keys           = [_associations keyEnumerator];
+  self->mappings = calloc(self->count, sizeof(OWAttribute));
+  
+  for (mapping = self->mappings; (key = [keys nextObject]); mapping++) {
+    WOAssociation *value;
+        
+    value = [_associations objectForKey:key];
+    mapping->key   = [key copy];
+    mapping->value = [value retain];
+  }
+  [_associations removeAllObjects];
+}
+
+- (void)_configureForConstantElementName:(NSString *)s {
+  if ([self _isASCIIString:s]) {
+    unsigned char *cs;
+    unsigned len;
+        
+    len = [s cStringLength];
+    cs = malloc(len + 2);
+    [s getCString:cs];
+    cs[len] = '\0';
+    self->tagName = cs;
+    self->tagNameType = TagNameType_ASCII;
+  }
+  else {
+    /* a tagname which is not ASCII ?? */
+    self->tagName = [s copy];
+    self->tagNameType = TagNameType_String;
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  template:(WOElement *)_template
+{
+  self = [super initWithName:_name
+                associations:_associations
+                template:_template];
+  
+  if (self) {
+    WOAssociation *a;
+    
+    self->tagName     = a = OWGetProperty(_associations, @"elementName");
+    self->tagNameType = TagNameType_Assoc;
+    self->count   = [_associations count];
+    
+    if ([a isValueConstant]) {
+      [self _configureForConstantElementName:[a stringValueInComponent:nil]];
+      [a release]; a = nil;
+    }
+    
+    if (self->count > 0)
+      [self _setupAssociations:(NSMutableDictionary *)_associations];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (self->mappings) {
+    OWAttribute *map;
+    unsigned cnt;
+
+    for (cnt = 0, map = self->mappings; cnt < self->count; cnt++, map++) {
+      [map->key   release]; map->key   = nil;
+      [map->value release]; map->value = nil;
+    }
+    if (self->mappings) free(self->mappings);
+    self->mappings = NULL;
+  }
+  
+  switch (self->tagNameType) {
+    case TagNameType_Assoc:  [(id)self->tagName release]; break;
+    case TagNameType_String: [(id)self->tagName release]; break;
+    case TagNameType_ASCII:
+      if (self->tagName) free(self->tagName);
+      break;
+    default:
+      NSLog(@"ERROR: unknown tag-name-type %i !", self->tagNameType);
+      break;
+  }
+  [super dealloc];
+}
+
+/* response generation */
+
+- (void)_appendAttributesToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  // TODO: this seems to take some time during profiling, maybe we can
+  //       optimize that (ASCII keys, constant assocs)
+  WOComponent *sComponent = [_ctx component];
+  OWAttribute *map;
+  unsigned cnt;
+  
+  for (cnt = 0, map = self->mappings; cnt < self->count; cnt++, map++) {
+    register id value;
+    
+    if ((value = [map->value valueInComponent:sComponent]) == nil)
+      continue;
+
+    WOResponse_AddChar(_response, ' ');
+    WOResponse_AddString(_response, map->key);
+    WOResponse_AddCString(_response, "=\"");
+    WOResponse_AddHtmlString(_response, [value stringValue]);
+    WOResponse_AddChar(_response, '"');
+  }
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSString    *tag;
+  
+  if ([[_ctx request] isFromClientComponent])
+    return;
+  
+  sComponent = [_ctx component];
+  
+  WOResponse_AddChar(_response, '<');
+  switch (self->tagNameType) {
+    case TagNameType_Assoc:
+      tag = [(id)self->tagName stringValueInComponent:sComponent];
+      WOResponse_AddString(_response, tag);
+      break;
+    case TagNameType_String:
+      WOResponse_AddString(_response, self->tagName);
+      break;
+    case TagNameType_ASCII:
+      WOResponse_AddCString(_response, self->tagName);
+      break;
+  }
+  
+  [self _appendAttributesToResponse:_response inContext:_ctx];
+  
+  if (self->otherTagString) {
+    NSString *s;
+    
+    s = [self->otherTagString stringValueInComponent:sComponent];
+    WOResponse_AddString(_response, s);
+  }
+  WOResponse_AddCString(_response, " />");
+}
+
+@end /* WOGenericElement */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOHTMLDynamicElement.h b/skyrix-sope/NGObjWeb/DynamicElements/WOHTMLDynamicElement.h
new file mode 100644 (file)
index 0000000..e7ea64e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOHTMLDynamicElement_H__
+#define __NGObjWeb_WOHTMLDynamicElement_H__
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@class NSDictionary;
+@class WOAssociation, WOContext;
+
+@interface WOHTMLDynamicElement : WODynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+}
+
+@end
+
+@interface WOHTMLDynamicElement(ActiveElement)
+- (id)executeAction:(WOAssociation *)_action inContext:(WOContext *)_ctx;
+@end
+
+/* private functions */
+
+NSDictionary *OWExtractQueryParameters(NSDictionary *_set);
+
+#endif /* __NGObjWeb_WOHTMLDynamicElement_H__ */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOHTMLDynamicElement.m b/skyrix-sope/NGObjWeb/DynamicElements/WOHTMLDynamicElement.m
new file mode 100644 (file)
index 0000000..da0838a
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHTMLDynamicElement.h"
+#include "WOElement+private.h"
+#include "common.h"
+
+@implementation WOHTMLDynamicElement
+
+static BOOL debugActionExecute = NO;
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
+
++ (void)initialize {
+  NSUserDefaults *ud;
+    
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  ud = [NSUserDefaults standardUserDefaults];
+  debugActionExecute = [ud boolForKey:@"WODebugActions"];
+}
+
+/* active element */
+
+- (id)executeAction:(WOAssociation *)_action inContext:(WOContext *)_ctx {
+  // TODO: I think this is deprectated?
+  id  object;
+  SEL act;
+  
+  if (_action == nil) {
+    if (debugActionExecute) {
+      [self logWithFormat:@"%@(%@): got no action to execute ..",
+              NSStringFromClass([self class]), _ctx];
+    }
+    return nil;
+  }
+  
+  if ((object = [_ctx component]) == nil) {
+    if (debugActionExecute) {
+      [self logWithFormat:@"%@(%@): got no object to execute action: %@",
+              NSStringFromClass([self class]), _ctx, _action];
+    }
+    return nil;
+  }
+  
+  if (![_action isValueConstant]) {
+    /* action specified like this: action = doIt; */
+    id result;
+    
+    result = [_action valueInComponent:object];
+    if (debugActionExecute) {
+      [self logWithFormat:@"%@(%@): executed dynamic action, got: %@",
+              NSStringFromClass([self class]), _ctx, result];
+    }
+    
+    if ([result respondsToSelector:@selector(ensureAwakeInContext:)]) {
+      if (debugActionExecute) {
+        [self logWithFormat:@"%@(%@): ensure result is awake in ctx",
+                NSStringFromClass([self class]), _ctx];
+      }
+      [result ensureAwakeInContext:_ctx];
+    }
+    return result;
+  }
+    
+  /* action specified like this: action = "doIt"; */
+
+  [[_ctx component]
+         debugWithFormat:@"WARNING: %@ used with 'string' action !", self];
+
+  act = NSSelectorFromString([_action stringValueInComponent:object]);
+  if ([object respondsToSelector:act])
+    return [object performSelector:act];
+  
+  [[_ctx component] logWithFormat:
+                      @"%@[0x%08X]: %@ does not respond to action @%@",
+                      NSStringFromClass([self class]), self,
+                      object,
+                      NSStringFromSelector(act)];
+  return nil;
+}
+
+@end /* WOHTMLDynamicElement */
+
+NSDictionary *OWExtractQueryParameters(NSDictionary *_set) {
+  NSMutableDictionary *paras = nil;
+  NSMutableArray      *paraKeys = nil;
+  NSEnumerator        *keys;
+  NSString            *key;
+
+  /* locate query parameters */
+  keys = [_set keyEnumerator];
+  while ((key = [keys nextObject])) {
+    if ([key hasPrefix:@"?"]) {
+      WOAssociation *value;
+
+      if ([key isEqualToString:@"?wosid"])
+        continue;
+
+      value = [_set objectForKey:key];
+          
+      if (paraKeys == nil)
+        paraKeys = [NSMutableArray arrayWithCapacity:8];
+      if (paras == nil)
+        paras = [NSMutableDictionary dictionaryWithCapacity:8];
+          
+      [paraKeys addObject:key];
+      [paras setObject:value forKey:[key substringFromIndex:1]];
+    }
+  }
+
+  // remove query parameters
+  if (paraKeys) {
+    unsigned cnt, count;
+    for (cnt = 0, count = [paraKeys count]; cnt < count; cnt++) {
+      [(NSMutableDictionary *)_set removeObjectForKey:
+                                     [paraKeys objectAtIndex:cnt]];
+    }
+  }
+
+  // assign parameters
+  return [paras copy];
+}
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOHiddenField.m b/skyrix-sope/NGObjWeb/DynamicElements/WOHiddenField.m
new file mode 100644 (file)
index 0000000..23ce924
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOInput.h"
+#include "common.h"
+
+@interface WOHiddenField : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // WOInput:    name
+  // WOInput:    value
+  // WOInput:    disabled
+}
+
+@end /* WOHiddenField */
+
+@implementation WOHiddenField
+
+// responder
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![[_ctx request] isFromClientComponent]) {
+    BOOL isDisabled;
+
+    isDisabled = [self->disabled boolValueInComponent:[_ctx component]];
+    
+    if (isDisabled) {
+      NSString *s;
+
+      s = [self->value stringValueInComponent:[_ctx component]];
+      [_response appendContentHTMLString:s];
+    }
+    else {
+      NSString *v;
+
+      v = [self->value stringValueInComponent:[_ctx component]];
+      
+      WOResponse_AddCString(_response, "<input type=\"hidden\" name=\"");
+      [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+      WOResponse_AddCString(_response, "\" value=\"");
+      [_response appendContentHTMLAttributeValue:v];
+      WOResponse_AddChar(_response, '"');
+      [self appendExtraAttributesToResponse:_response inContext:_ctx];
+      if (self->otherTagString) {
+        WOResponse_AddString(_response,
+                             [self->otherTagString stringValueInComponent:
+                                  [_ctx component]]);
+      }
+      WOResponse_AddCString(_response, " />");
+    }
+  }
+}
+
+@end /* WOHiddenField */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOHtml.m b/skyrix-sope/NGObjWeb/DynamicElements/WOHtml.m
new file mode 100644 (file)
index 0000000..183b671
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOElement+private.h"
+#include "WOHTMLDynamicElement.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+
+@class WOAssociation;
+
+@interface WOHtml : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOElement *template;
+}
+@end
+
+@implementation WOHtml
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->template  = RETAIN(_c);
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->template);
+  [super dealloc];
+}
+#endif
+
+// accessors
+
+- (WOElement *)template {
+  return self->template;
+}
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+}
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_req inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if ([[_ctx request] isFromClientComponent]) {
+    [self->template appendToResponse:_response inContext:_ctx];
+    return;
+  }
+  
+  WOResponse_AddCString(_response, "<html>");
+  
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  WOResponse_AddCString(_response, "</html>");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:128];
+  
+  if (self->template)  [str appendFormat:@" template=%@",  self->template];
+  
+  return str;
+}
+
+@end /* WOHtml */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOHyperlink.h b/skyrix-sope/NGObjWeb/DynamicElements/WOHyperlink.h
new file mode 100644 (file)
index 0000000..03de545
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOHyperlink_H__
+#define __NGObjWeb_WOHyperlink_H__
+
+#include "WOHTMLDynamicElement.h"
+
+@class NSString;
+@class WOHyperlinkInfo;
+
+@interface WOHyperlink : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+}
+
+- (id)initWithName:(NSString *)_name
+  hyperlinkInfo:(WOHyperlinkInfo *)_info
+  template:(WOElement *)_t;
+
+@end /* WOHyperlink */
+
+@interface _WOTemporaryHyperlink : NSObject
+@end
+
+#endif /* __NGObjWeb_WOHyperlink_H__ */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOHyperlink.m b/skyrix-sope/NGObjWeb/DynamicElements/WOHyperlink.m
new file mode 100644 (file)
index 0000000..eb616ed
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHyperlink.h"
+#include "WOElement+private.h"
+#include "WOHyperlinkInfo.h"
+#include "WOCompoundElement.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGExtensions/NSString+Ext.h>
+#include "common.h"
+
+#define PROFILE_CLUSTERS 0
+
+#if PROFILE_CLUSTERS
+#  warning HYPERLINK CLUSTER PROFILING IS TURNED ON !!!
+#endif
+
+// TODO(perf): all adding of links to an anker can probably be added using
+//             appendContentCString because they are already escaped
+//             => check that for umlauts in downloads !
+
+/*
+  WOHyperlink associations:
+
+    href | pageName | action | (directActionName & actionClass)
+    fragmentIdentifier
+    string
+    target
+    disabled
+    queryDictionary
+
+  Concrete Class Hierachy
+
+    _WOTemporaryHyperlink
+    WOHTMLDynamicElement
+      WOHyperlink
+        _WOComplexHyperlink
+          _WOHrefHyperlink
+          _WOActionHyperlink
+          _WOPageHyperlink
+          _WODirectActionHyperlink
+        _WOSimpleActionHyperlink
+          _WOSimpleStringActionHyperlink
+        _WOCommonStaticDAHyperlink
+*/
+
+@implementation WOHyperlink
+
++ (int)version {
+  return [super version] + 2 /* v4 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
++ (id)allocWithZone:(NSZone *)zone {
+  static Class WOHyperlinkClass = Nil;
+  static _WOTemporaryHyperlink *temporaryHyperlink = nil;
+  
+  if (WOHyperlinkClass == Nil)
+    WOHyperlinkClass = [WOHyperlink class];
+  if (temporaryHyperlink == nil)
+    temporaryHyperlink = [_WOTemporaryHyperlink allocWithZone:zone];
+  
+  if (self == WOHyperlinkClass)
+    return temporaryHyperlink;
+  else {
+#if PROFILE_CLUSTERS
+    static unsigned totalCount        = 0;
+    static unsigned countSimpleAction = 0;
+    static unsigned countAction       = 0;
+    static unsigned countHref         = 0;
+    static unsigned countDirectAction = 0;
+    static unsigned countCommonDA     = 0;
+    static unsigned countOther        = 0;
+    totalCount++;
+    if (self == [_WOSimpleActionHyperlink class])
+      countSimpleAction++;
+    else if (self == [_WOActionHyperlink class])
+      countAction++;
+    else if (self == [_WODirectActionHyperlink class])
+      countDirectAction++;
+    else if (self == [_WOHrefHyperlink class])
+      countHref++;
+    else if (self == NSClassFromString(@"_WOCommonStaticDAHyperlink"))
+      countCommonDA++;
+    else
+      countOther++;
+
+    if (totalCount % 30 == 0) {
+      NSLog(@"WOHyperlink statistics:\n"
+            @" total: %d,"
+            @" simple action: %d,"
+            @" action: %d,"
+            @" direct action: %d,"
+            @" common DA:     %d,"
+            @" href: %d,"
+            @" other: %d",
+            totalCount, countSimpleAction, countAction,
+            countDirectAction, countCommonDA, countHref, countOther);
+    }
+#endif
+    return NSAllocateObject(self, 0, zone);
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  hyperlinkInfo:(WOHyperlinkInfo *)_info
+  template:(WOElement *)_t
+{
+  return [super initWithName:_name associations:nil template:_t];
+}
+
+@end /* WOHyperlink */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOHyperlinkInfo.h b/skyrix-sope/NGObjWeb/DynamicElements/WOHyperlinkInfo.h
new file mode 100644 (file)
index 0000000..38a611e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOHyperlinkInfo_H__
+#define __WOHyperlinkInfo_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSMutableDictionary, NSDictionary;
+@class WOAssociation, WOElement;
+
+/* a temporary object to store all associations relevant for WOHyperlink */
+
+@interface WOHyperlinkInfo : NSObject
+{
+@public
+  NSMutableDictionary *rest;
+  unsigned char initialCount;
+  unsigned char assocCount;   /* count of ivar associations which are set */
+  
+  WOAssociation *action;
+  WOAssociation *href;
+  WOAssociation *pageName;
+  WOAssociation *actionClass;
+  WOAssociation *directActionName;
+  
+  BOOL          sidInUrl;
+
+  /* 'ivar' associations */
+  WOAssociation *string;
+  WOAssociation *fragmentIdentifier;
+  WOAssociation *target;
+  WOAssociation *disabled;
+  WOAssociation *queryDictionary;
+  NSDictionary  *queryParameters;
+  WOAssociation *filename;
+  WOAssociation *framework;
+  WOAssociation *src;
+  WOAssociation *disabledFilename;
+}
+
+- (id)initWithConfig:(NSMutableDictionary *)_config;
+
+@end
+
+#endif /* __WOHyperlinkInfo_H__ */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOHyperlinkInfo.m b/skyrix-sope/NGObjWeb/DynamicElements/WOHyperlinkInfo.m
new file mode 100644 (file)
index 0000000..b5770d4
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHyperlinkInfo.h"
+#include "WOElement+private.h"
+#include "WOHTMLDynamicElement.h"
+#include "common.h"
+
+@implementation WOHyperlinkInfo
+
+- (id)initWithConfig:(NSMutableDictionary *)_config {
+  unsigned count;
+
+  if ((self->initialCount = count = [_config count]) == 0) {
+    NSLog(@"%s: missing associations for WOHyperlink !", __PRETTY_FUNCTION__);
+    RELEASE(self);
+    return nil;
+  }
+  
+  self->sidInUrl = YES;
+  
+  //NSLog(@"CONFIG: %@", _config);
+  
+  if ((self->action = OWGetProperty(_config, @"action"))) {
+    count--;
+#if DEBUG
+    if (count > 0) {
+      if ([_config objectForKey:@"pageName"] ||
+          [_config objectForKey:@"href"]     ||
+          [_config objectForKey:@"directActionName"] ||
+          [_config objectForKey:@"actionClass"]) {
+        NSLog(@"WARNING: inconsistent association settings in WOHyperlink !"
+              @" (assign only one of pageName, href, "
+              @"directActionName or action)");
+      }
+    }
+#endif
+    if ([self->action isValueConstant]) {
+      /* make a direct-action ... */
+      self->directActionName = self->action;
+      self->action = nil;
+
+      if (count > 0) {
+        if ((self->actionClass = OWGetProperty(_config,@"actionClass")))
+          count--;
+      }
+      if (count > 0) {
+        WOAssociation *sidInUrlAssoc;
+        
+        if ((sidInUrlAssoc = OWGetProperty(_config, @"?wosid"))) {
+          self->sidInUrl = [sidInUrlAssoc boolValueInComponent:nil];
+          RELEASE(sidInUrlAssoc);
+          count--;
+        }
+        else
+          self->sidInUrl = YES;
+      }
+      else
+        self->sidInUrl = YES;
+    }
+  }
+  else if ((self->pageName = OWGetProperty(_config, @"pageName"))) {
+    count--;
+#if DEBUG
+    if (count > 0) {
+      if ([_config objectForKey:@"action"] ||
+          [_config objectForKey:@"href"]     ||
+          [_config objectForKey:@"directActionName"] ||
+          [_config objectForKey:@"actionClass"]) {
+        NSLog(@"WARNING: inconsistent association settings in WOHyperlink !"
+              @" (assign only one of pageName, href, "
+              @"directActionName or action)");
+      }
+    }
+#endif
+  }
+  else if ((self->href = OWGetProperty(_config, @"href"))) {
+    count--;
+    if (count > 0) {
+      WOAssociation *sidInUrlAssoc;
+      
+      if ((sidInUrlAssoc = OWGetProperty(_config, @"?wosid"))) {
+        self->sidInUrl = [sidInUrlAssoc boolValueInComponent:nil];
+        RELEASE(sidInUrlAssoc);
+        count--;
+      }
+      else
+        self->sidInUrl = NO;
+    }
+#if DEBUG
+    if (count > 0) {
+      if ([_config objectForKey:@"action"] ||
+          [_config objectForKey:@"pageName"]     ||
+          [_config objectForKey:@"directActionName"] ||
+          [_config objectForKey:@"actionClass"]) {
+        NSLog(@"WARNING: inconsistent association settings in WOHyperlink !"
+              @" (assign only one of pageName, href, "
+              @"directActionName or action)");
+      }
+    }
+#endif
+  }
+  else if ((self->directActionName = OWGetProperty(_config,@"directActionName"))) {
+    count--;
+    if (count > 0) {
+      if ((self->actionClass = OWGetProperty(_config,@"actionClass")))
+        count--;
+    }
+    if (count > 0) {
+      WOAssociation *sidInUrlAssoc;
+      
+      if ((sidInUrlAssoc = OWGetProperty(_config, @"?wosid"))) {
+        self->sidInUrl = [sidInUrlAssoc boolValueInComponent:nil];
+        RELEASE(sidInUrlAssoc);
+        count--;
+      }
+      else
+        self->sidInUrl = YES;
+    }
+    
+#if DEBUG
+    if (count > 0) {
+      if ([_config objectForKey:@"action"] ||
+          [_config objectForKey:@"href"]     ||
+          [_config objectForKey:@"pageName"]) {
+        NSLog(@"WARNING: inconsistent association settings in WOHyperlink !"
+              @" (assign only one of pageName, href, "
+              @"directActionName or action)");
+      }
+    }
+#endif
+  }
+  else {
+    NSLog(@"%s: missing link-type specified for WOHyperlink (config=%@) !",
+          __PRETTY_FUNCTION__, _config);
+    RELEASE(self);
+    return nil;
+  }
+  
+  if (count > 0) {
+    if ((self->string = OWGetProperty(_config, @"string"))) {
+      count--;
+      assocCount++;
+    }
+  }
+  if (count > 0) {
+    if ((self->fragmentIdentifier=OWGetProperty(_config, @"fragmentIdentifier"))) {
+      count--;
+      assocCount++;
+    }
+  }
+  if (count > 0) {
+    if ((self->target = OWGetProperty(_config, @"target"))) {
+      count--;
+      assocCount++;
+    }
+  }
+  if (count > 0) {
+    if ((self->queryDictionary = OWGetProperty(_config, @"queryDictionary"))) {
+      count--;
+      assocCount++;
+    }
+  }
+  if (count > 0) {
+    if ((self->queryParameters = OWExtractQueryParameters(_config))) {
+      count--;
+      assocCount++;
+    }
+  }
+  if (count > 0) {
+    if ((self->disabled = OWGetProperty(_config, @"disabled"))) {
+      count--;
+      assocCount++;
+    }
+  }
+
+  if (count > 0) {
+    if ((self->filename = OWGetProperty(_config, @"filename"))) {
+      count--;
+      assocCount++;
+    }
+  }
+  if (count > 0) {
+    if ((self->framework = OWGetProperty(_config, @"framework"))) {
+      count--;
+      assocCount++;
+    }
+  }
+  if (count > 0) {
+    if ((self->src = OWGetProperty(_config, @"src"))) {
+      count--;
+      assocCount++;
+    }
+  }
+  if (count > 0) {
+    if ((self->disabledFilename = OWGetProperty(_config, @"disabledFilename"))) {
+      count--;
+      assocCount++;
+    }
+  }
+  
+  self->rest = _config;
+  
+  return self;
+}
+
+@end /* WOHyperlinkInfo */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOIFrame.m b/skyrix-sope/NGObjWeb/DynamicElements/WOIFrame.m
new file mode 100644 (file)
index 0000000..d675046
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOElement+private.h"
+#include "WOHTMLDynamicElement.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WODynamicElement.h>
+#include "common.h"
+
+#define FRAME_TYPE_None  0
+#define FRAME_TYPE_Page  1
+#define FRAME_TYPE_Href  2
+#define FRAME_TYPE_Value 3
+#define FRAME_TYPE_DA    4
+
+@interface WOIFrame : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  /* new in WO4 */
+  WOAssociation *queryDictionary;
+  NSDictionary  *queryParameters;  /* associations beginning with ? */
+  WOElement     *template;
+}
+
+@end
+
+@interface _WOPageIFrame : WOIFrame
+{
+  WOAssociation *pageName;
+}
+@end
+
+@interface _WOHrefIFrame : WOIFrame
+{
+  WOAssociation *src;
+}
+@end
+
+@interface _WOValueIFrame : WOIFrame
+{
+  WOAssociation *value;
+  WOAssociation *filename;
+}
+@end
+
+@interface _WODirectActionIFrame : WOIFrame
+{
+  WOAssociation *actionClass;
+  WOAssociation *directActionName;
+  BOOL          sidInUrl;          /* include session-id in wa URL ? */
+}
+@end
+
+@interface WOIFrame(PrivateMethods)
+
+- (id)_initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t;
+
+- (NSString *)associationDescription;
+
+@end
+
+#if NeXT_Foundation_LIBRARY || APPLE_FOUNDATION_LIBRARY
+@interface NSObject(Miss)
+- (void)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+@implementation WOIFrame
+
++ (int)version {
+  return 1;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  Class frameClass = Nil;
+  
+  if ([_config objectForKey:@"value"])
+    frameClass = [_WOValueIFrame class];
+  else if ([_config objectForKey:@"pageName"])
+    frameClass = [_WOPageIFrame class];
+  else if ([_config objectForKey:@"src"])
+    frameClass = [_WOHrefIFrame class];
+  else
+    frameClass = [_WODirectActionIFrame class];
+
+  [self release];
+  return [[frameClass alloc]
+                      initWithName:_name associations:_config template:_t];
+}
+
+- (id)_initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmpl
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmpl])) {
+    self->queryDictionary = OWGetProperty(_config, @"queryDictionary");
+    self->queryParameters = OWExtractQueryParameters(_config);
+
+    self->template = [_tmpl retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template        release];
+  [self->queryDictionary release];
+  [self->queryParameters release];
+  [super dealloc];
+}
+
+// ******************** responder ********************
+
+#define StrVal(__x__) [self->__x__ stringValueInComponent:sComponent]
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  [self subclassResponsibility:_cmd];
+  return NO;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![[_ctx request] isFromClientComponent]) {
+    WOComponent *sComponent = [_ctx component];
+    NSString *queryString = nil;
+
+    WOResponse_AddCString(_response, "<iframe src=\"");
+
+    if ([self _appendHrefToResponse:_response inContext:_ctx]) {
+      queryString = [self queryStringForQueryDictionary:
+                            [self->queryDictionary valueInComponent:sComponent]
+                          andQueryParameters:self->queryParameters
+                          inContext:_ctx];
+    }
+
+    if (queryString) {
+      [_response appendContentCharacter:'?'];
+      WOResponse_AddString(_response, queryString);
+    }
+    WOResponse_AddChar(_response, '"');
+    
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    
+    if (self->otherTagString) {
+      WOResponse_AddString(_response,
+                           [self->otherTagString stringValueInComponent:
+                                                   [_ctx component]]);
+    }
+    WOResponse_AddChar(_response, '>');
+
+    [self->template appendToResponse:_response inContext:_ctx];
+    
+    WOResponse_AddCString(_response, "</iframe>");
+  }
+}
+
+// description
+
+- (NSString *)associationDescription {
+  return @"";
+}
+
+@end /* WOIFrame */
+
+@implementation _WOPageIFrame
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    self->pageName = OWGetProperty(_config, @"pageName");
+
+    if (self->pageName == nil) {
+      NSLog(@"missing pageName association for WOIFrame ..");
+      [self release];
+      return nil;
+    }
+
+#if DEBUG
+    if ([_config objectForKey:@"value"] ||
+        [_config objectForKey:@"src"]     ||
+        [_config objectForKey:@"directActionName"] ||
+        [_config objectForKey:@"actionClass"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOIFrame !"
+            @" (assign only one of pageName, href, "
+            @"directActionName or action)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->pageName release];
+  [super dealloc];
+}
+
+/* value generation */
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString    *name;
+  WOComponent *page;
+
+  name = [self->pageName stringValueInComponent:[_ctx component]];
+  page = [[WOApplication application] pageWithName:name inContext:_ctx];
+
+  [[_ctx component] debugWithFormat:@"deliver page %@", [page name]];
+
+  return page;
+}
+
+/* href generation */
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOResponse_AddString(_response, [_ctx componentActionURL]);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" pageName=%@", self->pageName];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOPageIFrame */
+
+@implementation _WOHrefIFrame
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    self->src = OWGetProperty(_config, @"src");
+
+    if (self->src == nil) {
+      NSLog(@"missing src association for WOIFrame ..");
+      [self release];
+      return nil;
+    }
+
+#if DEBUG
+    if ([_config objectForKey:@"value"] ||
+        [_config objectForKey:@"pageName"]     ||
+        [_config objectForKey:@"directActionName"] ||
+        [_config objectForKey:@"actionClass"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOIFrame !"
+            @" (assign only one of pageName, src, directActionName or value)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->src release];
+  [super dealloc];
+}
+
+/* URI generation */
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  WOResponse_AddString(_r, [self->src stringValueInComponent:[_ctx component]]);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" src=%@", self->src];
+  [str appendString:[super associationDescription]];
+
+  return str;
+}
+
+@end /* _WOHrefIFrame */
+
+@implementation _WODirectActionIFrame
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    WOAssociation *sidInUrlAssoc;
+
+    sidInUrlAssoc          = OWGetProperty(_config, @"?wosid");
+    self->actionClass      = OWGetProperty(_config, @"actionClass");
+    self->directActionName = OWGetProperty(_config, @"directActionName");
+
+    self->sidInUrl = (sidInUrlAssoc)
+      ? [sidInUrlAssoc boolValueInComponent:nil]
+      : YES;
+    
+#if DEBUG
+    if ([_config objectForKey:@"value"] ||
+        [_config objectForKey:@"src"]     ||
+        [_config objectForKey:@"pageName"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOIFrame !"
+            @" (assign only one of value, src, directActionName or pageName)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->actionClass      release];
+  [self->directActionName release];
+  [super dealloc];
+}
+
+/* href */
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent         *sComponent;
+  NSString            *daClass;
+  NSString            *daName;
+  NSMutableDictionary *qd;
+  NSDictionary        *tmp;
+
+  sComponent = [_ctx component];
+  daClass = [self->actionClass stringValueInComponent:sComponent];
+  daName  = [self->directActionName stringValueInComponent:sComponent];
+
+  if (daClass) {
+    if (daName) {
+      if (![daClass isEqualToString:@"DirectAction"])
+        daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
+    }
+    else
+      daName = daClass;
+  }
+
+  qd = [NSMutableDictionary dictionaryWithCapacity:16];
+
+      /* add query dictionary */
+      
+  if (self->queryDictionary) {
+    if ((tmp = [self->queryDictionary valueInComponent:sComponent]))
+      [qd addEntriesFromDictionary:tmp];
+  }
+      
+  /* add ?style parameters */
+
+  if (self->queryParameters) {
+    NSEnumerator *keys;
+    NSString     *key;
+
+    keys = [self->queryParameters keyEnumerator];
+    while ((key = [keys nextObject])) {
+      id assoc, value;
+
+      assoc = [self->queryParameters objectForKey:key];
+      value = [assoc stringValueInComponent:sComponent];
+          
+      [qd setObject:(value ? value : @"") forKey:key];
+    }
+  }
+      
+  /* add session ID */
+
+  if (self->sidInUrl) {
+    if ([_ctx hasSession]) {
+      WOSession *sn = [_ctx session];
+          
+      [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
+          
+      if (![sn isDistributionEnabled]) {
+        [qd setObject:[[WOApplication application] number]
+            forKey:WORequestValueInstance];
+      }
+    }
+  }
+
+  WOResponse_AddString(_response,
+                       [_ctx directActionURLForActionNamed:daName
+                             queryDictionary:qd]);
+  return NO;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  if (self->actionClass)
+    [str appendFormat:@" actionClass=%@", self->actionClass];
+  if (self->directActionName)
+    [str appendFormat:@" directAction=%@", self->directActionName];
+  
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WODirectActionIFrame */
+
+@implementation _WOValueIFrame
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    self->value    = OWGetProperty(_config, @"value");
+    self->filename = OWGetProperty(_config, @"filename");
+
+    if (self->value == nil) {
+      NSLog(@"missing value association for WOIFrame ..");
+      [self release];
+      return nil;
+    }
+
+#if DEBUG
+    if ([_config objectForKey:@"pageName"] ||
+        [_config objectForKey:@"href"]     ||
+        [_config objectForKey:@"directActionName"] ||
+        [_config objectForKey:@"actionClass"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOIFrame !"
+            @" (assign only one of pageName, href, directActionName or value)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->filename release];
+  [self->value    release];
+  [super dealloc];
+}
+
+/* dynamic invocation */
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  return [self->value valueInComponent:[_ctx component]];
+}
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *uri, *fn;
+  
+  uri = [_ctx componentActionURL];
+  fn  = [self->filename stringValueInComponent:[_ctx component]];
+
+  if ([fn length] > 0) {
+    uri = [uri stringByAppendingString:@"/"];
+    uri = [uri stringByAppendingString:fn];
+  }
+  
+  WOResponse_AddString(_response, uri);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" value=%@", self->value];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOValueIFrame */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOImage.h b/skyrix-sope/NGObjWeb/DynamicElements/WOImage.h
new file mode 100644 (file)
index 0000000..72fcf5c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_DynElems_WOImage_H__
+#define __NGObjWeb_DynElems_WOImage_H__
+
+#include "WOHTMLDynamicElement.h"
+
+/*
+  WOImage is a class cluster with separate subclasses for the different
+  image types (dynamic, element, external and resource - image).
+  
+  Note: WOImage is a class cluster!
+  
+  WOImage associations:
+    otherTagString
+    filename
+    framework
+    src
+    value
+    data
+    mimeType
+    key
+*/
+
+@interface WOImage : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+}
+
+@end /* WOImage */
+
+@interface WOImage(Privates)
+
+- (NSString *)associationDescription;
+
+@end
+
+#endif /* __NGObjWeb_DynElems_WOImage_H__ */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOImage.m b/skyrix-sope/NGObjWeb/DynamicElements/WOImage.m
new file mode 100644 (file)
index 0000000..53fb531
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOImage.h"
+
+@interface _WOTemporaryImage : NSObject
+@end
+
+@interface _WODynamicImage : WOImage /* new in WO4 */
+{
+  WOAssociation *data;
+  WOAssociation *mimeType;
+  WOAssociation *key;
+}
+@end
+
+@interface _WOElementImage : WOImage
+{
+  WOAssociation *value;     // image data (eg from a database)
+}
+@end
+
+@interface _WOExternalImage : WOImage
+{
+  WOAssociation *src;       // absolute URL
+}
+@end
+
+@interface WOImage(PrivateMethods)
+
+- (NSString *)associationDescription;
+
+@end
+
+#include "WOElement+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+
+#if NeXT_Foundation_LIBRARY || APPLE_FOUNDATION_LIBRARY
+@interface NSObject(Miss)
+- (void)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+@implementation WOImage
+
++ (id)allocWithZone:(NSZone *)zone {
+  static Class WOImageClass = Nil;
+  static _WOTemporaryImage *temporaryImage = nil;
+  
+  if (WOImageClass == Nil)
+    WOImageClass = [WOImage class];
+  if (temporaryImage == nil)
+    temporaryImage = [_WOTemporaryImage allocWithZone:zone];
+  
+  return (self == WOImageClass)
+    ? (id)temporaryImage
+    : NSAllocateObject(self, 0, zone);
+}
+
+/* request handling */
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  NSLog(@"no value configured for WOImage %@", self);
+  return nil;
+}
+
+- (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  [self subclassResponsibility:_cmd];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if ([[_ctx request] isFromClientComponent])
+    return;
+
+  WOResponse_AddCString(_response, "<img src=\"");
+    
+#if DEBUG && USE_EXCEPTION_HANDLER
+  NS_DURING {
+    [self _appendSrcToResponse:_response inContext:_ctx];
+  }
+  NS_HANDLER {
+    fprintf(stderr, "exception in %s: %s\n",
+            [[self description] cString],
+            [[localException description] cString]);
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+#else
+  [self _appendSrcToResponse:_response inContext:_ctx];
+#endif
+  
+  WOResponse_AddChar(_response, '"');
+  
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  
+  WOResponse_AddCString(_response, " />");
+}
+
+@end /* WOImage */
+
+@implementation _WODynamicImage
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->data     = OWGetProperty(_config, @"data");
+    self->mimeType = OWGetProperty(_config, @"mimeType");
+    self->key      = OWGetProperty(_config, @"key");
+    
+#if DEBUG
+    if ([_config objectForKey:@"value"]     ||
+        [_config objectForKey:@"filename"]  ||
+        [_config objectForKey:@"framework"] ||
+        [_config objectForKey:@"src"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOImage !"
+            @" (assign only one of value, src, data or filename)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->key      release];
+  [self->data     release];
+  [self->mimeType release];
+  [super dealloc];
+}
+
+/* dynamic delivery */
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  WOComponent *sComponent = [_ctx component];
+  NSData     *adata;
+  NSString   *atype;
+  WOResponse *response;
+
+  adata = [self->data     valueInComponent:sComponent];
+  atype = [self->mimeType stringValueInComponent:sComponent];
+
+  response = [_ctx response];
+    
+  [response setContent:adata];
+  [response setHeader:atype ? atype : @"application/octet-stream"
+            forKey:@"content-type"];
+    
+  return response;
+}
+
+/* HTML generation */
+
+- (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  WOResourceManager *rm;
+  WOComponent *sComponent;
+  NSString *kk, *url;
+
+  sComponent = [_ctx component];
+  
+  if ((kk = [self->key stringValueInComponent:sComponent]) == nil) {
+    WOResponse_AddString(_resp, [_ctx componentActionURL]);
+    return;
+  }
+
+  if ((rm = [[_ctx component] resourceManager]) == nil)
+    rm = [[_ctx application] resourceManager];
+    
+  [rm setData:[self->data valueInComponent:sComponent] forKey:kk
+      mimeType:[self->mimeType stringValueInComponent:sComponent]
+      session:[_ctx hasSession] ? [_ctx session] : nil];
+    
+  url = [_ctx urlWithRequestHandlerKey:
+                [WOApplication resourceRequestHandlerKey]
+              path:[@"/" stringByAppendingString:kk]
+              queryString:nil];
+    
+  WOResponse_AddString(_resp, url);
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:64];
+  if (self->data)      [str appendFormat:@" data=%@",      self->data];
+  if (self->mimeType)  [str appendFormat:@" mimeType=%@",  self->mimeType];
+  if (self->key)       [str appendFormat:@" key=%@",       self->key];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WODynamicImage */
+
+@implementation _WOElementImage
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->value = OWGetProperty(_config, @"value");
+
+#if DEBUG
+    if ([_config objectForKey:@"data"]      ||
+        [_config objectForKey:@"mimeType"]  ||
+        [_config objectForKey:@"key"]       ||
+        [_config objectForKey:@"filename"]  ||
+        [_config objectForKey:@"framework"] ||
+        [_config objectForKey:@"src"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOImage !"
+            @" (assign only one of value, src, data or filename)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->value);
+  [super dealloc];
+}
+
+/* dynamic delivery */
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  WOElement *element;
+  
+  if ((element = [self->value valueInComponent:[_ctx component]]) == nil) {
+    NSLog(@"WARNING: missing element value for WOImage %@", self);
+    return nil;
+  }
+
+  [element appendToResponse:[_ctx response] inContext:_ctx];
+  return [_ctx response];
+}
+
+/* HTML generation */
+
+- (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  WOResponse_AddString(_resp, [_ctx componentActionURL]);
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:64];
+
+  [str appendFormat:@" value=%@", self->value];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOElementImage */
+
+@implementation _WOExternalImage
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->src = OWGetProperty(_config, @"src");
+
+#if DEBUG
+    if ([_config objectForKey:@"data"]      ||
+        [_config objectForKey:@"mimeType"]  ||
+        [_config objectForKey:@"key"]       ||
+        [_config objectForKey:@"filename"]  ||
+        [_config objectForKey:@"framework"] ||
+        [_config objectForKey:@"value"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOImage !"
+            @" (assign only one of value, src, data or filename)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->src);
+  [super dealloc];
+}
+
+/* HTML generation */
+
+- (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  [_resp appendContentHTMLAttributeValue:
+           [self->src stringValueInComponent:[_ctx component]]];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:64];
+
+  [str appendFormat:@" src=%@", self->src];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOExternalImage */
+
+@implementation _WOTemporaryImage
+
+- (id)initWithName:(NSString *)_n
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  // TODO: cache class objects?
+  Class imageClass = Nil;
+  WOAssociation *a;
+  
+  if ((a = [_config objectForKey:@"filename"])) {
+    if ([a isValueConstant] && [_config objectForKey:@"framework"] == nil)
+      imageClass = NSClassFromString(@"_WOConstResourceImage");
+    else
+      imageClass = NSClassFromString(@"_WOResourceImage");
+  }
+  else if ([_config objectForKey:@"src"])
+    imageClass = [_WOExternalImage class];
+  else if ([_config objectForKey:@"value"])
+    imageClass = [_WOElementImage class];
+  else if ([_config objectForKey:@"data"])
+    imageClass = [_WODynamicImage class];
+  else {
+    NSLog(@"WARNING: missing data source association for WOImage !");
+  }
+  
+  return [[imageClass alloc] initWithName:_n associations:_config template:_t];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  contentElements:(NSArray *)_contents
+{
+  WOAssociation *a;
+  Class imageClass = Nil;
+  
+  if ((a = [_associations objectForKey:@"filename"])) {
+    if ([a isValueConstant] && [_associations objectForKey:@"framework"]==nil)
+      imageClass = NSClassFromString(@"_WOConstResourceImage");
+    else
+      imageClass = NSClassFromString(@"_WOResourceImage");
+  }
+  else if ([_associations objectForKey:@"src"])
+    imageClass = [_WOExternalImage class];
+  else if ([_associations objectForKey:@"value"])
+    imageClass = [_WOElementImage class];
+  else if ([_associations objectForKey:@"data"])
+    imageClass = [_WODynamicImage class];
+  else {
+    NSLog(@"WARNING: missing data source association for WOImage !");
+  }
+  
+  return [[imageClass alloc] initWithName:_name
+                             associations:_associations
+                             contentElements:_contents];
+}
+
+- (void)dealloc {
+  NSLog(@"ERROR: called dealloc on %@", self);
+#if DEBUG
+  abort();
+#endif
+  return;
+}
+
+@end /* _WOTemporaryImage */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOImageButton.m b/skyrix-sope/NGObjWeb/DynamicElements/WOImageButton.m
new file mode 100644 (file)
index 0000000..4b5f013
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOInput.h"
+
+@interface WOImageButton : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // WOInput:    name
+  // WOInput:    value
+  // WOInput:    disabled
+@protected
+  WOAssociation *filename;  // image path relative to WebServerResources
+  WOAssociation *framework;
+  WOAssociation *src;       // absolute URL
+  WOAssociation *action;
+  WOAssociation *pageName;
+  WOAssociation *x;
+  WOAssociation *y;
+  
+  // new in WO4:
+  WOAssociation *queryDictionary;
+  NSDictionary  *queryParameters;  // associations beginning with ?
+  WOAssociation *actionClass;
+  WOAssociation *directActionName;
+  BOOL          sidInUrl;
+  
+  // non-WO
+  WOAssociation *disabledFilename; // image path to icon for 'disabled' state
+}
+
+@end /* WOImageButton */
+
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+
+@implementation WOImageButton
+
++ (int)version {
+  return 2;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    WOAssociation *sidInUrlAssoc;
+    
+    sidInUrlAssoc   = OWGetProperty(_config, @"?wosid");
+    self->action    = OWGetProperty(_config, @"action");
+    self->filename  = OWGetProperty(_config, @"filename");
+    self->framework = OWGetProperty(_config, @"framework");
+    self->pageName  = OWGetProperty(_config, @"pageName");
+    self->x         = OWGetProperty(_config, @"x");
+    self->y         = OWGetProperty(_config, @"y");
+
+    self->queryDictionary  = OWGetProperty(_config, @"queryDictionary");
+    self->queryParameters  = OWExtractQueryParameters(_config);
+    self->actionClass      = OWGetProperty(_config, @"actionClass");
+    self->directActionName = OWGetProperty(_config, @"directActionName");
+    
+    self->disabledFilename = OWGetProperty(_config, @"disabledFilename");
+    
+    self->sidInUrl = (sidInUrlAssoc)
+      ? [sidInUrlAssoc boolValueInComponent:nil]
+      : YES;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->actionClass);
+  RELEASE(self->directActionName);
+  RELEASE(self->queryDictionary);
+  RELEASE(self->queryParameters);
+  RELEASE(self->action);
+  RELEASE(self->disabledFilename);
+  RELEASE(self->framework);
+  RELEASE(self->filename);
+  RELEASE(self->src);
+  RELEASE(self->pageName);
+  RELEASE(self->x);
+  RELEASE(self->y);
+  [super dealloc];
+}
+
+/* handling requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  WOComponent *sComponent = [_ctx component];
+  NSString *baseId = nil;
+  id       xVal    = nil;
+  id       yVal    = nil;
+
+  //NSLog(@"%s: take values ...", __PRETTY_FUNCTION__);
+  
+  if (self->disabled) {
+    if ([self->disabled boolValueInComponent:sComponent])
+      return;
+  }
+  
+  baseId = OWFormElementName(self, _ctx);
+  
+  xVal = [_rq formValueForKey:[baseId stringByAppendingString:@".x"]];
+  yVal = [_rq formValueForKey:[baseId stringByAppendingString:@".y"]];
+
+  if (xVal) {
+    if ([self->x isValueSettable]) {
+      [self->x setUnsignedIntValue:[xVal unsignedIntValue]
+           inComponent:sComponent];
+    }
+  }
+  if (yVal) {
+    if ([self->y isValueSettable]) {
+      [self->y setUnsignedIntValue:[yVal unsignedIntValue]
+           inComponent:sComponent];
+    }
+  }
+  
+  if (((xVal != nil) || (yVal != nil)) &&
+      ((self->action != nil) || (self->pageName != nil))) {
+    /* should perform action */
+    [_ctx addActiveFormElement:self];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  if (self->disabled) {
+    if ([self->disabled boolValueInComponent:[_ctx component]])
+      return nil;
+  }
+  
+  /* check whether this is the active form element (determined above) */
+  if (![[_ctx elementID] isEqualToString:[_ctx senderID]]) {
+    NSLog(@"WOImageButton is not active (%@ vs %@) !",
+          [_ctx elementID], [_ctx senderID]);
+    return nil;
+  }
+  
+  if (self->action)
+    return [self executeAction:self->action inContext:_ctx];
+    
+  if (self->pageName) {
+    NSString    *pname = nil;
+    WOComponent *page = nil;
+
+    pname = [self->pageName stringValueInComponent:[_ctx component]];
+    page = [[_ctx application] pageWithName:pname inContext:_ctx];
+
+    if (page == nil) {
+      [[_ctx session] logWithFormat:
+                      @"%@[0x%08X]: did not find page with name %@ !",
+                      NSStringFromClass([self class]), self, pname];
+    }
+    NSLog(@"%@: showing page %@", self, page);
+    return page;
+  }
+  return nil;
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent = [_ctx component];
+  NSString *uUri = nil;
+  NSString *uFi  = nil;
+
+  uUri = [self->src stringValueInComponent:sComponent];
+
+  if ([self->disabled boolValueInComponent:sComponent]) {
+    uFi =  [self->disabledFilename stringValueInComponent:sComponent];
+    if (uFi == nil)
+      uFi = [self->filename stringValueInComponent:sComponent];
+  }
+  else
+    uFi = [self->filename stringValueInComponent:sComponent];
+    
+  WOResponse_AddCString(_response, "<input type=\"image\" name=\"");
+  [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+  WOResponse_AddChar(_response, '"');
+  
+  WOResponse_AddCString(_response, " src=\"");
+  if (uFi) {
+    WOResourceManager *rm;
+    NSArray *langs;
+    NSString  *frameworkName;
+
+    if ((rm = [[_ctx component] resourceManager]) == nil)
+      rm = [[_ctx application] resourceManager];
+
+    langs = [_ctx hasSession]
+      ? [[_ctx session] languages]
+      : [[_ctx request] browserLanguages];
+    
+    /* If 'framework' binding is not set, use parent component's framework */
+    if (self->framework){
+      frameworkName = [self->framework stringValueInComponent:sComponent];
+      if (frameworkName != nil && [frameworkName isEqualToString:@"app"])
+        frameworkName = nil;
+    }
+    else
+      frameworkName = [sComponent frameworkName];
+    
+    uFi = [rm urlForResourceNamed:uFi
+               inFramework:frameworkName
+               languages:langs
+               request:[_ctx request]];
+    if (uFi == nil) {
+      NSLog(@"%@: did not find resource '%@'", sComponent,
+            [self->filename stringValueInComponent:sComponent]);
+      uFi = uUri;
+    }
+    [_response appendContentHTMLAttributeValue:uFi];
+  }
+  else
+    [_response appendContentHTMLAttributeValue:uUri];
+  WOResponse_AddChar(_response, '"');
+    
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  WOResponse_AddCString(_response, " />");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+  
+  str = [NSMutableString stringWithCapacity:128];
+  [str appendString:[super associationDescription]];
+  if (self->action)   [str appendFormat:@" action=%@", self->action];
+  if (self->pageName) [str appendFormat:@" page=%@", self->pageName];
+  if (self->filename) [str appendFormat:@" file=%@", self->filename];
+  if (self->src)      [str appendFormat:@" src=%@",  self->src];
+  if (self->x)        [str appendFormat:@" x=%@",    self->x];
+  if (self->y)        [str appendFormat:@" y=%@",    self->y];
+
+  if (self->actionClass)
+    [str appendFormat:@" actionClass=%@", self->actionClass];
+  if (self->directActionName)
+    [str appendFormat:@" directAction=%@", self->directActionName];
+  
+  return str;
+}
+
+@end /* WOImageButton */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOInput.h b/skyrix-sope/NGObjWeb/DynamicElements/WOInput.h
new file mode 100644 (file)
index 0000000..52aff85
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOInput_H__
+#define __NGObjWeb_WOInput_H__
+
+#include "WOHTMLDynamicElement.h"
+
+@class WOAssociation;
+
+/*
+  An element that can participate in a FORM request
+*/
+
+@interface WOInput : WOHTMLDynamicElement // abstract
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *name;
+  WOAssociation *value;
+  WOAssociation *disabled;
+}
+
+// called in -takeValues.. before a form value is passed into the component
+- (id)parseFormValue:(id)_value inContext:(WOContext *)_ctx;
+
+@end
+
+#include "WOElement+private.h"
+#include "WOContext+private.h"
+
+@interface WOInput(PrivateMethods)
+
+- (NSString *)associationDescription;
+
+@end
+
+NSString *OWFormElementName(WOInput *self, WOContext *_ctx);
+
+#endif /* __NGObjWeb_WOInput_H__ */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOInput.m b/skyrix-sope/NGObjWeb/DynamicElements/WOInput.m
new file mode 100644 (file)
index 0000000..6f049b4
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOInput.h"
+#include "WOElement+private.h"
+#include "common.h"
+
+@implementation WOInput
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
+
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  template:(WOElement *)_rootChild
+{
+  self = [super initWithName:_name associations:_associations
+                template:_rootChild];
+  if (self) {
+    self->containsForm = YES;
+    self->name     = OWGetProperty(_associations, @"name");
+    self->value    = OWGetProperty(_associations, @"value");
+    self->disabled = OWGetProperty(_associations, @"disabled");
+    
+    /* type is defined by the element itself ... */
+    [(NSMutableDictionary *)_associations removeObjectForKey:@"type"];
+    
+    if ([_associations objectForKey:@"NAME"]) {
+      NSLog(@"WARNING: found 'NAME' association in element %@, "
+            @"'name' is probably the right thing ..",
+            self);
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->name     release];
+  [self->value    release];
+  [self->disabled release];
+  [super dealloc];
+}
+
+/* form support */
+
+NSString *OWFormElementName(WOInput *self, WOContext *_ctx) {
+  NSString *name;
+  
+  if (self->name == nil)
+    return [_ctx elementID];
+  
+  if ((name = [self->name stringValueInComponent:[_ctx component]]))
+    return name;
+  
+  [[_ctx component]
+         logWithFormat:
+               @"WARNING: in element %@, 'name' attribute configured (%@),"
+               @"but no name assigned (using elementID as name) !",
+               self, self->name];
+  return [_ctx elementID];
+}
+
+// ******************** responder ********************
+
+- (id)parseFormValue:(id)_value inContext:(WOContext *)_ctx {
+  return _value;
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSString *formName;
+  id formValue = nil;
+  
+  if ([self->disabled boolValueInComponent:[_ctx component]])
+    return;
+  
+  formName = OWFormElementName(self, _ctx);
+  
+  if ((formValue = [_req formValueForKey:formName])) {
+#if DEBUG && 0
+    NSLog(@"%s(%@): form=%@ ctx=%@ value=%@ ..", __PRETTY_FUNCTION__,
+         [_ctx elementID], formName, [_ctx contextID], formValue);
+#endif
+    
+    if ([self->value isValueSettable]) {
+      formValue = [self parseFormValue:formValue inContext:_ctx];
+      [self->value setStringValue:formValue inComponent:[_ctx component]];
+    }
+#if DEBUG
+    else {
+      NSLog(@"%s: form value is not settable: %@", __PRETTY_FUNCTION__,
+            self->value);
+    }
+#endif
+  }
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:128];
+
+  if (self->value)    [str appendFormat:@" value=%@",    self->value];
+  if (self->name)     [str appendFormat:@" name=%@",     self->name];
+  if (self->disabled) [str appendFormat:@" disabled=%@", self->disabled];
+
+  return str;
+}
+
+@end /* WOInput */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOJavaScript.m b/skyrix-sope/NGObjWeb/DynamicElements/WOJavaScript.m
new file mode 100644 (file)
index 0000000..4352811
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHTMLDynamicElement.h"
+
+@interface WOJavaScript : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *scriptFile;
+  WOAssociation *scriptString;
+  WOAssociation *scriptSource;
+  WOAssociation *hideInComment;
+}
+
+@end /* WOJavaScript */
+
+#include "WOElement+private.h"
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@implementation WOJavaScript
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmp
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmp])) {
+    self->scriptFile    = OWGetProperty(_config, @"scriptFile");
+    self->scriptString  = OWGetProperty(_config, @"scriptString");
+    self->scriptSource  = OWGetProperty(_config, @"scriptSource");
+    self->hideInComment = OWGetProperty(_config, @"hideInComment");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->scriptFile    release];
+  [self->scriptString  release];
+  [self->scriptSource  release];
+  [self->hideInComment release];
+  [super dealloc];
+}
+
+/* response generation */
+
+- (void)appendScriptFileToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx 
+{
+  NSString *s;
+
+  if (self->scriptFile == nil)
+    return;
+  if ((s = [self->scriptFile stringValueInComponent:[_ctx component]]) == nil)
+    return;
+
+  /* load file */
+
+  if ([s isAbsolutePath]) {
+    s = [[NSString alloc] initWithContentsOfFile:s];
+  }
+  else {
+    WOResourceManager *rm;
+    NSArray           *languages;
+          
+    if ((rm = [[_ctx component] resourceManager]) == nil)
+      rm = [[_ctx application] resourceManager];
+    
+    languages = [_ctx hasSession]
+      ? [[_ctx session] languages]
+      : [[_ctx request] browserLanguages];
+    s = [rm pathForResourceNamed:s inFramework:nil languages:languages];
+    if (s) s = [[NSString alloc] initWithContentsOfFile:s];
+  }
+
+  /* append to response */
+  
+  if (s) WOResponse_AddString(_response, s);
+  [s release];
+}
+
+- (void)appendScriptContentToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx 
+{
+  if (self->scriptString) {
+    NSString *s;
+
+    if ((s = [self->scriptString stringValueInComponent:[_ctx component]]))
+      WOResponse_AddString(_response, s);
+  }
+  
+  if (self->scriptFile)
+    [self appendScriptFileToResponse:_response inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  BOOL hide;
+  
+  if ([[_ctx request] isFromClientComponent])
+    return;
+  
+  sComponent = [_ctx component];
+  hide = [self->hideInComment boolValueInComponent:sComponent];
+    
+  WOResponse_AddCString(_response, "<script language=\"JavaScript\" ");
+
+  /* add URL to script */
+  if (self->scriptSource) {
+    WOResponse_AddCString(_response, " src=\"");
+    [_response appendContentHTMLAttributeValue:
+                 [self->scriptSource stringValueInComponent:sComponent]];
+    WOResponse_AddCString(_response, "\"");
+  }
+    
+  if (self->otherTagString) {
+    NSString *s;
+    
+    s = [self->otherTagString stringValueInComponent:sComponent];
+    WOResponse_AddString(_response, s);
+  }
+  WOResponse_AddChar(_response, '>');
+  if (hide) 
+    WOResponse_AddCString(_response, "<!-- hide from older browsers\n");
+  
+  [self appendScriptContentToResponse:_response inContext:_ctx];
+  
+  if (hide) 
+    WOResponse_AddCString(_response, "// hide from older browsers -->");
+  WOResponse_AddCString(_response, "</script>");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [[NSMutableString alloc] init];
+  
+  str = [NSMutableString stringWithCapacity:64];
+  if (self->scriptFile)   [str appendFormat:@" file=%@",   self->scriptFile];
+  if (self->scriptString) [str appendFormat:@" string=%@", self->scriptString];
+  if (self->scriptSource) [str appendFormat:@" source=%@", self->scriptSource];
+  if (self->hideInComment)
+    [str appendFormat:@" hide=%@",   self->hideInComment];
+  
+  return str;
+}
+
+@end /* WOJavaScript */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOMetaRefresh.m b/skyrix-sope/NGObjWeb/DynamicElements/WOMetaRefresh.m
new file mode 100644 (file)
index 0000000..7f0a3f4
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOHTMLDynamicElement.h"
+#include "WOElement+private.h"
+#include <NGObjWeb/WOAssociation.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+/*
+  WOMetaRefresh associations:
+
+    href | pageName | action | (directActionName & actionClass)
+    fragmentIdentifier
+    disabled
+    timeout
+*/
+
+@interface WOMetaRefresh : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *action;
+  WOAssociation *href;
+  WOAssociation *pageName;
+  WOAssociation *directActionName;
+  WOAssociation *actionClass;
+  WOAssociation *disabled;
+  WOAssociation *fragmentIdentifier;
+  WOAssociation *timeout;
+
+  WOAssociation *queryDictionary;
+  NSDictionary  *queryParameters;  /* associations beginning with ? */
+  BOOL          sidInUrl;
+}
+
+@end
+
+@implementation WOMetaRefresh
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    WOAssociation *sidInUrlAssoc;
+    
+    sidInUrlAssoc            = OWGetProperty(_config, @"?wosid");
+    self->action             = OWGetProperty(_config, @"action");
+    self->href               = OWGetProperty(_config, @"href");
+    self->pageName           = OWGetProperty(_config, @"pageName");
+    self->fragmentIdentifier = OWGetProperty(_config, @"fragmentIdentifier");
+    self->disabled           = OWGetProperty(_config, @"disabled"); 
+    self->timeout            = OWGetProperty(_config, @"timeout"); 
+    self->directActionName   = OWGetProperty(_config, @"directActionName"); 
+    self->actionClass        = OWGetProperty(_config, @"actionClass"); 
+    
+    self->sidInUrl = (sidInUrlAssoc)
+      ? [sidInUrlAssoc boolValueInComponent:nil]
+      : YES;
+    
+    self->queryDictionary = OWGetProperty(_config, @"queryDictionary");
+    self->queryParameters = OWExtractQueryParameters(_config);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->queryParameters    release];
+  [self->queryDictionary    release];
+  [self->directActionName   release];
+  [self->actionClass        release];
+  [self->action             release];
+  [self->href               release];
+  [self->pageName           release];
+  [self->fragmentIdentifier release];
+  [self->disabled           release];
+  [self->timeout            release];
+  [super dealloc];
+}
+
+/* ******************** responder ******************** */
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if ([self->disabled boolValueInComponent:[_ctx component]])
+    return nil;
+  
+  if (self->action)
+    return [self executeAction:self->action inContext:_ctx];
+
+  if (self->pageName) {
+    NSString    *name;
+    WOComponent *page;
+
+    name = [self->pageName stringValueInComponent:[_ctx component]];
+    page = [[_ctx application] pageWithName:name inContext:_ctx];
+      
+    if (page == nil) {
+      [[_ctx component] logWithFormat:
+                          @"%@[0x%08X]: did not find page with name %@ !",
+                          NSStringFromClass([self class]), self, name];
+    }
+    [self debugWithFormat:@"showing page %@", page];
+    return page;
+  }
+  
+  [[_ctx component] 
+         logWithFormat:@"%@[0x%08X]: no action/page set !",
+           NSStringFromClass([self class]), self];
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent = [_ctx component];
+  int         to;
+  NSString    *url;
+  NSString    *queryString = nil;
+  BOOL addSID;
+  
+  if ([[_ctx request] isFromClientComponent])
+    return;
+  
+  to = [self->timeout intValueInComponent:sComponent];
+  WOResponse_AddCString(_response, "<meta http-equiv=\"refresh\" content=\"");
+  WOResponse_AddInt(_response, to);
+  WOResponse_AddCString(_response, "; url=");
+
+  if (self->href) {
+    /* a href was explicitly assigned */
+    url = [self->href stringValueInComponent:sComponent];
+    addSID = self->sidInUrl;
+  }
+  else if (self->directActionName) {
+    /* a direct action */
+    NSString *daClass;
+    NSString *daName;
+
+    daClass = [self->actionClass      stringValueInComponent:sComponent];
+    daName  = [self->directActionName stringValueInComponent:sComponent];
+    
+    if (daClass) {
+      if (daName) {
+        if (![daClass isEqualToString:@"DirectAction"])
+          daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
+      }
+      else
+        daName = daClass;
+    }
+
+    url = [_ctx directActionURLForActionNamed:daName queryDictionary:nil];
+    addSID = self->sidInUrl;
+  }
+  else {
+    url = [_ctx componentActionURL];
+    addSID = NO;
+  }
+  WOResponse_AddString(_response, url);
+  
+  queryString = [self queryStringForQueryDictionary:
+                        [self->queryDictionary valueInComponent:sComponent]
+                      andQueryParameters:self->queryParameters
+                      inContext:_ctx];
+  if (addSID && [sComponent hasSession]) {
+    WOSession *sn = [sComponent session];
+    
+    if ([queryString length] == 0) {
+      queryString = [NSString stringWithFormat:@"%@=%@", 
+                             WORequestValueSessionID, [sn sessionID]];
+    }
+    else {
+      queryString = [queryString stringByAppendingFormat:@"&%@=%@", 
+                             WORequestValueSessionID, [sn sessionID]];
+    }
+  }
+  
+  if (self->fragmentIdentifier) {
+    [_response appendContentCharacter:'#'];
+    WOResponse_AddString(_response,
+                         [self->fragmentIdentifier stringValueInComponent:
+                              sComponent]);
+  }
+  
+  if (queryString) {
+    [_response appendContentCharacter:'?'];
+    WOResponse_AddString(_response, queryString);
+  }
+  
+  [_response appendContentCharacter:'"']; // close CONTENT attribute
+  
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  WOResponse_AddCString(_response, " />");
+}
+
+// description
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  if (self->action)   [str appendFormat:@" action=%@",   self->action];
+  if (self->href)     [str appendFormat:@" href=%@",     self->href];
+  if (self->pageName) [str appendFormat:@" pageName=%@", self->pageName];
+  if (self->fragmentIdentifier)
+    [str appendFormat:@" fragment=%@", self->fragmentIdentifier];
+  if (self->disabled) [str appendFormat:@" disabled=%@", self->disabled];
+  
+  return str;
+}
+
+@end /* WOMetaRefresh */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WONestedList.m b/skyrix-sope/NGObjWeb/DynamicElements/WONestedList.m
new file mode 100644 (file)
index 0000000..eb86266
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOHTMLDynamicElement.h"
+#include "WOElement+private.h"
+#include "common.h"
+
+@interface WONestedList : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *list;
+  WOAssociation *item;
+  WOAssociation *value;
+  WOAssociation *sublist;
+  WOAssociation *action;
+  WOAssociation *selection;
+  WOAssociation *index;
+  WOAssociation *level;
+  WOAssociation *isOrdered;
+  WOAssociation *prefix;
+  WOAssociation *suffix;
+}
+
+@end /* WONestedList */
+
+@implementation WONestedList
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_root
+{
+  if ((self = [super initWithName:_name associations:_config template:_root])) {
+    self->action          = OWGetProperty(_config, @"action");
+    self->list            = OWGetProperty(_config, @"list");
+    self->item            = OWGetProperty(_config, @"item");
+    self->index           = OWGetProperty(_config, @"index");
+    self->selection       = OWGetProperty(_config, @"selection");
+    self->prefix          = OWGetProperty(_config, @"prefix");
+    self->suffix          = OWGetProperty(_config, @"suffix");
+    self->sublist         = OWGetProperty(_config, @"sublist");
+    self->value           = OWGetProperty(_config, @"value");
+    self->isOrdered       = OWGetProperty(_config, @"isOrdered");
+    self->level           = OWGetProperty(_config, @"level");
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->level);
+  RELEASE(self->isOrdered);
+  RELEASE(self->value);
+  RELEASE(self->sublist);
+  RELEASE(self->list);
+  RELEASE(self->item);
+  RELEASE(self->index);
+  RELEASE(self->selection);
+  RELEASE(self->prefix);
+  RELEASE(self->suffix);
+  RELEASE(self->action);
+  [super dealloc];
+}
+#endif
+
+// OWResponder
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  // not a container ..
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  WOComponent *sComponent = [_ctx component];
+  id       idxId   = nil;
+  id       object  = nil;
+  unsigned nesting = 0;
+  NSArray  *array;
+
+  array  = [self->list valueInComponent:sComponent];
+  if ([array count] < 1) return nil;
+  
+  idxId = [_ctx currentElementID]; // top level index
+  while ((idxId != nil) && (array != nil)) {
+    unsigned idx = [idxId unsignedIntValue];
+    
+    object = [array objectAtIndex:idx];
+
+    if ([self->level isValueSettable])
+      [self->level setUnsignedIntValue:nesting inComponent:sComponent];
+    if ([self->index isValueSettable])
+      [self->index setUnsignedIntValue:idx inComponent:sComponent];
+    if ([self->item isValueSettable])
+      [self->item setValue:object inComponent:sComponent];
+
+    array = [self->sublist valueInComponent:sComponent];
+    idxId = [_ctx consumeElementID]; // sub level index
+    nesting++;
+  }
+
+  if ([self->selection isValueSettable])
+    [self->selection setValue:object inComponent:sComponent];
+
+  return [self executeAction:self->action inContext:_ctx];
+}
+
+- (void)appendList:(NSArray *)_list atLevel:(unsigned int)_level
+  toResponse:(WOResponse *)_response inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent = [_ctx component];
+  unsigned    count       = [_list count];
+  unsigned    cnt;
+
+  if (count > 0) {
+    BOOL ordered;
+    
+    if ([self->level isValueSettable])
+      [self->level setUnsignedIntValue:_level inComponent:sComponent];
+
+    ordered = [self->isOrdered boolValueInComponent:sComponent];
+    
+    WOResponse_AddString(_response, ordered ? @"<ol>" : @"<ul>");
+
+    [_ctx appendZeroElementIDComponent];
+    for (cnt = 0; cnt < count; cnt++) {
+      id object = [_list objectAtIndex:cnt];
+
+      if ([self->index isValueSettable])
+        [self->index setUnsignedIntValue:cnt inComponent:sComponent];
+
+      if ([self->item isValueSettable])
+        [self->item setValue:object inComponent:sComponent];
+
+      // add item
+      WOResponse_AddCString(_response, "<li>");
+      {
+        NSArray *sl = [self->sublist valueInComponent:sComponent];
+        
+        if (self->prefix) {
+          NSString *ps;
+
+          ps = [self->prefix stringValueInComponent:sComponent];
+          WOResponse_AddString(_response, ps);
+        }
+        
+        if (self->value) {
+          if (self->action) {
+            WOResponse_AddCString(_response, "<a href=\"");
+            WOResponse_AddString(_response, [_ctx componentActionURL]);
+            [_response appendContentCharacter:'"'];
+            [self appendExtraAttributesToResponse:_response inContext:_ctx];
+            [_response appendContentCharacter:'>'];
+          }
+
+          WOResponse_AddHtmlString(_response,
+            [self->value stringValueInComponent:sComponent]);
+          if (self->action)
+            WOResponse_AddCString(_response, "</a>");
+        }
+
+        if (self->suffix) {
+          NSString *ss;
+
+          ss = [self->suffix stringValueInComponent:sComponent];
+          WOResponse_AddString(_response, ss);
+        }
+
+        if ([sl count] > 0) { // not a leaf
+          [self appendList:sl
+                atLevel:(_level + 1)
+                toResponse:_response
+                inContext:_ctx];
+          if ([self->level isValueSettable])
+            [self->level setUnsignedIntValue:_level inComponent:sComponent];
+        }
+      }
+      WOResponse_AddCString(_response, "</li>\n");
+      
+      [_ctx incrementLastElementIDComponent];
+    }
+    [_ctx deleteLastElementIDComponent]; // list index
+
+    WOResponse_AddString(_response, ordered ? @"</ol>" : @"</ul>");
+
+    if ([self->level isValueSettable])
+      [self->level setUnsignedIntValue:_level inComponent:sComponent];
+  }
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSArray *top = [self->list valueInComponent:[_ctx component]];
+
+  if ([top count] > 0) {
+    [self appendList:top
+          atLevel:0
+          toResponse:_response
+          inContext:_ctx];
+  }
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [[NSMutableString alloc] init];
+
+  if (self->action)    [str appendFormat:@" action=%@",    self->action];
+  if (self->list)      [str appendFormat:@" list=%@",      self->list];
+  if (self->sublist)   [str appendFormat:@" sublist=%@",   self->sublist];
+  if (self->item)      [str appendFormat:@" item=%@",      self->item];
+  if (self->index)     [str appendFormat:@" index=%@",     self->index];
+  if (self->prefix)    [str appendFormat:@" prefix=%@",    self->prefix];
+  if (self->suffix)    [str appendFormat:@" suffix=%@",    self->suffix];
+  if (self->selection) [str appendFormat:@" selection=%@", self->selection];
+  if (self->value)     [str appendFormat:@" value=%@",     self->value];
+  if (self->isOrdered) [str appendFormat:@" isOrdered=%@", self->isOrdered];
+  if (self->level)     [str appendFormat:@" level=%@",     self->level];
+
+  return AUTORELEASE(str);
+}
+
+@end /* WONestedList */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOPasswordField.m b/skyrix-sope/NGObjWeb/DynamicElements/WOPasswordField.m
new file mode 100644 (file)
index 0000000..bdb62d5
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOInput.h"
+#include "common.h"
+
+@interface WOPasswordField : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // WOInput:    name
+  // WOInput:    value
+  // WOInput:    disabled
+@protected
+  // non WO:
+  WOAssociation *size;
+}
+
+@end /* WOPasswordField */
+
+@implementation WOPasswordField
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_root {
+
+  if ((self = [super initWithName:_name associations:_config template:_root])) {
+    self->size = OWGetProperty(_config, @"size");
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->size); self->size = nil;
+  [super dealloc];
+}
+#endif
+
+// ******************** responder ********************
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString     *v = [self->value stringValueInComponent:[_ctx component]];
+  unsigned int s  = [self->size  unsignedIntValueInComponent:[_ctx component]];
+
+  WOResponse_AddCString(_response, "<input type=\"password\" name=\"");
+  [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+  WOResponse_AddCString(_response, "\" value=\"");
+  [_response appendContentHTMLAttributeValue:v];
+  [_response appendContentCharacter:'"'];
+  if (s > 0) {
+    WOResponse_AddCString(_response, " size=\"");
+    WOResponse_AddUInt(_response, s);
+    [_response appendContentCharacter:'"'];
+  }
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  WOResponse_AddCString(_response, " />");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = nil;
+  str = [[NSMutableString alloc] initWithString:[super associationDescription]];
+
+  if (self->size) [str appendFormat:@" size=%@", self->size];
+
+  return AUTORELEASE(str);
+}
+
+@end /* WOPasswordField */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOPopUpButton.m b/skyrix-sope/NGObjWeb/DynamicElements/WOPopUpButton.m
new file mode 100644 (file)
index 0000000..70f3660
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOInput.h"
+
+@class WOAssociation;
+
+@interface WOPopUpButton : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // WOInput:    name
+  // WOInput:    value
+  // WOInput:    disabled
+@protected
+  WOAssociation *list;
+  WOAssociation *item;
+  WOAssociation *selection;
+  WOAssociation *string;            // WO4
+  WOAssociation *noSelectionString; // WO4
+  WOAssociation *selectedValue;     // WO4.5
+  WOAssociation *escapeHTML;        // WO4.5
+}
+
+@end
+
+@class WOResponse, WOContext;
+
+@interface WOPopUpButton(PrivateMethods)
+- (void)appendOptionsToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+@end
+
+#include "common.h"
+
+#ifdef DEBUG
+static int profElements  = -1;
+static Class NSDateClass = Nil;
+
+@interface WOContext(ComponentStackCount)
+- (unsigned)componentStackCount;
+@end
+
+#endif
+
+@implementation WOPopUpButton
+
+static NSNumber *yesNum = nil;
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
+
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  if (yesNum == nil) yesNum = [[NSNumber numberWithBool:YES] retain];
+}
+
+- (void)_handleDeprecatedBindings:(NSDictionary *)_config {
+  id tmp;
+  
+  if ((tmp = OWGetProperty(_config, @"singleSelection"))) {
+    if ([tmp isValueConstant]) {
+      if ([tmp boolValueInComponent:nil]) {
+       [self debugWithFormat:
+               @"Note: template uses deprecated 'singleSelection' binding!"];
+      }
+      else {
+         [self debugWithFormat:
+                 @"ERROR: 'singleSelection' binding is set to NO, which is "
+                 @"unsupported now!"];
+      }
+    }
+    else {
+      [self logWithFormat:
+             @"ERROR: will ignore deprecated 'singleSelection' binding: %@",
+             tmp];
+    }
+    [tmp release];
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+#if DEBUG
+  if (profElements == -1) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    profElements = [[ud objectForKey:@"WOProfileElements"] boolValue] ? 1 : 0;
+  }
+  if (NSDateClass == Nil)
+    NSDateClass = [NSDate class];
+#endif
+  
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->list              = OWGetProperty(_config, @"list");
+    self->item              = OWGetProperty(_config, @"item");
+    self->selection         = OWGetProperty(_config, @"selection");
+    self->string            = OWGetProperty(_config, @"string");
+    if (self->string == nil )
+        self->string = OWGetProperty(_config, @"displayString");
+    
+    self->noSelectionString = OWGetProperty(_config, @"noSelectionString");
+    self->selectedValue     = OWGetProperty(_config, @"selectedValue");
+    self->escapeHTML        = OWGetProperty(_config, @"escapeHTML");
+    
+    if (self->selection != nil && self->selectedValue != nil)
+      [self logWithFormat:
+        @"cannot have both 'selection' and 'selectedValue' bindings!"];
+    
+    /* compatiblity */
+    
+    if (self->noSelectionString == nil)
+      self->noSelectionString = OWGetProperty(_config, @"nilString");
+    
+    if (self->escapeHTML == nil)
+      self->escapeHTML = [[WOAssociation associationWithValue:yesNum] retain];
+    
+    [self _handleDeprecatedBindings:_config];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->noSelectionString release];
+  [self->escapeHTML        release];
+  [self->list              release];
+  [self->item              release];
+  [self->selection         release];
+  [self->string            release];
+  [self->selectedValue     release];
+  [super dealloc];
+}
+
+/* handling the request */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSString    *formValue;
+  NSArray     *objects;
+  id          object;
+  
+  sComponent = [_ctx component];
+  if ([self->disabled boolValueInComponent:[_ctx component]])
+    return;
+  
+  formValue = [_rq formValueForKey:OWFormElementName(self, _ctx)];
+#if 0
+  [self logWithFormat:@"%@: value=%@ ..", [self elementID], formValue];
+#endif
+    
+  if (formValue == nil) {
+    /* nothing changed, or not in submitted form */
+    return;
+  }
+      
+  objects = [self->list valueInComponent:sComponent];
+      
+  object = nil;
+  if (self->value) {
+    /* has a value binding, walk list to find object */
+    unsigned i, toGo;
+
+    for (i = 0, toGo = [objects count]; i < toGo; i++) {
+      NSString *cv;
+          
+      object = [objects objectAtIndex:i];
+      
+      if ([self->item isValueSettable])
+       [self->item setValue:object inComponent:sComponent];
+      
+      cv = [self->value stringValueInComponent:sComponent];
+          
+      if ([cv isEqualToString:formValue])
+       break;
+    }
+  }
+  else if (![formValue isEqualToString:WONoSelectionString]) {
+    /* an index binding */
+    int idx;
+        
+    idx = [formValue intValue];
+    if (idx >= (int)[objects count]) {
+      [[_ctx page] logWithFormat:@"popup-index %i out of range 0-%i",
+                    idx, [objects count] - 1];
+      object = nil;
+    }
+    else 
+      object = [objects objectAtIndex:idx];
+  }
+
+  if ([self->selectedValue isValueSettable])
+      [self->selectedValue setValue:formValue inComponent:sComponent];
+
+  /* process selection */
+      
+  if ([self->selection isValueSettable]) {
+    NSArray *sel;
+        
+    if (object) {
+      sel = [object retain];
+    }
+    else /* nil item selected */
+      sel = nil;
+          
+    [self->selection setValue:sel inComponent:sComponent];
+    [sel release]; sel = nil;
+  }
+  if ([self->item isValueSettable])
+    [self->item setValue:nil inComponent:sComponent]; // Reset 'item'
+}
+
+- (void)appendOptionsToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent = [_ctx component];
+  NSString *nilStr  = nil;
+  NSArray  *array   = nil;
+  id       sel = nil;
+  int      i, toGo;
+  BOOL     escapesHTML;
+  BOOL     byVal;
+#if DEBUG
+  NSTimeInterval st = 0.0;
+    
+  if (profElements)
+    st = [[NSDateClass date] timeIntervalSince1970];
+#endif
+    
+  escapesHTML = [self->escapeHTML        boolValueInComponent:sComponent];
+  nilStr      = [self->noSelectionString stringValueInComponent:sComponent];
+  array       = [self->list              valueInComponent:sComponent];
+  if (self->selection == nil){
+    if (self->selectedValue != nil){
+      byVal = YES;
+      sel = [self->selectedValue valueInComponent:sComponent];
+    }
+    else{
+      byVal = NO;
+      sel = nil;
+    }
+  }
+  else{
+    if (self->selectedValue != nil){
+      byVal = YES;
+      sel = [self->selectedValue valueInComponent:sComponent];
+      NSLog(@"WARNING(%@): "
+            @"using both 'selection' and 'selectedValue' bindings!",
+            self);
+    }
+    else{
+      byVal = NO;
+      sel = [self->selection valueInComponent:sComponent];
+    }
+  }
+  toGo     = [array count];
+  
+#if DEBUG
+  if (profElements) {
+    NSTimeInterval diff;
+    int j;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    if (diff > 0.001) {
+      for (j = [_ctx componentStackCount]; j >= 0; j--)
+        printf("  ");
+      printf("PopUpOption[setup] %s: %0.3fs\n",
+             [[_ctx elementID] cString], diff);
+    }
+  }
+#endif
+  
+  if (nilStr) {
+    WOResponse_AddCString(_response, "<option value=\"");
+    WOResponse_AddString(_response, WONoSelectionString);
+    WOResponse_AddCString(_response, "\">");
+    WOResponse_AddHtmlString(_response, nilStr);
+    WOResponse_AddCString(_response, "</option>");
+  }
+  
+  for (i = 0; i < toGo; i++) {
+    NSString *v         = nil;
+    NSString *displayV  = nil;
+    id       object;
+    BOOL     isSelected;
+#if DEBUG
+    NSTimeInterval st = 0.0;
+    
+    if (profElements)
+      st = [[NSDateClass date] timeIntervalSince1970];
+#endif
+    
+    object = [array objectAtIndex:i];
+    
+    if ([self->item isValueSettable])
+      [self->item setValue:object inComponent:sComponent];
+    
+    isSelected = sel ? [sel isEqual:object] : NO;
+    v = self->value
+      ? [self->value stringValueInComponent:sComponent]
+      : [NSString stringWithFormat:@"%i", i];
+
+    if (byVal){
+        isSelected = sel ? [sel isEqual:v] : NO;
+    }
+    else
+      isSelected = sel ? [sel isEqual:object] : NO;
+    
+    displayV = self->string
+      ? [self->string stringValueInComponent:sComponent]
+      : [object stringValue];
+
+    if (displayV == nil) displayV = @"<nil>";
+    
+    WOResponse_AddCString(_response, "<option value=\"");
+    WOResponse_AddHtmlString(_response, v); // WO escapes it
+    WOResponse_AddCString(_response, 
+                         isSelected ? 
+                         "\" selected=\"selected\">" : "\">");
+    if (escapesHTML){
+      WOResponse_AddHtmlString(_response, displayV);
+    }
+    else{
+      WOResponse_AddString(_response, displayV);
+    }
+    WOResponse_AddCString(_response, "</option>");
+    
+#if DEBUG
+    if (profElements) {
+      NSTimeInterval diff;
+      int j;
+      diff = [[NSDateClass date] timeIntervalSince1970] - st;
+      if (diff > 0.001) {
+#if 1
+        for (j = [_ctx componentStackCount]; j >= 0; j--)
+          printf("  ");
+#endif
+        printf("PopUpOption[%i] %s: %0.3fs\n", i,
+               [[_ctx elementID] cString], diff);
+      }
+    }
+#endif
+  }
+  if ([self->item isValueSettable])
+    [self->item setValue:nil inComponent:sComponent]; // Reset 'item'
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+#if DEBUG
+  NSTimeInterval st = 0.0;
+
+  if (profElements)
+    st = [[NSDateClass date] timeIntervalSince1970];
+#endif
+  
+  WOResponse_AddCString(_response, "<select name=\"");
+  [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+  WOResponse_AddChar(_response, '"');
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    WOResponse_AddChar(_response, ' ');
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  WOResponse_AddChar(_response, '>');
+
+  [self appendOptionsToResponse:_response inContext:_ctx];
+
+  WOResponse_AddCString(_response, "</select>");
+  
+#if DEBUG
+  if (profElements) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    if (diff > 0.001) {
+#if 1
+      for (i = [_ctx componentStackCount]; i >= 0; i--)
+        printf("  ");
+#endif
+      printf("PopUpButton %s: %0.3fs\n",
+             [[_ctx elementID] cString], diff);
+    }
+  }
+#endif
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+  
+  str = [NSMutableString stringWithCapacity:256];
+  [str appendString:[super associationDescription]];
+
+  if (self->list)      [str appendFormat:@" list=%@",      self->list];
+  if (self->item)      [str appendFormat:@" item=%@",      self->item];
+  if (self->selection) [str appendFormat:@" selection=%@", self->selection];
+  if (self->string)    [str appendFormat:@" displayString=%@", self->string];
+  if (self->noSelectionString)
+    [str appendFormat:@" noselection=%@", self->noSelectionString];
+  if (self->escapeHTML)
+    [str appendFormat:@" escapeHTML=%@", self->escapeHTML];
+  if (self->selectedValue)
+    [str appendFormat:@" selectedValue=%@", self->selectedValue];
+  
+  return str;
+}
+
+@end /* WOPopUpButton */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOQuickTime.m b/skyrix-sope/NGObjWeb/DynamicElements/WOQuickTime.m
new file mode 100644 (file)
index 0000000..39644a9
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOHTMLDynamicElement.h"
+#include "WOElement+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+
+/*
+  A QuickTime movie, picture, ...
+  
+  The HTML tag attributes are described at:
+    http://www.apple.com/quicktime/authoring/embed2.html
+*/
+
+@interface WOQuickTime : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOElement     *template;
+  WOAssociation *filename;
+  WOAssociation *framework;
+  WOAssociation *src;
+
+  WOAssociation *action;
+  WOAssociation *href;
+  WOAssociation *pageName;
+  WOAssociation *prefixHost;
+  
+  WOAssociation *width;
+  WOAssociation *height;
+  WOAssociation *pluginsPage;
+  WOAssociation *hotspotList;
+  WOAssociation *selection;
+  WOAssociation *bgcolor;
+  WOAssociation *target;
+  WOAssociation *volume;
+  WOAssociation *pan;
+  WOAssociation *tilt;
+  WOAssociation *fov;
+  WOAssociation *node;
+  WOAssociation *correction;
+  WOAssociation *cache;
+  WOAssociation *autoplay;
+  WOAssociation *hidden;
+  WOAssociation *playEveryFrame;
+  WOAssociation *controller;
+}
+
+@end /* WOQuickTime */
+
+@interface WODynamicElement(UsedPrivates)
+- (id)_initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t;
+@end
+
+@implementation WOQuickTime
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super _initWithName:_name associations:_config template:_t])) {
+    self->template = [_t retain];
+    
+    self->filename       = OWGetProperty(_config, @"filename");
+    self->framework      = OWGetProperty(_config, @"framework");
+    self->src            = OWGetProperty(_config, @"src");
+
+    self->action         = OWGetProperty(_config, @"action");
+    self->href           = OWGetProperty(_config, @"href");
+    self->pageName       = OWGetProperty(_config, @"pageName");
+    self->prefixHost     = OWGetProperty(_config, @"prefixHost");
+  
+    self->width          = OWGetProperty(_config, @"width");
+    self->height         = OWGetProperty(_config, @"height");
+    self->pluginsPage    = OWGetProperty(_config, @"pluginsPage");
+    self->hotspotList    = OWGetProperty(_config, @"hotspotList");
+    self->selection      = OWGetProperty(_config, @"selection");
+    self->bgcolor        = OWGetProperty(_config, @"bgcolor");
+    self->target         = OWGetProperty(_config, @"target");
+    self->volume         = OWGetProperty(_config, @"volume");
+    self->pan            = OWGetProperty(_config, @"pan");
+    self->tilt           = OWGetProperty(_config, @"tilt");
+    self->fov            = OWGetProperty(_config, @"fov");
+    self->node           = OWGetProperty(_config, @"node");
+    self->correction     = OWGetProperty(_config, @"correction");
+    self->cache          = OWGetProperty(_config, @"cache");
+    self->autoplay       = OWGetProperty(_config, @"autoplay");
+    self->hidden         = OWGetProperty(_config, @"hidden");
+    self->playEveryFrame = OWGetProperty(_config, @"playEveryFrame");
+    self->controller     = OWGetProperty(_config, @"controller");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->template);
+  RELEASE(self->filename);
+  RELEASE(self->framework);
+  RELEASE(self->src);
+  RELEASE(self->action);
+  RELEASE(self->href);
+  RELEASE(self->pageName);
+  RELEASE(self->prefixHost);
+  RELEASE(self->width);
+  RELEASE(self->height);
+  RELEASE(self->pluginsPage);
+  RELEASE(self->hotspotList);
+  RELEASE(self->selection);
+  RELEASE(self->bgcolor);
+  RELEASE(self->target);
+  RELEASE(self->volume);
+  RELEASE(self->pan);
+  RELEASE(self->tilt);
+  RELEASE(self->fov);
+  RELEASE(self->node);
+  RELEASE(self->correction);
+  RELEASE(self->cache);
+  RELEASE(self->autoplay);
+  RELEASE(self->hidden);
+  RELEASE(self->playEveryFrame);
+  RELEASE(self->controller);
+  [super dealloc];
+}
+
+/* event handling */
+
+/* HTML generation */
+
+/* description */
+
+@end
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WORadioButton.m b/skyrix-sope/NGObjWeb/DynamicElements/WORadioButton.m
new file mode 100644 (file)
index 0000000..41f54fd
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOInput.h"
+#include "common.h"
+
+@interface WORadioButton : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // WOInput:    name
+  // WOInput:    value
+  // WOInput:    disabled
+@protected
+  WOAssociation *selection;
+  WOAssociation *checked;
+}
+
+@end /* WORadioButton */
+
+@implementation WORadioButton
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t 
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->selection = OWGetProperty(_config, @"selection");
+    self->checked   = OWGetProperty(_config, @"checked");
+    
+    if ((self->checked != nil) && (self->value != nil)) {
+      NSLog(@"WARNING: specified both, 'checked' and 'value', "
+            @"associations for radio button!");
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->selection release];
+  [self->checked   release];
+  [super dealloc];
+}
+
+/* handling requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  id formValue;
+  
+  sComponent = [_ctx component];
+  if ([self->disabled boolValueInComponent:sComponent])
+    return;
+  
+  formValue = [_req formValueForKey:OWFormElementName(self, _ctx)];
+
+  if (self->checked) {
+    if ([self->checked isValueSettable]) {
+      [self->checked setBoolValue:[formValue isEqual:[_ctx elementID]]
+                     inComponent:sComponent];
+    }
+  }
+  
+  if ([self->selection isValueSettable])
+    [self->selection setValue:formValue inComponent:sComponent];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSString *lvalue;
+  
+  sComponent = [_ctx component];
+  lvalue = self->checked
+    ? [_ctx elementID]
+    : [self->value stringValueInComponent:sComponent];
+  
+  WOResponse_AddCString(_response, "<input type=\"radio\" name=\"");
+  [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+  WOResponse_AddCString(_response, "\" value=\"");
+  [_response appendContentHTMLAttributeValue:lvalue];
+  WOResponse_AddCString(_response, "\"");
+  
+  if (self->checked) {
+    if ([self->checked boolValueInComponent:sComponent])
+      WOResponse_AddCString(_response, " checked=\"checked\"");
+  }
+  else {
+    id v   = [self->value     valueInComponent:sComponent];
+    id sel = [self->selection valueInComponent:sComponent];
+    
+    if ([v isEqual:sel])
+      WOResponse_AddCString(_response, " checked=\"checked\"");
+  }
+  
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              sComponent]);
+  }
+  WOResponse_AddCString(_response, " />");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = nil;
+  
+  str = [[[super associationDescription] mutableCopy] autorelease];
+  if (self->selection) [str appendFormat:@" selection=%@", self->selection];
+  if (self->checked)   [str appendFormat:@" checked=%@", self->checked];
+  return str;
+}
+
+@end /* WORadioButton */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WORadioButtonList.m b/skyrix-sope/NGObjWeb/DynamicElements/WORadioButtonList.m
new file mode 100644 (file)
index 0000000..716ff78
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOInput.h"
+
+@interface WORadioButtonList : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // WOInput:    name
+  // WOInput:    value
+  // WOInput:    disabled
+@protected
+  WOAssociation *list;
+  WOAssociation *item;
+  WOAssociation *index;
+  WOAssociation *selection;
+  WOAssociation *prefix;
+  WOAssociation *suffix;
+}
+
+@end /* WORadioButtonList */
+
+#include "common.h"
+
+// TODO: add support for template? (does WO provide this?)
+
+@implementation WORadioButtonList
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c 
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->list      = OWGetProperty(_config, @"list");
+    self->item      = OWGetProperty(_config, @"item");
+    self->index     = OWGetProperty(_config, @"index");
+    self->selection = OWGetProperty(_config, @"selection");
+    self->prefix    = OWGetProperty(_config, @"prefix");
+    self->suffix    = OWGetProperty(_config, @"suffix");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->list      release];
+  [self->item      release];
+  [self->index     release];
+  [self->selection release];
+  [self->prefix    release];
+  [self->suffix    release];
+  [super dealloc];
+}
+
+/* processing requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent = [_ctx component];
+  unsigned idx;
+  NSArray  *array;
+  id       formValue;
+  
+  if ([self->disabled boolValueInComponent:sComponent])
+    return;
+  
+  formValue = [_request formValueForKey:OWFormElementName(self, _ctx)];
+  if (formValue == nil)
+    return;
+  
+  idx   = [formValue unsignedIntValue];
+  array = [self->list valueInComponent:sComponent];
+
+  if ([self->index isValueSettable])
+    [self->index setUnsignedIntValue:idx inComponent:sComponent];
+
+  if ([self->item isValueSettable])
+    [self->item setValue:[array objectAtIndex:idx] inComponent:sComponent];
+      
+  if ([self->selection isValueSettable]) {
+    [self->selection setValue:[array objectAtIndex:idx]
+                    inComponent:sComponent];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  return nil;
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSArray     *array;
+  unsigned    goCount;
+  unsigned    cnt;
+  NSString    *n;
+  id          sel;
+
+  sComponent = [_ctx component];
+  array      = [self->list valueInComponent:sComponent];
+  goCount    = [array count];
+
+  if (goCount <= 0)
+    return;
+
+  n   = OWFormElementName(self, _ctx);
+  sel = [self->selection valueInComponent:sComponent];
+
+  for (cnt = 0; cnt < goCount; cnt++) {
+    id object = [array objectAtIndex:cnt];
+
+    if ([self->index isValueSettable])
+      [self->index setUnsignedIntValue:cnt inComponent:sComponent];
+
+    if ([self->item isValueSettable])
+      [self->item setValue:object inComponent:sComponent];
+
+    if (self->prefix) {
+      WOResponse_AddString(_response,
+                          [self->prefix stringValueInComponent:sComponent]);
+    }
+
+    /* add radio button */
+    {
+      WOResponse_AddCString(_response, "<input type=\"radio\" name=\"");
+      [_response appendContentHTMLAttributeValue:n];
+      WOResponse_AddCString(_response, "\" value=\"");
+      WOResponse_AddInt(_response, cnt);
+      WOResponse_AddCString(_response, "\"");
+
+      if ([sel isEqual:object])
+       WOResponse_AddCString(_response, " checked=\"checked\"");
+      [self appendExtraAttributesToResponse:_response inContext:_ctx];
+      if (self->otherTagString) {
+       WOResponse_AddString(_response,
+                            [self->otherTagString stringValueInComponent:
+                                    [_ctx component]]);
+      }
+      WOResponse_AddCString(_response, " />");
+
+      // the value in a radio list is the string besides the button
+      if (self->value) {
+       NSString *s;
+       
+       s = [self->value stringValueInComponent:sComponent];
+       WOResponse_AddHtmlString(_response, s);
+      }
+    }
+        
+    if (self->suffix) {
+      WOResponse_AddString(_response,
+                          [self->suffix stringValueInComponent:sComponent]);
+    }
+  }
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:128];
+  [str appendString:[super associationDescription]];
+  if (self->list)      [str appendFormat:@" list=%@",      self->list];
+  if (self->item)      [str appendFormat:@" item=%@",      self->item];
+  if (self->index)     [str appendFormat:@" index=%@",     self->index];
+  if (self->prefix)    [str appendFormat:@" prefix=%@",    self->prefix];
+  if (self->suffix)    [str appendFormat:@" suffix=%@",    self->suffix];
+  if (self->selection) [str appendFormat:@" selection=%@", self->selection];
+
+  return str;
+}
+
+@end /* WORadioButtonList */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WORepetition.m b/skyrix-sope/NGObjWeb/DynamicElements/WORepetition.m
new file mode 100644 (file)
index 0000000..39d3c5d
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+#include "WOElement+private.h"
+#include <NGExtensions/NSString+misc.h>
+#include "common.h"
+
+@interface WORepetition : WODynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOElement *template;
+#if DEBUG
+  NSString  *repName;
+#endif
+}
+
+@end /* WORepetition */
+
+@interface _WOComplexRepetition : WORepetition
+{
+  WOAssociation *list;       // array of objects to iterate through
+  WOAssociation *item;       // current item in the array
+  WOAssociation *index;      // current index
+  WOAssociation *identifier; // unique id for element
+  WOAssociation *count;      // number of times the contents will be repeated
+  
+  // non-WO
+  WOAssociation *startIndex;
+  WOAssociation *separator;  // string inserted between repetitions
+}
+
+@end
+
+@interface _WOSimpleRepetition : WORepetition
+{
+  WOAssociation *list; // array of objects to iterate through
+  WOAssociation *item; // current item in the array
+}
+
+@end
+
+@interface _WOTemporaryRepetition : NSObject
+@end
+
+//#define PROF_REPETITION_CLUSTER 1
+
+static int descriptiveIDs  = -1;
+static int debugTakeValues = -1;
+
+#if PROF_REPETITION_CLUSTER
+static int complexCount = 0;
+static int simpleCount = 0;
+#endif
+
+@implementation _WOTemporaryRepetition
+
+static inline Class _classForConfig(NSDictionary *_config) {
+  Class repClass = Nil;
+  unsigned c;
+
+  switch ((c = [_config count])) {
+    case 0:
+      repClass = [_WOSimpleRepetition class];
+      break;
+    case 1:
+      if ([_config objectForKey:@"list"])
+        repClass = [_WOSimpleRepetition class];
+      else if ([_config objectForKey:@"item"])
+        repClass = [_WOSimpleRepetition class];
+      break;
+    case 2:
+      if ([_config objectForKey:@"list"] &&
+          [_config objectForKey:@"item"])
+        repClass = [_WOSimpleRepetition class];
+      break;
+    default:
+      repClass = [_WOComplexRepetition class];
+      break;
+  }
+  
+  if (repClass == Nil)
+    repClass = [_WOComplexRepetition class];
+
+  return repClass;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_template
+{
+  Class repClass = Nil;
+
+  repClass = _classForConfig(_config);
+  
+  return [[repClass alloc]
+                    initWithName:_name
+                    associations:_config
+                    template:_template];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  contentElements:(NSArray *)_contents
+{
+  Class repClass = Nil;
+  
+  repClass = _classForConfig(_config);
+  
+  return [[repClass alloc]
+                    initWithName:_name
+                    associations:_config
+                    contentElements:_contents];
+}
+
+@end /* _WOTemporaryRepetition */
+
+@implementation WORepetition
+
++ (int)version {
+  return [super version] + 1 /* v3 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+
+  if (debugTakeValues == -1) {
+    debugTakeValues = 
+      [[NSUserDefaults standardUserDefaults] boolForKey:@"WODebugTakeValues"]
+      ? 1 : 0;
+    
+    if (debugTakeValues) NSLog(@"WORepetition: WODebugTakeValues on.");
+  }
+}
+
++ (id)allocWithZone:(NSZone *)zone {
+  static Class WORepetitionClass = Nil;
+  static _WOTemporaryRepetition *temporaryRepetition = nil;
+  
+  if (WORepetitionClass == Nil)
+    WORepetitionClass = [WORepetition class];
+  if (temporaryRepetition == nil)
+    temporaryRepetition = [_WOTemporaryRepetition allocWithZone:zone];
+  
+  return (self == WORepetitionClass)
+    ? (id)temporaryRepetition
+    : NSAllocateObject(self, 0, zone);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if (descriptiveIDs == -1) {
+    descriptiveIDs = [[[NSUserDefaults standardUserDefaults]
+                                       objectForKey:@"WODescriptiveElementIDs"]
+                                       boolValue] ? 1 : 0;
+  }
+  
+#if DEBUG
+  self->repName = _name ? [_name copy] : @"R";
+#endif
+  
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->template = RETAIN(_c);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template release];
+#if DEBUG
+  [self->repName release];
+#endif
+  [super dealloc];
+}
+
+@end /* WORepetition */
+
+@implementation _WOComplexRepetition
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+#if PROF_REPETITION_CLUSTER
+    complexCount++;
+
+    if (complexCount % 10 == 0) {
+      NSLog(@"REPETITION CLUSTER: %i simple, %i complex",
+            simpleCount, complexCount);
+    }
+#endif
+    self->list       = OWGetProperty(_config, @"list");
+    self->item       = OWGetProperty(_config, @"item");
+    self->index      = OWGetProperty(_config, @"index");
+    self->identifier = OWGetProperty(_config, @"identifier");
+    self->count      = OWGetProperty(_config, @"count");
+    self->startIndex = OWGetProperty(_config, @"startIndex");
+    self->separator  = OWGetProperty(_config, @"separator");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->separator  release];
+  [self->list       release];
+  [self->item       release];
+  [self->index      release];
+  [self->identifier release];
+  [self->count      release];
+  [self->startIndex release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOElement *)template {
+  return self->template;
+}
+
+/* OWResponder */
+
+static inline void
+_applyIdentifier(_WOComplexRepetition *self,
+                 WOComponent *sComponent,
+                 NSString *_idx)
+{
+  NSArray *array;
+  unsigned count;
+
+#if DEBUG
+  NSCAssert(self->identifier, @"this method is only to be called on objects "
+            @"with a specified 'identifier' association !");
+#endif
+
+  array = [self->list valueInComponent:sComponent];
+  count = [array count];
+
+  if (count > 0) {
+    unsigned cnt;
+
+    /* find subelement for unique id */
+    
+    for (cnt = 0; cnt < count; cnt++) {
+      NSString *ident;
+      
+      if (self->index)
+        [self->index setUnsignedIntValue:cnt inComponent:sComponent];
+
+      if (self->item) {
+        [self->item setValue:[array objectAtIndex:cnt]
+                    inComponent:sComponent];
+      }
+
+      ident = [self->identifier stringValueInComponent:sComponent];
+
+      if ([ident isEqualToString:_idx]) {
+        /* found subelement with unique id */
+        return;
+      }
+    }
+    
+    [sComponent logWithFormat:
+                  @"WORepetition: array did change, "
+                  @"unique-id isn't contained."];
+    [self->item  setValue:nil          inComponent:sComponent];
+    [self->index setUnsignedIntValue:0 inComponent:sComponent];
+  }
+}
+
+static inline void
+_applyIndex(_WOComplexRepetition *self, WOComponent *sComponent, unsigned _idx)
+{
+  NSArray *array;
+  
+  array = [self->list valueInComponent:sComponent];
+  
+  if (self->index)
+    [self->index setUnsignedIntValue:_idx inComponent:sComponent];
+
+  if (self->item) {
+    unsigned count = [array count];
+
+    if (_idx < count) {
+      [self->item setValue:[array objectAtIndex:_idx]
+                  inComponent:sComponent];
+    }
+    else {
+      [sComponent logWithFormat:
+                    @"WORepetition: array did change, index is invalid."];
+      [self->item setValue:nil inComponent:sComponent];
+    }
+  }
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  // iterate ..
+  WOComponent *sComponent;
+  NSArray     *array;
+  unsigned    aCount;
+  unsigned    goCount;
+
+#if DEBUG
+  if (descriptiveIDs)
+    [_ctx appendElementIDComponent:self->repName];
+#endif
+  
+  sComponent = [_ctx component];
+  array = [self->list valueInContext:_ctx];
+  aCount = [array count];
+  
+  goCount = self->count
+    ? [self->count unsignedIntValueInComponent:sComponent]
+    : aCount;
+  
+  if (goCount > 0) {
+    unsigned startIdx, goUntil;
+    unsigned cnt;
+    
+    startIdx =
+      [self->startIndex unsignedIntValueInComponent:sComponent];
+    
+    if (self->identifier == nil) {
+      if (startIdx == 0)
+        [_ctx appendZeroElementIDComponent];
+      else
+        [_ctx appendIntElementIDComponent:startIdx];
+    }
+    
+    if (self->list) {
+      goUntil = (aCount > (startIdx + goCount))
+        ? startIdx + goCount
+        : aCount;
+    }
+    else
+      goUntil = startIdx + goCount;
+
+#if DEBUG
+    if (debugTakeValues) {
+      [sComponent debugWithFormat:
+                    @"%@: name=%@ id='%@' start walking rep (%i-%i) ..",
+                    NSStringFromClass([self class]),
+                    self->repName,
+                    [_ctx elementID],
+                    startIdx, goUntil];
+    }
+#endif
+    
+    for (cnt = startIdx; cnt < goUntil; cnt++) {
+      _applyIndex(self, sComponent, cnt);
+      
+      if (self->identifier) {
+        NSString *s;
+        
+        s = [self->identifier stringValueInComponent:sComponent];
+        [_ctx appendElementIDComponent:s];
+      }
+
+      if (debugTakeValues) {
+       [[_ctx component] 
+         debugWithFormat:@"%@<%@>: let template take values ..",
+           [_ctx elementID], NSStringFromClass([self class])];
+      }
+      
+      [self->template takeValuesFromRequest:_request inContext:_ctx];
+      
+      if (self->identifier == nil)
+        [_ctx incrementLastElementIDComponent];
+      else
+        [_ctx deleteLastElementIDComponent];
+    }
+    
+    if (self->identifier == nil)
+      [_ctx deleteLastElementIDComponent]; // Repetition Index
+  }
+  else if (debugTakeValues) {
+    [[_ctx component] debugWithFormat:
+                        @"%@<%@>: takevalues -> no contents to walk ! ..",
+                        [_ctx elementID], NSStringFromClass([self class])];
+  }
+  
+#if DEBUG
+  if (descriptiveIDs)
+    [_ctx deleteLastElementIDComponent];
+#endif
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent;
+  id result = nil;
+  id idxId;
+  
+  sComponent = [_ctx component];
+
+#if DEBUG
+  if (descriptiveIDs) {
+    if (![[_ctx currentElementID] isEqualToString:self->repName]) {
+      [[_ctx session]
+             logWithFormat:@"%s: %@ missing repetition ID 'R' !",
+               __PRETTY_FUNCTION__, self];
+      return nil;
+    }
+    [_ctx consumeElementID]; // consume 'R'
+    [_ctx appendElementIDComponent:self->repName];
+  }
+#endif
+  
+  if ((idxId  = [_ctx currentElementID])) {
+    [_ctx consumeElementID]; // consume index-id
+    
+    /* this updates the element-id path */
+    [_ctx appendElementIDComponent:idxId];
+    
+    if (self->identifier)
+      _applyIdentifier(self, sComponent, idxId);
+    else
+      _applyIndex(self, sComponent, [idxId intValue]);
+    
+    result = [self->template invokeActionForRequest:_request inContext:_ctx];
+
+    [_ctx deleteLastElementIDComponent];
+  }
+  else {
+    [[_ctx session]
+           logWithFormat:@"%s: %@: MISSING INDEX ID in URL !",
+             __PRETTY_FUNCTION__,
+             self];
+  }
+
+#if DEBUG
+  if (descriptiveIDs)
+    [_ctx deleteLastElementIDComponent];
+#endif
+  
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  static Class NSAutoreleasePoolClass = Nil;
+  WOComponent *sComponent;
+  NSArray  *array;
+  unsigned aCount, goCount, startIdx;
+  NSAutoreleasePool *pool;
+
+#if DEBUG
+  if (descriptiveIDs)
+    [_ctx appendElementIDComponent:self->repName];
+#endif
+  
+  if (NSAutoreleasePoolClass == Nil)
+    NSAutoreleasePoolClass = [NSAutoreleasePool class];
+  
+  pool = [[NSAutoreleasePoolClass alloc] init];
+  
+  sComponent = [_ctx component];
+  array    = [self->list valueInContext:_ctx];
+  aCount   = [array count];
+  startIdx = [self->startIndex unsignedIntValueInComponent:sComponent];
+  
+  goCount = self->count
+    ? [self->count unsignedIntValueInComponent:sComponent]
+    : aCount;
+  
+  if (goCount > 0) {
+    unsigned cnt, goUntil;
+
+#if HTML_DEBUG
+    // append debugging info
+    WOResponse_AddString(_response,
+                         [NSString stringWithFormat:
+                                     @"<!-- WORep. count=%d arraySize=%d -->\n",
+                                     goCount, [array count]]);
+#endif
+
+    if (self->identifier == nil) {
+      if (startIdx == 0)
+        [_ctx appendZeroElementIDComponent];
+      else
+        [_ctx appendIntElementIDComponent:startIdx];
+    }
+
+    if (self->list) {
+      goUntil = (aCount > (startIdx + goCount))
+        ? startIdx + goCount
+        : aCount;
+    }
+    else
+      goUntil = startIdx + goCount;
+    
+    for (cnt = startIdx; cnt < goUntil; cnt++) {
+      id ident = nil;
+      id lItem;
+      
+      if ((cnt != startIdx) && (self->separator != nil)) {
+        WOResponse_AddString(_response,
+                             [self->separator stringValueInComponent:
+                                                sComponent]);
+      }
+      
+      if (self->index)
+        [self->index setUnsignedIntValue:cnt inComponent:sComponent];
+
+      lItem = [array objectAtIndex:cnt];
+      
+      if (self->item) {
+        [self->item setValue:lItem inComponent:sComponent];
+      }
+      else {
+       /* push cursor */
+       [_ctx pushCursor:lItem];
+      }
+      
+      /* get identifier used for action-links */
+      
+      if (self->identifier) {
+        /* use a unique id for subelement detection */
+        ident = [self->identifier stringValueInComponent:sComponent];
+        ident = [ident stringByEscapingURL];
+        [_ctx appendElementIDComponent:ident];
+      }
+
+#if HTML_DEBUG
+      /* append debugging info */
+      WOResponse_AddString(_response, [NSString stringWithFormat:
+                                         @"  <!-- iteration=%d -->\n", cnt]);
+#endif
+
+      /* append child elements */
+      
+      [self->template appendToResponse:_response inContext:_ctx];
+
+      /* cleanup */
+
+      if (self->identifier)
+        [_ctx deleteLastElementIDComponent];
+      else
+        [_ctx incrementLastElementIDComponent];
+    }
+
+    if (self->identifier == nil)
+      [_ctx deleteLastElementIDComponent]; /* repetition index */
+
+    if (self->item == nil) {
+      [_ctx popCursor];
+    }
+    
+    //if (self->index) [self->index setUnsignedIntValue:0];
+    //if (self->item)  [self->item  setValue:nil];
+  }
+#if HTML_DEBUG
+  else {
+    WOResponse_AddCString(_response, "<!-- repetition with no contents -->");
+  }
+#endif
+  
+  [pool release];
+  
+#if DEBUG
+  if (descriptiveIDs)
+    [_ctx deleteLastElementIDComponent];
+#endif
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:32];
+
+  if (self->list)       [str appendFormat:@" list=%@",     self->list];
+  if (self->item)       [str appendFormat:@" item=%@",     self->item];
+  if (self->index)      [str appendFormat:@" index=%@",    self->index];
+  if (self->identifier) [str appendFormat:@" id=%@",       self->identifier];
+  if (self->count)      [str appendFormat:@" count=%@",    self->count];
+  if (self->template)   [str appendFormat:@" template=%@", self->template];
+
+  return str;
+}
+
+@end /* _WOComplexRepetition */
+
+@implementation _WOSimpleRepetition
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+#if PROF_REPETITION_CLUSTER
+    simpleCount++;
+
+    if (simpleCount % 10 == 0) {
+      NSLog(@"REPETITION CLUSTER: %i simple, %i complex",
+            simpleCount, complexCount);
+    }
+#endif
+    self->list = OWGetProperty(_config, @"list");
+    self->item = OWGetProperty(_config, @"item");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->list release];
+  [self->item release];
+  [super dealloc];
+}
+
+/* processing */
+
+static inline void
+_sapplyIndex(_WOSimpleRepetition *self, WOComponent *sComponent, NSArray *array, unsigned _idx)
+{
+  if (self->item) {
+    unsigned count = [array count];
+
+    if (_idx < count) {
+      [self->item setValue:[array objectAtIndex:_idx]
+                  inComponent:sComponent];
+    }
+    else {
+      [sComponent logWithFormat:
+                    @"WORepetition: array did change, index is invalid."];
+      [self->item setValue:nil inComponent:sComponent];
+    }
+  }
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  // iterate ..
+  WOComponent *sComponent;
+  NSArray     *array;
+  unsigned    aCount;
+  unsigned    goCount;
+
+#if DEBUG
+  if (descriptiveIDs)
+    [_ctx appendElementIDComponent:self->repName];
+#endif
+  
+  sComponent = [_ctx component];
+  array      = [self->list valueInContext:_ctx];
+  goCount    = aCount = [array count];
+  
+  if (goCount > 0) {
+    unsigned cnt;
+    
+    [_ctx appendZeroElementIDComponent];
+    
+#if DEBUG
+    if (debugTakeValues) {
+      NSLog(@"%s: name=%@ id='%@' start walking rep (count=%i) ..",
+           __PRETTY_FUNCTION__, self->repName, [_ctx elementID], aCount);
+    }
+#endif
+    
+    for (cnt = 0; cnt < aCount; cnt++) {
+      _sapplyIndex(self, sComponent, array, cnt);
+      
+#if DEBUG
+      if (debugTakeValues) {
+       NSLog(@"%s:    %@<%@>: idx[%i] let template take values ..",
+             __PRETTY_FUNCTION__,
+             [_ctx elementID], NSStringFromClass([self class]), cnt);
+      }
+#endif
+      
+      [self->template takeValuesFromRequest:_request inContext:_ctx];
+      
+      [_ctx incrementLastElementIDComponent];
+    }
+    
+    [_ctx deleteLastElementIDComponent]; // Repetition Index
+  }
+#if DEBUG
+  else if (debugTakeValues) {
+    NSLog(@"%s: %@<%@>: takevalues -> no contents to walk:\n"
+         @"  component: %@\n"
+         @"  list:      %@\n"
+         @"  count:     %i",
+         __PRETTY_FUNCTION__,
+         [_ctx elementID], NSStringFromClass([self class]),
+         sComponent, array, goCount);
+  }
+#endif
+  
+#if DEBUG
+  if (descriptiveIDs)
+    [_ctx deleteLastElementIDComponent];
+#endif
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent;
+  id result = nil;
+  id idxId;
+  
+  sComponent = [_ctx component];
+  
+#if DEBUG
+  if (descriptiveIDs) {
+    if (![[_ctx currentElementID] isEqualToString:self->repName]) {
+      [[_ctx session]
+             logWithFormat:@"%s: %@ missing repetition ID 'R' !",
+               __PRETTY_FUNCTION__, self];
+      return nil;
+    }
+    [_ctx consumeElementID]; // consume 'R'
+    [_ctx appendElementIDComponent:self->repName];
+  }
+#endif
+  
+  if ((idxId  = [_ctx currentElementID])) {
+    int idx;
+    
+    idx = [idxId intValue];
+    [_ctx consumeElementID]; // consume index-id
+    
+    /* this updates the element-id path */
+    [_ctx appendElementIDComponent:idxId];
+    
+    _sapplyIndex(self, sComponent, 
+                [self->list valueInContext:_ctx], idx);
+    
+    result = [self->template invokeActionForRequest:_request inContext:_ctx];
+
+    [_ctx deleteLastElementIDComponent];
+  }
+  else {
+    [[_ctx session]
+           logWithFormat:@"%s: %@: MISSING INDEX ID in URL !",
+             __PRETTY_FUNCTION__,
+             self];
+  }
+
+#if DEBUG
+  if (descriptiveIDs)
+    [_ctx deleteLastElementIDComponent];
+#endif
+  
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  static Class NSAutoreleasePoolClass = Nil;
+  WOComponent *sComponent;
+  NSArray  *array;
+  unsigned aCount;
+  NSAutoreleasePool *pool;
+
+#if DEBUG
+  if (descriptiveIDs)
+    [_ctx appendElementIDComponent:self->repName];
+#endif
+  
+  if (NSAutoreleasePoolClass == Nil)
+    NSAutoreleasePoolClass = [NSAutoreleasePool class];
+  
+  pool = [[NSAutoreleasePoolClass alloc] init];
+  
+  sComponent = [_ctx component];
+  array    = [self->list valueInContext:_ctx];
+  aCount   = [array count];
+  
+  if (aCount > 0) {
+    unsigned cnt;
+
+#if HTML_DEBUG
+    // append debugging info
+    WOResponse_AddString(_response,
+                         [NSString stringWithFormat:
+                                     @"<!-- WORep. count=%d arraySize=%d -->\n",
+                                     goCount, [array count]]);
+#endif
+
+    [_ctx appendZeroElementIDComponent];
+    
+    for (cnt = 0; cnt < aCount; cnt++) {
+      if (self->item) {
+        [self->item setValue:[array objectAtIndex:cnt]
+                    inComponent:sComponent];
+      }
+      else {
+       [_ctx pushCursor:[array objectAtIndex:cnt]];
+      }
+      
+#if HTML_DEBUG
+      // append debugging info
+      WOResponse_AddString(_response, [NSString stringWithFormat:
+                                         @"  <!-- iteration=%d -->\n", cnt]);
+#endif
+      
+      /* append child elements */
+      
+      [self->template appendToResponse:_response inContext:_ctx];
+
+      /* cleanup */
+      
+      [_ctx incrementLastElementIDComponent];
+      
+      if (self->item == nil)
+       [_ctx popCursor];
+    }
+
+    [_ctx deleteLastElementIDComponent]; /* repetition index */
+    
+    //if (self->item)  [self->item  setValue:nil];
+  }
+#if HTML_DEBUG
+  else {
+    WOResponse_AddCString(_response, "<!-- repetition with no contents -->");
+  }
+#endif
+  
+  [pool release];
+  
+#if DEBUG
+  if (descriptiveIDs)
+    [_ctx deleteLastElementIDComponent];
+#endif
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:24];
+  if (self->list)     [str appendFormat:@" list=%@",     self->list];
+  if (self->item)     [str appendFormat:@" item=%@",     self->item];
+  if (self->template) [str appendFormat:@" template=%@", self->template];
+  return str;
+}
+
+@end /* _WOSimpleRepetition */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOResetButton.m b/skyrix-sope/NGObjWeb/DynamicElements/WOResetButton.m
new file mode 100644 (file)
index 0000000..52b2f4f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOInput.h"
+#include "WOElement+private.h"
+#include "common.h"
+
+@interface WOResetButton : WOInput
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  // WOInput:    name
+  // WOInput:    value
+  // WOInput:    disabled
+}
+
+@end /* WOResetButton */
+
+@implementation WOResetButton
+
+// ******************** responder ********************
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *v = [self->value stringValueInComponent:[_ctx component]];
+
+  if ((self->name != nil) || (self->disabled != nil)) {
+    NSLog(@"WARNING: 'name' and 'disabled' properties are "
+          @"not supported in WOResetButton !");
+  }
+
+  WOResponse_AddCString(_response, "<input type=\"reset\" value=\"");
+  [_response appendContentHTMLAttributeValue:v];
+  WOResponse_AddChar(_response, '"');
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  WOResponse_AddCString(_response, " />");
+}
+
+@end /* WOResetButton */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOResourceURL.m b/skyrix-sope/NGObjWeb/DynamicElements/WOResourceURL.m
new file mode 100644 (file)
index 0000000..9577fa2
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WOResourceURL : WODynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *filename;  // path relative to WebServerResources
+  WOAssociation *framework;
+  WOAssociation *data;      // data (eg from a database)
+  WOAssociation *mimeType;  // the type of data
+  WOAssociation *key;       // the cache key
+  WOElement     *template;  // subelements
+}
+
+@end
+
+#include "WOElement+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+
+@implementation WOResourceURL
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmpl
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmpl])) {
+    self->template  = [_tmpl retain];
+    self->filename  = OWGetProperty(_config, @"filename");
+    self->framework = OWGetProperty(_config, @"framework");
+    self->data      = OWGetProperty(_config, @"data");
+    self->mimeType  = OWGetProperty(_config, @"mimeType");
+    self->key       = OWGetProperty(_config, @"key");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->template);
+  RELEASE(self->framework);
+  RELEASE(self->filename);
+  RELEASE(self->data);
+  RELEASE(self->key);
+  RELEASE(self->mimeType);
+  [super dealloc];
+}
+
+/* responder */
+
+#define StrVal(__x__) [self->__x__ stringValueInComponent:sComponent]
+
+/* request handling */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent = [_ctx component];
+  NSData     *adata;
+  NSString   *atype;
+  WOResponse *response;
+
+  if (self->data == nil)
+    return [self->template invokeActionForRequest:_request inContext:_ctx];
+  
+  adata = [self->data     valueInComponent:sComponent];
+  atype = [self->mimeType stringValueInComponent:sComponent];
+
+  response = [_ctx response];
+    
+  [response setContent:adata];
+  [response setHeader:atype ? atype : @"application/octet-stream"
+            forKey:@"content-type"];
+    
+  return response;
+}
+
+/* response generation */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSString    *uFi;
+  
+  if ([[_ctx request] isFromClientComponent])
+    return;
+  
+  sComponent = [_ctx component];
+    
+  uFi = [self->filename stringValueInComponent:sComponent];
+  
+  if (uFi) {
+    WOResourceManager *rm;
+    NSString          *frameworkName;
+    NSArray           *languages;
+    
+    if ((rm = [[_ctx component] resourceManager]) == nil)
+      rm = [[_ctx application] resourceManager];
+    
+    /* If 'framework' binding is not set, use parent component's framework */
+    if (self->framework){
+      frameworkName = [self->framework stringValueInComponent:sComponent];
+      if (frameworkName != nil && [frameworkName isEqualToString:@"app"])
+        frameworkName = nil;
+    }
+    else
+      frameworkName = [sComponent frameworkName];
+    
+    languages = [_ctx hasSession]
+      ? [[_ctx session] languages]
+      : [[_ctx request] browserLanguages];
+    uFi = [rm urlForResourceNamed:uFi
+              inFramework:frameworkName
+              languages:languages
+              request:[_ctx request]];
+    if (uFi == nil) {
+      NSLog(@"%@: did not find resource '%@'", sComponent,
+            [self->filename stringValueInComponent:sComponent]);
+    }
+    else
+      [_response appendContentHTMLAttributeValue:uFi];
+  }
+  else if (self->data != nil) {
+    NSString *kk;
+    
+    if ((kk = [self->key stringValueInComponent:sComponent])) {
+      NSString          *url;
+      WOResourceManager *rm;
+      
+      if ((rm = [[_ctx component] resourceManager]) == nil)
+        rm = [[_ctx application] resourceManager];
+    
+      [rm setData:[self->data valueInComponent:sComponent]
+          forKey:kk
+          mimeType:[self->mimeType stringValueInComponent:sComponent]
+          session:[_ctx hasSession] ? [_ctx session] : nil];
+      
+      url = [_ctx urlWithRequestHandlerKey:
+                    [WOApplication resourceRequestHandlerKey]
+                  path:[@"/" stringByAppendingString:kk]
+                  queryString:nil];
+      
+      WOResponse_AddString(_response, url);
+    }
+    else {
+      /* a component action link */
+      uFi = [_ctx componentActionURL];
+      WOResponse_AddString(_response, uFi);
+    }
+  }
+  else {
+    [sComponent logWithFormat:@"missing resource URL for element %@", self];
+  }
+  
+  /* content */
+  [self->template appendToResponse:_response inContext:_ctx];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [[NSMutableString alloc] init];
+
+  if (self->filename)  [str appendFormat:@" filename=%@",  self->filename];
+  if (self->framework) [str appendFormat:@" framework=%@", self->framework];
+  if (self->data)      [str appendFormat:@" data=%@",      self->data];
+  if (self->mimeType)  [str appendFormat:@" mimeType=%@",  self->mimeType];
+  if (self->key)       [str appendFormat:@" key=%@",       self->key];
+  
+  return AUTORELEASE(str);
+}
+
+@end /* WOResourceURL */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOSetCursor.m b/skyrix-sope/NGObjWeb/DynamicElements/WOSetCursor.m
new file mode 100644 (file)
index 0000000..71560f3
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+#include "WOElement+private.h"
+
+@interface WOSetCursor : WODynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOElement     *template;
+  WOAssociation *object;
+}
+
+@end
+
+#include "common.h"
+
+@implementation WOSetCursor
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->object   = OWGetProperty(_config, @"object");
+    self->template = RETAIN(_c);
+    
+    /* support 'value' ?, support 'expr' (string evaluated as script ?) */
+  }
+  return self;
+}
+- (void)dealloc {
+  RELEASE(self->template);
+  RELEASE(self->object);
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOElement *)template {
+  return self->template;
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  id obj;
+  
+  obj = [[self->object valueInContext:_ctx] retain];
+  [_ctx pushCursor:obj];
+  
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+  
+  [_ctx popCursor];
+  [obj autorelease];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  id result;
+  id obj;
+  
+  obj = [[self->object valueInContext:_ctx] retain];
+  [_ctx pushCursor:obj];
+  
+  result = [[self->template invokeActionForRequest:_rq inContext:_ctx] retain];
+  
+  [_ctx popCursor];
+  [obj autorelease];
+  return [result autorelease];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  id obj;
+  
+  obj = [[self->object valueInContext:_ctx] retain];
+  [_ctx pushCursor:obj];
+  NSLog(@"pushed cursor: %@", obj);
+  
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  [_ctx popCursor];
+  [obj autorelease];
+}
+
+@end /* WOSetCursor */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOString.m b/skyrix-sope/NGObjWeb/DynamicElements/WOString.m
new file mode 100644 (file)
index 0000000..de38a5a
--- /dev/null
@@ -0,0 +1,783 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHTMLDynamicElement.h"
+#include "WOElement+private.h"
+#include "common.h"
+#import <Foundation/NSNumberFormatter.h>
+#import <Foundation/NSDateFormatter.h>
+
+/*
+  Usage:
+    MyString: WOString {
+      value      = myCalendarDate;
+      dateformat = "%B %Y %T";
+      insertBR   = NO;
+      nilString  = "no date is set !";
+      escapeHTML = YES;
+    };
+
+  Hierarchy:
+    WOHTMLDynamicElement
+      WOString
+        _WOSimpleStaticString
+        _WOSimpleStaticASCIIString
+        _WOComplexString
+*/
+
+@interface WOString : WOHTMLDynamicElement
+@end /* WOString */
+
+@interface _WOTemporaryString : NSObject
+@end
+
+@interface _WOSimpleStaticString : WOString
+{
+  NSString *value;
+}
+@end /* WOSimpleStaticString */
+
+@interface _WOSimpleStaticASCIIString : WOString
+{
+  const unsigned char *value;
+}
+@end /* _WOSimpleStaticASCIIString */
+
+@interface _WOSimpleDynamicString : WOString
+{
+  WOAssociation *value;
+}
+@end /* WOSimpleStaticString */
+
+@interface _WOComplexString : WOString
+{
+  WOAssociation *value;          // object
+  WOAssociation *escapeHTML;     // BOOL
+  WOAssociation *numberformat;   // string
+  WOAssociation *dateformat;     // string
+  WOAssociation *formatter;      // WO4: NSFormatter object
+  WOAssociation *valueWhenEmpty; // WO4.5
+  
+  // non-WO attributes
+  WOAssociation *insertBR;   // insert <BR> tags for newlines
+  WOAssociation *nilString;  // string to use if value is nil - DEPRECATED!
+  WOAssociation *style;      // insert surrounding <span class="style">
+}
+
+@end /* WOComplexString */
+
+@implementation WOString
+
++ (int)version {
+  return [super version] + 1 /* v3 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
++ (id)allocWithZone:(NSZone *)zone {
+  static Class WOStringClass = Nil;
+  static _WOTemporaryString *temporaryString = nil;
+  
+  if (WOStringClass == Nil)
+    WOStringClass = [WOString class];
+  if (temporaryString == nil)
+    temporaryString = [_WOTemporaryString allocWithZone:zone];
+  
+  return (self == WOStringClass)
+    ? (id)temporaryString
+    : NSAllocateObject(self, 0, zone);
+}
+
+@end /* WOString */
+
+@implementation _WOSimpleDynamicString
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->value = OWGetProperty(_config, @"value");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->value release];
+  [super dealloc];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [_response appendContentHTMLString:[self->value stringValueInContext:_ctx]];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  return [NSString stringWithFormat:@" value='%@'", self->value];
+}
+
+@end /* _WOSimpleDynamicString */
+
+@implementation _WOSimpleStaticString
+
+- (id)initWithValue:(WOAssociation *)_value escapeHTML:(BOOL)_flag {
+  if ((self = [super initWithName:nil associations:nil template:nil])) {
+    // ENCODING, UNICODE
+    NSString *v;
+    unsigned length;
+
+    v = [_value stringValueInComponent:nil];
+    length = [v cStringLength];
+
+    if (length == 0) {
+      v = @"";
+    }
+    else if (_flag) {
+      char buffer[length * 6]; /* longest-encoding: '&quot;' */
+      unsigned clen = [v cStringLength];
+      char     *cbuf;
+      register char *cstr;
+      register unsigned i;
+      register char *bufPtr;
+
+#if NeXT_Foundation_LIBRARY
+      cbuf = malloc(clen + 1);
+#else
+      cbuf = NGMallocAtomic(clen + 1);
+#endif
+      [v getCString:cbuf]; cbuf[clen] = '\0';
+      cstr = cbuf;
+      
+      for (i = 0, bufPtr = buffer; i < length; i++) {
+        switch (cstr[i]) {
+          case '&': /* &amp; */
+            bufPtr[0] = '&'; bufPtr[1] = 'a'; bufPtr[2] = 'm'; bufPtr[3] = 'p';
+            bufPtr[4] = ';';
+            bufPtr += 5;
+            break;
+            
+          case '<': /* &lt;   */
+            bufPtr[0] = '&'; bufPtr[1] = 'l'; bufPtr[2] = 't'; bufPtr[3] = ';';
+            bufPtr += 4;
+            break;
+            
+          case '>': /* &gt;   */
+            bufPtr[0] = '&'; bufPtr[1] = 'g'; bufPtr[2] = 't'; bufPtr[3] = ';';
+            bufPtr += 4;
+            break;
+            
+          case '"': /* &quot; */
+            bufPtr[0] = '&'; bufPtr[1] = 'q'; bufPtr[2] = 'u';
+            bufPtr[3] = 'o'; bufPtr[4] = 't'; bufPtr[5] = ';';
+            bufPtr += 6;
+            break;
+            
+          default:
+            *bufPtr = cstr[i];
+            bufPtr++;
+            break;
+        }
+      }
+#if NeXT_Foundation_LIBRARY
+      if (cbuf) free(cbuf);
+#else
+      if (cbuf) NGFree(cbuf);
+#endif
+      self->value = [[NSString allocWithZone:[self zone]]
+                               initWithCString:&(buffer[0])
+                               length:(bufPtr - &(buffer[0]))];
+    }
+    else {
+      self->value = [v copyWithZone:[self zone]];
+    }
+  }
+  return self;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    WOAssociation *avalue, *aescape;
+    BOOL doEscape;
+    
+    avalue  = OWGetProperty(_config, @"value");
+    aescape = OWGetProperty(_config, @"escapeHTML");
+    
+    doEscape = (aescape != nil) ? [aescape boolValueInComponent:nil] : YES;
+    self = [self initWithValue:avalue escapeHTML:doEscape];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->value release];
+  [super dealloc];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOResponse_AddString(_response, self->value);
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  return [NSString stringWithFormat:@" value='%@'", self->value];
+}
+
+@end /* WOSimpleStaticString */
+
+@implementation _WOSimpleStaticASCIIString
+
+- (id)initWithValue:(WOAssociation *)_value escapeHTML:(BOOL)_flag {
+  if ((self = [super initWithName:nil associations:nil template:nil])) {
+    // ENCODING, UNICODE
+    NSString *v;
+    unsigned length;
+    
+    v = [_value stringValueInComponent:nil];
+    length = [v cStringLength];
+    
+    if (length == 0) {
+      self->value = NULL;
+    }
+    else if (_flag) {
+      unsigned char *buffer;
+      register unsigned char *cbuf;
+      register unsigned char *bufPtr;
+      register unsigned      i;
+      unsigned clen;
+      BOOL didEscape = NO;
+      
+      clen = [v cStringLength];
+      cbuf = malloc(clen + 2);
+      [v getCString:cbuf]; cbuf[clen] = '\0';
+      
+      buffer = malloc(clen * 6 + 2); /* longest-encoding: '&quot;' */
+      
+      for (i = 0, bufPtr = buffer; i < length; i++) {
+        switch (cbuf[i]) {
+          case '&': /* &amp; */
+            bufPtr[0] = '&'; bufPtr[1] = 'a'; bufPtr[2] = 'm'; bufPtr[3] = 'p';
+            bufPtr[4] = ';';
+            bufPtr += 5;
+            didEscape = YES;
+            break;
+            
+          case '<': /* &lt;   */
+            bufPtr[0] = '&'; bufPtr[1] = 'l'; bufPtr[2] = 't'; bufPtr[3] = ';';
+            bufPtr += 4;
+            didEscape = YES;
+            break;
+            
+          case '>': /* &gt;   */
+            bufPtr[0] = '&'; bufPtr[1] = 'g'; bufPtr[2] = 't'; bufPtr[3] = ';';
+            bufPtr += 4;
+            didEscape = YES;
+            break;
+            
+          case '"': /* &quot; */
+            bufPtr[0] = '&'; bufPtr[1] = 'q'; bufPtr[2] = 'u';
+            bufPtr[3] = 'o'; bufPtr[4] = 't'; bufPtr[5] = ';';
+            bufPtr += 6;
+            didEscape = YES;
+            break;
+            
+          default:
+            if ((*bufPtr = cbuf[i]) > 127) {
+              NSLog(@"WARNING: string is not ASCII as required for "
+                    @"SimpleStaticASCIIString !!! '%@'", v);
+            }
+            bufPtr++;
+            break;
+        }
+      }
+      if (didEscape) {
+        if (cbuf) free(cbuf);
+        clen = (bufPtr - buffer);
+        self->value = malloc(clen + 2);
+        strncpy((char *)self->value, buffer, clen);
+        ((unsigned char *)self->value)[clen] = '\0';
+      }
+      else {
+        self->value = cbuf;
+      }
+      if (buffer) free(buffer);
+    }
+    else {
+      self->value = malloc(length + 2);
+      [v getCString:(char*)self->value];
+    }
+  }
+  return self;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    WOAssociation *avalue, *aescape;
+    BOOL doEscape;
+    
+    avalue  = OWGetProperty(_config, @"value");
+    aescape = OWGetProperty(_config, @"escapeHTML");
+    
+    doEscape = (aescape != nil) ? [aescape boolValueInComponent:nil] : YES;
+    self = [self initWithValue:avalue escapeHTML:doEscape];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (self->value) free((char *)self->value);
+  [super dealloc];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (self->value) WOResponse_AddCString(_response, self->value);
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  return [NSString stringWithFormat:@" value='%s'", 
+                     self->value ? self->value : (void*)""];
+}
+
+@end /* WOSimpleStaticASCIIString */
+
+@implementation _WOComplexString
+
+static NSNumber      *yesNum = nil;
+static WOAssociation *yesAssoc = nil;
+
++ (void)initialize {
+  if (yesNum   == nil) yesNum = [[NSNumber numberWithBool:YES] retain];
+  if (yesAssoc == nil) 
+    yesAssoc = [[WOAssociation associationWithValue:yesNum] retain];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->value          = OWGetProperty(_config, @"value");
+    self->escapeHTML     = OWGetProperty(_config, @"escapeHTML");
+    self->insertBR       = OWGetProperty(_config, @"insertBR");
+    self->nilString      = OWGetProperty(_config, @"nilString");
+    self->valueWhenEmpty = OWGetProperty(_config, @"valueWhenEmpty");
+    self->style          = OWGetProperty(_config, @"style");
+
+    if (self->nilString != nil && self->valueWhenEmpty != nil) {
+      [self logWithFormat:
+             @"WARNING: 'valueWhenEmpty' AND 'nilString' bindings are set, "
+             @"use only one! (nilString is deprecated!)"];
+    }
+    else if (self->nilString != nil) {
+      [self debugWithFormat:
+             @"Note: using deprecated 'nilString' binding, "
+             @"use 'valueWhenEmpty' instead."];
+    }
+    
+    self->formatter    = OWGetProperty(_config, @"formatter");
+    self->numberformat = OWGetProperty(_config, @"numberformat");
+    self->dateformat   = OWGetProperty(_config, @"dateformat");
+    
+    if (self->formatter == nil) {
+      if ([_config objectForKey:@"formatterClass"]) {
+        WOAssociation *assoc;
+        NSString      *className;
+        NSFormatter   *fmt = nil;
+        Class         clazz;
+        
+        assoc = [OWGetProperty(_config, @"formatterClass") autorelease];
+        if (![assoc isValueConstant])
+          [self logWithFormat:@"non-constant 'formatterClass' binding!"];
+        className = [assoc stringValueInComponent:nil];
+        clazz     = NSClassFromString(className);
+        
+        if ((assoc = [OWGetProperty(_config, @"format") autorelease])) {
+          NSString *format = nil;
+          
+          if (![assoc isValueConstant])
+            [self logWithFormat:@"non-constant 'format' binding!"];
+          format = [assoc stringValueInComponent:nil];
+          
+          if ([clazz instancesRespondToSelector:@selector(initWithString:)])
+            fmt = [[clazz alloc] initWithString:format];
+          else {
+            [self logWithFormat:
+                    @"cannot instantiate formatter with format: '%@'", format];
+            fmt = [[clazz alloc] init];
+          }
+        }
+        else
+          fmt = [[clazz alloc] init];
+        
+        self->formatter = [[WOAssociation associationWithValue:fmt] retain];
+        [fmt release];
+      }
+    }
+
+    if (self->escapeHTML == nil)
+      self->escapeHTML = [yesAssoc retain];
+    
+    /* check formats */
+    {
+      int num = 0;
+      if (self->formatter)    num++;
+      if (self->numberformat) num++;
+      if (self->dateformat)   num++;
+      if (num > 1)
+        NSLog(@"WARNING: more than one formats specified in element %@", self);
+    }
+  }
+  return self;
+}
+
+- (id)initWithValue:(WOAssociation *)_value escapeHTML:(BOOL)_flag {
+  if ((self = [super initWithName:nil associations:nil template:nil])) {
+    self->value      = [_value retain];
+    self->escapeHTML = _flag
+      ? yesAssoc
+      : [WOAssociation associationWithValue:[NSNumber numberWithBool:NO]];
+    self->escapeHTML = [self->escapeHTML retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->numberformat   release];
+  [self->dateformat     release];
+  [self->formatter      release];
+  [self->nilString      release];
+  [self->valueWhenEmpty release];
+  [self->value          release];
+  [self->escapeHTML     release];
+  [self->insertBR       release];
+  [self->style          release];
+  [super dealloc];
+}
+
+/* response generation */
+
+- (void)_appendStringLines:(NSString *)_s withSeparator:(NSString *)_br
+  contentSelector:(SEL)_sel
+  toResponse:(WOResponse *)_response inContext:(WOContext *)_ctx
+{
+  NSArray *lines;
+  unsigned i, count;
+  
+  lines = [_s componentsSeparatedByString:@"\n"];
+
+  for (i = 0, count = [lines count]; i < count; i++) {
+    NSString *line;
+
+    line = [lines objectAtIndex:i];
+    if (i != 0) WOResponse_AddString(_response, _br);
+    
+    [_response performSelector:_sel withObject:line];
+  }
+}
+
+- (NSFormatter *)_formatterInContext:(WOContext *)_ctx {
+  if (self->numberformat) {
+    NSNumberFormatter *fmt;
+
+    fmt = [[[NSNumberFormatter alloc] init] autorelease];
+    [fmt setFormat:[self->numberformat valueInComponent:[_ctx component]]];
+    return fmt;
+  }
+
+  if (self->dateformat) {
+    NSDateFormatter *fmt;
+    NSString *s;
+    
+    s = [self->dateformat valueInComponent:[_ctx component]];
+    fmt = [[NSDateFormatter alloc] initWithDateFormat:s
+                                  allowNaturalLanguage:NO];
+    return [fmt autorelease];
+  }
+  
+  if (self->formatter)
+    return [self->formatter valueInComponent:[_ctx component]];
+  
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent = [_ctx component];
+  NSFormatter *fmt;
+  id          obj    = nil;
+  SEL         addSel = NULL;
+  NSString    *styleName;
+
+  fmt = [self _formatterInContext:_ctx];
+#if DEBUG
+  if (fmt!=nil && ![fmt respondsToSelector:@selector(stringForObjectValue:)]) {
+    [sComponent logWithFormat:
+                  @"invalid formatter determined by keypath %@: %@",
+                  self->formatter, fmt];
+  }
+#endif
+  
+  obj    = [self->value valueInContext:_ctx];
+  addSel = [self->escapeHTML boolValueInComponent:sComponent]
+    ? @selector(appendContentHTMLString:)
+    : @selector(appendContentString:);
+
+  if (fmt) {
+    NSString *formattedObj;
+    
+    formattedObj = [fmt stringForObjectValue:obj];
+#if 0
+    if (formattedObj == nil) {
+      NSLog(@"WARNING: formatter %@ returned nil string for object %@",
+            fmt, obj);
+    }
+#endif
+    
+    obj = formattedObj;
+  }
+  
+  obj = [obj stringValue];
+
+  styleName = [self->style stringValueInContext:_ctx];
+
+  /* handling of empty and nil values */
+
+  if (self->valueWhenEmpty) {
+    if (obj == nil || [obj length] == 0) {
+      NSString *s;
+      
+      s = [self->valueWhenEmpty stringValueInComponent:sComponent];
+      
+      /* Note: the missing escaping is intentional for WO 4.5 compatibility */
+      if (s != nil) {
+        if (styleName) {
+          [_response appendContentString:@"<span class=\""];
+          [_response appendContentHTMLAttributeValue:styleName];
+          [_response appendContentString:@"\">"];
+        }
+        [_response appendContentString:s];
+      }
+      goto closeSpan;
+    }
+  }
+  else if (self->nilString != nil && obj == nil) {
+    NSString *s;
+
+    if (styleName) {
+      [_response appendContentString:@"<span class=\""];
+      [_response appendContentHTMLAttributeValue:styleName];
+      [_response appendContentString:@"\">"];
+    }
+    s = [self->nilString stringValueInComponent:sComponent];
+    [_response performSelector:addSel withObject:s];
+    goto closeSpan;
+  }
+  else if (obj == nil)
+    return;
+
+  /* handling of non-empty values */
+  
+  if (styleName) {
+    [_response appendContentString:@"<span class=\""];
+    [_response appendContentHTMLAttributeValue:styleName];
+    [_response appendContentString:@"\">"];
+  }
+
+  if (![self->insertBR boolValueInComponent:sComponent]) {
+    [_response performSelector:addSel withObject:obj];
+  }
+  else {
+    [self _appendStringLines:obj withSeparator:@"<br />"
+          contentSelector:addSel toResponse:_response inContext:_ctx];
+  }
+  
+closeSpan:
+  if (styleName) {
+    [_response appendContentString:@"</span>"];
+  }
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+  
+  str = [NSMutableString stringWithCapacity:64];
+  
+  if (self->value)      [str appendFormat:@" value=%@",      self->value];
+  if (self->escapeHTML) [str appendFormat:@" escape=%@",     self->escapeHTML];
+  if (self->insertBR)   [str appendFormat:@" insertBR=%@",   self->insertBR];
+  if (self->formatter)  [str appendFormat:@" formatter=%@",  self->formatter];
+  if (self->dateformat) [str appendFormat:@" dateformat=%@", self->dateformat];
+  if (self->numberformat)
+    [str appendFormat:@" numberformat=%@", self->numberformat];
+
+  if (self->valueWhenEmpty) 
+    [str appendFormat:@" valueWhenEmpty=%@", self->valueWhenEmpty];
+  if (self->style) 
+      [str appendFormat:@" style=%@", self->style];
+  
+  return str;
+}
+
+@end /* _WOComplexString */
+
+@implementation _WOTemporaryString
+
+static Class ComplexStringClass     = Nil;
+static Class SimpleStringClass      = Nil;
+static Class SimpleASCIIStringClass = Nil;
+static Class SimpleDynStringClass   = Nil;
+
+#define ENSURE_CACHE \
+  if (ComplexStringClass == Nil)\
+    ComplexStringClass = [_WOComplexString class];\
+  if (SimpleStringClass == Nil)\
+    SimpleStringClass = [_WOSimpleStaticString class];\
+  if (SimpleASCIIStringClass == Nil)\
+    SimpleASCIIStringClass = [_WOSimpleStaticASCIIString class];\
+  if (SimpleDynStringClass == Nil)\
+    SimpleDynStringClass = [_WOSimpleDynamicString class];
+
+static inline Class _classForConfig(NSDictionary *_config) {
+  Class         sClass = Nil;
+  WOAssociation *assoc, *assoc2;
+  unsigned      c;
+  
+  switch ((c = [_config count])) {
+    case 0:
+      sClass = SimpleStringClass;
+      break;
+      
+    case 1:
+      if ((assoc = [_config objectForKey:@"value"])) {
+        if ([assoc isValueConstant])
+          sClass = SimpleStringClass;
+        else
+          sClass = SimpleDynStringClass;
+        break;
+      }
+      if ((assoc = [_config objectForKey:@"escapeHTML"])) {
+        if ([assoc isValueConstant])
+          sClass = SimpleStringClass;
+        break;
+      }
+      break;
+      
+    case 2:
+      if ((assoc = [_config objectForKey:@"value"])) {
+        if ((assoc2 = [_config objectForKey:@"escapeHTML"])) {
+          if ([assoc isValueConstant] && [assoc2 isValueConstant])
+            sClass = SimpleStringClass;
+
+          break;
+        }
+      }
+      break;
+      
+    default:
+      sClass = ComplexStringClass;
+      break;
+  }
+  
+  return sClass ? sClass : ComplexStringClass;
+}
+
+- (id)initWithName:(NSString *)_n
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  Class stringClass;
+  ENSURE_CACHE;
+
+#if DEBUG
+  if (_t != nil) {
+    NSLog(@"WARNING: WOString '%@' has contents !", _n);
+    abort();
+  }
+#endif
+
+  stringClass = _classForConfig(_config);
+  
+  return [[stringClass alloc]
+                       initWithName:_n associations:_config template:nil];
+}
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  contentElements:(NSArray *)_contents
+{
+  Class stringClass;
+  ENSURE_CACHE;
+
+#if DEBUG
+  if ([_contents count] > 0) {
+    NSLog(@"WARNING: WOString has contents !");
+    abort();
+  }
+#endif
+  
+  stringClass = _classForConfig(_associations);
+  
+  return [[stringClass alloc]
+                       initWithName:_name
+                       associations:_associations
+                       contentElements:nil];
+}
+
+- (id)initWithValue:(WOAssociation *)_value escapeHTML:(BOOL)_flag {
+  Class stringClass;
+  ENSURE_CACHE;
+  
+  if ((_value == nil) || [_value isValueConstant])
+    stringClass = SimpleStringClass;
+  else
+    stringClass = ComplexStringClass;
+    
+  return [[stringClass alloc] initWithValue:_value escapeHTML:_flag];
+}
+
+- (void)dealloc {
+  NSLog(@"ERROR: called dealloc on %@", self);
+#if DEBUG
+  abort();
+#endif
+  return;
+}
+
+@end /* _WOTemporaryString */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOSubmitButton.m b/skyrix-sope/NGObjWeb/DynamicElements/WOSubmitButton.m
new file mode 100644 (file)
index 0000000..4e9950e
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOInput.h"
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@interface WOSubmitButton : WOInput
+{
+  // WOInput: name
+  // WOInput: value
+  // WOInput: disabled
+@protected
+  WOAssociation *action;
+  WOAssociation *pageName;
+
+  // new in WO4:
+  WOAssociation *queryDictionary;
+  NSDictionary  *queryParameters;  // associations beginning with ?
+  WOAssociation *actionClass;
+  WOAssociation *directActionName;
+  BOOL          sidInUrl;
+}
+
+@end /* WOSubmitButton */
+
+@implementation WOSubmitButton
+
++ (int)version {
+  return 2;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    WOAssociation *sidInUrlAssoc;
+
+    sidInUrlAssoc  = OWGetProperty(_config, @"?wosid");
+    self->action   = OWGetProperty(_config, @"action");
+    self->pageName = OWGetProperty(_config, @"pageName");
+
+    self->queryDictionary    = OWGetProperty(_config, @"queryDictionary");
+    self->queryParameters    = OWExtractQueryParameters(_config);
+    self->actionClass        = OWGetProperty(_config, @"actionClass");
+    self->directActionName   = OWGetProperty(_config, @"directActionName");
+    
+    self->sidInUrl = (sidInUrlAssoc)
+      ? [sidInUrlAssoc boolValueInComponent:nil]
+      : YES;
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->actionClass);
+  RELEASE(self->directActionName);
+  RELEASE(self->queryDictionary);
+  RELEASE(self->queryParameters);
+  RELEASE(self->action);
+  RELEASE(self->pageName);
+  [super dealloc];
+}
+#endif
+
+// responder
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  id formValue;
+  
+  if (self->disabled) {
+    if ([self->disabled boolValueInComponent:[_ctx component]])
+      return;
+  }
+  
+  if ((formValue = [_request formValueForKey:OWFormElementName(self, _ctx)])) {
+    //NSLog(@"%@: value=%@ ..", [self elementID], formValue);
+    
+    if ([self->value isValueSettable]) {
+      [self->value setStringValue:formValue
+           inComponent:[_ctx component]];
+    }
+    if ((self->action != nil) || (self->pageName != nil))
+      [_ctx addActiveFormElement:self];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  if (self->disabled) {
+    if ([self->disabled boolValueInComponent:[_ctx component]])
+      return nil;
+  }
+  
+  /* check whether this is the active form element (determined in take-values) */
+  if (![[_ctx elementID] isEqualToString:[_ctx senderID]]) {
+    NSLog(@"SUBMITBUTTON is not active (%@ vs %@) !",
+          [_ctx elementID], [_ctx senderID]);
+    return nil;
+  }
+  
+  if (self->action)
+    return [self executeAction:self->action inContext:_ctx];
+
+  if (self->pageName) {
+    NSString    *pname = nil;
+    WOComponent *page = nil;
+
+    pname = [self->pageName stringValueInComponent:[_ctx component]];
+    page = [[_ctx application] pageWithName:pname inContext:_ctx];
+
+    if (page == nil) {
+      [[_ctx session] logWithFormat:
+                      @"%@[0x%08X]: did not find page with name %@ !",
+                      NSStringFromClass([self class]), self, pname];
+    }
+    NSLog(@"%@: showing page %@", self, page);
+    return page;
+  }
+
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *v = [self->value stringValueInComponent:[_ctx component]];
+
+  WOResponse_AddCString(_response, "<input type=\"submit\" name=\"");
+  [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+  WOResponse_AddCString(_response, "\" value=\"");
+  [_response appendContentHTMLAttributeValue:v];
+  WOResponse_AddChar(_response, '"');
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  WOResponse_AddCString(_response, " />");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:128];
+  [str appendString:[super associationDescription]];
+  if (self->action)   [str appendFormat:@" action=%@", self->action];
+  if (self->pageName) [str appendFormat:@" page=%@",   self->pageName];
+
+  if (self->actionClass)
+    [str appendFormat:@" actionClass=%@", self->actionClass];
+  if (self->directActionName)
+    [str appendFormat:@" directAction=%@", self->directActionName];
+  return str;
+}
+
+@end /* WOSubmitButton */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOSwitchComponent.m b/skyrix-sope/NGObjWeb/DynamicElements/WOSwitchComponent.m
new file mode 100644 (file)
index 0000000..bc27986
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOHTMLDynamicElement.h"
+
+@class NSDictionary;
+@class WOAssociation;
+
+@interface WOSwitchComponent : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *componentName; // WOComponentName attribute
+  NSDictionary  *bindings;
+  WOElement     *template;
+}
+
+@end
+
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOAssociation.h>
+#include <NGObjWeb/WOContext.h>
+#import "WOElement+private.h"
+#import "WOContext+private.h"
+#import "WOComponent+private.h"
+#include "common.h"
+
+@implementation WOSwitchComponent
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->containsForm  = YES;
+    self->componentName = OWGetProperty(_config, @"WOComponentName");
+    self->bindings      = [_config copyWithZone:[self zone]];
+    [(NSMutableDictionary *)_config removeAllObjects];
+
+    self->template = RETAIN(_c);
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->template);
+  RELEASE(self->componentName);
+  RELEASE(self->bindings);
+  [super dealloc];
+}
+#endif
+
+- (WOComponent *)lookupComponent:(NSString *)cname inContext:(WOContext *)_ctx {
+  WOComponent *component;
+  
+  if (cname == nil)
+    return nil;
+
+  if ((component = [[_ctx component] pageWithName:cname]) == nil) {
+    [[_ctx component] debugWithFormat:@"couldn't find component '%@'", cname];
+    return nil;
+  }
+  
+  [component setParent:[_ctx component]];
+  [component setBindings:self->bindings];
+  
+  return component;
+}
+
+// responder
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *c;
+  NSString    *cname;
+  
+  cname = [self->componentName stringValueInComponent:[_ctx component]];
+  
+  if ((c = [self lookupComponent:cname inContext:_ctx]) == nil)
+    return;
+  
+  [_ctx appendElementIDComponent:cname];
+  [_ctx enterComponent:c content:self->template];
+  [c takeValuesFromRequest:_req inContext:_ctx];
+  [_ctx leaveComponent:c];
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *c;
+  id       result;
+  NSString *cname, *reqname;
+
+  if ((reqname = [_ctx currentElementID]) == nil)
+    /* missing id in request */
+    return nil;
+  
+  cname = [self->componentName stringValueInComponent:[_ctx component]];
+
+  if (![cname isEqualToString:reqname]) {
+    /* component mismatch */
+    [[_ctx component] logWithFormat:
+                        @"WOSwitchComponent: component name mismatch (%@ vs %@),"
+                        @"ignoring action.",
+                        cname, reqname];
+    return nil;
+  }
+  
+  if ((c = [self lookupComponent:cname inContext:_ctx]) == nil)
+    return nil;
+
+  [_ctx appendElementIDComponent:cname];
+  [_ctx enterComponent:c content:self->template];
+  result = [c invokeActionForRequest:_req inContext:_ctx];
+  [_ctx leaveComponent:c];
+  [_ctx deleteLastElementIDComponent];
+  
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *c;
+  NSString    *cname;
+  
+  cname = [self->componentName stringValueInComponent:[_ctx component]];
+  
+  if ((c = [self lookupComponent:cname inContext:_ctx]) == nil)
+    return;
+  
+  [_ctx appendElementIDComponent:cname];
+  [_ctx enterComponent:c content:self->template];
+  [c appendToResponse:_response inContext:_ctx];
+  [_ctx leaveComponent:c];
+  [_ctx deleteLastElementIDComponent];
+}
+
+@end /* WOSwitchComponent */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOText.m b/skyrix-sope/NGObjWeb/DynamicElements/WOText.m
new file mode 100644 (file)
index 0000000..ba34595
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOInput.h"
+#include "common.h"
+#import <Foundation/NSNumberFormatter.h>
+#import <Foundation/NSDateFormatter.h>
+
+@interface WOText : WOInput
+{
+  // inherited: name
+  // inherited: value
+  // inherited: disabled
+@protected
+  // non WO:
+  WOAssociation *rows;
+  WOAssociation *cols;
+  WOAssociation *numberformat; // string
+  WOAssociation *dateformat;   // string
+  WOAssociation *formatter;
+}
+
+@end /* WOText */
+
+@interface NSObject(UsedKeyPath)
+- (NSString *)keyPath;
+@end
+
+@implementation WOText
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_root {
+
+  if ((self = [super initWithName:_name associations:_config template:_root])) {
+    self->rows         = OWGetProperty(_config, @"rows");
+    self->cols         = OWGetProperty(_config, @"cols");
+    self->formatter    = OWGetProperty(_config, @"formatter");
+    self->numberformat = OWGetProperty(_config, @"numberformat");
+    self->dateformat   = OWGetProperty(_config, @"dateformat");
+
+    if (self->formatter == nil) {
+      if ([_config objectForKey:@"formatterClass"]) {
+        id className;
+
+        className = OWGetProperty(_config, @"formatterClass");
+        className = [className autorelease];
+        
+        className = [className valueInComponent:nil];
+        className = NSClassFromString(className);
+        className = [[className alloc] init];
+
+        self->formatter = [WOAssociation associationWithValue:className];
+        self->formatter = [self->formatter retain];
+        [className release];
+      }
+    }
+
+    // check formats
+    {
+      int num = 0;
+      if (self->formatter)    num++;
+      if (self->numberformat) num++;
+      if (self->dateformat)   num++;
+      if (num > 1)
+        NSLog(@"WARNING: more than one formats specified in element %@", self);
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->numberformat release];
+  [self->dateformat   release];
+  [self->formatter    release];
+  [self->rows         release];
+  [self->cols         release];
+  [super dealloc];
+}
+
+/* formatter */
+
+static inline NSFormatter *_getFormatter(WOText *self, WOContext *_ctx) {
+  NSFormatter *fmt   = nil;
+  
+  if (self->numberformat) {
+    fmt = [[[NSNumberFormatter alloc] init] autorelease];
+    [(NSNumberFormatter *)fmt setFormat:
+        [self->numberformat valueInComponent:[_ctx component]]];
+  }
+  else if (self->dateformat) {
+    fmt = [[NSDateFormatter alloc]
+                            initWithDateFormat:
+                              [self->dateformat valueInComponent:
+                                                  [_ctx component]]
+                            allowNaturalLanguage:NO];
+    fmt = [fmt autorelease];
+  }
+  else if (self->formatter) {
+    fmt = [self->formatter valueInComponent:[_ctx component]];
+  }
+
+  return fmt;
+}
+
+// ******************** responder ********************
+
+- (id)parseFormValue:(id)_value inContext:(WOContext *)_ctx {
+  NSFormatter *fmt = nil;
+
+  fmt = _getFormatter(self, _ctx);
+  
+  if (fmt) {
+    NSString *errorText = nil;
+    id       object     = nil;
+
+    //fmt = [self->formatter valueInComponent:[_ctx component]];
+
+    if ([fmt getObjectValue:&object forString:[_value stringValue]
+             errorDescription:&errorText]) {
+
+      return object;
+    }
+    else {
+      NSException *formatException = nil;
+      NSString    *keyPath         = nil;
+      
+      if ([self->value respondsToSelector:@selector(keyPath)])
+        keyPath = [(id)self->value keyPath];
+
+      formatException = [NSException exceptionWithName:@"WOValidationException"
+                                     reason:errorText
+                                     userInfo:nil];
+
+      [[_ctx component] validationFailedWithException:formatException
+                        value:_value
+                        keyPath:keyPath];
+      return nil;
+    }
+  }
+  else
+    return [super parseFormValue:_value inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSFormatter *fmt;
+  id          v;
+  unsigned    r;
+  unsigned    c;
+  
+  sComponent = [_ctx component];
+  v  = [self->value valueInComponent:sComponent];
+  r  = [self->rows  unsignedIntValueInComponent:sComponent];
+  c  = [self->cols  unsignedIntValueInComponent:sComponent];
+  
+  fmt = _getFormatter(self, _ctx);
+  if (fmt) {
+    NSString *formattedObj = nil;
+
+    formattedObj = [fmt editingStringForObjectValue:v];
+    v = formattedObj;
+  }
+  else
+    v = [v stringValue];
+  
+  WOResponse_AddCString(_response, "<textarea name=\"");
+  [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+  WOResponse_AddChar(_response, '"');
+  if (r > 0) {
+    WOResponse_AddCString(_response, " rows=\"");
+    WOResponse_AddUInt(_response, r);
+    WOResponse_AddChar(_response, '"');
+  }
+  if (c > 0) {
+    WOResponse_AddCString(_response, " cols=\"");
+    WOResponse_AddUInt(_response, c);
+    WOResponse_AddChar(_response, '"');
+  }
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  WOResponse_AddChar(_response, '>');
+
+  if ([v length] > 0) {
+    BOOL     removeCR = NO;
+    NSString *ua;
+    
+    ua = [[_ctx request] headerForKey:@"user-agent"];
+    
+    if ([ua rangeOfString:@"Opera"].length > 0)
+      removeCR = YES;
+    
+    if (removeCR)
+      v = [v stringByReplacingString:@"\r" withString:@""];
+    
+    [_response appendContentHTMLString:v];
+  }
+  
+  WOResponse_AddCString(_response, "</textarea>");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = nil;
+  
+  str = [NSMutableString stringWithCapacity:64];
+  [str appendString:[super associationDescription]];
+  
+  if (self->rows) [str appendFormat:@" rows=%@", self->rows];
+  if (self->cols) [str appendFormat:@" cols=%@", self->cols];
+  if (self->formatter)  [str appendFormat:@" formatter=%@", self->formatter];
+  if (self->dateformat) [str appendFormat:@" dateformat=%@", self->dateformat];
+  if (self->numberformat)
+    [str appendFormat:@" numberformat=%@", self->numberformat];
+
+  return str;
+}
+
+@end /* WOText */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOTextField.m b/skyrix-sope/NGObjWeb/DynamicElements/WOTextField.m
new file mode 100644 (file)
index 0000000..96c9447
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOInput.h"
+#include "common.h"
+#import <Foundation/NSNumberFormatter.h>
+#import <Foundation/NSDateFormatter.h>
+
+/*
+  Usage:
+
+    PhoneNumber: WOTextField {
+      size               = 30;
+      formatter          = session.phoneNumberFormatter;
+      formatErrorString  = errorString;
+      formatFailedAction = "handleFormattingError";
+    };
+
+  The textfield calls the -validationFailed:.. method of the associated
+  component if a formatter could not format a value.
+*/
+
+@interface WOTextField : WOInput
+{
+  // inherited: name
+  // inherited: value
+  // inherited: disabled
+@protected
+  WOAssociation *numberformat; // string
+  WOAssociation *dateformat;   // string
+  WOAssociation *formatter;    // WO4
+  
+  // non WO:
+  WOAssociation *size;
+}
+
+@end /* WOTextField */
+
+@interface NSObject(UsedKeyPath)
+- (NSString *)keyPath;
+@end
+
+@implementation WOTextField
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_root
+{
+  if ((self = [super initWithName:_name associations:_config template:_root])) {
+    self->size         = OWGetProperty(_config, @"size");
+    self->formatter    = OWGetProperty(_config, @"formatter");
+    self->numberformat = OWGetProperty(_config, @"numberformat");
+    self->dateformat   = OWGetProperty(_config, @"dateformat");
+
+    if (self->formatter == nil) {
+      if ([_config objectForKey:@"formatterClass"]) {
+        id className;
+
+        className = OWGetProperty(_config, @"formatterClass");
+        className = AUTORELEASE(className);
+
+        className = [className valueInComponent:nil];
+        className = NSClassFromString(className);
+        className = [[className alloc] init];
+
+        self->formatter = [WOAssociation associationWithValue:className];
+        self->formatter = RETAIN(self->formatter);
+        RELEASE(className);
+      }
+    }
+
+    // check formats
+    {
+      int num = 0;
+      if (self->formatter)    num++;
+      if (self->numberformat) num++;
+      if (self->dateformat)   num++;
+      if (num > 1)
+        NSLog(@"WARNING: more than one formats specified in element %@", self);
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->numberformat release];
+  [self->dateformat   release];
+  [self->formatter    release];
+  [self->size         release];
+  [super dealloc];
+}
+
+/* formatter */
+
+static inline NSFormatter *_getFormatter(WOTextField *self, WOContext *_ctx) {
+  NSFormatter *fmt   = nil;
+  
+  if (self->numberformat) {
+    fmt = [[[NSNumberFormatter alloc] init] autorelease];
+    [(NSNumberFormatter *)fmt setFormat:
+        [self->numberformat valueInComponent:[_ctx component]]];
+  }
+  else if (self->dateformat) {
+    fmt = [[NSDateFormatter alloc]
+                            initWithDateFormat:
+                              [self->dateformat valueInComponent:
+                                                  [_ctx component]]
+                            allowNaturalLanguage:NO];
+    fmt = [fmt autorelease];
+  }
+  else if (self->formatter) {
+    fmt = [self->formatter valueInComponent:[_ctx component]];
+  }
+
+  return fmt;
+}
+
+// ******************** responder ********************
+
+- (id)parseFormValue:(id)_value inContext:(WOContext *)_ctx {
+  NSFormatter *fmt = nil;
+
+  fmt = _getFormatter(self, _ctx);
+  
+  if (fmt) {
+    NSString    *errorText = nil;
+    id          object     = nil;
+
+    //fmt = [self->formatter valueInComponent:[_ctx component]];
+
+    if ([fmt getObjectValue:&object forString:[_value stringValue]
+             errorDescription:&errorText]) {
+
+      return object;
+    }
+    else {
+      NSException *formatException = nil;
+      NSString    *keyPath         = nil;
+      
+      if ([self->value respondsToSelector:@selector(keyPath)])
+        keyPath = [(id)self->value keyPath];
+
+      formatException = [NSException exceptionWithName:@"WOValidationException"
+                                     reason:errorText
+                                     userInfo:nil];
+
+      [[_ctx component] validationFailedWithException:formatException
+                        value:_value
+                        keyPath:keyPath];
+      return nil;
+    }
+  }
+  else
+    return [super parseFormValue:_value inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSFormatter *fmt = nil;
+  id       obj = nil;
+  unsigned s   = 0;
+
+  obj = [self->value valueInComponent:[_ctx component]];
+  s   = [self->size  unsignedIntValueInComponent:[_ctx component]];
+
+  fmt = _getFormatter(self, _ctx);
+  if (fmt) {
+    NSString *formattedObj = nil;
+
+    formattedObj = [fmt editingStringForObjectValue:obj];
+
+#if 0
+    if (formattedObj == nil) {
+      NSLog(@"WARNING: formatter %@ returned nil string for object %@",
+            fmt, obj);
+    }
+#endif
+    obj = formattedObj;
+  }
+  
+  WOResponse_AddCString(_response, "<input type=\"text\" name=\"");
+  [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+  WOResponse_AddCString(_response, "\" value=\"");
+  [_response appendContentHTMLAttributeValue:[obj stringValue]];
+  WOResponse_AddChar(_response, '"');
+  if (s > 0) {
+    WOResponse_AddCString(_response, " size=\"");
+    WOResponse_AddUInt(_response, s);
+    WOResponse_AddChar(_response, '"');
+  }
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  WOResponse_AddCString(_response, " />");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+  
+  str = [NSMutableString stringWithCapacity:128];
+  [str appendString:[super associationDescription]];
+
+  if (self->size)       [str appendFormat:@" size=%@",      self->size];
+  if (self->formatter)  [str appendFormat:@" formatter=%@", self->formatter];
+  if (self->dateformat) [str appendFormat:@" dateformat=%@", self->dateformat];
+  if (self->numberformat)
+    [str appendFormat:@" numberformat=%@", self->numberformat];
+
+  return str;
+}
+
+@end /* WOTextField */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOVBScript.m b/skyrix-sope/NGObjWeb/DynamicElements/WOVBScript.m
new file mode 100644 (file)
index 0000000..715cae1
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOHTMLDynamicElement.h"
+#include "WOElement+private.h"
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@interface WOVBScript : WOHTMLDynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *scriptFile;
+  WOAssociation *scriptString;
+  WOAssociation *scriptSource;
+  WOAssociation *hideInComment;
+}
+
+@end /* WOVBScript */
+
+@implementation WOVBScript
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmpl
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmpl])) {
+    self->scriptFile    = OWGetProperty(_config, @"scriptFile");
+    self->scriptString  = OWGetProperty(_config, @"scriptString");
+    self->scriptSource  = OWGetProperty(_config, @"scriptSource");
+    self->hideInComment = OWGetProperty(_config, @"hideInComment");
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->scriptFile);
+  RELEASE(self->scriptString);
+  RELEASE(self->scriptSource);
+  RELEASE(self->hideInComment);
+  [super dealloc];
+}
+#endif
+
+// ******************** responder ********************
+
+#define StrVal(__x__) [self->__x__ stringValueInComponent:sComponent]
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![[_ctx request] isFromClientComponent]) {
+    WOComponent *sComponent = [_ctx component];
+    BOOL hide = [self->hideInComment boolValueInComponent:sComponent];
+    
+    WOResponse_AddCString(_response, "<script language=\"VBScript\" ");
+
+    /* add URL to script */
+    if (self->scriptSource) {
+      WOResponse_AddCString(_response, " src=\"");
+      [_response appendContentHTMLAttributeValue:
+                   [self->scriptSource stringValueInComponent:sComponent]];
+      WOResponse_AddCString(_response, "\"");
+    }
+    
+    if (self->otherTagString) {
+      WOResponse_AddString(_response,
+                           [self->otherTagString stringValueInComponent:
+                                                   [_ctx component]]);
+    }
+    WOResponse_AddChar(_response, '>');
+    if (hide) WOResponse_AddCString(_response, "<!--hide from older browsers");
+
+    /* add a script string */
+    if (self->scriptString) {
+      NSString *s = [self->scriptString stringValueInComponent:sComponent];
+
+      if (s) WOResponse_AddString(_response, s);
+    }
+
+    /* add a script file */
+    if (self->scriptFile) {
+      NSString *s;
+
+      s = [NSString stringWithContentsOfFile:
+                      [self->scriptFile stringValueInComponent:sComponent]];
+      if (s) WOResponse_AddString(_response, s);
+    }
+    
+    if (hide) WOResponse_AddCString(_response, "//hide from older browsers-->");
+    WOResponse_AddCString(_response, "</script>");
+  }
+}
+
+// description
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [[NSMutableString alloc] init];
+
+  if (self->scriptFile)    [str appendFormat:@" file=%@",   self->scriptFile];
+  if (self->scriptString)  [str appendFormat:@" string=%@", self->scriptString];
+  if (self->scriptSource)  [str appendFormat:@" source=%@", self->scriptSource];
+  if (self->hideInComment)
+    [str appendFormat:@" hide=%@",   self->hideInComment];
+  
+  return AUTORELEASE(str);
+}
+
+@end /* WOVBScript */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOxControlElemBuilder.m b/skyrix-sope/NGObjWeb/DynamicElements/WOxControlElemBuilder.m
new file mode 100644 (file)
index 0000000..cbb5de3
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <NGObjWeb/WOxElemBuilder.h>
+
+/*
+  This builder builds control flow elements, eg conditionals and
+  repetitions.
+
+  Supported tags:
+    <var:if .../>      maps to WOConditional
+    <var:foreach .../> maps to WORepetition
+    <var:with .../>    maps to WOSetCursor
+*/
+
+@interface WOxControlElemBuilder : WOxTagClassElemBuilder
+{
+}
+
+@end
+
+#include <SaxObjC/XMLNamespaces.h>
+#include "common.h"
+
+@implementation WOxControlElemBuilder
+
+- (Class)classForElement:(id<DOMElement>)_element {
+  NSString *nsuri;
+  NSString *tag;
+  
+  if (_element == nil) return nil;
+  
+  nsuri = [_element namespaceURI];
+  if (![nsuri isEqualToString:XMLNS_OD_BIND])
+    return Nil;
+  
+  tag = [_element tagName];
+  
+  if ([tag isEqualToString:@"if"]) {
+    static Class clazz = Nil;
+    if (clazz == Nil)
+      clazz = NSClassFromString(@"WOConditional");
+    return clazz;
+  }
+  if ([tag isEqualToString:@"foreach"] || [tag isEqualToString:@"for-each"]) {
+    static Class clazz = Nil;
+    if (clazz == Nil)
+      clazz = NSClassFromString(@"WORepetition");
+    return clazz;
+  }
+  if ([tag isEqualToString:@"with"]) {
+    static Class clazz = Nil;
+    if (clazz == Nil)
+      clazz = NSClassFromString(@"WOSetCursor");
+    return clazz;
+  }
+  
+  return Nil;
+}
+
+@end /* SxControlElemBuilder */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOxHTMLElemBuilder.m b/skyrix-sope/NGObjWeb/DynamicElements/WOxHTMLElemBuilder.m
new file mode 100644 (file)
index 0000000..914d2ba
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <NGObjWeb/WOxElemBuilder.h>
+
+/*
+  This builder builds all standard elements which are defined in the XHTML
+  or HTML 4 namespace.
+
+  Supported tags:
+    - all other tags are represented using either WOGenericElement or
+      WOGenericContainer, so this builder is "final destination" for
+      all HTML related tags.
+  
+    <input> - the "type" attribute of the input must be static and further
+              specifies the generated element
+      type="submit"   maps to WOSubmitButton
+      type="reset"    maps to WOResetButton
+      type="image"    maps to WOImageButton
+      type="radio"    maps to WORadioButton
+      type="checkbox" maps to WOCheckBox
+      type="file"     maps to WOFileUpload
+      type="hidden"   maps to WOHiddenField
+      type="password" maps to WOPasswordField
+      all other       map  to WOTextField
+    <a>..</a>         maps to WOHyperlink
+    <img .../>        maps to WOImage
+    <form .../>              maps to WOForm
+    <textarea .../>   maps to WOText
+    <embed .../>      maps to WOEmbeddedObject
+    <frame .../>      maps to WOFrame
+    <iframe .../>     maps to WOIFrame
+    <body .../>       maps to WOBody
+    <entity .../>     maps to WOEntity
+*/
+
+@interface WOxHTMLElemBuilder : WOxTagClassElemBuilder
+{
+}
+
+@end
+
+#include "common.h"
+#include <SaxObjC/XMLNamespaces.h>
+
+@implementation WOxHTMLElemBuilder
+
+- (Class)classForInputElement:(id<DOMElement>)_element {
+  NSString *type;
+  unsigned tl;
+  unichar c1;
+  
+  type = [_element attribute:@"type" namespaceURI:XMLNS_XHTML];
+  tl = [type length];
+
+  if (tl == 0)
+    return NSClassFromString(@"WOTextField");
+  else if (tl > 0)
+    c1 = [type characterAtIndex:0];
+  
+  switch (tl) {
+    case 0:
+
+    case 4:
+      if (c1 == 't') {
+        if ([type isEqualToString:@"text"])
+          return NSClassFromString(@"WOTextField");
+      }
+      else if (c1 == 'f') {
+        if ([type isEqualToString:@"file"])
+          return NSClassFromString(@"WOFileUpload");
+      }
+      break;
+      
+    case 5:
+      if (c1 == 'i' && [type isEqualToString:@"image"])
+        return NSClassFromString(@"WOImageButton");
+      else if (c1 == 'r') {
+        if ([type isEqualToString:@"radio"])
+          return NSClassFromString(@"WORadioButton");
+        if ([type isEqualToString:@"reset"])
+          return NSClassFromString(@"WOResetButton");
+      }
+      break;
+      
+    case 6:
+      if (c1 == 's' && [type isEqualToString:@"submit"])
+        return NSClassFromString(@"WOSubmitButton");
+      else if (c1 == 'h' && [type isEqualToString:@"hidden"])
+        return NSClassFromString(@"WOHiddenField");
+      break;
+
+    case 8:
+      if (c1 == 'c' && [type isEqualToString:@"checkbox"])
+        return NSClassFromString(@"WOCheckBox");
+      else if (c1 == 'p' && [type isEqualToString:@"password"])
+        return NSClassFromString(@"WOPasswordField");
+      
+    default:
+      break;
+  }
+  
+  [self logWithFormat:@"WARNING: unknown input type '%@' !", type];
+  return NSClassFromString(@"WOTextField");
+}
+
+- (Class)classForElement:(id<DOMElement>)_element {
+  NSString *nsuri;
+  NSString *tag;
+  unsigned tl;
+
+  if ((nsuri = [_element namespaceURI]) == nil)
+    return Nil;
+  
+  if (![nsuri isEqualToString:XMLNS_XHTML]) {
+    /* check HTML 4 namespace */
+    if (![nsuri isEqualToString:XMLNS_HTML40])
+      return Nil;
+  }
+  
+  tag = [_element tagName];
+  
+  if ((tl = [tag length]) == 0)
+    return Nil;
+  
+  switch (tl) {
+    case 1:
+        if ([tag isEqualToString:@"a"]) {
+            if ([_element hasAttribute:@"name" namespaceURI:@"*"])
+              return NSClassFromString(@"WOGenericContainer");
+            
+            return NSClassFromString(@"WOHyperlink");
+        }
+      break;
+
+    case 3:
+      if ([tag isEqualToString:@"img"])
+        return NSClassFromString(@"WOImage");
+      break;
+
+    case 4:
+      if ([tag isEqualToString:@"body"])
+        return NSClassFromString(@"WOBody");
+#if 0
+      if ([tag isEqualToString:@"html"])
+        return NSClassFromString(@"WOHtml");
+#endif
+      if ([tag isEqualToString:@"form"])
+        return NSClassFromString(@"WOForm");
+
+      if ([tag isEqualToString:@"meta"]) {
+       NSString *val;
+       
+        val = [_element attribute:@"http-equiv" namespaceURI:XMLNS_XHTML];
+       if (val) {
+         val = [[val stringValue] lowercaseString];
+         if ([val hasPrefix:@"refresh"])
+           return NSClassFromString(@"WOMetaRefresh");
+       }
+      }
+      break;
+      
+    case 5:
+      if ([tag isEqualToString:@"input"])
+        return [self classForInputElement:_element];
+      if ([tag isEqualToString:@"frame"])
+        return NSClassFromString(@"WOFrame");
+      if ([tag isEqualToString:@"embed"])
+        return NSClassFromString(@"WOEmbeddedObject");
+      break;
+      
+    default:
+      if ([tag isEqualToString:@"textarea"])
+        return NSClassFromString(@"WOText");
+      if ([tag isEqualToString:@"iframe"])
+        return NSClassFromString(@"WOIFrame");
+      
+      if ([tag isEqualToString:@"entity"])
+        return NSClassFromString(@"WOEntity");
+      break;
+  }
+
+  if ([_element hasChildNodes])
+    return NSClassFromString(@"WOGenericContainer");
+  else
+    return NSClassFromString(@"WOGenericElement");
+}
+
+@end /* WOxHTMLElemBuilder */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOxMiscElemBuilder.m b/skyrix-sope/NGObjWeb/DynamicElements/WOxMiscElemBuilder.m
new file mode 100644 (file)
index 0000000..54b4998
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOxElemBuilder.h>
+
+// TODO: multiselection should set the "multiple" binding?
+
+/*
+  This builder builds control flow elements, eg conditionals and
+  repetitions.
+  
+  Supported tags:
+    <var:string .../>              maps to WOString
+    <var:component-content/>       maps to WOComponentContent
+    <var:entity .../>              maps to WOEntity
+    <var:nbsp .../>                maps to WOEntity
+    <var:popup ../>                maps to WOPopUpButton
+    <var:singleselection ../>      maps to WOBrowser
+    <var:multiselection .../>      maps to WOBrowser
+    <var:radio-button-matrix .../> maps to WORadioButtonMatrix
+    <var:checkbox-list .../>       maps to WOCheckBoxList
+*/
+
+@interface WOxMiscElemBuilder : WOxTagClassElemBuilder
+{
+}
+
+@end
+
+#include <SaxObjC/XMLNamespaces.h>
+#include "common.h"
+
+@implementation WOxMiscElemBuilder
+
+- (Class)classForElement:(id<DOMElement>)_element {
+  NSString *nsuri;
+  NSString *tag;
+  unsigned tl;
+
+  if (_element == nil) return nil;
+  
+  nsuri = [_element namespaceURI];
+  if (![nsuri isEqualToString:XMLNS_OD_BIND])
+    return Nil;
+  
+  tag = [_element tagName];
+  tl  = [tag length];
+
+  if (tl < 5)
+    return Nil;
+  
+  switch ([tag characterAtIndex:0]) {
+    case 'c':
+      if ([tag isEqualToString:@"component-content"])
+        return NSClassFromString(@"WOComponentContent");
+      if ([tag isEqualToString:@"checkbox-list"])
+        return NSClassFromString(@"WOCheckBoxList");
+      break;
+      
+    case 'e':
+      if ([tag isEqualToString:@"entity"])
+        return NSClassFromString(@"WOEntity");
+      break;
+
+    case 'm':
+      if ([tag isEqualToString:@"multiselection"])
+        return NSClassFromString(@"WOBrowser");
+      break;
+      
+    case 'n':
+      if ([tag isEqualToString:@"nbsp"]) {
+        NSLog(@"WARNING(%s): found <var:nbsp/>, "
+              @"use <var:entity name='nbsp'/> !",
+              __PRETTY_FUNCTION__);
+        return NSClassFromString(@"WOEntity");
+      }
+      break;
+
+    case 'p':
+      if ([tag isEqualToString:@"popup"])
+        return NSClassFromString(@"WOPopUpButton");
+      break;
+
+    case 'r':
+      if ([tag isEqualToString:@"radio-button-matrix"])
+        return NSClassFromString(@"WORadioButtonMatrix");
+      break;
+      
+    case 's':
+      if ([tag isEqualToString:@"string"])
+        return NSClassFromString(@"WOString");
+      if ([tag isEqualToString:@"singleselection"])
+        return NSClassFromString(@"WOBrowser");
+      break;
+  }
+  return Nil;
+}
+
+@end /* SxMiscElemBuilder */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/WOxXULElemBuilder.m b/skyrix-sope/NGObjWeb/DynamicElements/WOxXULElemBuilder.m
new file mode 100644 (file)
index 0000000..5b8718b
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/WOxElemBuilder.h>
+
+/*
+  This builder builds all standard elements which are defined in the 
+  XUL namespace.
+
+  Supported tags:
+    - all other tags are represented using either WOGenericElement or
+      WOGenericContainer, so this builder is "final destination" for
+      all XUL related tags.
+  
+    <iframe .../>     maps to WOIFrame
+    <entity .../>     maps to WOEntity
+*/
+
+@interface WOxXULElemBuilder : WOxTagClassElemBuilder
+{
+}
+
+@end
+
+#include "common.h"
+#include <SaxObjC/XMLNamespaces.h>
+
+@implementation WOxXULElemBuilder
+
+- (Class)classForElement:(id<DOMElement>)_element {
+  NSString *nsuri;
+  NSString *tag;
+  unsigned tl;
+
+  if ((nsuri = [_element namespaceURI]) == nil)
+    return Nil;
+  
+  if (![nsuri isEqualToString:XMLNS_XUL])
+    return Nil;
+  
+  tag = [_element tagName];
+  
+  if ((tl = [tag length]) == 0)
+    return Nil;
+  
+  switch (tl) {
+    default:
+      if ([tag isEqualToString:@"iframe"])
+        return NSClassFromString(@"WOIFrame");
+      if ([tag isEqualToString:@"entity"])
+        return NSClassFromString(@"WOEntity");
+      break;
+  }
+  
+  if ([_element hasChildNodes])
+    return NSClassFromString(@"WOGenericContainer");
+  else
+    return NSClassFromString(@"WOGenericElement");
+}
+
+@end /* WOxXULElemBuilder */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/_WOCommonStaticDAHyperlink.m b/skyrix-sope/NGObjWeb/DynamicElements/_WOCommonStaticDAHyperlink.m
new file mode 100644 (file)
index 0000000..0c283ff
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHyperlink.h"
+
+@class NSString, NSDictionary;
+@class WOElement, WOAssociation;
+
+/*
+  Class Hierachy
+    [WOHTMLDynamicElement]
+      [WOHyperlink]
+        _WOCommonStaticDAHyperlink
+*/
+
+@interface _WOCommonStaticDAHyperlink : WOHyperlink
+{
+  NSString      *daName;
+  WOElement     *template;
+  WOAssociation *string;
+  NSDictionary  *queryParameters;  /* associations beginning with ? */
+  BOOL          sidInUrl;          /* include session-id in wa URL ? */
+}
+@end /* _WOCommonStaticDAHyperlink */
+
+#include "WOHyperlinkInfo.h"
+#include "WOElement+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOAssociation.h>
+#include "common.h"
+
+@implementation _WOCommonStaticDAHyperlink
+
+- (id)initWithName:(NSString *)_name
+  hyperlinkInfo:(WOHyperlinkInfo *)_info
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) {
+    NSString *dc, *dn;
+    
+    self->template        = [_t retain];
+    self->string          = _info->string;
+    self->queryParameters = _info->queryParameters;
+    
+    dc = [_info->actionClass       stringValueInComponent:nil];
+    dn = [ _info->directActionName stringValueInComponent:nil];
+    
+    if (![dc isEqualToString:@"DirectAction"] && ([dc length] != 0))
+      self->daName = [[NSString alloc] initWithFormat:@"%@/%@", dc, dn];
+    else
+      self->daName = [dn copy];
+    
+    self->containsForm = NO;
+    self->sidInUrl     = _info->sidInUrl;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->daName   release];
+  [self->template release];
+  [self->string   release];
+  [self->queryParameters release];
+  [super dealloc];
+}
+
+/* responder */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSMutableDictionary *qd;
+  
+  if ([[_ctx request] isFromClientComponent])
+    return;
+
+  sComponent = [_ctx component];
+  WOResponse_AddCString(_response, "<a href=\"");
+  
+  /* href */
+  if (self->queryParameters) {
+    NSEnumerator *keys;
+    NSString     *key;
+
+    qd = [NSMutableDictionary dictionaryWithCapacity:
+                                [self->queryParameters count]];
+    keys = [self->queryParameters keyEnumerator];
+    while ((key = [keys nextObject])) {
+      id assoc, value;
+      
+      assoc = [self->queryParameters objectForKey:key];
+      value = [assoc stringValueInComponent:sComponent];
+          
+      [qd setObject:(value ? value : @"") forKey:key];
+    }
+  }
+  else
+    qd = nil;
+
+  /* add session ID */
+
+  if (self->sidInUrl) {
+    if ([_ctx hasSession]) {
+      WOSession *sn;
+      
+      if (qd == nil)
+        qd = [NSMutableDictionary dictionaryWithCapacity:2];
+      
+      sn = [_ctx session];
+      [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
+      
+      if (![sn isDistributionEnabled]) {
+        [qd setObject:[[WOApplication application] number]
+            forKey:WORequestValueInstance];
+      }
+    }
+  }
+  
+  WOResponse_AddString(_response,
+                       [_ctx directActionURLForActionNamed:self->daName
+                             queryDictionary:qd]);
+  
+  WOResponse_AddCString(_response, "\"");
+
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  [_response appendContentCharacter:'>'];
+
+  /* content */
+  
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  if (self->string) {
+    [_response appendContentHTMLString:
+                 [self->string stringValueInComponent:sComponent]];
+  }
+  
+  /* closing tag */
+  WOResponse_AddCString(_response, "</a>");
+}
+
+@end /* _WOCommonStaticDAHyperlink */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/_WOComplexHyperlink.m b/skyrix-sope/NGObjWeb/DynamicElements/_WOComplexHyperlink.m
new file mode 100644 (file)
index 0000000..546f863
--- /dev/null
@@ -0,0 +1,682 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHyperlink.h"
+
+/*
+  Class Hierachy
+    [WOHTMLDynamicElement]
+      [WOHyperlink]
+        _WOComplexHyperlink
+          _WOHrefHyperlink
+          _WOActionHyperlink
+          _WOPageHyperlink
+          _WODirectActionHyperlink
+*/
+
+@interface _WOComplexHyperlink : WOHyperlink
+{
+  /* superclass of most hyperlink classes */
+@protected
+  WOAssociation *fragmentIdentifier;
+  WOAssociation *string;
+  WOAssociation *target;
+  WOAssociation *disabled;
+  WOElement     *template;
+  
+  /* new in WO4: */
+  WOAssociation *queryDictionary;
+  NSDictionary  *queryParameters;  /* associations beginning with ? */
+
+  /* non WO, image stuff */
+  WOAssociation *filename;         /* path relative to WebServerResources */
+  WOAssociation *framework;
+  WOAssociation *src;              /* absolute URL */
+  WOAssociation *disabledFilename; /* icon for 'disabled' state */
+}
+
+- (NSString *)associationDescription;
+
+@end
+
+@interface _WOHrefHyperlink : _WOComplexHyperlink
+{
+  WOAssociation *href;
+}
+@end
+
+@interface _WOActionHyperlink : _WOComplexHyperlink
+{
+  WOAssociation *action;
+}
+@end
+
+@interface _WOPageHyperlink : _WOComplexHyperlink
+{
+  WOAssociation *pageName;
+}
+@end
+
+@interface _WODirectActionHyperlink : _WOComplexHyperlink
+{
+  WOAssociation *actionClass;
+  WOAssociation *directActionName;
+  BOOL          sidInUrl;          /* include session-id in wa URL ? */
+}
+@end
+
+#include "WOElement+private.h"
+#include "WOHyperlinkInfo.h"
+#include "WOCompoundElement.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGExtensions/NSString+Ext.h>
+#include "common.h"
+
+static Class NSURLClass = Nil;
+
+@implementation _WOComplexHyperlink
+
++ (int)version {
+  return [super version] /* v4 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 4,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  if (NSURLClass == Nil)
+    NSURLClass = [NSURL class];
+}
+
+- (id)initWithName:(NSString *)_name
+  hyperlinkInfo:(WOHyperlinkInfo *)_info
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) {
+    self->template = [_t retain];
+    
+    self->fragmentIdentifier = _info->fragmentIdentifier;
+    self->string             = _info->string;
+    self->target             = _info->target;
+    self->disabled           = _info->disabled;
+    self->queryDictionary    = _info->queryDictionary;
+    self->queryParameters    = _info->queryParameters;
+    
+    /* image */
+    self->filename         = _info->filename;
+    self->framework        = _info->framework;
+    self->src              = _info->src;
+    self->disabledFilename = _info->disabledFilename;
+    
+    self->containsForm = self->queryParameters ? YES : NO;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template           release];
+  [self->queryDictionary    release];
+  [self->queryParameters    release];
+  [self->disabledFilename   release];
+  [self->filename           release];
+  [self->framework          release];
+  [self->src                release];
+  [self->fragmentIdentifier release];
+  [self->string             release];
+  [self->target             release];
+  [self->disabled           release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOElement *)template {
+  return self->template;
+}
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  /* links can take form values !!!! (for query-parameters) */
+  
+  if (self->queryParameters) {
+    /* apply values to ?style parameters */
+    WOComponent  *sComponent = [_ctx component];
+    NSEnumerator *keys;
+    NSString     *key;
+
+    keys = [self->queryParameters keyEnumerator];
+    while ((key = [keys nextObject])) {
+      id assoc, value;
+
+      assoc = [self->queryParameters objectForKey:key];
+      
+      if ([assoc isValueSettable]) {
+        value = [_req formValueForKey:key];
+        [assoc setValue:value inComponent:sComponent];
+      }
+    }
+  }
+  
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if (self->disabled) {
+    if ([self->disabled boolValueInComponent:[_ctx component]])
+      return nil;
+  }
+  
+  if (![[_ctx elementID] isEqualToString:[_ctx senderID]])
+    /* link is not the active element */
+    return [self->template invokeActionForRequest:_request inContext:_ctx];
+  
+  /* link is active */
+  [[_ctx session] logWithFormat:@"%@[0x%08X]: no action/page set !",
+                  NSStringFromClass([self class]), self];
+  return nil;
+}
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  [self subclassResponsibility:_cmd];
+  return NO;
+}
+
+- (void)_addImageToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  WOComponent *sComponent = [_ctx component];
+  NSString *uUri;
+  NSString *uFi  = nil;
+  NSArray *languages;
+  
+  uUri = [[self->src valueInContext:_ctx] stringValue];
+      
+  if ([self->disabled boolValueInComponent:sComponent]) {
+    uFi =  [self->disabledFilename stringValueInComponent:sComponent];
+    if (uFi == nil)
+      uFi = [self->filename stringValueInComponent:sComponent];
+  }
+  else
+    uFi = [self->filename stringValueInComponent:sComponent];
+  
+  if (!((uFi != nil) || (uUri != nil))) 
+    return;
+
+  languages = [_ctx hasSession]
+    ? [[_ctx session] languages]
+    : [[_ctx request] browserLanguages];
+        
+  WOResponse_AddCString(_resp, "<img src=\"");
+  
+  if (uFi) {
+    WOResourceManager *rm;
+          
+    if ((rm = [[_ctx component] resourceManager]) == nil)
+      rm = [[_ctx application] resourceManager];
+          
+    uFi = [rm urlForResourceNamed:uFi
+             inFramework:
+               [self->framework stringValueInComponent:sComponent]
+             languages:languages
+             request:[_ctx request]];
+    if (uFi == nil) {
+      NSLog(@"%@: did not find resource %@", sComponent,
+           [self->filename stringValueInComponent:sComponent]);
+      uFi = uUri;
+    }
+    [_resp appendContentHTMLAttributeValue:uFi];
+  }
+  else {
+    [_resp appendContentHTMLAttributeValue:uUri];
+  }
+  WOResponse_AddChar(_resp, '"');
+  
+  [self appendExtraAttributesToResponse:_resp inContext:_ctx];
+  WOResponse_AddCString(_resp, " />");
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent = [_ctx component];
+  NSString *content;
+  NSString *targetView;
+  NSString *queryString = nil;
+
+  if ([[_ctx request] isFromClientComponent])
+    return;
+  
+  content    = [self->string valueInContext:_ctx];
+  targetView = [self->target stringValueInComponent:sComponent];
+    
+  WOResponse_AddCString(_response, "<a href=\"");
+    
+  if ([self _appendHrefToResponse:_response inContext:_ctx]) {
+      queryString = [self queryStringForQueryDictionary:
+                            [self->queryDictionary valueInComponent:sComponent]
+                          andQueryParameters:self->queryParameters
+                          inContext:_ctx];
+  }
+  
+  if (self->fragmentIdentifier) {
+      [_response appendContentCharacter:'#'];
+      WOResponse_AddString(_response,
+         [self->fragmentIdentifier stringValueInComponent:sComponent]);
+  }
+  if (queryString) {
+    [_response appendContentCharacter:'?'];
+    WOResponse_AddString(_response, queryString);
+  }
+  [_response appendContentCharacter:'"'];
+    
+  if (targetView) {
+    WOResponse_AddCString(_response, " target=\"");
+    WOResponse_AddString(_response, targetView);
+    [_response appendContentCharacter:'"'];
+  }
+    
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    
+  if (self->otherTagString) {
+    NSString *s;
+    
+    s = [self->otherTagString stringValueInComponent:[_ctx component]];
+    WOResponse_AddString(_response, s);
+  }
+  [_response appendContentCharacter:'>'];
+    
+  /* content */
+  [self->template appendToResponse:_response inContext:_ctx];
+  if (content) [_response appendContentHTMLString:content];
+  
+  /* image content */
+  if ((self->src != nil) || (self->filename != nil))
+    [self _addImageToResponse:_response inContext:_ctx];
+  
+  /* closing tag */
+  WOResponse_AddCString(_response, "</a>");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  if (self->fragmentIdentifier)
+    [str appendFormat:@" fragment=%@", self->fragmentIdentifier];
+  if (self->string)   [str appendFormat:@" string=%@",   self->string];
+  if (self->target)   [str appendFormat:@" target=%@",   self->target];
+  if (self->disabled) [str appendFormat:@" disabled=%@", self->disabled];
+
+  /* image .. */
+  if (self->filename)  [str appendFormat:@" filename=%@",  self->filename];
+  if (self->framework) [str appendFormat:@" framework=%@", self->framework];
+  if (self->src)       [str appendFormat:@" src=%@",       self->src];
+
+  return str;
+}
+
+@end /* _WOComplexHyperlink */
+
+@implementation _WOHrefHyperlink
+
+static BOOL debugStaticLinks = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  debugStaticLinks = [ud boolForKey:@"WODebugStaticLinkProcessing"];
+}
+
+- (id)initWithName:(NSString *)_name
+  hyperlinkInfo:(WOHyperlinkInfo *)_info
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) {
+    self->href = _info->href;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->href release];
+  [super dealloc];
+}
+
+/* URI generation */
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  NSString *s;
+  id    hrefValue;
+  NSURL *url, *base;
+  
+  base      = [_ctx baseURL];
+  hrefValue = [self->href valueInContext:_ctx];
+  url       = hrefValue;
+  
+  if (hrefValue == nil)
+    return NO;
+   
+  if ([hrefValue isKindOfClass:NSURLClass]) {
+    s = [hrefValue stringValueRelativeToURL:base];
+  }
+  else {
+    s = [hrefValue stringValue];
+    
+    if (!([s hasPrefix:@"mailto:"] || [s hasPrefix:@"javascript:"])) {
+      if ([s isAbsoluteURL]) {
+        // TODO: why are we doing this? we could just pass through the string?
+        //    => probably to generate relative links
+        url = [NSURLClass URLWithString:s];
+      }
+      else if (base != nil) {
+        url = [NSURLClass URLWithString:s relativeToURL:base];
+      }
+      else {
+        [self logWithFormat:@"WARNING: missing base URL in context ..."];
+        WOResponse_AddString(_r, s);
+        return YES;
+      }
+      
+      if (url == nil) {
+        [self logWithFormat:
+                @"couldn't construct URL from 'href' string '%@' (base=%@)",
+                s, base];
+        return NO;
+      }
+      s = [url stringValueRelativeToURL:base];
+    }
+  }
+  
+  /* generate URL */
+  
+  if (debugStaticLinks) {
+    [self logWithFormat:@"static links based on 'href': '%@'", hrefValue];
+    [self logWithFormat:@"  base     %@", base];
+    [self logWithFormat:@"  base-abs %@", [base absoluteString]];
+    [self logWithFormat:@"  url      %@", url];
+    [self logWithFormat:@"  url-abs  %@", [url absoluteString]];
+    [self logWithFormat:@"  string   %@", s];
+  }
+  WOResponse_AddString(_r, s);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" href=%@", self->href];
+  [str appendString:[super associationDescription]];
+  
+  return str;
+}
+
+@end /* _WOHrefHyperlink */
+
+@implementation _WOActionHyperlink
+
+- (id)initWithName:(NSString *)_name
+  hyperlinkInfo:(WOHyperlinkInfo *)_info
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) {
+    self->action = _info->action;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->action release];
+  [super dealloc];
+}
+
+/* dynamic invocation */
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if (self->disabled) {
+    if ([self->disabled boolValueInComponent:[_ctx component]])
+      return nil;
+  }
+
+  if (![[_ctx elementID] isEqualToString:[_ctx senderID]])
+    /* link is not the active element */
+    return [self->template invokeActionForRequest:_request inContext:_ctx];
+  
+  /* link is active */
+  return [self executeAction:self->action inContext:_ctx];
+}
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOResponse_AddString(_response, [_ctx componentActionURL]);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" action=%@", self->action];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOActionHyperlink */
+
+@implementation _WOPageHyperlink
+
+- (id)initWithName:(NSString *)_name
+  hyperlinkInfo:(WOHyperlinkInfo *)_info
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) {
+    self->pageName = _info->pageName;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->pageName release];
+  [super dealloc];
+}
+
+/* actions */
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *page;
+  NSString    *name;
+
+  if (self->disabled) {
+    if ([self->disabled boolValueInComponent:[_ctx component]])
+      return nil;
+  }
+  
+  if (![[_ctx elementID] isEqualToString:[_ctx senderID]])
+    /* link is not the active element */
+    return [self->template invokeActionForRequest:_request inContext:_ctx];
+  
+  /* link is the active element */
+  
+  name = [self->pageName stringValueInComponent:[_ctx component]];
+  page = [[_ctx application] pageWithName:name inContext:_ctx];
+
+  if (page == nil) {
+    [[_ctx session] logWithFormat:
+                      @"%@[0x%08X]: did not find page with name %@ !",
+                      NSStringFromClass([self class]), self, name];
+  }
+  return page;
+}
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  /*
+    Profiling:
+      87% -componentActionURL
+      13% NSString dataUsingEncoding(appendContentString!)
+    TODO(prof): use addcstring
+  */
+  WOResponse_AddString(_response, [_ctx componentActionURL]);
+  return YES;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  [str appendFormat:@" pageName=%@", self->pageName];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOPageHyperlink */
+
+@implementation _WODirectActionHyperlink
+
+- (id)initWithName:(NSString *)_name
+  hyperlinkInfo:(WOHyperlinkInfo *)_info
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) {
+    self->actionClass      = _info->actionClass;
+    self->directActionName = _info->directActionName;
+    self->sidInUrl         = _info->sidInUrl;
+
+    self->containsForm = NO; /* direct actions are never form stuff ... */
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->actionClass      release];
+  [self->directActionName release];
+  [super dealloc];
+}
+
+/* href */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  /* DA links can *never* take form values !!!! */
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  /* DA links can *never* invoke an action !!!! */
+  return [self->template invokeActionForRequest:_request inContext:_ctx];
+}
+
+- (BOOL)_appendHrefToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent         *sComponent;
+  NSString            *daClass;
+  NSString            *daName;
+  NSMutableDictionary *qd;
+  NSDictionary        *tmp;
+
+  sComponent = [_ctx component];
+  daClass = [self->actionClass stringValueInComponent:sComponent];
+  daName  = [self->directActionName stringValueInComponent:sComponent];
+
+  if (daClass) {
+    if (daName) {
+      if (![daClass isEqualToString:@"DirectAction"])
+        daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
+    }
+    else
+      daName = daClass;
+  }
+  
+  qd = [NSMutableDictionary dictionaryWithCapacity:16];
+  
+  /* add query dictionary */
+  
+  if (self->queryDictionary) {
+    if ((tmp = [self->queryDictionary valueInComponent:sComponent]))
+      [qd addEntriesFromDictionary:tmp];
+  }
+  
+  /* add ?style parameters */
+
+  if (self->queryParameters) {
+    NSEnumerator *keys;
+    NSString     *key;
+
+    keys = [self->queryParameters keyEnumerator];
+    while ((key = [keys nextObject])) {
+      id assoc, value;
+
+      assoc = [self->queryParameters objectForKey:key];
+      value = [assoc stringValueInComponent:sComponent];
+          
+      [qd setObject:(value ? value : @"") forKey:key];
+    }
+  }
+      
+  /* add session ID */
+  
+  if (self->sidInUrl) {
+    if ([_ctx hasSession]) {
+      WOSession *sn;
+      
+      sn = [_ctx session];
+      [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
+      
+      if (![sn isDistributionEnabled]) {
+        [qd setObject:[[WOApplication application] number]
+            forKey:WORequestValueInstance];
+      }
+    }
+  }
+
+  WOResponse_AddString(_response,
+                       [_ctx directActionURLForActionNamed:daName
+                             queryDictionary:qd]);
+  return NO;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:256];
+
+  if (self->actionClass)
+    [str appendFormat:@" actionClass=%@", self->actionClass];
+  if (self->directActionName)
+    [str appendFormat:@" directAction=%@", self->directActionName];
+  
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WODirectActionHyperlink */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/_WOConstResourceImage.m b/skyrix-sope/NGObjWeb/DynamicElements/_WOConstResourceImage.m
new file mode 100644 (file)
index 0000000..65c30bb
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOImage.h"
+
+@interface _WOConstResourceImage : WOImage
+{
+  NSString *filename;  // path relative to WebServerResources
+}
+@end
+
+#include "WOElement+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+
+@implementation _WOConstResourceImage
+
+static BOOL debugOn = NO;
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    WOAssociation *tmp;
+
+    tmp = OWGetProperty(_config, @"filename");
+    self->filename  = [[tmp stringValueInComponent:nil] copy];
+    [tmp release];
+    
+    if (self->filename == nil) {
+      NSLog(@"missing filename association for WOImage ..");
+      [self release];
+      return nil;
+    }
+
+#if DEBUG
+    if ([_config objectForKey:@"value"]    ||
+        [_config objectForKey:@"data"]     ||
+        [_config objectForKey:@"mimeType"] ||
+        [_config objectForKey:@"key"]      ||
+        [_config objectForKey:@"src"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOImage !"
+            @" (assign only one of value, src, data or filename)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->filename release];
+  [super dealloc];
+}
+
+/* HTML generation */
+
+- (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSString    *uFi;
+  NSArray     *languages;
+  WOResourceManager *rm;
+  NSString    *frameworkName;
+  
+  sComponent = [_ctx component];
+  
+  if (self->filename == nil) {
+    [_resp appendContentHTMLAttributeValue:
+             @"/missingImage?reason=nilfilenamebinding"];
+    [self debugWithFormat:@"missing 'filename' binding value ..."];
+    return;
+  }
+  
+  /* this has no measurable effect on performance ... */
+  if ((rm = [[_ctx component] resourceManager]) == nil)
+    rm = [[_ctx application] resourceManager];
+  
+  languages = [_ctx hasSession]
+    ? [[_ctx session] languages]
+    : [[_ctx request] browserLanguages];
+
+  if (debugOn) {
+    [self debugWithFormat:@"WOImage: filename '%@'\n  rm %@\n  languages %@",
+           self->filename, rm, [languages componentsJoinedByString:@","]];
+  }
+  
+  /* 
+     'framework' binding is not set in that case -> use parent component's 
+     framework 
+  */
+  frameworkName = [[_ctx component] frameworkName];
+  uFi = [rm urlForResourceNamed:self->filename
+            inFramework:frameworkName 
+            languages:languages
+            request:[_ctx request]];
+  if (uFi == nil) {
+    [self logWithFormat:
+           @"%@: did not find resource '%@'", sComponent, self->filename];
+    uFi = [@"/missingImage?" stringByAppendingString:self->filename];
+  }
+  
+  if (debugOn)
+    [self debugWithFormat:@"WOImage: constant resource URL: '%@'", uFi];
+  
+  [_resp appendContentHTMLAttributeValue:uFi];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:64];
+  
+  [str appendFormat:@" filename=%@", self->filename];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOConstResourceImage */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/_WOResourceImage.m b/skyrix-sope/NGObjWeb/DynamicElements/_WOResourceImage.m
new file mode 100644 (file)
index 0000000..dd5f197
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOImage.h"
+
+@interface _WOResourceImage : WOImage
+{
+  WOAssociation *filename;  // path relative to WebServerResources
+  WOAssociation *framework;
+}
+@end
+
+#include "WOElement+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+
+@implementation _WOResourceImage
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->filename  = OWGetProperty(_config, @"filename");
+    self->framework = OWGetProperty(_config, @"framework");
+    
+    if (self->filename == nil) {
+      NSLog(@"missing filename association for WOImage ..");
+      [self release];
+      return nil;
+    }
+
+#if DEBUG
+    if ([_config objectForKey:@"value"]    ||
+        [_config objectForKey:@"data"]     ||
+        [_config objectForKey:@"mimeType"] ||
+        [_config objectForKey:@"key"]      ||
+        [_config objectForKey:@"src"]) {
+      NSLog(@"WARNING: inconsistent association settings in WOImage !"
+            @" (assign only one of value, src, data or filename)");
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->framework release];
+  [self->filename  release];
+  [super dealloc];
+}
+
+/* HTML generation */
+
+- (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSString    *uFi;
+  NSArray     *languages;
+  WOResourceManager *rm;
+  NSString    *frameworkName;
+  
+  sComponent = [_ctx component];
+
+  if (self->filename == nil) {
+    [_resp appendContentHTMLAttributeValue:
+             @"/missingImage?reason=nofilenamebinding"];
+    return;
+  }
+  
+  if ((uFi = [self->filename stringValueInComponent:sComponent]) == nil) {
+    [_resp appendContentHTMLAttributeValue:
+             @"/missingImage?reason=nilfilenamebinding"];
+    return;
+  }
+  
+  if ((rm = [[_ctx component] resourceManager]) == nil)
+    rm = [[_ctx application] resourceManager];
+  
+  languages = [_ctx hasSession] ? [[_ctx session] languages] : nil;
+  
+  /* If 'framework' binding is not set, use parent component's framework */
+  if (self->framework){
+    frameworkName = [self->framework stringValueInComponent:sComponent];
+    if (frameworkName != nil && [frameworkName isEqualToString:@"app"])
+      frameworkName = nil;
+  }
+  else
+    frameworkName = [sComponent frameworkName];
+
+  uFi = [rm urlForResourceNamed:uFi
+            inFramework:frameworkName
+            languages:languages
+            request:[_ctx request]];
+  if (uFi == nil) {
+    uFi = [self->filename stringValueInComponent:sComponent];
+    NSLog(@"%@: did not find resource '%@'", sComponent, uFi);
+    uFi = [@"/missingImage?" stringByAppendingString:uFi];
+  }
+  
+#if HEAVY_DEBUG
+  [self logWithFormat:@"RESOURCE IMAGE: %@", uFi];
+#endif
+  [_resp appendContentHTMLAttributeValue:uFi];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [NSMutableString stringWithCapacity:64];
+
+  [str appendFormat:@" filename=%@", self->filename];
+  if (self->framework) [str appendFormat:@" framework=%@", self->framework];
+  [str appendString:[super associationDescription]];
+  return str;
+}
+
+@end /* _WOResourceImage */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/_WOSimpleActionHyperlink.m b/skyrix-sope/NGObjWeb/DynamicElements/_WOSimpleActionHyperlink.m
new file mode 100644 (file)
index 0000000..a53710c
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHyperlink.h"
+
+/*
+  Class Hierachy
+    [WOHTMLDynamicElement]
+      [WOHyperlink]
+        _WOSimpleActionHyperlink
+          _WOSimpleStringActionHyperlink
+*/
+
+@interface _WOSimpleActionHyperlink : WOHyperlink
+{
+  WOAssociation *action;
+  WOElement     *template;
+}
+@end /* _WOSimpleActionHyperlink */
+
+@interface _WOSimpleStringActionHyperlink : _WOSimpleActionHyperlink
+{
+  WOAssociation *string;
+}
+@end /* _WOSimpleStringActionHyperlink */
+
+#include "WOHyperlinkInfo.h"
+#include "WOElement+private.h"
+#include <NGObjWeb/WOAssociation.h>
+#include "common.h"
+
+@implementation _WOSimpleActionHyperlink
+
++ (int)version {
+  return [super version] + 0 /* v4 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 4,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  hyperlinkInfo:(WOHyperlinkInfo *)_info
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) {
+    self->template     = RETAIN(_t);
+    self->containsForm = NO;
+    self->action       = _info->action;
+#if DEBUG
+    NSAssert(self->action, @"missing action ?!");
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template release];
+  [self->action   release];
+  [super dealloc];
+}
+
+/* dynamic invocation */
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if (![[_ctx elementID] isEqualToString:[_ctx senderID]]) {
+    /* link is not the active element */
+#if DEBUG
+    NSLog(@"HYPERLINK is not active (%@ vs %@) !",
+          [_ctx elementID], [_ctx senderID]);
+#endif
+    return [self->template invokeActionForRequest:_request inContext:_ctx];
+  }
+  
+  //NSLog(@"%s: invoke called ...", __PRETTY_FUNCTION__);
+  
+  /* link is active */
+  return [self executeAction:self->action inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if ([[_ctx request] isFromClientComponent])
+    return;
+  
+  WOResponse_AddCString(_response, "<a href=\"");
+  WOResponse_AddString(_response, [_ctx componentActionURL]);
+  
+  [_response appendContentCharacter:'"'];
+  
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              [_ctx component]]);
+  }
+  [_response appendContentCharacter:'>'];
+  
+  /* content */
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  /* closing tag */
+  WOResponse_AddCString(_response, "</a>");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  return [NSString stringWithFormat:@"action=%@", self->action];
+}
+
+@end /* _WOSimpleActionHyperlink */
+
+@implementation _WOSimpleStringActionHyperlink
+
+- (id)initWithName:(NSString *)_name
+  hyperlinkInfo:(WOHyperlinkInfo *)_info
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) {
+    self->string = _info->string;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->string release];
+  [super dealloc];
+}
+
+/* HTML generation */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSString *content;
+
+  if ([[_ctx request] isFromClientComponent])
+    return;
+  
+  sComponent = [_ctx component];
+  content = [self->string stringValueInComponent:sComponent];
+    
+  WOResponse_AddCString(_response, "<a href=\"");
+  WOResponse_AddString(_response, [_ctx componentActionURL]);
+    
+  [_response appendContentCharacter:'"'];
+    
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  
+  if (self->otherTagString) {
+    WOResponse_AddString(_response,
+                         [self->otherTagString stringValueInComponent:
+                              sComponent]);
+  }
+  [_response appendContentCharacter:'>'];
+    
+  /* content */
+  [self->template appendToResponse:_response inContext:_ctx];
+  if (content) [_response appendContentHTMLString:content];
+
+  /* closing tag */
+  WOResponse_AddCString(_response, "</a>");
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  return [NSString stringWithFormat:@"action=%@, string=%@",
+                     self->action, self->string];
+}
+
+@end /* _WOSimpleStringActionHyperlink */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/_WOTemporaryHyperlink.m b/skyrix-sope/NGObjWeb/DynamicElements/_WOTemporaryHyperlink.m
new file mode 100644 (file)
index 0000000..e3497ee
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHyperlink.h"
+#include "WOHyperlinkInfo.h"
+#include "WOCompoundElement.h"
+#include <NGObjWeb/WOAssociation.h>
+#include "common.h"
+
+@implementation _WOTemporaryHyperlink
+
+static Class _WOSimpleActionHyperlinkClass       = Nil;
+static Class _WOSimpleStringActionHyperlinkClass = Nil;
+static Class _WOActionHyperlinkClass             = Nil;
+static Class _WOPageHyperlinkClass               = Nil;
+static Class _WOHrefHyperlinkClass               = Nil;
+static Class _WOCommonStaticDAHyperlinkClass     = Nil;
+static Class _WODirectActionHyperlinkClass       = Nil;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+
+  _WOSimpleActionHyperlinkClass = 
+    NSClassFromString(@"_WOSimpleActionHyperlink");
+  _WOSimpleStringActionHyperlinkClass = 
+    NSClassFromString(@"_WOSimpleStringActionHyperlink");
+
+  _WOActionHyperlinkClass = NSClassFromString(@"_WOActionHyperlink");
+  _WOPageHyperlinkClass   = NSClassFromString(@"_WOPageHyperlink");
+  _WOHrefHyperlinkClass   = NSClassFromString(@"_WOHrefHyperlink");
+
+  _WOCommonStaticDAHyperlinkClass = 
+    NSClassFromString(@"_WOCommonStaticDAHyperlink");
+  _WODirectActionHyperlinkClass = 
+    NSClassFromString(@"_WODirectActionHyperlink");
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  WOHyperlinkInfo *info;
+  Class linkClass = Nil;
+  
+  if ((info = [[WOHyperlinkInfo alloc] initWithConfig:(id)_config]) == nil) {
+    return nil;
+  }
+  
+  if (info->action) {
+    if (info->assocCount == 0)
+      linkClass = [_WOSimpleActionHyperlinkClass class];
+    else if ((info->assocCount == 1) && (info->string != nil))
+      linkClass = [_WOSimpleStringActionHyperlinkClass class];
+    else
+      linkClass = [_WOActionHyperlinkClass class];
+  }
+  else if (info->pageName) {
+    linkClass = [_WOPageHyperlinkClass class];
+  }
+  else if (info->href) {
+    linkClass = [_WOHrefHyperlinkClass class];
+  }
+  else if (info->directActionName) {
+    linkClass = Nil;
+    
+    if (info->assocCount < 3) {
+      if ([info->directActionName isValueConstant]) {
+        if (info->actionClass == nil ||
+            ([info->actionClass isValueConstant])) {
+          if (info->assocCount == 1) {
+            if (info->queryParameters != nil || info->string != nil)
+              linkClass = [_WOCommonStaticDAHyperlinkClass class];
+          }
+          else if (info->assocCount == 2 &&
+                   (info->queryParameters != nil) &&
+                   (info->string != nil)) {
+            linkClass = [_WOCommonStaticDAHyperlinkClass class];
+          }
+        }
+      }
+    }
+
+    if (linkClass == Nil)
+      linkClass = [_WODirectActionHyperlinkClass class];
+  }
+  else {
+    NSLog(@"%s: found no setting for link named '%@', assocs %@",
+          __PRETTY_FUNCTION__, _name, _config);
+    return nil;
+  }
+  
+  self =
+    [[linkClass alloc] initWithName:_name hyperlinkInfo:info template:_t];
+  [info release]; info = nil;
+  return self;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  contentElements:(NSArray *)_contents
+{
+  WOCompoundElement *template;
+  int count;
+  
+  count = [_contents count];
+  
+  if (count == 0) {
+    template = nil;
+  }
+  else if (count == 1) {
+    template = [_contents objectAtIndex:0];
+  }
+  else {
+    template = [[WOCompoundElement allocForCount:[_contents count]
+                                   zone:[self zone]]
+                                   initWithContentElements:_contents];
+  }
+  
+  return [self initWithName:_name
+               associations:_associations
+               template:template];
+}
+
+- (void)dealloc {
+  NSLog(@"ERROR: called dealloc on %@", self);
+#if DEBUG
+  abort();
+#endif
+  return;
+}
+
+@end /* _WOTemporaryHyperlink */
diff --git a/skyrix-sope/NGObjWeb/DynamicElements/common.h b/skyrix-sope/NGObjWeb/DynamicElements/common.h
new file mode 100644 (file)
index 0000000..4d60bf7
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_DynElem_common_H__
+#define __NGObjWeb_DynElem_common_H__
+
+#include <objc/objc-api.h>
+#import <Foundation/Foundation.h>
+
+#if !LIB_FOUNDATION_LIBRARY && !GNUSTEP_BASE_LIBRARY
+#  import <NGExtensions/NGObjectMacros.h>
+#  import <NGExtensions/NSString+Ext.h>
+#endif /* NeXT_Foundation_LIBRARY */
+
+#if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(MethodsRequiredByDynamicElements)
+- (void)subclassResponsibility:(SEL)_cmd;
+@end
+#endif
+
+#include <NGExtensions/NGExtensions.h>
+
+#endif /* __NGObjWeb_DynElem_common_H__ */
diff --git a/skyrix-sope/NGObjWeb/GNUmakefile b/skyrix-sope/NGObjWeb/GNUmakefile
new file mode 100644 (file)
index 0000000..e4d177d
--- /dev/null
@@ -0,0 +1,164 @@
+# $Id$
+
+include ../common.make
+include ./Version
+
+GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT)
+
+LIBRARY_NAME  = libNGObjWeb
+RESOURCES_DIR = $(GNUSTEP_RESOURCES)/NGObjWeb
+
+libNGObjWeb_CPPFLAGS += -pipe -DCOMPILING_NGOBJWEB=1
+
+libNGObjWeb_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libNGObjWeb_SUBPROJECTS = \
+       NGHttp          \
+       Associations    \
+       Templates       \
+       DynamicElements \
+       WOHttpAdaptor   \
+       SoObjects       \
+       WebDAV          \
+       SoOFS           \
+       NGXmlRpc        \
+
+libNGObjWeb_HEADER_FILES_DIR         = NGObjWeb
+libNGObjWeb_HEADER_FILES_INSTALL_DIR = /NGObjWeb
+
+libNGObjWeb_RESOURCES = \
+       Defaults.plist          \
+       Languages.plist         \
+       DAVPropMap.plist        \
+
+libNGObjWeb_HEADER_FILES = \
+       NGObjWebDecls.h         \
+       NGObjWeb.h              \
+       OWResponder.h           \
+       OWViewRequestHandler.h  \
+       OWResourceManager.h     \
+       WEClientCapabilities.h  \
+       WOActionResults.h       \
+       WOAdaptor.h             \
+       WOApplication.h         \
+       WOCoreApplication.h     \
+       WOAssociation.h         \
+       WOComponent.h           \
+       WOContext.h             \
+       WOCookie.h              \
+       WODirectAction.h        \
+       WODisplayGroup.h        \
+       WODynamicElement.h      \
+       WOElement.h             \
+       WOHTTPConnection.h      \
+       WOMailDelivery.h        \
+       WOMessage.h             \
+       WORequest.h             \
+       WORequestHandler.h      \
+       WOResourceManager.h     \
+       WOResponse.h            \
+       WOSession.h             \
+       WOSessionStore.h        \
+       WOStatisticsStore.h     \
+       WOTemplateBuilder.h     \
+        WOxElemBuilder.h       \
+       WOTemplate.h            \
+       WOComponentScript.h     \
+       WOProxyRequestHandler.h \
+       WOPageGenerationContext.h       \
+       WOElementTrackingContext.h      \
+
+NGObjWebCore_OBJC_FILES = \
+       NSObject+WO.m                   \
+       WOApplication+defaults.m        \
+       WOApplication.m                 \
+       WOCoreApplication.m             \
+       WOComponent.m                   \
+       WOComponent+Sync.m              \
+       WOComponentDefinition.m         \
+       WOComponentFault.m              \
+       WOContext.m                     \
+       WOElement.m                     \
+       WOMessage.m                     \
+       WORequest.m                     \
+       WOResourceManager.m             \
+       WOResponse.m                    \
+       WORunLoop.m                     \
+       WOSession.m                     \
+       WOSessionStore.m                \
+       WOStatisticsStore.m             \
+       _WOStringTable.m                \
+       WOScriptedComponent.m           \
+        WOElementID.m                  \
+
+libNGObjWeb_OBJC_FILES = \
+       $(NGObjWebCore_OBJC_FILES)      \
+       NGHttp+WO.m                     \
+       NGObjWeb.m                      \
+       OWViewRequestHandler.m          \
+       OWResourceManager.m             \
+       SNSConnection.m                 \
+       UnixSignalHandler.m             \
+       WEClientCapabilities.m          \
+       WOAdaptor.m                     \
+       WOApplicationMain.m             \
+       WOChildComponentReference.m     \
+       WOComponent+JS.m                \
+       WOComponentRequestHandler.m     \
+       WOCookie.m                      \
+       WOCoreApplication+Bundle.m      \
+       WODirectAction.m                \
+       WODirectActionRequestHandler.m  \
+       WODisplayGroup.m                \
+       WODynamicElement.m              \
+       WOFileSessionStore.m            \
+       WOHTTPConnection.m              \
+       WOHTTPURLHandle.m               \
+       WOMailDelivery.m                \
+       WOMessage+XML.m                 \
+       WOMessage+Validation.m          \
+       WOPageRequestHandler.m          \
+       WOProxyRequestHandler.m         \
+       WORequestHandler.m              \
+       WOResourceRequestHandler.m      \
+       WOServerSessionStore.m          \
+       WOSession+JS.m                  \
+       WOSimpleHTTPParser.m            \
+       WOStats.m                       \
+       WOWatchDogApplicationMain.m     \
+
+# ----- SoCore product for SOPE core registrations
+
+BUNDLE_NAME      = SoCore SoOFS
+BUNDLE_EXTENSION = .sxp
+BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SoProducts
+
+SoCore_OBJC_FILES      = SoCoreProduct.m
+SoCore_RESOURCE_FILES  = SoObjects/product.plist Version
+SoCore_PRINCIPAL_CLASS = SoCoreProduct
+
+SoOFS_OBJC_FILES       = SoOFSProduct.m
+SoOFS_RESOURCE_FILES   = SoOFS/product.plist Version
+SoOFS_PRINCIPAL_CLASS  = SoOFSProduct
+
+# ----- NGObjWeb tools
+
+TOOL_NAME = wod xmlrpc_call sope
+
+wod_OBJC_FILES  += wod.m $(NGObjWebCore_OBJC_FILES)
+ifeq ($(FOUNDATION_LIB),gnu)
+wod_OBJC_FILES  += UnixSignalHandler.m
+endif
+wod_SUBPROJECTS = Templates Associations
+
+xmlrpc_call_OBJC_FILES = xmlrpc_call.m
+sope_OBJC_FILES        = sope.m
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+include $(GNUSTEP_MAKEFILES)/bundle.make
+include $(GNUSTEP_MAKEFILES)/tool.make
+-include GNUmakefile.postamble
+
+autodoc :
+       autodoc $(AUTODOC_FLAGS) -dest $(AUTODOC_DESTPATH)/NGObjWeb/ -proj .
diff --git a/skyrix-sope/NGObjWeb/GNUmakefile.postamble b/skyrix-sope/NGObjWeb/GNUmakefile.postamble
new file mode 100644 (file)
index 0000000..588b071
--- /dev/null
@@ -0,0 +1,25 @@
+# $Id$
+
+$(RESOURCES_DIR) :
+       $(MKDIRS) $(RESOURCES_DIR)
+
+ngobjweb-resources : $(RESOURCES_DIR) $(libNGObjWeb_RESOURCES)
+       @(if [ "$(libNGObjWeb_RESOURCES)" != "" ]; then \
+         echo "Copying resources into install path ..."; \
+          for ff in $(libNGObjWeb_RESOURCES); do \
+           cp $$ff $(RESOURCES_DIR)/$$ff; \
+          done; \
+       fi)
+
+after-install :: ngobjweb-resources
+#      $(INSTALL_DATA) woapp.make wobundle.make $(GNUSTEP_MAKEFILES)
+
+after-install ::
+       $(MKDIRS) $(GNUSTEP_MAKEFILES)/Additional/
+       $(INSTALL_DATA) ngobjweb.make $(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make
+
+ifneq ($(GNUSTEP_MAKE_VERSION),1.3.0)
+after-install ::
+       $(INSTALL_DATA) woapp-gs.make    $(GNUSTEP_MAKEFILES)/woapp.make
+       $(INSTALL_DATA) wobundle-gs.make $(GNUSTEP_MAKEFILES)/wobundle.make
+endif
diff --git a/skyrix-sope/NGObjWeb/GNUmakefile.preamble b/skyrix-sope/NGObjWeb/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..3c1576a
--- /dev/null
@@ -0,0 +1,96 @@
+# $Id$
+
+ADDITIONAL_CPPFLAGS += -Wall -DCOMPILE_FOR_GSTEP_MAKE=1
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I.                     \
+       -I./DynamicElements/    \
+       -I./Templates/          \
+       -I..                    \
+       -I../../skyrix-core             \
+       -I../../skyrix-core/NGStreams/  \
+       -I../../skyrix-core/NGExtensions
+
+libNGObjWeb_OBJCFLAGS += -Wall -Wno-import -Wno-protocol
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_JS=$(GNUSTEP_BUILD_DIR)/../../../ThirdParty/js-1.5
+RELBUILD_DIR_SOPE=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/../../skyrix-core
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                                            \
+       -L$(RELBUILD_DIR_SOPE)/NGJavaScript/$(GNUSTEP_OBJ_DIR_NAME)     \
+       -L$(RELBUILD_DIR_SOPE)/NGScripting/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxCore)/NGMime/$(GNUSTEP_OBJ_DIR_NAME)         \
+       -L$(RELBUILD_DIR_SxCore)/NGStreams/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+       -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxXml)/XmlRpc/$(GNUSTEP_OBJ_DIR_NAME)          \
+       -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)             \
+       -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)         \
+       -L$(RELBUILD_DIR_JS)/$(GNUSTEP_OBJ_DIR_NAME)
+
+else
+libNGObjWeb_LIB_DIRS += \
+       -L./$(GNUSTEP_OBJ_DIR)                  \
+       -L../NGJavaScript/$(GNUSTEP_OBJ_DIR)    \
+       -L../NGScripting/$(GNUSTEP_OBJ_DIR)     \
+       -L../../skyrix-core/NGMime/$(GNUSTEP_OBJ_DIR)           \
+       -L../../skyrix-core/NGStreams/$(GNUSTEP_OBJ_DIR)        \
+       -L../../skyrix-core/NGExtensions/$(GNUSTEP_OBJ_DIR)     \
+       -L../../skyrix-core/EOControl/$(GNUSTEP_OBJ_DIR)        \
+       -L../../skyrix-xml/XmlRpc/$(GNUSTEP_OBJ_DIR)            \
+       -L../../skyrix-xml/DOM/$(GNUSTEP_OBJ_DIR)               \
+       -L../../skyrix-xml/SaxObjC/$(GNUSTEP_OBJ_DIR)
+endif
+
+libNGObjWeb_LIBRARIES_DEPEND_UPON += \
+       -lNGJavaScript -lNGScripting                    \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC                        \
+       -ljs
+
+wod_LIB_DIRS  += $(libNGObjWeb_LIB_DIRS)
+wod_TOOL_LIBS += \
+       -lNGObjWeb -lNGJavaScript -lNGScripting \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lDOM -lSaxObjC
+
+xmlrpc_call_LIB_DIRS += $(libNGObjWeb_LIB_DIRS)
+sope_LIB_DIRS        += $(libNGObjWeb_LIB_DIRS)
+
+xmlrpc_call_TOOL_LIBS += \
+       -lNGObjWeb -lNGJavaScript -lNGScripting \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC
+
+sope_TOOL_LIBS += \
+       -lNGObjWeb -lNGJavaScript -lNGScripting \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC
+
+# platform specific settings
+
+ifneq ($(findstring openbsd3, $(GNUSTEP_TARGET_OS)), openbsd3)
+# OpenBSD does not require libcrypt
+ifneq ($(findstring darwin, $(GNUSTEP_TARGET_OS)), darwin)
+# and neither does MacOSX? ...
+libNGObjWeb_LIBRARIES_DEPEND_UPON += -lcrypt
+sope_TOOL_LIBS += -lcrypt
+endif
+endif
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libNGObjWeb_PREBIND_ADDR="0xC4900000"
+libNGObjWeb_LDFLAGS += -seg1addr $(libNGObjWeb_PREBIND_ADDR)
+endif
+
+ifeq ($(FOUNDATION_LIB),nx)
+wod_TOOL_LIBS += -lDOM -lSaxObjC -lFoundationExt
+wod_LDFLAGS += -framework Foundation
+libNGObjWeb_LIBRARIES_DEPEND_UPON += -lFoundationExt
+endif
diff --git a/skyrix-sope/NGObjWeb/Languages.plist b/skyrix-sope/NGObjWeb/Languages.plist
new file mode 100644 (file)
index 0000000..c85f324
--- /dev/null
@@ -0,0 +1,174 @@
+{
+"__doc__" = "
+/* Browser Language-Mappings for NGObjWeb */
+/*
+   ISO 639 Language Codes from:
+
+     http://www.stonehand.com/unicode/standard/iso639.html
+
+   map ISO codes to OpenStep names.
+*/";
+  "aa"          = "Afar";
+  "ab"          = "Abkhazian";
+  "af"    = "Afrikaans";                           
+  "am"    = "Amharic";
+  "ar"    = "Arabic";                           
+  "as"    = "Assamese";   
+  "ay"    = "Aymara";                           
+  "az"    = "Azerbaijani";   
+  "ba"    = "Bashkir";                           
+  "be"    = "Byelorussian";  
+  "bg"    = "Bulgarian";                           
+  "bh"    = "Bihari";
+  "bi"    = "Bislama";                           
+  "bn"    = "Bengali";  
+  "bo"    = "Tibetan";                           
+  "br"    = "Breton";  
+  "ca"    = "Catalan";                           
+  "co"    = "Corsican";  
+  "cs"    = "Czech";                           
+  "cy"    = "Welsh";    
+  "da"    = "Danish";
+  "da-dk" = "Danish";                           
+  "de"    = "German";
+  "de-at" = "German";
+  "de-de" = "German";
+  "de-ch" = "German";
+  "de-lu" = "German"; // TODO: should be Luxembourgish?
+  "dz"    = "Bhutani";
+  "el"    = "Greek";
+  "en"    = "English";
+  "en-us" = "English";
+  "en-gb" = "English";
+  "eo"    = "Esperanto";
+  "es"    = "Spanish";
+  "es-cl" = "Spanish";
+  "es-es" = "Spanish";
+  "et"    = "Estonian";
+  "eu"    = "Basque";
+  "fa"    = "Persian";
+  "fi"    = "Finnish";
+  "fi-fi" = "Finnish";
+  "fj"    = "Fiji";
+  "fo"    = "Faeroese";
+  "fr"    = "French";
+  "fr-fr" = "French";
+  "fr-be" = "French";
+  "fr-lu" = "French";
+  "fy"    = "Frisian";
+  "ga"    = "Irish";
+  "gd"    = "ScotsGaelic";
+  "gl"    = "Galician";
+  "gn"    = "Guarani";
+  "gu"    = "Gujarati";
+  "ha"    = "Hausa";
+  "he"    = "Hebrew";
+  "hi"    = "Hindi";
+  "hr"    = "Croatian";
+  "hu"    = "Hungarian";
+  "hy"    = "Armenian";
+  "ia"    = "Interlingua";
+  "id"    = "Indonesian";
+  "ie"    = "Interlingue";
+  "ik"    = "Inupiak";
+  "in"    = "Indonesian";
+  "is"    = "Icelandic";
+  "it"    = "Italian";
+  "it-it" = "Italian";
+  "iu"    = "Inuktitut";
+  "iw"    = "Hebrew";
+  "ja"    = "Japanese";
+  "ja-jp" = "Japanese";
+  "ji"    = "Yiddish";
+  "jw"    = "Javanese";
+  "ka"    = "Georgian";
+  "kk"    = "Kazakh";
+  "kl"    = "Greenlandic";
+  "km"    = "Cambodian";
+  "kn"    = "Kannada";
+  "ko"    = "Korean";
+  "ks"    = "Kashmiri";
+  "ku"    = "Kurdish";
+  "ky"    = "Kirghiz";
+  "la"    = "Latin";
+  "ln"    = "Lingala";
+  "lo"    = "Laothian";
+  "lt"    = "Lithuanian";
+  "lv"    = "Latvian";
+  "mg"    = "Malagasy";
+  "mi"    = "Maori";
+  "mk"    = "Macedonian";
+  "ml"    = "Malayalam";
+  "mn"    = "Mongolian";
+  "mo"    = "Moldavian";
+  "mr"    = "Marathi";
+  "ms"    = "Malay";
+  "mt"    = "Maltese";
+  "my"    = "Burmese";  
+  "na"    = "Nauru";
+  "nb"    = "NorwegianBokmaal";
+  "ne"    = "Nepali";    
+  "nl"    = "Dutch";                           
+  "nl-nl" = "Dutch";                           
+  "no"    = "Norwegian";    
+  "no-no" = "Norwegian";    
+  "oc"    = "Occitan";                           
+  "om"    = "Oromo";  
+  "or"    = "Oriya";                           
+  "pa"    = "Punjabi";    
+  "pl"    = "Polish";                           
+  "ps"    = "Pashto";   
+  "pt"    = "Portuguese";                           
+  "pt-br" = "ptBR";                           
+  "pt-pt" = "Portuguese";                           
+  "qu"    = "Quechua";
+  "rm"    = "RhaetoRomance";
+  "rn"    = "Kirundi";
+  "ro"    = "Romanian";                           
+  "ru"    = "Russian";   
+  "rw"    = "Kinyarwanda";                           
+  "sa"    = "Sanskrit";
+  "sd"    = "Sindhi";                           
+  "sg"    = "Sangro";
+  "sh"    = "SerboCroatian";
+  "si"    = "Singhalese";
+  "sk"    = "Slovak";
+  "sl"    = "Slovenian";     
+  "sm"    = "Samoan";                           
+  "sn"    = "Shona";     
+  "so"    = "Somali";                           
+  "sq"    = "Albanian";     
+  "sr"    = "Serbian";                           
+  "ss"    = "Siswati";    
+  "st"    = "Sesotho";                           
+  "su"    = "Sundanese";    
+  "sv"    = "Swedish";                           
+  "sv-se" = "Swedish";                           
+  "sw"    = "Swahili";    
+  "ta"    = "Tamil";                           
+  "te"    = "Tegulu";      
+  "tg"    = "Tajik";                           
+  "th"    = "Thai";      
+  "ti"    = "Tigrinya";                           
+  "tk"    = "Turkmen";   
+  "tl"    = "Tagalog";                           
+  "tn"    = "Setswana";    
+  "to"    = "Tonga";                           
+  "tr"    = "Turkish";      
+  "ts"    = "Tsonga";                           
+  "tt"    = "Tatar";     
+  "tw"    = "Twi";                           
+  "ug"    = "Uigur";        
+  "uk"    = "Ukrainian";                           
+  "ur"    = "Urdu";  
+  "uz"    = "Uzbek";                           
+  "vi"    = "Vietnamese";      
+  "vo"    = "Volapuk";                           
+  "wo"    = "Wolof";    
+  "xh"    = "Xhosa";                           
+  "yi"    = "Yiddish";      
+  "yo"    = "Yoruba";                           
+  "za"    = "Zhuang";     
+  "zh"    = "Chinese";                           
+  "zu"    = "Zulu";    
+}
diff --git a/skyrix-sope/NGObjWeb/NGHttp+WO.h b/skyrix-sope/NGObjWeb/NGHttp+WO.h
new file mode 100644 (file)
index 0000000..19dd905
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_NGHttp_WO_H__
+#define __NGObjWeb_NGHttp_WO_H__
+
+#include <NGHttp/NGHttpRequest.h>
+
+@class NSString, NSData, NSArray;
+@class WORequest;
+
+@interface NGHttpRequest(WOSupport)
+
+/* transformation */
+
+- (id)initWithWORequest:(WORequest *)_request;
+- (WORequest *)woRequest;
+
+/* headers */
+
+- (NSArray *)woHeaderKeys;
+- (NSString *)woHeaderForKey:(NSString *)_key;
+- (NSArray *)woHeadersForKey:(NSString *)_key;
+
+/* cookies */
+
+- (NSArray *)woCookies;
+
+/* content */
+
+- (NSData *)woContent;
+
+/* form parameters */
+
+- (NGHashMap *)formParameters;
+
+@end
+
+#endif /* __NGObjWeb_NGHttpRequest_WO_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp+WO.m b/skyrix-sope/NGObjWeb/NGHttp+WO.m
new file mode 100644 (file)
index 0000000..c643154
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGHttp+WO.h"
+#include <NGHttp/NGHttp.h>
+#include <NGObjWeb/WOCookie.h>
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+@interface WORequest(NGSupport)
+- (void)_setHttpRequest:(NGHttpRequest *)_request;
+@end
+
+@implementation NGHttpRequest(WOSupport)
+
+static Class NSArrayClass = Nil;
+
+- (id)initWithWORequest:(WORequest *)_request {
+  NGHashMap *hm;
+  
+  hm = [NGHashMap hashMapWithDictionary:[_request headers]];
+    
+  self = [self initWithMethod:[_request method]
+               uri:[_request uri]
+               header:hm
+               version:[_request httpVersion]];
+  [self setBody:[_request content]];
+  
+  /* transfer cookies */
+  if ([[_request cookies] count] > 0)
+    NSLog(@"WARNING: cannot transfer cookies to NGHttpRequest yet !");
+
+  /* transfer headers !!! */
+  
+  return self;
+}
+
+- (WORequest *)woRequest {
+  NSAutoreleasePool *pool;
+  WORequest    *request;
+  NSDictionary *woHeaders;
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  woHeaders = nil;
+  
+  request = [[WORequest alloc]
+                        initWithMethod:[self methodName]
+                        uri:[self uri]
+                        httpVersion:[self httpVersion]
+                        headers:woHeaders
+                        content:[self woContent]
+                        userInfo:nil];
+  request = [request autorelease];
+  
+  [request _setHttpRequest:self];
+  
+  /* process cookies */
+  {
+    NSEnumerator *cs;
+    WOCookie *cookie;
+    
+    cs = [[self woCookies] objectEnumerator];
+    while ((cookie = [cs nextObject]))
+      [request addCookie:cookie];
+  }
+  
+  /* process headers */
+  {
+    NSEnumerator *keys;
+    NSString *key;
+
+    if (NSArrayClass == Nil)
+      NSArrayClass = [NSArray class];
+    
+    keys = [self headerFieldNames];
+    while ((key = [keys nextObject])) {
+      NSEnumerator *values;
+      id value;
+      
+      values = [self valuesOfHeaderFieldWithName:key];
+      while ((value = [values nextObject])) {
+        if ([value isKindOfClass:NSArrayClass]) {
+          NSEnumerator *ev2;
+
+          ev2 = [value objectEnumerator];
+          while ((value = [ev2 nextObject])) {
+            value = [value stringValue];
+            [request appendHeader:value forKey:key];
+          }
+        }
+        else {
+          value = [value stringValue];
+          [request appendHeader:value forKey:key];
+        }
+      }
+    }
+  }
+  
+  request = [request retain];
+  [pool release]; pool = nil;
+  
+  return [request autorelease];
+}
+
+/* headers */
+
+- (NSArray *)woHeaderKeys {
+  NSMutableArray *keys;
+  NSEnumerator   *ekeys;
+  NSString       *key   = nil;
+  
+  keys  = [[NSMutableArray alloc] init];
+  ekeys = [self headerFieldNames];
+  
+  while ((key = [ekeys nextObject]))
+    [keys addObject:key];
+  
+  return [keys autorelease];
+}
+
+- (NSString *)woHeaderForKey:(NSString *)_key {
+  return [[[self valuesOfHeaderFieldWithName:_key]
+                 nextObject]
+                 stringValue];
+}
+
+- (NSArray *)woHeadersForKey:(NSString *)_key {
+  NSMutableArray *vals;
+  NSEnumerator   *evals;
+  NSString       *value = nil;
+
+  vals  = [NSMutableArray arrayWithCapacity:2];
+  evals = [self valuesOfHeaderFieldWithName:_key];
+  
+  while ((value = [evals nextObject])) {
+    if ((value = [value stringValue]))
+      [vals addObject:value];
+  }
+
+  return vals;
+}
+
+/* cookies */
+
+- (void)_addHTTPCookie:(id)_cookie to:(NSMutableArray *)_a {
+  static Class NGHttpCookieClass = Nil;
+  static Class WOCookieClass = Nil;
+  WOCookie *cookie;
+  id cookieValue;
+  
+  if (_cookie == nil)
+    return;
+  
+  if (NGHttpCookieClass == Nil) NGHttpCookieClass = [NGHttpCookie class];
+  if (WOCookieClass     == Nil) WOCookieClass = NSClassFromString(@"WOCookie");
+
+  if (![_cookie isKindOfClass:NGHttpCookieClass]) {
+    static NGHttpCookieFieldParser *cookieParser = nil;
+          
+    if (cookieParser == nil)
+      cookieParser = [[NGHttpCookieFieldParser alloc] init];
+          
+    _cookie = [_cookie stringValue];
+    _cookie = [_cookie dataUsingEncoding:NSISOLatin1StringEncoding];
+    _cookie = [cookieParser parseValue:_cookie ofHeaderField:@"cookie"];
+  }
+  
+  if ([_cookie isKindOfClass:[NSArray class]]) {
+    id singleCookie;
+      
+    _cookie = [_cookie objectEnumerator];
+    
+    while ((singleCookie = [_cookie nextObject]))
+      [self _addHTTPCookie:singleCookie to:_a];
+    return;
+  }
+
+    
+    cookieValue = [_cookie value];
+    if ([cookieValue isKindOfClass:[NSArray class]]) {
+      if ([cookieValue count] == 0)
+        cookieValue = @"";
+      else if ([cookieValue count] == 1)
+        cookieValue = [[cookieValue objectAtIndex:0] stringValue];
+      else {
+        [self logWithFormat:
+                @"got %i values for cookie '%@', using first only.",
+                [cookieValue count],
+                [_cookie cookieName]];
+        cookieValue = [[cookieValue objectAtIndex:0] stringValue];
+      }
+    }
+    else
+      cookieValue = [cookieValue stringValue];
+    
+    cookie = [WOCookieClass cookieWithName:[_cookie cookieName]
+                            value:cookieValue
+                            path:[_cookie path]
+                            domain:[_cookie domainName]
+                            expires:[_cookie expireDate]
+                            isSecure:[_cookie needsSecureChannel]];
+  
+    /* WOMessage */
+    if (cookie)
+      [_a addObject:cookie];
+}
+
+- (NSArray *)woCookies {
+  NSMutableArray *womCookies;
+  NSArray        *woCookies;
+  NSEnumerator   *mcookies;
+  id             cookie;
+
+  if (NSArrayClass == Nil) NSArrayClass = [NSArray class];
+  
+  womCookies = [NSMutableArray arrayWithCapacity:8];
+  
+  mcookies = [self valuesOfHeaderFieldWithName:@"cookie"];
+  while ((cookie = [mcookies nextObject])) {
+    if ([cookie isKindOfClass:NSArrayClass]) {
+      id singleCookie;
+      
+      cookie = [cookie objectEnumerator];
+      
+      while ((singleCookie = [cookie nextObject]))
+        [self _addHTTPCookie:singleCookie to:womCookies];
+      
+      continue;
+    }
+    
+    [self _addHTTPCookie:cookie to:womCookies];
+  }
+  
+  woCookies = [womCookies copy];
+  return [woCookies autorelease];
+}
+
+/* content */
+
+- (NSData *)woContent {
+  NGMimePartGenerator *gen;
+  id content;
+  
+  if ((content = [self body]) == nil) {
+    /* no body */
+    return nil;
+  }
+  
+  if ([content isKindOfClass:[NSData class]])
+    return content;
+  
+  if (![content conformsToProtocol:@protocol(NGMimePart)])
+    return [[content stringValue] dataUsingEncoding:NSASCIIStringEncoding];
+  
+  gen  = [[NGMimePartGenerator alloc] init];
+  content = [gen generateMimeFromPart:content];
+  [gen release];
+  return content;
+}
+
+/* form parameters */
+
+static NGMimeType *multipartFormData = nil;
+static Class      DispClass = Nil;
+
+- (id)_decodeMultiPartFormDataContent {
+  NGMutableHashMap    *formContent;
+  NGMimeMultipartBody *ebody;
+  NSArray             *parts;
+  unsigned            i, count;
+
+  if (DispClass == Nil)
+    DispClass = [NGMimeContentDispositionHeaderField class];
+  
+  ebody = [self body];
+  if (![ebody isKindOfClass:[NGMimeMultipartBody class]]) {
+    [self logWithFormat:
+           @"ERROR: form-data parser expected MultipartBody, got %@", ebody];
+    return [[NGHashMap alloc] init];
+  }
+  
+  parts = [ebody parts];
+  count = [parts count];
+  
+  [self debugWithFormat:@"%s:   %i parts %@", __PRETTY_FUNCTION__, 
+          count, parts];
+  
+  formContent = [[NGMutableHashMap alloc] init];
+  for (i = 0; i < count; i++) {
+    NGMimeContentDispositionHeaderField *disposition;
+    id<NGMimePart> bodyPart;
+    NSString *name;
+    id       partBody;
+         
+    bodyPart = [parts objectAtIndex:i];
+    disposition =
+      [[bodyPart valuesOfHeaderFieldWithName:@"content-disposition"]nextObject];
+          
+    if (disposition == nil) {
+      [self logWithFormat:
+             @"ERROR: did not find content disposition in form part %@",
+             bodyPart];
+      continue;
+    }
+
+    /* morph to disposition field in case it's unparsed ... */
+    if (![disposition isKindOfClass:DispClass]) {
+              disposition =
+                [[DispClass alloc] initWithString:[disposition stringValue]];
+              [disposition autorelease];
+    }
+            
+    name     = [disposition name];
+    partBody = [bodyPart body];
+    
+    if (partBody)
+      [(NGMutableHashMap *)formContent addObject:partBody forKey:name];
+  }
+  return formContent;
+}
+
+- (NGHashMap *)_decodeFormContentURLParameters:(id)formContent {
+  /* all this sounds expensive ;-) */
+  NSString   *s;
+  unsigned   urilen;
+  char       *uribuf;
+  const char *p = uribuf;
+  NGHashMap  *map;
+  
+  if ((s = [self uri]) == nil)
+    return formContent;
+  if ([s rangeOfString:@"?"].length == 0)
+    return formContent;
+  
+  urilen = [s cStringLength];
+  p = uribuf = malloc(urilen + 4);
+  [s getCString:uribuf]; // UNICODE?
+  
+  if ((p = index(p, '?')) == NULL) {
+    if (uribuf) free(uribuf);
+    return formContent;
+  }
+  
+  p++; // skip the '?'
+  map = NGDecodeUrlFormParameters(p, strlen(p));
+  if (uribuf) free(uribuf); uribuf = NULL; p = NULL;
+  
+  if (map == nil) 
+    return formContent;
+  if (formContent == nil)
+    return map;
+  
+  map = [map autorelease]; // NGDecodeUrlFormParameters returns a retained map!
+  
+  if ([formContent isKindOfClass:[NGHashMap class]]) {
+    NSEnumerator *keys;
+    id key, tmp;
+  
+    tmp = formContent;
+    formContent =  [[NGMutableHashMap alloc] initWithHashMap:tmp];
+    [tmp release];
+  
+    keys = [map keyEnumerator];
+    while ((key = [keys nextObject])) {
+      NSEnumerator *values;
+      id value;
+            
+      values = [map objectEnumeratorForKey:key];
+      while ((value = [values nextObject]))
+       [formContent addObject:value forKey:key];
+    }
+  }
+  else if ([formContent isKindOfClass:[NSDictionary class]]) {
+    NSEnumerator *keys;
+    id key, tmp;
+         
+    tmp = formContent;
+    formContent = [[NGMutableHashMap alloc] initWithDictionary:tmp];
+    [tmp release];
+  
+    keys = [map keyEnumerator];
+    while ((key = [keys nextObject])) {
+      NSEnumerator *values;
+      id value;
+  
+      values = [map objectEnumeratorForKey:key];
+      while ((value = [values nextObject]))
+       [formContent addObject:value forKey:key];
+    }
+  }
+  return formContent;
+}
+
+- (NGHashMap *)formParameters {
+  id formContent;
+  
+  if (multipartFormData == nil) {
+    multipartFormData = [NGMimeType mimeType:@"multipart/form-data"];
+    multipartFormData = [multipartFormData retain];
+  }
+  
+  if ([[self methodName] isEqualToString:@"POST"]) {
+    NGMimeType *contentType = [self contentType];
+    
+    //NSLog(@"%s: process POST, ctype %@", __PRETTY_FUNCTION__, contentType);
+    
+    formContent = [contentType hasSameType:multipartFormData]
+      ? [self _decodeMultiPartFormDataContent]
+      : [[self body] retain];
+  }
+  else
+    formContent = nil;
+  
+  /* decode URL parameters */
+  formContent = [self _decodeFormContentURLParameters:formContent];
+  
+  return [formContent autorelease];
+}
+
+@end /* NGHttpRequest */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/.cvsignore b/skyrix-sope/NGObjWeb/NGHttp/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-sope/NGObjWeb/NGHttp/ChangeLog b/skyrix-sope/NGObjWeb/NGHttp/ChangeLog
new file mode 100644 (file)
index 0000000..22f5e36
--- /dev/null
@@ -0,0 +1,253 @@
+2004-06-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile: added some include pathes to allow "in-place" 
+         compilation of SOPE (v4.2.408)
+
+2004-01-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpRequest.m, NGHttpMessage.m: minor cleanups, do not log form
+         processing on the command line (v4.2.286)
+
+2003-10-15  Helge Hess  <helge@groove.local.>
+
+       * NGHttpHeaderFields.m: fixed warning on OSX (v4.2.227)
+
+2003-05-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpCookie.m: small cleanups (v4.2.173)
+
+2003-01-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpMessageParser.m: check superclass version
+
+       * NGHttpBodyParser.m: check superclass version
+
+2002-11-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpMessageParser.m: parses now checks the HTTP version when
+         determining whether to parse a body of a request without content-
+         length (v4.2.68)
+
+2002-10-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpMessageParser.m: added SUBSCRIBE/UNSCRIBE to the request 
+         methods were no body parsing is performed (v4.2.59)
+
+2002-10-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpRequest.h: added some WebDAV/HTTP methods (v4.2.52)
+
+2002-10-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpMessageParser.m ([NGHttpMessageParser -parserForBodyOfPart:data:]): 
+         do not parse MKCOL and DELETE HTTP requests (v4.2.40)
+
+2002-06-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpHeaderFieldParser.m: removed all -removeCommentsFromValue:
+         calls, since HTTP doesn't allow comments in headers anyway.
+
+Fri Jun  7 17:21:59 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGHttpHeaderFieldParser.m: changes for charset NGMime support
+
+Fri May 17 15:34:51 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved as a subproject to NGObjWeb
+
+       * GNUmakefile: removed linking against NGZlib
+
+Thu Feb 21 11:19:48 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed NGHttpServer, EventHandler etc (all serving related stuff)
+
+Thu Nov 29 10:45:52 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpHeaderFieldParser.m ([NGHttpCookieFieldParser -parseValuePart:length:zone:]):
+         improved error handling ...
+
+Wed Oct 17 01:44:40 2001  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NGUrlFormCoder.m: fixed unsigned char bug
+
+Fri Oct 12 10:29:38 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpHeaderFields.m: added +credentialsWithString:
+
+Thu Aug  9 16:19:20 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpHeaderFieldParser.m: use -stringByUnescapingURL
+
+       * NGHttpCookie.m: use -stringByEscapingURL
+
+Tue Jul 24 20:51:32 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpMessageParser.m: don't parse bodies of OPTION requests
+
+Thu Jul  5 21:15:26 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGUrlFormCoder.m: changed to break formvalues on '?' as well 
+         (specified is '&' only ..., but sometimes incorrect URLs are 
+         generated)
+
+Wed Jun  6 16:24:23 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpHeaderFields.m: less restrictive parsing of 'connection' header
+
+Tue May 29 18:41:42 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGHttpMessageParser.m: made less whitespace sensitive during request
+         line parsing (since Netscape 4.77 sometimes sends broken URLs ..)
+
+Thu Feb  1 19:30:25 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpRequest.m: added MKCOL, LOCK and UNLOCK request methods
+
+Wed Jan 31 15:12:27 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpRequest.m: added PROPFIND, PROPPATCH request method
+
+Wed Dec 13 14:05:54 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpMessageParser.m: always parse response content
+
+Mon Dec  4 13:03:32 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpMessageParser.m: extracted dead code (some kind of own HTTP
+         parser ??)
+
+Mon Sep 18 11:09:46 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpHeaderFields.m: connection-header-parser can parse 'close'
+
+Fri Sep 15 01:09:52 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpMessageParser: implemented parsing of response lines
+
+Tue Aug 15 12:06:04 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpHeaderFieldParser.m: fixed bug in header-field parser
+
+Wed Jul  5 13:47:49 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpServer.m: removed exit(0)
+
+Fri Jun 23 14:25:00 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpMessageParser.m: reverted changes for buffers
+
+Fri Jun 23 12:09:16 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpMessageParser.m: fixed malloc bug
+
+Wed Jun 14 17:30:44 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGUrlFormCoder.m: added NSString method to encode strings in URL 
+         encoding
+
+Fri Jun  9 17:54:58 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * GNUmakefile (ADDITIONAL_CPPFLAGS): added -Wall
+
+Tue Feb 29 18:29:08 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * MOF3 import
+
+Fri Sep 17 15:05:54 1999  Helge Hess  <helge.hess@mdlink.de>
+
+       * NGHttpHeaderFields.m: fixed bugs in -stringValue methods
+
+Mon Jul 19 10:47:16 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpEventHandler.m: disabled request logging
+
+Mon May 31 14:15:59 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpHeaderFieldParser.m: string header field parsers do not
+         remove comments anymore (eg user-agent field)
+
+Thu Apr 22 19:02:29 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * adopted to modifications in NGMime
+
+Mon Mar 29 11:42:55 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpServer.h: fixed bug in header file
+
+       * GNUmakefile: added kit class
+
+Fri Jan 29 20:25:20 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * removed NGLog's
+
+Tue Jan 19 14:50:47 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpServer.m: support server termination
+
+       * NGHttpMessage.m: no extracted headers to keep content consistent
+
+       * NGHttpHeaderFieldParser.m: fixed some bugs
+
+Sat Jan  9 21:09:02 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpEventHandler.m: added request logging
+
+Fri Jan  8 16:26:53 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpMessage.m: added -addValue:toHeaderFieldWithName: and
+         -removeValue:fromHeaderFieldWithName: methods
+
+Mon Jan  4 17:38:13 1999  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpEventHandler.m: added support for local domain sockets
+
+Mon Dec 28 16:00:55 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpServer.m: added -logWithFormat:, replaced NSLog
+
+       * NGHttpEventHandler.m: added on-the-fly compression
+
+       * NGHttpEventHandler.m: added -logWithFormat: method
+
+       * NGHttpServer.m: added accessors to set/get maxThreadCount
+
+Wed Dec 16 10:39:26 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpServer.h: fixed bug in header
+
+Fri Nov 27 16:04:14 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * started WIN32 support
+
+Thu Nov 26 10:14:50 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpHeaderFieldParser.m: added 'accept-encoding' field parser,
+         new register function for defaultParserSet
+
+Wed Nov 11 16:21:14 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * GNUmakefile: uses ../kit.make, ../common.make now
+
+Wed Nov  4 14:48:16 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpRequest.m: added capability to decode URL form parameters
+
+       * added NGUrlFormCoder to unescape/decode x-www-form-urlencoded strings
+
+       * NGHttpBodyParser.m: added FORM Url Body parser
+
+Wed Oct 28 18:35:34 1998  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpServer.m: added methods to manually add services and mappings
+
+       * NGHttpServer.m: added request timing
+
+1998-10-19  Helge Hess  <helge@trex.mdlink.de>
+
+       * NGHttpServer.m: prepared for multi-threading
+
+1998-10-09  Helge Hess  <helge@trex.mdlink.de>
+
+       * moved NSRunLoop outside NGHttpServer
+
+       * created ChangeLog
diff --git a/skyrix-sope/NGObjWeb/NGHttp/GNUmakefile b/skyrix-sope/NGObjWeb/NGHttp/GNUmakefile
new file mode 100644 (file)
index 0000000..7fb02d8
--- /dev/null
@@ -0,0 +1,39 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT)
+
+SUBPROJECT_NAME = NGHttp
+
+NGHttp_HEADER_FILES_DIR         = .
+NGHttp_HEADER_FILES_INSTALL_DIR = /NGHttp
+
+NGHttp_HEADER_FILES = \
+       NGHttpDecls.h                   \
+       NGHttp.h                        \
+       NGHttpCookie.h                  \
+       NGHttpHeaderFieldParser.h       \
+       NGHttpHeaderFields.h            \
+       NGHttpBodyParser.h              \
+       NGHttpMessage.h                 \
+       NGHttpMessageParser.h           \
+       NGHttpRequest.h                 \
+       NGHttpResponse.h                \
+       NGUrlFormCoder.h                \
+
+NGHttp_OBJC_FILES = \
+       NGHttp.m                        \
+       NGHttpCookie.m                  \
+       NGHttpHeaderFieldParser.m       \
+       NGHttpHeaderFields.m            \
+       NGHttpBodyParser.m              \
+       NGHttpMessage.m                 \
+       NGHttpMessageParser.m           \
+       NGHttpRequest.m                 \
+       NGHttpResponse.m                \
+       NGUrlFormCoder.m                \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjWeb/NGHttp/GNUmakefile.preamble b/skyrix-sope/NGObjWeb/NGHttp/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..04fc04d
--- /dev/null
@@ -0,0 +1,9 @@
+# $Id$
+
+NGHttp_INCLUDE_DIRS += \
+       -I.. -I../..    \
+       -I../../../skyrix-core                  \
+       -I../../../skyrix-core/NGStreams        \
+       -I../../../skyrix-core/NGExtensions     \
+
+ADDITIONAL_CPPFLAGS += -Wall -pipe
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttp-Info.plist b/skyrix-sope/NGObjWeb/NGHttp/NGHttp-Info.plist
new file mode 100644 (file)
index 0000000..d9f48b1
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGHttp</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.NGHttp</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttp.h b/skyrix-sope/NGObjWeb/NGHttp/NGHttp.h
new file mode 100644 (file)
index 0000000..7b9facb
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_H__
+#define __NGHttp_H__
+
+#import <NGHttp/NGHttpMessage.h>
+#import <NGHttp/NGHttpMessageParser.h>
+#import <NGHttp/NGHttpRequest.h>
+#import <NGHttp/NGHttpResponse.h>
+#import <NGHttp/NGHttpHeaderFieldParser.h>
+#import <NGHttp/NGHttpHeaderFields.h>
+#import <NGHttp/NGHttpCookie.h>
+#import <NGHttp/NGUrlFormCoder.h>
+
+// kit class
+
+@interface NGHttp : NSObject
+@end
+
+#define LINK_NGHttp \
+  static void __link_NGHttp(void) { \
+    [NGHttp self]; \
+    __link_NGHttp(); \
+  }
+
+#endif /* __NGHttp_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttp.m b/skyrix-sope/NGObjWeb/NGHttp/NGHttp.m
new file mode 100644 (file)
index 0000000..6cf431b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "NGHttp.h"
+#import <NGStreams/NGStreams.h>
+#import <NGStreams/NGNet.h>
+#import <NGMime/NGMime.h>
+
+@implementation NGHttp
+@end /* NGHttp */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpBodyParser.h b/skyrix-sope/NGObjWeb/NGHttp/NGHttpBodyParser.h
new file mode 100644 (file)
index 0000000..ab38070
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_NGHttpBodyParser_H__
+#define __NGHttp_NGHttpBodyParser_H__
+
+#import <NGMime/NGMimeBodyParser.h>
+
+@interface NGFormUrlBodyParser : NSObject < NGMimeBodyParser >
+{
+}
+
+@end
+
+@interface NGHttpMultipartFormDataBodyParser: NGMimeMultipartBodyParser
+{
+}
+
+@end
+
+#endif /* __NGHttp_NGHttpBodyParser_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpBodyParser.m b/skyrix-sope/NGObjWeb/NGHttp/NGHttpBodyParser.m
new file mode 100644 (file)
index 0000000..c3e4f04
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NGHttpBodyParser.h"
+#import "NGUrlFormCoder.h"
+
+@implementation NGFormUrlBodyParser
+
+- (id)parseBodyOfPart:(id<NGMimePart>)_part data:(NSData *)_data delegate:(id)_d {
+  const char *bytes;
+  unsigned   len;
+  id         body;
+
+  len   = [_data length];
+  bytes = [_data bytes];
+
+  // cut off spaces at the end
+  while (len > 0) {
+    if ((bytes[len - 1] == '\r') || (bytes[len - 1] == '\n'))
+      len--;
+    else
+      break;
+  }
+  if (len == 0) return nil;
+
+  body = NGDecodeUrlFormParameters(bytes, len);
+  return [body autorelease];
+}
+
+@end /* NGFormUrlBodyParser */
+
+@implementation NGHttpMultipartFormDataBodyParser
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (BOOL)parseImmediatlyWithDelegate:(id)_delegate
+  multipart:(id<NGMimePart>)_part data:(NSData *)_data {
+
+  return YES;
+}
+
+- (id)parseBodyOfPart:(id<NGMimePart>)_part data:(NSData *)_data delegate:(id)_d {
+  NGMimeMultipartBody *body;
+  
+  body = [super parseBodyOfPart:_part data:_data delegate:_d];
+  
+  if ([body isKindOfClass:[NGMimeMultipartBody class]]) {
+    NGMutableHashMap *map;
+    NSArray  *parts;
+    unsigned i, count;
+
+    parts = [body parts];
+    count = [parts count];
+    
+    if (count == 0) // no form fields ..
+      return nil;
+
+    map = [NGMutableHashMap hashMapWithCapacity:count];
+    for (i = 0; i < count; i++) {
+      NGMimeContentDispositionHeaderField *disposition = nil;
+      id<NGMimePart> bodyPart;
+      
+      bodyPart = [parts objectAtIndex:i];
+      
+      disposition =
+        [[bodyPart valuesOfHeaderFieldWithName:@"content-disposition"]
+                   nextObject];
+      
+      if (disposition) {
+        NSString *name    = [disposition name];
+        id       partBody = [bodyPart body];
+        
+        if (partBody)
+          [map addObject:partBody forKey:name];
+      }
+      else
+        NSLog(@"ERROR(%s): did not find content disposition in form part %@",
+              __PRETTY_FUNCTION__, bodyPart);
+    }
+    NSLog(@"made map %@", map);
+    return map;
+  }
+  else {
+    NSLog(@"ERROR: form-data parser expected MultipartBody, got %@", body);
+    body = nil;
+  }
+  return body;
+}
+
+@end /* NGHttpMultipartFormDataBodyParser */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpCookie.h b/skyrix-sope/NGObjWeb/NGHttp/NGHttpCookie.h
new file mode 100644 (file)
index 0000000..7f599f6
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_NGHttpCookie_H__
+#define __NGHttp_NGHttpCookie_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSDate;
+
+/*
+  Cookie values. Occures in 'Cookie' and 'Set-Cookie' header fields. Examples:
+
+    'Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/'
+    'Cookie: CUSTOMER=WILE_E_COYOTE'
+*/
+@interface NGHttpCookie : NSObject
+{
+@protected
+  NSString *name;
+  id       value;        // the value of the cookie, should respond to -stringValue
+  NSDate   *expireDate;  // defines how long the cookies is valid
+  NSString *path;        // the root-path where the cookie is valid
+  NSString *domainName;  // the domain where the cookie is valid (default: hostname)
+  BOOL     onlyIfSecure; // send only if communication-channel is secure (SSL)
+}
+
++ (id)cookieWithName:(NSString *)_name;
+- (id)initWithName:(NSString *)_name value:(id)_value;
+
+// accessors
+
+- (void)setCookieName:(NSString *)_name;
+- (NSString *)cookieName;
+
+- (void)setValue:(id)_value;
+- (id)value;
+- (void)addAdditionalValue:(id)_value; // use with care !
+
+- (void)setExpireDate:(NSDate *)_date;
+- (NSDate *)expireDate;
+- (BOOL)doesExpireWhenUserSessionEnds;
+
+- (void)setPath:(NSString *)_path;
+- (NSString *)path;
+- (void)setDomainName:(NSString *)_domainName;
+- (NSString *)domainName;
+- (void)setNeedsSecureChannel:(BOOL)_flag;
+- (BOOL)needsSecureChannel;
+
+// description
+
+- (NSString *)stringValue;
+
+@end
+
+#endif /* __NGHttp_NGHttpCookie_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpCookie.m b/skyrix-sope/NGObjWeb/NGHttp/NGHttpCookie.m
new file mode 100644 (file)
index 0000000..c387ade
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NGHttpCookie.h"
+
+@implementation NGHttpCookie
+
+// abbr weekday, day-of-month, abbr-month, year hour:min:sec GMT
+static NSString *cookieDateFormat =  @"%a, %d-%b-%Y %H:%M:%S %Z";
+
++ (id)cookieWithName:(NSString *)_name {
+  return [[[self alloc] initWithName:_name value:nil] autorelease];
+}
+
+- (id)initWithName:(NSString *)_name value:(id)_value {
+  if ((self = [super init])) {
+    self->name  = [_name copy];
+    self->value = [_value retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->name       release];
+  [self->value      release];
+  [self->expireDate release];
+  [self->path       release];
+  [self->domainName release];
+  [super dealloc];
+}
+
+// accessors
+
+- (void)setCookieName:(NSString *)_name {
+  if (_name != self->name) {
+    [self->name autorelease];
+    self->name = [_name copy];
+  }
+}
+- (NSString *)cookieName {
+  return self->name;
+}
+
+- (void)setValue:(id)_value {
+  if (_value != self->value) {
+    [self->value autorelease];
+    self->value = [_value retain];
+  }
+}
+- (id)value {
+  return self->value;
+}
+
+- (void)addAdditionalValue:(id)_value {
+  if (![self->value isKindOfClass:[NSMutableArray class]]) {
+    NSMutableArray *array = [[NSMutableArray alloc] init];
+
+    if (self->value) [array addObject:self->value];
+    [self->value release];
+
+    self->value = array;
+  }
+
+  NSAssert([self->value isKindOfClass:[NSMutableArray class]],
+           @"invalid object state, value should be mutable array");
+
+  if (_value)
+    [self->value addObject:_value];
+}
+
+- (void)setExpireDate:(NSDate *)_date {
+  if (_date != self->expireDate) {
+    [self->expireDate autorelease];
+    self->expireDate = [_date copy];
+  }
+}
+- (NSDate *)expireDate {
+  return self->expireDate;
+}
+- (BOOL)doesExpireWhenUserSessionEnds {
+  return (self->expireDate == nil) ? YES : NO;
+}
+
+- (void)setPath:(NSString *)_path {
+  if (_path != self->path) {
+    RELEASE(self->path);
+    self->path = [_path copyWithZone:[self zone]];
+  }
+}
+- (NSString *)path {
+  return self->path;
+}
+
+- (void)setDomainName:(NSString *)_domainName {
+  if (_domainName != self->domainName) {
+    RELEASE(self->domainName);
+    self->domainName = [_domainName copyWithZone:[self zone]];
+  }
+}
+- (NSString *)domainName {
+  return self->domainName;
+}
+
+- (void)setNeedsSecureChannel:(BOOL)_flag {
+  self->onlyIfSecure = _flag;
+}
+- (BOOL)needsSecureChannel {
+  return self->onlyIfSecure;
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  NSMutableString *str = [NSMutableString stringWithCapacity:64];
+  
+  [str appendString:[self->name stringByEscapingURL]];
+  [str appendString:@"="];
+  [str appendString:[[self->value stringValue] stringByEscapingURL]];
+
+  if (self->expireDate) {
+    // TODO: may deliver in wrong timezone due to buggy NSDate
+    NSString *s;
+    [str appendString:@"; expires="];
+    s = [self->expireDate
+            descriptionWithCalendarFormat:cookieDateFormat
+            timeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]
+            locale:nil];
+    [str appendString:s];
+  }
+  if (self->path) {
+    [str appendString:@"; path="];
+    [str appendString:self->path];
+  }
+  if (self->domainName) {
+    [str appendString:@"; domain="];
+    [str appendString:self->domainName];
+  }
+  if (self->onlyIfSecure)
+    [str appendString:@"; secure"];
+
+  return str;
+}
+
+- (NSString *)description {
+  NSMutableString *str = [NSMutableString stringWithCapacity:128];
+
+  [str appendFormat:@"<%@[0x%08X]: name=%@ value=%@",
+         NSStringFromClass([self class]), self,
+         self->name, self->value];
+
+  if (self->expireDate) {
+    [str appendString:@" expires="];
+    [str appendString:[self->expireDate description]];
+  }
+  
+  if (self->path) {
+    [str appendString:@" path="];
+    [str appendString:self->path];
+  }
+  if (self->domainName) {
+    [str appendString:@" domain="];
+    [str appendString:self->domainName];
+  }
+  if (self->onlyIfSecure)
+    [str appendString:@" secure"];
+
+  [str appendString:@">"];
+
+  return str;
+}
+
+@end /* NGHttpCookie */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpDecls.h b/skyrix-sope/NGObjWeb/NGHttp/NGHttpDecls.h
new file mode 100644 (file)
index 0000000..9fb6b86
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_NGHttpDecls_H__
+#define __NGHttp_NGHttpDecls_H__
+
+#if BUILD_libNGHttp_DLL
+#  define NGHttp_EXPORT __declspec(dllexport)
+#elif libNGHttp_ISDLL
+#  define NGHttp_EXPORT extern __declspec(dllimport)
+#else
+#  define NGHttp_EXPORT extern
+#endif
+
+#endif /* __NGHttp_NGStreamDecls_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFieldParser.h b/skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFieldParser.h
new file mode 100644 (file)
index 0000000..9db76ac
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_NGHttpHeaderFieldParser_H__
+#define __NGHttp_NGHttpHeaderFieldParser_H__
+
+#import <Foundation/NSMapTable.h>
+#import <NGMime/NGMimeHeaderFieldParser.h>
+
+@interface NGHttpStringHeaderFieldParser : NGMimeHeaderFieldParser
+@end
+
+@interface NGHttpCredentialsFieldParser : NGMimeHeaderFieldParser
+@end
+
+@interface NGHttpStringArrayHeaderFieldParser : NGMimeHeaderFieldParser
+{
+@protected
+  unsigned char splitChar; // the char to split at, usually ','
+}
+
+- (id)initWithSplitChar:(unsigned char)_splitChar;
+
+// this methods returns a retained element of the array, nil is a valid ret-value
+- (id)parseValuePart:(const char *)_bytes length:(unsigned)_len zone:(NSZone *)_zone;
+
+@end
+
+@interface NGHttpCharsetHeaderFieldParser : NGHttpStringArrayHeaderFieldParser
+@end
+
+@interface NGHttpTypeArrayHeaderFieldParser : NGHttpStringArrayHeaderFieldParser
+@end
+
+@interface NGHttpLanguageArrayHeaderFieldParser : NGHttpStringArrayHeaderFieldParser
+@end
+
+@interface NGHttpCookieFieldParser : NGHttpStringArrayHeaderFieldParser
+{
+@protected
+  NSMapTable *fetchedCookies; // WARNING: parser is not reentrant !
+  BOOL       isRunning;       // to check for ^^
+  BOOL       foundInvalidPairs;
+}
+
+@end
+
+@interface NGMimeHeaderFieldParserSet(HttpFieldParserSet)
+
++ (id)defaultHttpHeaderFieldParserSet;
+
+@end
+
+#endif /* __NGHttp_NGHttpHeaderFieldParser_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFieldParser.m b/skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFieldParser.m
new file mode 100644 (file)
index 0000000..b66072c
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NGHttpHeaderFieldParser.h"
+#import "NGHttpHeaderFields.h"
+#import "NGHttpCookie.h"
+
+static Class NSArrayClass = Nil;
+
+@implementation NGHttpStringHeaderFieldParser
+
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
+  unsigned              len   = 0;
+  const unsigned char         *src  = NULL;
+  NGHttpHostHeaderField *value = nil;
+  NSString *str = nil;
+
+  if ([_data isKindOfClass:[NSData class]]) {
+    len   = [_data length];
+    src = (unsigned char *)[_data bytes];
+  }
+  else {
+    len = [_data cStringLength];
+    src = [_data cString];
+  }
+  if (len == 0) {
+#if DEBUG
+    NSLog(@"WARNING: empty value for header field %@ ..", _field);
+#endif
+    return nil;
+  }
+
+  // strip leading spaces
+  while (isRfc822_LWSP(*src) && (len > 0)) {
+    src++;
+    len--;
+  }
+
+  str = [[NSString alloc] initWithCString:src length:len];
+  NSAssert(str, @"string allocation failed ..");
+
+  if ([_field isEqualToString:@"host"])
+    value = [[NGHttpHostHeaderField alloc] initWithString:str];
+  else if ([_field isEqualToString:@"user-agent"])
+    value = [[NGHttpUserAgent alloc] initWithString:str];
+  else if ([_field isEqualToString:@"connection"])
+    value = [[NGHttpConnectionHeaderField alloc] initWithString:str];
+  else
+    value = RETAIN(str);
+  
+  RELEASE(str); str = nil;
+  
+  return AUTORELEASE(value);
+}
+
+@end /* NGHttpStringHeaderFieldParser */
+
+@implementation NGHttpCredentialsFieldParser
+
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
+  unsigned      len     = 0;
+  const unsigned char *src    = NULL;
+  NSString      *scheme = nil;
+  NSData        *data   = nil;
+  
+  if ([_data isKindOfClass:[NSData class]]) {
+    len   = [_data length];
+    src = (unsigned char *)[_data bytes];
+  }
+  else {
+    len = [_data cStringLength];
+    src = [_data cString];
+  }
+
+  if (len == 0) {
+    NSLog(@"WARNING: empty value for header field %@ ..", _field);
+    return nil;
+  }
+
+  // strip leading spaces
+  while (isRfc822_LWSP(*src) && (len > 0)) {
+    src++;
+    len--;
+  }
+  if (len == 0) {
+    NSLog(@"WARNING: empty value for header field %@ ..", _field);
+    return nil;
+  }
+
+  // find name
+  {
+    const unsigned char *start = src;
+    
+    while (!isRfc822_LWSP(*src) && (len > 0)) {
+      src++;
+      len--;
+    }
+    scheme = [NSString stringWithCString:start length:(src - start)];
+  }
+
+  // skip spaces
+  while (isRfc822_LWSP(*src) && (len > 0)) {
+    src++;
+    len--;
+  }
+  if (len == 0) {
+    NSLog(@"WARNING: invalid credentials header field %@ .. (missing credentials)",
+          _field);
+    return nil;
+  }
+  
+  // make credentials
+  data = [NSData dataWithBytes:src length:len];
+
+  return [NGHttpCredentials credentialsWithScheme:[scheme lowercaseString]
+                            credentials:data];
+}
+
+@end /* NGHttpCredentialsFieldParser */
+
+@implementation NGHttpStringArrayHeaderFieldParser
+
+- (id)initWithSplitChar:(unsigned char)_c {
+  if ((self = [super init])) {
+    self->splitChar = _c;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithSplitChar:','];
+}
+
+- (id)parseValuePart:(const char *)_b length:(unsigned)_len
+  zone:(NSZone *)_zone
+{
+  return [[NSString allocWithZone:_zone]
+                    initWithCString:_b length:_len];
+}
+
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
+  unsigned       len   = 0;
+  const unsigned char  *src  = NULL;
+  NSMutableArray *array = nil;
+  
+  if ([_data isKindOfClass:[NSData class]]) {
+    len   = [_data length];
+    src = (unsigned char *)[_data bytes];
+  }
+  else {
+    len = [_data cStringLength];
+    src = [_data cString];
+  }
+
+  if (len == 0) {
+#if DEBUG
+    NSLog(@"WARNING: empty value for header field %@ ..", _field);
+#endif
+    return nil;
+  }
+  
+#if 0 && DEBUG
+  NSLog(@"field %@ is %@",
+        _field,
+        [[NSString alloc] initWithData:_data encoding:NSASCIIStringEncoding]);
+#endif
+  
+
+  array = [NSMutableArray arrayWithCapacity:16];
+  NSAssert(array, @"array allocation failed ..");
+  do {
+    const unsigned char *startPos = NULL;
+    
+    // strip leading spaces
+    while ((*src != '\0') && isRfc822_LWSP(*src) && (len > 0)) {
+      src++;
+      len--;
+    }
+    if (len <= 0)
+      break;
+    else
+      startPos = src;
+    
+    while ((*src != self->splitChar) && !isRfc822_LWSP(*src) && (len > 0)) {
+      src++;
+      len--;
+    }
+    
+    if (src > startPos) {
+      id part = nil;
+      unsigned partLen;
+
+      partLen = (src - startPos);
+#if DEBUG && 0
+      NSLog(@"field %@: current len=%i %s(%i)", _field, len, startPos, partLen);
+#endif
+      
+      part = [self parseValuePart:startPos
+                   length:partLen
+                   zone:[array zone]];
+      if (part) {
+        [array addObject:part];
+        RELEASE(part); part = nil;
+      }
+    }
+
+    if (len > 0) {
+      if (isRfc822_LWSP(*src)) { // skip until splitchar or to len ..
+        while ((*src != '\0') && (*src != self->splitChar) && (len > 0)) {
+          src++;
+          len--;
+        }
+      }
+      else if (*src == self->splitChar) { // skip ','
+        src++;
+        len--;
+      }
+    }
+  }
+  while ((*src != '\0') && (len > 0));
+
+  return array;
+}
+
+@end /* NGHttpStringArrayHeaderFieldParser */
+
+@implementation NGHttpCharsetHeaderFieldParser
+
+- (id)parseValue:(NSData *)_data ofHeaderField:(NSString *)_field {
+  id value = nil;
+
+  value = [super parseValue:_data ofHeaderField:_field];
+  if (value) {
+    if (NSArrayClass == Nil)
+      NSArrayClass = [NSArray class];
+    
+    NSAssert([value isKindOfClass:NSArrayClass], @"invalid value ..");
+    
+    value = [[NGHttpCharsetHeaderField alloc] initWithArray:value];
+    value = AUTORELEASE(value);
+  }
+  return value;
+}
+
+@end /* NGHttpCharsetHeaderFieldParser */
+
+@implementation NGHttpTypeArrayHeaderFieldParser
+
+- (id)parseValuePart:(const char *)_b length:(unsigned)_len zone:(NSZone *)_zone {
+  NSString   *typeString = [[NSString alloc] initWithCString:_b length:_len];
+  NGMimeType *type       = nil;
+
+  type = typeString ? [NGMimeType mimeType:typeString] : nil;
+  RELEASE(typeString);
+  
+  return RETAIN(type);
+}
+
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
+  id value = nil;
+
+  value = [super parseValue:_data ofHeaderField:_field];
+  if (value) {
+    if (NSArrayClass == Nil)
+      NSArrayClass = [NSArray class];
+    
+    NSAssert([value isKindOfClass:NSArrayClass], @"invalid value ..");
+    
+    value = [[NGHttpTypeSetHeaderField alloc] initWithArray:value];
+    value = AUTORELEASE(value);
+  }
+  return value;
+}
+
+@end /* NGHttpTypeArrayHeaderFieldParser */
+
+@implementation NGHttpLanguageArrayHeaderFieldParser
+
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
+  id value = nil;
+
+  value = [super parseValue:_data ofHeaderField:_field];
+  if (value) {
+    if (NSArrayClass == Nil)
+      NSArrayClass = [NSArray class];
+    
+    NSAssert([value isKindOfClass:NSArrayClass], @"invalid value ..");
+    
+    value = [[NGHttpLanguageSetHeaderField alloc] initWithArray:value];
+    value = AUTORELEASE(value);
+  }
+  return value;
+}
+
+@end /* NGHttpLanguageArrayHeaderFieldParser */
+
+@implementation NGHttpCookieFieldParser
+
+- (id)init {
+  return [self initWithSplitChar:';'];
+}
+- (id)initWithSplitChar:(unsigned char)_splitChar {
+  if ((self = [super initWithSplitChar:_splitChar])) {
+    self->fetchedCookies = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                            NSObjectMapValueCallBacks,
+                                            16);
+    self->isRunning      = NO;
+    self->foundInvalidPairs = NO;
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  if (self->fetchedCookies) {
+    NSFreeMapTable(self->fetchedCookies);
+    self->fetchedCookies = NULL;
+  }
+  [super dealloc];
+}
+#endif
+
+- (id)parseValuePart:(const char *)_bytes length:(unsigned)_len
+  zone:(NSZone *)_z
+{
+  NGHttpCookie *cookie   = nil;
+  unsigned     pos, toGo;
+
+  for (pos = 0, toGo = _len; (toGo > 0) && (_bytes[pos] != '='); toGo--, pos++)
+    ;
+  
+  if (toGo > 0) {
+    NSString *name   = nil;
+    NSString *value  = nil;
+    
+    // NSLog(@"pos=%i toGo=%i", pos, toGo);
+    
+    name  = [[NSString allocWithZone:_z]
+                       initWithCString:_bytes
+                       length:pos];
+    value = [[NSString allocWithZone:_z]
+                       initWithCString:&(_bytes[pos + 1])
+                       length:(toGo - 1)];
+
+    //NSLog(@"pair='%@'", [NSString stringWithCString:_bytes length:_len]);
+    //NSLog(@"name='%@' value='%@'", name, value);
+
+    if (name == nil) {
+      NSLog(@"ERROR: invalid cookie pair missing name: %@",
+            [NSString stringWithCString:_bytes length:_len]);
+      RELEASE(name);
+      RELEASE(value);
+      return nil;
+    }
+    else if (value == nil) {
+      NSLog(@"ERROR: invalid cookie pair missing value (name=%@): %@",
+            name,
+            [NSString stringWithCString:_bytes length:_len]);
+      RELEASE(name);
+      RELEASE(value);
+      return nil;
+    }
+    else {
+      cookie = (id)NSMapGet(self->fetchedCookies, name);
+      
+      if (cookie) {
+        [cookie addAdditionalValue:[value stringByUnescapingURL]];
+        cookie = nil;
+      }
+      else {
+        cookie = [[NGHttpCookie allocWithZone:_z]
+                                initWithName:[name stringByUnescapingURL]
+                                value:[value stringByUnescapingURL]];
+        NSMapInsert(self->fetchedCookies, name, cookie);
+      }
+    }
+    
+    RELEASE(name);  name  = nil;
+    RELEASE(value); value = nil;
+  }
+#if DEBUG
+  else {
+    NSLog(@"ERROR(%s:%i): invalid cookie pair: %@",
+          __PRETTY_FUNCTION__, __LINE__,
+          [NSString stringWithCString:_bytes length:_len]);
+    self->foundInvalidPairs = YES;
+  }
+#endif
+  return cookie;
+}
+
+- (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
+  id value = nil;
+  
+  if (NSArrayClass == Nil)
+    NSArrayClass = [NSArray class];
+
+  NSAssert(self->isRunning == NO, @"parser used in multiple threads !");
+  self->foundInvalidPairs = NO;
+
+#if 0 && DEBUG
+  NSLog(@"cookie: field %@ is %@",
+        _field,
+        [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding]);
+#endif
+  
+  self->isRunning = YES; // semi-lock
+  {
+    value = [super parseValue:_data ofHeaderField:_field];
+    NSResetMapTable(self->fetchedCookies);
+  }
+  self->isRunning = NO; // semi-unlock
+  
+  if (self->foundInvalidPairs) {
+#if DEBUG
+    NSString *s;
+
+    if ([_data isKindOfClass:[NSData class]]) 
+      s = [[NSString alloc] initWithData:_data encoding:NSASCIIStringEncoding];
+    else
+      s = _data;
+    
+    NSLog(@"ERROR(%s:%i): got invalid cookie pairs for field %@ data %@.",
+          __PRETTY_FUNCTION__, __LINE__,
+          _field, s);
+    RELEASE(s);
+#endif
+    // return nil;
+  }
+  
+  if (value) {
+    NSAssert1([value isKindOfClass:NSArrayClass],
+              @"invalid value '%@' ..", value);
+    
+    //value = [[NGHttpTypeSetHeaderField alloc] initWithArray:value];
+    //AUTORELEASE(value);
+  }
+  return value;
+}
+
+@end /* NGHttpCookieFieldParser */
+
+@implementation NGMimeHeaderFieldParserSet(HttpFieldParserSet)
+
+static NGMimeHeaderFieldParserSet *httpSet = nil;
+
+static inline void NGRegisterParser(NSString *_field, NSString *_parserClass) {
+  id parser = [[NSClassFromString(_parserClass) alloc] init];
+  
+  if (parser) {
+    [httpSet setParser:parser forField:_field];
+    RELEASE(parser);
+    parser = nil;
+  }
+  else {
+    NSLog(@"WARNING: did not find header field parser %@", _parserClass);
+  }
+}
+
++ (id)defaultHttpHeaderFieldParserSet {
+  if (httpSet == nil) {
+    id parser = nil;
+    
+    httpSet = [[self alloc] initWithParseSet:
+      [NGMimeHeaderFieldParserSet defaultRfc822HeaderFieldParserSet]];
+
+    parser = [[NGHttpStringHeaderFieldParser alloc] init];
+    [httpSet setParser:parser forField:@"host"];
+    [httpSet setParser:parser forField:@"user-agent"];
+    [httpSet setParser:parser forField:@"connection"];
+    RELEASE(parser); parser = nil;
+
+    NGRegisterParser(@"accept-charset",  @"NGHttpCharsetHeaderFieldParser");
+    NGRegisterParser(@"accept-language", @"NGHttpLanguageArrayHeaderFieldParser");
+    NGRegisterParser(@"accept",          @"NGHttpTypeArrayHeaderFieldParser");
+    NGRegisterParser(@"accept-encoding", @"NGHttpStringArrayHeaderFieldParser");
+    NGRegisterParser(@"cookie",          @"NGHttpCookieFieldParser");
+    NGRegisterParser(@"authorization",   @"NGHttpCredentialsFieldParser");
+  }
+  return httpSet;
+}
+
+@end /* NGMimeHeaderFieldParserSet(HttpFieldParserSet) */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFields.h b/skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFields.h
new file mode 100644 (file)
index 0000000..75e0d3b
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_NGHttpHeaderFields_H__
+#define __NGHttp_NGHttpHeaderFields_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSHost, NSDate, NSDictionary;
+@class NGInternetSocketAddress;
+
+/*
+  Value field that occures in the HTTP 'Host' header field.
+  Looks like this: 'Host: trex@skyrix.com:80'
+*/
+@interface NGHttpHostHeaderField : NSObject
+{
+@protected
+  NSString *hostName;
+  int      port;
+}
+
+- (id)initWithString:(NSString *)_value;
+
+// accessors
+
+- (NSString *)hostName;
+- (int)port;
+
+// advanced conversions
+
+- (NGInternetSocketAddress *)socketAddress;
+- (NSHost *)host;
+
+// description
+
+- (NSString *)stringValue;
+
+@end
+
+/*
+  Value field that occures in the HTTP 'accept-charset' header field.
+  Looks like this: 'accept-charset: iso-8859-1,*,utf-8'
+*/
+@interface NGHttpCharsetHeaderField : NSObject
+{
+  NSArray *charsets;
+  BOOL    containsWildcard;
+}
+
+- (id)initWithArray:(NSArray *)_charsetArray;
+- (id)initWithString:(NSString *)_value;
+
+// accessors
+
+- (NSEnumerator *)charsets;
+- (BOOL)containsCharset:(NSString *)_setName;
+
+@end
+
+/*
+  Value field that occures in the HTTP 'accept' header field.
+  Looks like this: 'accept: image/gif, image/x-xbitmap, image/jpeg, wildcard'
+*/
+@interface NGHttpTypeSetHeaderField : NSObject
+{
+  NSArray *types;
+}
+
+- (id)initWithArray:(NSArray *)_typeArray;
+
+// accessors
+
+- (NSEnumerator *)types;
+- (BOOL)containsMimeType:(NGMimeType *)_type;
+
+@end
+
+/*
+  Value field that occures in the HTTP 'accept-language' header field.
+*/
+@interface NGHttpLanguageSetHeaderField : NSObject
+{
+  NSArray *languages;
+}
+
+- (id)initWithArray:(NSArray *)_langArray;
+
+// accessors
+
+- (NSEnumerator *)languages;
+- (BOOL)containsLanguage:(NSString *)_language;
+
+@end
+
+/*
+  Value field that occures in the HTTP 'user-agent' header field.
+  Looks like this: 'user-agent: Mozilla/4.5b2 [en] '
+*/
+@interface NGHttpUserAgent : NSObject
+{
+@protected
+  NSString *value;
+  NSString *browser;
+  char     majorVersion;
+  char     minorVersion;
+}
+
+- (id)initWithString:(NSString *)_value;
+
+// browsers
+
+- (BOOL)isMozilla;
+- (BOOL)isInternetExplorer;
+- (int)majorVersion;
+- (int)minorVersion;
+
+@end
+
+/*
+  Value field that occures in the HTTP 'connection' header field.
+  Looks like this: 'connection: Keep-Alive'
+*/
+@interface NGHttpConnectionHeaderField : NSObject
+{
+@protected
+  BOOL close;
+  BOOL keepAlive;
+  BOOL isTE;
+}
+
+- (id)initWithString:(NSString *)_value;
+
+// accessors
+
+- (BOOL)keepAlive;
+
+@end
+
+/*
+  Value field that occures in the HTTP 'authorization' header field.
+  Looks like this: 'authorization: Basic aGVsZ2U6ZG9vZg=='
+  (class cluster)
+*/
+@interface NGHttpCredentials : NSObject
+{
+  NSString *scheme;
+  NSData   *credentials;
+}
+
++ (id)credentialsWithString:(NSString *)_cred;
++ (id)credentialsWithScheme:(NSString *)_scheme
+  credentials:(NSData *)_credentials;
+
+// accessors
+
+- (NSString *)scheme;
+- (NSData *)credentials;
+
+- (NSString *)userName;
+- (NSString *)password;
+
+// description
+
+- (NSString *)stringValue;
+
+@end
+
+/*
+  Value field that occures in the HTTP 'www-authenticate' header field.
+  Looks like this: 'www-authorization: Basic realm="SKYRIX"'
+*/
+@interface NGHttpChallenge : NSObject
+{
+  NSString     *scheme;
+  NSDictionary *parameters;
+}
+
++ (id)basicChallengeWithRealm:(NSString *)_realm;
+- (id)initWithScheme:(NSString *)_scheme realm:(NSString *)_realm;
+
+// accessors
+
+- (NSString *)scheme;
+
+- (void)setRealm:(NSString *)_realm;
+- (NSString *)realm;
+
+// description
+
+- (NSString *)stringValue;
+
+@end
+
+#endif /* __NGHttp_NGHttpHeaderFields_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFields.m b/skyrix-sope/NGObjWeb/NGHttp/NGHttpHeaderFields.m
new file mode 100644 (file)
index 0000000..c947d7e
--- /dev/null
@@ -0,0 +1,677 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include "NGHttpHeaderFields.h"
+
+@implementation NGHttpHostHeaderField
+
+- (id)initWithString:(NSString *)_value {
+  if ([_value length] < 1) {
+    NSLog(@"invalid value for HTTP host header field ..");
+    self = AUTORELEASE(self);
+    return nil;
+  }
+  
+  if ((self = [super init])) {
+    NSRange rng = [_value rangeOfString:@":"];
+
+    if (rng.length == 0) {
+      self->hostName = [_value copyWithZone:[self zone]];
+      self->port     = -1;
+    }
+    else {
+      self->hostName = [[_value substringToIndex:rng.location] retain];
+      self->port     = [[_value substringFromIndex:(rng.location + rng.length)]
+                                intValue];
+    }
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->hostName);
+  [super dealloc];
+}
+#endif
+
+// accessors
+
+- (NSString *)hostName {
+  return self->hostName;
+}
+- (int)port {
+  return self->port;
+}
+
+// advanced conversions
+
+- (NGInternetSocketAddress *)socketAddress {
+  return [NGInternetSocketAddress addressWithPort:[self port]
+                                  onHost:[self hostName]];
+}
+- (NSHost *)host {
+  return [NSHost hostWithName:[self hostName]];
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  if (self->port > 0) {
+    return [NSString stringWithFormat:@"%s:%i",
+                       [self->hostName cString], self->port];
+  }
+  else
+    return self->hostName;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<HostField[0x%08X]: host=%@ port=%i>",
+                     self, [self hostName], [self port]];
+}
+
+@end /* NGHttpHostHeaderField */
+
+@implementation NGHttpCharsetHeaderField
+
+- (id)init {
+  return [self initWithString:nil];
+}
+
+- (id)initWithArray:(NSArray *)_charsetArray {
+  if ([_charsetArray count] < 1) {
+    NSLog(@"invalid value for HTTP charset header field ..");
+    self = AUTORELEASE(self);
+    return nil;
+  }
+
+  if ((self = [super init])) {
+    self->charsets = RETAIN(_charsetArray);
+    NSAssert([self->charsets count] >= 1, @"no content in array ..");
+
+    self->containsWildcard = [self->charsets containsObject:@"*"];
+  }
+  return self;
+}
+- (id)initWithString:(NSString *)_value {
+  if ([_value length] < 1) {
+    NSLog(@"invalid value for HTTP charset header field ..");
+    self = AUTORELEASE(self);
+    return nil;
+  }
+
+  return [self initWithArray:[_value componentsSeparatedByString:@","]];
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->charsets);
+  [super dealloc];
+}
+#endif
+
+// accessors
+
+- (NSEnumerator *)charsets {
+  return [self->charsets objectEnumerator];
+}
+- (BOOL)containsCharset:(NSString *)_setName {
+  if (self->containsWildcard)
+    return YES;
+  else
+    return [self->charsets containsObject:_setName];
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  NSMutableString *str = [[NSMutableString allocWithZone:[self zone]] init];
+  int  cnt, count = [self->charsets count];
+
+  for (cnt = 0; cnt < count; cnt++) {
+    if (cnt != 0) [str appendString:@","];
+    [str appendString:[self->charsets objectAtIndex:cnt]];
+  }
+  return AUTORELEASE(str);
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<HttpCharset[0x%08X]: %@>",
+                     self, self->charsets];
+}
+
+@end /* NGHttpCharsetHeaderField */
+
+@implementation NGHttpTypeSetHeaderField
+
+- (id)init {
+  return [self initWithArray:nil];
+}
+
+- (id)initWithArray:(NSArray *)_typeArray {
+  if ([_typeArray count] < 1) {
+    NSLog(@"invalid value for HTTP charset header field ..");
+    self = AUTORELEASE(self);
+    return nil;
+  }
+
+  if ((self = [super init])) {
+    self->types = RETAIN(_typeArray);
+    NSAssert([self->types count] >= 1, @"no content in array ..");
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->types); self->types = nil;
+  [super dealloc];
+}
+#endif
+
+// accessors
+
+- (NSEnumerator *)types {
+  return [self->types objectEnumerator];
+}
+- (BOOL)containsMimeType:(NGMimeType *)_type {
+  return [self->types containsObject:_type];
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  NSMutableString *str;
+  int  cnt, count;
+
+  str = [[NSMutableString allocWithZone:[self zone]] init];
+  count = [self->types count];
+
+  for (cnt = 0; cnt < count; cnt++) {
+    if (cnt != 0) [str appendString:@", "];
+    [str appendString:[[self->types objectAtIndex:cnt] stringValue]];
+  }
+  return AUTORELEASE(str);
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<HttpMimeTypes[0x%08X]: %@>",
+                     self, self->types];
+}
+
+@end /* NGHttpTypeSetHeaderField */
+
+@implementation NGHttpLanguageSetHeaderField
+
+- (id)init {
+  return [self initWithArray:nil];
+}
+
+- (id)initWithArray:(NSArray *)_languageArray {
+  if ([_languageArray count] < 1) {
+    NSLog(@"invalid value for HTTP charset header field ..");
+    self = AUTORELEASE(self);
+    return nil;
+  }
+
+  if ((self = [super init])) {
+    self->languages = RETAIN(_languageArray);
+    NSAssert([self->languages count] >= 1, @"no content in array ..");
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->languages); self->languages = nil;
+  [super dealloc];
+}
+#endif
+
+// accessors
+
+- (NSEnumerator *)languages {
+  return [self->languages objectEnumerator];
+}
+- (BOOL)containsLanguage:(NSString *)_language {
+  return [self->languages containsObject:_language];
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  NSMutableString *str = [[NSMutableString allocWithZone:[self zone]] init];
+  int  cnt, count = [self->languages count];
+
+  for (cnt = 0; cnt < count; cnt++) {
+    if (cnt != 0) [str appendString:@", "];
+    [str appendString:[self->languages objectAtIndex:cnt]];
+  }
+  return AUTORELEASE(str);
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<HttpLanguages[0x%08X]: %@>",
+                     self, self->languages];
+}
+
+@end /* NGHttpLanguageSetHeaderField */
+
+@implementation NGHttpUserAgent
+
+static void _parseUserAgent(NGHttpUserAgent *self) {
+  [self->browser release]; self->browser = nil;
+
+  if ([self->value hasPrefix:@"Mozilla"]) {
+    // Mozilla Browser or compatible
+    NSRange r;
+    int idx, av, iv;
+
+    r = [self->value rangeOfString:@"/"];
+    idx = r.location;
+    if (r.length > 0) {
+      NSString *tmp;
+
+      tmp = [self->value substringFromIndex:(idx + 1)];
+      r   = [tmp rangeOfString:@" "];
+      idx = r.location;
+      if (r.length > 0)
+        tmp = [tmp substringToIndex:idx];
+
+      self->browser = @"Mozilla";
+
+      sscanf([tmp cString], "%i.%i", &av, &iv);
+      self->majorVersion = av;
+      self->minorVersion = iv;
+
+      if (idx != NSNotFound) {
+        r = [self->value rangeOfString:@"MSIE "];
+        idx = r.location;
+        if (r.length > 0) {
+          tmp = [self->value substringFromIndex:(idx + 5)];
+          self->browser = @"MSIE";
+
+          sscanf([tmp cString], "%i.%i", &av, &iv);
+          self->majorVersion = av;
+          self->minorVersion = iv;
+        }
+      }
+      return;
+    }
+  }
+}
+
+- (id)initWithString:(NSString *)_value {
+  if ((self = [super init])) {
+    self->value = [_value copyWithZone:[self zone]];
+    _parseUserAgent(self);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->browser release];
+  [self->value   release];
+  [super dealloc];
+}
+
+/* browsers */
+
+- (BOOL)isMozilla {
+  return [self->browser isEqualToString:@"Mozilla"];
+}
+- (BOOL)isInternetExplorer {
+  return [self->browser isEqualToString:@"MSIE"];
+}
+
+- (int)majorVersion {
+  return self->majorVersion;
+}
+- (int)minorVersion {
+  return self->minorVersion;
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  return self->value;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<HttpUserAgent[0x%08X]: %@ "
+                     @"(detected=%@, major=%i, minor=%i)>",
+                     self, self->value, self->browser,
+                     self->majorVersion, self->minorVersion];
+}
+
+@end /* NGHttpUserAgent */
+
+@implementation NGHttpConnectionHeaderField
+
+- (id)initWithString:(NSString *)_value {
+  NSString *s;
+  
+  s = [_value lowercaseString];
+
+  if ([s rangeOfString:@"keep-alive"].length > 0) {
+    if ((self = [super init])) {
+      self->keepAlive = YES;
+    }
+    return self;
+  }
+  else if ([s rangeOfString:@"close"].length > 0) {
+    if ((self = [super init])) {
+      self->close = YES;
+    }
+    return self;
+  }
+  else if ([s rangeOfString:@"te"].length > 0) {
+    if ((self = [super init])) {
+      self->isTE = YES;
+    }
+    return self;
+  }
+  else {
+    NSLog(@"WARNING(%s): cannot parse HTTP connection header value: '%@'",
+          __PRETTY_FUNCTION__, _value);
+    self = AUTORELEASE(self);
+    return [_value copy];
+  }
+}
+
+/* accessors */
+
+- (BOOL)keepAlive {
+  return self->keepAlive;
+}
+- (BOOL)close {
+  return self->close;
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  if (self->close)
+    return @"close";
+  if (self->keepAlive)
+    return @"Keep-Alive";
+  if (self->isTE)
+    return @"TE";
+
+  return nil;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<HttpConnection[0x%08X]: keepAlive=%s close=%s TE=%s>",
+                     self,
+                     self->keepAlive ? "yes" : "no",
+                     self->close     ? "yes" : "no",
+                     self->isTE      ? "yes" : "no"
+  ];
+}
+
+@end /* NGHttpConnectionHeaderField */
+
+// authorization
+
+@interface NGConcreteHttpBasicCredentials : NGHttpCredentials
+{
+  NSString *user;
+  NSString *password;
+}
+
+@end
+
+@interface NGHttpCredentials(PrivateMethods)
+- (id)initWithScheme:(NSString *)_scheme credentials:(NSData *)_credentials;
+@end
+
+@implementation NGHttpCredentials
+
++ (id)credentialsWithString:(NSString *)_cred {
+  NSRange rng;
+  NSString *lscheme;
+  NSData   *cred;
+  
+  if ([_cred length] == 0)
+    return nil;
+  rng = [_cred rangeOfString:@" "];
+  if (rng.length <= 0)
+    return nil;
+
+  lscheme = [_cred substringToIndex:rng.location];
+  cred    = [[_cred substringFromIndex:(rng.location + 1)]
+                    dataUsingEncoding:NSISOLatin1StringEncoding];
+  
+  return [self credentialsWithScheme:lscheme credentials:cred];
+}
+
++ (id)credentialsWithScheme:(NSString *)_scheme
+  credentials:(NSData *)_credentials
+{
+  if ([_scheme caseInsensitiveCompare:@"basic"] == NSOrderedSame) {
+    return [[[NGConcreteHttpBasicCredentials alloc]
+                                             initWithScheme:_scheme
+                                             credentials:_credentials]
+                                             autorelease];
+  }
+
+  return [[[self alloc] initWithScheme:_scheme
+                        credentials:_credentials] autorelease];
+}
+
+- (id)initWithScheme:(NSString *)_scheme credentials:(NSData *)_credentials {
+  if ((self = [super init])) {
+    self->scheme      = [_scheme      copy];
+    self->credentials = [_credentials copy];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithScheme:@"basic" credentials:nil];
+}
+
+- (void)dealloc {
+  [self->scheme      release];
+  [self->credentials release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)scheme {
+  return self->scheme;
+}
+
+- (NSData *)credentials {
+  return self->credentials;
+}
+
+- (NSString *)userName {
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+  // TODO: raise exception
+  return nil;
+#else
+  return [self subclassResponsibility:_cmd];
+#endif
+}
+- (NSString *)password {
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+  // TODO: raise exception
+  return nil;
+#else
+  return [self subclassResponsibility:_cmd];
+#endif
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  NSMutableString *str;
+  
+  str = [NSMutableString stringWithCapacity:64];
+  [str appendString:self->scheme];
+  [str appendString:@" "];
+  [str appendString:[NSString stringWithCString:[self->credentials bytes]
+                              length:[self->credentials length]]];
+  return str;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: %@>",
+                     NSStringFromClass([self class]), self,
+                     [self stringValue]];
+}
+
+@end /* NGHttpCredentials */
+
+@implementation NGConcreteHttpBasicCredentials
+
+- (id)initWithScheme:(NSString *)_scheme credentials:(NSData *)_credentials {
+  if ((self = [super initWithScheme:_scheme credentials:_credentials])) {
+    NSData *data = [_credentials dataByDecodingBase64];
+
+    if (data) {
+      char *str   = (char *)[data bytes];
+      int  len    = [data length];
+      char *start = str;
+
+      while ((*str != '\0') && (*str != ':') && (len > 0)) {
+        str++;
+        len--;
+      }
+      self->user = 
+        [[NSString alloc] initWithCString:start length:(str - start)];
+      // skip ':'
+      str++; len--;
+      
+      if (len > 0) {
+        self->password = [[NSString alloc] initWithCString:str length:len];
+      }
+
+      //NSLog(@"decoded user %@ password %@", self->user, self->password);
+    }
+    else
+      NSLog(@"ERROR: could not decode credentials (invalid base64 encoding)");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->user     release];
+  [self->password release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)userName {
+  return self->user;
+}
+- (NSString *)password {
+  return self->password;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<BasicCredentials[0x%08X]: user=%@ hasPassword=%s>",
+                     self,
+                     [self userName],
+                     self->password ? "yes" : "no"
+                   ];
+}
+
+@end /* NGConcreteHttpBasicCredentials */
+
+@implementation NGHttpChallenge
+
++ (id)basicChallengeWithRealm:(NSString *)_realm {
+  return [[[self alloc] initWithScheme:@"basic" realm:_realm] autorelease];
+}
+
+- (id)initWithScheme:(NSString *)_scheme realm:(NSString *)_realm {
+  if ((self = [super init])) {
+    self->scheme     = [_scheme copy];
+    self->parameters = [[NSMutableDictionary alloc] init];
+
+    if (_realm)
+      [(NSMutableDictionary *)self->parameters setObject:_realm forKey:@"realm"];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithScheme:@"basic" realm:@"NGHttp"];
+}
+
+- (void)dealloc {
+  [self->scheme     release];
+  [self->parameters release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)scheme {
+  return self->scheme;
+}
+
+- (void)setRealm:(NSString *)_realm {
+  [(NSMutableDictionary *)self->parameters setObject:_realm forKey:@"realm"];
+}
+- (NSString *)realm {
+  return [self->parameters objectForKey:@"realm"];
+}
+
+/* description */
+
+- (NSString *)stringValue {
+  NSMutableString *str;
+  NSEnumerator    *keys;
+  NSString        *key  = nil;
+
+  str  = [NSMutableString stringWithCapacity:128];
+  keys = [self->parameters keyEnumerator];
+  [str appendString:self->scheme];
+  
+  while ((key = [keys nextObject])) {
+    [str appendString:@" "];
+    [str appendString:key];
+    [str appendString:@"=\""];
+    [str appendString:[[self->parameters objectForKey:key] stringValue]];
+    [str appendString:@"\""];
+  }
+
+  return str;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: %@>",
+                     NSStringFromClass([self class]), self,
+                     [self stringValue]];
+}
+
+@end /* NGHttpChallenge */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpMessage.h b/skyrix-sope/NGObjWeb/NGHttp/NGHttpMessage.h
new file mode 100644 (file)
index 0000000..96b783a
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_NGHttpMessage_H__
+#define __NGHttp_NGHttpMessage_H__
+
+#import <Foundation/NSObject.h>
+#import <NGMime/NGPart.h>
+
+@class NSString, NSArray;
+@class NGHashMap;
+@class NGMimeType;
+@class NGHttpCookie;
+
+// used in 'Accept-Encoding' and 'Content-Encoding'
+extern NSString *NGHttpContentCoding_gzip;     // 'gzip'
+extern NSString *NGHttpContentCoding_compress; // 'compress'
+extern NSString *NGHttpContentCoding_deflate;  // 'deflate'
+extern NSString *NGHttpContentCoding_identity; // 'identity'
+
+// used in 'Transfer-Encoding'
+extern NSString *NGHttpTransferCoding_chunked;  // 'chunked'
+extern NSString *NGHttpTransferCoding_identity; // 'identity'
+extern NSString *NGHttpTransferCoding_gzip;     // 'gzip'
+extern NSString *NGHttpTransferCoding_compress; // 'compress'
+extern NSString *NGHttpTransferCoding_deflate;  // 'deflate'
+
+@interface NGHttpMessage : NSObject < NGPart, NGMimePart >
+{
+@protected
+  NGHashMap *header;
+  id        body;
+
+  // http enhancements
+  char      majorVersion;
+  char      minorVersion;
+}
+
+// accessors
+
+- (NSString *)httpVersion;
+- (char)majorVersion;
+- (char)minorVersion;
+
+// Cookies
+
+- (NSArray *)cookies; // 'cookie' header
+- (id)valueOfCookieWithName:(NSString *)_name;
+
+- (void)addClientCookie:(NGHttpCookie *)_cookie; // 'Set-Cookie' header
+- (NSArray *)clientCookies;
+
+// headers
+
+- (id)valueOfHeaderFieldWithName:(NSString *)_name;
+
+// NGPart
+
+- (NSEnumerator *)valuesOfHeaderFieldWithName:(NSString *)_name;
+- (NSEnumerator *)headerFieldNames;
+
+- (void)setBody:(id)_body;
+- (id)body;
+
+// NGMimePart
+
+- (NGMimeType *)contentType;
+- (NSString *)contentId;
+- (NSArray *)contentLanguage;
+- (NSString *)contentMd5;
+- (NSString *)encoding;
+- (NSString *)contentDescription;
+
+// headers
+
+- (void)setValue:(id)_value ofHeaderFieldWithName:(NSString *)_name;
+- (void)addValue:(id)_value toHeaderFieldWithName:(NSString *)_name;
+- (void)removeValue:(id)_value fromHeaderFieldWithName:(NSString *)_name;
+  
+- (void)setContentType:(NGMimeType *)_type;
+- (void)setContentLength:(unsigned)_length;
+- (unsigned)contentLength;
+
+@end
+
+#endif /* __NGHttp_NGHttpMessage_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpMessage.m b/skyrix-sope/NGObjWeb/NGHttp/NGHttpMessage.m
new file mode 100644 (file)
index 0000000..e884443
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGHttpMessage.h"
+#include "common.h"
+#include "NGHttpCookie.h"
+
+@interface NGHttpMessage(PrivateMethods)
+- (void)extractCommonHeaders;
+@end
+
+@implementation NGHttpMessage
+
+- (id)initWithHeader:(NGHashMap *)_header version:(NSString *)_version {
+  if ((self = [super init])) {
+    self->header = [_header retain];
+    self->body   = nil;
+
+    if ([_version hasSuffix:@"0.9"]) {
+      self->majorVersion = 0;
+      self->minorVersion = 9;
+    }
+    else if ([_version hasSuffix:@"1.0"]) {
+      self->majorVersion = 1;
+      self->minorVersion = 0;
+    }
+    else if ([_version hasSuffix:@"1.1"]) {
+      self->majorVersion = 1;
+      self->minorVersion = 1;
+    }
+    else {
+      self->majorVersion = 0;
+      self->minorVersion = 9;
+    }
+    
+    [self extractCommonHeaders];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithHeader:nil version:nil];
+}
+
+- (void)dealloc {
+  [self->header release];
+  [self->body   release];
+  [super dealloc];
+}
+
+/* headers */
+
+- (void)extractCommonHeaders {
+}
+
+- (void)setValue:(id)_value ofHeaderFieldWithName:(NSString *)_name {
+  if (![self->header isKindOfClass:[NGMutableHashMap class]]) {
+    id new = [self->header mutableCopy];
+    [self->header release];
+    self->header = new;
+  }
+  [(NGMutableHashMap *)self->header setObject:_value forKey:_name];
+}
+- (void)addValue:(id)_value toHeaderFieldWithName:(NSString *)_name {
+  if (![self->header isKindOfClass:[NGMutableHashMap class]]) {
+    id new = [self->header mutableCopy];
+    [self->header release];
+    self->header = new;
+  }
+  [(NGMutableHashMap *)self->header addObject:_value forKey:_name];
+}
+- (void)removeValue:(id)_value fromHeaderFieldWithName:(NSString *)_name {
+  if (![self->header isKindOfClass:[NGMutableHashMap class]]) {
+    id new = [self->header mutableCopyWithZone:[self zone]];
+    [self->header release];
+    self->header = new;
+  }
+  [(NGMutableHashMap *)self->header removeAllObjects:_value forKey:_name];
+}
+
+/* common headers */
+
+- (void)setContentType:(NGMimeType *)_type {
+  [self setValue:_type ofHeaderFieldWithName:@"content-type"];
+}
+- (void)setContentLength:(unsigned)_length {
+  [self setValue:[NSNumber numberWithUnsignedInt:_length]
+        ofHeaderFieldWithName:@"content-length"];
+}
+
+- (unsigned)contentLength {
+  return [[self->header objectForKey:@"content-length"] intValue];
+}
+
+- (id)valueOfHeaderFieldWithName:(NSString *)_name {
+  return [self->header objectForKey:_name];
+}
+
+/* accessors */
+
+- (NSString *)httpVersion {
+  return [NSString stringWithFormat:@"HTTP/%i.%i",
+                     self->majorVersion,
+                     self->minorVersion];
+}
+- (char)majorVersion {
+  return self->majorVersion;
+}
+- (char)minorVersion {
+  return self->minorVersion;
+}
+
+/* Cookies */
+
+- (NSArray *)cookies {
+  return [self->header objectForKey:@"cookie"];
+}
+
+- (id)valueOfCookieWithName:(NSString *)_name {
+  NSArray *cookies   = [self->header objectForKey:@"cookie"];
+  int     pos, count = [cookies count];
+
+  //NSLog(@"cookies=%@", cookies);
+
+  for (pos = 0; pos < count; pos++) {
+    NGHttpCookie *cookie = [cookies objectAtIndex:pos];
+
+    NSAssert([cookie isKindOfClass:[NGHttpCookie class]],
+             @"invalid cookie value");
+    
+    if ([[cookie cookieName] isEqualToString:_name])
+      return [cookie value];
+  }
+  return nil;
+}
+
+- (void)addClientCookie:(NGHttpCookie *)_cookie {
+  // 'Set-Cookie' header
+  [(NGMutableHashMap *)self->header addObject:_cookie forKey:@"set-cookie"];
+}
+- (NSArray *)clientCookies {
+  return [self->header objectsForKey:@"set-cookie"];
+}
+
+/* NGPart */
+
+- (NSEnumerator *)valuesOfHeaderFieldWithName:(NSString *)_name {
+  return [self->header objectEnumeratorForKey:_name];
+}
+- (NSEnumerator *)headerFieldNames {
+  return [self->header keyEnumerator];
+}
+
+- (void)setBody:(id)_body {
+  ASSIGN(self->body, _body);
+}
+- (id)body {
+  return self->body;
+}
+
+/* NGMimePart */
+
+- (NGMimeType *)contentType {
+  id type;
+  
+  if ((type = [self valueOfHeaderFieldWithName:@"content-type"]) == nil)
+    return [NGMimeType mimeType:@"text/plain"];
+
+  if (![type isKindOfClass:[NGMimeType class]])
+    type = [NGMimeType mimeType:[type stringValue]];
+  
+  return type;
+}
+- (NSString *)contentId {
+  return [[self->header objectForKey:@"content-id"] stringValue];
+}
+- (NSArray *)contentLanguage {
+  id val;
+
+  if ((val = [self->header objectForKey:@"content-language"]) == nil)
+    return nil;
+
+  if (![val isKindOfClass:[NSArray class]])
+    val = [[val stringValue] componentsSeparatedByString:@","];
+  
+  return val;
+}
+- (NSString *)contentMd5 {
+  return [[self->header objectForKey:@"content-md5"] stringValue];
+}
+- (NSString *)encoding {
+  return [[self->header objectForKey:@"content-encoding"] stringValue];
+}
+- (NSString *)contentDescription {
+  return [[self->header objectForKey:@"content-description"] stringValue];
+}
+
+@end /* NGHttpMessage */
+
+/* constants */
+
+// used in 'Accept-Encoding' and 'Content-Encoding'
+NSString *NGHttpContentCoding_gzip      = @"gzip";
+NSString *NGHttpContentCoding_compress  = @"compress";
+NSString *NGHttpContentCoding_deflate   = @"deflate";
+NSString *NGHttpContentCoding_identity  = @"identity";
+
+// used in 'Transfer-Encoding'
+NSString *NGHttpTransferCoding_chunked  = @"chunked";
+NSString *NGHttpTransferCoding_identity = @"identity";
+NSString *NGHttpTransferCoding_gzip     = @"gzip";
+NSString *NGHttpTransferCoding_compress = @"compress";
+NSString *NGHttpTransferCoding_deflate  = @"deflate";
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpMessageParser.h b/skyrix-sope/NGObjWeb/NGHttp/NGHttpMessageParser.h
new file mode 100644 (file)
index 0000000..d748e75
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_NGHttpMessageParser_H__
+#define __NGHttp_NGHttpMessageParser_H__
+
+#import <NGMime/NGMimePartParser.h>
+#import <NGMime/NGPart.h>
+
+@class NGHashMap;
+@class NGHttpMessage, NGHttpRequest, NGHttpResponse;
+
+@interface NGHttpMessageParser : NGMimePartParser
+{
+@protected
+  struct {
+    BOOL parseRequest:1; // whether a request or a response is expected
+  } flags;
+  
+  struct {
+    BOOL httpParserWillParseRequest:1;
+    BOOL httpParserDidParseRequest:1;
+    BOOL httpParserWillParseResponse:1;
+    BOOL httpParserDidParseResponse:1;
+  } httpDelegateRespondsTo;
+
+  // used during parsing
+  NSString *methodName; // 'GET', 'PUT', ..
+  NSString *uri;        // either '*' | absolute-URI | absolute-path
+  NSString *version;    // eg 'HTTP/1.1'
+  int      status;
+  NSString *reason;
+}
+
+// accessors
+
+- (void)setDelegate:(id)_delegate; // sets the additional flags ..
+
+/* HTTP parsing */
+
+- (BOOL)parseRequestLine;
+- (BOOL)parseStatusLine;
+- (BOOL)parseStartLine;
+
+/* body parsing */
+
+- (id<NGMimePart>)producePartWithHeader:(NGHashMap *)_header;
+
+- (NGHttpRequest *)produceRequestWithMethodName:(NSString *)_method
+  uri:(NSString *)_uri version:(NSString *)_version
+  header:(NGHashMap *)_header;
+
+- (NGHttpResponse *)produceResponseWithStatusCode:(int)_code
+  statusText:(NSString *)_text version:(NSString *)_version
+  header:(NGHashMap *)_header;
+
+- (NGHttpRequest *)parseRequestFromStream:(id<NGStream>)_stream;
+- (NGHttpResponse *)parseResponseFromStream:(id<NGStream>)_stream;
+
+@end
+
+@interface NSObject(NGHttpMessageParserDelegate)
+
+- (BOOL)httpParserWillParseRequest:(NGHttpMessageParser *)_parser;
+- (BOOL)httpParserWillParseResponse:(NGHttpMessageParser *)_parser;
+
+- (void)httpParser:(NGHttpMessageParser *)_parser
+  didParseRequest:(NGHttpRequest *)_request;
+- (void)httpParser:(NGHttpMessageParser *)_parser
+  didParseResponse:(NGHttpResponse *)_response;
+
+@end
+
+#endif /* __NGHttp_NGHttpMessageParser_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpMessageParser.m b/skyrix-sope/NGObjWeb/NGHttp/NGHttpMessageParser.m
new file mode 100644 (file)
index 0000000..e30c801
--- /dev/null
@@ -0,0 +1,740 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NGHttpMessageParser.h"
+#import "NGHttpMessage.h"
+#import "NGHttpRequest.h"
+#import "NGHttpResponse.h"
+#import "NGHttpHeaderFieldParser.h"
+#import "NGHttpBodyParser.h"
+
+static inline void NGAddChar(NSMutableData *_data, int c) {
+  unsigned char c8 = c;
+  static Class lastClass = Nil; // THREAD
+  static void  (*addBytes)(id,SEL,void*,unsigned) = NULL;
+  if (_data == nil) return;
+  
+  if (*(Class *)_data != lastClass) {
+    lastClass  = *(Class *)_data;
+    addBytes = (void*)[_data methodForSelector:@selector(appendBytes:length:)];
+  }
+  
+  if (addBytes)
+    addBytes(_data, @selector(appendBytes:length:), &c8, 1);
+  else
+    [_data appendBytes:&c8 length:1];
+}
+
+@implementation NGHttpMessageParser
+
++ (int)version {
+  return [super version] + 0 /* v3 */;
+}
+
+static NGMimeType           *wwwFormUrlEncoded = nil;
+static NGMimeType           *multipartFormData = nil;
+static id<NGMimeBodyParser> wwwFormUrlParser   = nil;
+static id<NGMimeBodyParser> multipartFormDataParser = nil;
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    isInitialized = YES;
+
+    NSAssert2([super version] == 3,
+             @"invalid superclass (%@) version %i !",
+             NSStringFromClass([self superclass]), [super version]);
+    
+    wwwFormUrlEncoded = 
+      [[NGMimeType mimeType:@"application/x-www-form-urlencoded"] retain];
+    multipartFormData = [[NGMimeType mimeType:@"multipart/form-data"] retain];
+    
+    wwwFormUrlParser = [[NGFormUrlBodyParser alloc] init];
+    multipartFormDataParser = [[NGHttpMultipartFormDataBodyParser alloc] init];
+  }
+}
+
+static inline int _readByte(NGHttpMessageParser *self) {
+  return self->readByte
+    ? self->readByte(self->source, @selector(readByte))
+    : [self->source readByte];
+}
+
+static inline int _skipLWSP(NGHttpMessageParser *self, int _c) {
+  int c = _c;
+  while ((c == 32) || (c == '\t'))
+    c = _readByte(self);
+  return c;
+}
+
+/* init */
+
+- (id)init {
+  if ((self = [super init])) {
+    self->useContentLength = YES;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->reason     release];
+  [self->methodName release];
+  [self->uri     release];
+  [self->version release];
+  [super dealloc];
+}
+
+// accessors
+
+- (void)setDelegate:(id)_delegate {
+  [super setDelegate:_delegate];
+  
+  self->httpDelegateRespondsTo.httpParserWillParseRequest
+    = [self->delegate respondsToSelector:@selector(httpParserWillParseRequest:)];
+  self->httpDelegateRespondsTo.httpParserWillParseResponse
+    = [self->delegate respondsToSelector:@selector(httpParserWillParseResponse:)];
+
+  self->httpDelegateRespondsTo.httpParserDidParseRequest
+    = [self->delegate respondsToSelector:@selector(httpParser:didParseRequest:)];
+  self->httpDelegateRespondsTo.httpParserDidParseResponse
+    = [self->delegate respondsToSelector:@selector(httpParser:didParseResponse:)];
+}
+
+/* headers */
+
+- (id<NGMimeHeaderFieldParser>)parserForHeaderField:(NSString *)_name {
+  //NSLog(@"asked for header field parser of %@", _name);
+#if 1
+  //#warning does not use header field parsers by default ...
+  return nil;
+#else
+  return [NGMimeHeaderFieldParserSet defaultHttpHeaderFieldParserSet];
+#endif
+}
+
+// preparation
+
+- (BOOL)prepareForParsingFromStream:(id<NGStream>)_stream {
+  if ([super prepareForParsingFromStream:_stream]) {
+    if (self->methodName) {
+      [self->methodName release]; self->methodName = nil;
+    }
+    if (self->uri) {
+      [self->uri release]; self->uri = nil;
+    }
+    if (self->version) {
+      [self->version release]; self->version = nil;
+    }
+    
+    return YES;
+  }
+  return NO;
+}
+- (void)finishParsingOfPart:(id<NGMimePart>)_part {
+  [self->methodName release]; self->methodName = nil;
+}
+
+// parse request/response line
+
+- (BOOL)parseRequestLine {
+  int c;
+  
+#if DEBUG
+  NSAssert1(self->source, @"missing source %@ !", self);
+#endif
+  
+  /* ignore prefix CRLF's, as described in RFC (HTTP/1.1, section 4.1) */
+  do {
+    c = _readByte(self);
+  }
+  while ((c == 13) || (c == 10));
+  if (c == -1) /* unexpected EOF */
+    return NO;
+
+#if 1
+  /* parse the request method */
+  {
+    char buf[16];
+    int  i = 0;
+    
+    do {
+      buf[i] = c; // one char is already present ..
+      c = _readByte(self);
+      i++;
+    }
+    while ((c != 32) && (c != '\r') && (c != '\n') && (c != -1) && (i < 15));
+    buf[i] = '\0';
+    
+    if (c == -1) // unexpected EOF
+      return NO;
+
+    if (i >= 15) {
+      NSLog(@"WARNING: truncated request method "
+            @"(may not longer than 15 chars): %s",
+            buf);
+    }
+
+    self->methodName = [[NSString alloc] initWithCString:buf length:i];
+  }
+  
+  c = _skipLWSP(self, c);
+  if (c == -1) { // unexpected EOF
+    RELEASE(self->methodName); self->methodName = nil;
+    return NO;
+  }
+  
+  /* read data till end of line ... */
+  {
+    NSMutableData *data = nil;
+    unsigned char *bytes, *tmp;
+    unsigned len;
+    
+    data = [[NSMutableData alloc] initWithCapacity:256];
+    do {
+      NGAddChar(data, c); /* one char is in queue ... */
+      c = _readByte(self);
+    }
+    while ((c != 13) && (c != 10) && (c != -1));
+    NGAddChar(data, 0);
+    
+    if (c == -1) { /* unexpected EOF */
+      [data             release]; data = nil;
+      [self->methodName release]; self->methodName = nil;
+      return NO;
+    }
+    
+    if (c == 13) { /* if CR */
+      c = _readByte(self); /* read LF */
+      
+      if ((c != 10) && (c != -1)) {
+        NSLog(@"WARNING(%s): missed LF after CR (got %i)\n",
+              __PRETTY_FUNCTION__, c);
+      }
+    }
+    
+    bytes = [data mutableBytes];
+    
+    /* strip trailing spaces ... */
+    len = strlen(bytes);
+    while (len > 0) {
+      if (bytes[len - 1] != 32) break;
+      len--;
+      bytes[len] = '\0';
+    }
+    
+    if ((tmp = rindex(bytes, 32))) {
+      unsigned char *t2;
+      
+      if ((t2 = strstr(tmp, "HTTP"))) {
+        /* has a HTTP version spec ... */
+        
+        *tmp = '\0';
+        tmp++;
+        self->version = [[NSString alloc] initWithCString:tmp];
+        
+        /* strip trailing spaces ... */
+        len = strlen(bytes);
+        while (len > 0) {
+          if (bytes[len - 1] != 32) break;
+          len--;
+          bytes[len] = '\0';
+        }
+      }
+      else {
+        /* has no HTTP version spec, but possibly trailing spaces */
+        
+        /* strip trailing spaces ... */
+        len = strlen(bytes);
+        while (len > 0) {
+          if (bytes[len - 1] != 32) break;
+          len--;
+          bytes[len] = '\0';
+        }
+      }
+    }
+    else {
+      /* has no HTTP version spec */
+    }
+    self->uri = [[NSString alloc] initWithCString:bytes];
+    
+    RELEASE(data); data = nil;
+  }
+
+#if 0
+  [self logWithFormat:@"parsed request line: %@ uri=%@",
+         self->methodName, self->uri];
+#endif
+#else
+  /* now start processing request line (one char is already present) .. */
+  
+  { /* process method */
+    char buf[16];
+    int  i = 0;
+
+    do {
+      buf[i] = c; // one char is already present ..
+      c = _readByte(self);
+      i++;
+    }
+    while ((c != 32) && (c != '\r') && (c != '\n') && (c != -1) && (i < 15));
+    buf[i] = '\0';
+    
+    if (c == -1) // unexpected EOF
+      return NO;
+
+    if (i >= 15) {
+      NSLog(@"WARNING: truncated request method "
+            @"(may not longer than 15 chars): %s",
+            buf);
+    }
+
+    self->methodName = [[NSString alloc] initWithCString:buf length:i];
+  }
+  
+  c = _skipLWSP(self, c);
+  if (c == -1) { // unexpected EOF
+    RELEASE(self->methodName); self->methodName = nil;
+    return NO;
+  }
+
+  { /* process path */
+    NSMutableData *data = nil;
+    
+    data = [[NSMutableData allocWithZone:[self zone]] initWithCapacity:256];
+    do {
+      NGAddChar(data, c);
+      c = _readByte(self);
+    }
+    while ((c != 32) && (c != '\r') && (c != '\n') && (c != -1));
+    if (c == -1) { // unexpected EOF
+      RELEASE(data); data = nil;
+      RELEASE(self->methodName); self->methodName = nil;
+      return NO;
+    }
+
+    self->uri = [[NSString allocWithZone:[self zone]]
+                           initWithCString:[data bytes] length:[data length]];
+    RELEASE(data); data = nil;
+  }
+
+  c = _skipLWSP(self, c);
+  if (c == -1) { // unexpected EOF
+    RELEASE(self->methodName); self->methodName = nil;
+    RELEASE(self->uri);        self->uri        = nil;
+    return NO;
+  }
+  
+  if ((c == 13) || (c == 10)) { // no HTTP version was provided, using HTTP/0.9
+    if (c == 13) // if CR
+      c = _readByte(self); // read LF
+
+    if (c != 10)
+      NSLog(@"WARNING: expected LF after CR in request line, got %i", c);
+
+    self->version = @"HTTP/0.9";
+  }
+  else { /* HTTP version next .. */
+    char buf[16];
+    int  i = 0;
+
+    do {
+      buf[i] = c; // one char is already present ..
+      c = _readByte(self);
+      i++;
+    }
+    while ((c != 13) && (c != 10) && (c != 32) && (c != '\t') &&
+           (c != -1) && (i < 15));
+    buf[i] = '\0';
+    
+    if (c == -1) { // unexpected EOF
+      RELEASE(self->methodName); self->methodName = nil;
+      RELEASE(self->uri);        self->uri        = nil;
+      return NO;
+    }
+
+    if (i >= 15) {
+      NSLog(@"WARNING: truncated protocol version "
+            @"(may not be longer than 15 chars): %s", buf);
+    }
+
+    self->version = [[NSString allocWithZone:[self zone]]
+                               initWithCString:buf length:i];
+
+    /* and now read all remaining chars (spaces and CRLF..) */
+    while ((c != 10) && (c != -1))
+      c = _readByte(self);
+
+    if (c == -1) { // unexpected EOF
+      RELEASE(self->methodName); self->methodName = nil;
+      RELEASE(self->uri);        self->uri        = nil;
+      RELEASE(self->version);    self->version    = nil;
+      return NO;
+    }
+  }
+#endif
+  return YES;
+}
+
+- (BOOL)parseStatusLine {
+  int c;
+
+#if DEBUG
+  NSAssert1(self->source, @"missing source %@ !", self);
+#endif
+
+  /* ignore prefix CRLF's, as described in RFC (HTTP/1.1, section 4.1) */
+  do {
+    c = _readByte(self);
+  }
+  while ((c == 13) || (c == 10));
+  if (c == -1) // unexpected EOF
+    return NO;
+  
+  /* now start processing response line (one char is already present) .. */
+
+  { /* process HTTP version */
+    char buf[16];
+    int  i = 0;
+    
+    do {
+      buf[i] = c; // one char is already present ..
+      c = _readByte(self);
+      i++;
+    }
+    while ((c != 32) && (c != '\r') && (c != '\n') && (c != -1) && (i < 15));
+    buf[i] = '\0';
+    
+    if (c == -1) // unexpected EOF
+      return NO;
+    
+    if (i >= 15) {
+      NSLog(@"WARNING: truncated response version "
+            @"(may not longer than 15 chars): %s",
+            buf);
+    }
+    
+    self->version = [[NSString alloc] initWithCString:buf length:i];
+  }
+
+  c = _skipLWSP(self, c);
+  if (c == -1) { // unexpected EOF
+    RELEASE(self->methodName); self->methodName = nil;
+    return NO;
+  }
+
+  { /* process HTTP status */
+    char buf[5];
+    int  i = 0;
+    
+    do {
+      buf[i] = c; // one char is already present ..
+      c = _readByte(self);
+      i++;
+    }
+    while ((c != 32) && (c != '\r') && (c != '\n') && (c != -1) && (i < 5));
+    buf[i] = '\0';
+    
+    if (c == -1) // unexpected EOF
+      return NO;
+    
+    if (i >= 5) {
+      NSLog(@"WARNING: truncated response status "
+            @"(may not longer than 3 chars): %s",
+            buf);
+    }
+
+    self->status = atoi(buf);
+  }
+  
+  if ((c = _skipLWSP(self, c)) == -1) { // unexpected EOF
+    RELEASE(self->methodName); self->methodName = nil;
+    RELEASE(self->uri);        self->uri        = nil;
+    return NO;
+  }
+  
+  if ((c == 13) || (c == 10)) { // no HTTP reason was provided
+    if (c == 13) // if CR
+      c = _readByte(self); // read LF
+
+    if (c != 10)
+      NSLog(@"WARNING: expected LF after CR in request line, got %i", c);
+  }
+  else { // HTTP reason text next
+    // to be done ..
+    
+    // and now read all remaining chars (spaces and CRLF..)
+    while ((c != 10) && (c != -1))
+      c = _readByte(self);
+
+    if (c == -1) { // unexpected EOF
+      RELEASE(self->reason);  self->reason  = nil;
+      RELEASE(self->version); self->version = nil;
+      return NO;
+    }
+  }
+  
+  return YES;
+}
+
+- (BOOL)parseStartLine {
+  return (self->flags.parseRequest)
+    ? [self parseRequestLine]
+    : [self parseStatusLine];
+}
+
+- (BOOL)parsePrefix {
+  if ([super parsePrefix])
+    return [self parseStartLine];
+  else
+    return NO;
+}
+
+- (NGMimeBodyParser *)parserForBodyOfPart:(id<NGMimePart>)_part
+  data:(NSData *)_dt
+{
+  NGMimeType *contentType;
+  
+  contentType = [_part contentType];
+  
+#if 0
+  NSLog(@"%s: was asked for parser for type %@ (data with len %d) ..",
+        __PRETTY_FUNCTION__, contentType, [_dt length]);
+#endif
+  
+  if ([contentType hasSameType:wwwFormUrlEncoded])
+    return (NGMimeBodyParser *)wwwFormUrlParser;
+  
+  return (NGMimeBodyParser *)[super parserForBodyOfPart:_part data:_dt];
+}
+
+- (void)parseBodyOfPart:(id<NGMimePart>)_part {
+  BOOL doParse, hasCLenHeader;
+  id   clenValues;
+  
+  if (_part == nil) {
+    NSLog(@"WARNING(%s:%i): got no part !", __PRETTY_FUNCTION__, __LINE__);
+    return;
+  }
+  
+  /* parse only if content-length > 0 */
+  clenValues = [_part valuesOfHeaderFieldWithName:@"content-length"];
+  hasCLenHeader = clenValues ? YES : NO;
+  if ((clenValues = [clenValues nextObject])) {
+    if ([(id)_part contentLength] > 0)
+      doParse = YES;
+    else {
+      //NSLog(@"%s: does not parse body, clen is 0", __PRETTY_FUNCTION__);
+      doParse = NO;
+    }
+  }
+  else {
+    /* parse until EOF */
+#if 0
+    NSLog(@"WARNING(%s): parsing until EOF, "
+          @"missed content-length header in part %@..",
+          __PRETTY_FUNCTION__, _part);
+#endif
+    doParse = YES;
+  }
+  
+  if (self->flags.parseRequest) {
+    NGHttpRequest *rq;
+    
+    rq = (NGHttpRequest *)_part;
+#if DEBUG
+    if (![rq isKindOfClass:[NGHttpRequest class]]) {
+      NSLog(@"ERROR(%s:%i): got invalid part for request parsing !",
+           __PRETTY_FUNCTION__, __LINE__);
+    }
+#endif
+    
+    switch ([rq method]) {
+      case NGHttpMethod_GET:
+      case NGHttpMethod_OPTIONS:
+      case NGHttpMethod_HEAD:
+      case NGHttpMethod_DELETE:
+      case NGHttpMethod_UNLOCK:
+        /* never parse body of the requests above */
+        if ([rq contentLength] > 0) {
+         [self logWithFormat:
+                 @"WARNING: expected no content with this method !"];
+       }
+       doParse = NO;
+        break;
+        
+      case NGHttpMethod_POST:
+      case NGHttpMethod_PUT:
+      default:
+       if (doParse && ([rq contentLength] == 0)) {
+         /*
+           Two cases: 
+             HTTP/1.0, HTTP/0.9 - read till EOF if no content-length is set
+             HTTP/1.1 and above: if no content-length is set, body is empty
+         */
+         if ([rq majorVersion] < 1)
+           doParse = YES;
+         else if ([rq majorVersion] == 1 && [rq minorVersion] == 0)
+           doParse = YES;
+         else
+           doParse = NO;
+       }
+        break;
+    }
+    
+    if (doParse)
+      [super parseBodyOfPart:_part];
+  }
+  else {
+#if DEBUG
+    NSAssert([_part isKindOfClass:[NGHttpResponse class]],
+             @"part should be a response ..");
+#endif
+    
+    doParse = YES;
+    
+    if (doParse)
+      [super parseBodyOfPart:_part];
+  }
+}
+
+/* part parsing */
+
+- (NGHttpRequest *)produceRequestWithMethodName:(NSString *)_method
+  uri:(NSString *)_uri version:(NSString *)_version
+  header:(NGHashMap *)_header
+{
+  NGHttpRequest *request = nil;
+
+  request = [[NGHttpRequest allocWithZone:[self zone]]
+                            initWithMethod:_method
+                            uri:_uri
+                            header:_header
+                            version:_version];
+  return AUTORELEASE(request);
+}
+
+- (NGHttpResponse *)produceResponseWithStatusCode:(int)_code
+  statusText:(NSString *)_text version:(NSString *)_version
+  header:(NGHashMap *)_header
+{
+  NGHttpResponse *response = nil;
+  
+  response = [[NGHttpResponse allocWithZone:[self zone]]
+                              initWithStatus:_code
+                              reason:_text
+                              header:_header
+                              version:_version];
+  return AUTORELEASE(response);
+}
+
+- (id<NGMimePart>)producePartWithHeader:(NGHashMap *)_header {
+  // NSLog(@"producing part with header: %@", _header);
+  
+  if (self->flags.parseRequest) {
+    NGHttpRequest *request = nil;
+
+    request = [self produceRequestWithMethodName:self->methodName
+                    uri:self->uri
+                    version:self->version
+                    header:_header];
+    
+    RELEASE(self->methodName); self->methodName = nil;
+    RELEASE(self->uri);        self->uri        = nil;
+    RELEASE(self->version);    self->version    = nil;
+
+    return request;
+  }
+  else {
+    NGHttpResponse *response = nil;
+
+    response = [self produceResponseWithStatusCode:self->status
+                     statusText:self->reason
+                     version:self->version
+                     header:_header];
+    
+    RELEASE(self->version); self->version = nil;
+    
+    return response;
+  }
+}
+
+- (NGHttpRequest *)parseRequestFromStream:(id<NGStream>)_stream {
+  NGHttpRequest *request = nil;
+
+#if DEBUG
+  NSAssert1(_stream, @"missing stream %@ ..", _stream);
+#endif
+  
+  self->flags.parseRequest = YES;
+
+  if (self->httpDelegateRespondsTo.httpParserWillParseRequest) {
+    if ([self->delegate httpParserWillParseRequest:self] == NO) {
+      // parsing aborted
+      return nil;
+    }
+  }
+
+  //NSLog(@"%s: parse part from stream ..", __PRETTY_FUNCTION__);
+  request = (NGHttpRequest *)[self parsePartFromStream:_stream];
+
+  if (request) {
+    if (self->httpDelegateRespondsTo.httpParserDidParseRequest)
+      [self->delegate httpParser:self didParseRequest:request];
+  }
+  return request;
+}
+
+- (NGHttpResponse *)parseResponseFromStream:(id<NGStream>)_stream {
+  NGHttpResponse *response = nil;
+  
+#if DEBUG
+  NSAssert1(_stream, @"missing stream %@ ..", _stream);
+#endif
+  
+  self->flags.parseRequest = NO;
+
+  if (self->httpDelegateRespondsTo.httpParserWillParseResponse) {
+    if ([self->delegate httpParserWillParseResponse:self] == NO) {
+      // parsing aborted
+      return nil;
+    }
+  }
+  
+  response = (NGHttpResponse *)[self parsePartFromStream:_stream];
+
+  if (response) {
+    if (self->httpDelegateRespondsTo.httpParserDidParseResponse)
+      [self->delegate httpParser:self didParseResponse:response];
+  }
+  return response;
+}
+
+#if 0
+- (id<NGMimePart>)parsePartFromStream:(id<NGByteSequenceStream>)_stream {
+  NSLog(@"do not use parsePartFromStream: with NGHttpMessageParser !");
+  abort();
+  return nil;
+}
+#endif
+
+@end /* NGHttpMessageParser */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpRequest.h b/skyrix-sope/NGObjWeb/NGHttp/NGHttpRequest.h
new file mode 100644 (file)
index 0000000..68b5d1a
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGHttp_NGHttpRequest_H__
+#define __NGHttp_NGHttpRequest_H__
+
+#import "NGHttpMessage.h"
+
+@class NSString;
+
+typedef enum {
+  NGHttpMethod_unknown = 0,
+  NGHttpMethod_OPTIONS = 1,
+  NGHttpMethod_GET,
+  NGHttpMethod_HEAD,
+  NGHttpMethod_POST,
+  NGHttpMethod_PUT,
+  NGHttpMethod_PATCH,
+  NGHttpMethod_COPY,
+  NGHttpMethod_MOVE,
+  NGHttpMethod_DELETE,
+  NGHttpMethod_LINK,
+  NGHttpMethod_UNLINK,
+  NGHttpMethod_TRACE,
+  NGHttpMethod_WRAPPED,
+  NGHttpMethod_CONNECT,
+  NGHttpMethod_PROPFIND,
+  NGHttpMethod_PROPPATCH,
+  NGHttpMethod_MKCOL,
+  NGHttpMethod_LOCK,
+  NGHttpMethod_UNLOCK,
+  /* Exchange Ext Methods */
+  NGHttpMethod_SEARCH, 
+  NGHttpMethod_SUBSCRIBE,
+  NGHttpMethod_UNSUBSCRIBE,
+  NGHttpMethod_NOTIFY,
+  NGHttpMethod_POLL,
+  /* Exchange Bulk Methods */
+  NGHttpMethod_BCOPY,
+  NGHttpMethod_BDELETE,
+  NGHttpMethod_BMOVE,
+  NGHttpMethod_BPROPFIND,
+  NGHttpMethod_BPROPPATCH,
+  NGHttpMethod_last
+} NGHttpMethod;
+
+NGHttpMethod NGHttpMethodFromString(NSString *_value);
+
+@interface NGHttpRequest : NGHttpMessage
+{
+  NGHttpMethod method;
+  NSString     *uri;
+  NGHashMap    *uriParameters;
+}
+
+- (id)initWithMethod:(NSString *)_methodName uri:(NSString *)_uri
+  header:(NGHashMap *)_header version:(NSString *)_version;
+
+/* accessors */
+
+- (NGHttpMethod)method;
+- (NSString *)methodName;
+- (NSString *)uri;
+
+- (NGHashMap *)uriParameters; // parameters in x-www-form-urlencoded encoding
+
+@end
+
+#endif /* __NGHttp_NGHttpRequest_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpRequest.m b/skyrix-sope/NGObjWeb/NGHttp/NGHttpRequest.m
new file mode 100644 (file)
index 0000000..cc9ff0f
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGHttpRequest.h"
+#include "common.h"
+#include "NGUrlFormCoder.h"
+
+NSString *methodNames[] = {
+  @"<unknown HTTP method>",
+  @"OPTIONS",
+  @"GET",
+  @"HEAD",
+  @"POST",
+  @"PUT",
+  @"PATCH",
+  @"COPY",
+  @"MOVE",
+  @"DELETE",
+  @"LINK",
+  @"UNLINK",
+  @"TRACE",
+  @"WRAPPED",
+  @"CONNECT",
+  @"PROPFIND",
+  @"PROPPATCH",
+  @"MKCOL",
+  @"LOCK",
+  @"UNLOCK",
+  /* Exchange Ext Methods */
+  @"SEARCH", 
+  @"SUBSCRIBE",
+  @"UNSUBSCRIBE",
+  @"NOTIFY",
+  @"POLL",
+  /* Exchange Bulk Methods */
+  @"BCOPY",
+  @"BDELETE",
+  @"BMOVE",
+  @"BPROPFIND",
+  @"BPROPPATCH",
+  nil
+};
+
+@interface NGHttpMessage(PrivateMethods)
+- (id)initWithHeader:(NGHashMap *)_header version:(NSString *)_version;
+@end
+
+@implementation NGHttpRequest
+
+- (id)initWithMethod:(NSString *)_methodName uri:(NSString *)_uri
+  header:(NGHashMap *)_header version:(NSString *)_version
+{
+  if ((self = [super initWithHeader:_header version:_version])) {
+    self->method = NGHttpMethodFromString(_methodName);
+    self->uri    = [_uri copyWithZone:[self zone]];
+  }
+  return self;
+}
+- (id)initWithHeader:(NGHashMap *)_header version:(NSString *)_version {
+  return [self initWithMethod:@"GET" uri:@"/" header:_header version:_version];
+}
+
+- (void)dealloc {
+  [self->uri           release];
+  [self->uriParameters release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NGHttpMethod)method {
+  return self->method;
+}
+- (NSString *)methodName {
+  return (self->method < NGHttpMethod_last) ? methodNames[self->method] : nil;
+}
+
+- (NSString *)path {
+  return self->uri;
+}
+
+- (NSString *)uri {
+  return self->uri;
+}
+
+- (NGHashMap *)uriParameters { // parameters in x-www-form-urlencoded encoding
+  if (self->uriParameters == nil) {
+    const char *cstr = [self->uri cString];
+    const char *pos  = index(cstr, '?');
+
+    if (pos) {
+      pos++;
+      self->uriParameters = NGDecodeUrlFormParameters(pos, strlen(pos));
+    }
+  }
+  return self->uriParameters;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return NO;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<HttpRequest: method=%@ uri=%@ header=%@ body=%@>",
+                     [self methodName],
+                     [self uri],
+                     self->header,
+                     self->body];
+}
+
+@end /* NGHttpRequest */
+
+NGHttpMethod NGHttpMethodFromString(NSString *_value) {
+  int i = 0;
+
+  for (i = 1; i < NGHttpMethod_last; i++) {
+    NSString *name = methodNames[i];
+
+    if ([name isEqualToString:_value])
+      return i;
+  }
+  return 0;
+}
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpResponse.h b/skyrix-sope/NGObjWeb/NGHttp/NGHttpResponse.h
new file mode 100644 (file)
index 0000000..5381ec0
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_NGHttpResponse_H__
+#define __NGHttp_NGHttpResponse_H__
+
+#import "NGHttpMessage.h"
+
+@class NSString;
+@class NGHttpRequest, NGHttpChallenge;
+
+typedef enum {
+  NGHttpStatusCode_unknown = 0,
+
+  // 1xx informational
+  NGHttpStatusCode_Continue                    = 100,
+  NGHttpStatusCode_SwitchingProtocols          = 101,
+
+  // 2xx successful
+  NGHttpStatusCode_OK                          = 200,
+  NGHttpStatusCode_Created                     = 201,
+  NGHttpStatusCode_Accepted                    = 202,
+  NGHttpStatusCode_NonAuthoritativeInformation = 203,
+  NGHttpStatusCode_NoContent                   = 204,
+  NGHttpStatusCode_ResetContent                = 205,
+  NGHttpStatusCode_PartialContent              = 206,
+
+  // 3xx redirection
+  NGHttpStatusCode_MultipleChoices             = 300,
+  NGHttpStatusCode_MovedPermanently            = 301,
+  NGHttpStatusCode_MovedTemporarily            = 302,
+  NGHttpStatusCode_SeeOther                    = 303,
+  NGHttpStatusCode_NotModified                 = 304,
+  NGHttpStatusCode_UseProxy                    = 305,
+
+  // 4xx client error
+  NGHttpStatusCode_BadRequest                  = 400,
+  NGHttpStatusCode_Unauthorized                = 401,
+  NGHttpStatusCode_PaymentRequired             = 402,
+  NGHttpStatusCode_Forbidden                   = 403,
+  NGHttpStatusCode_NotFound                    = 404,
+  NGHttpStatusCode_MethodNotAllowed            = 405,
+  NGHttpStatusCode_NoneAcceptable              = 406,
+  NGHttpStatusCode_ProxyAuthenticationRequired = 407,
+  NGHttpStatusCode_RequestTimeout              = 408,
+  NGHttpStatusCode_Conflict                    = 409,
+  NGHttpStatusCode_Gone                        = 410,
+  NGHttpStatusCode_LengthRequired              = 411,
+  NGHttpStatusCode_UnlessTrue                  = 412,
+
+  // 5xx server error
+  NGHttpStatusCode_InternalServerError         = 500,
+  NGHttpStatusCode_NotImplemented              = 501,
+  NGHttpStatusCode_BadGateway                  = 502,
+  NGHttpStatusCode_ServiceUnavailable          = 503,
+  NGHttpStatusCode_GatewayTimeout              = 504,
+
+  NGHttpStatusCode_last
+} NGHttpStatusCode;
+
+@interface NGHttpResponse : NGHttpMessage
+{
+  NGHttpStatusCode statusCode;
+  NSString         *reason;
+
+  NGHttpRequest *request;
+}
+
+- (id)initWithRequest:(NGHttpRequest *)_request;
+
+- (id)initWithStatus:(int)_status reason:(NSString *)_reason
+  header:(NGHashMap *)_header version:(NSString *)_version;
+
+// accessors
+
+- (void)setStatusCode:(NGHttpStatusCode)_code;
+- (NGHttpStatusCode)statusCode;
+
+- (void)setReason:(NSString *)_text;
+- (NSString *)reason;
+
+- (void)setRequest:(NGHttpRequest *)_request;
+- (NGHttpRequest *)request;
+
+@end
+
+@interface NGHttpResponse(CommonHeaders)
+
+- (void)setWWWAuthenticate:(NGHttpChallenge *)_challenge;
+- (NGHttpChallenge *)wwwAuthenticate;
+
+@end
+
+static inline BOOL NGIsInformationalHttpStatusCode(NGHttpStatusCode _code) {
+  return ((_code >= 100) && (_code < 200)) ? YES : NO;
+}
+static inline BOOL NGIsSuccessfulHttpStatusCode(NGHttpStatusCode _code) {
+  return ((_code >= 200) && (_code < 300)) ? YES : NO;
+}
+static inline BOOL NGIsRedirectionHttpStatusCode(NGHttpStatusCode _code) {
+  return ((_code >= 300) && (_code < 400)) ? YES : NO;
+}
+static inline BOOL NGIsClientErrorHttpStatusCode(NGHttpStatusCode _code) {
+  return ((_code >= 400) && (_code < 500)) ? YES : NO;
+}
+static inline BOOL NGIsServerErrorHttpStatusCode(NGHttpStatusCode _code) {
+  return ((_code >= 500) && (_code < 600)) ? YES : NO;
+}
+
+#endif /* __NGHttp_NGHttpResponse_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGHttpResponse.m b/skyrix-sope/NGObjWeb/NGHttp/NGHttpResponse.m
new file mode 100644 (file)
index 0000000..9eff55a
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NGHttpResponse.h"
+#import "NGHttpRequest.h"
+#import "NGHttpHeaderFields.h"
+
+@interface NGHttpMessage(PrivateMethods)
+- (id)initWithHeader:(NGHashMap *)_header version:(NSString *)_version;
+@end
+
+@implementation NGHttpResponse
+
+- (id)init {
+  return [super initWithHeader:nil version:@"1.0"];
+}
+- (id)initWithRequest:(NGHttpRequest *)_request {
+  if ((self = [super init])) {
+    self->header     = [[NGMutableHashMap allocWithZone:[self zone]] init];
+    self->body       = nil;
+
+    if (_request) {
+      self->majorVersion = [_request majorVersion];
+      self->minorVersion = [_request minorVersion];
+      self->request    = RETAIN(_request);
+    }
+    else {
+      self->majorVersion = 1;
+      self->minorVersion = 0;
+    }
+    
+    self->statusCode = NGHttpStatusCode_OK;
+    self->reason     = nil;
+  }
+  return self;
+}
+
+- (id)initWithStatus:(int)_status reason:(NSString *)_reason
+  header:(NGHashMap *)_header version:(NSString *)_version
+{
+  if ((self = [super initWithHeader:_header version:_version])) {
+    self->statusCode = _status;
+    self->reason = [_reason copy];
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->request);
+  RELEASE(self->reason);
+  [super dealloc];
+}
+#endif
+
+// accessors
+
+- (void)setStatusCode:(NGHttpStatusCode)_code {
+  self->statusCode = _code;
+}
+- (NGHttpStatusCode)statusCode {
+  return self->statusCode;
+}
+
+- (void)setReason:(NSString *)_text {
+  if (self->reason != _text) {
+    RELEASE(self->reason);
+    self->reason = [_text copyWithZone:[self zone]];
+  }
+}
+- (NSString *)reason {
+  return self->reason;
+}
+
+- (void)setRequest:(NGHttpRequest *)_request {
+  ASSIGN(self->request, _request);
+}
+- (NGHttpRequest *)request {
+  return self->request;
+}
+
+// description
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<HttpResponse: "
+                     @"status=%i reason=%@ header=%@ version=%i/%i body=%@>",
+                     self->statusCode,
+                     self->reason,
+                     self->header,
+                     self->majorVersion, self->minorVersion,
+                     self->body
+                   ];
+}
+
+@end
+
+@implementation NGHttpResponse(CommonHeaders)
+
+- (void)setWWWAuthenticate:(NGHttpChallenge *)_challenge {
+  [self setValue:_challenge ofHeaderFieldWithName:@"www-authenticate"];
+}
+- (NGHttpChallenge *)wwwAuthenticate {
+  return [self valueOfHeaderFieldWithName:@"www-authenticate"];
+}
+
+@end
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGUrlFormCoder.h b/skyrix-sope/NGObjWeb/NGHttp/NGUrlFormCoder.h
new file mode 100644 (file)
index 0000000..57593b7
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_NGUrlFormCoder_H__
+#define __NGHttp_NGUrlFormCoder_H__
+
+#import <Foundation/NSString.h>
+
+@class NGHashMap;
+
+/*
+  Decodes 'x-www-form-urlencoded' buffers.
+
+  The _buffer parameter starts with the string after the '?' in a URI, that is,
+  the buffer is _not_ the complete URI.
+  The function returns a retained hashmap.
+*/
+NGHashMap *NGDecodeUrlFormParameters(const char *_buffer, unsigned _len);
+
+#if 0 /* do not use, use NGExtensions/NSString+misc.h ... */
+@interface NSString(FormURLCoding)
+
+- (NSString *)stringByApplyingURLEncoding;
+
+@end
+#endif
+
+#endif /* __NGHttp_NGUrlFormCoder_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/NGUrlFormCoder.m b/skyrix-sope/NGObjWeb/NGHttp/NGUrlFormCoder.m
new file mode 100644 (file)
index 0000000..7f3748a
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "NGUrlFormCoder.h"
+
+static inline BOOL isURLSafeChar(unsigned char _c) {
+  if ((_c > 64) && (_c < 91))
+    return YES;
+
+  if ((_c > 96) && (_c < 123))
+    return YES;
+
+  if (_c == 95)
+    return YES;
+
+  if ((_c > 47) && (_c < 58))
+    return YES;
+  
+  return NO;
+}
+
+static inline int _valueOfHexChar(unsigned char _c) {
+  switch (_c) {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      return (_c - 48); // 0-9 (ascii-char)'0' - 48 => (int)0
+      
+    case 'A': case 'B': case 'C':
+    case 'D': case 'E': case 'F':
+      return (_c - 55); // A-F, A=10..F=15, 'A'=65..'F'=70
+      
+    case 'a': case 'b': case 'c':
+    case 'd': case 'e': case 'f':
+      return (_c - 87); // a-f, a=10..F=15, 'a'=97..'f'=102
+
+    default:
+      return -1;
+  }
+}
+
+static inline unsigned _unescapeUrl(const char *_src, unsigned _len, char *_dest) {
+  register unsigned i, i2;
+
+  for (i = 0, i2 = 0; i < _len; i++, i2++) {
+    register char c = _src[i];
+    
+    switch (c) {
+      case '+': // encoded space
+        _dest[i2] = ' ';
+        break;
+          
+      case '%': // encoded hex ('%FF')
+        _dest[i2] = _valueOfHexChar(_src[i + 1]) * 16 +
+          _valueOfHexChar(_src[i + 2]);
+        i += 2; // skip the two hexchars
+        break;
+
+      default:  // normal char
+        _dest[i2] = c;
+        break;
+    }
+  }
+  return i2; // return unescaped length
+}
+
+NGHashMap *NGDecodeUrlFormParameters(const char *_buffer, unsigned _len) {
+  Class StrClass = [NSString class];
+  NGMutableHashMap *dict = nil;
+  unsigned pos = 0;
+  
+  if (_len == 0) return nil;
+
+  dict = [[NGMutableHashMap alloc] initWithCapacity:16];
+
+  do {
+    NSString *key = nil, *value = nil;
+    unsigned tmp, len;
+    char     buffer[_len];
+
+    /* read key */
+    tmp = pos;
+    while ((pos < _len) && (_buffer[pos] != '='))
+      pos++;
+
+    len = _unescapeUrl(&(_buffer[tmp]), (pos - tmp), buffer);
+    if (len > 0) {
+      key = [[StrClass allocWithZone:[dict zone]]
+                       initWithCString:buffer length:len];
+    }
+    else
+      key = @"";
+
+    //NSLog(@"read key %@", key);
+
+    if (pos < _len) { // value pending
+      NSCAssert(_buffer[pos] == '=', @"invalid parser state ..");
+      pos++; // skip '='
+
+      /* read value */
+      tmp = pos;
+      while ((pos < _len) && (_buffer[pos] != '&') && (_buffer[pos] != '?')) {
+        pos++;
+      }
+      
+      len = _unescapeUrl(&(_buffer[tmp]), (pos - tmp), buffer);
+
+      if (len > 0) {
+        value = [[StrClass allocWithZone:[dict zone]]
+                           initWithCString:buffer length:len];
+      }
+      else
+        value = @"";
+
+      //NSLog(@"read value: %@", value);
+      
+      // skip '&'
+      if (_buffer[pos] == '&' || _buffer[pos] == '?') pos++;
+    }
+    
+    if (value == nil)
+      value = @"";
+
+    /* store in dictionary */
+    if (key)
+      [dict addObject:value forKey:key];
+
+    RELEASE(key);   key   = nil;
+    RELEASE(value); value = nil;
+  }
+  while (pos < _len);
+
+  return dict;
+}
+
+@implementation NSString(FormURLCoding)
+
+- (NSString *)stringByApplyingURLEncoding {
+#if 1
+  /* NGExtensions/NSString+misc.h */
+  return [self stringByEscapingURL];
+#else
+  char     *buf, *encBuf;
+  unsigned clen, i, j;
+
+  if ((clen = [self cStringLength]) == 0)
+    return self;
+  
+  buf  = malloc(clen + 1);
+  [self getCString:buf]; buf[clen] = '\0';
+  
+  encBuf = malloc(clen * 3 + 1);
+  
+  for (i = 0, j = 0; i < clen; i++) {
+    register unsigned char c = buf[i];
+
+    if (isURLSafeChar(c)) {
+      encBuf[j] = c;
+      j++;
+    }
+    else if (c == ' ') {
+      encBuf[j] = '+';
+      j++;
+    }
+    else {
+      sprintf(&(encBuf[j]), "%%%02X", (int)c);
+      j += 3;
+    }
+  }
+  return [NSString stringWithCString:encBuf length:j];
+  /* was buggy, does not release encbuf .. */
+#endif
+}
+
+@end /* NSString(FormURLCoding) */
diff --git a/skyrix-sope/NGObjWeb/NGHttp/README b/skyrix-sope/NGObjWeb/NGHttp/README
new file mode 100644 (file)
index 0000000..80627cb
--- /dev/null
@@ -0,0 +1,25 @@
+# $Id$
+
+Note: This should be removed in favor of WOSimpleHTTPParser which should
+      be completed to implement all features
+      The MIME based implementation of NGHttp is a bit overkill for parsing
+      HTTP ...
+
+NGObjWeb HTTP Implementation
+
+  Debugging Topics:
+
+    topic     used by
+    showreq   NGHttpShowRequestService
+    http      NGHttpEventHandler
+    server    NGHttpServer
+
+Deleted in 4.1, available in MOF3
+
+  NGHttpFileService
+  NGHttpCGIService
+  NGHttpShowRequestService
+
+--
+Helge Hess
+2002-12-02
diff --git a/skyrix-sope/NGObjWeb/NGHttp/common.h b/skyrix-sope/NGObjWeb/NGHttp/common.h
new file mode 100644 (file)
index 0000000..88d41be
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGHttp_common_H__
+#define __NGHttp_common_H__
+
+#include <string.h>
+
+#if !defined(__MINGW32__)
+#  include <strings.h>
+#endif
+
+#import <Foundation/Foundation.h>
+#import <Foundation/NSHost.h>
+#import <Foundation/NSUtilities.h>
+#include <NGExtensions/NGExtensions.h>
+#include <NGStreams/NGStreams.h>
+#include <NGStreams/NGNet.h>
+#include <NGMime/NGMime.h>
+
+#if LIB_FOUNDATION_LIBRARY
+#  include <Foundation/exceptions/GeneralExceptions.h>
+#endif
+
+#endif /* __NGHttp_common_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb-Info.plist b/skyrix-sope/NGObjWeb/NGObjWeb-Info.plist
new file mode 100644 (file)
index 0000000..fee1cca
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGObjWeb</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.NGObjWeb</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb.m b/skyrix-sope/NGObjWeb/NGObjWeb.m
new file mode 100644 (file)
index 0000000..6f5552c
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/NGObjWeb.h>
+
+@implementation NGObjWeb
+
+@end
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/NGObjWeb.h b/skyrix-sope/NGObjWeb/NGObjWeb/NGObjWeb.h
new file mode 100644 (file)
index 0000000..088a683
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_H__
+#define __NGObjWeb_H__
+
+#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#  include <NGExtensions/NGExtensions.h>
+#endif
+
+#include <NGObjWeb/OWResponder.h>
+#include <NGObjWeb/WOAdaptor.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOAssociation.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOCookie.h>
+#include <NGObjWeb/WODirectAction.h>
+#include <NGObjWeb/WODynamicElement.h>
+#include <NGObjWeb/WOElement.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WORequestHandler.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOSessionStore.h>
+#include <NGObjWeb/WODisplayGroup.h>
+#include <NGObjWeb/WOHTTPConnection.h>
+#include <NGObjWeb/WOMailDelivery.h>
+#include <NGObjWeb/WOStatisticsStore.h>
+
+#include <NGObjWeb/WOxElemBuilder.h>
+
+// kit class
+
+@interface NGObjWeb : NSObject
+@end
+
+#define LINK_NGObjWeb \
+  static void __link_NGObjWeb(void) { \
+    [NGObjWeb self];  \
+    __link_NGObjWeb(); \
+  }
+
+#endif /* __NGObjWeb_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/NGObjWebDecls.h b/skyrix-sope/NGObjWeb/NGObjWeb/NGObjWebDecls.h
new file mode 100644 (file)
index 0000000..e0ae870
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_NGObjWebDecls_H__
+#define __NGObjWeb_NGObjWebDecls_H__
+
+#if BUILD_libNGObjWeb_DLL
+#  define NGObjWeb_EXPORT  __declspec(dllexport)
+#  define NGObjWeb_DECLARE __declspec(dllexport)
+#elif libNGObjWeb_ISDLL
+#  define NGObjWeb_EXPORT  extern __declspec(dllimport)
+#  define NGObjWeb_DECLARE extern __declspec(dllimport)
+#else
+#  define NGObjWeb_EXPORT  extern
+#  define NGObjWeb_DECLARE 
+#endif
+
+#endif /* __NGObjWeb_NGObjWebDecls_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/OWResourceManager.h b/skyrix-sope/NGObjWeb/NGObjWeb/OWResourceManager.h
new file mode 100644 (file)
index 0000000..0818f54
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_OWResourceManager_H__
+#define __NGObjWeb_OWResourceManager_H__
+
+// ATTENTION: this class is for OGo legacy, so that WO compatibility changes 
+//            to WOResourceManager do not break OGo.
+//            So: do not use that class, its DEPRECATED!
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSLock.h>
+#import <Foundation/NSMapTable.h>
+#import <Foundation/NSHashTable.h>
+
+@class NSString, NSArray, NSData;
+@class WORequest, WOComponent, WOElement, WOSession;
+
+@interface OWResourceManager : NSObject < NSLocking >
+{
+@protected
+  NSString   *base;
+@private
+  NSString   *w3resources;
+  NSString   *resources;
+  NSMapTable *componentDefinitions; // name.language => definition
+  NSMapTable *stringTables;         // path => tableinfo
+  NSMapTable *existingPathes;
+  NSMapTable *keyedResources;
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages;
+
+- (NSString *)urlForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages
+  request:(WORequest *)_request;
+
+/* string tables */
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_default
+  languages:(NSArray *)_languages;
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_defaultValue
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_languages;
+
+@end
+
+@interface OWResourceManager(KeyedData)
+
+/* keyed storage */
+
+- (void)setData:(NSData *)_data
+  forKey:(NSString *)_key
+  mimeType:(NSString *)_type
+  session:(WOSession *)_session;
+- (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session;
+- (void)flushDataCache;
+
+@end
+
+@interface OWResourceManager(PrivateMethods)
+
+- (id)initWithPath:(NSString *)_path;
++ (void)setResourcePrefix:(NSString *)_prefix;
+
+- (WOElement *)templateWithName:(NSString *)_name languages:(NSArray *)_langs;
+- (id)pageWithName:(NSString *)_name languages:(NSArray *)_langs;
+
+- (NSString *)pathToComponentNamed:(NSString *)_name
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_langs;
+
+- (void)setCachingEnabled:(BOOL)_flag;
+- (BOOL)isCachingEnabled;
+
+@end
+
+@interface OWResourceManager(DeprecatedMethods)
+
+- (NSString *)pathForResourceNamed:(NSString *)_name;
+- (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type;
+- (NSString *)urlForResourceNamed:(NSString *)_name;
+- (NSString *)urlForResourceNamed:(NSString *)_name ofType:(NSString *)_type;
+
+@end
+
+#endif /* __NGObjWeb_OWResourceManager_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/OWResponder.h b/skyrix-sope/NGObjWeb/NGObjWeb/OWResponder.h
new file mode 100644 (file)
index 0000000..ae420be
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_OWResponder_H__
+#define __NGObjWeb_OWResponder_H__
+
+#import <Foundation/NSObject.h>
+
+@class WORequest, WOResponse, WOContext;
+
+@protocol OWResponder < NSObject >
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_context;
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_context;
+
+- (void)appendToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+
+@end
+
+typedef void (*OWTakeValuesMethod)    (id, SEL, WORequest  *, WOContext *);
+typedef id   (*OWInvokeMethod)        (id, SEL, WORequest  *, WOContext *);
+typedef void (*OWAppendResponseMethod)(id, SEL, WOResponse *, WOContext *);
+
+#endif /* __NGObjWeb_OWResponder_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/OWViewRequestHandler.h b/skyrix-sope/NGObjWeb/NGObjWeb/OWViewRequestHandler.h
new file mode 100644 (file)
index 0000000..ee90c86
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_OWViewRequestHandler_H__
+#define __NGObjWeb_OWViewRequestHandler_H__
+
+#import <NGObjWeb/WORequestHandler.h>
+
+@interface OWViewRequestHandler : WORequestHandler
+{
+}
+
+@end
+
+#endif /* __NGObjWeb_OWViewRequestHandler_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WEClientCapabilities.h b/skyrix-sope/NGObjWeb/NGObjWeb/WEClientCapabilities.h
new file mode 100644 (file)
index 0000000..a5905d4
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WEExtensions_WEClientCapabilities_H__
+#define __WEExtensions_WEClientCapabilities_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+
+@interface WEClientCapabilities : NSObject
+{
+  NSString *userAgent;
+  
+  unsigned short browser;
+  unsigned short os;
+  unsigned short cpu;
+  unsigned char  browserMajorVersion;
+  unsigned char  browserMinorVersion;
+  
+  struct {
+    int acceptUTF8:1;
+    int reserved:31;
+  } flags;
+}
+
+/* accessors */
+
+- (NSString *)userAgent;
+- (NSString *)userAgentType;
+- (NSString *)os;
+- (NSString *)cpu;
+- (unsigned char)majorVersion;
+- (unsigned char)minorVersion;
+
+/* browser capabilities */
+
+- (BOOL)isJavaScriptBrowser;
+- (BOOL)isVBScriptBrowser;
+- (BOOL)isFastTableBrowser;
+- (BOOL)isCSS1Browser;
+- (BOOL)isCSS2Browser;
+- (BOOL)ignoresCSSOnFormElements;
+- (BOOL)isTextModeBrowser;
+- (BOOL)isIFrameBrowser;
+- (BOOL)isXULBrowser;
+- (BOOL)isRobot;
+- (BOOL)isDAVClient;
+- (BOOL)isXmlRpcClient;
+- (BOOL)isBLogClient;
+
+- (BOOL)doesSupportCSSOverflow;
+- (BOOL)doesSupportDHTMLDragAndDrop;
+- (BOOL)doesSupportXMLDataIslands;
+- (BOOL)doesSupportUTF8Encoding;
+
+/* user-agent (it's better to use ^capabilities !) */
+
+- (BOOL)isInternetExplorer;
+- (BOOL)isInternetExplorer5;
+- (BOOL)isNetscape;
+- (BOOL)isNetscape6;
+- (BOOL)isLynx;
+- (BOOL)isOpera;
+- (BOOL)isAmaya;
+- (BOOL)isEmacs;
+- (BOOL)isWget;
+- (BOOL)isWebFolder;
+- (BOOL)isMozilla;
+- (BOOL)isOmniWeb;
+- (BOOL)isICab;
+- (BOOL)isKonqueror;
+
+/* OS */
+
+- (BOOL)isWindowsBrowser;
+- (BOOL)isLinuxBrowser;
+- (BOOL)isMacBrowser;
+- (BOOL)isSunOSBrowser;
+- (BOOL)isUnixBrowser;
+- (BOOL)isX11Browser;
+
+@end
+
+#include <NGObjWeb/WORequest.h>
+
+@interface WORequest(ClientCapabilities)
+
+/* the object is cached in the WORequest's userInfo */
+- (WEClientCapabilities *)clientCapabilities;
+
+@end
+
+#include <NGObjWeb/WODynamicElement.h>
+
+/*
+  The following element uses JavaScript to find out even more about the client
+  browser.
+*/
+
+@interface JSClientCapabilityDetector : WODynamicElement
+{
+  WOAssociation *formName;
+  WOAssociation *clientCaps;
+}
+@end
+
+#endif /* __WEExtensions_WEClientCapabilities_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOActionResults.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOActionResults.h
new file mode 100644 (file)
index 0000000..0eb584b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOActionResults_H__
+#define __NGObjWeb_WOActionResults_H__
+
+#import <Foundation/NSObject.h>
+
+@class WOResponse;
+
+@protocol WOActionResults
+
+- (WOResponse *)generateResponse;
+
+@end
+
+#endif /* __NGObjWeb_WOActionResults_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOAdaptor.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOAdaptor.h
new file mode 100644 (file)
index 0000000..6cbb4c9
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOAdaptor_H__
+#define __NGObjWeb_WOAdaptor_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSDictionary;
+@class WOCoreApplication;
+
+@interface WOAdaptor : NSObject
+{
+@protected
+  NSString          *name;
+  WOCoreApplication *application; // not retained
+}
+
+/*
+  Note: Arguments is a NSDictionary since WO4
+*/
+- (id)initWithName:(NSString *)_name
+  arguments:(NSDictionary *)_args
+  application:(WOCoreApplication *)_application;
+
+// register
+
+- (void)registerForEvents;
+- (void)unregisterForEvents;
+
+@end
+
+#endif /* __NGObjWeb_WOAdaptor_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOApplication.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOApplication.h
new file mode 100644 (file)
index 0000000..44aef5a
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOApplication_H__
+#define __NGObjWeb_WOApplication_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSLock.h>
+#import <Foundation/NSMapTable.h>
+#include <NGObjWeb/NGObjWebDecls.h>
+#include <NGObjWeb/WOCoreApplication.h>
+
+@class NSString, NSRunLoop, NSArray, NSTimer, NSException, NSNumber, NSURL;
+@class NSMutableDictionary, NSDictionary;
+@class WOResourceManager, WOComponent, WOContext, WOSession;
+@class WORequest, WOResponse, WOAdaptor, WORequestHandler;
+@class WOSessionStore, WODynamicElement, WOElement, WOStatisticsStore;
+
+@interface WOApplication : WOCoreApplication
+{
+@private
+  int                 minimumActiveSessionsCount;
+  NSString            *name;
+  NSString            *path;
+  WORequestHandler    *defaultRequestHandler;
+  NSMapTable          *requestHandlerRegistry;
+  WOSessionStore      *iSessionStore;
+  WOStatisticsStore   *iStatisticsStore;
+  WOResourceManager   *resourceManager;
+  void                *_unused;
+  NSTimer             *expirationTimer;
+  NSString            *instanceNumber;
+  short               pageCacheSize;
+  short               permanentPageCacheSize;
+
+  struct {
+    BOOL doesRefuseNewSessions:1;
+    BOOL isPageRefreshOnBacktrackEnabled:1;
+    BOOL isCachingEnabled:1;
+  } appFlags;
+}
+
+/* accessors */
+
+- (NSString *)name;
+- (BOOL)monitoringEnabled;
+- (NSString *)path;
+- (NSString *)number;
+
+/* request handlers */
+
+- (void)registerRequestHandler:(WORequestHandler *)_hdl forKey:(NSString *)_key;
+- (void)removeRequestHandlerForKey:(NSString *)_key;
+- (void)setDefaultRequestHandler:(WORequestHandler *)_hdl;
+- (WORequestHandler *)defaultRequestHandler;
+- (NSArray *)registeredRequestHandlerKeys;
+
+/* sessions */
+
+- (id)createSessionForRequest:(WORequest *)_request;
+- (id)restoreSessionWithID:(NSString *)_id inContext:(WOContext *)_ctx;
+- (void)saveSessionForContext:(WOContext *)_ctx;
+
+- (void)setSessionStore:(WOSessionStore *)_store;
+- (WOSessionStore *)sessionStore;
+- (NSString *)sessionStoreClassName;
+- (void)refuseNewSessions:(BOOL)_flag;
+- (BOOL)isRefusingNewSessions;
+- (int)activeSessionsCount;
+
+- (void)setMinimumActiveSessionsCount:(int)_minimum;
+- (int)minimumActiveSessionsCount;
+
+- (WOResponse *)handleSessionCreationErrorInContext:(WOContext *)_context;
+- (WOResponse *)handleSessionRestorationErrorInContext:(WOContext *)_context;
+- (WOResponse *)handlePageRestorationErrorInContext:(WOContext *)_context;
+
+/* statistics */
+
+- (void)setStatisticsStore:(WOStatisticsStore *)_statStore;
+- (WOStatisticsStore *)statisticsStore;
+- (bycopy NSDictionary *)statistics;
+
+/* resources */
+
+- (void)setResourceManager:(WOResourceManager *)_manager;
+- (WOResourceManager *)resourceManager;
+- (NSURL *)baseURL;
+- (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type;
+
+/* notifications */
+
+- (void)awake;
+- (void)sleep;
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_req  inContext:(WOContext *)_ctx;
+- (id)invokeActionForRequest:(WORequest *)_req   inContext:(WOContext *)_ctx;
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx;
+
+/* dynamic elements */
+
+- (WOElement *)dynamicElementWithName:(NSString *)_name // element class name
+  associations:(NSDictionary *)_associations            // bindings
+  template:(WOElement *)_template                       // child elements
+  languages:(NSArray *)_languages;
+
+/* pages */
+
+- (void)setPageRefreshOnBacktrackEnabled:(BOOL)_flag;
+- (BOOL)isPageRefreshOnBacktrackEnabled;
+- (void)setCachingEnabled:(BOOL)_flag;
+- (BOOL)isCachingEnabled;
+- (void)setPageCacheSize:(int)_size;
+- (int)pageCacheSize;
+- (void)setPermanentPageCacheSize:(int)_size;
+- (int)permanentPageCacheSize;
+
+- (id)pageWithName:(NSString *)_name inContext:(WOContext *)_ctx;
+- (id)pageWithName:(NSString *)_name forRequest:(WORequest *)_req;
+
+/* exceptions */
+
+- (WOResponse *)handleException:(NSException *)_exc
+  inContext:(WOContext *)_ctx;
+
+@end
+
+@interface WOApplication(DeprecatedMethodsInWO4)
+
+- (id)session;
+- (WOContext *)context;
+
+- (id)createSession;
+- (id)restoreSession;
+- (void)saveSession:(WOSession *)_session;
+
+- (WOResponse *)handleSessionCreationError;
+- (WOResponse *)handleSessionRestorationError;
+- (WOResponse *)handlePageRestorationError;
+
+- (void)savePage:(WOComponent *)_page;
+- (id)restorePageForContextID:(NSString *)_ctxId;
+
+- (id)pageWithName:(NSString *)_name;
+
+- (WOResponse *)handleException:(NSException *)_exception;
+- (WOResponse *)handleRequest:(WORequest *)_request;
+
+- (WOElement *)dynamicElementWithName:(NSString *)_name // element class name
+  associations:(NSDictionary *)_associations            // bindings
+  template:(WOElement *)_template;                      // child elements
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_default;
+
+@end
+
+@interface WOApplication(NonWOMethods)
+
+- (WORequestHandler *)requestHandlerForKey:(NSString *)_key;
+
+- (NSString *)sessionIDFromRequest:(WORequest *)_request;
+- (NSString *)createSessionIDForSession:(WOSession *)_session;
+
++ (Class)eoEditingContextClass;
++ (BOOL)implementsEditingContexts;
+
+@end
+
+@interface WOApplication(Defaults)
+
+/* WOComponentRequestHandlerKey */
++ (void)setComponentRequestHandlerKey:(NSString *)_key;
++ (NSString *)componentRequestHandlerKey;
+
+/* WODirectActionRequestHandlerKey */
++ (void)setDirectActionRequestHandlerKey:(NSString *)_key;
++ (NSString *)directActionRequestHandlerKey;
+
+/* WOResourceRequestHandlerKey */
++ (void)setResourceRequestHandlerKey:(NSString *)_key;
++ (NSString *)resourceRequestHandlerKey;
+
+/* WODefaultSessionTimeOut */
++ (void)setSessionTimeOut:(NSNumber *)_timeOut;
++ (NSNumber *)sessionTimeOut;
+
+/* WOCachingEnabled */
++ (BOOL)isCachingEnabled;
+
+/* WODebuggingEnabled */
++ (BOOL)isDebuggingEnabled;
+
+@end
+
+@interface WOApplication(WODebugging)
+/* implemented in NGExtensions */
+
+- (void)debugWithFormat:(NSString *)_format, ...;
+- (void)logWithFormat:(NSString *)_format, ...;
+
+@end
+
+#endif /* __NGObjWeb_WOApplication_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOAssociation.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOAssociation.h
new file mode 100644 (file)
index 0000000..d277427
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOAssociation_H__
+#define __NGObjWeb_WOAssociation_H__
+
+#import <Foundation/NSObject.h>
+
+@class WOComponent, WOContext;
+
+@interface WOAssociation : NSObject /* abstract/cluster */
+{
+}
+
++ (WOAssociation *)associationWithKeyPath:(NSString *)_keyPath;
++ (WOAssociation *)associationWithValue:(id)_value;
+
+/* value */
+
+- (void)setValue:(id)_value inContext:(WOContext *)_ctx;
+- (id)valueInContext:(WOContext *)_ctx;
+- (void)setValue:(id)_value inComponent:(WOComponent *)_component;
+- (id)valueInComponent:(WOComponent *)_component;
+
+- (BOOL)isValueConstant;
+- (BOOL)isValueSettable;
+
+/* deprecated methods */
+
+- (void)setValue:(id)_value; // deprecated in WO4
+- (id)value;                 // deprecated in WO4
+
+@end
+
+@interface WOAssociation(SpecialsValues)
+
+- (void)setUnsignedCharValue:(unsigned char)_v inComponent:(WOComponent *)_c;
+- (void)setCharValue:(char)_value inComponent:(WOComponent *)_component;
+- (void)setUnsignedIntValue:(unsigned int)_v inComponent:(WOComponent *)_comp;
+- (void)setIntValue:(int)_value inComponent:(WOComponent *)_component;
+- (void)setBoolValue:(BOOL)_value inComponent:(WOComponent *)_component;
+
+- (unsigned char)unsignedCharValueInComponent:(WOComponent *)_component;
+- (char)charValueInComponent:(WOComponent *)_component;
+- (unsigned int)unsignedIntValueInComponent:(WOComponent *)_component;
+- (int)intValueInComponent:(WOComponent *)_component;
+- (BOOL)boolValueInComponent:(WOComponent *)_component;
+
+- (void)setStringValue:(NSString *)_v inComponent:(WOComponent *)_component;
+- (NSString *)stringValueInComponent:(WOComponent *)_component;
+
+/* special context values */
+
+- (void)setUnsignedCharValue:(unsigned char)_v inContext:(WOContext *)_c;
+- (void)setCharValue:(char)_value              inContext:(WOContext *)_ctx;
+- (void)setUnsignedIntValue:(unsigned int)_v   inContext:(WOContext *)_c;
+- (void)setIntValue:(int)_value                inContext:(WOContext *)_ctx;
+- (void)setBoolValue:(BOOL)_value              inContext:(WOContext *)_ctx;
+
+- (unsigned char)unsignedCharValueInContext:(WOContext *)_ctx;
+- (char)charValueInContext:(WOContext *)_ctx;
+- (unsigned int)unsignedIntValueInContext:(WOContext *)_ctx;
+- (int)intValueInContext:(WOContext *)_ctx;
+- (BOOL)boolValueInContext:(WOContext *)_ctx;
+
+- (void)setStringValue:(NSString *)_v inContext:(WOContext *)_ctx;
+- (NSString *)stringValueInContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __NGObjWeb_WOAssociation_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOComponent.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOComponent.h
new file mode 100644 (file)
index 0000000..25968dd
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOComponent_H__
+#define __NGObjWeb_WOComponent_H__
+
+#import <Foundation/NSMapTable.h>
+#import <NGObjWeb/WOElement.h>
+#include <NGObjWeb/WOActionResults.h>
+
+@class NSString, NSDictionary, NSMutableDictionary, NSURL, NSException;
+@class WOElement, WOContext, WOSession, WOApplication, WOResourceManager;
+
+@interface WOComponent : WOElement < WOActionResults, NSCoding >
+{
+@private
+  NSDictionary        *wocBindings;     // bindings to parent component
+  NSString            *wocName;         // name of component
+  
+  WOComponent         *parentComponent; // non-retained;
+  NSDictionary        *subcomponents;   // subcomponents
+  NSMutableDictionary *wocVariables;    // user variables
+
+  struct {
+    BOOL reloadTemplates:1; // component definition caching
+    BOOL isAwake:1;
+  } componentFlags;
+
+@protected // transient (non-retained)
+  WOContext     *context;
+  WOApplication *application;
+  WOSession     *session;
+}
+
+- (id)initWithContext:(WOContext *)_ctx;
+
+- (void)awake;
+- (void)sleep;
+
+/*
+  This method needs to be called before using a component cached by yourself.
+*/
+- (void)ensureAwakeInContext:(WOContext *)_ctx;
+
+/* accessors */
+
+- (NSString *)name;
+- (NSString *)path;
+- (NSURL *)baseURL;
+
+- (id)application;
+- (id)session;
+- (WOContext *)context;
+- (BOOL)hasSession; // new in WO4
+
+/* component definition caching */
+
+- (void)setCachingEnabled:(BOOL)_flag;
+- (BOOL)isCachingEnabled;
+
+/* resources */
+
+- (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_ext;
+- (NSString *)frameworkName;
+
+/* templates */
+
+- (WOElement *)templateWithName:(NSString *)_name;
+
+- (WOElement *)templateWithHTMLString:(NSString *)_html
+  declarationString:(NSString *)_wod
+  languages:(NSArray *)_languages;
+  
+- (id)pageWithName:(NSString *)_name; // new in WO4
+
+- (void)setTemplate:(id)_template;
+
+/* child components */
+
+- (BOOL)synchronizesVariablesWithBindings;                // new in WO4
+- (void)setValue:(id)_value forBinding:(NSString *)_name; // new in WO4
+- (id)valueForBinding:(NSString *)_name;                  // new in WO4
+- (BOOL)hasBinding:(NSString *)_name;                     // new in WO4
+- (BOOL)canSetValueForBinding:(NSString *)_name;          // new in WO4
+- (BOOL)canGetValueForBinding:(NSString *)_name;          // new in WO4
+
+- (id)performParentAction:(NSString *)_attributeName;
+- (id)parent;
+
+/* variables */
+
+- (BOOL)isStateless; // new in WO4.5
+- (void)reset;       // new in WO4.5
+
+- (void)setObject:(id)_object forKey:(NSString *)_key;
+- (id)objectForKey:(NSString *)_key;
+
+- (void)validationFailedWithException:(NSException *)_exception
+  value:(id)_value
+  keyPath:(NSString *)_keyPath; // new in WO4
+
+/* logging */
+
+- (BOOL)isEventLoggingEnabled;
+
+@end /* WOComponent */
+
+@interface WOComponent(Logging)
+/* implemented in NGExtensions */
+
+- (void)logWithFormat:(NSString *)_fmt arguments:(va_list)_arguments;
+- (void)logWithFormat:(NSString *)_fmt, ...;
+- (void)debugWithFormat:(NSString *)_fmt, ...;
+
+@end
+
+@interface WOComponent(SkyrixExtensions)
+
+- (WOResourceManager *)resourceManager;
+- (id)existingSession;
+
+- (id<WOActionResults>)redirectToLocation:(id)_loc;
+- (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c;
+
+@end
+
+@interface WOComponent(DeprecatedMethodsInWO4)
+
+- (WOElement *)templateWithHTMLString:(NSString *)_html
+  declarationString:(NSString *)_wod;
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_default;
+
+@end /* WOComponent(DeprecatedMethodsInWO4) */
+
+@interface WOComponent(AdvancedBindingAccessors)
+
+- (void)setUnsignedIntValue:(unsigned)_value forBinding:(NSString *)_name;
+- (unsigned)unsignedIntValueForBinding:(NSString *)_name;
+- (void)setIntValue:(int)_value forBinding:(NSString *)_name;
+- (int)intValueForBinding:(NSString *)_name;
+
+@end /* WOComponent(AdvancedBindingAccessors) */
+
+@interface WOComponent(Statistics)
+
+- (NSString *)descriptionForResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+
+@end /* WOComponent(Statistics) */
+
+@interface WOComponent(DirectActionExtensions)
+
+- (void)takeFormValuesForKeyArray:(NSArray *)_keys;
+- (void)takeFormValuesForKeys:(NSString *)_key1,...;
+- (id<WOActionResults>)defaultAction;
+- (id<WOActionResults>)performActionNamed:(NSString *)_actionName;
+
+@end /* WOComponent(DirectActionExtensions) */
+
+#endif /* __NGObjWeb_WOComponent_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOComponentScript.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOComponentScript.h
new file mode 100644 (file)
index 0000000..9ed9d4d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOComponentScript_H__
+#define __NGObjWeb_WOComponentScript_H__
+
+#import <Foundation/NSObject.h>
+#include <NGObjWeb/WOElement.h>
+
+#include <NGObjWeb/WOTemplate.h>
+
+@class NSArray, NSString, NSURL;
+@class WOComponentScriptPart;
+
+@interface WOComponentScript : NSObject
+{
+  NSArray  *scriptParts;
+  NSString *language;
+}
+
+- (id)initWithContentsOfFile:(NSString *)_path;
+
+/* accessors */
+
+- (NSString *)language;
+
+/* operations */
+
+- (void)addScriptPart:(WOComponentScriptPart *)_part;
+
+@end
+
+@interface WOComponentScriptPart : NSObject
+{
+  NSURL    *url;
+  unsigned startLine;
+  NSString *script;
+}
+
+- (id)initWithContentsOfFile:(NSString *)_path;
+- (id)initWithURL:(NSURL *)_url startLine:(unsigned)_ln script:(NSString *)_s;
+
+@end
+
+#endif /* __NGObjWeb_WOComponentScript_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOContext.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOContext.h
new file mode 100644 (file)
index 0000000..25ee537
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOContext_H__
+#define __NGObjWeb_WOContext_H__
+
+#import <Foundation/NSObject.h>
+#include <NGObjWeb/WOPageGenerationContext.h>
+#include <NGObjWeb/WOElementTrackingContext.h>
+
+/*
+  WOContext
+  
+  The WOContext is the central object for processing a single HTTP
+  transaction. It manages request, response, the session, the current
+  element id for component actions, the active component etc.
+*/
+
+@class NSString, NSMutableDictionary, NSMutableArray, NSMutableSet;
+@class NSDictionary, NSURL;
+@class WOApplication, WOSession, WOComponent, WORequest, WOResponse;
+@class WOElementID;
+
+#define NGObjWeb_MAX_COMPONENT_NESTING_DEPTH 50
+
+@interface WOContext : NSObject < WOPageGenerationContext >
+{
+@protected
+  WOApplication       *application;     // non-retained
+  NSString            *ctxId;
+  WORequest           *request;
+  WOResponse          *response;
+  NSMutableDictionary *variables;
+  WOComponent         *page;
+  WOSession           *session;
+  NSMutableSet        *awakeComponents; // components that were woken up
+  
+  /* URLs */
+  NSURL               *baseURL;
+  NSURL               *appURL;
+  
+  /* element ids */
+  WOElementID *elementID;
+  WOElementID *reqElementID;
+  NSString    *urlPrefix; /* cached URL prefix */
+  
+  /* component stack */
+  id          componentStack[NGObjWeb_MAX_COMPONENT_NESTING_DEPTH];
+  id          contentStack[NGObjWeb_MAX_COMPONENT_NESTING_DEPTH];
+  signed char componentStackCount;
+  
+  /* FORM support */
+  BOOL inForm;
+  id   activeFormElement;
+  
+  NSString *qpJoin;
+  
+  /* tracking component actions */
+  BOOL savePageRequired;
+  
+  /* SOPE */
+  id             clientObject;
+  NSMutableArray *traversalStack;
+  NSString       *soRequestType; // WebDAV, XML-RPC, METHOD
+  id             objectDispatcher;
+  NSString       *pathInfo;
+  
+#if WITH_DEALLOC_OBSERVERS
+@private
+  id             *deallocObservers;
+  unsigned short deallocObserverCount;
+  unsigned short deallocObserverCapacity;
+#endif
+}
+
++ (id)contextWithRequest:(WORequest *)_request;
+- (id)initWithRequest:(WORequest *)_request;
++ (id)context;
+- (id)init;
+
+/* URLs */
+
+- (NSURL *)baseURL;
+- (NSURL *)applicationURL;
+- (NSURL *)serverURL;
+- (NSURL *)urlForKey:(NSString *)_key;
+
+/* variables */
+
+- (void)setObject:(id)_obj forKey:(NSString *)_key;
+- (id)objectForKey:(NSString *)_key;
+- (void)removeObjectForKey:(NSString *)_key;
+- (void)takeValue:(id)_value forKey:(NSString *)_key;
+- (id)valueForKey:(NSString *)_key;
+
+@end
+
+@interface WOContext(ElementIDs) < WOElementTrackingContext >
+@end
+
+@interface WOContext(URLs)
+
+- (NSString *)componentActionURL;
+
+- (NSString *)directActionURLForActionNamed:(NSString *)_actionName
+  queryDictionary:(NSDictionary *)_queryDict;
+
+- (NSString *)urlWithRequestHandlerKey:(NSString *)_key
+  path:(NSString *)_path
+  queryString:(NSString *)_query;
+- (NSString *)completeURLWithRequestHandlerKey:(NSString *)_key
+  path:(NSString *)_path
+  queryString:(NSString *)_query
+  isSecure:(BOOL)_isSecure
+  port:(int)_port;
+
+- (NSString *)senderID; // new in WO4
+
+- (NSString *)queryStringFromDictionary:(NSDictionary *)_queryDict;
+
+@end
+
+@interface WOContext(PrivateMethods)
+
+- (void)setRequestSenderID:(NSString *)_rqsid;
+- (BOOL)savePageRequired;
+
+@end
+
+@interface WOContext(DeprecatedMethodsInWO4)
+
+- (id)application; // use WOApplication:+application
+
+- (void)setDistributionEnabled:(BOOL)_flag; // use methods in
+- (BOOL)isDistributionEnabled;              // WOSession instead
+
+- (NSString *)url;              // use componentActionURL methods
+- (NSString *)urlSessionPrefix; // use componentActionURL methods
+
+@end
+
+#endif /* __NGObjWeb_WOContext_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOCookie.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOCookie.h
new file mode 100644 (file)
index 0000000..3230c15
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOCookie_H__
+#define __NGObjWeb_WOCookie_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSDate;
+
+@interface WOCookie : NSObject < NSCopying >
+{
+@protected
+  NSString *name;
+  NSString *value;
+
+  // cookie configuration
+  NSDate   *expireDate;  // defines how long the cookies is valid
+  NSString *path;        // the root-path where the cookie is valid
+  NSString *domainName;  // the domain where the cookie is valid (def: hostname)
+  BOOL     onlyIfSecure; // send only if communication-channel is secure (SSL)
+}
+
++ (id)cookieWithName:(NSString *)_name value:(NSString *)_value;
+
++ (id)cookieWithName:(NSString *)_name value:(NSString *)_value
+  path:(NSString *)_path domain:(NSString *)_domain
+  expires:(NSDate *)_date
+  isSecure:(BOOL)_secure;
+
+/* accessors */
+
+- (void)setName:(NSString *)_name;
+- (NSString *)name;
+- (void)setValue:(NSString *)_value;
+- (NSString *)value;
+- (void)setExpires:(NSDate *)_date;
+- (NSDate *)expires;
+- (void)setPath:(NSString *)_path;
+- (NSString *)path;
+- (void)setDomain:(NSString *)_domain;
+- (NSString *)domain;
+- (void)setIsSecure:(BOOL)_flag;
+- (BOOL)isSecure;
+
+/* description */
+
+- (NSString *)headerString;
+- (NSString *)stringValue; // called by HTTP server
+
+@end
+
+#endif /* __NGObjWeb_WOCookie_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOCoreApplication.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOCoreApplication.h
new file mode 100644 (file)
index 0000000..daf6c90
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOCoreApplication_H__
+#define __NGObjWeb_WOCoreApplication_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSLock.h>
+#import <Foundation/NSDate.h>
+#include <NGObjWeb/NGObjWebDecls.h>
+
+@class NSArray, NSNumber, NSDictionary, NSRunLoop;
+@class WOAdaptor, WORequest, WOResponse, WORequestHandler;
+@class NSBundle;
+
+NGObjWeb_EXPORT NSString *WOApplicationWillFinishLaunchingNotification;
+NGObjWeb_EXPORT NSString *WOApplicationDidFinishLaunchingNotification;
+NGObjWeb_EXPORT NSString *WOApplicationWillTerminateNotification;
+NGObjWeb_EXPORT NSString *WOApplicationDidTerminateNotification;
+
+@interface WOCoreApplication : NSObject < NSLocking >
+{
+  NSRecursiveLock *lock;
+  NSLock          *requestLock;
+
+  struct {
+    BOOL isTerminating:1;
+  } cappFlags;
+  
+@protected
+  NSArray         *adaptors;
+}
+
+/* active application */
+
++ (id)application;
+- (void)activateApplication;
+- (void)deactivateApplication;
+
+/* adaptors */
+
+- (NSArray *)adaptors;
+- (WOAdaptor *)adaptorWithName:(NSString *)_name
+  arguments:(NSDictionary *)_args;
+- (BOOL)allowsConcurrentRequestHandling;
+- (BOOL)adaptorsDispatchRequestsConcurrently;
+
+/* multithreading */
+
+- (void)lockRequestHandling;
+- (void)unlockRequestHandling;
+- (void)lock;
+- (void)unlock;
+- (BOOL)tryLock;
+
+/* request recording */
+
+- (NSString *)recordingPath;
+
+/* runloop */
+
+- (void)run;
+- (NSRunLoop *)mainThreadRunLoop;
+
+- (void)terminate;
+- (void)terminateAfterTimeInterval:(NSTimeInterval)_interval;
+- (BOOL)isTerminating;
+
+/* dispatching requests */
+
+- (WORequestHandler *)handlerForRequest:(WORequest *)_request;
+
+- (WOResponse *)dispatchRequest:(WORequest *)_request;
+- (WOResponse *)dispatchRequest:(WORequest *)_request
+  usingHandler:(WORequestHandler *)_handler;;
+
+- (void)setPrintsHTMLParserDiagnostics:(BOOL)_flag;
+- (BOOL)printsHTMLParserDiagnostics;
+
+@end
+
+int WOApplicationMain(NSString *_appClassName, int argc, const char *argv[]);
+int WOWatchDogApplicationMain
+  (NSString *_appClassName, int argc, const char *argv[]);
+
+@interface WOCoreApplication(DeprecatedMethodsInWO4)
+
+- (NSRunLoop *)runLoop;
+- (WOResponse *)handleRequest:(WORequest *)_request;
+
+@end
+
+@interface WOCoreApplication(Defaults)
+
+/* WOAdaptor */
++ (void)setAdaptor:(NSString *)_key;
++ (NSString *)adaptor;
+
+/* WOAdditionalAdaptors */
++ (void)setAdditionalAdaptors:(NSArray *)_names;
++ (NSArray *)additionalAdaptors;
+
+/* WOPort */
++ (void)setPort:(NSNumber *)_port;
++ (NSNumber *)port;
+
+/* WOWorkerThreadCount */
++ (NSNumber *)workerThreadCount;
+
+/* WOListenQueueSize */
++ (NSNumber *)listenQueueSize;
+
+@end
+
+@interface WOCoreApplication(Logging)
+/* implemented in NGExtensions */
+- (void)logWithFormat:(NSString *)_fmt, ...;
+- (void)debugWithFormat:(NSString *)_fmt, ...;
+@end
+
+@interface WOCoreApplication(Bundle)
+
+/* application bundles (run bundles in the WOApp container ...) */
+
++ (BOOL)didLoadDaemonBundle:(NSBundle *)_bundle;
++ (int)runApplicationBundle:(NSString *)_bundleName
+  domainPath:(NSString *)_p
+  arguments:(void *)_argv count:(int)_argc;
++ (int)runApplicationBundle:(NSString *)_bundleName
+  arguments:(void *)_argv count:(int)_argc;
++ (int)loadApplicationBundle:(NSString *)_bundleName
+  domainPath:(NSString *)_domain;
+
+@end
+
+#endif /* __NGObjWeb_WOCoreApplication_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WODirectAction.h b/skyrix-sope/NGObjWeb/NGObjWeb/WODirectAction.h
new file mode 100644 (file)
index 0000000..d831800
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WODirectAction_H__
+#define __NGObjWeb_WODirectAction_H__
+
+#import <Foundation/NSObject.h>
+#include <NGObjWeb/WOActionResults.h>
+
+@class NSString, NSDictionary, NSArray;
+@class WORequest, WOComponent, WOSession, WOContext;
+
+@interface WODirectAction : NSObject
+{
+  WOContext *context;
+}
+
+- (id)initWithContext:(WOContext *)_context;
+- (id)initWithRequest:(WORequest *)_request;
+
+/* accessors */
+
+- (WORequest *)request;
+- (id)session;
+- (id)existingSession;
+
+/* actions */
+
+- (id<WOActionResults>)performActionNamed:(NSString *)_actionName;
+
+- (void)takeFormValuesForKeyArray:(NSArray *)_keys;
+- (void)takeFormValuesForKeys:(NSString *)_key1,...;
+- (void)takeFormValueArraysForKeyArray:(NSArray *)_keys;
+- (void)takeFormValueArraysForKeys:(NSString *)_key1,...;
+
+/* pages */
+
+- (id)pageWithName:(NSString *)_name;
+
+@end
+
+@interface WODirectAction(NGObjWebAdditions)
+
+- (WOContext *)context;
+
+@end
+
+@interface WODirectAction(WODebugging)
+/* implemented in NGExtensions */
+
+- (void)debugWithFormat:(NSString *)_format, ...;
+- (void)logWithFormat:(NSString *)_format, ...;
+
+@end
+
+#endif /* __NGObjWeb_WODirectAction_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WODisplayGroup.h b/skyrix-sope/NGObjWeb/NGObjWeb/WODisplayGroup.h
new file mode 100644 (file)
index 0000000..0ef1d13
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WODisplayGroup_H__
+#define __NGObjWeb_WODisplayGroup_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSDictionary, NSArray, NSNotification, NSMutableDictionary;
+@class EODataSource, EOQualifier;
+
+@interface WODisplayGroup : NSObject < NSCoding >
+{
+  id           delegate;               /* non-retained ! */
+  EODataSource *dataSource;
+  NSArray      *sortOrderings;
+  NSDictionary *insertedObjectDefaults;
+  unsigned     numberOfObjectsPerBatch;
+  NSArray      *selectionIndexes;
+  NSArray      *objects;
+  NSArray      *displayObjects;
+  EOQualifier  *qualifier;
+  NSString     *defaultStringMatchFormat;
+  NSString     *defaultStringMatchOperator;
+  unsigned     currentBatchIndex;
+
+  NSMutableDictionary *_queryBindings;
+  NSMutableDictionary *_queryMatch;
+  NSMutableDictionary *_queryMin;
+  NSMutableDictionary *_queryMax;
+  NSMutableDictionary *_queryOperator;
+  
+  struct {
+    BOOL fetchesOnLoad:1;
+    BOOL selectFirstAfterFetch:1;
+    BOOL validatesChangesImmediatly:1;
+    BOOL inQueryMode:1;
+  } flags;
+}
+
+
+/* accessors */
+
+- (void)setDelegate:(id)_delegate;
+- (id)delegate;
+
+- (void)setDataSource:(EODataSource *)_ds;
+- (EODataSource *)dataSource;
+
+- (void)setSortOrderings:(NSArray *)_orderings;
+- (NSArray *)sortOrderings;
+
+- (void)setFetchesOnLoad:(BOOL)_flag;
+- (BOOL)fetchesOnLoad;
+
+- (void)setInsertedObjectDefaultValues:(NSDictionary *)_values;
+- (NSDictionary *)insertedObjectDefaultValues;
+
+- (void)setNumberOfObjectsPerBatch:(unsigned)_count;
+- (unsigned)numberOfObjectsPerBatch;
+
+- (void)setSelectsFirstObjectAfterFetch:(BOOL)_flag;
+- (BOOL)selectsFirstObjectAfterFetch;
+
+- (void)setValidatesChangesImmediatly:(BOOL)_flag;
+- (BOOL)validatesChangesImmediatly;
+
+/* display */
+
+- (void)redisplay;
+
+/* batches */
+
+- (BOOL)hasMultipleBatches;
+- (unsigned)batchCount;
+- (void)setCurrentBatchIndex:(unsigned)_currentBatchIndex;
+- (unsigned)currentBatchIndex;
+- (unsigned)indexOfFirstDisplayedObject;
+- (unsigned)indexOfLastDisplayedObject;
+- (id)displayNextBatch;
+- (id)displayPreviousBatch;
+- (id)displayBatchContainingSelectedObject;
+
+/* selection */
+
+- (BOOL)setSelectionIndexes:(NSArray *)_selection;
+- (NSArray *)selectionIndexes;
+- (BOOL)clearSelection;
+
+- (id)selectNext;
+- (id)selectPrevious;
+
+- (void)setSelectedObject:(id)_obj;
+- (id)selectedObject;
+- (void)setSelectedObjects:(NSArray *)_objs;
+- (NSArray *)selectedObjects;
+
+- (BOOL)selectObject:(id)_obj;
+- (BOOL)selectObjectsIdenticalTo:(NSArray *)_objs;
+- (BOOL)selectObjectsIdenticalTo:(NSArray *)_objs
+            selectFirstOnNoMatch:(BOOL)_flag;
+
+/* objects */
+
+- (void)setObjectArray:(NSArray *)_objects;
+- (NSArray *)allObjects;
+- (NSArray *)displayedObjects;
+
+- (id)fetch;
+- (void)updateDisplayedObjects;
+
+/* query */
+
+- (void)setInQueryMode:(BOOL)_flag;
+- (BOOL)inQueryMode;
+
+- (EOQualifier *)qualifierFromQueryValues;
+- (NSMutableDictionary *)queryBindings;
+- (NSMutableDictionary *)queryMatch;
+- (NSMutableDictionary *)queryMin;
+- (NSMutableDictionary *)queryMax;
+- (NSMutableDictionary *)queryOperator;
+
+- (void)setDefaultStringMatchFormat:(NSString *)_tmp;
+- (NSString *)defaultStringMatchFormat;
+- (void)setDefaultStringMatchOperator:(NSString *)_tmp;
+- (NSString *)defaultStringMatchOperator;
++ (NSString *)globalDefaultStringMatchFormat;
++ (NSString *)globalDefaultStringMatchOperator;
+
+/* qualifiers */
+
+- (void)setQualifier:(EOQualifier *)_q;
+- (EOQualifier *)qualifier;
+
+- (NSArray *)allQualifierOperators;
+- (NSArray *)stringQualifierOperators;
+- (NSArray *)relationalQualifierOperators;
+
+- (void)qualifyDisplayGroup;
+- (void)qualifyDataSource;
+
+@end
+
+@interface NSObject(WODisplayGroupDelegate)
+
+- (void)displayGroup:(WODisplayGroup *)_dg
+  createObjectFailedForDataSource:(EODataSource *)_ds;
+
+- (BOOL)displayGroupShouldFetch:(WODisplayGroup *)_dg;
+- (void)displayGroup:(WODisplayGroup *)_dg
+  didFetchObjects:(NSArray *)_objects;
+
+- (BOOL)displayGroup:(WODisplayGroup *)_dg
+  shouldInsertObject:(id)_object
+  atIndex:(unsigned int)_idx;
+- (void)displayGroup:(WODisplayGroup *)_dg
+  didInsertObject:(id)_object;
+
+- (BOOL)displayGroup:(WODisplayGroup *)_dg
+  shouldDeleteObject:(id)_object;
+- (void)displayGroup:(WODisplayGroup *)_dg
+  didDeleteObject:(id)_object;
+
+- (void)displayGroup:(WODisplayGroup *)_dg
+  didSetValue:(id)_value forObject:(id)_object key:(NSString *)_key;
+
+- (void)displayGroupDidChangeDataSource:(WODisplayGroup *)_dg;
+- (BOOL)displayGroup:(WODisplayGroup *)_dg
+  shouldRedisplayForEditingContextChangeNotification:(NSNotification *)_not;
+
+- (BOOL)displayGroup:(WODisplayGroup *)_dg
+  shouldChangeSelectionToIndexes:(NSArray *)_idxs;
+- (void)displayGroupDidChangeSelectedObjects:(WODisplayGroup *)_dg;
+- (void)displayGroupDidChangeSelection:(WODisplayGroup *)_dg;
+
+- (NSArray *)displayGroup:(WODisplayGroup *)_dg
+  displayArrayForObjects:(NSArray *)_objects;
+
+@end
+
+#endif /* __NGObjWeb_WODisplayGroup_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WODynamicElement.h b/skyrix-sope/NGObjWeb/NGObjWeb/WODynamicElement.h
new file mode 100644 (file)
index 0000000..017b60d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WODynamicElement_H__
+#define __NGObjWeb_WODynamicElement_H__
+
+#include <NGObjWeb/WOElement.h>
+
+@class NSArray, NSDictionary;
+@class WOElement, WOAssociation;
+
+struct _WOExtraAttrStruct;
+
+@interface WODynamicElement : WOElement
+{
+@private
+  /* attribute mappings which aren't parsed */
+  struct _WOExtraAttrStruct *extraAttributes;
+  
+@protected
+  WOAssociation  *otherTagString;  /* new in WO4 */
+  BOOL           containsForm;
+@private
+  BOOL           debug;            /* new in WO4 */
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  template:(WOElement *)_childElement;
+
+/* this method was discovered in the SSL example and might be private ! */
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  contentElements:(NSArray *)_children;
+
+@end
+
+@interface WODynamicElement(PrivateMethods)
+
+- (void)setExtraAttributes:(NSDictionary *)_extras;
+- (void)appendExtraAttributesToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+
+- (id)template;
+
+@end
+
+#endif /* __NGObjWeb_WODynamicElement_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOElement.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOElement.h
new file mode 100644 (file)
index 0000000..bd41f0f
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOElement_H__
+#define __NGObjWeb_WOElement_H__
+
+#import <Foundation/NSObject.h>
+#include <NGObjWeb/OWResponder.h>
+#include <NGObjWeb/NGObjWebDecls.h>
+
+@class NSDictionary, NSString;
+
+@interface WOElement : NSObject < OWResponder >
+{
+@public
+  // cached selectors
+  OWTakeValuesMethod     takeValues;
+  OWAppendResponseMethod appendResponse;
+}
+
+NGObjWeb_DECLARE id OWGetProperty(NSDictionary *_set, NSString *_name);
+
+@end
+
+#endif /* __NGObjWeb_WOElement_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOElementTrackingContext.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOElementTrackingContext.h
new file mode 100644 (file)
index 0000000..57ba622
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOElementTrackingContext_H__
+#define __NGObjWeb_WOElementTrackingContext_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+
+@protocol WOElementTrackingContext
+
+- (NSString *)elementID;
+- (void)appendElementIDComponent:(NSString *)_eid;
+- (void)appendZeroElementIDComponent;
+- (void)deleteAllElementIDComponents;
+- (void)deleteLastElementIDComponent;
+- (void)incrementLastElementIDComponent;
+- (void)appendIntElementIDComponent:(int)_eid;
+
+/* advanced element IDs */
+
+- (id)currentElementID;
+- (id)consumeElementID;
+
+@end
+
+#endif /* __NGObjWeb_WOElementTrackingContext_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOHTTPConnection.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOHTTPConnection.h
new file mode 100644 (file)
index 0000000..f67a233
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOHTTPConnection_H__
+#define __NGObjWeb_WOHTTPConnection_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  WOHTTPConnection
+  
+  This class can be used to access HTTP based services using the
+  NGObjWeb infrastructure.
+*/
+
+@class NSURL;
+@class NGCTextStream;
+@class WORequest, WOResponse, NSException;
+
+@interface WOHTTPConnection : NSObject
+{
+  NSURL         *url;
+  
+  BOOL          keepAlive;
+  int           connectTimeout;
+  int           sendTimeout;
+  int           receiveTimeout;
+  
+  BOOL          useProxy;
+  BOOL          useSSL;
+  
+  id            socket;
+  id            log;
+  NGCTextStream *io;
+  NSException   *lastException;
+  
+  BOOL didRegisterForNotification;
+}
+
+- (id)initWithHost:(NSString *)_h onPort:(unsigned int)_p secure:(BOOL)_flag;
+- (id)initWithHost:(NSString *)_hostName onPort:(unsigned int)_port;
+- (id)initWithURL:(id)_url;
+
+/* IO */
+
+- (BOOL)sendRequest:(WORequest *)_request;
+- (WOResponse *)readResponse;
+
+- (void)setKeepAliveEnabled:(BOOL)_flag;
+- (BOOL)keepAliveEnabled;
+
+/* timeouts */
+
+- (void)setConnectTimeout:(int)_seconds;
+- (int)connectTimeout;
+- (void)setReceiveTimeout:(int)_seconds;
+- (int)receiveTimeout;
+- (void)setSendTimeout:(int)_seconds;
+- (int)sendTimeout;
+
+@end
+
+extern NSString *WOHTTPConnectionCanReadResponse;
+
+@interface WOHTTPConnection(SkyrixAdds)
+
+/* error handling */
+
+- (NSException *)lastException;
+
+@end
+
+#endif /* __NGObjWeb_WOHTTPConnection_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOMailDelivery.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOMailDelivery.h
new file mode 100644 (file)
index 0000000..bdd8cbe
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOMailDelivery_H__
+#define __NGObjWeb_WOMailDelivery_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSArray;
+@class WOComponent;
+
+@interface WOMailDelivery : NSObject
+{
+}
+
++ (id)sharedInstance;
+
+// composing mails
+
+- (id)composeEmailFrom:(NSString *)_senderAddress
+  to:(NSArray *)_receiverAddresses
+  cc:(NSArray *)_ccAddresses
+  subject:(NSString *)_subject
+  plainText:(NSString *)_text
+  send:(BOOL)_sendFlag;
+
+- (id)composeEmailFrom:(NSString *)_senderAddress
+  to:(NSArray *)_receiverAddresses
+  cc:(NSArray *)_ccAddresses
+  subject:(NSString *)_subject
+  component:(WOComponent *)_component
+  send:(BOOL)_sendFlag;
+
+// sending mails
+
+- (BOOL)sendEmail:(id)_email;
+
+@end
+
+#endif /* __NGObjWeb_WOMailDelivery_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOMessage.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOMessage.h
new file mode 100644 (file)
index 0000000..785f5a0
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOMessage_H__
+#define __NGObjWeb_WOMessage_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+#include <NGStreams/NGStreamProtocols.h>
+
+/*
+  WOMessage
+  
+  Abstract superclass of both, WORequest and WOResponse.
+*/
+
+@class NSDictionary, NSArray, NSData, NSMutableData, NSMutableArray;
+@class NGMutableHashMap;
+@class WOCookie;
+
+@interface WOMessage : NSObject
+{
+@private
+  NSString         *version;
+  NSMutableData    *content;
+  NGMutableHashMap *header;
+  NSDictionary     *userInfo;
+  NSMutableArray   *cookies;
+  NSStringEncoding contentEncoding;
+  id<NGStream>     contentStream;
+  
+  struct {
+    BOOL didStartWriting:1; // afterwards no headers may be changed
+    int  reserved:31;
+  } womFlags;
+  
+@public // cached selectors
+  void (*addChar)(id, SEL, char);
+  void (*addStr)(id, SEL, NSString *);
+  void (*addHStr)(id, SEL, NSString *);
+  void (*addCStr)(id, SEL, const unsigned char *);
+  void (*addBytes)(id, SEL, const void *, unsigned);
+}
+
+/* accessors */
+
+- (void)setUserInfo:(NSDictionary *)_userInfo;
+- (NSDictionary *)userInfo;
+
+/* HTTP */
+
+- (void)setHTTPVersion:(NSString *)_httpVersion;
+- (NSString *)httpVersion;
+
+/* cookies (new in WO4) */
+
+- (void)addCookie:(WOCookie *)_cookie;
+- (void)removeCookie:(WOCookie *)_cookie;
+- (NSArray *)cookies;
+
+/* header */
+
+- (void)setHeader:(NSString *)_header forKey:(NSString *)_key;
+- (NSString *)headerForKey:(NSString *)_key;
+- (void)setHeaders:(NSArray *)_headers forKey:(NSString *)_key;
+- (NSArray *)headersForKey:(NSString *)_key;
+- (NSArray *)headerKeys;
+
+- (void)appendHeader:(NSString *)_header forKey:(NSString *)_key;
+- (void)appendHeaders:(NSArray *)_headers forKey:(NSString *)_key;
+
+- (void)setHeaders:(NSDictionary *)_headers;
+- (NSDictionary *)headers;
+- (NSString *)headersAsString;
+
+/* generic content */
+
+- (void)setContent:(NSData *)_data;
+- (NSData *)content;
+- (void)setContentEncoding:(NSStringEncoding)_encoding;
+- (NSStringEncoding)contentEncoding;
++ (void)setDefaultEncoding:(NSStringEncoding)_encoding;
++ (NSStringEncoding)defaultEncoding;
+
+/* structured content */
+
+- (void)appendContentBytes:(const void *)_bytes length:(unsigned)_length;
+- (void)appendContentCharacter:(unichar)_c;
+- (void)appendContentData:(NSData *)_data;
+
+- (void)appendContentString:(NSString *)_value;
+- (void)appendContentCString:(const unsigned char *)_value;
+
+- (void)appendContentHTMLAttributeValue:(NSString *)_value;
+- (void)appendContentHTMLString:(NSString *)_value;
+- (void)appendContentXMLAttributeValue:(NSString *)_value;
+- (void)appendContentXMLString:(NSString *)_value;
+
+@end
+
+@interface WOMessage(Escaping)
+
+/* this escapes '&', '"', '<' and '>' */
++ (NSString *)stringByEscapingHTMLString:(NSString *)_string;
+
+/* this escapes '&', '"', '<', '>', '\t', '\r' and '\n' */
++ (NSString *)stringByEscapingHTMLAttributeValue:(NSString *)_string;
+
+@end
+
+@interface WOMessage(NGObjWebExtensions)
+- (NSString *)contentAsString;
+- (BOOL)doesStreamContent;
+- (NSArray *)validateContent;
+@end
+
+@interface WOMessage(DOMXML)
+- (void)setContentDOMDocument:(id)_dom;
+- (void)appendContentDOMDocumentFragment:(id)_domfrag;
+- (id)contentAsDOMDocument;
+@end
+
+#endif /* __NGObjWeb_WOMessage_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOPageGenerationContext.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOPageGenerationContext.h
new file mode 100644 (file)
index 0000000..45adb36
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOPageGenerationContext_H__
+#define __NGObjWeb_WOPageGenerationContext_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+@class WORequest, WOResponse;
+
+@protocol WOPageGenerationContext
+
+- (id)session;              // creates new session if none was set
+- (BOOL)hasSession;
+
+- (id)page;
+- (id)component;
+- (NSString *)contextID;    // returns nil if no session is set
+- (WORequest *)request;
+- (WOResponse *)response;
+
+- (void)setInForm:(BOOL)_form;
+- (BOOL)isInForm;
+
+/* cursor */
+
+- (void)pushCursor:(id)_obj;
+- (id)popCursor;
+- (id)cursor;
+
+@end
+
+#endif /* __NGObjWeb_WOPageGenerationContext_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOProxyRequestHandler.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOProxyRequestHandler.h
new file mode 100644 (file)
index 0000000..555ec27
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOProxyRequestHandler_H__
+#define __NGObjWeb_WOProxyRequestHandler_H__
+
+#import <NGObjWeb/WORequestHandler.h>
+
+@class WOHTTPConnection;
+
+/*
+  This request-handler can be used to forward and debug HTTP requests. It
+  can log requests/responses to stdout and it can perform some request
+  manipulations:
+    rewriteHost     => change the host: header to match the destination
+    connectionClose => replace the connection handler with connection: close
+*/
+
+@interface WOProxyRequestHandler : WORequestHandler
+{
+  WOHTTPConnection *client;
+  BOOL     rawLogRequest;
+  BOOL     rawLogResponse;
+  BOOL     rewriteHost;
+  BOOL     connectionClose;
+  NSString *logFilePrefix;
+  int      rqcount;
+}
+
+- (id)initWithHost:(NSString *)_hostName onPort:(unsigned int)_port;
+
+/* settings */
+
+- (void)enableRawLogging;
+- (void)setLogFilePrefix:(NSString *)_p;
+
+/* fixups */
+
+- (WORequest *)fixupRequest:(WORequest *)_request;
+- (WOResponse *)fixupResponse:(WOResponse *)_r;
+
+@end
+
+#endif /* __NGObjWeb_WOProxyRequestHandler_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WORequest.h b/skyrix-sope/NGObjWeb/NGObjWeb/WORequest.h
new file mode 100644 (file)
index 0000000..a8089da
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WORequest_H__
+#define __NGObjWeb_WORequest_H__
+
+#import <Foundation/NSString.h>
+#include <NGObjWeb/WOMessage.h>
+#include <NGObjWeb/NGObjWebDecls.h>
+
+@class NSString, NSArray, NSData, NSDictionary;
+@class NGHashMap;
+@class NGHttpRequest;
+
+NGObjWeb_EXPORT NSString *WORequestValueData;
+NGObjWeb_EXPORT NSString *WORequestValueInstance;
+NGObjWeb_EXPORT NSString *WORequestValuePageName;
+NGObjWeb_EXPORT NSString *WORequestValueContextID;
+NGObjWeb_EXPORT NSString *WORequestValueSenderID;
+NGObjWeb_EXPORT NSString *WORequestValueSessionID;
+NGObjWeb_EXPORT NSString *WONoSelectionString;
+
+@interface WORequest : WOMessage
+{
+@private
+  NGHttpRequest *request;     // NGHttp Request
+  id            formContent;  // FORM data (message content or URL paras)
+  
+@private
+  NSString      *method;
+  NSString      *_uri;
+  
+@protected
+  NSString     *adaptorPrefix;
+  NSString     *appName;
+  NSString     *requestHandlerKey;
+  NSString     *requestHandlerPath;
+}
+
+- (id)initWithMethod:(NSString *)_method
+  uri:(NSString *)_uri
+  httpVersion:(NSString *)_version
+  headers:(NSDictionary *)_headers
+  content:(NSData *)_body
+  userInfo:(NSDictionary *)_userInfo;
+
+/* WO accessors */
+
+- (BOOL)isFromClientComponent;
+
+- (NSString *)applicationName;
+- (NSString *)adaptorPrefix;
+
+/* HTTP accessors */
+
+- (NSString *)method;
+- (NSString *)uri;
+- (BOOL)isProxyRequest; /* check whether uri is a full URL */
+
+/* forms */
+
+- (NSStringEncoding)formValueEncoding;
+- (void)setDefaultFormValueEncoding:(NSStringEncoding)_enc;
+- (NSStringEncoding)defaultFormValueEncoding;
+- (void)setFormValueEncodingDetectionEnabled:(BOOL)_flag;
+- (BOOL)isFormValueEncodingDetectionEnabled;
+
+- (NSArray *)formValueKeys;
+- (NSString *)formValueForKey:(NSString *)_key;
+- (NSArray *)formValuesForKey:(NSString *)_key;
+- (NSDictionary *)formValues;
+
+/* HTTP header */
+
+- (NSArray *)browserLanguages; // new in WO4
+
+/* request handler */
+
+- (NSString *)requestHandlerKey;       // new in WO4
+- (NSString *)requestHandlerPath;      // new in WO4
+- (NSArray *)requestHandlerPathArray;  // new in WO4
+
+/* cookie support (new in WO4) */
+
+- (NSArray *)cookieValuesForKey:(NSString *)_key;
+- (NSString *)cookieValueForKey:(NSString *)_key;
+- (NSDictionary *)cookieValues;
+
+@end
+
+#if COMPILING_NGOBJWEB
+
+@interface WORequest(PrivateMethods)
+
+- (NGHttpRequest *)httpRequest;
+
+/* accessors */
+
+- (NGHashMap *)formParameters;
+
+@end
+
+#endif
+
+@interface WORequest(DeprecatedMethodsInWO4)
+
+- (NSString *)applicationHost; // use NSProcessInfo and/or NSTask
+- (NSString *)sessionID;       // [[context session] sessionID]
+- (NSString *)senderID;        // replaced by WOContext:-senderID
+- (NSString *)contextID;       // use WOContext:-contextID
+
+@end
+
+#endif /* __NGObjWeb_WORequest_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WORequestHandler.h b/skyrix-sope/NGObjWeb/NGObjWeb/WORequestHandler.h
new file mode 100644 (file)
index 0000000..3ed6833
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WORequestHandler_H__
+#define __NGObjWeb_WORequestHandler_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSLock.h>
+
+@class NSRecursiveLock;
+@class WOSession, WORequest, WOResponse, WOContext, WOApplication;
+
+@interface WORequestHandler : NSObject < NSLocking >
+{
+@protected
+  NSRecursiveLock *lock;
+}
+
+- (WOResponse *)handleRequest:(WORequest *)_request;
+
+@end
+
+#endif /* __NGObjWeb_WORequestHandler_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOResourceManager.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOResourceManager.h
new file mode 100644 (file)
index 0000000..8ab66f5
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOResourceManager_H__
+#define __NGObjWeb_WOResourceManager_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSLock.h>
+#import <Foundation/NSMapTable.h>
+#import <Foundation/NSHashTable.h>
+
+@class NSString, NSArray, NSData;
+@class WORequest, WOComponent, WOElement, WOSession;
+
+@interface WOResourceManager : NSObject < NSLocking >
+{
+@protected
+  NSString   *base;
+@private
+  NSString   *w3resources;
+  NSString   *resources;
+  NSMapTable *componentDefinitions; // name.language => definition
+  NSMapTable *stringTables;         // path => tableinfo
+  NSMapTable *existingPathes;
+  NSMapTable *keyedResources;
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages;
+
+- (NSString *)urlForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages
+  request:(WORequest *)_request;
+
+/* string tables */
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_default
+  languages:(NSArray *)_languages;
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_defaultValue
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_languages;
+
+@end
+
+@interface WOResourceManager(KeyedData)
+
+/* keyed storage */
+
+- (void)setData:(NSData *)_data
+  forKey:(NSString *)_key
+  mimeType:(NSString *)_type
+  session:(WOSession *)_session;
+- (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session;
+- (void)flushDataCache;
+
+@end
+
+@interface WOResourceManager(PrivateMethods)
+
+- (id)initWithPath:(NSString *)_path;
++ (void)setResourcePrefix:(NSString *)_prefix;
+
+- (WOElement *)templateWithName:(NSString *)_name languages:(NSArray *)_langs;
+- (id)pageWithName:(NSString *)_name languages:(NSArray *)_langs;
+
+- (NSString *)pathToComponentNamed:(NSString *)_name
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_langs;
+
+- (void)setCachingEnabled:(BOOL)_flag;
+- (BOOL)isCachingEnabled;
+
+@end
+
+@interface WOResourceManager(DeprecatedMethods)
+
+- (NSString *)pathForResourceNamed:(NSString *)_name;
+- (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type;
+- (NSString *)urlForResourceNamed:(NSString *)_name;
+- (NSString *)urlForResourceNamed:(NSString *)_name ofType:(NSString *)_type;
+
+@end
+
+#endif /* __NGObjWeb_WOResourceManager_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOResponse.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOResponse.h
new file mode 100644 (file)
index 0000000..3585d56
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOResponse_H__
+#define __NGObjWeb_WOResponse_H__
+
+#import <Foundation/NSString.h>
+#include <NGObjWeb/WOMessage.h>
+#include <NGObjWeb/WOActionResults.h>
+
+/*
+  WOResponse
+  
+  This WOMessage subclass add functionality for HTTP responses, mostly
+  the HTTP status. WOResponse also provides some methods for zipping itself.
+*/
+
+@class NSData;
+@class WORequest;
+
+@interface WOResponse : WOMessage < WOActionResults >
+{
+  unsigned int status;
+}
+
+/* HTTP */
+
+- (void)setStatus:(unsigned int)_status;
+- (unsigned int)status;
+
+@end
+
+@interface WOResponse(PrivateMethods)
+
++ (WOResponse *)responseWithRequest:(WORequest *)_request;
+- (id)initWithRequest:(WORequest *)_request;
+
+- (void)disableClientCaching;
+
+@end
+
+@interface WOResponse(Zipping)
+
+- (BOOL)shouldZipResponseToRequest:(WORequest *)_rq;
+- (NSData *)zipResponse;
+
+@end
+
+#endif /* __NGObjWeb_WOResponse_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOSession.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOSession.h
new file mode 100644 (file)
index 0000000..62c1fdc
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOSession_H__
+#define __NGObjWeb_WOSession_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSLock.h>
+#import <Foundation/NSDate.h>
+#include <NGObjWeb/NGObjWebDecls.h>
+
+@class NSString, NSArray, NSRecursiveLock, NSMutableDictionary, NSDate;
+@class WOContext, WOApplication;
+@class WORequest, WOResponse, WOContext, WOComponent;
+
+struct WOSessionCacheEntry;
+
+NGObjWeb_EXPORT NSString *WOSessionDidTimeOutNotification;
+NGObjWeb_EXPORT NSString *WOSessionDidRestoreNotification;
+NGObjWeb_EXPORT NSString *WOSessionDidCreateNotification;
+NGObjWeb_EXPORT NSString *WOSessionDidTerminateNotification;
+
+@interface WOSession : NSObject < NSLocking >
+{
+@private
+  NSArray             *wosLanguages;
+  BOOL                isTerminating;
+  NSRecursiveLock     *wosLock;
+  NSString            *wosSessionId;
+  NSMutableDictionary *wosVariables;     // session variables
+  NSTimeInterval      wosTimeOut;
+  id                  wosDefaultEditingContext;
+  struct {
+    BOOL              storesIDsInURLs:1;
+    BOOL              storesIDsInCookies:1;
+    BOOL              isAwake:1;
+  } wosFlags;
+
+@private
+  struct {
+    struct WOSessionCacheEntry *entries;
+    unsigned short             index;
+    unsigned short             size;
+  } pageCache;
+  struct {
+    struct WOSessionCacheEntry *entries;
+    unsigned short             index;
+    unsigned short             size;
+  } permanentPageCache;
+
+@protected // transients (non-retained)
+  WOApplication *application;
+  WOContext     *context;
+}
+
+/* session */
+
+- (NSString *)sessionID;
+- (void)setStoresIDsInURLs:(BOOL)_flag;
+- (BOOL)storesIDsInURLs;
+- (void)setStoresIDsInCookies:(BOOL)_flag;
+- (BOOL)storesIDsInCookies;
+- (NSString *)domainForIDCookies;
+- (NSDate *)expirationDateForIDCookies;
+
+- (void)setDistributionEnabled:(BOOL)_flag;
+- (BOOL)isDistributionEnabled;
+
+- (void)setTimeOut:(NSTimeInterval)_timeout;
+- (NSTimeInterval)timeOut;
+- (void)terminate;
+- (BOOL)isTerminating;
+
+- (WOContext *)context;
+
+/* editing context */
+
+- (id)defaultEditingContext;
+
+/* localization */
+
+- (void)setLanguages:(NSArray *)_langs;
+- (NSArray *)languages;
+
+/* notifications */
+
+- (void)awake;
+- (void)sleep;
+
+/* pages */
+
+- (id)restorePageForContextID:(NSString *)_idx;
+- (void)savePage:(WOComponent *)_page;
+- (void)savePageInPermanentCache:(WOComponent *)_page; // new in WO4
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_request inContext:(WOContext *)_ctx;
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx;
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx;
+
+/* multithreading */
+
+- (void)lock;
+- (void)unlock;
+- (BOOL)tryLock;
+
+/* session variables */
+
+- (void)setObject:(id)_obj forKey:(NSString *)_key;
+- (id)objectForKey:(NSString *)_key;
+- (void)removeObjectForKey:(NSString *)_key;
+
+/* statistics */
+
+- (NSArray *)statistics;
+
+@end
+
+@interface WOSession(DeprecatedMethodsInWO4)
+
+- (id)application; // use [WOApplication application] instead
+
+@end
+
+@interface WOSession(PrivateMethods)
+- (void)_awakeWithContext:(WOContext *)_ctx;
+- (void)_sleepWithContext:(WOContext *)_ctx;
+@end
+
+@interface WOSession(NSCoding) < NSCoding >
+@end
+
+@interface WOSession(Logging)
+
+- (void)logWithFormat:(NSString *)_format, ...;
+- (void)debugWithFormat:(NSString *)_format, ...; // new in WO4
+
+@end
+
+#endif /* __NGObjWeb_WOSession_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOSessionStore.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOSessionStore.h
new file mode 100644 (file)
index 0000000..04909e3
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOSessionStore_H__
+#define __NGObjWeb_WOSessionStore_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSMapTable.h>
+
+@class NSString, NSMutableSet, NSRecursiveLock, NSConditionLock, NSTimer;
+@class WOSession, WOContext, WORequest;
+
+@interface WOSessionStore : NSObject
+{
+@protected
+  NSRecursiveLock *lock;
+  NSConditionLock *checkoutLock;
+  NSMutableSet    *checkedOutSessions;
+}
+
++ (WOSessionStore *)serverSessionStore;
+
+/* checkin/out */
+
+- (id)checkOutSessionWithSessionID:(NSString *)_id
+  request:(WORequest *)_request;
+
+- (void)checkInSessionForContext:(WOContext *)_context;
+
+/* store (WO4) */
+
+- (id)restoreSessionWithID:(NSString *)_id request:(WORequest *)_request;
+
+- (void)saveSessionForContext:(WOContext *)_context;
+
+/* store (deprecated in WO4) */
+
+- (void)saveSession:(WOSession *)_session; // deprecated in WO4
+- (id)restoreSessionWithID:(NSString *)_id; // deprecated in WO4
+
+@end
+
+@interface WOSessionStore(PrivateMethods)
+
+- (int)activeSessionsCount;
+- (void)sessionExpired:(NSString *)_sessionID;
+- (void)sessionTerminated:(WOSession *)_session;
+
+@end
+
+#endif /* __NGObjWeb_WOSessionStore_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOStatisticsStore.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOStatisticsStore.h
new file mode 100644 (file)
index 0000000..c092a80
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOStatisticsStore_H__
+#define __NGObjWeb_WOStatisticsStore_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSLock.h>
+#import <Foundation/NSDate.h>
+
+@class NSString, NSDictionary, NSMutableDictionary;
+@class WOResponse, WOContext;
+
+@interface WOStatisticsStore : NSObject < NSLocking >
+{
+  id<NSLocking,NSObject> lock;
+  NSDate   *startTime;
+  
+  NSMutableDictionary *pageStatistics;
+  unsigned       totalResponseCount;
+  unsigned       pageResponseCount;
+  unsigned       totalResponseSize;
+  unsigned       zippedResponsesCount;
+  unsigned       totalZippedSize;
+  int            smallestResponseSize;
+  unsigned       largestResponseSize;
+  NSTimeInterval minimumDuration;
+  NSTimeInterval maximumDuration;
+  NSTimeInterval totalDuration;
+}
+
+/* query */
+
+- (NSDictionary *)statistics;
+
+/* recording */
+
+- (void)recordStatisticsForResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+
+- (NSString *)descriptionForResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+
+/* formatting */
+
+- (NSString *)formatDescription:(NSString *)_description
+  forResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context;
+
+/* NSLocking */
+
+- (void)lock;
+- (void)unlock;
+
+@end
+
+#endif /* __NGObjWeb_WOStatisticsStore_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOTemplate.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOTemplate.h
new file mode 100644 (file)
index 0000000..3369f5f
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOTemplate_H__
+#define __NGObjWeb_WOTemplate_H__
+
+#import <Foundation/NSObject.h>
+#include <NGObjWeb/WOElement.h>
+
+@class NSURL, NSDate, NSString, NSDictionary, NSMutableDictionary;
+@class NSEnumerator;
+@class WOTemplate, WOSubcomponentInfo, WOComponentScript;
+
+@interface WOTemplate : WOElement
+{
+  /* should add some info about the logic of the component ... */
+  NSURL               *url;
+  WOElement           *rootElement;
+  NSDate              *loadDate;
+  NSMutableDictionary *subcomponentInfos;
+  WOComponentScript   *componentScript;
+  NSDictionary        *kvcTemplateVars;
+}
+
+- (id)initWithURL:(NSURL *)_url rootElement:(WOElement *)_element;
+
+/* component info */
+
+- (void)setComponentScript:(WOComponentScript *)_script;
+- (WOComponentScript *)componentScript;
+
+- (void)setKeyValueArchivedTemplateVariables:(NSDictionary *)_vars;
+- (NSDictionary *)keyValueArchivedTemplateVariables;
+
+/* subcomponent info */
+
+- (void)addSubcomponentWithKey:(NSString *)_key
+  name:(NSString *)_name
+  bindings:(NSDictionary *)_bindings;
+
+- (BOOL)hasSubcomponentInfos;
+- (NSEnumerator *)infoKeyEnumerator;
+- (WOSubcomponentInfo *)subcomponentInfoForKey:(NSString *)_key;
+
+/* accessors */
+
+- (void)setRootElement:(WOElement *)_element;
+- (WOElement *)rootElement;
+
+- (NSURL *)url;
+
+@end
+
+@interface WOSubcomponentInfo : NSObject
+{
+  NSString     *componentName;
+  NSDictionary *bindings;
+}
+
+- (id)initWithName:(NSString *)_name bindings:(NSDictionary *)_bindings;
+
+/* accessors */
+
+- (NSString *)componentName;
+- (NSDictionary *)bindings;
+
+@end
+
+#endif /* __NGObjWeb_WOTemplate_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOTemplateBuilder.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOTemplateBuilder.h
new file mode 100644 (file)
index 0000000..cb276c5
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOTemplateBuilder_H__
+#define __NGObjWeb_WOTemplateBuilder_H__
+
+#import <Foundation/NSObject.h>
+#include <NGObjWeb/WOElement.h>
+
+@class NSURL, NSDate, NSString, NSDictionary, NSMutableDictionary;
+@class NSEnumerator;
+@class WOTemplate, WOSubcomponentInfo, WOComponentScript;
+
+@interface WOTemplateBuilder : NSObject
+{
+}
+
++ (WOTemplateBuilder *)templateBuilderForPath:(NSString *)_path;
++ (WOTemplateBuilder *)templateBuilderForURL:(NSURL *)_url;
+
+- (WOTemplate *)buildTemplateAtURL:(NSURL *)_url;
+
+@end
+
+#include <NGObjWeb/WOTemplate.h>
+#include <NGObjWeb/WOComponentScript.h>
+
+#endif /* __NGObjWeb_WOTemplateBuilder_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGObjWeb/WOxElemBuilder.h b/skyrix-sope/NGObjWeb/NGObjWeb/WOxElemBuilder.h
new file mode 100644 (file)
index 0000000..7a21547
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOxElemBuilder_H__
+#define __WOxElemBuilder_H__
+
+#import <Foundation/NSObject.h>
+#include <DOM/DOMProtocols.h>
+
+@class NSString, NSArray, NSMutableDictionary, NSMutableArray;
+@class WOElement, WOAssociation, WOComponent, WOResourceManager;
+@class WOComponentScript, WOComponentScriptPart;
+
+/*
+  Abstract class to build NGObjWeb WOElement templates from
+  XML DOM structures.
+  
+  Template builders can be stacked in a processing queue, so that
+  unknown elements are produced by the "nextBuilder". When processing
+  is done using a stack, the first stack builder is called the
+  "templateBuilder" and used to keep global state (eg the template
+  builder must be used to create further elements if the same element
+  set is required).
+  
+  WOxElemBuilder stacks are not thread-safe since the template builder
+  stores subcomponent creation info in an instance variable.
+*/
+
+@interface WOxElemBuilder : NSObject
+{
+@protected
+  WOxElemBuilder      *nextBuilder;
+  NSMutableArray      *subcomponentInfos;
+  NSMutableDictionary *nsToAssoc;
+  NSMutableArray      *scriptParts;
+  WOComponentScript   *script;
+}
+
++ (WOxElemBuilder *)createBuilderQueue:(NSArray *)_classNames;
++ (WOxElemBuilder *)createBuilderQueueV:(NSString *)_className, ...;
+
+/* building a template from a DOM structure */
+
+- (WOElement *)buildTemplateFromDocument:(id<DOMDocument>)_document;
+
+/* node-type build dispatcher method ... */
+
+- (WOElement *)buildNode:(id<DOMNode>)_node templateBuilder:(id)_bld;
+- (NSArray *)buildNodes:(id<DOMNodeList>)_node templateBuilder:(id)_bld;
+
+/* building parts of a DOM ... */
+
+- (WOElement *)buildDocument:(id<DOMDocument>)_node templateBuilder:(id)_bld;
+- (WOElement *)buildElement:(id<DOMElement>)_node   templateBuilder:(id)_bld;
+
+- (WOElement *)buildCharacterData:(id<DOMCharacterData>)_node
+  templateBuilder:(id)_builder;
+- (WOElement *)buildText:(id<DOMText>)_node
+  templateBuilder:(id)_builder;
+- (WOElement *)buildCDATASection:(id<DOMCDATASection>)_node
+  templateBuilder:(id)_builder;
+- (WOElement *)buildComment:(id<DOMComment>)_node
+  templateBuilder:(id)_builder;
+
+/* association callbacks */
+
+- (WOAssociation *)associationForValue:(id)_value;
+- (WOAssociation *)associationForKeyPath:(NSString *)_path;
+- (WOAssociation *)associationForJavaScript:(NSString *)_js;
+
+// this one uses the attribute namespace to determine the association class
+- (WOAssociation *)associationForAttribute:(id<DOMAttr>)_attribute;
+// map the attribute names to dict keys and use the method above for the value
+// "_name" attributes are mapped to "?name" query keys
+- (NSMutableDictionary *)associationsForAttributes:(id<DOMNamedNodeMap>)_attrs;
+
+- (void)registerAssociationClass:(Class)_class forNamespaceURI:(NSString *)_ns;
+- (Class)associationClassForNamespaceURI:(NSString *)_ns;
+
+/* creating unique IDs */
+
+- (NSString *)uniqueIDForNode:(id)_node;
+  
+/* logging */
+
+- (void)logWithFormat:(NSString *)_format, ...;
+- (void)debugWithFormat:(NSString *)_format, ...;
+
+/* managing builder queues */
+
+- (void)setNextBuilder:(WOxElemBuilder *)_builder;
+- (WOxElemBuilder *)nextBuilder;
+
+/* component script parts */
+
+- (WOComponentScript *)componentScript;
+- (void)addComponentScriptPart:(WOComponentScriptPart *)_part;
+- (void)addComponentScript:(NSString *)_script line:(unsigned)_line;
+
+/* subcomponent registry, created during parsing ... */
+
+- (void)registerSubComponentWithId:(NSString *)_cid
+  componentName:(NSString *)_name
+  bindings:(NSMutableDictionary *)_bindings;
+
+- (NSArray *)subcomponentInfos;
+
+- (void)reset;
+
+@end
+
+@interface WOxElemBuilderComponentInfo : NSObject
+{
+  NSString            *cid;
+  NSString            *pageName;
+  NSMutableDictionary *bindings;
+}
+
+- (id)initWithComponentId:(NSString *)_cid
+  componentName:(NSString *)_name
+  bindings:(NSMutableDictionary *)_bindings;
+
+/* accessors */
+
+- (NSString *)componentId;
+- (NSString *)pageName;
+- (NSMutableDictionary *)bindings;
+
+/* create the component ... */
+
+- (id)instantiateWithResourceManager:(WOResourceManager *)_rm
+  languages:(NSArray *)_languages;
+
+@end
+
+/*
+  Specialized superclass for builders which directly map DOM elements
+  to NGObjWeb dynamic elements (which is usually the case ...).
+
+  The classes returned must conform to the WOxTagClassInit protocol and
+  can use the _builder argument to continue building for child nodes
+  of the given DOM element.
+*/
+
+@interface NSObject(WOxTagClassInit)
+
+- (id)initWithElement:(id<DOMElement>)_element
+  templateBuilder:(WOxElemBuilder *)_builder;
+
+@end
+
+@interface WOxTagClassElemBuilder : WOxElemBuilder
+
+- (Class)classForElement:(id<DOMElement>)_element;
+
+@end
+
+#endif /* WOxElemBuilder */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/.cvsignore b/skyrix-sope/NGObjWeb/NGXmlRpc/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/ChangeLog b/skyrix-sope/NGObjWeb/NGXmlRpc/ChangeLog
new file mode 100644 (file)
index 0000000..8c11f51
--- /dev/null
@@ -0,0 +1,244 @@
+2004-04-17  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * WODirectAction+XmlRpc.m: replaced "catched" with "caught" in comment.
+
+2004-03-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * EOFetchSpecification+XmlRpcCoding.m: do not use deprecated plist
+         init method (v4.2.322)
+
+2004-03-01  Helge Hess  <helge.hess@opengroupware.org>
+
+       * NGXmlRpcClient.m: added ability to specify additional, HTTP level
+         headers to be used when creating the WORequest for the XML-RPC
+         invocation (v4.2.315)
+
+2004-02-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGXmlRpcClient.m: deprecated non-URL based API, add -login method
+         (v4.2.289)
+
+2003-08-26  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpc.m: small cleanup to exception handling 
+         (v4.2.216)
+
+2003-01-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.138
+
+       * WODirectAction+XmlRpc.m: added special handling for NULL selectors,
+         since the MacOSX Foundation does not allow -respondsToSelector:NULL
+
+       * NSObject+Reflection.m: added reflection for Apple runtime (required
+         by system.listMethods)
+
+       * NGXmlRpcRequestHandler.m: replaced some release macros
+
+2003-01-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpcIntrospection.m: added patch provided by Bjoern
+         (fixes SKYRiX bug 918)
+
+2003-01-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpc.m: fixed a bug (incorrect number of arguments
+         passed to a selector)
+
+2003-01-09  Helge Hess  <helge.hess@skyrix.com>
+       
+       * NGXmlRpcClient.m: started support for HTTP digest authentication
+         (v4.2.112)
+       
+Mon Dec 23 15:47:38 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpc.m: fixed a gcc 3.2 warning (v4.2.103)
+
+2002-10-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed the change below (v4.2.38) :-(
+
+       * NGXmlRpcAction+Registry.m: use -skyDictionaryWithContentsOfFile:
+         for parsing of property lists (so that comments work on OSX) 
+         (v4.2.37)
+
+2002-08-29  Helge Hess  <helge.hess@skyrix.com>
+       
+       * NGXmlRpcRequestHandler.m: small fix to make gcc 3.1 happy (v4.2.35)
+
+2002-07-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGXmlRpcAction.m: fixed a bug in auth handling (www-authenticate
+         header was not set, if access was denied)
+         - allow an action selector to have more arguments than the associated
+         signature (the remaining args are filled with nil ...)
+
+2002-06-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGXmlRpcAction+Registry.m: added a default to control the logging of
+         selector<->rpc-method mapping
+
+2002-06-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcMethodResponse+WO.m: changed back to use WOResponse
+         content encoding
+
+Wed Jun 19 18:53:49 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * XmlRpcMethodResponse+WO.m: changed default response
+         encoding to UTF-8 (was defaultCStringEncoding before)
+
+Fri May 10 15:29:14 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGXmlRpcAction.m: improved error handling
+
+       * NGXmlRpcClient.m: improved error handling
+
+Sun May  5 14:27:12 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved as a subproject to NGObjWeb
+
+Mon Apr 22 13:34:44 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: always build xmlrpc_call
+
+Fri Apr 12 14:35:30 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGXmlRpcAction.m: added ability to coredump if a fault is going
+         to be delivered
+
+Tue Apr  9 15:19:13 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * NGXmlRpcClient.m: fixed adding of authorization to headers
+         even if no username/password was set
+
+Fri Apr  5 15:20:47 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpc.m ([WODirectAction -selectorForXmlRpcAction:parameters:]): 
+         don't print warning if system.* methods are invoked
+
+Tue Mar 26 19:26:15 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * added xmlrpc_call tool
+
+Mon Mar 25 16:54:20 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NGXmlRpcRequestHandler, NGXmlRpcAction, NGAsyncResultProxy
+         from SkyDaemon
+
+Fri Mar 15 15:29:31 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcMethodResponse+WO.m: set content-type to text/xml
+
+Mon Mar 11 18:09:54 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcMethodResponse+WO.h: conforms to WOActionResults
+
+Tue Feb 26 18:27:37 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * WODirectAction+XmlRpcIntrospection.m: component namespace
+         is now added for all functions who are not introspection methods
+
+Thu Feb 14 11:09:19 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOFetchSpecification+XmlRpcCoding.m: use EOQualifier to decode
+         a property list  parameter
+
+Wed Feb 13 13:52:09 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved generic stuff to XML/XmlRpc
+
+Sat Feb  9 13:00:11 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcSaxHandler.m: added warning and error handlers ...
+
+       * XmlRpcDecoder.m: improved error output
+
+Fri Feb  8 17:35:05 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcDecoder.m: fixed charset problems
+
+       * WODirectAction+XmlRpcIntrospection.m: changed to return "string"
+         signature for object types
+
+Thu Feb  7 20:19:55 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpc.m: autogenerate SandStorm component name
+
+Wed Jan 30 18:16:31 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpcIntrospection.m: fixed bug with method names
+
+       * NGXmlRpcInvocation.m: convert types prior to call, if signature
+         is available
+
+Tue Jan 29 18:30:56 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NGXmlRpcInvocation, NGXmlRpcMethodSignature
+
+Mon Jan 28 18:46:34 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpc.m: improved reflection capabilities
+
+       * WODirectAction+XmlRpc.m: support a GET action for dynamic reflection
+
+       * WODirectAction+XmlRpc.m: added method to define component prefix
+
+Fri Jan 25 18:36:58 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpc.m: use RPC2 as action name ...
+
+       * added NGXmlRpcClient class
+
+Thu Jan 17 17:23:09 2002  Martin Spindler  <spindler@mdlink.de>
+
+       * NSObject+XmlRpc.m: raise exception if coding methods arn't supported
+
+Tue Nov 13 09:34:54 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOKeyGlobalID+XmlRpcCoding.m: removed unnecessary retain/autorelease
+
+Tue Nov 13 01:06:50 2001  Jan Reichmann  <jan@skyrix.com>
+
+       * EOKeyGlobalID+XmlRpcCoding.m: fixed decoding bug
+
+Wed Oct 24 13:23:54 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * XmlRpcSaxHandler.m: fixed multiple call of -characters:length:
+
+Mon Oct 22 20:53:33 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcEncoder.m: normalize NSString subclasses
+
+       * XmlRpcMethodResponse+WO.m: enabled UTF-8 for result encoding
+
+Wed Oct 10 19:42:17 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * XmlRpcEncoder.m: use -classForCoder instead of -class
+
+Tue Aug 28 15:38:05 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * changed 'timeZone' - tag into 'timeZone' - attribute
+
+       * support of 'timeZone' - tag (not xmlprc compatible!)
+
+       * XmlRpcCoder: added accessors for defaultTimeZone
+
+Mon Aug 27 10:47:03 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved SKYRiX Logic categories back to skyxmlrpcd
+
+Wed Aug 22 15:41:39 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcDecoder.m: decode dates as calendar-dates
+
+       * use ObjC base-types for decoding/encoding numbers
+
+       * NSDate+XmlRpcCoding.m: fixed NSTimeZone decoding
+
+       * NSArray+XmlRpcCoding.m: fixed NSEnumerator coding, fixed RC bugs
+
+Mon Aug 20 21:55:41 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * created ChangeLog
+
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/EOFetchSpecification+XmlRpcCoding.m b/skyrix-sope/NGObjWeb/NGXmlRpc/EOFetchSpecification+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..aa39e15
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <EOControl/EOFetchSpecification.h>
+#include <EOControl/EOSortOrdering.h>
+#include "common.h"
+#include <XmlRpc/XmlRpcCoder.h>
+#include <EOControl/EOQualifier.h>
+
+@implementation EOFetchSpecification(XmlRpcCoding)
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  if ((self = [super init])) {
+    id q;
+    
+    [self setUsesDistinct:[_coder decodeBooleanForKey:@"usesDistinct"]];
+    [self setLocksObjects:[_coder decodeBooleanForKey:@"locksObjects"]];
+    [self setEntityName:  [_coder decodeStringForKey:@"entityName"]];
+    [self setFetchLimit:  [_coder decodeIntForKey:@"fetchLimit"]];
+    [self setHints:       [_coder decodeStructForKey:@"hints"]];
+    
+    if ((q = [_coder decodeObjectForKey:@"qualifier"])) {
+      if ([q isKindOfClass:[EOQualifier class]])
+        /* already a qualifier :-) [ObjC on the other side ..] */
+        [q retain];
+      else {
+        q = [[EOQualifier alloc] initWithPropertyList:q owner:nil];
+      }
+    }
+    
+    [self setQualifier:q];
+    [self setSortOrderings:[_coder decodeObjectForKey:@"sortOrderings"]];
+    
+    [q release];
+  }
+  return self;
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeBoolean:[self usesDistinct] forKey:@"usesDistinct"];
+  [_coder encodeBoolean:[self locksObjects] forKey:@"locksObjects"];
+  [_coder encodeString:[self entityName]    forKey:@"entityName"];
+  [_coder encodeInt:[self fetchLimit]       forKey:@"fetchLimit"];
+  [_coder encodeStruct:[self hints]         forKey:@"hints"];
+  [_coder encodeObject:[self qualifier]     forKey:@"qualifier"];
+  [_coder encodeObject:[self sortOrderings] forKey:@"sortOrderings"];
+}
+
+@end /* EOFetchSpecification(XmlRpcCoding) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/EOKeyGlobalID+XmlRpcCoding.m b/skyrix-sope/NGObjWeb/NGXmlRpc/EOKeyGlobalID+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..b0b04d8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EOKeyGlobalID.h>
+#include "common.h"
+#include <XmlRpc/XmlRpcCoder.h>
+
+@implementation EOKeyGlobalID(XmlRpcCoding)
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  EOKeyGlobalID *globalID;
+  NSString      *name;
+  NSArray       *keyVals;
+  int           i, cnt;
+  id            *vals;
+
+  name    = [_coder decodeStringForKey:@"entityName"];
+  keyVals = [_coder decodeArrayForKey:@"keyValues"];
+  cnt     = [keyVals count];
+
+  vals = calloc(cnt, sizeof(id));
+  
+  for (i = 0; i < cnt; i++)
+    vals[i] = [keyVals objectAtIndex:i];
+  
+  globalID = [EOKeyGlobalID globalIDWithEntityName:name
+                            keys:vals
+                            keyCount:cnt
+                            zone:[self zone]];
+
+  free(vals); vals = NULL;
+  
+  RELEASE(self);
+  return [globalID retain];
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeString:[self entityName]    forKey:@"entityName"];
+  [_coder encodeArray:[self keyValuesArray] forKey:@"keyValues"];
+}
+
+@end /* EOKeyGlobalID(XmlRpcCoding) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/EONull+XmlRpcCoding.m b/skyrix-sope/NGObjWeb/NGXmlRpc/EONull+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..6e34361
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EONull.h>
+#include "common.h"
+#include <XmlRpc/XmlRpcCoder.h>
+
+@implementation EONull(XmlRpcCoding)
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [[NSNull null] retain];
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeString:@""];
+}
+
+@end /* EONull(XmlRpcCoding) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/EOQualifier+XmlRpcCoding.m b/skyrix-sope/NGObjWeb/NGXmlRpc/EOQualifier+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..c74c511
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EOQualifier.h>
+#include "common.h"
+#include <XmlRpc/XmlRpcCoder.h>
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (void)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+@implementation EOQualifier(XmlRpcCoding)
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  // TODO: hh asks: whats that ?
+  return [self init];
+}
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [self subclassResponsibility:_cmd];
+}
+
+@end /* EOQualifier */
+
+@implementation EOAndQualifier(XmlRpcCoding)
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  NSArray *quals = [_coder decodeArrayForKey:@"qualifiers"];
+  
+  return [self initWithQualifierArray:quals];
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeArray:[self qualifiers] forKey:@"qualifiers"];
+}
+
+@end /* EOAndQualifier(XmlRpcCoding) */
+
+@implementation EOOrQualifier(XmlRpcCoding)
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  NSArray *quals = [_coder decodeArrayForKey:@"qualifiers"];
+  
+  return [self initWithQualifierArray:quals];
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeArray:[self qualifiers] forKey:@"qualifiers"];
+}
+
+@end /* EOOrQualifier(XmlRpcCoding) */
+
+@implementation EONotQualifier(XmlRpcCoding)
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [self initWithQualifier:[_coder decodeObject]];
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeObject:[self qualifier]];
+}
+
+@end /* EONotQualifier(XmlRpcCoding) */
+
+@implementation EOKeyValueQualifier(XmlRpcCoding)
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  NSString *k  = nil;
+  id       val = nil;
+  SEL      sel = NULL;
+
+  k = [_coder decodeStringForKey:@"selector"];
+  if (k) sel = NSSelectorFromString(k);
+  val = [_coder decodeObjectForKey:@"value"];
+  k   = [_coder decodeStringForKey:@"key"];
+  
+  return [self initWithKey:k operatorSelector:sel value:val];
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeString:[self key]   forKey:@"key"];
+  [_coder encodeObject:[self value] forKey:@"value"];
+  [_coder encodeString:NSStringFromSelector([self selector])
+          forKey:@"selector"];
+}
+
+@end /* EOKeyValueQualifier(XmlRpcCoding) */
+
+@implementation EOKeyComparisonQualifier(XmlRpcCoding)
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  NSString *lKey = nil;
+  NSString *rKey = nil;
+  SEL      sel   = NULL;
+
+  lKey = [_coder decodeStringForKey:@"selector"];
+  if (lKey) sel = NSSelectorFromString(lKey);
+  lKey = [_coder decodeObjectForKey:@"leftKey"];
+  rKey = [_coder decodeStringForKey:@"rightKey"];
+  
+  return [self initWithLeftKey:lKey operatorSelector:sel rightKey:rKey];
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeString:[self leftKey]  forKey:@"leftKey"];
+  [_coder encodeObject:[self rightKey] forKey:@"rightKey"];
+  [_coder encodeString:NSStringFromSelector([self selector])
+          forKey:@"selector"];
+}
+
+@end /* EOKeyComparisonQualifier(XmlRpcCoding) */
+
+@implementation EOQualifierVariable(XmlRpcCoding)
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [self initWithKey:[_coder decodeString]];
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeString:[self key]];
+}
+
+@end /* EOQualifierVariable(XmlRpcCoding) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/EOSortOrdering+XmlRpcCoding.m b/skyrix-sope/NGObjWeb/NGXmlRpc/EOSortOrdering+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..836e48d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <EOControl/EOSortOrdering.h>
+#include "common.h"
+#include <XmlRpc/XmlRpcCoder.h>
+
+@implementation EOSortOrdering(XmlRpcCoding)
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  NSString *k = nil;
+  SEL      sel  = NULL;
+
+  k = [_coder decodeStringForKey:@"selector"];
+  if (k) sel = NSSelectorFromString(k);
+  k = [_coder decodeStringForKey:@"key"];
+  
+  return [self initWithKey:k selector:sel];
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeString:[self key] forKey:@"key"];
+  [_coder encodeString:NSStringFromSelector([self selector])
+                forKey:@"selector"];
+}
+
+@end /* EOSortOrdering(XmlRpcCoding) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/GNUmakefile b/skyrix-sope/NGObjWeb/NGXmlRpc/GNUmakefile
new file mode 100644 (file)
index 0000000..087aff7
--- /dev/null
@@ -0,0 +1,48 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = NGXmlRpc
+
+NGXmlRpc_HEADER_FILES_DIR         = .
+NGXmlRpc_HEADER_FILES_INSTALL_DIR = /NGXmlRpc
+
+NGXmlRpc_HEADER_FILES = \
+       NGAsyncResultProxy.h                    \
+       NGXmlRpc.h                              \
+       NGXmlRpcAction.h                        \
+       NGXmlRpcClient.h                        \
+       NGXmlRpcInvocation.h                    \
+       NGXmlRpcMethodSignature.h               \
+       NGXmlRpcRequestHandler.h                \
+       NSObject+Reflection.h                   \
+       WODirectAction+XmlRpc.h                 \
+       WODirectAction+XmlRpcIntrospection.h    \
+       XmlRpcMethodCall+WO.h                   \
+       XmlRpcMethodResponse+WO.h               \
+
+NGXmlRpc_OBJC_FILES = \
+       EOFetchSpecification+XmlRpcCoding.m     \
+       EOKeyGlobalID+XmlRpcCoding.m            \
+       EONull+XmlRpcCoding.m                   \
+       EOQualifier+XmlRpcCoding.m              \
+       EOSortOrdering+XmlRpcCoding.m           \
+       NGAsyncResultProxy.m                    \
+       NGXmlRpcAction.m                        \
+       NGXmlRpcClient.m                        \
+       NGXmlRpcInvocation.m                    \
+       NGXmlRpcMethodSignature.m               \
+       NGXmlRpcRequestHandler.m                \
+       NSObject+Reflection.m                   \
+       WODirectAction+XmlRpc.m                 \
+       WODirectAction+XmlRpcIntrospection.m    \
+       WOMessage+XmlRpcCoding.m                \
+       WORequest+XmlRpcCoding.m                \
+       WOResponse+XmlRpcCoding.m               \
+       XmlRpcMethodCall+WO.m                   \
+       XmlRpcMethodResponse+WO.m               \
+       NGXmlRpcAction+Registry.m               \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/GNUmakefile.preamble b/skyrix-sope/NGObjWeb/NGXmlRpc/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..367108b
--- /dev/null
@@ -0,0 +1,13 @@
+# $Id$
+
+ADDITIONAL_CPPFLAGS += -pipe 
+
+ADDITIONAL_CPPFLAGS += -pipe -Wall
+ADDITIONAL_CPPFLAGS += -DCOMPILING_NGOBJWEB=1
+
+NGXmlRpc_INCLUDE_DIRS += \
+       -I.. -I. -I../..        \
+       -I../../../skyrix-core                  \
+       -I../../../skyrix-core/NGStreams        \
+       -I../../../skyrix-core/NGExtensions     \
+       -I../../../skyrix-xml
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGAsyncResultProxy.h b/skyrix-sope/NGObjWeb/NGXmlRpc/NGAsyncResultProxy.h
new file mode 100644 (file)
index 0000000..9bcefb4
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGXmlRpc_AsyncResultProxy_H__
+#define __NGXmlRpc_AsyncResultProxy_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSException, NSMutableArray, NSString, NSMutableArray;
+
+@interface NGAsyncResultProxy : NSObject
+{
+  BOOL           isReady;
+  id             result;
+  id             target;
+  SEL            action;
+  NSString       *token;       /* response token for NGObjWeb */
+  NSMutableArray *keptObjects; /* keep RC for those objects   */
+}
+
+- (BOOL)isReady;
+- (id)result;
+
+- (void)postResult:(id)_result;
+- (void)postFaultResult:(NSException *)_result;
+
+- (void)setTarget:(id)_target;
+- (id)target;
+- (void)setAction:(SEL)_action;
+- (SEL)action;
+
+- (void)setToken:(NSString *)_token;
+- (NSString *)token;
+
+- (void)becameReady; /* for subclasses to cleanup */
+
+- (void)retainObject:(id)_object;
+- (void)releaseObject:(id)_object;
+
+@end
+
+#endif /* __SkyDaemon_AsyncResultProxy_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGAsyncResultProxy.m b/skyrix-sope/NGObjWeb/NGXmlRpc/NGAsyncResultProxy.m
new file mode 100644 (file)
index 0000000..a06f122
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGXmlRpc/NGAsyncResultProxy.h>
+#include "common.h"
+
+@implementation NGAsyncResultProxy
+
+- (void)dealloc {
+  [self->token  release];
+  [self->target release];
+  [self->result release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (BOOL)isReady {
+  return self->isReady;
+}
+- (id)result {
+  return self->result;
+}
+
+- (void)setTarget:(id)_target {
+  ASSIGN(self->target, _target);
+}
+- (id)target {
+  return self->target;
+}
+- (void)setAction:(SEL)_action {
+  self->action = _action;
+}
+- (SEL)action {
+  return self->action;
+}
+
+- (void)setToken:(NSString *)_token {
+  ASSIGN(self->token, _token);
+}
+- (NSString *)token {
+  return self->token;
+}
+
+- (void)becameReady {
+  AUTORELEASE(self->keptObjects);
+  self->keptObjects = nil;
+
+  AUTORELEASE(RETAIN(self));
+  [self->target performSelector:self->action withObject:self];
+}
+
+- (void)postResult:(id)_result {
+  //[self logWithFormat:@"post result: %@", _result];
+  self->isReady = YES;
+  ASSIGN(self->result, _result);
+  [self becameReady];
+}
+- (void)postFaultResult:(NSException *)_result {
+  //[self logWithFormat:@"post fault result: %@", _result];
+  ASSIGN(self->result, _result);
+  self->isReady = YES;
+  [self becameReady];
+}
+
+- (void)retainObject:(id)_object {
+  if (self->keptObjects == nil)
+    self->keptObjects = [[NSMutableArray alloc] initWithCapacity:4];
+  [self->keptObjects addObject:_object];
+}
+- (void)releaseObject:(id)_object {
+  [[_object retain] autorelease];
+  [self->keptObjects removeObjectIdenticalTo:_object];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if ([self isReady])
+    [ms appendFormat:@" ready=%@", self->result];
+  else
+    [ms appendString:@" pending"];
+  
+  [ms appendFormat:@" token=%@", self->token];
+  [ms appendFormat:@" target=%@", self->target];
+  
+  if ([self->keptObjects count] > 0)
+    [ms appendFormat:@" keeping=%@", self->keptObjects];
+  
+  [ms appendString:@">"];
+  
+  return ms;
+}
+
+@end /* NGAsyncResultProxy */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpc-Info.plist b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpc-Info.plist
new file mode 100644 (file)
index 0000000..59dd833
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGXmlRpc</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.NGXmlRpc</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpc.h b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpc.h
new file mode 100644 (file)
index 0000000..00b6329
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGXmlRpc_H__
+#define __NGXmlRpc_H__
+
+#include <XmlRpc/XmlRpc.h>
+#include <NGXmlRpc/XmlRpcMethodCall+WO.h>
+#include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
+
+#include <NGXmlRpc/NGXmlRpcRequestHandler.h>
+#include <NGXmlRpc/NGXmlRpcAction.h>
+#include <NGXmlRpc/NGAsyncResultProxy.h>
+
+#endif /* __NGXmlRpc_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcAction+Registry.m b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcAction+Registry.m
new file mode 100644 (file)
index 0000000..bc016bc
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGXmlRpc/NGXmlRpcAction.h>
+#include "common.h"
+
+@interface NGXmlRpcActionSelMapping : NSObject
+{
+  NSMutableArray *signatures;
+  NSMutableArray *selectors;
+  unsigned count;
+}
+
+- (void)registerSelector:(SEL)_sel forSignature:(NSArray *)_signature;
+- (SEL)selectorForSignature:(NSArray *)_signature;
+- (NSArray *)signatures;
+
+@end
+
+@implementation NGXmlRpcActionSelMapping
+
+static int logSelMapping = -1;
+
+- (id)init {
+  if (logSelMapping == -1) {
+    logSelMapping = [[NSUserDefaults standardUserDefaults]
+                     boolForKey:@"WOLogXmlRpcSelectorMapping"]
+      ? 1 : 0;
+  }
+
+  self->signatures = [[NSMutableArray alloc] initWithCapacity:2];
+  self->selectors  = [[NSMutableArray alloc] initWithCapacity:2];
+  return self;
+}
+- (void)dealloc {
+  RELEASE(self->selectors);
+  RELEASE(self->signatures);
+  [super dealloc];
+}
+
+- (void)registerSelector:(SEL)_sel forSignature:(NSArray *)_signature {
+  [self->signatures addObject:_signature];
+  [self->selectors  addObject:NSStringFromSelector(_sel)];
+  self->count++;
+}
+
+- (BOOL)signature:(NSArray *)_base matches:(NSArray *)_query {
+  unsigned bc, qc;
+  
+  bc = [_base  count];
+  qc = [_query count];
+  if (bc != qc) return NO;
+  /* should check further */
+  return YES;
+}
+- (SEL)selectorForSignature:(NSArray *)_signature {
+  unsigned i;
+  
+  for (i = 0; i < self->count; i++) {
+    NSArray *sig;
+    
+    sig = [self->signatures objectAtIndex:i];
+    if ([self signature:sig matches:_signature])
+      return NSSelectorFromString([self->selectors objectAtIndex:i]);
+  }
+#if DEBUG
+  if (self->count > 0) {
+    [self debugWithFormat:
+            @"found no signature matching argcount %i, signatures: %@, got: %@",
+            ([_signature count] - 1),
+            self->signatures, _signature];
+  }
+#endif
+  return NULL;
+}
+- (NSArray *)signatures {
+  return self->signatures;
+}
+
+@end /* NGXmlRpcActionSelMapping */
+
+@implementation NGXmlRpcAction(Registry)
+
+/* class registry */
+
+static NSMutableDictionary *uriToClass = nil;
+static NSMutableDictionary *classToMethodDict = nil;
+
++ (void)registerActionClass:(Class)_class forURI:(NSString *)_uri {
+  [(id<NSObject>)_class self]; /* ensure initialize */
+  if (uriToClass == nil)
+    uriToClass = [[NSMutableDictionary alloc] initWithCapacity:4];
+  [uriToClass setObject:_class forKey:_uri];
+  
+  NSLog(@"%s: mapped uri '%@' to class %@", __PRETTY_FUNCTION__,
+        _uri, NSStringFromClass(_class));
+}
++ (Class)actionClassForURI:(NSString *)_uri {
+  return [uriToClass objectForKey:_uri];
+}
+
++ (void)registerSelector:(SEL)_selector
+  forMethodNamed:(NSString *)_method
+  signature:(id)_signature
+{
+  NSMutableDictionary      *md;
+  NGXmlRpcActionSelMapping *methodInfo;
+
+  if (![_signature isKindOfClass:[NSArray class]])
+    _signature = [[_signature stringValue] componentsSeparatedByString:@","];
+  
+  if (classToMethodDict == nil)
+    classToMethodDict = [[NSMutableDictionary alloc] initWithCapacity:4];
+  
+  if ((md = [classToMethodDict objectForKey:self]) == nil) {
+    md = [[NSMutableDictionary alloc] initWithCapacity:16];
+    [classToMethodDict setObject:md forKey:self];
+    RELEASE(md);
+  }
+
+  if ((methodInfo = [md objectForKey:_method]) == nil) {
+    methodInfo = [[NGXmlRpcActionSelMapping alloc] init];
+    [md setObject:methodInfo forKey:_method];
+    RELEASE(methodInfo);
+  }
+  
+  [methodInfo registerSelector:_selector forSignature:_signature];
+  
+  if (logSelMapping) {
+    NSLog(@"%@: registered selector %@ for method %@ %@",
+         NSStringFromClass(self),
+         NSStringFromSelector(_selector),
+         _method,
+         [_signature componentsJoinedByString:@","]);
+  }
+}
++ (SEL)selectorForActionNamed:(NSString *)_name
+  signature:(NSArray *)_signature
+{
+  NSMutableDictionary      *methodDict;
+  NGXmlRpcActionSelMapping *methodInfo;
+  
+  if ((methodDict = [classToMethodDict objectForKey:self]) == nil)
+    /* nothing registered */
+    return NULL;
+  
+  if ((methodInfo = [methodDict objectForKey:_name]) == nil)
+    /* no action with that name is registered */
+    return NULL;
+  
+  return [methodInfo selectorForSignature:_signature];
+}
+
++ (NSArray *)registeredMethodNames {
+  NSMutableDictionary *methodDict;
+  
+  if ((methodDict = [classToMethodDict objectForKey:self]) == nil)
+    /* nothing registered */
+    return nil;
+  return [methodDict allKeys];
+}
++ (NSArray *)signaturesForMethodNamed:(NSString *)_name {
+  NSMutableDictionary      *methodDict;
+  NGXmlRpcActionSelMapping *methodInfo;
+  
+  if ((methodDict = [classToMethodDict objectForKey:self]) == nil)
+    /* nothing registered */
+    return NULL;
+  
+  if ((methodInfo = [methodDict objectForKey:_name]) == nil)
+    /* no action with that name is registered */
+    return NULL;
+  
+  return [methodInfo signatures];
+}
+
+/* mapping files */
+
++ (BOOL)registerSystemMethods {
+  if ([self instancesRespondToSelector:@selector(system_listMethodsAction)]) {
+    [self registerSelector:@selector(system_listMethodsAction)
+          forMethodNamed:@"system.listMethods"
+          signature:[NSArray arrayWithObject:@"array"]];
+  }
+  else {
+    NSLog(@"WARNING(%s): class does not have a listMethods action !",
+          __PRETTY_FUNCTION__);
+  }
+  if ([self instancesRespondToSelector:
+              @selector(system_methodSignatureAction:)]) {
+    [self registerSelector:@selector(system_methodSignatureAction:)
+          forMethodNamed:@"system.methodSignature"
+          signature:[NSArray arrayWithObjects:@"array", @"string", nil]];
+  }
+  if ([self instancesRespondToSelector:
+              @selector(system_methodHelpAction:)]) {
+    [self registerSelector:@selector(system_methodHelpAction:)
+          forMethodNamed:@"system.methodHelp"
+          signature:[NSArray arrayWithObjects:@"string", @"string", nil]];
+  }
+  return YES;
+}
+
++ (BOOL)registerMappingsInFile:(NSString *)_path {
+  NSString     *path;
+  NSDictionary *cfg;
+  NSEnumerator *keys;
+  NSString     *methodName;
+  
+  if (![_path isAbsolutePath]) {
+    NSBundle *b;
+    
+    b = [NSBundle bundleForClass:self];
+    if ((path = [b pathForResource:_path ofType:@"plist"]) == nil)
+      path = _path;
+  }
+  else
+    path = _path;
+  
+  NSLog(@"%s: register mappings in file %@", __PRETTY_FUNCTION__, path);
+  
+  if ((cfg = [NSDictionary dictionaryWithContentsOfFile:path]) == nil) {
+    NSLog(@"%s:   could not load file %@", __PRETTY_FUNCTION__, path);
+    return NO;
+  }
+  
+  if (![self registerSystemMethods])
+    return NO;
+  
+  keys = [cfg keyEnumerator];
+  while ((methodName = [keys nextObject])) {
+    NSDictionary *mi;
+    NSEnumerator *sigs;
+    NSArray      *sig;
+    
+    if ([methodName hasPrefix:@"__"])
+      continue;
+    
+    mi = [cfg objectForKey:methodName];
+    if (![mi respondsToSelector:@selector(keyEnumerator)]) {
+      [self logWithFormat:@"entry '%@' in mapping file is no dictionary, skipping: %@", methodName, mi];
+      continue;
+    }
+    
+    sigs = [mi keyEnumerator];
+    while ((sig = [sigs nextObject])) {
+      NSString *selName;
+      SEL sel;
+      
+      selName = [mi objectForKey:sig];
+      
+      if ((sel = NSSelectorFromString(selName)) == NULL) {
+        NSLog(@"%s:  did not find selector '%@'", __PRETTY_FUNCTION__,
+              selName);
+        continue;
+      }
+      
+      if (![self instancesRespondToSelector:sel]) {
+        NSLog(@"WARNING(%s):  instances of %@ do not respond to selector '%@'",
+              __PRETTY_FUNCTION__, NSStringFromClass(self),
+              selName);
+      }
+      
+      [self registerSelector:sel
+            forMethodNamed:methodName
+            signature:sig];
+    }
+  }
+  return YES;
+}
+
+@end /* NGXmlRpcAction(Registry) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcAction.h b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcAction.h
new file mode 100644 (file)
index 0000000..d552f4f
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGXmlRpc_NGXmlRpcAction_H__
+#define __NGXmlRpc_NGXmlRpcAction_H__
+
+#import <Foundation/NSObject.h>
+#import <NGObjWeb/WOActionResults.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGXmlRpc/WODirectAction+XmlRpc.h>
+
+@class NSArray, NSString, NSException;
+@class XmlRpcMethodCall;
+@class NGAsyncResultProxy;
+@class WORequest;
+
+@interface NGXmlRpcAction : NSObject
+{
+@protected
+  WOContext *context;
+}
+
+/* initializer */
+
+- (id)initWithContext:(WOContext *)_context;
+
+/* accessors */
+
+- (id)application;
+- (WORequest *)request;
+- (id)session;
+- (id)existingSession;
+
+/* notifications */
+
+- (void)awake;
+- (void)sleep;
+
+/* sandstorm components */
+
+- (NSString *)xmlrpcComponentNamespacePrefix;
+- (NSString *)xmlrpcComponentName;
+- (NSString *)xmlrpcComponentNamespace;
+
+/* XML-RPC direct action dispatcher ... */
+
+- (id)performActionNamed:(NSString *)_name parameters:(NSArray *)_params;
+- (id<WOActionResults>)performMethodCall:(XmlRpcMethodCall *)_call;
+
+- (id<WOActionResults>)missingAuthAction;
+- (id<WOActionResults>)accessDeniedAction;
+
+- (id<WOActionResults>)actionResponseForResult:(id)resValue;
+
+/* async operation*/
+
+- (WOResponse *)responseForAsyncResult:(NGAsyncResultProxy *)_proxy;
+
+/* command context */
+
+- (BOOL)hasAuthorizationHeader;
+- (NSString *)credentials;
+
+@end
+
+@interface NGXmlRpcAction(Registry)
+
+/* class registry */
+
++ (void)registerActionClass:(Class)_class forURI:(NSString *)_uri;
++ (Class)actionClassForURI:(NSString *)_uri;
+
+/* action registry */
+
++ (BOOL)registerMappingsInFile:(NSString *)_path;
+
++ (void)registerSelector:(SEL)_selector
+  forMethodNamed:(NSString *)_method
+  signature:(id)_signature; /* either array or CSV */
+
++ (SEL)selectorForActionNamed:(NSString *)_name
+  signature:(NSArray *)_signature;
+
++ (NSArray *)registeredMethodNames; /* can be used for listMethods */
++ (NSArray *)signaturesForMethodNamed:(NSString *)_method;
++ (NSArray *)registeredMethodNames;
+
+@end
+
+@interface WOApplication(XmlRpcActionClass)
+
+- (Class)defaultActionClassForRequest:(WORequest *)_request;
+
+@end
+
+#endif /* __NGXmlRpc_NGXmlRpcAction_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcAction.m b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcAction.m
new file mode 100644 (file)
index 0000000..5a38954
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGXmlRpc/NGXmlRpcAction.h>
+#include <NGXmlRpc/NGAsyncResultProxy.h>
+#include <NGXmlRpc/NGXmlRpc.h>
+#include <NGXmlRpc/XmlRpcMethodCall+WO.h>
+#include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+
+@implementation WOCoreApplication(XmlRpcActionClass)
+
+- (Class)defaultActionClassForRequest:(WORequest *)_request {
+  return NSClassFromString(@"DirectAction");
+}
+
+@end
+
+@implementation NGXmlRpcAction
+
++ (int)version {
+  return 1;
+}
+
++ (BOOL)coreOnFault {
+#if DEBUG
+  return [[NSUserDefaults standardUserDefaults] 
+                         boolForKey:@"WOCoreOnXmlRpcFault"];
+#else
+  return NO;
+#endif
+}
+
+/* initialization */
+
+- (id)initWithContext:(WOContext *)_ctx {
+  if ((self = [super init])) {
+    self->context = RETAIN(_ctx);
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithContext:nil];
+}
+
+- (void)dealloc {
+  RELEASE(self->context);
+  [super dealloc];
+}
+
+/* sandstorm components */
+
+- (NSString *)xmlrpcComponentNamespacePrefix {
+  NSString *np;
+  
+  np = [[NSUserDefaults standardUserDefaults]
+                        stringForKey:@"SxDefaultNamespacePrefix"];
+  if ([np length] > 0)
+    return np;
+
+  [self logWithFormat:
+          @"WARNING: SxDefaultNamespacePrefix default is not set !"];
+  
+  np = [(NSHost *)[NSHost currentHost] name];
+  if ([np length] > 0) {
+    if (!isdigit([np characterAtIndex:0])) {
+      NSArray *parts;
+
+      parts = [np componentsSeparatedByString:@"."];
+      if ([parts count] == 0) {
+      }
+      else if ([parts count] == 1)
+        return [parts objectAtIndex:0];
+      else {
+        NSEnumerator *e;
+        BOOL     isFirst = YES;
+        NSString *s;
+        
+        e = [parts reverseObjectEnumerator];
+        while ((s = [e nextObject])) {
+          if (isFirst) {
+            isFirst = NO;
+            np = s;
+          }
+          else {
+            np = [[np stringByAppendingString:@"."] stringByAppendingString:s];
+          }
+        }
+        return np;
+      }
+    }
+  }
+  
+  return @"com.skyrix";
+}
+- (NSString *)xmlrpcComponentName {
+  NSString *s;
+
+  s = NSStringFromClass([self class]);
+  if (![s isEqualToString:@"DirectAction"])
+    return s;
+  
+  return [[NSProcessInfo processInfo] processName];
+}
+
+- (NSString *)xmlrpcComponentNamespace {
+  NSString *ns, *n;
+  
+  ns = [self xmlrpcComponentNamespacePrefix];
+  n  = [self xmlrpcComponentName];
+  return [[ns stringByAppendingString:@"."] stringByAppendingString:n];
+}
+
+/* notifications */
+
+- (void)awake {
+}
+- (void)sleep {
+}
+
+- (id)application {
+  return [WOCoreApplication application];
+}
+
+- (NSNotificationCenter *)notificationCenter {
+  return [NSNotificationCenter defaultCenter];
+}
+
+- (WOContext *)context {
+  if (self->context == nil)
+    self->context = RETAIN([[WOApplication application] context]);
+  return self->context;
+}
+
+- (WORequest *)request {
+  return [[self context] request];
+}
+
+- (WOSession *)session {
+  return [[self context] session];
+}
+
+- (WOSession *)existingSession {
+  WOContext *ctx = [self context];
+  
+  /* check whether the context has a session */
+  
+  return [ctx hasSession] ? [ctx session] : nil;
+}
+
+/* XML-RPC direct action dispatcher ... */
+
+- (NSString *)authRealm {
+  WOApplication *app = [self application];
+  return [app name];
+}
+
+- (id<WOActionResults>)missingAuthAction {
+  WOResponse *resp;
+  NSString *auth;
+
+  auth = [NSString stringWithFormat:@"basic realm=\"%@\"",[self authRealm]];
+  
+  resp = [(WOResponse *)[WOResponse alloc] initWithRequest:[self request]];
+  [resp setStatus:401 /* unauthorized */];
+  [resp setHeader:auth forKey:@"www-authenticate"];
+  // TODO: should embed an XML-RPC fault representing the auth-problem
+  return [resp autorelease];
+}
+- (id<WOActionResults>)accessDeniedAction {
+  WOResponse *resp;
+  NSString *auth;
+  
+  auth = [NSString stringWithFormat:@"basic realm=\"%@\"",[self authRealm]];
+  
+  [self logWithFormat:@"access was denied"];
+  
+  resp = [(WOResponse *)[WOResponse alloc] initWithRequest:[self request]];
+  [resp setStatus:401 /* unauthorized */];
+  [resp setHeader:auth forKey:@"www-authenticate"];
+  // TODO: should embed an XML-RPC fault representing the auth-problem
+  return [resp autorelease];
+}
+
+- (id<WOActionResults>)actionResponseForResult:(id)resValue {
+  if ([resValue isKindOfClass:[NGAsyncResultProxy class]]) {
+    /* async result ... */
+    return [self responseForAsyncResult:resValue];
+  }
+  else if ([resValue conformsToProtocol:@protocol(WOActionResults)]) {
+    /* a "HTTP" result ... */
+    return resValue;
+  }
+  else {
+    /* an XML-RPC result ... */
+    XmlRpcMethodResponse *mResponse;
+    
+    mResponse = [[[XmlRpcMethodResponse alloc]
+                                        initWithResult:resValue]
+                                        autorelease];
+    return mResponse;
+  }
+}
+
+- (void)proxyReady:(NGAsyncResultProxy *)_sender {
+  id<WOActionResults> ares;
+  WOResponse *r;
+  
+  AUTORELEASE(RETAIN(self)); /* keep me around ;-) */
+  
+  //[self debugWithFormat:@"ready: %@", _sender];
+  
+  [_sender setTarget:nil];
+  [_sender setAction:NULL];
+  
+  ares = [self actionResponseForResult:[_sender result]];
+  //[self debugWithFormat:@"  result: %@", ares];
+
+  r = [ares generateResponse];
+  //[self debugWithFormat:@"  response: %@", r];
+
+  [[self notificationCenter]
+         postNotificationName:@"WOAsyncResponseReadyNotification"
+         object:[_sender token]
+         userInfo:[NSDictionary dictionaryWithObject:r
+                                forKey:@"WOAsyncResponse"]];
+}
+
+- (WOResponse *)responseForAsyncResult:(NGAsyncResultProxy *)_proxy {
+  static int cnt = 0;
+  NSString   *token;
+  WOResponse *r;
+  NSDictionary *ui;
+
+  //[self debugWithFormat:@"shall create async result for proxy:\n  %@", _proxy];
+  
+  token = [NSString stringWithFormat:@"0x%08X-%i", _proxy, cnt++];
+  //[self debugWithFormat:@"token: %@", token];
+  ui = [NSDictionary dictionaryWithObject:token
+                     forKey:@"WOAsyncResponseToken"];
+  
+  r = [WOResponse responseWithRequest:[self request]];
+  [r setStatus:20001 /* async response */];
+  [r setUserInfo:ui];
+  
+  /* map token to result proxy ... */
+  [_proxy setTarget:self];
+  [_proxy setAction:@selector(proxyReady:)];
+  [_proxy setToken:token];
+  
+  return r;
+}
+
+- (id)faultFromException:(NSException *)_exception
+  methodCall:(XmlRpcMethodCall *)_call
+{
+  /* add some more information to generic exceptions ... */
+  if (_call) {
+    NSMutableDictionary *ui;
+    
+    ui = [[_exception userInfo] mutableCopy];
+    if (ui == nil) ui = [[NSMutableDictionary alloc] init];
+    
+    [ui setObject:[_call methodName] forKey:@"methodName"];
+    [ui setObject:[_call parameters] forKey:@"methodParameters"];
+    
+    [_exception setUserInfo:ui];
+    RELEASE(ui);
+  }
+
+  [self logWithFormat:@"%s: turning exception into fault %@\n",
+          __PRETTY_FUNCTION__,
+          [_exception description]];
+
+  if ([[self class] coreOnFault])
+    abort();
+  
+  return _exception;
+}
+- (id)faultFromException:(NSException *)_exception {
+  return [self faultFromException:_exception methodCall:nil];
+}
+
+- (NSArray *)signatureForParameters:(NSArray *)_params {
+  NSMutableArray *ma;
+  unsigned count, i;
+  
+  if ((count = [_params count]) == 0)
+    return [NSArray arrayWithObject:@"*"];
+  
+  ma = [NSMutableArray arrayWithCapacity:(count + 1)];
+  [ma addObject:@"*"]; // return type, unknown from request ...
+  for (i = 0; i < count; i++)
+    [ma addObject:[[_params objectAtIndex:i] xmlRpcType]];
+  return ma;
+}
+- (SEL)selectorForXmlRpcAction:(NSString *)_name
+  parameters:(NSArray *)_params
+{
+  NSArray *sig = nil;
+
+  if ((sig = [self signatureForParameters:_params]) == nil)
+    [self logWithFormat:@"found not signature for params ..."];
+  
+  return [[self class] selectorForActionNamed:_name
+                       signature:sig];
+}
+
+- (NSString *)_methodNameWithoutPrefix:(NSString *)_name {
+  NSString *n;
+  int len;
+
+  if ((n = [self xmlrpcComponentNamespacePrefix]) == nil)
+    return _name;
+  if ((len = [n length]) == 0)
+    return _name;
+  if (![_name hasPrefix:n])
+    return _name;
+  
+  n = _name;
+  _name = [_name substringFromIndex:len];
+  if ([_name hasPrefix:@"."])
+    _name = [_name substringFromIndex:1];
+  return _name;
+}
+
+- (id)performActionNamed:(NSString *)_name parameters:(NSArray *)_params {
+  NSMethodSignature *sign;
+  NSInvocation      *invo;
+  id       result = nil;
+  SEL      sel;
+  int      i, cnt;
+  NSString *n;
+  
+  n = _name;
+  _name = [self _methodNameWithoutPrefix:_name];
+  
+  /* generate selector */
+  if ((sel = [self selectorForXmlRpcAction:_name parameters:_params]) ==NULL) {
+    /* return a fault .. */
+    NSString     *r;
+    NSDictionary *ui;
+    
+    [self debugWithFormat:@"found no selector for XML-RPC action %@", _name];
+    
+    ui = nil;
+    r = [NSString stringWithFormat:
+                    @"found no XML-RPC method named '%@' "
+                    @"(%i parameters, component=%@)",
+                    n, [_params count], [self xmlrpcComponentNamespace]];
+    
+    return [NSException exceptionWithName:@"NoSuchXmlRpcMethod"
+                        reason:r
+                        userInfo:ui];
+  }
+  
+  sign = [[self class] instanceMethodSignatureForSelector:sel];
+  invo = [NSInvocation invocationWithMethodSignature:sign];
+  [invo setSelector:sel];
+  [invo setTarget:self];
+  
+  /* more arguments may be passed than supported by the method .. */
+  cnt = [sign numberOfArguments] - 2;
+  cnt = (cnt > (int)[_params count]) ? (int)[_params count] : cnt;
+  for (i = 0; i < cnt; i++) {
+    id param = [_params objectAtIndex:i];
+    /* 
+       TODO: bjoern
+       is this correct ? shouldnt that break, because the address of
+       param is always the same (who says, that NSInvocation copies the
+       values ???)
+    */
+    [invo setArgument:&param atIndex:(i + 2)];
+  }
+  
+  /* fill additional selector values with nil ... */
+  if (cnt < ((int)[sign numberOfArguments] - 2)) {
+    static id nilValue = nil;
+    unsigned int oldCnt = cnt;
+    
+    for (i = oldCnt, cnt = ([sign numberOfArguments] - 2); i < cnt; i++)
+      [invo setArgument:&nilValue atIndex:(i + 2)];
+  }
+  
+  [invo invoke];
+  [invo getReturnValue:&result];
+  
+  return result;
+}
+- (id<WOActionResults>)performMethodCall:(XmlRpcMethodCall *)_call {
+  id resValue;
+  
+  NS_DURING {
+    resValue = [self performActionNamed:[_call methodName]
+                     parameters:[_call parameters]];
+    resValue = [resValue retain];
+  }
+  NS_HANDLER {
+    resValue = [self faultFromException:localException
+                     methodCall:_call];
+    if ([[self class] coreOnFault])
+      abort();
+    resValue = [resValue retain];
+  }
+  NS_ENDHANDLER;
+  
+  resValue = [resValue autorelease];
+  
+  if ([[self class] coreOnFault]) {
+    if ([resValue isKindOfClass:[NSException class]]) {
+      abort();
+    }
+  }
+  return [self actionResponseForResult:resValue];
+}
+
+/* command context */
+
+- (BOOL)hasAuthorizationHeader {
+  WORequest *rq;
+  NSString  *cred;
+  
+  if ((rq = [self request]) == nil)
+    return NO;
+
+  if ((cred = [rq headerForKey:@"authorization"]) == nil)
+    return NO;
+  
+  return YES;
+}
+
+- (NSString *)credentials {
+  WORequest *rq;
+  NSString  *cred;
+  NSRange   r;
+  
+  if ((rq = [self request]) == nil)
+    return nil;
+  if ((cred = [rq headerForKey:@"authorization"]) == nil)
+    return nil;
+  
+  r = [cred rangeOfString:@" " options:NSBackwardsSearch];
+  if (r.length == 0) {
+    [self logWithFormat:@"invalid 'authorization' header: '%@'", cred];
+    return nil;
+  }
+  return [cred substringFromIndex:(r.location + r.length)];
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@"RPC>%@>",
+                     NSStringFromClass([self class])];
+}
+
+/* reflection (do not define as a category, as other may do this .. */
+
+- (NSArray *)system_listMethodsAction {
+  NSArray *names;
+  
+  names = [[self class] registeredMethodNames];
+  names = [names sortedArrayUsingSelector:@selector(compare:)];
+  
+  return names;
+}
+- (NSArray *)system_methodSignatureAction:(NSString *)_method {
+  return [[self class] signaturesForMethodNamed:_method];
+}
+
+@end /* NGXmlRpcAction */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcClient.h b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcClient.h
new file mode 100644 (file)
index 0000000..2af74dc
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGXmlRpcClient_H__
+#define __NGXmlRpcClient_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  NGXmlRpcClient
+  
+  This class is a raw XML-RPC client based on WOHTTPConnection. To see how
+  it works, take a look at the xmlrpc_call.m tool included in skyrix-sope-42.
+
+  XML-RPC over Unix domain sockets. NGXmlRpcClient (will) support XML-RPC over
+  a Unix domain socket, as used in the ximian_xmlrpclib.py. The transport
+  protocol used is "$body$\r\n\r\n".
+  
+  Usage:
+    NGXmlRpcClient *server;
+    
+    server =
+      [[NGXmlRpcClient alloc] initWithURL:@"http://betty.userland.com/RPC2"];
+    
+    NSLog(@"result: %@", [server call:@"state.getByNumber", @"42", nil]);
+*/
+
+@class NSArray, NSString, NSURL, NSDictionary;
+@class WOHTTPConnection;
+
+@interface NGXmlRpcClient : NSObject
+{
+  /* performing HTTP requests */
+  WOHTTPConnection *httpConnection;
+  NSString         *userName;
+  NSString         *password;
+  NSString         *uri;
+  NSDictionary     *additionalHeaders;
+  
+  /* performing RAW requests */
+  id address;
+  
+  /* some transactional state is required for digest authentication */
+  id digestInfo;
+  
+  // TODO: add timeout parameters
+}
+
+- (id)initWithURL:(id)_url;
+- (id)initWithURL:(id)_url login:(NSString *)_login password:(NSString *)_pwd;
+
+- (id)initWithRawAddress:(id)_address;
+
+/* accessors */
+
+- (void)setUserName:(NSString *)_userName;
+- (NSString *)userName;
+- (NSString *)login;
+
+- (void)setPassword:(NSString *)_password;
+- (NSString *)password;
+
+- (void)setUri:(NSString *)_uri;
+- (NSString *)uri;
+
+- (void)setAdditionalHeaders:(NSDictionary *)_headers;
+- (NSDictionary *)additionalHeaders;
+
+/* invoking methods */
+
+- (id)invoke:(NSString *)_methodName params:(id)first,...;
+
+- (id)invokeMethodNamed:(NSString *)_methodName;
+- (id)invokeMethodNamed:(NSString *)_methodName withParameter:(id)_param;
+- (id)invokeMethodNamed:(NSString *)_methodName parameters:(NSArray *)_params;
+
+/*
+  terminate parameter list with nil, eg:
+
+    [rpc call:@"state.getByNumber", @"42", nil];
+*/
+- (id)call:(NSString *)_methodName,...;
+
+@end
+
+#endif /* __NGXmlRpcClient_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcClient.m b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcClient.m
new file mode 100644 (file)
index 0000000..a0ea10b
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NGXmlRpcClient.h"
+#include "common.h"
+#include <XmlRpc/XmlRpcMethodCall.h>
+#include <XmlRpc/XmlRpcMethodResponse.h>
+#include <NGObjWeb/WOHTTPConnection.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGStreams/NGBufferedStream.h>
+
+@interface NSString(DigestInfo)
+- (NSDictionary *)parseHTTPDigestInfo;
+@end
+
+@implementation NGXmlRpcClient
+
++ (int)version {
+  return 2;
+}
+
+- (Class)connectionClass {
+  return [WOHTTPConnection class];
+}
+- (Class)requestClass {
+  return [WORequest class];
+}
+
+- (id)initWithHost:(NSString *)_h uri:(NSString *)_u port:(unsigned int)_port {
+  if ((self = [super init])) {
+    self->httpConnection = 
+      [[[self connectionClass] alloc] initWithHost:_h onPort:_port];
+    self->uri = [_u copy];
+  }
+  return self;
+}
+
+- (id)initWithHost:(NSString *)_host   // e.g. @"inster.in.skyrix.com"
+  uri:(NSString *)_uri    // e.g. @"skyxmlrpc.woa/xmlrpc"
+  port:(unsigned int)_port // e.g. 20000
+  userName:(NSString *)_userName
+  password:(NSString *)_password
+{
+  if ((self = [self initWithHost:_host uri:_uri port:_port])) {
+    self->userName = [_userName copy];
+    self->password = [_password copy];
+  }
+  return self;
+}
+- (id)initWithURL:(id)_url {
+  NSURL *url;
+  
+  url = [_url isKindOfClass:[NSURL class]]
+    ? _url
+    : [NSURL URLWithString:[_url stringValue]];
+  if (url == nil) {
+    [self release];
+    return nil;
+  }
+
+  if ((self = [super init])) {
+    self->httpConnection = [[[self connectionClass] alloc] initWithURL:url];
+    
+    if ([[url scheme] hasPrefix:@"http"])
+      self->uri = [[url path] copy];
+    else
+      /* hack for easier XMLRPC-over-Unix-Domain-sockets */
+      self->uri = @"/RPC2";
+    self->userName = [[url user]     copy];
+    self->password = [[url password] copy];
+  }
+  return self;
+}
+- (id)initWithURL:(id)_url login:(NSString *)_login password:(NSString *)_pwd {
+  if ((self = [self initWithURL:_url])) {
+    if (_login) [self setUserName:_login];
+    if (_pwd)   [self setPassword:_pwd];
+  }
+  return self;
+}
+
+- (id)initWithRawAddress:(id)_address {
+  if (_address == nil) {
+    [self release];
+    return nil;
+  }
+  if ((self = [super init])) {
+    self->address = [_address retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->additionalHeaders release];
+  [self->address        release];
+  [self->httpConnection release];
+  [self->userName       release];
+  [self->password       release];
+  [self->uri            release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSURL *)url {
+  NSString *p;
+  NSURL    *url;
+  
+  // TODO: not final yet ... (hh asks: bjoern, is this used anywhere anyway ?)
+  p = [[NSString alloc] initWithFormat:@"http://%@:%i%@",
+                  @"localhost",
+                  80,
+                  self->uri];
+  url = [NSURL URLWithString:p];
+  [p release];
+  return url;
+}
+
+- (void)setUserName:(NSString *)_userName {
+  ASSIGNCOPY(self->userName, _userName);
+}
+- (NSString *)userName {
+  return self->userName;
+}
+- (NSString *)login {
+  return self->userName;
+}
+
+- (void)setPassword:(NSString *)_password {
+  ASSIGNCOPY(self->password, _password);
+}
+- (NSString *)password {
+  return self->password;
+}
+
+- (void)setUri:(NSString *)_uri {
+  ASSIGNCOPY(self->uri, _uri);
+}
+- (NSString *)uri {
+  return self->uri;
+}
+
+- (void)setAdditionalHeaders:(NSDictionary *)_headers {
+  ASSIGNCOPY(self->additionalHeaders, _headers);
+}
+- (NSDictionary *)additionalHeaders {
+  return self->additionalHeaders;
+}
+
+/* performing the method */
+
+- (id)invokeMethodNamed:(NSString *)_methodName {
+  return [self invokeMethodNamed:_methodName parameters:nil];
+}
+
+- (id)invokeMethodNamed:(NSString *)_methodName withParameter:(id)_param {
+  NSArray *params = nil;
+
+  if (_param)
+    params = [NSArray arrayWithObject:_param];
+                
+  return [self invokeMethodNamed:_methodName parameters:params];
+}
+
+- (id)invoke:(NSString *)_methodName params:(id)firstObj,... {
+  id array, obj, *objects;
+  va_list list;
+  unsigned int count;
+  
+  va_start(list, firstObj);
+  for (count = 0, obj = firstObj; obj; obj = va_arg(list,id))
+    count++;
+  va_end(list);
+  
+  objects = calloc(count, sizeof(id));
+  {
+    va_start(list, firstObj);
+    for (count = 0, obj = firstObj; obj; obj = va_arg(list,id))
+      objects[count++] = obj;
+    va_end(list);
+
+    array = [NSArray arrayWithObjects:objects count:count];
+  }
+  free(objects);
+  
+  return [self invokeMethodNamed:_methodName parameters:array];
+}
+
+- (id)call:(NSString *)_methodName,... {
+  id array, obj, *objects;
+  va_list list;
+  unsigned int count;
+  
+  va_start(list, _methodName);
+  for (count = 0, obj = va_arg(list, id); obj; obj = va_arg(list,id))
+    count++;
+  va_end(list);
+  
+  objects = calloc(count, sizeof(id));
+  {
+    va_start(list, _methodName);
+    for (count = 0, obj = va_arg(list, id); obj; obj = va_arg(list,id))
+      objects[count++] = obj;
+    va_end(list);
+    
+    array = [NSArray arrayWithObjects:objects count:count];
+  }
+  free(objects);
+  return [self invokeMethodNamed:_methodName parameters:array];
+}
+
+- (NSString *)_authorization {
+  NSString *tmp = nil;
+  
+  if (self->userName == nil)
+    return nil;
+  
+  if (self->digestInfo) {
+    [self logWithFormat:@"need to construct digest authentication using %@", 
+           self->digestInfo];
+    return nil;
+  }
+
+  tmp = @"";
+  tmp = [tmp stringByAppendingString:self->userName];
+  tmp = [tmp stringByAppendingString:@":"];
+  
+  if (self->password)
+    tmp = [tmp stringByAppendingString:self->password];
+  
+  if (tmp != nil) {
+    tmp = [tmp stringByEncodingBase64];
+    tmp = [@"Basic " stringByAppendingString:tmp];
+  }
+  return tmp;
+}
+
+- (id)sendFailed:(NSException *)e {
+  if (e)
+    return e;
+  else {
+    return [NSException exceptionWithName:@"XmlRpcSendFailed"
+                        reason:
+                          @"unknown reason, no exception set in "
+                          @"http-connection"
+                        userInfo:nil];
+  }
+}
+
+- (id)callFailed:(WOResponse *)_response {
+  NSException  *exc;
+  NSString     *r;
+  NSDictionary *ui;
+  
+#if 0
+  NSLog(@"%s: XML-RPC response status: %i", __PRETTY_FUNCTION__,
+        [_response status]);
+#endif
+  
+  /* construct exception */
+  
+  r = [NSString stringWithFormat:@"call failed with HTTP status code %i",
+                  [_response status]];
+  
+  ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                       self,      @"NGXmlRpcClient",
+                       _response, @"WOResponse",
+                       [NSNumber numberWithInt:[_response status]],
+                       @"HTTPStatusCode",
+                       nil];
+  
+  exc = [NSException exceptionWithName:@"XmlRpcCallFailed"
+                     reason:r
+                     userInfo:ui];
+  return exc;
+}
+- (id)invalidXmlRpcResponse:(WOResponse *)_response {
+  return [NSException exceptionWithName:@"XmlRpcCallFailed"
+                      reason:@"got malformed XML-RPC response?!"
+                      userInfo:nil];
+}
+
+- (id)processHTMLResponse:(WOResponse *)_response {
+  NSDictionary *ui;
+  
+  if (_response == nil) return nil;
+  [self debugWithFormat:@"Note: got HTML response: %@", _response];
+
+  ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                      _response, @"response",
+                    nil];
+  return [NSException exceptionWithName:@"XmlRpcCallFailed"
+                     reason:@"got HTML response"
+                     userInfo:ui];
+}
+
+- (id)doCallViaHTTP:(XmlRpcMethodCall *)_call {
+  XmlRpcMethodResponse *methodResponse;
+  WOResponse           *response;
+  WORequest            *request;
+  NSString             *authorization, *ctype;
+
+  request = [[[self requestClass] alloc] initWithMethod:@"POST"
+                               uri:self->uri
+                               httpVersion:@"HTTP/1.0"
+                               headers:self->additionalHeaders
+                               content:nil
+                               userInfo:nil];
+  [request setHeader:@"text/xml" forKey:@"content-type"];
+  [request setContentEncoding:NSUTF8StringEncoding];
+  [request appendContentString:[_call xmlRpcString]];
+  request = [request autorelease];
+  
+  if ((authorization = [self _authorization]) != nil)
+    [request setHeader:authorization forKey:@"Authorization"];
+  
+  if (![self->httpConnection sendRequest:request])
+    return [self sendFailed:[self->httpConnection lastException]];
+  
+  response = [self->httpConnection readResponse];
+  
+  [self->digestInfo release]; self->digestInfo = nil;
+  
+  if ([response status] != 200) {
+    if ([response status] == 401 /* authentication required */) {
+      /* process info required for digest authentication */
+      NSString *wwwauth;
+      
+      wwwauth = [response headerForKey:@"www-authenticate"];
+      if ([[wwwauth lowercaseString] hasPrefix:@"digest"]) {
+        self->digestInfo = [[wwwauth parseHTTPDigestInfo] retain];
+        //[self debugWithFormat:@"got HTTP digest info: %@", self->digestInfo];
+      }
+    }
+    
+    return [self callFailed:response];
+  }
+
+  if ((ctype = [response headerForKey:@"content-type"]) == nil)
+    ctype = @"text/xml"; // TODO, does it make sense? For simplistic servers?
+  
+  if ([ctype hasPrefix:@"text/html"])
+    return [self processHTMLResponse:response];
+  
+  methodResponse = 
+    [[XmlRpcMethodResponse alloc] initWithXmlRpcString:
+        [response contentAsString]];
+  if (methodResponse == nil)
+    return [self invalidXmlRpcResponse:response];
+  
+  return [methodResponse autorelease];
+}
+
+- (id)doRawCall:(XmlRpcMethodCall *)_call {
+  XmlRpcMethodResponse *methodResponse;
+  NGActiveSocket   *socket;
+  NGBufferedStream *io;
+  NSString *s;
+  NSData   *rq;
+
+  /* get body for XML-RPC request */
+  
+  if ((s = [_call xmlRpcString]) == nil)
+    return nil;
+  if ((rq = [s dataUsingEncoding:NSUTF8StringEncoding]) == nil)
+    return nil;
+  
+  /* connect */
+  
+  // TODO: add timeout values
+  socket = [NGActiveSocket socketConnectedToAddress:self->address];
+  if (socket == nil) {
+    [self logWithFormat:@"could not connect %@", self->address];
+    return [self sendFailed:nil];
+  }
+  io = [NGBufferedStream filterWithSource:socket bufferSize:4096];
+  
+  /* write body + \r\n\r\n */
+  
+  if (![io writeData:rq])
+    return [self sendFailed:[io lastException]];
+  if (![io safeWriteBytes:"\r\n\r\n" count:4])
+    return [self sendFailed:[io lastException]];
+  if (![io flush])
+    return [self sendFailed:[io lastException]];
+  
+  /* read response */
+  
+  {
+    NSMutableData *data;
+    NSString *s;
+    
+    data = [NSMutableData dataWithCapacity:1024];
+    do {
+      unsigned readCount;
+      unsigned char buf[1024 + 10];
+      
+      readCount = [io readBytes:&buf count:1024];
+      if (readCount == NGStreamError) {
+       NSException *e;
+       
+       if ((e = [io lastException]) == nil)
+         break;
+       else if ([e isKindOfClass:[NGEndOfStreamException class]])
+         break;
+       else
+         /* an error */
+         return [self sendFailed:e];
+      }
+      buf[readCount] = '\0';
+      
+      [data appendBytes:buf length:readCount];
+    }
+    while (YES);
+    
+    s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+    methodResponse = [[XmlRpcMethodResponse alloc] initWithXmlRpcString:s];
+    [s release];
+  }
+  
+  [io close];
+  
+  return [methodResponse autorelease];
+}
+
+- (id)invokeMethodNamed:(NSString *)_methodName parameters:(NSArray *)_params {
+  XmlRpcMethodCall *methodCall;
+  id result;
+  
+  methodCall = [[XmlRpcMethodCall alloc] initWithMethodName:_methodName
+                                         parameters:_params];
+  
+  if (self->httpConnection)
+    result = [self doCallViaHTTP:methodCall];
+  else
+    result = [self doRawCall:methodCall];
+  
+  [methodCall release]; methodCall = nil;
+  
+  if ([result isKindOfClass:[XmlRpcMethodResponse class]])
+    result = [result result];
+  
+  if (result == nil)
+    [self logWithFormat:@"got nil value from XML-RPC ..."];
+  return result;
+}
+
+@end /* NGXmlRpcClient */
+
+@implementation NSString(DigestInfo)
+
+- (NSDictionary *)parseHTTPDigestInfo {
+  /*
+    eg: 
+      www-authenticate: Digest realm="RCD", \
+        nonce="1572920321042107679", \
+       qop="auth,auth-int", \
+       algorithm="MD5,MD5-sess"
+  */
+  NSMutableDictionary *md;
+  NSEnumerator *parts;
+  NSString *part;
+  
+  md = [NSMutableDictionary dictionaryWithCapacity:8];
+  
+  /* 
+     TODO: fix this parser, it only works if the components of the header
+     value are separated using ", " and the component *values* are separated
+     by a "," (not followed by a space).
+     Works with rcd, probably with nothing else ...
+  */
+  parts = [[self componentsSeparatedByString:@", "] objectEnumerator];
+  
+  while ((part = [parts nextObject])) {
+    NSRange  r;
+    NSString *key, *value;
+    
+    r = [part rangeOfString:@"="];
+    if (r.length == 0) continue;
+    
+    key   = [[part substringToIndex:r.location] stringByTrimmingSpaces];
+    value = [[part substringFromIndex:(r.location + r.length)] 
+                  stringByTrimmingSpaces];
+
+    //[self logWithFormat:@"key '%@' value '%@'", key, value];
+    
+    if ([value hasPrefix:@"\""] && [value hasSuffix:@"\""]) {
+      r.location = 1;
+      r.length   = [value length] - 2;
+      value = [value substringWithRange:r];
+    }
+    //[self logWithFormat:@"key '%@' value '%@'", key, value];
+    
+    [md setObject:value forKey:[key lowercaseString]];
+  }
+  return md;
+}
+
+@end /* NSString(DigestInfo) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcInvocation.h b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcInvocation.h
new file mode 100644 (file)
index 0000000..a693897
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGXmlRpcInvocation_H__
+#define __NGXmlRpcInvocation_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSMutableArray;
+@class NGXmlRpcClient;
+@class NGXmlRpcMethodSignature;
+
+@interface NGXmlRpcInvocation : NSObject < NSCoding >
+{
+  NGXmlRpcClient          *target;
+  NSString                *methodName;
+  NGXmlRpcMethodSignature *signature;
+  
+  NSMutableArray *arguments;
+  id             result;
+}
+
+- (id)initWithMethodSignature:(NGXmlRpcMethodSignature *)_sig;
+
+/* arguments */
+
+- (NGXmlRpcMethodSignature *)methodSignature;
+
+- (void)setArgument:(id)_argument atIndex:(int)index;
+- (id)argumentAtIndex:(int)index;
+
+- (void)setReturnValue:(id)_result;
+- (id)returnValue;
+
+- (void)setMethodName:(NSString *)_mname;
+- (NSString *)methodName;
+
+- (void)setTarget:(NGXmlRpcClient *)_target;
+- (NGXmlRpcClient *)target;
+
+/* Dispatching an Invocation */
+
+- (void)invoke;
+- (void)invokeWithTarget:(NGXmlRpcClient *)_target;
+
+@end
+
+@interface NSObject(XmlRpcValue)
+
+- (id)asXmlRpcValueOfType:(NSString *)_xmlRpcValueType;
+
+@end
+
+#endif /* __NGXmlRpcInvocation_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcInvocation.m b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcInvocation.m
new file mode 100644 (file)
index 0000000..68db273
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGXmlRpcInvocation.h"
+#include "NGXmlRpcMethodSignature.h"
+#include "NGXmlRpcClient.h"
+#include "common.h"
+
+@implementation NGXmlRpcInvocation
+
+static NSNull *null = nil;
+
+- (void)_ensureArgs {
+  unsigned i, count;
+
+  if (self->arguments) return;
+  if (self->signature == nil) return;
+  if (null == nil) null = [[NSNull null] retain];
+
+  count = [self->signature numberOfArguments];
+  
+  self->arguments = [[NSMutableArray alloc] initWithCapacity:count];
+  for (i = 0; i < count; i++)
+    [self->arguments addObject:null];
+}
+
+- (id)initWithMethodSignature:(NGXmlRpcMethodSignature *)_sig {
+  if (_sig == nil) {
+    RELEASE(self);
+    return nil;
+  }
+  
+  self->signature = RETAIN(_sig);
+  [self _ensureArgs];
+  
+  return self;
+}
+- (id)init {
+  return [self initWithMethodSignature:nil];
+}
+
+- (void)dealloc {
+  RELEASE(self->arguments);
+  RELEASE(self->result);
+  RELEASE(self->target);
+  RELEASE(self->methodName);
+  RELEASE(self->signature);
+  [super dealloc];
+}
+
+/* arguments */
+
+- (NGXmlRpcMethodSignature *)methodSignature {
+  return self->signature;
+}
+
+- (void)setArgument:(id)_argument atIndex:(int)_idx {
+  if (_argument == nil) _argument = null;
+  [self->arguments replaceObjectAtIndex:_idx withObject:_argument];
+}
+- (id)argumentAtIndex:(int)_idx {
+  id res;
+  
+  res = [self->arguments objectAtIndex:_idx];
+  if (res == null) res = nil;
+  return res;
+}
+
+- (void)setTarget:(NGXmlRpcClient *)_target {
+  ASSIGN(self->target, _target);
+}
+- (NGXmlRpcClient *)target {
+  return self->target;
+}
+
+- (void)setMethodName:(NSString *)_name {
+  ASSIGNCOPY(self->methodName, _name);
+}
+- (NSString *)methodName {
+  return self->methodName;
+}
+
+- (void)setReturnValue:(id)_result {
+  ASSIGN(self->result, _result);
+}
+- (id)returnValue {
+  return self->result;
+}
+
+/* Dispatching an Invocation */
+
+- (void)invoke {
+  [self invokeWithTarget:[self target]];
+}
+
+- (void)invokeWithTarget:(NGXmlRpcClient *)_target {
+  NSAutoreleasePool *pool;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    NSArray *args;
+    id res;
+    unsigned count;
+    NGXmlRpcMethodSignature *sig;
+
+    sig = [self methodSignature];
+    
+    /* collect arguments, coerce types ... */
+    if ((count = [self->arguments count]) == 0)
+      args = self->arguments;
+    else if (sig) {
+      unsigned i;
+      id *aa;
+      
+      aa = calloc(count, sizeof(id));
+      for (i = 0; i < count; i++) {
+        NSString *xrtype;
+        id value;
+        
+        xrtype = [sig argumentTypeAtIndex:i];
+        
+        value = [self->arguments objectAtIndex:i];
+        value = [value asXmlRpcValueOfType:xrtype];
+        aa[i] = value ? value : null;
+      }
+      args = [NSArray arrayWithObjects:aa count:count];
+      if (aa) free(aa);
+    }
+    else
+      args = self->arguments;
+    
+    /* invoke remote method */
+    res = [_target invokeMethodNamed:[self methodName] parameters:args];
+    
+    /* store return value */
+    [self setReturnValue:res];
+  }
+  RELEASE(pool);
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->target];
+  [_coder encodeObject:self->methodName];
+  [_coder encodeObject:self->signature];
+  [_coder encodeObject:self->arguments];
+  [_coder encodeObject:self->result];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  if (null == nil) null = [[NSNull null] retain];
+  
+  self->target     = [[_coder decodeObject] retain];
+  self->methodName = [[_coder decodeObject] copy];
+  self->signature  = [[_coder decodeObject] retain];
+  self->arguments  = [[_coder decodeObject] retain];
+  self->result     = [[_coder decodeObject] retain];
+  
+  if (self->signature == nil) {
+    NSLog(@"%s: missing signature (required during decoding)",
+          __PRETTY_FUNCTION__);
+    RELEASE(self);
+    return nil;
+  }
+  [self _ensureArgs];
+  
+  return self;
+}
+
+@end /* NGXmlRpcInvocation */
+
+@implementation NSObject(XmlRpcValue)
+
+- (NSArray *)asXmlRpcArray {
+  if ([self respondsToSelector:@selector(objectEnumerator)]) {
+    return [[[NSArray alloc]
+                      initWithObjectsFromEnumerator:
+                        [(id)self objectEnumerator]]
+                      autorelease];
+  }
+  return nil;
+}
+
+- (NSDictionary *)asXmlRpcStruct {
+  return [self valuesForKeys:[[self classDescription] attributeKeys]];
+}
+
+- (NSString *)asXmlRpcString {
+  return [self stringValue];
+}
+- (int)asXmlRpcInt {
+  return [self intValue];
+}
+- (int)asXmlRpcDouble {
+  return [self doubleValue];
+}
+
+- (NSData *)asXmlRpcBase64 {
+  return [[self stringValue] dataUsingEncoding:NSUTF8StringEncoding];
+}
+- (NSDate *)asXmlRpcDateTime {
+  return [[[NSDate alloc] initWithString:[self stringValue]] autorelease];
+}
+
+- (id)asXmlRpcValueOfType:(NSString *)_xmlRpcValueType {
+  unsigned len;
+  
+  if ((len = [_xmlRpcValueType length]) == 0)
+    return self;
+
+  if ([_xmlRpcValueType isEqualToString:@"string"])
+    return [self asXmlRpcString];
+  if ([_xmlRpcValueType isEqualToString:@"int"])
+    return [NSNumber numberWithInt:[self asXmlRpcInt]];
+  if ([_xmlRpcValueType isEqualToString:@"i4"])
+    return [NSNumber numberWithInt:[self asXmlRpcInt]];
+  if ([_xmlRpcValueType isEqualToString:@"double"])
+    return [NSNumber numberWithDouble:[self asXmlRpcDouble]];
+  if ([_xmlRpcValueType isEqualToString:@"float"])
+    return [NSNumber numberWithDouble:[self asXmlRpcDouble]];
+  if ([_xmlRpcValueType isEqualToString:@"array"])
+    return [self asXmlRpcArray];
+  if ([_xmlRpcValueType isEqualToString:@"struct"])
+    return [self asXmlRpcStruct];
+  if ([_xmlRpcValueType isEqualToString:@"datetime"])
+    return [self asXmlRpcDateTime];
+  if ([_xmlRpcValueType isEqualToString:@"base64"])
+    return [self asXmlRpcBase64];
+  
+  return self;
+}
+
+@end /* NSObject(XmlRpcValue) */
+
+@implementation NSArray(XmlRpcValue)
+
+- (NSArray *)asXmlRpcArray {
+  return self;
+}
+
+- (id)asXmlRpcValueOfType:(NSString *)_xmlRpcValueType {
+  return self;
+}
+
+@end /* NSArray(XmlRpcValue) */
+
+@implementation NSDictionary(XmlRpcValue)
+
+- (NSArray *)asXmlRpcArray {
+  return [self allValues];
+}
+
+- (NSDictionary *)asXmlRpcStruct {
+  return self;
+}
+
+@end /* NSDictionary(XmlRpcValue) */
+
+@implementation NSDate(XmlRpcValue)
+
+- (NSDate *)asXmlRpcDateTime {
+  return self;
+}
+
+@end /* NSDate(XmlRpcValue) */
+
+@implementation NSData(XmlRpcValue)
+
+- (NSData *)asXmlRpcBase64 {
+  return self;
+}
+
+@end /* NSCalendarDate(XmlRpcValue) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcMethodSignature.h b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcMethodSignature.h
new file mode 100644 (file)
index 0000000..915abf8
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGXmlRpcMethodSignature_H__
+#define __NGXmlRpcMethodSignature_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  XML-RPC types:
+    string
+    i4
+    base64
+    datetime
+*/
+
+@class NSArray;
+
+@interface NGXmlRpcMethodSignature : NSObject
+{
+  NSArray *signature;
+}
+
++ (id)signatureWithXmlRpcTypes:(NSArray *)_args;
+- (id)initWithXmlRpcTypes:(NSArray *)_arg;
+
+- (unsigned)numberOfArguments;
+- (NSString *)argumentTypeAtIndex:(unsigned int)_idx;
+- (NSString *)methodReturnType;
+- (BOOL)isOneway;
+
+- (NSArray *)xmlRpcTypes;
+
+@end
+
+#endif /* __NGXmlRpcMethodSignature_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcMethodSignature.m b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcMethodSignature.m
new file mode 100644 (file)
index 0000000..dce37d2
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGXmlRpcMethodSignature.h"
+#include "common.h"
+
+@implementation NGXmlRpcMethodSignature
+
++ (id)signatureWithXmlRpcTypes:(NSArray *)_args {
+  return [[[self alloc] initWithXmlRpcTypes:_args] autorelease];
+}
+- (id)initWithXmlRpcTypes:(NSArray *)_arg {
+  if ([_arg count] < 1) {
+    RELEASE(self);
+    return nil;
+  }
+  self->signature = [_arg copy];
+  return self;
+}
+- (id)init {
+  return [self initWithXmlRpcTypes:nil];
+}
+
+- (unsigned)numberOfArguments {
+  return ([self->signature count] - 1);
+}
+
+- (NSString *)argumentTypeAtIndex:(unsigned int)_idx {
+  return [self->signature objectAtIndex:(_idx + 1)];
+}
+
+- (NSString *)methodReturnType {
+  return [self->signature objectAtIndex:0];
+}
+
+- (BOOL)isOneway {
+  return NO;
+}
+
+- (NSArray *)xmlRpcTypes {
+  return self->signature;
+}
+
+@end /* NGXmlRpcMethodSignature */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcRequestHandler.h b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcRequestHandler.h
new file mode 100644 (file)
index 0000000..1232eb7
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGXmlRpc_XmlRpcRequestHandler_H__
+#define __NGXmlRpc_XmlRpcRequestHandler_H__
+
+#include <NGObjWeb/WORequestHandler.h>
+
+@interface NGXmlRpcRequestHandler : WORequestHandler
+@end
+
+#endif /* __NGXmlRpc_WORequestHandler_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcRequestHandler.m b/skyrix-sope/NGObjWeb/NGXmlRpc/NGXmlRpcRequestHandler.m
new file mode 100644 (file)
index 0000000..b32c0cd
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGXmlRpc/NGXmlRpcRequestHandler.h>
+#include <NGXmlRpc/NGXmlRpcAction.h>
+#include <NGXmlRpc/NGXmlRpc.h>
+#include <NGXmlRpc/XmlRpcMethodCall+WO.h>
+#include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOStatisticsStore.h>
+#include "common.h"
+
+static BOOL  perflog = NO;
+static Class NSDateClass = Nil;
+
+//#define USE_POOLS 1
+
+@interface NSObject(RPC2)
+- (id<WOActionResults>)RPC2Action;
+@end
+
+@implementation NGXmlRpcRequestHandler
+
++ (int)version {
+  return [super version] + 0 /* 2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+
+  NSDateClass = [NSDate class];
+  perflog = [[NSUserDefaults standardUserDefaults]
+                             boolForKey:
+                               @"WOProfileXmlRpcActionRequestHandler"];
+}
+
+/*
+  The request handler part of a direct action URI looks like this:
+
+    [actionClass/]actionName[?key=value&key=value&...]
+*/
+
+- (WOResponse *)_runObject:(NGXmlRpcAction *)_object
+  request:(WORequest *)_req 
+{
+  WOResponse       *result;
+  XmlRpcMethodCall *call;
+  
+  if (_object == nil) return nil;
+  
+  if (![[_req method] isEqualToString:@"POST"]) {
+    /* only POST is allowed ! */
+    return nil;
+  }
+    
+  call = [(XmlRpcMethodCall *)[XmlRpcMethodCall alloc] initWithRequest:_req];
+  call = [call autorelease];
+    
+  if (call == nil) {
+    NSData *content;
+      
+    content = [_req content];
+    
+    [self logWithFormat:@"couldn't decode XMLRPC content:\n"];
+    [self logWithFormat:@"  content-len: %d", [content length]];
+    [self logWithFormat:@"  encoding:    %d", [_req contentEncoding]];
+    result = nil;
+  }
+  else {
+    [_object awake];
+    result = [[_object performMethodCall:call] generateResponse];
+    [_object sleep];
+  }
+  
+  if (result == nil)
+    return nil;
+  
+  if (![result isKindOfClass:[WOResponse class]]) {
+    /* morph an object result into a XML-RPC response .. */
+    XmlRpcMethodResponse *r;
+    
+    r = [[XmlRpcMethodResponse alloc] initWithResult:result];
+    result = [[[r generateResponse] retain] autorelease];
+    [r release];
+  }
+  
+  return result;
+}
+
+- (WOResponse *)handleRequest:(WORequest *)_request {
+  NSTimeInterval    startHandling = 0.0;
+#if USE_POOLS
+  NSAutoreleasePool *pool = nil;
+#endif
+  WOApplication *app;
+  NSString      *handlerPath = nil;
+  NSString      *actionClassName;
+  WOResponse    *response   = nil;
+  WOContext     *context    = nil;
+  NSThread      *thread;
+  NSMutableDictionary *threadDict;
+  Class         actionClass = Nil;
+  
+  if (![[_request method] isEqualToString:@"POST"]) {
+    [self logWithFormat:@"only POST requests are valid XML-RPC requests ..."];
+    return nil;
+  }
+  
+  if (perflog)
+    startHandling = [[NSDateClass date] timeIntervalSince1970];
+  
+  thread = [NSThread currentThread];
+  NSAssert(thread, @"missing current thread ...");
+  threadDict = [thread threadDictionary];
+  NSAssert(threadDict, @"missing current thread's dictionary ...");
+  
+  if (_request == nil) return nil;
+  
+  *(&app)             = nil;
+  *(&actionClassName) = nil;
+  
+  app = [WOApplication application];
+  
+  handlerPath = [_request uri];
+  actionClass = [NGXmlRpcAction actionClassForURI:handlerPath];
+  
+  if (actionClass == Nil) {
+    [self logWithFormat:@"found no action class for URI: %@", handlerPath];
+    actionClass = [app defaultActionClassForRequest:_request];
+  }
+  
+#if DEBUG_XMLRPC_ACTION
+  NSLog(@"[XML-RPC request handler] class=%@ ..",
+        actionClassName);
+#endif
+  
+#if USE_POOLS
+  *(&pool) = [[NSAutoreleasePool alloc] init];
+#endif
+  {
+    /* setup context */
+    context = [WOContext contextWithRequest:_request];
+    NSAssert(context, @"no context assigned ..");
+    NSAssert(threadDict, @"missing current thread's dictionary ...");
+    [threadDict setObject:context forKey:@"WOContext"];
+    
+    NS_DURING {
+      [app awake];
+      {
+        NGXmlRpcAction      *actionObject = nil;
+        id<WOActionResults> result = nil;
+
+        *(&result) = nil;
+        
+        NS_DURING {
+#if USE_POOLS
+          NSAutoreleasePool *pool2 = [NSAutoreleasePool new];
+#endif
+
+          {
+            /* create direct action object */
+            actionObject = [actionClass alloc];
+            actionObject = [actionObject initWithContext:context];
+            actionObject = [actionObject autorelease];
+            
+            if (actionObject == nil) {
+              [app logWithFormat:
+                   @"ERROR: could not create direct action object of class %@",
+                   actionClassName];
+              actionObject = nil;
+            }
+            else {
+              result = [self _runObject:actionObject request:_request];
+              result = [(id)result retain];
+              
+              if (result == nil) {
+                [self logWithFormat:
+                      @"WARNING: got empty result from action .."];
+                response = [WOResponse alloc];
+                response = [response initWithRequest:_request];
+                [response setStatus:500];
+              }
+              else {
+                /* generate response */
+                response = [[result generateResponse] retain];
+              }
+              
+              [(id)result release]; result = nil;
+            }
+          }
+
+#if USE_POOLS
+          RELEASE(pool2); pool2 = nil;
+#endif
+          response = [response autorelease];
+        }
+        NS_HANDLER {
+          response = [app handleException:localException inContext:context];
+        }
+        NS_ENDHANDLER;
+        
+        response = [response retain];
+      }
+      [app sleep];
+    }  
+    NS_HANDLER {
+      response = [app handleException:localException inContext:context];
+      response = [response retain];
+    }
+    NS_ENDHANDLER;
+    
+    NSAssert(threadDict, @"missing current thread's dictionary ...");
+    [threadDict removeObjectForKey:@"WOContext"];
+  }
+#if USE_POOLS
+  [pool release]; pool = nil;
+#endif
+
+  if (perflog) {
+    NSTimeInterval rt;
+    rt = [[NSDateClass date] timeIntervalSince1970] - startHandling;
+    NSLog(@"[da-handler]: handleRequest took %4.3fs.",
+          rt < 0.0 ? -1.0 : rt);
+  }
+  
+  return AUTORELEASE(response);
+}
+
+@end /* NGXmlRpcRequestHandler */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NSObject+Reflection.h b/skyrix-sope/NGObjWeb/NGXmlRpc/NSObject+Reflection.h
new file mode 100644 (file)
index 0000000..c76e23f
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NSObject_Reflection_H__
+#define __NSObject_Reflection_H__
+
+@interface NSObject(Reflection)
+
+/* this method returns the selectors defined by the exact class only */
++ (NSArray *)classImplementsSelectors;
+
+/* those two methods return the selectors defined by the whole class hierachy*/
++ (NSArray *)instancesRespondToSelectors;
+- (NSArray *)respondsToSelectors;
+
+@end /* NSObject(Reflection) */
+
+#endif /* __NSObject_Reflection_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/NSObject+Reflection.m b/skyrix-sope/NGObjWeb/NGXmlRpc/NSObject+Reflection.m
new file mode 100644 (file)
index 0000000..f0e961a
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#import <objc/objc.h>
+#import <objc/objc-api.h>
+#import <objc/Protocol.h>
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+#  import <objc/objc.h>
+#  import <objc/objc-class.h>
+#else
+#  import <objc/encoding.h>
+#endif
+
+@implementation NSObject(Reflection)
+
++ (void)_addSelectorsOfClassToArray:(NSMutableSet *)_sels {
+#if GNU_RUNTIME
+  MethodList_t methods;
+  
+  for (methods = ((Class)self)->methods; methods;
+       methods = methods->method_next) {
+    int i;
+    
+    for (i = 0; i < methods->method_count; i++) {
+      Method_t internalMethod;
+      SEL      sel;
+      NSString *selName;
+      
+      internalMethod = &(methods->method_list[i]);
+      sel     = internalMethod->method_name;
+      selName = NSStringFromSelector(sel);
+      
+      if ([selName length] == 0) {
+        NSLog(@"WARNING(%s): did not get selector for method 0x%08X",
+              __PRETTY_FUNCTION__, internalMethod);
+        continue;
+      }
+      
+      [_sels addObject:selName];
+    }
+  }
+#else
+  struct objc_method_list *mlist;
+  void *iterator = NULL;
+  
+  //NSLog(@"adding selectors of class: %@", NSStringFromClass(self));
+  
+  while ((mlist = class_nextMethodList(self, &iterator)) != NULL) {
+    int mcount;
+    
+    //NSLog(@"  processing %i selectors ...", mlist->method_count);
+    
+    for (mcount = mlist->method_count; mcount > 0; mcount--) {
+      NSString *selName;
+      SEL sel;
+      
+      if ((sel = mlist->method_list[mcount - 1].method_name) == NULL)
+        continue;
+      
+      selName = NSStringFromSelector(sel);
+      if ([selName length] == 0) {
+        NSLog(@"WARNING(%s): did not get selector for method 0x%08X",
+              __PRETTY_FUNCTION__, mlist->method_list[mcount - 1]);
+        continue;
+      }
+      [_sels addObject:selName];
+    }
+  }
+#endif
+}
+
++ (NSArray *)classImplementsSelectors {
+  NSMutableSet *a;
+  
+  a = [[[NSMutableSet alloc] initWithCapacity:32] autorelease];
+  [self _addSelectorsOfClassToArray:a];
+  return [a allObjects];
+}
+
++ (NSArray *)instancesRespondToSelectors {
+  NSMutableSet *a;
+  Class clazz;
+  
+  a = [NSMutableSet setWithCapacity:128];
+  for (clazz = self; clazz; clazz = [clazz superclass])
+    [clazz _addSelectorsOfClassToArray:a];
+  return [a allObjects];
+}
+
+- (NSArray *)respondsToSelectors {
+  return [[self class] instancesRespondToSelectors];
+}
+
+@end /* NSObject(Reflection) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpc.h b/skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpc.h
new file mode 100644 (file)
index 0000000..e286e34
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __WODirectAction_XMLRPC_H__
+#define __WODirectAction_XMLRPC_H__
+
+#import <NGObjWeb/WODirectAction.h>
+@class NSString, NSArray;
+
+@interface WODirectAction(XmlRpc)
+- (NSString *)xmlrpcComponentNamespacePrefix;
+- (NSString *)xmlrpcComponentName;
+- (NSString *)xmlrpcComponentNamespace;
+@end /* WODirectAction(XmlRpc) */
+
+@interface WODirectAction(XmlRpcValues)
+
+/* mapping XML-RPC actions to selectors */
+
+- (NSString *)selectorForXmlRpcAction:(NSString *)_name;
+- (NSString *)selectorForXmlRpcAction:(NSString *)_name
+  parameters:(NSArray *)_params;
+
+/* dispatcher */
+
+- (id)performActionNamed:(NSString *)_actionName parameters:(NSArray *)_params;
+
+/* direct action */
+
+- (id<WOActionResults>)RPC2Action;
+
+@end
+
+@interface WODirectAction(XmlRpcInfo)
+
+/*
+  use reflection to show an "WebService" info page ...
+*/
+- (id<WOActionResults>)RPC2InfoPageAction;
+
+@end
+
+#endif /* __WODirectAction_XMLRPC_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpc.m b/skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpc.m
new file mode 100644 (file)
index 0000000..b1fecd1
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WODirectAction+XmlRpc.h"
+#include <NGXmlRpc/NSObject+Reflection.h>
+#include <NGXmlRpc/XmlRpcMethodCall+WO.h>
+#include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+@implementation WODirectAction(XmlRpc)
+
+static int CoreOnException = -1;
+
+- (NSString *)xmlrpcComponentNamespacePrefix {
+  NSString *np;
+  
+  np = [[NSUserDefaults standardUserDefaults]
+                        stringForKey:@"SxDefaultNamespacePrefix"];
+  if ([np length] > 0)
+    return np;
+
+  [self logWithFormat:
+          @"WARNING: SxDefaultNamespacePrefix default is not set !"];
+  
+  np = [(NSHost *)[NSHost currentHost] name];
+  if ([np length] > 0) {
+    if (!isdigit([np characterAtIndex:0])) {
+      NSArray *parts;
+
+      parts = [np componentsSeparatedByString:@"."];
+      if ([parts count] == 0) {
+      }
+      else if ([parts count] == 1)
+        return [parts objectAtIndex:0];
+      else {
+        NSEnumerator *e;
+        BOOL     isFirst = YES;
+        NSString *s;
+        
+        e = [parts reverseObjectEnumerator];
+        while ((s = [e nextObject])) {
+          if (isFirst) {
+            isFirst = NO;
+            np = s;
+          }
+          else {
+            np = [[np stringByAppendingString:@"."] stringByAppendingString:s];
+          }
+        }
+        return np;
+      }
+    }
+  }
+  
+  return @"com.skyrix";
+}
+- (NSString *)xmlrpcComponentName {
+  NSString *s;
+
+  s = NSStringFromClass([self class]);
+  if (![s isEqualToString:@"DirectAction"])
+    return s;
+  
+  return [[NSProcessInfo processInfo] processName];
+}
+
+- (NSString *)xmlrpcComponentNamespace {
+  NSString *ns, *n;
+  
+  ns = [self xmlrpcComponentNamespacePrefix];
+  n  = [self xmlrpcComponentName];
+  return [[ns stringByAppendingString:@"."] stringByAppendingString:n];
+}
+
+- (NSArray *)_methodActionNames {
+  NSMutableArray *ma;
+  NSEnumerator   *sels;
+  NSString       *sel;
+
+  sels = [[self respondsToSelectors] objectEnumerator];
+
+  ma = [NSMutableArray arrayWithCapacity:16];
+  while ((sel = [sels nextObject])) {
+    unsigned idx, len;
+    NSString *actionName;
+    NSRange rng;
+    
+    rng = [sel rangeOfString:@"Action"];
+    if (rng.length <= 0) continue;
+    
+    actionName = sel;
+    
+    /* ensure that only dots are following the 'Action' */
+    for (idx = (rng.location + rng.length), len = [sel length]; 
+         idx < len; idx++) {
+      unichar c = [sel characterAtIndex:idx];
+      if (c != ':') {
+        actionName = nil;
+        break;
+      }
+    }
+    
+    /* go to next selector if ... */
+    if ([actionName length] == 0) continue;
+    
+    /* add to reflection set */
+    [ma addObject:actionName];
+  }
+  return [[ma copy] autorelease];
+}
+
+- (NSString *)selectorForXmlRpcAction:(NSString *)_name {
+  NSString *actionName;
+  NSString *p;
+
+  actionName = @"Action";
+
+  /* check component namespace and strip it ;-) */
+  
+  p = [self xmlrpcComponentNamespace];
+  
+  if ([p length] > 0) {
+    if ([_name hasPrefix:@"system."])
+      ;
+    else if ([_name hasPrefix:p]) {
+      _name = [_name substringFromIndex:[p length]];
+      if ([_name length] > 0) {
+        if ([_name characterAtIndex:0] == '.')
+          _name = [_name substringFromIndex:1];
+      }
+    }
+    else {
+      [self logWithFormat:
+            @"WARNING: tried to invoke XML-RPC method from "
+            @"different component (namespace=%@): %@",
+            p, _name];
+    }
+  }
+  
+  /* replace namespace points by '_' */
+  
+  _name      = [_name stringByReplacingString:@"." withString:@"_"];
+  actionName = [_name stringByAppendingString:actionName];
+  
+  /* finished */
+  return actionName;
+}
+
+- (NSString *)selectorForXmlRpcAction:(NSString *)_name
+  parameters:(NSArray *)_params
+{
+  NSString *actionName;
+  int i, cnt;
+  
+  actionName = [self selectorForXmlRpcAction:_name];
+  
+  /* append ':' for each parameter */
+
+  switch ((cnt = [_params count])) {
+    case 0:
+      break;
+    case 1:
+      actionName = [actionName stringByAppendingString:@":"];
+      break;
+    case 2:
+      actionName = [actionName stringByAppendingString:@"::"];
+      break;
+    case 3:
+      actionName = [actionName stringByAppendingString:@":::"];
+      break;
+    case 4:
+      actionName = [actionName stringByAppendingString:@"::::"];
+      break;
+      
+    default:
+      for (i = 0, cnt = [_params count]; i < cnt; i++)
+        actionName = [actionName stringByAppendingString:@":"];
+      break;
+  }
+  
+  /* finished */
+  return actionName;
+}
+
+- (id)performActionNamed:(NSString *)_name parameters:(NSArray *)_params {
+  NSMethodSignature *sign;
+  NSInvocation      *invo;
+  NSString          *actionName;
+  id   result = nil;
+  SEL  sel;
+  int  i, cnt = 0;
+  
+  /* generate selector */
+  actionName = [self selectorForXmlRpcAction:_name parameters:_params];
+  sel = NSSelectorFromString(actionName);
+  
+  if (![self respondsToSelector:sel]) {
+    NSEnumerator *actEnum;
+    NSString     *name    = nil;
+    NSString     *act     = nil;
+    
+    actEnum    = [[self _methodActionNames] objectEnumerator];
+    name       = [actionName stringByReplacingString:@":" withString:@""];
+    actionName = nil;
+    while ((act = [actEnum nextObject])) {
+      NSString *tmp = [act stringByReplacingString:@":" withString:@""];
+      
+      if ([tmp isEqualToString:name]) actionName = act;
+    }
+    sel = NSSelectorFromString(actionName);
+    
+    if (sel == NULL) {
+      /* Note: NULL selectors are not caught by MacOSX -respondsToSel: ! */
+      [self logWithFormat:@"no such XMLRPC action: '%@'", _name];
+      return [NSException exceptionWithName:@"NoSuchAction"
+                          reason:@"action not implemented"
+                          userInfo:nil];
+    }
+    else if (![self respondsToSelector:sel]) {
+      [self logWithFormat:@"no such XMLRPC action: '%@' (selector=%@)",
+              _name, NSStringFromSelector(sel)];
+      
+      return [NSException exceptionWithName:@"NoSuchAction"
+                          reason:@"action not implemented"
+                          userInfo:nil];
+    }
+    else {
+      // count the ':'
+      cnt = [[actionName componentsSeparatedByString:@":"] count] - 1;
+    }
+  }
+  sign = [[self class] instanceMethodSignatureForSelector:sel];
+  invo = [NSInvocation invocationWithMethodSignature:sign];
+  [invo setSelector:sel];
+  if (cnt == 0) cnt = ([sign numberOfArguments] - 2);
+  
+  [invo setTarget:self];
+  
+  cnt = (cnt > (int)[_params count]) ? (int)[_params count] : cnt;
+  
+  for (i = 0; i < cnt; i++) {
+    id param = [_params objectAtIndex:i];
+    [invo setArgument:&param atIndex:(i + 2)];
+  }
+  // TODO(hh): should fill the remaining args when less params available ?
+  
+  [invo invoke];
+  [invo getReturnValue:&result];
+
+  return result;
+}
+
+- (id)_faultForException:(NSException *)_exception {
+  if (CoreOnException == -1) {
+    // TODO: add default
+    CoreOnException =   
+      [[NSUserDefaults standardUserDefaults] 
+                      boolForKey:@"WOCoreOnXmlRpcFault"] ? 1 : 0;
+  }
+  
+  if (CoreOnException) {
+    [self logWithFormat:@"core on exception: %@", _exception];
+    abort();
+    return nil;
+  }
+  else {
+    [self logWithFormat:@"turn exception into fault: %@", _exception];
+    return _exception;
+  }
+}
+
+- (id)RPC2Action {
+  XmlRpcMethodCall     *call;
+  XmlRpcMethodResponse *mResponse;
+  id                   result;
+  
+  if (![[[self request] method] isEqualToString:@"POST"]) {
+    /* only POST is allowed for direct XML-RPC requests ! */
+    
+    if ([[[self request] method] isEqualToString:@"GET"])
+      return [self RPC2InfoPageAction];
+    
+    return nil;
+  }
+
+  call = [XmlRpcMethodCall alloc];
+  call = [[call initWithRequest:[self request]] autorelease];
+  
+  if (call == nil) {
+    WORequest *rq;
+    NSData    *content;
+    
+    rq      = [self request];
+    content = [rq content];
+    
+    [self logWithFormat:@"couldn't decode XMLRPC content:\n"];
+    [self logWithFormat:@"  content-len: %d", [content length]];
+    [self logWithFormat:@"  encoding:    %d", [rq contentEncoding]];
+    return nil;
+  }
+  
+  [self debugWithFormat:@"decoded XMLRPC call: %@", call];
+  
+  NS_DURING {
+    result = [[self performActionNamed:[call methodName]
+                    parameters:[call parameters]]
+                    retain];
+  }
+  NS_HANDLER
+    result = [[self _faultForException:localException] retain];
+  NS_ENDHANDLER;
+  
+  mResponse =
+    [[[XmlRpcMethodResponse alloc] initWithResult:result] autorelease];
+  
+  [result release]; result = nil;
+  
+  return [mResponse generateResponse];
+}
+- (id<WOActionResults>)xmlrpcAction {
+  [self debugWithFormat:@"deprecated, please use /RPC2 as direct action !"];
+  return [self RPC2Action];
+}
+
+@end /* WODirectAction(XmlRpc) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpcIntrospection.h b/skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpcIntrospection.h
new file mode 100644 (file)
index 0000000..4ab53a3
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGXmlRpc_WODirectAction_XmlRpcIntrospection_H__
+#define __NGXmlRpc_WODirectAction_XmlRpcIntrospection_H__
+
+#include "WODirectAction+XmlRpc.h"
+
+@interface WODirectAction(XmlRpcIntrospection)
+
+- (NSArray *)system_listMethodsAction;
+- (NSArray *)system_methodSignatureAction:(NSString *)_xmlrpcMethod;
+- (NSString *)system_methodHelpAction:(NSString *)_xmlrpcMethod;
+
+@end
+
+#endif /*  __NGXmlRpc_WODirectAction_XmlRpcIntrospection_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpcIntrospection.m b/skyrix-sope/NGObjWeb/NGXmlRpc/WODirectAction+XmlRpcIntrospection.m
new file mode 100644 (file)
index 0000000..a71844d
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WODirectAction+XmlRpcIntrospection.h"
+#include "WODirectAction+XmlRpc.h"
+#include "NSObject+Reflection.h"
+#include <NGXmlRpc/XmlRpcMethodCall+WO.h>
+#include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+@interface NSMethodSignature(XmlRpcSignature)
+
+- (NSArray *)xmlRpcSignature;
+
+@end
+
+@implementation NSMethodSignature(XmlRpcSignature)
+
+- (NSString *)xmlRpcTypeForObjCType:(const char *)_type {
+  if (_type == NULL) return nil;
+#if GNU_RUNTIME
+  switch (*_type) {
+    case _C_ID:
+    case _C_CLASS:
+      return @"string";
+
+    case _C_SEL:
+    case _C_CHARPTR:
+      return @"string";
+      
+    case _C_CHR:
+    case _C_UCHR:
+      return @"boolean";
+      
+    case _C_INT:
+    case _C_UINT:
+    case _C_SHT:
+    case _C_USHT:
+    case _C_LNG:
+    case _C_ULNG:
+      return @"i4";
+
+    case _C_ARY_B:
+      return @"array";
+    case _C_STRUCT_B:
+      return @"struct";
+      
+    case _C_FLT:
+    case _C_DBL:
+      return @"double";
+  }
+#endif
+  return @"string";
+}
+
+- (NSArray *)xmlRpcSignature {
+  NSMutableArray *signature;
+  unsigned i;
+
+  signature = [NSMutableArray arrayWithCapacity:8];
+
+  /* return value */
+  [signature addObject:[self xmlRpcTypeForObjCType:[self methodReturnType]]];
+  
+  /* arguments */
+  for (i = 2; i < [self numberOfArguments]; i++) {
+    const char *t;
+    
+    t = [self getArgumentTypeAtIndex:i];
+    [signature addObject:[self xmlRpcTypeForObjCType:t]];
+  }
+  
+  return signature;
+}
+
+@end /* NSMethodSignature(XmlRpcSignature) */
+
+@implementation WODirectAction(XmlRpcIntrospection)
+
+static NSArray *blacklist = nil;
+
+- (NSArray *)system_listMethodsAction {
+  NSMutableArray *ma;
+  NSEnumerator   *sels;
+  NSString       *sel;
+  NSString       *namespace;
+  NSArray        *selectors;
+
+  namespace = [self xmlrpcComponentNamespace];
+
+  if (blacklist == nil) {  
+    blacklist = [[NSArray alloc] initWithObjects:@"RPC2Action",
+                                 @"RPC2InfoPageAction",
+                                 @"xmlrpcAction",
+                                 @"commitFailedAction",
+                                 @"WOStatsAction",
+                                 @"defaultAction",
+                                 @"missingAuthAction",
+                                 @"selectorForXmlRpcAction:",
+                                 @"accessDeniedAction",nil];
+  }
+
+  selectors = [self respondsToSelectors];
+  sels = [selectors objectEnumerator];
+
+  ma = [NSMutableArray arrayWithCapacity:[selectors count]];
+
+  while ((sel = [sels nextObject])) {
+    unsigned idx, len;
+    NSString *actionName;
+    NSRange rng;
+
+    if ([blacklist containsObject:sel])
+      continue;
+
+    rng = [sel rangeOfString:@"Action"];
+    if (rng.length <= 0) continue;
+    
+    /* strip Action */
+    actionName = [sel substringToIndex:rng.location];
+
+    /* ensure that only dots are following the 'Action' */
+    for (idx = (rng.location + rng.length), len = [sel length]; 
+         idx < len; idx++) {
+      unichar c = [sel characterAtIndex:idx];
+      if (c != ':') {
+        actionName = nil;
+        break;
+      }
+    }
+    
+    /* go to next selector if ... */
+    if ([actionName length] == 0) continue;
+    
+    /* make action name XMLRPC-style friendly */    
+    actionName = [actionName stringByReplacingString:@"_" withString:@"."];
+
+    if (namespace == nil)
+      [ma addObject:actionName];
+    else {
+      /* add to reflection set */
+      if ([actionName hasPrefix:@"system."])
+        [ma addObject:actionName];
+      else {
+        NSString *s;
+        
+        s = [[NSString alloc] initWithFormat:@"%@.%@", namespace,actionName];
+        [ma addObject:s];
+        [s release];
+      }
+    }
+  }
+
+  return [[[ma copy] autorelease] sortedArrayUsingSelector:
+                     @selector(caseInsensitiveCompare:)];
+}
+
+- (NSArray *)system_methodSignatureAction:(NSString *)_xmlrpcMethod {
+  /*
+    It returns an array of possible signatures for this method. A signature
+    is an array of types. The first of these types is the return type of the
+    method, the rest are parameters.
+
+    Multiple signatures (ie. overloading) are permitted: this is the reason
+    that an array of signatures are returned by this method.
+
+    Signatures themselves are restricted to the top level parameters expected
+    by a method. For instance if a method expects one array of structs as a
+    parameter, and it returns a string, its signature is simply
+    "string, array". If it expects three integers, its signature is
+    "string, int, int, int".
+
+    If no signature is defined for the method, a none-array value is returned.
+  */
+  NSMutableArray *signatures;
+  NSString       *actionName;
+  NSEnumerator   *sels;
+  NSString       *sel;
+  unsigned len;
+  Class clazz;
+
+  clazz      = [self class];
+  signatures = [NSMutableArray arrayWithCapacity:4];
+  actionName = [self selectorForXmlRpcAction:_xmlrpcMethod];
+  
+  len = [actionName length];
+  
+  sels = [[self respondsToSelectors] objectEnumerator];
+  while ((sel = [sels nextObject])) {
+    NSArray *signature;
+    NSMethodSignature *ms;
+    
+    if (![sel hasPrefix:actionName]) continue;
+    
+    ms = [self methodSignatureForSelector:NSSelectorFromString(sel)];
+    if (ms) {
+      signature = [ms xmlRpcSignature];
+    }
+    else {
+      [self logWithFormat:@"missing Objective-C method signature for %@ ...",
+              sel];
+      signature = nil;
+    }
+    
+    if (signature)
+      [signatures addObject:signature];
+  }
+  
+  return ([signatures count] > 0)
+    ? signatures
+    : (id)[NSNumber numberWithBool:NO];
+}
+
+- (NSString *)system_methodHelpAction:(NSString *)_xmlrpcMethod {
+  return
+    @"Note: the Objective-C runtime cannot return the correct XML-RPC type "
+    @"for object parameters automatically (only for base types ...).";
+}
+
+@end /* WODirectAction(XmlRpcIntrospection) */
+
+#include <NGObjWeb/WOResponse.h>
+
+@implementation WODirectAction(XmlRpcInfo)
+
+- (id<WOActionResults>)RPC2InfoPageAction {
+  WOResponse *r;
+  NSEnumerator *e;
+  id tmp;
+
+  r = [WOResponse alloc];
+  r = [[r initWithRequest:[self request]] autorelease];
+  [r setHeader:@"text/html" forKey:@"content-type"];
+
+  [r appendContentString:@"<html><head><title>WebService at "];
+  [r appendContentHTMLString:[[self request] uri]];
+  [r appendContentString:@"</title></head><body bgcolor=\"#FFFFFF\">"];
+  
+  [r appendContentString:@"<h3>WebService at "];
+  [r appendContentHTMLString:[[self request] uri]];
+  [r appendContentString:@"</h3>"];
+  
+  [r appendContentString:@"<h4>methods</h4>"];
+
+  [r appendContentString:@"<table border='1'>\n"];
+  [r appendContentString:
+     @"<tr><th>name</th><th>signature</th><th>info</th></tr>\n"];
+  
+  e = [[self system_listMethodsAction] objectEnumerator];
+  while ((tmp = [e nextObject])) {
+    NSString *mname, *info;
+    id sig;
+
+    mname = [tmp stringValue];
+    [r appendContentString:@"<tr>"];
+    
+    [r appendContentString:@"<td>"];
+    [r appendContentHTMLString:mname];
+    [r appendContentString:@"</td>"];
+    
+    sig  = [self system_methodSignatureAction:mname];
+    info = [self system_methodHelpAction:mname];
+
+    [r appendContentString:@"<td>"];
+    if ([sig isKindOfClass:[NSArray class]]) {
+      [r appendContentHTMLString:[sig stringValue]];
+    }
+    [r appendContentString:@"</td>"];
+
+    if ([info length] > 0) {
+      [r appendContentString:@"<td>"];
+      [r appendContentString:info];
+      [r appendContentString:@"</td>"];
+    }
+    
+    [r appendContentString:@"</tr>\n"];
+  }
+  [r appendContentString:@"</table>"];
+  
+  [r appendContentString:@"</body></html>"];
+  
+  return r;
+}
+
+@end /* WODirectAction(XmlRpcInfo) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/WOMessage+XmlRpcCoding.m b/skyrix-sope/NGObjWeb/NGXmlRpc/WOMessage+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..355a8b4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <XmlRpc/XmlRpcCoder.h>
+#include <NGExtensions/NGExtensions.h>
+#include <NGObjWeb/WOMessage.h>
+#include "common.h"
+
+@implementation WOMessage(XmlRpcCoding)
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeString:[self httpVersion] forKey:@"http-version"];
+  [_coder encodeStruct:[self headers]     forKey:@"headers"];
+  [_coder encodeBase64:[self content]     forKey:@"content"];  
+  [_coder encodeArray:[self cookies]      forKey:@"cookies"];
+}
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  if ((self = [super init])) {
+    NSArray      *cooks    = [_coder decodeArrayForKey:@"cookies"];
+    NSEnumerator *cookEnum = [cooks objectEnumerator];
+    WOCookie     *cook     = nil;
+
+    while ((cook = [cookEnum nextObject])) {
+      [self addCookie:cook];
+    }
+    [self setHTTPVersion:[_coder decodeStringForKey:@"http-version"]];
+    [self setHeaders:    [_coder decodeStructForKey:@"headers"]];
+    [self setContent:    [_coder decodeBase64ForKey:@"content"]];
+
+    return self;
+  }
+  return nil;
+}
+
+@end /* WOMessage(XmlRpcCoding) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/WORequest+XmlRpcCoding.m b/skyrix-sope/NGObjWeb/NGXmlRpc/WORequest+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..ec872f0
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <XmlRpc/XmlRpcMethodResponse.h>
+#include <XmlRpc/XmlRpcCoder.h>
+#include "common.h"
+#include <NGObjWeb/WORequest.h>
+
+@implementation WORequest(XmlRpcCoding)
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [super encodeWithXmlRpcCoder:_coder];
+  [_coder encodeString:[self method] forKey:@"method"];
+  [_coder encodeString:[self uri]    forKey:@"uri"];
+}
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  if ((self = [self initWithMethod:[_coder decodeStringForKey:@"method"]
+                    uri:[_coder decodeStringForKey:@"uri"]
+                    httpVersion:[_coder decodeStringForKey:@"http-version"]
+                    headers:[_coder decodeStructForKey:@"headers"]
+                    content:[_coder decodeBase64ForKey:@"content"]
+                    userInfo:nil])) {
+    NSArray      *cooks    = [_coder decodeArrayForKey:@"cookies"];
+    NSEnumerator *cookEnum = [cooks objectEnumerator];
+    WOCookie     *cook     = nil;
+
+    while ((cook = [cookEnum nextObject])) {
+      [self addCookie:cook];
+    }
+    return self;
+  }
+  return nil;
+}
+
+@end /* WORequest(XmlRpcCoding) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/WOResponse+XmlRpcCoding.m b/skyrix-sope/NGObjWeb/NGXmlRpc/WOResponse+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..3627b3d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <XmlRpc/XmlRpcMethodResponse.h>
+#include <XmlRpc/XmlRpcCoder.h>
+#include "common.h"
+#include <NGExtensions/NGExtensions.h>
+#include <NGObjWeb/WOResponse.h>
+
+@interface WOMessage(UsedPrivates)
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder;
+@end
+
+@implementation WOResponse(XmlRpcCoding)
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [super encodeWithXmlRpcCoder:_coder];
+  [_coder encodeInt:[self status] forKey:@"status"];
+}
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  if ((self = [super initWithXmlRpcCoder:_coder])) {
+    [self setStatus:[_coder decodeIntForKey:@"status"]];
+  }
+  return self;
+}
+
+@end /* WOResponse(XmlRpcCoding) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodCall+WO.h b/skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodCall+WO.h
new file mode 100644 (file)
index 0000000..bffc686
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SkyXmlRpcServer__XmlRpcMethodCall_WO_H__
+#define __SkyXmlRpcServer__XmlRpcMethodCall_WO_H__
+
+#include <XmlRpc/XmlRpcMethodCall.h>
+
+@class WORequest;
+
+@interface XmlRpcMethodCall(WO)
+
+- (id)initWithRequest:(WORequest *)_request;
+- (WORequest *)generateRequestWithUri:(NSString *)_uri;
+
+@end
+
+#endif /* __SkyXmlRpcServer__XmlRpcMethodCall_WO_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodCall+WO.m b/skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodCall+WO.m
new file mode 100644 (file)
index 0000000..9ebbefb
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <XmlRpc/XmlRpcMethodCall.h>
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+@implementation XmlRpcMethodCall(WO)
+
+// TODO: not required anymore by NGXmlRpcClient, can be removed ?
+
+- (id)initWithRequest:(WORequest *)_request {
+  /* do not use -initWithXmlRpcString here !!! */
+  return [self initWithXmlRpcData:[_request content]];
+}
+
+- (WORequest *)generateRequestWithUri:(NSString *)_uri {
+  WORequest *request;
+  
+  request = [[WORequest alloc] initWithMethod:@"POST"
+                               uri:_uri
+                               httpVersion:@"HTTP/1.0"
+                               headers:nil
+                               content:nil
+                               userInfo:nil];
+
+  [request setHeader:@"text/xml" forKey:@"content-type"];
+  [request setContentEncoding:NSUTF8StringEncoding];
+  
+  [request appendContentString:[self xmlRpcString]];
+  
+  return [request autorelease];
+}
+
+@end /* XmlRpcMethodCall(WO) */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodResponse+WO.h b/skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodResponse+WO.h
new file mode 100644 (file)
index 0000000..98f58bc
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __XmlRpcMethodResponse_WO_H__
+#define __XmlRpcMethodResponse_WO_H__
+
+#include <XmlRpc/XmlRpcMethodResponse.h>
+#include <NGObjWeb/WOActionResults.h>
+
+@class WOResponse;
+
+@interface XmlRpcMethodResponse(WO) < WOActionResults >
+
+- (id)initWithResponse:(WOResponse *)_response;
+- (WOResponse *)generateResponse;
+
+@end
+
+#endif /* __XmlRpcMethodResponse_H__ */
diff --git a/skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodResponse+WO.m b/skyrix-sope/NGObjWeb/NGXmlRpc/XmlRpcMethodResponse+WO.m
new file mode 100644 (file)
index 0000000..6871c3f
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@implementation XmlRpcMethodResponse(WO)
+
+// TODO: not required anymore by NGXmlRpcClient, can be removed ?
+
+- (id)initWithResponse:(WOResponse *)_response {
+  /* 
+     should be based on NSData, so that the XML parser can decide the string
+     encoding (based on the <?xml > declaration) !
+  */
+  NSString *xmlRpcString;
+  
+  xmlRpcString = [[NSString alloc] initWithData:[_response content]
+                                  encoding:[_response contentEncoding]];
+  
+  self = [self initWithXmlRpcString:xmlRpcString];
+  [xmlRpcString release];
+  return self;
+}
+
+- (WOResponse *)generateResponse {
+  WOResponse *response;
+  
+  response = [[[WOResponse alloc] init] autorelease];
+  [response setStatus:200];
+  [response setHTTPVersion:@"HTTP/1.0"];
+  [response setContentEncoding:NSUTF8StringEncoding];
+  [response setHeader:@"text/xml" forKey:@"content-type"];
+  [response appendContentString:[self xmlRpcString]];
+  return response;
+}
+
+@end /* XmlRpcMethodResponse(WO) */
diff --git a/skyrix-sope/NGObjWeb/NSObject+WO.h b/skyrix-sope/NGObjWeb/NSObject+WO.h
new file mode 100644 (file)
index 0000000..8903bbf
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_NSObject_WO_H__
+#define __NGObjWeb_NSObject_WO_H__
+
+#import <Foundation/NSObject.h>
+#import <EOControl/EOKeyValueCoding.h>
+
+@interface NSObject(NGObjWebKVC)
+
+- (BOOL)kvcIsPreferredInKeyPath;
+
+@end
+
+@interface NSObject(NGObjWebFaultChecks)
+
++ (BOOL)isFault;
+- (BOOL)isFault;
+
+@end
+
+BOOL WOSetKVCValueUsingMethod(id object, NSString *_key, id _value);
+IMP  WOGetKVCGetMethod(id object, NSString *_key);
+id   WOGetKVCValueUsingMethod(id object, NSString *_key);
+
+#endif /* __NGObjWeb_NSObject_WO_H__ */
diff --git a/skyrix-sope/NGObjWeb/NSObject+WO.m b/skyrix-sope/NGObjWeb/NSObject+WO.m
new file mode 100644 (file)
index 0000000..2882cc4
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSObject+WO.h"
+#include "common.h"
+
+#if APPLE_RUNTIME || NeXT_RUNTIME
+#  include <objc/objc-class.h>
+#endif
+
+#if NeXT_Foundation_LIBRARY || APPLE_FOUNDATION_LIBRARY || \
+    COCOA_Foundation_LIBRARY
+
+#ifndef __APPLE__
+@implementation NSObject(FoundationCompability)
+
+- (id)copyWithZone:(NSZone *)_z {
+  return [self retain];
+}
+
+@end /* NSObject(FoundationCompability) */
+#endif
+
+#endif /* NeXT_Foundation_LIBRARY */
+
+#if GNUSTEP_BASE_LIBRARY
+extern BOOL __objc_responds_to(id, SEL);
+#endif
+
+@implementation NSObject(NGObjWebKVC)
+
+- (BOOL)kvcIsPreferredInKeyPath {
+  return NO;
+}
+
+@end /* NSObject(NGObjWebKVC) */
+
+@implementation NSDictionary(NGObjWebKVC)
+
+- (BOOL)kvcIsPreferredInKeyPath {
+  return YES;
+}
+
+@end /* NSDictionary(NGObjWebKVC) */
+
+@implementation NSObject(Faults)
+#ifndef __APPLE__
++ (BOOL)isFault {
+  return NO;
+}
+- (BOOL)isFault {
+  return NO;
+}
+#endif
+@end /* NSObject(Faults) */
+
+// ******************** KVC methods ********************
+
+static inline void _getSetSelName(register unsigned char *buf,
+                                  register const unsigned char *_key,
+                                  register unsigned _len) {
+  buf[0] = 's';
+  buf[1] = 'e';
+  buf[2] = 't';
+
+  switch (_len) {
+    case 0: break;
+
+    case 1:
+      buf[3] = _key[0];
+      break;
+    case 2:
+      buf[3] = _key[0];
+      buf[4] = _key[1];
+      break;
+    case 3:
+      buf[3] = _key[0];
+      buf[4] = _key[1];
+      buf[5] = _key[2];
+      break;
+    case 4:
+      buf[3] = _key[0];
+      buf[4] = _key[1];
+      buf[5] = _key[2];
+      buf[6] = _key[3];
+      break;
+    case 5:
+      buf[3] = _key[0];
+      buf[4] = _key[1];
+      buf[5] = _key[2];
+      buf[6] = _key[3];
+      buf[7] = _key[4];
+      break;
+    case 6:
+      buf[3] = _key[0];
+      buf[4] = _key[1];
+      buf[5] = _key[2];
+      buf[6] = _key[3];
+      buf[7] = _key[4];
+      buf[8] = _key[5];
+      break;
+      
+    default:
+      memcpy(&(buf[3]), _key, _len);
+      break;
+  }
+  buf[3] = toupper(buf[3]);
+  buf[_len + 3] = ':';
+  buf[_len + 4] = '\0';
+}
+static inline SEL _getSetSel(register const unsigned char *_key,
+                             register unsigned _len) {
+  char buf[259];
+  _getSetSelName(buf, _key, _len);
+#if APPLE_RUNTIME || NeXT_RUNTIME
+  return sel_getUid(buf);
+#else
+  return sel_get_uid(buf);
+#endif
+}
+
+typedef union {
+  IMP            method; // real method or takeValue:ForKey:
+  char           (*cmethod) (id, SEL);
+  unsigned char  (*ucmethod)(id, SEL);
+  int            (*imethod) (id, SEL);
+  unsigned int   (*uimethod)(id, SEL);
+  short          (*smethod) (id, SEL);
+  unsigned short (*usmethod)(id, SEL);
+  const char *   (*strmethod)(id, SEL);
+  float          (*fmethod)(id, SEL);
+  double         (*dmethod)(id, SEL);
+} WOGetMethodType;
+
+typedef union {
+  IMP  method; // real method or takeValue:ForKey:
+  void (*omethod)  (id, SEL, id);
+  void (*cmethod)  (id, SEL, char);
+  void (*ucmethod) (id, SEL, unsigned char);
+  void (*imethod)  (id, SEL, int);
+  void (*uimethod) (id, SEL, unsigned int);
+  void (*smethod)  (id, SEL, short);
+  void (*usmethod) (id, SEL, unsigned short);
+  void (*strmethod)(id, SEL, const char *);
+  void (*fmethod)  (id, SEL, float);
+  void (*dmethod)  (id, SEL, double);
+} WOSetMethodType;
+
+BOOL WOSetKVCValueUsingMethod(id object, NSString *_key, id _value) {
+  NSMethodSignature *sig = nil;
+  WOSetMethodType   sm;
+  const char        *argType;
+  SEL               setSel;
+  unsigned          keyLen;
+  char              *buf;
+  
+  if (object == nil) return NO;
+  if (_key   == nil) return NO;
+
+  keyLen = [_key cStringLength];
+  
+  buf = malloc(keyLen + 2);
+  [_key getCString:buf];
+  setSel = _getSetSel(buf, keyLen);
+  free(buf); buf = NULL;
+  
+  if (setSel == NULL) // no such selector
+    return NO;
+
+  sig = [object methodSignatureForSelector:setSel];
+  if (sig == nil) // no signature
+    return NO;
+  
+  sm.method = [object methodForSelector:setSel];
+  if (sm.method) {
+    argType = [sig getArgumentTypeAtIndex:2];
+    
+    switch (*argType) {
+      case _C_CLASS:
+      case _C_ID:
+        sm.omethod(object, setSel, _value);
+        break;
+
+      case _C_CHR:
+        sm.cmethod(object, setSel, [(NSValue *)_value charValue]);
+        break;
+      case _C_UCHR:
+        sm.ucmethod(object, setSel, [_value unsignedCharValue]);
+        break;
+
+      case _C_SHT:
+        sm.smethod(object, setSel, [_value shortValue]);
+        break;
+      case _C_USHT:
+        sm.usmethod(object, setSel, [_value unsignedShortValue]);
+        break;
+            
+      case _C_INT:
+        sm.imethod(object, setSel, [_value intValue]);
+        break;
+      case _C_UINT:
+        sm.uimethod(object, setSel, [_value unsignedIntValue]);
+        break;
+        
+      case _C_FLT:
+        sm.fmethod(object, setSel, [_value floatValue]);
+        break;
+        
+      case _C_DBL:
+        sm.dmethod(object, setSel, [_value doubleValue]);
+        break;
+
+      case _C_CHARPTR: {
+        char *s;
+        s = NGMallocAtomic([_value cStringLength] + 1);
+        [_value getCString:s];
+        sm.strmethod(object, setSel, s);
+        NGFree(s); s = NULL;
+        break;
+      }
+      
+      default:
+        NSLog(@"%s: cannot set type '%c' yet (key=%@, method=%@) ..",
+              __PRETTY_FUNCTION__,
+              *argType, _key, NSStringFromSelector(setSel));
+        [NSException raise:@"WORuntimeException"
+                     format:@"cannot set type '%c' yet (key=%@, method=%@)",
+                       *argType, _key, NSStringFromSelector(setSel)];
+        return NO;
+    }
+    return YES;
+  }
+  else // did not find method
+    return NO;
+}
+
+IMP WOGetKVCGetMethod(id object, NSString *_key) {
+  register SEL getSel;
+  
+  if (object == nil) return NULL;
+  if (_key   == nil) return NULL;
+
+#if GNU_RUNTIME
+  {
+    unsigned keyLen;
+    char     *buf;
+    
+    keyLen = [_key cStringLength];
+    buf = malloc(keyLen + 1);
+    [_key getCString:buf]; buf[keyLen] = '\0';
+    getSel = sel_get_uid(buf);
+    free(buf);
+
+    if (getSel == NULL) // no such selector
+      return NULL;
+#if GNUSTEP_BASE_LIBRARY
+    if (!__objc_responds_to(object, getSel))
+      return NULL;
+#endif
+
+    return [object methodForSelector:getSel];
+  }
+#else
+  if ((getSel = NSSelectorFromString(_key)) == NULL) // no such selector
+    return NULL;
+
+  if ([object respondsToSelector:getSel])
+    return [object methodForSelector:getSel];
+
+  return NULL;
+#endif
+}
+
+id WOGetKVCValueUsingMethod(id object, NSString *_key) {
+  NSMethodSignature *sig = nil;
+  WOGetMethodType   gm;
+  const char        *retType;
+  SEL               getSel;
+  unsigned          keyLen;
+  
+  if (object == nil) return nil;
+  if (_key   == nil) return nil;
+  
+  // TODO: this su***
+  // TODO: add support for ivars
+  keyLen = [_key cStringLength];
+
+  {
+    char *buf;
+    buf = malloc(keyLen + 1);
+    [_key getCString:buf];
+#if APPLE_RUNTIME || NeXT_RUNTIME
+    getSel = sel_getUid(buf);
+#else
+    getSel = sel_get_uid(buf);
+#endif
+    if (getSel == NULL) // no such selector
+      return nil;
+    free(buf); buf = NULL;
+  }
+#if GNUSTEP_BASE_LIBRARY
+  if (!__objc_responds_to(object, getSel))
+    return nil;
+#endif
+  
+  gm.method = [object methodForSelector:getSel];
+  if (gm.method == NULL) // no such method
+    return nil;
+  
+  sig = [object methodSignatureForSelector:getSel];
+  if (sig == nil) // no signature
+    return nil;
+
+  {
+    static Class NSNumberClass = Nil;
+    id value = nil;
+
+    if (NSNumberClass == Nil)
+      NSNumberClass = [NSNumber class];
+    
+    retType = [sig methodReturnType];
+    
+    switch (*retType) {
+      case _C_CLASS:
+      case _C_ID:
+        value = gm.method(object, getSel);
+        value = AUTORELEASE(RETAIN(value));
+        break;
+
+      case _C_CHR:
+        value = [NSNumberClass numberWithChar:gm.cmethod(object, getSel)];
+        break;
+      case _C_UCHR:
+        value = [NSNumberClass numberWithUnsignedChar:
+                                 gm.ucmethod(object, getSel)];
+        break;
+
+      case _C_SHT:
+        value = [NSNumberClass numberWithShort:gm.smethod(object, getSel)];
+        break;
+      case _C_USHT:
+        value = [NSNumberClass numberWithUnsignedShort:
+                                 gm.usmethod(object, getSel)];
+        break;
+            
+      case _C_INT:
+        value = [NSNumberClass numberWithInt:gm.imethod(object, getSel)];
+        break;
+      case _C_UINT:
+        value = [NSNumberClass numberWithUnsignedInt:
+                                 gm.uimethod(object, getSel)];
+        break;
+
+      case _C_FLT:
+        value = [NSNumberClass numberWithFloat:gm.fmethod(object, getSel)];
+        break;
+      case _C_DBL:
+        value = [NSNumberClass numberWithDouble:gm.dmethod(object, getSel)];
+        break;
+        
+      case _C_CHARPTR: {
+        const char *cstr = gm.strmethod(object, getSel);
+        value = cstr ? [NSString stringWithCString:cstr] : nil;
+        break;
+      }
+            
+      default:
+        NSLog(@"%s: cannot get type '%c' yet (key=%@, method=%@) ..",
+              __PRETTY_FUNCTION__,
+              *retType, _key, NSStringFromSelector(getSel));
+        [NSException raise:@"WORuntimeException"
+                     format:@"cannot get type '%c' yet (key=%@, method=%@)",
+                       *retType, _key, NSStringFromSelector(getSel)];
+        return nil;
+    }
+    return value;
+  }
+}
diff --git a/skyrix-sope/NGObjWeb/OWResourceManager.m b/skyrix-sope/NGObjWeb/OWResourceManager.m
new file mode 100644 (file)
index 0000000..46ed12a
--- /dev/null
@@ -0,0 +1,1220 @@
+/*
+  Copyright (C) 2000-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$
+
+// ATTENTION: this class is for OGo legacy, so that WO compatibility changes 
+//            to WOResourceManager do not break OGo.
+//            So: do not use that class, its DEPRECATED!
+
+#include <NGObjWeb/OWResourceManager.h>
+#include "WOComponentDefinition.h"
+#include "WOComponent+private.h"
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+#import <Foundation/NSNull.h>
+#include "_WOStringTable.h"
+
+/*
+  Component Discovery and Page Creation
+
+    All WO code uses either directly or indirectly the OWResourceManager's
+    -pageWithName:languages: method to instantiate WO components.
+
+    This methods works in three steps:
+      
+      1. discovery of files associated with the component
+      
+      2. creation of a proper WOComponentDefinition, which is some kind
+         of 'blueprint' or 'class' for components
+      
+      3. component instantiation using the definition
+    
+    All the instantiation/setup work is done by a component definition, the
+    resource manager is only responsible for managing those 'blueprint'
+    resources.
+
+    If you want to customize component creation, you can supply your
+    own WOComponentDefinition in a subclass of OWResourceManager by
+    overriding:
+      - (WOComponentDefinition *)definitionForComponent:(id)_name
+        inFramework:(NSString *)_frameworkName
+        languages:(NSArray *)_languages
+*/
+
+/* 
+   Note: this was #if !COMPILE_FOR_GSTEP_MAKE - but there is no difference
+         between Xcode and gstep-make?!
+        The only possible difference might be that .wo wrappers are directly
+        in the bundle/framework root - but this doesn't relate to Resources.
+        
+        OK, this breaks gstep-make based template lookup which places .wo
+        wrappers in .woa/Resources/xxx.wo.
+        This is an issue because .wox are looked up in Contents/Resources
+        but .wo ones in just Resources.
+        
+        This issue should be fixed in recent woapp-gs.make ...
+*/
+#if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+#  define RSRCDIR_CONTENTS 1
+#endif
+
+@implementation OWResourceManager
+
++ (int)version {
+  return 4;
+}
+
+static Class    UrlClass             = Nil;
+static NSString *resourcePrefix      = @"";
+static NSString *rapidTurnAroundPath = nil;
+static NSNull   *null                = nil;
+static BOOL     debugOn                 = NO;
+static BOOL     debugComponentLookup    = NO;
+static BOOL     debugResourceLookup     = NO;
+static BOOL     genMissingResourceLinks = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL isInitialized = NO;
+  NSDictionary *defs;
+  if (isInitialized) return;
+  isInitialized = YES;
+    
+  null = [[NSNull null] retain];
+  UrlClass = [NSURL class];
+  
+  defs = [NSDictionary dictionaryWithObjectsAndKeys:
+                         [NSArray arrayWithObject:@"wo"],
+                         @"WOComponentExtensions",
+                       nil];
+  [ud registerDefaults:defs];
+  debugOn                 = [WOApplication isDebuggingEnabled];
+  debugComponentLookup    = [ud boolForKey:@"WODebugComponentLookup"];
+  debugResourceLookup     = [ud boolForKey:@"WODebugResourceLookup"];
+  genMissingResourceLinks = [ud boolForKey:@"WOGenerateMissingResourceLinks"];
+  rapidTurnAroundPath     = [[ud stringForKey:@"WOProjectDirectory"] copy];
+}
+
+static inline BOOL
+_pathExists(OWResourceManager *self, NSFileManager *fm, NSString *path)
+{
+  BOOL doesExist;
+  
+  if (self->existingPathes && (path != nil)) {
+    int i;
+    
+    i = (int)NSMapGet(self->existingPathes, path);
+    if (i == 0) {
+      doesExist = [fm fileExistsAtPath:path];
+      NSMapInsert(self->existingPathes, path, (void*)(doesExist ? 1 : 0xFF));
+    }
+    else
+      doesExist = i == 1 ? YES : NO;
+  }
+  else
+    doesExist = [fm fileExistsAtPath:path];
+  return doesExist;
+}
+
++ (void)setResourcePrefix:(NSString *)_prefix {
+  [resourcePrefix autorelease];
+  resourcePrefix = [_prefix copy];
+}
+  
+- (id)initWithPath:(NSString *)_path {
+#if __APPLE__
+  if ([_path length] == 0) {
+    NSLog(@"ERROR(%s): missing path!", __PRETTY_FUNCTION__);
+    /* this doesn't work with subclasses which do not require a path ... */
+#if 0
+    [self release];
+    return nil;
+#endif
+  }
+#endif
+  
+  if ((self = [super init])) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    NSString *rprefix = nil;
+    NSString *tmp;
+    
+    self->componentDefinitions =
+      NSCreateMapTable(NSObjectMapKeyCallBacks,
+                       NSObjectMapValueCallBacks,
+                       128);
+    self->stringTables = 
+      NSCreateMapTable(NSObjectMapKeyCallBacks,
+                       NSObjectMapValueCallBacks,
+                       16);
+    
+    tmp = [_path stringByStandardizingPath];
+    if (tmp) _path = tmp;
+    
+    self->base = [_path copy];
+    
+    if ([WOApplication isCachingEnabled]) {
+      self->existingPathes = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                              NSIntMapValueCallBacks,
+                                              256);
+    }
+    
+    rprefix = [ud stringForKey:@"WOResourcePrefix"];
+    if (rprefix) [[self class] setResourcePrefix:rprefix];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithPath:[[NGBundle mainBundle] bundlePath]];
+}
+
+- (void)dealloc {
+  if (self->existingPathes)       NSFreeMapTable(self->existingPathes);
+  if (self->stringTables)         NSFreeMapTable(self->stringTables);
+  if (self->componentDefinitions) NSFreeMapTable(self->componentDefinitions);
+  if (self->keyedResources)       NSFreeMapTable(self->keyedResources);
+  [self->w3resources release];
+  [self->resources   release];
+  [self->base        release];
+  [super dealloc];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+/* path methods */
+
+- (NSFileManager *)fileManager {
+  static NSFileManager *fm = nil;
+  if (fm == nil)
+    fm = [[NSFileManager defaultManager] retain];
+  return fm;
+}
+
+- (NSString *)basePath {
+  return self->base;
+}
+
+- (NSString *)resourcesPath {
+  NSFileManager *fm;
+  
+  if (self->resources)
+    return self->resources;
+  
+  fm = [self fileManager];
+  if ([self->base length] > 0) {
+    if (![fm fileExistsAtPath:self->base]) {
+      NSLog(@"WARNING(%s): Resources base path '%@' does not exist !",
+            __PRETTY_FUNCTION__, self->base);
+      return nil;
+    }
+  }
+  
+#if RSRCDIR_CONTENTS
+  if ([rapidTurnAroundPath length] > 0) {
+    /* 
+      In rapid turnaround mode, first check for a Resources subdir in the
+      project directory, then directly in the project dir.
+      Note: you cannot have both! Either put stuff in a Resources subdir *or*
+            in the project dir.
+    */
+    NSString *tmp;
+    BOOL isDir;
+    
+    tmp = [rapidTurnAroundPath stringByAppendingPathComponent:@"Resources"];
+    if (![fm fileExistsAtPath:tmp isDirectory:&isDir])
+      isDir = NO;
+    if (!isDir)
+      tmp = rapidTurnAroundPath;
+    
+    self->resources = [tmp copy];
+  }
+  else {
+    self->resources =
+      [[[self->base stringByAppendingPathComponent:@"Contents"]
+                    stringByAppendingPathComponent:@"Resources"] 
+                    copy];
+  }
+#else
+  self->resources =
+    [[self->base stringByAppendingPathComponent:@"Resources"] copy];
+#endif
+  
+  if ([self->resources length] > 0) {
+    if (![fm fileExistsAtPath:self->resources]) {
+      [self debugWithFormat:
+              @"WARNING(%s): Resources path %@ does not exist !",
+              __PRETTY_FUNCTION__, self->resources];
+      [self->resources release]; self->resources = nil;
+    }
+    else if (self->existingPathes && (self->resources != nil))
+      NSMapInsert(self->existingPathes, self->resources, (void*)1);
+  }
+  return self->resources;
+}
+
+- (NSString *)resourcesPathForFramework:(NSString *)_fw {
+  if (_fw == nil) 
+    return [self resourcesPath];
+  
+#if RSRCDIR_CONTENTS
+  return [[_fw stringByAppendingPathComponent:@"Contents"]
+               stringByAppendingPathComponent:@"Resources"];
+#else
+  return [_fw stringByAppendingPathComponent:@"Resources"];
+#endif
+}
+
+- (NSString *)webServerResourcesPath {
+  NSFileManager *fm;
+  
+  if (self->w3resources)
+    return self->w3resources;
+
+#if GNUSTEP_BASE_LIBRARY && 0
+  self->w3resources =
+    [[self->base stringByAppendingPathComponent:@"Resources/WebServer"] copy];
+#else  
+  self->w3resources =
+    [[self->base stringByAppendingPathComponent:@"WebServerResources"] copy];
+#endif
+  
+  fm = [self fileManager];
+  if ([self->w3resources length] == 0)
+    return nil;
+  
+  if (![fm fileExistsAtPath:self->w3resources]) {
+    static BOOL didLog = NO;
+    if (!didLog) {
+      didLog = YES;
+      [self debugWithFormat:
+              @"WARNING(%s): WebServerResources path '%@' does not exist !",
+              __PRETTY_FUNCTION__, self->w3resources];
+    }
+    [self->w3resources release]; self->w3resources = nil;
+  }
+  else if (self->existingPathes && (self->w3resources != nil))
+    NSMapInsert(self->existingPathes, self->w3resources, (void*)1);
+  
+  if (debugResourceLookup)
+    [self logWithFormat:@"WebServerResources: '%@'", self->w3resources];
+  return self->w3resources;
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages
+{
+  NSFileManager *fm;
+  NSString      *resource = nil;
+  unsigned      langCount;
+  NSString      *w3rp, *rp;
+  
+  if (debugResourceLookup) {
+    [self logWithFormat:@"lookup '%@' bundle=%@ languages=%@", 
+          _name, _frameworkName, [_languages componentsJoinedByString:@","]];
+  }
+  
+  fm        = [self fileManager];
+  langCount = [_languages count];
+  
+  if ((w3rp = [self webServerResourcesPath])) {
+    NSString *langPath = nil;
+    unsigned i;
+    
+    // first check Language.lproj in WebServerResources
+    for (i = 0; i < langCount; i++) {
+      langPath = [_languages objectAtIndex:i];
+      langPath = [langPath stringByAppendingPathExtension:@"lproj"];
+      langPath = [w3rp stringByAppendingPathComponent:langPath];
+      
+      if (!_pathExists(self, fm, langPath)) {
+        if (debugResourceLookup) {
+          [self logWithFormat:
+                  @"  no language project for '%@' in WebServerResources: %@",
+                  [_languages objectAtIndex:i],resource];
+        }
+        continue;
+      }
+      
+      resource = [langPath stringByAppendingPathComponent:_name];
+      
+      if (debugResourceLookup) 
+        [self logWithFormat:@"  check in WebServerResources: %@", resource];
+      if (_pathExists(self, fm, resource))
+        return resource;
+    }
+    
+    /* next check in WebServerResources itself */
+    resource = [w3rp stringByAppendingPathComponent:_name];
+    if (debugResourceLookup) 
+      [self logWithFormat:@"  check in WebServerResources-flat: %@", resource];
+    if (_pathExists(self, fm, resource))
+      return resource;
+  }
+  
+  if ((rp = [self resourcesPathForFramework:_frameworkName])) {
+    NSString *langPath = nil;
+    unsigned i;
+    
+    if (debugResourceLookup) [self logWithFormat:@"  path %@", rp];
+    
+    // first check Language.lproj in Resources
+    for (i = 0; i < langCount; i++) {
+      langPath = [_languages objectAtIndex:i];
+      langPath = [langPath stringByAppendingPathExtension:@"lproj"];
+      langPath = [rp stringByAppendingPathComponent:langPath];
+      
+      if (_pathExists(self, fm, langPath)) {
+        resource = [langPath stringByAppendingPathComponent:_name];
+
+        if (debugResourceLookup) 
+          [self logWithFormat:@"  check in Resources: %@", resource];
+        if (_pathExists(self, fm, resource))
+          return resource;
+      }
+    }
+    
+    // next check in Resources itself
+    resource = [rp stringByAppendingPathComponent:_name];
+    if (debugResourceLookup) 
+      [self logWithFormat:@"  check in Resources-flat: %@", resource];
+    if (_pathExists(self, fm, resource))
+      return resource;
+  }
+  
+  /* and last check in the application directory */
+  if (_pathExists(self, fm, self->base)) {
+    resource = [self->base stringByAppendingPathComponent:_name];
+    if (_pathExists(self, fm, resource))
+      return resource;
+  }
+  return nil;
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name {
+  IS_DEPRECATED;
+  return [self pathForResourceNamed:_name inFramework:nil languages:nil];
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
+  _name = [_name stringByAppendingPathExtension:_type];
+  return [self pathForResourceNamed:_name];
+}
+
+/* URL methods */
+
+- (NSString *)urlForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages
+  request:(WORequest *)_request
+{
+  WOApplication *app;
+  NSString *resource = nil, *tmp;
+  
+  app = [WOApplication application];
+  
+  if (_languages == nil)
+    _languages = [_request browserLanguages];
+  
+  resource = [self pathForResourceNamed:_name
+                   inFramework:_frameworkName
+                   languages:_languages];
+#if RSRCDIR_CONTENTS
+  if ([resource rangeOfString:@"/Contents/"].length > 0) {
+    resource = [resource stringByReplacingString:@"/Contents"
+                         withString:@""];
+  }
+#endif
+#if 0
+  tmp = [resource stringByStandardizingPath];
+  if (tmp) resource = tmp;
+#endif
+  
+  if (resource) {
+    NSString *path = nil, *sbase;
+    unsigned len;
+    
+    sbase = self->base;
+    tmp  = [sbase commonPrefixWithString:resource options:0];
+    
+    len  = [tmp length];
+    path = [sbase    substringFromIndex:len];
+    tmp  = [resource substringFromIndex:len];
+    if (([path length] > 0) && ![tmp hasPrefix:@"/"] && ![tmp hasPrefix:@"\\"])
+      path = [path stringByAppendingString:@"/"];
+    path = [path stringByAppendingString:tmp];
+
+#ifdef __WIN32__
+    {
+      NSArray *cs;
+      cs   = [path componentsSeparatedByString:@"\\"];
+      path = [cs componentsJoinedByString:@"/"];
+    }
+#endif
+    
+    if (path) {
+      static NSString *suffix = nil;
+      NSMutableString *url = nil;
+
+      if (suffix == nil) {
+       NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+        suffix = [ud stringForKey:@"WOApplicationSuffix"];
+      }
+      
+      url = [[NSMutableString alloc] initWithCapacity:256];
+#if 0
+      [url appendString:[_request adaptorPrefix]];
+#endif
+      if (resourcePrefix)
+        [url appendString:resourcePrefix];
+      if (![url hasSuffix:@"/"]) [url appendString:@"/"];
+      [url appendString:app ? [app name] : [_request applicationName]];
+      [url appendString:suffix];
+      if (![path hasPrefix:@"/"]) [url appendString:@"/"];
+      [url appendString:path];
+      
+      path = [url copy];
+      [url release];
+      
+      return [path autorelease];
+    }
+  }
+  
+  if (genMissingResourceLinks) {
+    return [NSString stringWithFormat:
+                       @"/missingresource?name=%@&application=%@",
+                       _name, app ? [app name] : [_request applicationName]];
+  }
+  return nil;
+}
+
+- (NSString *)urlForResourceNamed:(NSString *)_name {
+  IS_DEPRECATED;
+  return [self urlForResourceNamed:_name
+               inFramework:nil
+               languages:nil
+               request:nil];
+}
+- (NSString *)urlForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
+  return [self urlForResourceNamed:
+                 [_name stringByAppendingPathExtension:_type]];
+}
+
+/* string tables */
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_defaultValue
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_languages;
+{
+  NSFileManager  *fm;
+  _WOStringTable *table     = nil;
+  NSString       *path      = nil;
+  
+  fm = [self fileManager];
+  
+  if (_tableName == nil)
+    _tableName = @"default";
+
+  /* take a look whether a matching table is already loaded */
+  
+  path = [_tableName stringByAppendingPathExtension:@"strings"];
+  path = [self pathForResourceNamed:path inFramework:_framework 
+               languages:_languages];
+  
+  if (path != nil) {
+    if ((table = NSMapGet(self->stringTables, path)) == NULL) {
+      if ([fm fileExistsAtPath:path]) {
+       table = [_WOStringTable allocWithZone:[self zone]]; /* for gcc */
+        table = [table initWithPath:path];
+        NSMapInsert(self->stringTables, path, table);
+        [table release];
+      }
+    }
+    if (table != nil)
+      return [table stringForKey:_key withDefaultValue:_defaultValue];
+  }
+  /* didn't found table in cache */
+  
+  return _defaultValue;
+}
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_default
+  languages:(NSArray *)_languages
+{
+  return [self stringForKey:_key inTableNamed:_tableName
+               withDefaultValue:_default
+               inFramework:nil
+               languages:_languages];
+}
+
+
+/* NSLocking */
+
+- (void)lock {
+}
+- (void)unlock {
+}
+
+/* component definitions */
+
+- (NSString *)pathToComponentNamed:(NSString *)_name
+  inFramework:(NSString *)_framework
+{
+  /* search for component wrapper .. */
+  NSEnumerator *e;
+  NSString     *ext;
+  
+  if (_name == nil) {
+#if DEBUG
+    NSLog(@"WARNING(%s): tried to get path to component with <nil> name !",
+          __PRETTY_FUNCTION__);
+#endif
+    return nil;
+  }
+  
+  /* scan for name.$ext resource ... */
+  e = [[[NSUserDefaults standardUserDefaults]
+                        arrayForKey:@"WOComponentExtensions"]
+                        objectEnumerator];
+    
+  while ((ext = [e nextObject])) {
+    NSString *specName;
+    NSString *path;
+      
+    specName = [_name stringByAppendingPathExtension:ext];
+      
+    path = [self pathForResourceNamed:specName
+                 inFramework:_framework
+                 languages:nil];
+    if (path) return path;
+  }
+  return nil;
+}
+
+- (NSString *)pathToComponentNamed:(NSString *)_name
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_langs
+{
+  return [self pathToComponentNamed:_name inFramework:_framework];
+}
+
+- (WOComponentDefinition *)_definitionForPathlessComponent:(NSString *)_name
+  languages:(NSArray *)_languages
+{
+  /* definition factory */
+  WOComponentDefinition *cdef;
+  
+  cdef = [[WOComponentDefinition allocWithZone:[self zone]]
+                                 initWithName:_name
+                                 path:nil
+                                 baseURL:nil
+                                 frameworkName:nil];
+  
+  return [cdef autorelease];
+}
+
+- (WOComponentDefinition *)_definitionWithName:(NSString *)_name
+  url:(NSURL *)_url
+  baseURL:(NSURL *)_baseURL
+  frameworkName:(NSString *)_fwname
+{
+  /* definition factory */
+  static Class DefClass;
+  id cdef;
+  
+  if (DefClass == Nil)
+    DefClass = [WOComponentDefinition class];
+  
+  cdef = [[DefClass alloc] initWithName:_name
+                           path:[_url path]
+                           baseURL:_baseURL frameworkName:_fwname];
+  return cdef;
+}
+- (WOComponentDefinition *)_definitionWithName:(NSString *)_name
+  path:(NSString *)_path
+  baseURL:(NSURL *)_baseURL
+  frameworkName:(NSString *)_fwname
+{
+  NSURL *url;
+  
+  url = ([_path length] > 0)
+    ? [[[NSURL alloc] initFileURLWithPath:_path] autorelease]
+    : nil;
+  
+  return [self _definitionWithName:_name url:url
+               baseURL:_baseURL frameworkName:_fwname];
+}
+
+- (WOComponentDefinition *)_cachedDefinitionForComponent:(id)_name
+  languages:(NSArray *)_languages
+{
+  NSArray *cacheKey;
+  id      cdef;
+
+  if (self->componentDefinitions == NULL)
+    return nil;
+  if (![[WOApplication application] isCachingEnabled])
+    return nil;
+  
+  cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
+  cdef     = NSMapGet(self->componentDefinitions, cacheKey);
+  
+  return cdef;
+}
+- (WOComponentDefinition *)_cacheDefinition:(id)_cdef
+  forComponent:(id)_name
+  languages:(NSArray *)_languages
+{
+  NSArray *cacheKey;
+
+  if (self->componentDefinitions == NULL)
+    return _cdef;
+  if (![[WOApplication application] isCachingEnabled])
+    return _cdef;
+  
+  cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
+  NSMapInsert(self->componentDefinitions, cacheKey, _cdef ? _cdef : null);
+
+  return _cdef;
+}
+
+- (NSString *)resourceNameForComponentNamed:(NSString *)_name {
+  return [_name stringByAppendingPathExtension:@"wox"];
+}
+
+- (BOOL)_isValidWrapperDirectory:(NSString *)_path 
+  containingTemplate:(NSString *)_name 
+{
+  /* 
+     Check whether this actually does contain a template! 
+       
+     This is new and hopefully doesn't break anything, but as far as I can
+     see checking for Component.html inside should do the right thing (unless
+     there are template wrappers which are not .wo wrappers ;-)
+  */
+  NSString *htmlPath;
+  
+  htmlPath = [_name stringByAppendingPathExtension:@"html"];
+  htmlPath = [_path stringByAppendingPathComponent:htmlPath];
+  return [[self fileManager] fileExistsAtPath:htmlPath];
+}
+
+- (WOComponentDefinition *)_processWrapperLanguageProjects:(NSString *)_name
+  componentPath:(NSString *)componentPath
+  languages:(NSArray *)_langs
+{
+  /* 
+     this looks for language projects contained in template wrapper 
+     directories, eg "Main.wo/English.lproj/"
+  */
+  WOComponentDefinition *cdef = nil;
+  NSFileManager         *fm   = nil;
+  NSEnumerator *languages;
+  NSString     *language;
+  NSString     *sname;
+  BOOL         doesCache;
+
+  if ([_langs count] == 0)
+    return nil;
+  
+  doesCache = [[WOApplication application] isCachingEnabled];
+  fm        = [self fileManager];
+  sname     = [_name stringByAppendingString:@"\t"];
+  
+  languages = [_langs objectEnumerator];
+  while ((language = [languages nextObject])) {
+    NSString *compoundKey  = nil;
+    NSString *languagePath = nil;
+    BOOL     isDirectory   = NO;
+    NSString *baseUrl = nil;
+    
+    // [self logWithFormat:@"check %@ / %@", _name, language];
+    
+    compoundKey = [sname stringByAppendingString:language];
+    if (doesCache) {
+      cdef = NSMapGet(self->componentDefinitions, compoundKey);
+      
+      if (cdef == (id)null)
+       /* resource does not exist */
+       continue;
+          
+      [cdef touch];
+      if (cdef) return cdef; // found definition in cache
+    }
+        
+    /* take a look into the file system */
+    languagePath = [language stringByAppendingPathExtension:@"lproj"];
+    languagePath = [componentPath stringByAppendingPathComponent:languagePath];
+        
+    if (![fm fileExistsAtPath:languagePath isDirectory:&isDirectory]) {
+      if (doesCache) {
+       // register null in cache, so that we know it's non-existent
+       NSMapInsert(self->componentDefinitions, compoundKey, null);
+      }
+      continue;
+    }
+    
+    if (!isDirectory) {
+      NSLog(@"WARNING(%s): language entry %@ is not a directory !",
+           __PRETTY_FUNCTION__, languagePath);
+      if (doesCache && (compoundKey != nil)) {
+       // register null in cache, so that we know it's non-existent
+       NSMapInsert(self->componentDefinitions, compoundKey, null);
+      }
+      continue;
+    }
+    
+    /* 
+       Now check whether this actually does contain a template! 
+       
+       This is new and hopefully doesn't break anything, but as far as I can
+       see checking for Component.html inside should do the right thing (unless
+       there are template wrappers which are not .wo wrappers ;-)
+    */
+    if (![self _isValidWrapperDirectory:languagePath
+              containingTemplate:_name]){
+      [self debugWithFormat:@"no HTML template for inside lproj '%@': '%@'",
+             _name, languagePath];
+      if (doesCache && (compoundKey != nil)) {
+       // register null in cache, so that we know it's non-existent
+       NSMapInsert(self->componentDefinitions, compoundKey, null);
+      }
+      continue;
+    }
+    
+    /* construct the base URL */
+    
+    baseUrl = [[[WOApplication application] baseURL] absoluteString];
+    baseUrl = [NSString stringWithFormat:@"%@/%@.lproj/%@.wo",
+                         baseUrl, language, _name];
+    
+    /* create WOComponentDefinition object */
+    
+    cdef = [self _definitionWithName:_name
+                path:languagePath
+                baseURL:[NSURL URLWithString:baseUrl]
+                frameworkName:nil];
+    if (cdef == nil) {
+      NSLog(@"WARNING(%s): could not load component definition of "
+           @"'%@' from language project: %@", 
+           __PRETTY_FUNCTION__, _name, languagePath);
+      if (doesCache && (compoundKey != nil)) {
+       // register null in cache, so that we know it's non-existent
+       NSMapInsert(self->componentDefinitions, compoundKey, null);
+      }
+      continue;
+    }
+    
+    if (doesCache && (compoundKey != nil)) {
+      // register in cache
+      NSMapInsert(self->componentDefinitions, compoundKey, cdef);
+      [cdef release];
+    }
+    else {
+      // don't register in cache
+      cdef = [cdef autorelease];
+    }
+    
+    return cdef;
+  }
+  
+  return nil; /* no lproj containing templates was found */
+}
+
+- (WOComponentDefinition *)definitionForComponent:(id)_name
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_languages
+{
+  // TODO: this method is too large
+  WOApplication         *app;
+  NSFileManager         *fm            = nil;
+  WOComponentDefinition *cdef          = nil;
+  NSURL                 *componentURL;
+  BOOL                  doesCache, isDir;
+  
+  app       = [WOApplication application];
+  doesCache = [app isCachingEnabled];
+  
+  /* lookup component path */
+  
+  if ([_name isKindOfClass:UrlClass]) {
+    componentURL = _name;
+    _name = [componentURL path];
+    if (debugComponentLookup) {
+      [self debugWithFormat:@"using URL %@ for component %@",
+              componentURL, _name];
+    }
+  }
+  else {
+    NSString *path;
+    
+    if (_framework == nil && _name != nil) {
+      Class clazz;
+      
+      /* 
+         Note: this is a bit of a hack ..., actually this method should never
+         be called without a framework and pages shouldn't be instantiated
+         without specifying their framework.
+         But for legacy reasons this needs to be done and seems to work without
+         problems. It is required for loading components from bundles.
+      */
+      if ((_framework = rapidTurnAroundPath) == nil) {
+        if ((clazz = NSClassFromString(_name)))
+          _framework = [[NSBundle bundleForClass:clazz] bundlePath];
+      }
+    }
+    
+    if (debugComponentLookup) {
+      [self logWithFormat:@"lookup: component '%@' in framework '%@'", 
+              _name, _framework];
+    }
+    
+    /* look for .wox component */
+    
+    path = [self pathForResourceNamed:
+                   [self resourceNameForComponentNamed:_name]
+                 inFramework:_framework
+                 languages:_languages];
+    
+    if (debugComponentLookup)
+      [self logWithFormat:@"lookup:  path-to-resource: '%@'", path];
+    
+    /* look for .wo component */
+    
+    if ([path length] == 0) {
+      path = [self pathToComponentNamed:_name
+                   inFramework:_framework
+                   languages:_languages];
+      if (debugComponentLookup)
+        [self logWithFormat:@"lookup:  path-to-component: '%@'", path];
+    }
+    
+    /* make URL from path */
+    
+    componentURL = ([path length] > 0)
+      ? [[[UrlClass alloc] initFileURLWithPath:path] autorelease]
+      : nil;
+  }
+  
+  if (debugComponentLookup) {
+    [self logWithFormat:@"  component='%@' in framework='%@'", 
+            _name, _framework];
+    [self logWithFormat:@"  => '%@'", [componentURL absoluteString]];
+  }
+  
+  /* check whether it's a 'template-less' component ... */
+  
+  if (componentURL == nil) {
+    /* did not find component wrapper ! */
+    [app debugWithFormat:@"  component '%@' has no template !", _name];
+    
+    cdef = [self _definitionForPathlessComponent:_name languages:_languages];
+    return cdef;
+  }
+  
+  fm = [self fileManager];
+  
+  /* ensure that the component exists */
+  
+  isDir = NO;
+  if ([componentURL isFileURL]) {
+    NSString *componentPath;
+    
+    componentPath = [componentURL path];
+    
+    if (![fm fileExistsAtPath:componentPath isDirectory:&isDir]) {
+      [[WOApplication application]
+                      debugWithFormat:
+                        @"%s: did not find component '%@' at path '%@' !",
+                        __PRETTY_FUNCTION__,
+                        _name, componentPath];
+      return nil;
+    }
+    
+    /* if the component spec is a directory (eg a .wo), scan lproj's inside */
+    if (isDir && [_languages count] > 0) {
+      if (debugComponentLookup) {
+       [self logWithFormat:@"  check wrapper languages (%d)", 
+             [_languages count]];
+      }
+      cdef = [self _processWrapperLanguageProjects:_name
+                  componentPath:componentPath
+                  languages:_languages];
+      if (cdef != nil) {
+       if (debugComponentLookup)
+         [self logWithFormat:@"  => FOUND: %@", cdef];
+       return cdef;
+      }
+      else if (debugComponentLookup)
+       [self logWithFormat:@"  ... no language template found ..."];
+    }
+  }
+  
+  /* look flat */
+  
+  if (doesCache) {
+    cdef = NSMapGet(self->componentDefinitions, componentURL);
+    if (cdef == (id)null)
+      /* resource does not exist */
+      return nil;
+    [cdef touch];
+    
+    if (cdef != nil) return cdef; // found definition in cache
+  }
+
+  /* 
+     in case the "componentURL" is a directory, check whether it contains
+     an HTML file
+  */
+  if (isDir) {
+    if (![self _isValidWrapperDirectory:[componentURL path]
+              containingTemplate:_name]) {
+      if (debugComponentLookup)
+       [self logWithFormat:@"  not a valid wrapper '%@': '%@'",
+               _name, [componentURL absoluteString]];
+      if (doesCache) {
+        /* register null in cache, so that we know it's non-existent */
+        NSMapInsert(self->componentDefinitions, componentURL, null);
+      }
+      return nil;
+    }
+  }
+  
+  /* take a look into the file system */
+  {
+    NSString *baseUrl = nil;
+    
+    baseUrl = [NSString stringWithFormat:@"%@/%@",
+                          [[app baseURL] absoluteString], 
+                         [_name lastPathComponent]];
+    
+    cdef = [self _definitionWithName:_name
+                 url:componentURL
+                 baseURL:[NSURL URLWithString:baseUrl]
+                 frameworkName:nil];
+    if (cdef == nil) {
+      NSLog(@"WARNING(%s): could not load component definition of '%@' from "
+            @"component wrapper: '%@'", 
+            __PRETTY_FUNCTION__, _name, componentURL);
+      if (doesCache) {
+        /* register null in cache, so that we know it's non-existent */
+        NSMapInsert(self->componentDefinitions, componentURL, null);
+      }
+      return nil;
+    }
+    
+    if (doesCache) {
+      /* register in cache */
+      NSMapInsert(self->componentDefinitions, componentURL, cdef);
+      [cdef release];
+    }
+    else
+      /* don't register in cache, does not cache */
+      cdef = [cdef autorelease];
+
+    return cdef;
+  }
+  
+  /* did not find component */
+  return nil;
+}
+- (WOComponentDefinition *)definitionForComponent:(id)_name
+  languages:(NSArray *)_langs
+{
+  return [self definitionForComponent:_name inFramework:nil languages:_langs];
+}
+
+- (WOComponentDefinition *)__definitionForComponent:(id)_name
+  languages:(NSArray *)_languages
+{
+  WOComponentDefinition *cdef;
+  
+  /* look into cache */
+  
+  cdef = [self _cachedDefinitionForComponent:_name languages:_languages];
+  if (cdef) {
+    if (cdef == (id)null)
+      /* component does not exist */
+      return nil;
+
+    if ([cdef respondsToSelector:@selector(touch)])
+      [cdef touch];
+    return cdef;
+  }
+  
+  /* not cached, create a definition */
+  
+  cdef = [self definitionForComponent:_name languages:_languages];
+
+  /* cache created definition */
+  
+  return [self _cacheDefinition:cdef forComponent:_name languages:_languages];
+}
+
+- (WOElement *)templateWithName:(NSString *)_name
+  languages:(NSArray *)_languages
+{
+  WOComponentDefinition *cdef;
+  
+  cdef = [self __definitionForComponent:_name languages:_languages];
+  if (cdef == nil) return nil;
+  
+  return (WOElement *)[cdef template];
+}
+
+- (WOComponent *)pageWithName:(NSString *)_name
+  languages:(NSArray *)_languages
+{
+  /* 
+     TODO: this appears to be deprecated since the WOComponent initializer
+           is now -initWithContext: and we have no context here ...
+  */
+  NSAutoreleasePool     *pool      = nil;
+  WOComponentDefinition *cdef      = nil;
+  WOComponent           *component = nil;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    cdef = [self __definitionForComponent:_name languages:_languages];
+    if (cdef) {
+      component = 
+       [cdef instantiateWithResourceManager:(WOResourceManager *)self 
+             languages:_languages];
+      component = [component retain];
+    }
+  }
+  [pool release];
+  
+  return [component autorelease];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: path=%@>",
+                     [self class], self, self->base];
+                   
+}
+
+@end /* OWResourceManager */
+
+@implementation OWResourceManager(KeyedData)
+
+- (void)setData:(NSData *)_data
+  forKey:(NSString *)_key
+  mimeType:(NSString *)_type
+  session:(WOSession *)_session
+{
+  if ((_key == nil) || (_data == nil))
+    return;
+  if (_type == nil)
+    _type = @"application/octet-stream";
+  
+  [self lock];
+  
+  if (self->keyedResources == NULL) {
+    self->keyedResources = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                            NSObjectMapValueCallBacks,
+                                            128);
+  }
+
+  NSMapInsert(self->keyedResources,
+              _key,
+              [NSDictionary dictionaryWithObjectsAndKeys:
+                              _type, @"mimeType",
+                              _key,  @"key",
+                              _data, @"data",
+                            nil]);
+  
+  [self unlock];
+}
+
+- (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid {
+  id tmp;
+
+  [self lock];
+  
+  if (self->keyedResources)
+    tmp = NSMapGet(self->keyedResources, _key);
+  else
+    tmp = nil;
+  
+  tmp = [[tmp retain] autorelease];
+  
+  [self unlock];
+
+  return tmp;
+}
+
+- (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session {
+  [self lock];
+  
+  if (self->keyedResources)
+    NSMapRemove(self->keyedResources, _key);
+  
+  [self unlock];
+}
+
+- (void)flushDataCache {
+  [self lock];
+
+  if (self->keyedResources) {
+    NSFreeMapTable(self->keyedResources);
+    self->keyedResources = NULL;
+  }
+  
+  [self unlock];
+}
+
+@end /* OWResourceManager(KeyedData) */
+
+@implementation OWResourceManager(JavaScript)
+
+- (id)_jsfunc_pathForResourceNamed:(NSArray *)_args {
+  unsigned argc = [_args count];
+  
+  return [self pathForResourceNamed:
+                 argc > 0 ? [_args objectAtIndex:0] : nil
+               inFramework:argc > 1 ? [_args objectAtIndex:1] : nil
+               languages:argc > 2 ? [_args objectAtIndex:2] : nil];
+}
+
+- (id)_jsfunc_loadPropertyListNamed:(NSArray *)_args {
+  NSString *s;
+  
+  if ((s = [self _jsfunc_pathForResourceNamed:_args]) == nil)
+    return nil;
+  
+  if ((s = [NSString stringWithContentsOfFile:s]) == nil)
+    return nil;
+
+  return [s propertyList];
+}
+
+@end /* OWResourceManager(JavaScript) */
diff --git a/skyrix-sope/NGObjWeb/OWViewRequestHandler.m b/skyrix-sope/NGObjWeb/OWViewRequestHandler.m
new file mode 100644 (file)
index 0000000..b90c15a
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/OWViewRequestHandler.h>
+#include "WORequestHandler+private.h"
+#include "WOContext+private.h"
+#include "WOComponent+private.h"
+#include "WOApplication+private.h"
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSessionStore.h>
+#include <NGObjWeb/WOSession.h>
+#include "common.h"
+
+NSString *OWAppDidRefuseSessionName = @"OWAppDidRefuseSession";
+static BOOL perflog = NO;
+
+//#define USE_POOLS 1
+
+#if USE_POOLS
+#  warning extensive pools are enabled ...
+#endif
+
+@implementation OWViewRequestHandler
+
++ (int)version {
+  return [super version] + 0 /* 2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  perflog = [[NSUserDefaults standardUserDefaults]
+                             boolForKey:@"OWViewRequestHandlerProfile"];
+}
+
+- (NSString *)loggingPrefix {
+  return @"[ow-handler]";
+}
+
+- (id)init {
+  //NSLog(@"DEPRECATED: OWViewRequestHandler is being allocated ...");
+  return [super init];
+}
+
+- (WOResponse *)runTransactionWithContext:(WOContext *)_ctx {
+  WOApplication *app      = nil;
+  WOSession     *sn       = nil;
+  WOResponse    *response = nil;
+  id<NSObject,WOActionResults> result;
+  
+  app = [_ctx application];
+  sn  = [_ctx session];
+  NSAssert(_ctx != nil, @"no context available");
+  NSAssert(sn   != nil, @"no session available");
+  NSAssert(app  != nil, @"no application available in context");
+
+  /* take request values */
+
+  [app takeValuesFromRequest:[_ctx request] inContext:_ctx];
+
+  /* invoke action */
+    
+  result = [app invokeActionForRequest:[_ctx request] inContext:_ctx];
+    
+  /* check whether there is an page set at all ! */
+
+  if ([_ctx page] == nil) {
+    /* no page is set yet, load Main .. */
+    WOComponent *mainPage;
+
+    if ((mainPage = [app pageWithName:nil inContext:_ctx])) {
+      [_ctx setPage:mainPage];
+      [mainPage _awakeWithContext:_ctx];
+    }
+  }
+  
+  /* make response */
+  
+  if ((result == nil) || [result isKindOfClass:[WOComponent class]]) {
+    /* determine the response page */
+      
+    if (result == nil) {
+      /* make the request page the response page */
+      if ((result = [_ctx page]) == nil) {
+        /* no request page (probably the first request) */
+        result = [app pageWithName:nil inContext:_ctx];
+        [(id)result _awakeWithContext:_ctx];
+        [_ctx setPage:(WOComponent *)result];
+      }
+    }
+
+    response = [self generateResponseForComponent:(WOComponent *)result
+                     inContext:_ctx
+                     application:app];
+      
+    /* save page in session */
+      
+    if ([_ctx savePageRequired]) {
+      [sn savePage:[_ctx page]];
+#if DEBUG && 0
+      [self logWithFormat:@"saved page ..."];
+#endif
+    }
+#if DEBUG && 0
+    else {
+      [self logWithFormat:@"no save page required ..."];
+    }
+#endif
+  }
+  else {
+    /* generate response from WOActionResult */
+    if ([result respondsToSelector:@selector(generateResponse)]) {
+      [app debugWithFormat:@"generating response for result .."];
+      response = [result generateResponse];
+    }
+    else {
+      [app logWithFormat:
+             @"action result (class=%@) doesn't conform to "
+             @"WOActionResult protocol !",
+             NSStringFromClass([result class])];
+        
+      response = [[WOResponse alloc] init];
+      [response setStatus:200];
+      [response appendContentString:@"<pre>"];
+      [response appendContentHTMLString:
+                  @"ERROR:\n"
+                  @"Result of action doesn't conform to WOActionResult "
+                  @"protocol:\n---\n"
+                  @"Content-Class: "];
+      [response appendContentHTMLString:
+                   [NSStringFromClass([result class]) description]];
+      [response appendContentHTMLString:@"\nContent:\n"];
+      [response appendContentHTMLString:[result description]];
+      [response appendContentString:@"</pre>\n"];
+      AUTORELEASE(response);
+    }
+  }
+    
+  [_ctx sleepComponents];
+    
+  return response;
+}
+
+- (NSString *)sessionIDFromRequest:(WORequest *)_request
+  application:(WOApplication *)_app
+{
+  NSString *sessionId = nil;
+  id tmp;
+  
+  if ((tmp = [_request formValueForKey:WORequestValueSenderID]) == nil) {
+    if ([[_request requestHandlerPath] length] > 0) {
+      /* traditional style URLs */
+      NSArray *spath;
+      
+      spath = [_request requestHandlerPathArray];
+      if ([spath count] > 0)
+        sessionId = [spath objectAtIndex:0];
+    }
+  }
+  
+  if ([sessionId length] == 0)
+    sessionId = [_app sessionIDFromRequest:_request];
+  
+  return sessionId;
+}
+
+- (BOOL)autocreateSessionForRequest:(WORequest *)_request {
+  /* autocreate a session if none was restored */
+  return YES;
+}
+- (BOOL)requiresSessionForRequest:(WORequest *)_request {
+  /* _ensure_ that a session is available */
+  return YES;
+}
+
+- (WOResponse *)handleRequest:(WORequest *)_request
+  inContext:(WOContext *)context
+  session:(WOSession *)session
+  application:(WOApplication *)app
+{
+  NSString       *requestContextID;
+  WOResponse     *response;
+  WOComponent    *requestComponent;
+  NSString       *cid;
+  NSTimeInterval startRunTx = 0.0;
+  id tmp;
+
+  *(&requestContextID) = nil;
+  *(&response)         = nil;
+  *(&requestComponent) = nil;
+  
+  NSAssert(session, @"no session given !");
+
+  /*
+    parse handler path (URL)
+      
+    The format is:
+      session/context-id.element-id
+      
+    or
+      pageName?_i=context-id.element-id&wosid=session&_c=context-id
+  */
+  
+  if ((tmp = [_request formValueForKey:WORequestValueSenderID])) {
+    /* new query-para style URL */
+    [context setRequestSenderID:tmp];
+    
+    if ((tmp = [_request formValueForKey:WORequestValueContextID]))
+      requestContextID = tmp;
+    else
+      requestContextID = [context currentElementID];
+  }
+  else if ([[_request requestHandlerPath] length] > 0) {
+    /* traditional style URLs */
+    NSArray *spath;
+    
+    spath = [_request requestHandlerPathArray];
+      
+    if ([spath count] > 1) {
+      [context setRequestSenderID:[spath objectAtIndex:1]];
+      requestContextID = [context currentElementID];
+    }
+    // at idx 0 => sessionId
+  }
+  
+  /* determine request component */
+
+  if ([[self sessionIDFromRequest:_request application:app]
+             isEqualToString:[session sessionID]])
+    cid = [context currentElementID];
+  else
+    /* the session is different, was autocreated ... */
+    cid = nil;
+  
+  if ((session != nil) && ([cid length] > 0)) {
+    requestComponent = [session restorePageForContextID:cid];
+    
+    if (requestComponent == nil) {
+      /* could not restore page ... */
+      response = [app handlePageRestorationErrorInContext:context];
+      if (response) {
+        [self logWithFormat:
+                @"returning because of page restoration error ..."];
+        return response;
+      }
+    }
+  }
+  if (requestComponent) {
+    [context setPage:requestComponent];
+    [requestComponent _awakeWithContext:context];
+  }
+  
+  /* run transaction */
+
+  if (perflog)
+    startRunTx = [[NSDate date] timeIntervalSince1970];
+  
+  response = [self runTransactionWithContext:context];
+  
+  if (perflog) {
+    NSTimeInterval rt;
+    rt = [[NSDate date] timeIntervalSince1970] - startRunTx;
+    [self logWithFormat:@"running tx took %4.3fs.", rt < 0.0 ? -1.0 : rt];
+  }
+  
+  return response;
+}
+
+@end /* OWViewRequestHandler */
diff --git a/skyrix-sope/NGObjWeb/README b/skyrix-sope/NGObjWeb/README
new file mode 100644 (file)
index 0000000..70ecc5d
--- /dev/null
@@ -0,0 +1,76 @@
+# $Id$
+
+NGObjWeb Library
+  Part of the SKYRiX Object Publishing Environment
+  Copyright (C) 2000-2003 SKYRIX Software AG - http://www.skyrix.com/
+
+Subprojects
+===========
+
+- DynamicElements
+- Associations
+- Templates
+- NGHttp
+- WOHttpAdaptor
+- NGXmlRpc
+- SoObjects
+- WebDAV
+- SoOFS
+
+UserDefaults
+============
+
+    Default                 | Type   | Example Value
+    =============================================================
+    WOAdaptor               | String | WOHttpAdaptor
+    WOCachingEnabled        | bool   | NO
+    WODebuggingEnabled      | bool   | YES
+    WODefaultSessionTimeOut | int    | 3600
+    WOIsRedirectionEnabled  | bool   | NO
+    WOPort                  | String | "*:20000"
+    WOResourcePrefix        | String | "http://localhost:9000"
+    WORunMultithreaded      | bool   | NO
+    WOSendMail              | String | /usr/lib/sendmail
+    WOSMTPHost              | String | mail
+    SNSPort                 | String | "/tmp/.snsd"
+    SNSPingInterval         | int    | 10
+    SNSLogActivity          | bool   | NO
+    WORequestValueSessionID | string | wosid
+    WORequestValueInstance  | string | woinst
+    WOProxyServer           | string | 
+    WONoProxySuffixes      | array  |
+    WODebugHttpTransaction  | bool   |
+    WOHttpAdaptor_LogStream | bool   |
+    WOProjectDirectory      | String | /Users/znek/Projects/Foo
+
+Class-Hierachy
+==============
+
+    NSObject
+      WOApplication
+      WOContext
+      WOElement                 < OWResponder >
+        WOComponent             < WOActionResults >
+        WODynamicElement
+      WOAssociation
+        WOKeyPathAssociation
+        WOValueAssociation
+      WORequest
+      WOResponse                < WOActionResults >
+      WOResourceManager
+      WOSession
+      WOSessionStore
+        WOServerSessionStore
+
+  Categories
+
+  Protocols
+
+    OWResponder
+    WOActionResults
+
+  Log Topics
+
+--
+Helge Hess (helge.hess@skyrix.com)
+SKYRIX Software AG, 2003-01-06
diff --git a/skyrix-sope/NGObjWeb/SNSConnection.h b/skyrix-sope/NGObjWeb/SNSConnection.h
new file mode 100644 (file)
index 0000000..2eb80cd
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_SNSConnection_H__
+#define __NGObjWeb_SNSConnection_H__
+
+#import <Foundation/NSObject.h>
+#include <NGStreams/NGSocketProtocols.h>
+
+@class NSString, NSTimer;
+@class WOApplication;
+
+@interface SNSConnection : NSObject
+{
+@protected
+  WOApplication      *application; // non-retained
+  id<NGActiveSocket> socket;
+  id<NGStream>       io;
+  NSTimer            *pingTimer;
+  BOOL               loggingEnabled;
+}
+
++ (SNSConnection *)defaultSNSConnection;
+- (void)disconnectFromSessionNameService;
+
+- (void)applicationCreatedSession:(NSString *)_sessionID;
+- (void)sessionTerminated:(NSString *)_sessionID;
+- (void)sessionExpired:(NSString *)_sessionID;
+
+@end
+
+#endif /* __NGObjWeb_SNSConnection_H__ */
diff --git a/skyrix-sope/NGObjWeb/SNSConnection.m b/skyrix-sope/NGObjWeb/SNSConnection.m
new file mode 100644 (file)
index 0000000..99616f7
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "SNSConnection.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOAdaptor.h>
+#include <NGObjWeb/WOSession.h>
+#include "common.h"
+
+#if !LIB_FOUNDATION_LIBRARY
+#  include <NGExtensions/NSRunLoop+FileObjects.h>
+#endif
+
+// TODO: NEED TO FIX FOR Exception-less IO !!! (safeWrite...)
+
+typedef enum {
+  SNSUnregisterInstance = 0,
+  SNSRegisterInstance   = 1,
+  SNSRegisterSession    = 2,
+  SNSExpireSession      = 3,
+  SNSTerminateSession   = 4,
+  SNSLookupSession      = 50,
+  SNSInstanceAlive      = 100
+} SNSMessageCode;
+
+@interface SNSConnection(PrivateMethods)
+
+- (void)initWithApplication:(WOApplication *)_application;
+
+- (BOOL)registerWithSessionNameService;
+- (void)disconnectFromSessionNameService;
+
+@end
+
+@interface WOAdaptor(SocketAddress)
+- (id<NGSocketAddress>)socketAddress;
+@end
+
+@implementation SNSConnection
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  if (!isInitialized) {
+    NSDictionary *snsDefaults = nil;
+    
+    isInitialized = YES;
+
+    snsDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
+                                  @"/tmp/.snsd", @"SNSPort",
+                                  @"60",         @"SNSPingInterval",
+                                  @"NO",         @"SNSLogActivity",
+                                  nil];
+    [[NSUserDefaults standardUserDefaults]
+                     registerDefaults:snsDefaults];
+  }
+}
+
++ (SNSConnection *)defaultSNSConnection {
+  static SNSConnection *connection = nil;
+  if (connection) return connection;
+  connection = [[self alloc] init];
+  return connection;
+}
+
+- (void)initWithApplication:(WOApplication *)_application {
+  NSUserDefaults *ud;
+  id<NGSocketAddress> sns = nil;
+  int waitCnt = 0;
+  
+  ud = [NSUserDefaults standardUserDefaults];
+    
+  self->loggingEnabled = [[ud objectForKey:@"SNSLogActivity"] boolValue];
+  
+  sns = NGSocketAddressFromString([ud stringForKey:@"SNSPort"]);
+  if (sns == nil) {
+    NSLog(@"ERROR(%s): Could not create socket address for snsd(port=%@).",
+          __PRETTY_FUNCTION__, sns);
+    RELEASE(self);
+    return;
+  }
+
+#if 1
+  self->socket = [NGActiveSocket socketInDomain:[sns domain]];
+  do {
+    if (waitCnt > 0) {
+      [self logWithFormat:@"waiting %i seconds for snsd to come up ...",
+              waitCnt];
+      sleep(waitCnt);
+    }
+    
+    if (![self->socket connectToAddress:sns]) {
+      [self logWithFormat:@"  connect failed: %@",
+              [self->socket lastException]];
+    }
+    waitCnt++;
+  }
+  while (![self->socket isConnected] && (waitCnt < 5));
+#else
+  NS_DURING {
+    self->socket = [NGActiveSocket socketConnectedToAddress:sns];
+  }
+  NS_HANDLER {
+    self->socket = nil;
+  }
+  NS_ENDHANDLER;
+#endif
+  
+  if (![self->socket isConnected]) {
+    NSLog(@"ERROR: Could not connect socket %@ to snsd (port=%@), "
+          @"terminating: %@", self->socket, sns, [self->socket lastException]);
+    ASSIGN(self->socket, (id)nil);
+    RELEASE(self);
+    [[WOApplication application] terminate];
+    return;
+  }
+  self->socket = RETAIN(self->socket);
+
+  self->io = [NGBufferedStream filterWithSource:self->socket];
+  self->io = RETAIN(self->io);
+    
+  self->application = _application;
+
+  NS_DURING {
+    [self registerWithSessionNameService];
+  }
+  NS_HANDLER {
+    RELEASE(self->socket); self->socket = nil;
+  }
+  NS_ENDHANDLER;
+  
+  if (self->socket == nil) {
+    NSLog(@"ERROR: Could not register with snsd (port=%@).", sns);
+    RELEASE(self);
+    return;
+  }
+    [[NSNotificationCenter defaultCenter]
+                           addObserver:self selector:@selector(receiveMessage:)
+                           name:NSFileObjectBecameActiveNotificationName
+                           object:self->socket];
+    { // ping
+      int interval = [[ud objectForKey:@"SNSPingInterval"] intValue];
+      if (interval > 0) {
+        self->pingTimer =
+          [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)interval
+                   target:self selector:@selector(pingSNS:)
+                   userInfo:nil repeats:YES];
+        self->pingTimer = RETAIN(self->pingTimer);
+      }
+    }
+}
+- (id)init {
+  NSNotificationCenter *nc;
+  
+  self->loggingEnabled = [[[NSUserDefaults standardUserDefaults]
+                                           objectForKey:@"SNSLogActivity"]
+                                           boolValue];
+
+  nc = [NSNotificationCenter defaultCenter];
+
+  [nc addObserver:self selector:@selector(appDidFinishLaunching:)
+      name:WOApplicationDidFinishLaunchingNotification object:nil];
+  [nc addObserver:self selector:@selector(appWillTerminate:)
+      name:WOApplicationWillTerminateNotification object:nil];
+  
+  [nc addObserver:self selector:@selector(sessionDidCreate:)
+      name:WOSessionDidCreateNotification object:nil];
+  [nc addObserver:self selector:@selector(sessionDidTimeOut:)
+      name:WOSessionDidTimeOutNotification object:nil];
+  [nc addObserver:self selector:@selector(sessionDidTerminate:)
+      name:WOSessionDidTerminateNotification object:nil];
+
+  return self;
+}
+
+- (void)dealloc {
+  [self disconnectFromSessionNameService];
+  [self->pingTimer invalidate];
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [self disconnectFromSessionNameService];
+  RELEASE(self->pingTimer);
+  RELEASE(self->io);
+  RELEASE(self->socket);
+  [super dealloc];
+}
+
+/* notifications */
+
+- (void)appDidFinishLaunching:(NSNotification *)_notification {
+  WOApplication *app = [_notification object];
+  [self initWithApplication:app];
+}
+- (void)appWillTerminate:(NSNotification *)_notification {
+  [self disconnectFromSessionNameService];
+}
+
+- (void)sessionDidCreate:(NSNotification *)_notification {
+  WOSession *sn = [_notification object];
+  if (sn) [self applicationCreatedSession:[sn sessionID]];
+}
+- (void)sessionDidTimeOut:(NSNotification *)_notification {
+  NSString *sn = [_notification object];
+  if (sn) [self sessionExpired:sn];
+}
+- (void)sessionDidTerminate:(NSNotification *)_notification {
+  WOSession *sn = [_notification object];
+  if (sn) [self sessionTerminated:[sn sessionID]];
+}
+
+/* connection */
+
+- (BOOL)registerWithSessionNameService {
+  id<NGSocketAddress> port = nil;
+  BOOL      result    = NO;
+  NSArray   *adaptors = [self->application adaptors];
+  WOAdaptor *adaptor  = nil;
+
+  NSAssert([adaptors count] > 0, @"no adaptors registered for application");
+  *(&adaptor) = [adaptors objectAtIndex:0];
+
+  if ([adaptor respondsToSelector:@selector(socketAddress)])
+    *(&port) = [adaptor socketAddress];
+  if (port == nil)
+    return NO;
+
+  *(&result) = YES;
+
+  if (self->loggingEnabled)
+    NSLog(@"register instance with snsd.");
+  
+  {
+    NSString      *tmp;
+    int           len;
+    char          buf[2048];
+    unsigned int  i;
+    unsigned char c = SNSRegisterInstance;
+
+    if (![self->io safeWriteBytes:&c count:sizeof(c)])
+      [[self->io lastException] raise];
+
+    tmp = [self->application name];
+    len = [tmp cStringLength];
+    NSAssert1(len <= 2000, @"application name to long (%i bytes)..", len);
+    [tmp getCString:buf maxLength:2000];
+    if (![self->io safeWriteBytes:&len count:sizeof(len)])
+      [[self->io lastException] raise];
+    if (![self->io safeWriteBytes:buf count:len])
+      [[self->io lastException] raise];
+
+    tmp = [self->application path];
+    len = [tmp cStringLength];
+    NSAssert1(len <= 2000, @"bundle name to long (%i bytes) ..", len);
+    [tmp getCString:buf maxLength:2000];
+    if (![self->io safeWriteBytes:&len count:sizeof(len)])
+      [[self->io lastException] raise];
+    if (![self->io safeWriteBytes:buf count:len])
+      [[self->io lastException] raise];
+
+    i = getpid();
+    if (![self->io safeWriteBytes:&i count:sizeof(i)])
+      [[self->io lastException] raise];
+    
+    { // encode port info
+      NSData *data;
+
+      data = [NSArchiver archivedDataWithRootObject:port];
+      len = [data length];
+      NSAssert1(len <= 2000, @"socket name to long (%i bytes) ..", len);
+      if (![self->io safeWriteBytes:&len count:sizeof(len)])
+        [[self->io lastException] raise];
+      if (![self->io safeWriteBytes:[data bytes] count:len])
+        [[self->io lastException] raise];
+    }
+
+    if (![self->io flush])
+      [[self->io lastException] raise];
+  }
+  
+  if (self->loggingEnabled)
+    NSLog(@"registered instance with snsd: %s", result ? "YES" : "NO");
+  
+  return result;
+}
+
+- (void)disconnectFromSessionNameService {
+  if (self->socket) {
+    if (self->loggingEnabled)
+      NSLog(@"disconnecting instance from snsd ..");
+  
+    NS_DURING {
+      unsigned char c = SNSUnregisterInstance;
+      
+      (void)[self->socket safeWriteBytes:&c count:sizeof(c)];
+      (void)[self->socket flush];
+      
+      if ([self->socket respondsToSelector:@selector(shutdownSendChannel)])
+        (void)[(NGActiveSocket *)self->socket shutdownSendChannel];
+    }
+    NS_HANDLER {}
+    NS_ENDHANDLER;
+    
+    NS_DURING {
+      (void)[self->socket shutdown];
+    }
+    NS_HANDLER {}
+    NS_ENDHANDLER;
+
+    RELEASE(self->socket); self->socket = nil;
+  }
+}
+
+- (void)sendMessage:(unsigned char)_msg {
+  if (self->loggingEnabled)
+    NSLog(@"send msg %i", _msg);
+  if (![self->io safeWriteBytes:&_msg count:1])
+    [[self->io lastException] raise];
+  if (![self->io flush])
+    [[self->io lastException] raise];
+}
+- (void)sendMessage:(unsigned char)_msg sessionID:(NSString *)_sessionID {
+  int  len;
+  char buf[2048];
+
+  len = [_sessionID cStringLength];
+  NSAssert1((len < 2000) && (len > 0), @"Invalid session id (%i bytes).", len);
+  [_sessionID getCString:buf maxLength:2000];
+
+  if (self->loggingEnabled)
+    NSLog(@"send msg %i with sessionID %@ (len=%i)", _msg, _sessionID, len);
+
+  if (![self->io safeWriteBytes:&_msg count:1])
+    [[self->io lastException] raise];
+  if (![self->io safeWriteBytes:&len count:sizeof(len)])
+    [[self->io lastException] raise];
+  if (![self->io safeWriteBytes:buf count:len])
+    [[self->io lastException] raise];
+  if (![self->io flush])
+    [[self->io lastException] raise];
+}
+
+- (void)lostConnectionToNameServer:(NSException *)_exception {
+  NSLog(@"ERROR: application lost connection to snsd: %@", _exception);
+  [[WOApplication application] terminate];
+}
+- (void)lostConnectionToNameServer {
+  [self lostConnectionToNameServer:nil];
+}
+
+- (void)applicationCreatedSession:(NSString *)_sessionID {
+  NS_DURING {
+    [self sendMessage:SNSRegisterSession sessionID:_sessionID];
+  }
+  NS_HANDLER {
+    [self lostConnectionToNameServer:localException];
+  }
+  NS_ENDHANDLER;
+}
+
+- (void)sessionTerminated:(NSString *)_sessionID {
+  NS_DURING {
+    [self sendMessage:SNSTerminateSession sessionID:_sessionID];
+  }
+  NS_HANDLER {
+    [self lostConnectionToNameServer:localException];
+  }
+  NS_ENDHANDLER;
+}
+- (void)sessionExpired:(NSString *)_sessionID {
+  NSLog(@"%s: expired: %@", __PRETTY_FUNCTION__, _sessionID);
+  NS_DURING {
+    [self sendMessage:SNSExpireSession sessionID:_sessionID];
+  }
+  NS_HANDLER {
+    [self lostConnectionToNameServer:localException];
+  }
+  NS_ENDHANDLER;
+}
+
+- (void)pingSNS:(NSNotification *)_notification {
+  NS_DURING {
+    [self sendMessage:SNSInstanceAlive];
+  }
+  NS_HANDLER {
+    [self lostConnectionToNameServer:localException];
+  }
+  NS_ENDHANDLER;
+}
+
+// back link from SNS
+
+- (void)receiveMessage:(NSNotification *)_notification {
+  unsigned char msgCode;
+  
+  if ((id)[_notification object] != (id)self->socket)
+    return;
+
+  NSLog(@"SNS: receive message from snsd ..");
+  [self->io safeReadBytes:&msgCode count:1];
+}
+
+@end
diff --git a/skyrix-sope/NGObjWeb/SoCoreProduct.m b/skyrix-sope/NGObjWeb/SoCoreProduct.m
new file mode 100644 (file)
index 0000000..a10ce7e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <Foundation/NSObject.h>
+
+/* 
+   Note: do not include that file in the subproject, it is linked in the 
+         product bundle 
+*/
+
+@interface SoCoreProduct : NSObject
+@end
+
+@implementation SoCoreProduct
+@end /* SoCoreProduct */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/.cvsignore b/skyrix-sope/NGObjWeb/SoOFS/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-sope/NGObjWeb/SoOFS/GNUmakefile b/skyrix-sope/NGObjWeb/SoOFS/GNUmakefile
new file mode 100644 (file)
index 0000000..5fff25f
--- /dev/null
@@ -0,0 +1,53 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = SoOFS
+
+SoOFS_HEADER_FILES_DIR         = .
+SoOFS_HEADER_FILES_INSTALL_DIR = /SoOFS
+
+SoOFS_HEADER_FILES = \
+       SoOFS.h                 \
+       OFSBaseObject.h         \
+       OFSFactoryContext.h     \
+       OFSFactoryRegistry.h    \
+       OFSFile.h               \
+       OFSFileRenderer.h       \
+       OFSFolder.h             \
+       OFSImage.h              \
+       OFSPropertyListObject.h \
+       OFSResourceManager.h    \
+       OFSWebMethod.h          \
+       OFSWebMethodRenderer.h  \
+       OFSWebTemplate.h        \
+       OFSWebDocument.h        \
+       OFSHttpPasswd.h         \
+       OFSChangeLog.h          \
+       OFSFolderDataSource.h   \
+
+SoOFS_OBJC_FILES = \
+       OFSBaseObject.m                 \
+       OFSFactoryContext.m             \
+       OFSFactoryRegistry.m            \
+       OFSFile.m                       \
+       OFSFileRenderer.m               \
+       OFSFolder+SoDAV.m               \
+       OFSFolder.m                     \
+       OFSFolderClassDescription.m     \
+       OFSImage.m                      \
+       OFSPropertyListObject.m         \
+       OFSResourceManager.m            \
+       OFSWebMethod.m                  \
+       OFSWebMethodRenderer.m          \
+       OFSWebTemplate.m                \
+       OFSWebDocument.m                \
+       OFSHttpPasswd.m                 \
+       OFSChangeLog.m                  \
+       OFSFolderDataSource.m           \
+
+#SoOFS_RESOURCE_FILES =
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjWeb/SoOFS/GNUmakefile.preamble b/skyrix-sope/NGObjWeb/SoOFS/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..9289f99
--- /dev/null
@@ -0,0 +1,12 @@
+# $Id$
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I.             \
+       -I../SoObjects  \
+       -I../WebDAV     \
+       -I..            \
+       -I../../../skyrix-core                  \
+       -I../../../skyrix-core/NGStreams        \
+       -I../../../skyrix-core/NGExtensions     \
+       -I../../../skyrix-xml
+
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSBaseObject.h b/skyrix-sope/NGObjWeb/SoOFS/OFSBaseObject.h
new file mode 100644 (file)
index 0000000..6329f3b
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __OFS_OFSBaseObject_H__
+#define __OFS_OFSBaseObject_H__
+
+#import <Foundation/NSObject.h>
+#include <NGExtensions/NGFileManager.h>
+
+/*
+  OFSBaseObject
+  
+  This is the base class for OFS objects. Every OFS object has at least
+  - a name
+  - a container (not retained !)
+  - a filemanager
+  - a storage path (relative to the filemanager)
+  
+  Note that filemanager and storage path should in no case be made available
+  to the web for security reasons !
+  
+  The name is tracked in the child since it is required of URL construction
+  (to know the URI name the child was found with).
+*/
+
+@class NSString, NSException, NSClassDescription;
+@class EOGlobalID;
+@class WOContext;
+@class SoClass;
+@class OFSFactoryContext;
+
+@interface OFSBaseObject : NSObject
+{
+  id<NSObject,NGFileManager> fileManager;
+  NSString *storagePath;
+  SoClass  *soClass;
+  NSString *name;
+  id       container;
+}
+
+/* accessors */
+
+- (id<NSObject,NGFileManager>)fileManager;
+- (NSString *)storagePath;
+- (EOGlobalID *)globalID;
+
+- (BOOL)isCollection;
+- (BOOL)hasChildren;
+- (BOOL)doesExist;
+
+/* containment */
+
+- (id)container;
+- (NSString *)nameInContainer;
+- (void)setContainer:(id)_container andName:(NSString *)_name;
+- (NSException *)takeStorageInfoFromContext:(OFSFactoryContext *)_ctx;
+
+/* operations */
+
+- (void)detachFromContainer;
+- (BOOL)isAttachedToContainer;
+
+- (id)DELETEAction:(id)_ctx;
+
+/* instantiation */
+
+- (id)awakeFromFetchInContext:(OFSFactoryContext *)_ctx;
+- (id)awakeFromInsertionInContext:(OFSFactoryContext *)_ctx;
+
+/* WebDAV */
+
+- (NSString *)davDisplayName; // returns NSFileSubject or -name
+
+/* key validations */
+
+- (NSException *)validateForDelete;
+- (NSException *)validateForInsert;
+- (NSException *)validateForUpdate;
+- (NSException *)validateForSave;
+
+/* security */
+
+- (NSString *)ownerInContext:(id)_ctx;
+- (id)authenticatorInContext:(id)_ctx;
+
+/* version control */
+
+- (BOOL)isCvsControlled;
+- (BOOL)isSvnControlled;
+
+@end
+
+#endif /* __OFS_OFSBaseObject_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSBaseObject.m b/skyrix-sope/NGObjWeb/SoOFS/OFSBaseObject.m
new file mode 100644 (file)
index 0000000..9032ca0
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSBaseObject.h"
+#include "OFSFactoryContext.h"
+#include "OFSFolder.h"
+#include "common.h"
+
+@implementation OFSBaseObject
+
++ (int)version {
+  return 1;
+}
+
+- (void)dealloc {
+  [self detachFromContainer];
+  [self->name        release];
+  [self->fileManager release];
+  [self->storagePath release];
+  [self->soClass     release];
+  [super dealloc];
+}
+
+/* awake */
+
+- (NSException *)takeStorageInfoFromContext:(OFSFactoryContext *)_ctx {
+  self->fileManager = [[_ctx fileManager] retain];
+  self->storagePath = [[_ctx storagePath] copy];
+  [self setContainer:[_ctx container] andName:[_ctx nameInContainer]];
+  return nil;
+}
+
+- (id)awakeFromFetchInContext:(OFSFactoryContext *)_ctx {
+  if (self->fileManager == nil || self->storagePath == nil)
+    [self logWithFormat:@"WARNING: object has no storage info !"];
+  
+  return self;
+}
+- (id)awakeFromInsertionInContext:(OFSFactoryContext *)_ctx {
+  self->fileManager = [[_ctx fileManager] retain];
+  self->storagePath = [[_ctx storagePath] copy];
+  [self setContainer:[_ctx container] andName:[_ctx nameInContainer]];
+  return self;
+}
+
+/* accessors */
+
+- (SoClass *)soClass {
+  if (self->soClass == nil)
+    return [super soClass];
+  return self->soClass;
+}
+
+- (id<NSObject,NGFileManager>)fileManager {
+  return self->fileManager;
+}
+- (NSString *)storagePath {
+  return self->storagePath;
+}
+- (EOGlobalID *)globalID {
+  return [[self fileManager] globalIDForPath:[self storagePath]];
+}
+
+- (BOOL)isCollection {
+  return NO;
+}
+- (BOOL)hasChildren {
+  return [self isCollection];
+}
+- (BOOL)doesExist {
+  return [[self fileManager] fileExistsAtPath:[self storagePath]];
+}
+
+/* containment */
+
+- (id)container {
+  return self->container;
+}
+- (NSString *)nameInContainer {
+  return self->name;
+}
+- (void)setContainer:(id)_container andName:(NSString *)_name {
+  self->container = _container;
+  ASSIGNCOPY(self->name, _name);
+}
+
+/* operations */
+
+- (void)detachFromContainer {
+  self->container = nil;
+  [self->name release]; self->name = nil;
+}
+- (BOOL)isAttachedToContainer {
+  return self->container ? YES : NO;
+}
+
+- (id)DELETEAction:(id)_ctx {
+  NSException *e;
+  id fm;
+  
+  if ((e = [self validateForDelete]))
+    return e;
+  
+  if ((fm = [self fileManager]) == nil) {
+    [self logWithFormat:@"missing filemanager for delete."];
+    return [NSException exceptionWithHTTPStatus:500 /* server error */
+                       reason:@"missing filemanager for object ?!"];
+  }
+  
+  if (![self doesExist])
+    return [NSException exceptionWithHTTPStatus:404 /* not found */];
+  
+  if ([fm removeFileAtPath:[self storagePath] handler:nil])
+    /* nil means "everything OK" ;-) [for the WebDAV renderer] */
+    return [NSNumber numberWithBool:YES];
+  
+  if ([fm respondsToSelector:@selector(lastException)])
+    return [fm lastException];
+  
+  return [NSException exceptionWithHTTPStatus:500 /* server error */
+                     reason:@"filemanager couldn't remove file at path."];
+}
+
+/* KVC */
+
+- (id)handleQueryWithUnboundKey:(NSString *)key {
+  // TODO: any drawbacks when doing this ?
+  return nil;
+}
+
+- (id)valueForKey:(NSString *)_name {
+  /* map out some very private keys */
+  unsigned nl;
+  unichar  c;
+  
+  if ((nl = [_name length]) == 0)
+    return nil;
+  
+  c = [_name characterAtIndex:0];
+  if ((c == 's') && (nl == 11)) {
+    if ([_name isEqualToString:@"storagePath"])
+      /* do not allow KVC access to storage path */
+      return nil;
+  }
+  else if ((c == 'f') && (nl == 11)) {
+    if ([_name isEqualToString:@"fileManager"])
+      /* do not allow KVC access to filemanager */
+      return nil;
+  }
+  
+  return [super valueForKey:_name];
+}
+
+/* key validations */
+
+- (NSException *)validateForDelete {
+  return nil;
+}
+- (NSException *)validateForInsert {
+  return nil;
+}
+- (NSException *)validateForUpdate {
+  return nil;
+}
+- (NSException *)validateForSave {
+  return nil;
+}
+
+/* WebDAV */
+
+- (NSString *)davDisplayName {
+  NSString *s;
+  if ((s = [self valueForKey:@"NSFileSubject"])) return s;
+  return [self nameInContainer];
+}
+- (id)davLastModified {
+  return [self valueForKey:NSFileModificationDate];
+}
+
+/* schema */
+
+- (NSClassDescription *)soClassDescription {
+  return nil;
+}
+
+/* security */
+
+- (NSString *)ownerInContext:(id)_ctx {
+  /* ask container ... */
+  id c;
+  
+  if ((c = [self container]) == nil)
+    return nil;
+
+  if ([c respondsToSelector:@selector(ownerOfChild:inContext:)])
+    return [c ownerOfChild:self inContext:_ctx];
+
+  if (c == self)
+    /* avoid endless recursion ... */
+    return nil;
+
+  return [c ownerInContext:_ctx];
+}
+
+- (id)authenticatorInContext:(id)_ctx {
+  /* ask container ... */
+  id lContainer;
+  
+  if ((lContainer = [self container]) == nil)
+    return nil;
+
+  if (lContainer == self)
+    /* avoid endless recursion ... */
+    return nil;
+
+  return [lContainer authenticatorInContext:_ctx];
+}
+
+/* version control */
+
+- (BOOL)isCvsControlled {
+  return NO;
+}
+- (BOOL)isSvnControlled {
+  return NO;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+#if DEBUG
+  return YES;
+#else
+  return NO;
+#endif
+}
+- (NSString *)loggingPrefix {
+  /* improve perf ... */
+  NSString *n = [self nameInContainer];
+  return [NSString stringWithFormat:@"0x%08X[%@]:%@",
+                    self, NSStringFromClass([self class]),
+                    n ? n : @"ROOT"];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->storagePath) 
+    [ms appendFormat:@" path=%@", self->storagePath];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* OFSBaseObject */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSChangeLog.h b/skyrix-sope/NGObjWeb/SoOFS/OFSChangeLog.h
new file mode 100644 (file)
index 0000000..c275962
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoOFS_OFSChangeLog_H__
+#define __SoOFS_OFSChangeLog_H__
+
+#include <SoOFS/OFSFile.h>
+
+/*
+  OFSChangeLog
+
+  This class is intended to wrap a ChangeLog text file. It should provide
+  web methods to view and edit ChangeLog information in a convenient way.
+*/
+
+@interface OFSChangeLog : OFSFile
+{
+}
+
+@end
+
+#endif /* __SoOFS_OFSChangeLog_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSChangeLog.m b/skyrix-sope/NGObjWeb/SoOFS/OFSChangeLog.m
new file mode 100644 (file)
index 0000000..b71b650
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSChangeLog.h"
+#include "common.h"
+
+@implementation OFSChangeLog
+
+// TODO: IMPLEMENT ;-) !
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+@end /* OFSChangeLog */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFactoryContext.h b/skyrix-sope/NGObjWeb/SoOFS/OFSFactoryContext.h
new file mode 100644 (file)
index 0000000..d84f588
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __OFS_OFSFactoryContext_H__
+#define __OFS_OFSFactoryContext_H__
+
+#import <Foundation/NSObject.h>
+#include <NGExtensions/NGFileManager.h>
+
+/*
+  OFSFactoryContext
+
+  The factory context is used to transport the instantiation environment
+  for OFS objects.
+*/
+
+@class NSString;
+@class OFSFolder;
+
+@interface OFSFactoryContext : NSObject
+{
+@public
+  id<NSObject,NGFileManager> fileManager;
+  NSString *storagePath;
+  NSString *fileType;
+  NSString *mimeType;
+  NSString *name;
+  id       container;
+  BOOL     isNewObject;
+}
+
++ (OFSFactoryContext *)contextForChild:(NSString *)_name
+  storagePath:(NSString *)_sp
+  ofFolder:(OFSFolder *)_folder;
++ (OFSFactoryContext *)contextWithFileManager:(id<NSObject,NGFileManager>)_fm
+  storagePath:(NSString *)_sp;
+
++ (OFSFactoryContext *)contextForNewChild:(NSString *)_name
+  storagePath:(NSString *)_sp
+  ofFolder:(OFSFolder *)_folder;
+
+/* accessors */
+
+- (id<NSObject,NGFileManager>)fileManager;
+- (NSString *)storagePath;
+- (id)container;
+- (NSString *)nameInContainer;
+
+- (NSString *)fileType;
+- (NSString *)mimeType;
+
+- (BOOL)isNewObject;
+
+@end
+
+#endif /* __OFS_OFSFactoryContext_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFactoryContext.m b/skyrix-sope/NGObjWeb/SoOFS/OFSFactoryContext.m
new file mode 100644 (file)
index 0000000..d8eb507
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSFactoryContext.h"
+#include "OFSFolder.h"
+#include "common.h"
+
+@implementation OFSFactoryContext
+
++ (OFSFactoryContext *)contextForChild:(NSString *)_name
+  storagePath:(NSString *)_sp
+  ofFolder:(OFSFolder *)_folder
+{
+  OFSFactoryContext *ctx;
+  
+  ctx = [[self alloc] init];
+  ctx->fileManager = [[_folder fileManager] retain];
+  ctx->storagePath = [_sp copy];
+  ctx->container   = [_folder retain];
+  ctx->name        = [_name copy];
+  return [ctx autorelease];
+}
++ (OFSFactoryContext *)contextForNewChild:(NSString *)_name
+  storagePath:(NSString *)_sp
+  ofFolder:(OFSFolder *)_folder
+{
+  OFSFactoryContext *ctx;
+  
+  if ((ctx = [self contextForChild:_name storagePath:_sp ofFolder:_folder])) {
+    ctx->isNewObject = YES;
+  }
+  return ctx;
+}
+
++ (OFSFactoryContext *)contextWithFileManager:(id<NSObject,NGFileManager>)_fm
+  storagePath:(NSString *)_sp
+{
+  OFSFactoryContext *ctx;
+  
+  ctx = [[self alloc] init];
+  ctx->fileManager = [_fm retain];
+  ctx->storagePath = [_sp copy];
+  return [ctx autorelease];
+}
+
+- (void)dealloc {
+  [self->fileType    release];
+  [self->mimeType    release];
+  [self->fileManager release];
+  [self->container   release];
+  [self->name        release];
+  [self->storagePath release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id<NSObject,NGFileManager>)fileManager {
+  return self->fileManager;
+}
+- (NSString *)storagePath {
+  return self->storagePath;
+}
+- (id)container {
+  return self->container;
+}
+- (NSString *)nameInContainer {
+  return self->name;
+}
+
+- (NSString *)fileType {
+  return self->fileType;
+}
+- (NSString *)mimeType {
+  return self->mimeType;
+}
+
+- (BOOL)isNewObject {
+  return self->isNewObject;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->isNewObject)
+    [ms appendString:@" NEW"];
+  if (self->name)        [ms appendFormat:@" create=%@", self->name];
+  if (self->container)   [ms appendFormat:@" in=%@",   self->container];
+  if (self->fileType)    [ms appendFormat:@" type=%@", self->fileType];
+  if (self->mimeType)    [ms appendFormat:@" mime=%@", self->mimeType];
+  if (self->storagePath) [ms appendFormat:@" path=%@", self->storagePath];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* OFSFactoryContext */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFactoryRegistry.h b/skyrix-sope/NGObjWeb/SoOFS/OFSFactoryRegistry.h
new file mode 100644 (file)
index 0000000..b4c4545
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __OFS_OFSFactoryRegistry_H__
+#define __OFS_OFSFactoryRegistry_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  OFSFactoryRegistry
+  
+  The registry is responsible to select factories for producing objects
+  for either new objects or for unarchiving stored objects.
+  It's not the task of the registry to perform the creation itself.
+  
+  Note that the registry is usually not accessed directly, but rather
+  through OFSFolder.
+*/
+
+@class NSString, NSMutableDictionary;
+@class SoClass;
+@class OFSFactoryContext;
+
+@interface OFSFactoryRegistry : NSObject
+{
+  NSMutableDictionary *classToFileFactory;
+  NSMutableDictionary *extToFileFactory;
+  NSMutableDictionary *nameToFileFactory;
+  id defaultFolderFactory;
+  id defaultFileFactory;
+}
+
++ (id)sharedFactoryRegistry;
+
+/* lookup */
+
+- (id)restorationFactoryForContext:(OFSFactoryContext *)_ctx;
+- (id)creationFactoryForContext:(OFSFactoryContext *)_ctx;
+
+/* registration */
+
+- (void)registerFileFactory:(id)_factory forSoClass:(SoClass *)_clazz;
+- (void)registerFileFactory:(id)_factory forClass:(Class)_clazz;
+
+- (void)registerFileFactory:(id)_factory forExtension:(NSString *)_ext;
+- (void)registerFileFactory:(id)_factory forExactName:(NSString *)_name;
+
+@end
+
+#endif /* __OFS_OFSFactoryRegistry_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFactoryRegistry.m b/skyrix-sope/NGObjWeb/SoOFS/OFSFactoryRegistry.m
new file mode 100644 (file)
index 0000000..c523d17
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSFactoryRegistry.h"
+#include "OFSFolder.h"
+#include "OFSFile.h"
+#include "OFSFactoryContext.h"
+#include "SoClassRegistry.h"
+#include "SoObjCClass.h"
+#include "common.h"
+
+@interface SoClass(Factory)
+- (id)ofsObjectFactory;
+@end
+
+@implementation OFSFactoryRegistry
+
+static int factoryDebugOn    = 0;
+static int factoryRegDebugOn = 0;
+
++ (id)sharedFactoryRegistry {
+  static id reg = nil;
+  if (reg == nil) reg = [[OFSFactoryRegistry alloc] init];
+  return reg;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->classToFileFactory = 
+      [[NSMutableDictionary alloc] initWithCapacity:32];
+    self->extToFileFactory = 
+      [[NSMutableDictionary alloc] initWithCapacity:64];
+    self->nameToFileFactory = 
+      [[NSMutableDictionary alloc] initWithCapacity:64];
+    
+    self->defaultFolderFactory = [OFSFolder class];
+    self->defaultFileFactory   = [OFSFile   class];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->defaultFileFactory   release];
+  [self->defaultFolderFactory release];
+  [self->classToFileFactory   release];
+  [self->extToFileFactory     release];
+  [self->nameToFileFactory    release];
+  [super dealloc];
+}
+
+/* lookup factory */
+
+- (id)factoryForChildKey:(NSString *)_key 
+  ofFolder:(OFSFolder *)_folder
+  fileType:(NSString *)_ftype
+  mimeType:(NSString *)_mimeType
+{
+  SoClassRegistry *classRegistry;
+  NSString *pe;
+  SoClass  *soClass;
+  BOOL     isDir;
+  id       factory = nil;
+  
+  isDir = [_ftype isEqualToString:NSFileTypeDirectory] ? YES : NO;
+  
+  if (factoryDebugOn) {
+    [self debugWithFormat:@"lookup factory for key %@ type=%@ mime=%@",
+           _key, _ftype, _mimeType];
+  }
+  
+  /* first check fixed child classes */
+  
+  if (_folder && !isDir) {
+    factory = [self->classToFileFactory objectForKey:[_folder soClass]];
+    if (factory) {
+      if (factoryDebugOn) {
+       [self debugWithFormat:
+               @"selected a file factory fixed to folderclass: %@", factory];
+      }
+      return factory;
+    }
+  }
+  
+  /* then, check exact names (eg 'htpasswd') */
+
+  if ((factory = [self->nameToFileFactory objectForKey:_key])) {
+    if (factoryDebugOn) {
+      [self debugWithFormat:@"selected file factory by exact name '%@': %@",
+              _key, factory];
+    }
+    return factory;
+  }
+  
+  /* now check extension */
+  
+  pe = [_key pathExtension];
+  if (pe == nil) pe = @"";
+  
+  if ((factory = [self->extToFileFactory objectForKey:pe])) {
+    if (factoryDebugOn) {
+      [self debugWithFormat:@"selected file factory by extension '%@': %@",
+              pe, factory];
+    }
+    return factory;
+  }
+  
+  /* check for SoClass factories */
+
+  classRegistry = [SoClassRegistry sharedClassRegistry];
+  
+  if ((soClass = [classRegistry soClassForExactName:_key])) {
+    if (factoryDebugOn) {
+      [self debugWithFormat:@"selected SoClass factory by exact name '%@': %@",
+              _key, factory];
+    }
+  }
+  else if ((soClass = [classRegistry soClassForExtension:pe])) {
+    if (factoryDebugOn) {
+      [self debugWithFormat:@"selected SoClass factory by extension '%@': %@",
+              pe, factory];
+    }
+  }
+  
+  if (soClass) {
+    if ((factory = [soClass ofsObjectFactory]))
+      return factory;
+    else {
+      if (factoryDebugOn) {
+       [self debugWithFormat:
+                @"did not use SoClass for name/extension %@/'%@': %@",
+               _key, pe, soClass];
+      }
+    }
+  }
+  
+  /* apply defaults */
+  
+  return isDir ? self->defaultFolderFactory : self->defaultFileFactory;
+}
+
+- (id)restorationFactoryForContext:(OFSFactoryContext *)_ctx {
+  return [self factoryForChildKey:[_ctx nameInContainer]
+              ofFolder:[_ctx container]
+              fileType:_ctx->fileType
+              mimeType:_ctx->mimeType];
+}
+- (id)creationFactoryForContext:(OFSFactoryContext *)_ctx {
+  return [self factoryForChildKey:[_ctx nameInContainer]
+              ofFolder:[_ctx container]
+              fileType:_ctx->fileType
+              mimeType:_ctx->mimeType];
+}
+
+/* registration */
+
+- (void)registerFileFactory:(id)_factory forSoClass:(SoClass *)_clazz {
+  if (_factory == nil) return;
+  if (_clazz   == nil) return;
+  if (factoryRegDebugOn) {
+    [self debugWithFormat:@"registering file factory '%@' for class %@",
+           _factory, _clazz];
+  }
+  [self->classToFileFactory setObject:_factory forKey:_clazz];
+}
+
+- (void)registerFileFactory:(id)_factory forClass:(Class)_clazz {
+  [self registerFileFactory:_factory forSoClass:[_clazz soClass]];
+}
+
+- (void)registerFileFactory:(id)_factory forExtension:(NSString *)_ext {
+  if (_factory == nil) return;
+  if (_ext     == nil) return;
+  
+  if (factoryRegDebugOn) {
+    [self debugWithFormat:@"registering file factory '%@' for extension %@",
+           _factory, _ext];
+  }
+  [self->extToFileFactory setObject:_factory forKey:_ext];
+}
+
+- (void)registerFileFactory:(id)_factory forExactName:(NSString *)_name {
+  if (_factory == nil) return;
+  if (_name    == nil) return;
+  
+  if (factoryRegDebugOn) {
+    [self debugWithFormat:@"registering file factory '%@' for exact name '%@'",
+           _factory, _name];
+  }
+  [self->nameToFileFactory setObject:_factory forKey:_name];
+}
+
+@end /* OFSFactoryRegistry */
+
+@implementation SoClass(Factory)
+
+- (id)ofsObjectFactory {
+  return nil;
+}
+
+@end /* SoClass(Factory) */
+
+@implementation SoObjCClass(Factory)
+
+- (id)ofsObjectFactory {
+  Class bClazz;
+  
+  if ((bClazz = [self objcClass]) == Nil)
+    return nil;
+  
+  if (![bClazz respondsToSelector:@selector(instantiateInFactoryContext:)])
+    return nil;
+  
+  return bClazz;
+}
+
+@end /* SoObjCClass(Factory) */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFile.h b/skyrix-sope/NGObjWeb/SoOFS/OFSFile.h
new file mode 100644 (file)
index 0000000..83e9795
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __OFS_OFSFile_H__
+#define __OFS_OFSFile_H__
+
+#include <SoOFS/OFSBaseObject.h>
+
+/*
+  OFSFile
+  
+  OFSFile represents file objects in OFS (child nodes, non-folders). Files
+  have a BLOB and can have associated meta-attributes (usually the filesystem
+  attributes given by the filemanager)
+  
+  OFSFile contains a basic implementation of WebDAV support methods and 
+  properties.
+*/
+
+@class NSDictionary;
+@class OFSFactoryContext;
+@class WOContext;
+
+@interface OFSFile : OFSBaseObject
+{
+  NSDictionary *attrCache;
+}
+
+/* writing content */
+
+- (NSException *)writeState:(id)_value;
+- (NSString *)contentAsString;
+
+/* implemented actions */
+
+- (NSString *)contentTypeInContext:(WOContext *)_ctx;
+- (id)GETAction:(WOContext *)_ctx;
+- (id)viewAction:(WOContext *)_ctx;
+- (id)PUTAction:(WOContext *)_ctx;
+
+/* factory */
+
++ (id)instantiateInFactoryContext:(OFSFactoryContext *)_ctx;
+
+@end
+
+#endif /* __OFS_OFSFile_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFile.m b/skyrix-sope/NGObjWeb/SoOFS/OFSFile.m
new file mode 100644 (file)
index 0000000..07e860c
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSFile.h"
+#include "OFSFolder.h"
+#include "OFSFactoryContext.h"
+#include "OFSFileRenderer.h"
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@implementation OFSFile
+
++ (int)version {
+  return [super version] + 0 /* v1 */;
+}
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    didInit = YES;
+    NSAssert2([super version] == 1,
+             @"invalid superclass (%@) version %i !",
+             NSStringFromClass([self superclass]), [super version]);
+  }
+}
+
+- (void)dealloc {
+  [self->attrCache release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (BOOL)isCollection {
+  return NO;
+}
+- (BOOL)hasChildren {
+  return NO;
+}
+
+- (NSStringEncoding)contentEncoding {
+  return [NSString defaultCStringEncoding];
+}
+
+- (NSString *)contentAsString {
+  NSData   *data;
+  NSString *s;
+  
+  if ((data = [[self fileManager] contentsAtPath:[self storagePath]]) == nil)
+    return nil;
+  
+  s = [[NSString alloc] initWithData:data encoding:[self contentEncoding]];
+  return [s autorelease];
+}
+
+/* writing content */
+
+- (NSException *)writeState:(id)_value {
+  NSData *data;
+  id fm;
+  
+  if (_value == nil) {
+    return [NSException exceptionWithHTTPStatus:500
+                       reason:@"missing value to write !"];
+  }
+  
+  // TODO: could support some more objects ?
+  if ([_value isKindOfClass:[NSData class]])
+    data = _value;
+  else
+    data = [[_value stringValue] dataUsingEncoding:[self contentEncoding]];
+  
+  fm = [self fileManager];
+  if (![fm writeContents:data atPath:[self storagePath]]) {
+    if ([fm respondsToSelector:@selector(lastException)]) {
+      NSException *e = [fm lastException];
+      [self logWithFormat:@"write of %i bytes failed: %@", [data length], e];
+      return e;
+    }
+    
+    return [NSException exceptionWithHTTPStatus:500
+                       reason:@"could not write content, reason unknown"];
+  }
+  
+  return nil; /* nil is OK */
+}
+
+/* attributes */
+
+- (NSDictionary *)fileAttributes {
+  id fm;
+  
+  if ((fm = [self fileManager]) == nil)
+    return nil;
+  if (self->attrCache == nil) {
+    self->attrCache =
+      [[fm fileAttributesAtPath:[self storagePath] traverseLink:NO] copy];
+  }
+  return self->attrCache;
+}
+
+/* KVC */
+
+- (BOOL)allowAccessToFileAttribute:(NSString *)_name {
+  return YES;
+}
+
+- (id)valueForKey:(NSString *)_name {
+  unsigned nl;
+  unichar  c;
+  
+  if ((nl = [_name length]) == 0)
+    return nil;
+  
+  c = [_name characterAtIndex:0];
+  if (c == 'N' && (nl > 6)) {
+    if ([_name hasPrefix:@"NSFile"]) {
+      if ([self allowAccessToFileAttribute:_name])
+       return [[self fileAttributes] objectForKey:_name];
+    }
+  }
+  
+  return [super valueForKey:_name];
+}
+
+/* operations */
+
+- (NSString *)contentTypeInContext:(WOContext *)_ctx {
+  NSString *ext, *type;
+  
+  type = nil;
+  if ((ext = [[self nameInContainer] pathExtension])) {
+    // TODO: read /etc/mime.types
+    if ([ext isEqualToString:@"html"])       type = @"text/html";
+    else if ([ext isEqualToString:@"xhtml"]) type = @"text/xhtml";
+    else if ([ext isEqualToString:@"gif"])   type = @"image/gif";
+    else if ([ext isEqualToString:@"png"])   type = @"image/png";
+  }
+  return type ? type : @"application/octet-stream";
+}
+
+- (id)davContentLength {
+  return [[self fileAttributes] objectForKey:NSFileSize];
+}
+- (NSDate *)davLastModified {
+  return [[self fileAttributes] objectForKey:NSFileModificationDate];
+}
+
+- (id)rendererForObject:(id)_object inContext:(WOContext *)_ctx {
+  return nil;
+}
+
+- (id)viewAction:(WOContext *)_ctx {
+  return self;
+}
+- (id)GETAction:(WOContext *)_ctx {
+  return self;
+}
+- (id)HEADAction:(WOContext *)_ctx {
+  return self;
+}
+
+- (id)PUTAction:(WOContext *)_ctx {
+  NSException *e;
+  NSData *content;
+  
+  if ((e = [self validateForSave])) {
+    [self debugWithFormat:@"object did not validate for save ..."];
+    return e;
+  }
+  
+  if ((content = [[_ctx request] content]) == nil)
+    content = [NSData data];
+  
+  if ((e = [self writeState:content]))
+    return e;
+  
+  return self;
+}
+
+/* version control */
+
+- (BOOL)isCvsControlled {
+  return [[self container] isCvsControlled];
+}
+- (BOOL)isSvnControlled {
+  return [[self container] isSvnControlled];
+}
+
+/* factory */
+
++ (id)instantiateInFactoryContext:(OFSFactoryContext *)_ctx {
+  id object;
+  
+  object = [[self soClass] instantiateObject];
+  [object takeStorageInfoFromContext:_ctx];
+  return object;
+}
+
+@end /* OFSFile */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFileRenderer.h b/skyrix-sope/NGObjWeb/SoOFS/OFSFileRenderer.h
new file mode 100644 (file)
index 0000000..de87294
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoOFS_OFSFileRenderer_H__
+#define __SoOFS_OFSFileRenderer_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  OFSFileRenderer
+  
+  Renders the actual contents of a file without any evaluation (eg used for
+  delivering images stored in OFS)
+*/
+
+@class NSException;
+@class WOContext;
+
+@interface OFSFileRenderer : NSObject
+{
+}
+
++ (id)sharedRenderer;
+
+/* rendering */
+
+- (NSException *)renderObject:(id)_object inContext:(WOContext *)_ctx;
+- (BOOL)canRenderObject:(id)_object inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __SoOFS_OFSFileRenderer_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFileRenderer.m b/skyrix-sope/NGObjWeb/SoOFS/OFSFileRenderer.m
new file mode 100644 (file)
index 0000000..a3adc15
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSFileRenderer.h"
+#include "OFSFile.h"
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOContext.h>
+#include "NSException+HTTP.h"
+#include "common.h"
+
+@interface OFSFile(Render)
+
+- (id)davContentLength;
+- (NSDate *)davLastModified;
+
+@end
+
+@implementation OFSFileRenderer
+
+static NSTimeZone *gmt = nil;
+
++ (void)initialize {
+  gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+}
+
++ (id)sharedRenderer {
+  static OFSFileRenderer *singleton = nil;
+  if (singleton == nil)
+    singleton = [[OFSFileRenderer alloc] init];
+  return singleton;
+}
+
+/* rendering */
+
+- (NSException *)renderHeadOfObject:(id)_object inContext:(WOContext *)_ctx {
+  WOResponse *r;
+  id tmp;
+  
+  r = [_ctx response];
+  
+  /* render headers */
+  
+  if ((tmp = [_object contentTypeInContext:_ctx]))
+    [r setHeader:tmp forKey:@"content-type"];
+  if ((tmp = [_object davContentLength]))
+    [r setHeader:tmp forKey:@"content-length"];
+  
+  if ((tmp = [_object davLastModified])) {
+    NSCalendarDate *date;
+
+#if COCOA_Foundation_LIBRARY
+    date = [[NSCalendarDate alloc] initWithTimeIntervalSinceReferenceDate:
+                                    [tmp timeIntervalSinceReferenceDate]];
+#else
+    date = [[NSCalendarDate alloc] initWithTimeIntervalSince1970:
+                                    [tmp timeIntervalSince1970]];
+#endif
+    [date setTimeZone:gmt];
+    
+    // "Tue, 10 Jul 2001 14:09:06 GMT"
+    tmp = [date descriptionWithCalendarFormat:@"%a, %d %b %Y %H:%M:%S GMT"];
+    [date release];
+    [r setHeader:tmp forKey:@"last-modified"];
+  }
+  
+  return nil;
+}
+
+- (NSException *)renderBodyOfObject:(id)_object inContext:(WOContext *)_ctx {
+  WOResponse *r;
+  NSData     *content;
+  NSString   *storePath;
+  id fm;
+  
+  fm        = [_object fileManager];
+  storePath = [_object storagePath];
+  content   = [fm contentsAtPath:storePath];
+  
+  /* some error handling */
+  
+  if (content == nil) {
+    // TODO: should render exception ?
+    if ([fm respondsToSelector:@selector(lastException)])
+      return (id)[fm lastException];
+    return [NSException exceptionWithHTTPStatus:404 /* not found */];
+  }
+  
+  /* render body */
+  r = [_ctx response];
+  [r setContent:content];
+  return nil;
+}
+
+- (NSException *)renderObject:(id)_object inContext:(WOContext *)_ctx {
+  NSException *e;
+  
+  if ((e = [self renderHeadOfObject:_object inContext:_ctx]))
+    return e;
+  
+  if (![[[_ctx request] method] isEqualToString:@"HEAD"]) {
+    if ((e = [self renderBodyOfObject:_object inContext:_ctx]))
+      return e;
+  }
+  return nil;
+}
+
+- (BOOL)canRenderObject:(id)_object inContext:(WOContext *)_ctx {
+  return [_object isKindOfClass:[OFSFile class]];
+}
+
+@end /* OFSFileRenderer */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFolder+SoDAV.m b/skyrix-sope/NGObjWeb/SoOFS/OFSFolder+SoDAV.m
new file mode 100644 (file)
index 0000000..26fb8ba
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSFolder.h"
+#include "common.h"
+
+/*
+  Some special WebDAV keys:
+    .autodiskmounted - queried by the MacOSX DAV filesystem
+    .directory       - queried by Nautilus
+  
+  both seem to work if the keys do not exist (no special handling required).
+*/
+
+@implementation OFSFolder(SoDAV)
+
+static int davDebugOn = 0;
+
+- (BOOL)davIsCollection {
+  return YES;
+}
+- (BOOL)davIsFolder {
+  /* this can be overridden by compound documents (aka filewrappers) */
+  return [self davIsCollection];
+}
+
+- (BOOL)davHasSubFolders {
+  /* search for subfolders (tries to be smart and load as little as p. ;-) */
+  NSArray  *ak;
+  unsigned i, count;
+  
+  if ((ak = [self allKeys]) == nil) return NO;
+  if ((count = [ak count]) == 0) return NO;
+  
+  /* first scan the already loaded children */
+  for (i = 0; i < count; i++) {
+    id child;
+    
+    child = [self->children objectForKey:[ak objectAtIndex:i]];
+    if ([child davIsFolder]) return YES;
+  }
+  
+  /* now scan all children */
+  
+  if (self->flags.didLoadAll) 
+    return NO; /* we've already seen all children */
+  [self allValues];          /* otherwise trigger a load */
+  
+  for (i = 0; i < count; i++) {
+    id child;
+    
+    child = [self->children objectForKey:[ak objectAtIndex:i]];
+    if ([child davIsFolder]) return YES;
+  }
+  
+  return NO;
+}
+
+- (NSString *)fileExtensionForChildrenInContext:(id)_ctx {
+  /* 
+     This can be used to enforce a common extension for all children, this is
+     useful for WebDAV directory listings (eg all children of an address folder
+     can appear as vcf files in cadaver or OSX).
+  */
+  return nil;
+}
+
+- (NSEnumerator *)davChildKeysInContext:(id)_ctx {
+  NSArray  *keys;
+  NSString *ext;
+  unsigned len;
+  
+  keys = [self allKeys];
+  if ((len = [keys count]) == 0) {
+    if (davDebugOn)
+      [self debugWithFormat:@"no DAV child keys for delivery ..."];
+    return [keys objectEnumerator];
+  }
+  
+  if ((ext = [self fileExtensionForChildrenInContext:_ctx])) {
+    NSMutableArray *ma;
+    unsigned i;
+    BOOL didChange;
+    
+    ma = [NSMutableArray arrayWithCapacity:len];
+    didChange = NO;
+    for (i = 0; i < len; i++) {
+      NSString *k, *pe;
+      
+      k = [keys objectAtIndex:i];
+      
+      if ((pe = [k pathExtension]) == nil)
+       [ma addObject:k];
+      else if ([pe length] == 0)
+       [ma addObject:k];
+      else {
+       k = [k stringByDeletingPathExtension];
+       k = [k stringByAppendingPathExtension:ext];
+       [ma addObject:k];
+       didChange = YES;
+      }
+    }
+    if (didChange) keys = ma;
+  }
+  if (davDebugOn) {
+    [self debugWithFormat:@"DAV child keys for delivery: %@",
+           [keys componentsJoinedByString:@","]];
+  }
+  return [keys objectEnumerator];
+}
+
+- (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx {
+  id<NSObject,NGFileManager> fm;
+  NSString *p;
+  BOOL     ok;
+  
+  if ([_name hasPrefix:@"."]) {
+    return [NSException exceptionWithHTTPStatus:405 /* not allowed */
+                        reason:@"creation of collections with a "
+                          @"leading dot is not allowed."];
+  }
+  
+  [self debugWithFormat:@"should create collection: %@", _name];
+  
+  p = [[self storagePath] stringByAppendingPathComponent:_name];
+  [self debugWithFormat:@"  path for new collection: %@", p];
+  
+  fm = [self fileManager];
+  ok = [fm createDirectoryAtPath:p attributes:nil];
+  if (!ok) {
+    [self debugWithFormat:@"  could not created collection at: %@", p];
+    return [NSException exceptionWithHTTPStatus:405 /* not allowed */
+                        reason:
+                          @"this OFSFolder could not create the collection"];
+  }
+  
+  [self debugWithFormat:@"  created collection."];
+  self->flags.didLoadAll = NO; /* not valid anymore */
+  return nil;
+}
+
+@end /* OFSFolder(SoDAV) */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFolder.h b/skyrix-sope/NGObjWeb/SoOFS/OFSFolder.h
new file mode 100644 (file)
index 0000000..e62496b
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __OFS_OFSFolder_H__
+#define __OFS_OFSFolder_H__
+
+#include <SoOFS/OFSBaseObject.h>
+
+/*
+  OFSFolder
+  
+  OFSFolder's map to filesystem directories and are "collections" of other
+  OFS objects. OFSFolder's can also store custom properties in a special file
+  (.props.plist).
+  
+  How collections are loaded
+  ==========================
+  When an OFSFolder is loaded, it doesn't instantiate any of it child objects
+  (since this would result in a cascade sucking in all the filesystem below.
+  As long as OFSFolder isn't sent -allObjects, it isn't fully loaded, instead
+  the objects are stored in the children hash and loaded on demand when the key
+  is looked up.
+  
+  How child objects are instantiated
+  ==================================
+  An OFSFolder also acts as a factory for it's children since it needs to
+  unarchive them into memory. That is, it's the task of the folder to select
+  an appropriate class for the in-memory representation of a childresource.
+  
+  Security
+  ========
+  The folder can manage the owner of the children and manages it's own
+  owner. The own owner is stored in the SoOwner field of the propertylist
+  and the children in the SoChildOwners field (which has to be a dictionary).
+*/
+
+@class NSArray, NSDictionary, NSMutableDictionary, NSString, NSEnumerator;
+@class WOResourceManager;
+@class SoClass;
+@class OFSFactoryContext, OFSFactoryRegistry;
+
+@interface OFSFolder : OFSBaseObject
+{
+@private
+  NSArray             *childNames;
+  NSMutableDictionary *children;
+  NSDictionary        *props;
+  struct {
+    BOOL didLoadAll:1;
+    BOOL hasCVS:1;
+    BOOL hasSvn:1;
+    BOOL checkedVersionSpecials:1;
+    int  reserved:28;
+  } flags;
+  WOResourceManager *resourceManager;
+}
+
+/* mimic a dictionary */
+
+- (NSArray *)allKeys;
+- (NSArray *)allValues;
+- (BOOL)hasKey:(NSString *)_key;
+- (id)objectForKey:(NSString *)_key;
+- (NSEnumerator *)keyEnumerator;
+- (NSEnumerator *)objectEnumerator;
+
+- (BOOL)isValidKey:(NSString *)_key;
+
+/* storage */
+
+- (void)willChange;
+
+- (NSString *)storagePathForChildKey:(NSString *)_name;
+
+- (id)restorationFactoryForContext:(OFSFactoryContext *)_ctx;
+- (id)creationFactoryForContext:(OFSFactoryContext *)_ctx;
+
+- (NSException *)reload;
+
+/* actions */
+
+- (NSString *)defaultMethodNameInContext:(id)_ctx;
+
+- (id)GETAction:(id)_ctx;
+- (id)PUTAction:(id)_ctx;
+- (id)MKCOLAction:(id)_ctx;
+- (id)DELETEAction:(id)_ctx;
+
+/* security */
+
+- (NSString *)ownerInContext:(id)_ctx;
+- (NSString *)ownerOfChild:(id)_child inContext:(id)_ctx;
+
+/* WO integration */
+
+- (WOResourceManager *)resourceManagerInContext:(id)_ctx;
+
+/* factory lookup */
+
+- (OFSFactoryRegistry *)factoryRegistry;
+- (id)restorationFactoryForContext:(OFSFactoryContext *)_ctx;
+- (id)creationFactoryForContext:(OFSFactoryContext *)_ctx;
+
+@end
+
+#endif /* __OFS_OFSFolder_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFolder.m b/skyrix-sope/NGObjWeb/SoOFS/OFSFolder.m
new file mode 100644 (file)
index 0000000..f76f853
--- /dev/null
@@ -0,0 +1,939 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSFolder.h"
+#include "OFSFile.h"
+#include "OFSFactoryContext.h"
+#include "OFSFactoryRegistry.h"
+#include "OFSResourceManager.h"
+#include "OFSFolderClassDescription.h"
+#include "OFSFolderDataSource.h"
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@implementation OFSFolder
+
+static BOOL factoryDebugOn  = NO;
+static BOOL debugLookup     = NO;
+static BOOL debugRestore    = NO;
+static BOOL debugNegotiate  = NO;
+static BOOL debugAuthLookup = NO;
+
++ (int)version {
+  return [super version] + 1 /* v2 */;
+}
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    NSAssert2([super version] == 1,
+             @"invalid superclass (%@) version %i !",
+             NSStringFromClass([self superclass]), [super version]);
+    
+    debugLookup     = [ud boolForKey:@"SoDebugKeyLookup"];
+    factoryDebugOn  = [ud boolForKey:@"SoOFSDebugFactory"];
+    debugRestore    = [ud boolForKey:@"SoOFSDebugRestore"];
+    debugNegotiate  = [ud boolForKey:@"SoOFSDebugNegotiate"];
+    debugAuthLookup = [ud boolForKey:@"SoOFSDebugAuthLookup"];
+  }
+}
+
+- (void)dealloc {
+  [(OFSResourceManager *)self->resourceManager invalidate];
+  [self->resourceManager release];
+  
+  [[self->children allValues] 
+    makeObjectsPerformSelector:@selector(detachFromContainer)];
+  
+  [self->childNames  release];
+  [self->props    release];
+  [self->children release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)propertyFilename {
+  return @".props.plist";
+}
+
+- (BOOL)isCollection {
+  return YES;
+}
+- (BOOL)hasChildren {
+  return [self->childNames count] > 0 ? YES : NO;
+}
+
+- (NSArray *)allKeys {
+  return self->childNames;
+}
+
+- (BOOL)hasKey:(NSString *)_key {
+  return [self->childNames containsObject:_key];
+}
+
+- (id)objectForKey:(NSString *)_key {
+  OFSFactoryContext *ctx;
+  NSDictionary *fileAttrs;
+  NSString     *fileType, *mimeType;
+  NSString     *childPath;
+  id child;
+  id factory;
+  
+  if ((child = [self->children objectForKey:_key]))
+    /* cached */
+    return [child isNotNull] ? child : nil;
+  
+  if ([_key hasPrefix:@"."])
+    /* do not consider keys starting with a point ... */
+    return nil;
+  
+  if (self->flags.didLoadAll)
+    /* everything is cached, should be in there .. */
+    return nil;
+  
+  if (![self->childNames containsObject:_key])
+    /* not a storage key anyway */
+    return nil;
+  
+  /* find out filetype */
+  
+  childPath = [self storagePathForChildKey:_key];
+  fileAttrs = [[self fileManager] fileAttributesAtPath:childPath
+                                 traverseLink:YES];
+  fileType  = [fileAttrs objectForKey:NSFileType];
+  mimeType  = [fileAttrs objectForKey:@"NSFileMimeType"];
+  
+  if (fileType == nil)
+    [self logWithFormat:@"got no file type for child %@ ...", _key];
+  
+  /* create factory context */
+  
+  ctx = [OFSFactoryContext contextForChild:_key
+                          storagePath:childPath
+                          ofFolder:self];
+  ctx->fileType = [fileType copy];
+  ctx->mimeType = [mimeType copy];
+  
+  /* lookup factory */
+  
+  if ((factory = [self restorationFactoryForContext:ctx]) == nil) {
+    [self logWithFormat:@"found no factory for key '%@' (%@, mime=%@)",
+           _key, fileType, mimeType];
+    return [NSException exceptionWithHTTPStatus:500
+                       reason:@"found no factory for object !"];
+  }
+  
+  if (factoryDebugOn)
+    [self debugWithFormat:@"selected factory %@ for key %@", factory, _key];
+  
+  /* instantiate and register */
+  
+  if (self->children == nil) {
+    self->children =
+      [[NSMutableDictionary alloc] initWithCapacity:[self->childNames count]];
+  }
+  
+  if ((child = [factory instantiateInFactoryContext:ctx]) == nil) {
+    [self logWithFormat:@"factory did not instantiate object for key '%@'",
+           _key];
+    child = [NSException exceptionWithHTTPStatus:500
+                        reason:@"instantiation of object failed !"];
+  }
+  
+  [self->children setObject:child forKey:_key];
+  
+  /* awake object, handle possible replacement result */
+  
+  if (![child isKindOfClass:[NSException class]]) {
+    id replacement;
+    
+    replacement = [child awakeFromFetchInContext:ctx];
+    if (replacement != child) {
+      if (replacement == nil)
+       [self->children removeObjectForKey:_key];
+      else
+       [self->children setObject:replacement forKey:_key];
+    }
+  }
+  
+  return child;
+}
+
+- (NSArray *)allValues {
+  NSEnumerator *keys;
+  NSString     *key;
+  
+  if (self->flags.didLoadAll)
+    return [self->children allValues];
+  
+  /* query each key to load it into the children cache */
+  
+  keys = [self->childNames objectEnumerator];
+  while ((key = [keys nextObject]))
+    [self objectForKey:key];
+  
+  self->flags.didLoadAll = 1;
+  return [self->children allValues];
+}
+
+- (NSEnumerator *)keyEnumerator {
+  return [self->childNames objectEnumerator];
+}
+- (NSEnumerator *)objectEnumerator {
+  return [[self allValues] objectEnumerator];
+}
+
+- (BOOL)isValidKey:(NSString *)_key {
+  /* 
+     Check whether key is usable for storage (extract some FS sensitive or 
+     private keys)
+  */
+  unichar c;
+  if ([_key length] == 0) return NO;
+  c = [_key characterAtIndex:0];
+  if (c == '.') return NO;
+  if (c == '~') return NO;
+  if (c == '%') return NO;
+  if (c == '/') return NO;
+  if ([_key rangeOfString:@"/"].length  > 0) 
+    // TBD: we should allow '/' in filenames
+    return NO;
+  if ([_key isEqualToString:[self propertyFilename]])
+    return NO;
+  return YES;
+}
+
+/* datasource */
+
+- (EODataSource *)contentDataSource {
+  return [OFSFolderDataSource dataSourceOnFolder:self];
+}
+
+/* storage */
+
+- (void)willChange {
+}
+
+- (NSString *)storagePathForChildKey:(NSString *)_name {
+  if (![self isValidKey:_name]) return nil;
+  return [[self storagePath] stringByAppendingPathComponent:_name];
+}
+
+- (OFSFactoryRegistry *)factoryRegistry {
+  return [OFSFactoryRegistry sharedFactoryRegistry];
+}
+
+- (id)restorationFactoryForContext:(OFSFactoryContext *)_ctx {
+  return [[self factoryRegistry] restorationFactoryForContext:_ctx];
+}
+- (id)creationFactoryForContext:(OFSFactoryContext *)_ctx {
+  return [[self factoryRegistry] creationFactoryForContext:_ctx];
+}
+
+/* unarchiving */
+
+- (NSClassDescription *)soClassDescription {
+  // TODO: cache class description ?
+  return [[[OFSFolderClassDescription alloc] initWithFolder:self] autorelease];
+}
+- (NSArray *)attributeKeys {
+  return [self->props allKeys];
+}
+- (NSArray *)toOneRelationshipKeys {
+  return [self allKeys];
+}
+
+- (void)filterChildNameArray:(NSMutableArray *)p {
+  unsigned i;
+  
+  [p removeObject:[self propertyFilename]];
+  
+  for (i = 0; i < [p count];) {
+    NSString *k;
+    unsigned kl;
+    
+    k = [p objectAtIndex:i];
+    kl = [k length];
+    if (kl == 3 && !self->flags.hasCVS && [k isEqualToString:@"CVS"]) {
+      self->flags.hasCVS = 1;
+      [p removeObjectAtIndex:i];
+    }
+    else if (kl == 4 && !self->flags.hasSvn && [k isEqualToString:@".svn"]) {
+      self->flags.hasSvn = 1;
+      [p removeObjectAtIndex:i];
+    }
+    else if ([k hasPrefix:@"."])
+      [p removeObjectAtIndex:i];
+    else
+      i++;
+  }
+  self->flags.checkedVersionSpecials = 1;
+}
+
+- (id)awakeFromFetchInContext:(OFSFactoryContext *)_ctx {
+  NSString *sp;
+  id       p;
+  
+  if (debugRestore)
+    [self debugWithFormat:@"-awakeFromContext:%@", _ctx];
+  
+  if ((p = [super awakeFromFetchInContext:_ctx]) != self) {
+    if (debugRestore)
+      [self debugWithFormat:@"  parent replaced object with: %@", p];
+    return p;
+  }
+  
+  sp = [_ctx storagePath];
+  if (debugRestore)
+    [self debugWithFormat:@"  restore path: '%@'", sp];
+  
+  /* load the dictionary properties */
+  
+  p = [sp stringByAppendingPathComponent:[self propertyFilename]];
+  self->props = [[NSDictionary alloc] initWithContentsOfFile:p];
+  
+  if (debugRestore) {
+    [self debugWithFormat:@"  restored %i properties: %@", 
+           [self->props count],
+           [[self->props allKeys] componentsJoinedByString:@","]];
+  }
+  
+  /* load the collection children names */
+  
+  p = [[[_ctx fileManager] directoryContentsAtPath:sp] mutableCopy];
+  if (p == nil) {
+    [self debugWithFormat:@"couldn't get child names at path '%@'.", p];
+    return nil;
+  }
+  if (debugRestore)
+    [self debugWithFormat:@"  storage child names at '%@': %@", sp, p];
+  
+  [self filterChildNameArray:p];
+  [p sortUsingSelector:@selector(compare:)];
+  
+  self->childNames = [p copy];
+  [p release];
+  
+  if (debugRestore) {
+    [self debugWithFormat:@"  restored child names: %@", 
+           [self->childNames componentsJoinedByString:@","]];
+  }
+  
+  return self;
+}
+
+- (void)flushChildCache {
+  [[self->children allValues] 
+    makeObjectsPerformSelector:@selector(detachFromContainer)];
+  [self->children removeAllObjects];
+  self->flags.didLoadAll = 0;
+}
+
+- (NSException *)reload {
+  // TODO: reload folder !
+  [self flushChildCache];
+  return nil;
+}
+
+/* KVC */
+
+- (id)valueForKey:(NSString *)_name {
+  /* map out some very private keys */
+  unsigned nl;
+  unichar  c;
+  NSString *v;
+  
+  if ((v = [self->props objectForKey:_name]))
+    return v;
+  
+  if ((nl = [_name length]) == 0)
+    return nil;
+  
+  c = [_name characterAtIndex:0];
+  // TBD ?
+  
+  return [super valueForKey:_name];
+}
+
+/* operations */
+
+- (BOOL)allowRecursiveDeleteInContext:(id)_ctx {
+  return NO;
+}
+
+- (NSString *)defaultMethodNameInContext:(id)_ctx {
+  return @"index";
+}
+- (id)lookupDefaultMethod {
+  id ctx = nil;
+  
+  ctx = [[WOApplication application] context];
+  return [self lookupName:[self defaultMethodNameInContext:ctx]
+              inContext:ctx
+              acquire:YES];
+}
+
+- (id)GETAction:(id)_ctx {
+  WOResponse *r = [(id <WOPageGenerationContext>)_ctx response];
+  NSString   *uri, *qs, *method;
+  NSRange    ra;
+  
+  if (![[_ctx soRequestType] isEqualToString:@"METHOD"])
+    return self;
+  
+  if ((method = [self defaultMethodNameInContext:_ctx]) == nil)
+    /* no default method */
+    return self;
+
+  /* construct URI */
+  
+  uri = [[(id <WOPageGenerationContext>)_ctx request] uri];
+  ra = [uri rangeOfString:@"?"];
+  if (ra.length > 0) {
+    qs  = [uri substringFromIndex:ra.location];
+    uri = [uri substringToIndex:ra.location];
+  }
+  else
+    qs = nil;
+  uri = [uri stringByAppendingPathComponent:method];
+  if (qs) uri = [uri stringByAppendingString:qs];
+  
+  [r setStatus:302 /* moved */];
+  [r setHeader:uri forKey:@"location"];
+  return r;
+}
+
+- (id)DELETEAction:(id)_ctx {
+  NSException *e;
+  
+  if ((e = [self validateForDelete]))
+    return e;
+  
+  if ([self hasChildren]) {
+    if (![self allowRecursiveDeleteInContext:_ctx]) {
+      return [NSException exceptionWithHTTPStatus:403 /* forbidden */
+                         reason:@"tried to delete a filled folder"];
+    }
+  }
+  return [super DELETEAction:_ctx];
+}
+
+- (id)PUTAction:(id)_ctx {
+  OFSFactoryContext *ctx;
+  NSString    *pathInfo;
+  NSString    *childPath;
+  id          factory;
+  id          result, child;
+  id          childPutMethod;
+  
+  pathInfo = [_ctx pathInfo];
+  /* TODO: NEED TO REWRITE path info to a key (eg strip .vcf) ! */
+  
+  // TODO: return conflict, on attempt to create subfolder
+  if ([pathInfo length] == 0) {
+    [self debugWithFormat:@"attempt to PUT to an OFSFolder !"];
+    [self debugWithFormat:@"body:\n%@", [[(id <WOPageGenerationContext>)_ctx request] contentAsString]];
+    
+    return [NSException exceptionWithHTTPStatus:405 /* method not allowed */
+                       reason:@"HTTP PUT not allowed on a folder resource"];
+  }
+  
+  if ([self->childNames containsObject:pathInfo]) {
+    /*
+      Explained: PUT can be and is used to overwrite existing resources. But
+      if PUT was issued on an existing resource, the SoObject for this resource
+      will receive the PUT action, not it's contained.
+      So: the container (folder) only receives a PUT action with a PATH_INFO if
+      the resource to be PUT is new.
+    */
+    [self debugWithFormat:
+           @"internal inconsistency, tried to create an existing resource !"];
+    return [NSException exceptionWithHTTPStatus:500 /* method not allowed */
+                       reason:@"tried to create an existing resource"];
+  }
+  
+  if ((childPath = [self storagePathForChildKey:pathInfo]) == nil) {
+    [self debugWithFormat:@"invalid name for child !"];
+    return [NSException exceptionWithHTTPStatus:400 /* bad request */
+                       reason:@"the name for the child creation was invalid"];
+  }
+  
+  /* create factory context */
+  
+  ctx = [OFSFactoryContext contextForNewChild:pathInfo
+                          storagePath:childPath
+                          ofFolder:self];
+  ctx->fileType = [NSFileTypeRegular retain];
+  ctx->mimeType = [[[(id <WOPageGenerationContext>)_ctx request] headerForKey:@"content-type"] copy];
+  
+  /* lookup factory */
+  
+  if ((factory = [self creationFactoryForContext:ctx]) == nil) {
+    [self logWithFormat:@"found no factory for new key '%@' (%@, mime=%@)",
+           pathInfo, ctx->fileType, [ctx mimeType]];
+    return [NSException exceptionWithHTTPStatus:500
+                       reason:@"found no factory for new object !"];
+  }
+  
+  if (factoryDebugOn) {
+    [self debugWithFormat:@"selected factory %@ for new child named %@", 
+           factory, pathInfo];
+  }
+  
+  /* instantiate and register */
+  
+  if (self->children == nil) {
+    self->children =
+      [[NSMutableDictionary alloc] initWithCapacity:[self->childNames count]];
+  }
+  
+  if ((child = [factory instantiateInFactoryContext:ctx]) == nil) {
+    [self logWithFormat:
+           @"factory did not instantiate new object for key '%@'",
+           pathInfo];
+    return [NSException exceptionWithHTTPStatus:500
+                       reason:@"instantiation of object failed !"];
+  }
+  if ([child isKindOfClass:[NSException class]])
+    return child;
+  
+  childPutMethod = [child lookupName:@"PUT" inContext:_ctx acquire:NO];
+  if (childPutMethod == nil) {
+    return [NSException exceptionWithHTTPStatus:405 /* method not allowed */
+                       reason:@"new child does not support HTTP PUT."];
+  }
+  
+  [self->children setObject:child forKey:pathInfo];
+  
+  /* awake object, handle possible replacement result */
+  
+  {
+    id replacement;
+    
+    replacement = [child awakeFromInsertionInContext:ctx];
+    if (replacement != child) {
+      if ([replacement isKindOfClass:[NSException class]]) {
+       replacement = [replacement retain];
+       [self->children removeObjectForKey:pathInfo];
+       return [replacement autorelease];
+      }
+      
+      if (replacement == nil) {
+       [self->children removeObjectForKey:pathInfo];
+       return [NSException exceptionWithHTTPStatus:500
+                           reason:@"awake failed, reason unknown"];
+      }
+      else {
+       childPutMethod = 
+         [replacement lookupName:@"PUT" inContext:_ctx acquire:NO];
+       
+       if (childPutMethod == nil) {
+         [self->children removeObjectForKey:pathInfo];
+         return [NSException exceptionWithHTTPStatus:405 /* not allowed */
+                             reason:@"new child does not support HTTP PUT."];
+       }
+       
+       [self->children setObject:replacement forKey:pathInfo];
+       child = replacement;
+      }
+    }
+  }
+  
+  /* now forward the PUT to the child */
+  
+  result = [[childPutMethod bindToObject:child inContext:_ctx]
+                           callOnObject:child inContext:_ctx];
+  
+  /* check whether put was successful */
+  
+  if ([result isKindOfClass:[NSException class]]) {
+    /* creation failed, unregister from childlist */
+    [child detachFromContainer];
+    [self->children removeObjectForKey:pathInfo];
+  }
+  
+  return result;
+}
+
+- (id)MKCOLAction:(id)_ctx {
+  NSString *pathInfo;
+  
+  pathInfo = [_ctx pathInfo];
+  pathInfo = [pathInfo stringByUnescapingURL];
+  
+  if ([pathInfo length] == 0) {
+    [self debugWithFormat:@"attempt to MKCOL an existint OFSFolder !"];
+    return [NSException exceptionWithHTTPStatus:405 /* method not allowed */
+                       reason:@"tried MKCOL an an existing resource"];
+  }
+  
+  // TBD: create new child
+  // TBD: return conflict, on attempt to create subfolder
+  return [NSException exceptionWithHTTPStatus:403 /* forbidden */
+                     reason:@"creating collections is forbidden"];
+}
+
+/* lookup */
+
+- (NSString *)normalizeKey:(NSString *)_name inContext:(id)_ctx {
+  /* useful for content-negotiation */
+  return _name;
+}
+
+- (NSString *)selectBestMatchForName:(NSString *)_name 
+  fromChildNames:(NSArray *)_matches
+  inContext:(id)_ctx
+{
+  NSString *storeName;
+  unsigned count;
+  
+  if ((count = [_matches count]) == 0)
+    storeName = nil;
+  else if (count == 1)
+    storeName = [_matches objectAtIndex:0];
+  else {
+    // TODO: some real negotiation based on "accept", "language", ..
+    storeName = [_matches objectAtIndex:0];
+    [self logWithFormat:@"negotiate: selected '%@' from: %@.", storeName,
+           [_matches componentsJoinedByString:@","]];
+  }
+  if (debugNegotiate) [self logWithFormat:@"negotiated: '%@'", storeName];
+  return storeName;
+}
+  
+- (NSString *)negotiateName:(NSString *)_name inContext:(id)_ctx {
+  /* returns a "storeName", one which can be resolved in the store */
+  NSMutableArray *matches;
+  NSString *askedExt, *normName, *storeName;
+  NSArray  *availKeys;
+  unsigned i, count;
+
+  if (debugNegotiate) [self logWithFormat:@"negotiate: %@", _name];
+  
+  availKeys = [self allKeys];
+  if ((count = [availKeys count]) == 0)
+    return nil;   /* no content */
+  if ([availKeys containsObject:_name])
+    return _name; /* exact match */
+  
+  /* some hard-coded content negotiation */
+  
+  askedExt = [_name pathExtension];
+  normName = [_name stringByDeletingPathExtension];
+  
+  for (i = 0, matches = nil; i < count; i++) {
+    NSString *storeName, *childNormName;
+    
+    storeName     = [availKeys objectAtIndex:i];
+    childNormName = [storeName stringByDeletingPathExtension];
+    
+    if (debugNegotiate) [self logWithFormat:@"  check: %@", storeName];
+    
+    if (![normName isEqualToString:childNormName])
+      /* does not match */
+      continue;
+    
+    if (matches == nil) matches = [[NSMutableArray alloc] initWithCapacity:16];
+    [matches addObject:storeName];
+  }
+  
+  if (matches == nil)
+    return nil; /* no matches */
+  
+  storeName = [self selectBestMatchForName:normName 
+                   fromChildNames:matches
+                   inContext:_ctx];
+  storeName = [[storeName copy] autorelease];
+  [matches release];
+  return storeName;
+}
+
+- (BOOL)hasName:(NSString *)_name inContext:(id)_ctx {
+  _name = [self normalizeKey:_name inContext:_ctx];
+  
+  if ([self hasKey:_name])
+    /* is a stored key ! */
+    return YES;
+  
+  /* queried something else */
+  return [super hasName:_name inContext:_ctx];
+}
+
+- (NSException *)validateName:(NSString *)_name inContext:(id)_ctx {
+  return [super validateName:[self normalizeKey:_name inContext:_ctx] inContext:_ctx];
+}
+
+- (id)lookupStoredName:(NSString *)_name inContext:(id)_ctx {
+  NSString *storeName;
+  
+  if ((storeName = [self negotiateName:_name inContext:_ctx]) == nil)
+    return nil;
+  
+  /* is a stored key ! */
+  return [self objectForKey:storeName];
+}
+
+- (id)handleMissingName:(NSString *)_name inContext:(id)_ctx {
+  // TODO: object autocreation support (aka "create on access")
+  if (debugLookup)
+    [self debugWithFormat:@"  found no matching value for key: %@", _name];
+  return nil;
+}
+
+- (id)lookupName:(NSString *)_name inContext:(id)_ctx acquire:(BOOL)_flag {
+  id value;
+  
+  if (debugLookup) [self debugWithFormat:@"lookup key '%@'", _name];
+
+  /* normalize key */
+  
+  _name = [self normalizeKey:_name inContext:_ctx];
+  if (debugLookup)
+    [self debugWithFormat:@"  normalized '%@'", _name];
+
+  /* lookup in folder storage */
+  
+  if ((value = [self lookupStoredName:_name inContext:_ctx])) {
+    /* found an SoOFS child in storage */
+    if (debugLookup) [self debugWithFormat:@"  stored value: %@", value];
+    return value;
+  }
+  
+  if (debugLookup) {
+    [self debugWithFormat:@"  not a collection child: %@", 
+           [[self allKeys] componentsJoinedByString:@","]];
+  }
+  
+  /* queried something else */
+  if ((value = [super lookupName:_name inContext:_ctx acquire:_flag])) {
+    if (debugLookup)
+      [self debugWithFormat:@"  value from superclass: %@", value];
+    return value;
+  }
+  
+  return [self handleMissingName:_name inContext:_ctx];
+}
+
+/* security */
+
+- (id)lookupAuthenticatorNamed:(NSString *)_name inContext:(id)_ctx {
+  /* look for a "user-folder" (an authentication database) */
+  id auth, res;
+
+  if ((auth = [self lookupName:_name inContext:_ctx acquire:NO])==nil)
+    return nil;
+  
+  if (debugAuthLookup)
+    [self logWithFormat:@"use '%@' user-folder: %@", _name, auth];
+  if (auth == self) {
+    if (debugAuthLookup)
+      [self logWithFormat:@"  auth recursion detected: %@", auth];
+    return nil;
+  }
+  
+  res = [auth authenticatorInContext:_ctx];
+  if (debugAuthLookup)
+    [self logWithFormat:@"  got authenticator: %@", res];
+  if (res == self) {
+    if (debugAuthLookup) {
+      [self logWithFormat:
+             @"  recursion detected (%@ returned folder): %@, auth: %@", 
+             _name, res, auth];
+    }
+    return nil;
+  }
+  else if (res == auth) {
+    if (debugAuthLookup) {
+      [self logWithFormat:
+             @"  recursion detected (%@ returned auth): %@", 
+             _name, auth];
+    }
+    return nil;
+  }
+  return res;
+}
+
+- (id)authenticatorInContext:(id)_ctx {
+  /* look for a "user-folder" (an authentication database) */
+  id auth;
+  
+  /* the following are flawed and can lead to recursions */
+  if ((auth = [self lookupAuthenticatorNamed:@"htpasswd" inContext:_ctx]))
+    return auth;
+  if ((auth = [self lookupAuthenticatorNamed:@"acl_users" inContext:_ctx]))
+    return auth;
+  
+  // TODO: check children for extensions
+  
+  if (debugAuthLookup)
+    [self logWithFormat:@"no user-folder in folder ..."];
+  
+  return [super authenticatorInContext:_ctx];
+}
+
+- (NSString *)ownerInContext:(id)_ctx {
+  NSString *owner;
+  
+  if ((owner = [self->props objectForKey:@"SoOwner"]))
+    return owner;
+  
+  /* let parent handle my owner */
+  return [[self container] ownerOfChild:self inContext:_ctx];
+}
+
+- (NSString *)ownerOfChild:(id)_child inContext:(id)_ctx {
+  NSDictionary *childOwners;
+  NSString *owner;
+  
+  if ((childOwners = [self->props objectForKey:@"SoChildOwners"])) {
+    if ((owner = [childOwners objectForKey:[_ctx nameInContainer]]))
+      return owner;
+  }
+  
+  /* let child inherit owner of container */
+  return [self ownerInContext:_ctx];
+}
+
+/* WO integration */
+
+- (WOResourceManager *)resourceManagerInContext:(id)_ctx {
+  if (self->resourceManager == nil) {
+    self->resourceManager =
+      [[OFSResourceManager alloc] initWithBaseObject:self inContext:_ctx];
+  }
+  return self->resourceManager;
+}
+
+/* version control */
+
+- (void)checkVersionControlSpecials {
+  id<NGFileManager> fm;
+  NSString *sp, *p;
+  BOOL isDir = NO;
+  
+  if ((fm = [self fileManager]) == nil) return;
+  if ((sp = [self storagePath]) == nil) return;
+  
+  p = [sp stringByAppendingPathComponent:@"CVS"];
+  self->flags.hasCVS = [fm fileExistsAtPath:p isDirectory:&isDir]
+    ? (isDir ? 1 : 0)
+    : 0;
+  
+  p = [sp stringByAppendingPathComponent:@".svn"];
+  self->flags.hasSvn = [fm fileExistsAtPath:p isDirectory:&isDir]
+    ? (isDir ? 1 : 0)
+    : 0;
+  
+  self->flags.checkedVersionSpecials = 1;
+}
+- (BOOL)isCvsControlled {
+  if (!self->flags.checkedVersionSpecials)
+    [self checkVersionControlSpecials];
+  return self->flags.hasCVS;
+}
+- (BOOL)isSvnControlled {
+  if (!self->flags.checkedVersionSpecials)
+    [self checkVersionControlSpecials];
+  return self->flags.hasSvn;
+}
+
+@end /* OFSFolder */
+
+@implementation OFSFolder(Factory)
+
++ (id)instantiateInFactoryContext:(OFSFactoryContext *)_ctx {
+  /* look into plist for class */
+  NSDictionary *plist;
+  NSData       *content;
+  SoClass      *clazz;
+  NSString     *plistPath;
+  id object;
+  
+  plistPath = [[_ctx storagePath] 
+                    stringByAppendingPathComponent:@".props.plist"];
+  content = [[_ctx fileManager] contentsAtPath:plistPath];
+  if (content == nil) {
+    /* found no plist */
+    clazz = [self soClass];
+  }
+  else {
+    /* parse the existing plist file */
+    NSString *string;
+    NSString *className;
+    
+    string = [[NSString alloc] initWithData:content
+                            encoding:[NSString defaultCStringEncoding]];
+    if (string == nil) {
+      [self logWithFormat:@"could not make string for stored data."];
+      return [NSException exceptionWithHTTPStatus:500
+                       reason:@"stored property list is corrupted"];
+    }
+    
+    if ((plist = [string propertyList]) == nil) {
+      [string release];
+      [self logWithFormat:@"could not make plist for stored data."];
+      return [NSException exceptionWithHTTPStatus:500
+                       reason:
+                         @"stored property list is corrupted "
+                         @"(not in plist format)"];
+    }
+    [string release];
+  
+    /* lookup the classname in plist */
+    
+    className = [plist objectForKey:@"SoClassName"];
+    if ([className length] == 0) {
+      if ((className = [plist objectForKey:@"SoFolderClassName"]))
+        [self logWithFormat:
+               @"%@: SoFolderClassName is deprecated (use SoClassName) !",
+               plistPath];
+    }
+    
+    if ([className length] == 0) {
+      /* no special class assigned, use default */
+      clazz = [self soClass];
+    }
+    else {
+      clazz = [[SoClassRegistry sharedClassRegistry] 
+               soClassWithName:className];
+      if (clazz == nil) {
+        [self logWithFormat:@"did not find SoClass: %@", className];
+        return nil;
+      }
+    }
+  }
+  
+  /* instantiate */
+  
+  if (factoryDebugOn) {
+    [self debugWithFormat:@"instantiate child %@ from class %@",
+           [_ctx nameInContainer], clazz];
+  }
+  
+  object = [clazz instantiateObject];
+  [object takeStorageInfoFromContext:_ctx];
+  return object;
+}
+
+@end /* OFSFolder(Factory) */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFolderClassDescription.h b/skyrix-sope/NGObjWeb/SoOFS/OFSFolderClassDescription.h
new file mode 100644 (file)
index 0000000..bb0e553
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoOFS_OFSFolderClassDescription_H__
+#define __SoOFS_OFSFolderClassDescription_H__
+
+#import <Foundation/NSClassDescription.h>
+
+/*
+  OFSFolderClassDescription
+  
+  A class description of a folder is dynamic and depends on the contents of
+  the folder. For example a folder exports it's contained objects as
+  toOneRelationshipKeys.
+*/
+
+@class OFSFolder;
+
+@interface OFSFolderClassDescription : NSClassDescription
+{
+  OFSFolder *object;
+}
+
+- (id)initWithFolder:(OFSFolder *)_folder;
+
+@end
+
+#endif /* __SoOFS_OFSFolderClassDescription_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFolderClassDescription.m b/skyrix-sope/NGObjWeb/SoOFS/OFSFolderClassDescription.m
new file mode 100644 (file)
index 0000000..ac6dbe0
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSFolderClassDescription.h"
+#include "OFSFolder.h"
+#include "common.h"
+
+@implementation OFSFolderClassDescription
+
+- (id)initWithFolder:(OFSFolder *)_folder {
+  if ((self = [super init])) {
+    self->object = [_folder retain];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->object release];
+  [super dealloc];
+}
+
+- (NSArray *)attributeKeys {
+  return [self->object attributeKeys];
+}
+
+- (NSArray *)toOneRelationshipKeys {
+  return [self->object toOneRelationshipKeys];
+}
+
+@end /* OFSFolderClassDescription */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFolderDataSource.h b/skyrix-sope/NGObjWeb/SoOFS/OFSFolderDataSource.h
new file mode 100644 (file)
index 0000000..6203f55
--- /dev/null
@@ -0,0 +1,25 @@
+// $Id$
+
+#ifndef __SoOFS_OFSFolderDataSource_H__
+#define __SoOFS_OFSFolderDataSource_H__
+
+#include <EOControl/EODataSource.h>
+
+@class EOFetchSpecification;
+
+@interface OFSFolderDataSource : EODataSource < NSCopying >
+{
+  EOFetchSpecification *fetchSpecification;
+  id folder;
+}
+
++ (id)dataSourceOnFolder:(id)_folder;
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec;
+- (EOFetchSpecification *)fetchSpecification;
+
+@end
+
+#endif /* __SoOFS_OFSFolderDataSource_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSFolderDataSource.m b/skyrix-sope/NGObjWeb/SoOFS/OFSFolderDataSource.m
new file mode 100644 (file)
index 0000000..d0b244d
--- /dev/null
@@ -0,0 +1,207 @@
+// $Id$
+
+#include "OFSFolderDataSource.h"
+#include <EOControl/EOQualifier.h>
+#include <EOControl/EOSortOrdering.h>
+#include "common.h"
+
+@interface OFSFolderFetchEnum : NSEnumerator
+{
+  id           folder;
+  NSEnumerator *names;
+  EOQualifier  *qualifier;
+  unsigned     limit;
+  unsigned     count;
+}
+
+- (id)initWithFolder:(id)_folder 
+  fetchSpecification:(EOFetchSpecification *)_fs;
+
+@end
+
+@implementation OFSFolderDataSource
+
+- (id)initWithFolder:(id)_folder {
+  if ((self = [super init])) {
+    self->folder = [_folder retain];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithFolder:nil];
+}
++ (id)dataSourceOnFolder:(id)_folder {
+  return [[[self alloc] initWithFolder:_folder] autorelease];
+}
+
+- (void)dealloc {
+  [self->fetchSpecification release];
+  [self->folder             release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id)folder {
+  return self->folder;
+}
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec {
+  if ([self->fetchSpecification isEqual:_fspec])
+    return;
+  
+  [self->fetchSpecification autorelease];
+  self->fetchSpecification = [_fspec copy];
+  
+  [self postDataSourceChangedNotification];
+}
+- (EOFetchSpecification *)fetchSpecification {
+  return self->fetchSpecification;
+}
+
+/* operations */
+
+- (NSEnumerator *)fetchEnumerator {
+  OFSFolderFetchEnum   *e;
+  EOFetchSpecification *fs;
+  NSArray              *sortOrderings;
+  NSAutoreleasePool    *pool;
+  NSArray              *array;
+  unsigned    limit;
+  EOQualifier *q;
+  
+  if ((fs = [self fetchSpecification]) == nil) {
+    e = [[OFSFolderFetchEnum alloc] initWithFolder:[self folder]
+                                      fetchSpecification:nil];
+    return [e autorelease];
+  }
+    
+  sortOrderings = [fs sortOrderings];
+  if ([sortOrderings count] == 0) {
+    /* can do incremental fetch ... */
+    e = [[OFSFolderFetchEnum alloc] initWithFolder:[self folder]
+                                      fetchSpecification:fs];
+    return [e autorelease];
+  }
+  
+  /* fetch => filter => limit => sort, then return enum ... */
+  
+  pool = [[NSAutoreleasePool alloc] init];
+       
+  array = [[self folder] allValues];
+  
+  if ((q = [fs qualifier])) 
+    array = [array filteredArrayUsingQualifier:q];
+
+  if ((limit = [fs fetchLimit]) > 0) {
+    /* limit ... */
+    if (limit < [array count])
+      array = [array subarrayWithRange:NSMakeRange(0, limit)];
+  }
+  
+  array = [array sortedArrayUsingKeyOrderArray:sortOrderings];
+  
+  e = [[array objectEnumerator] retain];
+  
+  [pool release];
+  return [e autorelease];
+}
+
+- (NSArray *)fetchObjects {
+  NSEnumerator *e;
+  
+  e = [self fetchEnumerator];
+  return [[[NSArray alloc] initWithObjectsFromEnumerator:e] autorelease];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  OFSFolderDataSource *ds;
+  
+  ds = [[[self class] alloc] initWithFolder:[self folder]];
+  [ds setFetchSpecification:[self fetchSpecification]];
+  return ds;
+}
+
+@end /* OFSFolderDataSource */
+
+@implementation OFSFolderFetchEnum
+
+- (id)initWithFolder:(id)_folder 
+  fetchSpecification:(EOFetchSpecification *)_fs
+{
+  if ((self = [super init])) {
+    self->folder    = [_folder retain];
+    self->names     = [[[self->folder allKeys] objectEnumerator] retain];
+    self->qualifier = [[_fs qualifier] retain];
+    self->limit     = [_fs fetchLimit];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithFolder:nil fetchSpecification:nil];
+}
+
+- (void)dealloc {
+  [self->qualifier release];
+  [self->names     release];
+  [self->folder    release];
+  [super dealloc];
+}
+
+/* state */
+
+- (void)clear {
+  [self->qualifier release]; self->qualifier = nil;
+  [self->names     release]; self->names     = nil;
+  [self->folder    release]; self->folder    = nil;
+}
+
+/* enumerator */
+
+- (id)_nextObjectToBeFiltered {
+  NSString *nextName;
+  id object;
+  
+  if ((nextName = [self->names nextObject]) == nil) {
+    [self clear];
+    return nil;
+  }
+  if ((object = [self->folder objectForKey:nextName]) == nil) {
+    [self clear];
+    return nil;
+  }
+  return object;
+}
+
+- (id)nextObject {
+  id obj;
+
+  if(self->qualifier != nil) {
+    do {
+      if ((obj = [self _nextObjectToBeFiltered]) == nil) {
+        [self clear];
+        return nil;
+      }
+    }
+    while (![(id<EOQualifierEvaluation>)self->qualifier
+      evaluateWithObject:obj]);
+  }
+  else {
+    if ((obj = [self _nextObjectToBeFiltered]) == nil) {
+      [self clear];
+      return nil;
+    }
+  }
+
+  self->count++;
+  if (self->limit > 0 && self->count > self->limit) {
+    [self clear];
+    return nil;
+  }
+  
+  return obj;
+}
+
+@end /* OFSFolderFetchEnum */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSHttpPasswd.h b/skyrix-sope/NGObjWeb/SoOFS/OFSHttpPasswd.h
new file mode 100644 (file)
index 0000000..f482696
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoOFS_OFSHttpPasswd_H__
+#define __SoOFS_OFSHttpPasswd_H__
+
+#include <SoOFS/OFSFile.h>
+
+/*
+  OFSHttpPasswd
+  
+  A user-folder which uses an Apache htpasswd file as a authentication
+  database (only crypt is currently supported !)
+*/
+
+@class NSString, NSArray, NSDictionary;
+
+@interface OFSHttpPasswd : OFSFile
+{
+  id           authenticator; /* cache */
+  NSDictionary *content;
+}
+
+/* implementation */
+- (NSString *)authRealm;
+- (NSArray *)rolesForLogin:(NSString *)_login;
+- (BOOL)checkLogin:(NSString *)_login password:(NSString *)_pwd;
+
+@end
+
+#endif /* __SoOFS_OFSHttpPasswd_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSHttpPasswd.m b/skyrix-sope/NGObjWeb/SoOFS/OFSHttpPasswd.m
new file mode 100644 (file)
index 0000000..8556808
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSHttpPasswd.h"
+#include "SoHTTPAuthenticator.h"
+#include "common.h"
+
+#if defined (__APPLE__) || defined(__FreeBSD__)
+#  include <unistd.h>
+#else
+#  if defined(__OpenBSD__)
+#    include <des.h>
+#  else
+#    include <crypt.h>
+#  endif
+#endif
+
+/*
+  Note: a user-folder is different to an authenticator (though a user
+  folder can be a authenticator itself) ! A user-folder manages the whole
+  user-database while an authenticator decodes HTTP authentication info,
+  checks a password against a user and retrieves only authentication related
+  information on a user.
+  
+  So: a user-folder is strongly related to an authenticator, but isn't
+  usually the actual authenticator object (which usually inherits from
+  SoHTTPAuthenticator).
+*/
+
+// TODO: implement ...
+
+@interface OFSHttpPasswdAuthenticator : SoHTTPAuthenticator
+{
+  OFSHttpPasswd *passwd; /* non-retained */
+}
+
+- (id)initWithObject:(id)_obj;
+- (void)detach;
+
+@end
+
+@implementation OFSHttpPasswd
+
+static BOOL    debugOn     = NO;
+static NSArray *plainRoles = nil;
+static NSArray *rootRoles  = nil;
+
++ (void)initialize {
+  if (plainRoles == nil) {
+    plainRoles = [[NSArray alloc] initWithObjects:
+                     SoRole_Authenticated, SoRole_Anonymous, nil];
+  }
+  if (rootRoles == nil) {
+    rootRoles = [[NSArray alloc] initWithObjects:
+                                  SoRole_Manager, SoRole_Authenticated, 
+                                  SoRole_Anonymous, nil];
+  }
+}
+
+- (void)dealloc {
+  [self->content release];
+  [self->authenticator detach];
+  [self->authenticator release];
+  [super dealloc];
+}
+
+- (id)authenticatorInContext:(id)_ctx {
+  if (self->authenticator == nil) {
+    self->authenticator = 
+      [[OFSHttpPasswdAuthenticator alloc] initWithObject:self];
+  }
+  return self->authenticator;
+}
+
+/* loading htpasswd */
+
+- (NSException *)primaryLoad {
+  NSMutableDictionary *md;
+  NSString *s;
+  NSArray  *lines;
+  unsigned i, count;
+
+  [self->content release]; self->content = nil;
+  
+  s = [self contentAsString];
+  lines = [s componentsSeparatedByString:@"\n"];
+  count = [lines count];
+  md = [NSMutableDictionary dictionaryWithCapacity:(count + 1)];
+  
+  for (i = 0; i < count; i++) {
+    NSString *s;
+    NSRange  r;
+    NSString *login, *pwd;
+    
+    s = [lines objectAtIndex:i];
+    r = [s rangeOfString:@":"];
+    if (r.length == 0) continue;
+    
+    login = [s substringToIndex:r.location];
+    pwd   = [s substringFromIndex:(r.location + r.length)];
+    
+    [md setObject:pwd forKey:login];
+  }
+  self->content = [md copy];
+  return nil;
+}
+
+- (NSString *)cryptedPasswordForLogin:(NSString *)_login {
+  NSException *error;
+  
+  if ([_login length] < 1)
+    return nil;
+  if (self->content)
+    return [self->content objectForKey:_login];
+  
+  if ((error = [self primaryLoad]))
+    return nil;
+  
+  return [self->content objectForKey:_login];
+}
+
+/* authenticator implementation */
+
+- (BOOL)checkLogin:(NSString *)_login password:(NSString *)_pwd {
+  NSString *cryptedPwd;
+  NSString *cpo;
+  const char *cp;
+  
+  if (debugOn)
+    [self debugWithFormat:@"check '%@' against pwd ...", _login];
+  
+  if ((cryptedPwd = [self cryptedPasswordForLogin:_login]) == nil) {
+    [self debugWithFormat:@"  user '%@' not available in htpasswd", _login];
+    return NO;
+  }
+  
+  if (debugOn)
+    [self debugWithFormat:@"  check crypted pwd of user '%@' ...", _login];
+  
+  // salt is user-pwd itself (crypt(pwd, cryptedpwd))
+  cp = crypt([_pwd cString], [cryptedPwd cString]);
+  cpo = cp ? [NSString stringWithCString:cp] : nil;
+  
+  return [cryptedPwd isEqualToString:cpo];
+}
+
+- (NSString *)authRealm {
+  return [(WOApplication *)[WOApplication application] name];
+}
+
+- (BOOL)isRootLogin:(NSString *)_login {
+  return [_login isEqualToString:@"root"];
+}
+- (NSArray *)rolesForLogin:(NSString *)_login {
+  return [self isRootLogin:_login] ? rootRoles : plainRoles;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* OFSHttpPasswd */
+
+@implementation OFSHttpPasswdAuthenticator
+
+- (id)initWithObject:(id)_obj {
+  NSAssert(_obj, @"missing htpasswd user folder in argument ...");
+  if ((self = [super init])) {
+    self->passwd = _obj;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithObject:nil];
+}
+
+- (void)detach {
+  self->passwd = nil;
+}
+
+/* implement using folder itself ... */
+
+- (BOOL)checkLogin:(NSString *)_login password:(NSString *)_pwd {
+  return [self->passwd checkLogin:_login password:_pwd];
+}
+
+- (NSString *)authRealm {
+  return [self->passwd authRealm];
+}
+
+- (NSArray *)rolesForLogin:(NSString *)_login {
+  return [self->passwd rolesForLogin:_login];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* OFSHttpPasswdAuthenticator */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSImage.h b/skyrix-sope/NGObjWeb/SoOFS/OFSImage.h
new file mode 100644 (file)
index 0000000..2f5750f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __OFS_OFSImage_H__
+#define __OFS_OFSImage_H__
+
+#include <SoOFS/OFSFile.h>
+
+/*
+  OFSImage
+
+  OFSImage is just like OFSFile. It will also be able to calculate image
+  dimension and has different management panels.
+*/
+
+@interface OFSImage : OFSFile
+{
+}
+
+@end
+
+#endif /* __OFS_OFSImage_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSImage.m b/skyrix-sope/NGObjWeb/SoOFS/OFSImage.m
new file mode 100644 (file)
index 0000000..e44fdc1
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSImage.h"
+#include "common.h"
+
+@implementation OFSImage
+
++ (int)version {
+  return [super version] + 0 /* v1 */;
+}
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    didInit = YES;
+    NSAssert2([super version] == 1,
+             @"invalid superclass (%@) version %i !",
+             NSStringFromClass([self superclass]), [super version]);
+  }
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* operations */
+
+- (NSString *)contentTypeInContext:(WOContext *)_ctx {
+  NSString *ext;
+  
+  ext = [[self storagePath] pathExtension];
+  if ([ext isEqualToString:@"gif"])  return @"image/gif";
+  if ([ext isEqualToString:@"jpg"])  return @"image/jpeg";
+  if ([ext isEqualToString:@"png"])  return @"image/png";
+  if ([ext isEqualToString:@"jpeg"]) return @"image/jpeg";
+  return @"image/octet-stream";
+}
+
+@end /* OFSImage */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSPropertyListObject.h b/skyrix-sope/NGObjWeb/SoOFS/OFSPropertyListObject.h
new file mode 100644 (file)
index 0000000..164964d
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __OFS_OFSPropertyListObject_H__
+#define __OFS_OFSPropertyListObject_H__
+
+#include <SoOFS/OFSFile.h>
+
+/*
+  OFSPropertyListObject
+  
+  The OFSPropertyListObject represents objects archived in a property list,
+  that is, it's a quick way to store objects structured in a simple way.
+  
+  Note that the property list is loaded on-demand (if a stored key is 
+  accessed).
+  
+  The class OFSPropertyListObject also acts as an object factory.
+*/
+
+@class NSArray, NSMutableDictionary;
+
+@interface OFSPropertyListObject : OFSFile
+{
+  NSMutableDictionary *record; /* loaded on-demand */
+  NSArray *recordKeys;
+  struct {
+    BOOL isLoading:1;
+    BOOL isLoaded:1;
+    BOOL isEdited:1;
+    BOOL isNew:1;
+    int  reserved:28;
+  } flags;
+}
+
+/* accessors */
+
+- (NSArray *)allKeys;
+
+/* storage */
+
+- (void)willChange;
+- (BOOL)isRestored;
+- (NSException *)restoreObject;
+- (NSException *)saveObject;
+
+@end
+
+#endif /* __OFS_OFSPropertyListObject_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSPropertyListObject.m b/skyrix-sope/NGObjWeb/SoOFS/OFSPropertyListObject.m
new file mode 100644 (file)
index 0000000..516a711
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSPropertyListObject.h"
+#include "OFSFactoryContext.h"
+#include "SoObject+SoDAV.h"
+#include "common.h"
+
+@interface OFSPropertyListObjectClassDescription : NSClassDescription
+{
+@public
+  OFSPropertyListObject *object;
+}
+
+@end
+
+@implementation OFSPropertyListObject
+
+static int debugOn = 0;
+
++ (int)version {
+  return [super version] + 0 /* v1 */;
+}
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    NSAssert2([super version] == 1,
+             @"invalid superclass (%@) version %i !",
+             NSStringFromClass([self superclass]), [super version]);
+    
+    debugOn = [ud boolForKey:@"SoOFSDebugPlistObject"] ? 1 : 0;
+  }
+}
+
+- (void)dealloc {
+  [self->recordKeys release];
+  [self->record     release];
+  [super dealloc];
+}
+
+/* storage */
+
+- (NSStringEncoding)stringEncoding {
+  return [NSString defaultCStringEncoding];
+}
+
+- (void)setSoResourceClassName:(NSString *)_name {} // ignore
+- (void)setSoClassName:(NSString *)_name         {} // ignore
+- (NSString *)soResourceClassName { // deprecated
+  return [[self soClass] className];
+}
+- (NSString *)soClassName {
+  return [[self soClass] className];
+}
+
+- (NSArray *)attributeKeys {
+  [[self restoreObject] raise];
+  return self->recordKeys;
+}
+
+- (NSArray *)allKeys {
+  return [self attributeKeys];
+}
+
+- (NSClassDescription *)soClassDescription {
+  OFSPropertyListObjectClassDescription *cd;
+  cd = [[OFSPropertyListObjectClassDescription alloc] init];
+  cd->object = [self retain];
+  return [cd autorelease];
+}
+
+- (NSString *)contentAsString {
+  /* do not allow access to raw contents ! */
+  return nil;
+}
+
+- (void)removeSpecialKeysFromRestoreDictionary:(NSMutableDictionary *)_md {
+  /* remove special storage keys like SoClassName to plist */
+  [_md removeObjectForKey:@"SoClassName"];
+  [_md removeObjectForKey:@"SoResourceClassName"];
+}
+- (void)addSpecialKeysToSaveDictionary:(NSMutableDictionary *)_md {
+  /* add special storage keys like SoClassName to plist */
+  [_md setObject:[self soClassName] forKey:@"SoClassName"];
+}
+
+- (NSException *)restoreObject {
+  NSMutableDictionary *plist = nil;
+  NSException *e;
+  NSData      *content;
+  NSString    *s;
+  id fm;
+  
+  if (self->flags.isLoaded) return nil;
+  if ((fm = [self fileManager]) == nil) {
+    e = [NSException exceptionWithHTTPStatus:500
+                     reason:@"plist object has no filemanager ??"];
+    return e;
+  }
+  s = [self storagePath];
+  if ([s length] == 0) {
+    e = [NSException exceptionWithHTTPStatus:500
+                     reason:@"plist object has no storage path ??"];
+    return e;
+  }
+  
+  self->flags.isLoading = 1;
+  self->flags.isLoaded  = 1;
+  e = nil;
+  
+  /* load file, convert into string, then into a property list */
+  
+  if ((content = [fm contentsAtPath:s])==nil) {
+    if (([fm respondsToSelector:@selector(lastException)])) {
+      e = [fm lastException];
+      goto done;
+    }
+    else {
+      e = [NSException exceptionWithHTTPStatus:404 /* not found */
+                      reason:@"failed to load property list file ..."];
+      goto done;
+    }
+  }
+  s = [[NSString alloc] initWithData:content encoding:[self stringEncoding]];
+  if (s == nil) {
+    e = [NSException exceptionWithHTTPStatus:500
+                    reason:@"failed to create string from file ..."];
+    goto done;
+  }
+  plist = [[s propertyList] mutableCopy];
+  [s release];
+  if (plist == nil) {
+    e = [NSException exceptionWithHTTPStatus:500
+                    reason:@"failed to create property list from file ..."];
+    goto done;
+  }
+  
+  [self removeSpecialKeysFromRestoreDictionary:plist];
+  
+  self->recordKeys = [[plist allKeys] copy];
+  if (debugOn)
+    [self debugWithFormat:@"taking values of: %@", plist];
+  [self takeValuesFromDictionary:plist];
+  [plist release];
+  
+ done:
+  self->flags.isEdited  = 0;
+  self->flags.isLoading = 0;
+  return e;
+}
+
+- (void)willChange {
+  if (!self->flags.isLoading)
+    self->flags.isEdited = 1;
+}
+- (BOOL)isRestored {
+  return self->flags.isLoaded ? YES : NO;
+}
+
+- (NSException *)saveObject {
+  NSMutableDictionary *d;
+  NSException  *e;
+  NSString     *s;
+  NSData       *content;
+  id           fm;
+  
+  e = (self->flags.isNew)
+    ? [self validateForInsert]
+    : [self validateForSave];
+  if (e) return e;
+  
+  if (!self->flags.isNew) {
+    if ((e = [self restoreObject]))
+      return e;
+  }
+  
+  d = (self->recordKeys)
+    ? [[self valuesForKeys:self->recordKeys] mutableCopy]
+    : [self->record mutableCopy];
+  
+  if (d == nil) {
+    [self logWithFormat:@"got no dict to save ..."];
+    return [NSException exceptionWithHTTPStatus:500
+                       reason:@"got no record to save ..."];
+  }
+  
+  [self addSpecialKeysToSaveDictionary:d];
+  
+  s = [d description];
+  [d release];
+  
+  content = [s dataUsingEncoding:[self stringEncoding]];
+  
+  fm = [self fileManager];
+  
+  if (![fm writeContents:content atPath:[self storagePath]]) {
+    [self logWithFormat:@"failed to update file: %@", [self storagePath]];
+    
+    if (([fm respondsToSelector:@selector(lastException)]))
+      return [fm lastException];
+    else {
+      return [NSException exceptionWithHTTPStatus:500
+                         reason:@"failed to update property list file ..."];
+    }
+  }
+  
+  self->flags.isNew = 0;
+  return nil;
+}
+
+/* KVC */
+
+- (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
+  id oldValue;
+  
+  if ((oldValue = [self->record objectForKey:_key]) == nil) {
+    if (_value == nil) return;
+  }
+  else if (![_value isNotNull]) {
+    [self willChange];
+    [self->record removeObjectForKey:_key];
+    return;
+  }
+  else if (oldValue == _value) {
+    return;
+  }
+  else if ([oldValue isEqual:_value])
+    return;
+  
+  [self willChange];
+  
+  if (self->record == nil)
+    self->record = [[NSMutableDictionary alloc] initWithCapacity:16];
+  
+  if (!self->flags.isLoading && debugOn)
+    [self debugWithFormat:@"set unbound key: %@", _key];
+  
+  if (![self->recordKeys containsObject:_key]) {
+    NSMutableArray *rk;
+    
+    rk = [self->recordKeys mutableCopy];
+    [rk addObject:_key];
+    [self->recordKeys release];
+    self->recordKeys = rk;
+  }
+  
+  [self->record setObject:_value?_value:@"" forKey:_key];
+}
+
+- (BOOL)isStoredKey:(NSString *)_key {
+  /* says whether we need to restore the object to access the key */
+  if ([_key hasPrefix:@"NS"]) {
+    if ([_key isEqualToString:@"NSFileSubject"])
+      return YES;
+    return NO;
+  }
+  return YES;
+}
+
+- (void)takeValue:(id)_value forKey:(NSString *)_name {
+  if (!self->flags.isLoaded && !self->flags.isLoading) {
+    if ([self isStoredKey:_name])
+      [[self restoreObject] raise];
+  }
+  
+  [super takeValue:_value forKey:_name];
+}
+
+- (id)valueForKey:(NSString *)_name {
+  id v = nil;
+  
+  if ([_name hasPrefix:@"NS"]) {
+    if ([_name isEqualToString:@"NSFileSize"])
+      v = [self davContentLength];
+    else if ([_name isEqualToString:@"NSFileSubject"])
+      v = [self davDisplayName];
+    else
+      /* this implies that stored keys never begin with NS ! (good ?) */
+      v = [super valueForKey:_name];
+  }
+  else if ([self isStoredKey:_name]) {
+    if ((v = [self restoreObject]))
+      /* v is the restoration exception, do not want to raise */;
+    else if ((v = [self->record objectForKey:_name]))
+      /* a record value */;
+    else
+      /* stored-key doesn't say *where* it is stored ! */
+      v = [super valueForKey:_name];
+  }
+  else
+    v = [super valueForKey:_name];
+  
+  return v;
+}
+
+/* operations */
+
+- (id)GETAction:(WOContext *)_ctx {
+  NSException *e;
+  
+  if ((e = [self restoreObject]))
+    return e;
+  
+  /* let the renderer deal with our representation ... */
+  return self;
+}
+
+- (id)PUTAction:(id)_ctx {
+  return [NSException exceptionWithHTTPStatus:405 /* method not allowed */
+                     reason:@"HTTP PUT not yet allowed on plist objects"];
+}
+
+/* WebDAV support */
+
+- (NSString *)davDisplayName {
+  return [[self nameInContainer] stringByDeletingPathExtension];
+}
+- (id)davContentLength {
+  static NSNumber *zero = nil;
+  if (zero == nil) zero = [[NSNumber numberWithInt:0] retain];
+  return zero;
+}
+
+- (NSException *)davSetProperties:(NSDictionary *)_setProps
+  removePropertiesNamed:(NSArray *)_delProps 
+  inContext:(id)_ctx
+{
+  NSException *e;
+  
+  if (debugOn)
+    [self debugWithFormat:@"patch: %@, del: %@", _setProps, _delProps];
+  
+  if ((e = [self restoreObject]))
+    return e;
+  
+  if ([_setProps count] > 0)
+    [self takeValuesFromDictionary:_setProps];
+  
+  if ([_delProps count] > 0) {
+    NSMutableArray *rk;
+    
+    [self->record removeObjectsForKeys:_delProps];
+    rk = [self->recordKeys mutableCopy];
+    [rk removeObjectsInArray:_delProps];
+    [self->recordKeys release];
+    self->recordKeys = rk;
+  }
+  
+  if ((e = [self saveObject])) {
+    [self logWithFormat:@"update failed ..."];
+    return e;
+  }
+  
+  return nil;
+}
+
+/* factory */
+
++ (id)instantiateInFactoryContext:(OFSFactoryContext *)_ctx {
+  /* look into plist for class */
+  NSException  *e;
+  OFSPropertyListObject *object;
+  SoClass      *clazz;
+  
+  if ([_ctx isNewObject]) {
+    /* create a new object in the storage */
+    clazz = [self soClass];
+    
+    /* instantiate */
+    if (debugOn) {
+      [self debugWithFormat:@"instantiate child %@ from class %@",
+           [_ctx nameInContainer], clazz];
+    }
+    
+    object = [clazz instantiateObject];
+    [object takeStorageInfoFromContext:_ctx];
+    
+    if ([object isKindOfClass:[OFSPropertyListObject class]])
+      object->flags.isNew = 1;
+
+    if ((e = [object saveObject])) {
+      [self debugWithFormat:@"  save failed: %@", e];
+      return e;
+    }
+  }
+  else {
+    /* restore object from storage */
+    NSDictionary *plist;
+    NSData       *content;
+    NSString     *string;
+    NSString     *className;
+    
+    content = [[_ctx fileManager] contentsAtPath:[_ctx storagePath]];
+    if (content == nil)
+      /* hm, file doesn't exist ? */
+      return [super instantiateInFactoryContext:_ctx];
+    
+    /* parse the existing plist file */
+    
+    string = [[NSString alloc] initWithData:content
+                            encoding:[NSString defaultCStringEncoding]];
+    if (string == nil) {
+      [self logWithFormat:@"could not make string for stored data."];
+      return [NSException exceptionWithHTTPStatus:500
+                       reason:@"stored property list is corrupted"];
+    }
+    
+    if ((plist = [string propertyList]) == nil) {
+      [string release];
+      [self logWithFormat:@"could not make plist for stored data."];
+      return [NSException exceptionWithHTTPStatus:500
+                       reason:
+                         @"stored property list is corrupted "
+                         @"(not in plist format)"];
+    }
+    [string release];
+  
+    /* lookup the classname in plist */
+    
+    className = [plist objectForKey:@"SoClassName"];
+    if ([className length] == 0)
+      /* no special class assigned, use default */
+      clazz = [self soClass];
+    else {
+      clazz = [[SoClassRegistry sharedClassRegistry] soClassWithName:className];
+      if (clazz == nil) {
+        [self logWithFormat:@"did not find SoClass: %@", className];
+        return nil;
+      }
+    }
+    
+    /* instantiate */
+    
+    if (debugOn) {
+      [self debugWithFormat:@"instantiate child %@ from class %@",
+           [_ctx nameInContainer], clazz];
+    }
+    
+    object = [clazz instantiateObject];
+    [object takeStorageInfoFromContext:_ctx];
+    
+    /* restore */
+    
+    if (debugOn) {
+      [self debugWithFormat:@"restore child %@: %@",
+           [_ctx nameInContainer], object];
+    }
+    
+    if ((e = [object restoreObject])) {
+      [self debugWithFormat:@"  restore failed: %@", e];
+      return e;
+    }
+  }  
+  return object;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn ? YES : NO;
+}
+
+@end /* OFSPropertyListObject */
+
+@implementation OFSPropertyListObjectClassDescription
+
+- (void)dealloc {
+  [self->object release];
+  [super dealloc];
+}
+
+- (NSArray *)attributeKeys {
+  return [self->object attributeKeys];
+}
+
+@end /* OFSPropertyListObjectClassDescription */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSResourceManager.h b/skyrix-sope/NGObjWeb/SoOFS/OFSResourceManager.h
new file mode 100644 (file)
index 0000000..989f09c
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoOFS_OFSResourceManager_H__
+#define __SoOFS_OFSResourceManager_H__
+
+#include <NGObjWeb/WOResourceManager.h>
+
+/*
+  OFSResourceManager
+  
+  OFSResourceManager is an NGObjWeb resource manager which locates resources
+  by traversing the OFS hierarchy.
+*/
+
+@interface OFSResourceManager : WOResourceManager
+{
+  id baseObject; /* non-retained ! */
+  id context;    /* non-retained ! */
+}
+
+- (id)initWithBaseObject:(id)_object inContext:(id)_ctx;
+
+/* lookup */
+
+- (NSString *)pathForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages;
+
+- (NSString *)urlForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages
+  request:(WORequest *)_request;
+
+/* operations */
+
+- (void)invalidate;
+
+@end
+
+#endif /* __SoOFS_OFSResourceManager_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSResourceManager.m b/skyrix-sope/NGObjWeb/SoOFS/OFSResourceManager.m
new file mode 100644 (file)
index 0000000..279b30e
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSResourceManager.h"
+#include "OFSBaseObject.h"
+#include "WOComponentDefinition.h"
+#include "common.h"
+
+@interface WOResourceManager(UsedPrivates)
+- (WOComponentDefinition *)definitionForComponent:(id)_name
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_languages;
+@end
+
+@interface WOComponentDefinition(UsedPrivates)
+- (void)setComponentClass:(Class)_clazz;
+@end
+
+@implementation OFSResourceManager
+
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  debugOn = [ud boolForKey:@"SoOFSResourceManagerDebugEnabled"];
+}
+
+- (id)initWithBaseObject:(id)_object inContext:(id)_ctx {
+  if ((self = [super init])) {
+    self->baseObject = _object;
+    self->context    = _ctx;
+    
+    if (self->baseObject == nil) {
+      [self release];
+      return nil;
+    }
+    
+    if (self->context == nil)
+      [self debugWithFormat:@"WARNING: got not context !"];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+- (void)invalidate {
+  self->baseObject = nil;
+  self->context    = nil;
+}
+
+/* accessors */
+
+- (id)context {
+  if (self->context == nil)
+    return [[WOApplication application] context];
+  return self->context;
+}
+
+/* base object lookup */
+
+- (BOOL)doesAcquireResources {
+  return YES;
+}
+
+- (id)soObjectForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages
+{
+  id resourceObject;
+  
+  if (debugOn) {
+    [self debugWithFormat:@"lookup resource object named '%@' in %@",
+            _name, self->baseObject];
+  }
+  
+  if ([self doesAcquireResources]) {
+    NSException *error = nil;
+    id subctx;
+    
+    /* 
+       Note: this will first look into the object traversal stack of the
+             context which might be different to the base object!
+            e.g. its common to use the resource manager on the container
+            of the clientObject (baseObject==container) instead of the
+            object itself.
+    */
+    subctx = [[self context] createSubContext];
+    resourceObject = [self->baseObject 
+                          traverseKey:_name
+                          inContext:subctx
+                          error:&error
+                          acquire:YES];
+    if (error) {
+      if (debugOn) {
+       [self debugWithFormat:@"  name: %@", _name];
+       [self debugWithFormat:@"  base: %@", self->baseObject];
+       [self debugWithFormat:@"  ctx:  %@", subctx];
+      }
+      [self logWithFormat:@"ERROR: %@", error];
+    }
+  }
+  else {
+    resourceObject = [self->baseObject lookupName:_name 
+                                       inContext:[self context]
+                                       acquire:YES];
+  }
+  
+  if (debugOn)
+    [self debugWithFormat:@"  found: %@", resourceObject];
+  return resourceObject;
+}
+
+/* components */
+
+- (WOComponentDefinition *)definitionForComponent:(id)_name
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_languages
+{
+  WOComponentDefinition *cdef;
+  
+  cdef = [super definitionForComponent:_name
+               inFramework:_framework
+               languages:_languages];
+  [cdef setComponentClass:NSClassFromString(@"WOComponent")];
+  return cdef;
+}
+
+/* resource manager methods */
+
+- (NSString *)forcedComponentExtension {
+  /* the content negotiation should select an extension for us ! */
+  return nil;
+}
+
+- (NSString *)resourceNameForComponentNamed:(NSString *)_name {
+  NSString *ext;
+  
+  if ((ext = [self forcedComponentExtension])) {
+    if ([[_name pathExtension] length] == 0)
+      _name = [_name stringByAppendingPathExtension:ext];
+  }
+  return _name;
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_fw
+  languages:(NSArray *)_langs
+{
+  // TODO: add a cache
+  id obj;
+  
+  obj = [self soObjectForResourceNamed:_name inFramework:_fw languages:_langs];
+  if (obj == nil)
+    [self debugWithFormat:@"found no resource object named '%@'", _name];
+  else
+    [self debugWithFormat:@"found resource object '%@': %@", _name, obj];
+  
+  return [obj storagePath];
+}
+
+- (NSString *)urlForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_fw
+  languages:(NSArray *)_langs
+  request:(WORequest *)_request
+{
+  // TODO: add a cache
+  id obj;
+  
+  obj = [self soObjectForResourceNamed:_name inFramework:_fw languages:_langs];
+  if (obj == nil)
+    [self logWithFormat:@"found no object named '%@'", _name];
+  
+  return [obj baseURLInContext:[self context]];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->baseObject) 
+    [ms appendFormat:@" base=%@", self->baseObject];
+  if (self->context) 
+    [ms appendFormat:@" ctx=0x%08X", self->context];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* OFSResourceManager */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSWebDocument.h b/skyrix-sope/NGObjWeb/SoOFS/OFSWebDocument.h
new file mode 100644 (file)
index 0000000..28317ba
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoOFS_OFSWebDocument_H__
+#define __SoOFS_OFSWebDocument_H__
+
+#include <SoOFS/OFSWebMethod.h>
+
+/*
+  OFSWebDocument
+
+  A web-document is basically the same thing like a web method - the only 
+  difference is the assignment of the "clientObject" in the context. A method
+  always applies on the object prior in it's traversal path while a document
+  applies to itself.
+*/
+
+@interface OFSWebDocument : OFSWebMethod
+{
+}
+
+@end
+
+#endif /* __SoOFS_OFSWebDocument_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSWebDocument.m b/skyrix-sope/NGObjWeb/SoOFS/OFSWebDocument.m
new file mode 100644 (file)
index 0000000..cb7eff2
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSWebDocument.h"
+#include "common.h"
+
+@implementation OFSWebDocument
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* calling (being a document ...) */
+
+- (BOOL)isCallable {
+  return NO;
+}
+
+- (id)callOnObject:(id)_client inContext:(id)_ctx {
+  if (_client == nil || _client == self)
+    return self;
+  
+  [self logWithFormat:@"attempt to use OFSWebDocument as a method ?"];
+  return [self viewAction:_ctx];
+}
+
+- (id)clientObject {
+  return self;
+}
+
+@end /* OFSWebDocument */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSWebMethod.h b/skyrix-sope/NGObjWeb/SoOFS/OFSWebMethod.h
new file mode 100644 (file)
index 0000000..8fff587
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __OFS_OFSWebMethod_H__
+#define __OFS_OFSWebMethod_H__
+
+#include <SoOFS/OFSFile.h>
+
+/*
+  OFSWebMethod
+
+  OFSWebMethod is for storing and activating NGObjWeb based components
+  from OFS.
+*/
+
+@class NSException;
+@class WOComponent, WOResourceManager, WOContext;
+
+@interface OFSWebMethod : OFSFile
+{
+  WOComponent *component;
+}
+
+/* page */
+
+- (WOComponent *)component;
+
+/* actions */
+
+- (id)GETAction:(WOContext *)_ctx;
+- (id)viewAction:(WOContext *)_ctx;
+
+@end
+
+@interface NSObject(OFSWebMethodClassify)
+- (BOOL)isOFSWebMethod;
+@end
+
+#endif /* __OFS_OFSWebMethod_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSWebMethod.m b/skyrix-sope/NGObjWeb/SoOFS/OFSWebMethod.m
new file mode 100644 (file)
index 0000000..75a84b6
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSWebMethod.h"
+#include "WOContext+private.h" // required for page rendering
+#include <NGObjWeb/WEClientCapabilities.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@interface WOComponent(RM)
+- (void)setResourceManager:(WOResourceManager *)_rm;
+@end
+
+@implementation OFSWebMethod
+
+static BOOL debugOn = NO;
+
++ (int)version {
+  return [super version] + 0 /* v1 */;
+}
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    didInit = YES;
+    NSAssert2([super version] == 1,
+             @"invalid superclass (%@) version %i !",
+             NSStringFromClass([self superclass]), [super version]);
+    
+    debugOn = [[NSUserDefaults standardUserDefaults] 
+                              boolForKey:@"SoOFSWebMethodDebugEnabled"];
+  }
+}
+
+- (void)dealloc {
+  [self->component release];
+  [super dealloc];
+}
+
+/* page */
+
+- (WOResourceManager *)resourceManagerInContext:(id)_ctx {
+  return [[self container] resourceManagerInContext:_ctx];
+}
+
+- (WOComponent *)componentInContext:(WOContext *)_ctx {
+  WOResourceManager *rm;
+  WOComponent *lPage;
+  NSArray     *languages;
+  
+  if (self->component)
+    return self->component;
+  
+  [self debugWithFormat:@"should load component: %@", [self storagePath]];
+  if ((rm = [self resourceManagerInContext:_ctx]) == nil) {
+    [self logWithFormat:@"got no resource manager ..."];
+    return nil;
+  }
+    
+  /* determine language */
+    
+  languages = [_ctx hasSession]
+    ? [(WOSession *)[_ctx session] languages]
+    : [[_ctx request] browserLanguages];
+    
+  /* instantiate */
+    
+  lPage = [rm pageWithName:[self nameInContainer] languages:languages];
+  [lPage ensureAwakeInContext:_ctx];
+  [lPage setResourceManager:rm];
+  
+  [self debugWithFormat:@"   page: %@", lPage];
+  
+  self->component = [lPage retain];
+  return self->component;
+}
+- (WOComponent *)component {
+  return [self componentInContext:[[WOApplication application] context]];
+}
+
+/* actions */
+
+- (id)rendererForObject:(id)_object inContext:(WOContext *)_ctx {
+  // TODO: should return the component ?
+  // TODO: add OFSWebMethodRenderer which selects on DAV ?
+  return nil;
+}
+
+- (id)getUnparsedContentInContext:(WOContext *)_ctx {
+  /* this method should not be publically available ! */
+  // TODO: check permission for source-view !
+  return [super GETAction:_ctx];
+}
+
+- (BOOL)useRendererForComponentCreation {
+  /* will GET/view return the component as a result or self ? */
+  return NO;
+}
+
+- (id)viewAction:(WOContext *)_ctx {
+  /* 
+     The difference to get is, that view always renders the content, so
+     you can get a rendered representation even with a WebDAV client.
+  */
+  
+  /* the default renderer will recognize that as a component ... */
+  return [self useRendererForComponentCreation]
+    ? self 
+    : (id)[self componentInContext:_ctx];
+}
+
+- (id)GETAction:(WOContext *)_ctx {
+  WORequest *rq;
+  NSString  *translate;
+  
+  rq = [_ctx request];
+  translate = [[rq headerForKey:@"translate"] lowercaseString];
+  
+  if ([translate hasPrefix:@"f"]) {
+    /* return the unparsed body */
+    if (debugOn)
+      [self debugWithFormat:@"returning unparsed content (translate f)"];
+    return [self getUnparsedContentInContext:_ctx];
+  }
+  
+  if ([[rq clientCapabilities] isDAVClient]) {
+    /* return the unparsed body */
+    if (debugOn)
+      [self debugWithFormat:@"returning unparsed content (DAV-client)"];
+    return [self getUnparsedContentInContext:_ctx];
+  }
+  
+  /* the default renderer will recognize that as a component ... */
+  if (debugOn) [self debugWithFormat:@"return component object for GET ..."];
+  return [self viewAction:_ctx];
+}
+- (id)POSTAction:(WOContext *)_ctx {
+  WOComponent *comp;
+  
+  if (debugOn) [self debugWithFormat:@"process POST using component ..."];
+  
+  if ((comp = [self componentInContext:_ctx]) == nil)
+    return nil;
+  
+  // TODO: should we invoke some action ?
+  // TODO: maybe the renderer should do the takeValues/invoke/... ??
+  [comp takeValuesFromRequest:[_ctx request] inContext:_ctx];
+  return comp;
+}
+
+- (BOOL)isOFSWebMethod {
+  return YES;
+}
+
+/* calling (being a method ...) */
+
+- (BOOL)isCallable {
+  return YES;
+}
+
+- (id)callOnObject:(id)_client inContext:(id)_ctx {
+  WOComponent *c;
+  
+  if ((c = [self componentInContext:_ctx]) == nil)
+    return nil;
+  
+  [c setClientObject:_client];
+  return c;
+}
+
+- (id)clientObject {
+  return [[[WOApplication application] context] clientObject];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* OFSWebMethod */
+
+@implementation NSObject(OFSWebMethodClassify)
+
+- (BOOL)isOFSWebMethod {
+  return NO;
+}
+
+@end /* NSObject(OFSWebMethodClassify) */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSWebMethodRenderer.h b/skyrix-sope/NGObjWeb/SoOFS/OFSWebMethodRenderer.h
new file mode 100644 (file)
index 0000000..c57bf84
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoOFS_OFSWebMethodRenderer_H__
+#define __SoOFS_OFSWebMethodRenderer_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  OFSWebMethodRenderer
+
+  Renders OFSWebMethod objects by getting it's WOComponent and render that.
+*/
+
+@class NSException;
+@class WOContext;
+
+@interface OFSWebMethodRenderer : NSObject
+{
+}
+
++ (id)sharedRenderer;
+
+- (NSException *)renderObject:(id)_object inContext:(WOContext *)_ctx;
+- (BOOL)canRenderObject:(id)_object inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __SoOFS_OFSWebMethodRenderer_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSWebMethodRenderer.m b/skyrix-sope/NGObjWeb/SoOFS/OFSWebMethodRenderer.m
new file mode 100644 (file)
index 0000000..6c5dc77
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSWebMethodRenderer.h"
+#include "OFSWebMethod.h"
+#include "WOContext+private.h" // required for page rendering
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@interface OFSWebMethod(Privates)
+- (WOComponent *)componentInContext:(WOContext *)_ctx;
+@end
+
+@implementation OFSWebMethodRenderer
+
++ (id)sharedRenderer {
+  static OFSWebMethodRenderer *singleton = nil;
+  if (singleton == nil)
+    singleton = [[OFSWebMethodRenderer alloc] init];
+  return singleton;
+}
+
+/* rendering */
+
+- (NSException *)renderComponent:(WOComponent *)_c inContext:(WOContext *)_ctx{
+  WOResponse *r = [_ctx response];
+  
+  [r setHeader:@"text/html" forKey:@"content-type"];
+  [_ctx setPage:_c];
+  [_ctx enterComponent:_c content:nil];
+  [_c appendToResponse:r inContext:_ctx];
+  [_ctx leaveComponent:_c];
+  return nil;
+}
+
+- (NSException *)renderObject:(id)_object inContext:(WOContext *)_ctx {
+  WOComponent *component;
+  
+  if (![_object isOFSWebMethod])
+    return [NSException exceptionWithHTTPStatus:500 /* server error */];
+  
+  if ((component = [_object componentInContext:_ctx]) == nil)
+    return [NSException exceptionWithHTTPStatus:500 /* server error */];
+  
+  return [self renderComponent:component inContext:_ctx];
+}
+
+- (BOOL)canRenderObject:(id)_object inContext:(WOContext *)_ctx {
+  return [_object isOFSWebMethod];
+}
+
+/* debugging */
+
+- (NSString *)loggingPrefix {
+  return @"[so-component-renderer]";
+}
+
+@end /* OFSWebMethodRenderer */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSWebTemplate.h b/skyrix-sope/NGObjWeb/SoOFS/OFSWebTemplate.h
new file mode 100644 (file)
index 0000000..4932330
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoOFS_OFSWebTemplate_H__
+#define __SoOFS_OFSWebTemplate_H__
+
+#include <SoOFS/OFSWebMethod.h>
+
+/*
+  OFSWebTemplate
+
+  A specialized SoClass for handling SOPE templates. The major difference
+  is, that templates cannot be access through the web !
+  
+  [TODO: implement the web-limit, templates should not be callable !]
+*/
+
+@interface OFSWebTemplate : OFSWebMethod
+{
+}
+
+@end
+
+#endif /* __SoOFS_OFSWebTemplate_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/OFSWebTemplate.m b/skyrix-sope/NGObjWeb/SoOFS/OFSWebTemplate.m
new file mode 100644 (file)
index 0000000..e2617d2
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "OFSWebTemplate.h"
+#include "common.h"
+
+@implementation OFSWebTemplate
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+@end /* OFSWebTemplate */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/README b/skyrix-sope/NGObjWeb/SoOFS/README
new file mode 100644 (file)
index 0000000..35f9ecb
--- /dev/null
@@ -0,0 +1,27 @@
+# $Id$
+
+The SOPE Object File System (OFS)
+=================================
+
+First note that SOPE OFS is different from Zope OFS. Zope OFS is basically a
+filesystem view on the ZODB Python object database while SOPE OFS is SoObject
+support for filesystem based entities (so basically the reverse, Zope OFS
+provides a FS view on objects, SOPE OFS provides an object view on FS objects)
+
+Note that you can use any filemanager class as a storage for SOPE objects, not
+only NSFileManager, eg NGImap4FileManager or NGLdapFileManager. On the other
+side you are not required to use OFS for storing SOPE objects.
+
+OFS itself does no caching and conflict detection beyond the life of the 
+context, this is the task of either an own OFS subclass or of the filemanager
+depending on the requirements.
+
+Class Hierarchy:
+  OFSBaseObject                    (keeps name, container, fm and storage path)
+    OFSFile                (has a BLOB and attributes)
+      OFSImage             (different class since different methods are bound)
+      OFSPropertyListObject (objects stored as a plist)
+      OFSWebMethod         (handles component templates inside OFS)
+    OFSFolder              (collections of OFSFile's and OFSFolder's)
+  OFSFactoryContext        (keeps instantiation state)
+  OFSFactoryRegistry       (select a factory object)
diff --git a/skyrix-sope/NGObjWeb/SoOFS/SoOFS-Info.plist b/skyrix-sope/NGObjWeb/SoOFS/SoOFS-Info.plist
new file mode 100644 (file)
index 0000000..0b78ca2
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SoOFS</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.NGObjWeb.SoOFS</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/NGObjWeb/SoOFS/SoOFS-SXP-Info.plist b/skyrix-sope/NGObjWeb/SoOFS/SoOFS-SXP-Info.plist
new file mode 100644 (file)
index 0000000..9cc848c
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SoOFS</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>org.OpenGroupware.SOPE.SoOFS</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>BNDL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+       <key>NSPrincipalClass</key>
+       <string>SoOFSProduct</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/NGObjWeb/SoOFS/SoOFS.h b/skyrix-sope/NGObjWeb/SoOFS/SoOFS.h
new file mode 100644 (file)
index 0000000..b9d7e19
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_SoOFS_H__
+#define __NGObjWeb_SoOFS_H__
+
+#include <SoOFS/OFSBaseObject.h>
+#include <SoOFS/OFSFactoryContext.h>
+#include <SoOFS/OFSFactoryRegistry.h>
+#include <SoOFS/OFSFile.h>
+#include <SoOFS/OFSFolder.h>
+#include <SoOFS/OFSImage.h>
+#include <SoOFS/OFSPropertyListObject.h>
+
+#endif /* __NGObjWeb_SoOFS_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoOFS/TODO b/skyrix-sope/NGObjWeb/SoOFS/TODO
new file mode 100644 (file)
index 0000000..364f943
--- /dev/null
@@ -0,0 +1,50 @@
+# $Id: TODO,v 1.1.1.1 2003/07/09 22:57:27 cvs Exp $
+
+Todo's for SOPE OFS
+
+- distinguish between WebMethods and WebDocuments !!! WebMethods operate
+  on the 'clientObject' while WebDocuments operate on themselves (eg
+  /a/b.wox - if b.wox is a method, the clientObject is 'a')
+
+- currently OFSImage/OFSFile "GET" returns a WOResponse, it should return 
+  itself and the SOPE rendering step should morph the OFSImage into a 
+  WOResponse, this way we are much more flexible in handling (eg a renderer
+  could convert or compress an image on the fly)
+  [DONE?]
+
+- autodetect "special" versioned folders based on ".svn" and "CVS", this
+  should be supported in the core to trigger categories based on that ?
+  [DONE?]
+
+- add some caching logic, eg a "cached" filemanager which wraps an 
+  NGFileManager (remember, SOPE objects itself should be controller !)
+
+- OFSImage/OFSFile (or their renderer) should properly deliver the last
+  modified and etag HTTP headers
+
+- add MIME-type mapping to OFSFile/OFSImage using /etc/mime.types
+
+- store permissions of objects in folders (special file ?)
+  - acquire object permissions from parent folders ?
+
+- a "property storage" object for abstracting where OFS properties are
+  stored:
+  - in a plist file
+  - in Subversion
+  - in ...
+  The property storage should not be fixed on the OFS SoClass !
+
+- add support for Zope Page Template syntax (create a WOxElementBuilder for
+  the tal: namespace)
+
+- add a dynamic element for "rendering" HTTP headers, eg:
+  <http:header name="content-type" value="text/xml+svg" />
+
+- add an XSLT method using libxml2
+
+- add a PHP OFS method
+  - how to apply templates ? 
+  - internal redirect ?
+
+- add support for "source.html", like in Zope
+  - edit raw source of a document
diff --git a/skyrix-sope/NGObjWeb/SoOFS/common.h b/skyrix-sope/NGObjWeb/SoOFS/common.h
new file mode 100644 (file)
index 0000000..854a633
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+
+#if LIB_FOUNDATION_LIBRARY
+#  import <Foundation/exceptions/GeneralExceptions.h>
+#elif NeXT_Foundation_LIBRARY || APPLE_FOUNDATION_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#  include <NGExtensions/NSString+Ext.h>
+#endif
+
+#include <NGExtensions/NGExtensions.h>
+
+#include "NSException+HTTP.h"
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGExtensions/NGFileManager.h>
+
+#include "SoClass.h"
+#include "SoClassRegistry.h"
+#include "SoClassSecurityInfo.h"
+#include "SoDefaultRenderer.h"
+#include "SoObject.h"
+#include "SoObjectMethodDispatcher.h"
+#include "SoObjectRequestHandler.h"
+#include "SoPermissions.h"
+#include "SoSecurityManager.h"
+#include "SoUser.h"
+#include "WOContext+SoObjects.h"
+#include "NSException+HTTP.h"
+
+@interface NSObject(LastException)
+- (NSException *)lastException;
+@end
diff --git a/skyrix-sope/NGObjWeb/SoOFS/product.plist b/skyrix-sope/NGObjWeb/SoOFS/product.plist
new file mode 100644 (file)
index 0000000..67d5b2f
--- /dev/null
@@ -0,0 +1,112 @@
+{
+  CVSID = "$Id: product.plist,v 1.2 2003/10/10 23:15:35 helge Exp $";
+  
+  requires = ( SoCore );
+  
+  classes = {
+
+    OFSBaseObject = {
+      protectedBy = "<public>";
+
+      methods = {
+       DELETE = { protectedBy = "Delete Objects"; };
+      };
+    };
+    
+    OFSFile = {
+      protectedBy = "<public>";
+
+      methods = {
+        GET = {
+         protectedBy = "View"; 
+        };
+        view = {
+         protectedBy = "View"; 
+        };
+       DELETE = { 
+         protectedBy = "Delete Objects"; 
+       };
+        PUT = {
+         protectedBy = "Change Images and Files"; 
+        };
+      };
+      
+      defaultRoles = {
+        "WebDAV Access"           = "Authenticated";
+        "Change Images and Files" = "Owner";
+        "Delete Objects"          = "Owner";
+        "View"                    = "Owner";
+        "WebDAV Lock Items"       = "Authenticated";
+        "WebDAV Unlock Items"     = "Authenticated";
+      };
+    };
+    
+    OFSPropertyListObject = {
+      protectedBy = "<public>";
+      defaultAccess = "allow";
+      extension   = plist;
+    };
+    
+    OFSImage = {
+      protectedBy = "<public>";
+      defaultAccess = "allow";
+      extensions  = ( gif, jpg, jpeg, png, ico );
+    };
+    
+    OFSFolder = {
+      protectedBy   = "<public>";
+      defaultAccess = "allow";
+      
+      methods = {
+        GET = {
+          protectedBy = "View";
+        };
+        PUT = {
+         protectedBy = "Change Images and Files";
+        };
+        DELETE = {
+         protectedBy = "Delete Objects";
+        };
+        MKCOL = {
+         protectedBy = "Add Folders";
+        };
+      };
+      
+      defaultRoles = {
+        "WebDAV Access"                   = "Authenticated";
+        "Change Images and Files"         = "Owner";
+        "Delete Objects"                  = "Owner";
+        "View"                            = "Owner";
+       "Add Documents, Images and Files" = "Owner";
+       "Add Folders"                     = "Owner";
+      };
+    };
+    
+    OFSWebMethod = {
+      protectedBy   = "<public>";
+      defaultAccess = "allow";
+      extensions    = ( wox );
+    };
+    OFSWebDocument = {
+      protectedBy   = "<public>";
+      defaultAccess = "allow";
+      extensions    = ( xhtml );
+    };
+    OFSWebTemplate = {
+      protectedBy   = "<public>";
+      defaultAccess = "allow";
+      extensions    = ( xtmpl );
+    };
+    
+    OFSHttpPasswd = {
+      protectedBy    = "<private>";
+      defaultAccess  = "deny";
+      extensions     = ( htpasswd ); // either blah.htpasswd
+      exactFilenames = ( htpasswd ); // or just "htpasswd"
+    };
+    OFSChangeLog = {
+      extensions     = ( changelog ); // either blah.changelog
+      exactFilenames = ( ChangeLog ); // or just "ChangeLog"
+    };
+  };
+}
diff --git a/skyrix-sope/NGObjWeb/SoOFSProduct.m b/skyrix-sope/NGObjWeb/SoOFSProduct.m
new file mode 100644 (file)
index 0000000..1a83354
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2002-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$
+
+#import <Foundation/NSObject.h>
+
+/* 
+   Note: do not include that file in the subproject, it is linked in the 
+         product bundle 
+*/
+
+@interface SoOFSProduct : NSObject
+@end
+
+@implementation SoOFSProduct
+@end /* SoOFSProduct */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/.cvsignore b/skyrix-sope/NGObjWeb/SoObjects/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-sope/NGObjWeb/SoObjects/GNUmakefile b/skyrix-sope/NGObjWeb/SoObjects/GNUmakefile
new file mode 100644 (file)
index 0000000..49462f6
--- /dev/null
@@ -0,0 +1,78 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = SoObjects
+
+SoObjects_HEADER_FILES_DIR         = .
+SoObjects_HEADER_FILES_INSTALL_DIR = /NGObjWeb
+
+SoObjects_HEADER_FILES = \
+       SoObjects.h                     \
+       NSException+HTTP.h              \
+       SoClass.h                       \
+       SoClassRegistry.h               \
+       SoClassSecurityInfo.h           \
+       SoDefaultRenderer.h             \
+       SoHTTPAuthenticator.h           \
+       SoObjCClass.h                   \
+       SoObject.h                      \
+       SoObjectMethodDispatcher.h      \
+       SoObjectRequestHandler.h        \
+       SoPageInvocation.h              \
+       SoPermissions.h                 \
+       SoProduct.h                     \
+       SoProductClassInfo.h            \
+       SoProductRegistry.h             \
+       SoProductResourceManager.h      \
+       SoSecurityManager.h             \
+       SoSelectorInvocation.h          \
+       SoUser.h                        \
+       WOContext+SoObjects.h           \
+       WORequest+So.h                  \
+       SoControlPanel.h                \
+       SoApplication.h                 \
+       SoLookupAssociation.h           \
+       SoTemplateRenderer.h            \
+       SoSubContext.h                  \
+       SoSecurityException.h           \
+       SoComponent.h                   \
+
+SoObjects_OBJC_FILES = \
+       NSException+HTTP.m              \
+       SoApplication.m                 \
+       SoClass.m                       \
+       SoClassRegistry.m               \
+       SoClassSecurityInfo.m           \
+       SoControlPanel.m                \
+       SoDefaultRenderer.m             \
+       SoHTTPAuthenticator.m           \
+       SoObjCClass.m                   \
+       SoObject+Traversal.m            \
+       SoObject.m                      \
+       SoObjectMethodDispatcher.m      \
+       SoObjectRequestHandler.m        \
+       SoObjectXmlRpcDispatcher.m      \
+       SoObjectSOAPDispatcher.m        \
+       SoPageInvocation.m              \
+       SoPermissions.m                 \
+       SoProduct.m                     \
+       SoProductClassInfo.m            \
+       SoProductRegistry.m             \
+       SoProductResourceManager.m      \
+       SoSecurityManager.m             \
+       SoSelectorInvocation.m          \
+       SoUser.m                        \
+       SoLookupAssociation.m           \
+       WOContext+SoObjects.m           \
+       WODirectAction+SoObjects.m      \
+       WODirectActionRequestHandler+SoObjects.m\
+       WORequest+So.m                  \
+       SoTemplateRenderer.m            \
+       SoSubContext.m                  \
+       SoSecurityException.m           \
+       SoComponent.m                   \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjWeb/SoObjects/GNUmakefile.preamble b/skyrix-sope/NGObjWeb/SoObjects/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..ddd1b69
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..                    \
+       -I../DynamicElements/   \
+       -I../WebDAV/            \
+       -I../..                 \
+       -I../../../skyrix-core                  \
+       -I../../../skyrix-core/NGStreams        \
+       -I../../../skyrix-core/NGExtensions     \
+       -I../../../skyrix-xml
diff --git a/skyrix-sope/NGObjWeb/SoObjects/NOTES b/skyrix-sope/NGObjWeb/SoObjects/NOTES
new file mode 100644 (file)
index 0000000..b6f80dd
--- /dev/null
@@ -0,0 +1,301 @@
+# $Id$
+
+Some Notes on the implementation ...
+
+OFSWebMethod / SoTemplateRenderer
+=================================
+
+should a GET on OFSWebMethod 
+a) return the method and let a renderer instantiate the component 
+- or -
+b) should a GET return the component
+
+a) has the advantage that the renderer has more control and more
+   information about the thing being rendered
+   new: and: OFSWebMethod objects can be returned as method results !
+b) has the advantage that the OFSWebMethod more directly corresponds
+   to a WOComponent and can be flexible about performing actions
+
+The template-renderer doesn't need to have OFSWebMethod directly but
+can rather use the clientObject in the context and it's hierarchy to
+locate a template.
+
+=> for now we should return the component, maybe reconsider later
+
+
+Acquision: lookupName vs traverseKey
+====================================
+
+The question is: should -lookupName do acquisition if the flag is set,
+or is the acquisition flag just a "hint" that acquisition is in progress ?
+If it *does* acquisition, should it consider the traversal-stack in the
+context ? What about 'binding' the result ? Currently the result is
+bound to the position where it was located and not to the object the
+lookup was performed on.
+
+Currently the major difference in traverseKey is, that traverseKey
+maintains the objectTraversalStack in the given context. This implies,
+that for "sub-traversals" a new context should be created.
+
+So for now -lookupName: acquires in the containment hierarchy if the
+aquisition flag is turned on and traverseKey acquires along the context
+hierarchy.
+
+Hm. This lookup issue needs to be cleared up and written down.
+
+
+Acquisition of "relative" Resources
+===================================
+
+Consider you have a page called "Test" which acquires and embeds
+a component called "Embed". And "Embed" itself embeds another object
+called "Who":
+
+  - Embed.dtml
+  - Who.dtml (A)
+  - Folder/
+    - Test.dtml
+    - Who.dtml (B)
+
+If Test embeds "Embed" how does "Embed" locate the "Who" object ?
+A) Will it start looking at it's local position ?
+B) Will it start looking at Test's position ?
+
+I tried with Zope and it always embeds Who.dtml (B) - that is,
+lookup for any "subobject" seems to go over the root-context
+traversal hierarchy and not relative to the object's position.
+
+I'm currently unsure whether that's a good solution, since when
+designing a reusable component (or template) you probably want to keep 
+the associated resources in the component's location, not in the
+location where the component is used ...
+Indeed this is how it works in SkyPublisher.
+Hm.
+
+All this gets even more tricky if you consider URL processing. Zope
+does not do any URL processing resulting in a similiar problem. When
+you write to reusable component you are probably thinking in the
+context of that component, not in the context of the invocation. So
+it probably makes perfect sense to rewrite URLs.
+Hm.
+
+Products: a product can use "filename" bindings to trigger the resource
+manager and this will return a product-relative URL. Maybe we can use that
+for templates as well (eg Manage-Templates ?)
+
+Templates
+=========
+
+Should we use .xtmpl as the extension for templates and forbid web-access
+to those ? Probably.
+Maybe we should even create a custom OFSWebMethod subclass for templates.
+=> do that for now.
+
+We currently do not support sites without a template :-( This is because
+NGObjWeb currently always "finds" a component, even if it has neither a
+template nor a class (probably something todo with scripting or forms).
+
+Note: just remembered about Zope Page Templates ZPT which are similiar to
+      .xtmpl templates.
+How are ZPT templates activated ?
+
+
+Templates vs WebMethods
+=======================
+
+What's the difference between a web-"method" and a "template" ? Both operate
+on a document (the "clientObject") to perform some tasks.
+
+  Method:   /folder/index.html/manage
+  Template: /folder/index.html?template=manage
+
+Apparently templates and methods are quite similiar. In practice they are not 
+and can be used in conjunction. "Methods", like the name suggests, are intended
+to perform some operation, eg "adduser", while "templates" are for *rendering*
+objects (usually in HTML).
+
+Again:
+- Methods:   for performing operations on behalf of the clientObject
+- Templates: for rendering a clientObject
+
+It's a bit difficult to get that right and to decide what is best for a given
+task ;-) 
+
+You most often use templates for automatic reuse of HTML "frames", eg instead
+of the Zope typical:
+
+  <dtml-var standard_html_header>
+  ... my content ...
+  <dtml-var standard_html_footer>
+
+In SOPE you simply defined a Main.xtmpl which does that for you. It's also 
+very common to use templates to provide navigation, banners, etc.
+
+A template is somewhat like the thing known as a "skin", eg in the management
+interface you activate a "management skin".
+
+
+File Extensions and Class Hierarchy
+===================================
+
+One problem with file-extensions is that they do not represent the SoClass
+hierarchy. Consider that you are looking for a "user-folder" to perform
+authentication. So the straight forward approach would be to walk up the
+context and look for a child which has the ".userfolder" extension, eg:
+
+  /folder/*.userfolder
+  /*.userfolder
+
+But this would defeat the whole purpose of user-folders and SoClasses, you
+cannot replace the folder class with an "LDAPUserFolder", because extensions
+are bound to classes.
+
+Some ideas to solve this problem:
+- define a default which contains the sequence of the extensions to look up
+  (too limited, a new default for *each* kind of resource ?)
+- instantiate each object and look at it's class
+  (too expensive, SOPE idea is to avoid instantiation if possible)
+- look at a fixed name instead of the extension (eg acl_users.*)
+  - maybe, a bit limiting
+- let the content-negotiation decide (like above)
+  - maybe, but how do we feed to negotiator ? Hm.
+
+Currently I think we need to extend the SoClass system to provide a list. 
+Something like
+  [SoClass gimmeAllExtensionsForClassAndIncludeParents:YES
+           includeChildren:NO]
+
+Hm.
+
+Similiar problem exists with various lookups. Eg "gimme a template" - currently
+we can only lookup templates that end with ".xtmpl".
+
+
+Security
+========
+
+How does a security lookup flow ? Eg what leads to a 401 if the protected
+'manage' method is called ? When are authenticators triggered ?
+
+First: the SoSecurityManagerDebugEnabled default is your friend :-) By 
+activating that you can easily find out why access to a specific object
+was denied or permitted (eg what role was selected)
+
+Sequence:
+- if a path is traversed, each 'name' is validated prior being queried by
+  calling the -validateName:inContext: method on the container
+- the default-implementation in turn calls -validateName:ofObject:inContext:
+  on the shared security manager (SoSecurityManager object)
+- the security manager first validates the object itself by calling
+  -validateObject:inContext:, this method checks whether a object is declared
+  public or which permissions are required to access the object
+  - if a permission is required, the security manager calls
+    -validatePermission:onObject:inContext:, this methods 
+    - determines the "roles" which provide the permission (currently only by 
+      using the class security info)
+    - then calls -userInContext:object: to get a SoUser object
+    - then compares the roles associated with the user and the roles required
+      to find out whether to allow access
+...
+
+
+Manager vs Developer
+====================
+
+In Zope a manager is basically the same thing like a developer since the ZMI
+provides the development environment. In SOPE things are intended to be a bit
+different, more like in traditional WO development.
+
+Especially I would like to avoid the requirement to deploy the management
+interface on the live site ! In contrast I would like to run a development
+system for editing the web application and a deployment system for running the
+application. Basically all things are intended to be read-only on the deployed
+system (if only for security reasons).
+
+This has some side-effects:
+- different user-management in the deployed site ?
+- manage dynamic site data *not* in SoOFS !
+
+Eg an easy way to deploy a site would be a read-only subversion checkout area
+which is updated periodically.
+
+[say more why etc]
+- dislike mix of templates and content
+- dislike "live" editing of things, even if happening in a snapshot
+- security issues, disable everything not required on the live site
+  (eg WebDAV write access)
+
+
+"Special" Method Name Form Values
+=================================
+
+We currently support three "special" form-values that are processed during
+method lookup:
+
+a) Cmd,        eg ?Cmd=freebusy
+b) :method,    eg ?:method=addFolder
+c) XXX:method, eg ?XXX:method=blah
+
+The first is for compatibility with ASP, the second is convenient for 
+attaching methods to form elements like popups and the third is for attaching
+methods to submit buttons which display their value in the browser.
+
+
+Product Resources
+=================
+
+How does a template stored in a product (bundle) acquire it's resources ? In
+Zope it seems to use a special "/p_/" path, eg the ZMI tab locates it's images
+using "/p_/ltab.gif" - search for "Using the p_ folder" in Google.
+
+This is related to the acquisition of relative resources.
+[write more]
+
+
+Resource Manager and Bundles
+============================
+
+Problem: WOResourceManager cannot discover templates in bundles since the
+application wide manager only looks in it's own path.
+
+This is not really necessary since classes know their bundles and therefore
+could locate templates using that information. But bundle classes should also
+be able to "see" all the other components for embedding, so we can't simply
+restrict the lookup to a bundle local manager.
+
+Skyrix41e WebUI does that by creating an own, global, LSWResourceManager which
+uses the NGBundleManager and the bundle-info.plist to locate resources.
+
+What to do ?
+... for now I have added SoComponent as a superclass which uses the product
+for lookup.
+
+Problem: pageWithName: uses the global resource manager to lookup components.
+- the WOResourceManager *does* find the class
+- but it does *not* find the template
+=> need a way in WOResourceManager to map a class to a different RM ?
+- currently pages can only be loaded by the global resource manager
+=> put a hack into WOResourceManager, check's the class' bundle path
+
+
+Acquisition of Templates
+========================
+
+When we acquire a template by name on a custom object which itself is private
+the custom object will reject the request for the template resource name with
+a security exception.
+This will abort the whole traverse-key method even though the container (or a
+parent of the container has a perfectly valid template with public access).
+
+Well, right now we allow public access to OFSImage and OFSPropertyListObject
+to work around that issue, yet it may not be the "preferred" solution.
+Some other options:
+- treat a security exception like a missing resources .. urks, nope, this is
+  properly no good solution ...
+- always lookup the template in the container?
+- if the lookup fails in the object itself, lookup the template in the 
+  container?
+- somehow check whether the object itself does intend to deal with such keys
+  at all (try something like hasKey: before attempting to use validateKey: on
+  an object which does not have it anyway ...)
+Hm.
diff --git a/skyrix-sope/NGObjWeb/SoObjects/NSException+HTTP.h b/skyrix-sope/NGObjWeb/SoObjects/NSException+HTTP.h
new file mode 100644 (file)
index 0000000..525196a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __SoObjects_NSException_HTTP_H__
+#define __SoObjects_NSException_HTTP_H__
+
+#import <Foundation/NSException.h>
+
+@interface NSException(HTTP)
+
++ (id)exceptionWithHTTPStatus:(unsigned short)_status;
++ (id)exceptionWithHTTPStatus:(unsigned short)_status reason:(NSString *)_r;
+- (id)initWithHTTPStatus:(unsigned short)_status reason:(NSString *)_r;
+
++ (NSString *)exceptionNameForHTTPStatus:(unsigned short)_status;
++ (NSString *)exceptionReasonForHTTPStatus:(unsigned short)_status;
+
+- (unsigned short)httpStatus;
+
+@end
+
+@interface SoHTTPException : NSException
+{
+  unsigned short status;
+}
+
+@end
+
+#endif /* __SoObjects_NSException_HTTP_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/NSException+HTTP.m b/skyrix-sope/NGObjWeb/SoObjects/NSException+HTTP.m
new file mode 100644 (file)
index 0000000..e652a0b
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSException+HTTP.h"
+#include "common.h"
+
+@implementation NSException(HTTP)
+
++ (id)exceptionWithHTTPStatus:(unsigned short)_status {
+  return [self exceptionWithHTTPStatus:_status reason:nil];
+}
+
++ (NSString *)exceptionNameForHTTPStatus:(unsigned short)_status {
+  switch (_status) {
+    case 401: return @"AuthRequired";
+    case 403: return @"Forbidden";
+    case 404: return @"NotFound";
+    default:  return [NSString stringWithFormat:@"HTTP %i", _status];
+  }
+}
++ (NSString *)exceptionReasonForHTTPStatus:(unsigned short)_status {
+  switch (_status) {
+    case 401: return @"authentication is required for access to the object!";
+    case 403: return @"you are not allowed to access the object!";
+    case 404: return @"the requested object could not be found!";
+    default:  return @"reason for HTTP error unknown";
+  }
+}
+
++ (id)exceptionWithHTTPStatus:(unsigned short)_status reason:(NSString *)_r {
+  return [[[SoHTTPException alloc] 
+           initWithHTTPStatus:_status reason:_r] autorelease];
+}
+- (id)initWithHTTPStatus:(unsigned short)_status reason:(NSString *)_r {
+  NSDictionary *ui;
+  NSString *errorName;
+  NSString *lReason;
+
+  ui = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:_status]
+                    forKey:@"http-status"];
+  
+  errorName = [[self class] exceptionNameForHTTPStatus:_status];
+  lReason   = _r ? _r : [[self class] exceptionReasonForHTTPStatus:_status];
+  
+  return [self initWithName:errorName reason:lReason userInfo:ui];
+}
+
+- (unsigned short)httpStatus {
+  return [[[self userInfo] objectForKey:@"http-status"] intValue];
+}
+
+- (void)detachFromContainer {
+  /* to be usable in OFS */
+}
+
+/* KVC */
+
+- (id)handleQueryWithUnboundKey:(NSString *)_key {
+  // TODO: is this considered a hack ?
+  return nil;
+}
+
+@end /* NSException(HTTP) */
+
+@implementation SoHTTPException
+
+- (id)initWithHTTPStatus:(unsigned short)_status reason:(NSString *)_r {
+  NSString *errorName;
+  NSString *lReason;
+  
+  errorName = [[self class] exceptionNameForHTTPStatus:_status];
+  lReason   = _r ? _r : [[self class] exceptionReasonForHTTPStatus:_status];
+  
+  if (([self initWithName:errorName reason:lReason userInfo:nil])) {
+    self->status = _status;
+  }
+  return self;
+}
+
+- (unsigned short)httpStatus {
+  return self->status;
+}
+
+@end /* SoHTTPException */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/README b/skyrix-sope/NGObjWeb/SoObjects/README
new file mode 100644 (file)
index 0000000..624e9a5
--- /dev/null
@@ -0,0 +1,61 @@
+# $Id$
+
+SoObjects
+=========
+
+An attempt to rewrite some Zope concepts in NGObjWeb, basically object
+publishing.
+
+It defines a new type system (SoClasses) and a new KVC system (which returns
+methods/selectors as objects).
+Further it provides the SoObjectRequestHandler for publishing objects on the
+web.
+
+TODO
+====
+
+- Object based security (now security-info can only get attached to classes)
+
+NOTES
+=====
+
+- we support ASP style ?Cmd query parameters !
+- we support :method form parameters
+  - both, when found, are added to the traversal path, this has the advantage
+    that it leaves the URI of a node intact
+
+Class Hierarchy
+===============
+
+<NSObject>
+  <NSException>
+    SoHTTPException
+  <WOApplication>
+    SoApplication
+  <WOAssociation>
+    SoLookupAssociation
+  <WORequestHandler>
+    SoObjectRequestHandler
+  <WOResourceManager>
+    SoProductResourceManager
+  SoClass
+    SoObjCClass
+  SoClassRegistry
+  SoClassSecurityInfo
+  SoControlPanel
+  SoDefaultRenderer
+  SoHTTPAuthenticator
+  SoObjectMethodDispatcher
+    SoObjectXmlRpcDispatcher
+  SoPageInvocation
+  SoProduct
+  SoProductClassInfo
+  SoProductRegistry
+  SoSecurityManager
+  SoSelectorInvocation
+  SoUser < SoUser >
+  WODirectActionPubInvocation
+
+Protocols
+  SoUserDatabase
+  SoUser
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoApplication.h b/skyrix-sope/NGObjWeb/SoObjects/SoApplication.h
new file mode 100644 (file)
index 0000000..fbd9764
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoApplication_H__
+#define __SoObjects_SoApplication_H__
+
+#include <NGObjWeb/WOApplication.h>
+
+/*
+  SoApplication
+  
+  A convenience WOApplication subclass for So based products. It:
+  - registeres SoObjectRequestHandler as 'so','dav','RPC2' and default handler
+  - loads products based on the SoApplicationLoadProducts default
+  - initializes all required global objects (registries, security manager)
+*/
+
+@class SoProductRegistry, SoClassRegistry, SoSecurityManager;
+
+@interface SoApplication : WOApplication
+{
+  SoProductRegistry *productRegistry;
+  SoClassRegistry   *classRegistry;
+  SoSecurityManager *securityManager;
+}
+
+/* accessors */
+
+- (SoProductRegistry *)productRegistry;
+- (SoClassRegistry *)classRegistry;
+- (SoSecurityManager *)securityManager;
+
+/* SoObject */
+
+- (id)rootObjectInContext:(id)_ctx;
+
+@end
+
+@interface SoApplication(Authenticator)
+
+- (id)authenticatorInContext:(id)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoApplication_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoApplication.m b/skyrix-sope/NGObjWeb/SoObjects/SoApplication.m
new file mode 100644 (file)
index 0000000..c702804
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoApplication.h"
+#include "SoClassRegistry.h"
+#include "SoControlPanel.h"
+#include "SoObject.h"
+#include "SoObjectRequestHandler.h"
+#include "SoProductRegistry.h"
+#include "SoSecurityManager.h"
+#include "SoApplication.h"
+#include "SoObject+SoDAV.h"
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+@implementation SoApplication
+
+static BOOL debugLookup = NO;
+
+- (BOOL)loadProducts:(id)_spec  {
+  if (_spec) {
+    // TODO: load specified products
+    [self logWithFormat:@"load products (not implemented): %@", _spec];
+    return NO;
+  }
+  else
+    [self->productRegistry loadAllProducts];
+  
+  return YES;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    id tmp;
+    
+    debugLookup = [ud boolForKey:@"SoDebugKeyLookup"];
+    
+    /* setup global objects */
+    
+    self->securityManager = [[SoSecurityManager sharedSecurityManager] retain];
+    self->classRegistry   = [[SoClassRegistry sharedClassRegistry] retain];
+    self->productRegistry = [[SoProductRegistry sharedProductRegistry] retain];
+    
+    /* Object Publishing */
+    tmp = [[SoObjectRequestHandler alloc] init];
+    [self registerRequestHandler:tmp forKey:@"so"];
+    [self registerRequestHandler:tmp forKey:@"dav"];
+    [self registerRequestHandler:tmp forKey:@"RPC2"];
+    [self setDefaultRequestHandler:tmp];
+    [tmp release];
+    
+    /* load products */
+    if (![self loadProducts:[ud objectForKey:@"SoApplicationLoadProducts"]]) {
+      [self logWithFormat:@"failed to load the products ..."];
+      [self release];
+      return nil;
+    }
+    
+#if LIB_FOUNDATION_LIBRARY
+    /* debugging */
+    if ([[ud objectForKey:@"EnableDoubleReleaseCheck"] boolValue])
+      [NSAutoreleasePool enableDoubleReleaseCheck:YES];
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->securityManager release];
+  [self->classRegistry   release];
+  [self->productRegistry release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (SoProductRegistry *)productRegistry {
+  return self->productRegistry;
+}
+- (SoClassRegistry *)classRegistry {
+  return self->classRegistry;
+}
+- (SoSecurityManager *)securityManager {
+  return self->securityManager;
+}
+
+/* application as the SoObject root */
+
+- (id)rootObjectInContext:(id)_ctx {
+  return nil;
+}
+
+- (NSException *)validateName:(NSString *)_key inContext:(id)_ctx {
+  id root;
+  
+  if ([self hasName:_key inContext:_ctx])
+    return [super validateName:_key inContext:_ctx];
+  
+  root = [self rootObjectInContext:_ctx];
+  return (root != self) 
+    ? [root validateName:_key inContext:_ctx] 
+    : [super validateName:_key inContext:_ctx];
+}
+
+- (BOOL)hasName:(NSString *)_key inContext:(id)_ctx {
+  id root;
+  
+  if ([_key isEqualToString:@"ControlPanel"])
+    return YES;
+  
+  if ([[self registeredRequestHandlerKeys] containsObject:_key])
+    return YES;
+  
+  if ([super hasName:_key inContext:_ctx])
+    return YES;
+  
+  root = [self rootObjectInContext:_ctx];
+  if (root != self)
+    return [root hasName:_key inContext:_ctx];
+  
+  return NO;
+}
+
+- (id)controlPanel:(NSString *)_name inContext:(id)_ctx {
+  return [[[SoControlPanel alloc] init] autorelease];
+}
+
+- (BOOL)isApplicationNameLookup:(NSString *)_name inContext:(id)_ctx {
+  static NSString *WOApplicationSuffix = nil;
+  NSString *appName;
+
+  appName = [[(WOContext *)_ctx request] applicationName];
+  if ([_name isEqual:appName]) {
+    if (debugLookup) [self logWithFormat:@"  matched appname: %@", appName];
+    return YES;
+  }
+
+  if (WOApplicationSuffix == nil) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    WOApplicationSuffix = [[ud stringForKey:@"WOApplicationSuffix"] copy];
+  }
+  appName = [appName stringByAppendingString:WOApplicationSuffix];
+  if ([_name isEqual:appName]) {
+    if (debugLookup) [self logWithFormat:@"  matched appname: %@", appName];
+    return YES;
+  }
+  
+  return NO;
+}
+
+- (id)lookupName:(NSString *)_name inContext:(id)_ctx acquire:(BOOL)_flag {
+  id v;
+  
+  if ([_name isEqualToString:@"ControlPanel"])
+    return [self controlPanel:_name inContext:_ctx];
+  
+  if ([[self registeredRequestHandlerKeys] containsObject:_name]) {
+    /* 
+      need to check registeredRequestHandlerKeys because requestHandlerForKey:
+      returns the default handler if the key could not be found ...
+    */
+    if ((v = [super requestHandlerForKey:_name]))
+      return v;
+  }
+  
+  if (debugLookup) [self logWithFormat:@"lookup name: %@", _name];
+  
+  if ((v = [super lookupName:_name inContext:_ctx acquire:NO]) == nil) {
+    id root;
+    
+    root = [self rootObjectInContext:_ctx];
+    if (debugLookup) [self logWithFormat:@"  lookup in root object: %@", v];
+    
+    if (root != self)
+      v = [root lookupName:_name inContext:_ctx acquire:_flag];
+    else if (debugLookup)
+      [self logWithFormat:@"  root is application object"];
+  }
+  
+  if (debugLookup) [self logWithFormat:@"  GOT: %@", v];
+  
+  /* 
+     hack to allow "/myapp/folder/", it is a hack because it also allows
+     /myapp/myapp/myapp/.../folder/ ...
+  */
+  if (v == nil && [self isApplicationNameLookup:_name inContext:_ctx])
+    v = self;
+  
+  return v;
+}
+
+- (NSArray *)toOneRelationshipKeys {
+  NSMutableSet *ma;
+  id root;
+  
+  ma = ((root = [super toOneRelationshipKeys]))
+    ? [[NSMutableSet alloc] initWithArray:root]
+    : [[NSMutableSet alloc] init];
+  
+  [ma addObjectsFromArray:[self registeredRequestHandlerKeys]];
+  [ma addObject:@"ControlPanel"];
+  
+  root = [self rootObjectInContext:[self context]];
+  if (root != nil && (root != self)) 
+    [ma addObjectsFromArray:[root toOneRelationshipKeys]];
+  
+  root = [ma allObjects];
+  [ma release];
+  return root;
+}
+
+/* WebDAV support for root objects */
+
+- (id)davCreateObject:(NSString *)_name
+  properties:(NSDictionary *)_props
+  inContext:(id)_ctx
+{
+  id root;
+
+  if ((root = [self rootObjectInContext:_ctx]) == nil)
+    return [super davCreateObject:_name properties:_props inContext:_ctx];
+  
+  return [root davCreateObject:_name properties:_props inContext:_ctx];
+}
+
+- (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx {
+  id root;
+
+  if ((root = [self rootObjectInContext:_ctx]) == nil)
+    return [super davCreateCollection:_name inContext:_ctx];
+  
+  //[self debugWithFormat:@"let root '%@' create collection '%@'", root,_name];
+  return [root davCreateCollection:_name inContext:_ctx];
+}
+
+@end /* SoApplication */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoClass.h b/skyrix-sope/NGObjWeb/SoObjects/SoClass.h
new file mode 100644 (file)
index 0000000..ef0c05f
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_SoClass_H__
+#define __SoObjects_SoClass_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoClass
+  
+  Abstract baseclass for SoObject classes. SoClasses collect common keys
+  and security info for sets of objects.
+  
+  See SoObjCClass and SoExtClass for examples of concrete SoClasses.
+*/
+
+@class NSString, NSMutableDictionary, NSArray, NSClassDescription;
+@class SoClassSecurityInfo;
+
+@interface SoClass : NSObject
+{
+  SoClass             *soSuperClass;
+  NSMutableDictionary *slots;
+  SoClassSecurityInfo *security;
+}
+
+- (id)initWithSoSuperClass:(SoClass *)_soClass;
+
+/* hierachy */
+
+- (SoClass *)soSuperClass;
+
+/* keys (traverse hierarchy) */
+
+- (BOOL)hasKey:(NSString *)_key  inContext:(id)_ctx;
+- (id)lookupKey:(NSString *)_key inContext:(id)_ctx;
+- (NSArray *)allKeys;
+
+/* slots (only works on the exact class) */
+
+- (void)setValue:(id)_value forSlot:(NSString *)_key;
+- (id)valueForSlot:(NSString *)_key;
+- (NSArray *)slotNames;
+
+/* security */
+
+- (SoClassSecurityInfo *)soClassSecurityInfo;
+
+/* factory */
+
+- (id)instantiateObject;
+- (NSClassDescription *)soClassDescription;
+- (NSString *)className;
+
+@end
+
+#endif /* __SoObjects_SoClass_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoClass.m b/skyrix-sope/NGObjWeb/SoObjects/SoClass.m
new file mode 100644 (file)
index 0000000..c4b4ad7
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoClass.h"
+#include "SoClassSecurityInfo.h"
+#include "common.h"
+
+#if APPLE_RUNTIME || NeXT_RUNTIME
+@interface NSObject(Miss)
+- (void)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+@implementation SoClass
+
+static BOOL debugOn = NO;
+
+- (id)initWithSoSuperClass:(SoClass *)_soClass {
+  if ((self = [super init])) {
+    self->soSuperClass = [_soClass retain];
+    self->slots        = [[NSMutableDictionary alloc] init];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithSoSuperClass:nil];
+}
+
+- (void)dealloc {
+  [self->security     release];
+  [self->slots        release];
+  [self->soSuperClass release];
+  [super dealloc];
+}
+
+/* hierachy */
+
+- (SoClass *)soSuperClass {
+  return self->soSuperClass;
+}
+
+/* keys (traverse hierarchy) */
+
+- (BOOL)hasKey:(NSString *)_key inContext:(id)_ctx {
+  if ([self valueForSlot:_key] != nil)
+    return YES;
+  
+  return [self->soSuperClass hasKey:_key inContext:_ctx];
+}
+
+- (id)lookupKey:(NSString *)_key inContext:(id)_ctx {
+  id value;
+  
+  if ((value = [self valueForSlot:_key]))
+    return value;
+  
+  return [self->soSuperClass lookupKey:_key inContext:_ctx];
+}
+
+- (NSArray *)allKeys {
+  SoClass *soClass;
+  NSMutableSet *keys;
+  
+  keys = [NSMutableSet setWithCapacity:64];
+  for (soClass = self; soClass != nil; soClass = [soClass soSuperClass])
+    [keys addObjectsFromArray:[soClass slotNames]];
+  return [keys allObjects];
+}
+
+/* slots (only works on the exact class) */
+
+- (void)setValue:(id)_value forSlot:(NSString *)_key {
+  if (debugOn)
+    [self logWithFormat:@"set value for slot '%@': %@", _key, _value];
+
+  if ([_key length] == 0) {
+    [self logWithFormat:@"attempt to set value for invalid slot '%@'", _key];
+    return;
+  }
+  [self->slots setObject:(_value ? _value : [NSNull null]) forKey:_key];
+}
+- (id)valueForSlot:(NSString *)_key {
+  id value;
+  
+  value = [self->slots objectForKey:_key];
+  if (debugOn)
+    [self logWithFormat:@"queried value for slot '%@': %@", _key, value];
+  return value;
+}
+- (NSArray *)slotNames {
+  return self->slots ?  [self->slots allKeys] : [NSArray array];
+}
+
+/* security */
+
+- (SoClassSecurityInfo *)soClassSecurityInfo {
+  if (self->security == nil)
+    self->security = [[SoClassSecurityInfo alloc] initWithSoClass:self];
+  return self->security;
+}
+
+- (NSException *)validateKey:(NSString *)_key inContext:(id)_ctx {
+  /* 
+     nil means: access fully granted 
+     
+     IMPORTANT: to properly support acquisition, this method must return
+     nil on keys which should be acquired (since validateKey is called before
+     the lookup is performed) !
+  */
+  NSString *r;
+  
+  r = [NSString stringWithFormat:@"tried to access private key %@", _key];
+  return [NSException exceptionWithName:@"KeyDenied" reason:r userInfo:nil];
+}
+
+/* factory */
+
+- (id)instantiateObject {
+  [self subclassResponsibility:_cmd];
+  return nil;
+}
+
+- (NSClassDescription *)soClassDescription {
+  return nil;
+}
+
+- (NSString *)className {
+  return nil;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  /* 
+    This is required on OSX because the class is used as a dict-key in
+    OFSFactoryRegistry.
+  */
+  return [self retain];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self,
+        NSStringFromClass((Class)*(void**)self)];
+  
+  if (self->soSuperClass)
+    [ms appendFormat:@" super=0x%08X", self->soSuperClass];
+  else
+    [ms appendString:@" root"];
+  
+  if ([self->slots count] > 0) {
+    [ms appendFormat:@" slots=%@", 
+         [[self->slots allKeys] componentsJoinedByString:@","]];
+  }
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SoClass */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoClassRegistry.h b/skyrix-sope/NGObjWeb/SoObjects/SoClassRegistry.h
new file mode 100644 (file)
index 0000000..a118e37
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoClassRegistry_H__
+#define __SoObjects_SoClassRegistry_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoClassRegistry
+  
+  The class registry is used to map ObjC classes to SoClasses, to map names
+  to SoClasses and to map file-extensions to SoClasses.
+*/
+
+@class NSMutableDictionary, NSString, NSException;
+@class SoClass;
+
+@interface SoClassRegistry : NSObject
+{
+  NSMutableDictionary *objcToSoClass;
+  NSMutableDictionary *extToSoClass;
+  NSMutableDictionary *nameToSoClass;
+}
+
++ (id)sharedClassRegistry;
+
+/* name registry */
+
+- (SoClass *)soClassWithName:(NSString *)_name;
+- (SoClass *)soClassForExtension:(NSString *)_ext;
+- (SoClass *)soClassForExactName:(NSString *)_name;
+
+- (NSException *)registerSoClass:(SoClass *)_clazz forExtension:(NSString *)_e;
+- (NSException *)registerSoClass:(SoClass *)_clazz forExactName:(NSString *)_n;
+
+/* ObjC classes */
+
+- (SoClass *)soClassForClass:(Class)_clazz;
+
+@end
+
+#endif /* __SoObjects_SoClassRegistry_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoClassRegistry.m b/skyrix-sope/NGObjWeb/SoObjects/SoClassRegistry.m
new file mode 100644 (file)
index 0000000..96d0415
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoClassRegistry.h"
+#include "SoObjCClass.h"
+#include "common.h"
+
+@implementation SoClassRegistry
+
+// TODO: register for bundle-did-load notification !!
+static SoClassRegistry *registry = nil; // THREAD
+
++ (id)sharedClassRegistry {
+  if (registry == nil)
+    registry = [[SoClassRegistry alloc] init];
+  return registry;
+}
+- (id)init {
+  if ((self = [super init])) {
+    self->objcToSoClass = [[NSMutableDictionary alloc] initWithCapacity:64];
+    self->extToSoClass  = [[NSMutableDictionary alloc] initWithCapacity:32];
+    self->nameToSoClass = [[NSMutableDictionary alloc] initWithCapacity:32];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->extToSoClass  release];
+  [self->nameToSoClass release];
+  [self->objcToSoClass release];
+  [super dealloc];
+}
+
+/* name registry */
+
+- (SoClass *)soClassWithName:(NSString *)_name {
+  Class clazz;
+  
+  if ([_name length] == 0) return nil;
+  
+  if ((clazz = NSClassFromString(_name)))
+    return [self soClassForClass:clazz];
+  
+  return nil;
+}
+
+- (SoClass *)soClassForExtension:(NSString *)_ext {
+  SoClass *soClass;
+  
+  if ((soClass = [self->extToSoClass objectForKey:_ext]) == nil)
+    return nil;
+
+  return soClass;
+}
+- (NSException *)registerSoClass:(SoClass *)_clazz forExtension:(NSString *)_e{
+  SoClass *soClass;
+  
+  NSAssert(_clazz, @"invalid class parameter !");
+  NSAssert(_e,     @"invalid file extension parameter !");
+  
+  if ((soClass = [self->extToSoClass objectForKey:_e])) {
+    if (soClass == _clazz)
+      /* already registered */
+      return nil;
+    
+    [self debugWithFormat:
+           @"overriding existing registration for extension '%@': %@",
+           _e, soClass];
+  }
+  
+  [self->extToSoClass setObject:_clazz forKey:_e];
+  return nil;
+}
+
+- (SoClass *)soClassForExactName:(NSString *)_name {
+  SoClass *soClass;
+  
+  if ((soClass = [self->nameToSoClass objectForKey:_name]) == nil)
+    return nil;
+
+  return soClass;
+}
+- (NSException *)registerSoClass:(SoClass *)_clazz forExactName:(NSString *)_n{
+  SoClass *soClass;
+  
+  NSAssert(_clazz, @"invalid class parameter !");
+  NSAssert(_n,     @"invalid file extension parameter !");
+  
+  if ((soClass = [self->nameToSoClass objectForKey:_n])) {
+    if (soClass == _clazz)
+      /* already registered */
+      return nil;
+    
+    [self debugWithFormat:
+           @"overriding existing registration for name '%@': %@",
+           _n, soClass];
+  }
+  
+  [self->nameToSoClass setObject:_clazz forKey:_n];
+  return nil;
+}
+
+/* ObjC classes */
+
+- (SoClass *)soClassForClass:(Class)_clazz {
+  SoObjCClass *soClass;
+  SoClass     *soSuper;
+  
+  if (_clazz == Nil)
+    return nil;
+  if ((soClass = [self->objcToSoClass objectForKey:_clazz]))
+    return soClass;
+  
+  soSuper = [self soClassForClass:[_clazz superclass]];
+  soClass = [[SoObjCClass alloc] initWithSoSuperClass:soSuper class:_clazz];
+  
+  if (soClass == nil) {
+    [self debugWithFormat:@"could not create SoClass for class %@ !", _clazz];
+    return nil;
+  }
+  [self->objcToSoClass setObject:soClass forKey:_clazz];
+  [soClass rescanClass];
+  [self debugWithFormat:@"mapped class %@ to SoClass %@", 
+         NSStringFromClass(_clazz), soClass];
+  return [soClass autorelease];
+}
+
+@end /* SoClassRegistry */
+
+@implementation SoClassRegistry(Logging)
+
+- (NSString *)loggingPrefix {
+  return @"[so-class-registry]";
+}
+- (BOOL)isDebuggingEnabled {
+  static int debugOn = -1;
+  if (debugOn == -1) {
+    debugOn = [[NSUserDefaults standardUserDefaults]
+               boolForKey:@"SoClassRegistryDebugEnabled"] ? 1 : 0;
+  }
+  return debugOn ? YES : NO;
+}
+
+@end /* SoClassRegistry(Logging) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoClassSecurityInfo.h b/skyrix-sope/NGObjWeb/SoObjects/SoClassSecurityInfo.h
new file mode 100644 (file)
index 0000000..be4022c
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoClassSecurityInfo_H__
+#define __SoObjects_SoClassSecurityInfo_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSMutableSet, NSMutableDictionary, NSArray;
+
+/*
+  SoClassSecurityInfo
+
+  Storing security info for a SoClass.
+
+  Declaring Roles: mapping permissions to roles is the task of the system
+  administrator. Programmers should only declare default roles for:
+  - Anonymous
+  - Manager
+  - Owner
+  
+  TODO: default access (this is done in the meantime ?)
+  
+  Adding security information to a class
+  ======================================
+  
+  Per default classes are protected from outside access. Defining incorrect
+  protections is one of the most common problems when writing SOPE applications
+  since "security is hard" (Jim Fulton) ;-)
+  
+  Because of that, we provide some user-defaults to control logging of
+  security:
+    SoSecurityManagerDebugEnabled (bool) - debugging access
+    SoLogSecurityDeclarations     (bool) - track information
+  
+  To declare security information on an Objective-C class which you are using
+  as a SoClass, it's based to implemented the +initialize method:
+  
+    + (void)initialize {
+      // to mark the object public (not restricted to a user/role)
+      [[self soClassSecurityInfo] declareObjectPublic];
+      
+      // to allow public access to all contained objects (subkeys)
+      [[self soClassSecurityInfo] setDefaultAccess:@"allow"];
+
+      // to protect a specific object
+      [[self soClassSecurityInfo] 
+             declareProtected:SoPerm_View:@"test.html",nil];
+    }
+  
+  For products it's much easier to declare the products' SoClasses and
+  their protections in the "product.plist" file.
+*/
+
+@class SoClass;
+
+@interface SoClassSecurityInfo : NSObject
+{
+  NSMutableSet        *publicNames;
+  NSMutableSet        *privateNames;
+  NSMutableDictionary *nameToPerm;
+  NSMutableDictionary *defRoles;
+  NSString            *defaultAccess;
+  
+  NSString *objectPermission;
+  BOOL     isObjectPublic;
+  BOOL     isObjectPrivate;
+  
+  NSString *className;
+}
+
+- (id)initWithSoClass:(SoClass *)_class;
+
+/* attribute security */
+
+- (BOOL)hasProtectionsForKey:(NSString *)_key;
+- (BOOL)isKeyPrivate:(NSString *)_key;
+- (BOOL)isKeyPublic:(NSString *)_key;
+- (NSString *)permissionRequiredForKey:(NSString *)_key;
+
+- (void)setDefaultAccess:(NSString *)_access;
+- (NSString *)defaultAccess;
+- (BOOL)hasDefaultAccessDeclaration;
+- (void)declarePublic:(NSString *)_firstName, ...;
+- (void)declarePrivate:(NSString *)_firstName, ...;
+- (void)declareProtected:(NSString *)_perm:(NSString *)_firstName, ...;
+
+/* object security */
+
+- (BOOL)hasObjectProtections;
+- (BOOL)isObjectPublic;
+- (BOOL)isObjectPrivate;
+- (NSString *)permissionRequiredForObject;
+- (void)declareObjectPublic;
+- (void)declareObjectPrivate;
+- (void)declareObjectProtected:(NSString *)_perm;
+
+/* default role mappings */
+
+- (BOOL)hasDefaultRoleForPermission:(NSString *)_p;
+
+- (void)declareRole:(NSString *)_role  asDefaultForPermission:(NSString *)_p;
+- (void)declareRoles:(NSArray *)_roles asDefaultForPermission:(NSString *)_p;
+- (NSArray *)defaultRolesForPermission:(NSString *)_p;
+
+- (void)declareRole:(NSString *)_role 
+  asDefaultForPermissions:(NSString *)_firstPerm,...;
+
+@end
+
+@interface NSObject(ObjCClassSecurityInfo)
+
++ (SoClassSecurityInfo *)soClassSecurityInfo;
+
+@end
+
+#endif /* __SoObjects_SoClassSecurityInfo_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoClassSecurityInfo.m b/skyrix-sope/NGObjWeb/SoObjects/SoClassSecurityInfo.m
new file mode 100644 (file)
index 0000000..e925ed5
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoClassSecurityInfo.h"
+#include "SoClass.h"
+#include "common.h"
+
+@implementation SoClassSecurityInfo
+
+- (id)initWithSoClass:(SoClass *)_class {
+  if ((self = [self init])) {
+    self->className = [[_class className] copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->defaultAccess release];
+  [self->publicNames   release];
+  [self->privateNames  release];
+  [self->nameToPerm    release];
+  [self->defRoles      release];
+  [self->objectPermission release];
+  [self->className     release];
+  [super dealloc];
+}
+
+/* attribute security */
+
+- (void)_logPermAlreadySetForName:(NSString *)_name {
+  [self logWithFormat:
+         @"WARNING: tried to declare permission for attribute '%@' twice!",
+         _name];
+}
+
+- (void)setDefaultAccess:(NSString *)_access {
+  if (self->defaultAccess)
+    [self _logPermAlreadySetForName:@"<default>"];
+  else {
+    self->defaultAccess = [_access isNotNull] ? [_access copy] : nil;
+    [self debugWithFormat:@"set default access: '%@'", self->defaultAccess];
+  }
+}
+- (NSString *)defaultAccess {
+  return self->defaultAccess;
+}
+- (BOOL)hasDefaultAccessDeclaration {
+  return [self->defaultAccess length] > 0 ? YES : NO;
+}
+
+- (void)declarePublic:(NSString *)_firstName, ... {
+  va_list va;
+  NSString *aname;
+
+  if (self->publicNames == nil)
+    self->publicNames = [[NSMutableSet alloc] init];
+  
+  va_start(va, _firstName);
+  for (aname = _firstName; aname != nil; aname = va_arg(va, id)) {
+    if ([self->publicNames containsObject:aname])
+      [self _logPermAlreadySetForName:aname];
+    else if ([self->privateNames containsObject:aname])
+      [self _logPermAlreadySetForName:aname];
+    else if ([self->nameToPerm objectForKey:aname])
+      [self _logPermAlreadySetForName:aname];
+    else {
+      [self->publicNames addObject:aname];
+      [self debugWithFormat:@"set key public: '%@'", aname];
+    }
+  }
+  va_end(va);
+}
+
+- (void)declarePrivate:(NSString *)_firstName, ... {
+  va_list va;
+  NSString *aname;
+  
+  if (self->privateNames == nil)
+    self->privateNames = [[NSMutableSet alloc] init];
+  
+  va_start(va, _firstName);
+  for (aname = _firstName; aname != nil; aname = va_arg(va, id)) {
+    if ([self->publicNames containsObject:aname])
+      [self _logPermAlreadySetForName:aname];
+    else if ([self->privateNames containsObject:aname])
+      [self _logPermAlreadySetForName:aname];
+    else if ([self->nameToPerm objectForKey:aname])
+      [self _logPermAlreadySetForName:aname];
+    else {
+      [self->privateNames addObject:aname];
+      [self debugWithFormat:@"set key private: '%@'", aname];
+    }
+  }
+  va_end(va);
+}
+
+- (void)declareProtected:(NSString *)_perm:(NSString *)_firstName, ... {
+  va_list  va;
+  NSString *aname;
+
+  _perm = [_perm lowercaseString];
+  
+  if (self->nameToPerm == nil)
+    self->nameToPerm = [[NSMutableDictionary alloc] initWithCapacity:16];
+  
+  va_start(va, _firstName);
+  for (aname = _firstName; aname != nil; aname = va_arg(va, id)) {
+    if ([self->publicNames containsObject:aname])
+      [self _logPermAlreadySetForName:aname];
+    else if ([self->privateNames containsObject:aname])
+      [self _logPermAlreadySetForName:aname];
+    else if ([self->nameToPerm objectForKey:aname])
+      [self _logPermAlreadySetForName:aname];
+    else {
+      [self->nameToPerm setObject:_perm forKey:aname];
+      [self debugWithFormat:@"protect key by '%@': '%@'", _perm, aname];
+    }
+  }
+  va_end(va);
+}
+
+- (BOOL)hasProtectionsForKey:(NSString *)_key {
+  if (_key == nil) return NO;
+  
+  if ([self->publicNames  containsObject:_key]) return YES;
+  if ([self->privateNames containsObject:_key]) return YES;
+  if ([self->nameToPerm objectForKey:_key]) return YES;
+  return NO;
+}
+
+- (BOOL)isKeyPrivate:(NSString *)_key {
+  return [self->privateNames containsObject:_key];
+}
+- (BOOL)isKeyPublic:(NSString *)_key {
+  return [self->publicNames containsObject:_key];
+}
+- (NSString *)permissionRequiredForKey:(NSString *)_key {
+  return [self->nameToPerm objectForKey:_key];
+}
+
+/* object security */
+
+- (void)_logObjPermAlreadySet {
+  [self logWithFormat:
+         @"WARNING: tried to declare object permission twice! "
+         @"(perm=%@,private=%s,public=%s)",
+         self->objectPermission, 
+         self->isObjectPrivate?"yes":"no",
+         self->isObjectPublic?"yes":"no"];
+}
+
+- (BOOL)hasObjectProtections {
+  if (self->objectPermission) return YES;
+  if (self->isObjectPrivate)  return YES;
+  if (self->isObjectPublic)   return YES;
+  return NO;
+}
+- (BOOL)isObjectPublic {
+  return self->isObjectPublic;
+}
+- (BOOL)isObjectPrivate {
+  return self->isObjectPrivate;
+}
+- (NSString *)permissionRequiredForObject {
+  return self->objectPermission;
+}
+
+- (void)declareObjectPublic {
+  if ([self->objectPermission isNotNull] || self->isObjectPrivate)
+    [self _logObjPermAlreadySet];
+  else {
+    [self debugWithFormat:@"declared object public"];
+    self->isObjectPublic = YES;
+  }
+}
+- (void)declareObjectPrivate {
+  if ([self->objectPermission isNotNull] || self->isObjectPublic)
+    [self _logObjPermAlreadySet];
+  else {
+    [self debugWithFormat:@"declared object private"];
+    self->isObjectPrivate = YES;
+  }
+}
+- (void)declareObjectProtected:(NSString *)_perm {
+  _perm = [_perm isNotNull] ? [_perm lowercaseString] : nil;
+  
+  if ([_perm length] == 0) {
+    [self logWithFormat:@"tried to declare empty permission !", _perm];
+    return;
+  }
+  
+  if (self->isObjectPrivate || self->isObjectPublic || 
+      (self->objectPermission != nil)) {
+    [self _logObjPermAlreadySet];
+  }
+  else {
+    [self debugWithFormat:@"declared object protected by: %@", _perm];
+    self->objectPermission = [_perm copy];
+  }
+}
+
+/* default role mappings */
+
+- (BOOL)hasDefaultRoleForPermission:(NSString *)_p {
+  if (_p == nil) return NO;
+  _p = [_p lowercaseString];
+  return [self->defRoles objectForKey:_p] == nil ? NO : YES;
+}
+
+- (void)declareRole:(NSString *)_role asDefaultForPermission:(NSString *)_per{
+  id tmp;
+  
+  _per = [_per isNotNull] ? [_per lowercaseString] : nil;
+  
+  if (self->defRoles == nil)
+    self->defRoles = [[NSMutableDictionary alloc] initWithCapacity:8];
+  
+  if ((tmp = [self->defRoles objectForKey:_per])) {
+    [self logWithFormat:@"WARNING: tried to set default role of '%@' twice!"
+           @" (set to %@)", _per, tmp];
+    return;
+  }
+  
+  tmp = [_role isNotNull] ? [NSArray arrayWithObject:_role] : [NSArray array];
+  [self->defRoles setObject:tmp forKey:_per];
+}
+- (void)declareRole:(NSString *)_role
+  asDefaultForPermissions:(NSString *)_p,...
+{
+  va_list va;
+  NSString *aperm;
+  
+  va_start(va, _p);
+  for (aperm = _p; aperm != nil; aperm = va_arg(va, id)) {
+    [self declareRole:_role asDefaultForPermission:aperm];
+  }
+  va_end(va);
+}
+
+- (void)declareRoles:(NSArray *)_roles asDefaultForPermission:(NSString *)_p {
+  id tmp;
+  
+  _p = [_p isNotNull] ? [_p lowercaseString] : nil;
+  
+  if (self->defRoles == nil)
+    self->defRoles = [[NSMutableDictionary alloc] initWithCapacity:8];
+  
+  if ((tmp = [self->defRoles objectForKey:_p])) {
+    [self logWithFormat:@"WARNING: tried to set default role of '%@' twice!"
+           @" (set to %@)", _p, tmp];
+    return;
+  }
+  
+  tmp = [_roles isNotNull] ? _roles : [NSArray array];
+  [self->defRoles setObject:tmp forKey:_p];
+}
+
+- (NSArray *)defaultViewRoles {
+  static NSArray *defViewRoles = nil;
+  if (defViewRoles == nil) {
+    defViewRoles = [[NSArray alloc] initWithObjects:
+                                     @"Anonymous", @"Manager", nil];
+  }
+  return defViewRoles;
+}
+- (NSArray *)defaultContentsRoles {
+  static NSArray *defContentRoles = nil;
+  if (defContentRoles == nil) {
+    defContentRoles = [[NSArray alloc] initWithObjects:
+                                        @"Anonymous", @"Manager", nil];
+  }
+  return defContentRoles;
+}
+- (NSArray *)defaultRoles {
+  static NSArray *defRolesA = nil;
+  if (defRolesA == nil)
+    defRolesA = [[NSArray alloc] initWithObjects:@"Manager", nil];
+  return defRolesA;
+}
+
+- (NSArray *)defaultRolesForPermission:(NSString *)_p {
+  NSArray *roles;
+  
+  _p = [_p lowercaseString];
+  
+  if ((roles = [self->defRoles objectForKey:_p]))
+    ;
+  else if ([_p isEqualToString:@"view"])
+    roles = [self defaultViewRoles];
+  else if ([_p isEqualToString:@"access contents information"])
+    roles = [self defaultContentsRoles];
+  else
+    roles = [self defaultRoles];
+  
+  return roles;
+}
+
+@end /* SoClassSecurityInfo */
+
+@implementation SoClassSecurityInfo(Logging)
+
+- (NSString *)loggingPrefix {
+  return [self->className length] > 0
+    ? [NSString stringWithFormat:@"[so-secinfo %@]", self->className]
+    : [NSString stringWithFormat:@"[so-secinfo 0x%08X]", self];
+}
+- (BOOL)isDebuggingEnabled {
+  static int debugOn = -1;
+  if (debugOn == -1) {
+    debugOn = [[NSUserDefaults standardUserDefaults]
+               boolForKey:@"SoLogSecurityDeclarations"] ? 1 : 0;
+  }
+  return debugOn ? YES : NO;
+}
+
+@end /* SoClassSecurityInfo(Logging) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoComponent.h b/skyrix-sope/NGObjWeb/SoObjects/SoComponent.h
new file mode 100644 (file)
index 0000000..50e41a9
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoComponent_H__
+#define __SoObjects_SoComponent_H__
+
+#include <NGObjWeb/WOComponent.h>
+
+/*
+  SoComponent
+  
+  This is a subclass of WOComponent intendend for use with components which
+  are placed into a product bundle. The main difference is, that SoComponent's
+  use the SoProductResourceManager to locate their resources.
+*/
+
+@class NSURL;
+@class WOElement;
+@class SoProductResourceManager;
+
+@interface SoComponent : WOComponent
+{
+  SoProductResourceManager *soResourceManager; // __worm
+  NSURL     *soBaseURL;  // __wobaseurl
+  WOElement *soTemplate; // __wotemplate
+}
+
+@end
+
+#endif /* __SoObjects_SoComponent_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoComponent.m b/skyrix-sope/NGObjWeb/SoObjects/SoComponent.m
new file mode 100644 (file)
index 0000000..ba79e5c
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "SoComponent.h"
+#include "SoProductResourceManager.h"
+#include "SoProductRegistry.h"
+#include "SoProduct.h"
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@implementation SoComponent
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  static BOOL didInit = NO;
+  
+  if (didInit) return;
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  didInit = YES;
+}
+
+- (void)dealloc {
+  [self->soResourceManager release];
+  [self->soTemplate        release];
+  [self->soBaseURL         release];
+  [super dealloc];
+}
+
+/* resource manager */
+
+- (NSBundle *)componentBundle {
+  return [NSBundle bundleForClass:[self class]];
+}
+- (SoProduct *)componentProduct {
+  static SoProductRegistry *reg = nil;
+  SoProduct *product;
+  NSBundle  *bundle;
+  
+  if (reg == nil)
+    reg = [[SoProductRegistry sharedProductRegistry] retain];
+  if (reg == nil)
+    [self logWithFormat:@"ERROR: missing product registry!"];
+  
+  if ((bundle = [self componentBundle]) == nil)
+    [self logWithFormat:@"WARNING: did not find bundle of component !"];
+  
+  if ((product = [reg productForBundle:bundle]) == nil)
+    [self logWithFormat:
+            @"WARNING: did not find product of component (bundle=%@)", bundle];
+  return product;
+}
+
+- (void)setResourceManager:(WOResourceManager *)_rm {
+  ASSIGN(self->soResourceManager, _rm);
+}
+- (WOResourceManager *)resourceManager {
+  if (self->soResourceManager)
+    return self->soResourceManager;
+  
+  self->soResourceManager = [[[self componentProduct] resourceManager] retain];
+  if (self->soResourceManager)
+    return self->soResourceManager;
+  
+  return [super resourceManager];
+}
+
+/* move some extra vars into ivars */
+
+- (void)setBaseURL:(NSURL *)_url {
+  ASSIGN(self->soBaseURL, _url);
+}
+- (NSURL *)baseURL {
+  NSURL *url;
+  
+  if (self->soBaseURL)
+    return self->soBaseURL;
+  
+  url = [(WOApplication *)[self application] baseURL];
+  url = [NSURL URLWithString:@"WebServerResources" relativeToURL:url];
+  self->soBaseURL = [url copy];
+  return self->soBaseURL;
+}
+
+- (void)setTemplate:(id)_template {
+  /*
+    WO has private API for this:
+      - (void)setTemplate:(WOElement *)template;
+    As mentioned in the OmniGroup WO mailing list ...
+  */
+  ASSIGN(self->soTemplate, _template);
+}
+- (WOElement *)_woComponentTemplate {
+  WOElement *tmpl;
+  
+  if (self->soTemplate)
+    return self->soTemplate;
+  
+  tmpl = [self templateWithName:[self name]];
+  if (tmpl == nil) {
+    [self logWithFormat:
+           @"WARNING: found not template named '%@' for component.",
+           [self name]];
+  }
+  return tmpl;
+}
+
+@end /* SoComponent */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoControlPanel.h b/skyrix-sope/NGObjWeb/SoObjects/SoControlPanel.h
new file mode 100644 (file)
index 0000000..d17c75f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoControlPanel_H__
+#define __SoObjects_SoControlPanel_H__
+
+#import <Foundation/NSObject.h>
+
+@interface SoControlPanel : NSObject
+{
+}
+
+@end
+
+#endif /* __SoObjects_SoControlPanel_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoControlPanel.m b/skyrix-sope/NGObjWeb/SoObjects/SoControlPanel.m
new file mode 100644 (file)
index 0000000..5c77b29
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "SoControlPanel.h"
+#include "SoClassSecurityInfo.h"
+#include "SoProductRegistry.h"
+#include "SoObject.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@implementation SoControlPanel
+
++ (int)version {
+  return 1;
+}
+
+- (id)handleQueryWithUnboundKey:(NSString *)_key {
+  return [self lookupName:_key 
+              inContext:[[WOApplication application] context]
+              acquire:YES];
+}
+
+- (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_ac {
+  if ([_key isEqualToString:@"Products"])
+    return [SoProductRegistry sharedProductRegistry];
+  
+  return [super lookupName:_key inContext:_ctx acquire:_ac];
+}
+
+- (NSArray *)toOneRelationshipKeys {
+  NSArray *a;
+  
+  if ((a = [super toOneRelationshipKeys])) {
+    return ([a containsObject:@"Products"])
+      ? a : [a arrayByAddingObject:@"Products"];
+  }
+  else
+    return [NSArray arrayWithObject:@"Products"];
+}
+
+- (NSArray *)manageMenuChildNames {
+  return nil;
+}
+
+/* if accessed directly ... */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(id)_ctx {
+  // should invoke GETAction in the SMI ...
+  [_response appendContentString:@"<h3>SOPE Control Panel</h3>"];
+  [_response appendContentString:
+              @"<li><a href=\"Products/\">Products</a></li>"];
+}
+
+@end /* SoControlPanel */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoCore-SXP-Info.plist b/skyrix-sope/NGObjWeb/SoObjects/SoCore-SXP-Info.plist
new file mode 100644 (file)
index 0000000..a7edfe1
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SoCore</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>org.OpenGroupware.SOPE.SoCore</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>BNDL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+       <key>NSPrincipalClass</key>
+       <string>SoCoreProduct</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoDefaultRenderer.h b/skyrix-sope/NGObjWeb/SoObjects/SoDefaultRenderer.h
new file mode 100644 (file)
index 0000000..04936d5
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_SoDefaultRenderer_H__
+#define __SoObjects_SoDefaultRenderer_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoDefaultRenderer
+  
+  This renderer can render any object, at least as it's description.
+
+  It renders the following things (in order):
+  - NSExceptions (acks the http-status userInfo field)
+  - NSData       (as an application/octet-stream)
+  - tuples if turned on like described for Zope
+  - WOComponents
+  - WOElements   (anything that has appendToResponse:inContext:)
+  - *            by retrieving the stringValue
+*/
+
+@class NSException;
+@class WOContext;
+
+@interface SoDefaultRenderer : NSObject
+{
+}
+
++ (id)sharedRenderer;
+
+- (NSException *)renderObject:(id)_object inContext:(WOContext *)_ctx;
+- (BOOL)canRenderObject:(id)_object inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoDefaultRenderer_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoDefaultRenderer.m b/skyrix-sope/NGObjWeb/SoObjects/SoDefaultRenderer.m
new file mode 100644 (file)
index 0000000..314dbed
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoDefaultRenderer.h"
+#include "SoObjectRequestHandler.h"
+#include "SoSecurityManager.h"
+#include "WOContext+private.h" // required for page rendering
+#include "WOContext+SoObjects.h"
+#include "SoSecurityManager.h"
+#include "SoSecurityException.h"
+#include "SoObject.h"
+#include "NSException+HTTP.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOElement.h>
+#include <NGObjWeb/WOComponent.h>
+#include "common.h"
+
+@implementation SoDefaultRenderer
+
+static int debugOn = 0;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    
+    debugOn = [ud boolForKey:@"SoRendererDebugEnabled"];
+  }
+}
+
++ (id)sharedRenderer {
+  static SoDefaultRenderer *singleton = nil;
+  if (singleton == nil)
+    singleton = [[SoDefaultRenderer alloc] init];
+  return singleton;
+}
+
+/* rendering */
+
+- (NSException *)renderException:(NSException *)_ex 
+  inContext:(WOContext *)_ctx 
+{
+  WOResponse *r = [_ctx response];
+  int stat;
+  
+  /* check whether it's a security framework exception */
+  
+  if ([_ex isKindOfClass:[SoSecurityException class]]) {
+    id authenticator;
+    
+    if (debugOn)
+      [self debugWithFormat:@"    render as security exception: %@", _ex];
+    
+    authenticator = [(SoSecurityException *)_ex authenticator];
+    if (authenticator == nil)
+      authenticator = [[_ctx application] authenticatorInContext:_ctx];
+    
+    if (authenticator) {
+      if (debugOn)
+       [self debugWithFormat:@"    authenticator: %@", authenticator];
+      
+      if (([authenticator renderException:_ex inContext:_ctx])) {
+       if (debugOn)
+         [self debugWithFormat:@"    authenticator did render exception."];
+       return nil;
+      }
+    }
+    else {
+      if (debugOn)
+       [self debugWithFormat:@"    missing authenticator."];
+    }
+  }
+  
+  if (debugOn)
+    [self debugWithFormat:@"    as exception"];
+  
+  if ((stat = [_ex httpStatus]) > 0)
+    [r setStatus:stat];
+  else
+    [r setStatus:500];
+  
+  [r setHeader:@"text/html; charset=\"iso-8859-1\"" forKey:@"content-type"];
+  [r appendContentString:
+       @"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+       @"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
+       @"<body>"
+       @"<h3>An error occured during object publishing</h3>"];
+  [r appendContentString:@"<p>"];
+  [r appendContentString:[_ex reason]];
+  [r appendContentString:@"</p>"];
+  [r appendContentString:@"</body>\n"];
+  [r appendContentString:@"</html>\n"];
+  return nil;
+}
+
+- (NSException *)renderComponent:(WOComponent *)_c inContext:(WOContext *)_ctx{
+  WOResponse *r = [_ctx response];
+  
+  if (debugOn) {
+    [self debugWithFormat:
+           @"    as component (use appendToResponse:inContext:)"];
+  }
+  [r setHeader:@"text/html" forKey:@"content-type"];
+  [_ctx setPage:_c];
+  [_ctx enterComponent:_c content:nil];
+  [_c appendToResponse:r inContext:_ctx];
+  [_ctx leaveComponent:_c];
+  return nil;
+}
+
+- (NSException *)renderElement:(WOElement *)_e inContext:(WOContext *)_ctx {
+  if (debugOn)
+    [self debugWithFormat:@"    as element (use appendToResponse:inContext:"];
+  [_e appendToResponse:[_ctx response] inContext:_ctx];
+  return nil;
+}
+
+- (NSException *)renderData:(NSData *)_data inContext:(WOContext *)_ctx {
+  /* this could be extended to do some MIME magic */
+  WOResponse *r = [_ctx response];
+  
+  [r setStatus:200];
+  [r setHeader:@"application/octet-stream" forKey:@"content-type"];
+  [r setHeader:[NSString stringWithFormat:@"%i", [_data length]] 
+     forKey:@"content-length"];
+  [r setContent:_data];
+  return nil;
+}
+
+- (NSException *)renderTuple:(NSArray *)_tuple inContext:(WOContext *)_ctx {
+  WOResponse *r = [_ctx response];
+  NSString   *title = nil, *body = nil;
+  
+  if (debugOn)
+    [self debugWithFormat:@"    as tuple"];
+  [r setStatus:200];
+  [r appendContentString:@"<html>"];
+  
+  switch ([_tuple count]) {
+  case 0: break;
+  case 1: 
+    body = [_tuple objectAtIndex:0]; 
+    break;
+  case 2: 
+    title = [_tuple objectAtIndex:0];
+    body  = [_tuple objectAtIndex:1];
+    break;
+  case 3: 
+    title = [_tuple objectAtIndex:0];
+    body  = [[_tuple subarrayWithRange:NSMakeRange(1, [_tuple count] - 1)]
+             componentsJoinedByString:@"<br />"];
+    break;
+  }
+  
+  if ([title length] > 0) {
+    [r appendContentString:@"<head><title>"];
+    [r appendContentHTMLString:title];
+    [r appendContentString:@"</title></head>"];
+  }
+  if ([body length] > 0) {
+    [r appendContentString:@"<body>"];
+    [r appendContentHTMLString:body];
+    [r appendContentString:@"</body>"];
+  }
+  [r appendContentString:@"</html>"];
+  return nil;
+}
+
+- (NSException *)renderObjectAsString:(id)_object inContext:(WOContext *)_ctx {
+  /* fall back, use stringValue */
+  WOResponse *r;
+  
+  if (debugOn)
+    [self debugWithFormat:@"    render as string (last fallback)"];
+  
+  r = [_ctx response];
+  [r setStatus:200];
+  [r setHeader:@"text/html" forKey:@"content-type"];
+  [r appendContentString:
+       @"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+       @"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
+       @"<body>"];
+  [r appendContentHTMLString:[_object stringValue]];
+  [r appendContentString:@"</body>\n"];
+  [r appendContentString:@"</html>\n"];
+  return nil;
+}
+
+/* master dispatcher */
+
+- (BOOL)processTupleResults {
+  return NO;
+}
+
+- (NSException *)renderObject:(id)_object inContext:(WOContext *)_ctx {
+  SoSecurityManager *sm;
+  NSException *e;
+  
+  if ([_object isKindOfClass:[WOResponse class]]) {
+    if (_object != [_ctx response]) {
+      [self logWithFormat:@"response mismatch !"];
+      return [NSException exceptionWithHTTPStatus:500 /* internal error */];
+    }
+    return nil; /* already rendered */
+  }
+  
+  /* base types, no useful security validation possible */
+  
+  if ([_object isKindOfClass:[NSException class]])
+    return [self renderException:_object inContext:_ctx];
+  
+  if ([_object isKindOfClass:[NSData class]])
+    return [self renderData:_object inContext:_ctx];
+  
+  if ([_object isKindOfClass:[NSArray class]] && [self processTupleResults])
+    return [self renderTuple:_object inContext:_ctx];
+  
+  /* objects that require validation */
+  
+  sm = [_ctx soSecurityManager];
+  if ((e = [sm validateObject:_object inContext:_ctx]) != nil)
+    return [self renderException:e inContext:_ctx];
+  
+  if ([_object isKindOfClass:[WOComponent class]])
+    return [self renderComponent:_object inContext:_ctx];
+  
+  if ([_object respondsToSelector:@selector(appendToResponse:inContext:)])
+    return [self renderElement:_object inContext:_ctx];
+  
+  return [self renderObjectAsString:_object inContext:_ctx];
+}
+
+- (BOOL)canRenderObject:(id)_object inContext:(WOContext *)_ctx {
+  return YES;
+}
+
+/* debugging */
+
+- (NSString *)loggingPrefix {
+  return @"[so-dflt-renderer]";
+}
+
+@end /* SoDefaultRenderer */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoHTTPAuthenticator.h b/skyrix-sope/NGObjWeb/SoObjects/SoHTTPAuthenticator.h
new file mode 100644 (file)
index 0000000..771ea52
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoHTTPAuthenticator_H__
+#define __SoObjects_SoHTTPAuthenticator_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoHTTPAuthenticator
+
+  SoHTTPAuthenticator is an abstract base class for HTTP (basic 
+  authentication) based user databases. It deals with all the encoding,
+  decoding of credentials.
+  In the simplest case you only need to override -checkLogin:password:
+  to ensure login/password combinations.
+*/
+
+@class NSString, NSException, NSArray;
+@class WOContext, WOResponse;
+@class SoUser;
+
+@interface SoHTTPAuthenticator : NSObject
+{
+}
+
+/* password checker (override in subclasses !) */
+
+- (BOOL)checkLogin:(NSString *)_login password:(NSString *)_pwd;
+
+/* HTTP basic authentication */
+
+- (NSString *)authRealm;
+- (WOResponse *)preprocessCredentialsInContext:(WOContext *)_ctx;
+
+- (NSString *)checkCredentials:(NSString *)_creds;
+- (NSString *)checkCredentialsInContext:(WOContext *)_ctx;
+- (NSArray *)parseCredentials:(NSString *)_creds;
++ (NSArray *)parseCredentials:(NSString *)_creds;
+
+/* user management */
+
+- (SoUser *)userInContext:(WOContext *)_ctx;
+- (NSArray *)rolesForLogin:(NSString *)_login;
+
+/* render auth exceptions of SoSecurityManager */
+
+- (BOOL)renderException:(NSException *)_e inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoHTTPAuthenticator_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoHTTPAuthenticator.m b/skyrix-sope/NGObjWeb/SoObjects/SoHTTPAuthenticator.m
new file mode 100644 (file)
index 0000000..93eb7f2
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoHTTPAuthenticator.h"
+#include "SoUser.h"
+#include "SoPermissions.h"
+#include "NSException+HTTP.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGExtensions/NSString+Ext.h>
+#include "common.h"
+
+#if APPLE_RUNTIME || NeXT_RUNTIME
+@interface NSObject(Miss)
+- (void)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+@implementation SoHTTPAuthenticator
+
++ (int)version {
+  return 1;
+}
+
+/* HTTP basic authentication */
+
+- (NSString *)authRealm {
+  return [(WOApplication *)[WOApplication application] name];
+}
+
+/* check for roles */
+
+- (BOOL)checkLogin:(NSString *)_login password:(NSString *)_pwd {
+  [self subclassResponsibility:_cmd];
+  return NO;
+}
+
++ (NSArray *)parseCredentials:(NSString *)_creds {
+  NSRange  rng;
+  NSString *login, *pwd;
+  NSString *k;
+  
+  if ([_creds length] == 0) {
+    static NSArray *anon = nil;
+    if (anon == nil)
+      anon = [[NSArray alloc] initWithObjects:@"anonymous", @"", nil];
+    return anon;
+  }
+  if ([_creds length] < 6) {
+    [self logWithFormat:@"cannot handle authentication token: %@", _creds];
+    return nil;
+  }
+  
+  k = [[_creds substringToIndex:5] lowercaseString];
+  if (![k hasPrefix:@"basic"]) {
+    [self logWithFormat:@"tried unknown authentication method: %@", _creds];
+    return nil;
+  }
+  
+  k = [_creds substringFromIndex:6];
+  k = [k stringByDecodingBase64];
+  if (k == nil) return nil;
+
+  rng = [k rangeOfString:@":"];
+  if (rng.length <= 0) {
+    [self logWithFormat:@"got malformed basic credentials!"];
+    return nil;
+  }
+  login = [k substringToIndex:rng.location];
+  pwd   = [k substringFromIndex:(rng.location + rng.length)];
+  
+  rng = [login rangeOfString:@"\\"];
+  if (rng.length > 0) {
+    [self debugWithFormat:@"splitting of domain in login: '%@'", login];
+    login = [login substringFromIndex:(rng.location + rng.length)];
+  }
+  return [NSArray arrayWithObjects:login, pwd, nil];
+}
+- (NSArray *)parseCredentials:(NSString *)_creds {
+  return [[self class] parseCredentials:_creds];
+}
+
+- (NSString *)checkCredentials:(NSString *)_creds {
+  /* checks credentials, returnes login if successful */
+  NSString *login, *pwd;
+  NSArray  *creds;
+  
+  if ((creds = [self parseCredentials:_creds]) == nil)
+    return nil;
+
+  login = [creds objectAtIndex:0];
+  if ([login isEqualToString:@"anonymous"])
+    return @"anonymous";
+  
+  pwd = [creds objectAtIndex:1];
+  if (![self checkLogin:login password:pwd])
+    return nil;
+  
+  return login;
+}
+
+- (NSString *)checkCredentialsInContext:(WOContext *)_ctx {
+  WORequest *rq;
+  NSString  *auth;
+  
+  rq = [_ctx request];
+  if ((auth = [rq headerForKey:@"authorization"]) == nil) {
+    /* no auth supplied */
+    return @"anonymous";
+  }
+  return [self checkCredentials:auth];
+}
+
+- (NSArray *)rolesForLogin:(NSString *)_login {
+  NSArray *uroles = nil;
+  
+  // could add manager of login=root
+  
+  uroles = [NSArray arrayWithObjects:
+                     SoRole_Authenticated,
+                     SoRole_Anonymous,
+                     nil];
+  return uroles;
+}
+
+- (SoUser *)userInContext:(WOContext *)_ctx {
+  static SoUser *anonymous = nil;
+  NSString  *login;
+  NSArray   *uroles;
+  
+  if (anonymous == nil) {
+    NSArray *ar = [NSArray arrayWithObject:SoRole_Anonymous];
+    anonymous = [[SoUser alloc] initWithLogin:@"anonymous" roles:ar];
+  }
+  
+  if ((login = [self checkCredentialsInContext:_ctx]) == nil)
+    /* some error (otherwise result would have been anonymous */
+    return nil;
+  
+  if ([login isEqualToString:@"anonymous"])
+    return anonymous;
+  
+  uroles = [self rolesForLogin:login];
+  return [[[SoUser alloc] initWithLogin:login roles:uroles] autorelease];
+}
+
+- (WOResponse *)preprocessCredentialsInContext:(WOContext *)_ctx {
+  WOResponse *r;
+  NSString *auth;
+  NSString *k;
+  NSString *user, *pwd;
+  NSRange rng;
+
+  if ((auth = [[_ctx request] headerForKey:@"authorization"]) == nil) {
+    /* no authentication provided */
+    static NSArray *anon = nil;
+    if (anon == nil)
+      anon = [[NSArray alloc] initWithObjects:SoRole_Anonymous, nil];
+    
+    [_ctx setObject:anon forKey:@"SoAuthenticatedRoles"];
+    return nil;
+  }
+  
+  /* authentication provided, check whether it's valid */
+  
+  r = [_ctx response];
+  if ([auth length] < 6) {
+    [self logWithFormat:@"tried unknown authentication method: %@ (A)", auth];
+    [r setStatus:400 /* bad request */];
+    [r appendContentString:@"tried unsupported authentication"];
+    return r;
+  }
+  k = [[auth substringToIndex:5] lowercaseString];
+  if (![k hasPrefix:@"basic"]) {
+    [self logWithFormat:@"tried unknown authentication method: %@ (B)", auth];
+    [r setStatus:400 /* bad request */];
+    [r appendContentString:@"tried unsupported authentication"];
+    return r;
+  }
+  
+  k = [auth substringFromIndex:6];
+  if ((k = [k stringByDecodingBase64]) == nil) {
+    [self logWithFormat:@"tried unknown authentication method: %@ (C)", auth];
+    [r setStatus:400 /* bad request */];
+    [r appendContentString:@"could not decode base64 credentials"];
+    return r;
+  }
+
+  rng = [k rangeOfString:@":"];
+  if (rng.length <= 0) {
+    [self logWithFormat:@"got malformed basic credentials!"];
+    [r setStatus:400 /* bad request */];
+    [r appendContentString:@"did not find colon separator in credentials"];
+    return r;
+  }
+
+  user = [k substringToIndex:rng.location];
+  pwd  = [k substringFromIndex:(rng.location + rng.length)];
+
+  rng = [user rangeOfString:@"\\"];
+  if (rng.length > 0) {
+    [self debugWithFormat:@"splitting of domain in user: '%@'", user];
+    user = [user substringFromIndex:(rng.location + rng.length)];
+  }
+  
+  if ([user length] == 0) {
+    [self logWithFormat:@"got malformed basic credentials!"];
+    [r setStatus:400 /* bad request */];
+    [r appendContentString:@"invalid login in credentials"];
+    return r;
+  }
+  if ([pwd length] == 0) {
+    [self logWithFormat:@"got empty password for user '%@'!", user];
+    
+    auth = [NSString stringWithFormat:@"basic realm=\"%@\"",[self authRealm]];
+    [r setStatus:401 /* unauthorized */];
+    [r setHeader:auth forKey:@"www-authenticate"];
+    [r appendContentString:@"empty password in credentials"];
+    return r;
+  }
+  
+  /* authenticate valid credentials */
+
+  if (![self checkLogin:user password:pwd]) {
+    [self logWithFormat:@"tried wrong password for user '%@'!", user];
+    auth = [NSString stringWithFormat:@"basic realm=\"%@\"",[self authRealm]];
+    [r setStatus:401 /* unauthorized */];
+    [r setHeader:auth forKey:@"www-authenticate"];
+    return r;
+  }
+  
+  //[self debugWithFormat:@"authenticated user '%@'", user];
+  
+  /* authentication succeeded */
+  {
+    static NSArray *auth = nil;
+    if (auth == nil) {
+      auth = [[NSArray alloc] initWithObjects:
+                               SoRole_Authenticated, SoRole_Anonymous, nil];
+    }
+    [_ctx setObject:auth forKey:@"SoAuthenticatedRoles"];
+  }
+  return nil;
+}
+
+/* render auth exceptions */
+
+- (BOOL)renderException:(NSException *)_e inContext:(WOContext *)_ctx {
+  if ([_e httpStatus] == 401) {
+    WOResponse *r;
+    NSString   *auth;
+    
+    r = [_ctx response];
+    auth = [NSString stringWithFormat:@"basic realm=\"%@\"", [self authRealm]];
+    [r setStatus:[_e httpStatus] /* unauthorized */];
+    [r setHeader:auth forKey:@"www-authenticate"];
+    return YES;
+  }
+  return NO;
+}
+
+@end /* SoHTTPAuthenticator */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoLookupAssociation.h b/skyrix-sope/NGObjWeb/SoObjects/SoLookupAssociation.h
new file mode 100644 (file)
index 0000000..21cfc3a
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoLookupAssociation_H__
+#define __SoObjects_SoLookupAssociation_H__
+
+#include <NGObjWeb/WOAssociation.h>
+
+/*
+  SoLookupAssociation
+
+  This association is experimental, behaviour isn't fixed yet.
+
+  Namespace: http://www.skyrix.com/od/so-lookup
+*/
+
+@class NSArray;
+
+@interface SoLookupAssociation : WOAssociation
+{
+  NSArray *traversalPath;
+  BOOL    acquire;
+}
+
+/* accessors */
+
+- (NSArray *)traversalPath;
+- (BOOL)doesAcquire;
+
+/* value */
+
+- (BOOL)isValueConstant; // returns NO
+- (BOOL)isValueSettable; // returns NO
+
+@end
+
+#endif /* __SoObjects_SoLookupAssociation_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoLookupAssociation.m b/skyrix-sope/NGObjWeb/SoObjects/SoLookupAssociation.m
new file mode 100644 (file)
index 0000000..dd02198
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoLookupAssociation.h"
+#include "SoObject.h"
+#include <NGObjWeb/WOComponent.h>
+#include "common.h"
+
+@implementation SoLookupAssociation
+
++ (int)version {
+  return [super version] /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithTraversalPath:(NSArray *)_tp acquire:(BOOL)_ac {
+  if ((self = [super init])) {
+    self->traversalPath = [_tp copy];
+    self->acquire = _ac;
+  }
+  return self;
+}
+
+- (id)initWithString:(NSString *)_s {
+  BOOL acq;
+  
+  if ((acq = [_s hasPrefix:@"+"]))
+    _s = [_s substringFromIndex:1];
+  
+  return [self initWithTraversalPath:[_s pathComponents] acquire:acq];
+}
+
+- (void)dealloc {
+  [self->traversalPath release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSArray *)traversalPath {
+  return self->traversalPath;
+}
+- (BOOL)doesAcquire {
+  return self->acquire;
+}
+
+/* value */
+
+- (BOOL)isValueConstant {
+  return NO;
+}
+- (BOOL)isValueSettable {
+  return NO;
+}
+
+/* op */
+
+- (void)setValue:(id)_value inComponent:(WOComponent *)_component {
+  // not settable
+  [NSException raise:@"AssociationException"
+               format:@"association value is not settable !"];
+}
+
+- (id)valueInComponent:(WOComponent *)_component {
+  return [_component traversePathArray:self->traversalPath 
+                    acquire:self->acquire];
+}
+
+@end /* SoLookupAssociation */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjCClass.h b/skyrix-sope/NGObjWeb/SoObjects/SoObjCClass.h
new file mode 100644 (file)
index 0000000..d812b43
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoObjCClass_H__
+#define __SoObjects_SoObjCClass_H__
+
+#include <SoObjects/SoClass.h>
+
+/*
+  This is a concrete SoClass subclass which implements it's methods
+  based on an Objective-C class.
+  
+  ClassName:
+  The name of a SoObjCClass is the same as the name of the backend
+  Objective-C class.
+  
+  Methods:
+  SoClass methods are located by scanning the class methods for
+  selectors ending in "Action", for example "doItAction:".
+  
+  Class-Description:
+  The class description for SoObjCClass'es is located using
+  NSClassDescription.
+  
+  Instantiation:
+  SoObjCClass objects are instantiated using the usual
+  alloc,init,autorelease sequence.
+*/
+
+@interface SoObjCClass : SoClass
+{
+  Class clazz;
+}
+
+- (id)initWithSoSuperClass:(SoClass *)_soClass class:(Class)_clazz;
+
+/* accessors */
+
+- (NSString *)className;
+- (Class)objcClass;
+
+/* scan the class for actions (need to rescan after bundles are loaded) */
+
+- (void)rescanClass;
+
+@end
+
+#endif /* __SoObjects_SoObjCClass_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjCClass.m b/skyrix-sope/NGObjWeb/SoObjects/SoObjCClass.m
new file mode 100644 (file)
index 0000000..0d045f4
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoObjCClass.h"
+#include "SoSelectorInvocation.h"
+#include <NGExtensions/NGObjCRuntime.h>
+#include <NGExtensions/NSString+Ext.h>
+#include "common.h"
+
+@implementation SoObjCClass
+
+- (id)initWithSoSuperClass:(SoClass *)_soClass class:(Class)_clazz {
+  NSAssert(_clazz, @"missing ObjC class parameter !");
+  if ((self = [super initWithSoSuperClass:_soClass])) {
+    self->clazz = _clazz;
+  }
+  return self;
+}
+- (id)initWithSoSuperClass:(SoClass *)_soClass {
+  return [self initWithSoSuperClass:_soClass class:nil];
+}
+
+- (void)rescanClass {
+  NSMutableDictionary *prefixMap;
+  NSEnumerator *e;
+  NSString *methodName;
+  
+  prefixMap = [[NSMutableDictionary alloc] initWithCapacity:32];
+  
+  [self debugWithFormat:@"scanning ObjC class %@ for SoObject methods ...",
+         NSStringFromClass(self->clazz)];
+  e = [self->clazz methodNameEnumerator];
+  while ((methodName = [e nextObject])) {
+    SoSelectorInvocation *invocation;
+    NSString *methodPrefix;
+    NSRange  r;
+    unsigned len;
+    
+    if ((len = [methodName length]) < 6)
+      continue;
+    
+    r = [methodName rangeOfString:@"Action"];
+    if (r.length == 0) continue;
+    
+    methodPrefix = [methodName substringToIndex:(r.location + r.length)];
+    
+    if ((r.location + r.length) > len) {
+      /* something is beyond the xxxAction, *must* be followed by a colon */
+      if ([methodName characterAtIndex:(r.location + r.length)] != ':')
+       continue;
+    }
+    
+    [self debugWithFormat:@"  found an action: %@", methodName];
+    
+    if ((invocation = [prefixMap objectForKey:methodPrefix]) == nil) {
+      invocation = [[SoSelectorInvocation alloc] init];
+      [prefixMap setObject:invocation forKey:methodPrefix];
+      [invocation release];
+    }
+    [invocation addSelectorNamed:methodName];
+  }
+  
+  e = [prefixMap keyEnumerator];
+  while ((methodName = [e nextObject])) {
+    SoSelectorInvocation *inv;
+    NSString *slotName;
+    
+    slotName = [methodName hasSuffix:@"Action"]
+      ? [methodName substringToIndex:([methodName length] - 6)]
+      : methodName;
+    inv = [prefixMap objectForKey:methodName];
+    [self setValue:inv forSlot:slotName];
+  }
+}
+
+/* factory */
+
+- (id)instantiateObject {
+  return [[[self->clazz alloc] init] autorelease];
+}
+
+- (NSClassDescription *)soClassDescription {
+  return [NSClassDescription classDescriptionForClass:self->clazz];
+}
+
+- (NSString *)className {
+  return NSStringFromClass(self->clazz);
+}
+- (Class)objcClass {
+  return self->clazz;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self,
+        NSStringFromClass((Class)*(void**)self)];
+  
+  if (self->soSuperClass)
+    [ms appendFormat:@" super=0x%08X", self->soSuperClass];
+  else
+    [ms appendString:@" root"];
+
+  if (self->clazz)
+    [ms appendFormat:@" objc=%@", NSStringFromClass(self->clazz)];
+  else
+    [ms appendString:@" <no-objc-class>"];
+  
+  if ([self->slots count] > 0) {
+    [ms appendFormat:@" slots=%@", 
+         [[self->slots allKeys] componentsJoinedByString:@","]];
+  }
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@"[so-objc-class:%@]", 
+                    NSStringFromClass(self->clazz)];
+}
+- (BOOL)isDebuggingEnabled {
+  static int debugOn = -1;
+  if (debugOn == -1) {
+    debugOn = [[NSUserDefaults standardUserDefaults]
+               boolForKey:@"SoObjCClassDebugEnabled"] ? 1 : 0;
+  }
+  return debugOn ? YES : NO;
+}
+
+@end /* SoObjCClass */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObject+Traversal.m b/skyrix-sope/NGObjWeb/SoObjects/SoObject+Traversal.m
new file mode 100644 (file)
index 0000000..46f3921
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "SoObjectRequestHandler.h"
+#include "SoObject.h"
+#include "SoSecurityManager.h"
+#include "WOContext+SoObjects.h"
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+/*
+  The implementation for HTTP path traversion, just uses lookupKey
+  of SoObject.
+
+  The traverseKey:inContext: basically reflects Zope's __bobo_traverse__()
+  method. But __bobo_traverse__ can return a tuple with a set of objects
+  to be inserted in the traversion path (what is that good for ?).
+  
+  Zope has an additional __before_publishing_traverse__() which is called
+  before traversion. This is used to change requests and supposed to be
+  useful for virtual hosting and special authentication controls. (need a
+  specific example why a special method is required for that)
+*/
+
+@implementation NSObject(SoObjectLookup)
+
+static int debugTraversal = -1;
+static BOOL _isDebugOn(void) {
+  if (debugTraversal == -1) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    debugTraversal = [ud boolForKey:@"SoDebugObjectTraversal"] ? 1 : 0;
+  }
+  return debugTraversal;
+}
+
+- (id)traverseKey:(NSString *)_key inContext:(id)_ctx {
+  /* this corresponds to Zope's __bobo_traverse__() */
+  return [self lookupName:_key inContext:_ctx acquire:NO];
+}
+
+/* path traversion */
+
+- (id)handleValidationError:(NSException *)_error 
+  duringTraveralOfKey:(NSString *)_key
+  inContext:(id)_ctx 
+{
+  if (_isDebugOn()) {
+    [self debugWithFormat:@"traversal validation error for key '%@':", _key];
+    [self debugWithFormat:@"  error:  %@", [_error name]];
+    [self debugWithFormat:@"  reason: %@", [_error reason]];
+  }
+  return nil;
+}
+
+- (id)traverseKey:(NSString *)_name
+  inContext:(id)_ctx
+  error:(NSException **)_error
+  acquire:(BOOL)_acquire
+{
+  SoSecurityManager *sm;
+  id obj;
+  
+  if (_isDebugOn()) {
+    [self debugWithFormat:@"traverse key '%@' (acquire=%s) ..",
+           _name, _acquire ? "yes" : "no"];
+  }
+  
+  /* check access right */
+  
+  if ((*_error = [self validateName:_name inContext:_ctx])) {
+    /* not allowed ! */
+    if (debugTraversal)
+      [self debugWithFormat:@"  key '%@' did not validate !", _name];
+    return nil;
+  }
+  
+  /* lookup in object (and acquire from strict parents) */
+  
+  sm = [_ctx soSecurityManager];
+  if ((obj = [self traverseKey:_name inContext:_ctx])) {
+    *_error = [sm validateValue:obj forName:_name ofObject:self inContext:_ctx];
+    if (*_error) {
+      /* not allowed ! */
+      if (debugTraversal)
+       [self debugWithFormat:@"  value of key '%@' did not validate !",_name];
+      return nil;
+    }
+    
+    if (debugTraversal)
+      [self debugWithFormat:@"  key '%@' resolved: %@", _name, obj];
+    return obj;
+  }
+  
+  if (_acquire) {
+    /* now try to acquire from parents in URL path */
+    NSEnumerator *e;
+
+    if (debugTraversal) {
+      [self debugWithFormat:@"  try to acquire key '%@' from traversal stack",
+             _name];
+    }
+    
+    e = [[_ctx objectTraversalStack] reverseObjectEnumerator];
+    while ((obj = [e nextObject])) {
+      NSException *e;
+      
+      if ((e = [obj validateName:_name inContext:_ctx])) {
+       /* access restriction */
+       *_error = e;
+       return nil;
+      }
+      
+      if ((obj = [obj traverseKey:_name inContext:_ctx])) {
+       /* found .. */
+       e = [sm validateValue:obj forName:_name 
+               ofObject:self inContext:_ctx];
+       if (e) {
+         *_error = e;
+         return nil;
+       }
+       return obj;
+      }
+    }
+  }
+  else {
+    if (debugTraversal)
+      [self debugWithFormat:@"  acquisition disabled."];
+  }
+  
+  /* did not find object ... */
+  if (_isDebugOn())
+    [self debugWithFormat:@"  lookup of key '%@' failed.", _name];
+  return nil;
+}
+
+- (id)traversePathArray:(NSArray *)traversalPath
+  inContext:(id)_ctx
+  error:(NSException **)_error
+  acquire:(BOOL)_acquire
+{
+  register BOOL doDebug = _isDebugOn();
+  WORequest *rq;
+  BOOL      isCreateIfMissingMethod = NO;
+  BOOL      isCreateMethod = NO;
+  unsigned  i, count;
+  id        root, currentObject, clientObject;
+  
+  if (doDebug) {
+    [self logWithFormat:@"traverse%s: %@",
+           _acquire ? "(acquire)" : "",
+           [traversalPath componentsJoinedByString:@" => "]];
+  }
+  
+  /* reset error */
+  if (_error) *_error = nil;
+  
+  if ((rq = [(id <WOPageGenerationContext>)_ctx request])) {
+    /* isn't that somewhat hackish, directly accessing the HTTP method? */
+    NSString *m;
+    
+    if ((m = [rq method])) {
+      if ([m isEqualToString:@"PUT"])
+       isCreateIfMissingMethod = YES;
+      else if ([m isEqualToString:@"PROPPATCH"])
+       isCreateIfMissingMethod = YES;
+      else if ([m isEqualToString:@"MKCOL"])
+       /* this one is strictly creating */
+       isCreateMethod = YES;
+      // TODO: the following are only create-if-missing on the target!
+      else if ([m isEqualToString:@"MOVE"] ||
+              [m isEqualToString:@"COPY"]) {
+       isCreateIfMissingMethod = 
+         [[(WOContext *)_ctx objectForKey:@"isDestinationPathLookup"] 
+                              boolValue];
+      }
+    }
+  }
+  
+  root          = self;
+  currentObject = self;
+  clientObject  = nil;
+  [_ctx addObjectToTraversalStack:currentObject];
+  
+  /* do traversion */
+  
+  for (i = 0, count = [traversalPath count]; i < count; i++) {
+    NSException *error = nil;
+    NSString    *name;
+    id          nextObject = nil;
+    
+    /* get next name */
+    name = [traversalPath objectAtIndex:i];
+    if (doDebug) [self logWithFormat:@"  do traverse name: '%@'", name];
+    if ([name length] == 0)
+      /* empty name ?, ignore */
+      continue;
+    
+    if ([name isEqualToString:@"/"])
+      /* ignore root */
+      continue;
+    
+    if (i == (count - 1)) {
+      /* 
+        is last object, special handling for MKCOL, with MKCOL queries
+        the last part of the URI is a collection to be created and not
+        yet in the object tree ...
+      */
+      // TODO: should check whether the resource exists, but access is denied
+      if (isCreateMethod) {
+       [_ctx setPathInfo:name];
+        if (doDebug)
+         [self logWithFormat:@"create-method: PATH_INFO: %@", name];
+       break;
+      }
+    }
+    
+    /* lookup next object */
+    
+    nextObject = [currentObject traverseKey:name inContext:_ctx error:&error
+                               acquire:_acquire];
+    if (nextObject == nil) {
+      if (doDebug) {
+       [self logWithFormat:@"  traverse miss: name=%@%s: i=%i,count=%i", 
+               name, _acquire ? ", acquire" : "", i, count];
+      }
+      if (i == (count - 1)) {
+       /* 
+          Is last object, special handling for PUT, with PUT queries
+          the last part of the URI is allowed to be missing. If this
+          is the case, the PUT is actually a "creation" operation.
+          The same goes for PROPPATCH.
+       */
+       // should check whether the resource exists, but access is denied
+       if (isCreateIfMissingMethod) {
+         [_ctx setPathInfo:name];
+         if (doDebug)
+           [self logWithFormat:@"create-if-missing: PATH_INFO: %@", name];
+         break;
+       }
+       if (doDebug) [self logWithFormat:@"    miss is last object."];
+      }
+      
+      if (error) {
+       if (doDebug) [self logWithFormat:@"    handle miss error: %@", error];
+       currentObject = [currentObject handleValidationError:error 
+                                      duringTraveralOfKey:name
+                                      inContext:_ctx];
+       if (currentObject == nil) {
+         if (_error) 
+           *_error = error;
+         else
+           currentObject = error;
+         break;
+       }
+       if (doDebug) [self logWithFormat:@"    miss error continues ..."];
+      }
+      if (doDebug) [self logWithFormat:@"    got no error for miss."];
+    }
+    
+    /* check whether the current object is executable */
+    /*
+      TODO: why did I add this check?, we cannot break on the first 
+            executable, otherwise we cannot use methods on methods!
+      So:   but we can break if the nextObject could not be found, so
+            that we can generate a proper pathinfo!
+    */
+    
+    if (nextObject == nil && [currentObject isCallable]) {
+      NSArray *piArray;
+      NSRange r;
+      
+      r.location = i;
+      r.length   = (count - i);
+      piArray = [traversalPath subarrayWithRange:r];
+      if (doDebug) [self logWithFormat:@"PATH_INFO: %@", piArray];
+      [_ctx setPathInfo:[piArray componentsJoinedByString:@"/"]];
+      break;
+    }
+    else if (nextObject == nil && doDebug) {
+      [self logWithFormat:
+             @"Note: next object is nil, but currentObject "
+             @"is not callable: %@",
+             currentObject];
+    }
+    
+    /* found an object */
+    currentObject = nextObject;
+    [_ctx addObjectToTraversalStack:currentObject];
+  }
+  
+  /* fill clientObject */
+  
+  if ([currentObject isCallable]) {
+    unsigned count;
+    NSArray  *tstack;
+    
+    tstack = [_ctx objectTraversalStack];
+    count  = [tstack count];
+    if (count > 2)
+      clientObject = [tstack objectAtIndex:(count - 2)];
+  }
+  else
+    clientObject = currentObject;
+  
+  if (clientObject) {
+    if (doDebug)
+      [self logWithFormat:@"set clientObject: %@", clientObject];
+    [_ctx setClientObject:clientObject];
+  }
+  
+  /* return result */
+  return currentObject;
+}
+
+- (id)traversePathArray:(NSArray *)_tp acquire:(BOOL)_acquire {
+  NSAutoreleasePool *pool;
+  NSException *error = nil;
+  WOContext   *context;
+  id          result;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    // TODO: shouldn't we use a "subcontext"?
+    context = [WOContext context];
+  
+    result = [self traversePathArray:_tp
+                  inContext:context
+                  error:&error
+                  acquire:_acquire];
+    result = error ? [error retain] : [result retain];
+  }
+  [pool release];
+
+  return [result autorelease];
+}
+
+- (id)traversePath:(id)_tp acquire:(BOOL)_acquire {
+  if (![_tp isNotNull]) return nil;
+  
+  if ([_tp isKindOfClass:[NSArray class]])
+    return [self traversePathArray:_tp acquire:_acquire];
+  
+  if ([_tp isKindOfClass:[NSString class]])
+    return [self traversePathArray:[_tp pathComponents] acquire:_acquire];
+  
+  if ([_tp respondsToSelector:@selector(objectEnumerator)]) {
+    _tp = [[[NSArray alloc] initWithObjectsFromEnumerator:_tp] autorelease];
+    return [self traversePathArray:_tp acquire:_acquire];
+  }
+  
+  [self logWithFormat:
+         @"ERROR(%s): don't know how to turn path object %@ into an array",
+         __PRETTY_FUNCTION__, _tp];
+  return nil;
+}
+
+@end /* NSObject(SoObjectLookup) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObject.h b/skyrix-sope/NGObjWeb/SoObjects/SoObject.h
new file mode 100644 (file)
index 0000000..fd8fe05
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __SoObjects_SoObject_H__
+#define __SoObjects_SoObject_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  This mostly defines a new KVC interface on NSObject. The major difference
+  to KVC is, that KVC calls method keys while SoObjectLookup returns an
+  invocation object.
+  It also introduces a new "class" hierachy used for "web" methods and classes
+  that basically mirrors the Python object system (where ivars and methods are
+  both "attributes").
+*/
+
+@class NSString, NSException, NSClassDescription, NSArray;
+@class SoClass, SoClassSecurityInfo;
+
+@interface NSObject(SoObject)
+
+/* classes */
+
++ (SoClass *)soClass;
+- (SoClass *)soClass;
++ (SoClassSecurityInfo *)soClassSecurityInfo;
+- (NSClassDescription *)soClassDescription;
+
+/* basic names */
+
+- (BOOL)hasName:(NSString *)_key  inContext:(id)_ctx;
+- (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag;
+- (NSException *)validateName:(NSString *)_key inContext:(id)_ctx;
+
+/* invocation */
+
+- (BOOL)isCallable;
+- (id)clientObject;
+- (id)callOnObject:(id)_client inContext:(id)_ctx;
+- (NSString *)defaultMethodNameInContext:(id)_ctx;
+- (id)lookupDefaultMethod;
+
+/* binding (returns self by default [unbound objects]) */
+
+- (id)bindToObject:(id)_object inContext:(id)_ctx;
+
+/* security */
+
+- (NSString *)ownerInContext:(id)_ctx;
+- (id)authenticatorInContext:(id)_ctx;
+
+/* containment */
+
+- (id)container;
+- (void)detachFromContainer;
+- (NSString *)nameInContainer;
+- (NSArray *)objectContainmentStack;
+- (NSArray *)pathArrayToSoObject;
+- (NSArray *)reversedPathArrayToSoObject;
+
+- (NSString *)baseURLInContext:(id)_ctx;
+- (NSString *)rootURLInContext:(id)_ctx;
+
+@end
+
+@interface NSObject(SoObjectLookup)
+
+/* your object can override this methods to use specialized lookup */
+
+- (id)traverseKey:(NSString *)_key inContext:(id)_ctx;
+
+/* traversal implementation */
+
+- (id)handleValidationError:(NSException *)_error 
+  duringTraveralOfKey:(NSString *)_key
+  inContext:(id)_ctx;
+- (id)traverseKey:(NSString *)_name
+  inContext:(id)_ctx
+  error:(NSException **)_error
+  acquire:(BOOL)_acquire;
+
+- (id)traversePathArray:(NSArray *)traversalPath
+  inContext:(id)_ctx
+  error:(NSException **)_error
+  acquire:(BOOL)_acquire;
+
+/*
+  The following is a convenience method, it creates a context for
+  traversal and returns the error as the result - the right thing
+  for all "custom" lookups.
+*/
+- (id)traversePath:(id)_tp acquire:(BOOL)_acquire;
+- (id)traversePathArray:(NSArray *)_tp acquire:(BOOL)_acquire;
+
+@end
+
+#endif /* __SoObjects_SoObject_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObject.m b/skyrix-sope/NGObjWeb/SoObjects/SoObject.m
new file mode 100644 (file)
index 0000000..337ae90
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoObject.h"
+#include "SoClassRegistry.h"
+#include "SoClass.h"
+#include "SoSecurityManager.h"
+#include <EOControl/EOClassDescription.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+@interface NSObject(Folders)
+- (BOOL)isFolderish;
+@end
+
+static NSString *SoRootURLVarKey = @"SoRootURL";
+
+@implementation NSObject(SoObject)
+
+static int debugLookup  = -1;
+static int debugBaseURL = -1;
+static void _initialize(void) {
+  if (debugLookup == -1) {
+    debugLookup = [[NSUserDefaults standardUserDefaults]
+                                  boolForKey:@"SoDebugKeyLookup"] ? 1 : 0;
+  }
+  if (debugBaseURL == -1) {
+    debugBaseURL = [[NSUserDefaults standardUserDefaults]
+                                    boolForKey:@"SoDebugBaseURL"] ? 1 : 0;
+  }
+}
+
+/* classes */
+
++ (SoClass *)soClass {
+  static SoClassRegistry *registry = nil; // THREAD
+  if (registry == nil)
+    registry = [[SoClassRegistry sharedClassRegistry] retain];
+  return [registry soClassForClass:self];
+}
+- (SoClass *)soClass {
+  return [[self class] soClass];
+}
+- (NSString *)soClassName {
+  return [[self soClass] className];
+}
+
++ (SoClassSecurityInfo *)soClassSecurityInfo {
+  return [[self soClass] soClassSecurityInfo];
+}
+
+- (NSClassDescription *)soClassDescription {
+  return [[self soClass] soClassDescription];
+}
+
+/* invocation */
+
+- (BOOL)isCallable {
+  return NO;
+}
+- (id)clientObject {
+  return self;
+}
+
+- (id)callOnObject:(id)_client inContext:(id)_ctx {
+  return nil;
+}
+
+- (NSString *)defaultMethodNameInContext:(id)_ctx {
+  return @"index";
+}
+- (id)lookupDefaultMethod {
+  id ctx = nil;
+  
+  // TODO: lookupDefaultMethod should be rewritten to take a context!
+  ctx = [[WOApplication application] context];
+
+  // TODO: we might want to return a redirect?!
+  
+  return [self lookupName:[self defaultMethodNameInContext:ctx]
+              inContext:ctx
+              acquire:YES];
+}
+
+/* keys */
+
+- (BOOL)hasName:(NSString *)_key inContext:(id)_ctx {
+  /* this corresponds to Zope's/Pythons __hasattr__() */
+  if ([[self soClass] hasKey:_key inContext:_ctx])
+    return YES;
+  if ([[self toOneRelationshipKeys] containsObject:_key])
+    return YES;
+  return NO;
+}
+
+- (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
+  /* this corresponds to Zope's/Pythons __getattr__() */
+  id value;
+  _initialize();
+  
+  if (debugLookup)
+    [self debugWithFormat:@"lookup key '%@'", _key];
+  
+  /* we might want to cache class methods ? */
+  if ((value = [[self soClass] lookupKey:_key inContext:_ctx]) == nil) {
+    if (debugLookup) {
+      [self logWithFormat:@"  did not find key '%@' in SoClass: %@", 
+              _key, [self soClass]];
+    }
+    
+    if ([[self toOneRelationshipKeys] containsObject:_key]) {
+      if (debugLookup) {
+       [self logWithFormat:
+                @"  %@ is a toOneRelationshipKey (use -valueForKey:)", _key];
+      }
+      value = [self valueForKey:_key];
+    }
+  }
+  
+  if (value) {
+    if ((value = [value bindToObject:self inContext:_ctx]) == nil) {
+      if (debugLookup)
+        [self logWithFormat:@"  value from class did not bind: %@", 
+             [self soClass]];
+      return nil;
+    }
+  }
+  else if (_flag) { /* try to acquire from container */
+    if (debugLookup)
+      [self logWithFormat:@"  try to acquire %@ from container ...", _key];
+    value = [[self container] lookupName:_key inContext:_ctx acquire:YES];
+  }
+  
+  if (debugLookup) [self logWithFormat:@"  looked up value: %@", value];
+  return value;
+}
+
+- (NSException *)validateName:(NSString *)_key inContext:(id)_ctx {
+  static SoSecurityManager *sm = nil;
+  if (sm == nil) sm = [[SoSecurityManager sharedSecurityManager] retain];
+  return [sm validateName:_key ofObject:self inContext:_ctx];
+}
+
+/* binding */
+
+- (id)bindToObject:(id)_object inContext:(id)_ctx {
+  return self;
+}
+
+/* security */
+
+- (NSString *)ownerInContext:(id)_ctx {
+  /* objects are not owned by default, suggest to inherit owner */
+  return [[self container] ownerInContext:_ctx];
+}
+- (id)authenticatorInContext:(id)_ctx {
+  return [[_ctx application] authenticatorInContext:_ctx];
+}
+
+/* containment */
+
+- (id)container {
+  return nil;
+}
+- (void)detachFromContainer {
+}
+- (NSString *)nameInContainer {
+  return nil;
+}
+
+- (NSArray *)objectContainmentStack {
+  NSMutableArray *ma;
+  id object;
+  
+  if ((object = [self container]) == nil)
+    /* this is root */
+    return [NSArray arrayWithObject:self];
+  
+  ma = [[NSMutableArray alloc] initWithCapacity:16];
+  for (object = self; object; object = [object container])
+    [ma insertObject:(object ? object : (id)[NSNull null]) atIndex:0];
+
+  object = [ma shallowCopy];
+  [ma release];
+  return [object autorelease];
+}
+
+- (NSArray *)reversedPathArrayToSoObject {
+  NSMutableArray *ma;
+  id object, nextObject;
+  
+  if ((object = [self container]) == nil)
+    /* this is root */
+    return [NSArray array];
+  
+  ma = [NSMutableArray arrayWithCapacity:16];
+  for (object = self; (nextObject = [object container]); object = nextObject) {
+    NSString *oname;
+    
+    oname = [object nameInContainer];
+    [ma addObject:(oname ? oname : (id)[NSNull null])];
+  }
+  return ma;
+}
+- (NSArray *)pathArrayToSoObject {
+  NSArray      *pathArray;
+  NSEnumerator *e;
+  
+  if ((pathArray = [self reversedPathArrayToSoObject]) == nil)
+    return nil;
+  
+  e = [pathArray reverseObjectEnumerator];
+  pathArray = [[[NSArray alloc] initWithObjectsFromEnumerator:e] autorelease];
+  return pathArray;
+}
+
+- (NSString *)baseURLInContext:(id)_ctx {
+  NSString *baseURL;
+  id parent;
+  _initialize();
+  
+  // TODO: should we check the traversal path?
+  
+  if ((parent = [self container]) != nil) {
+    /* Note: cannot use -stringByAppendingPathComponent: on OSX! */
+    NSString *name;
+    
+    if (parent == self) {
+      [self logWithFormat:
+             @"WARNING: container==object in baseURL calculation (loop?): %@",
+             self];
+    }
+    
+    baseURL = [parent baseURLInContext:_ctx];
+    if (![baseURL hasSuffix:@"/"])
+      baseURL = [baseURL stringByAppendingString:@"/"];
+    
+    name    = [[self nameInContainer] stringByEscapingURL];
+    baseURL = [baseURL stringByAppendingString:name];
+    
+    if (debugBaseURL) {
+      [self logWithFormat:@"baseURL(%@,%@): %@", 
+              [self nameInContainer], [[self container] baseURL], baseURL];
+    }
+  }
+  else {
+    baseURL = [self rootURLInContext:_ctx];
+    if (debugBaseURL) {
+      [self logWithFormat:@"ROOT baseURL(no container, name=%@): %@", 
+              [self nameInContainer], baseURL];
+    }
+  }
+  
+  /* add a trailing slash for folders */
+  
+  if (![baseURL hasSuffix:@"/"]) {
+    if ([self respondsToSelector:@selector(isFolderish)]) {
+      if ([self isFolderish])
+       baseURL = [baseURL stringByAppendingString:@"/"];
+    }
+  }
+  
+  return baseURL;
+}
+- (NSString *)rootURLInContext:(id)_ctx {
+  NSMutableString *ms;
+  BOOL      isHTTPS = NO; // TODO: what about https??
+  NSString  *rootURL;
+  WORequest *rq;
+  NSString  *rh, *tmp;
+  int       port;
+  _initialize();
+  
+  if ((rootURL = [(WOContext *)_ctx objectForKey:SoRootURLVarKey]) != nil) {
+    if (debugBaseURL) {
+      [self logWithFormat:@"  using root-url from context (SoRootURL): %@",
+              rootURL];
+    }
+    return rootURL;
+  }
+
+  // TODO: this is somewhat weird, why don't we use WOContext for URL gen.?
+  
+  rq   = [(WOContext *)_ctx request];
+  port = [[rq headerForKey:@"x-webobjects-server-port"] intValue];
+  
+  /* TODO: how to handle Evolution bug which sends invalid port ? */
+  if (port == 0) {
+    static BOOL didWarn = NO;
+    if (!didWarn) {
+      [self logWithFormat:
+             @"WARNING(%s:%i): got an empty port, probably buggy "
+             @"SOUP host header!",
+             __PRETTY_FUNCTION__, __LINE__];
+      didWarn = YES;
+    }
+    port = 23000;
+  }
+
+  ms = [[NSMutableString alloc] initWithCapacity:128];
+  
+  if ((tmp = [rq headerForKey:@"host"])) { 
+    /* check whether we have a host header with port */
+    if ([tmp rangeOfString:@":"].length == 0)
+      tmp = nil;
+  }
+
+  if (tmp) {
+    isHTTPS = 
+      [[rq headerForKey:@"x-webobjects-server-url"] hasPrefix:@"https"];
+    [ms appendString:isHTTPS ? @"https://" : @"http://"]; 
+    [ms appendString:tmp];
+  }
+  else if ((tmp = [rq headerForKey:@"x-webobjects-server-url"])) {
+    /* sometimes the URL is just wrong! (suggests port 80) */
+    if ([tmp hasSuffix:@":0"] && [tmp length] > 2) // TODO: bad bad bad
+      tmp = [tmp substringToIndex:([tmp length] - 2)];
+    [ms appendString:tmp];
+  }
+  else {
+    [ms appendString:isHTTPS ? @"https://" : @"http://"]; 
+  
+    [ms appendString:[rq headerForKey:@"x-webobjects-server-name"]];
+    if ((isHTTPS ? (port != 443) : (port != 80)) && port != 0)
+      [ms appendFormat:@":%i", port];
+  }
+  if (![ms hasSuffix:@"/"]) [ms appendString:@"/"];
+  
+  /* appname, two cases: */
+  /*   a) direct access,  eg /MyFolder */
+  /*   b) access via app, eg /MyApp/so/MyFolder */
+  [ms appendString:[rq applicationName]];
+  [ms appendString:@"/"];
+  
+  /* done */
+  rootURL = [[ms copy] autorelease];
+  [ms release];
+  if (debugBaseURL)
+    [self logWithFormat:@"  constructed root-url: %@", rootURL];
+  
+  /* some hack for the request handler? */
+  rh = [rq requestHandlerKey];
+  if ([[[_ctx application] registeredRequestHandlerKeys] containsObject:rh])
+    rootURL = [rootURL stringByAppendingFormat:@"%@/", rh];
+  
+  if (debugBaseURL) {
+    [self logWithFormat:@"  setting root-url in context (SoRootURL): %@",
+           rootURL];
+  }
+  [(WOContext *)_ctx setObject:rootURL forKey:SoRootURLVarKey];
+  return rootURL;
+}
+
+- (NSString *)baseURL {
+  /* you should use the context method ! */
+  return [self baseURLInContext:[[WOApplication application] context]];
+}
+
+@end /* NSObject(SoObject) */
+
+@implementation WOApplication(Authenticator)
+
+- (NSString *)ownerInContext:(id)_ctx {
+  /* objects are not owned by default */
+  return nil;
+}
+- (id)authenticatorInContext:(id)_ctx {
+  return nil;
+}
+
+@end /* WOApplication(Authenticator) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjectMethodDispatcher.h b/skyrix-sope/NGObjWeb/SoObjects/SoObjectMethodDispatcher.h
new file mode 100644 (file)
index 0000000..7567ff4
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoObjectMethodDispatcher_H__
+#define __SoObjects_SoObjectMethodDispatcher_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoObjectMethodDispatcher
+
+  This dispatcher translates HTTP calls into SoObject method calls. It's
+  the default dispatcher for interacting with browsers.
+  
+  Turn on advanced logging using: SoObjectMethodDispatcherDebugEnabled
+*/
+
+@class WOContext;
+
+@interface SoObjectMethodDispatcher : NSObject
+{
+  id object;
+}
+
+- (id)initWithObject:(id)_object;
+
+/* dispatch */
+
+- (id)dispatchInContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoObjectMethodDispatcher_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjectMethodDispatcher.m b/skyrix-sope/NGObjWeb/SoObjects/SoObjectMethodDispatcher.m
new file mode 100644 (file)
index 0000000..ddc70e3
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoObjectMethodDispatcher.h"
+#include "SoObject.h"
+#include "SoClass.h"
+#include "SoObjectRequestHandler.h"
+#include "WOContext+SoObjects.h"
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOElement.h>
+#include "common.h"
+
+@implementation SoObjectMethodDispatcher
+
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+
+  debugOn = [ud boolForKey:@"SoObjectMethodDispatcherDebugEnabled"];
+}
+
+- (id)initWithObject:(id)_object {
+  if ((self = [super init])) {
+    self->object = [_object retain];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->object release];
+  [super dealloc];
+}
+
+/* perform dispatch */
+
+- (id)dispatchInContext:(WOContext *)_ctx {
+  NSAutoreleasePool *pool;
+  WORequest *rq;
+  id clientObject;
+  id methodObject;
+  id resultObject;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  rq   = [_ctx request];
+  
+  /* find client object */
+  
+  if ((clientObject = [_ctx clientObject])) {
+    if (debugOn)
+      [self debugWithFormat:@"client object set in ctx: %@", clientObject];
+  }
+  else if ((clientObject = [self->object clientObject])) {
+    if (debugOn)
+      [self debugWithFormat:@"setting client object: %@", clientObject];
+    [_ctx setClientObject:clientObject];
+  }
+  
+  // TODO: should check XML-RPC !!! 
+  //       (hm, why ? XML-RPC is handled by other dispatcher ?)
+  
+  /* find callable (method) object */
+  
+  if ([self->object isCallable]) {
+    if (debugOn)
+      [self debugWithFormat:@"traversed object is callable: %@", self->object];
+    methodObject = self->object;
+  }
+  else if ([[self->object soClass] hasKey:[rq method] inContext:_ctx]) {
+    // TODO: I'm not sure whether this step is correct
+    /* the class has a GET method */
+    methodObject = [self->object lookupName:[rq method] 
+                                inContext:_ctx
+                                acquire:NO];
+  }
+  else {
+    // TODO: should we replace the methodObject with a redirect to the
+    //       default method name? This would ensure proper URLs
+    methodObject = [self->object lookupDefaultMethod];
+    if (debugOn)
+      [self debugWithFormat:@"using default method: %@", methodObject];
+  }
+  
+  /* apply arguments */
+    
+  if ([methodObject respondsToSelector:
+                     @selector(takeValuesFromRequest:inContext:)]) {
+    if (debugOn)
+      [self debugWithFormat:@"applying values from request ..."];
+    [methodObject takeValuesFromRequest:rq inContext:_ctx];
+  }
+
+  /* perform call */
+    
+  if (methodObject == nil || ![methodObject isCallable]) {
+    /*
+      The object is neither callable nor does it have a default method,
+      so we just pass it through.
+    */
+    resultObject = self->object;
+    if (debugOn) {
+      [self debugWithFormat:@"got no method, using object as result: %@", 
+             resultObject];
+    }
+  }
+  else {
+    resultObject = [methodObject callOnObject:[_ctx clientObject]
+                                inContext:_ctx];
+    if (debugOn) {
+      if ([resultObject isKindOfClass:[WOResponse class]]) {
+       [self debugWithFormat:@"call produced response: 0x%08X (code=%i)", 
+               resultObject, [(WOResponse *)resultObject status]];
+      }
+      else
+       [self debugWithFormat:@"call produced result: %@", resultObject];
+    }
+  }
+  
+  resultObject = [resultObject retain];
+  [pool release];
+  
+  /* deliver result */
+  return [resultObject autorelease];
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return @"[obj-mth-dispatch]";
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn ? YES : NO;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self,
+        NSStringFromClass((Class)*(void**)self)];
+  
+  if (self->object)
+    [ms appendFormat:@" object=%@", self->object];
+  else
+    [ms appendString:@" <no object>"];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SoObjectMethodDispatcher */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjectRequestHandler.h b/skyrix-sope/NGObjWeb/SoObjects/SoObjectRequestHandler.h
new file mode 100644 (file)
index 0000000..9363b15
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_SoObjectRequestHandler_H__
+#define __NGObjWeb_SoObjectRequestHandler_H__
+
+#include <NGObjWeb/WORequestHandler.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOCoreApplication.h>
+#import <Foundation/NSObject.h>
+
+/*
+  SoObjectRequestHandler
+  
+  This request handler is used to handle requests by traversing objects.
+  
+  It also defines a new KVC interface on NSObject. The major difference
+  to KVC is, that KVC calls method keys while SoObjectLookup returns an
+  invocation object.
+
+  How objects are "published"
+
+  First how the object is located. The handler starts at it's root instance
+  variable which usually is the global NGObjWeb application object. Then
+  it walks over each path component of the requestHandlerPathArray as
+  returned by WORequest. For each pathcomponent the dispatcher first calls
+  the SoObject validation primitive then the SoObject lookup primitive to
+  find the next object. If an object couldn't be found (the lookup returned
+  nil), an HTTP 404 (Not Found) is returned.
+  Note that the two HTTP methods MKCOL and PUT leave out the last path
+  component during dispatch and insert it as the PATH_INFO in the context.
+
+  Next, the dispatch. Once the object is found a dispatcher is selected. There
+  are basically three dispatchers: method, WebDAV and XML-RPC. Which one is
+  used is determined either using the object if it supports a 
+  -dispatcherForContext: method or selected on request based information
+  otherwise.
+  To trigger WebDAV: use 'dav' as the request handler key. Otherwise heuristics
+  are used to select the DAV dispatcher (most problematic are DAV GET requests)
+  
+  And finally, the rendering. Often a method will return a WOResponse. If this
+  is the case the response is simply delivered. If a method returns an 
+  NSException object, an HTTP error response is generated. Otherwise the
+  renderer looks for -generateResponse and -appendToResponse:inContext: 
+  methods, if this still doesn't work out, -stringValue is used ;-)
+  
+  If all the processing is done, all objects in the traversal stack are sent
+  _sleepWithContext:, -sleep or nothing, depending on what they implement ...
+  
+  Some special form keys:
+    ":method" - like in Zope
+    "Cmd"     - like in ASP
+*/
+
+@class NSString, NSException;
+@class NGRuleContext;
+
+@interface SoObjectRequestHandler : WORequestHandler
+{
+  BOOL          doesNoRequestPathAcquisition;
+  id            rootObject;
+  NGRuleContext *dispatcherRules;
+}
+
+@end
+
+@interface WOCoreApplication(RendererSelection)
+
+- (id)rendererForObject:(id)_object inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __NGObjWeb_SoObjectRequestHandler_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjectRequestHandler.m b/skyrix-sope/NGObjWeb/SoObjects/SoObjectRequestHandler.m
new file mode 100644 (file)
index 0000000..f834599
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoObjectRequestHandler.h"
+#include "SoObject.h"
+#include "SoObjectMethodDispatcher.h"
+#include "SoSecurityManager.h"
+#include "SoDefaultRenderer.h"
+#include "WOContext+SoObjects.h"
+#include "WORequest+So.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOElement.h>
+#include <NGObjWeb/WOTemplate.h>
+#include <NGObjWeb/WEClientCapabilities.h>
+#include <SoOFS/OFSBaseObject.h>
+#include <NGExtensions/NGRuleContext.h>
+#include "WOComponent+private.h"
+#include "common.h"
+
+@interface NSObject(ObjectDispatcher)
+- (id)dispatcherForContext:(WOContext *)_ctx;
+- (WOResponse *)preprocessCredentialsInContext:(WOContext *)_ctx;
+- (void)_sleepWithContext:(WOContext *)_ctx;
+@end
+
+@implementation SoObjectRequestHandler
+
+static BOOL debugOn       = NO;
+static BOOL debugRulesOn  = NO;
+static BOOL disableZLHack = NO;
+
+static Class WOTemplateClass = Nil;
+static NSString *rapidTurnAroundPath = nil;
+
++ (int)version {
+  return [super version] + 0 /* 2 */;
+}
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    NSAssert2([super version] == 2,
+             @"invalid superclass (%@) version %i !",
+             NSStringFromClass([self superclass]), [super version]);
+    debugOn       = [ud boolForKey:@"SoObjectRequestHandlerDebugEnabled"];
+    debugRulesOn  = [ud boolForKey:@"SoObjectRequestHandlerRulesDebugEnabled"];
+    disableZLHack = [ud boolForKey:@"DisableZideLookHack"];
+
+    WOTemplateClass     = [WOTemplate class];
+    rapidTurnAroundPath = [[ud stringForKey:@"WOProjectDirectory"] copy];    
+  }
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->dispatcherRules =
+      [[NGRuleContext ruleContextWithModelInUserDefault:
+                        @"SoRequestDispatcherRules"] retain];
+    if (debugRulesOn) [self->dispatcherRules setDebugEnabled:YES];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->dispatcherRules release];
+  [self->rootObject      release];
+  [super dealloc];
+}
+
+/* type the request */
+
+- (BOOL)isObjectPublishingContext:(WOContext *)_ctx {
+  /* 
+     Find out, whether we should do acquisition and dynamic method publishing.
+     This is only appropriate for HEAD/GET/POST requests from non-WebDAV
+     clients ?
+  */
+  id value;
+  
+  value = [self->dispatcherRules valueForKey:@"useAcquisition"];
+  if (debugRulesOn) [self debugWithFormat:@"acquision: %@", value];
+  return [value boolValue];
+}
+
+/* request path acquisition */
+
+- (BOOL)enableZideLookHack {
+  /* Temporary Hack for ZideLook */
+  return disableZLHack ? NO : YES;
+}
+
+- (BOOL)skipApplicationName {
+  /* is the application name path of a URI part of the traversal path ? */
+  return NO;
+}
+
+- (NSString *)hackZideLookURI:(NSString *)m {
+  if ([m hasPrefix:@"H_chste_Ebene_der_Pers_nlichen_Ordner"]) {
+    m = [m stringByReplacingString:@"H_chste_Ebene_der_Pers_nlichen_Ordner"
+          withString:@"helge"];
+  }
+  else if ([m hasPrefix:@"Suchpfad"]) {
+    m = [m stringByReplacingString:@"Suchpfad"
+          withString:@"helge"];
+  }
+  else if ([m hasPrefix:@"public"]) {
+    /* Evolution query on "/public" */
+    ; // keep it completly
+  }
+  else if ([self skipApplicationName]) {
+    /* cut of appname */
+    NSRange r;
+    r = [m rangeOfString:@"/"];
+    m = [m substringFromIndex:(r.location + r.length)];
+  }
+  return m;
+}
+- (NSString *)hackZideLookName:(NSString *)_p {
+  if ([_p isEqualToString:@"Gel_schte_Objekte"])
+    return @"Trash";
+  return _p;
+}
+
+- (NSMutableArray *)addSpecialFormValuesInRequest:(WORequest *)_rq
+  toTraversalPath:(NSMutableArray *)_traversalPath
+{
+  NSArray  *keys;
+  unsigned i, count;
+  
+  keys = [_rq formValueKeys];
+  if ((count = [keys count]) == 0)
+    return _traversalPath;
+  
+  for (i = 0; i < count; i++) {
+    NSString *key;
+    unsigned klen;
+    NSString *m;
+    
+    key  = [keys objectAtIndex:i];
+    klen = [key length];
+    if (klen != 3 && klen < 7)
+      continue;
+    
+    /* calculate method name */
+    
+    m = nil;
+    if (klen == 3 && [key isEqualToString:@"Cmd"]) {
+      /* 
+        check for ASP style ?Cmd query parameter (required in ZideStore),
+        the value is the additional path we need to add
+      */
+      m = [_rq formValueForKey:key]; // need to unescape somehow ?
+    }
+    else if (klen == 7 && [key isEqualToString:@":method"]) {
+      /* 
+        check for ":method" form value, the value is the additional path we 
+        need to add
+      */
+      m = [_rq formValueForKey:key]; // need to unescape somehow ?
+    }
+    else if ([key hasSuffix:@":method"]) {
+      /*
+       Check for XXX:method form-keys, the value is ignored and the
+       XXX is added to the path. This is useful for binding actions
+       to submit buttons, since the value of a submit button is 
+       displayed as it's label in the browser
+      */
+      klen = klen - 7;
+      m = [key substringToIndex:klen];
+    }
+    
+    /* check calculated method */
+    
+    if (m == nil)
+      continue;
+    else if ([m length] == 0) {
+      [self debugWithFormat:@"empty '%@' query parameter !", key];
+      continue;
+    }
+    
+    /* add to path */
+    [_traversalPath addObject:m];
+  }
+  return _traversalPath;
+}
+
+- (NSArray *)traversalPathFromRequest:(WORequest *)_rq {
+  static NSArray *rqKeys = nil;
+  NSMutableArray *traversalPath;
+  unsigned i, count;
+  NSString *m;
+  NSArray  *a;
+
+  if (rqKeys == nil)
+    /* cache set of registered request handlers */
+    rqKeys = [[[WOApplication application] registeredRequestHandlerKeys] copy];
+  
+  m = [_rq requestHandlerKey];
+  if ([rqKeys containsObject:m]) {
+    /* 
+       If the request-handler-key parsed by WORequest is valid, we'll consider
+       it a "usual" NGObjWeb query. Note that the appname is *not* processed !
+       Example:
+         /MyApp/wo/...   => match
+         /MyApp/bla/...  => fail
+         /blah/wa/...    => match
+    */
+    a = [_rq requestHandlerPathArray];
+  }
+  else {
+    /* TODO: more options, eg allow the appname to be part of the path */
+    NSRange r;
+
+    /* get URI, cut of leading slash */
+    m = [_rq uri];
+    m = [m substringFromIndex:1];
+    
+    if ([self enableZideLookHack]) 
+      m = [self hackZideLookURI:m];
+    else if ([self skipApplicationName]) {
+      /* cut of application name */
+      r = [m rangeOfString:@"/"];
+      m = [m substringFromIndex:(r.location + r.length)];
+    }
+    
+    /* cut of query parameters */
+    r = [m rangeOfString:@"?"];
+    if (r.length > 0)
+      m = [m substringToIndex:r.location];
+    
+    /* split into path components */
+    a = [m componentsSeparatedByString:@"/"];
+  }
+  
+  count = [a count];
+  traversalPath = [NSMutableArray arrayWithCapacity:(count + 1)];
+  for (i = 0; i < count; i++) {
+    NSString *p;
+    
+    p = [a objectAtIndex:i];
+    
+    if ([p hasPrefix:@"_range"])
+      /* a ZideLook range query, further handled by WebDAV dispatcher */
+      continue;
+    
+    p = [p stringByUnescapingURL];
+    
+    if ([self enableZideLookHack])
+      p = [self hackZideLookName:p];
+    
+    if ([p length] > 0)
+      [traversalPath addObject:p];
+  }
+  
+  traversalPath = [self addSpecialFormValuesInRequest:_rq
+                       toTraversalPath:traversalPath];
+  
+  return traversalPath;
+}
+
+- (id)rootObjectForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  id object;
+  
+  if (self->rootObject)
+    return self->rootObject;
+    
+  if ((object = [_ctx application]) == nil)
+    object = [WOApplication application];
+  
+#if 0
+  /* 
+    if we resolve in this location, we won't be able to resolve
+    application names like "Control_Panel".
+  */
+  if ([object respondsToSelector:@selector(rootObjectInContext:)])
+    object = [object rootObjectInContext:_ctx];
+#endif
+  
+  return object;
+}
+
+- (id)lookupObjectForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  NSAutoreleasePool *pool;
+  NSArray     *traversalPath;
+  id currentObject;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    NSException *error = nil;
+    id   root;
+    BOOL doAcquire;
+    
+    /* build traversal path */
+    
+    traversalPath = [self traversalPathFromRequest:_rq];
+    if (traversalPath)
+      [_ctx setSoRequestTraversalPath:traversalPath];
+    
+    /* setup root object */
+    
+    root = [self rootObjectForRequest:_rq inContext:_ctx];
+    
+    doAcquire = self->doesNoRequestPathAcquisition
+      ? NO
+      : [self isObjectPublishingContext:_ctx];
+
+    [self debugWithFormat:@"traverse (%@): %@ %@", 
+            [_rq uri], 
+            [traversalPath componentsJoinedByString:@" => "],
+            doAcquire ? @"[acquires]" : @"(no acquisition)"];
+    
+    currentObject = [root traversePathArray:traversalPath
+                         inContext:_ctx
+                         error:&error
+                         acquire:doAcquire];
+    if (error)
+      currentObject = error;
+    
+    /* retain result */
+    currentObject = [currentObject retain];
+  }
+  [pool release];
+  return [currentObject autorelease];
+}
+
+/* object invocation */
+
+- (id)dispatcherForObject:(id)_object inContext:(WOContext *)_ctx {
+  NSString *dpClass, *rqType;
+  id dispatcher = nil;
+  
+  /* ask object for dispatcher */
+  
+  if ([_object respondsToSelector:@selector(dispatcherForContext:)]) {
+    if ((dispatcher = [_object dispatcherForContext:_ctx]))
+      return dispatcher;
+  }
+  
+  if (debugRulesOn) {
+    [self debugWithFormat:@"select dispatcher using rules: %@", 
+            self->dispatcherRules];
+  }
+  
+  /* query */
+  dpClass = [self->dispatcherRules valueForKey:@"dispatcher"];
+  rqType  = [self->dispatcherRules valueForKey:@"requestType"];
+  if (debugRulesOn) {
+    [self debugWithFormat:@"  selected dispatcher: %@", dpClass];
+    [self debugWithFormat:@"  selected rq-type:    %@", rqType];
+  }
+  
+  /* create dispatcher */
+  
+  if (rqType != nil) [_ctx setSoRequestType:rqType];
+  if ((dispatcher = NSClassFromString(dpClass)) == nil) {
+    [self logWithFormat:@"ERROR: did not find dispatcher class '%@'", dpClass];
+    return nil;
+  }
+  
+  if ((dispatcher = [[dispatcher alloc] initWithObject:_object]))
+    [_ctx setObjectDispatcher:dispatcher];
+  
+  return [dispatcher autorelease];
+}
+
+/* object rendering */
+
+- (WOResponse *)renderObject:(id)_object inContext:(WOContext *)_ctx {
+  SoDefaultRenderer *renderer;
+  NSException  *error;
+  NSEnumerator *e;
+  id container;
+  
+  [self debugWithFormat:@"    render in ctx: %@", _ctx];
+
+  if ([_object isKindOfClass:[WOResponse class]])
+    /* already rendered ... */
+    return _object;
+  
+  /* check whether a container on the traversal stack provides a renderer */
+  
+  renderer = nil;
+  e = [[_ctx objectTraversalStack] reverseObjectEnumerator];
+  while ((container = [e nextObject])) {
+    if (![container respondsToSelector:
+                     @selector(rendererForObject:inContext:)]) {
+      /* does not provide a renderer factory ... */
+      continue;
+    }
+    
+    if ((renderer = [container rendererForObject:_object inContext:_ctx])) {
+      /* the container provided an own renderer for the object */
+      [self debugWithFormat:@"    use container renderer: %@", renderer];
+      break;
+    }
+  }
+  
+  /* if we didn't find a renderer, determine using rules */
+  
+  if (renderer == nil) {
+    NSString *rendererClass;
+    
+    rendererClass = [self->dispatcherRules valueForKey:@"renderer"];
+    if (rendererClass) {
+      Class clazz;
+      
+      if ((clazz = NSClassFromString(rendererClass)) == Nil) {
+        [self logWithFormat:@"did not find class of selected renderer %@", 
+                rendererClass];
+      }
+      else if ((renderer = [clazz sharedRenderer]) == nil) {
+        [self logWithFormat:@"could not get renderer of class %@", 
+                rendererClass];
+      }
+      else if (![renderer canRenderObject:_object inContext:_ctx]) {
+        [self debugWithFormat:@"renderer %@ rejected rendering of object %@", 
+                renderer, _object];
+        renderer = [SoDefaultRenderer sharedRenderer];
+      }
+    }
+    
+    if (renderer)
+      [self debugWithFormat:@"    use rule-selected renderer: %@", renderer];
+  }
+  
+  if (renderer == nil)
+    [self debugWithFormat:@"    found no renderer for object: %@", _object];
+  
+  if ((error = [renderer renderObject:_object inContext:_ctx])) {
+    if (renderer != [SoDefaultRenderer sharedRenderer]) {
+      NSException *e2;
+      
+      e2 = [(SoDefaultRenderer *)[SoDefaultRenderer sharedRenderer] 
+                                 renderObject:error inContext:_ctx];
+      if (e2) {
+        [self logWithFormat:@"default renderer could not render error %@: %@",
+                error, e2];
+        return nil;
+      }
+    }
+    else {
+      [self logWithFormat:@"default renderer returned error: %@", error];
+      return nil;
+    }
+  }
+  return [_ctx response];
+}
+
+- (BOOL)doesRejectFavicon {
+  return NO;
+}
+
+- (WOResponse *)handleRequest:(WORequest *)_rq
+  inContext:(WOContext *)_ctx
+  session:(WOSession *)_sn
+  application:(WOApplication *)app
+{
+  /* split up this big method */
+  WOResponse *r;
+  id object;
+  id authenticator;
+  BOOL doDispatch;
+  
+  if (debugOn) {
+    [self debugWithFormat:@"request 0x%08X: %@ %@ (ctx=0x%08X)", _rq, 
+            [_rq method], [_rq uri], _ctx];
+    if (_sn) [self debugWithFormat:@"  session 0x%08X: %@", _sn, _sn];
+  }
+  
+  /* setup rule context */
+  
+  [self->dispatcherRules reset];
+  [self->dispatcherRules takeValue:_rq           forKey:@"request"];
+  [self->dispatcherRules takeValue:[_rq headers] forKey:@"headers"];
+  [self->dispatcherRules takeValue:[_rq method]  forKey:@"method"];
+  [self->dispatcherRules takeValue:_ctx          forKey:@"context"];
+  
+  /* preprocess authentication credentials with global auth handler */
+  
+  if ((authenticator = [app authenticatorInContext:_ctx])) {
+    [_ctx setObject:authenticator forKey:@"SoAuthenticator"];
+    
+    /* give authenticator the chance to reject invalid credentials */
+    
+    if ((r = [authenticator preprocessCredentialsInContext:_ctx])) {
+      [self->dispatcherRules reset];
+      return r;
+    }
+    
+    [self debugWithFormat:@"authenticator allowed request."];
+  }
+  else {
+    [self debugWithFormat:@"WARNING: no authenticator available."];
+  }
+  
+  /* lookup object */
+  
+  doDispatch = YES;
+  object = [self lookupObjectForRequest:_rq inContext:_ctx];
+  
+  if (object) {
+    [self->dispatcherRules 
+         takeValue:[_ctx clientObject] forKey:@"clientObject"];
+    [self->dispatcherRules takeValue:object forKey:@"object"];
+  }
+  else {
+    r = [_ctx response];
+    [r setStatus:404];
+    [r setHeader:@"text/html" forKey:@"content-type"];
+    [r appendContentString:@"object not found: "];
+    [r appendContentHTMLString:
+        [[_ctx soRequestTraversalPath] componentsJoinedByString:@" => "]];
+    doDispatch = NO;
+    object = r;
+  }
+  
+  /* dispatch object */
+  
+  if ([object isKindOfClass:[NSException class]]) {
+    /* exceptions are not called ... */
+    [self debugWithFormat:@"  not calling exception: %@", object];
+    doDispatch = NO;
+  }
+  
+  if (doDispatch) {
+    id dispatcher;
+    
+    dispatcher = [self dispatcherForObject:object inContext:_ctx];
+    [self debugWithFormat:@"  dispatcher: %@", dispatcher];
+    
+    [self debugWithFormat:@"  dispatch object: %@", object];
+    object = [dispatcher dispatchInContext:_ctx];
+
+    if (object) [self->dispatcherRules takeValue:object forKey:@"result"];
+  }
+  
+  /* render result */
+  
+  if (object == nil) {
+    [self debugWithFormat:@"  got an empty result !"];
+    r = [_ctx response];
+    [r setStatus:500];
+    [r appendContentString:@"the called object returned no result"];
+  }
+  else if ([object isKindOfClass:[WOResponse class]]) {
+    r = object;
+    [self debugWithFormat:
+           @"  got response: 0x%08X (status=%i,len=%@,type=%@)", 
+           r, [r status], 
+           [r headerForKey:@"content-length"],
+           [r headerForKey:@"content-type"]];
+  }
+  else {
+    if (debugOn) {
+      if ([object isKindOfClass:[NSData class]]) {
+       [self debugWithFormat:@"  render data 0x%08X[len=%i]",
+               object, [object length]];
+      }
+      else
+       [self debugWithFormat:@"  render object: %@", object];
+    }
+    
+    [self->dispatcherRules takeValue:object forKey:@"result"];
+    r = [self renderObject:object inContext:_ctx];
+    
+    if (debugOn) {
+      [self debugWithFormat:
+           @"  made response: 0x%08X (status=%i,len=%@,type=%@)", 
+           r, [r status], 
+           [r headerForKey:@"content-length"],
+           [r headerForKey:@"content-type"]];
+    }
+  }
+  
+  /* add header with primary key of new objects (for ZideLook) */
+  if (r != nil) {
+    id key;
+    
+    if ((key = [_ctx objectForKey:@"SxNewObjectID"])) {
+      key = [NSString stringWithFormat:@"%@", key];
+      [r setHeader:key forKey:@"x-skyrix-newname"];
+      [self logWithFormat:@"added new key header to response: '%@'", key];
+    }
+  }
+
+  /* rapid turnaround */
+  if(rapidTurnAroundPath != nil) {
+    WOComponent *page;
+    NSString *_path = nil;
+
+    if((page = [_ctx page])) {
+      WOElement *template;
+          
+      template = [page _woComponentTemplate];
+      if([template isKindOfClass:WOTemplateClass])
+        _path = [[(WOTemplate *)template url] path];
+    }
+    else {
+      if([object isKindOfClass:[OFSBaseObject class]])
+        _path = [object storagePath];
+    }
+    if(_path != nil)
+      [r setHeader:_path forKey:@"x-sope-template-path"];
+  }
+  
+  /* sleep traversal stack */
+  {
+    NSEnumerator *e;
+    id obj;
+    
+    e = [[_ctx objectTraversalStack] reverseObjectEnumerator];
+    while ((obj = [e nextObject])) {
+      if (![obj isNotNull])
+       continue;
+      
+      if ([obj respondsToSelector:@selector(_sleepWithContext:)])
+       [obj _sleepWithContext:_ctx];
+      else if ([obj respondsToSelector:@selector(sleep)])
+       [obj sleep];
+    }
+  }
+  
+  [self->dispatcherRules reset];
+  
+  return r;
+}
+
+@end /* SoObjectRequestHandler */
+
+@implementation WOCoreApplication(RendererSelection)
+
+- (id)rendererForObject:(id)_object inContext:(WOContext *)_ctx {
+  return nil;
+}
+
+@end /* WOCoreApplication(RendererSelection) */
+
+@implementation SoObjectRequestHandler(Logging)
+
+- (NSString *)loggingPrefix {
+  return @"[object-handler]";
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn ? YES : NO;
+}
+
+@end /* SoObjectRequestHandler(Logging) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjectSOAPDispatcher.h b/skyrix-sope/NGObjWeb/SoObjects/SoObjectSOAPDispatcher.h
new file mode 100644 (file)
index 0000000..ae0432e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  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$
+
+#ifndef __SoObjects_SoObjectSOAPDispatcher_H__
+#define __SoObjects_SoObjectSOAPDispatcher_H__
+
+#include "SoObjectMethodDispatcher.h"
+
+/*
+  SoObjectSOAPDispatcher
+
+  A specialized variant of the method dispatcher that deals with SOAP
+  method invocations.
+
+  WORK IN PROGRESS
+
+  Objects stored in the context:
+    SOAPEnvelope - DOMElement
+    SOAPBody     - DOMElement
+    SOAPHeader   - DOMElement
+*/
+
+@interface SoObjectSOAPDispatcher : SoObjectMethodDispatcher
+@end
+
+#endif /* __SoObjects_SoObjectSOAPDispatcher_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjectSOAPDispatcher.m b/skyrix-sope/NGObjWeb/SoObjects/SoObjectSOAPDispatcher.m
new file mode 100644 (file)
index 0000000..be8bade
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+  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$
+
+#include "SoObjectSOAPDispatcher.h"
+#include "SoObject.h"
+#include "NSException+HTTP.h"
+#include "WOContext+SoObjects.h"
+#include "SoDefaultRenderer.h"
+#include <NGObjWeb/WOActionResults.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+#include <DOM/DOM.h>
+#include <SaxObjC/XMLNamespaces.h>
+
+/*
+  TODO: is it required by SOAP that the HTTP method is POST?
+
+  SOAP sample:
+    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+    <SOAP-ENV:Envelope 
+      xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
+      xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
+      xmlns:xsd="http://www.w3.org/1999/XMLSchema" 
+      xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
+    >
+      <SOAP-ENV:Body 
+        xmlns:types="http://schemas.novell.com/2003/10/NCSP/types.xsd" 
+        SOAP-ENV:encodingStyle=""
+      >
+        <loginRequest>
+          <types:auth xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+                      xsi:type="types:PlainText"
+          >
+            <types:username>dummy</types:username>
+            <types:password>user</types:password>
+          </types:auth>
+        </loginRequest>
+      </SOAP-ENV:Body>
+    </SOAP-ENV:Envelope>
+*/
+
+@interface SoSOAPRenderer : SoDefaultRenderer
+@end
+
+@implementation SoObjectSOAPDispatcher
+
+static BOOL debugOn      = NO;
+static BOOL debugParsing = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  debugOn = [ud boolForKey:@"SoObjectSOAPDispatcherDebugEnabled"];
+  if (debugOn) NSLog(@"Note: SOPE SOAP dispatcher debugging turned on.");
+}
+
+/* XML actions */
+
+- (id)performSOAPAction:(NSString *)_actionName
+  header:(id<DOMElement>)_header body:(id<DOMElement>)_body
+  inContext:(WOContext *)_ctx
+{
+  id clientObject;
+  id methodObject;
+  id resultObject;
+
+  if (debugOn) 
+    [self debugWithFormat:@"calling SOAP method: '%@'", _actionName];
+  
+  /* find client object */
+  
+  if ((clientObject = [_ctx clientObject]) != nil) {
+    if (debugOn)
+      [self debugWithFormat:@"  client object from ctx: %@", clientObject];
+  }
+  else if ((clientObject = [self->object clientObject])) {
+    if (debugOn)
+      [self debugWithFormat:@"  setting client object: %@", clientObject];
+    [_ctx setClientObject:clientObject];
+  }
+
+  /* find callable (method) object */
+  
+  // TODO: should we allow acquisition?
+  methodObject = [clientObject lookupName:_actionName inContext:_ctx
+                              acquire:NO];
+  if (methodObject == nil) {
+    if ([_actionName hasSuffix:@"Request"])
+      _actionName = [_actionName substringToIndex:[_actionName length] - 7];
+    methodObject = [clientObject lookupName:_actionName inContext:_ctx
+                                acquire:NO];
+  }
+  
+  if (methodObject == nil) {
+    [self debugWithFormat:@"WARNING: could not locate SOAP method: %@", 
+           _actionName];
+    return [NSException exceptionWithHTTPStatus:501 /* not implemented */
+                       reason:@"did not find the specified SOAP method"];
+  }
+  else if (![methodObject isCallable]) {
+    [self debugWithFormat:
+           @"WARNING: object found for SOAP method '%@' is not callable: "
+           @"%@", _actionName, methodObject];
+    return [NSException exceptionWithHTTPStatus:501 /* not implemented */
+                       reason:@"did not find the specified SOAP method"];
+  }
+  if (debugOn) [self debugWithFormat:@"  method: %@", methodObject];
+  
+  /* apply arguments */
+  
+  // TODO: use some query syntax in product.plist to retrieve parameters
+  //       from SOAP
+  
+  // TODO: somehow apply SOPE header/body?
+  if (_header) [_ctx setObject:_header forKey:@"SOAPHeader"];
+  if (_body)   [_ctx setObject:_body   forKey:@"SOAPBody"];
+  
+  if ([methodObject respondsToSelector:
+                     @selector(takeValuesFromRequest:inContext:)]) {
+    if (debugOn)
+      [self debugWithFormat:@"  applying values from request ..."];
+    [methodObject takeValuesFromRequest:[_ctx request] inContext:_ctx];
+  }
+  
+  /* perform call */
+  
+  resultObject = [methodObject callOnObject:[_ctx clientObject] 
+                              inContext:_ctx];
+  if (debugOn) [self debugWithFormat:@"got SOAP result: %@", resultObject];
+  return resultObject;
+}
+
+- (id)performSOAPAction:(NSString *)_actionName document:(id)_dom
+  inContext:(WOContext *)_ctx
+{
+  id<DOMElement>  envelope;
+  id<DOMElement>  header;
+  id<DOMElement>  body;
+  id<DOMNodeList> list;
+
+  /* envelope */
+
+  envelope = [_dom documentElement];
+  if (![[envelope tagName] isEqualToString:@"Envelope"] ||
+      ![[envelope namespaceURI] isEqualToString:XMLNS_SOAP_ENVELOPE]) {
+    [self debugWithFormat:@"Note: missing SOAP envelope at document root."];
+    return [NSException exceptionWithHTTPStatus:400 /* bad request */
+                       reason:@"could not parse SOAP content of request"];
+  }
+  if (debugParsing) [self debugWithFormat:@"envelope: %@", envelope];
+  
+  [_ctx setObject:envelope forKey:@"SOAPEnvelope"];
+  
+  /* header */
+
+  list = [envelope getElementsByTagName:@"Header"];
+  // TODO: not yet supported by DOMElement: namespaceURI:XMLNS_SOAP_ENVELOPE];
+  if ([list length] > 1) {
+    [self logWithFormat:
+           @"WARNING: multiple SOAP headers in request?! (using first)"];
+  }
+  header = [list length] > 0 ? [list objectAtIndex:0] : nil;
+  if (debugParsing) [self debugWithFormat:@"header: %@", header];
+
+  /* body */
+  
+  list = [envelope getElementsByTagName:@"Body"];
+  // TODO: not yet supported by DOMElement: namespaceURI:XMLNS_SOAP_ENVELOPE];
+  if ([list length] == 0) {
+    [self debugWithFormat:@"Note: missing SOAP body."];
+    return [NSException exceptionWithHTTPStatus:400 /* bad request */
+                       reason:@"could not parse SOAP body of request"];
+  }
+  else if ([list length] > 1) {
+    [self logWithFormat:
+           @"WARNING: multiple SOAP bodies in request?! (using first)"];
+  }
+  body = [list objectAtIndex:0];
+  if (debugParsing) [self debugWithFormat:@"body: %@", body];
+  
+  /* process */
+  
+  return [self performSOAPAction:_actionName 
+              header:header body:body inContext:_ctx];
+}
+
+/* main dispatcher */
+
+- (id)dispatchInContext:(WOContext *)_ctx {
+  NSAutoreleasePool *pool;
+  WORequest         *rq;
+  NSString          *SOAPAction;
+  id<DOMDocument>   dom;
+  id resultObject;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  if ((rq = [_ctx request]) == nil) {
+    [self logWithFormat:@"ERROR: missing request in context!"];
+    return nil;
+  }
+  
+  /* 
+     Note: the SOAPAction is also contained in the body which is probably
+           considered the authority.
+  */
+  
+  SOAPAction = [rq headerForKey:@"soapaction"];
+  if ([SOAPAction length] == 0) {
+    [self logWithFormat:@"ERROR: missing SOAPAction HTTP header!"];
+    return nil;
+  }
+
+  /* parse XML */
+  
+  if ((dom = [rq contentAsDOMDocument]) == nil) {
+    [self debugWithFormat:@"Note: could not parse XML content of request"];
+    return [NSException exceptionWithHTTPStatus:400 /* bad request */
+                       reason:@"could not parse XML content of request"];
+  }
+  
+  resultObject = 
+    [[self performSOAPAction:SOAPAction document:dom inContext:_ctx]retain];
+  [pool release];
+  
+  return [resultObject autorelease];
+}
+
+/* debugging */
+
+- (NSString *)loggingPrefix {
+  return @"[obj-soap-dispatch]";
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* SoObjectSOAPDispatcher */
+
+@implementation SoSOAPRenderer
+
+// TODO: render exceptions as SOAP faults
+// TODO: maybe support rendering of DOM trees? (should be supported by default)
+// TODO: maybe some "schema" driven rendering
+
+@end /* SoSOAPRenderer */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjectXmlRpcDispatcher.h b/skyrix-sope/NGObjWeb/SoObjects/SoObjectXmlRpcDispatcher.h
new file mode 100644 (file)
index 0000000..ced7949
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_SoObjectXmlRpcDispatcher_H__
+#define __SoObjects_SoObjectXmlRpcDispatcher_H__
+
+#include "SoObjectMethodDispatcher.h"
+
+/*
+  SoObjectXmlRpcDispatcher
+
+  A specialized variant of the method dispatcher that deals with XML-RPC
+  method invocations.
+*/
+
+@interface SoObjectXmlRpcDispatcher : SoObjectMethodDispatcher
+@end
+
+#endif /* __SoObjects_SoObjectXmlRpcDispatcher_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjectXmlRpcDispatcher.m b/skyrix-sope/NGObjWeb/SoObjects/SoObjectXmlRpcDispatcher.m
new file mode 100644 (file)
index 0000000..ad10721
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoObjectXmlRpcDispatcher.h"
+#include "SoObject.h"
+#include "NSException+HTTP.h"
+#include <NGXmlRpc/XmlRpcMethodCall+WO.h>
+#include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
+#include <NGObjWeb/WOActionResults.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@interface NSObject(XmlRpcCall)
+
+- (id)callOnObject:(id)_client 
+  withPositionalParameters:(NSArray *)_args
+  inContext:(id)_ctx;
+
+@end
+
+@implementation SoObjectXmlRpcDispatcher
+
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  debugOn = [ud boolForKey:@"SoObjectXmlRpcDispatcherDebugEnabled"];
+  if (debugOn) NSLog(@"Note: SOPE XML-RPC Dispatcher Debugging turned on.");
+}
+
+/* error handling */
+
+- (NSException *)missingMethodFault:(NSString *)_method 
+  inContext:(WOContext *)_ctx
+{
+  NSString *r;
+  
+  r = [@"Could not locate requested XML-RPC method: " 
+       stringByAppendingString:_method];
+  return [NSException exceptionWithHTTPStatus:404 /* not found */
+                     reason:r];
+}
+
+/* perform call on object */
+
+- (id)performActionNamed:(NSString *)_name parameters:(NSArray *)_params 
+  inContext:(WOContext *)_ctx
+{
+  NSString *methodName;
+  NSRange  r;
+  id       clientObject;
+  id       method;
+
+  // TODO: check whether _name is set
+  
+  [self debugWithFormat:@"should perform: %@", _name];
+  methodName = nil;
+  
+  r = [_name rangeOfString:@"." options:(NSLiteralSearch|NSBackwardsSearch)];
+  if (r.length > 0) {
+    /* has a prefix, eg "folder.folder.a()" => traverse */
+    NSArray     *nsParts;
+    NSException *error = nil;
+    unsigned    count;
+    
+    nsParts    = [_name componentsSeparatedByString:@"."];
+    count      = [nsParts count];
+    methodName = [[[nsParts objectAtIndex:(count - 1)] copy] autorelease];
+    nsParts    = [nsParts subarrayWithRange:NSMakeRange(0, count - 1)];
+    
+    [self debugWithFormat:@"XML-RPC traversal: %@",
+           [nsParts componentsJoinedByString:@" => "]];
+    
+    /*
+       TODO: we might not want to use -traverse.. so that the clientObject
+             stays the same (the one bound to the URL)?
+    */
+    clientObject = [self->object 
+                       traversePathArray:nsParts inContext:_ctx error:&error
+                       acquire:YES];
+    if (error) {
+      [self debugWithFormat:@"  XML-RPC traversal error: %@", error];
+      return error;
+    }
+  }
+  else {
+    clientObject = self->object;
+    methodName   = _name;
+  }
+  
+  method = [clientObject lookupName:methodName inContext:_ctx acquire:YES];
+  if (method == nil) {
+    // TODO: return proper fault!
+    [self logWithFormat:@"did not find requested XML-RPC method: '%@'",
+           methodName];
+    return [self missingMethodFault:methodName inContext:_ctx];
+  }
+  if (![method isCallable]) {
+    // TODO: return proper fault!
+    [self logWithFormat:
+           @"located object (%@) is not callable (class=%@):\n  %@", 
+           methodName, NSStringFromClass([method class]), method];
+    return nil;
+  }
+  
+  /* TODO: do we need to bind or is this automatic? */
+  
+  if ([method respondsToSelector:
+               @selector(callOnObject:withPositionalParameters:inContext:)]) {
+    [self debugWithFormat:
+           @"calling XML-RPC method with %i positional parameters.",
+           [_params count]];
+    return [method callOnObject:clientObject 
+                  withPositionalParameters:_params 
+                  inContext:_ctx];
+  }
+  
+  if ([_params count] > 0) {
+    [self logWithFormat:
+           @"WARNING: invoking SOPE method via XML-RPC without "
+           @"positional paramters (%i parameters defined)",
+           [_params count]];
+  }
+  return [method callOnObject:clientObject inContext:_ctx];
+}
+
+- (id)faultFromException:(NSException *)_exception
+  methodCall:(XmlRpcMethodCall *)_call
+{
+  /* add some more information to generic exceptions ... */
+  if (_call) {
+    NSMutableDictionary *ui;
+    
+    ui = [[_exception userInfo] mutableCopy];
+    if (ui == nil) ui = [[NSMutableDictionary alloc] init];
+    
+    [ui setObject:[_call methodName] forKey:@"methodName"];
+    [ui setObject:[_call parameters] forKey:@"methodParameters"];
+    
+    [_exception setUserInfo:ui];
+    [ui release];
+  }
+  
+  [self logWithFormat:@"%s: turning exception into fault %@\n",
+          __PRETTY_FUNCTION__,
+          [_exception description]];
+  
+  return _exception;
+}
+
+- (id<WOActionResults>)actionResponseForResult:(id)resValue {
+  if ([resValue conformsToProtocol:@protocol(WOActionResults)]) {
+    /* a "HTTP" result ... */
+    return resValue;
+  }
+  else {
+    /* an XML-RPC result ... */
+    XmlRpcMethodResponse *mResponse;
+    
+    mResponse = [[XmlRpcMethodResponse alloc] initWithResult:resValue];
+    return [mResponse autorelease];
+  }
+}
+
+- (id)performMethodCall:(XmlRpcMethodCall *)_call inContext:(WOContext *)_ctx{
+  id resValue;
+  
+  NS_DURING {
+    resValue = [self performActionNamed:[_call methodName]
+                     parameters:[_call parameters]
+                    inContext:_ctx];
+    resValue = [resValue retain];
+  }
+  NS_HANDLER {
+    resValue = [self faultFromException:localException
+                     methodCall:_call];
+    resValue = [resValue retain];
+  }
+  NS_ENDHANDLER;
+  
+  resValue = [resValue autorelease];
+  
+  return [self actionResponseForResult:resValue];
+}
+
+- (id)couldNotDecodeXmlRpcRequestInContext:(WOContext *)_ctx {
+  WOResponse *r = [_ctx response];
+  
+  [r setStatus:400 /* bad request */];
+  [r appendContentString:@"malformed XML-RPC request !"];
+  return r;
+}
+
+- (id)handleXmlRpcEncodingException:(NSException *)_exception object:(id)_obj {
+  [self logWithFormat:@"could not encode object: %@ (%@): %@",
+         _obj, NSStringFromClass([_obj class]), _exception];
+  return nil;
+}
+
+- (id)dispatchInContext:(WOContext *)_ctx {
+  XmlRpcMethodResponse *r;
+  XmlRpcMethodCall *call;
+  id result;
+  
+  call = [XmlRpcMethodCall alloc];
+  call = [call initWithRequest:[_ctx request]];
+  call = [call autorelease];
+  
+  if (call == nil)
+    return [self couldNotDecodeXmlRpcRequestInContext:_ctx];
+  
+  if ((result = [self performMethodCall:call inContext:_ctx]) == nil)
+    /* TODO: should we return a fault instead? */
+    return nil;
+  
+  if ([result isKindOfClass:[WOResponse class]])
+    /* pass WOResponse objects through ... */
+    return result;
+  
+  NS_DURING {
+    if ([result isKindOfClass:[XmlRpcMethodResponse class]])
+      r = result;
+    else
+      r = [[[XmlRpcMethodResponse alloc] initWithResult:result] autorelease];
+    
+    result = [[[r generateResponse] retain] autorelease];
+  }
+  NS_HANDLER {
+    result = [self handleXmlRpcEncodingException:localException
+                  object:result];
+  }
+  NS_ENDHANDLER;
+  
+  return result;
+}
+
+/* debugging */
+
+- (NSString *)loggingPrefix {
+  return @"[obj-xmlrpc-dispatch]";
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* SoObjectXmlRpcDispatcher */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoObjects.h b/skyrix-sope/NGObjWeb/SoObjects/SoObjects.h
new file mode 100644 (file)
index 0000000..c2280e6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_SoObjects_H__
+#define __NGObjWeb_SoObjects_H__
+
+#include <NGObjWeb/NSException+HTTP.h>
+#include <NGObjWeb/SoClass.h>
+#include <NGObjWeb/SoClassRegistry.h>
+#include <NGObjWeb/SoClassSecurityInfo.h>
+#include <NGObjWeb/SoDefaultRenderer.h>
+#include <NGObjWeb/SoObject.h>
+#include <NGObjWeb/SoObjectMethodDispatcher.h>
+#include <NGObjWeb/SoObjectRequestHandler.h>
+#include <NGObjWeb/SoPageInvocation.h>
+#include <NGObjWeb/SoPermissions.h>
+#include <NGObjWeb/SoProduct.h>
+#include <NGObjWeb/SoProductRegistry.h>
+#include <NGObjWeb/SoProductResourceManager.h>
+#include <NGObjWeb/SoSecurityManager.h>
+#include <NGObjWeb/SoSelectorInvocation.h>
+#include <NGObjWeb/SoUser.h>
+#include <NGObjWeb/SoApplication.h>
+#include <NGObjWeb/WOContext+SoObjects.h>
+#include <NGObjWeb/WORequest+So.h>
+
+#endif /* __NGObjWeb_SoObjects_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoPageInvocation.h b/skyrix-sope/NGObjWeb/SoObjects/SoPageInvocation.h
new file mode 100644 (file)
index 0000000..355308d
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_SoPageInvocation_H__
+#define __SoObjects_SoPageInvocation_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  An invocation object for WOComponent based SoClass methods.
+  
+  If the invocation is bound, the component is instantiated and initialized,
+  if it is called, the "actionName" is called and the result is returned or
+  if no "actionName" is set, the component itself is returned.
+*/
+
+@class NSString, NSDictionary;
+@class WOComponent;
+@class SoProduct;
+
+@interface SoPageInvocation : NSObject
+{
+  NSString     *pageName;
+  NSString     *actionName;
+  SoProduct    *product; /* non-retained ! */
+  
+  /* for bound invocations */
+  WOComponent  *page;
+  id           object;
+  
+  NSDictionary *argumentSpecifications;
+}
+
+- (id)initWithPageName:(NSString *)_pageName;
+- (id)initWithPageName:(NSString *)_pageName actionName:(NSString *)_action;
+- (id)initWithPageName:(NSString *)_pageName actionName:(NSString *)_action
+  product:(SoProduct *)_product;
+
+/* accessors */
+
+- (NSString *)pageName;
+- (NSString *)actionName;
+
+- (void)setArgumentSpecifications:(NSDictionary *)_specs;
+- (NSDictionary *)argumentSpecifications;
+
+/* bindings */
+
+- (BOOL)isBound;
+- (id)bindToObject:(id)_object inContext:(id)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoPageInvocation_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoPageInvocation.m b/skyrix-sope/NGObjWeb/SoObjects/SoPageInvocation.m
new file mode 100644 (file)
index 0000000..a2b9dc0
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoPageInvocation.h"
+#include "SoClassSecurityInfo.h"
+#include "SoProduct.h"
+#include "WOContext+SoObjects.h"
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOApplication.h>
+#include <DOM/EDOM.h>
+#include "common.h"
+
+@interface WOComponent(UsedPrivates)
+/* this is defined in WOPageRequestHandler */
+- (id<WOActionResults>)performActionNamed:(NSString *)_actionName;
+- (id<WOActionResults>)defaultAction;
+- (void)setResourceManager:(WOResourceManager *)_rm;
+@end
+
+@interface WOContext(UsedPrivates)
+- (void)setPage:(WOComponent *)_page;
+@end
+
+@implementation SoPageInvocation
+
+static int debugOn = 0;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    
+    debugOn = [ud boolForKey:@"SoPageInvocationDebugEnabled"] ? 1 : 0;
+  }
+}
+
+- (id)initWithPageName:(NSString *)_pageName actionName:(NSString *)_action {
+  if ((self = [super init])) {
+    self->pageName   = [_pageName copy];
+    self->actionName = [_action   copy];
+  }
+  return self;
+}
+- (id)initWithPageName:(NSString *)_pageName {
+  return [self initWithPageName:_pageName actionName:nil];
+}
+- (id)init {
+  return [self initWithPageName:nil];
+}
+- (id)initWithPageName:(NSString *)_pageName actionName:(NSString *)_action
+  product:(SoProduct *)_product
+{
+  if ((self = [self initWithPageName:_pageName actionName:_action])) {
+    self->product = _product;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->argumentSpecifications release];
+  [self->page       release];
+  [self->object     release];
+  [self->pageName   release];
+  [self->actionName release];
+  [super dealloc];
+}
+
+/* containment */
+
+- (void)detachFromContainer {
+  self->product = nil;
+}
+- (id)container {
+  return self->product;
+}
+- (NSString *)nameInContainer {
+  /* could ask product */
+  return nil;
+}
+
+/* accessors */
+
+- (NSString *)pageName {
+  return self->pageName;
+}
+- (NSString *)actionName {
+  return self->actionName;
+}
+
+- (void)setArgumentSpecifications:(NSDictionary *)_specs {
+  ASSIGNCOPY(self->argumentSpecifications, _specs);
+}
+- (NSDictionary *)argumentSpecifications {
+  return self->argumentSpecifications;
+}
+
+/* argument processing */
+
+- (NSDictionary *)extractSOAPArgumentsFromContext:(id)_ctx 
+  specification:(id)_spec 
+{
+  /* 
+     spec is supposed to be a dictionary with the KVC keys as the 
+     keys and DOM query pathes as the values.
+  */
+  NSMutableDictionary *args;
+  NSEnumerator *keys;
+  NSString     *key;
+  id           soapEnvelope;
+  
+  // TODO: I guess that should be improved a bit in the dispatcher
+  if ((soapEnvelope = [_ctx valueForKey:@"SOAPEnvelope"]) == nil) {
+    // TODO: generate some kind of fault? (NSException?)
+    [self logWithFormat:@"ERROR: no SOAP envelope available in context!"];
+    return nil;
+  }
+  
+  /* for each positional selector argument we have a query path */
+  
+  args = [NSMutableDictionary dictionaryWithCapacity:8];
+  keys = [_spec keyEnumerator];
+  while ((key = [keys nextObject])) {
+    NSString *qppath;
+    id value;
+    
+    qppath = [_spec valueForKey:key];
+    value  = [qppath isNotNull] ? [soapEnvelope lookupQueryPath:qppath] : nil;
+    
+    [args setObject:(value != nil ? value : [NSNull null]) forKey:key];
+  }
+  return args;
+}
+
+- (NSDictionary *)extractArgumentsFromContext:(id)_ctx
+  forRequestType:(NSString *)_type
+  specification:(id)_spec 
+{
+  if ([_type isEqualToString:@"SOAP"])
+    return [self extractSOAPArgumentsFromContext:_ctx specification:_spec];
+  
+  [self logWithFormat:
+         @"ERROR: cannot extract parameters for request type: '%@'", _type];
+  return nil;
+}
+
+/* page construction */
+
+- (WOComponent *)instantiatePageInContext:(id)_ctx {
+  WOResourceManager *rm;
+  WOComponent *lPage;
+  NSArray     *languages;
+  
+  if (debugOn) {
+    [self debugWithFormat:@"instantiate page: %@", self->pageName];
+    if (self->product == nil)
+      [self debugWithFormat:@"  no product is set."];
+  }
+
+  if (_ctx == nil) {
+    [self debugWithFormat:
+           @"Note: got no explicit context for page instantiation, using "
+           @"application context."];
+    _ctx = [[WOApplication application] context];
+  }
+  
+  /* lookup available resource manager (product,component,app) */
+  
+  if ((rm = [self->product resourceManager]) == nil) {
+    if ((rm = [[_ctx component] resourceManager]) == nil) {
+      rm = [[_ctx application] resourceManager];
+      if (debugOn) [self debugWithFormat:@"   app-rm: %@", rm];
+    }
+    else
+      if (debugOn) [self debugWithFormat:@"   component-rm: %@", rm];
+  }
+  else
+    if (debugOn) [self debugWithFormat:@"   product-rm: %@", rm];
+  
+  /* determine language */
+  
+  languages = [_ctx hasSession]
+    ? [(WOSession *)[_ctx session] languages]
+    : [[(id <WOPageGenerationContext>)_ctx request] browserLanguages];
+
+  /* instantiate */
+  
+  lPage = [rm pageWithName:self->pageName languages:languages];
+  [lPage ensureAwakeInContext:_ctx];
+  [lPage setResourceManager:rm];
+  
+  if (debugOn) [self debugWithFormat:@"   page: %@", lPage];
+  
+  return lPage;
+}
+
+/* invocation */
+
+- (BOOL)isCallable {
+  return YES;
+}
+- (id)clientObject {
+  return self->object;
+}
+
+- (id)callOnObject:(id)_client inContext:(id)_ctx {
+  NSDictionary *argspec;
+  WOComponent  *lPage;
+  WORequest    *rq;
+  
+  if (self->object != _client) {
+    /* rebind */
+    return [[self bindToObject:_client inContext:_ctx]
+                 callOnObject:_client inContext:_ctx];
+  }
+  
+  if ((lPage = self->page) == nil)
+    lPage = [self instantiatePageInContext:_ctx];
+  
+  if (lPage == nil) {
+    [self logWithFormat:@"found no page named '%@' for call !", 
+         self->pageName];
+    return nil;
+  }
+  
+  /* make page the "request" page */
+  
+  [_ctx setPage:lPage];
+
+  /* set client object in page */
+  
+  [lPage setClientObject:_client];
+  
+  /* apply request parameters */
+  
+  rq = [(id <WOPageGenerationContext>)_ctx request];
+  
+  if ([lPage shouldTakeValuesFromRequest:rq inContext:_ctx]) {
+    [[_ctx application] takeValuesFromRequest:rq
+                       inContext:_ctx];
+  }
+  
+  /* apply extracted parameters (TODO: what should be done first?) */
+
+  argspec = [self->argumentSpecifications objectForKey:[_ctx soRequestType]];
+  if (argspec != nil) {
+    NSDictionary *args;
+    
+    args = [self extractArgumentsFromContext:_ctx
+                forRequestType:[_ctx soRequestType]
+                specification:argspec];
+    if (debugOn) [self debugWithFormat:@"extracted args %@", args];
+    
+    if (args != nil) [lPage takeValuesFromDictionary:args];
+  }
+  
+  /* call action */
+  
+  if (self->actionName) {
+    if (debugOn) {
+      [self debugWithFormat:@"  performing action %@ on page: %@", 
+             self->actionName, lPage];
+    }
+    return [lPage performActionNamed:self->actionName];
+  }
+  else {
+    if (debugOn) {
+      [self debugWithFormat:@"  performing default action on page: %@", 
+             lPage];
+    }
+    return [lPage defaultAction];
+  }
+}
+
+/* bindings */
+
+- (BOOL)isBound {
+  return self->object != nil ? YES : NO;
+}
+
+- (id)bindToObject:(id)_object inContext:(id)_ctx {
+  SoPageInvocation *inv;
+  
+  if (_object == nil) return nil;
+  
+  // TODO: clean up this section, a bit hackish
+  inv = [[SoPageInvocation alloc] initWithPageName:self->pageName];
+  inv = [inv autorelease];
+  
+  inv->product    = self->product; // non-owned (cannot be detached !!!)
+  inv->object     = [_object retain];
+  inv->actionName = [self->actionName copy];
+  inv->page       = [[inv instantiatePageInContext:_ctx] retain];
+  inv->argumentSpecifications = [self->argumentSpecifications copy];
+  
+  if (inv->page == nil) {
+    [self logWithFormat:@"ERROR: did not find page method '%@'", 
+           self->pageName];
+    return nil;
+  }
+  
+  return inv;
+}
+
+/* delivering as content (can happen in DAV !) */
+
+- (void)appendToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  [_r appendContentString:@"native component method: "];
+  [_r appendContentHTMLString:[self description]];
+}
+
+/* key/value coding */
+
+- (id)valueForUndefinedKey:(NSString *)_key {
+  if (debugOn) [self debugWithFormat:@"return nil for KVC key: '%@'", _key];
+  return nil;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->pageName)   [ms appendFormat:@" page=%@",   self->pageName];
+  if (self->actionName) [ms appendFormat:@" action=%@", self->actionName];
+  
+  if (self->object) [ms appendString:@" bound"];
+  if (self->page)   [ms appendString:@" instantiated"];
+  
+  if (self->product) [ms appendFormat:@" product=%@", self->product];
+  
+  if ([self->argumentSpecifications count] > 0) {
+    id tmp;
+    
+    tmp = [self->argumentSpecifications allKeys];
+    tmp = [tmp componentsJoinedByString:@","];
+    [ms appendFormat:@" arg-handlers=%@",tmp];
+  }
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SoPageInvocation */
+
+@implementation SoPageInvocation(Logging)
+
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@"[so-page 0x%08X %@]", 
+                    self, self->pageName];
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn ? YES : NO;
+}
+
+@end /* SoPageInvocation(Logging) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoPermissions.h b/skyrix-sope/NGObjWeb/SoObjects/SoPermissions.h
new file mode 100644 (file)
index 0000000..530045d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoPermissions_H__
+#define __SoObjects_SoPermissions_H__
+
+#import <Foundation/NSString.h>
+
+/*
+  Constants for Permission Names and Roles
+  
+  Reuse predefined permissions ! Added constants for most permissions found
+  in Zope to make this more convenient.
+*/
+
+extern NSString *SoRole_Manager;
+extern NSString *SoRole_Anonymous;
+extern NSString *SoRole_Authenticated;
+extern NSString *SoRole_Owner;
+
+extern NSString *SoPerm_AccessContentsInformation;
+extern NSString *SoPerm_AddDatabaseMethods;
+extern NSString *SoPerm_AddDocumentsImagesAndFiles;
+extern NSString *SoPerm_AddExternalMethods;
+extern NSString *SoPerm_AddFolders;
+extern NSString *SoPerm_AddMailHostObjects;
+extern NSString *SoPerm_AddPythonScripts;
+extern NSString *SoPerm_AddSiteRoots;
+extern NSString *SoPerm_AddUserFolders;
+extern NSString *SoPerm_AddVersions;
+extern NSString *SoPerm_AddVocabularies;
+extern NSString *SoPerm_ChangeDatabaseConnections;
+extern NSString *SoPerm_ChangeExternalMethods;
+extern NSString *SoPerm_ChangeImagesAndFiles;
+extern NSString *SoPerm_ChangePythonScripts;
+extern NSString *SoPerm_ChangeVersions;
+extern NSString *SoPerm_ChangeBindings;
+extern NSString *SoPerm_ChangeConfiguration;
+extern NSString *SoPerm_ChangePermissions;
+extern NSString *SoPerm_ChangeProxyRoles;
+extern NSString *SoPerm_DeleteObjects;
+extern NSString *SoPerm_ManageAccessRules;
+extern NSString *SoPerm_ManageVocabulary;
+extern NSString *SoPerm_ManageProperties;
+extern NSString *SoPerm_ManageUsers;
+extern NSString *SoPerm_OpenCloseDatabaseConnections;
+extern NSString *SoPerm_QueryVocabulary;
+extern NSString *SoPerm_SaveDiscardVersionChanges;
+extern NSString *SoPerm_TakeOwnership;
+extern NSString *SoPerm_TestDatabaseConnections;
+extern NSString *SoPerm_UndoChanges;
+extern NSString *SoPerm_UseDatabaseMethods;
+extern NSString *SoPerm_UseMailHostServices;
+extern NSString *SoPerm_View;
+extern NSString *SoPerm_ViewHistory;
+extern NSString *SoPerm_ViewManagementScreens;
+extern NSString *SoPerm_WebDAVAccess;
+extern NSString *SoPerm_WebDAVLockItems;
+extern NSString *SoPerm_WebDAVUnlockItems;
+
+#endif /* __SoObjects_SoPermissions_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoPermissions.m b/skyrix-sope/NGObjWeb/SoObjects/SoPermissions.m
new file mode 100644 (file)
index 0000000..402c722
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoPermissions.h"
+#include "common.h"
+
+/* roles */
+
+NSString *SoRole_Manager       = @"Manager";
+NSString *SoRole_Anonymous     = @"Anonymous";
+NSString *SoRole_Authenticated = @"Authenticated";
+NSString *SoRole_Owner         = @"Owner";
+
+/* permissions */
+
+NSString *SoPerm_AccessContentsInformation    = @"Access Contents Information";
+NSString *SoPerm_AddDatabaseMethods           = @"Add Database Methods";
+NSString *SoPerm_AddDocumentsImagesAndFiles   = @"Add Documents, Images, and Files";
+NSString *SoPerm_AddExternalMethods           = @"Add External Methods";
+NSString *SoPerm_AddFolders                   = @"Add Folders";
+NSString *SoPerm_AddMailHostObjects           = @"Add MailHost Objects";
+NSString *SoPerm_AddPythonScripts             = @"Add Python Scripts";
+NSString *SoPerm_AddSiteRoots                 = @"Add Site Roots";
+NSString *SoPerm_AddUserFolders               = @"Add User Folders";
+NSString *SoPerm_AddVersions                  = @"Add Versions";
+NSString *SoPerm_AddVocabularies              = @"Add Vocabularies";
+NSString *SoPerm_ChangeDatabaseConnections    = @"Change Database Connections";
+NSString *SoPerm_ChangeExternalMethods        = @"Change External Methods";
+NSString *SoPerm_ChangeImagesAndFiles         = @"Change Images and Files";
+NSString *SoPerm_ChangePythonScripts          = @"Change Python Scripts";
+NSString *SoPerm_ChangeVersions               = @"Change Versions";
+NSString *SoPerm_ChangeBindings               = @"Change Bindings";
+NSString *SoPerm_ChangeConfiguration          = @"Change Configuration";
+NSString *SoPerm_ChangePermissions            = @"Change Permissions";
+NSString *SoPerm_ChangeProxyRoles             = @"Change Proxy Roles";
+NSString *SoPerm_DeleteObjects                = @"Delete Objects";
+NSString *SoPerm_ManageAccessRules            = @"Manage Access Rules";
+NSString *SoPerm_ManageVocabulary             = @"Manage Vocabulary";
+NSString *SoPerm_ManageProperties             = @"Manage Properties";
+NSString *SoPerm_ManageUsers                  = @"Manage Users";
+NSString *SoPerm_OpenCloseDatabaseConnections = @"Open/Close Database Connections";
+NSString *SoPerm_QueryVocabulary           = @"Query Vocabulary";
+NSString *SoPerm_SaveDiscardVersionChanges = @"Save/Discard Version Changes";
+NSString *SoPerm_TakeOwnership             = @"Take Ownership";
+NSString *SoPerm_TestDatabaseConnections   = @"Test Database Connections";
+NSString *SoPerm_UndoChanges               = @"Undo Changes";
+NSString *SoPerm_UseDatabaseMethods        = @"Use Database Methods";
+NSString *SoPerm_UseMailHostServices       = @"Use MailHost Services";
+NSString *SoPerm_View                      = @"View";
+NSString *SoPerm_ViewHistory               = @"View History";
+NSString *SoPerm_ViewManagementScreens     = @"View Management Screens";
+NSString *SoPerm_WebDAVAccess              = @"WebDAV Access";
+NSString *SoPerm_WebDAVLockItems           = @"WebDAV Lock Items";
+NSString *SoPerm_WebDAVUnlockItems         = @"WebDAV Unlock Items";
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoProduct.h b/skyrix-sope/NGObjWeb/SoObjects/SoProduct.h
new file mode 100644 (file)
index 0000000..8a32c7c
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_SoProduct_H__
+#define __SoObjects_SoProduct_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoProduct
+  
+  SoProduct are packages of SOPE pages, methods, resources etc. SoProducts
+  are usually represented by bundles and defined using the product.plist
+  manifest resource inside of the bundle.
+  
+  The manifest.plist has four root keys:
+    "classes"         - classes declared by the product
+    "categories"      - categories declared by the product
+    "requires"        - products this product depends upon
+    "publicResources" - names of the resources exported to the web
+*/
+
+@class NSString, NSException, NSBundle, NSMutableDictionary, NSArray;
+@class WOApplication, WOResourceManager;
+@class SoProductResourceManager;
+
+@interface SoProduct : NSObject
+{
+  NSBundle                 *bundle;
+  NSMutableDictionary      *classes;
+  NSMutableDictionary      *categories;
+  NSArray                  *requiredProducts;
+  NSArray                  *publicResources;
+  SoProductResourceManager *resourceManager;
+  
+  struct {
+    BOOL isLoaded:1;
+    BOOL isCodeLoaded:1;
+    int  reserved:30;
+  } flags;
+}
+
+- (id)initWithBundle:(NSBundle *)_bundle;
+
+/* accessors */
+
+- (NSArray *)requiredProducts;
+- (BOOL)isPublicResource:(NSString *)_key;
+- (NSBundle *)bundle;
+- (NSString *)productName;
+- (BOOL)isMainProduct;
+
+/* loading */
+
+- (BOOL)load;
+- (BOOL)reloadIfPossible;
+
+/* resource manager */
+
+- (WOResourceManager *)resourceManager;
+
+@end
+
+#endif /* __SoObjects_SoProduct_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoProduct.m b/skyrix-sope/NGObjWeb/SoObjects/SoProduct.m
new file mode 100644 (file)
index 0000000..76e41bf
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoProduct.h"
+#include "SoProductClassInfo.h"
+#include "SoProductResourceManager.h"
+#include "SoClassRegistry.h"
+#include "SoClassSecurityInfo.h"
+#include "SoObject.h"
+#include "SoSecurityManager.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@interface SoProduct(Privates)
+- (void)registerClassesFromDictionary:(NSDictionary *)_classToInfo;
+- (void)registerCategoriesFromDictionary:(NSDictionary *)_classToInfo;
+@end
+
+@implementation SoProduct
+
+static int debugOn     = 1;
+static int regDebugOn  = 0;
+static int loadDebugOn = 0;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    regDebugOn  = [ud boolForKey:@"SoDebugProductRegistry"] ? 1 : 0;
+    loadDebugOn = [ud boolForKey:@"SoDebugProductLoading"] ? 1 : 0;
+  }
+}
+
+- (id)initWithDictionary:(NSDictionary *)_dict {
+  if ((self = [super init])) {
+    self->requiredProducts = [[_dict objectForKey:@"requires"] copy];
+    self->publicResources  = [[_dict objectForKey:@"publicResources"] copy];
+    
+    [self registerClassesFromDictionary:[_dict objectForKey:@"classes"]];
+    [self registerCategoriesFromDictionary:[_dict objectForKey:@"categories"]];
+  }
+  return self;
+}
+
+- (id)initWithBundle:(NSBundle *)_bundle {
+  NSString     *manifestPath;
+  NSDictionary *manifest;
+  
+  if (_bundle == nil) {
+    [self release];
+    return nil;
+  }
+  self->bundle = [_bundle retain];
+  manifestPath = [self->bundle pathForResource:@"product" ofType:@"plist"];
+  if ([manifestPath length] == 0) {
+    [self release];
+    return nil;
+  }
+  
+  manifest = [NSDictionary dictionaryWithContentsOfFile:manifestPath];
+  if (manifest == nil) {
+    [self logWithFormat:@"could not parse manifest: %@", manifestPath];
+    [self release];
+    return nil;
+  }
+  
+  self->resourceManager =
+    [[SoProductResourceManager alloc] initWithProduct:self];
+  if (self->resourceManager == nil)
+    [self logWithFormat:@"failed to instantiate resourcemanager for bundle"];
+  
+  return [self initWithDictionary:manifest];
+}
+
+- (void)dealloc {
+  [self->resourceManager detachFromContainer];
+  
+  [self->resourceManager  release];
+  [self->publicResources  release];
+  [self->requiredProducts release];
+  [self->categories       release];
+  [self->classes          release];
+  [self->bundle           release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSArray *)requiredProducts {
+  return self->requiredProducts;
+}
+
+- (NSBundle *)bundle {
+  return self->bundle;
+}
+
+- (BOOL)isMainProduct {
+  if (self->bundle == nil) return YES;
+  if (self->bundle == [NSBundle mainBundle]) return YES;
+  return NO;
+}
+
+- (NSString *)productName {
+  if ([self isMainProduct])
+    return @"MAIN";
+  
+  return [[[self->bundle bundlePath]
+           lastPathComponent] stringByDeletingPathExtension];
+}
+
+- (BOOL)isPublicResource:(NSString *)_key {
+  return [self->publicResources containsObject:_key] ? YES : NO;
+}
+
+/* parsing manifest */
+
+- (void)registerCategoryNamed:(NSString *)_name info:(NSDictionary *)_info {
+  SoProductCategoryInfo *catInfo;
+  
+  if (regDebugOn)
+    [self logWithFormat:@"  register category on '%@'", _name];
+  
+  catInfo = [[SoProductCategoryInfo alloc] 
+               initWithName:_name manifest:_info product:self];
+  if (catInfo == nil) {
+    [self logWithFormat:@"   could not init category info for '%@'", _name];
+    return;
+  }
+  if ([self->categories objectForKey:_name]) {
+    [self logWithFormat:
+           @"ERROR: duplicate declaration of category on '%@' in product.",
+           _name];
+    [catInfo release];
+    return;
+  }
+  
+  if (self->categories == nil)
+    self->categories = [[NSMutableDictionary alloc] init];
+  
+  [self->categories setObject:catInfo forKey:_name];
+  [catInfo autorelease];
+}
+
+- (void)registerClassNamed:(NSString *)_name info:(NSDictionary *)_info {
+  SoProductClassInfo *classInfo;
+  
+  if (regDebugOn)
+    [self logWithFormat:@"  register class: %@", _name];
+  
+  classInfo = [[SoProductClassInfo alloc] 
+               initWithName:_name manifest:_info product:self];
+  if (classInfo == nil) {
+    [self debugWithFormat:@"   could not init class info for '%@'", _name];
+    return;
+  }
+  if ([self->classes objectForKey:_name]) {
+    [self logWithFormat:
+           @"ERROR: duplicate declaration of class %@ in product "
+           @"(registering as category)",
+           _name];
+    [classInfo release];
+    [self registerCategoryNamed:_name info:_info];
+    return;
+  }
+  
+  if (self->classes == nil)
+    self->classes = [[NSMutableDictionary alloc] init];
+  
+  [self->classes setObject:classInfo forKey:_name];
+  [classInfo autorelease];
+}
+
+- (void)registerClassesFromDictionary:(NSDictionary *)_classToInfo {
+  NSEnumerator *names;
+  NSMutableSet *regClasses;
+  NSString *className;
+  
+  regClasses = [NSMutableSet setWithCapacity:16];
+  names = [_classToInfo keyEnumerator];
+  while ((className = [names nextObject])) {
+    NSDictionary *info;
+    
+    if ([regClasses containsObject:className])
+      continue;
+    
+    info = [_classToInfo objectForKey:className];
+    [self registerClassNamed:className info:info];
+    [regClasses addObject:className];
+  }
+}
+- (void)registerCategoriesFromDictionary:(NSDictionary *)_classToInfo {
+  NSEnumerator *names;
+  NSMutableSet *regCats;
+  NSString *className;
+  
+  regCats = [NSMutableSet setWithCapacity:16];
+  names = [_classToInfo keyEnumerator];
+  while ((className = [names nextObject])) {
+    NSDictionary *info;
+    
+    if ([regCats containsObject:className])
+      continue;
+    
+    info = [_classToInfo objectForKey:className];
+    [self registerCategoryNamed:className info:info];
+    [regCats addObject:className];
+  }
+}
+
+/* loading */
+
+- (BOOL)load {
+  SoClassRegistry *registry;
+  
+  if (self->flags.isLoaded) {
+    if (loadDebugOn)
+      [self logWithFormat:@"product already loaded: %@", self];
+    return YES;
+  }
+  
+  if (loadDebugOn)
+    [self logWithFormat:@"loading product: %@", self];
+  self->flags.isLoaded = 1;
+  
+  /* check whether bundle is binary ! */
+  
+  if ((self->bundle != nil) && (self->bundle != [NSBundle mainBundle])) {
+    if (loadDebugOn) {
+      [self logWithFormat:@"  loading bundle of product: %@", 
+             [self->bundle bundlePath]];
+    }
+    
+    if (![self->bundle load]) {
+      if (loadDebugOn) [self logWithFormat:@"  failed to load bundle."];
+      return NO;
+    }
+    self->flags.isCodeLoaded = 1;
+  }
+  
+  registry = [SoClassRegistry sharedClassRegistry];
+  
+  if (loadDebugOn) {
+    [self logWithFormat:@"  registering %i classes ...", 
+           [self->classes count]];
+  }
+  
+  [[self->classes allValues] 
+    makeObjectsPerformSelector:@selector(applyOnRegistry:)
+    withObject:registry];
+  
+  if (loadDebugOn) {
+    [self logWithFormat:@"  registering %i categories ...", 
+           [self->categories count]];
+  }
+  
+  [[self->categories allValues] 
+    makeObjectsPerformSelector:@selector(applyOnRegistry:)
+    withObject:registry];
+  
+  if (loadDebugOn)
+    [self logWithFormat:@"done loading product."];
+  return YES;
+}
+
+- (BOOL)reloadIfPossible {
+  /* only possible if no product ObjC code is loaded */
+  if (self->flags.isCodeLoaded) return NO;
+  
+  return NO;
+}
+
+/* product as a SoObject */
+
+- (NSString *)baseURLInContext:(id)_ctx {
+  /* Note: cannot use -stringByAppendingPathComponent: on OSX ! */
+  NSString *baseURL, *cname;
+  
+  baseURL = [self rootURLInContext:_ctx];
+  if (![baseURL hasSuffix:@"/"]) 
+    baseURL = [baseURL stringByAppendingString:@"/"];
+  
+  baseURL = [baseURL stringByAppendingString:@"ControlPanel/Products/"];
+  cname   = [[self productName] stringByEscapingURL];
+  baseURL = [baseURL stringByAppendingString:cname];
+  return baseURL;
+}
+
+- (NSArray *)allKeys {
+  return [NSArray arrayWithObject:@"Resources"];
+}
+
+- (BOOL)hasName:(NSString *)_key inContext:(id)_ctx {
+  if ([_key isEqualToString:@"Resources"])
+    return YES;
+  return [super hasName:_key inContext:_ctx];
+}
+
+- (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
+  if ([_key isEqualToString:@"Resources"])
+    return [self resourceManager];
+  
+  return [super lookupName:_key inContext:_ctx acquire:_flag];
+}
+
+/* resource manager */
+
+- (WOResourceManager *)resourceManager {
+  if ([self isMainProduct])
+    return [[WOApplication application] resourceManager];
+  
+  if (self->resourceManager == nil) {
+    [self logWithFormat:@"WARNING: resource-manager was nil ..."];
+    self->resourceManager =
+      [[SoProductResourceManager alloc] initWithProduct:self];
+  }
+  return self->resourceManager;
+}
+
+/* HTML representation */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(id)_ctx {
+  [_response appendContentString:@"<h3>SOPE Product: "];
+  [_response appendContentHTMLString:[self productName]];
+  [_response appendContentString:@"</h3>"];
+  
+  [_response appendContentString:
+              @"<li><a href=\"Resources/\">Resources</a></li>"];
+}
+
+/* debugging */
+
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@"[so-product:%@]",
+                     [[[self bundle] bundlePath] lastPathComponent]];
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn ? YES : NO;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  unsigned cnt;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (self->flags.isLoaded)
+    [ms appendFormat:@" loaded"];
+  if (self->flags.isCodeLoaded)
+    [ms appendFormat:@" code-loaded"];
+
+  if (self->bundle)
+    [ms appendFormat:@" bundle=%@", [self->bundle bundlePath]];
+  
+  if ((cnt = [self->classes count]) > 0)
+    [ms appendFormat:@" #classes=%d", cnt];
+  if ((cnt = [self->categories count]) > 0)
+    [ms appendFormat:@" #categories=%d", cnt];
+  if ((cnt = [self->publicResources count]) > 0)
+    [ms appendFormat:@" #pubrsrc=%d", cnt];
+  
+  if (self->resourceManager)
+    [ms appendFormat:@" rm=0x%08X", self->resourceManager];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SoProduct */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoProductClassInfo.h b/skyrix-sope/NGObjWeb/SoObjects/SoProductClassInfo.h
new file mode 100644 (file)
index 0000000..409e5a2
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_SoProductClassInfo_H__
+#define __SoObjects_SoProductClassInfo_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoProductClassInfo
+
+  This class represents a class entry in the product manifest. It parses the
+  following class keys:
+    
+    protectedBy            string       [eg "<public>" or "view"]
+    defaultAccess          string       [eg "allow"]
+    defaultRoles           dict         [eg {View = Anonymous;Edit=Owner}]
+    extension / extensions string|array [eg "gif"]
+    exactFilenames         array        [eg "ChangeLog"]
+    methods
+    slots
+
+  Slots Keys:
+    value       required
+    valueClass  optional
+
+  Method Keys:
+    pageName              creates a SoPageInvocation
+    actionName  optional  (used in conjunction with pageName)
+    selector              creates a SoSelectorInvocation
+*/
+
+@class NSString, NSDictionary, NSMutableDictionary, NSArray;
+@class SoClassRegistry, SoProduct;
+
+@interface SoProductSlotSetInfo : NSObject
+{
+  NSString            *className;
+  NSString            *protectedBy;
+  NSString            *defaultAccess;
+  NSDictionary        *roleInfo;
+  NSArray             *extensions;
+  NSArray             *exactFilenames;
+  SoProduct           *product; /* non-retained ! */
+  
+  NSMutableDictionary *slotValues;
+  NSMutableDictionary *slotProtections;
+}
+
+- (id)initWithName:(NSString *)_name 
+  manifest:(NSDictionary *)_dict
+  product:(SoProduct *)_product;
+
+- (void)applyOnRegistry:(SoClassRegistry *)_registry;
+
+@end
+
+@interface SoProductClassInfo : SoProductSlotSetInfo
+@end
+
+@interface SoProductCategoryInfo : SoProductSlotSetInfo
+@end
+
+#endif /* __SoObjects_SoProductClassInfo_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoProductClassInfo.m b/skyrix-sope/NGObjWeb/SoObjects/SoProductClassInfo.m
new file mode 100644 (file)
index 0000000..229c66b
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoProductClassInfo.h"
+#include "SoPageInvocation.h"
+#include "SoSelectorInvocation.h"
+#include "SoClassSecurityInfo.h"
+#include "SoClass.h"
+#include "SoClassRegistry.h"
+#include "SoProduct.h"
+#include "common.h"
+
+static int debugOn     = 1;
+static int loadDebugOn = 0;
+
+@interface SoProductSlotSetInfo(ManifestLoading)
+- (BOOL)_loadManifest:(NSDictionary *)_m;
+@end
+
+@interface SoProductSlotSetInfo(Privates)
+- (void)reset;
+@end
+
+@interface NSObject(PListInit)
+- (id)initWithPropertyList:(id)_plist;
+- (id)initWithPropertyList:(id)_plist owner:(id)_owner;
+@end
+
+@implementation SoProductSlotSetInfo
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  loadDebugOn = [ud boolForKey:@"SoDebugProductLoading"] ? 1 : 0;
+}
+
+- (void)reset {
+  [self->protectedBy   release]; self->protectedBy   = nil;
+  [self->defaultAccess release]; self->defaultAccess = nil;
+  [self->roleInfo      release]; self->roleInfo      = nil;
+  [self->slotValues      removeAllObjects];
+  [self->slotProtections removeAllObjects];
+}
+
+- (id)initWithName:(NSString *)_name manifest:(NSDictionary *)_dict
+  product:(SoProduct *)_product
+{
+  if ((self = [super init])) {
+    self->product   = _product; // non-retained
+    self->className = [_name copy];
+    [self _loadManifest:_dict];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[self->slotValues allValues]
+    makeObjectsPerformSelector:@selector(detachFromContainer)];
+  
+  [self->roleInfo        release];
+  [self->protectedBy     release];
+  [self->extensions      release];
+  [self->exactFilenames  release];
+  [self->className       release];
+  [self->slotValues      release];
+  [self->slotProtections release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)className {
+  return self->className;
+}
+- (Class)objcClass {
+  return NSClassFromString([self className]);
+}
+
+/* apply */
+
+- (void)applyClassSecurity:(SoClassSecurityInfo *)_security {
+  if (self->protectedBy) {
+    if ([self->protectedBy isEqualToString:@"<public>"])
+      [_security declareObjectPublic];
+    else if ([self->protectedBy isEqualToString:@"<private>"])
+      [_security declareObjectPrivate];
+    else
+      [_security declareObjectProtected:self->protectedBy];
+  }
+  
+  if (self->defaultAccess)
+    [_security setDefaultAccess:self->defaultAccess];
+  
+  if (self->roleInfo) {
+    NSEnumerator *perms;
+    NSString *perm;
+    
+    perms = [self->roleInfo keyEnumerator];
+    while ((perm = [perms nextObject])) {
+      NSString *role = [self->roleInfo objectForKey:perm];
+      
+      [_security declareRole:role asDefaultForPermission:perm];
+    }
+  }
+}
+
+- (void)applySlotSecurity:(SoClassSecurityInfo *)_security {
+  NSEnumerator *names;
+  NSString *slotName;
+  
+  names = [self->slotProtections keyEnumerator];
+  while ((slotName = [names nextObject])) {
+    NSString *perm;
+    
+    if ((perm = [self->slotProtections objectForKey:slotName]))
+      [_security declareProtected:perm:slotName,nil];
+  }
+}
+
+- (void)applySlotValues:(SoClass *)_soClass {
+  NSEnumerator *names;
+  NSString *slotName;
+
+  if (loadDebugOn) {
+    [self debugWithFormat:@"  applying %i slots on class %@ ...", 
+            [self->slotValues count], [self className]];
+  }
+  
+  names = [self->slotValues keyEnumerator];
+  while ((slotName = [names nextObject])) {
+    id slot;
+    
+    slot = [self->slotValues objectForKey:slotName];
+    if (slot == nil)
+      continue;
+    
+    if (loadDebugOn) {
+      [self debugWithFormat:@"  register slot named %@ on class %@", 
+             slotName, [_soClass className]];
+    }
+    
+    /* if an implementation was provided, register it with the class */
+      
+    if ([_soClass valueForSlot:slotName]) {
+       [self logWithFormat:@"WARNING: redefining slot '%@' of class '%@'",
+             slotName, _soClass];
+    }
+       
+    [_soClass setValue:slot forSlot:slotName];
+    [slot release];
+  }
+}
+
+- (void)applyExtensionsForSoClass:(SoClass *)_soClass
+  onRegistry:(SoClassRegistry *)_registry
+{
+  NSEnumerator *e;
+  NSString     *ext;
+  NSException *error;
+  
+  if (_soClass == nil) {
+    [self logWithFormat:@"ERROR(%s): missing soClass parameter?!",
+            __PRETTY_FUNCTION__];
+    return;
+  }
+  if (_registry == nil) {
+    [self logWithFormat:@"ERROR: missing registry ?!"];
+    return;
+  }
+  
+  e = [self->extensions objectEnumerator];
+  while ((ext = [e nextObject])) {
+    if ((error = [_registry registerSoClass:_soClass forExtension:ext])) {
+      [self logWithFormat:
+              @"ERROR: failed to register class %@ for extension %@: %@", 
+              [_soClass className], ext, error];
+    }
+    else if (loadDebugOn) {
+      [self debugWithFormat:@"  registered class %@ for extension %@", 
+              [_soClass className], ext];
+    }
+  }
+  
+  e = [self->exactFilenames objectEnumerator];
+  while ((ext = [e nextObject])) {
+    if ((error = [_registry registerSoClass:_soClass forExactName:ext])) {
+      [self logWithFormat:
+              @"ERROR: failed to register class %@ for name %@: %@", 
+              [_soClass className], ext, error];
+    }
+    else if (loadDebugOn) {
+      [self debugWithFormat:@"  registered class %@ for name %@", 
+              [_soClass className], ext];
+    }
+  }
+}
+
+- (void)applyOnRegistry:(SoClassRegistry *)_registry {
+  SoClass *soClass;
+  id security;
+  
+  if ((soClass = [_registry soClassWithName:[self className]]) == nil) {
+    [self logWithFormat:
+            @"ERROR: did not find exported SoClass '%@' in product %@!", 
+            [self className], self->product];
+    return;
+  }
+  
+  security = [soClass soClassSecurityInfo];
+  if (loadDebugOn) {
+    [self debugWithFormat:@"loading info for class %@: %@", 
+            [self className], soClass];
+  }
+  
+  [self applyClassSecurity:security];
+  [self applySlotSecurity:security];
+  [self applySlotValues:soClass];
+
+  /* filename extensions for OFS */
+  [self applyExtensionsForSoClass:soClass onRegistry:_registry];
+  
+  if (loadDebugOn)
+    [self debugWithFormat:@"info for class %@ loaded.", [soClass className]];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn ? YES : NO;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  unsigned cnt;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  [ms appendFormat:@" name=%@", self->className];
+  
+  if ((cnt = [self->extensions count]) > 0)
+    [ms appendFormat:@" #extensions=%d", cnt];
+  if ((cnt = [self->slotValues count]) > 0)
+    [ms appendFormat:@" #slotvals=%d", cnt];
+  if ((cnt = [self->slotProtections count]) > 0)
+    [ms appendFormat:@" #slotperms=%d", cnt];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SoProductSlotSetInfo */
+
+@implementation SoProductClassInfo
+
+/* debugging */
+
+- (NSString *)loggingPrefix {
+  return @"[so-class-info]";
+}
+
+@end /* SoProductClassInfo */
+
+@implementation SoProductCategoryInfo
+
+/* debugging */
+
+- (NSString *)loggingPrefix {
+  return @"[so-category-info]";
+}
+
+@end /* SoProductCategoryInfo */
+
+@implementation SoProductSlotSetInfo(ManifestLoading)
+
+- (BOOL)isPageInvocationManifest:(NSDictionary *)_m {
+  return [_m objectForKey:@"pageName"] ? YES : NO;
+}
+
+- (id)makePageInvocationForMethodNamed:(NSString *)_name 
+  manifest:(NSDictionary *)_m 
+{
+  /*
+    Page invocation:
+      {
+        pageName   = "Main";
+       actionName = "doIt";
+        arguments = {
+          SOAP = {
+           login    = "loginRequest/auth/username/!textValue";
+           password = "loginRequest/auth/password/!textValue";
+          };
+        }
+      }
+  */
+  SoPageInvocation *method;
+  NSString     *pageName;
+  NSDictionary *argspecs;
+  
+  pageName = [_m objectForKey:@"pageName"];
+  argspecs = [_m objectForKey:@"arguments"];
+  
+  method = [[SoPageInvocation alloc]
+            initWithPageName:pageName
+            actionName:[_m objectForKey:@"actionName"]
+            product:self->product];
+  [method setArgumentSpecifications:argspecs];
+  return method;
+}
+
+- (id)makeInvocationForMethodNamed:(NSString *)_name selector:(id)_config {
+  SoSelectorInvocation *method;
+  
+  if (_config == nil) {
+    [self logWithFormat:
+           @"ERROR: missing config for selector invocation method: '%@'",
+           _name];
+    return nil;
+  }
+  
+  if ([_config isKindOfClass:[NSString class]]) {
+    /* form: selector = "doItInContext:" */
+    method = [[SoSelectorInvocation alloc] initWithSelectorNamed:_config 
+                                          addContextParameter:YES];
+  }
+  else if ([_config isKindOfClass:[NSDictionary class]]) {
+    /*
+      Selector Invocation:
+        selector = {
+         name                = "doItInContext:";
+         addContextParameter = YES;
+         // TODO: positionalArgumentBindings = ( );
+         // TODO: names (for mapping different argcounts)
+          arguments = {
+            SOAP = (
+              "loginRequest/auth/username/!textValue",
+              "loginRequest/auth/password/!textValue"
+            );
+          }
+        };
+    */
+    NSDictionary *config;
+    NSDictionary *argspecs;
+    NSString     *selector;
+    BOOL         ctxParameter;
+
+    config = (NSDictionary *)_config;
+    
+    selector = [config objectForKey:@"name"];
+    if ([selector length] == 0) {
+      [self logWithFormat:
+             @"ERROR: missing 'name' in selector config of method '%@': %@",
+             _name, _config];
+      return nil;
+    }
+    
+    argspecs = [config objectForKey:@"arguments"];
+    
+    ctxParameter = [[config objectForKey:@"addContextParameter"]boolValue];
+    
+    method = [[SoSelectorInvocation alloc] init];
+    [method addSelectorNamed:selector];
+    [method setDoesAddContextParameter:ctxParameter];
+    [method setArgumentSpecifications:argspecs];
+  }
+  else {
+    [self logWithFormat:@"ERROR: cannot handle selector configuration: %@",
+           _config];
+    return nil;
+  }
+  return method;
+}
+
+- (id)cannotHandleManifest:(NSDictionary *)_m ofMethodNamed:(NSString *)_name {
+  /* no implementation provided */
+  if (loadDebugOn) {
+    /* 
+       note, a manifest does not need to contain the actual implementation
+       info, eg it can be used to just define the protections
+    */
+    [self logWithFormat:
+           @"Note: missing implemention info for method '%@' !", _name];
+  }
+  return nil;
+}
+
+- (BOOL)_loadManifest:(NSDictionary *)_m ofMethodNamed:(NSString *)_name {
+  NSString *mp;
+  NSString *selector;
+  id       method;
+  
+  /* security */
+  
+  if ((mp = [_m objectForKey:@"protectedBy"]))
+    [self->slotProtections setObject:mp forKey:_name];
+  
+  /* implementation */
+  
+  if ([self isPageInvocationManifest:_m])
+    method = [self makePageInvocationForMethodNamed:_name manifest:_m];
+  else if ((selector = [_m objectForKey:@"selector"]))
+    method = [self makeInvocationForMethodNamed:_name selector:selector];
+  else
+    method = [self cannotHandleManifest:_m ofMethodNamed:_name];
+  
+  if (method) {
+    [self->slotValues setObject:method forKey:_name];
+    [method release];
+  }
+  
+  return YES;
+}
+
+- (id)instantiateObjectOfClass:(Class)clazz withPlist:(id)value {
+  /* returns a retained instance */
+  
+  if ([value isKindOfClass:[NSDictionary class]]) {
+    if ([clazz instancesRespondToSelector:@selector(initWithDictionary:)])
+      return [[clazz alloc] initWithDictionary:value];
+  }
+  else if ([value isKindOfClass:[NSArray class]]) {
+    if ([clazz instancesRespondToSelector:@selector(initWithArray:)])
+      return [[clazz alloc] initWithArray:value];
+  }
+  else if ([value isKindOfClass:[NSData class]]) {
+    if ([clazz instancesRespondToSelector:@selector(initWithData:)])
+      return [[clazz alloc] initWithData:value];
+  }
+  else {
+    if ([clazz instancesRespondToSelector:@selector(initWithString:)])
+      return [[clazz alloc] initWithString:[value stringValue]];
+  }
+  
+  if ([clazz instancesRespondToSelector:
+               @selector(initWithPropertyList:owner:)])
+    return [[clazz alloc] initWithPropertyList:value owner:nil];
+  if ([clazz instancesRespondToSelector:@selector(initWithPropertyList:)])
+    return [[clazz alloc] initWithPropertyList:value];
+  
+  return nil;
+}
+
+- (BOOL)_loadManifest:(NSDictionary *)_m ofSlotNamed:(NSString *)_name {
+  NSString *mp;
+  NSString *valueClassName;
+  Class    valueClass;
+  id value;
+  
+  /* security */
+  
+  if ((mp = [_m objectForKey:@"protectedBy"]))
+    [self->slotProtections setObject:mp forKey:_name];
+  
+  if ((valueClassName = [[_m objectForKey:@"valueClass"] stringValue])) {
+    // TODO: hack, we need to load the bundle of the product to have the
+    //       contained classes available as valueClasses (But: shouldn't
+    //       that be already done by NGBundleManager?)
+    [[self->product bundle] load];
+    
+    // TODO: should we allow/use SoClasses here?
+    if ((valueClass = NSClassFromString(valueClassName)) == Nil) {
+      [self logWithFormat:
+             @"ERROR: did not find value class '%@' for slot: '%@'",
+             valueClassName, _name];
+      return NO;
+    }
+  }
+  else
+    valueClass = Nil;
+  
+  if ((value = [_m objectForKey:@"value"])) {
+    if (valueClass) {
+      value = [self instantiateObjectOfClass:valueClass withPlist:value];
+      
+      if (value == nil) {
+       [self logWithFormat:
+               @"ERROR: could not initialize value of slot %@ with class %@",
+               _name, valueClassName];
+       return NO;
+      }
+      value = [value autorelease];
+    }
+    else
+      /* pass through property list */;
+  }
+  else if (valueClass) {
+    /* 
+       Note: a manifest does not need to contain the actual value, eg it can be
+       used to just define the protections
+    */
+    if (loadDebugOn) 
+      [self logWithFormat:@"Note: slot no value: '%@'", _name];
+    
+    value = [[[valueClass alloc] init] autorelease];
+    if (value == nil) {
+      [self logWithFormat:
+             @"ERROR: could not initialize value of slot '%@' with class: %@",
+             _name, valueClassName];
+      return NO;
+    }
+  }
+  
+  if (value)
+    [self->slotValues setObject:value forKey:_name];
+  
+  return YES;
+}
+
+- (BOOL)_loadManifest:(NSDictionary *)_m {
+  NSDictionary *slots;
+  id tmp;
+  
+  [self reset];
+  self->protectedBy   = [[_m objectForKey:@"protectedBy"] copy];
+  self->defaultAccess = [[_m objectForKey:@"defaultAccess"] copy];
+  self->roleInfo      = [[_m objectForKey:@"defaultRoles"] copy];
+  
+  self->exactFilenames = [[_m objectForKey:@"exactFilenames"] copy];
+  
+  self->extensions = [[_m objectForKey:@"extensions"] copy];
+  if ((tmp = [_m objectForKey:@"extension"])) {
+    if (self->extensions == nil) {
+      self->extensions = [tmp isKindOfClass:[NSArray class]]
+       ? [tmp copy]
+       : [[NSArray alloc] initWithObjects:&tmp count:1];
+    }
+    else {
+      tmp = [tmp isKindOfClass:[NSArray class]]
+       ? [[self->extensions arrayByAddingObjectsFromArray:tmp] retain]
+       : [[self->extensions arrayByAddingObject:tmp] retain];
+      [self->extensions autorelease];
+      self->extensions = tmp;
+    }
+  }
+  
+  if (self->slotValues == nil)
+    self->slotValues = [[NSMutableDictionary alloc] init];
+  if (self->slotProtections == nil)
+    self->slotProtections = [[NSMutableDictionary alloc] init];
+  
+  if ((slots = [_m objectForKey:@"methods"])) {
+    NSEnumerator *names;
+    NSString *methodName;
+    
+    names = [slots keyEnumerator];
+    while ((methodName = [names nextObject])) {
+      NSDictionary *info;
+      
+      info = [slots objectForKey:methodName];
+      
+      if (![self _loadManifest:info ofMethodNamed:methodName])
+       [self logWithFormat:@"manifest of method %@ is broken.", methodName];
+    }
+  }
+  if ((slots = [_m objectForKey:@"slots"])) {
+    NSEnumerator *names;
+    NSString *slotName;
+    
+    names = [slots keyEnumerator];
+    while ((slotName = [names nextObject])) {
+      NSDictionary *info;
+      
+      info = [slots objectForKey:slotName];
+      
+      if (![self _loadManifest:info ofSlotNamed:slotName])
+       [self logWithFormat:@"manifest of slot %@ is broken.", slotName];
+    }
+  }
+  return YES;
+}
+
+@end /* SoProductSlotSetInfo(ManifestLoading) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoProductRegistry.h b/skyrix-sope/NGObjWeb/SoObjects/SoProductRegistry.h
new file mode 100644 (file)
index 0000000..aa217e1
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_SoProductRegistry_H__
+#define __SoObjects_SoProductRegistry_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSBundle.h>
+
+@class NSString, NSMutableDictionary, NSArray, NSBundle;
+@class SoProduct;
+
+@interface SoProductRegistry : NSObject
+{
+  NSMutableDictionary *products;
+  NSMutableDictionary *bundlePathToFirstName;
+}
+
++ (id)sharedProductRegistry;
+
+/* operations */
+
+- (void)scanForAvailableProducts;
+- (void)scanForProductsInDirectory:(NSString *)_path;
+- (void)registerProductAtPath:(NSString *)_path;
+
+/* registering products */
+
+- (BOOL)loadProductNamed:(NSString *)_name;
+- (BOOL)loadAllProducts;
+
+- (void)registerProductBundle:(NSBundle *)_bundle;
+
+/* lookup products */
+
+- (SoProduct *)productWithName:(NSString *)_name;
+- (NSArray *)registeredProductNames;
+
+/* bundle */
+
+- (SoProduct *)productForBundle:(NSBundle *)_bundle;
+
+@end
+
+#endif /* __SoObjects_SoProductRegistry_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoProductRegistry.m b/skyrix-sope/NGObjWeb/SoObjects/SoProductRegistry.m
new file mode 100644 (file)
index 0000000..a6632b4
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoProductRegistry.h"
+#include "SoProduct.h"
+#include "SoObject.h"
+#include "SoClassSecurityInfo.h"
+#include "common.h"
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOContext.h>
+
+@implementation SoProductRegistry
+
+static int debugOn = 0;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    debugOn = [ud boolForKey:@"SoProductRegistryDebugEnabled"] ? 1 : 0;
+  }
+}
+
++ (id)sharedProductRegistry {
+  static SoProductRegistry *reg = nil; // THREAD
+  if (reg == nil)
+    reg = [[SoProductRegistry alloc] init];
+  return reg;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    [self scanForAvailableProducts];
+
+    [[NSNotificationCenter defaultCenter]
+      addObserver:self selector:@selector(_bundleDidLoad:)
+      name:@"NSBundleDidLoadNotification" object:nil];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [self->bundlePathToFirstName release];
+  [self->products              release];
+  [super dealloc];
+}
+
+/* notifications */
+
+- (void)_bundleDidLoad:(NSNotification *)_notification {
+  /* 
+     If bundles are loaded by some other code, check whether they contain
+     SOPE products ...
+  */
+  [self registerProductBundle:[_notification object]];
+}
+
+/* operations */
+
+- (NSFileManager *)fileManager {
+  return [NSFileManager defaultManager];
+}
+
+- (void)registerProductBundle:(NSBundle *)_bundle {
+  NSString  *productName, *firstProductName, *bundlePath;
+  SoProduct *product;
+  NSString  *manifest;
+  
+  if (![_bundle isNotNull])
+    return;
+
+  bundlePath = [_bundle bundlePath];
+  
+  if (_bundle != [NSBundle mainBundle]) {
+    productName = 
+      [[bundlePath lastPathComponent] stringByDeletingPathExtension];
+  }
+  else
+    productName = @"MAIN";
+  
+  if ((product = [self->products objectForKey:productName])) {
+    [self debugWithFormat:@"product '%@' already registered.", productName];
+    [product reloadIfPossible];
+    return;
+  }
+  
+  firstProductName = 
+    [self->bundlePathToFirstName objectForKey:bundlePath];
+  if (firstProductName != nil) {
+    [self debugWithFormat:
+           @"Note: register bundle with a different name '%@': '%@'",
+           productName, bundlePath];
+    if ((product = [self->products objectForKey:firstProductName]) != nil) {
+      [self debugWithFormat:
+             @"add additional name '%@' (first %@) for product '%@'",
+             productName, firstProductName, product];
+      [self->products setObject:product forKey:productName];
+      return;
+    }
+    else {
+      [self logWithFormat:
+             @"WARNING: no product object for first name '%@' "
+             @"(name=%@,bundle=%@)",
+             firstProductName, productName, bundlePath];
+    }
+  }
+  
+  manifest = [_bundle pathForResource:@"product" ofType:@"plist"];
+  if ([manifest length] == 0) {
+    if ([productName isEqualToString:@"MAIN"])
+      [self debugWithFormat:@"  main bundle has no manifest."];
+    return;
+  }
+  
+  /* setup caches */
+  
+  if (self->products == nil)
+    self->products = [[NSMutableDictionary alloc] initWithCapacity:32];
+  if (self->bundlePathToFirstName == nil) {
+    self->bundlePathToFirstName = 
+      [[NSMutableDictionary alloc] initWithCapacity:32];
+  }
+  
+  /* register */
+  
+  [self debugWithFormat:@"register product bundle: '%@' (0x%08X[%@])", 
+         bundlePath, _bundle, NSStringFromClass([_bundle class])];
+  
+  [self debugWithFormat:@"  register as product: %@", productName];
+  
+  if ((product = [[SoProduct alloc] initWithBundle:_bundle]) == nil) {
+    [self debugWithFormat:@"  could not init product from bundle: %@", 
+           _bundle];
+    return;
+  }
+  
+  [self->bundlePathToFirstName setObject:productName forKey:bundlePath];
+  [self->products              setObject:product     forKey:productName];
+  [product release];
+}
+
+- (void)registerProductAtPath:(NSString *)_path {
+  static NGBundleManager *bm = nil;
+  NSBundle *bundle;
+  
+  if (![_path isNotNull])
+    return;
+  
+  if (bm == nil) bm = [[NGBundleManager defaultBundleManager] retain];
+  bundle = [bm bundleWithPath:_path];
+  
+  if (bundle == nil) {
+    [self logWithFormat:@"could not init bundle object for path: %@", _path];
+    return;
+  }
+  [self registerProductBundle:bundle];
+}
+
+- (void)scanForProductsInDirectory:(NSString *)_path {
+  NSFileManager *fm;
+  NSEnumerator  *pathes;
+  NSString      *lPath;
+  
+  fm = [self fileManager];
+  pathes = [[fm directoryContentsAtPath:_path] objectEnumerator];
+  while ((lPath = [pathes nextObject])) {
+    BOOL isDir;
+    
+    lPath = [_path stringByAppendingPathComponent:lPath];
+    
+    if (![fm fileExistsAtPath:lPath isDirectory:&isDir])
+      continue;
+    if (!isDir)
+      continue;
+    
+    [self registerProductAtPath:lPath];
+  }
+}
+
+- (void)scanForAvailableProducts {
+  NSFileManager *fm;
+  NSProcessInfo *pi;
+  NSArray  *pathes;
+  NSBundle *bundle;
+  unsigned i;
+
+  /* scan mail bundle & frameworks */
+  
+  if ((bundle = [NSBundle mainBundle]))
+    [self registerProductBundle:bundle];
+  else
+    NSLog(@"%s: missing main bundle ...", __PRETTY_FUNCTION__);
+  
+  pathes = [NSBundle allFrameworks];
+  for (i = 0; i < [pathes count]; i++)
+    [self registerProductBundle:[pathes objectAtIndex:i]];
+
+  pathes = [NSBundle allBundles];
+  for (i = 0; i < [pathes count]; i++)
+    [self registerProductBundle:[pathes objectAtIndex:i]];
+  
+  /* scan library pathes */
+  
+  fm = [NSFileManager defaultManager];
+  pi = [NSProcessInfo processInfo];
+  
+#if COCOA_Foundation_LIBRARY
+  /* 
+     TODO: (like COMPILE_FOR_GNUSTEP)
+     This should actually check whether we are compiling in the
+     GNUstep environment since this modifies the location of bundles.
+  */
+  pathes = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
+                                              NSAllDomainsMask,
+                                              YES);
+#else
+  pathes = [[pi environment] objectForKey:@"GNUSTEP_PATHPREFIX_LIST"];
+  if (pathes == nil)
+    pathes = [[pi environment] objectForKey:@"GNUSTEP_PATHLIST"];
+  
+  pathes = [[pathes stringValue] componentsSeparatedByString:@":"];
+#endif
+
+  if ([pathes count] == 0) {
+    [self debugWithFormat:@"found no product pathes."];
+    return;
+  }
+  
+  [self debugWithFormat:@"scanning for products ..."];
+  
+  for (i = 0; i < [pathes count]; i++) {
+    NSString *lPath;
+    BOOL     isDir;
+    
+    lPath = [pathes objectAtIndex:i];
+#if !COCOA_Foundation_LIBRARY
+    lPath = [lPath stringByAppendingPathComponent:@"Library"];
+#endif
+    lPath = [lPath stringByAppendingPathComponent:@"SoProducts"];
+    
+    if (![fm fileExistsAtPath:lPath isDirectory:&isDir])
+      continue;
+    if (!isDir)
+      continue;
+    
+    [self debugWithFormat:@"  directory %@", lPath];
+    [self scanForProductsInDirectory:lPath];
+  }
+  
+  [self debugWithFormat:
+         @"finished scan for products (%i products registered).",
+         [self->products count]];
+}
+
+/* registering products */
+
+- (BOOL)loadProductNamed:(NSString *)_name {
+  SoProduct    *product;
+  NSEnumerator *requiredProducts;
+  NSString     *rqname;
+  
+  if ((product = [self->products objectForKey:_name]) == nil) {
+    [self debugWithFormat:@"did not find product: %@", _name];
+    return NO;
+  }
+  
+  /* load dependencies (TODO: should detect cycles) */
+  requiredProducts = [[product requiredProducts] objectEnumerator];
+  while ((rqname = [requiredProducts nextObject])) {
+    if (![self loadProductNamed:rqname]) {
+      if ([rqname isEqualToString:@"MAIN"]) continue;
+      [self logWithFormat:@"ERROR: failed to load product %@ required by %@.",
+             rqname, _name];
+      return NO;
+    }
+  }
+  
+  return [product load];
+}
+
+- (BOOL)loadAllProducts {
+  NSEnumerator *e;
+  NSString *p;
+  
+  e = [self->products keyEnumerator];
+  while ((p = [e nextObject])) {
+    if (![self loadProductNamed:p])
+      [self logWithFormat:@"could not load product: %@", p];
+  }
+  return YES;
+}
+
+/* lookup products */
+
+- (NSArray *)registeredProductNames {
+  return [self->products allKeys];
+}
+- (SoProduct *)productWithName:(NSString *)_name {
+  return [self->products objectForKey:_name];
+}
+
+/* bundle */
+
+- (SoProduct *)productForBundle:(NSBundle *)_bundle {
+  /* TODO: add a registry based on path ... */
+  NSString  *pname, *bpath;
+  SoProduct *product;
+  
+  bpath = [_bundle bundlePath];
+  
+  /* check whether a name is cached for the bundle .. */
+  
+  pname = [self->bundlePathToFirstName objectForKey:bpath];
+  if ((product = [self productWithName:pname]) != nil)
+    return product;
+  
+  /* 'calculate' name of bundle */
+  
+  pname = [[bpath lastPathComponent] stringByDeletingPathExtension];
+  if ((product = [self productWithName:pname]) != nil)
+    return product;
+  
+  /* load missing product */
+  
+  [self logWithFormat:
+          @"product '%@' not yet registered, attempting to load ...", pname];
+  if (![self loadProductNamed:pname])
+    return nil;
+  return [self productWithName:pname];
+}
+
+/* product registry as a SoObject */
+
+- (NSArray *)allKeys {
+  return [self registeredProductNames];
+}
+
+- (BOOL)hasName:(NSString *)_key inContext:(id)_ctx {
+  if ([self->products objectForKey:_key])
+    return YES;
+  return [super hasName:_key inContext:_ctx];
+}
+
+- (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
+  SoProduct *product;
+  
+  if ((product = [self productWithName:_key]))
+    return product;
+  
+  return [super lookupName:_key inContext:_ctx acquire:_flag];
+}
+
+- (NSArray *)toOneRelationshipKeys {
+  NSMutableSet *ma;
+  id root;
+
+  if ((root = [super toOneRelationshipKeys]) == nil)
+    return [self->products allKeys];
+  
+  ma = [[NSMutableSet alloc] initWithArray:root];
+  [ma addObjectsFromArray:[self->products allKeys]];
+  root = [ma allObjects];
+  [ma release];
+  return root;
+}
+
+/* debugging */
+
+- (NSString *)loggingPrefix {
+  return @"[so-product-registry]";
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn ? YES : NO;
+}
+
+/* web representation */
+
+- (void)appendToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  NSEnumerator *e;
+  NSString *name;
+  
+  [_r appendContentString:@"<h3>SOPE Product Registry</h3>"];
+  
+  e = [[self toOneRelationshipKeys] objectEnumerator];
+  while ((name = [e nextObject])) {
+    [_r appendContentString:@"<li><a href=\""];
+    [_r appendContentHTMLAttributeValue:name];
+    [_r appendContentString:@"\">"];
+    [_r appendContentHTMLString:name];
+    [_r appendContentString:@"</a></li>"];
+  }    
+}
+
+@end /* SoProductRegistry */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoProductResourceManager.h b/skyrix-sope/NGObjWeb/SoObjects/SoProductResourceManager.h
new file mode 100644 (file)
index 0000000..df725b2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_SoProductResourceManager_H__
+#define __SoObjects_SoProductResourceManager_H__
+
+#include <NGObjWeb/WOResourceManager.h>
+
+/*
+  SoProductResourceManager
+  
+  A special resource-manager for products. Resources are delivered using
+  the ControlPanel URL, templates are properly found inside of the bundle.
+  
+  TODO: look for pages in different resource managers !
+*/
+
+@class SoProduct;
+
+@interface SoProductResourceManager : WOResourceManager
+{
+  SoProduct *product; /* non-retained */
+}
+
+- (id)initWithProduct:(SoProduct *)_product;
+
+@end
+
+#endif /* __SoObjects_SoProductResourceManager_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoProductResourceManager.m b/skyrix-sope/NGObjWeb/SoObjects/SoProductResourceManager.m
new file mode 100644 (file)
index 0000000..bd34fa3
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoProductResourceManager.h"
+#include "SoProduct.h"
+#include "SoObject.h"
+#include "SoClassSecurityInfo.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+@interface WOResourceManager(UsedPrivates)
+- (NSString *)webServerResourcesPath;
+- (NSString *)resourcesPath;
+@end
+
+@implementation SoProductResourceManager
+
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  debugOn = [ud boolForKey:@"SoProductResourceManagerDebugEnabled"];
+}
+
+- (id)initWithProduct:(SoProduct *)_product {
+  if ((self = [super initWithPath:[[_product bundle] bundlePath]])) {
+    self->product = _product;
+  }
+  return self;
+}
+
+/* containment */
+
+- (void)detachFromContainer {
+  self->product = nil;
+}
+- (id)container {
+  return self->product;
+}
+- (NSString *)nameInContainer {
+  return @"Resources";
+}
+
+/* generate URL for resources (eg filename binding in WOImage) */
+
+- (NSString *)webServerResourcesPath {
+  /* to avoid warning that WebServerResources path does not exist ... */
+  return [[[WOApplication application] resourceManager]
+                          webServerResourcesPath];
+}
+
+- (NSString *)urlForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages
+  request:(WORequest *)_request
+{
+  NSString *resource = nil, *tmp;
+  NSString *path = nil, *sbase;
+  unsigned len;
+  NSString *url;
+
+  if (debugOn) [self debugWithFormat:@"lookup url: '%@'", _name];
+  
+  if (_languages == nil) _languages = [_request browserLanguages];
+  
+  resource = [self pathForResourceNamed:_name
+                   inFramework:_frameworkName
+                   languages:_languages];
+#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+  if ([resource rangeOfString:@"/Contents/"].length > 0) {
+    resource = [resource stringByReplacingString:@"/Contents"
+                         withString:@""];
+  }
+#endif
+  //tmp = [resource stringByStandardizingPath];
+  //if (tmp) resource = tmp;
+
+  if (resource == nil)
+    return nil;
+  
+  sbase = self->base;
+  tmp  = [sbase commonPrefixWithString:resource options:0];
+  
+  len  = [tmp length];
+  path = [sbase    substringFromIndex:len];
+  tmp  = [resource substringFromIndex:len];
+  if (([path length] > 0) && ![tmp hasPrefix:@"/"] && ![tmp hasPrefix:@"\\"])
+    path = [path stringByAppendingString:@"/"];
+  path = [path stringByAppendingString:tmp];
+  
+#ifdef __WIN32__
+  {
+    NSArray *cs;
+    cs   = [path componentsSeparatedByString:@"\\"];
+    path = [cs componentsJoinedByString:@"/"];
+  }
+#endif
+  if (path == nil)
+    return nil;
+  
+  if ([path hasPrefix:@"/Resources/"])
+    path = [path substringFromIndex:11];
+  else if ([path hasPrefix:@"Resources/"])
+    path = [path substringFromIndex:10];
+  
+  /* Note: cannot use -stringByAppendingPathComponent: on OSX ! */
+  url = [self baseURLInContext:[[WOApplication application] context]];
+  if (debugOn) [self debugWithFormat:@" base: '%@'", url];
+  
+  if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
+  url = [url stringByAppendingString:path];
+  
+  if (debugOn) [self debugWithFormat:@"  => '%@'", url];
+  return url;
+}
+
+- (WOElement *)templateWithName:(NSString *)_name
+  languages:(NSArray *)_languages
+{
+  [self logWithFormat:@"lookup template with name '%@' (languages=%@)",
+         _name, [_languages componentsJoinedByString:@","]];
+  return [super templateWithName:_name languages:_languages];
+}
+
+/* resource manager as a SoObject */
+
+- (NSString *)mimeTypeForExtension:(NSString *)_ext {
+  // TODO: HACK, move to some object
+  NSString *ctype = nil;
+  
+  if ([_ext isEqualToString:@"css"])       ctype = @"text/css";
+  else if ([_ext isEqualToString:@"gif"])  ctype = @"image/gif";
+  else if ([_ext isEqualToString:@"jpg"])  ctype = @"image/jpeg";
+  else if ([_ext isEqualToString:@"png"])  ctype = @"image/png";
+  else if ([_ext isEqualToString:@"html"]) ctype = @"text/html";
+  else if ([_ext isEqualToString:@"xml"])  ctype = @"text/xml";
+  else if ([_ext isEqualToString:@"txt"])  ctype = @"text/plain";
+  else if ([_ext isEqualToString:@"js"])   ctype = @"application/x-javascript";
+  else if ([_ext isEqualToString:@"xhtml"]) ctype = @"application/xhtml+xml";
+  return ctype;
+}
+
+- (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
+  WOResponse *r;
+  NSBundle   *b;
+  NSString   *p, *pe, *ctype;
+  NSData     *data;
+  NSArray    *languages = nil;
+  
+  /* TODO: add support for languages (eg English.lproj/ok.gif) ! */
+  
+  /* check whether the resource is made public */
+  
+  if (![self->product isPublicResource:_key]) {
+    [self debugWithFormat:@"key '%@' is not declared a public resource.",_key];
+    return nil;
+  }
+  
+  if ((b = [self->product bundle]) == nil) {
+    [self debugWithFormat:@"product has no bundle for lookup of %@", _key];
+    return nil;
+  }
+  
+  pe = [_key pathExtension];
+
+  /* ask resource-manager (self) for path */
+  
+  languages = [_ctx hasSession]
+    ? [(WOSession *)[_ctx session] languages]
+    : [[(id <WOPageGenerationContext>)_ctx request] browserLanguages];
+  
+  p = [self pathForResourceNamed:_key 
+           inFramework:[b bundlePath]
+           languages:languages];
+  if (p == nil) {
+    [self logWithFormat:@"ERROR: did not find product resource: %@", _key];
+    return nil;
+  }
+
+  /* load data */
+
+  if ((data = [NSData dataWithContentsOfMappedFile:p]) == nil) {
+    [self logWithFormat:@"ERROR: failed to load product resource: %@", _key];
+    return nil;
+  }
+  
+  /* and deliver as a complete response */
+  
+  r = [(id<WOPageGenerationContext>)_ctx response];
+  
+  [r setStatus:200 /* OK */];
+  [r setContent:data];
+  
+  if ((ctype = [self mimeTypeForExtension:pe]) == nil) {
+    [self logWithFormat:
+           @"WARNING: did not recognize extension '%@', "
+           @"delivering as application/octet-stream.", pe];
+    ctype = @"application/octet-stream";
+  }
+
+  {
+    NSDate *expDate = nil;
+    NSString *str = nil;
+    
+    expDate = [[NSDate alloc] initWithTimeInterval:(60 * 60 * 1) /* 1 hour */
+                             sinceDate:[NSDate date]];
+    str = [expDate descriptionWithCalendarFormat:
+                    @"%a, %d %b %Y %H:%M:%S GMT"
+                  timeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]
+                  locale:nil];
+    [r setHeader:str forKey:@"expires"];
+    [expDate release];
+  }
+  
+  [r setHeader:ctype forKey:@"content-type"];
+  return r;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* SoProductResourceManager */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoSecurityException.h b/skyrix-sope/NGObjWeb/SoObjects/SoSecurityException.h
new file mode 100644 (file)
index 0000000..4e3b3d9
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoSecurityException_H__
+#define __SoObjects_SoSecurityException_H__
+
+#import <Foundation/NSException.h>
+
+@class SoSecurityManager;
+
+@interface SoSecurityException : NSException
+{
+  SoSecurityManager *securityManager;
+  id authenticator;
+  id object;
+}
+
++ (id)securityExceptionOnObject:(id)_object
+  withAuthenticator:(id)_auth
+  andManager:(id)_manager;
+- (id)initWithObject:(id)_object authenticator:(id)_auth manager:(id)_manager;
+
+- (SoSecurityManager *)securityManager;
+- (id)authenticator;
+- (id)object;
+
+@end
+
+@interface SoAuthRequiredException : SoSecurityException
+@end
+
+@interface SoAccessDeniedException : SoSecurityException
+@end
+
+#endif /* __SoObjects_SoSecurityException_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoSecurityException.m b/skyrix-sope/NGObjWeb/SoObjects/SoSecurityException.m
new file mode 100644 (file)
index 0000000..4d44b76
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoSecurityException.h"
+#include "SoSecurityManager.h"
+#include "common.h"
+
+@implementation SoSecurityException
+
++ (id)securityExceptionOnObject:(id)_o 
+  withAuthenticator:(id)_a 
+  andManager:(id)_m 
+{
+  return [[[self alloc] 
+           initWithObject:_o authenticator:_a manager:_m] autorelease];
+}
+- (id)initWithObject:(id)_object authenticator:(id)_auth manager:(id)_manager {
+  NSString *n, *r;
+  
+  if ((n = [self name]) == nil)
+    n = NSStringFromClass([self class]);
+  if ((r = [self reason]) == nil)
+    r = @"generic security exception";
+  
+  if ((self = [super initWithName:n reason:r userInfo:nil])) {
+    self->object          = [_object  retain];
+    self->authenticator   = [_auth    retain];
+    self->securityManager = [_manager retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->object          release];
+  [self->securityManager release];
+  [self->authenticator   release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (SoSecurityManager *)securityManager {
+  return self->securityManager;
+}
+- (id)authenticator {
+  return self->authenticator;
+}
+- (id)object {
+  return self->object;
+}
+
+@end /* SoSecurityManager */
+
+@implementation SoAuthRequiredException
+
+- (unsigned short)httpStatus {
+  return 401;
+}
+
+- (NSString *)name {
+  return @"SoAuthRequired";
+}
+- (NSString *)reason {
+  return @"authentication required";
+}
+
+@end /* SoAuthRequiredException */
+
+@implementation SoAccessDeniedException
+
+- (unsigned short)httpStatus {
+  return 403;
+}
+
+@end /* SoAccessDeniedException */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoSecurityManager.h b/skyrix-sope/NGObjWeb/SoObjects/SoSecurityManager.h
new file mode 100644 (file)
index 0000000..c20e903
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoSecurityManager_H__
+#define __SoObjects_SoSecurityManager_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoSecurityManager
+  
+  This is the central object for security management.
+  [TODO: more docu]
+  
+  Note: security info is associated with SoClasses using SoClassSecurityInfo
+  objects. Take a look in the SoClassSecurityInfo.h header file for more
+  information.
+*/
+
+@class NSString, NSArray, NSException;
+
+@protocol SoUserDatabase // TODO: what about that ?
+@end
+
+@interface SoSecurityManager : NSObject
+{
+}
+
++ (id)sharedSecurityManager;
+
+/* validation */
+
+- (NSException *)validatePermission:(NSString *)_perm
+  onObject:(id)_object 
+  inContext:(id)_ctx;
+
+- (NSException *)validateObject:(id)_object inContext:(id)_ctx;
+
+- (NSException *)validateName:(NSString *)_key 
+  ofObject:(id)_object
+  inContext:(id)_ctx;
+
+- (NSException *)validateValue:(id)_value
+  forName:(NSString *)_key 
+  ofObject:(id)_object
+  inContext:(id)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoSecurityManager_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoSecurityManager.m b/skyrix-sope/NGObjWeb/SoObjects/SoSecurityManager.m
new file mode 100644 (file)
index 0000000..ad2de07
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoSecurityManager.h"
+#include "SoObject.h"
+#include "SoClass.h"
+#include "SoClassSecurityInfo.h"
+#include "SoPermissions.h"
+#include "SoUser.h"
+#include "SoSecurityException.h"
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@interface NSObject(WOAppAuth)
+- (BOOL)isPublicInContext:(id)_ctx;
+@end
+
+@interface NSObject(UserDB)
+- (id)userInContext:(WOContext *)_ctx;
+@end
+
+@interface NSString(SpecialPermissionChecks)
+- (BOOL)isSoPublicPermission;
+- (BOOL)isSoAnonymousUserLogin;
+@end
+
+static NSString *SoActiveUser     = @"SoActiveUser";
+static NSString *SoObjPermCache   = @"__validatedobjs";
+#if USE_PERM_CACHE
+static NSString *SoPermCache      = @"__validatedperms";
+#endif
+
+@implementation SoSecurityManager
+
+static int debugOn = -1;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  debugOn = [ud boolForKey:@"SoSecurityManagerDebugEnabled"] ? 1 : 0;
+}
+
++ (id)sharedSecurityManager {
+  static SoSecurityManager *sharedManager = nil; // THREAD
+  
+  if (sharedManager == nil)
+    sharedManager = [[SoSecurityManager alloc] init];
+  return sharedManager;
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* exceptions */
+
+- (NSException *)makeExceptionForObject:(id)_obj reason:(NSString *)_r {
+  NSException *e;
+  if (_obj == nil) return nil;
+  e = [SoAccessDeniedException securityExceptionOnObject:_obj
+                              withAuthenticator:nil
+                              andManager:self];
+  if ([_r length] > 0) [e setReason:_r];
+  return e;
+}
+
+- (NSException *)isPrivateExceptionForObject:(id)_object {
+  return [self makeExceptionForObject:_object 
+              reason:@"tried to access private object"];
+}
+- (NSException *)missingPermissionException:(NSString *)_perm 
+  forObject:(id)_object
+{
+  return [self makeExceptionForObject:_object 
+              reason:@"missing object permission"];
+}
+
+- (NSException *)isPrivateKeyException:(NSString *)_key ofObject:(id)_object {
+  NSException *e;
+  NSString    *s;
+  
+  s = [[NSString alloc] initWithFormat:
+                         @"tried to access private key '%@' of object: %@",
+                         _key, _object];
+  e = [self makeExceptionForObject:_object reason:s];
+  [s release];
+  return e;
+}
+
+/* secinfo lookup */
+
+- (SoClassSecurityInfo *)lookupInfoOfClass:(SoClass *)_soClass
+  condition:(SEL)_sel
+  object:(id)_object
+{
+  SoClass *soClass;
+  
+  for (soClass = _soClass; soClass; soClass = [soClass soSuperClass]) {
+    SoClassSecurityInfo *sinfo;
+    IMP m;
+    
+    if ((sinfo = [soClass soClassSecurityInfo]) == nil) continue;
+    if ((m = [sinfo methodForSelector:_sel])) {
+      BOOL ok;
+      
+      ok = (_object)
+       ? ((BOOL (*)(id, SEL, id))m)(sinfo, _sel, _object)
+       : ((BOOL (*)(id, SEL))m)(sinfo, _sel);
+      if (ok) return sinfo;
+    }
+  }
+  return nil;
+}
+
+/* validation */
+
+- (id)authenticatorInContext:(id)_ctx object:(id)_object {
+  id authenticator;
+
+  if ((authenticator = [_object authenticatorInContext:_ctx]) == nil)
+    authenticator = [[WOApplication application] authenticatorInContext:_ctx];
+  return authenticator;
+}
+- (id<SoUser>)userInContext:(id)_ctx object:(id)_object {
+  id user, authenticator;
+  
+  if ((user = [(WOContext *)_ctx objectForKey:SoActiveUser]))
+    return [user isNotNull] ? user : nil;
+  
+  authenticator = [self authenticatorInContext:_ctx object:_object];
+    
+  if ((user = [authenticator userInContext:_ctx]))
+    [(WOContext *)_ctx setObject:user forKey:SoActiveUser];
+  
+  return [user isNotNull] ? user : nil;
+}
+
+- (BOOL)isUser:(id<SoUser>)_user ownerOfObject:(id)_obj inContext:(id)_ctx {
+  NSString *objectOwner;
+  
+  if ((objectOwner = [_obj ownerInContext:_ctx]) == nil)
+    return NO;
+  
+  if ([[_user login] isEqualToString:objectOwner])
+    return YES;
+  
+  return NO;
+}
+
+- (NSException *)validatePermission:(NSString *)_perm
+  onObject:(id)_object 
+  inContext:(id)_ctx
+{
+  NSMutableDictionary *validatedPerms;
+  NSArray             *rolesHavingPermission;
+  SoClassSecurityInfo *sinfo;
+  id<SoUser> user;
+  NSArray      *userRoles;
+  NSEnumerator *e;
+  NSString     *role;
+  
+  if (_perm == nil)
+    return [self missingPermissionException:_perm forObject:_object];
+  
+#if !USE_PERM_CACHE
+  validatedPerms = nil;
+#else
+  // TODO: Bug !! The cache must go on Permission+ObjectID since the
+  //              permission can be set without the ID !
+  
+  /* check the cache */
+  if ((validatedPerms = [_ctx objectForKey:SoPermCache])) {
+    NSException *o;
+  
+    if ((o = [validatedPerms objectForKey:_perm])) {
+      if (debugOn)
+       [self debugWithFormat:@"permission '%@' cached as valid ...", _perm];
+      
+      if ([o isNotNull])
+       /* an exception */
+       return o;
+      return nil;
+    }
+  }
+  else {
+    /* setup cache */
+    validatedPerms = [[NSMutableDictionary alloc] init];
+    [_ctx setObject:validatedPerms forKey:SoPermCache];
+    [validatedPerms autorelease];
+  }
+#endif
+  
+  if (debugOn) {
+    [self debugWithFormat:@"validate permission '%@' on object: %@",
+           _perm, _object];
+  }
+  
+  if ([_perm isSoPublicPermission])
+    /* the object is public */
+    goto found;
+  
+  /* determine the possible roles for the permission */
+  
+  // TODO: check object for policy (currently only default roles are checked)
+  
+  sinfo = [self lookupInfoOfClass:[_object soClass] 
+               condition:@selector(hasDefaultRoleForPermission:)
+               object:_perm];
+  
+  if (sinfo == nil)
+    sinfo = [[_object soClass] soClassSecurityInfo];
+  
+  rolesHavingPermission = [sinfo defaultRolesForPermission:_perm];
+  if (debugOn) {
+    [self debugWithFormat:@"  possible roles for permission '%@': %@",
+           _perm, [rolesHavingPermission componentsJoinedByString:@", "]];
+  }
+  
+  if ([rolesHavingPermission containsObject:SoRole_Anonymous]) {
+    /* is public */
+    [self debugWithFormat:@"  allowed because of anonymous roles."];
+    goto found;
+  }
+  if ([rolesHavingPermission count] == 0) {
+    /* is public */
+    [self debugWithFormat:@"  allowed because no roles are required."];
+    goto found;
+  }
+  
+  /* now retrieve the user that is logged in */
+  
+  if ((user = [self userInContext:_ctx object:_object]) == nil) {
+    /* no user, anonymous */
+    [self debugWithFormat:@"  got no user (=> auth required)."];
+    return [SoAuthRequiredException securityExceptionOnObject:_object
+                                   withAuthenticator:
+                                     [self authenticatorInContext:_ctx 
+                                           object:_object]
+                                   andManager:self];
+  }
+  
+  [self debugWithFormat:@"  got user: %@)", user];
+  
+  /* process user */
+  
+  userRoles = [user rolesForObject:_object inContext:_ctx];
+  [self debugWithFormat:@"    user roles: %@", 
+        [userRoles componentsJoinedByString:@","]];
+  if ([userRoles count] == 0)
+    return [self isPrivateExceptionForObject:_object];
+    
+  /* now check whether the roles subset */
+      
+  e = [userRoles objectEnumerator];
+  while ((role = [e nextObject])) {
+    if ([rolesHavingPermission containsObject:role]) {
+      /* found role ! */
+      break;
+    }
+  }
+    
+  /* if no role was found, check whether the user is the owner */
+    
+  if (role == nil) {
+    if ([rolesHavingPermission containsObject:SoRole_Owner]) {
+      if ([self isUser:user ownerOfObject:_object inContext:_ctx]) {
+        role = SoRole_Owner;
+        [self debugWithFormat:@"    user is owner of object."];
+      }
+      else if ([_object ownerInContext:_ctx] == nil) {
+        role = SoRole_Owner;
+        [self debugWithFormat:@"    object is not owned, grant access."];
+      }
+      else {
+        role = nil;
+        [self debugWithFormat:
+                @"    user is not the owner of object (owner=%@).",
+              [_object ownerInContext:_ctx]];
+      }
+    }
+  }
+    
+  /* check whether a role was finally found */
+    
+  if (role == nil) {
+    [self debugWithFormat:@"    found no matching role."];
+    
+    if ([[user login] isSoAnonymousUserLogin]) {
+      [self debugWithFormat:@"still anonymous, requesting login ..."];
+      return [SoAuthRequiredException securityExceptionOnObject:_object
+                                      withAuthenticator:
+                                        [self authenticatorInContext:_ctx
+                                              object:_object]
+                                      andManager:self];
+    }
+    else {
+      /* 
+         Note: AFAIK Zope will present the user a login panel in any
+         case. IMHO this is not good in practice (you don't change
+         identities very often ;-), and the 403 code has it's value too.
+      */
+      [self debugWithFormat:@"valid user, denying access ..."];
+      return [self isPrivateExceptionForObject:_object];
+    }
+  }
+    
+  [self debugWithFormat:@"    found a valid role: '%@'.", role];
+  
+ found:
+  [self debugWithFormat:@"  successfully validated permission '%@'.", _perm];
+  [validatedPerms setObject:[NSNull null] forKey:_perm];
+  return nil;
+}
+
+- (NSException *)validateObject:(id)_object inContext:(id)_ctx {
+  /* This methods check how the object itself is protected. */
+  NSMutableArray      *validatedObjects;
+  SoClassSecurityInfo *sinfo;
+  NSString            *perm;
+  NSException *e;
+  
+  if (_object == nil) return nil;
+  
+  /* some objects are always public */
+  if ([_object isPublicInContext:_ctx])
+    return nil;
+  
+  /* check the cache */
+  if ((validatedObjects = [(WOContext *)_ctx objectForKey:SoObjPermCache])) {
+    if ([validatedObjects indexOfObjectIdenticalTo:_object] != NSNotFound)
+      return nil;
+  }
+  else {
+    /* setup cache */
+    validatedObjects = [[NSMutableArray alloc] init];
+    [(WOContext *)_ctx setObject:validatedObjects forKey:SoObjPermCache];
+    [validatedObjects autorelease];
+  }
+  
+  [self debugWithFormat:@"validate object: %@", _object];
+  
+  /* find the security info which has object protections */
+  sinfo = [self lookupInfoOfClass:[_object soClass] 
+               condition:@selector(hasObjectProtections)
+               object:nil];
+  if (sinfo == nil) {
+    [self debugWithFormat:
+           @"found no security info with object protection for object "
+           @"(rejecting access):\n  object: %@\n  class: %@\n  soclass: %@)", 
+           _object, NSStringFromClass([_object class]), [_object soClass]];
+    return [self isPrivateExceptionForObject:_object];
+  }
+  
+  if ([sinfo isObjectPublic]) {
+    /* object is public ... */
+    [self debugWithFormat:@"  object is public."];
+    [validatedObjects addObject:_object];
+    return nil;
+  }
+  
+  if ([sinfo isObjectPrivate]) {
+    /* object is private ... */
+    [self debugWithFormat:@"  object is private."];
+    return [self isPrivateExceptionForObject:_object];
+  }
+  
+  perm = [sinfo permissionRequiredForObject];
+  if ((e = [self validatePermission:perm onObject:_object inContext:_ctx]))
+    return e;
+  
+  [self debugWithFormat:@"  successfully validated object (perm=%@).", perm];
+  [validatedObjects addObject:_object];
+  return nil;
+}
+
+- (NSException *)validateName:(NSString *)_key 
+  ofObject:(id)_object
+  inContext:(id)_ctx
+{
+  /* note: this does not check object-value restrictions */
+  SoClassSecurityInfo *sinfo;
+  NSException *e;
+  NSString    *perm;
+  
+  /* step a: find out permission required for object */
+  
+  if ((e = [self validateObject:_object inContext:_ctx])) {
+    [self debugWithFormat:@"  object did not validate (tried lookup on %@).",
+           _key];
+    return e;
+  }
+  
+  /* step b: find out permission required for key */
+  
+  [self debugWithFormat:@"validate key %@ of object: %@", _key, _object];
+  
+  /* find the security info which has protections for the key */
+  sinfo = [self lookupInfoOfClass:[_object soClass]
+               condition:@selector(hasProtectionsForKey:)
+               object:_key];
+  
+  if (sinfo == nil) {
+    /* found no security for key, so we take the defaults */
+    [self debugWithFormat:@"  found no security info for key (class %@): %@",
+           NSStringFromClass([_object class]), _key];
+    
+    sinfo = [self lookupInfoOfClass:[_object soClass]
+                 condition:@selector(hasDefaultAccessDeclaration)
+                 object:nil];
+    
+    // TODO: search superclasses for one with declared default-access
+    if ([[sinfo defaultAccess] isEqualToString:@"allow"]) {
+      [self debugWithFormat:@"  default is allow ..."];
+      return nil;
+    }
+    return [self isPrivateKeyException:_key ofObject:_object];
+  }
+  
+  if ([sinfo isKeyPublic:_key])
+    return nil;
+  
+  if ([sinfo isKeyPrivate:_key])
+    /* key is private ... */
+    return [self isPrivateKeyException:_key ofObject:_object];
+  
+  perm = [sinfo permissionRequiredForKey:_key];
+  if ((e = [self validatePermission:perm onObject:_object inContext:_ctx]))
+    return e;
+  
+  [self debugWithFormat:@"  successfully validated key (%@).", _key];
+  return nil;
+}
+
+- (NSException *)validateValue:(id)_value
+  forName:(NSString *)_key 
+  ofObject:(id)_object
+  inContext:(id)_ctx
+{
+  /* this additionally checks object restrictions of the value */
+  if (_value) {
+    NSException *e;
+    
+    if ((e = [self validateObject:_value inContext:_ctx])) {
+      [self debugWithFormat:@"value (0x%08X,%@) of key %@ didn't validate",
+             _value, NSStringFromClass([_value class]), _key];
+      return e;
+    }
+  }
+  return [self validateName:_key ofObject:_object inContext:_ctx];
+}
+
+@end /* SoSecurityManager */
+
+@implementation SoSecurityManager(Logging)
+// Note: this is a category, so that its more difficult to override (of course
+//       still not impossible ...
+
+- (NSString *)loggingPrefix {
+  return @"[so-security]";
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn ? YES : NO;
+}
+
+@end /* SoSecurityManager(Logging) */
+
+
+/* public objects */
+
+@implementation NSObject(Pub)
+- (BOOL)isPublicInContext:(id)_ctx { return NO; }
+@end
+
+@implementation NSArray(Pub)
+- (BOOL)isPublicInContext:(id)_ctx { return YES; }
+@end
+
+@implementation NSString(Pub)
+- (BOOL)isPublicInContext:(id)_ctx { return YES; }
+@end
+
+@implementation NSDictionary(Pub)
+- (BOOL)isPublicInContext:(id)_ctx { return YES; }
+@end
+
+@implementation NSException(Pub)
+- (BOOL)isPublicInContext:(id)_ctx { return YES; }
+@end
+
+@implementation NSString(SpecialPermissionChecks)
+
+- (BOOL)isSoPublicPermission {
+  return [@"<public>" isEqualToString:self];
+}
+- (BOOL)isSoAnonymousUserLogin {
+  return [@"anonymous" isEqualToString:self];
+}
+
+@end /* NSString(SpecialPermissionChecks) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoSelectorInvocation.h b/skyrix-sope/NGObjWeb/SoObjects/SoSelectorInvocation.h
new file mode 100644 (file)
index 0000000..6d3582d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_SoSelectorInvocation_H__
+#define __SoObjects_SoSelectorInvocation_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  An invocation object for Objective-C selector based SoClass methods. Multiple
+  selectors can map to a single SoClass method because those methods have a
+  name independend from the arguments.
+*/
+
+@class NSString, NSDictionary;
+
+@interface SoSelectorInvocation : NSObject
+{
+  SEL sel;
+  int argCount;
+  struct {
+    int addContextParameter:1;
+    int reserved:31;
+  } flags;
+  /* for bound invocations */
+  IMP method;
+  id  object;
+  
+  NSDictionary *argumentSpecifications;
+}
+
+- (id)initWithSelectorNamed:(NSString *)_sel addContextParameter:(BOOL)_f;
+
+/* configuration */
+
+- (void)addSelectorNamed:(NSString *)_name;
+
+- (void)setDoesAddContextParameter:(BOOL)_flag;
+- (BOOL)doesAddContextParameter;
+
+- (void)setArgumentSpecifications:(NSDictionary *)_specs;
+- (NSDictionary *)argumentSpecifications;
+
+/* binding */
+
+- (BOOL)isBound;
+- (id)bindToObject:(id)_object inContext:(id)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoSelectorInvocation_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoSelectorInvocation.m b/skyrix-sope/NGObjWeb/SoObjects/SoSelectorInvocation.m
new file mode 100644 (file)
index 0000000..0cde44c
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoSelectorInvocation.h"
+#include "SoClassSecurityInfo.h"
+#include "NSException+HTTP.h"
+#include "WOContext+SoObjects.h"
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOContext.h>
+#include <DOM/EDOM.h>
+#include "common.h"
+
+@implementation SoSelectorInvocation
+
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  /* per default selector invocations are public */
+  [[self soClassSecurityInfo] declareObjectPublic];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    [self setDoesAddContextParameter:YES];
+  }
+  return self;
+}
+
+- (id)initWithSelectorNamed:(NSString *)_sel addContextParameter:(BOOL)_wc {
+  if ((self = [self init])) {
+    [self addSelectorNamed:_sel];
+    [self setDoesAddContextParameter:_wc];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->argumentSpecifications release];
+  [self->object release];
+  [super dealloc];
+}
+
+/* containment */
+
+- (void)detachFromContainer {
+}
+- (id)container {
+  return nil;
+}
+- (NSString *)nameInContainer {
+  return nil;
+}
+
+/* configuration */
+
+- (void)addSelectorNamed:(NSString *)_name {
+  unsigned len;
+  
+  if ((len = [_name length]) == 0) 
+    return;
+  if (self->sel != NULL) {
+    [self logWithFormat:@"not yet ready for operator overloading (%@).",
+           _name];
+    return;
+  }
+  
+  /* count arguments (do we have something like this as a string method?) */
+  
+  self->argCount = 0;
+  while (len > 0) {
+    len--;
+    
+    if ([_name characterAtIndex:len] == ':')
+      self->argCount++;
+  }
+  
+  if ((self->sel = NSSelectorFromString(_name)) == NULL) {
+    /* this can happen if the product bundle is not yet loaded ... */
+#if GNU_RUNTIME
+    const char *sname = [_name cString];
+    if ((self->sel = sel_get_any_uid(sname)) == NULL)
+      self->sel = sel_register_name(sname);
+#else
+    /* TODO: not tested against this ObjC runtime */
+    NSLog(@"WARNING(%s): not tested against this ObjC runtime, "
+          @"product bundle loading may be broken.", __PRETTY_FUNCTION__);
+#endif
+  }
+  if (self->sel == NULL)
+    [self logWithFormat:@"WARNING: did not find selector: %@", _name];
+}
+
+- (void)setDoesAddContextParameter:(BOOL)_flag {
+  self->flags.addContextParameter = _flag ? 1 : 0;
+}
+- (BOOL)doesAddContextParameter {
+  return self->flags.addContextParameter ? YES : NO;
+}
+
+- (void)setArgumentSpecifications:(NSDictionary *)_specs {
+  ASSIGNCOPY(self->argumentSpecifications, _specs);
+}
+- (NSDictionary *)argumentSpecifications {
+  return self->argumentSpecifications;
+}
+
+/* error objects */
+
+- (NSException *)unsupportedSelectorError:(SEL)_sel {
+  return [NSException exceptionWithHTTPStatus:500 /* Server Error */
+                     reason:@"tried to call unsupported selector"];
+}
+
+- (NSException *)noSelectorForArgumentCountError:(unsigned)_callArgCount {
+  NSString *s;
+
+  s = [NSString stringWithFormat:
+                 @"incorrect argument count for SOPE method: "
+                 @"required %i for %@, got %i", 
+                 self->argCount, NSStringFromSelector(self->sel), 
+                 _callArgCount];
+  return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
+                     reason:s];
+}
+
+/* arguments */
+
+- (NSArray *)extractSOAPArgumentsFromContext:(id)_ctx specification:(id)_spec {
+  /* spec is supposed to be an array of DOM query pathes ... */
+  NSMutableArray *args;
+  unsigned       i, count;
+  id             soapEnvelope;
+  
+  // TODO: I guess that should be improved a bit in the dispatcher
+  if ((soapEnvelope = [_ctx valueForKey:@"SOAPEnvelope"]) == nil) {
+    // TODO: generate some kind of fault? (NSException?)
+    [self logWithFormat:@"ERROR: no SOAP envelope available in context!"];
+    return nil;
+  }
+  
+  /* for each positional selector argument we have a query path */
+  count = [_spec count];
+  args  = [NSMutableArray arrayWithCapacity:count];
+  for (i = 0; i < count; i++) {
+    NSString *qppath;
+    id value;
+    
+    qppath = [_spec objectAtIndex:i];
+    value  = [qppath isNotNull] ? [soapEnvelope lookupQueryPath:qppath] : nil;
+    
+    [args addObject:(value != nil ? value : [NSNull null])];
+  }
+  return args;
+}
+
+- (NSArray *)extractArgumentsFromContext:(id)_ctx
+  forRequestType:(NSString *)_type
+  specification:(id)_spec 
+{
+  if ([_type isEqualToString:@"SOAP"])
+    return [self extractSOAPArgumentsFromContext:_ctx specification:_spec];
+  
+  [self logWithFormat:
+         @"ERROR: cannot extract parameters for request type: '%@'", _type];
+  return nil;
+}
+
+/* invocation */
+
+- (BOOL)isCallable {
+  return YES;
+}
+- (id)clientObject {
+  return self->object;
+}
+
+- (id)primaryCallSelector:(SEL)_sel withArguments:(NSArray *)_args {
+  unsigned     i, callArgCount;
+  NSInvocation *inv;
+  id result;
+  
+  if (self->object == nil || _sel == NULL)
+    return nil;
+  
+  if (![self->object respondsToSelector:_sel]) {
+    [self logWithFormat:
+           @"Object does not support selector %@, probably broken "
+           @"product.plist file.",
+           NSStringFromSelector(_sel)];
+    return [self unsupportedSelectorError:_sel];
+  }
+  
+  callArgCount = [_args count];
+  
+  /* use primitives if possible */
+  
+  if (callArgCount == 0)
+    return [self->object performSelector:_sel];
+  if (callArgCount == 1) {
+    return [self->object performSelector:_sel
+               withObject:[_args objectAtIndex:0]];
+  }
+  if (callArgCount == 2) {
+    return [self->object performSelector:_sel 
+               withObject:[_args objectAtIndex:0] 
+               withObject:[_args objectAtIndex:1]];
+  }
+  
+  /* construct NSInvocation */
+
+  // TODO: do security audit, can this lead to "issues"? (should not)
+  
+  inv = [NSInvocation invocationWithMethodSignature:
+                       [self->object methodSignatureForSelector:_sel]];
+  [inv setSelector:_sel];
+  [inv setTarget:self->object];
+  
+  for (i = 0; i < callArgCount; i++) {
+    id arg;
+    
+    arg = [_args objectAtIndex:i];
+    [inv setArgument:&arg atIndex:(i + 2)];
+  }
+  
+  NS_DURING {
+    [inv invoke];
+    [inv getReturnValue:&result];
+  }
+  NS_HANDLER
+    result = [[localException retain] autorelease];
+  NS_ENDHANDLER;
+  return result;
+}
+
+- (SEL)selectorForNumberOfArguments:(unsigned)_argcount {
+#if 1
+  // for now, we require an exact match
+  return self->argCount == _argcount ? self->sel : NULL;
+#else
+  // we fill up missing args with nil/NSNull (TODO: prior validation!)
+  return self->argCount >= _argcount ? self->sel : NULL;
+#endif
+}
+
+- (id)callOnObject:(id)_client inContext:(id)_ctx {
+  /* call method for keyword arguments or other stuff */
+  NSArray      *args;
+  NSDictionary *argspec;
+  SEL          selector;
+  
+  /* do not rebind, this breaks if client!=lookup */
+  if (self->object == nil) {
+    /* bind on demand */
+    return [[self bindToObject:_client inContext:_ctx]
+                 callOnObject:_client inContext:_ctx];
+  }
+
+  /* process arguments */
+  
+  args    = nil;
+  argspec = [self->argumentSpecifications objectForKey:[_ctx soRequestType]];
+  if (argspec == nil) {
+    /* no argument extractors defined */
+    if (debugOn) {
+      [self debugWithFormat:@"no arg type spec for type: '%@'",
+             [_ctx soRequestType]];
+    }
+    if ([self doesAddContextParameter])
+      args = [NSArray arrayWithObject:(_ctx ? _ctx : [NSNull null])];
+  }
+  else {
+    args = [self extractArgumentsFromContext:_ctx
+                forRequestType:[_ctx soRequestType]
+                specification:argspec];
+    if (debugOn) [self debugWithFormat:@"extracted args %@", args];
+    if ([self doesAddContextParameter]) {
+      args = args != nil
+       ? [args arrayByAddingObject:(_ctx ? _ctx : [NSNull null])]
+       : [NSArray arrayWithObject:(_ctx ? _ctx : [NSNull null])];
+    }
+  }
+  
+  /* find selector */
+  
+  selector = [self selectorForNumberOfArguments:[args count]];
+  if (selector == NULL) {
+    [self logWithFormat:@"WARNING: missing selector for invocation!"];
+    return [self noSelectorForArgumentCountError:[args count]];
+  }
+  
+  // TODO: check whether this is really a "context invocation"
+  // TODO: check number of arguments
+
+  /* invoke */
+  
+  /* if prebound, call on the bound object, not on the client ! */
+  return [self primaryCallSelector:self->sel withArguments:args];
+}
+
+- (id)callOnObject:(id)_client 
+  withPositionalParameters:(NSArray *)_args
+  inContext:(id)_ctx
+{
+  /* call method for positional parameters */
+  SEL      selector;
+  unsigned callArgCount;
+  
+  if (self->object == nil) {
+    /* bind on demand */
+    return [[self bindToObject:_client inContext:_ctx]
+                 callOnObject:_client 
+                 withPositionalParameters:_args inContext:_ctx];
+  }
+  
+  callArgCount = [_args count];
+  if ([self doesAddContextParameter]) callArgCount++;
+  
+  if ((selector = [self selectorForNumberOfArguments:callArgCount]) == NULL) {
+    [self logWithFormat:@"WARNING: missing selector for invocation (args=%d)!",
+           callArgCount];
+    return [self noSelectorForArgumentCountError:callArgCount];
+  }
+  
+  // TODO:
+  //   step A: fill up missing arguments (support default values?!)
+  //   step B: validate arguments!
+  
+  if ([self doesAddContextParameter])
+    _args = [_args arrayByAddingObject:_ctx ? _ctx : [NSNull null]];
+  
+  if (debugOn) {
+    [self debugWithFormat:@"call on %@ with args(%i) %@ context %@",
+           _client, [_args count], _args, _client];
+  }
+  return [self primaryCallSelector:self->sel withArguments:_args];
+}
+
+/* binding */
+
+- (BOOL)isBound {
+  return self->object == nil ? NO : YES;
+}
+
+- (id)bindToObject:(id)_object inContext:(id)_ctx {
+  SoSelectorInvocation *inv;
+  
+  if (_object == nil) return nil;
+  
+  inv = [SoSelectorInvocation alloc];
+  inv->sel      = self->sel;
+  inv->argCount = self->argCount;
+  inv->flags    = self->flags;
+  inv->object   = [_object retain];
+  inv->method   = [_object methodForSelector:inv->sel];
+  inv->argumentSpecifications = [self->argumentSpecifications copy];
+  return [inv autorelease];
+}
+
+/* delivering as content (can happen in DAV !) */
+
+- (void)appendToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  [_r appendContentString:@"Compiled SOPE method: "];
+  
+  if (self->sel)
+    [_r appendContentHTMLString:NSStringFromSelector(self->sel)];
+  else
+    [_r appendContentHTMLString:@"missing selector!"];
+
+  if (self->object) {
+    [_r appendContentHTMLString:@" (method is bound to object of class "];
+    [_r appendContentHTMLString:NSStringFromClass([self->object class])];
+    [_r appendContentHTMLString:@")"];
+  }
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->sel) {
+    [ms appendFormat:@" sel=%@", NSStringFromSelector(self->sel)];
+    [ms appendFormat:@"(%i args)", self->argCount];
+  }
+  if (self->object) {
+    [ms appendFormat:@" bound(0x%08X,%@)", 
+          self->object, NSStringFromClass([self->object class])];
+  }
+
+  if ([self doesAddContextParameter])
+    [ms appendFormat:@" ctx-arg"];
+  
+  if ([self->argumentSpecifications count] > 0) {
+    id tmp;
+    
+    tmp = [self->argumentSpecifications allKeys];
+    tmp = [tmp componentsJoinedByString:@","];
+    [ms appendFormat:@" arg-handlers=%@",tmp];
+  }
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SoSelectorInvocation */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoSubContext.h b/skyrix-sope/NGObjWeb/SoObjects/SoSubContext.h
new file mode 100644 (file)
index 0000000..958dceb
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_SoSubContext_H__
+#define __SoObjects_SoSubContext_H__
+
+#include <NGObjWeb/WOContext.h>
+
+/*
+  SoSubContext
+
+  This is a simplified "sub-context" required to issue recursive queries in
+  SOPE. It copies most of the state from WOContext, but keeps and own traversal
+  stack etc.
+*/
+
+@interface SoSubContext : WOContext
+{
+  WOContext *parentContext;
+}
+
+- (id)initWithParentContext:(WOContext *)_parent;
+
+/* accessors */
+
+- (WOContext *)parentContext;
+
+@end
+
+#endif /* __SoObjects_SoSubContext_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoSubContext.m b/skyrix-sope/NGObjWeb/SoObjects/SoSubContext.m
new file mode 100644 (file)
index 0000000..56743be
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoSubContext.h"
+#include "WOElementID.h"
+#include "WOContext+SoObjects.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@implementation SoSubContext
+
++ (int)version {
+  return [super version] + 0 /* v7 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 7,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithParentContext:(WOContext *)_parent {
+  if ((self = [super init])) {
+    self->parentContext = [_parent retain];
+
+    self->qpJoin = @"&";
+    
+    self->elementID = [[WOElementID alloc] init];
+    self->request   = [[_parent request]  retain];
+    self->response  = [[_parent response] retain];
+    
+    self->traversalStack = [[_parent objectTraversalStack] mutableCopy];
+    self->clientObject   = [[_parent clientObject] retain];
+    
+    self->soRequestType = @"INTERNAL";
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithParentContext:[[WOApplication application] context]];
+}
+
+- (void)dealloc {
+  [self->parentContext release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOContext *)parentContext {
+  return self->parentContext;
+}
+- (WOContext *)rootContext {
+  return [[self parentContext] rootContext];
+}
+
+/* overrides */
+
+- (NSString *)contextID {
+  /* a subcontext currently has no ID */
+  /*
+    NOTE: a subcontext may *NOT* have the same ID as the parent-context,
+          otherwise havoc is done in component activation
+  */
+  return nil;
+}
+
+- (void)setSession:(WOSession *)_session {
+  [self logWithFormat:@"ignoring -setSession:%@ on sub-context", _session];
+}
+- (WOSession *)session {
+  return [[self parentContext] session];
+}
+
+- (BOOL)hasSession {
+  return [[self parentContext] hasSession];
+}
+- (BOOL)savePageRequired {
+  return [[self parentContext] savePageRequired];
+}
+
+- (void)setPage:(WOComponent *)_page {
+  [self logWithFormat:@"ignoring -setPage:%@ on sub-context", _page];
+}
+- (WOComponent *)page {
+  return [[self parentContext] page];
+}
+
+- (NSURL *)serverURL {
+  return [[self parentContext] serverURL];
+}
+- (NSURL *)baseURL {
+  return [[self parentContext] baseURL];
+}
+- (NSURL *)applicationURL {
+  return [[self parentContext] applicationURL];
+}
+- (NSURL *)urlForKey:(NSString *)_key {
+  return [[self parentContext] urlForKey:_key];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<0x%08X[%@]: parent=0x%08X>",
+                     (unsigned)self, NSStringFromClass([self class]),
+                     [self parentContext]];
+}
+
+@end /* SoSubContext */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoTemplateRenderer.h b/skyrix-sope/NGObjWeb/SoObjects/SoTemplateRenderer.h
new file mode 100644 (file)
index 0000000..8a5aa35
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoTemplateRenderer_H__
+#define __SoObjects_SoTemplateRenderer_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoTemplateRenderer
+  
+  This renderer is intended to render webpages or content by using a
+  "template". A template is usually an OFSWebMethod or WOComponent
+  exported by a product.
+  
+  Templates are located by several aspects.
+  TODO: describe
+  - lookup based on hierarchy
+  - lookup based on query-key
+  - lookup based on folder-type
+  - default template (Main)
+*/
+
+@class NSException;
+@class WOContext;
+
+@interface SoTemplateRenderer : NSObject
+{
+}
+
++ (id)sharedRenderer;
+
+- (NSException *)renderObject:(id)_object inContext:(WOContext *)_ctx;
+- (BOOL)canRenderObject:(id)_object inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoTemplateRenderer_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoTemplateRenderer.m b/skyrix-sope/NGObjWeb/SoObjects/SoTemplateRenderer.m
new file mode 100644 (file)
index 0000000..fa82feb
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoTemplateRenderer.h"
+#include "SoSecurityManager.h"
+#include "WOContext+SoObjects.h"
+#include "WOContext+private.h" // required for page rendering
+#include "NSException+HTTP.h"
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@interface NSObject(UsedPrivates)
+- (id)resourceManagerInContext:(WOContext *)_ctx;
+- (id)container;
+- (id)nameInContainer;
+- (void)setResourceManager:(WOResourceManager *)_rm;
+- (void)setName:(NSString *)_name;
+@end
+
+@interface SoTemplateCustomObjectComponent : WOComponent
+{
+@public
+  id customObject;
+}
+
+/* accessors */
+
+- (NSString *)customObject;
+
+@end
+
+@implementation SoTemplateRenderer
+
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    
+    debugOn = [ud boolForKey:@"SoTemplateRendererDebugEnabled"];
+  }
+}
+
++ (id)sharedRenderer {
+  static SoTemplateRenderer *singleton = nil;
+  if (singleton == nil)
+    singleton = [[SoTemplateRenderer alloc] init];
+  return singleton;
+}
+
+/* master dispatcher */
+
+- (NSException *)renderComponentWithoutTemplate:(WOComponent *)_component 
+  inContext:(WOContext *)_ctx 
+{
+  WOResponse *r;
+  
+  [self debugWithFormat:@"render component without template: %@", _component];
+  
+  r = [_ctx response];
+  [r setHeader:@"text/html" forKey:@"content-type"];
+  
+  [_ctx setPage:_component];
+  
+  [_ctx enterComponent:_component content:nil];
+  [_component appendToResponse:r inContext:_ctx];
+  [_ctx leaveComponent:_component];
+  return nil;
+}
+
+- (NSException *)renderComponent:(WOComponent *)_c inContext:(WOContext *)_ctx{
+  WOResponse *r;
+  WOComponent *template;
+  NSString    *templateName;
+  
+  [self debugWithFormat:@"template renderer render component: %@", _c]; 
+
+  /* determine name of template */
+  
+  templateName = [[_ctx request] formValueForKey:@"template"];
+  if ([templateName length] == 0) templateName = @"Main";
+  
+  /* lookup template */
+  
+  if ((template = [_c pageWithName:templateName])==nil){
+    [self debugWithFormat:@"did not find a template named '%@'", templateName];
+    return [self renderComponentWithoutTemplate:_c inContext:_ctx];
+  }
+  
+  [self debugWithFormat:@"  render with template: %@", template];
+  
+  /* render template */
+  
+  r = [_ctx response];
+  [r setHeader:@"text/html" forKey:@"content-type"];
+  
+  // TODO: use template as page? may be required for component actions,
+  //       but mixes up the system?
+  [_ctx setPage:_c];
+  
+  [_ctx enterComponent:template content:nil];
+  [template appendToResponse:r inContext:_ctx];
+  [_ctx leaveComponent:template];
+  
+  return nil;
+}
+
+- (NSException *)renderCustomObject:(id)_obj inContext:(WOContext *)_ctx {
+  SoTemplateCustomObjectComponent *component;
+  WOResourceManager *rm;
+  NSException       *e;
+  NSString          *componentName;
+  
+  [self debugWithFormat:@"template renderer render custom object: %@", _obj]; 
+  
+  /* create resource manager for object */
+  
+  if ([_obj respondsToSelector:@selector(resourceManagerInContext:)])
+    rm = [_obj resourceManagerInContext:_ctx];
+  else {
+    id container;
+    
+    if ([_obj respondsToSelector:@selector(container)])
+      container = [_obj container];
+    else
+      container = nil;
+    
+    if ([container respondsToSelector:@selector(resourceManagerInContext:)])
+      rm = [container resourceManagerInContext:_ctx];
+    else {
+      /* TODO: maybe not the best solution? ;-) */
+      rm = [[WOApplication application] resourceManager];
+    }
+  }
+  [self debugWithFormat:@"  using resource manager: %@", rm];
+  
+  /* create a component wrapper for the custom object */
+  
+  component = [[SoTemplateCustomObjectComponent alloc] initWithContext:_ctx];
+  component->customObject = [_obj retain];
+
+  if ((componentName = [_obj nameInContainer])) {
+    componentName = [componentName stringByDeletingPathExtension];
+    [component setName:componentName];
+  }
+  [component ensureAwakeInContext:_ctx];
+  [component setResourceManager:rm];
+  [self debugWithFormat:@"  custom object component: %@", component];
+  
+  /* render custom component like a usual one ... */
+  
+  e = [self renderComponent:component inContext:_ctx];
+  [component release];
+  return e;
+}
+
+- (NSException *)renderObject:(id)_object inContext:(WOContext *)_ctx {
+  SoSecurityManager *sm;
+  NSException *e;
+  
+  [self debugWithFormat:@"template renderer render: %@ in ctx 0x%08X", 
+          _object, _ctx];
+  
+  sm = [_ctx soSecurityManager];
+  if ((e = [sm validateObject:_object inContext:_ctx]) != nil)
+    return e;
+  
+  if ([_object isKindOfClass:[WOComponent class]])
+    return [self renderComponent:_object inContext:_ctx];
+  
+  return [self renderCustomObject:_object inContext:_ctx];
+}
+
+- (BOOL)canRenderObject:(id)_object inContext:(WOContext *)_ctx {
+  // TODO: we could add specialized templates for exceptions !
+  
+  [self debugWithFormat:@"template renderer shall render: %@", _object];
+  
+#if 0 
+  /* 
+     TODO: does that harm anyone?, in theory templates can render without
+           embedding "page". Though if they do, all this breaks ... (since
+          the page is probably the template?)
+  */
+  if (![_object isKindOfClass:[WOComponent class]])
+    return NO;
+#endif
+  
+  return YES;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+- (NSString *)loggingPrefix {
+  return @"[so-tmpl-renderer]";
+}
+
+@end /* SoTemplateRenderer */
+
+@implementation SoTemplateCustomObjectComponent
+
+- (void)dealloc {
+  [self->customObject release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)customObject {
+  return self->customObject;
+}
+
+/* key/value coding */
+
+- (id)objectForKey:(NSString *)_key {
+  return [self->customObject valueForKey:_key];
+}
+
+/* response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [_response appendContentString:@"<!-- custom object -->"];
+  [super appendToResponse:_response inContext:_ctx];
+}
+
+@end /* SoTemplateCustomObjectComponent */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoUser.h b/skyrix-sope/NGObjWeb/SoObjects/SoUser.h
new file mode 100644 (file)
index 0000000..1fd5d16
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoUser_H__
+#define __SoObjects_SoUser_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoUser
+  
+  A protocol and a basic implementation of a user object for the SOPE
+  authentication system.
+  
+  Note: the "context" is usually the WOContext, not the "object context"
+  like in Zope. You can get the roles for an object by using 
+  -rolesForObject:inContext:.
+*/
+
+@class NSException, NSString, NSArray;
+
+@protocol SoUser
+
+- (NSString *)login;
+
+/* returns the names of the roles assigned to the user */
+- (NSArray *)rolesInContext:(id)_ctx;
+
+/* 
+   Returns the names of the roles assigned to the user including
+   local roles from the object.
+*/
+- (NSArray *)rolesForObject:(id)_object inContext:(id)_ctx;
+
+@end
+
+@interface SoUser : NSObject < SoUser >
+{
+  NSString *login;
+  NSArray  *roles;
+}
+
+- (id)initWithLogin:(NSString *)_login roles:(NSArray *)_roles;
+
+@end
+
+#endif /* __SoObjects_SoUser_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/SoUser.m b/skyrix-sope/NGObjWeb/SoObjects/SoUser.m
new file mode 100644 (file)
index 0000000..7354194
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoUser.h"
+#include "common.h"
+
+@implementation SoUser
+
+- (id)initWithLogin:(NSString *)_login roles:(NSArray *)_roles {
+  if (_login == nil) {
+    [self release];
+    return nil;
+  }
+  if ((self = [super init])) {
+    self->login = [_login copy];
+    self->roles = [_roles copy];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithLogin:nil roles:nil];
+}
+
+- (void)dealloc {
+  [self->login release];
+  [self->roles release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)login {
+  return self->login;
+}
+
+/* roles */
+
+- (NSArray *)rolesInContext:(id)_ctx {
+  return self->roles;
+}
+
+- (NSArray *)rolesForObject:(id)_object inContext:(id)_ctx {
+  NSArray *aroles, *localRoles;
+  
+  aroles = [self rolesInContext:_ctx];
+  if (aroles == nil) aroles = [NSArray array];
+  
+  /* 
+     TODO: collect all local roles (of the object and its parents, local
+     roles are stored in __ac_local_roles__ of the object in Zope. Note
+     that this attribute can be a callable returning the roles !
+  */
+  localRoles = nil;
+  
+  return aroles;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:16];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  [ms appendFormat:@" login=%@", self->login];
+  [ms appendFormat:@" roles=%@", [self->roles componentsJoinedByString:@","]];
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SoUser */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/TODO b/skyrix-sope/NGObjWeb/SoObjects/TODO
new file mode 100644 (file)
index 0000000..d68840e
--- /dev/null
@@ -0,0 +1,53 @@
+# $Id: TODO,v 1.2 2003/12/07 22:54:06 helge Exp $
+
+Todo's for SOPE subsystem
+=========================
+
+- add a "lightweight" WOContext for doing internal SOPE calls
+  [done: SoSubContext]
+- add a template rendering system
+  [done: SoTemplateRenderer]
+
+- implement XML-RPC invocations and mapping of XML-RPC parameters to
+  SoMethod parameters!
+
+- there is a bug with embedded components in templates (SoTemplateRenderer?)
+
+- add proper mapping of HTTP methods and parameters to selector
+  invocations !
+- should we generate HTTP redirects after performing content negotiation 
+  instead of resolving to the right object on the server side ? probably
+- add object base security (currently we only have class based security)
+
+- support special context variables like Zope (very useful for path handling):
+  URLn
+  URLPATHn
+  BASEn
+  BASEPATHn
+  eg:
+  URL0  - "http://blah/a/b/c"
+  URL1  - "http://blah/a/b"
+  URL2  - "http://blah/a"
+  BASE0 - "http://blah/"
+  BASE1 - "http://blah/a"
+  BASE2 - "http://blah/a/b"
+  
+- add a "property sheet" API for "controlled" access to object properties.
+  - eg an OFS object can check whether it's in subversion and if so,
+    present a subversion-property-sheet
+
+- add typed form keys, eg:
+    [rq formValueForTypedKey:@"ids"]
+  will check for all form-keys beginning with "ids:" (and "ids" itself and 
+  apply a type coercion based on the "coercion key" following the "ids:",
+  eg "ids:list", "ids:int". The coercion key should be dynamic and extensible
+  to provide custom serialization formats
+  - maybe formatters are well-suited for this task ! formatters could be used
+    in selector-invocations as well
+
+- renderer for DOM tree !
+  - it should be easy for a method to return a DOM tree which is then rendered
+    to it's XML representation
+
+- associate a sort-ordering with a container, so that we can easily retrieve 
+  next/previous links (eg for Mozilla navigation URL support)
diff --git a/skyrix-sope/NGObjWeb/SoObjects/WOContext+SoObjects.h b/skyrix-sope/NGObjWeb/SoObjects/WOContext+SoObjects.h
new file mode 100644 (file)
index 0000000..f7e3745
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_WOContext_SoObjects_H__
+#define __SoObjects_WOContext_SoObjects_H__
+
+#include <NGObjWeb/WOContext.h>
+
+/*
+  WOContext(SoObjects)
+  
+  The WOContext is the central access point for SOPE too. It has several new
+  variables representing publishing state like the client object or the
+  traversal path. You also access global SOPE objects using the context, for
+  example the security manager.
+*/
+
+@class NSArray;
+@class SoSecurityManager, SoSubContext;
+
+@interface WOContext(SoObjects)
+
+/* security */
+
+- (SoSecurityManager *)soSecurityManager;
+
+/* traversal */
+
+- (void)addObjectToTraversalStack:(id)_object;
+- (NSArray *)objectTraversalStack;
+- (id)traversalRoot;
+
+- (void)setClientObject:(id)_object;
+- (id)clientObject;
+
+- (void)setObjectDispatcher:(id)_dispatcher;
+- (id)objectDispatcher;
+
+- (void)setSoRequestType:(NSString *)_rqType;
+- (NSString *)soRequestType;
+- (void)setSoRequestTraversalPath:(NSArray *)_path;
+- (NSArray *)soRequestTraversalPath;
+
+- (void)setPathInfo:(NSString *)_pi;
+- (NSString *)pathInfo;
+
+/* subcontexts */
+
+- (SoSubContext *)createSubContext;
+- (WOContext *)parentContext;
+- (WOContext *)rootContext;
+
+@end
+
+/* all the following methods are convenience methods that access WOContext */
+
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WODirectAction.h>
+
+@interface WOComponent(SoObjects)
+- (void)setClientObject:(id)_object;
+- (id)clientObject;
+@end
+
+@interface WODirectAction(SoObjects)
+- (id)clientObject;
+@end
+
+#endif /* __SoObjects_WOContext_SoObjects_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/WOContext+SoObjects.m b/skyrix-sope/NGObjWeb/SoObjects/WOContext+SoObjects.m
new file mode 100644 (file)
index 0000000..8dc63d6
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "WOContext+SoObjects.h"
+#include "SoObjectRequestHandler.h"
+#include "SoSubContext.h"
+#include "SoSecurityManager.h"
+#include <NGObjWeb/WOComponent.h>
+#include "common.h"
+
+@implementation WOContext(SoSecurityManager)
+
+- (SoSecurityManager *)soSecurityManager {
+  return [SoSecurityManager sharedSecurityManager];
+}
+
+@end /* WOContext(SoSecurityManager) */
+
+@implementation WOContext(SoObjectRequestHandler)
+
+static BOOL debugOn = NO;
+
+- (void)setClientObject:(id)_object {
+  if (debugOn) [self logWithFormat:@"set client: %@", _object];
+  ASSIGN(self->clientObject, _object);
+}
+- (id)clientObject {
+  return self->clientObject;
+}
+
+- (void)addObjectToTraversalStack:(id)_object {
+  if (self->traversalStack == nil)
+    self->traversalStack = [[NSMutableArray alloc] initWithCapacity:16];
+  [self->traversalStack addObject:_object ? _object : [NSNull null]];
+}
+
+- (id)traversalRoot {
+  unsigned count;
+  if ((count = [self->traversalStack count]) == 0)
+    return nil;
+  return [self->traversalStack objectAtIndex:0];
+}
+
+- (NSArray *)objectTraversalStack {
+  return self->traversalStack;
+}
+
+- (void)setObjectDispatcher:(id)_dispatcher {
+  ASSIGN(self->objectDispatcher, _dispatcher);
+}
+- (id)objectDispatcher {
+  return self->objectDispatcher;
+}
+
+- (void)setSoRequestType:(NSString *)_rqType {
+  ASSIGNCOPY(self->soRequestType, _rqType);
+}
+- (NSString *)soRequestType {
+  return self->soRequestType;
+}
+
+- (void)setSoRequestTraversalPath:(NSArray *)_path {
+  // TODO: add ivar
+  [self setObject:_path forKey:@"SoRequestTraversalPath"];
+}
+- (NSArray *)soRequestTraversalPath {
+  return [self objectForKey:@"SoRequestTraversalPath"];
+}
+
+- (void)setPathInfo:(NSString *)_pi {
+  ASSIGNCOPY(self->pathInfo, _pi);
+}
+- (NSString *)pathInfo {
+  return self->pathInfo;
+}
+
+/* subcontexts */
+
+- (SoSubContext *)createSubContext {
+  return [[[SoSubContext alloc] initWithParentContext:self] autorelease];
+}
+- (WOContext *)parentContext {
+  return nil;
+}
+- (WOContext *)rootContext {
+  return self;
+}
+
+@end /* WOContext(SoObjectRequestHandler) */
+
+@implementation WOComponent(SoObjects)
+
+- (void)setClientObject:(id)_client {
+  if (debugOn) [self debugWithFormat:@"set client: %@", _client];
+  [self setObject:_client forKey:@"__soclient"];
+}
+- (id)clientObject {
+  id client;
+  
+  if ((client = [self objectForKey:@"__soclient"]))
+    return client;
+  
+  return [[self context] clientObject];
+}
+
+@end /* WOComponent(SoObjects) */
+
+@implementation WODirectAction(SoObjects)
+
+- (id)clientObject {
+  return [[(id)self context] clientObject];
+}
+
+@end /* WODirectAction(SoObjects) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/WODirectAction+SoObjects.m b/skyrix-sope/NGObjWeb/SoObjects/WODirectAction+SoObjects.m
new file mode 100644 (file)
index 0000000..8379c2f
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODirectAction.h>
+#include "SoObject.h"
+#include "common.h"
+
+@interface WODirectActionPubInvocation : NSObject
+{
+@public
+  WODirectAction *parent;
+  NSString *daName;
+}
+@end
+
+@implementation WODirectAction(SoObjectRequestHandler)
+
+- (id)lookupName:(NSString *)_name inContext:(id)_ctx acquire:(BOOL)_flag {
+  WODirectActionPubInvocation *inv;
+  NSString *daName;
+  SEL sel;
+  
+  daName = [_name stringByAppendingString:@"Action"];
+  sel    = NSSelectorFromString(daName);
+  
+  if (![self respondsToSelector:sel])
+    return [super lookupName:_name inContext:_ctx acquire:_flag];
+    
+  inv = [[WODirectActionPubInvocation alloc] init];
+  inv->daName = [_name copy];
+  inv->parent = [self retain];
+  return [inv autorelease];
+}
+
+@end /* WODirectAction(SoObjectRequestHandler) */
+
+@implementation WODirectActionPubInvocation
+
+- (void)dealloc {
+  [self->daName release];
+  [self->parent release];
+  [super dealloc];
+}
+
+- (id)parentObject {
+  return self->parent;
+}
+
+- (BOOL)isCallable {
+  return YES;
+}
+- (id)callOnObject:(id)_object inContext:(WOContext *)_ctx {
+  return [_object ? _object : self->parent performActionNamed:self->daName];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  [ms appendFormat:@" action=%@", self->daName];
+  [ms appendFormat:@" class=%@", NSStringFromClass([self->parent class])];
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* WODirectActionPubInvocation */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/WODirectActionRequestHandler+SoObjects.m b/skyrix-sope/NGObjWeb/SoObjects/WODirectActionRequestHandler+SoObjects.m
new file mode 100644 (file)
index 0000000..aa19a0a
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODirectActionRequestHandler.h>
+#include <NGObjWeb/WODirectAction.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOApplication.h>
+#include "SoObject.h"
+#include "common.h"
+
+@implementation WODirectActionRequestHandler(Pub)
+
+- (id)parentObject {
+  return [WOApplication application];
+}
+
+- (BOOL)allowDirectActionClass:(Class)_clazz {
+#if 0
+#warning to be completed ...
+    if (![clazz isSubclassOfClass:[WODirectAction class]])
+      clazz = Nil;
+#endif
+  return YES;
+}
+
+- (id)lookupName:(NSString *)_name inContext:(id)_ctx acquire:(BOOL)_ac {
+  Class clazz;
+  BOOL  lookupInAction = NO;
+  
+  /* check whether name is a direct-action class */
+  if ((clazz = NSClassFromString(_name))) {
+    if (![self allowDirectActionClass:clazz])
+      clazz = Nil;
+  }
+  else {
+    /* automatically use DirectAction class */
+    lookupInAction = YES;
+    clazz = NSClassFromString(@"DirectAction");
+  }
+  
+  /* found a class, construct direct action */
+  if (clazz) {
+    WODirectAction *actionObject;
+    WOContext      *ctx;
+    
+    ctx = _ctx ? _ctx : [[WOApplication application] context];
+    
+    if ((actionObject = [[clazz alloc] initWithContext:ctx]) == nil) {
+      /* failed to create object */
+      return nil;
+    }
+    actionObject = [actionObject autorelease];
+    
+    return lookupInAction
+      ? [actionObject lookupName:_name inContext:ctx acquire:_ac]
+      : actionObject;
+  }
+  
+  return [super lookupName:_name inContext:_ctx acquire:_ac];
+}
+
+@end /* WODirectActionRequestHandler(Pub) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/WORequest+So.h b/skyrix-sope/NGObjWeb/SoObjects/WORequest+So.h
new file mode 100644 (file)
index 0000000..e34e7c3
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __SoObjects_WORequest_So_H__
+#define __SoObjects_WORequest_So_H__
+
+#import <NGObjWeb/WORequest.h>
+
+/*
+  WORequest(SoRequestClassification)
+  
+  Classify a request to be able to select the proper handler.
+*/
+
+@interface WORequest(SoRequestClassification)
+
+- (BOOL)isSoWebDAVRequest;
+- (BOOL)isSoXmlRpcRequest;
+- (BOOL)isSoSOAPRequest;
+- (BOOL)isSoWCAPRequest;
+- (BOOL)isSoBrkDAVRequest;
+
+@end
+
+#endif /* __SoObjects_WORequest_So_H__ */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/WORequest+So.m b/skyrix-sope/NGObjWeb/SoObjects/WORequest+So.m
new file mode 100644 (file)
index 0000000..c62d118
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "WORequest+So.h"
+#include <NGObjWeb/WEClientCapabilities.h>
+#include "common.h"
+
+@implementation WORequest(SoRequestClassification)
+
+static BOOL _debugClassify(void) {
+  static int debugOn = -1;
+  if (debugOn == -1) {
+    debugOn = [[NSUserDefaults standardUserDefaults] 
+                boolForKey:@"SoDebugRequestClassification"] ? 1 : 0;
+    if (debugOn)
+      NSLog(@"SoDebugRequestClassification: enabled");
+  }
+  return debugOn ? YES : NO;
+}
+
+- (BOOL)isSoWebDAVRequest {
+  WEClientCapabilities *cc;
+  id tmp;
+  
+  /* check handler key */
+  if ([[self requestHandlerKey] isEqualToString:@"dav"]) {
+    /* this can be used to force WebDAV */
+    if (_debugClassify())
+      [self logWithFormat:@"classified as WebDAV by request-handler-key"];
+    return YES;
+  }
+  
+  /* check client type */
+  cc = [self clientCapabilities];
+  if ([cc isDAVClient]) {
+    if (_debugClassify()) {
+      [self logWithFormat: 
+              @"classified as WebDAV by user-agent (it's a DAV client)"];
+    }
+    return YES;
+  }
+  
+  /* check translate header */
+  if ((tmp = [self headerForKey:@"translate"])) {
+    NSString *h = tmp;
+    if ([h hasPrefix:@"t"] || [h hasPrefix:@"T"]) {
+      if (_debugClassify()) {
+        [self logWithFormat:
+                @"classified as WebDAV by a 'true' translation header"];
+      }
+      return YES;
+    }
+  }
+  
+  /* check HTTP methods */
+  {
+    static NSMutableSet *davMethods = nil;
+    if (davMethods == nil) {
+      NSArray *m;
+      m = [[NSUserDefaults standardUserDefaults] 
+                           arrayForKey:@"SoWebDAVDetectionMethods"];
+      davMethods = [[NSMutableSet alloc] initWithArray:m];
+    }
+    if ([davMethods containsObject:[self method]]) {
+      if (_debugClassify()) {
+        [self logWithFormat:
+                @"classified as WebDAV because of the method name"];
+      }
+      return YES;
+    }
+  }
+  
+  /* found no WebDAV indicator */
+  return NO;
+}
+
+- (BOOL)isSoXmlRpcRequest {
+  NSString *t;
+  
+  if (![[self method] isEqualToString:@"POST"])
+    /* XML-RPC requests must be POST ... */
+    return NO;
+  
+  /* check handler key */
+  if ([[self requestHandlerKey] isEqualToString:@"RPC2"]) {
+    /* this can be used to force XML-RPC */
+    if (_debugClassify()) {
+      [self logWithFormat:
+              @"classified as XML-RPC because of request-handler-key"];
+    }
+    return YES;
+  }
+  
+  /* look at content type */
+  t = [self headerForKey:@"content-type"];
+  if (![t hasPrefix:@"text/xml"])
+    /* XML-RPC requests must be text/xml ... */
+    return NO;
+  if ([t hasPrefix:@"text/xml+"])
+    /* XML-RPC requests must be text/xml ... */
+    return NO;
+
+  /* look at content length */
+  t = [self headerForKey:@"content-length"];
+  if ([t intValue] < 51)
+    /* an XML-RPC request has some minimum length ... */
+    return NO;
+  
+  /* now it becomes difficult, how do we distinguish plain XML and RPC ? */
+  {
+    /*
+      We check for some contents, see below. Not exactly the most
+      efficient thing on earth, but ...
+      
+      must be longer than 50 chars:
+      <methodCall><methodName>x</methodName></methodCall>
+    */
+    NSString *s;
+    NSRange crng, nrng;
+
+    s = [self contentAsString];
+    if ([s length] < 51)
+      return NO;
+
+    crng = [s rangeOfString:@"<methodCall>"];
+    nrng = [s rangeOfString:@"<methodName>"];
+    if (crng.length <= 0) return NO;
+    if (nrng.length <= 0) return NO;
+    if (nrng.location < crng.location) return NO;
+
+    crng = [s rangeOfString:@"</methodCall>"];
+    nrng = [s rangeOfString:@"</methodName>"];
+    if (crng.length <= 0) return NO;
+    if (nrng.length <= 0) return NO;
+    if (nrng.location > crng.location) return NO;
+
+    if (_debugClassify()) {
+      [self logWithFormat:
+             @"classified as XML-RPC because of POST and the contents "
+             @"looks like XML-RPC "];
+    }
+    return YES;
+  }
+  
+  /* found no XML-RPC indicator */
+  return NO;
+}
+
+- (BOOL)isSoSOAPRequest {
+  NSString *soapAction;
+  
+  if ((soapAction = [self headerForKey:@"soapaction"]) == nil)
+    return NO;
+  
+  if (_debugClassify()) {
+    [self logWithFormat:
+           @"classified as SOAP because the SOAPAction header is set."];
+  }
+  
+  return YES;
+}
+
+- (BOOL)isSoWCAPRequest {
+  NSString *s;
+  NSRange  r;
+  
+  s = [self uri];
+  r = [s rangeOfString:@"?"];
+  if (r.length > 0) s = [s substringToIndex:r.location];
+  r = [s rangeOfString:@"#"];
+  if (r.length > 0) s = [s substringToIndex:r.location];
+  
+  return [s hasSuffix:@".wcap"];
+}
+
+- (BOOL)isSoBrkDAVRequest {
+  /* a broken WebDAV request */
+  return [[self uri] hasPrefix:@"/servlet/webdav."];
+}
+
+@end /* WORequest(SoRequestClassification) */
diff --git a/skyrix-sope/NGObjWeb/SoObjects/product.plist b/skyrix-sope/NGObjWeb/SoObjects/product.plist
new file mode 100644 (file)
index 0000000..f45b7b2
--- /dev/null
@@ -0,0 +1,88 @@
+{
+  CVSID = "$Id: product.plist,v 1.1.1.1 2003/07/09 22:57:27 cvs Exp $";
+
+  classes = {
+    
+    NSObject = {
+      defaultRoles = {
+        "WebDAV Access"               = "Authenticated";
+        "Change Images and Files"     = "Owner";
+        "Delete Objects"              = "Owner";
+        "View"                        = "Authenticated";
+        "WebDAV Lock Items"           = "Authenticated";
+        "WebDAV Unlock Items"         = "Authenticated";
+        "Access Contents Information" = "Authenticated";
+      };
+    };
+    NSException = {
+      protectedBy = "<public>";
+      defaultAccess = "allow";
+    };
+    
+    WOComponent = {
+      protectedBy = "<public>";
+      defaultAccess = "allow";
+      defaultRoles = {
+        "View" = "Anonymous";
+      };
+    };
+    WOApplication = {
+      protectedBy = "<public>";
+      defaultAccess = "allow";
+    };
+    WOResourceManager = {
+      protectedBy   = "<public>";
+      defaultAccess = "allow";
+    };
+    WOResponse = {
+      protectedBy = "<public>";
+      defaultAccess = "allow";
+    };
+    WOContext = {
+      protectedBy = "<public>";
+      defaultAccess = "allow";
+    };
+    
+    SoApplication = {
+      superclass = "WOApplication";
+      slots = {
+        ControlPanel = {
+         protectedBy = "<public>";
+        };
+      };
+    };
+    SoObjectRequestHandler = {
+      protectedBy = "<public>";
+      defaultAccess = "allow";
+    };
+    SoControlPanel = {
+      protectedBy = "<public>";
+      defaultAccess = "allow";
+      slots = {
+        Products = {
+         protectedBy = "<public>";
+        };
+      };
+    };
+    SoPageInvocation = {
+      protectedBy = "<public>";
+      defaultAccess = "allow";
+    };
+    SoProduct = {
+      protectedBy = "<public>";
+      slots = {
+       Resources = {
+         protectedBy = "<public>";
+        };
+      };
+    };
+    SoProductRegistry = {
+      protectedBy   = "<public>";
+      defaultAccess = "allow";
+    };
+    SoProductResourceManager = {
+      protectedBy   = "<public>";
+      defaultAccess = "allow";
+    };
+  };
+}
diff --git a/skyrix-sope/NGObjWeb/TODO b/skyrix-sope/NGObjWeb/TODO
new file mode 100644 (file)
index 0000000..4fdc45f
--- /dev/null
@@ -0,0 +1,69 @@
+# $Id: TODO,v 1.11 2004/07/17 16:28:23 helge Exp $
+
+- remove dependency on NGJavaScript
+
+- find out what the OOo WebDAV properties are supposed to do
+
+- TOO MUCH duplicate code for URL processing ...
+
+- add a hack for redirecting "/" to "/$bundleName" in case the default
+  request handler is WOComponentRequestHandler or WODirectActionRequestHandler
+
+- add an HTML compatibility mode to the dynamic elements to support WO pages
+  which start with:
+    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+Dynamic Elements
+================
+- none missing?
+
+WOx
+===
+- bind 
+
+XML-RPC
+=======
+- add timeout capability to NGXmlRpcClient
+
+
+Ivars
+=====
+currently stored in extended attributes or userInfo:
+- WORequest:
+  - WORequestStartDate
+  - WORequestStartProcStatistics
+- WOComponent:
+  - _ODCycleCtx (used for cursor)  TODO: isn't that a WOComponent ivar?
+  - component definition during init (currently wosVariables)
+- WOContext
+  - SoRootURL
+  - SoObjPermCache
+- WOMessage
+  - WODOMContent (cache for -contentAsDOMDocument)
+
+Misc
+====
+
+- WebScript, maybe using StepTalk?
+
+- catch requests to /favicon.ico
+
+- watchdog does restart child even on a clean termination ?
+
+MacOSX port
+===========
+
+- really hackish use of COCOA_Foundation_LIBRARY to distinguish
+  whether we are compiling for the GNUstep environment or not
+
+WOMessage / WOResponse
+======================
+
+- support streaming (prepared)
+
+- queue append calls instead of processing them in-place
+  - use WOProfileResponse for profiling
+  - avg:     ~1500 str calls, ~250 char/cstr, ~300 HTML
+  - regular: ~5000 str calls, ~2000 char, ~1200 HTML
+  - hopefully we could gain major performance benefits by doing bulk
+    charset=> data conversions?
diff --git a/skyrix-sope/NGObjWeb/TROUBLESHOOTING b/skyrix-sope/NGObjWeb/TROUBLESHOOTING
new file mode 100644 (file)
index 0000000..2dfa096
--- /dev/null
@@ -0,0 +1,22 @@
+# $Id: TROUBLESHOOTING,v 1.1 2003/10/15 02:08:59 helge Exp $
+
+Collect "common" issues around NGObjWeb ...
+
+___________________________________________________________________________
+* Endless Recursion in sope -authenticatorInContext:
+
+  sope coredump, endless recursion: -authenticatorInContext:
+---snip---
+#1038 0x00eda4c4 in -[OFSFolder authenticatorInContext:] (self=0x937b30, _cmd=0x3be4, _ctx=0x9387d0) at OFSFolder.m:747
+#1039 0x00ed4074 in -[OFSBaseObject authenticatorInContext:] (self=0x943f30, _cmd=0x3be4, _ctx=0x9387d0) at OFSBaseObject.m:219
+---snap---
+  - this occures if htpasswd cannot be resolved as the authenticator
+    - htpasswd will be returned as a regular file (OFSFile object) which 
+      leads to a recursion
+    use: -SoOFSDebugAuthLookup YES to detect
+    - htpasswd becomes an OFSFile instead of a OFSHttpPasswd because the
+      core SoProducts (SoOFS.sxp) are not properly found!
+    - mixed up on GNUstep on MacOSX
+    use: SoProductRegistryDebugEnabled YES to detect
+
+___________________________________________________________________________
diff --git a/skyrix-sope/NGObjWeb/Templates/.cvsignore b/skyrix-sope/NGObjWeb/Templates/.cvsignore
new file mode 100644 (file)
index 0000000..68453b4
--- /dev/null
@@ -0,0 +1,3 @@
+*-42.m
+Resources
+shared_debug_obj
diff --git a/skyrix-sope/NGObjWeb/Templates/GNUmakefile b/skyrix-sope/NGObjWeb/Templates/GNUmakefile
new file mode 100644 (file)
index 0000000..ba56059
--- /dev/null
@@ -0,0 +1,25 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = Templates
+
+Templates_HEADER_FILES_DIR         = .
+Templates_HEADER_FILES_INSTALL_DIR = /NGObjWeb
+
+Templates_OBJC_FILES =   \
+       WOComponentScript.m             \
+       WOComponentScriptPart.m         \
+       WODParser.m                     \
+       WOHTMLParser.m                  \
+       WOSubcomponentInfo.m            \
+       WOTemplate.m                    \
+       WOTemplateBuilder.m             \
+       WOWrapperTemplateBuilder.m      \
+       WOxComponentElemBuilder.m       \
+       WOxTemplateBuilder.m            \
+        WOxElemBuilder.m               \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjWeb/Templates/GNUmakefile.preamble b/skyrix-sope/NGObjWeb/Templates/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..8dac922
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id$
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..                    \
+       -I../DynamicElements/   \
+       -I../..                 \
+       -I../../../skyrix-core                  \
+       -I../../../skyrix-core/NGStreams        \
+       -I../../../skyrix-core/NGExtensions     \
+       -I../../../skyrix-xml
diff --git a/skyrix-sope/NGObjWeb/Templates/README-Templates.txt b/skyrix-sope/NGObjWeb/Templates/README-Templates.txt
new file mode 100644 (file)
index 0000000..7fa9a68
--- /dev/null
@@ -0,0 +1,113 @@
+# $Id$
+
+How Templates Work ...
+======================
+
+In general we have two kinds of templates, XML based ones and "hash" based 
+ones.
+The 'hash' templates are simple scanners for strings which start and end with 
+"<#" and "</#", while the XML based templates are valid and "namespace'd" XML 
+files.
+
+Practical difference:
+- XML templates can be created, parsed, transformed, ... with any standard XML
+  tool
+- hash templates can be used in a non-tag way, eg this is a valid template:
+    <a href="<#MyHRef/>">blah</a>
+  Since unlike the XML parser the hash parser only scans for "<#", this is OK.
+- hash templates use "wod" files for declarations which may or may not improve
+  the visual clutter in the template itself
+- XML templates do not need to have a 1:1 mapping from tag to WODynamicElement
+  and the mapping between tag and element is completely controlled by the
+  builder while for hash templates you always use the actuall WODynamicElement
+  subclass name in the .wod file
+
+Class Overview
+==============
+
+WOTemplate (WOElement)
+- an WOElement subclass
+- this represents the 'real' root element of the template and contains some
+  additional information like the URL it was loaded from and the subcomponents
+  declared in the template
+- an WOTemplate object will be bound to a WOComponent once instantiated
+
+WOSubcomponentInfo
+- used in WOTemplate to track information on the subcomponents declared in
+  the template (like bindings and component name)
+- if a WOComponent is instantiated this will be used to construct the 
+  subcomponents
+
+WODParser
+- a parser for the .wod file format
+- works someone like a SAX parser and requires a delegate to collect the
+  actual information out of the parsed objects
+
+WOHTMLParser
+- the parser for the "hash" template format
+- requires a callback for instantiation of dynamic elements
+
+WOComponentScript / WOComponentScriptPart
+- this is used to collect server side template scripts declared in an
+  XML file or or in a name-associated file (eg Main.js). sample:
+    <script runat='server'>a = 1 + 2;</script>
+- a WOComponentScriptPart is one entry while WOComponentScript is the set of
+  all entries (which usually will be joined into one script for evaluation)
+
+WOTemplateBuilder
+- the common superclass for the XML and hash based builder classes
+- also acts as the build "registry"
+    + (WOTemplateBuilder *)templateBuilderForURL:(NSURL *)_url
+  this currently returns the WOxTemplateBuilder for .wox extensions and the
+  hash builder for all other templates
+- one API method:
+    - (WOTemplate *)buildTemplateAtURL:(NSURL *)_url
+
+WOWrapperTemplateBuilder (WOTemplateBuilder)
+- subclass of WOTemplateBuilder for "hash" templates
+- uses WOHTMLParser and WODParser for processing .wo wrappers
+- supports language projects inside wrappers (eg a.wo/English.lproj/a.html)
+- looks for JavaScript component scripts (Name.js files)
+
+_WODFileEntry
+- used in WOWrapperTemplateBuilder
+- somewhat like WOSubcomponentInfo, contains information on a parsed WOD
+  entry (will be stored in a name=>entry map)
+
+WOxTemplateBuilder (WOTemplateBuilder)
+- subclass of WOTemplateBuilder for XML templates (also called 'wox' templates)
+- defaults: WOxBuilderClasses
+- also scans for "WOxElemBuilder" resources using NGBundleManager
+- this one parses a DOM tree from the "build-URL" and then delegates the actual
+  building to so called "element builders" (subclasses of WOxElemBuilder)
+
+WOxElemBuilder
+- superclass for all other element builders
+- has a 'nextBuilder' for passing on unsupported tags
+
+WOxElemBuilderComponentInfo
+- somewhat like _WODFileEntry,
+- used in WOxElemBuilder for tracking subcomponent references
+- some API:
+  - (WOElement *)buildTemplateFromDocument:(id<DOMDocument>)_document;
+  - (WOElement *)buildNode:(id<DOMNode>)_node templateBuilder:(id)_bld;
+  - (NSArray *)buildNodes:(id<DOMNodeList>)_node templateBuilder:(id)_bld;
+- also manages WOAssociation to namespace mappings, binds a WOAssociation 
+  subclass to a certain namespace, eg:
+    "var" => "WOKeyValueAssociation"
+    "<td var:width='calculatedWidth'>"
+
+WOxComponentElemBuilder (WOxElemBuilder)
+- build subcomponent references:
+  - WOChildComponentReference
+  - WOComponentReference
+  (but currently no WOSwitchComponent?)
+- processes: "<script>", "<component>"
+- fallback is: use tagname (not recommended), eg:
+  <var:Main/>
+
+WOxTagClassElemBuilder (WOxElemBuilder)
+- superclass for builders which map an XML tag to a WODynamicElement
+- subclasses can return the class required using:
+    - (Class)classForElement:(id<DOMElement>)_element
+  everything else will be managed by the tag-builder
diff --git a/skyrix-sope/NGObjWeb/Templates/WOComponentScript.m b/skyrix-sope/NGObjWeb/Templates/WOComponentScript.m
new file mode 100644 (file)
index 0000000..6c75f3a
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOTemplateBuilder.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGScripting/NSObject+Scripting.h>
+#include "common.h"
+
+@interface WOComponentScriptPart(UsedPrivates)
+- (void)initScriptWithComponent:(WOComponent *)_object;
+@end
+
+@implementation WOComponentScript
+
+- (id)initWithContentsOfFile:(NSString *)_path {
+  if ((self = [self init])) {
+    WOComponentScriptPart *part;
+    
+    if ([[_path pathExtension] isEqualToString:@"js"])
+      self->language = @"javascript";
+    
+    part = [[WOComponentScriptPart alloc] initWithContentsOfFile:_path];
+    if (part == nil) {
+      [self release];
+      return nil;
+    }
+    [self addScriptPart:part];
+    [part release];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->language    release];
+  [self->scriptParts release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)language {
+  return self->language;
+}
+
+/* operations */
+
+- (void)addScriptPart:(WOComponentScriptPart *)_part {
+  NSArray *tmp;
+  
+  if (_part == nil) 
+    return;
+  
+  tmp = self->scriptParts
+    ? [self->scriptParts arrayByAddingObject:_part]
+    : [NSArray arrayWithObject:_part];
+  ASSIGN(self->scriptParts, tmp);
+}
+
+- (void)initScriptWithComponent:(WOComponent *)_object {
+  NSEnumerator      *e;
+  NSAutoreleasePool *pool;
+  WOComponentScriptPart *part;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  e = [self->scriptParts objectEnumerator];
+  while ((part = [e nextObject]))
+    [part initScriptWithComponent:_object];
+  
+  [pool release];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:32];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if ([self->language length] > 0)
+    [ms appendFormat:@" language=%@", self->language];
+  
+  if ([self->scriptParts count] == 0)
+    [ms appendString:@" no parts"];
+  else if ([self->scriptParts count] == 1)
+    [ms appendFormat:@" part=%@", [self->scriptParts objectAtIndex:0]];
+  else
+    [ms appendFormat:@" parts=%@", self->scriptParts];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* WOComponentScript */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOComponentScriptPart.m b/skyrix-sope/NGObjWeb/Templates/WOComponentScriptPart.m
new file mode 100644 (file)
index 0000000..8c96e5b
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOTemplateBuilder.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGScripting/NSObject+Scripting.h>
+#include "common.h"
+
+@implementation WOComponentScriptPart
+
+- (id)initWithURL:(NSURL *)_url startLine:(unsigned)_ln script:(NSString *)_s {
+  self->url       = RETAIN(_url);
+  self->startLine = _ln;
+  self->script    = [_s copy];
+  return self;
+}
+- (id)initWithContentsOfFile:(NSString *)_path {
+  NSURL    *furl;
+  NSString *s;
+  
+  if ([_path length] == 0) {
+    RELEASE(self);
+    return nil;
+  }
+  
+  if ((s = [[NSString alloc] initWithContentsOfFile:_path]) == nil) {
+    RELEASE(self);
+    return nil;
+  }
+  
+  furl = [[NSURL alloc] initFileURLWithPath:_path];
+  self = [self initWithURL:furl startLine:0 script:s];
+  RELEASE(furl);
+  RELEASE(s);
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->url);
+  RELEASE(self->script);
+  [super dealloc];
+}
+
+/* operations */
+
+- (NSException *)handleException:(NSException *)_exception {
+  if (self->startLine == 0)
+    return _exception;
+  
+  if ([[_exception name] isEqualToString:@"JavaScriptError"]) {
+    /* correct script start lines to actual value */
+    NSMutableDictionary *ui;
+    int line;
+    
+    ui = [[_exception userInfo] mutableCopy];
+    line = [[ui objectForKey:@"line"] intValue];
+    if (ui == nil) ui = [[NSMutableDictionary alloc] init];
+    [ui setObject:[NSNumber numberWithInt:(line + self->startLine)]
+       forKey:@"line"];
+    [_exception setUserInfo:ui];
+    RELEASE(ui);
+  }
+  return _exception;
+}
+
+- (void)initScriptWithComponent:(WOComponent *)_object {
+  /* fixed on JavaScript, part should have a language ... */
+  NS_DURING {
+    [_object evaluateScript:self->script language:@"javascript"
+            source:[self->url absoluteString] line:self->startLine];
+  }
+  NS_HANDLER
+    [[self handleException:localException] raise];
+  NS_ENDHANDLER;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:32];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->url) {
+    if ([self->url isFileURL])
+      [ms appendFormat:@" path=%@", [self->url path]];
+    else
+      [ms appendFormat:@" url=%@", self->url];
+    if (self->startLine > 0)
+      [ms appendFormat:@":%i", self->startLine];
+  }
+  else if (self->startLine > 0)
+    [ms appendFormat:@" line=%@", self->startLine];
+
+  if ([self->script length] == 0)
+    [ms appendString:@" no script"];
+  else if ([self->script length] < 16)
+    [ms appendFormat:@" script=%@", self->script];
+  else
+    [ms appendFormat:@" script=%@...", [self->script substringToIndex:13]];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* WOComponentScriptPart */
diff --git a/skyrix-sope/NGObjWeb/Templates/WODParser.h b/skyrix-sope/NGObjWeb/Templates/WODParser.h
new file mode 100644 (file)
index 0000000..ddb6559
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WODParser_H__
+#define __WODParser_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSDictionary, NSException, NSData;
+
+@protocol WODParserHandler
+
+- (BOOL)parser:(id)_parser willParseDeclarationData:(NSData *)_data;
+- (void)parser:(id)_parser finishedParsingDeclarationData:(NSData *)_data
+  declarations:(NSDictionary *)_decls;
+- (void)parser:(id)_parser failedParsingDeclarationData:(NSData *)_data
+  exception:(NSException *)_exception;
+
+- (id)parser:(id)_parser makeAssociationWithValue:(id)_value;
+- (id)parser:(id)_parser makeAssociationWithKeyPath:(NSString *)_keyPath;
+- (id)parser:(id)_parser makeDefinitionForComponentNamed:(NSString *)_cname
+  associations:(id)_entry
+  elementName:(NSString *)_elemName;
+
+@end
+
+@interface WODParser : NSObject
+{
+  id<WODParserHandler,NSObject> callback;
+}
+
+- (id)initWithHandler:(id<WODParserHandler,NSObject>)_handler;
+
+/* parsing */
+
+- (NSDictionary *)parseDeclarationData:(NSData *)_decl;
+
+@end
+
+#endif /* __WODParser_H__ */
diff --git a/skyrix-sope/NGObjWeb/Templates/WODParser.m b/skyrix-sope/NGObjWeb/Templates/WODParser.m
new file mode 100644 (file)
index 0000000..23cec76
--- /dev/null
@@ -0,0 +1,1274 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WODParser.h"
+#include "common.h"
+
+@implementation WODParser
+
+static Class    StrClass    = Nil;
+static Class    DictClass   = Nil;
+static Class    NumberClass = Nil;
+static NSNumber *yesNum     = nil;
+static NSNumber *noNum      = nil;
+static BOOL     useUTF8     = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
+  StrClass    = [NSString class];
+  DictClass   = [NSMutableDictionary class];
+  NumberClass = [NSNumber      class];
+  
+  if (yesNum == nil) yesNum = [[NumberClass numberWithBool:YES] retain];
+  if (noNum  == nil) noNum  = [[NumberClass numberWithBool:NO]  retain];
+  
+  useUTF8 = [ud boolForKey:@"WOParsersUseUTF8"];
+}
+
+- (id)initWithHandler:(id<WODParserHandler,NSObject>)_handler {
+  ASSIGN(self->callback, _handler);
+  return self;
+}
+- (void)dealloc {
+  [self->callback release];
+  [super dealloc];
+}
+
+/* callbacks */
+
+- (id)associationWithValue:(id)_value {
+  return [self->callback parser:self makeAssociationWithValue:_value];
+}
+- (id)associationWithKeyPath:(NSString *)_keyPath {
+  return [self->callback parser:self makeAssociationWithKeyPath:_keyPath];
+}
+
+- (id)elementDefinitionForComponent:(NSString *)_cname
+  associations:(id)_entry
+  elementName:(NSString *)_elemName
+{
+  return [self->callback parser:self
+                         makeDefinitionForComponentNamed:_cname
+                         associations:_entry
+                         elementName:_elemName];
+}
+
+/* parser */
+
+static id _parseProperty(NSZone *_zone, const char *_buffer, unsigned *_idx,
+                         unsigned _len, NSException **_exception,
+                         BOOL _allowAssoc, id self);
+static id _parseWodEntry(NSZone *_zone, const char *_buffer, unsigned *_idx,
+                         unsigned _len, NSException **_exception,
+                         NSString **_name, NSString **_class,
+                         id self);
+
+static NSString *_makeStringForBuffer(const unsigned char *_buf, unsigned _l) {
+  // TODO: duplicate code with WOHTMLParser, but probably isn't worth a
+  //       separate file
+  NSString *r;
+  NSData   *data;
+
+  if (_l == 0)
+    return @"";
+  
+  if (!useUTF8)
+    return [[StrClass alloc] initWithCString:_buf length:_l];
+  
+  // Note: we cast the pointer because we are not going to modify _buf for the
+  //       duration and we are never going to write the data - should work
+  //       with any Foundation, but isn't strictly API compatible
+  data = [[NSData alloc] initWithBytesNoCopy:(void *)_buf length:_l 
+                         freeWhenDone:NO];
+  r = [[StrClass alloc] initWithData:data encoding:NSUTF8StringEncoding];
+  [data release];
+  return r;
+}
+
+- (NSException *)parseDefinitionsFromBuffer:(const char *)_buffer
+  length:(unsigned)_len
+  mappings:(NSMutableDictionary *)_mappings
+{
+  NSException *exception     = nil;
+  NSString    *elementName   = nil;
+  NSString    *componentName = nil;
+  unsigned    idx            = 0;
+  id          entry          = nil;
+  
+  [_mappings removeAllObjects];
+  
+  while ((entry = _parseWodEntry(NULL, _buffer, &idx, _len, &exception,
+                                 &elementName, &componentName,
+                                 self))) {
+    id def;
+    
+    if (exception) {
+      RELEASE(entry);         entry         = nil;
+      RELEASE(elementName);   elementName   = nil;
+      RELEASE(componentName); componentName = nil;
+      break;
+    }
+
+    if ([_mappings objectForKey:elementName] != nil)
+      NSLog(@"WARNING: duplicate definition of element %@  !", elementName);
+
+    def = [self elementDefinitionForComponent:componentName
+                associations:entry
+                elementName:elementName];
+    
+    RELEASE(componentName); componentName = nil;
+    RELEASE(entry);         entry         = nil;
+
+    if ((def != nil) && (elementName != nil))
+      [_mappings setObject:def forKey:elementName];
+#if 0
+    NSLog(@"defined element %@ definition=%@", elementName, def);
+#endif
+    RELEASE(elementName); elementName = nil;
+  }
+
+  return exception;
+}
+
+/* parsing */
+
+- (NSDictionary *)parseDeclarationData:(NSData *)_decl {
+  NSMutableDictionary *defs;
+  NSException *ex;
+  
+  if (![self->callback parser:self willParseDeclarationData:_decl])
+    return nil;
+
+  defs = [NSMutableDictionary dictionaryWithCapacity:100];
+  
+  ex = [self parseDefinitionsFromBuffer:[_decl bytes]
+             length:[_decl length]
+             mappings:defs];
+  
+  if (ex)
+    [self->callback parser:self failedParsingDeclarationData:_decl exception:ex];
+  else {
+    [self->callback parser:self finishedParsingDeclarationData:_decl
+                    declarations:defs];
+  }
+  
+  return defs;
+}
+
+
+static int _numberOfLines(const char *_buffer, unsigned _lastIdx) {
+  register unsigned pos, lineCount = 1;
+
+  for (pos = 0; (pos < _lastIdx) && (_buffer[pos] != '\0'); pos++) {
+    if (_buffer[pos] == '\n')
+      lineCount++;
+  }
+  return lineCount;
+}
+
+static inline BOOL _isBreakChar(unsigned char _c) {
+  switch (_c) {
+    case ' ': case '\t': case '\n': case '\r':
+    case '=':  case ';':  case ',':
+    case '{': case '(':  case '"':  case '<':
+    case '.': case ':':
+    case ')': case '}':
+      return YES;
+
+    default:
+      return NO;
+  }
+}
+static inline BOOL _isIdChar(unsigned char _c) {
+  return (_isBreakChar(_c) && (_c != '.')) ? NO : YES;
+}
+
+static inline int _valueOfHexChar(unsigned char _c) {
+  switch (_c) {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      return (_c - 48); // 0-9 (ascii-char)'0' - 48 => (int)0
+      
+    case 'A': case 'B': case 'C':
+    case 'D': case 'E': case 'F':
+      return (_c - 55); // A-F, A=10..F=15, 'A'=65..'F'=70
+      
+    case 'a': case 'b': case 'c':
+    case 'd': case 'e': case 'f':
+      return (_c - 87); // a-f, a=10..F=15, 'a'=97..'f'=102
+
+    default:
+      return -1;
+  }
+}
+static inline BOOL _isHexDigit(unsigned char _c) {
+  switch (_c) {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+    case 'A': case 'B': case 'C':
+    case 'D': case 'E': case 'F':
+    case 'a': case 'b': case 'c':
+    case 'd': case 'e': case 'f':
+      return YES;
+
+    default:
+      return NO;
+  }
+}
+
+static NSException *_makeException(NSException *_exception,
+                                   const char *_buffer, unsigned _idx,
+                                   unsigned _len, NSString *_text)
+{
+  NSMutableDictionary *ui = nil;
+  NSException *exception = nil;
+  int         numLines;
+  BOOL        atEof;
+  
+  numLines   = _numberOfLines(_buffer, _idx);
+  atEof      = (_idx >= _len) ? YES : NO;
+  
+  if (_exception)
+    // error resulted from a previous error (exception already set)
+    return _exception;
+
+  if (atEof)
+    _text = [@"Unexpected end: " stringByAppendingString:[_text stringValue]];
+  else {
+    _text = [StrClass stringWithFormat:@"Syntax error in line %i: %@",
+                        numLines, _text];
+  }
+
+  // user info
+  ui = [[exception userInfo] mutableCopy];
+  if (ui == nil)
+    ui = [[DictClass alloc] initWithCapacity:8];
+
+  [ui setObject:[NumberClass numberWithInt:numLines] forKey:@"line"];
+  [ui setObject:[NumberClass numberWithInt:_len]     forKey:@"size"];
+  [ui setObject:[NumberClass numberWithInt:_idx]     forKey:@"position"];
+
+  if (!atEof && (_idx > 0)) {
+    register unsigned pos;
+    const char *startPos, *endPos;
+
+    for (pos = _idx; (pos >= 0) && (_buffer[pos] != '\n'); pos--)
+      ;
+    startPos = &(_buffer[pos + 1]);
+
+    for (pos = _idx; ((pos < _len) && (_buffer[pos] != '\n')); pos++)
+      ;
+    endPos = &(_buffer[pos - 1]);
+    
+    if (startPos < endPos) {
+      NSString *ll;
+
+      ll = _makeStringForBuffer(startPos, endPos - startPos);
+      [ui setObject:ll forKey:@"lastLine"];
+      [ll release];
+    }
+    else {
+      NSLog(@"%s: startPos=0x%08X endPos=0x%08X", __PRETTY_FUNCTION__,
+            startPos, endPos);
+    }
+  }
+
+  exception = [NSException exceptionWithName:@"SyntaxError"
+                           reason:_text
+                           userInfo:ui];
+  [ui release]; ui = nil;
+
+  return exception;
+}
+
+static BOOL _skipComments(const char *_buffer, unsigned *_idx, unsigned _len,
+                          NSException **_exception)
+{
+  register unsigned pos = *_idx;
+  BOOL lookAgain;
+
+  if (pos >= _len)
+    return NO;
+
+  //NSLog(@"start at '%c' (%i)", _buffer[pos], pos);
+  
+  do { // until all comments are filtered ..
+    lookAgain = NO;
+    
+    if ((_buffer[pos] == '/') && (pos + 1 < _len)) {
+      if (_buffer[pos + 1] == '/') { // single line comments
+        pos += 2; // skip '//'
+
+        // search for '\n' ..
+        while ((pos < _len) && (_buffer[pos] != '\n'))
+          pos++;
+
+        if ((pos < _len) && (_buffer[pos] == '\n')) {
+          pos++; // skip newline, otherwise EOF was reached
+          lookAgain = YES;
+        }
+      }
+      else if (_buffer[pos + 1] == '*') { /* multiline comments */
+        BOOL commentIsClosed = NO;
+      
+        pos += 2; // skip '/*'
+
+        do { // search for '*/'
+          while ((pos < _len) && (_buffer[pos] != '*'))
+            pos++;
+
+          if (pos < _len) { // found '*'
+            if ((pos + 1) < _len) {
+              if (_buffer[pos + 1] == '/') { // found '*/'
+                commentIsClosed = YES;
+                pos += 2; // skip '*/'
+                lookAgain = YES;
+                break; // leave loop
+              }
+            }
+          }
+        }
+        while (pos < _len);
+
+        if (!commentIsClosed) {
+          // EOF found, comment wasn't closed
+          *_exception =
+            _makeException(*_exception, _buffer, *_idx, _len,
+                           @"comment was not closed (expected '*/')");
+          return NO;
+        }
+      }
+    }
+    else if (isspace((int)_buffer[pos])) {
+      pos++;
+      lookAgain = YES;
+    }
+  }
+  while (lookAgain && (pos < _len));
+  
+  // store position ..
+  *_idx = pos;
+  //NSLog(@"end at '%c' (%i)", _buffer[pos], pos);
+
+  return (pos < _len);
+}
+
+static NSString *_parseIdentifier(NSZone *_zone,
+                                  const char *_buffer, unsigned *_idx,
+                                  unsigned _len, NSException **_exception)
+{
+  register unsigned pos = *_idx;
+  register unsigned len = 0;
+  unsigned startPos = pos;
+
+  // skip comments and spaces
+  if (!_skipComments(_buffer, _idx, _len, _exception)) {
+    // EOF reached during comment-skipping
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                        @"did not find an id (expected 'a-zA-Z0-9') !");
+    return nil;
+  }
+  
+  // loop until break char
+  while (_isIdChar(_buffer[pos]) && (pos < _len)) {
+    pos++;
+    len++;
+  }
+
+  if (len == 0) { // wasn't a string ..
+    *_exception =
+      _makeException(*_exception, _buffer, *_idx, _len,
+                     @"did not find an id (expected 'a-zA-Z0-9') !");
+    return nil;
+  }
+  else {
+    *_idx = pos;
+    return _makeStringForBuffer(&(_buffer[startPos]), len);
+  }
+}
+static NSString *_parseKeyPath(NSZone *_zone,
+                               const char *_buffer, unsigned *_idx,
+                               unsigned _len, NSException **_exception,
+                               id self)
+{
+  NSMutableString *keypath   = nil;
+  NSString        *component = nil;
+  
+  if (!_skipComments(_buffer, _idx, _len, _exception)) {
+    // EOF reached during comment-skipping
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"did not find keypath (expected id)");
+    return nil;
+  }
+
+  component = _parseIdentifier(_zone, _buffer, _idx, _len, _exception);
+  if (component == nil) {
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"did not find keypath (expected id)");
+    return nil;
+  }
+  if (_buffer[*_idx] != '.') // single id-keypath
+    return component;
+
+  keypath = [[NSMutableString allocWithZone:_zone] init];
+  [keypath appendString:component];
+  
+  while ((_buffer[*_idx] == '.') && (component != nil)) {
+    *_idx += 1; // skip '.'
+    [keypath appendString:@"."];
+
+    RELEASE(component); component = nil;
+    component = _parseIdentifier(_zone, _buffer, _idx, _len, _exception);
+
+    if (component == nil) {
+      RELEASE(keypath); keypath = nil;
+      *_exception =
+        _makeException(*_exception, _buffer, *_idx, _len,
+                       @"expected component after '.' in keypath !");
+      break;
+    }
+
+    [keypath appendString:component];
+  }
+  RELEASE(component); component = nil;
+
+  return keypath;
+}
+
+static NSString *_parseQString(NSZone *_zone,
+                               const char *_buffer, unsigned *_idx,
+                               unsigned _len, NSException **_exception,
+                               id self)
+{
+  // skip comments and spaces
+  if (!_skipComments(_buffer, _idx, _len, _exception)) {
+    // EOF reached during comment-skipping
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                        @"did not find a quoted string (expected '\"') !");
+    return nil;
+  }
+
+  if (_buffer[*_idx] != '"') { // it's not a quoted string that's follows
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"did not find quoted string (expected '\"')");
+    return nil;
+  }
+  else { // a quoted string
+    register unsigned pos = *_idx;
+    register unsigned len = 0;
+    unsigned startPos = pos + 1;
+    BOOL     containsEscaped = NO;
+    
+    pos++; // skip starting quote
+
+    // loop until closing quote
+    while ((_buffer[pos] != '"') && (pos < _len)) {
+      if (_buffer[pos] == '\\') {
+        containsEscaped = YES;
+        pos++; // skip following char
+        if (pos == _len) {
+          *_exception =
+            _makeException(*_exception, _buffer, *_idx, _len,
+                           @"escape in quoted string not finished !");
+          return nil;
+        }
+      }
+      pos++;
+      len++;
+    }
+
+    if (pos == _len) { // syntax error, quote not closed
+      *_idx = pos;
+      *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"quoted string not closed (expected '\"')");
+      return nil;
+    }
+
+    pos++;       // skip closing quote
+    *_idx = pos; // store pointer
+    pos = 0;
+    
+    if (len == 0) { // empty string
+      return @"";
+    }
+    else if (containsEscaped) {
+      register unsigned pos2;
+      id   ostr = nil;
+      unsigned char *str;
+      
+      NSCAssert(len > 0, @"invalid length ..");
+      str = malloc(len + 3);
+      
+      for (pos = startPos, pos2 = 0; _buffer[pos] != '"'; pos++, pos2++) {
+        //NSLog(@"char=%c pos=%i pos2=%i", _buffer[pos], pos2);
+        if (_buffer[pos] == '\\') {
+          pos++;
+          switch (_buffer[pos]) {
+            case 'a':  str[pos2] = '\a'; break;
+            case 'b':  str[pos2] = '\b'; break;
+            case 'f':  str[pos2] = '\f'; break;
+            case 'n':  str[pos2] = '\n'; break;
+            case 't':  str[pos2] = '\t'; break;
+            case 'v':  str[pos2] = '\v'; break;
+            case '\\': str[pos2] = '\\'; break;
+            
+            default:
+              str[pos2] = _buffer[pos];
+              break;
+          }
+        }
+        else {
+          str[pos2] = _buffer[pos];
+        }
+      }
+      str[pos2] = '\0';
+      NSCAssert(pos2 == len, @"invalid unescape ..");
+      
+      ostr = _makeStringForBuffer(str, pos2);
+      if (str) free(str); str = NULL;
+
+      return ostr;
+    }
+    else {
+      NSCAssert(len > 0, @"invalid length ..");
+      return _makeStringForBuffer(&(_buffer[startPos]), len);
+    }
+  }
+}
+
+static NSData *_parseData(NSZone *_zone, const char *_buffer,
+                          unsigned *_idx, unsigned _len,
+                          NSException **_exception,
+                          id self)
+{
+  if (!_skipComments(_buffer, _idx, _len, _exception)) {
+    // EOF reached during comment-skipping
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"did not find a data (expected '<') !");
+    return nil;
+  }
+
+  if (_buffer[*_idx] != '<') { // it's not a data that's follows
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"did not find a data (expected '<') !");
+    return nil;
+  }
+  else {
+    register      unsigned pos = *_idx + 1;
+    register      unsigned len = 0;
+    unsigned      endPos = 0;
+    NSMutableData *data  = nil;
+    
+    *_idx += 1; // skip '<'
+
+    if (!_skipComments(_buffer, _idx, _len, _exception)) {
+      *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"data was not closed (expected '>') ..");
+      return nil; // EOF
+    }
+
+    if (_buffer[*_idx] == '>') { // empty data
+      *_idx += 1; // skip '>'
+      return [[NSData allocWithZone:_zone] init];
+    }
+
+    // count significant chars
+    while ((_buffer[pos] != '>') && (pos < _len)) {
+      if ((_buffer[pos] == ' ') || (_buffer[pos] == '\t'))
+        ;
+      else if (_isHexDigit(_buffer[pos]))
+        len++;
+      else {
+        *_idx = pos;
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"invalid char in data property");
+        return nil;
+      }
+      pos++;
+    }
+    if (pos == _len) {
+      *_idx = pos;
+      *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"data was not closed (expected '>')");
+      return nil; // EOF
+    }
+    endPos = pos; // store position of closing '>'
+
+    // if odd, then add one byte for trailing nibble
+    len = (len % 2 == 1) ? len / 2 + 1 : len / 2;
+    data = [[NSMutableData allocWithZone:_zone] initWithLength:len];
+
+    /* now copy bytes ... */
+    {
+      register unsigned i;
+      register int pending = -1;
+      char *buf = [data mutableBytes];
+      
+      for (pos = *_idx, i = 0; (pos < endPos) && (i < len); pos++) {
+        int value = _valueOfHexChar(_buffer[pos]);
+
+        if (value != -1) {
+          if (pending == -1)
+            pending = value;
+          else {
+            value = value * 16 + pending;
+            pending = -1;
+
+            buf[i] = value;
+            i++;
+          }
+        }
+      }
+      if (pending != -1) { // was odd, now add the trailer ..
+        NSCAssert(i < len, @"invalid length ..");
+        buf[i] = pending * 16;
+      }
+    }
+    
+    // update global position
+    *_idx = endPos + 1; // endPos + 1 (*endPos == '>', 1 => skips '>')
+
+    return data;
+  }
+}
+
+static NSDictionary *_parseDict(NSZone *_zone,
+                                const char *_buffer, unsigned *_idx,
+                                unsigned _len, NSException **_exception,
+                                id self)
+{
+  if (!_skipComments(_buffer, _idx, _len, _exception)) {
+    // EOF reached during comment-skipping
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"did not find dictionary (expected '{')");
+    return nil;
+  }
+  
+  if (_buffer[*_idx] != '{') { // it's not a dict that's follows
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"did not find dictionary (expected '{')");
+    return nil;
+  }
+  else {
+    NSMutableDictionary *result = nil;
+    id   key     = nil;
+    id   value   = nil;
+    BOOL didFail = NO;
+    
+    *_idx += 1; // skip '{'
+
+    if (!_skipComments(_buffer, _idx, _len, _exception)) {
+      *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"dictionary was not closed (expected '}')");
+      return nil; // EOF
+    }
+
+    if (_buffer[*_idx] == '}') { // an empty dictionary
+      *_idx += 1; // skip the '}'
+      return [[DictClass allocWithZone:_zone] init];
+    }
+
+    result = [[DictClass allocWithZone:_zone] init];
+    do {
+      key   = nil;
+      value = nil;
+      
+      if (!_skipComments(_buffer, _idx, _len, _exception)) {
+        *_exception =
+          _makeException(*_exception, _buffer, *_idx, _len,
+                         @"dictionary was not closed (expected '}')");
+        didFail = YES;
+        break; // unexpected EOF
+      }
+
+      if (_buffer[*_idx] == '}') { // dictionary closed
+        *_idx += 1; // skip the '}'
+        break;
+      }
+      
+      // read key property
+      key = _parseProperty(_zone, _buffer, _idx, _len, _exception, NO, self);
+      if (key == nil) { // syntax error
+        if (*_exception == nil) {
+          *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                       @"got nil-key in dictionary ..");
+        }
+        didFail = YES;
+        break;
+      }
+
+      /* The following parses:  (comment|space)* '=' (comment|space)* */
+      if (!_skipComments(_buffer, _idx, _len, _exception)) {
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"expected '=' after key in dictionary");
+        didFail = YES;
+        break; // unexpected EOF
+      }
+      // no we need a '=' assignment
+      if (_buffer[*_idx] != '=') {
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"expected '=' after key in dictionary");
+        didFail = YES;
+        break;
+      }
+      *_idx += 1; // skip '='
+      if (!_skipComments(_buffer, _idx, _len, _exception)) {
+        *_exception =
+          _makeException(*_exception, _buffer, *_idx, _len,
+                         @"expected value after key '=' in dictionary");
+        didFail = YES;
+        break; // unexpected EOF
+      }
+
+      // read value property
+      value = _parseProperty(_zone, _buffer, _idx, _len, _exception, NO, self);
+#if 1
+      if (*_exception) {
+        didFail = YES;
+        break;
+      }
+#else
+      if (value == nil) { // syntax error
+        if (*_exception == nil) {
+          *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                       @"got nil-value in dictionary");
+        }
+        didFail = YES;
+        break;
+      }
+#endif
+      
+      if ((key != nil) && (value != nil))
+        [result setObject:value forKey:key];
+      
+      // release key and value
+      RELEASE(key);   key   = nil;
+      RELEASE(value); value = nil;
+
+      // read trailing ';' if available
+      if (!_skipComments(_buffer, _idx, _len, _exception)) {
+        *_exception =
+          _makeException(*_exception, _buffer, *_idx, _len,
+                         @"dictionary was not closed (expected '}')");
+        didFail = YES;
+        break; // unexpected EOF
+      }
+      if (_buffer[*_idx] == ';') {
+        *_idx += 1; // skip ';'
+      }
+      else { // no ';' at end of pair, only allowed at end of dictionary
+        if (!_skipComments(_buffer, _idx, _len, _exception)) {
+          *_exception =
+            _makeException(*_exception, _buffer, *_idx, _len,
+                           @"dictionary was not closed (expected '}')");
+          didFail = YES;
+          break; // unexpected EOF
+        }
+
+        if (_buffer[*_idx] != '}') { // dictionary wasn't closed
+          *_exception =
+            _makeException(*_exception, _buffer, *_idx, _len,
+                           @"key-value pair without ';' at the end");
+          didFail = YES;
+          break;
+        }
+      }
+    }
+    while ((*_idx < _len) && (result != nil) && !didFail);
+
+    RELEASE(key);    key    = nil;
+    RELEASE(value);  value  = nil;
+    if (didFail) {
+      [result release]; result = nil;
+      return nil;
+    }
+    else
+      return result;
+  }
+}
+
+static NSArray *_parseArray(NSZone *_zone, const char *_buffer, unsigned *_idx,
+                            unsigned _len, NSException **_exception,
+                            id self)
+{
+  if (!_skipComments(_buffer, _idx, _len, _exception)) {
+    // EOF reached during comment-skipping
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"did not find array (expected '(')");
+    return nil;
+  }
+
+  if (_buffer[*_idx] != '(') { // it's not an array that's follows
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"did not find array (expected '(')");
+    return nil;
+  }
+  else {
+    NSMutableArray *result = nil;
+    id element = nil;
+
+    *_idx += 1; // skip '('
+
+    if (!_skipComments(_buffer, _idx, _len, _exception)) {
+      *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                   @"array was not closed (expected ')')");
+      return nil; // EOF
+    }
+
+    if (_buffer[*_idx] == ')') { // an empty array
+      *_idx += 1; // skip the ')'
+      return [[NSArray allocWithZone:_zone] init];
+    }
+    
+    result = [[NSMutableArray allocWithZone:_zone] init];
+    do {
+      element = _parseProperty(_zone, _buffer, _idx, _len, _exception, NO, self);
+      if (element == nil) {
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"expected element in array");
+        [result release]; result = nil;
+        break;
+      }
+      [result addObject:element];
+      [element release]; element = nil;
+      
+      if (!_skipComments(_buffer, _idx, _len, _exception)) {
+        *_exception =
+          _makeException(*_exception, _buffer, *_idx, _len,
+                         @"array was not closed (expected ')' or ',')");
+        [result release];
+        result = nil;
+        break;
+      }
+      
+      if (_buffer[*_idx] == ')') { // closed array
+        *_idx += 1; // skip ')'
+        break;
+      }
+      else if (_buffer[*_idx] == ',') { // next element
+        *_idx += 1; // skip ','
+        
+        if (!_skipComments(_buffer, _idx, _len, _exception)) {
+          *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                       @"array was not closed (expected ')')");
+          [result release];
+          result = nil;
+          break;
+        }
+        if (_buffer[*_idx] == ')') { // closed array, like this '(1,2,)'
+          *_idx += 1; // skip ')'
+          break;
+        }
+      }
+      else { // syntax error
+        *_exception =
+          _makeException(*_exception, _buffer, *_idx, _len,
+                         @"expected ')' or ',' after array element");
+        [result release]; result = nil;
+        break;
+      }
+    }
+    while ((*_idx < _len) && (result != nil));
+    
+    [element release]; element = nil;
+
+    return result;
+  }
+}
+
+static NSNumber *_parseDigitPath(NSString *digitPath) {
+  NSRange  r;
+
+  r = [digitPath rangeOfString:@"."];
+  return r.length > 0 
+    ? [NumberClass numberWithDouble:[digitPath doubleValue]]
+    : [NumberClass numberWithInt:[digitPath intValue]];
+}
+
+static id _parseProperty(NSZone *_zone, const char *_buffer, unsigned *_idx,
+                         unsigned _len,
+                         NSException **_exception, BOOL _allowAssoc,
+                         id self)
+{
+  BOOL valueProperty = YES;
+  id   result = nil;
+  
+  if (!_skipComments(_buffer, _idx, _len, _exception))
+    return nil; // EOF
+
+  switch (_buffer[*_idx]) {
+    case '"': // quoted string
+      NSCAssert(result == nil, @"result is already set ..");
+      result = _parseQString(_zone, _buffer, _idx, _len, _exception, self);
+      break;
+
+    case '{': // dictionary
+      NSCAssert(result == nil, @"result is already set ..");
+      result = _parseDict(_zone, _buffer, _idx, _len, _exception, self);
+      break;
+
+    case '(': // array
+      NSCAssert(result == nil, @"result is already set ..");
+      result = _parseArray(_zone, _buffer, _idx, _len, _exception, self);
+      break;
+
+    case '<': // data
+      NSCAssert(result == nil, @"result is already set ..");
+      result = _parseData(_zone, _buffer, _idx, _len, _exception, self);
+      break;
+      
+    default:
+      NSCAssert(result == nil, @"result is already set ..");
+      
+      if (isdigit((int)_buffer[*_idx]) || (_buffer[*_idx] == '-')) {
+        id digitPath;
+        NSCAssert(result == nil, @"result is already set ..");
+        
+        digitPath = _parseKeyPath(_zone, _buffer, _idx, _len, _exception,self);
+        result = [_parseDigitPath(digitPath) retain];
+        [digitPath release]; digitPath = nil;
+        valueProperty = YES;
+      }
+      else if (_isIdChar(_buffer[*_idx])) {
+        valueProperty = NO;
+       
+        if ((_buffer[*_idx] == 'Y') || (_buffer[*_idx] == 'N')) {
+          // parse YES and NO
+          if ((*_idx + 4) < _len) {
+            if (strncmp(&(_buffer[*_idx]), "YES", 3) == 0 &&
+               _isBreakChar(_buffer[*_idx + 3])) {
+              result = [yesNum retain];
+              valueProperty = YES;
+              *_idx += 3; // skip the YES
+            }
+          }
+          if (((*_idx + 3) < _len) && !valueProperty) {
+            if (strncmp(&(_buffer[*_idx]), "NO", 2) == 0 &&
+               _isBreakChar(_buffer[*_idx + 2])) {
+              result = [noNum retain];
+              valueProperty = YES;
+              *_idx += 2; // skip the NO
+            }
+          }
+        }
+        else if ((_buffer[*_idx] == 't') || (_buffer[*_idx] == 'f')) {
+          // parse true and false
+          if ((*_idx + 5) < _len) {
+            if (strncmp(&(_buffer[*_idx]), "true", 4) == 0 &&
+               _isBreakChar(_buffer[*_idx + 4])) {
+              result = [yesNum retain];
+              valueProperty = YES;
+              *_idx += 4; // skip the true
+            }
+          }
+          if (((*_idx + 6) < _len) && !valueProperty) {
+            if (strncmp(&(_buffer[*_idx]), "false", 5) == 0 &&
+               _isBreakChar(_buffer[*_idx + 5])) {
+              result = [noNum retain];
+              valueProperty = YES;
+              *_idx += 5; // skip the false
+            }
+          }
+        }
+        
+        if (!valueProperty) {
+          NSCAssert(result == nil, @"result already set ..");
+          result = _parseKeyPath(_zone, _buffer, _idx, _len, _exception, self);
+        }
+      }
+      else {
+        NSCAssert(result == nil, @"result already set ..");
+        
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                     @"invalid char");
+      }
+      break;
+  }
+
+  if (*_exception)
+    return nil;
+  
+  if (result == nil) {
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"error in property value");
+  }
+
+  NSCAssert(result, @"missing property value ..");
+
+  if (_allowAssoc) {
+    id old = result;
+    
+    result = valueProperty
+      ? [self associationWithValue:result]
+      : [self associationWithKeyPath:result];
+    
+#if 0
+    NSCAssert(result, @"got no association for property ..");
+#endif
+    [old release]; old = nil;
+    
+    return [result retain];
+  }
+  
+  /* result is already retained */
+  return result;
+}
+
+static NSDictionary *_parseWodConfig(NSZone *_zone, const char *_buffer,
+                                     unsigned *_idx, unsigned _len,
+                                     NSException **_exception,
+                                     id self)
+{
+  if (!_skipComments(_buffer, _idx, _len, _exception)) {
+    // EOF reached during comment-skipping
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                     @"did not find element configuration (expected '{')");
+    return nil;
+  }
+  
+  if (_buffer[*_idx] != '{') { // it's not a dict that's follows
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                     @"did not find element configuration (expected '{')");
+    return nil;
+  }
+  else { // found '{'
+    NSMutableDictionary *result = nil;
+    NSString *key     = nil;
+    id       value    = nil;
+    BOOL     didFail  = NO;
+    
+    *_idx += 1; // skip '{'
+
+    if (!_skipComments(_buffer, _idx, _len, _exception)) {
+      *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                       @"element configuration was not closed (expected '}')");
+      return nil; // EOF
+    }
+
+    if (_buffer[*_idx] == '}') { // an empty configuration
+      *_idx += 1; // skip the '}'
+      return [[DictClass allocWithZone:_zone] init];
+    }
+
+    result = [[DictClass allocWithZone:_zone] init];
+    do {
+      key   = nil;
+      value = nil;
+      
+      if (!_skipComments(_buffer, _idx, _len, _exception)) {
+        *_exception =
+          _makeException(*_exception, _buffer, *_idx, _len,
+                         @"dictionary was not closed (expected '}')");
+        didFail = YES;
+        break; // unexpected EOF
+      }
+
+      if (_buffer[*_idx] == '}') { // dictionary closed
+        *_idx += 1; // skip the '}'
+        break;
+      }
+      
+      // read key property
+      key = _parseIdentifier(_zone, _buffer, _idx, _len, _exception);
+      if (key == nil) { // syntax error
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                         @"expected identifier in element configuration ..");
+        didFail = YES;
+        break;
+      }
+
+      /* The following parses:  (comment|space)* '=' (comment|space)* */
+      if (!_skipComments(_buffer, _idx, _len, _exception)) {
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                         @"expected '=' after id in element configuration");
+        didFail = YES;
+        break; // unexpected EOF
+      }
+      // no we need a '=' assignment
+      if (_buffer[*_idx] != '=') {
+        *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                         @"expected '=' after id in element configuration");
+        didFail = YES;
+        break;
+      }
+      *_idx += 1; // skip '='
+      if (!_skipComments(_buffer, _idx, _len, _exception)) {
+        *_exception =
+          _makeException(*_exception, _buffer, *_idx, _len,
+                         @"expected value after id '=' in "
+                         @"element configuration");
+        didFail = YES;
+        break; // unexpected EOF
+      }
+
+      // read value property
+      value = _parseProperty(_zone, _buffer, _idx, _len, _exception, YES, self);
+#if 1
+      if (*_exception) {
+        didFail = YES;
+        break;
+      }
+#else
+      if (value == nil) { // syntax error
+        if (*_exception == nil) {
+          *_exception =
+            _makeException(*_exception, _buffer, *_idx, _len,
+                           @"got nil-value in element configuration");
+        }
+        didFail = YES;
+        break;
+      }
+      NSCAssert(key,   @"invalid key ..");
+      NSCAssert(value, @"invalid value ..");
+#endif
+
+      if ((value != nil) && (key != nil))
+        [result setObject:value forKey:key];
+
+      // release key and value
+      RELEASE(key);   key   = nil;
+      RELEASE(value); value = nil;
+
+      // read trailing ';' if available
+      if (!_skipComments(_buffer, _idx, _len, _exception)) {
+        *_exception =
+          _makeException(*_exception, _buffer, *_idx, _len,
+                         @"element configuration was not "
+                         @"closed (expected '}')");
+        didFail = YES;
+        break; // unexpected EOF
+      }
+      if (_buffer[*_idx] == ';') {
+        *_idx += 1; // skip ';'
+      }
+      else { // no ';' at end of pair, only allowed at end of dictionary
+        if (!_skipComments(_buffer, _idx, _len, _exception)) {
+          *_exception =
+            _makeException(*_exception, _buffer, *_idx, _len,
+                           @"element configuration was not "
+                           @"closed (expected '}')");
+          didFail = YES;
+          break; // unexpected EOF
+        }
+
+        if (_buffer[*_idx] != '}') { // config wasn't closed
+          *_exception =
+            _makeException(*_exception, _buffer, *_idx, _len,
+                           @"key-value pair without ';' at the end");
+          didFail = YES;
+          break;
+        }
+      }
+    }
+    while ((*_idx < _len) && (result != nil) && !didFail);
+
+    [key   release]; key    = nil;
+    [value release]; value  = nil;
+    
+    if (didFail) {
+      [result release]; result = nil;
+      return nil;
+    }
+    else
+      return result;
+  }
+}
+
+static id _parseWodEntry(NSZone *_zone, const char *_buffer, unsigned *_idx,
+                         unsigned _len, NSException **_exception,
+                         NSString **_name, NSString **_class, id self)
+{
+  NSString     *elementName   = nil;
+  NSString     *componentName = nil;
+  NSDictionary *config        = nil;
+
+  *_name  = nil;
+  *_class = nil;
+  
+  if (!_skipComments(_buffer, _idx, _len, _exception))
+    return nil; // EOF
+
+  // Element name
+  elementName = _parseIdentifier(_zone, _buffer, _idx, _len, _exception);
+  if (elementName == nil) {
+    *_exception = _makeException(nil, _buffer, *_idx, _len,
+                                 @"expected element name");
+    goto failed;
+  }
+
+  if (!_skipComments(_buffer, _idx, _len, _exception))
+    goto failed;
+
+  // Element/Component separator
+  if (_buffer[*_idx] == ':') {
+    *_idx += 1; // skip ':'
+  }
+  else {
+    *_exception = _makeException(*_exception, _buffer, *_idx, _len,
+                                 @"expected ':' after element name");
+    goto failed;
+  }
+
+  if (!_skipComments(_buffer, _idx, _len, _exception))
+    goto failed;
+
+  // Component Name
+  componentName = _parseIdentifier(_zone, _buffer, _idx, _len, _exception);
+  if (componentName == nil) {
+    *_exception = _makeException(nil, _buffer, *_idx, _len,
+                                 @"expected component name");
+    goto failed;
+  }
+
+  if (!_skipComments(_buffer, _idx, _len, _exception))
+    goto failed;
+
+  // Configuration
+  config = _parseWodConfig(_zone, _buffer, _idx, _len, _exception, self);
+  if (config == nil)
+    goto failed;
+  
+  //NSLog(@"%@ : %@ %@", elementName, componentName, config);
+
+  // read trailing ';' if available
+  if (_skipComments(_buffer, _idx, _len, _exception)) {
+    if (_buffer[*_idx] == ';') {
+      *_idx += 1; // skip ';'
+    }
+  }
+
+  *_name  = elementName;
+  *_class = componentName;
+  return config;
+  
+ failed:
+#if 0
+  NSLog(@"failed at %@:%@ ..", elementName, componentName);
+#endif
+  [elementName   release]; elementName   = nil;
+  [componentName release]; componentName = nil;
+  [config        release]; config        = nil;
+  return nil;
+}
+
+@end /* WODParser */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOHTMLParser.h b/skyrix-sope/NGObjWeb/Templates/WOHTMLParser.h
new file mode 100644 (file)
index 0000000..a8dd05c
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOHTMLParser_H__
+#define __WOHTMLParser_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  WOHTMLParser
+  
+  This parser parses "old-style" .wo templates. It does *not* process the
+  whole HTML of the file, it only searches for text sections which start
+  with "<#". That way you can process "illegal" HTML code, eg:
+
+    <a href="<#MyLink" />"> ...
+
+  So the syntax is:
+    <#wod-name>...</#wod-name>
+*/
+
+@class NSString, NSDictionary, NSArray, NSException, NSData;
+@class WOElement;
+
+@protocol WOHTMLParserHandler
+
+- (BOOL)parser:(id)_parser willParseHTMLData:(NSData *)_data;
+- (void)parser:(id)_parser finishedParsingHTMLData:(NSData *)_data
+  elements:(NSArray *)_elements;
+- (void)parser:(id)_parser failedParsingHTMLData:(NSData *)_data
+  exception:(NSException *)_exception;
+
+- (WOElement *)dynamicElementWithName:(NSString *)_element
+  attributes:(NSDictionary *)_attributes // not the associations !
+  contentElements:(NSArray *)_subElements;
+
+@end
+
+@interface WOHTMLParser : NSObject
+{
+  id<NSObject,WOHTMLParserHandler> callback;
+  NSException *parsingException;
+}
+
+- (id)initWithHandler:(id<NSObject,WOHTMLParserHandler>)_handler;
+
+/* accessors */
+
+- (NSException *)parsingException;
+
+/* parsing */
+
+- (NSArray *)parseHTMLData:(NSData *)_html;
+
+@end
+
+#endif /* __WOHTMLParser_H__ */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOHTMLParser.m b/skyrix-sope/NGObjWeb/Templates/WOHTMLParser.m
new file mode 100644 (file)
index 0000000..b8905f7
--- /dev/null
@@ -0,0 +1,914 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHTMLParser.h"
+#include <NGObjWeb/WODynamicElement.h>
+#include <NGObjWeb/WOElement.h>
+#include "common.h"
+
+/*
+  Internals
+  
+  The root parse function is _parseElement() which calls either 
+  _parseWOElement() or _parseHashElement() if it finds a NGObjWeb tag at the 
+  beginning of the buffer. 
+  If it doesn't it collects all content till it encounteres an NGObjWeb tag, 
+  and reports that content as "static text" to the callback.
+  
+  Parsing a dynamic element is:
+    - parse the start tag
+    - parse the attributes
+    - parse the contents, static strings and elements
+      - add content to a children array
+    - produce WOElement by calling
+      -dynamicElementWithName:attributes:contentElements:
+    - parse close tag
+*/
+
+@interface WOElement(StaticStringElement)
+- (id)initWithBuffer:(const char *)_buffer length:(unsigned)_len;
+@end
+
+@implementation WOHTMLParser
+
+static WOElement *_parseElement(NSZone *_zone,
+                                const char *_buffer, unsigned *_idx,
+                                unsigned _len, NSException **_exception,
+                                WOHTMLParser *self);
+
+static Class StrClass      = Nil;
+static Class DictClass     = Nil;
+static Class NumberClass   = Nil;
+static Class WOStringClass = Nil;
+static BOOL  skipPlainTags = NO; /* do process markers inside HTML tags ? */
+static BOOL  compressHTMLWhitespace = YES;
+static BOOL  useUTF8 = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  StrClass      = [NSString            class];
+  DictClass     = [NSMutableDictionary class];
+  NumberClass   = [NSNumber            class];
+  WOStringClass = NSClassFromString(@"_WOStaticHTMLElement");
+
+  useUTF8       = [ud boolForKey:@"WOParsersUseUTF8"];
+}
+
+- (id)initWithHandler:(id<NSObject,WOHTMLParserHandler>)_handler {
+  self->callback = [_handler retain];
+  return self;
+}
+- (void)dealloc {
+  [self->parsingException release];
+  [self->callback         release];
+  [super dealloc];
+}
+
+/* callbacks */
+
+- (NSException *)_makeSyntaxErrorException {
+  return [NSException exceptionWithName:@"SyntaxError"
+                      reason:@"template syntax error"
+                      userInfo:nil];
+}
+
+- (WOElement *)dynamicElementWithName:(NSString *)_element
+  attributes:(NSDictionary *)_attributes // not the associations !
+  contentElements:(NSArray *)_subElements
+{
+  return [self->callback dynamicElementWithName:_element
+                         attributes:_attributes
+                         contentElements:_subElements];
+}
+
+- (id)_makeConstantStringElementWithBuffer:(const unsigned char *)_buf
+  length:(unsigned)_len
+{
+  return [[WOStringClass allocWithZone:NULL] initWithBuffer:_buf length:_len];
+}
+
+- (NSString *)_makeStringForBuffer:(const unsigned char *)_buf 
+  length:(unsigned)_len
+{
+  NSString *r;
+  NSData   *data;
+  
+  if (_len == 0)
+    return @"";
+  
+  if (!useUTF8)
+    return [[StrClass alloc] initWithCString:_buf length:_len];
+  
+  // Note: we cast the pointer because we are not going to modify _buf for the
+  //       duration and we are never going to write the data - should work
+  //       with any Foundation, but isn't strictly API compatible
+  data = [[NSData alloc] initWithBytesNoCopy:(void *)_buf length:_len 
+                         freeWhenDone:NO];
+  r = [[StrClass alloc] initWithData:data encoding:NSUTF8StringEncoding];
+  [data release];
+  return r;
+}
+
+/* accessors */
+
+- (NSException *)parsingException {
+  return self->parsingException;
+}
+
+/* parsing API */
+
+- (NSArray *)parseHTMLData:(NSData *)_html {
+  NSMutableArray *topLevel;
+  const char     *html;
+  unsigned       idx, len;
+  NSException    *exception = nil;
+
+  if (![self->callback parser:self willParseHTMLData:_html])
+    return nil;
+  
+  [self->parsingException release]; self->parsingException = nil;
+  
+  if (_html == nil)
+    return nil;
+  
+  topLevel = [NSMutableArray arrayWithCapacity:64];
+  idx  = 0;
+  len  = [_html length];
+  html = [_html bytes];
+  
+  while ((idx < len) && (exception == nil)) {
+    WOElement *element;
+    
+    if ((element = _parseElement(NULL, html, &idx, len, &exception, self))) {
+      [topLevel addObject:element];
+      [element release]; element = nil;
+    }
+  }
+  
+  ASSIGN(self->parsingException, exception);
+  
+  if (exception) {
+    [self->callback parser:self 
+                   failedParsingHTMLData:_html exception:exception];
+  }
+  else {
+    [self->callback parser:self 
+                   finishedParsingHTMLData:_html elements:topLevel];
+  }
+  
+  return self->parsingException ? nil : topLevel;
+}
+
+/* internal parsing */
+
+static int _numberOfLines(const char *_buffer, unsigned _lastIdx) {
+  register int pos, lineCount = 1;
+  
+  for (pos = 0; (pos < (int)_lastIdx) && (_buffer[pos] != '\0'); pos++) {
+    if (_buffer[pos] == '\n')
+      lineCount++;
+  }
+  return lineCount;
+}
+
+static inline BOOL _isHTMLSpace(char c) {
+  switch (c) {
+    case ' ': case '\t': case '\r': case '\n':
+      return YES;
+
+    default:
+      return NO;
+  }
+}
+
+static NSException *_makeHtmlException(NSException *_exception,
+                                       const char *_buffer, unsigned _idx,
+                                       unsigned _len, NSString *_text,
+                                       WOHTMLParser *self)
+{
+  NSMutableDictionary *ui = nil;
+  NSException *exception = nil;
+  int         numLines   = _numberOfLines(_buffer, _idx);
+  BOOL        atEof      = (_idx >= _len) ? YES : NO;
+
+  if (_exception)
+    // error resulted from a previous error (exception already set)
+    return _exception;
+  
+  exception = [self _makeSyntaxErrorException];
+
+  if (atEof)
+    _text = [@"Unexpected end: " stringByAppendingString:[_text stringValue]];
+  else {
+    _text = [StrClass stringWithFormat:@"Syntax error in line %i: %@",
+                      numLines, _text];
+  }
+  
+  [exception setReason:_text];
+
+  /* user info */
+  {
+    ui = [[exception userInfo] mutableCopy];
+    if (ui == nil)
+      ui = [[DictClass alloc] initWithCapacity:8];
+    
+    [ui setObject:[NumberClass numberWithInt:numLines] forKey:@"line"];
+    [ui setObject:[NumberClass numberWithInt:_len]     forKey:@"size"];
+    [ui setObject:[NumberClass numberWithInt:_idx]     forKey:@"position"];
+    
+    if (self)
+      [ui setObject:self forKey:@"handler"];
+    
+    if (!atEof && (_idx > 0)) {
+      register unsigned pos;
+      const unsigned char *startPos, *endPos;
+
+      for (pos = _idx; (pos >= 0) && (_buffer[pos] != '\n'); pos--)
+        ;
+      startPos = &(_buffer[pos + 1]);
+
+      for (pos = _idx; ((pos < _len) && (_buffer[pos] != '\n')); pos++)
+        ;
+      endPos = &(_buffer[pos - 1]);
+      
+      if (startPos < endPos) {
+        NSString *ll;
+        
+        ll = [self _makeStringForBuffer:startPos length:(endPos - startPos)];
+        [ui setObject:ll forKey:@"lastLine"];
+        [ll release];
+      }
+#if HEAVY_DEBUG
+      else {
+        //NSLog(@"startPos=0x%08X endPos=0x%08X", startPos, endPos);
+      }
+#endif
+    }
+    
+#if NeXT_Foundation_LIBRARY || APPLE_FOUNDATION_LIBRARY || \
+    COCOA_Foundation_LIBRARY
+    exception = [NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:ui];
+#else
+    [exception setUserInfo:ui];
+#endif
+
+    [ui release]; ui = nil;
+  }
+
+  return exception;
+}
+
+static inline BOOL
+_isComment(const char *_buffer, unsigned _idx, unsigned _len)
+{
+  // <!----> - 7 chars
+  if ((_idx + 7) >= _len)  // check whether it is long enough
+    return NO;
+  if (_buffer[_idx] != '<') // check whether it is a tag
+    return NO;
+
+  _idx++; if (_buffer[_idx] != '!') return NO;
+  _idx++; if (_buffer[_idx] != '-') return NO;
+  _idx++; if (_buffer[_idx] != '-') return NO;
+
+  return YES;
+}
+
+static inline BOOL _isHashTag(const char *_buf, unsigned _idx, unsigned _len) {
+  /* check for "<#.>" (len 4) */
+  if ((_idx + 3) >= _len)  // check whether it is long enough
+    return NO;
+  return (_buf[_idx] == '<' && _buf[_idx + 1] == '#') ? YES : NO;
+}
+static inline BOOL _isHashCloseTag(const char *_buf, 
+                                  unsigned _idx, unsigned _len) 
+{
+  /* check for "</#.>" (len 5) */
+  if ((_idx + 5) >= _len)  // check whether it is long enough
+    return NO;
+  return (_buf[_idx] == '<' && _buf[_idx + 1] == '/' && _buf[_idx + 2] == '#') 
+    ? YES : NO;
+}
+
+static inline BOOL _isWOTag(const char *_buf, unsigned _idx, unsigned _len) {
+  /* check for "<WEBOBJECT .......>" (len 19) (lowercase is allowed) */
+  if ((_idx + 18) >= _len)  // check whether it is long enough
+    return NO;
+  if (_buf[_idx] != '<') // check whether it is a tag
+    return NO;
+  
+  // now check for '<WEBOBJECT'
+  return (strncasecmp(&(_buf[_idx]), "<WEBOBJECT", 10) == 0) ? YES : NO;
+}
+
+static inline BOOL
+_isWOCloseTag(const char *_buf, unsigned _idx, unsigned _len)
+{
+  /* check for </WEBOBJECT> (len=12) */
+  if ((_idx + 12) > _len)  // check whether it is long enough
+    return NO;
+  if (_buf[_idx] != '<') // check whether it is a tag
+    return NO;
+  
+  return (strncasecmp(&(_buf[_idx]), "</WEBOBJECT>", 12) == 0) ? YES : NO;
+}
+
+static inline void _skipSpaces(register const char *_buffer, unsigned *_idx,
+                               unsigned _len)
+{
+  register unsigned pos = *_idx;
+
+  if (pos >= _len) return; // EOF
+
+  while ((pos < _len) && _isHTMLSpace(_buffer[pos]))
+    pos++;
+
+  *_idx = pos;
+}
+
+static NSString *_parseStringValue(NSZone *_zone,
+                                   register const char *_buffer,
+                                   unsigned *_idx, unsigned _len,
+                                   NSException **_exception,
+                                   WOHTMLParser *self)
+{
+  register unsigned pos = *_idx;
+  
+  _skipSpaces(_buffer, _idx, _len);
+  if (pos >= _len) return nil; // EOF
+  
+  if (_buffer[pos] == '>') return nil;
+  if (_buffer[pos] == '/') return nil;
+  if (_buffer[pos] == '=') return nil;
+  
+  if (_buffer[pos] == '"') { // quoted string
+    register unsigned len = 0;
+    unsigned startPos = pos + 1;
+
+    pos++; // skip starting quote ('"')
+    
+    // loop until closing quote
+    while ((_buffer[pos] != '"') && (pos < _len)) {
+      pos++;
+      len++;
+    }
+    
+    if (pos == _len) { // syntax error, quote not closed
+      *_idx = pos;
+      *_exception = _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                                   @"quoted string not closed (expected '\"')",
+                                   nil);
+      return nil;
+    }
+
+    NSCAssert(_buffer[pos] == '"', @"invalid parser state ..");
+    pos++;       // skip closing quote
+    *_idx = pos; // store pointer
+
+    if (len == 0) // empty string
+      return @"";
+    
+    return [self _makeStringForBuffer:&(_buffer[startPos]) length:len];
+  }
+  else {
+    unsigned startPos = pos;
+
+    //NSLog(@"parsing id at '%c'[%i] ..", _buffer[pos], pos);
+    
+    // loop until '>' or '=' or '/' or space
+    while ((_buffer[pos] != '>') &&
+           (_buffer[pos] != '=') &&
+           (_buffer[pos] != '/') &&
+           (!_isHTMLSpace(_buffer[pos])) &&
+           (pos < _len)) {
+      pos++;
+    }
+    *_idx = pos;
+
+    if ((pos - startPos) == 0) // wasn't a string ..
+      return nil;
+
+    return [self _makeStringForBuffer:&(_buffer[startPos]) 
+                 length:(pos - startPos)];
+  }
+}
+
+static WOElement *_parseHashElement(NSZone *_zone, const char *_buffer,
+                                   unsigned *_idx, unsigned _len,
+                                   NSException **_exc,
+                                   WOHTMLParser *self)
+{
+  /*
+    parses:
+      <#dynelem>....</#dynelem>
+    or
+      <#dynelem/>
+  */
+  static NSString *nameKey = @"NAME";
+  WOElement      *element    = nil;
+  BOOL           foundEndTag = NO;
+  BOOL           isAutoClose = NO;
+  NSMutableArray *children   = nil;
+  NSString       *name;
+  NSDictionary   *nameDict;
+  
+  if (*_idx >= _len) return nil; // EOF
+  
+  if (!_isHashTag(_buffer, *_idx, _len))
+    return nil; // not a hash tag ..
+  
+  // skip '<#'
+  *_idx += 2;
+  
+  if ((name = _parseStringValue(_zone, _buffer, _idx,_len,_exc,self)) == nil) {
+#if HEAVY_DEBUG
+    NSLog(@"ERROR: got no name for hash tag '<#NAME>'");
+#endif
+    if (_exc) // if there was an error ..
+      return nil;
+  }
+  
+  _skipSpaces(_buffer, _idx, _len);
+  if (*_idx >= _len) {
+    *_exc =
+      _makeHtmlException(*_exc, _buffer, *_idx, _len,
+                     @"unexpected EOF: missing '>' in hash element tag (EOF).",
+                     self);
+    [name release]; name = nil;
+    return nil; // unexpected EOF
+  }
+  if (_buffer[*_idx] != '>' && _buffer[*_idx] != '/') {
+    *_exc = _makeHtmlException(*_exc, _buffer, *_idx, _len,
+                                    @"missing '>' in hash element tag.", self);
+    [name release]; name = nil;
+    return nil; // unexpected EOF
+  }
+
+  if (_buffer[*_idx] == '>') {
+    /* has sub-elements (<#name>...</#name>) */
+    *_idx += 1; // skip '>'
+  
+    while ((*_idx < _len) && (*_exc == nil)) {
+      id subElement = nil;
+    
+#if HEAVY_DEBUG
+      NSLog(@"subelement at '%c'[%i] ..", _buffer[*_idx], *_idx);
+#endif
+    
+      if (_isHashCloseTag(_buffer, *_idx, _len)) {
+       foundEndTag = YES;
+       break;
+      }
+
+      subElement = _parseElement(_zone, _buffer, _idx, _len, _exc, self);
+    
+#if HEAVY_DEBUG
+      NSLog(@"  parsed subelement '%@' ..", subElement);
+#endif
+    
+      if (subElement) {
+       if (children == nil)
+         children = [NSMutableArray arrayWithCapacity:10];
+       [children addObject:subElement];
+       [subElement release]; subElement = nil;
+      }
+    }
+  }
+  else {
+    /* has no sub-elements (<#name/>) */
+    *_idx += 1; // skip '/'
+    isAutoClose = YES;
+    if (_buffer[*_idx] != '>') {
+      *_exc = _makeHtmlException(*_exc, _buffer, *_idx, _len,
+                                @"missing '>' in hash element tag.", self);
+      [name release]; name = nil;
+      return nil; // unexpected EOF
+    }
+    *_idx += 1; // skip '>'
+  }
+  
+  /* produce elements */
+
+  if ([name length] < 1) {
+    element = nil;
+    *_exc = _makeHtmlException(*_exc, NULL, 0, 0,
+                                    @"missing name in hash element tag.",
+                                    nil);
+    [name release];
+    return nil;
+  }
+  
+  nameDict = [[NSDictionary alloc] initWithObjects:&name forKeys:&nameKey 
+                                  count:1];
+  element = [self dynamicElementWithName:name
+                 attributes:nameDict
+                 contentElements:children];
+  [name release];     name = nil;
+  [nameDict release]; nameDict = nil;
+  
+  if (element == nil) { // build error
+    *_exc = _makeHtmlException(*_exc, _buffer, *_idx, _len,
+                                 @"could not build hash element !.", self);
+    return nil;
+  }
+  
+  if (!foundEndTag && !isAutoClose) {
+    *_exc = _makeHtmlException(*_exc, _buffer, *_idx, _len,
+                                 @"did not find hash end tag (</#...>) ..",
+                                 self);
+    [element release]; element = nil;
+    return nil;
+  }
+  else if (!isAutoClose) {
+    /* skip close tag ('</#name>') */
+    NSCAssert(_isHashCloseTag(_buffer, *_idx, _len), 
+             @"invalid parser state ..");
+    
+    *_idx += 3; // skip '</#'
+    while ((*_idx < _len) && (_buffer[*_idx] != '>'))
+      *_idx += 1;
+    *_idx += 1; // skip '>'
+#if HEAVY_DEBUG
+    NSLog(@"parsed close tag, now at '%c'[%i] ..", _buffer[*_idx], *_idx);
+#endif
+  }
+  return element;
+}
+
+static NSMutableDictionary *
+_parseTagAttributes(NSZone *_zone, const char *_buffer,
+                    unsigned *_idx, unsigned _len,
+                    NSException **_exception, WOHTMLParser *self)
+{
+  NSMutableDictionary *dict = nil;
+
+  _skipSpaces(_buffer, _idx, _len);
+  if (*_idx >= _len) return nil; // EOF
+
+#if HEAVY_DEBUG
+  NSLog(@"parsing attributes at '%c'[%i] ..", _buffer[*_idx], *_idx);
+#endif
+  
+  do {
+    NSString *key   = nil;
+    NSString *value = nil;
+    
+    _skipSpaces(_buffer, _idx, _len);
+    if (*_idx >= _len) break; // EOF
+
+    // read key
+    key = _parseStringValue(_zone, _buffer, _idx, _len, _exception, self);
+    if (key == nil) // ended
+      break;
+
+    /* The following parses:  space* '=' space* */
+
+    _skipSpaces(_buffer, _idx, _len);
+    if (*_idx >= _len) {
+      *_exception = _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                                   @"expected '=' after key in attributes ..",
+                                   nil);
+      break; // unexpected EOF
+    }
+    if (_buffer[*_idx] != '=') {
+      *_exception = _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                                   @"expected '=' after key in attributes ..",
+                                   nil);
+      break;
+    }
+    NSCAssert(_buffer[*_idx] == '=', @"invalid parser state ..");
+    *_idx += 1; // skip '='
+    _skipSpaces(_buffer, _idx, _len);
+    if (*_idx >= _len) {
+      *_exception = _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                                 @"expected value after key in attributes ..",
+                                 nil);
+      break; // unexpected EOF
+    }
+
+    // read value
+    value = _parseStringValue(_zone, _buffer, _idx, _len, _exception, self);
+    if (value == nil) {
+      *_exception = _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                                 @"expected value after key in attributes ..",
+                                 nil);
+      break; // unexpected EOF
+    }
+
+    NSCAssert(key,   @"invalid key ..");
+    NSCAssert(value, @"invalid value ..");
+
+    if (dict == nil)
+      dict = [[DictClass allocWithZone:_zone] init];
+    NSCAssert(dict, @"no attributes dictionary ?");
+    [dict setObject:value forKey:key];
+    
+    [key   release]; key   = nil;
+    [value release]; value = nil;
+  }
+  while (*_idx < _len);
+
+  return dict;
+}
+static WOElement *_parseWOElement(NSZone *_zone, const char *_buffer,
+                                  unsigned *_idx, unsigned _len,
+                                  NSException **_exception,
+                                  WOHTMLParser *self)
+{
+  WOElement           *element    = nil;
+  NSMutableDictionary *attrs      = nil;
+  BOOL                foundEndTag = NO;
+  NSMutableArray      *children   = nil;
+  
+  if (*_idx >= _len) return nil; // EOF
+  
+  if (!_isWOTag(_buffer, *_idx, _len))
+    return nil; // not a WO tag ..
+
+  NSCAssert(strncasecmp("<WEBOBJECT", &(_buffer[*_idx]), 10) == 0,
+            @"invalid parser state ..");
+  
+  // skip '<WEBOBJECT'
+  *_idx += 10;
+  
+  attrs = _parseTagAttributes(_zone, _buffer, _idx, _len, _exception, self);
+  if (attrs == nil) {
+    //NSLog(@"ERROR: got no attributes for WO tag (need at least 'NAME')..");
+    
+    if (_exception) // if there was an error ..
+      return nil;
+  }
+  
+  _skipSpaces(_buffer, _idx, _len);
+  if (*_idx >= _len) {
+    *_exception =
+      _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                     @"unexpected EOF: missing '>' in WEBOBJECT tag.",
+                     self);
+    [attrs release]; attrs = nil;
+    return nil; // unexpected EOF
+  }
+  if (_buffer[*_idx] != '>') {
+    *_exception = _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                                 @"missing '>' in WEBOBJECT tag.", self);
+    [attrs release]; attrs = nil;
+    return nil; // unexpected EOF
+  }
+  NSCAssert(_buffer[*_idx] == '>', @"invalid parser state ..");
+
+  *_idx += 1; // skip '>'
+
+  // parse sub-elements
+  
+  while ((*_idx < _len) && (*_exception == nil)) {
+    id subElement = nil;
+
+    //NSLog(@"subelement at '%c'[%i] ..", _buffer[*_idx], *_idx);
+
+    if (_isWOCloseTag(_buffer, *_idx, _len)) {
+      foundEndTag = YES;
+      break;
+    }
+
+    subElement = _parseElement(_zone, _buffer, _idx, _len, _exception, self);
+
+    //NSLog(@"  parsed subelement '%@' ..", subElement);
+
+    if (subElement) {
+      if (children == nil)
+        children = [NSMutableArray arrayWithCapacity:10];
+      [children addObject:subElement];
+      [subElement release]; subElement = nil;
+    }
+  }
+
+  /* produce elements */
+  {
+    NSString *name;
+    
+    if ((name = [attrs objectForKey:@"NAME"]) == nil)
+      name = [attrs objectForKey:@"name"];
+    if (name == nil) {
+      if ((name = [attrs objectForKey:@"name"])) {
+       NSLog(@"%s: missing 'name' attribute !",
+             __PRETTY_FUNCTION__);
+      }
+    }
+    
+    if ([name length] < 1) {
+      element = nil;
+      *_exception = _makeHtmlException(*_exception, NULL, 0, 0,
+                                       @"no NAME attribute in WEBOBJECT tag.",
+                                       nil);
+      return nil;
+    }
+    else {
+      element = [self dynamicElementWithName:name
+                      attributes:attrs
+                      contentElements:children];
+    }
+  }
+  [attrs release]; attrs = nil;
+
+  if (element == nil) { // build error
+    *_exception = _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                                 @"could not build WEBOBJECT.", self);
+    return nil;
+  }
+  
+  if (!foundEndTag) {
+    *_exception = _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                                 @"did not find WEBOBJECT end tag ..",
+                                 self);
+    [element release]; element = nil;
+    return nil;
+  }
+  else {
+    NSCAssert(_isWOCloseTag(_buffer, *_idx, _len), @"invalid parser state ..");
+    
+    // skip close tag ('</WEBOBJECT>')
+    *_idx += 11; // skip '</WEBOBJECT'
+    while ((*_idx < _len) && (_buffer[*_idx] != '>'))
+      *_idx += 1;
+    *_idx += 1; // skip '>'
+
+    //NSLog(@"parsed close tag, now at '%c'[%i] ..", _buffer[*_idx], *_idx);
+  }
+  return element;
+}
+
+static inline NSString *_makeTextString(NSZone *_zone, const char *_buffer,
+                                        unsigned _len, WOHTMLParser *self)
+{
+  NSString *result = nil;
+  register unsigned char *buffer;
+  register unsigned pos, bufPos;
+  
+  if (_len == 0) // empty string
+    return @"";
+
+  if (!compressHTMLWhitespace)
+    /* deliver whitespace as in template */
+    return [self _makeStringForBuffer:_buffer length:_len];
+  
+  buffer = malloc(_len + 3);
+
+  for (pos = 0, bufPos = 0; pos < _len; ) {
+      buffer[bufPos] = _buffer[pos];
+
+      if ((_buffer[pos] == ' ') || (_buffer[pos] == '\t')) {
+        do {
+          pos++;
+        }
+        while (((_buffer[pos] == ' ') || (_buffer[pos] =='\t')) &&
+               (pos < _len));
+        
+        bufPos++;
+      }
+      else {
+        pos++;
+        bufPos++;
+      }
+  }
+  
+  result = [self _makeStringForBuffer:buffer length:bufPos];
+  if (buffer) free(buffer);
+  return result;
+}
+
+static WOElement *_parseElement(NSZone *_zone,
+                                const char *_buffer, unsigned *_idx,
+                                unsigned _len, NSException **_exception,
+                                WOHTMLParser *self)
+{
+  register unsigned pos = *_idx;
+  unsigned startPos = pos;
+  
+  if (*_idx >= _len) // EOF
+    return nil;
+  
+  if (_isHashTag(_buffer, *_idx, _len)) {
+    /* start parsing of dynamic content */
+    return _parseHashElement(_zone, _buffer, _idx, _len, _exception, self);
+  }
+  if (_isHashCloseTag(_buffer, *_idx, _len)) {
+    /* check for a common template syntax error */
+    *_exception = _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                                    @"unexpected hash close tag (</#...>).",
+                                    self);
+    return nil;
+  }
+  
+  if (_isWOTag(_buffer, *_idx, _len)) {
+    /* start parsing of dynamic content */
+    return _parseWOElement(_zone, _buffer, _idx, _len, _exception, self);
+  }
+  if (_isWOCloseTag(_buffer, *_idx, _len)) {
+    /* check for a common template syntax error */
+    *_exception = _makeHtmlException(*_exception, _buffer, *_idx, _len,
+                                    @"unexpected WEBOBJECT close tag "
+                                    @"(</WEBOBJECT...>).",
+                                    self);
+    return nil;
+  }
+  
+  /* parse text/tag content */
+  do {
+    while ((_buffer[pos] != '<') && (pos < _len))
+      pos++;
+    
+    if (pos >= _len) // EOF was reached
+      break;
+    
+    NSCAssert(_buffer[pos] == '<', @"invalid parser state ..");
+    
+    if (_isHashTag(_buffer, pos, _len)) /* found Hash */
+      break;
+    if (_isHashCloseTag(_buffer, pos, _len))
+      break;
+    if (_isWOTag(_buffer, pos, _len)) /* found Hash */
+      break;
+    if (_isWOCloseTag(_buffer, pos, _len))
+      break;
+    
+#if HEAVY_DEBUG
+    NSLog(@"is comment ? from '%c%c%c'[%i]",
+          _buffer[pos], _buffer[pos+1], _buffer[pos+2], pos);
+#endif
+    if (_isComment(_buffer, pos, _len)) {
+      pos += 3; // skip '<--'
+
+      while (pos < _len) {
+       if (_buffer[pos] == '-') {
+         if (pos + 2 < _len) {
+           if ((_buffer[pos + 1] == '-') && (_buffer[pos + 2] == '>')) {
+             // found '-->'
+             pos += 3; // skip '-->'
+             *_idx = pos;
+             break;
+           }
+         }
+       }
+       pos++;
+      }
+      if (pos >= _len) // EOF was reached
+       break;
+    }
+    else {
+      // skip '<', read usual tag
+      pos++;
+      if (pos >= _len) { // EOF was reached with opening '<'
+       NSLog(@"WARNING: reached EOF with '<' at end !");
+       break;
+      }
+      
+      if (skipPlainTags) {
+       /* skip until end of HTML tag (not #-tag) */
+       do {
+         pos++;
+       }
+       while ((_buffer[pos] != '>') && (pos < _len));
+       if (pos >= _len) break; // EOF
+      }
+      
+      pos++;
+    }
+  }
+  while (pos < _len);
+  
+  /* store back position */
+  *_idx = pos;
+  
+#if HEAVY_DEBUG
+  NSLog(@"Debug: stopped parsing at '%c'[%i]", _buffer[pos], pos);
+#endif
+
+  if ((pos - startPos) > 0) {
+    return [self _makeConstantStringElementWithBuffer:&(_buffer[startPos])
+                length:(pos - startPos)];
+  }
+  else
+    return nil;
+}
+
+@end /* WOHTMLParser */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOSubcomponentInfo.m b/skyrix-sope/NGObjWeb/Templates/WOSubcomponentInfo.m
new file mode 100644 (file)
index 0000000..bd53fa5
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOTemplateBuilder.h>
+#include "common.h"
+
+@implementation WOSubcomponentInfo
+
+- (id)initWithName:(NSString *)_name bindings:(NSDictionary *)_bindings {
+  self->componentName = [_name     copy];
+  self->bindings      = [_bindings copy];
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->componentName);
+  RELEASE(self->bindings);
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)componentName {
+  return self->componentName;
+}
+- (NSDictionary *)bindings {
+  return self->bindings;
+}
+
+@end /* WOSubcomponentInfo */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOTemplate.m b/skyrix-sope/NGObjWeb/Templates/WOTemplate.m
new file mode 100644 (file)
index 0000000..d98de33
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOTemplateBuilder.h>
+#include "common.h"
+
+@implementation WOTemplate
+
++ (int)version {
+  return [super version] + 1 /* v3 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithURL:(NSURL *)_url rootElement:(WOElement *)_element {
+  if ((self = [super init])) {
+    self->url         = [_url     copy];
+    self->rootElement = [_element retain];
+    self->loadDate    = [[NSDate alloc] init];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->kvcTemplateVars   release];
+  [self->componentScript   release];
+  [self->subcomponentInfos release];
+  [self->loadDate          release];
+  [self->rootElement       release];
+  [self->url               release];
+  [super dealloc];
+}
+
+/* component info */
+
+- (void)setComponentScript:(WOComponentScript *)_script {
+  ASSIGN(self->componentScript, _script);
+}
+- (WOComponentScript *)componentScript {
+  return self->componentScript;
+}
+
+- (void)setKeyValueArchivedTemplateVariables:(NSDictionary *)_vars {
+  ASSIGN(self->kvcTemplateVars, _vars);
+}
+- (NSDictionary *)keyValueArchivedTemplateVariables {
+  return self->kvcTemplateVars;
+}
+
+/* component info */
+
+/* subcomponent info */
+
+- (BOOL)hasSubcomponentInfos {
+  return [self->subcomponentInfos count] > 0 ? YES : NO;
+}
+
+- (NSEnumerator *)infoKeyEnumerator {
+  return [self->subcomponentInfos keyEnumerator];
+}
+- (WOSubcomponentInfo *)subcomponentInfoForKey:(NSString *)_key {
+  if (_key == nil) return nil;
+  return [self->subcomponentInfos objectForKey:_key];
+}
+
+- (void)addSubcomponentWithKey:(NSString *)_key
+  name:(NSString *)_name
+  bindings:(NSDictionary *)_bindings
+{
+  WOSubcomponentInfo *info;
+  
+  info = [[WOSubcomponentInfo alloc] initWithName:_name bindings:_bindings];
+  if (info == nil)
+    return;
+
+  if (self->subcomponentInfos == nil)
+    self->subcomponentInfos = [[NSMutableDictionary alloc] initWithCapacity:4];
+    
+  [self->subcomponentInfos setObject:info forKey:_key];
+  [info release];
+}
+
+/* accessors */
+
+- (void)setRootElement:(WOElement *)_element {
+  ASSIGN(self->rootElement, _element);
+}
+- (WOElement *)rootElement {
+  return self->rootElement;
+}
+
+- (NSURL *)url {
+    return self->url;
+}
+
+/* WOElement methods */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  [self->rootElement takeValuesFromRequest:_req inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  return [self->rootElement invokeActionForRequest:_req inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [self->rootElement appendToResponse:_response inContext:_ctx];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms = [NSMutableString stringWithCapacity:128];
+  
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->url) {
+    if ([self->url isFileURL])
+      [ms appendFormat:@" path=%@", [self->url path]];
+    else
+      [ms appendFormat:@" url=%@", [self->url absoluteString]];
+  }
+  if (self->subcomponentInfos)
+    [ms appendFormat:@" #subcomponents=%i", [self->subcomponentInfos count]];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* WOTemplate */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOTemplateBuilder.m b/skyrix-sope/NGObjWeb/Templates/WOTemplateBuilder.m
new file mode 100644 (file)
index 0000000..c6db951
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOTemplateBuilder.h>
+#include "common.h"
+
+@implementation WOTemplateBuilder
+
+static NSArray *woxExtensions = nil;
+
++ (int)version {
+  return 1;
+}
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  woxExtensions = [[ud arrayForKey:@"WOxFileExtensions"] copy];
+}
+
+/* builder factory */
+
++ (WOTemplateBuilder *)templateBuilderForPath:(NSString *)_path {
+  NSString *ext;
+  
+  if ([_path length] == 0)
+    return nil;
+  
+  ext = [_path pathExtension];
+  if ([woxExtensions containsObject:ext]) {
+    static WOTemplateBuilder *woxBuilder = nil;
+    if (woxBuilder == nil)
+      woxBuilder = [[NSClassFromString(@"WOxTemplateBuilder") alloc] init];
+    return woxBuilder;
+  }
+  
+  {
+    static WOTemplateBuilder *woBuilder = nil;
+    if (woBuilder == nil) {
+      woBuilder =
+        [[NSClassFromString(@"WOWrapperTemplateBuilder") alloc] init];
+    }
+    return woBuilder;
+  }
+}
+
++ (WOTemplateBuilder *)templateBuilderForURL:(NSURL *)_url {
+  if ([_url isFileURL])
+    return [self templateBuilderForPath:[_url path]];
+  
+  [self logWithFormat:@"only supports file URLs: %@", _url];
+  return nil;
+}
+
+- (WOTemplate *)buildTemplateAtURL:(NSURL *)_url {
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+  return nil;
+#else
+  return [self subclassResponsibility:_cmd];
+#endif
+}
+
+@end /* WOTemplateBuilder */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOWrapperTemplateBuilder.h b/skyrix-sope/NGObjWeb/Templates/WOWrapperTemplateBuilder.h
new file mode 100644 (file)
index 0000000..45889bd
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOWrapperTemlateBuilder_H__
+#define __NGObjWeb_WOWrapperTemlateBuilder_H__
+
+#include <NGObjWeb/WOTemplateBuilder.h>
+
+@class NSMutableDictionary, NSMutableSet, NSException;
+
+@interface WOWrapperTemplateBuilder : WOTemplateBuilder
+{
+  NSException  *lastException;
+  
+  // transient, used for parsing
+  NSMutableSet        *componentNames;
+  NSMutableDictionary *definitions;
+  WOTemplate          *iTemplate;
+}
+
+- (void)reset;
+
+@end
+
+#endif /* __NGObjWeb_WOWrapperTemlateBuilder_H__ */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOWrapperTemplateBuilder.m b/skyrix-sope/NGObjWeb/Templates/WOWrapperTemplateBuilder.m
new file mode 100644 (file)
index 0000000..4b36022
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOWrapperTemplateBuilder.h"
+#include "WODParser.h"
+#include "WOHTMLParser.h"
+#include "WOCompoundElement.h"
+#include "WOChildComponentReference.h"
+#include <NGObjWeb/WOAssociation.h>
+#include "common.h"
+
+/*
+  .wo components need to know at parsing time whether we are dealing
+  with a component or a dynamic element, the .wod or the .html does
+  not contain this information.
+  
+  What to do ... ?? Always checking the class isn't very nice either ..
+*/
+
+@interface _WODFileEntry : NSObject
+{
+@public
+  NSString     *componentName;
+  NSDictionary *associations;
+  Class        componentClass;
+  signed char  isDynamicElement;
+}
+
+- (BOOL)isDynamicElement;
+- (Class)componentClass;
+
+@end
+
+@interface WODynamicElement(UsedPrivates)
+- (id)initWithElementName:(NSString *)_element
+  attributes:(NSDictionary *)_attributes
+  contentElements:(NSArray *)_subElements
+  componentDefinition:(id)_cdef;
++ (BOOL)isDynamicElement;
+@end
+
+static Class AssocClass  = Nil;
+static Class StrClass    = Nil;
+
+@implementation WOWrapperTemplateBuilder
+
+static BOOL logExtraAssociations = NO;
+static BOOL logScriptAdditions   = NO;
+static NSStringEncoding parserEncoding;
+
++ (int)version {
+  return [super version] + 0 /* v1 */;
+}
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  NSAssert2([super version] == 1,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  AssocClass = [WOAssociation class];
+  StrClass   = [NSString      class];
+  
+  if ([ud boolForKey:@"WOParsersUseUTF8"]) {
+    parserEncoding = NSUTF8StringEncoding;
+    NSLog(@"Note: using UTF-8 as wrapper template parser encoding.");
+  }
+  else
+    parserEncoding = [NSString defaultCStringEncoding];
+}
+
+- (void)dealloc {
+  [self->lastException  release];
+  [self->definitions    release];
+  [self->componentNames release];
+  [self->iTemplate      release];
+  [super dealloc];
+}
+
+/* parsing */
+
+- (BOOL)_parseDeclarationsFile:(NSData *)_decl {
+  NSDictionary *defs;
+  WODParser *parser;
+    
+  parser = [[[WODParser alloc] initWithHandler:(id)self] autorelease];
+  defs = [parser parseDeclarationData:_decl];
+  return defs ? YES : NO;
+}
+
+- (WOElement *)parseWithHTMLData:(NSData *)_html
+  declarationData:(NSData *)_decl
+{
+  WOHTMLParser *parser;
+  NSArray      *topLevel    = nil;
+  NSException  *exception   = nil;
+  WOElement    *rootElement;
+  
+  /* parse declarations file */
+  if (![self _parseDeclarationsFile:_decl])
+    return nil;
+  
+  /* parse HTML file */
+  parser = [[[WOHTMLParser alloc] initWithHandler:(id)self] autorelease];
+  if ((topLevel = [parser parseHTMLData:_html]) == nil)
+    exception = [parser parsingException];
+  
+  /* setup root element */
+  
+  if ([topLevel count] == 1) {
+    rootElement = [[topLevel objectAtIndex:0] retain];
+  }
+  else if ([topLevel count] > 1) {
+    static Class CompoundElemClass = Nil;
+    if (CompoundElemClass == Nil)
+      CompoundElemClass = NSClassFromString(@"WOCompoundElement");
+    
+    rootElement =
+      [[CompoundElemClass allocForCount:[topLevel count] zone:[self zone]]
+                          initWithChildren:topLevel];
+  }
+  else /* no topLevel element */
+    rootElement = nil;
+  
+  if (exception) [exception raise];
+  return rootElement;
+}
+
+- (void)reset {
+  [self->definitions    removeAllObjects];
+  [self->componentNames removeAllObjects];
+  [self->iTemplate release]; self->iTemplate = nil;
+}
+
+- (NSData *)rewriteData:(NSData *)_data 
+  fromEncoding:(NSStringEncoding)_from
+  toEncoding:(NSStringEncoding)_to
+{
+  NSString *s;
+  NSData   *d;
+  
+  if ((s = [[NSString alloc] initWithData:_data encoding:_from]) == nil) {
+    [self logWithFormat:@"ERROR: template file has incorrect encoding!"];
+    return _data;
+  }
+  if ((d = [s dataUsingEncoding:_to]) == nil) {
+    [self logWithFormat:
+            @"ERROR: could not represent template file in parser encoding!"];
+    return _data;
+  }
+  return d;
+}
+
+- (NSException *)_handleBuildException:(NSException *)_exc atURL:(NSURL *)_url{
+  NSException *newException;
+  NSDictionary *userInfo;
+  NSMutableDictionary *newUserInfo;
+
+  [self reset];
+
+  if ((userInfo = [_exc userInfo]) != nil) {
+    newUserInfo = [[NSMutableDictionary alloc] initWithCapacity:
+                                                 [userInfo count] + 1];
+    [newUserInfo addEntriesFromDictionary:userInfo];
+    [newUserInfo setObject:_url forKey:@"templateURL"];
+  }
+  else {
+    newUserInfo = (NSMutableDictionary *)
+      [[NSDictionary alloc] initWithObjectsAndKeys:_url, @"templateURL", nil];
+  }
+  newException = [NSException exceptionWithName:[_exc name]
+                              reason:[_exc reason]
+                              userInfo:newUserInfo];
+  return newException;
+}
+
+- (WOTemplate *)buildTemplateAtURL:(NSURL *)_url {
+  static NSData *emptyData = nil;
+  NSFileManager *fm;
+  WOTemplate    *template;
+  WOElement     *rootElement;
+  BOOL          withLanguage;
+  NSData        *wodFile     = nil;
+  NSData        *htmlFile    = nil;
+  NSDictionary  *wooFile     = nil;
+  NSString      *tmpPath;
+  NSString      *path, *name;
+  NSStringEncoding encoding;
+  WOComponentScript *script;
+  id tmp;
+  
+  NSAssert(self->iTemplate == nil, @"parsing in progress !!!");
+  [self reset];
+  [self->lastException release]; self->lastException = nil;
+  
+  if (_url == nil)
+    return nil;
+  
+  if (![_url isFileURL]) {
+    [self logWithFormat:@"can only process wrappers at file-URLs: %@", _url];
+    return nil;
+  }
+
+  if (emptyData == nil)
+    emptyData = [[NSData alloc] init];
+  
+  fm       = [NSFileManager defaultManager];
+  path     = [_url path];
+  
+  if (self->definitions == nil)
+    self->definitions = [[NSMutableDictionary alloc] initWithCapacity:64];
+  
+  tmpPath      = [path lastPathComponent];
+  withLanguage = [[tmpPath pathExtension] isEqualToString:@"lproj"];
+  
+  /*
+    TODO: can this code handle ".wo" templates without a wrapper? Eg if I place
+          Main.html and Main.wod directly into the bundle resources directory?
+    TODO: can this code handle static names for contained files? (eg 
+          template.wod instead of Main.wod) This way we could avoid renaming
+         the individual files if the wrapper name changes.
+  */
+  if (withLanguage) {
+    /* eg /a/b/c/a.wo/English.lproj/a.html */
+    tmpPath = [path stringByDeletingLastPathComponent];
+    name = [[tmpPath lastPathComponent] stringByDeletingPathExtension];
+  }
+  else {
+    /* eg /a/b/c/a.wo/a.html */
+    name = [[path lastPathComponent] stringByDeletingPathExtension];
+  }
+  
+  tmpPath = [name stringByAppendingPathExtension:@"wod"];
+  tmpPath = [path stringByAppendingPathComponent:tmpPath];
+  wodFile = [NSData dataWithContentsOfFile:tmpPath];
+  
+  tmpPath = [name stringByAppendingPathExtension:@"html"];
+  tmpPath = [path stringByAppendingPathComponent:tmpPath];
+  htmlFile = [NSData dataWithContentsOfFile:tmpPath];
+
+  tmpPath = [name stringByAppendingPathExtension:@"woo"];
+  tmpPath = [path stringByAppendingPathComponent:tmpPath];
+  if ([fm fileExistsAtPath:tmpPath])
+    wooFile = [NSDictionary dictionaryWithContentsOfFile:tmpPath];
+  
+  /* process language specific pathes */
+  
+  script = nil;
+  if (wodFile == nil) { /* no .wod, no script (cannot be bound ...) */
+    if (withLanguage) {
+      tmpPath = [name stringByAppendingPathExtension:@"wod"];
+      tmpPath = [[path stringByDeletingLastPathComponent]
+                       stringByAppendingPathComponent:tmpPath];
+      
+      if ((wodFile = [NSData dataWithContentsOfFile:tmpPath]) == nil) {
+        wodFile = emptyData;
+        [self logWithFormat:
+               @"%s:%i:\n"
+               @"  could not load wod file of component '%@'\n"
+                @"  URL:      '%@'\n"
+               @"  tmp-path: '%@'\n"
+                @"  path:     '%@'",
+               __PRETTY_FUNCTION__, __LINE__, 
+               name, [_url absoluteString], tmpPath, path];
+      }
+    }
+    else {
+      wodFile = emptyData;
+      [self logWithFormat:
+              @"%s:%i:\n  could not load wod file of %@\n"
+              @"  path=%@, not with lang.",
+              __PRETTY_FUNCTION__, __LINE__, name, path];
+    }
+  }
+  else {
+    /* check for script */
+    NSFileManager *fm = [NSFileManager defaultManager];
+    
+    tmpPath = [name stringByAppendingPathExtension:@"js"];
+    tmpPath = [path stringByAppendingPathComponent:tmpPath];
+    
+    if ([fm fileExistsAtPath:tmpPath])
+      script = [[WOComponentScript alloc] initWithContentsOfFile:tmpPath];
+  }
+  if (htmlFile == nil) {
+    [self logWithFormat:@"%s:\n  could not load html file of component %@.",
+            __PRETTY_FUNCTION__, name];
+    return nil;
+  }
+  
+  /* process string encoding */
+  
+  encoding = parserEncoding;
+  if ((tmp = [wooFile objectForKey:@"encoding"])) {
+    // TODO: move to an NSString category, isn't there a method for this in
+    //       Foundation?!
+
+    encoding = 0;
+    
+    if ([tmp isEqualToString:@"NSASCIIStringEncoding"])
+      encoding = NSASCIIStringEncoding;
+    else if ([tmp isEqualToString:@"NSNEXTSTEPStringEncoding"])
+      encoding = NSNEXTSTEPStringEncoding;
+    else if ([tmp isEqualToString:@"NSUTF8StringEncoding"])
+      encoding = NSUTF8StringEncoding;
+    else if ([tmp isEqualToString:@"NSISOLatin1StringEncoding"])
+      encoding = NSISOLatin1StringEncoding;
+    else if ([tmp isEqualToString:@"NSISOLatin2StringEncoding"])
+      encoding = NSISOLatin2StringEncoding;
+    else if ([tmp isEqualToString:@"NSUnicodeStringEncoding"])
+      encoding = NSUnicodeStringEncoding;
+    else if ([tmp length] == 0)
+      ; // keep platform encoding
+#if LIB_FOUNDATION_LIBRARY
+    else if ([tmp isEqualToString:@"NSISOLatin9StringEncoding"])
+      encoding = NSISOLatin9StringEncoding;
+    else if ([tmp isEqualToString:@"NSWinLatin1StringEncoding"])
+      encoding = NSWinLatin1StringEncoding;
+#endif
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+    else
+      encoding = [NSString stringEncodingForEncodingNamed:tmp];
+#endif
+    
+    if (encoding == 0) {
+      [self logWithFormat:
+              @"ERROR(%s): cannot deal with template encoding: '%@'",
+              __PRETTY_FUNCTION__, tmp];
+      encoding = parserEncoding;
+    }
+    
+    if (encoding != parserEncoding) {
+      // TODO: HACK and slow, the parsers should be able to deal with Unicode
+      // TODO: in case this works, remove the log
+      [self logWithFormat:
+              @"Note: rewriting template NSData for parser encoding (%@=>%@).",
+              [NSString localizedNameOfStringEncoding:encoding],
+              [NSString localizedNameOfStringEncoding:parserEncoding]];
+      
+      htmlFile = [self rewriteData:htmlFile 
+                       fromEncoding:encoding toEncoding:parserEncoding];
+      wodFile  = [self rewriteData:wodFile
+                       fromEncoding:encoding toEncoding:parserEncoding];
+    }
+  }
+  
+  /* instantiate template */
+  
+  self->iTemplate = [[WOTemplate alloc] initWithURL:_url rootElement:nil];
+  
+  NS_DURING
+    rootElement = [self parseWithHTMLData:htmlFile declarationData:wodFile];
+  NS_HANDLER
+    [[self _handleBuildException:localException atURL:_url] raise];
+  NS_ENDHANDLER;
+  
+  [self->iTemplate setRootElement:rootElement];
+  template = self->iTemplate;
+  self->iTemplate = nil;
+  
+  [self reset];
+  
+  if ((tmp = [wooFile objectForKey:@"variables"]))
+    [template setKeyValueArchivedTemplateVariables:tmp];
+  
+  if (script) {
+    if (logScriptAdditions) {
+      [self logWithFormat:@"adding script %@ to template: '%@'", 
+              script, template];
+    }
+    [template setComponentScript:script];
+    [script release];
+  }
+  
+  return [template autorelease];
+}
+
+/* HTML parser callbacks */
+
+- (NSString *)_uniqueComponentNameForDefinitionWithName:(NSString *)_element {
+  NSString *cname;
+  int      i = 0;
+  
+  if (self->componentNames == nil)
+    self->componentNames = [[NSMutableSet alloc] init];
+  
+  cname = _element;
+  while ([self->componentNames containsObject:cname]) {
+    cname = [NSString stringWithFormat:@"%@%i", _element, i];
+    i++;
+    if (i > 200) break;
+  }
+  
+  NSAssert3(i < 200,
+           @"more than 200 components for definition named %@ "
+           @"(last name %@) (names=%@) ??",
+           _element, cname, self->componentNames);
+  
+  [self->componentNames addObject:cname];
+  return cname;
+}
+
+- (WOElement *)componentWithName:(NSString *)_element
+  attributes:(NSDictionary *)_attributes // not the associations !
+  contentElements:(NSArray *)_subElements
+{
+  /* setup a new child component reference */
+  static Class ChildRefClass = Nil;
+  _WODFileEntry      *def;
+  WOChildComponentReference *element = nil;
+  NSString *cname = nil;
+  
+  if ((def = [self->definitions objectForKey:_element]) == nil)
+    return nil;
+  
+  if (ChildRefClass == Nil)
+    ChildRefClass = NSClassFromString(@"WOChildComponentReference");
+  
+  cname = [self _uniqueComponentNameForDefinitionWithName:_element];
+  
+  /* add subcomponent info */
+  [self->iTemplate
+       addSubcomponentWithKey:cname
+       name:def->componentName
+       bindings:def->associations];
+  
+  /* add subcomponent reference */
+  element = [[ChildRefClass alloc]
+                            initWithName:cname
+                            associations:nil
+                            contentElements:_subElements];
+  if (element == nil) {
+    [self logWithFormat:
+            @"ERROR: could not instantiate child component reference."];
+  }
+  
+  return element;
+}
+
+- (WOElement *)dynamicElementWithName:(NSString *)_element
+  attributes:(NSDictionary *)_attributes // not the associations !
+  contentElements:(NSArray *)_subElements
+{
+  _WODFileEntry *def;
+  Class               elementClass;
+  NSMutableDictionary *assoc = nil;
+  WODynamicElement    *element;
+
+  if ((def = [self->definitions objectForKey:_element]) == nil) {
+    [self logWithFormat:
+            @"ERROR: did not find definition of dynamic element '%@'",
+            _element];
+    return [[NSClassFromString(@"WONoContentElement") alloc]
+                                initWithElementName:_element
+                                attributes:_attributes
+                                contentElements:_subElements
+                                componentDefinition:nil];
+  }
+  
+  if (![def isDynamicElement]) {
+    /* definition describes a component */
+    return [self componentWithName:_element
+                 attributes:_attributes
+                 contentElements:_subElements];
+  }
+  
+  elementClass = [def componentClass];
+  NSAssert1(elementClass, @"got no class for element %@", def);
+  
+  assoc = [def->associations mutableCopy];
+
+  element = [[elementClass alloc]
+                           initWithName:_element
+                           associations:assoc
+                           contentElements:_subElements];
+  if (element == nil) {
+    NSLog(@"ERROR: could not instantiate dynamic element of class %@",
+          NSStringFromClass(elementClass));
+  }
+  if ([assoc count] > 0) {
+    if (logExtraAssociations)
+      [self logWithFormat:@"remaining definition attributes: %@", assoc];
+    [element setExtraAttributes:assoc];
+  }
+  [assoc release]; assoc = nil;
+
+  return element;
+}
+
+/* WOTemplate(HTMLParser) */
+
+- (BOOL)parser:(id)_parser willParseHTMLData:(NSData *)_data {
+  return YES;
+}
+
+- (void)parser:(id)_parser finishedParsingHTMLData:(NSData *)_data
+  elements:(NSArray *)_elements
+{
+}
+
+- (void)parser:(id)_parser failedParsingHTMLData:(NSData *)_data
+  exception:(NSException *)_exception
+{
+}
+
+/* WOTemplate(WODParser) */
+
+- (BOOL)parser:(id)_parser willParseDeclarationData:(NSData *)_data {
+  return YES;
+}
+- (void)parser:(id)_parser finishedParsingDeclarationData:(NSData *)_data
+  declarations:(NSDictionary *)_decls
+{
+}
+- (void)parser:(id)_parser failedParsingDeclarationData:(NSData *)_data
+  exception:(NSException *)_exception
+{
+  [_exception raise];
+}
+
+- (id)parser:(id)_parser makeAssociationWithValue:(id)_value {
+  return [AssocClass associationWithValue:_value];
+}
+- (id)parser:(id)_parser makeAssociationWithKeyPath:(NSString *)_keyPath {
+  NSCAssert([_keyPath isKindOfClass:StrClass],
+            @"invalid keypath property (expected string)");
+  return [AssocClass associationWithKeyPath:_keyPath];
+}
+- (id)parser:(id)_parser makeDefinitionForComponentNamed:(NSString *)_cname
+  associations:(id)_entry
+  elementName:(NSString *)_elemName
+{
+  _WODFileEntry *def;
+  
+  def = [[[_WODFileEntry alloc] init] autorelease];
+  def->componentName = [_cname copy];
+  def->associations  = [_entry retain];
+  
+  [self->definitions setObject:def forKey:_elemName];
+  
+  return def;
+}
+
+@end /* WOWrapperTemplateBuilder */
+
+@implementation _WODFileEntry
+
+- (id)init {
+  self->isDynamicElement = -1;
+  return self;
+}
+
+- (void)dealloc {
+  [self->componentName release];
+  [self->associations  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)componentName {
+  return self->componentName;
+}
+- (NSDictionary *)bindings {
+  return self->associations;
+}
+
+- (Class)componentClass {
+  if (self->componentClass == nil)
+    self->componentClass = NSClassFromString(self->componentName);
+  
+  return self->componentClass;
+}
+
+- (BOOL)isDynamicElement {
+  if (self->isDynamicElement == -1) {
+    self->isDynamicElement = 
+      [[self componentClass] isDynamicElement] ? 1 : 0;
+  }
+  return (self->isDynamicElement == 0) ? NO : YES;
+}
+
+@end /* _WODFileEntry */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOxComponentElemBuilder.m b/skyrix-sope/NGObjWeb/Templates/WOxComponentElemBuilder.m
new file mode 100644 (file)
index 0000000..8ecf022
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+  Copyright (C) 2002-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$
+
+#include <NGObjWeb/WOxElemBuilder.h>
+
+/*
+  This builder builds references to subcomponents. The subcomponent name is
+  derived from the tagname.
+  
+  NOTE: this builder is a "final destination" for all bind(var) namespace
+  tags !
+  
+  Sample:
+    <var:Embed a="a"/>
+
+  Supported tags:
+    <var:script src=...>....</var:script> maps to a component script part ...
+    <var:component className=... />       maps to WOSwitchComponent
+    <var:* ..../>
+*/
+
+@interface WOxComponentElemBuilder : WOxElemBuilder
+{
+}
+
+@end
+
+#include <SaxObjC/XMLNamespaces.h>
+#include <DOM/DOMProtocols.h>
+#include <DOM/DOMText.h>
+#include <NGObjWeb/WOAssociation.h>
+#include <NGObjWeb/WOComponentScript.h>
+#include "WOChildComponentReference.h"
+#include "common.h"
+
+@interface NSObject(LineInfo)
+- (unsigned)line;
+@end
+
+@implementation WOxComponentElemBuilder
+
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  debugOn = 
+    [[ud objectForKey:@"WOxComponentElemBuilderDebugEnabled"] boolValue];
+}
+
+/* extracting associations */
+
+- (NSMutableDictionary *)associationsForAttributes:(id<DOMNamedNodeMap>)_attrs
+  templateBuilder:(id)_b
+{
+  NSMutableDictionary *assocs;
+  
+  if ((assocs = [_b associationsForAttributes:_attrs]) == nil)
+    return nil;
+  
+  // should we check the tag or do we always remove className ?
+  if ([assocs objectForKey:@"className"])
+    [assocs removeObjectForKey:@"className"];
+  else if ([assocs objectForKey:@"value"])
+    [assocs removeObjectForKey:@"value"];
+  return assocs;
+}
+
+/* building elements */
+
+- (WOElement *)buildComponentReferenceElement:(id<DOMElement>)_element
+  templateBuilder:(id)_b 
+{
+  /*
+    TODO: I don't think that this already works - it uses the 'value'
+          binding but WOComponentReference expects 'component'
+  */
+  static Class LiveChildRefClass = Nil;
+  NSMutableDictionary *assocs;
+  NSArray             *children;
+  NSString            *value;
+  WOElement           *de;
+  
+  if (LiveChildRefClass == Nil)
+    LiveChildRefClass = NSClassFromString(@"WOComponentReference");
+  
+  if (debugOn)
+    [self debugWithFormat:@"build component-reference: %@",_element];
+  
+  value = [_element attribute:@"value" namespaceURI:XMLNS_OD_BIND];
+  if ([value length] == 0) return nil;
+  
+  /* construct child elements */
+  
+  children = [_element hasChildNodes]
+    ? [_b buildNodes:[_element childNodes] templateBuilder:_b]
+    : nil;
+  
+  /* build associations */
+  
+  assocs = [self associationsForAttributes:[_element attributes]
+                 templateBuilder:_b];
+  [assocs setObject:[WOAssociation associationWithKeyPath:value]
+          forKey:@"component"];
+  
+  /* build element */
+  
+  if (debugOn) {
+    [self debugWithFormat:
+            @"  create reference for keypath: '%@': children=%@, assocs=%@", 
+            value, children, assocs];
+  }
+  
+  de = [[LiveChildRefClass alloc] 
+                           initWithName:[_b uniqueIDForNode:_element]
+                           associations:assocs
+                           contentElements:children];
+  if (debugOn) [self debugWithFormat:@"  built: %@", de];
+  return de;
+}
+
+- (WOElement *)processScriptElement:(id<DOMElement>)_e templateBuilder:(id)_b {
+  /* process a component related script */
+  NSString *src;
+  
+  [self debugWithFormat:@"processing script element: %@", _e];
+  
+  /* first process src attribute ... */
+  if ((src = [_e attribute:@"src" namespaceURI:XMLNS_OD_BIND])) {
+    /* create script part for src ... */
+    [self logWithFormat:@"create script part for src '%@', not implemented",
+            src];
+  }
+    
+  /* create script part for content ... */
+  if ([_e hasChildNodes]) {
+    WOComponentScriptPart *lscript;
+    NSEnumerator      *e;
+    id                subnode;
+    NSMutableString   *content;
+    unsigned          line;
+    NSURL             *url;
+      
+    content = [[NSMutableString alloc] initWithCapacity:256];
+      
+    line = ([(NSObject *)_e respondsToSelector:@selector(line)])
+      ? [(id)_e line] : 0;
+    
+    url = nil;
+      
+    e = [(NSArray *)[_e childNodes] objectEnumerator];
+    while ((subnode = [e nextObject])) {
+      [content appendString:[subnode textValue]];
+    }
+      
+    lscript = [WOComponentScriptPart alloc];
+    lscript = [lscript initWithURL:url startLine:line script:content];
+    [content release];
+      
+    [_b addComponentScriptPart:lscript];
+    [lscript release];
+  }
+  
+  return nil;
+}
+
+- (WOElement *)buildElement:(id<DOMElement>)_element templateBuilder:(id)_b {
+  static Class ChildRefClass = Nil;
+  NSMutableDictionary *bindings;
+  NSArray  *children;
+  NSString *cid;
+  NSString *tagName;
+  NSString *compName;
+  
+  if (![[_element namespaceURI] isEqualToString:XMLNS_OD_BIND]) {
+    if (debugOn) {
+      [self debugWithFormat:
+              @"do not process element, not in bind namespace: %@", _element];
+    }
+    return nil;
+  }
+  
+  tagName = [_element tagName];
+  compName = nil;
+  
+  if ([tagName isEqualToString:@"script"])
+    return [self processScriptElement:_element templateBuilder:_b];
+  
+  if ([tagName isEqualToString:@"component"]) {
+    compName = [_element attribute:@"className" namespaceURI:XMLNS_OD_BIND];
+    if ([compName length] == 0) {
+      compName = [_element attribute:@"classname"
+                           namespaceURI:XMLNS_OD_BIND];
+    }
+    if ([compName length] == 0)
+      compName = [_element attribute:@"name" namespaceURI:XMLNS_OD_BIND];
+    
+    /* check whether we should use a "live" reference to a component object */
+    
+    if ([compName length] == 0) {
+      NSString *value;
+      
+      value = [_element attribute:@"value" namespaceURI:XMLNS_OD_BIND];
+      if ([value length] > 0) {
+        return [self buildComponentReferenceElement:_element 
+                     templateBuilder:_b];
+      }
+    }
+    
+    if ([compName length] == 0) {
+      [self logWithFormat:
+              @"missing 'name' or 'value' attribute in var:component: %@", 
+              [_element attributes]];
+      return nil;
+    }
+  }
+  else {
+    [self logWithFormat:@"Creating component %@ using tag. "
+          @"<var:component name='%@'/> is preferred !", 
+         _element, _element];
+  }
+  
+  if (debugOn)
+    [self debugWithFormat:@"creating static component reference: %@",_element];
+  
+  if (ChildRefClass == Nil)
+    ChildRefClass = NSClassFromString(@"WOChildComponentReference");
+  
+  cid = [_b uniqueIDForNode:_element];
+  if (debugOn)
+    [self debugWithFormat:@"BUILD Component(%@): %@", cid, _element];
+  
+  /* construct child elements */
+  
+  children = [_element hasChildNodes]
+    ? [_b buildNodes:[_element childNodes] templateBuilder:_b]
+    : nil;
+  
+  if (compName == nil)
+    compName = [_element tagName];
+
+  bindings = [self associationsForAttributes:[_element attributes]
+                  templateBuilder:_b];
+  if (debugOn)
+    [self debugWithFormat:@"  using bindings: %@", bindings];
+  
+  [_b registerSubComponentWithId:cid
+      componentName:compName
+      bindings:bindings];
+  
+  return [[ChildRefClass alloc]
+                         initWithName:cid
+                         associations:nil
+                         contentElements:children];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* WOxComponentElemBuilder */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOxElemBuilder.m b/skyrix-sope/NGObjWeb/Templates/WOxElemBuilder.m
new file mode 100644 (file)
index 0000000..3a18bfe
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOxElemBuilder.h>
+#include <DOM/EDOM.h>
+#include <SaxObjC/XMLNamespaces.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOElement.h>
+#include <NGObjWeb/WOAssociation.h>
+#include <NGObjWeb/WOComponentScript.h>
+#include "WOComponentFault.h"
+#include "common.h"
+
+@interface WOElement(UsedPrivates)
+- (id)initWithValue:(id)_value escapeHTML:(BOOL)_flag;
+@end
+
+@interface WOAssociation(misc)
+- (id)initWithScript:(NSString *)_script language:(NSString *)_lang;
+@end
+
+@implementation WOxElemBuilderComponentInfo
+
+- (id)initWithComponentId:(NSString *)_cid
+  componentName:(NSString *)_name
+  bindings:(NSMutableDictionary *)_bindings
+{
+  self->cid      = [_cid copy];
+  self->pageName = [_name copy];
+  self->bindings = [_bindings retain];
+  return self;
+}
+- (void)dealloc {
+  [self->cid      release];
+  [self->pageName release];
+  [self->bindings release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)componentId {
+  return self->cid;
+}
+
+- (NSString *)pageName {
+  return self->pageName;
+}
+
+- (NSMutableDictionary *)bindings {
+  return self->bindings;
+}
+
+/* operations */
+
+- (WOComponent *)instantiateWithResourceManager:(WOResourceManager *)_rm
+  languages:(NSArray *)_languages
+{
+  static Class FaultClass = Nil;
+  WOComponentFault *fault;
+  
+  if (FaultClass == Nil)
+    FaultClass = [WOComponentFault class];
+  
+  fault = [FaultClass alloc];
+  NSAssert1(fault, @"couldn't allocated object of class '%@' ..", FaultClass);
+  
+  fault = [fault initWithResourceManager:_rm
+                 pageName:self->pageName
+                 languages:_languages
+                 bindings:self->bindings];
+  return (id)fault;
+}
+
+@end /* SxElementBuilderComponentInfo */
+
+@implementation WOxElemBuilder
+
+static Class        StrClass  = Nil;
+static Class        AStrClass = Nil;
+static NSDictionary *defaultAssocMap = nil;
+static Class        ValAssoc = Nil;
+static BOOL         logAssocMap      = NO;
+static BOOL         logAssocCreation = NO;
+static BOOL         debugOn          = NO;
+
++ (int)version {
+  return 1;
+}
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  StrClass = NSClassFromString(@"_WOSimpleStaticString");
+  if (StrClass == Nil)
+    NSLog(@"ERROR: missing class _WOSimpleStaticString !");
+  AStrClass = NSClassFromString(@"_WOSimpleStaticASCIIString");
+  if (AStrClass == Nil)
+    NSLog(@"ERROR: missing class _WOSimpleStaticASCIIString !");
+
+  logAssocMap = [ud boolForKey:@"WOxElemBuilder_LogAssociationMapping"];
+  logAssocCreation = 
+    [ud boolForKey:@"WOxElemBuilder_LogAssociationCreation"];
+  if (logAssocMap)      NSLog(@"Note: association mapping is logged!");
+  if (logAssocCreation) NSLog(@"Note: association creation is logged!");
+  
+  defaultAssocMap = [[ud dictionaryForKey:@"WOxAssociationClassMapping"] copy];
+  if (defaultAssocMap == nil)
+    NSLog(@"WARNING: WOxAssociationClassMapping default is not set!");
+  
+  if (ValAssoc == Nil)
+    ValAssoc = NSClassFromString(@"WOValueAssociation");
+}
+
++ (WOxElemBuilder *)createBuilderQueue:(NSArray *)_classNames {
+  unsigned      i, count;
+  WOxElemBuilder *first, *current = nil;
+  NSMutableArray *missingBuilders = nil;
+  
+  if ((count = [_classNames count]) == 0)
+    return nil;
+  
+  for (first = nil, i = 0; i < count; i++) {
+    WOxElemBuilder *nx;
+    NSString *cn;
+    Class    clazz;
+    
+    cn = [_classNames objectAtIndex:i];
+    
+    if ((clazz = NSClassFromString(cn)) == Nil) {
+      if (missingBuilders == nil) 
+        missingBuilders = [NSMutableArray arrayWithCapacity:16];
+      [missingBuilders addObject:cn];
+      continue;
+    }
+    
+    if ((nx = [[clazz alloc] init])) {
+      if (first == nil) {
+        first = current = nx;
+        [nx autorelease];
+      }
+      else {
+        [current setNextBuilder:nx];
+        current = [nx autorelease];
+      }
+    }
+    else {
+      NSLog(@"%s: couldn't allocate builder (class=%@)", cn);
+      continue;
+    }
+  }
+  
+  if (missingBuilders) {
+    NSLog(@"WOxElemBuilder: could not locate builders: %@", 
+          [missingBuilders componentsJoinedByString:@","]);
+  }
+  return first;
+}
+
++ (WOxElemBuilder *)createBuilderQueueV:(NSString *)_className, ... {
+  // TODO: reimplement using createBuilderQueue:
+  va_list       ap;
+  NSString      *cn;
+  WOxElemBuilder *first, *current;
+  
+  if (_className == nil)
+    return [[[self alloc] init] autorelease];
+    
+  first = [[[NSClassFromString(_className) alloc] init] autorelease];
+    
+  va_start(ap, _className);
+  for (current = first; (cn = va_arg(ap, id)); ) {
+    WOxElemBuilder *nx;
+
+    nx = [[NSClassFromString(cn) alloc] init];
+    [current setNextBuilder:nx];
+    current = [nx autorelease];
+  }
+  va_end(ap);
+    
+  return first;
+}
+
+- (void)dealloc {
+  [self->script            release];
+  [self->subcomponentInfos release];
+  [self->nsToAssoc         release];
+  [self->nextBuilder       release];
+  [super dealloc];
+}
+
+/* building an element (returns a retained object !!!) */
+
+- (WOElement *)buildNode:(id<DOMNode>)_node templateBuilder:(id)_builder {
+  if (_node == nil)
+    return nil;
+
+  switch ([_node nodeType]) {
+    case DOM_ELEMENT_NODE:
+      return [self buildElement:(id<DOMElement>)_node
+                   templateBuilder:_builder];
+    case DOM_TEXT_NODE:
+      return [self buildText:(id<DOMText>)_node
+                   templateBuilder:_builder];
+    case DOM_CDATA_SECTION_NODE:
+      return [self buildCDATASection:(id<DOMCDATASection>)_node
+                   templateBuilder:_builder];
+    case DOM_COMMENT_NODE:
+      return [self buildComment:(id<DOMComment>)_node
+                   templateBuilder:_builder];
+    case DOM_DOCUMENT_NODE:
+      return [self buildDocument:(id<DOMDocument>)_node
+                   templateBuilder:_builder];
+      
+    default:
+      if (self->nextBuilder)
+        return [self->nextBuilder buildNode:_node templateBuilder:_builder];
+      else {
+        NSLog(@"unknown node type %i, node %@", [_node nodeType], _node);
+        return nil;
+      }
+  }
+}
+
+- (NSArray *)buildNodes:(id<DOMNodeList>)_nodes templateBuilder:(id)_bld {
+  // Note: returns a regular autoreleased array
+  NSMutableArray *children;
+  unsigned       i, count;
+  
+  if ((count = [_nodes length]) == 0)
+    return nil;
+  
+  children = [NSMutableArray arrayWithCapacity:(count + 1)];
+  
+  for (i = 0; i < count; i++) {
+    WOElement *e;
+
+    e = [_bld buildNode:[_nodes objectAtIndex:i] templateBuilder:_bld];
+    if (e) {
+      [children addObject:e];
+      [e release];
+    }
+  }
+  return children;
+}
+
+/* building methods specialized on type (return retained objects !!!) */
+
+- (WOElement *)buildDocument:(id<DOMDocument>)_node templateBuilder:(id)_bld {
+  return [self buildElement:[_node documentElement] templateBuilder:_bld];
+}
+
+- (WOElement *)buildElement:(id<DOMElement>)_node templateBuilder:(id)_bld {
+  if (self->nextBuilder)
+    return [self->nextBuilder buildElement:_node templateBuilder:_bld];
+
+  [self logWithFormat:@"cannot build node %@ (template builder %@)",
+          _node, _bld];
+  return nil;
+}
+
+- (WOElement *)buildCharacterData:(id<DOMCharacterData>)_text
+  templateBuilder:(id)_builder
+{
+  static Class ValClass = Nil;
+  WOElement *textElement;
+  unsigned len;
+  BOOL     isASCII = NO;
+  id       str;
+  
+  str = [_text data];
+  if ((len = [str length]) == 0) return nil;
+  
+  /* 
+     we use WOValueAssociation directly, because WOAssociation caches all
+     values
+  */
+  if (ValClass == Nil)
+    ValClass = NSClassFromString(@"WOValueAssociation");
+
+#if 0
+#  warning not using ASCII string !
+  isASCII = NO;
+#else
+  if (len > 1) {
+    // TODO(perf): improve on that
+    /* not very efficient, but only used during template parsing ... */
+    if ([str dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:NO])
+      isASCII = YES;
+    else
+      isASCII = NO;
+  }
+  else {
+    isASCII = ([str characterAtIndex:0] < 128) ? YES : NO;
+  }
+#endif
+  
+  str = [[ValClass alloc] initWithString:str];
+  textElement = 
+    [[(isASCII?AStrClass:StrClass) alloc] initWithValue:str escapeHTML:YES];
+  [str release];
+  return textElement;
+}
+- (WOElement *)buildText:(id<DOMText>)_node
+  templateBuilder:(id)_builder
+{
+  return [self buildCharacterData:_node templateBuilder:_builder];
+}
+- (WOElement *)buildCDATASection:(id<DOMCDATASection>)_node
+  templateBuilder:(id)_builder
+{
+  return [self buildCharacterData:_node templateBuilder:_builder];
+}
+
+- (WOElement *)buildComment:(id<DOMComment>)_node
+  templateBuilder:(id)_builder
+{
+  /* comments aren't delivered ... */
+  return nil;
+}
+
+/* building the whole template */
+
+- (WOElement *)buildTemplateFromDocument:(id<DOMDocument>)_document {
+  NSAutoreleasePool *pool;
+  WOElement *result;
+  
+  pool   = [[NSAutoreleasePool alloc] init];
+  result = [[self buildNode:_document templateBuilder:self] retain];
+  [pool release];
+  return [result autorelease];
+}
+
+/* association callbacks */
+
+- (WOAssociation *)associationForValue:(id)_value {
+  return [WOAssociation associationWithValue:_value];
+}
+
+- (WOAssociation *)associationForKeyPath:(NSString *)_path {
+  return [WOAssociation associationWithKeyPath:_path];
+}
+
+- (WOAssociation *)associationForJavaScript:(NSString *)_js {
+  WOAssociation *assoc;
+  
+  assoc = [NSClassFromString(@"WOScriptAssociation") alloc];
+  assoc = [(id)assoc initWithScript:_js language:@"javascript"];
+  return [assoc autorelease];
+}
+
+- (WOAssociation *)associationForAttribute:(id<DOMAttr>)_attribute {
+  NSString      *nsuri;
+  NSString      *value;
+  WOAssociation *assoc;
+  Class c;
+  
+  nsuri = [_attribute namespaceURI];
+  value = [_attribute nodeValue];
+  
+  c = [self associationClassForNamespaceURI:[_attribute namespaceURI]];
+  if (c == Nil) {
+    [self logWithFormat:
+           @"WARNING, found no association class for "
+           @"attribute %@ (namespace=%@)",
+           _attribute, [_attribute namespaceURI]];
+    return nil;
+  }
+  if (logAssocMap) {
+    [self logWithFormat:@"use class %@ for namespaceURI %@ (attribute %@)",
+           c, [_attribute namespaceURI], [_attribute name]];
+  }
+  
+  assoc = [[c alloc] initWithString:value];
+  if (logAssocCreation) {
+    [self logWithFormat:@"created assoc %@ for attribute %@", 
+           assoc, [_attribute name]];
+  }
+  
+  return [assoc autorelease];
+}
+
+- (NSMutableDictionary *)associationsForAttributes:(id<DOMNamedNodeMap>)_attrs{
+  NSMutableDictionary *assocs;
+  int i, count;
+  
+  if ((count = [_attrs length]) == 0)
+    return nil;
+  
+  assocs = [NSMutableDictionary dictionaryWithCapacity:(count + 1)];
+
+  for (i = 0; i < count; i++) {
+    id<DOMAttr>   attr;
+    WOAssociation *assoc;
+
+    attr = [_attrs objectAtIndex:i];
+    
+    if ((assoc = [self associationForAttribute:attr])) {
+      NSString *key;
+      
+      key = [attr name];
+      if ([key characterAtIndex:0] == '_')
+        key = [@"?" stringByAppendingString:[key substringFromIndex:1]];
+      
+      [assocs setObject:assoc forKey:key];
+    }
+  }
+  return assocs;
+}
+
+- (void)_ensureDefaultAssocMappings {
+  NSEnumerator *e;
+  NSString     *ns;
+  
+  if (self->nsToAssoc) 
+    return;
+  
+  self->nsToAssoc = [[NSMutableDictionary alloc] initWithCapacity:8];
+  e = [defaultAssocMap keyEnumerator];
+  while ((ns = [e nextObject])) {
+    NSString *className;
+    Class    clazz;
+    
+    className = [defaultAssocMap objectForKey:ns];
+    clazz = NSClassFromString(className);
+    
+    if (clazz == Nil) {
+      [self logWithFormat:@"WARNING: did not find association class: '%@'",
+             className];
+      continue;
+    }
+    
+    /* register */
+    [self->nsToAssoc setObject:clazz forKey:ns];
+  }
+}
+- (void)registerAssociationClass:(Class)_class forNamespaceURI:(NSString *)_ns{
+  if (_ns    == nil) return;
+  if (_class == Nil) return;
+  
+  [self _ensureDefaultAssocMappings];
+  [self->nsToAssoc setObject:_class forKey:_ns];
+}
+- (Class)associationClassForNamespaceURI:(NSString *)_ns {
+  Class c;
+  
+  [self _ensureDefaultAssocMappings];
+  
+  if ((c = [self->nsToAssoc objectForKey:_ns]) == nil)
+    /* if we have no class mapped for a namespace, we treat it as a value */
+    c = ValAssoc;
+  
+  if (debugOn)
+    [self debugWithFormat:@"using class %@ for namespace %@", c, _ns];
+  return c;
+}
+
+/* creating unique IDs */
+
+- (NSString *)uniqueIDForNode:(id)_node {
+  NSMutableArray  *nodePath;
+  NSMutableString *uid;
+  NSEnumerator    *topDown;
+  id   node, parent;
+  BOOL isFirst;
+
+  if (_node == nil) return nil;
+
+  nodePath = [NSMutableArray arrayWithCapacity:16];
+
+  /* collect all parent nodes in bottom-up form */
+
+  for (node = _node; node; node = [node parentNode])
+    [nodePath addObject:node];
+
+  /* generate ID */
+
+  uid     = [NSMutableString stringWithCapacity:64];
+  topDown = [nodePath reverseObjectEnumerator];
+  isFirst = YES;
+  parent  = nil;
+
+  for (isFirst = YES; (node = [topDown nextObject]); parent = node) {
+    if (!isFirst) {
+      NSArray  *children;
+      unsigned i, count;
+
+      [uid appendString:@"."];
+
+      /* determine index of _node */
+
+      children = (NSArray *)[parent childNodes];
+      for (i = 0, count = [children count]; i < count; i++) {
+        if ([children objectAtIndex:i] == node)
+          break;
+      }
+      [uid appendFormat:@"%d", i];
+    }
+    else {
+      [uid appendString:@"R"];
+      isFirst = NO;
+    }
+  }
+
+  return [[uid copy] autorelease];
+}
+
+/* logging */
+
+- (void)logWithFormat:(NSString *)_format, ... {
+  NSString *value = nil;
+  va_list  ap;
+
+  va_start(ap, _format);
+  value = [[NSString alloc] initWithFormat:_format arguments:ap];
+  va_end(ap);
+
+  NSLog(@"|%@| %@", self, value);
+  [value release];
+}
+- (void)debugWithFormat:(NSString *)_format, ... {
+  static char showDebug = 2;
+  NSString *value = nil;
+  va_list  ap;
+  
+  if (showDebug == 2) {
+    showDebug = [WOApplication isDebuggingEnabled] ? 1 : 0;
+  }
+  
+  if (showDebug) {
+    va_start(ap, _format);
+    value = [[NSString alloc] initWithFormat:_format arguments:ap];
+    va_end(ap);
+    
+    NSLog(@"|%@|D %@", self, value);
+    [value release];
+  }
+}
+
+/* managing builder queues */
+
+- (void)setNextBuilder:(WOxElemBuilder *)_builder {
+  ASSIGN(self->nextBuilder, _builder);
+}
+- (WOxElemBuilder *)nextBuilder {
+  return self->nextBuilder;
+}
+
+/* component script parts */
+
+- (void)addComponentScriptPart:(WOComponentScriptPart *)_part {
+  if (self->script == nil)
+    self->script = [[WOComponentScript alloc] init];
+  
+  [self->script addScriptPart:_part];
+}
+- (void)addComponentScript:(NSString *)_script line:(unsigned)_line {
+  WOComponentScriptPart *part;
+  
+  part = [[WOComponentScriptPart alloc] initWithURL:nil startLine:_line
+                                       script:_script];
+  [self addComponentScriptPart:part];
+  RELEASE(part);
+}
+
+- (WOComponentScript *)componentScript {
+  return self->script;
+}
+
+/* subcomponent registry, created during parsing ... */
+
+- (void)registerSubComponentWithId:(NSString *)_cid
+  componentName:(NSString *)_name
+  bindings:(NSMutableDictionary *)_bindings
+{
+  WOxElemBuilderComponentInfo *info;
+  
+  info = [[WOxElemBuilderComponentInfo alloc] initWithComponentId:_cid
+    componentName:_name
+    bindings:_bindings];
+    
+  if (self->subcomponentInfos == nil)
+    self->subcomponentInfos = [[NSMutableArray alloc] initWithCapacity:16];
+  [self->subcomponentInfos addObject:info];
+  RELEASE(info);
+}
+
+- (NSArray *)subcomponentInfos {
+  return self->subcomponentInfos;
+}
+
+- (void)reset {
+  [self->subcomponentInfos removeAllObjects];
+  ASSIGN(self->script, (id)nil);
+}
+
+@end /* WOxElemBuilder */
+
+@implementation WOxTagClassElemBuilder
+
+- (Class)classForElement:(id<DOMElement>)_element {
+  return Nil;
+}
+
+- (WOElement *)buildElement:(id<DOMElement>)_element templateBuilder:(id)_b {
+  Class clazz;
+  
+  if ((clazz = [self classForElement:_element]) == Nil) {
+    if (self->nextBuilder)
+      return [self->nextBuilder buildElement:_element templateBuilder:_b];
+    else {
+      [self logWithFormat:
+              @"did not find dynamic element class for DOM element %@",
+              _element];
+      return nil;
+    }
+  }
+  return [[clazz alloc] initWithElement:_element templateBuilder:_b];
+}
+
+@end /* SxTagClassElemBuilder */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOxTemplateBuilder.h b/skyrix-sope/NGObjWeb/Templates/WOxTemplateBuilder.h
new file mode 100644 (file)
index 0000000..83c4857
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOxTemlateBuilder_H__
+#define __NGObjWeb_WOxTemlateBuilder_H__
+
+#include <NGObjWeb/WOTemplateBuilder.h>
+
+@interface WOxTemplateBuilder : WOTemplateBuilder
+@end
+
+#endif /* __NGObjWeb_WOxTemlateBuilder_H__ */
diff --git a/skyrix-sope/NGObjWeb/Templates/WOxTemplateBuilder.m b/skyrix-sope/NGObjWeb/Templates/WOxTemplateBuilder.m
new file mode 100644 (file)
index 0000000..6373776
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOxTemplateBuilder.h"
+#include <NGObjWeb/WOxElemBuilder.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOElement.h>
+#include <DOM/DOM.h>
+#include <DOM/DOMBuilderFactory.h>
+#include "common.h"
+
+@implementation WOxTemplateBuilder
+
+static BOOL  profLoading = NO;
+static Class DateClass = Nil;
+
++ (int)version {
+  return [super version] + 0 /* v1 */;
+}
+
++ (void)initialize {
+  NSAssert2([super version] == 1,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  if (DateClass == Nil)
+    DateClass = [NSDate class];
+}
+
+- (WOxElemBuilder *)builderForDocument:(id<DOMDocument>)_document {
+  return [[WOApplication application] builderForDocument:_document];
+}
+- (Class)templateClass {
+  return [WOTemplate class];
+}
+
+- (WOTemplate *)buildTemplateFromDocument:(id<NSObject,DOMDocument>)_doc
+  url:(NSURL *)_url
+{
+  WOTemplate        *template;
+  NSTimeInterval    st = 0.0;
+  WOxElemBuilder    *builder;
+  WOElement         *root;
+  WOComponentScript *script;
+  
+  if (_doc == nil)
+    return nil;
+  
+  if (profLoading)
+    st = [[DateClass date] timeIntervalSince1970];
+  
+  builder = [self builderForDocument:_doc];
+  
+  root = [[builder buildTemplateFromDocument:_doc] retain];
+  
+  template = [[self templateClass] alloc];
+  template = [template initWithURL:_url rootElement:root];
+  template = [template autorelease];
+  
+  /* transform builder info's into element defs ... */
+  
+  if (template) {
+    NSEnumerator *scinfos;
+    WOxElemBuilderComponentInfo *scinfo;
+    
+    scinfos = [[builder subcomponentInfos] objectEnumerator];
+    
+    while ((scinfo = [scinfos nextObject])) {
+      [template addSubcomponentWithKey:[scinfo componentId]
+                name:[scinfo pageName]
+                bindings:[scinfo bindings]];
+    }
+    
+    if ((script = [builder componentScript]))
+      [template setComponentScript:script];
+  }
+  
+  /* reset building state */
+  [builder reset];
+  
+  if (profLoading) {
+    NSTimeInterval diff;
+    diff = [[DateClass date] timeIntervalSince1970] - st;
+    printf("  building from XML: %0.3fs\n", diff);
+  }
+  return template;
+}
+
+- (id<DOMBuilder>)xmlParser {
+  //static id builder = nil;
+  
+  return [[DOMBuilderFactory standardDOMBuilderFactory]
+                             createDOMBuilderForMimeType:@"text/xml"];
+}
+
+- (WOTemplate *)buildTemplateAtURL:(NSURL *)_url {
+  id<NSObject,DOMDocument> domDocument;
+  NSAutoreleasePool *pool;
+  id<DOMBuilder>    builder;
+  WOTemplate        *template;
+  
+  //NSLog(@"loading XML template %@ ...", self->path);
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  builder = [self xmlParser];
+  NSAssert(builder != nil, @"missing XML parser ..");
+  
+  domDocument = [builder buildFromSource:_url];
+  //[@"file://" stringByAppendingString:self->path]];
+  
+  /* construct template for DOM document */
+  
+  if (domDocument) {
+    template = [self buildTemplateFromDocument:domDocument url:_url];
+    
+    /* should scan document for class/script information */
+  }
+  else
+    template = nil;
+
+  template = [template retain];
+  [pool release];
+  
+  return [template autorelease];
+}
+
+@end /* WOxTemplateBuilder */
+
+@implementation WOApplication(BuilderStack)
+
+- (WOxElemBuilder *)builderForDocument:(id<DOMDocument>)_document {
+  static WOxElemBuilder *builder    = nil;
+  static NSArray        *defClasses = nil;
+  NSUserDefaults *ud;
+  NSArray *classes = nil;
+  NSArray *infos;
+  
+  if (builder != nil)
+    return builder;
+    
+  ud = [NSUserDefaults standardUserDefaults];
+  if (defClasses == nil)
+    defClasses = [[ud arrayForKey:@"WOxBuilderClasses"] copy];
+  
+  infos = [[NGBundleManager defaultBundleManager]
+                            providedResourcesOfType:@"WOxElemBuilder"];
+  if ([infos count] > 0) {
+    classes = [NSMutableArray arrayWithCapacity:24];
+    [(id)classes addObjectsFromArray:[infos valueForKey:@"name"]];
+    [(id)classes addObjectsFromArray:defClasses];
+  }
+  else
+    classes = defClasses;
+  
+  if ([ud boolForKey:@"WOxLogBuilderQueue"]) {
+    NSEnumerator *e;
+    NSString *b;
+      
+    if ([classes count] > 0) {
+      [self debugWithFormat:@"builder stack:"];
+      e = [classes objectEnumerator];
+      while ((b = [e nextObject]))
+       [self logWithFormat:@"  %@", b];
+    }
+    else {
+      [self debugWithFormat:@"empty wox-element builder stack !"];
+    }
+  }
+  
+  builder = [[WOxElemBuilder createBuilderQueue:classes] retain];
+  return builder;
+}
+
+@end /* WOApplication(BuilderStack) */
diff --git a/skyrix-sope/NGObjWeb/UnixSignalHandler.h b/skyrix-sope/NGObjWeb/UnixSignalHandler.h
new file mode 100644 (file)
index 0000000..7feddfc
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+   UnixSignalHandler.h
+
+   Copyright (C) 1995, 1996, 1997 Ovidiu Predescu and Mircea Oancea.
+   
+
+   Author: Ovidiu Predescu <ovidiu@net-community.com>
+   Date: November 1997
+
+   Based on a similar class written by Mircea Oancea in July 1995.
+
+   This file is part of libFoundation.
+
+   Permission to use, copy, modify, and distribute this software and its
+   documentation for any purpose and without fee is hereby granted, provided
+   that the above copyright notice appear in all copies and that both that
+   copyright notice and this permission notice appear in supporting
+   documentation.
+
+   We disclaim all warranties with regard to this software, including all
+   implied warranties of merchantability and fitness, in no event shall
+   we be liable for any special, indirect or consequential damages or any
+   damages whatsoever resulting from loss of use, data or profits, whether in
+   an action of contract, negligence or other tortious action, arising out of
+   or in connection with the use or performance of this software.
+*/
+
+#if LIB_FOUNDATION_LIBRARY
+
+#include <Foundation/UnixSignalHandler.h>
+
+#else
+
+#ifndef __UnixSignalHandler_h__
+#define __UnixSignalHandler_h__
+
+#if defined(__MINGW32__)
+#  include <signal.h>
+#else
+#  include <sys/signal.h>
+#endif
+#import <Foundation/NSObject.h>
+
+@class UnixSignalHandlerList;
+
+@interface UnixSignalHandler : NSObject
+{
+  UnixSignalHandlerList *signalHandlers[NSIG];
+  unsigned int          currentSigmask;
+  BOOL                  signalsPending;
+}
+
++ sharedHandler;
+
+- (void)addObserver:(id)observer
+  selector:(SEL)selector
+  forSignal:(int)signalNumber
+  immediatelyNotifyOnSignal:(BOOL)flag;
+- (void)removeObserver:(id)observer;
+- (void)removeObserver:(id)observer
+  forSignal:(int)signalNumber;
+
+/* Blocking or enabling signals */
+- (void)blockAllSignals;
+- (void)enableAllSignals;
+- (void)blockSignal:(int)signum;
+- (void)enableSignal:(int)signum;
+
+- (void)waitForSignal:(int)signum;
+
+- (BOOL)signalsPending;
+
+@end
+
+
+#endif /* __UnixSignalHandler_h__ */
+
+#endif
+
+/*
+  Local Variables:
+  c-basic-offset: 4
+  tab-width: 8
+  End:
+*/
diff --git a/skyrix-sope/NGObjWeb/UnixSignalHandler.m b/skyrix-sope/NGObjWeb/UnixSignalHandler.m
new file mode 100644 (file)
index 0000000..ef4fb71
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+   UnixSignalHandler.m
+
+   Copyright (C) 1995, 1996, 1997 Ovidiu Predescu and Mircea Oancea.
+   
+
+   Author: Ovidiu Predescu <ovidiu@net-community.com>
+   Date: November 1997
+
+   Based on a similar class written by Mircea Oancea in July 1995.
+
+   This file is part of libFoundation.
+
+   Permission to use, copy, modify, and distribute this software and its
+   documentation for any purpose and without fee is hereby granted, provided
+   that the above copyright notice appear in all copies and that both that
+   copyright notice and this permission notice appear in supporting
+   documentation.
+
+   We disclaim all warranties with regard to this software, including all
+   implied warranties of merchantability and fitness, in no event shall
+   we be liable for any special, indirect or consequential damages or any
+   damages whatsoever resulting from loss of use, data or profits, whether in
+   an action of contract, negligence or other tortious action, arising out of
+   or in connection with the use or performance of this software.
+*/
+
+#if !LIB_FOUNDATION_LIBRARY
+
+//#include <config.h>
+#define HAVE_SIGSETMASK 1
+#define RETSIGTYPE      void
+
+#include <signal.h>
+
+//#include "NSObjectMacros.h"
+#include "common.h"
+#import <Foundation/NSValue.h>
+#import <Foundation/NSNotification.h>
+#import <Foundation/NSNotificationQueue.h>
+#include "UnixSignalHandler.h"
+
+static NSString* UnixSignalPendingNotification
+    = @"UnixSignalPendingNotification";
+
+#if HAVE_SIGSETMASK
+#  define BSD_SIGNALS 1
+#elif HAVE_SIGHOLD
+#  define SYSV_SIGNALS 1
+#elif defined(__MINGW32__)
+#  warning "Don't know how to handle signals on Mingw32 !"
+#else
+#  error "Don't know how to handle signals!"
+#endif
+
+#if !defined(sigmask)
+# define sigmask(m)    (1 << ((m)-1))
+#endif
+
+static RETSIGTYPE signalHandlerFunction (int signum);
+
+typedef RETSIGTYPE (*PTSignalFunction)(int);
+
+@interface UnixSignalHandlerListItem : NSObject
+{
+@public
+  id observer;
+  SEL selector;
+  BOOL immediatelyNotifyOnSignal;
+  UnixSignalHandlerListItem* nextItem;
+}
+- (id)initWithObserver:observer
+  selector:(SEL)selector
+  immediatelyNotifyOnSignal:(BOOL)flag;
+- (id)removeObserver:observer;
+- (void)invokeForSignal:(int)signum;
+@end
+
+
+@implementation UnixSignalHandlerListItem
+
+- (id)initWithObserver:anObserver
+  selector:(SEL)aSelector
+  immediatelyNotifyOnSignal:(BOOL)flag
+{
+  self->observer = anObserver;
+  self->selector = aSelector;
+  self->immediatelyNotifyOnSignal = flag;
+  return self;
+}
+
+- (id)removeObserver:anObserver
+{
+  if (observer == anObserver) {
+    (void)AUTORELEASE(self);
+    return nextItem;
+  }
+  else {
+    nextItem = [nextItem removeObserver:anObserver];
+    return self;
+  }
+}
+
+- (void)invokeForSignal:(int)signum
+{
+  [observer performSelector:selector
+            withObject:[NSNumber numberWithLong:signum]];
+}
+
+@end
+
+
+@interface UnixSignalHandlerList : NSObject
+{
+@public
+  UnixSignalHandlerListItem* firstItem;
+  PTSignalFunction oldSignalHandler;
+  BOOL signalsPending;
+}
+
+- (void)addObserver:observer
+  selector:(SEL)selector
+  immediatelyNotifyOnSignal:(BOOL)flag;
+- (void)removeObserver:observer;
+- (void)invokeIfCalledImmediatelyIs:(BOOL)flag signal:(int)signum;
+
+@end
+
+
+@implementation UnixSignalHandlerList
+
+- (void)addObserver:anObserver
+  selector:(SEL)aSelector
+  immediatelyNotifyOnSignal:(BOOL)flag
+{
+  UnixSignalHandlerListItem* newItem = [UnixSignalHandlerListItem new];
+
+  newItem->nextItem = firstItem;
+  [newItem initWithObserver:anObserver
+          selector:aSelector
+          immediatelyNotifyOnSignal:flag];
+  firstItem = newItem;
+}
+
+- (void)removeObserver:observer
+{
+  firstItem = [firstItem removeObserver:observer];
+}
+
+- (void)invokeIfCalledImmediatelyIs:(BOOL)flag signal:(int)signum
+{
+  UnixSignalHandlerListItem* item = firstItem;
+
+  if (signalsPending) {
+    while (item) {
+      if (item->immediatelyNotifyOnSignal == flag)
+       [item invokeForSignal:signum];
+      item = item->nextItem;
+    }
+    signalsPending = NO;
+  }
+}
+
+@end /* UnixSignalHandlerList */
+
+
+
+@interface UnixSignalHandler (private)
+- (void)_pendingSignal:(int)signum;
+@end
+
+@implementation UnixSignalHandler
+
+static NSNotification* notification = nil;
+static UnixSignalHandler* sharedHandler = nil;
+
+static RETSIGTYPE signalHandlerFunction (int signum)
+{
+  /* Temporary disable the signals */
+  [sharedHandler blockAllSignals];
+
+  ((UnixSignalHandlerList*)(sharedHandler->signalHandlers[signum]))
+      ->signalsPending = YES;
+  sharedHandler->signalsPending = YES;
+
+  [[NSNotificationQueue defaultQueue]
+         enqueueNotification:notification
+         postingStyle:NSPostASAP];
+  [sharedHandler _pendingSignal:signum];
+
+  [sharedHandler enableAllSignals];
+}
+
++ (void)initialize
+{
+  static BOOL initialized = NO;
+
+  if (!initialized) {
+    initialized = YES;
+    sharedHandler = [self new];
+    notification = RETAIN([NSNotification
+                            notificationWithName:UnixSignalPendingNotification
+                            object:sharedHandler]);
+    [[NSNotificationCenter defaultCenter]
+         addObserver:self
+         selector:@selector(_dispatch:)
+         name:UnixSignalPendingNotification
+         object:nil];
+  }
+}
+
++ (id)sharedHandler
+{
+    return sharedHandler;
+}
+
+- (id)init
+{
+  int i;
+
+  for (i = 0; i < NSIG; i++)
+    signalHandlers[i] = [UnixSignalHandlerList new];
+
+#if BSD_SIGNALS
+  currentSigmask = sigblock (0);
+#endif
+
+  return self;
+}
+
+- (void)_pendingSignal:(int)signum
+{
+  /* Notify all the handlers that listen for the signal signum immediately.
+     Only those handlers that have requested an immediate notification on
+     signal are invoked here. Those that want to be called after the signal
+     occured are invoked at a later time, when the current NSRunLoop finishes
+     the current cycle. */
+  [signalHandlers[signum] invokeIfCalledImmediatelyIs:YES signal:signum];
+}
+
++ (void)_dispatch:(NSNotification *)notification
+{
+  int i;
+
+  /* Notify all the handlers that have requested to be called after the current
+     NSRunLoop cycle has finished. The others were already called when the
+     signal occurred. */
+  
+  if (sharedHandler->signalsPending) {
+    for (i = 0; i < NSIG; i++)
+      [sharedHandler->signalHandlers[i] 
+                   invokeIfCalledImmediatelyIs:NO signal:i];
+    sharedHandler->signalsPending = NO;
+  }
+}
+
+- (BOOL)signalsPending
+{
+    return signalsPending;
+}
+
+- (void)addObserver:(id)observer
+  selector:(SEL)selector
+  forSignal:(int)signum
+  immediatelyNotifyOnSignal:(BOOL)flag
+{
+  BOOL shouldInstall = (signalHandlers[signum]->firstItem == NULL);
+
+  [self blockSignal:signum];
+  [signalHandlers[signum] addObserver:observer
+                         selector:selector
+                         immediatelyNotifyOnSignal:flag];
+  if (shouldInstall)
+#if HAVE_SIGSET
+    signalHandlers[signum]->oldSignalHandler
+       = (PTSignalFunction)sigset (signum, signalHandlerFunction);
+#elif HAVE_SIGACTION && !defined(__alpha__)
+    {
+       struct sigaction act, oldact;
+
+       act.sa_handler = (PTSignalFunction)signalHandlerFunction;
+       sigemptyset (&act.sa_mask);
+       act.sa_flags = 0;
+       sigaction (signum, &act, &oldact);
+       signalHandlers[signum]->oldSignalHandler = oldact.sa_handler;
+    }
+#else
+    signalHandlers[signum]->oldSignalHandler
+       = (PTSignalFunction)signal (signum, signalHandlerFunction);
+#endif
+  [self enableSignal:signum];
+}
+
+- (void)removeObserver:(id)observer
+{
+  int i;
+
+  for (i = 0; i < NSIG; i++)
+    [self removeObserver:observer forSignal:i];
+}
+
+- (void)removeObserver:(id)observer
+  forSignal:(int)signum
+{
+  [self blockSignal:signum];
+  [signalHandlers[signum] removeObserver:observer];
+  if (signalHandlers[signum]->firstItem == NULL)
+#if HAVE_SIGSET
+    sigset (signum, signalHandlers[signum]->oldSignalHandler);
+#else
+    signal (signum, signalHandlers[signum]->oldSignalHandler);
+#endif
+  [self enableSignal:signum];
+}
+
+- (void)blockAllSignals
+{
+#if BSD_SIGNALS
+  sigsetmask ((unsigned)-1);
+#elif SYSV_SIGNALS
+  int i;
+
+  for (i = 0; i < NSIG; i++)
+    sighold (i);
+#endif
+}
+
+- (void)enableAllSignals
+{
+#if BSD_SIGNALS
+  sigsetmask (currentSigmask);
+#elif SYSV_SIGNALS
+  int i;
+
+  for (i = 0; i < NSIG; i++)
+      if ((currentSigmask & sigmask(i)))
+         sigrelse (i);
+#endif
+}
+
+- (void)blockSignal:(int)signum
+{
+  currentSigmask |= sigmask (signum);
+#if BSD_SIGNALS
+  sigsetmask (currentSigmask);
+#elif SYSV_SIGNALS
+  sighold (signum);
+#endif
+}
+
+- (void)enableSignal:(int)signum
+{
+  currentSigmask &= ~(sigmask (signum));
+#if BSD_SIGNALS
+  sigsetmask (currentSigmask);
+#elif SYSV_SIGNALS
+  sigrelse (signum);
+#endif
+}
+
+- (void)waitForSignal:(int)signum
+{
+#if BSD_SIGNALS
+  sigpause (sigmask (signum));
+#elif SYSV_SIGNALS
+  sigpause (signum);
+#endif
+}
+
+@end
+
+#endif /* !LIB_FOUNDATION_LIBRARY */
diff --git a/skyrix-sope/NGObjWeb/Version b/skyrix-sope/NGObjWeb/Version
new file mode 100644 (file)
index 0000000..93bd871
--- /dev/null
@@ -0,0 +1,13 @@
+# $Id$
+
+SUBMINOR_VERSION:=431
+
+ifeq ($(FOUNDATION_LIB),apple)
+# the MacOSX linker only allows versions up to 255 ...
+SUBMINOR_VERSION:=0
+endif
+
+# v4.2.413 requires libSaxObjC      v4.2.33
+# v4.2.341 requires libNGExtensions v4.2.77
+# v4.2.316 requires libEOControl    v4.2.39
+# v4.2.177 requires libNGExtensions v4.2.33
diff --git a/skyrix-sope/NGObjWeb/WEClientCapabilities.m b/skyrix-sope/NGObjWeb/WEClientCapabilities.m
new file mode 100644 (file)
index 0000000..94061d0
--- /dev/null
@@ -0,0 +1,1020 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WEClientCapabilities.h>
+#include <NGObjWeb/WOAssociation.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOResponse.h>
+#include <string.h>
+#include "common.h"
+
+#define WEUA_UNKNOWN          0
+#define WEUA_IE               1
+#define WEUA_Netscape         2
+#define WEUA_Lynx             3
+#define WEUA_Opera            4
+#define WEUA_Amaya            5
+#define WEUA_Emacs            6
+#define WEUA_Wget             7
+#define WEUA_WebFolder        8
+#define WEUA_Mozilla          9
+#define WEUA_OmniWeb          10
+#define WEUA_iCab             11
+#define WEUA_Konqueror        12
+#define WEUA_Links            13
+#define WEUA_DAVFS            14
+#define WEUA_CADAVER          15
+#define WEUA_GOLIVE           16
+#define WEUA_MACOSX_DAVFS     17
+#define WEUA_Dillo            18
+#define WEUA_JavaSDK          19
+#define WEUA_PythonURLLIB     20
+#define WEUA_AppleDAVAccess   21
+#define WEUA_MSWebPublisher   22
+#define WEUA_CURL             23
+#define WEUA_Evolution        24
+#define WEUA_MSOutlook        25
+#define WEUA_MSOutlookExpress 26
+#define WEUA_GNOMEVFS         27
+#define WEUA_ZideLook         28
+#define WEUA_Safari           29
+#define WEUA_SOUP             30
+#define WEUA_Entourage        31
+#define WEUA_NetNewsWire      32
+#define WEUA_xmlrpclib_py     33
+#define WEUA_Morgul           34
+#define WEUA_CFNetwork        35
+#define WEUA_KungLog          36
+#define WEUA_SOPE             37
+#define WEUA_Ecto             38
+
+#define WEOS_UNKNOWN   0
+#define WEOS_WINDOWS   1
+#define WEOS_LINUX     2
+#define WEOS_MACOS     3
+#define WEOS_SUNOS     4
+
+#define WECPU_UNKNOWN  0
+#define WECPU_IX86     1
+#define WECPU_SPARC    2
+#define WECPU_PPC      3
+
+@interface WEClientCapabilities(Privates)
+- (id)initWithRequest:(WORequest *)_request;
+@end
+
+@implementation WEClientCapabilities
+
+- (id)initWithRequest:(WORequest *)_request {
+  NSString *ac;
+  const unsigned char *ua;
+  const unsigned char *tmp;
+  int defaultOS  = WEOS_UNKNOWN;
+  int defaultCPU = WECPU_UNKNOWN;
+  
+  /* check charset */
+  
+  if ((ac = [_request headerForKey:@"accept-charset"])) {
+    /* not really correct ..., eg could have quality "0" ! */
+    ac = [ac lowercaseString];
+    if ([ac rangeOfString:@"utf-8"].length > 0)
+      self->flags.acceptUTF8 = 1;
+  }
+  
+  /* process user-agent */
+  
+  self->userAgent = [[_request headerForKey:@"user-agent"] copy];
+  ua = [self->userAgent cString];
+  if (ua == NULL) {
+    /* no user-agent, eg telnet */
+    ua = "";
+  }
+  
+  /* detect browser */
+  
+  if ((tmp = strstr(ua, "Opera"))) {
+    /* Opera (can fake to be MSIE or Netscape) */
+    self->browser = WEUA_Opera;
+
+    /* go to next space */
+    while (!isspace(*tmp) && (*tmp != '\0')) tmp++;
+    /* skip spaces */
+    while (isspace(*tmp) && (*tmp != '\0')) tmp++;
+    
+    self->browserMajorVersion = atoi(tmp);
+    if ((tmp = index(tmp, '.'))) {
+      tmp++;
+      self->browserMinorVersion = atoi(tmp);
+    }
+  }
+  else if (strstr(ua, "NeonConnection") != NULL || 
+           strstr(ua, "ZIDEStore") != NULL ||
+           strstr(ua, "ZideLook-Codeon") != NULL) {
+    self->browser = WEUA_ZideLook;
+    self->browserMinorVersion = 0;
+    self->browserMajorVersion = 0;
+  }
+  else if ((tmp = strstr(ua, "Safari/"))) {
+    /* Hm, Safari says it is a Mozilla/5.0 ? */
+    int combinedVersion;
+    self->browser = WEUA_Safari;
+    tmp += 7; /* skip "Safari/" */
+    combinedVersion = atoi(tmp);
+    /* well, don't know how this is supposed to work? 100=v1.1 */
+    if (combinedVersion == 100 /* 100 is v1.1 */) {
+      self->browserMajorVersion = 1;
+      self->browserMinorVersion = 1;
+    }
+    else {
+      /* watch for upcoming versions ... */
+      self->browserMajorVersion = combinedVersion / 100;
+    }
+  }
+  else if (strstr(ua, "Outlook-Express/")) {
+    /* Outlook Express 5.5 mailbox access via http */
+    self->browser = WEUA_MSOutlookExpress;
+  }
+  else if (strstr(ua, "Outlook Express/")) {
+    /* Outlook Express 5.0 mailbox access via http */
+    self->browser = WEUA_MSOutlookExpress;
+  }
+  else if (strstr(ua, "Microsoft-Outlook/")) {
+    /* Outlook 2002 mailbox access via http */
+    self->browser = WEUA_MSOutlook;
+  }
+  else if (strstr(ua, "Microsoft HTTP Post")) {
+    /* Outlook 2000 with WebPublishing Assistent */
+    self->browser = WEUA_MSWebPublisher;
+  }
+  else if (strstr(ua, "Entourage/10")) {
+    /* Entourage MacOSX 10.1.4 */
+    self->browser = WEUA_Entourage;
+  }
+  else if ((tmp = strstr(ua, "MSIE"))) {
+    /* Internet Explorer */
+    self->browser = WEUA_IE;
+    
+    /* go to next space */
+    while (!isspace(*tmp) && (*tmp != '\0')) tmp++;
+    /* skip spaces */
+    while (isspace(*tmp) && (*tmp != '\0')) tmp++;
+    
+    self->browserMajorVersion = atoi(tmp);
+    if ((tmp = index(tmp, '.'))) {
+      tmp++;
+      self->browserMinorVersion = atoi(tmp);
+    }
+  }
+  else if ((tmp = strstr(ua, "Konqueror"))) {
+    /* Konqueror (KDE2 FileManager) */
+    self->browser = WEUA_Konqueror;
+    
+    if ((tmp = index(tmp, '/'))) {
+      tmp++;
+      self->browserMajorVersion = atoi(tmp);
+      if ((tmp = index(tmp, '.'))) {
+        tmp++;
+        self->browserMinorVersion = atoi(tmp);
+      }
+    }
+  }
+  else if ((tmp = strstr(ua, "Netscape6"))) {
+    /* Netscape 6 */
+    self->browser = WEUA_Netscape;
+    
+    if ((tmp = index(tmp, '/'))) {
+      tmp++;
+      self->browserMajorVersion = atoi(tmp);
+      if ((tmp = index(tmp, '.'))) {
+        tmp++;
+        self->browserMinorVersion = atoi(tmp);
+      }
+    }
+  }
+  else if (strstr(ua, "Lynx")) {
+    /* Lynx */
+    self->browser = WEUA_Lynx;
+  }
+  else if (strstr(ua, "Links")) {
+    /* Links */
+    self->browser = WEUA_Links;
+  }
+  else if (strstr(ua, "gnome-vfs")) {
+    /* Links */
+    self->browser = WEUA_GNOMEVFS;
+  }
+  else if (strstr(ua, "cadaver")) {
+    /* Cadaver DAV browser */
+    self->browser = WEUA_CADAVER;
+  }
+  else if (strstr(ua, "GoLive")) {
+    /* Adobe GoLive */
+    self->browser = WEUA_GOLIVE;
+  }
+  else if (strstr(ua, "Darwin") != NULL && strstr(ua, "fetch/") != NULL) {
+    /* MacOSX 10.0 DAV FileSystem */
+    self->browser = WEUA_MACOSX_DAVFS;
+  }
+  else if (strstr(ua, "Darwin") != NULL && strstr(ua, "WebDAVFS/") != NULL) {
+    /* MacOSX DAV FileSystem */
+    self->browser = WEUA_MACOSX_DAVFS;
+  }
+  else if (strstr(ua, "OmniWeb")) {
+    /* OmniWeb */
+    self->browser = WEUA_OmniWeb;
+  }
+  else if (strstr(ua, "Evolution")) {
+    /* Evolution */
+    self->browser = WEUA_Evolution;
+  }
+  else if (strstr(ua, "Soup/")) {
+    /* SOUP (GNOME WebDAV library) */
+    self->browser = WEUA_SOUP;
+  }
+  else if (strstr(ua, "amaya")) {
+    /* W3C Amaya */
+    self->browser = WEUA_Amaya;
+  }
+  else if (strstr(ua, "NetNewsWire/")) {
+    /* NetNewsWire */
+    self->browser = WEUA_NetNewsWire;
+  }
+  else if (strstr(ua, "Dillo")) {
+    /* Dillo */
+    self->browser = WEUA_Dillo;
+  }
+  else if (strstr(ua, "Java")) {
+    /* Java SDK */
+    self->browser = WEUA_JavaSDK;
+  }
+  else if (strstr(ua, "Python-urllib")) {
+    /* Python URL module */
+    self->browser = WEUA_PythonURLLIB;
+  }
+  else if (strstr(ua, "xmlrpclib.py/")) {
+    /* Python XML-RPC module */
+    self->browser = WEUA_xmlrpclib_py;
+  }
+  else if (strstr(ua, "Emacs")) {
+    /* Emacs */
+    self->browser = WEUA_Emacs;
+  }
+  else if (strstr(ua, "iCab")) {
+    /* iCab ?? */
+    self->browser = WEUA_iCab;
+  }
+  else if (strstr(ua, "Wget")) {
+    /* Wget */
+    self->browser = WEUA_Wget;
+  }
+  else if (strstr(ua, "DAVAccess")) {
+    /* Apple MacOSX 10.2.1 / iCal 1.0 DAV Access Framework */
+    self->browser = WEUA_AppleDAVAccess;
+  }
+  else if (strstr(ua, "DAVKit/")) {
+    /* some iCal 1.x DAV Access Framework, report as Apple DAV access */
+    self->browser = WEUA_AppleDAVAccess;
+  }
+  else if (strstr(ua, "Microsoft Data Access Internet Publishing Provider")) {
+    /* WebFolder */
+    self->browser = WEUA_WebFolder;
+  }
+  else if (strstr(ua, "curl")) {
+    /* curl program */
+    self->browser = WEUA_CURL;
+  }
+  else if (strstr(ua, "Mozilla")) {
+    /* other Netscape browser */
+    if (strstr(ua, "Mozilla/5")) {
+      self->browser = WEUA_Mozilla;
+      self->browserMajorVersion = 5;
+    }
+    else if (strstr(ua, "Mozilla/4")) {
+      self->browser = WEUA_Netscape;
+      self->browserMajorVersion = 4;
+    }
+    else {
+      NSLog(@"%s: Unknown Mozilla Browser: user-agent='%@'",
+            __PRETTY_FUNCTION__, self->userAgent);
+    }
+  }
+  else if (strstr(ua, "Morgul")) {
+    self->browser = WEUA_Morgul;
+  }
+  else if (strstr(ua, "CFNetwork/1.1")) {
+    self->browser = WEUA_CFNetwork;
+  }
+  else if (strstr(ua, "Kung-Log/")) {
+    self->browser = WEUA_KungLog;
+  }
+  else if (strstr(ua, "ecto")) {
+    self->browser = WEUA_Ecto;
+  }
+  else if (strstr(ua, "SOPE/")) {
+    self->browser = WEUA_SOPE;
+  }
+  else {
+    /* unknown browser */
+    self->browser = WEUA_UNKNOWN;
+    
+    if (self->userAgent) {
+      NSLog(@"%s: Unknown WebClient: user-agent='%@'",
+            __PRETTY_FUNCTION__, self->userAgent);
+    }
+  }
+  
+  /* detect OS */
+
+  if (strstr(ua, "Windows") != NULL || strstr(ua, "WinNT") != NULL)
+    self->os = WEOS_WINDOWS;
+  else if (strstr(ua, "Linux"))
+    self->os = WEOS_LINUX;
+  else if (strstr(ua, "Mac"))
+    self->os = WEOS_MACOS;
+  else if (strstr(ua, "SunOS"))
+    self->os = WEOS_SUNOS;
+  else
+    self->os = defaultOS;
+
+  /* detect CPU */
+
+  if (strstr(ua, "sun4u"))
+    self->cpu = WECPU_SPARC;
+  else if (strstr(ua, "i686") || strstr(ua, "i586"))
+    self->cpu = WECPU_IX86;
+  else if (strstr(ua, "PowerPC") || strstr(ua, "ppc") || strstr(ua, "PPC"))
+    self->cpu = WECPU_PPC;
+  else if (self->os == WEOS_WINDOWS)
+    /* assume ix86 if OS is Windows .. */
+    self->cpu = WECPU_IX86;
+  else 
+    self->cpu = defaultCPU;
+  
+  return self;
+}
+
+- (void)dealloc {
+  [self->userAgent release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)userAgent {
+  return self->userAgent;
+}
+
+- (NSString *)userAgentType {
+  switch (self->browser) {
+    case WEUA_IE:               return @"IE";
+    case WEUA_Netscape:         return @"Netscape";
+    case WEUA_Lynx:             return @"Lynx";
+    case WEUA_Links:            return @"Links";
+    case WEUA_Opera:            return @"Opera";
+    case WEUA_Amaya:            return @"Amaya";
+    case WEUA_Emacs:            return @"Emacs";
+    case WEUA_Wget:             return @"Wget";
+    case WEUA_WebFolder:        return @"WebFolder";
+    case WEUA_DAVFS:            return @"DAVFS";
+    case WEUA_MACOSX_DAVFS:     return @"MacOSXDAVFS";
+    case WEUA_CADAVER:          return @"Cadaver";
+    case WEUA_GOLIVE:           return @"GoLive";
+    case WEUA_Mozilla:          return @"Mozilla";
+    case WEUA_OmniWeb:          return @"OmniWeb";
+    case WEUA_iCab:             return @"iCab";
+    case WEUA_Konqueror:        return @"Konqueror";
+    case WEUA_Dillo:            return @"Dillo";
+    case WEUA_JavaSDK:          return @"Java";
+    case WEUA_PythonURLLIB:     return @"Python-urllib";
+    case WEUA_AppleDAVAccess:   return @"AppleDAVAccess";
+    case WEUA_MSWebPublisher:   return @"MSWebPublisher";
+    case WEUA_CURL:             return @"CURL";
+    case WEUA_Evolution:        return @"Evolution";
+    case WEUA_SOUP:             return @"SOUP";
+    case WEUA_MSOutlook:        return @"MSOutlook";
+    case WEUA_MSOutlookExpress: return @"MSOutlookExpress";
+    case WEUA_GNOMEVFS:         return @"GNOME-VFS";
+    case WEUA_ZideLook:         return @"ZideLook";
+    case WEUA_Safari:           return @"Safari";
+    case WEUA_Entourage:        return @"Entourage";
+    case WEUA_NetNewsWire:      return @"NetNewsWire";
+    case WEUA_xmlrpclib_py:     return @"xmlrpclib.py";
+    case WEUA_Morgul:           return @"Morgul";
+    case WEUA_KungLog:          return @"KungLog";
+    case WEUA_Ecto:             return @"Ecto";
+    default:                    return @"unknown";
+  }
+}
+- (NSString *)os {
+  switch (self->os) {
+    case WEOS_WINDOWS: return @"Windows";
+    case WEOS_LINUX:   return @"Linux";
+    case WEOS_MACOS:   return @"MacOS";
+    case WEOS_SUNOS:   return @"SunOS";
+    default:           return @"unknown";
+  }
+}
+- (NSString *)cpu {
+  switch (self->cpu) {
+    case WECPU_IX86:  return @"ix86";
+    case WECPU_SPARC: return @"sparc";
+    case WECPU_PPC:   return @"ppc";
+    default:          return @"unknown";
+  }
+}
+
+- (unsigned char)majorVersion {
+  return self->browserMajorVersion;
+}
+- (unsigned char)minorVersion {
+  return self->browserMinorVersion;
+}
+
+/* browser capabilities */
+
+- (BOOL)isJavaScriptBrowser {
+  switch (self->browser) {
+    case WEUA_Mozilla:
+    case WEUA_IE:
+    case WEUA_Opera:
+    case WEUA_Netscape:
+    case WEUA_OmniWeb:
+    case WEUA_Konqueror:
+      return YES;
+      
+    default:
+      return NO;
+  }
+}
+- (BOOL)isVBScriptBrowser {
+  switch (self->browser) {
+    case WEUA_IE:
+      return YES;
+    
+    default:
+      return NO;
+  }
+}
+
+- (BOOL)isFastTableBrowser {
+  switch (self->browser) {
+    case WEUA_Mozilla:
+    case WEUA_IE:
+    case WEUA_Opera:
+      return YES;
+
+    case WEUA_Safari:
+    case WEUA_Konqueror:
+      /* to be tried */
+      return YES;
+      
+    case WEUA_Netscape:
+      return (self->browserMajorVersion >= 6)
+        ? YES : NO;
+      
+    default:
+      return NO;
+  }
+}
+
+- (BOOL)isCSS2Browser {
+  switch (self->browser) {
+    case WEUA_IE:        return (self->browserMajorVersion >= 5) ? YES : NO;
+    case WEUA_Netscape:  return (self->browserMajorVersion >= 6) ? YES : NO;
+    case WEUA_Opera:     return (self->browserMajorVersion >= 4) ? YES : NO;
+    case WEUA_Mozilla:   return YES;
+    case WEUA_Safari:    return YES;
+    case WEUA_Konqueror: return NO;
+    default:             return NO;
+  }
+}
+
+- (BOOL)isCSS1Browser {
+  switch (self->browser) {
+    case WEUA_IE:        return (self->browserMajorVersion >= 4) ? YES : NO;
+    case WEUA_Netscape:  return (self->browserMajorVersion >= 4) ? YES : NO;
+    case WEUA_Opera:     return (self->browserMajorVersion >= 4) ? YES : NO;
+    case WEUA_Safari:    return YES;
+    case WEUA_Konqueror: return NO;
+    default:             return NO;
+  }
+}
+
+- (BOOL)ignoresCSSOnFormElements {
+  if (self->browser == WEUA_Safari) /* Safari always displays Aqua buttons */
+    return YES;
+  
+  return [self isCSS1Browser] ? NO : YES;
+}
+
+- (BOOL)isXULBrowser {
+  if (self->browser == WEUA_Safari)
+    return NO;
+  if ((self->browser == WEUA_Netscape) && (self->browserMajorVersion >= 6))
+    return YES;
+  if (self->browser == WEUA_Mozilla)
+    return YES;
+  return NO;
+}
+
+- (BOOL)isTextModeBrowser {
+  if (self->browser == WEUA_Lynx)  return YES;
+  if (self->browser == WEUA_Links) return YES;
+  if (self->browser == WEUA_Emacs) return YES;
+  return NO;
+}
+
+- (BOOL)isIFrameBrowser {
+  if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
+    return YES;
+  
+  /* as suggested in OGo bug #634 */
+  if ((self->browser == WEUA_Mozilla) && (self->browserMajorVersion >= 5))
+    return YES;
+  
+  return NO;
+}
+
+- (BOOL)isRobot {
+  if (self->browser == WEUA_Wget)         return YES;
+  if (self->browser == WEUA_JavaSDK)      return YES;
+  if (self->browser == WEUA_PythonURLLIB) return YES;
+  return NO;
+}
+- (BOOL)isDAVClient {
+  if (self->browser == WEUA_WebFolder)        return YES;
+  if (self->browser == WEUA_DAVFS)            return YES;
+  if (self->browser == WEUA_MACOSX_DAVFS)     return YES;
+  if (self->browser == WEUA_CADAVER)          return YES;
+  if (self->browser == WEUA_GOLIVE)           return YES;
+  if (self->browser == WEUA_AppleDAVAccess)   return YES;
+  if (self->browser == WEUA_Evolution)        return YES;
+  if (self->browser == WEUA_SOUP)             return YES;
+  if (self->browser == WEUA_MSOutlook)        return YES;
+  if (self->browser == WEUA_MSOutlookExpress) return YES;
+  if (self->browser == WEUA_GNOMEVFS)         return YES;
+  if (self->browser == WEUA_ZideLook)         return YES;
+  if (self->browser == WEUA_Entourage)        return YES;
+  if (self->browser == WEUA_Morgul)           return YES;
+  return NO;
+}
+
+- (BOOL)isXmlRpcClient {
+  if (self->browser == WEUA_xmlrpclib_py) return YES;
+  if (self->browser == WEUA_KungLog)      return YES;
+  if (self->browser == WEUA_Ecto)         return YES;
+  return NO;
+}
+- (BOOL)isBLogClient {
+  if (self->browser == WEUA_KungLog) return YES;
+  if (self->browser == WEUA_Ecto)    return YES;
+  return NO;
+}
+
+- (BOOL)doesSupportCSSOverflow {
+  if (![self isCSS1Browser])
+    return NO;
+  if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
+    return YES;
+
+  return NO;
+}
+
+- (BOOL)doesSupportDHTMLDragAndDrop {
+  if (![self isJavaScriptBrowser])
+    return NO;
+  if (self->os != WEOS_WINDOWS)
+    return NO;
+  if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
+    return YES;
+  return NO;
+}
+
+- (BOOL)doesSupportXMLDataIslands {
+  if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
+    return YES;
+  return NO;
+}
+
+- (BOOL)doesSupportUTF8Encoding {
+  if (self->flags.acceptUTF8)
+    /* explicit UTF-8 support signaled in HTTP header */
+    return YES;
+  
+  switch (self->browser) {
+  case WEUA_Mozilla:
+  case WEUA_Safari:
+  case WEUA_ZideLook:
+  case WEUA_Evolution:
+  case WEUA_SOUP:
+  case WEUA_Morgul:
+    /* browser so new, that they always supported UTF-8 ... */
+    return YES;
+  case WEUA_IE:
+    if (self->browserMajorVersion >= 5)
+      return YES;
+    return NO; // TODO: find out, whether IE 4 gurantees UTF-8 support
+  default:
+    return NO;
+  }
+}
+
+/* user-agent */
+
+- (BOOL)isInternetExplorer {
+  return self->browser == WEUA_IE ? YES : NO;
+}
+- (BOOL)isInternetExplorer5 {
+  return (self->browser == WEUA_IE) && (self->browserMajorVersion == 5)
+    ? YES : NO;
+}
+
+- (BOOL)isNetscape {
+  return self->browser == WEUA_Netscape ? YES : NO;
+}
+- (BOOL)isNetscape6 {
+  return (self->browser == WEUA_Netscape) && (self->browserMajorVersion == 6)
+    ? YES : NO;
+}
+
+- (BOOL)isLynx {
+  return self->browser == WEUA_Lynx ? YES : NO;
+}
+- (BOOL)isOpera {
+  return self->browser == WEUA_Opera ? YES : NO;
+}
+- (BOOL)isAmaya {
+  return self->browser == WEUA_Amaya ? YES : NO;
+}
+- (BOOL)isEmacs {
+  return self->browser == WEUA_Emacs ? YES : NO;
+}
+- (BOOL)isWget {
+  return self->browser == WEUA_Wget ? YES : NO;
+}
+- (BOOL)isWebFolder {
+  return self->browser == WEUA_WebFolder ? YES : NO;
+}
+- (BOOL)isMozilla {
+  return self->browser == WEUA_Mozilla ? YES : NO;
+}
+- (BOOL)isOmniWeb {
+  return self->browser == WEUA_OmniWeb ? YES : NO;
+}
+- (BOOL)isICab {
+  return self->browser == WEUA_iCab ? YES : NO;
+}
+- (BOOL)isKonqueror {
+  return self->browser == WEUA_Konqueror ? YES : NO;
+}
+
+/* OS */
+
+- (BOOL)isWindowsBrowser {
+  return self->os == WEOS_WINDOWS ? YES : NO;
+}
+- (BOOL)isLinuxBrowser {
+  return self->os == WEOS_LINUX ? YES : NO;
+}
+- (BOOL)isMacBrowser {
+  return self->os == WEOS_MACOS ? YES : NO;
+}
+- (BOOL)isSunOSBrowser {
+  return self->os == WEOS_SUNOS ? YES : NO;
+}
+- (BOOL)isUnixBrowser {
+  switch (self->os) {
+    case WEOS_SUNOS:
+    case WEOS_LINUX:
+      return YES;
+    default: return NO;
+  }
+}
+- (BOOL)isX11Browser {
+  if ([self isTextModeBrowser])
+    return NO;
+  if (![self isUnixBrowser])
+    return NO;
+  return YES;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+
+  s = [NSMutableString stringWithFormat:@"<%@[0x%08X]:",
+                         NSStringFromClass([self class]), self];
+  
+  //[s appendFormat:@" ua='%@'", self->userAgent];
+  [s appendFormat:@" type=%@ v%i.%i>",
+       [self userAgentType],
+       self->browserMajorVersion, self->browserMinorVersion];
+  [s appendFormat:@" os=%@",   [self os]];
+  [s appendFormat:@" cpu=%@",  [self cpu]];
+  
+  if ([self isFastTableBrowser])  [s appendString:@" fast-tbl"];
+  if ([self isCSS1Browser])       [s appendString:@" css1"];
+  if ([self isCSS2Browser])       [s appendString:@" css2"];
+  if ([self isXULBrowser])        [s appendString:@" xul"];
+  if ([self isTextModeBrowser])   [s appendString:@" text"];
+  if ([self isRobot])             [s appendString:@" robot"];
+  if ([self isJavaScriptBrowser]) [s appendString:@" js"];
+  if ([self isVBScriptBrowser])   [s appendString:@" vb"];
+  
+  [s appendString:@">"];
+  return s;
+}
+
+@end /* WEClientCapabilities */
+
+static NSString *ClientCapsCacheKey = @"WEClientCapabilties";
+
+@implementation WORequest(ClientCapabilities)
+
+- (WEClientCapabilities *)clientCapabilities {
+  NSDictionary         *ua;
+  WEClientCapabilities *ccaps;
+  NSMutableDictionary  *md;
+
+  if ((ua = [self userInfo]) == nil) {
+    ccaps = [WEClientCapabilities alloc];
+    if ((ccaps = [ccaps initWithRequest:self]) == nil)
+      return nil;
+    ccaps = [ccaps autorelease];
+    
+    ua = [[NSDictionary alloc] initWithObjects:&ccaps
+                               forKeys:&ClientCapsCacheKey
+                               count:1];
+    [self setUserInfo:ua];
+    [ua release];
+    return ccaps;
+  }
+  
+  if ((ccaps = [ua objectForKey:ClientCapsCacheKey]))
+    return ccaps;
+  
+  ccaps = [WEClientCapabilities alloc];
+  if ((ccaps = [ccaps initWithRequest:self]) == nil)
+    return nil;
+  ccaps = [ccaps autorelease];
+    
+  md = [ua mutableCopy];
+  [md setObject:ccaps forKey:ClientCapsCacheKey];
+  ua = [md copy];
+  [md release];
+  [self setUserInfo:ua];
+  [ua release];
+  return ccaps;
+}
+
+@end /* WORequest(ClientCapabilities) */
+
+static NSString *WEClientDetectorFormName = @"WEClientDetect";
+
+@implementation JSClientCapabilityDetector
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->formName   = OWGetProperty(_config, @"formName");
+    self->clientCaps = OWGetProperty(_config, @"clientCaps");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->formName   release];
+  [self->clientCaps release];
+  [super dealloc];
+}
+
+- (NSString *)_formNameInContext:(WOContext *)_ctx {
+  if (self->formName)
+    return [self->formName stringValueInComponent:[_ctx component]];
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![_ctx isInForm]) {
+    [[_ctx component]
+           logWithFormat:@"WARNING: you must use %@ inside a form !",
+             NSStringFromClass([self class])];
+    return;
+  }
+  
+  if (![[[_ctx request] clientCapabilities] isJavaScriptBrowser])
+    /* only works on JavaScript browsers ... */
+    return;
+  
+  [_response appendContentString:@"<input type='hidden' name='"];
+  [_response appendContentString:WEClientDetectorFormName];
+  [_response appendContentString:@"' value='browserConfig' />"];
+  
+  [_response appendContentString:@"<script language='JavaScript'>\n"];
+  [_response appendContentString:@"<!-- hide\n"];
+  
+  [_response appendContentString:@"// -->\n"];
+  [_response appendContentString:@"</script>"];
+}
+
+@end /* JSClientCapabilityDetector */
+
+/*
+  Netscape 4.76, Windows NT 4
+    'Mozilla/4.76 [en] (WinNT; U)'
+  
+  Netscape 6, Windows NT 4
+    'Mozilla/5.0 (Windows; U; WinNT4.0; en-US; m18) Gecko/20001108 Netscape6/6.0'
+  
+  Netscape Navigator 3.01[de], MacOS 8.1
+    'Mozilla/3.01 [de]-C-MACOS8 (Macintosh; I; PPC)'
+
+  Netscape Communicator 4.51, SuSE Linux 6.1
+    'Mozilla/4.51 [en] (X11; I; Linux 2.2.13 i686)'
+  
+  Mozilla M17, Windows NT 4
+    'Mozilla/5.0 (Windows; U; WinNT4.0; en-US; m17) Gecko/20000807'
+  
+  Internet Explorer 5.5, Windows NT 4
+    'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0)'
+  
+  Internet Explorer 3.0.1, MacOS 8.1
+    'Mozilla/3.0 (compatible; MSIE 3.0.1; Mac_PowerPC; Mac OS8)'
+    
+  Internet Explorer 5.0, MacOS 8.1
+    'Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC)'
+
+  Internet Explorer 5.0, SPARC Solaris 2.6 (trex)
+    'Mozilla/4.0 (compatible; MSIE 5.0; SunOS 5.6 sun4u; X11)'
+  
+  Konqueror/2.0, SuSE Linux 7.0
+    'Mozilla/5.0 (compatible; Konqueror/2.0; X11); Supports MD5-Digest; Supports gzip encoding'
+  
+  Lynx, SuSE Linux 6.1 (marvin)
+    'Lynx/2.8rel.2 libwww-FM/2.14'
+
+  Lynx, SPARC Solaris 2.6 (trex)
+    'Lynx/2.7 libwww-FM/2.14'
+  
+  Opera 4.02, Windows NT 4
+    'Mozilla/4.73 (Windows NT 4.0; U) Opera 4.02  [en]'
+  
+  Opera 5.0, Windows NT 4
+    'Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0) Opera 5.0  [en]'
+  
+  Amaya 4.0, Windows NT 4
+    'amaya/V4.0 libwww/5.3.1'
+  
+  XEmacs, SuSE Linux 6.1
+    'Emacs-W3/4.0pre.39 URL/p4.0pre.39 (i686-pc-linux; X11)'
+
+  XEmacs, SuSE Linux 7.2
+    'Emacs-W3/4.0pre.46 URL/p4.0pre.46 (i386-suse-linux; X11)'
+  
+  wget, SuSE Linux 6.1
+    'Wget/1.5.3'
+  
+  Windows 'WebFolder' NT4
+    'Microsoft Data Access Internet Publishing Provider Cache Manager'
+    'Mozilla/2.0 (compatible; MS FrontPage 4.0)'
+    'MSFrontPage/4.0'
+
+  Windows 98 IE 5 WebFolders
+    'Microsoft Data Access Internet Publishing Provider DAV'
+
+  OmniWeb
+    'OmniWeb/3.0.2 OWF/1999C'
+
+  Links, SuSE Linux 6.1 (marvin)
+    'Links (0.95; Linux 2.2.13 i686)'
+
+  Linux DAVFS
+    'DAV-FS/0.0.1'
+
+  MacOSX 10.0 DAVFS
+    fetch/1.0 Darwin/1.3.7 (Power Macintosh)
+
+  MacOSX 10.1.1 DAV FS
+    WebDAVFS/1.0 Darwin/5.1 (Power Macintosh)
+  
+  MacOSX 10.2.1 DAV FS
+    WebDAVFS/1.2.1 (01218000) Darwin/6.1 (Power Macintosh)
+  
+  Cadaver 0.17.0
+    'cadaver/0.17.0 neon/0.12.0-dev'
+  
+  Adobe GoLive 5
+    'GoLive/5. 0 [] (Windows 98; RATBERT)'
+
+  Dillo 0.6.2
+    - (very) small X11 web browser
+    'Dillo/0.6.1'
+  
+  Java SDK 1.3
+    'Java1.3.0'
+
+  Python 2.0
+    'Python-urllib/1.13'
+  
+  Apple MacOSX 10.2.1 / iCal 1.0 DAV Access Framework
+    'DAVAccess/1.0'
+  
+  Outlook 2000 on W2K with M$ Web Publishing Assistent
+    'Microsoft HTTP Post (RFC1867)'
+  
+  CURL program (libcurl)
+    'curl/7.9.8 (i686-suse-linux) libcurl 7.9.8 (OpenSSL 0.9.6g) (ipv6 enabled)'
+
+  Evolution 1.0.8 with Exchange Connector (WebDAV)
+    'Evolution/1.0.8'
+  
+  Outlook 2002 on W2K (HotMail HTTP access)
+    'Microsoft-Outlook/10.0 (TmstmpExt)'
+  
+  Outlook Express 5.5 on W2K (HotMail HTTP access)
+    'Outlook-Express/5.5 (MSIE 5.5; Windows NT 5.0; Q312461; T312461; TmstmpExt)'
+  
+  Outlook Express 6.0 on W2K (HotMail HTTP access)
+    'Outlook-Express/6.0 (MSIE 6.0; Windows NT 5.0; Q312461; T312461; TmstmpExt)'
+
+  Nautilus (GNOME Virtual Filesystem)
+    'gnome-vfs/1.0.5'
+  
+  Konqueror 3.0.3 (SuSE 8.1)
+    - does not send a user-agent in webdav:// mode !
+
+  ZideLook 0.0
+    'neon/0.23.5 NeonConnection 0.0'
+
+  Safari v74 (MacOSX 10.2)
+    'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/74 (KHTML, like Gecko) Safari/74'
+    - why does it say Mozilla/5.0 ??
+
+  Evolution 1.4.0 with Exchange Connector 1.4.0 (SuSE 8.2)
+    'Evolution/1.4.0'
+    
+  Mozilla Firebird 0.6 (MacOSX 10.2)
+    'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6'
+
+  SOUP (Evo OGo Connector by Anders)
+    'Soup/1.99.24'
+
+  Entourage/X (Entourage WebDAV 10.1.4, MacOSX)
+    'Entourage/10.0 (Mac_PowerPC; DigExt; TmstmpExt)'
+  
+  Some unknown iCal.app
+    'DAVKit/0.1'
+
+  NetNewsWire full version: 
+    'NetNewsWire/1.0.5 (Mac OS X; http://ranchero.com/netnewswire/)'
+  
+  NetNewsWire lite version: 
+    'NetNewsWire/1.0.3 (Mac OS X; Lite; http://ranchero.com/netnewswire/)'
+
+  Python xmlrpclib:
+    'xmlrpclib.py/1.0.0 (by www.pythonware.com)'
+
+  Windows 2000 IE 6 WebFolders
+    'Microsoft Data Access Internet Publishing Provider DAV 1.1'
+
+  Morgul, Windows WebDAV client
+    'Morgul'
+
+  Apple iSync v122 / CoreFoundation Network
+    'CFNetwork/1.1'
+
+  Kung-Log (WebServicesCore)
+    'Kung-Log/1.3 (Macintosh; U; PPC Mac OS X) WebServicesCore'
+
+  Ecto (WebServicesCore)
+    'ecto (Macintosh; U; PPC Mac OS X) WebServicesCore'
+*/
diff --git a/skyrix-sope/NGObjWeb/WOAdaptor.m b/skyrix-sope/NGObjWeb/WOAdaptor.m
new file mode 100644 (file)
index 0000000..f3c72f1
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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: WOAdaptor.m,v 1.18 2000/10/11 10:06:15 helge Exp $
+
+#include <NGObjWeb/WOAdaptor.h>
+#include "common.h"
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (void)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+@implementation WOAdaptor
+
++ (int)version {
+  return 1;
+}
+
+- (id)initWithName:(NSString *)_name arguments:(NSDictionary *)_args
+  application:(WOCoreApplication *)_application
+{
+  if ((self = [super init])) {
+    self->application = _application;
+    self->name        = [_name copyWithZone:[self zone]];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  self->application = nil;
+  [self->name release];
+  [super dealloc];
+}
+
+- (void)registerForEvents {
+  [self subclassResponsibility:_cmd];
+}
+- (void)unregisterForEvents {
+  [self subclassResponsibility:_cmd];
+}
+
+@end /* WOAdaptor */
diff --git a/skyrix-sope/NGObjWeb/WOApplication+defaults.m b/skyrix-sope/NGObjWeb/WOApplication+defaults.m
new file mode 100644 (file)
index 0000000..2a5f8e8
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@interface WOApplication(DefaultsPrivates)
++ (NSUserDefaults *)userDefaults;
+@end
+
+@implementation WOApplication(Defaults)
+
+static NSString *ck = nil;
+static NSString *dk = nil;
+
++ (void)setComponentRequestHandlerKey:(NSString *)_key {
+  [[self userDefaults]
+         setObject:_key
+         forKey:@"WOComponentRequestHandlerKey"];
+  [ck release]; ck = nil;
+}
++ (NSString *)componentRequestHandlerKey {
+  if (ck == nil)
+    ck = [[[self userDefaults] stringForKey:@"WOComponentRequestHandlerKey"]
+          copy];
+  return ck;
+}
+
++ (void)setDirectActionRequestHandlerKey:(NSString *)_key {
+  [[self userDefaults]
+         setObject:_key
+         forKey:@"WODirectActionRequestHandlerKey"];
+  [dk release]; dk = nil;
+}
++ (NSString *)directActionRequestHandlerKey {
+  if (dk == nil) {
+    dk = [[[self userDefaults] 
+      stringForKey:@"WODirectActionRequestHandlerKey"] copy];
+  }
+  return dk;
+}
+
++ (void)setResourceRequestHandlerKey:(NSString *)_key {
+  [[self userDefaults] setObject:_key forKey:@"WOResourceRequestHandlerKey"];
+}
++ (NSString *)resourceRequestHandlerKey {
+  return [[self userDefaults] stringForKey:@"WOResourceRequestHandlerKey"];
+}
+
+/* WODefaultSessionTimeOut */
+
++ (void)setSessionTimeOut:(NSNumber *)_timeOut {
+  [[self userDefaults] setObject:_timeOut forKey:@"WODefaultSessionTimeOut"];
+}
+
++ (NSNumber *)sessionTimeOut {
+  NSUserDefaults *ud;
+  id o;
+
+  ud = [self userDefaults];
+  // Note: the second check is *intended* (Timeout vs TimeOut), it is
+  //       required for compatibility but should be phased out in the
+  //       long run. I don't know the proper default-name out of my
+  //       head (needs to be checked)
+  o  = [ud objectForKey:@"WODefaultSessionTimeout"];
+  if (o == nil) o = [ud objectForKey:@"WODefaultSessionTimeOut"];
+  return [NSNumber numberWithInt:[o intValue]];
+}
+
+/* WOCachingEnabled */
+
++ (BOOL)isCachingEnabled {
+  return [[[self userDefaults]
+                 objectForKey:@"WOCachingEnabled"]
+                 boolValue];
+}
+
+/* WODebuggingEnabled */
+
++ (BOOL)isDebuggingEnabled {
+  return [[[self userDefaults]
+                 objectForKey:@"WODebuggingEnabled"]
+                 boolValue];
+}
+
+/* WOCompatibility */
+
+static BOOL directConnectEnabled = YES;
+
++ (void)setDirectConnectEnabled:(BOOL)_flag {
+  directConnectEnabled = _flag;
+}
++ (BOOL)isDirectConnectEnabled {
+  return directConnectEnabled;
+}
+
++ (void)setCGIAdaptorURL:(NSString *)_url {
+  [[self userDefaults] setObject:_url forKey:@"WOCGIAdaptorURL"];
+}
++ (NSString *)cgiAdaptorURL {
+  return [[self userDefaults] stringForKey:@"WOCGIAdaptorURL"];
+}
+
+/* WOAutoOpenInBrowser */
+
++ (void) setAutoOpenInBrowser:(BOOL)_flag {
+  [[self userDefaults] setBool:_flag forKey:@"WOAutoOpenInBrowser"];
+}
++ (BOOL)autoOpenInBrowser {
+  return [[self userDefaults] boolForKey:@"WOAutoOpenInBrowser"];
+}
+
+/* WOApplicationBaseURL */
+
++ (void)setApplicationBaseURL:(NSString *)_url {
+  [[self userDefaults] setObject:_url forKey:@"WOApplicationBaseURL"];
+}
++ (NSString *)applicationBaseURL {
+  return [[self userDefaults] stringForKey:@"WOApplicationBaseURL"];
+}
+
+/* WOFrameworksBaseURL */
+
++ (void)setFrameworksBaseURL:(NSString *)_url {
+  [[self userDefaults] setObject:_url forKey:@"WOFrameworksBaseURL"];
+}
++ (NSString *)frameworksBaseURL {
+  return [[self userDefaults] stringForKey:@"WOFrameworksBaseURL"];
+}
+
+@end /* WOApplication(Defaults) */
diff --git a/skyrix-sope/NGObjWeb/WOApplication+private.h b/skyrix-sope/NGObjWeb/WOApplication+private.h
new file mode 100644 (file)
index 0000000..b070e60
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOApplication_private_H__
+#define __NGObjWeb_WOApplication_private_H__
+
+#include <NGObjWeb/WOApplication.h>
+#include <DOM/DOMDocument.h>
+
+@class WOContext, WOSession;
+@class WOxElemBuilder;
+
+@interface WOApplication(PrivateMethods)
+
+- (WOSession *)_initializeSessionInContext:(WOContext *)_ctx;
+
+@end
+
+@interface WOApplication(BuilderStack)
+
+- (WOxElemBuilder *)builderForDocument:(id<DOMDocument>)_document;
+
+@end
+
+#endif /* __NGObjWeb_WOApplication_private_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOApplication.m b/skyrix-sope/NGObjWeb/WOApplication.m
new file mode 100644 (file)
index 0000000..7732412
--- /dev/null
@@ -0,0 +1,1231 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOApplication.h>
+#include "WOContext+private.h"
+#include "WOElement+private.h"
+#include "WOComponent+private.h"
+#include <NGObjWeb/WOAdaptor.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WORequestHandler.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOSessionStore.h>
+#include <NGObjWeb/WOStatisticsStore.h>
+#include <NGObjWeb/WODynamicElement.h>
+#include <NGObjWeb/WOTemplate.h>
+#import <EOControl/EOControl.h>
+#include "common.h"
+#include <time.h>
+
+@interface WOApplication(PrivateMethods)
+- (id)_loadComponentDefinitionWithName:(NSString *)_name
+  language:(NSArray *)_langs;
+- (NSDictionary *)memoryStatistics;
+@end
+
+static NSRecursiveLock *classLock = nil;
+static BOOL  perflog     = NO;
+static Class NSDateClass = Nil;
+static Class WOTemplateClass = Nil;
+static BOOL  debugOn     = NO;
+static NSString *rapidTurnAroundPath = nil;
+
+@interface WOSessionStore(SnStore)
+- (void)performExpirationCheck:(NSTimer *)_timer;
+@end
+
+@implementation WOApplication
+
++ (int)version {
+  return [super version] + 5 /* v6 */;
+}
+
++ (void)_setupSNS {
+  Class clazz;
+  id c;
+  
+  clazz = NSClassFromString(@"SNSConnection");
+  c = [(id<NSObject>)clazz performSelector:@selector(defaultSNSConnection)];
+
+  if (c == nil) {
+    NSLog(@"could not connect SNS, exiting ..");
+    exit(20);
+  }
+  
+  NSLog(@"SNS enabled");
+}
+
++ (void)_initializeWOApp {
+  static BOOL isInitialized = NO;
+  NSAutoreleasePool *pool;
+  NSUserDefaults    *ud;
+  
+  if (isInitialized) return;
+
+  isInitialized = YES;
+
+  pool = [[NSAutoreleasePool alloc] init];
+  debugOn = [WOApplication isDebuggingEnabled];
+  
+  if (classLock == nil) classLock = [[NSRecursiveLock alloc] init];
+  ud = [NSUserDefaults standardUserDefaults];
+  
+  /* setup SNSConnection */
+  
+  if ([ud boolForKey:@"WOContactSNS"])
+    [self _setupSNS];
+  else
+    NSLog(@"SNS support disabled.");
+  
+  NSDateClass = [NSDate class];
+  WOTemplateClass = [WOTemplate class];
+
+  perflog               = [ud boolForKey:@"WOProfileApplication"];
+  rapidTurnAroundPath   = [[ud stringForKey:@"WOProjectDirectory"] copy];
+
+  [pool release];
+}
+
+/* old license checks */
+
+- (NSCalendarDate *)appExpireDate {
+  // TODO: can we remove that?
+  return nil;
+}
+- (BOOL)isLicenseExpired {
+  // TODO: can we remove that?
+  return NO;
+}
+
+/* app path */
+
+- (NSString *)_lookupAppPath {
+  static NSString *suffix = nil;
+  static BOOL    appPathMissing = NO;
+  NSUserDefaults *ud;
+  NSFileManager  *fm;
+  NSString       *cwd;
+  NSString       *result;
+  
+  if (appPathMissing)
+    return nil;
+
+  ud = [NSUserDefaults standardUserDefaults];
+  
+  // Check if appPath has been forced
+  result = [ud stringForKey:@"WOProjectDirectory"];
+  if(result != nil)
+      return result;
+
+  if (suffix == nil)
+    suffix = [ud stringForKey:@"WOApplicationSuffix"];
+  
+  fm  = [NSFileManager defaultManager];
+  cwd = [fm currentDirectoryPath];
+  
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+  result = [[NGBundle mainBundle] bundlePath];
+  //NSLog(@"%s: check path '%@'", __PRETTY_FUNCTION__, result);
+#else
+  result = cwd;
+#endif
+
+  if ([result hasSuffix:suffix]) {
+    /* started app inside of .woa directory */
+#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+    result = [[NGBundle mainBundle] bundlePath];
+#else
+    result = cwd;
+#endif
+  }
+  else {
+    NSString *wrapperName;
+    
+    wrapperName = [self->name stringByAppendingString:suffix];
+    
+    /* take a look whether ./AppName.woa exists */
+    result = [result stringByAppendingPathComponent:wrapperName];
+    if (![fm fileExistsAtPath:result]) {
+      /* lookup in process-path */
+      NSString *ppath;
+      
+      ppath = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0];
+      ppath = [ppath stringByDeletingLastPathComponent]; // del exe-name
+      ppath = [ppath stringByDeletingLastPathComponent]; // lib-combo
+      ppath = [ppath stringByDeletingLastPathComponent]; // os
+      ppath = [ppath stringByDeletingLastPathComponent]; // cpu
+
+      if ([ppath hasSuffix:suffix])
+        result = ppath;
+    }
+  }
+  
+  if (![fm fileExistsAtPath:result]) {
+    [self debugWithFormat:@"%s: missing path '%@'", 
+           __PRETTY_FUNCTION__, result];
+    appPathMissing = YES;
+    result = nil;
+  }
+
+  return result;
+}
+
++ (NSString *)defaultRequestHandlerClassName {
+  return @"WOComponentRequestHandler";
+}
+
+- (void)_logDefaults {
+  NSUserDefaults *ud;
+  NSArray        *keys;
+  NSEnumerator   *e;
+  NSString       *key;
+
+  ud   = [NSUserDefaults standardUserDefaults];
+  keys = [[ud dictionaryRepresentation] allKeys];
+  keys = [keys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
+
+  e    = [keys objectEnumerator];
+  while((key = [e nextObject]) != nil) {
+    if ([key hasPrefix:@"WO"] || [key isEqualToString:@"NSProjectSearchPath"])
+      NSLog(@"%@ = %@", key, [[ud objectForKey:key] description]);
+  }
+}
+
+- (id)initWithName:(NSString *)_name {
+  [WOApplication _initializeWOApp];
+  
+  if ((self = [super init])) {
+    NSUserDefaults   *ud;
+    WORequestHandler *rh;
+    NSString *rk;
+    
+    self->name = [_name copy];
+    
+    ud = [NSUserDefaults standardUserDefaults];
+    
+    [self setPageCacheSize:[ud integerForKey:@"WOPageCacheSize"]];
+    [self setPermanentPageCacheSize:
+            [ud integerForKey:@"WOPermanentPageCacheSize"]];
+    
+    [self setPageRefreshOnBacktrackEnabled:
+            [[ud objectForKey:@"WOPageRefreshOnBacktrack"] boolValue]];
+    
+    [self setCachingEnabled:[WOApplication isCachingEnabled]];
+    
+    /* setup request handlers */
+    
+    self->defaultRequestHandler =
+      [[NSClassFromString([[self class] defaultRequestHandlerClassName]) alloc] init];
+    
+    self->requestHandlerRegistry =
+      NSCreateMapTable(NSObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 8);
+    
+    rk = [WOApplication componentRequestHandlerKey];
+#if 1
+    rh = [[NSClassFromString(@"OWViewRequestHandler") alloc] init];
+#else
+    rh = [[NSClassFromString(@"WOComponentRequestHandler") alloc] init];
+#endif
+    if ([rk length] > 0 && (rh != nil))
+      [self registerRequestHandler:rh forKey:rk];
+    [rh release]; rh = nil;
+    
+    rk = [WOApplication directActionRequestHandlerKey];
+    rh = [[NSClassFromString(@"WODirectActionRequestHandler") alloc] init];
+    if ([rk length] > 0 && rh != nil)
+      [self registerRequestHandler:rh forKey:rk];
+    [rh release]; rh = nil;
+    
+    if ((rh = [[NSClassFromString(@"WOResourceRequestHandler") alloc] init])) {
+      rk = [WOApplication resourceRequestHandlerKey];
+      if ([rk length] > 0)
+        [self registerRequestHandler:rh forKey:rk];
+      [self registerRequestHandler:rh forKey:@"WebServerResources"];
+#ifdef __APPLE__
+      [self registerRequestHandler:rh forKey:@"Resources"];
+#endif
+      [rh release]; rh = nil;
+    }
+
+    /* setup session store */
+    
+    self->iSessionStore =
+      [[NSClassFromString([self sessionStoreClassName]) alloc] init];
+    
+    /* setup statistics store */
+    
+    self->iStatisticsStore = [[WOStatisticsStore alloc] init];
+    
+    /* register timers */
+    self->expirationTimer =
+      [[NSTimer scheduledTimerWithTimeInterval:
+                  [[ud objectForKey:@"WOExpirationTimeInterval"] intValue]
+                target:self
+                selector:@selector(performExpirationCheck:)
+                userInfo:nil
+                repeats:YES]
+                retain];
+    
+    if ([ud boolForKey:@"WOLogDefaultsOnStartup"])
+      [self _logDefaults];
+    
+    [[NSNotificationCenter defaultCenter]
+                           postNotificationName:
+                             WOApplicationWillFinishLaunchingNotification
+                           object:self];
+  }
+  return self;
+}
+
+- (id)init {
+  return [self initWithName:[[[NSProcessInfo processInfo]
+                                             processName]
+                                             stringByDeletingPathExtension]];
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  
+  [self->expirationTimer invalidate];
+
+  if (self->requestHandlerRegistry)
+    NSFreeMapTable(self->requestHandlerRegistry);
+  
+  [self->expirationTimer release];
+  [self->resourceManager release];
+  [self->iSessionStore   release];
+  [self->defaultRequestHandler release];
+  [self->path            release];
+  [self->name            release];
+  [self->instanceNumber  release];
+  [super dealloc];
+}
+
+- (void)processHupSignal:(int)_signal {
+  /* this isn't called immediatly */
+  [self logWithFormat:@"terminating on SIGHUP ..."];
+  [self terminate];
+}
+
+/* accessors */
+
+- (NSString *)name {
+  return self->name;
+}
+- (BOOL)monitoringEnabled {
+  return NO;
+}
+- (NSString *)path {
+  static BOOL missingPath = NO;
+  if (missingPath) return nil;
+  if (self->path == nil) {
+    if ((self->path = [[self _lookupAppPath] copy]) == nil) {
+      if (debugOn) {
+       [self debugWithFormat:
+               @"WARNING: could not find wrapper of application !"];
+      }
+      missingPath = YES;
+      return nil;
+    }
+  }
+  return self->path;
+}
+
+- (NSString *)number {
+  if (self->instanceNumber == nil) {
+    id num;
+      
+    if ((num = [[NSUserDefaults standardUserDefaults] objectForKey:@"n"])) {
+      self->instanceNumber = [[num stringValue] copy];
+    }
+    else {
+      unsigned pid;
+#if defined(__MINGW32__)
+      pid = (unsigned)GetCurrentProcessId();
+#else                     
+      pid = (unsigned)getpid();
+#endif
+      self->instanceNumber = [[NSString alloc] initWithFormat:@"%d", pid];
+    }
+  }
+  return self->instanceNumber;
+}
+
+- (WOContext *)context {
+  // deprecated in WO4
+  NSThread     *t;
+  NSDictionary *td;
+  
+  if ((t = [NSThread currentThread]) == nil) {
+    [self logWithFormat:@"ERROR: missing current thread !!!"];
+    return nil;
+  }
+  if ((td = [t threadDictionary]) == nil) {
+    [self logWithFormat:
+            @"ERROR: missing current thread's dictionary (thread=%@) !!!",
+            t];
+    return nil;
+  }
+  
+  return [td objectForKey:@"WOContext"];
+}
+
+/* request handlers */
+
+- (void)registerRequestHandler:(WORequestHandler *)_hdl
+  forKey:(NSString *)_key
+{
+  [self lock];
+  NSMapInsert(self->requestHandlerRegistry, _key, _hdl);
+  [self unlock];
+}
+- (void)removeRequestHandlerForKey:(NSString *)_key {
+  if (_key == nil) return;
+  [self lock];
+  NSMapRemove(self->requestHandlerRegistry, _key);
+  [self unlock];
+}
+
+- (void)setDefaultRequestHandler:(WORequestHandler *)_hdl {
+  [self lock];
+  ASSIGN(self->defaultRequestHandler, _hdl);
+  [self unlock];
+}
+- (WORequestHandler *)defaultRequestHandler {
+  return self->defaultRequestHandler;
+}
+- (WORequestHandler *)requestHandlerForKey:(NSString *)_key {
+  WORequestHandler *handler;
+  
+  [self lock];
+  handler = [(id)NSMapGet(self->requestHandlerRegistry, _key) retain];
+  if (handler == nil)
+    handler = [[self defaultRequestHandler] retain];
+  [self unlock];
+  
+  return [handler autorelease];
+}
+
+- (NSArray *)registeredRequestHandlerKeys {
+  NSMutableArray   *array = [NSMutableArray arrayWithCapacity:16];
+  NSMapEnumerator  e;
+  NSString         *key;
+  WORequestHandler *handler;
+  
+  [self lock];
+  e = NSEnumerateMapTable(self->requestHandlerRegistry);
+  while (NSNextMapEnumeratorPair(&e, (void**)&key, (void**)&handler))
+    [array addObject:key];
+  [self unlock];
+  
+  return [[array copy] autorelease];
+}
+
+- (WORequestHandler *)handlerForRequest:(WORequest *)_request {
+  WORequestHandler *handler;
+  NSString         *key;
+  
+  if ((key = [_request requestHandlerKey]) == nil)
+    return [self defaultRequestHandler];
+  
+  handler = NSMapGet(self->requestHandlerRegistry, key);
+  return (handler != nil) ? handler : [self defaultRequestHandler];
+}
+
+/* sessions */
+
+- (WOSession *)_initializeSessionInContext:(WOContext *)_ctx {
+  WOSession *sn;
+
+  sn = [self createSessionForRequest:[_ctx request]];
+  [_ctx setSession:sn];
+  
+  if ([sn respondsToSelector:@selector(prepare)]) {
+#if DEBUG
+    [self debugWithFormat:@"calling -prepare on session .."];
+#endif
+    [sn performSelector:@selector(prepare)];
+  }
+
+  [sn _awakeWithContext:_ctx];
+  
+  [[NSNotificationCenter defaultCenter]
+                         postNotificationName:WOSessionDidCreateNotification
+                         object:sn];
+  return [sn autorelease];
+}
+
+- (NSString *)sessionIDFromRequest:(WORequest *)_request {
+  NSString *sessionId;
+  
+  if (_request == nil) return nil;
+  
+  /* first look into form values */
+  if ((sessionId = [_request formValueForKey:WORequestValueSessionID])) {
+    if ([sessionId length] > 0)
+      return sessionId;
+  }
+  
+  /* now look into the cookies */
+  if ((sessionId = [_request cookieValueForKey:[self name]])) {
+    if ([sessionId respondsToSelector:@selector(objectEnumerator)]) {
+      NSEnumerator *e;
+      
+      e = [(id)sessionId objectEnumerator];
+      while ((sessionId = [e nextObject])) {
+        if ([sessionId length] > 0 && ![sessionId isEqual:@"nil"])
+          return sessionId;
+      }
+    }
+    else {
+      if ([sessionId length] > 0 && ![sessionId isEqual:@"nil"])
+        return sessionId;
+    }
+  }
+  
+  return nil;
+}
+
+- (NSString *)createSessionIDForSession:(WOSession *)_session {
+  /* session id must be 18 chars long for snsd to work ! */
+  static unsigned int sessionCount = 0;
+  NSString *wosid;
+  unsigned char buf[20];
+  
+  sessionCount++;
+  sprintf(buf, "%04X%04X%02X%08X",
+          [[self number] intValue], getpid(), sessionCount, 
+          (unsigned int)time(NULL));
+  wosid = [NSString stringWithCString:buf];
+  return wosid;
+}
+
+- (WOSession *)createSessionForRequest:(WORequest *)_request {
+  if ([self respondsToSelector:@selector(createSession)]) {
+    /* call deprecated method */
+    NSLog(@"WARNING: calling deprecated -createSession ..");
+    return [self createSession];
+  }
+  else {
+    Class snClass = Nil;
+    
+    if ((snClass = NSClassFromString(@"Session")) == Nil)
+      snClass = [WOSession class];
+    
+    return [[snClass alloc] init];
+  }
+}
+
+- (WOSession *)restoreSessionWithID:(NSString *)_sid
+  inContext:(WOContext *)_ctx
+{
+  WOSession *session;
+  
+  *(&session) = nil;
+
+  if ([self respondsToSelector:@selector(restoreSession)]) {
+    /* call deprecated method */
+    NSLog(@"WARNING: calling deprecated -restoreSession ..");
+    return [self restoreSession];
+  }
+  
+  SYNCHRONIZED(self) {
+    WOSessionStore *store;
+    
+    if ((store = [self sessionStore]) == nil) {
+      [self logWithFormat:@"missing session store ..."];
+    }
+    else {
+      session = [store restoreSessionWithID:_sid request:[_ctx request]];
+      if (session) {
+        [_ctx setSession:session];
+        [session _awakeWithContext:_ctx];
+      }
+      else {
+        [self debugWithFormat:@"did not find a session for sid '%@'", _sid];
+      }
+    }
+  }
+  END_SYNCHRONIZED;
+  
+  if (session) {
+    [[NSNotificationCenter defaultCenter]
+                           postNotificationName:WOSessionDidRestoreNotification
+                           object:session];
+  }
+  else {
+    if ([_sid hasPrefix:@"("]) {
+      id sid;
+
+      sid = [_sid propertyList];
+      
+      if ([sid respondsToSelector:@selector(objectEnumerator)]) {
+        NSEnumerator *e;
+        
+        [self logWithFormat:@"got multiple session IDs !"];
+        
+        e = [sid objectEnumerator];
+        while ((_sid = [e nextObject])) {
+          if ([_sid isEqualToString:@"nil"])
+            continue;
+          
+          if ((session = [self restoreSessionWithID:_sid inContext:_ctx]))
+            return session;
+          
+          //NSLog(@"WARNING: did not find session for sid %@", _sid);
+        }
+      }
+    }
+  }
+  return session;
+}
+- (void)saveSessionForContext:(WOContext *)_ctx {
+  NSTimeInterval startSave = 0.0;
+
+  if (perflog)
+    startSave = [[NSDateClass date] timeIntervalSince1970];
+  
+  if ([self respondsToSelector:@selector(saveSession:)]) {
+    /* call deprecated method */
+    NSLog(@"WARNING: calling deprecated -saveSession: ..");
+    [self saveSession:[_ctx session]];
+    return;
+  }
+  
+  SYNCHRONIZED(self) {
+    WOSession     *sn;
+    NSTimeInterval startSnSleep = 0.0, startStore = 0.0;
+    
+    sn = [_ctx session];
+
+    if (perflog)
+      startSnSleep = [[NSDateClass date] timeIntervalSince1970];
+    
+    /* put session to sleep */
+    [sn _sleepWithContext:_ctx];
+    
+    if (perflog) {
+      NSTimeInterval rt;
+      rt = [[NSDateClass date] timeIntervalSince1970] - startSnSleep;
+      NSLog(@"  [woapp]: session -sleep took %4.3fs.",
+            rt < 0.0 ? -1.0 : rt);
+    }
+    
+    if ([sn isTerminating]) {
+      [[NSNotificationCenter defaultCenter]
+                             postNotificationName:
+                               WOSessionDidTerminateNotification
+                             object:sn];
+    }
+    
+    if (perflog)
+      startStore = [[NSDateClass date] timeIntervalSince1970];
+    
+    [[self sessionStore] saveSessionForContext:_ctx];
+    
+    if (perflog) {
+      NSTimeInterval rt;
+      rt = [[NSDateClass date] timeIntervalSince1970] - startStore;
+      NSLog(@"  [woapp]: storing sn in store took %4.3fs.",
+            rt < 0.0 ? -1.0 : rt);
+    }
+  }
+  END_SYNCHRONIZED;
+
+  if (perflog) {
+    NSTimeInterval rt;
+    rt = [[NSDateClass date] timeIntervalSince1970] - startSave;
+    NSLog(@"[woapp]: saveSessionForContext took %4.3fs.",
+          rt < 0.0 ? -1.0 : rt);
+  }
+}
+
+- (void)refuseNewSessions:(BOOL)_flag {
+  self->appFlags.doesRefuseNewSessions = _flag ? 1 : 0;
+}
+- (BOOL)isRefusingNewSessions {
+  return self->appFlags.doesRefuseNewSessions;
+}
+- (int)activeSessionsCount {
+  return [[self sessionStore] activeSessionsCount];
+}
+
+- (void)setSessionStore:(WOSessionStore *)_store {
+  ASSIGN(self->iSessionStore, _store);
+}
+- (NSString *)sessionStoreClassName {
+  return [[NSUserDefaults standardUserDefaults] stringForKey:@"WOSessionStore"];
+}
+- (WOSessionStore *)sessionStore {
+  return self->iSessionStore;
+}
+
+- (void)setMinimumActiveSessionsCount:(int)_minimum {
+  self->minimumActiveSessionsCount = _minimum;
+}
+- (int)minimumActiveSessionsCount {
+  return self->minimumActiveSessionsCount;
+}
+
+- (void)performExpirationCheck:(NSTimer *)_timer {
+  WOSessionStore *ss;
+
+  /* let session store check for expiration ... */
+  
+  ss = [self sessionStore];
+  if ([ss respondsToSelector:@selector(performExpirationCheck:)])
+    [ss performExpirationCheck:_timer];
+  
+  /* check whether application should terminate ... */
+
+  if ([self isRefusingNewSessions] &&
+      ([self activeSessionsCount] < [self minimumActiveSessionsCount])) {
+    /* check whether the application instance is still valid .. */
+    [self debugWithFormat:
+            @"application terminates because it refuses new sessions and "
+            @"the active session count (%i) is below the minimum (%i).",
+            [self activeSessionsCount], [self minimumActiveSessionsCount]];
+    [self terminate];
+  }
+}
+
+- (WOSession *)session {
+  return [[self context] session];
+}
+
+- (WOResponse *)handleSessionCreationErrorInContext:(WOContext *)_ctx {
+  WOResponse *response = [_ctx response];
+  unsigned pid;
+  
+#ifdef __MINGW32__
+  pid = GetCurrentProcessId();
+#else
+  pid = getpid();
+#endif
+  
+  if ([self respondsToSelector:@selector(handleSessionCreationError)]) {
+    NSLog(@"WARNING: called deprecated -handleSessionCreationError method");
+    return [self handleSessionCreationError];
+  }
+  
+  [self logWithFormat:@"could not create session for context %@", _ctx];
+  
+  [response setStatus:200];
+  [response appendContentString:@"<h4>Session Creation Error</h4>\n<pre>"];
+  [response appendContentString:
+              @"Application Instance failed to create session."];
+  [response appendContentHTMLString:
+              [NSString stringWithFormat:
+                          @"   application: %@\n"
+                          @"   adaptor:     %@\n"
+                          @"   baseURL:     %@\n"
+                          @"   contextID:   %@\n"
+                          @"   instance:    %i\n"
+                          @"   request:     %@\n",
+                          [self name],
+                          [[_ctx request] adaptorPrefix],
+                          [self baseURL],
+                          [_ctx contextID],
+                          pid,
+                          [[_ctx request] description]]];
+  [response appendContentString:@"</pre>"];
+  return response;
+}
+
+- (WOResponse *)handleSessionRestorationErrorInContext:(WOContext *)_ctx {
+  if ([self respondsToSelector:@selector(handleSessionRestorationError)]) {
+    NSLog(@"WARNING: calling deprecated -handleSessionRestorationError "
+         @"method");
+    return [self handleSessionRestorationError];
+  }
+  
+  [self logWithFormat:@"could not restore session for context %@", _ctx];
+  return nil;
+}
+
+/* statistics */
+
+- (void)setStatisticsStore:(WOStatisticsStore *)_statStore {
+  ASSIGN(self->iStatisticsStore, _statStore);
+}
+- (WOStatisticsStore *)statisticsStore {
+  return self->iStatisticsStore;
+}
+
+- (bycopy NSDictionary *)statistics {
+  return [[self statisticsStore] statistics];
+}
+
+/* resources */
+
+- (void)setResourceManager:(WOResourceManager *)_manager {
+  ASSIGN(self->resourceManager, _manager);
+}
+- (WOResourceManager *)resourceManager {
+  if (self->resourceManager == nil) {
+    NSString *p;
+
+#if 0 && DEBUG
+    if ([(p = [self path]) length] > 0)
+      [self logWithFormat:@"setup WOResourceManager at path '%@' ...", p];
+#else
+    p = [self path];
+#endif
+    
+    self->resourceManager = 
+      [(WOResourceManager *)[WOResourceManager alloc] initWithPath:p];
+  }
+  return self->resourceManager;
+}
+
+- (NSURL *)baseURL {
+  NSString  *n;
+  WOContext *ctx = [self context];
+  
+  n = [[ctx request] applicationName];
+  n = [@"/" stringByAppendingString:n ? n : [self name]];
+  
+  return [NSURL URLWithString:n relativeToURL:[ctx baseURL]];
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
+  IS_DEPRECATED;
+  return [[self resourceManager] pathForResourceNamed:_name ofType:_type];
+}
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_default
+{
+  IS_DEPRECATED;
+  return [[self resourceManager] stringForKey:_key
+                                 inTableNamed:_tableName
+                                 withDefaultValue:_default
+                                 languages:
+                                   [(WOSession *)[self session] languages]];
+}
+
+/* notifications */
+
+- (void)awake {
+}
+- (void)sleep {
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  if ([_ctx hasSession])
+    [[_ctx session] takeValuesFromRequest:_req inContext:_ctx];
+  else {
+    WOComponent *page;
+    
+    if ((page = [_ctx page])) {
+      WOContext_enterComponent(_ctx, page, nil);
+      [page takeValuesFromRequest:_req inContext:_ctx];
+      WOContext_leaveComponent(_ctx, page);
+    }
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  id result;
+  
+  if ([_ctx hasSession])
+    result = [[_ctx session] invokeActionForRequest:_rq inContext:_ctx];
+  else {
+    WOComponent *page;
+    
+    if ((page = [_ctx page])) {
+      WOContext_enterComponent(_ctx, page, nil);
+      result = [[_ctx page] invokeActionForRequest:_rq inContext:_ctx];
+      WOContext_leaveComponent(_ctx, page);
+    }
+    else
+      result = nil;
+  }
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if ([_ctx hasSession])
+    [[_ctx session] appendToResponse:_response inContext:_ctx];
+  else {
+    WOComponent *page;
+    
+    if ((page = [_ctx page])) {
+      WOContext_enterComponent(_ctx, page, nil);
+      [page appendToResponse:_response inContext:_ctx];
+      WOContext_leaveComponent(_ctx, page);
+    }
+  }
+
+  if(rapidTurnAroundPath != nil) {
+      WOComponent *page;
+      
+      if((page = [_ctx page])) {
+          WOElement *template;
+          
+          template = [page _woComponentTemplate];
+          if([template isKindOfClass:WOTemplateClass]) {
+              NSString *_path;
+              
+              _path = [[(WOTemplate *)template url] path];
+              [_response setHeader:_path
+                            forKey:@"x-sope-template-path"];
+          }
+
+      }
+  }
+}
+
+// dynamic elements
+
+- (WOElement *)dynamicElementWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  template:(WOElement *)_template
+  languages:(NSArray *)_languages
+{
+  WOElement *element            = nil;
+  Class     dynamicElementClass = NSClassFromString(_name);
+
+  if (dynamicElementClass == Nil) {
+    NSLog(@"WARNING: did not find dynamic element class %@ !", _name);
+    return nil;
+  }
+  if (![dynamicElementClass isDynamicElement]) {
+    NSLog(@"WARNING: class %@ is not a dynamic element class !", _name);
+    return nil;
+  }
+  
+  element = [[dynamicElementClass allocWithZone:[_template zone]]
+                                  initWithName:_name
+                                  associations:_associations
+                                  template:_template];
+  return element;
+}
+- (WOElement *)dynamicElementWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  template:(WOElement *)_template
+{
+  return [self dynamicElementWithName:_name
+               associations:_associations
+               template:_template
+               languages:[(WOSession *)[self session] languages]];
+}
+
+// pages
+
+- (void)setPageRefreshOnBacktrackEnabled:(BOOL)_flag {
+  self->appFlags.isPageRefreshOnBacktrackEnabled = _flag ? 1 : 0;
+}
+- (BOOL)isPageRefreshOnBacktrackEnabled {
+  return self->appFlags.isPageRefreshOnBacktrackEnabled ? YES : NO;
+}
+
+- (void)setCachingEnabled:(BOOL)_flag {
+  self->appFlags.isCachingEnabled = _flag ? 1 : 0;
+}
+- (BOOL)isCachingEnabled {
+  // component definition caching
+  return self->appFlags.isCachingEnabled ? YES : NO;
+}
+
+- (void)setPageCacheSize:(int)_size {
+  self->pageCacheSize = _size;
+}
+- (int)pageCacheSize {
+  return self->pageCacheSize;
+}
+- (void)setPermanentPageCacheSize:(int)_size {
+  self->permanentPageCacheSize = _size;
+}
+- (int)permanentPageCacheSize {
+  return self->permanentPageCacheSize;
+}
+
+- (WOComponent *)pageWithName:(NSString *)_name {
+  // deprecated in WO4
+  return [self pageWithName:_name inContext:[self context]];
+}
+
+- (WOComponent *)_pageWithName:(NSString *)_name inContext:(WOContext *)_ctx {
+  /*
+    OSX profiling: 3.4% of dispatchRequest?
+      3.0%  rm -pageWithName..
+        1.5%  def instantiate
+          1.3% initWithName:...
+            0.76% initWithContent:.. (0.43 addobserver)
+        0.76% rm  defForComp (0.43% touch)
+        0.54% pool
+      0.11% ctx -component
+      0.11% pool
+  */
+  NSArray           *languages;
+  WOComponent       *page;
+  NSAutoreleasePool *pool;
+  WOResourceManager *rm;
+
+#if MEM_DEBUG
+  NSDictionary *start, *stop;
+  start = [self memoryStatistics];
+#endif
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  languages = [_ctx hasSession]
+    ? [(WOSession *)[_ctx session] languages]
+    : [[_ctx request] browserLanguages];
+
+  if ((rm = [[_ctx component] resourceManager]) == nil)
+    rm = [self resourceManager];
+  
+  page = [rm pageWithName:(_name ? _name : @"Main")
+             languages:languages];
+  [page ensureAwakeInContext:_ctx];
+  
+  page = [page retain];
+  [pool release];
+
+#if MEM_DEBUG
+  {
+    int rss, vmsize, lib;
+    stop = [self memoryStatistics];
+    rss    = [[stop objectForKey:@"VmRSS"] intValue] -
+             [[start objectForKey:@"VmRSS"] intValue];
+    vmsize = [[stop objectForKey:@"VmSize"] intValue] -
+             [[start objectForKey:@"VmSize"] intValue];
+    lib    = [[stop objectForKey:@"VmLib"] intValue] -
+             [[start objectForKey:@"VmLib"] intValue];
+    NSLog(@"loaded component %@; rss=%i vm=%i lib=%i.", _name, rss,vmsize,lib);
+  }
+#endif
+  
+  return [page autorelease];
+}
+- (WOComponent *)pageWithName:(NSString *)_name inContext:(WOContext *)_ctx {
+  return [self _pageWithName:_name inContext:_ctx];
+}
+- (WOComponent *)pageWithName:(NSString *)_name forRequest:(WORequest *)_req {
+  WOResourceManager *rm;
+
+  if ((rm = [self resourceManager]) == nil)
+    return nil;
+  
+  return [rm pageWithName:_name ? _name : @"Main"
+             languages:[_req browserLanguages]];
+}
+
+- (void)savePage:(WOComponent *)_page {
+  IS_DEPRECATED;
+  [[[self context] session] savePage:_page];
+}
+- (id)restorePageForContextID:(NSString *)_ctxId {
+  IS_DEPRECATED;
+  return [[[self context] session] restorePageForContextID:_ctxId];
+}
+
+- (WOResponse *)handlePageRestorationErrorInContext:(WOContext *)_ctx {
+  [self logWithFormat:
+          @"could not restore page for context-id %@\n  in context %@",
+          [_ctx currentElementID], _ctx];
+  
+  /* return main page ... */
+  return [[self pageWithName:nil inContext:_ctx] generateResponse];
+}
+- (WOResponse *)handlePageRestorationError {
+  IS_DEPRECATED;
+  return [self handlePageRestorationErrorInContext:[self context]];
+}
+
+/* exceptions */
+
+- (WOResponse *)handleException:(NSException *)_exc
+  inContext:(WOContext *)_ctx
+{
+  WORequest  *rq = [_ctx request];
+  WOResponse *r  = nil;
+  
+  if ([self respondsToSelector:@selector(handleException:)]) {
+    NSLog(@"WARNING: calling deprecated -handleException method !");
+    return [self handleException:_exc];
+  }
+  
+#if DEBUG
+  {
+    static int doCore = -1;
+    if (doCore == -1) {
+      doCore = [[NSUserDefaults standardUserDefaults] 
+                boolForKey:@"WOCoreOnApplicationException"]
+       ? 1 : 0;
+    }
+    if (doCore) {
+      [self logWithFormat:@"%@: caught (ctx=%@):\n  %@.",
+           self, _ctx, _exc];
+      abort();
+    }
+  }
+#endif
+  
+  if (_ctx == nil) {
+    [self logWithFormat:@"%@: caught (without context):\n  %@.", self, _exc];
+    [self terminate];
+  }
+  else if (rq == nil) {
+    [self logWithFormat:@"%@: caught (without request):\n  %@.", self, _exc];
+    [self terminate];
+  }
+  else {
+    static NSString *pageFormat =
+      @"Application Server caught exception:\n\n"
+      @"  session:   %@\n"
+      @"  element:   %@\n"
+      @"  context:   %@\n"
+      @"  request:   %@\n\n"
+      @"  class:     %@\n"
+      @"  name:      %@\n"
+      @"  reason:    %@\n"
+      @"  info:\n    %@\n"
+      @"  backtrace:\n%@\n";
+    NSString *str = nil;
+    NSString *bt  = nil;
+    
+    [self logWithFormat:@"%@: caught:\n  %@\nin context:\n  %@.",
+            self, _exc, _ctx];
+
+#if LIB_FOUNDATION_LIBRARY
+    if ([NSException respondsToSelector:@selector(backtrace)])
+      bt = [NSException backtrace];
+#endif
+    
+    if ((r = [WOResponse responseWithRequest:rq]) == nil)
+      [self logWithFormat:@"could not create response !"];
+    
+    [r setHeader:@"text/html" forKey:@"content-type"];
+    [r setHeader:@"no-cache" forKey:@"cache-control"];
+    if(rapidTurnAroundPath != nil) {
+        NSURL *templateURL;
+        
+        templateURL = [[_exc userInfo] objectForKey:@"templateURL"];
+        if(templateURL != nil)
+            [r setHeader:[templateURL path] forKey:@"x-sope-template-path"];
+    }
+
+    str = [NSString stringWithFormat:pageFormat,
+                      [_ctx hasSession] 
+                        ? [[_ctx session] sessionID]
+                        : @"[no session]",
+                      [_ctx elementID],
+                      [_ctx description],
+                      [rq description],
+                      NSStringFromClass([_exc class]),
+                      [_exc name],
+                      [_exc reason],
+                      [[_exc userInfo] description],
+                      bt];
+    
+    [r appendContentString:@"<html><head><title>Caught exception</title></head><body><pre>\n"];
+    [r appendContentHTMLString:str];
+    [r appendContentString:@"</pre></body></html>\n"];
+  }
+  return r;
+}
+
+/* runloop */
+
+- (BOOL)shouldTerminate {
+  if (![self isRefusingNewSessions])
+    return NO;
+  if ([self activeSessionsCount] >= [self minimumActiveSessionsCount])
+    return NO;
+
+  /* check whether the application instance is still valid .. */
+  [self debugWithFormat:
+         @"application terminates because it refuses new sessions and "
+         @"the active session count (%i) is below the minimum (%i).",
+         [self activeSessionsCount], [self minimumActiveSessionsCount]];
+  return YES;
+}
+
+- (void)terminate {
+  [self debugWithFormat:
+          @"application terminates:\n"
+          @"  %i active sessions\n"
+          @"  %i minimum active sessions\n"
+          @"  refuses new session: %s",
+          [self activeSessionsCount],
+          [self minimumActiveSessionsCount],
+          [self isRefusingNewSessions] ? "yes" : "no"];
+  [super terminate];
+}
+
+/* logging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@"|%@%@|", 
+                     [self name],
+                     [self isTerminating] ? @" terminating" : @""];
+}
+
+/* KVC */
+
+#if !LIB_FOUNDATION_LIBRARY
+- (id)valueForUndefinedKey:(NSString *)_key {
+  [self logWithFormat:@"WARNING: tried to access undefined KVC key: '%@'",
+         _key];
+  return nil;
+}
+#endif
+
+/* configuration */
+
++ (Class)eoEditingContextClass {
+  static Class eoEditingContextClass = Nil;
+  static BOOL  lookedUpForEOEditingContextClass = NO;
+  
+  if (!lookedUpForEOEditingContextClass) {
+    eoEditingContextClass = NSClassFromString(@"EOEditingContext");
+    lookedUpForEOEditingContextClass = YES;
+  }
+  return eoEditingContextClass;
+}
+
++ (BOOL)implementsEditingContexts {
+  return [self eoEditingContextClass] != NULL ? YES : NO;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: name=%@%@>",
+                     NSStringFromClass([self class]), self,
+                     [self name],
+                     [self isTerminating] ? @" terminating" : @""
+                   ];
+}
+
+@end /* WOApplication */
diff --git a/skyrix-sope/NGObjWeb/WOApplicationMain.m b/skyrix-sope/NGObjWeb/WOApplicationMain.m
new file mode 100644 (file)
index 0000000..c041e8c
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+NGObjWeb_DECLARE
+int WOApplicationMain(NSString *_appClassName, int argc, const char *argv[])
+{
+#if !LIB_FOUNDATION_BOEHM_GC
+  NSAutoreleasePool *pool = [NSAutoreleasePool new];
+#endif
+#if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS)
+  extern char **environ;
+  [NSProcessInfo initializeWithArguments:(void*)argv count:argc
+                 environment:(void*)environ];
+#endif
+  NGInitTextStdio();
+  {
+    WOApplication *app;
+    
+    app = [[NSClassFromString(_appClassName) alloc] init];
+
+    [app run];
+    [app release]; app = nil;
+  }
+  [pool release]; pool = nil;
+  return 0;
+}
diff --git a/skyrix-sope/NGObjWeb/WOChildComponentReference.h b/skyrix-sope/NGObjWeb/WOChildComponentReference.h
new file mode 100644 (file)
index 0000000..7b8f59a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOChildComponentReference_H__
+#define __NGObjWeb_WOChildComponentReference_H__
+
+#include <NGObjWeb/WODynamicElement.h>
+
+/*
+  This element is used to represent sub-components in templates.
+
+  Eg if
+
+    A: MyComponent {
+    }
+
+  The 'A' is turned into a WOChildComponentReference object.
+*/
+
+@interface WOChildComponentReference : WODynamicElement
+{
+@protected
+  NSString  *childName;
+  WOElement *template;
+}
+
+@end
+
+#endif /* __NGObjWeb_WOChildComponentReference_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOChildComponentReference.m b/skyrix-sope/NGObjWeb/WOChildComponentReference.m
new file mode 100644 (file)
index 0000000..3dadbd1
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOChildComponentReference.h"
+#include "WOComponent+private.h"
+#include "WOContext+private.h"
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@interface WOContext(ComponentStackCount)
+- (unsigned)componentStackCount;
+@end
+
+@implementation WOChildComponentReference
+
+static int profileComponents = -1;
+static Class NSDateClass = Nil;
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+
+  if (profileComponents == -1) {
+    profileComponents = [[[NSUserDefaults standardUserDefaults]
+                                          objectForKey:@"WOProfileComponents"]
+                                          boolValue] ? 1 : 0;
+  }
+  if (NSDateClass == Nil)
+    NSDateClass = [NSDate class];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  template:(WOElement *)_template
+{
+  self = [super initWithName:_name associations:nil template:_template];
+  if (self) {
+    self->childName = [_name copyWithZone:[self zone]];
+    self->template  = RETAIN(_template);
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->childName);
+  RELEASE(self->template);
+  [super dealloc];
+}
+#endif
+
+/* accessors */
+
+- (NSString *)childName {
+  return self->childName;
+}
+
+- (WOElement *)template {
+  return self->template;
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *parent, *child;
+  NSTimeInterval st = 0.0;
+  
+  if ((parent = [_ctx component]) == nil) {
+    [self logWithFormat:
+            @"WARNING(%s): did not find parent component of child %@",
+            __PRETTY_FUNCTION__, self->childName];
+    return;
+  }
+  if ((child = [parent childComponentWithName:self->childName]) == nil) {
+    [self logWithFormat:
+            @"WARNING: did not find child component %@ of parent %@",
+            self->childName, [parent name]];
+    return;
+  }
+  
+  if (profileComponents)
+    st = [[NSDateClass date] timeIntervalSince1970];
+
+  WOContext_enterComponent(_ctx, child, self->template);
+  [child takeValuesFromRequest:_request inContext:_ctx];
+  WOContext_leaveComponent(_ctx, child);
+  
+  if (profileComponents) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    for (i = [_ctx componentStackCount]; i >= 0; i--)
+      printf("  ");
+    printf("[%s %s]: %0.3fs\n",
+           [[child name] cString], sel_get_name(_cmd), diff);
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  WOComponent    *parent, *child;
+  id             result = nil;
+  NSTimeInterval st = 0.0;
+
+  if ((parent = [_ctx component]) == nil) {
+    [[_ctx session]
+           logWithFormat:@"WARNING: did not find parent component of child %@",
+             self->childName];
+    return nil;
+  }
+  if ((child = [parent childComponentWithName:self->childName]) == nil) {
+    [[_ctx session]
+           logWithFormat:
+             @"WARNING: did not find child component %@ of parent %@",
+             self->childName, [parent name]];
+    return nil;
+  }
+  
+  if (profileComponents)
+    st = [[NSDateClass date] timeIntervalSince1970];
+  
+  WOContext_enterComponent(_ctx, child, self->template);
+  result = [child invokeActionForRequest:_request inContext:_ctx];
+  WOContext_leaveComponent(_ctx, child);
+
+  if (profileComponents) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    for (i = [_ctx componentStackCount]; i >= 0; i--)
+      printf("  ");
+    printf("[%s %s]: %0.3fs\n",
+           [[child name] cString], sel_get_name(_cmd), diff);
+  }
+
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *parent, *child;
+  NSTimeInterval st = 0.0;
+  
+  if ((parent = [_ctx component]) == nil) {
+    [self logWithFormat:
+            @"WARNING(%s): did not find parent component of child %@",
+            __PRETTY_FUNCTION__, self->childName];
+    return;
+  }
+  if ((child = [parent childComponentWithName:self->childName]) == nil) {
+    [self logWithFormat:
+            @"WARNING: did not find child component %@ of parent %@",
+            self->childName, [parent name]];
+    [_response appendContentString:@"<pre>[missing component: "];
+    [_response appendContentHTMLString:self->childName];
+    [_response appendContentString:@"]</pre>"];
+    return;
+  }
+  
+  if (profileComponents)
+    st = [[NSDateClass date] timeIntervalSince1970];
+  
+  WOContext_enterComponent(_ctx, child, self->template);
+  [child appendToResponse:_response inContext:_ctx];
+  WOContext_leaveComponent(_ctx, child);
+  
+  if (profileComponents) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+    for (i = [_ctx componentStackCount]; i >= 0; i--)
+      printf("  ");
+    printf("[%s %s]: %0.3fs\n",
+           [[child name] cString], sel_get_name(_cmd), diff);
+  }
+}
+
+@end /* WOChildComponentReference */
diff --git a/skyrix-sope/NGObjWeb/WOComponent+JS.m b/skyrix-sope/NGObjWeb/WOComponent+JS.m
new file mode 100644 (file)
index 0000000..ab777e0
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include <NGObjWeb/NGObjWeb.h>
+
+/*
+  WOComponent JavaScript object
+
+  Properties
+
+    String      sessionID
+    String      name
+    String      path
+    String      baseURL
+    Object      context
+    Object      session
+    Object      application
+    WOComponent parent
+    bool        hasSession
+    bool        cachingEnabled
+    bool        isEventLoggingEnabled
+    bool        isStateless
+    bool        synchronizesVariablesWithBindings
+  
+  Methods
+
+    reset()    
+    WOComponent     pageWithName(name)
+    WOElement       templateWithName(name)
+    Object          performParentAction(name)
+    bool            canGetValueForBinding(name)
+    bool            canSetValueForBinding(name)
+                    setValueForBinding(value,name)
+    Object          valueForBinding(name)
+    bool            hasBinding(name)
+                    print(string[,...string])
+    ResourceManager getResourceManager()
+*/
+
+static NSNumber *nYes = nil;
+static NSNumber *nNo  = nil;
+
+#define ENSURE_BOOLNUMS {\
+  if (nYes == nil) nYes = [[NSNumber alloc] initWithBool:YES];\
+  if (nNo  == nil) nNo  = [[NSNumber alloc] initWithBool:NO];\
+}
+
+@implementation WOComponent(JSKVC)
+
+#if 1
+- (void)takeValue:(id)_value forJSPropertyNamed:(NSString *)_key {
+  [self takeValue:_value forKey:_key];
+}
+- (id)valueForJSPropertyNamed:(NSString *)_key {
+  return [self valueForKey:_key];
+}
+#endif
+
+@end /* WOComponent(JSKVC) */
+
+@implementation WOComponent(JSFunctions)
+
+- (id)_jsfunc_reset:(NSArray *)_args {
+  [self reset];
+  return self;
+}
+
+- (id)_jsfunc_pageWithName:(NSArray *)_args {
+  return [self pageWithName:[[_args objectAtIndex:0] stringValue]];
+}
+- (id)_jsfunc_templateWithName:(NSArray *)_args {
+  return [self templateWithName:[[_args objectAtIndex:0] stringValue]];
+}
+- (id)_jsfunc_performParentAction:(NSArray *)_args {
+  return [self performParentAction:[[_args objectAtIndex:0] stringValue]];
+}
+
+- (id)_jsfunc_canGetValueForBinding:(NSArray *)_args {
+  ENSURE_BOOLNUMS;
+  return [self canGetValueForBinding:[[_args objectAtIndex:0] stringValue]]
+    ? nYes : nNo;
+}
+- (id)_jsfunc_canSetValueForBinding:(NSArray *)_args {
+  ENSURE_BOOLNUMS;
+  return [self canSetValueForBinding:[[_args objectAtIndex:0] stringValue]]
+    ? nYes : nNo;
+}
+
+- (id)_jsfunc_setValueForBinding:(NSArray *)_args {
+  [self setValue:[_args objectAtIndex:0]
+        forBinding:[[_args objectAtIndex:1] stringValue]];
+  return self;
+}
+- (id)_jsfunc_valueForBinding:(NSArray *)_args {
+  return [self valueForBinding:[[_args objectAtIndex:0] stringValue]];
+}
+
+- (id)_jsfunc_hasBinding:(NSArray *)_args {
+  ENSURE_BOOLNUMS;
+  return [self hasBinding:[[_args objectAtIndex:0] stringValue]]
+    ? nYes : nNo;
+}
+
+- (id)_jsfunc_getResourceManager:(NSArray *)_args {
+  return [self resourceManager];
+}
+
+- (id)_jsfunc_print:(NSArray *)_args {
+  NSEnumerator    *e;
+  id              o;
+  BOOL            isFirst;
+  NSMutableString *ms;
+  
+  isFirst = YES;
+  ms = [NSMutableString stringWithCapacity:128];
+  
+  e = [_args objectEnumerator];
+  while ((o = [e nextObject])) {
+    NSString *s;
+    
+    if (!isFirst) [ms appendString:@" "];
+    else isFirst = NO;
+    
+    s = [o stringValue];
+    [ms appendString:s];
+  }
+  
+  [self logWithFormat:@"%@", ms];
+  
+  return self;
+}
+
+@end /* WOComponent(JSFunctions) */
+
+@implementation WOComponent(JSProperties)
+
+- (id)_jsprop_sessionID {
+  return [[self session] sessionID];
+}
+- (id)_jsprop_name {
+  return [self name];
+}
+- (id)_jsprop_path {
+  return [self path];
+}
+- (id)_jsprop_baseURL {
+  return [self baseURL];
+}
+
+- (id)_jsprop_context {
+  return [self context];
+}
+- (id)_jsprop_session {
+  return [self session];
+}
+- (id)_jsprop_application {
+  return [self application];
+}
+- (id)_jsprop_parent {
+  return [self parent];
+}
+
+- (id)_jsprop_hasSession {
+  ENSURE_BOOLNUMS;
+  return [self hasSession] ? nYes : nNo;
+}
+
+- (void)_jsprop_cachingEnabled:(id)_value {
+  [self setCachingEnabled:[_value boolValue]];
+}
+- (id)_jsprop_cachingEnabled {
+  ENSURE_BOOLNUMS;
+  return [self isCachingEnabled] ? nYes : nNo;
+}
+
+- (id)_jsprop_isEventLoggingEnabled {
+  ENSURE_BOOLNUMS;
+  return [self isEventLoggingEnabled] ? nYes : nNo;
+}
+- (id)_jsprop_isStateless {
+  ENSURE_BOOLNUMS;
+  return [self isStateless] ? nYes : nNo;
+}
+- (id)_jsprop_synchronizedVariablesWithBindings {
+  ENSURE_BOOLNUMS;
+  return [self synchronizesVariablesWithBindings] ? nYes : nNo;
+}
+
+@end /* WOComponent(JSProperties) */
diff --git a/skyrix-sope/NGObjWeb/WOComponent+Sync.m b/skyrix-sope/NGObjWeb/WOComponent+Sync.m
new file mode 100644 (file)
index 0000000..4f12036
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOAssociation.h>
+#include "common.h"
+
+@implementation WOComponent(OptimizedSynching)
+
+/*
+  optimized component synchronization. Uses extensive runtime caching.
+*/
+
+static Class lastEnumClass = Nil;
+static id (*nextKey)(id, SEL);
+static Class lastWocDictClass = Nil;
+static id (*wocObjForKey)(id, SEL, id);
+
+#if NeXT_RUNTIME
+
+#define CHK_ENUM_CACHE \
+  if (lastEnumClass != *(Class *)keys) {\
+    lastEnumClass = *(Class *)keys;\
+    nextKey = (void*)[keys methodForSelector:@selector(nextObject)];\
+  }
+
+#define CHK_WOCDICT_CACHE \
+  if (lastWocDictClass != *(Class *)self->wocBindings) {\
+    lastWocDictClass = *(Class *)self->wocBindings;\
+    wocObjForKey = (void*)[self->wocBindings methodForSelector:@selector(objectForKey:)];\
+  }
+
+#else
+
+#define CHK_ENUM_CACHE \
+  if (lastEnumClass != *(Class *)keys) {\
+    lastEnumClass = *(Class *)keys;\
+    nextKey = (void*)\
+      method_get_imp(class_get_instance_method(*(Class *)keys, \
+        @selector(nextObject)));\
+  }
+
+#define CHK_WOCDICT_CACHE \
+  if (lastWocDictClass != *(Class *)self->wocBindings) {\
+    lastWocDictClass = *(Class *)self->wocBindings;\
+    wocObjForKey = (void*)\
+      method_get_imp(class_get_instance_method(*(Class *)self->wocBindings, \
+        @selector(objectForKey:)));\
+  }
+
+#endif
+
+void WOComponent_syncFromParent(WOComponent *self, WOComponent *_parent) {
+  NSEnumerator *keys;
+  NSString     *key;
+  void (*takeValue)(id, SEL, id, NSString *);
+  
+  if ((keys = [self->wocBindings keyEnumerator]) == nil)
+    return;
+  
+  CHK_ENUM_CACHE;
+  CHK_WOCDICT_CACHE;
+#if NeXT_RUNTIME
+  takeValue = (void *)[self methodForSelector:@selector(takeValue:forKey:)];
+#else  
+  takeValue = (void*)method_get_imp(class_get_instance_method(self->isa,
+                @selector(takeValue:forKey:)));
+#endif
+  
+  while ((key = nextKey(keys, @selector(nextObject)))) {
+    static   Class lastAssocClass = Nil; // THREAD
+    static   id    (*valInComp)(id, SEL, WOComponent *);
+    register WOAssociation *binding;
+    register id value;
+    
+    binding = wocObjForKey(self->wocBindings, @selector(objectForKey:), key);
+    
+    if (*(Class *)binding != lastAssocClass) {
+      lastAssocClass = *(Class *)binding;
+#if NeXT_RUNTIME
+      valInComp = (void *)
+       [binding methodForSelector:@selector(valueInComponent:)];
+#else
+      valInComp = (void *)
+        method_get_imp(class_get_instance_method(*(Class *)binding,
+          @selector(valueInComponent:)));
+#endif
+    }
+    
+    // TODO: this is somewhat inefficient because -valueInComponent: does
+    //       value=>object coercion and then takeValue:forKey: does the
+    //       reverse coercion. We could improve performance for base values
+    //       if we implement takeValue:forKey: on our own and just pass over
+    //       the raw value (ie [self setIntA:[assoc intValueComponent:self]])
+    
+    value = valInComp(binding, @selector(valueInComponent:), _parent);
+
+    // TODO: this is a bit problematic in bool contexts if the input
+    //       parameter is a string because ObjC doesn't know about bool
+    //       and will evaluate the string as a char value
+    //       (this is common if you use const:mykey="YES" in WOx)
+    takeValue(self, @selector(takeValue:forKey:), value, key);
+  }
+}
+
+void WOComponent_syncToParent(WOComponent *self, WOComponent *_parent) {
+  NSEnumerator *keys;
+  NSString     *key;
+  id (*getValue)(id, SEL, NSString *);
+  
+  if ((keys = [self->wocBindings keyEnumerator]) == nil)
+    return;
+  
+  CHK_ENUM_CACHE;
+  CHK_WOCDICT_CACHE;
+
+#if NeXT_RUNTIME
+  getValue = (void *)[self methodForSelector:@selector(valueForKey:)];
+#else
+  getValue = (void*)method_get_imp(class_get_instance_method(self->isa,
+                @selector(valueForKey:)));
+#endif
+  
+  while ((key = nextKey(keys, @selector(nextObject)))) {
+    static   Class lastAssocClass = Nil;
+    static   BOOL  (*isSettable)(id, SEL);
+    static   void  (*setValInComp)(id, SEL, id, WOComponent *);
+    register WOAssociation *binding;
+    register id value;
+    
+    binding = wocObjForKey(self->wocBindings, @selector(objectForKey:), key);
+
+    if (*(Class *)binding != lastAssocClass) {
+      lastAssocClass = *(Class *)binding;
+
+#if NeXT_RUNTIME
+      isSettable   = 
+       (void*)[binding methodForSelector:@selector(isValueSettable)];
+      setValInComp = 
+       (void*)[binding methodForSelector:@selector(setValue:inComponent:)];
+#else
+      isSettable = (void*)
+        method_get_imp(class_get_instance_method(*(Class *)binding,
+          @selector(isValueSettable)));
+      setValInComp = (void*)
+        method_get_imp(class_get_instance_method(*(Class *)binding,
+          @selector(setValue:inComponent:)));
+#endif
+    }
+    
+    if (!isSettable(binding, @selector(isValueSettable)))
+      continue;
+    
+    value = getValue(self, @selector(valueForKey:), key);
+    
+    setValInComp(binding, @selector(setValue:inComponent:), value, _parent);
+  }
+}
+
+@end /* WOComponent(OptimizedSynching) */
diff --git a/skyrix-sope/NGObjWeb/WOComponent+private.h b/skyrix-sope/NGObjWeb/WOComponent+private.h
new file mode 100644 (file)
index 0000000..8d1b369
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOComponent_private_H__
+#define __NGObjWeb_WOComponent_private_H__
+
+#import <NGObjWeb/WOComponent.h>
+
+@class NSString;
+@class WOElement, WOTemplate, WOSession, WOApplication, WOContext;
+
+@interface WOComponent(PrivateMethods)
+
+- (void)setApplication:(WOApplication *)_application;
+
+/* URL generation */
+
+- (NSString *)componentActionURLForContext:(WOContext *)_ctx;
+
+/* activity */
+
+- (void)_awakeWithContext:(WOContext *)_ctx;
+- (void)_sleepWithContext:(WOContext *)_ctx;
+- (void)_setContext:(WOContext *)_ctx;
+
+/* used by WOApplication: */
+- (WOElement *)_woComponentTemplate;
+
+/* used by WOComponentReference: */
+- (void)setName:(NSString *)_name;
+- (void)setBindings:(NSDictionary *)_bindings;
+- (void)setSubComponents:(NSDictionary *)_dictionary;
+- (void)setParent:(WOComponent *)_parent;
+- (WOComponent *)childComponentWithName:(NSString *)_name;
+
+extern void WOComponent_syncFromParent(WOComponent *child, WOComponent *parent);
+extern void WOComponent_syncToParent(WOComponent *child, WOComponent *parent);
+
+@end /* WOComponent(PrivateMethods) */
+
+#endif /* __NGObjWeb_WOComponent_private_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOComponent.m b/skyrix-sope/NGObjWeb/WOComponent.m
new file mode 100644 (file)
index 0000000..94e3cb7
--- /dev/null
@@ -0,0 +1,1220 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+#include "WOComponent+private.h"
+#include "NSObject+WO.h"
+#include <NGObjWeb/WODynamicElement.h>
+#include "WOContext+private.h"
+#include "WOElement+private.h"
+#include "WOComponentDefinition.h"
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResponse.h>
+#include "WOComponentFault.h"
+#include "common.h"
+#include <NGExtensions/NGBundleManager.h>
+#include <EOControl/EOControl.h>
+#include <NGExtensions/NSString+Ext.h>
+
+@interface WOContext(ComponentStackCount)
+- (unsigned)componentStackCount;
+@end
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (id)notImplemented:(SEL)cmd;
+@end
+#endif
+
+#if !LIB_FOUNDATION_LIBRARY
+#  define NG_USE_KVC_FALLBACK 1
+#endif
+
+@implementation WOComponent
+
+static Class NSDateClass      = Nil;
+static Class WOComponentClass = Nil;
+static BOOL  profElements                      = NO;
+static BOOL  debugOn                           = NO;
+static BOOL  debugComponentAwake               = NO;
+static BOOL  debugTemplates                    = NO;
+static BOOL  abortOnAwakeComponentInCtxDealloc = NO;
+static BOOL  abortOnMissingCtx                 = NO;
+static BOOL  wakeupPageOnCreation              = NO;
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  WOComponentClass = [WOComponent class];
+  NSDateClass      = [NSDate class];
+  
+  profElements        = [ud boolForKey:@"WOProfileElements"];
+  debugOn             = [WOApplication isDebuggingEnabled];
+  debugComponentAwake = [ud boolForKey:@"WODebugComponentAwake"];
+  abortOnAwakeComponentInCtxDealloc = 
+    [ud boolForKey:@"WOCoreOnAwakeComponentInCtxDealloc"];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    NSNotificationCenter  *nc;
+    WOComponentDefinition *cdef;
+    
+    if ((cdef = (id)self->wocVariables)) { 
+      // HACK CD, see WOComponentDefinition
+      self->wocVariables = nil;
+    }
+    
+    if (self->wocName == nil)
+      self->wocName = [NSStringFromClass([self class]) copy];
+    
+    [self setCachingEnabled:[[self application] isCachingEnabled]];
+    
+    /* finish initialization */
+    
+    if (cdef) {
+      [cdef _finishInitializingComponent:self];
+      [cdef release]; cdef = nil;
+    }
+#if !APPLE_FOUNDATION_LIBRARY && !NeXT_Foundation_LIBRARY
+    else {
+      /* this is triggered by Publisher on MacOSX */
+      [self debugWithFormat:
+             @"Note: got no component definition according to HACK CD"];
+    }
+#endif
+    
+    /* add to notification center */
+    
+    nc = [NSNotificationCenter defaultCenter];
+    
+    [nc addObserver:self selector:@selector(_sessionWillDealloc:)
+        name:@"WOSessionWillDeallocate" object:nil];
+    
+    [nc addObserver:self selector:@selector(_contextWillDealloc:)
+        name:@"WOContextWillDeallocate" object:nil];
+  }
+  return self;
+}
+- (id)initWithContext:(WOContext *)_ctx {
+  [self _setContext:_ctx];
+  if ((self = [self init])) {
+    if (self->context)
+      [self ensureAwakeInContext:self->context];
+    else {
+      [self logWithFormat:
+              @"WARNING: no context given to -initWithContext: ..."];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  
+  [[self->subcomponents allValues]
+                        makeObjectsPerformSelector:@selector(setParent:)
+                        withObject:nil];
+  [self->subcomponents release];
+  
+  [self->wocBindings   release];
+  [self->wocVariables  release];
+  [self->wocName       release];
+  [super dealloc];
+}
+
+static inline void _setExtraVar(WOComponent *self, NSString *_key, id _obj) {
+  if (_obj) {
+    if (self->wocVariables == nil)
+      self->wocVariables = [[NSMutableDictionary alloc] initWithCapacity:16];
+    
+    [self->wocVariables setObject:_obj forKey:_key];
+  }
+  else
+    [self->wocVariables removeObjectForKey:_key];
+}
+static inline id _getExtraVar(WOComponent *self, NSString *_key) {
+  return [self->wocVariables objectForKey:_key];
+}
+
+/* observers */
+
+- (void)_sessionWillDealloc:(NSNotification *)_notification {
+#if DEBUG
+  NSAssert(_notification, @"missing valid session arg ...");
+#endif
+
+  if (self->session == nil) {
+    /* component isn't interested in session anymore anyway ... */
+    return;
+  }
+  if (self->session != [_notification object])
+    /* not the component's context ... */
+    return;
+  
+#if DEBUG && 0
+  [self debugWithFormat:@"resetting sn/ctx because session will dealloc .."];
+#endif
+  
+  if (self->componentFlags.isAwake) {
+    [self logWithFormat:
+            @"WARNING: session will dealloc, "
+           @"but component 0x%08X is awake (ctx=%@) !", self, self->context];
+    [self _sleepWithContext:self->context];
+  }
+  
+  self->session = nil;
+  [self _setContext:nil];
+}
+- (void)_contextWillDealloc:(NSNotification *)_notification {
+#if DEBUG
+  NSAssert(_notification, @"missing valid notification arg ...");
+#endif
+  
+  if (self->context == nil)
+    /* component isn't interested in context anyway ... */
+    return;
+  if (![[self->context contextID] isEqualToString:[_notification object]])
+    /* not the component's context ... */
+    return;
+  
+#if DEBUG && 0
+  [self debugWithFormat:@"resetting sn/ctx because context will dealloc .."];
+#endif
+  
+  if (self->componentFlags.isAwake) {
+    /*
+      Note: this is not necessarily a problem, no specific reason to log
+            the event?!
+    */
+    [self debugWithFormat:
+            @"WARNING: context %@ will dealloc, "
+            @"but component is awake in ctx %@!",
+            [_notification object], [self->context contextID]];
+    if (abortOnAwakeComponentInCtxDealloc)
+      abort();
+    
+    [self _sleepWithContext:nil];
+  }
+  
+  [self _setContext:nil];
+  self->session = nil;
+}
+
+/* awake & sleep */
+
+- (void)awake {
+}
+- (void)sleep {
+  if (debugOn) {
+    if (self->componentFlags.isAwake) {
+      [self debugWithFormat:
+              @"WARNING: component should not be awake if sleep is called !"];
+    }
+    if (self->context == nil) {
+      [self debugWithFormat:
+              @"WARNING: context should not be nil if sleep is called !"];
+    }
+  }
+  
+  self->componentFlags.isAwake = 0;
+  [self _setContext:nil];
+  self->application = nil;
+  self->session     = nil;
+}
+
+- (void)ensureAwakeInContext:(WOContext *)_ctx {
+#if DEBUG
+  NSAssert1(_ctx, @"missing context for awake (component=%@) ...", self);
+#endif
+  
+  if (debugComponentAwake) 
+    [self logWithFormat:@"0x%08X ensureAwakeInContext:0x%08X", self, _ctx];
+  
+  if (self->context == nil)     [self _setContext:_ctx];
+  if (self->application == nil) self->application = [_ctx application];
+  
+  if ((self->session == nil) && [_ctx hasSession])
+    self->session = [_ctx session];
+  
+  self->componentFlags.isAwake = 1;
+  
+  /* awake subcomponents */
+  {
+    NSEnumerator *children;
+    WOComponent  *child;
+    
+    children = [self->subcomponents objectEnumerator];
+    while ((child = [children nextObject]))
+      [child _awakeWithContext:_ctx];
+  }
+  
+  [self awake];
+}
+
+- (void)_awakeWithContext:(WOContext *)_ctx {
+  if (self->componentFlags.isAwake)
+    return;
+  
+  [self ensureAwakeInContext:_ctx];
+}
+- (void)_sleepWithContext:(WOContext *)_ctx {
+  if (debugComponentAwake) 
+    [self logWithFormat:@"0x%08X _sleepWithContext:0x%08X", self, _ctx];
+  
+  if (_ctx != self->context) {
+    if ((self->context != nil) && (_ctx != nil)) {
+      /* component is active in different context ... */
+      [self debugWithFormat:
+              @"WARNING: sleep context mismatch (own=0x%08X vs given=0x%08X)",
+              self->context, _ctx];
+      return;
+    }
+  }
+  
+  if (self->componentFlags.isAwake) {
+    /* 
+       Sleep all child components, this is necessary to ensure some ordering
+       in the sleep calls. All awake components are put to sleep in any case
+       by the WOContext destructor.
+    */
+    NSEnumerator *children;
+    WOComponent *child;
+    
+    children = [self->subcomponents objectEnumerator];
+    self->componentFlags.isAwake = 0;
+    
+    while ((child = [children nextObject]))
+      [child _sleepWithContext:_ctx];
+    
+    [self sleep];
+  }
+  [self _setContext:nil];
+  self->application = nil;
+  self->session     = nil;
+}
+
+/* accessors */
+
+- (NSString *)name {
+  return self->wocName;
+}
+- (NSString *)frameworkName {
+  return [[NGBundle bundleForClass:[self class]] bundleName];
+}
+- (NSString *)path {
+  NSArray *languages = nil;
+  
+#if 0 // the component might not yet be awake !
+  languages = [self hasSession]
+    ? [[self session] languages]
+    : [[[self context] request] browserLanguages];
+#endif
+  
+  return [[self resourceManager]
+                pathToComponentNamed:[self name]
+                inFramework:[self frameworkName]
+                languages:languages];
+}
+- (void)setBaseURL:(NSURL *)_url {
+  _setExtraVar(self, @"__wobaseurl", _url);
+}
+- (NSURL *)baseURL {
+  NSURL *url;
+  
+  if ((url = _getExtraVar(self, @"__wobaseurl")))
+    return url;
+  
+  url = [(WOApplication *)[self application] baseURL];
+  url = [NSURL URLWithString:@"WebServerResources" relativeToURL:url];
+  return url;
+}
+
+- (NSString *)componentActionURLForContext:(WOContext *)_ctx {
+  return [@"/" stringByAppendingString:[self name]];
+}
+
+- (WOApplication *)application {
+  if (self->application == nil)
+    return (self->application = [WOApplication application]);
+  return self->application;
+}
+
+- (id)existingSession {
+  if (self->session)
+    return self->session;
+  
+  if ([[self context] hasSession])
+    return [self session];
+
+  return nil;
+}
+- (WOSession *)session {
+  if (self->session == nil) {
+    if ((self->session = [[self context] session]) == nil) {
+      [self logWithFormat:@"could not get session object from context %@",
+              self->context];
+    }
+  }
+  
+  if (self->session == nil)
+    [self logWithFormat:@"WARNING: missing session for component!"];
+  
+  return self->session;
+}
+
+- (void)_setContext:(WOContext *)_ctx {
+  self->context = _ctx;
+}
+- (WOContext *)context {
+  if (self->context)
+    return self->context;
+  
+  [self debugWithFormat:
+          @"WARNING: missing context in component 0x%08X (component%s)",
+          self,
+          self->componentFlags.isAwake ? " is awake" : " is not awake"];
+  if (abortOnMissingCtx) {
+    [self logWithFormat:@"aborting, because ctx is missing !"];
+    abort();
+  }
+    
+  if (self->application == nil)
+    self->application = [WOApplication application];
+  [self _setContext:[self->application context]];
+  
+  if (self->context == nil)
+    [self logWithFormat:@"WARNING: could not determine context object!"];
+  
+  return self->context;
+}
+
+- (BOOL)hasSession {
+  return [[self context] hasSession];
+}
+
+- (void)setCachingEnabled:(BOOL)_flag {
+  self->componentFlags.reloadTemplates = _flag ? NO : YES;
+}
+- (BOOL)isCachingEnabled {
+  return (self->componentFlags.reloadTemplates == NO) ? YES : NO;
+}
+
+- (WOComponent *)pageWithName:(NSString *)_name {
+  NSArray *languages = nil;
+  WOResourceManager *rm;
+  WOComponent       *component;
+  
+  languages = [self hasSession]
+    ? [(WOSession *)[self session] languages]
+    : [[[self context] request] browserLanguages];
+  
+  rm = [self resourceManager];
+  
+  /* 
+     Note: this API is somewhat broken since the component expects the
+           -initWithContext: message for initialization yet we pass no
+           context ...
+  */
+  component = [rm pageWithName:_name languages:languages];
+  
+  // Note: should we call ensureAwakeInContext or is this to early ?
+  //       probably the component should be woken up if it enters the ctx.
+  //       If we create a page but never render it, we may get a warning 
+  //       that a context will dealloc but the page is active (yet not awake)
+  // Note: awake is not the same like "has context"! A component can have a
+  //       context without being awake - maybe we need an additional method
+  //       to hook up a component but the awake list
+  if (wakeupPageOnCreation)
+    [component ensureAwakeInContext:[self context]];
+  return component;
+}
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_default
+{
+  NSArray *langs;
+  IS_DEPRECATED;
+  
+  langs = [self hasSession]
+    ? [(WOSession *)[self session] languages]
+    : [[[self context] request] browserLanguages];
+  
+  return [[[self application]
+                 resourceManager]
+                 stringForKey:_key
+                 inTableNamed:_tableName
+                 withDefaultValue:_default
+                 languages:langs];
+}
+
+- (void)setName:(NSString *)_name {
+  if (![_name isNotNull])
+    [self logWithFormat:@"WARNING: setting 'nil' name on component!"];
+  
+  ASSIGNCOPY(self->wocName, _name);
+}
+
+- (void)setBindings:(NSDictionary *)_bindings {
+  // this is _very_ private and used by WOComponentReference
+  ASSIGNCOPY(self->wocBindings, _bindings);
+}
+- (NSDictionary *)_bindings {
+  // private method
+  return self->wocBindings;
+}
+
+- (void)setSubComponents:(NSDictionary *)_dictionary {
+  ASSIGNCOPY(self->subcomponents, _dictionary);
+}
+- (NSDictionary *)_subComponents {
+  // private method
+  return self->subcomponents;
+}
+
+- (void)setParent:(WOComponent *)_parent {
+  self->parentComponent = _parent;
+}
+- (WOComponent *)parent {
+  return self->parentComponent;
+}
+
+/* language change */
+
+- (void)languageArrayDidChange {
+}
+
+/* element name */
+
+- (NSString *)elementID {
+  return [self name];
+}
+
+/* resources */
+
+- (id<WOActionResults>)redirectToLocation:(id)_loc {
+  WOContext  *ctx = [self context];
+  WOResponse *r;
+  NSString   *target;
+
+  if (_loc == nil)
+    return nil;
+  
+  if ((r = [ctx response]) == nil)
+    r = [[[WOResponse alloc] init] autorelease];
+  
+  if ([_loc isKindOfClass:[NSURL class]])
+    target = [_loc absoluteString];
+  else {
+    _loc = [_loc stringValue];
+    if ([_loc isAbsoluteURL])
+      target = _loc;
+    else if ([_loc isAbsolutePath])
+      target = _loc;
+    else {
+      target = [[ctx request] uri];
+      
+      // TODO: check whether the algorithm is correct
+      if (![target hasSuffix:@"/"])
+       target = [target stringByDeletingLastPathComponent];
+      target = [target stringByAppendingPathComponent:_loc];
+    }
+  }
+  
+  if (target == nil)
+    return nil;
+  [r setStatus:302 /* moved */];
+  [r setHeader:target forKey:@"location"];
+  return r;
+}
+
+- (void)setResourceManager:(WOResourceManager *)_rm {
+  _setExtraVar(self, @"__worm", _rm);
+}
+- (WOResourceManager *)resourceManager {
+  WOResourceManager *rm;
+  WOComponent *p;
+  
+  if ((rm = _getExtraVar(self, @"__worm")))
+    return rm;
+  
+  /* ask parent component ... */
+  if ((p = [self parent])) {
+    NSAssert2(p != self, @"parent component == component !!! (%@ vs %@)",
+              p, self);
+    if ((rm = [p resourceManager]))
+      return rm;
+  }
+  
+  /* ask application ... */
+  return [[self application] resourceManager];
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_ext {
+  NSFileManager *fm         = [NSFileManager defaultManager];
+  NSEnumerator  *languages  = nil;
+  NSString      *language   = nil;
+  BOOL          isDirectory = NO;
+  NSString      *cpath      = [self path];
+  
+  if (_ext) _name = [_name stringByAppendingPathExtension:_ext];
+
+  if (cpath == nil) {
+    NSLog(@"WARNING: no path set in component %@", [self name]);
+    return nil;
+  }
+  if (![fm fileExistsAtPath:cpath isDirectory:&isDirectory]) {
+    NSLog(@"WARNING: component directory %@ does not exist !", cpath);
+    return nil;
+  }
+  if (!isDirectory) {
+    NSLog(@"WARNING: component path %@ is not a directory !", cpath);
+    return nil;
+  }
+
+  // check in language projects
+
+  languages = [[(WOSession *)[self session] languages] objectEnumerator];
+  while ((language = [languages nextObject])) {
+    language = [[cpath stringByAppendingPathComponent:
+                         [language stringByAppendingPathExtension:@"lproj"]]
+                       stringByAppendingPathExtension:_name];
+    
+    if ([fm fileExistsAtPath:language])
+      return language;
+  }
+
+  // check in component
+  cpath = [cpath stringByAppendingPathComponent:_name];
+  if ([fm fileExistsAtPath:cpath])
+    return cpath;
+
+  return nil;
+}
+
+/* template */
+
+- (WOElement *)templateWithHTMLString:(NSString *)_html
+  declarationString:(NSString *)_wod
+  languages:(NSArray *)_languages
+{
+  return [self notImplemented:_cmd];
+}
+- (WOElement *)templateWithHTMLString:(NSString *)_html
+  declarationString:(NSString *)_wod
+{
+  IS_DEPRECATED;
+  return [self templateWithHTMLString:_html
+               declarationString:_wod
+               languages:[(WOSession *)[self session] languages]];
+}
+
+- (WOElement *)templateWithName:(NSString *)_name {
+  WOResourceManager *resourceManager;
+  NSArray           *languages;
+  WOElement         *tmpl;
+  
+  if ((resourceManager = [self resourceManager]) == nil) {
+    [self logWithFormat:@"ERROR(%s): could not determine resource manager !",
+          __PRETTY_FUNCTION__];
+    return nil;
+  }
+  
+  languages = [self hasSession]
+    ? [(WOSession *)[self  session] languages]
+    : [[[self context] request] browserLanguages];
+  
+  tmpl = [resourceManager templateWithName:_name languages:languages];
+  if (debugTemplates) [self logWithFormat:@"found template: %@", tmpl];
+  return tmpl;
+}
+
+- (void)setTemplate:(id)_template {
+  /*
+    WO has private API for this:
+      - (void)setTemplate:(WOElement *)template;
+    As mentioned in the OmniGroup WO mailing list ...
+  */
+  _setExtraVar(self, @"__wotemplate", _template);
+}
+- (WOElement *)_woComponentTemplate {
+  WOElement *element;
+  
+  if ((element = _getExtraVar(self, @"__wotemplate")))
+    return element;
+  
+  return [self templateWithName:[self name]];
+}
+
+/* child components */
+
+- (WOComponent *)childComponentWithName:(NSString *)_name {
+  id child;
+  
+  child = [self->subcomponents objectForKey:_name];
+  if ([child isComponentFault]) {
+    NSMutableDictionary *tmp;
+    
+    child = [child resolveWithParent:self];
+    if (child == nil) {
+      [self logWithFormat:@"Could not resolve component fault: %@", _name];
+      return nil;
+    }
+    
+    tmp = [self->subcomponents mutableCopy];
+    [tmp setObject:child forKey:_name];
+    [self->subcomponents release]; self->subcomponents = nil;
+    self->subcomponents = [tmp copy];
+    [tmp release]; tmp = nil;
+  }
+  return child;
+}
+
+- (BOOL)synchronizesVariablesWithBindings {
+  return YES;
+}
+
+- (void)setValue:(id)_value forBinding:(NSString *)_name {
+  WOComponent      *parent;
+  WOContext        *ctx;
+  WODynamicElement *content;
+  
+  ctx     = [self context];
+  parent  = [ctx parentComponent];
+  content = [ctx componentContent];
+  
+  if (parent == nil) {
+    parent = [self parent];
+    NSLog(@"WARNING: tried to set value of binding '%@' in component '%@' "
+          @"without parent component (parent is '%@') !",
+          _name, [self name], [parent name]);
+  }
+  
+  [[self    retain] autorelease];
+  [[content retain] autorelease];
+  
+  WOContext_leaveComponent(ctx, self);
+  [[self->wocBindings objectForKey:_name] setValue:_value inComponent:parent];
+  WOContext_enterComponent(ctx, self, content);
+}
+- (id)valueForBinding:(NSString *)_name {
+  WOComponent      *parent;
+  WOContext        *ctx;
+  WODynamicElement *content;
+  id value;
+  
+  ctx     = [self context];
+  parent  = [ctx parentComponent];
+  content = [ctx componentContent];
+  
+  if (parent == nil) {
+    parent = [self parent];
+    NSLog(@"WARNING: tried to retrieve value of binding '%@' in"
+          @" component '%@' without parent component (parent is '%@') !",
+          _name, [self name], [parent name]);
+  }
+  
+  [[self    retain] autorelease];
+  [[content retain] autorelease];
+  
+  WOContext_leaveComponent(ctx, self);
+  value = [[self->wocBindings objectForKey:_name] valueInComponent:parent];
+  WOContext_enterComponent(ctx, self, content);
+  
+  return value;
+}
+
+- (BOOL)hasBinding:(NSString *)_name {
+  return ([self->wocBindings objectForKey:_name] != nil) ? YES : NO;
+}
+
+- (BOOL)canSetValueForBinding:(NSString *)_name {
+  WOAssociation *binding;
+
+  if ((binding = [self->wocBindings objectForKey:_name]) == nil)
+    return NO;
+  
+  return [binding isValueSettable];
+}
+- (BOOL)canGetValueForBinding:(NSString *)_name {
+  WOAssociation *binding;
+
+  if ((binding = [self->wocBindings objectForKey:_name]) == nil)
+    return NO;
+
+  return YES;
+}
+
+- (id)performParentAction:(NSString *)_name {
+  WOContext        *ctx;
+  WOComponent      *parent;
+  WODynamicElement *content;
+  SEL              action;
+  id               result   = nil;
+
+  ctx     = [self context];
+  parent  = [ctx parentComponent];
+  content = [ctx componentContent];
+  action  = NSSelectorFromString(_name);
+  
+  if (parent == nil)  return nil;
+  if (action == NULL) return nil;
+
+  NSAssert(parent != self, @"parent component equals current component");
+
+  if (![parent respondsToSelector:action]) {
+    [self logWithFormat:@"parent %@ doesn't respond to %@",
+          [parent name], _name];
+    return nil;
+  }
+
+  self = [self retain];
+  NS_DURING {
+    WOContext_leaveComponent(ctx, self);
+    *(&result) = [parent performSelector:action];
+    WOContext_enterComponent(ctx, self, content);
+  }
+  NS_HANDLER {
+    [self release];
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+  
+  [self release];
+  return result;
+}
+
+/* OWResponder */
+
+- (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
+  return NO;
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOElement *template = nil;
+  
+  NSAssert1(self->componentFlags.isAwake,
+            @"component %@ is not awake !", self);
+  
+  [self _setContext:_ctx];
+  template = [self _woComponentTemplate];
+  
+  if (template == nil)
+    return;
+
+  if (template->takeValues) {
+    template->takeValues(template,
+                        @selector(takeValuesFromRequest:inContext:),
+                        _req, _ctx);
+  }
+  else
+    [template takeValuesFromRequest:_req inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOElement *template = nil;
+  id result = nil;
+  
+  NSAssert1(self->componentFlags.isAwake, @"component %@ is not awake!", self);
+
+  [self _setContext:_ctx];
+  template = [self _woComponentTemplate];
+  result = [template invokeActionForRequest:_req inContext:_ctx];
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOElement *template = nil;
+  NSTimeInterval st = 0.0;
+  
+  NSAssert1(self->componentFlags.isAwake,
+            @"component %@ is not awake !", self);
+  if (debugOn) {
+    if (self->context != _ctx) {
+      [self debugWithFormat:@"WARNING(%s): component ctx != ctx (%@ vs %@)",
+              __PRETTY_FUNCTION__, self->context, _ctx];
+    }
+  }
+  
+  [self _setContext:_ctx];
+  
+  if ((template = [self _woComponentTemplate]) == nil) {
+    if (debugOn) {
+      [self debugWithFormat:@"component has no template (rm=%@).",
+              [self resourceManager]];
+    }
+    return;
+  }
+  
+  if (profElements)
+    st = [[NSDateClass date] timeIntervalSince1970];
+    
+  if (template->appendResponse) {
+    template->appendResponse(template,
+                             @selector(appendToResponse:inContext:),
+                             _response, _ctx);
+  }
+  else
+    [template appendToResponse:_response inContext:_ctx];
+
+  if (profElements) {
+    NSTimeInterval diff;
+    int i;
+    diff = [[NSDateClass date] timeIntervalSince1970] - st;
+#if 1
+    for (i = [_ctx componentStackCount]; i >= 0; i--)
+      printf("  ");
+#endif
+    printf("Template %s (comp %s): %0.3fs\n",
+           [[_ctx elementID] cString],
+           [[self name] cString],
+           diff);
+  }
+}
+  
+/* WOActionResults */
+
+- (WOResponse *)generateResponse {
+  WOResponse *response = nil;
+  WOContext  *ctx = nil;
+  NSString   *ctxID;
+  
+  ctx      = [self context];
+  ctxID    = [ctx  contextID];
+  response = [WOResponse responseWithRequest:[ctx request]];
+  
+  if (ctxID == nil) {
+    [self logWithFormat:@"missing ctx-id for context %@", ctx];
+    ctxID = @"noctx";
+  }
+  
+  [ctx deleteAllElementIDComponents];
+  [ctx appendElementIDComponent:ctxID];
+  
+  WOContext_enterComponent(ctx, self, nil);
+  [self appendToResponse:response inContext:ctx];
+  WOContext_leaveComponent(ctx, self);
+  
+  [ctx deleteLastElementIDComponent];
+
+  ctx = nil;
+
+#if 0
+  if ([[[ctx request] method] isEqualToString:@"HEAD"])
+    [response setContent:[NSData data]];
+#endif
+  
+  /* HTTP/1.1 caching directive, prevents browser from caching dynamic pages */
+  if ([[ctx application] isPageRefreshOnBacktrackEnabled])
+    [response disableClientCaching];
+  
+  return response;
+}
+
+/* coding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  BOOL doesReloadTemplates = self->componentFlags.reloadTemplates;
+
+  [_coder encodeObject:self->wocBindings];
+  [_coder encodeObject:self->wocName];
+  [_coder encodeConditionalObject:self->parentComponent];
+  [_coder encodeObject:self->subcomponents];
+  [_coder encodeObject:self->wocVariables];
+  [_coder encodeConditionalObject:self->session];
+  [_coder encodeValueOfObjCType:@encode(BOOL) at:&doesReloadTemplates];
+}
+- (id)initWithCoder:(NSCoder *)_decoder {
+  if ((self = [super init])) {
+    BOOL doesReloadTemplates = YES;
+
+    self->wocBindings     = [[_decoder decodeObject] retain];
+    self->wocName         = [[_decoder decodeObject] retain];
+    self->parentComponent = [_decoder decodeObject]; // non-retained
+    self->subcomponents   = [[_decoder decodeObject] retain];
+    self->wocVariables    = [[_decoder decodeObject] retain];
+    self->session         = [_decoder decodeObject]; // non-retained
+    
+    [_decoder decodeValueOfObjCType:@encode(BOOL) at:&doesReloadTemplates];
+    [self setCachingEnabled:!doesReloadTemplates];
+  }
+  return self;
+}
+
+/* component variables */
+
+- (BOOL)isStateless {
+  return NO;
+}
+- (void)reset {
+  [self->wocVariables removeAllObjects];
+}
+
+- (void)setObject:(id)_obj forKey:(NSString *)_key {
+  _setExtraVar(self, _key, _obj);
+}
+- (id)objectForKey:(NSString *)_key {
+  return _getExtraVar(self, _key);
+}
+- (NSDictionary *)variableDictionary {
+  return self->wocVariables;
+}
+
+- (BOOL)logComponentVariableCreations {
+  /* only if we have a subclass, we can store values in ivars ... */
+  return (self->isa != WOComponentClass) ? YES : NO;
+}
+
+#if !NG_USE_KVC_FALLBACK /* only override on libFoundation */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  if (WOSetKVCValueUsingMethod(self, _key, _value)) {
+    // method is used
+    return;
+  }
+  if (WOGetKVCGetMethod(self, _key) == NULL) {
+    if (_value == nil) {
+#if 0
+      [self debugWithFormat:
+              @"storing <nil> value in component variable %@", _key];
+#endif
+      
+      if ([self->wocVariables objectForKey:_key])
+        [self setObject:nil forKey:_key];
+      
+      return;
+    }
+#if DEBUG
+    if ([self logComponentVariableCreations]) {
+      /* only if we have a subclass, we can store values in ivars ... */
+      if (![[self->wocVariables objectForKey:_key] isNotNull]) {
+        [self logWithFormat:@"Created component variable (class=%@): '%@'.", 
+                NSStringFromClass(self->isa), _key];
+      }
+    }
+#endif
+    
+    [self setObject:_value forKey:_key];
+    return;
+  }
+
+  [self logWithFormat:
+          @"value %@ could not set via method or KVC "
+          @"(self responds to %@: %s).",
+         _key, _key,
+          [self respondsToSelector:NSSelectorFromString(_key)] ? "yes" : "no"];
+#if 0
+  return NO;
+#endif
+}
+- (id)valueForKey:(NSString *)_key {
+  id value;
+  
+  if ((value = WOGetKVCValueUsingMethod(self, _key)))
+    return value;
+
+#if DEBUG && 0
+  [self logWithFormat:@"KVC: accessed the component variable %@", _key];
+#endif
+  if ((value = [self objectForKey:_key]))
+    return value;
+  
+  return nil;
+}
+
+#else /* use fallback methods on other Foundation libraries */
+
+- (void)setValue:(id)_value forUndefinedKey:(NSString *)_key {
+  // Note: this is not used on libFoundation, insufficient KVC implementation
+  
+  if (_value == nil) {
+#if 0
+    [self debugWithFormat:
+           @"storing <nil> value in component variable %@", _key];
+#endif
+    
+    if ([self->wocVariables objectForKey:_key])
+      [self setObject:nil forKey:_key];
+      
+    return;
+  }
+  
+#if DEBUG
+  if ([self logComponentVariableCreations]) {
+    /* only if we have a subclass, we can store values in ivars ... */
+    if (![[self->wocVariables objectForKey:_key] isNotNull]) {
+      [self logWithFormat:@"Created component variable (class=%@): '%@'.", 
+             NSStringFromClass(self->isa), _key];
+    }
+  }
+#endif
+  
+  [self setObject:_value forKey:_key];
+}
+- (id)valueForUndefinedKey:(NSString *)_key {
+  // Note: this is not used on libFoundation, insufficient KVC implementation
+#if DEBUG && 0
+  [self logWithFormat:@"KVC: accessed the component variable %@", _key];
+#endif
+  return [self objectForKey:_key];
+}
+
+- (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
+  // deprecated: pre-Panther method
+  [self setValue:_value forUndefinedKey:_key];
+}
+- (id)handleQueryWithUnboundKey:(NSString *)_key {
+  // deprecated: pre-Panther method
+  return [self valueForUndefinedKey:_key];
+}
+
+- (void)unableToSetNilForKey:(NSString *)_key {
+  // TODO: should we call setValue:NSNull forKey?
+  [self logWithFormat:@"ERROR: unable to set 'nil' for key: '%@'", _key];
+}
+
+#endif /* KVC */
+
+- (void)validationFailedWithException:(NSException *)_exception
+  value:(id)_value keyPath:(NSString *)_keyPath
+{
+  [self logWithFormat:
+          @"WARNING: formatter failed for value %@ (keyPath=%@): %@",
+          _value, _keyPath, [_exception reason]];
+}
+
+/* logging */
+
+- (BOOL)isEventLoggingEnabled {
+  return YES;
+}
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+- (NSString *)loggingPrefix {
+  NSString *n;
+  
+  n = [self name];
+  if ([n length] == 0)
+    return @"<component without name>";
+  
+  return n;
+}
+
+/* woo/plist unarchiving */
+
+- (id)unarchiver:(EOKeyValueUnarchiver *)_archiver 
+  objectForReference:(id)_keyPath
+{
+  return [self valueForKeyPath:_keyPath];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  // TODO: find out who triggers this
+  return [self retain];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *str;
+  id tmp;
+  
+  str = [NSMutableString stringWithCapacity:128];
+  [str appendFormat:@"<0x%08X[%@]: name=%@", self,
+         NSStringFromClass([self class]), [self name]];
+
+  if (self->parentComponent)
+    [str appendFormat:@" parent=%@", [self->parentComponent name]];
+  if (self->subcomponents)
+    [str appendFormat:@" #subs=%i", [self->subcomponents count]];
+  
+  if (self->componentFlags.isAwake)
+    [str appendFormat:@" awake=0x%08X", self->context];
+  else if (self->context == nil)
+    [str appendString:@" no-ctx"];
+  
+  if ((tmp = _getExtraVar(self, @"__worm")))
+    [str appendFormat:@" rm=%@", tmp];
+  
+  [str appendString:@">"];
+  return str;
+}
+
+@end /* WOComponent */
+
+@implementation WOComponent(Statistics)
+
+- (NSString *)descriptionForResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  return [self name];
+}
+
+@end /* WOComponent(Statistics) */
+
+@implementation WOComponent(AdvancedBindingAccessors)
+
+- (void)setUnsignedIntValue:(unsigned)_value forBinding:(NSString *)_name {
+  [self setValue:[NSNumber numberWithUnsignedInt:_value] forBinding:_name];
+}
+- (unsigned)unsignedIntValueForBinding:(NSString *)_name {
+  return [[self valueForBinding:_name] unsignedIntValue];
+}
+
+- (void)setIntValue:(int)_value forBinding:(NSString *)_name {
+  [self setValue:[NSNumber numberWithInt:_value] forBinding:_name];
+}
+- (int)intValueForBinding:(NSString *)_name {
+  return [[self valueForBinding:_name] intValue];
+}
+
+- (void)setBoolValue:(BOOL)_value forBinding:(NSString *)_name {
+  [self setValue:[NSNumber numberWithBool:_value] forBinding:_name];
+}
+- (BOOL)boolValueForBinding:(NSString *)_name {
+  return [[self valueForBinding:_name] boolValue];
+}
+
+#if !NG_USE_KVC_FALLBACK
+- (id)handleQueryWithUnboundKey:(NSString *)_key {
+  [self logWithFormat:@"query for unbound key: %@", _key];
+  return [super handleQueryWithUnboundKey:_key];
+}
+#endif
+
+@end /* WOComponent(AdvancedBindingAccessors) */
diff --git a/skyrix-sope/NGObjWeb/WOComponentDefinition.h b/skyrix-sope/NGObjWeb/WOComponentDefinition.h
new file mode 100644 (file)
index 0000000..771a68e
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOComponentDefinition_H__
+#define __NGObjWeb_WOComponentDefinition_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSDate.h>
+
+@class NSString, NSMutableDictionary, NSArray, NSMutableArray, NSMutableSet;
+@class NSDictionary, NSURL;
+@class WOElement, WOComponent, WOResourceManager, WOTemplate;
+
+/*
+  Component definitions cache the contents of a .wo directory,
+  this is the HTML and wod files.
+*/
+@interface WOComponentDefinition : NSObject
+{
+@private
+  NSString       *name;
+  NSString       *path; /* can also contain a URL! */
+  NSURL          *baseUrl;
+  NSString       *frameworkName;
+  Class          componentClass;
+  NSTimeInterval lastTouch;
+  WOTemplate     *template;
+}
+
+- (id)initWithName:(NSString *)_name
+  path:(NSString *)_path
+  baseURL:(NSURL *)_baseUrl
+  frameworkName:(NSString *)_frameworkName;
+
+/* accessors */
+
+- (Class)componentClass;
+- (NSString *)componentName;
+
+/* templates */
+
+- (WOTemplate *)template;
+
+/* instantiation */
+
+- (WOComponent *)instantiateWithResourceManager:(WOResourceManager *)_rm
+  languages:(NSArray *)_languages;
+
+/* caching */
+
+- (void)touch; /* mark as used .. */
+- (NSTimeInterval)lastTouch;
+
+/* privates */
+
+- (void)_finishInitializingComponent:(WOComponent *)_component;
+
+@end
+
+@interface NSObject(WOComponentInfo)
+
+- (NSString *)componentName;
+- (Class)componentClass;
+- (NSDictionary *)bindings;
+
+@end
+
+#endif /* __NGObjWeb_WOComponentDefinition_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOComponentDefinition.m b/skyrix-sope/NGObjWeb/WOComponentDefinition.m
new file mode 100644 (file)
index 0000000..4791d9c
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOComponentDefinition.h"
+#include "WOComponent+private.h"
+#include "WOComponentFault.h"
+#include "WOScriptedComponent.h"
+#include <NGObjWeb/WOAssociation.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOElement.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+#include <EOControl/EOControl.h>
+
+#include <NGObjWeb/WOTemplateBuilder.h>
+
+static Class    StrClass    = Nil;
+static Class    DictClass   = Nil;
+static Class    AssocClass  = Nil;
+static Class    NumberClass = Nil;
+static Class    DateClass   = Nil;
+static NSNumber *yesNum     = nil;
+static NSNumber *noNum      = nil;
+
+@interface WOComponent(UsedPrivates)
+- (void)setBaseURL:(id)_url;
+@end
+
+@interface WONoContentElement : WOElement
+{
+  WOComponentDefinition *cdef;
+  NSString *element;
+}
+- (id)initWithElementName:(NSString *)_elementName
+  attributes:(NSDictionary *)_attributes
+  contentElements:(NSArray *)_subElements
+  componentDefinition:(WOComponentDefinition *)_cdef;
+@end
+
+@interface _WOStaticHTMLElement : WOElement
+{
+  NSString *text;
+}
+- (id)initWithBuffer:(const char *)_buffer length:(unsigned)_len;
+@end
+
+@interface WOComponentDefinition(PrivateMethods)
+
+- (BOOL)load;
+
+@end
+
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOSession.h>
+
+/*
+  TODO:
+  
+  WO's instantiation method is 
+    - componentInstanceInContext:forComponentReference:
+  with the primary being
+    - _componentInstanceInContext:forComponentReference:
+  
+  Maybe we should change to that. Currently this flow is a bit broken because
+  the resourcemanager sits in the middle, though I'm pretty sure that some
+  older WO used WOResourceManager just like we do in the moment.
+*/
+
+@implementation WOComponent(InfoSetup)
+
+- (Class)componentFaultClass {
+  return [WOComponentFault class];
+}
+
+- (NSMutableDictionary *)instantiateChildComponentsInTemplate:(WOTemplate *)_t
+  languages:(NSArray *)_languages
+{
+  NSMutableDictionary *childComponents = nil;
+  WOResourceManager *_rm;
+  WOTemplate *tmpl;
+  NSEnumerator *keys;
+  NSString     *key;
+  
+  if ((tmpl = _t) == nil)
+    return nil;
+  
+  _rm = [[WOApplication application] resourceManager];
+  
+  if ([tmpl hasSubcomponentInfos] == 0)
+    return nil;
+  
+  keys = [tmpl infoKeyEnumerator];
+  while ((key = [keys nextObject])) {
+    WOSubcomponentInfo *childInfo = nil;
+    WOComponentFault   *child     = nil;
+      
+    childInfo = [tmpl subcomponentInfoForKey:key];
+    
+    child = [[WOComponentFault alloc]
+              initWithResourceManager:nil //_rm
+              pageName:[childInfo componentName]
+              languages:_languages
+              bindings:[childInfo bindings]];
+
+    if (child) {
+      if (childComponents == nil)
+        childComponents = [NSMutableDictionary dictionaryWithCapacity:16];
+        
+      [childComponents setObject:child forKey:key];
+      [child release];
+    }
+    else {
+      [self logWithFormat:
+              @"ERROR(%s): "
+             @"Could not instantiate child fault %@, component: '%@'",
+              __PRETTY_FUNCTION__, key, [childInfo componentName]];
+    }
+  }
+  return childComponents;
+}
+
+- (id)initWithName:(NSString *)_cname
+  template:(WOTemplate *)_template
+  inContext:(WOContext *)_ctx
+{
+  // Note: the _template can be nil and will then get looked up dynamically!
+  [self setName:_cname];
+  if ((self = [self initWithContext:_ctx])) {
+    NSMutableDictionary *childComponents;
+    NSArray *langs;
+    
+    langs = [self hasSession]
+      ? [[self session] languages]
+      : [[_ctx request] browserLanguages];
+    
+    childComponents = [self instantiateChildComponentsInTemplate:_template
+                           languages:langs];
+    [self setSubComponents:childComponents];
+    [self setTemplate:_template];
+  }
+  return self;
+}
+
+- (id)initWithComponentDefinition:(WOComponentDefinition *)_cdef 
+  inContext:(WOContext *)_ctx
+{
+  /* 
+     HACK HACK HACK CD: 
+     We reuse the wocVariables ivar to pass over the component definition to 
+     the component which will then call -_finishInitializingComponent: on the
+     definition for applying the .woo.
+     
+     Sideeffects: if a component subclass uses extra vars prior calling
+     WOComponent -init, it will run into "issues".
+  */
+  NSAssert(self->wocVariables == nil,
+          @"extra variables dict is already set! cannot transfer component "
+          @"definition in that variable (use the HACK)");
+  self->wocVariables = (id)[_cdef retain];
+  
+  return [self initWithName:[_cdef componentName]
+              template:[_cdef template]
+              inContext:_ctx];
+}
+
+@end /* WOComponent(InfoSetup) */
+
+@implementation WOComponentDefinition
+
+static BOOL debugOn     = NO;
+static BOOL profLoading = NO;
+static BOOL enableClassLessComponents = NO;
+static BOOL enableWOOFiles            = NO;
+
++ (int)version {
+  return 4;
+}
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  NSUserDefaults *ud;
+  if (isInitialized) return;
+  isInitialized = YES;
+  ud = [NSUserDefaults standardUserDefaults];
+    
+  StrClass    = [NSString      class];
+  DictClass   = [NSMutableDictionary class];
+  AssocClass  = [WOAssociation class];
+  NumberClass = [NSNumber      class];
+  DateClass   = [NSDate        class];
+    
+  yesNum = [[NumberClass numberWithBool:YES] retain];
+  noNum  = [[NumberClass numberWithBool:NO]  retain];
+  
+  profLoading = [[ud objectForKey:@"WOProfileLoading"] boolValue];
+  enableClassLessComponents = 
+    [ud boolForKey:@"WOEnableComponentsWithoutClasses"];
+  enableWOOFiles = [ud boolForKey:@"WOComponentLoadWOOFiles"];
+  debugOn        = [ud boolForKey:@"WODebugComponentDefinition"];
+}
+
+- (id)initWithName:(NSString *)_name
+  path:(NSString *)_path
+  baseURL:(NSURL *)_baseUrl
+  frameworkName:(NSString *)_frameworkName
+{
+  /* 
+     this method is usually called by WOResourceManager
+     (_definitionWithName:...) 
+  */
+  if ((self = [super init])) {
+    /*
+      'name'    is the name of the component
+      'path'    contains a string or a NSURL with the location of the directory
+                containing the component - TODO: explain who calculates that!
+      'baseURL' contains a URL like /AppName/FrameworkName/Component/Eng.lProj
+                (the external URL of the component, not sure whether this is
+                actually used somewhere)
+    */
+    NSZone *z = [self zone];
+    
+    self->name          = [_name          copyWithZone:z];
+    self->path          = [_path          copyWithZone:z];
+    self->baseUrl       = [_baseUrl       copyWithZone:z];
+    self->frameworkName = [_frameworkName copyWithZone:z];
+  
+    if (debugOn) {
+      [self debugWithFormat:
+             @"init: '%@' path='%@'\n  URL='%@'\n  framework='%@'",
+             self->name, self->path, [self->baseUrl absoluteString], 
+             self->frameworkName];
+    }
+    
+    if (![self load]) { /* TODO: is this really required? */
+      [self release];
+      return nil;
+    }
+  }
+  return self;
+}
+
+- (id)init {
+  [self debugWithFormat:@"ERROR: called -init on WOComponentDefinition!"];
+  [self release];
+  return nil;
+}
+
+- (void)dealloc {
+  [self->template      release];
+  [self->name          release];
+  [self->path          release];
+  [self->baseUrl       release];
+  [self->frameworkName release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (Class)componentClassForScript:(WOComponentScript *)_script {
+  return Nil;
+}
+
+- (void)setComponentClass:(Class)_class {
+  self->componentClass = _class;
+}
+- (Class)componentClass {
+  if (self->componentClass == Nil)
+    self->componentClass = NSClassFromString(self->name);
+  
+  if (self->componentClass != Nil)
+    return self->componentClass;
+
+  if (self->name == nil)
+    return Nil;
+  
+  if ([self->name isAbsolutePath])
+       ;
+  else if ([self->name rangeOfString:@"."].length > 0)
+       ;
+  else if (enableClassLessComponents)
+       ;
+  else {
+    [self logWithFormat:@"Note: did not find component class with name '%@'",
+           self->name];
+  }
+  return Nil;
+}
+- (NSString *)componentName {
+  return self->name;
+}
+
+- (WOTemplate *)template {
+  return self->template;
+}
+
+- (NSString *)path {
+  return self->path;
+}
+
+- (NSURL *)baseURL {
+  return self->baseUrl;
+}
+- (NSString *)frameworkName {
+  return self->frameworkName;
+}
+
+/* caching */
+
+- (void)touch {
+  self->lastTouch = [DateClass timeIntervalSinceReferenceDate];
+}
+
+- (NSTimeInterval)lastTouch {
+  return self->lastTouch;
+}
+
+/* instantiation */
+
+- (BOOL)_checkComponentClassValidity:(Class)cClass {
+#if 0
+  /* this make no sense, need -isSubclassOfClass: ..,
+     class instances are never isKindOfClass:WOElement ... 
+  */
+  {
+    static Class WOElementClass = Nil;
+    if (WOElementClass == Nil) WOElementClass = [WOElement class];
+    if (![cClass isKindOfClass:WOElementClass] && cClass != nil) {
+      [self logWithFormat:@"WARNING(%s:%i): "
+            @"component class %@ is not a subclass of WOElement !",
+            __PRETTY_FUNCTION__, __LINE__,
+            NSStringFromClass(cClass)];
+      return NO;
+    }
+  }
+#endif
+  return YES;
+}
+- (BOOL)_checkComponentValidity:(id)component class:(Class)cClass {
+  if (![component isKindOfClass:cClass] && component != nil) {
+    NSLog(@"WARNING2(%s:%i): component %@ is not a subclass of "
+          @"component class %@ !",
+          __PRETTY_FUNCTION__, __LINE__,
+          component, NSStringFromClass(cClass));
+    return NO;
+  }
+  return YES;
+}
+
+- (void)_applyWOOVariables:(NSDictionary *)_vars
+  onComponent:(WOComponent *)_component 
+{
+  EOKeyValueUnarchiver *unarchiver;
+  NSAutoreleasePool    *pool;
+  NSEnumerator *keys;
+  NSString     *key;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  unarchiver = 
+    [[[EOKeyValueUnarchiver alloc] initWithDictionary:_vars] autorelease];
+  [unarchiver setDelegate:_component];
+  
+  keys = [_vars keyEnumerator];
+  while ((key = [keys nextObject])) {
+    id object;
+    
+    object = [unarchiver decodeObjectForKey:key];
+    [_component takeValue:object forKey:key];
+  }
+  [unarchiver finishInitializationOfObjects];
+  [unarchiver awakeObjects];
+
+  [pool release];
+}
+
+- (void)_applyWOOVariablesOnComponent:(WOComponent *)_component {
+  /* 
+     Note: we still need this, as components are not required to load the
+           template at all!
+  */
+  NSString     *wooPath;
+  NSDictionary *woo;
+
+  wooPath = [[_component path] stringByAppendingPathExtension:@"woo"];
+  if (![[NSFileManager defaultManager] fileExistsAtPath:wooPath])
+    return;
+  
+  if ((woo = [NSDictionary dictionaryWithContentsOfFile:wooPath]) == nil) {
+    [self logWithFormat:@"ERROR: could not load .woo-file: '%@'", wooPath];
+    return;
+  }
+  
+  [self _applyWOOVariables:[woo objectForKey:@"variables"]
+        onComponent:_component];
+}
+
+- (void)_finishInitializingComponent:(WOComponent *)_component {
+  if (self->baseUrl)
+    [_component setBaseURL:self->baseUrl];
+
+  if (enableWOOFiles) {
+    if (self->template) {
+      [self _applyWOOVariables:
+              [self->template keyValueArchivedTemplateVariables]
+            onComponent:_component];
+    }
+    else
+      [self _applyWOOVariablesOnComponent:_component];
+  }
+}
+
+- (WOComponent *)instantiateWithResourceManager:(WOResourceManager *)_rm
+  languages:(NSArray *)_languages
+{
+  WOComponent       *component = nil;
+  Class             cClass;
+  WOComponentScript *script;
+  
+  if ((script = [self->template componentScript])) 
+    cClass = [WOScriptedComponent class];
+  else
+    cClass = [self componentClass];
+  
+  if (cClass == nil) {
+    NSString *tmpPath;
+
+    if (enableClassLessComponents) {
+      [self debugWithFormat:@"Note: missing class for component: '%@'",
+             [self componentName]];
+    }
+    else {
+      [self logWithFormat:@"Note: missing class for component: '%@'",
+             [self componentName]];
+    }
+    
+    tmpPath = [self->name stringByAppendingPathExtension:@"html"];
+    tmpPath = [self->path stringByAppendingPathComponent:tmpPath];
+    
+    if ([[NSFileManager defaultManager] fileExistsAtPath:tmpPath]) {
+      cClass = [WOComponent class];
+    }
+    else {
+      [self debugWithFormat:@"Note: did not find .html template at path: '%@'",
+             tmpPath];
+    }
+  }
+  
+  if (![self _checkComponentClassValidity:cClass]) {
+    [self logWithFormat:@"Component Class '%@' is not valid.", cClass];
+    return nil;
+  }
+  
+  /* instantiate object (this will call _finishInitializingComponent) */
+  
+  component = [[cClass alloc] initWithComponentDefinition:self
+                             inContext:[[WOApplication application] context]];
+  component = [component autorelease];
+  if (component == nil)
+    return nil;
+  
+  /* check validity */
+  
+  if (debugOn)
+    [self _checkComponentValidity:component class:cClass];
+
+  if (debugOn) {
+    if (![component isKindOfClass:cClass]) {
+      [self debugWithFormat:
+              @"WARNING(%s:%i): component '%@' is not a subclass of "
+          @"component class '%@' !",
+          __PRETTY_FUNCTION__, __LINE__,
+          component, NSStringFromClass(cClass)];
+    }
+  }
+  return component;
+}
+
+/* templates */
+
+- (BOOL)load {
+  WOTemplateBuilder *builder;
+  NSURL *url;
+
+  if (self->path == nil)
+    /* a pathless component (a component without a template file) */
+    return YES;
+  
+  /*
+    Note: the URL can either point directly to the .wo or .wox file entry or
+          it can point to a .lproj inside a .wo (eg Main.wo/English.lproj)
+    Note: actually the WOTemplateBuilder only supports file URLs in the moment,
+          it just checks the path extension to select the proper builder.
+  */
+  url = [self->path isKindOfClass:[NSURL class]]
+    ? (NSURL *)self->path
+    : [[[NSURL alloc] initFileURLWithPath:self->path] autorelease];
+  
+  if (debugOn) [self debugWithFormat:@"url: %@", [url absoluteString]];
+  
+  // TODO: maybe we should move the builder selection to the resource-manager
+  builder = [WOTemplateBuilder templateBuilderForURL:url];
+  if (debugOn) [self debugWithFormat:@"builder: %@", builder];
+  
+  self->template = [[builder buildTemplateAtURL:url] retain];
+  if (debugOn) [self debugWithFormat:@"template: %@", self->template];
+  
+  return self->template ? YES : NO;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms = [NSMutableString stringWithCapacity:64];
+
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->name)    [ms appendFormat:@" name=%@", self->name];
+  if (self->path)    [ms appendFormat:@" path=%@", self->path];
+  if (self->baseUrl) [ms appendFormat:@" base=%@", self->baseUrl];
+  if (self->frameworkName) 
+    [ms appendFormat:@" framework=%@", self->frameworkName];
+  
+  if (!self->template) [ms appendString:@" no-template"];
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* WOComponentDefinition */
+
+@implementation WONoContentElement
+
+- (id)initWithElementName:(NSString *)_elementName
+  attributes:(NSDictionary *)_attributes
+  contentElements:(NSArray *)_subElements
+  componentDefinition:(WOComponentDefinition *)_cdef
+{
+  self->cdef    = [_cdef retain];
+  self->element = [_elementName copy];
+  return self;
+}
+
+- (void)dealloc {
+  [self->cdef    release];
+  [self->element release];
+  [super dealloc];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [_response appendContentHTMLString:@"<<missing element '"];
+  [_response appendContentHTMLString:self->element];
+  [_response appendContentHTMLString:@"' in component '"];
+  [_response appendContentHTMLString:[self->cdef componentName]];
+  [_response appendContentHTMLString:@"'>>"];
+}
+
+@end /* WONoContentElement */
+
+@implementation _WOStaticHTMLElement
+
+- (id)initWithBuffer:(const char *)_buffer length:(unsigned)_len {
+  if (StrClass == Nil)
+    StrClass = [NSString class];
+  
+  self->text = [[StrClass alloc] initWithCString:_buffer length:_len];
+  return self;
+}
+
+- (void)dealloc {
+  [self->text release];
+  [super dealloc];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (self->text)
+    [_response appendContentString:self->text];
+}
+
+@end /* _WOStaticHTMLElement */
diff --git a/skyrix-sope/NGObjWeb/WOComponentFault.h b/skyrix-sope/NGObjWeb/WOComponentFault.h
new file mode 100644 (file)
index 0000000..f6a7a91
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOComponentFault_H__
+#define __NGObjWeb_WOComponentFault_H__
+
+/*
+  This is a private stand-in class for a sub-component that isn't used yet.
+  This is required to be able to support recursive component nesting (otherwise
+  component instantiation would loop).
+*/
+
+#import <Foundation/NSObject.h>
+#include <NGObjWeb/WOComponent.h>
+
+@class NSString, NSArray, NSDictionary;
+@class WOComponent, WOContext, WOResourceManager;
+
+@interface WOComponentFault : NSObject < NSCoding >
+{
+@private
+  WOContext         *ctx;
+  WOResourceManager *resourceManager;
+  NSString          *pageName;
+  NSArray           *languages;
+  NSDictionary      *bindings;
+}
+
+- (id)initWithResourceManager:(WOResourceManager *)_rm
+  pageName:(NSString *)_name
+  languages:(NSArray *)_langs
+  bindings:(NSDictionary *)_bindings;
+
+// delayed notifications
+
+- (void)ensureAwakeInContext:(WOContext *)_ctx;
+- (void)_sleepWithContext:(WOContext *)_ctx;
+
+// resolving
+
+- (WOComponent *)resolveWithParent:(WOComponent *)_parent;
+
+// typing
+
+- (BOOL)isComponentFault;
+
+@end
+
+@interface WOComponent(WOComponentFault)
+- (BOOL)isComponentFault;
+@end
+
+#endif /* __NGObjWeb_WOComponentFault_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOComponentFault.m b/skyrix-sope/NGObjWeb/WOComponentFault.m
new file mode 100644 (file)
index 0000000..74352fe
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOComponentFault.h"
+#include "WOComponent+private.h"
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@implementation WOComponentFault
+
++ (int)version {
+  return 2;
+}
+
+- (id)initWithResourceManager:(WOResourceManager *)_rm
+  pageName:(NSString *)_name
+  languages:(NSArray *)_langs
+  bindings:(NSDictionary *)_bindings
+{
+  NSZone *z = [self zone];
+  self->resourceManager = RETAIN(_rm);
+  self->pageName        = [_name     copyWithZone:z];
+  self->languages       = [_langs    copyWithZone:z];
+  self->bindings        = [_bindings copyWithZone:z];
+  
+  [[NSNotificationCenter defaultCenter]
+                         addObserver:self
+                         selector:@selector(_contextWillDealloc:)
+                         name:@"WOContextWillDeallocate" object:nil];
+  
+  return self;
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  RELEASE(self->bindings);
+  RELEASE(self->resourceManager);
+  RELEASE(self->pageName);
+  RELEASE(self->languages);
+  [super dealloc];
+}
+
+/* ctx dealloc */
+
+- (void)_contextWillDealloc:(NSNotification *)_notification {
+#if DEBUG
+  NSAssert(_notification, @"missing valid notification arg ...");
+#endif
+  
+  if (self->ctx == nil)
+    /* component isn't interested in context anyway ... */
+    return;
+  if (![[self->ctx contextID] isEqualToString:[_notification object]])
+    /* not the component's context ... */
+    return;
+  
+  self->ctx = nil;
+}
+
+/* cached awake & sleep */
+
+- (void)ensureAwakeInContext:(WOContext *)_ctx {
+  self->ctx = _ctx;
+}
+- (void)_awakeWithContext:(WOContext *)_ctx {
+  [self ensureAwakeInContext:_ctx];
+}
+- (void)_sleepWithContext:(WOContext *)_ctx {
+  self->ctx = nil;
+}
+
+/* resolve */
+
+- (WOComponent *)resolveWithParent:(WOComponent *)_parent {
+  WOComponent *c;
+  WOResourceManager *rm;
+  
+#if DEBUG && 0
+  [self logWithFormat:@"resolving fault for component %@", self->pageName];
+#endif
+
+  if ((rm = self->resourceManager))
+    ;
+  else if ((rm = [_parent resourceManager]))
+    ;
+  else
+    rm = [[WOApplication application] resourceManager];
+  
+  c = [rm pageWithName:self->pageName languages:self->languages];
+  //[self logWithFormat:@"  rm:   %@", rm];
+  //[self logWithFormat:@"  c:    %@", c];
+  
+  [c setBindings:self->bindings];
+  [c setParent:_parent];
+  if (self->ctx) [c _awakeWithContext:self->ctx];
+  
+  if (c == NULL) {
+    [self logWithFormat:@"could not resolve fault for component: %@",
+            self->pageName];
+    [self logWithFormat:@"  resource-manager: %@", rm];
+    [self logWithFormat:@"  parent:           %@", _parent];
+  }
+  
+  return c;
+}
+
+- (void)setParent:(id)_parent {
+  /*
+    Not attached to a parent, this is called by WOComponent -dealloc on
+    each child (which can be a fault).
+  */
+}
+
+- (BOOL)isComponentFault {
+  return YES;
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->pageName];
+  [_coder encodeObject:self->languages];
+  [_coder encodeObject:self->bindings];
+}
+- (id)initWithCoder:(NSCoder *)_decoder {
+  if ((self = [super init])) {
+    self->pageName  = [[_decoder decodeObject] copy];
+    self->languages = [[_decoder decodeObject] retain];
+    self->bindings  = [[_decoder decodeObject] retain];
+  }
+  return self;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+@end /* WOComponentFault */
+
+@implementation WOComponent(WOComponentFault)
+
+- (BOOL)isComponentFault {
+  return NO;
+}
+
+@end /* WOComponent(WOComponentFault) */
diff --git a/skyrix-sope/NGObjWeb/WOComponentRequestHandler.h b/skyrix-sope/NGObjWeb/WOComponentRequestHandler.h
new file mode 100644 (file)
index 0000000..ae1e3ef
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOComponentRequestHandler_H__
+#define __NGObjWeb_WOComponentRequestHandler_H__
+
+#include <NGObjWeb/WORequestHandler.h>
+
+@interface WOComponentRequestHandler : WORequestHandler
+@end
+
+#endif /* __NGObjWeb_WORequestHandler_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOComponentRequestHandler.m b/skyrix-sope/NGObjWeb/WOComponentRequestHandler.m
new file mode 100644 (file)
index 0000000..870fece
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOComponentRequestHandler.h"
+#include "WORequestHandler+private.h"
+#include "WOContext+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOComponent.h>
+#include "common.h"
+
+@interface WOApplication(Privates)
+- (WOSession *)_initializeSessionInContext:(WOContext *)_ctx;
+@end
+
+@implementation WOComponentRequestHandler
+
++ (int)version {
+  return [super version] + 0 /* 2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (WOResponse *)restoreSessionWithID:(NSString *)_sid
+  inContext:(WOContext *)_ctx
+{
+  WOApplication *app = [WOApplication application];
+  WOResponse *response = nil;
+  
+  if (_sid == nil) {
+    // invalid session ID (or no session-ID ?!, which is no error ?) */
+    response = [app handleSessionRestorationErrorInContext:_ctx];
+  }
+  else {
+    WOSession *session = nil;
+    
+    if ((session = [app restoreSessionWithID:_sid inContext:_ctx])) {
+      // awake restored session
+      [_ctx setSession:session];
+      [session _awakeWithContext:_ctx];
+      
+      [session awake];
+      response = nil;
+    }
+    else {
+      response = [app handleSessionRestorationErrorInContext:_ctx];
+    }
+  }
+  return response;
+}
+
+/*
+  The request handler path of a component URI looks like this:
+
+    sessionID/componentName/contextID/elementID/instance/server
+*/
+
+- (WOResponse *)handleRequest:(WORequest *)_request {
+  NSString      *sessionID        = nil;
+  WOApplication *application      = nil;
+  WOContext     *context          = nil;
+  WOResponse    *response         = nil;
+  WOSession     *session          = nil;
+  WOComponent   *component        = nil;
+  BOOL          isLocked          = NO;
+  NSString      *handlerPath      = nil;
+
+  if (_request == nil) return nil;
+
+  application = [WOApplication application];
+  handlerPath = [_request requestHandlerPath];
+
+#if 0
+  NSLog(@"[component request handler] path=%@ ..", handlerPath);
+#endif
+
+  if (![application allowsConcurrentRequestHandling]) {
+    [application lockRequestHandling];
+    isLocked = YES;
+  }
+  
+  context = [WOContext contextWithRequest:_request];
+  [[[NSThread currentThread] threadDictionary]
+              setObject:context forKey:@"WOContext"];
+  
+  /*
+    parse handler path (URL)
+
+    The format is:
+
+      session/context.element-id
+  */
+  if ([handlerPath length] > 0) {
+    NSArray *spath = [_request requestHandlerPathArray];
+
+    if ([spath count] > 1)
+      [context setRequestSenderID:[spath objectAtIndex:1]];
+    if ([spath count] > 0)
+      sessionID = [spath objectAtIndex:0];
+  }
+  
+  if ([sessionID length] == 0)
+    sessionID = [application sessionIDFromRequest:_request];
+  
+#if 0
+  NSLog(@"%s: made context %@ (cid=%@, sn=%@) ..", __PRETTY_FUNCTION__
+        context, [context contextID], sessionID);
+#endif
+  
+  [application awake];
+  
+  /* restore or create session */
+  if (sessionID) {
+    response = [self restoreSessionWithID:sessionID inContext:context];
+    session = response ? nil : [context session];
+    
+    if (session) {
+      /* awake stored page */
+      component = [session restorePageForContextID:[context currentElementID]];
+      
+      if (component == nil)
+        response = [application handlePageRestorationErrorInContext:context];
+#if DEBUG
+      else {
+        NSLog(@"%s: restored request component %@", __PRETTY_FUNCTION__,
+              component);
+      }
+#endif
+    }
+    else if (response == nil) {
+      [[WOApplication application]
+                      logWithFormat:
+                        @"WARNING: got no session restoration error, "
+                        @"but missing session !"];
+    }
+  }
+  else {
+    /* create new session */
+    session = [application _initializeSessionInContext:context];
+    if (session) {
+      /* awake created session */
+      [session awake];
+      component = [application pageWithName:nil inContext:context];
+    }
+    else
+      response = [application handleSessionCreationErrorInContext:context];
+  }
+  
+  if ((session != nil) && (component != nil) && (response == nil)) {
+    WOComponent *newPage = nil;
+
+    [[session retain] autorelease];
+    
+#if DEBUG
+    NSAssert(application, @"missing application object ..");
+    NSAssert(session,     @"missing session object ..");
+#endif
+    
+    /* set request page in context */
+    [context setPage:component];
+    
+    /* run take-values phase */
+    [application takeValuesFromRequest:_request inContext:context];
+    
+    /* run invoke-action phase */
+    newPage = [application invokeActionForRequest:_request inContext:context];
+
+    /* process resulting page */
+    if (newPage == nil) {
+      if ((newPage = [context page]) == nil) {
+        newPage = [application pageWithName:nil inContext:context];
+        [context setPage:newPage];
+      }
+    }
+    else if ([newPage isKindOfClass:[WOComponent class]])
+      [context setPage:newPage];
+
+#if DEBUG
+    [self debugWithFormat:@"%s: new page: %@", __PRETTY_FUNCTION__, newPage];
+#endif
+    
+    /* generate response */
+#if 1 /* new code, ensure that _fixupResponse is called */
+    response = [self generateResponseForComponent:[context page]
+                    inContext:context
+                    application:application];
+#else /* old code */
+    response = [context response];
+    [application appendToResponse:response inContext:context];
+#endif
+  }
+  else {
+    NSLog(@"WARNING(%s): did not enter request/response transaction ...",
+          __PRETTY_FUNCTION__);
+  }
+
+  /* tear down */
+
+  /* sleep objects */
+  [context sleepComponents];
+  [session sleep];
+  
+  /* save objects */
+  if (session) {
+    if ([context savePageRequired])
+      [session savePage:[context page]];
+    
+    NSLog(@"saving session %@", [session sessionID]);
+    [application saveSessionForContext:context];
+  }
+  
+  [application sleep];
+  
+  /* locking */
+  
+  if (isLocked) {
+    [application unlockRequestHandling];
+    isLocked = NO;
+  }
+
+  [[[NSThread currentThread] threadDictionary]
+              removeObjectForKey:@"WOContext"];
+  return response;
+}
+
+@end /* WOComponentRequestHandler */
diff --git a/skyrix-sope/NGObjWeb/WOContext+private.h b/skyrix-sope/NGObjWeb/WOContext+private.h
new file mode 100644 (file)
index 0000000..31552e7
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOContext_private_H__
+#define __NGObjWeb_WOContext_private_H__
+
+#include <NGObjWeb/WOContext.h>
+
+@class WOComponent, WOSession, WOResponse, WOElement, WODynamicElement;
+
+extern void WOContext_enterComponent
+(WOContext *_ctx, WOComponent *_component, WOElement *element);
+extern void WOContext_leaveComponent(WOContext *_ctx, WOComponent *_component);
+
+@interface WOContext(NGObjWebInternal)
+
+- (void)enterComponent:(WOComponent *)_component content:(WOElement *)_content;
+- (void)leaveComponent:(WOComponent *)_component;
+- (void)sleepComponents;
+- (WOComponent *)parentComponent;
+- (WODynamicElement *)componentContent;
+
+- (void)setSession:(WOSession *)_session;
+- (void)setPage:(WOComponent *)_page;
+- (void)setResponse:(WOResponse *)_response;
+
+@end
+
+@interface WOContext(FormSupport)
+
+- (void)addActiveFormElement:(WOElement *)_formElement;
+- (WOElement *)activeFormElement;
+
+@end
+
+#if !LIB_FOUNDATION_BOEHM_GC
+
+@interface WOContext(DeallocNotifications)
+/* dealloc observers are *not* retained !!! */
+- (void)_objectWillDealloc:(id)_object;
+- (void)addDeallocObserver:(id)_observer;
+- (void)removeDeallocObserver:(id)_observer;
+@end
+
+#endif
+
+#endif /* __NGObjWeb_WOContext_private_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOContext.m b/skyrix-sope/NGObjWeb/WOContext.m
new file mode 100644 (file)
index 0000000..88b19b6
--- /dev/null
@@ -0,0 +1,1037 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOContext.h>
+#include "NSObject+WO.h"
+#include "WOComponent+private.h"
+#include "WOContext+private.h"
+#include "WOApplication+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSession.h>
+#import <EOControl/EONull.h>
+#include "WOElementID.h"
+#include "common.h"
+#include <time.h>
+
+
+@interface WOContext(Privates5)
+- (NSArray *)_componentStack;
+@end
+
+@interface WOComponent(Cursors)
+- (void)pushCursor:(id)_obj;
+- (id)popCursor;
+- (id)cursor;
+@end
+
+static Class WOAppClass = Nil;
+
+@implementation WOContext
+
++ (int)version {
+  return 7;
+}
+
+static Class MutableStrClass    = Nil;
+static int  contextCount        = 0;
+static int  logComponents       = -1;
+static int  relativeURLs        = -1;
+static BOOL debugOn             = NO;
+static int  debugCursor         = -1;
+static BOOL debugComponentAwake = NO;
+static BOOL testNSURLs          = NO;
+static BOOL newCURLStyle        = NO;
+static NSString *WOApplicationSuffix = nil;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInitialize = NO;
+  if (didInitialize) return;
+
+  if (WOAppClass == Nil)
+    WOAppClass = [WOApplication class];
+  if (MutableStrClass == Nil)
+    MutableStrClass = [NSMutableString class];
+  
+  didInitialize = YES;
+    
+  logComponents = [[ud objectForKey:@"WOLogComponents"] boolValue] ? 1 : 0;
+  relativeURLs  = [[ud objectForKey:@"WOUseRelativeURLs"] boolValue]? 1 : 0;
+  debugCursor         = [ud boolForKey:@"WODebugCursor"] ? 1 : 0;
+  debugComponentAwake = [ud boolForKey:@"WODebugComponentAwake"];
+  WOApplicationSuffix = [[ud stringForKey:@"WOApplicationSuffix"] copy];
+}
+
++ (id)contextWithRequest:(WORequest *)_request {
+  return [[(WOContext *)[self alloc] initWithRequest:_request] autorelease];
+}
+
+- (id)initWithRequest:(WORequest *)_request {
+  if ((self = [super init])) {
+    unsigned char buf[24];
+    self->qpJoin = @"&";
+    
+    sprintf(buf, "%03x%08x%08x", ++contextCount, (int)time(NULL), (int)self);
+    self->ctxId = [[NSString alloc] initWithCString:buf];
+    
+    self->elementID = [[WOElementID alloc] init];
+    self->awakeComponents = [[NSMutableSet alloc] initWithCapacity:64];
+    
+    self->request  = [_request retain];
+    self->response = [[WOResponse responseWithRequest:_request] retain];
+  }
+  return self;
+}
+
++ (id)context {
+  return [[[self alloc] init] autorelease];
+}
+- (id)init {
+  return [self initWithRequest:nil];
+}
+
+/* components */
+
+- (void)sleepComponents {
+  NSEnumerator *e;
+  WOComponent  *component;
+  BOOL sendSleepToPage;
+  
+  sendSleepToPage = YES;
+  e = [self->awakeComponents objectEnumerator];
+  while ((component = [e nextObject])) {
+    if (debugComponentAwake)
+      [self logWithFormat:@"sleep component: %@", component];
+    [component _sleepWithContext:self];
+    if (component == self->page) sendSleepToPage = NO;
+  }
+  if (sendSleepToPage && (self->page != nil)) {
+    if (debugComponentAwake)
+      [self logWithFormat:@"sleep page: %@", self->page];
+    [self->page _sleepWithContext:self];
+  }
+  
+  [self->awakeComponents removeAllObjects];
+}
+
+#if WITH_DEALLOC_OBSERVERS
+- (void)addDeallocObserver:(id)_observer {
+  if (_observer == NULL) return;
+  
+  /* check array */
+  if (self->deallocObservers == NULL) {
+    self->deallocObservers        = calloc(8, sizeof(id));
+    self->deallocObserverCount    = 0;
+    self->deallocObserverCapacity = 8;
+  }
+
+  /* check capacity */
+  if (self->deallocObserverCapacity == self->deallocObserverCount) {
+    /* need to increase array */
+    id *newa;
+    
+    newa = calloc(self->deallocObserverCapacity * 2, sizeof(id));
+    memcpy(newa, self->deallocObservers, 
+          sizeof(id) * self->deallocObserverCount);
+    free(self->deallocObservers);
+    self->deallocObservers = newa;
+    self->deallocObserverCapacity *= 2;
+  }
+  
+  /* register */
+  self->deallocObservers[self->deallocObserverCount] = _observer;
+  self->deallocObserverCount++;
+}
+- (void)removeDeallocObserver:(id)_observer {
+  /* the observer currently will only grow (this should be OK for WOContext) */
+  register int i;
+  if (_observer == NULL) return;
+  
+  for (i = self->deallocObserverCount - 1; i >= 0; i++) {
+    if ((self->deallocObservers[i]) == _observer)
+      self->deallocObservers[i] = NULL;
+  }
+}
+#endif
+
+- (void)dealloc {
+  [self sleepComponents];
+  
+#if WITH_DEALLOC_OBSERVERS
+  if (self->deallocObservers) {
+    register int i;
+    
+#if DEBUG
+    printf("%s: dealloc observer capacity: %i\n",
+           __PRETTY_FUNCTION__, self->deallocObserverCapacity);
+#endif
+    
+    /* GC!! process in reverse order ... */
+    for (i = self->deallocObserverCount - 1; i >= 0; i++)
+      [self->deallocObservers[i] _objectWillDealloc:self];
+    
+    free(self->deallocObservers);
+    self->deallocObservers = NULL;
+  }
+#endif
+  
+  [self->traversalStack   release];
+  [self->clientObject     release];
+  [self->objectDispatcher release];
+  [self->soRequestType    release];
+  [self->pathInfo         release];
+  
+  [[NSNotificationCenter defaultCenter]
+                         postNotificationName:@"WOContextWillDeallocate"
+                         object:self->ctxId];
+  
+  { /* release component stack */
+    int i;
+    for (i = (self->componentStackCount - 1); i >= 0; i--) {
+      [self->componentStack[i] release]; self->componentStack[i] = nil;
+      [self->contentStack[i]   release]; self->contentStack[i]   = nil;
+    }
+  }
+  
+  [self->urlPrefix         release];
+  [self->elementID         release];
+  [self->reqElementID      release];
+  [self->activeFormElement release];
+  [self->page              release];
+  [self->awakeComponents   release];
+  [self->appURL    release];
+  [self->baseURL   release];
+  [self->session   release];
+  [self->variables release];
+  [self->request   release];
+  [self->response  release];
+  [self->ctxId     release];
+  [super dealloc];
+}
+
+- (void)setSession:(WOSession *)_session {
+  ASSIGN(self->session, _session);
+}
+
+- (WOSession *)session {
+  // in WO4 -session creates a new session if none is associated
+  
+  if (self->session == nil) {
+    [[self application] _initializeSessionInContext:self];
+    
+    if (self->session == nil)
+      [self logWithFormat:@"%s: missing session for context ..",
+              __PRETTY_FUNCTION__];
+  }
+  
+  return self->session;
+}
+
+- (NSString *)contextID {
+  NSAssert(self->ctxId, @"context without id !");
+#if 0
+  // in WO4 -contextID returns nil if there is no associated session
+  return self->session ? self->ctxId : nil;
+#else
+  /*
+    IMHO the above isn't true, otherwise session cannot be automagically
+    generated!
+    
+    TODO: well, we might want to generate component URLs which work without
+          a session - at least in theory the ID tree should be stable even
+          without a session (and if proper uids are used for dynamic content).
+          eg this would be quite useful for SOPE.
+  */
+  return self->ctxId;
+#endif
+}
+
+- (WORequest *)request {
+  return self->request;
+}
+- (WOResponse *)response {
+  return self->response;
+}
+
+- (BOOL)hasSession {
+  return (self->session != nil) ? YES : NO;
+}
+
+- (BOOL)savePageRequired {
+  return self->savePageRequired;
+}
+
+/* cursors */
+
+- (void)pushCursor:(id)_obj {
+  if (debugCursor == -1) {
+    debugCursor = [[NSUserDefaults standardUserDefaults]
+                                   boolForKey:@"WODebugCursor"]
+      ? 1 : 0;
+  }
+  
+  if (debugCursor) [self logWithFormat:@"enter cursor: %@", _obj];
+  [[self component] pushCursor:_obj];
+}
+
+- (id)popCursor {
+  if (debugCursor) [self logWithFormat:@"leave cursor ..."];
+  return [[self component] popCursor];
+}
+
+- (id)cursor {
+  return [(id <WOPageGenerationContext>)[self component] cursor];
+}
+
+/* components */
+
+- (WOComponent *)component {
+  return (self->componentStackCount > 0)
+    ? self->componentStack[self->componentStackCount - 1]
+    : nil;
+}
+
+- (void)setPage:(WOComponent *)_page {
+  [_page ensureAwakeInContext:self];
+  ASSIGN(self->page, _page);
+}
+- (WOComponent *)page {
+  return self->page;
+}
+
+void WOContext_enterComponent
+(WOContext *self, WOComponent *_component, WOElement *_content)
+{
+  WOComponent *parent = nil;
+#if DEBUG
+  NSCAssert(_component, @"missing component to enter ...");
+#endif
+  
+  if (logComponents) {
+    [self->application logWithFormat:@"enter component %@ (content=%@) ..",
+                         [_component name], _content];
+  }
+  
+  parent = self->componentStackCount > 0
+    ? self->componentStack[self->componentStackCount - 1]
+    : nil;
+  
+  NSCAssert2(self->componentStackCount < NGObjWeb_MAX_COMPONENT_NESTING_DEPTH,
+             @"exceeded maximum component nesting depth (%i):\n%@",
+             NGObjWeb_MAX_COMPONENT_NESTING_DEPTH,
+             [self _componentStack]);
+  self->componentStack[(int)self->componentStackCount] = [_component retain];
+  self->contentStack[(int)self->componentStackCount]   = [_content   retain];
+  self->componentStackCount++;
+  
+  if (![self->awakeComponents containsObject:_component]) {
+    /* wake up component */
+    if (debugComponentAwake)
+      [self logWithFormat:@"awake component: %@", _component];
+    
+    [_component _awakeWithContext:self];
+    [self->awakeComponents addObject:_component];
+
+    if (debugComponentAwake)
+      [self logWithFormat:@"woke up component: %@", _component];
+  }
+  
+  if (parent) {
+    if ([_component synchronizesVariablesWithBindings])
+      WOComponent_syncFromParent(_component, parent);
+  }
+}
+void WOContext_leaveComponent(WOContext *self, WOComponent *_component) {
+  WOComponent *parent = nil;
+
+  BEGIN_PROFILE;
+
+  parent = (self->componentStackCount > 1)
+    ? self->componentStack[self->componentStackCount - 2]
+    : nil;
+  
+  if (parent) {
+    if ([_component synchronizesVariablesWithBindings])
+      WOComponent_syncToParent(_component, parent);
+  }
+
+  PROFILE_CHECKPOINT("after sync");
+  
+  /* remove last object */
+  self->componentStackCount--;
+  NSCAssert(self->componentStackCount >= 0,
+            @"tried to pop component from empty component stack !");
+  [self->componentStack[(int)self->componentStackCount] release];
+  self->componentStack[(int)self->componentStackCount] = nil;
+  [self->contentStack[(int)self->componentStackCount] release];
+  self->contentStack[(int)self->componentStackCount] = nil;
+  
+  if (logComponents)
+    [self->application logWithFormat:@"left component %@.", [_component name]];
+
+  END_PROFILE;
+}
+
+- (void)enterComponent:(WOComponent *)_comp content:(WOElement *)_content {
+  WOContext_enterComponent(self, _comp, _content);
+}
+- (void)leaveComponent:(WOComponent *)_component {
+  BEGIN_PROFILE;
+  WOContext_leaveComponent(self, _component);
+  END_PROFILE;
+}
+
+- (WOComponent *)parentComponent {
+  return (self->componentStackCount > 1)
+    ? self->componentStack[(int)self->componentStackCount - 2]
+    : nil;
+}
+
+- (WODynamicElement *)componentContent {
+  return (self->componentStackCount > 0)
+    ? self->contentStack[(int)self->componentStackCount - 1]
+    : nil;
+}
+
+- (unsigned)componentStackCount {
+  return self->componentStackCount;
+}
+- (NSArray *)_componentStack {
+  return [NSArray arrayWithObjects:self->componentStack
+                  count:self->componentStackCount];
+}
+
+/* URLs */
+
+- (NSURL *)serverURL {
+  WORequest *rq;
+  NSString  *serverURL;
+  NSURL     *url;
+  NSString  *host;
+    
+  if ((rq = [self request]) == nil) {
+    [self logWithFormat:@"missing request in -baseURL call .."];
+    return nil;
+  }
+  
+  if ((serverURL = [rq headerForKey:@"x-webobjects-server-url"]) == nil) {
+    if ((host = [rq headerForKey:@"host"]))
+      serverURL = [@"http://" stringByAppendingString:host];
+  }
+  else {
+    // TODO: fix that (host is also broken for example with SOUP)
+    /* sometimes the port is broken in the server URL ... */
+    if ([serverURL hasSuffix:@":0"]) { // bad bad bad
+      if ((host = [rq headerForKey:@"host"])) {
+       NSString *scheme;
+       scheme = [serverURL hasPrefix:@"https://"] ? @"https://" : @"http://";
+       serverURL = [scheme stringByAppendingString:host];
+      }
+    }
+  }
+  
+  if ([serverURL length] == 0) {
+    [self logWithFormat:
+           @"ERROR: could not find x-webobjects-server-url header !"];
+    return nil;
+  }
+  
+  if ((url = [NSURL URLWithString:serverURL]) == nil) {
+    [self logWithFormat:@"could not construct NSURL from string '%@'",
+            serverURL];
+    return nil;
+  }
+  return url;
+}
+
+- (NSURL *)baseURL {
+  WORequest *rq;
+  NSURL     *serverURL;
+
+  if (self->baseURL) 
+    return self->baseURL;
+    
+  if ((rq = [self request]) == nil) {
+    [self logWithFormat:@"missing request in -baseURL call .."];
+    return nil;
+  }
+    
+  serverURL = [self serverURL];
+  self->baseURL =
+    [[NSURL URLWithString:[rq uri] relativeToURL:serverURL] retain];
+    
+  if (self->baseURL == nil) {
+    [self logWithFormat:
+           @"could not construct NSURL for uri '%@' and base '%@' ...",
+           [rq uri], serverURL];
+  }
+  return self->baseURL;
+}
+
+- (NSURL *)applicationURL {
+  if (self->appURL == nil) {
+    NSString *s;
+
+    s = [self->request adaptorPrefix];
+    if ([s length] > 0) {
+      s = [NSString stringWithFormat:@"%@/%@/", 
+                     s, [self->request applicationName]];
+    }
+    else
+      s = [[self->request applicationName] stringByAppendingString:@"/"];
+    
+    self->appURL =
+      [[NSURL URLWithString:s relativeToURL:[self serverURL]] retain];
+  }
+  return self->appURL;
+}
+- (NSURL *)urlForKey:(NSString *)_key {
+  _key = [_key stringByAppendingString:@"/"];
+  return [NSURL URLWithString:_key relativeToURL:[self applicationURL]];
+}
+
+/* forms */
+
+- (void)setInForm:(BOOL)_form {
+  self->inForm = _form;
+}
+- (BOOL)isInForm {
+  return self->inForm;
+}
+
+- (void)addActiveFormElement:(WOElement *)_formElement {
+  if (self->activeFormElement) {
+    [[self component] debugWithFormat:@"active form element already set !"];
+    return;
+  }
+  
+  ASSIGN(self->activeFormElement, _formElement);
+  [self setRequestSenderID:[self elementID]];
+}
+- (WOElement *)activeFormElement {
+  return self->activeFormElement;
+}
+
+/* context variables (transient) */
+
+- (void)setObject:(id)_obj forKey:(NSString *)_key {
+  if (self->variables == nil) {
+    self->variables =
+      [[NSMutableDictionary allocWithZone:[self zone]]
+                            initWithCapacity:16];
+  }
+
+  if (_obj)
+    [self->variables setObject:_obj forKey:_key];
+  else
+    [self->variables removeObjectForKey:_key];
+}
+- (id)objectForKey:(NSString *)_key {
+  return [self->variables objectForKey:_key];
+}
+- (void)removeObjectForKey:(NSString *)_key {
+  [self->variables removeObjectForKey:_key];
+}
+
+- (NSDictionary *)variableDictionary {
+  return self->variables;
+}
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  if (WOSetKVCValueUsingMethod(self, _key, _value))
+    // method is used
+    return;
+  else if (WOGetKVCGetMethod(self, _key) == NULL) {
+    if (_value == nil)
+      _value = [EONull null];
+    
+    if (self->variables == nil) {
+      self->variables =
+        [[NSMutableDictionary allocWithZone:[self zone]]
+                              initWithCapacity:16];
+    }
+    [self->variables setObject:_value forKey:_key];
+    return;
+  }
+  else {
+    // only a 'get' method is defined for _key !
+    [self handleTakeValue:_value forUnboundKey:_key];
+  }
+}
+- (id)valueForKey:(NSString *)_key {
+  id value;
+  
+  if ((value = WOGetKVCValueUsingMethod(self, _key)))
+    return value;
+  value = [self->variables objectForKey:_key];
+  return value;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSString *sid = nil;
+  WOApplication *app = [self application];
+
+  if ([self hasSession])
+    sid = [[self session] sessionID];
+  
+  return [NSString stringWithFormat:
+                     @"<0x%08X[%@]: %@ app=%@ sn=%@ eid=%@ rqeid=%@>",
+                     (unsigned)self, NSStringFromClass([self class]),
+                     [self  contextID],
+                     [app name],
+                     sid ? sid : @"none",
+                     [self  elementID],
+                     [self  senderID]];
+}
+
+@end /* WOContext */
+
+@implementation WOContext(ElementIDs)
+
+- (NSString *)elementID {
+  return [self->elementID elementID];
+}
+- (void)appendElementIDComponent:(NSString *)_eid {
+  [self->elementID appendElementIDComponent:_eid];
+}
+- (void)appendZeroElementIDComponent {
+  [self->elementID appendZeroElementIDComponent];
+}
+- (void)deleteAllElementIDComponents {
+  [self->elementID deleteAllElementIDComponents];
+}
+- (void)deleteLastElementIDComponent {
+  [self->elementID deleteLastElementIDComponent];
+}
+- (void)incrementLastElementIDComponent {
+  [self->elementID incrementLastElementIDComponent];
+}
+- (void)appendIntElementIDComponent:(int)_eid {
+  [self->elementID appendIntElementIDComponent:_eid];
+}
+
+/* the following can be later moved to WOElementID */
+
+- (id)currentElementID {
+  return [self->reqElementID currentElementID];
+}
+- (id)consumeElementID {
+  return [self->reqElementID consumeElementID];
+}
+
+@end /* WOContext(ElementIDs) */
+
+@implementation WOContext(URLs)
+
+- (void)_generateCompleteURLs {
+  /* described in Apple TIL article 70101 */
+}
+
+- (NSString *)queryStringFromDictionary:(NSDictionary *)_queryDict {
+  NSEnumerator    *keys;
+  NSString        *key;
+  BOOL            isFirst;
+  NSMutableString *qs;
+  
+  qs   = [MutableStrClass stringWithCapacity:256];
+  keys = [_queryDict keyEnumerator];
+  for (isFirst = YES; (key = [keys nextObject]); ) {
+    NSString *value;
+    
+    if (isFirst)
+      isFirst = NO;
+    else
+      [qs appendString:self->qpJoin];
+    
+    value = [[_queryDict objectForKey:key] stringValue];
+    
+    key   = [key   stringByEscapingURL];
+    value = [value stringByEscapingURL];
+    
+    [qs appendString:key];
+    if (value) {
+      [qs appendString:@"="];
+      [qs appendString:value];
+    }
+  }
+  
+  return qs;
+}
+
+- (NSString *)directActionURLForActionNamed:(NSString *)_actionName
+  queryDictionary:(NSDictionary *)_queryDict
+{
+  NSMutableString *url;
+  NSString        *qs;
+
+  url = [MutableStrClass stringWithCapacity:256];
+  
+  if (!testNSURLs)
+     [url appendString:@"/"];
+  
+  [url appendString:_actionName];
+  
+  /* add query parameters */
+  
+  qs = [self queryStringFromDictionary:_queryDict];
+    
+  return [self urlWithRequestHandlerKey:
+                 [WOAppClass directActionRequestHandlerKey]
+               path:url queryString:qs];
+}
+
+- (NSString *)componentActionURL {
+  // TODO: add a -cComponentActionURL 
+  //       (without NSString for use with appendContentCString:)
+  // Profiling:
+  //   26% -urlWithRequestHandler...
+  //   21% -elementID (was 40% !! :-)
+  //   ~20% mutable string ops
+  if (newCURLStyle) {
+    NSMutableString *qs;
+    NSString *p;
+  
+    self->savePageRequired = YES;
+    qs = [MutableStrClass stringWithCapacity:64];
+  
+    [qs appendString:WORequestValueSenderID];
+    [qs appendString:@"="];
+    [qs appendString:[self elementID]];
+    [qs appendString:self->qpJoin];
+    [qs appendString:WORequestValueSessionID];
+    [qs appendString:@"="];
+    [qs appendString:[[self session] sessionID]];
+    [qs appendString:self->qpJoin];
+    [qs appendString:WORequestValueContextID];
+    [qs appendString:@"="];
+    [qs appendString:[self contextID]];
+  
+    p = [[self page] componentActionURLForContext:self];
+
+    if (testNSURLs) {
+      if ([p hasPrefix:@"/"]) p = [p substringFromIndex:1];
+    }
+  
+    return [self urlWithRequestHandlerKey:
+                  [WOAppClass componentRequestHandlerKey]
+                path:p
+                queryString:qs];
+  }
+  else {
+    /* old style URLs ... */
+    static NSMutableString *url = nil; // THREAD
+    static IMP addStr = NULL;
+    NSString *s;
+  
+    self->savePageRequired = YES;
+    if (url == nil) {
+      url = [[MutableStrClass alloc] initWithCapacity:256];
+      addStr = [url methodForSelector:@selector(appendString:)];
+      addStr(url, @selector(appendString:), @"/");
+    }
+    else
+      [url setString:@"/"];
+  
+    /*
+      Note: component actions *always* require sessions to be able to locate
+      the request component !
+    */
+    addStr(url, @selector(appendString:), [[self session] sessionID]);
+    addStr(url, @selector(appendString:), @"/");
+    addStr(url, @selector(appendString:), [self->elementID elementID]);
+  
+    s = [self urlWithRequestHandlerKey:
+               [WOAppClass componentRequestHandlerKey]
+             path:url queryString:nil];
+    return s;
+  }
+}
+
+- (NSString *)urlWithRequestHandlerKey:(NSString *)_key
+  path:(NSString *)_path
+  queryString:(NSString *)_query
+{
+  if (testNSURLs) { /* use NSURLs for processing */
+    NSURL    *rqUrl;
+    
+    if ([_path hasPrefix:@"/"]) {
+#if DEBUG
+      [self logWithFormat:@"WARNING: got absolute path '%@'", _path];
+#endif
+      _path = [_path substringFromIndex:1];
+    }
+    
+    if (_key == nil) _key = [WOAppClass componentRequestHandlerKey];
+    rqUrl = [self urlForKey:_key];
+  
+    if ([_query length] > 0) {
+      NSMutableString *s;
+    
+      s = [_path mutableCopy];
+      [s appendString:@"?"];
+      [s appendString:_query];
+      rqUrl = [NSURL URLWithString:s relativeToURL:rqUrl];
+      [s release];
+    }
+    else
+      rqUrl = [NSURL URLWithString:_path relativeToURL:rqUrl];
+    
+    //[self logWithFormat:@"constructed component URL: %@", rqUrl];
+    
+    return [rqUrl stringValueRelativeToURL:[self baseURL]];
+  }
+  else {
+    NSMutableString *url;
+    NSString *tmp;
+    IMP addStr;
+  
+    if (_key == nil) _key = [WOAppClass componentRequestHandlerKey];
+  
+    url = [MutableStrClass stringWithCapacity:256];
+    addStr = [url methodForSelector:@selector(appendString:)];
+  
+    /* static part */
+    if (self->urlPrefix == nil) {
+      if (!relativeURLs) {
+       if ((tmp = [self->request headerForKey:@"x-webobjects-server-url"])) {
+         if ([tmp hasSuffix:@":0"] && [tmp length] > 2) // TODO: BAD BAD BAD
+           tmp = [tmp substringToIndex:([tmp length] - 2)];
+         addStr(url, @selector(appendString:), tmp);
+       }
+       else if ((tmp = [self->request headerForKey:@"host"])) {
+         addStr(url, @selector(appendString:), @"http://");
+         addStr(url, @selector(appendString:), tmp);
+       }
+      }
+  
+      addStr(url, @selector(appendString:), [self->request adaptorPrefix]);
+      addStr(url, @selector(appendString:), @"/");
+      tmp = [[self request] applicationName];
+      if ([tmp length] == 0)
+        tmp = [(WOApplication *)[self application] name];
+      if ([tmp length] > 0) {
+       addStr(url, @selector(appendString:), tmp);
+       if (WOApplicationSuffix)
+         addStr(url, @selector(appendString:), WOApplicationSuffix);
+       addStr(url, @selector(appendString:), @"/");
+      }
+      
+      /* cache prefix */
+      self->urlPrefix = [url copy];
+      if (debugOn) [self debugWithFormat:@"URL prefix: '%@'", self->urlPrefix];
+    }
+    else {
+      /* prefix is cached :-) */
+      addStr(url, @selector(appendString:), self->urlPrefix);
+    }
+  
+    /* variable part */
+    addStr(url, @selector(appendString:), _key);
+    if (_path) 
+      addStr(url, @selector(appendString:), _path);
+    if ([_query length] > 0) {
+      addStr(url, @selector(appendString:), @"?");
+      addStr(url, @selector(appendString:), _query);
+    }
+    return url;
+  }
+}
+- (NSString *)completeURLWithRequestHandlerKey:(NSString *)_key
+  path:(NSString *)_path queryString:(NSString *)_query
+  isSecure:(BOOL)_isSecure port:(int)_port
+{
+  NSMutableString *url = [MutableStrClass stringWithCapacity:256];
+  [url appendString:_isSecure ? @"https://" : @"http://"];
+  [url appendString:[[self request] headerForKey:@"host"]];
+  if (_port > 0) {
+    if (!(_isSecure && _port == 443) && !(!_isSecure && _port == 80))
+      [url appendFormat:@":%i", _port];
+  }
+  [url appendString:[self urlWithRequestHandlerKey:_key
+                          path:_path
+                          queryString:_query]];
+  return url;
+}
+
+- (void)setRequestSenderID:(NSString *)_rid {
+  WOElementID *eid;
+  
+  eid = [[WOElementID alloc] initWithString:_rid];
+  [self->reqElementID release];
+  self->reqElementID = eid;
+}
+- (NSString *)senderID {
+#if 1
+  return [self->reqElementID elementID];
+#else
+  NSMutableString *eid;
+  IMP addStr;
+  int i;
+  
+  eid = [MutableStrClass stringWithCapacity:(self->reqElementIdCount * 4) + 1];
+  addStr = [eid methodForSelector:@selector(appendString:)];
+  for (i = 0; i < self->reqElementIdCount; i++) {
+    if (i != 0) addStr(eid, @selector(appendString:), @".");
+    addStr(eid, @selector(appendString:), [self->reqElementId[i] stringValue]);
+  }
+  return eid;
+#endif
+}
+
+@end /* WOContext(URLs) */
+
+@implementation WOContext(DeprecatedMethodsInWO4)
+
+- (WOApplication *)application {
+  if (self->application == nil)
+    self->application = [WOAppClass application];
+
+  if (self->application == nil)
+    NSLog(@"%s: missing application for context %@", __PRETTY_FUNCTION__, self);
+  
+  return self->application;
+}
+
+- (void)setDistributionEnabled:(BOOL)_flag {
+  IS_DEPRECATED;
+  [[self session] setDistributionEnabled:_flag];
+}
+- (BOOL)isDistributionEnabled {
+  IS_DEPRECATED;
+  return [[self session] isDistributionEnabled];
+}
+
+- (NSString *)url {
+  return [self componentActionURL];
+}
+
+- (NSString *)urlSessionPrefix {
+  NSMutableString *url;
+  NSString *tmp;
+
+  url = [MutableStrClass stringWithCapacity:128];
+  
+  [url appendString:[[self request] adaptorPrefix]];
+  [url appendString:@"/"];
+  tmp = [[self request] applicationName];
+  [url appendString:
+        tmp ? tmp : [(WOApplication *)[self application] name]];
+
+#if DEBUG
+  if ([url length] == 0) {
+    NSLog(@"WARNING(%s): could not determine session URL prefix !",
+          __PRETTY_FUNCTION__);
+  }
+#endif
+  
+  return url;
+}
+
+@end /* WOContext(DeprecatedMethodsInWO4) */
+
+@implementation WOComponent(Cursors)
+
+- (void)pushCursor:(id)_obj {
+  NSMutableArray *ctxStack;
+  
+  if (debugCursor)
+    [self logWithFormat:@"enter cursor: %@", _obj];
+  
+  if ((ctxStack = [self objectForKey:@"_ODCycleCtx"]) == nil) {
+    ctxStack = [NSMutableArray arrayWithCapacity:8];
+    [self setObject:ctxStack forKey:@"_ODCycleCtx"];
+  }
+  
+  /* add to cursor stack */
+  [ctxStack addObject:(_obj ? _obj : [NSNull null])];
+  
+  /* set active cursor */
+  if (![_obj isNotNull]) _obj = nil;
+  [self setObject:_obj forKey:@"_"];
+}
+
+- (id)popCursor {
+  NSMutableArray *ctxStack;
+  id old;
+  
+  /* retrieve last context */
+  old  = [[self objectForKey:@"_"] retain];
+  [self setObject:nil forKey:@"_"];
+  
+  /* restore old ctx */
+  if ((ctxStack = [self objectForKey:@"_ODCycleCtx"])) {
+    unsigned count;
+    
+    if ((count = [ctxStack count]) > 0) {
+      [ctxStack removeObjectAtIndex:(count - 1)];
+      count--;
+      
+      if (count > 0) {
+        id obj;
+        
+        obj = [ctxStack objectAtIndex:(count - 1)];
+      
+        if (![obj isNotNull]) obj = nil;
+        [self setObject:obj forKey:@"_"];
+      }      
+    }
+  }
+#if DEBUG
+  else {
+    [self debugWithFormat:@"WARNING: -popCursor called without cycle ctx !"];
+  }
+#endif
+  
+  if (debugCursor) {
+    [self logWithFormat:@"leave cursor: %@ (restored=%@)",
+            old, [self cursor]];
+  }
+  
+  return [old autorelease];
+}
+
+- (id)cursor {
+  NSMutableArray *ctxStack;
+  
+  // TODO: why do we check for _ODCycleCtx, if we query '_' ?
+  
+  if ((ctxStack = [self objectForKey:@"_ODCycleCtx"]) == nil)
+    /* no cycle context setup for component ... */
+    return self;
+  if ([ctxStack count] == 0)
+    /* nothing contained in cycle context ... */
+    return self;
+  
+  return [self objectForKey:@"_"];
+}
+
+@end /* WOComponent(Cursors) */
diff --git a/skyrix-sope/NGObjWeb/WOCookie.m b/skyrix-sope/NGObjWeb/WOCookie.m
new file mode 100644 (file)
index 0000000..9521bca
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOCookie.h>
+#include "common.h"
+
+@interface WOCookie(PrivateMethods)
+
+- (id)initWithName:(NSString *)_name value:(NSString *)_value
+  path:(NSString *)_path domain:(NSString *)_domain
+  expires:(NSDate *)_date
+  isSecure:(BOOL)_secure;
+
+@end
+
+@implementation WOCookie
+
+static WOCookie *_parseCookie(const char *_bytes, unsigned _len);
+
+// abbr weekday, day-of-month, abbr-month, year hour:min:sec GMT
+static NSString *cookieDateFormat =  @"%a, %d-%b-%Y %H:%M:%S %Z";
+
++ (id)cookieWithString:(NSString *)_string {
+  /* private method ! */
+  return _parseCookie([_string cString], [_string cStringLength]);
+}
+
++ (id)cookieWithName:(NSString *)_name value:(NSString *)_value {
+  return [[[self alloc] initWithName:_name value:_value
+                        path:nil domain:nil
+                        expires:nil isSecure:NO]
+                        autorelease];
+}
+
++ (id)cookieWithName:(NSString *)_name value:(NSString *)_value
+  path:(NSString *)_path domain:(NSString *)_domain
+  expires:(NSDate *)_date
+  isSecure:(BOOL)_secure
+{
+  return [[[self alloc] initWithName:_name value:_value
+                        path:_path domain:_domain
+                        expires:_date isSecure:_secure]
+                        autorelease];
+}
+
+- (id)initWithName:(NSString *)_name value:(NSString *)_value
+  path:(NSString *)_path domain:(NSString *)_domain
+  expires:(NSDate *)_date
+  isSecure:(BOOL)_secure
+{
+  if ((self = [super init])) {
+    NSZone *z = [self zone];
+    self->name         = [_name   copyWithZone:z];
+    self->value        = [_value  copyWithZone:z];
+    self->path         = [_path   copyWithZone:z];
+    self->domainName   = [_domain copyWithZone:z];
+    self->expireDate   = [expireDate retain];
+    self->onlyIfSecure = _secure;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->name       release];
+  [self->value      release];
+  [self->expireDate release];
+  [self->path       release];
+  [self->domainName release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)cookieName {
+  /* ?? */
+  return self->name;
+}
+
+- (void)setName:(NSString *)_name {
+  ASSIGNCOPY(self->name, _name);
+}
+- (NSString *)name {
+  return self->name;
+}
+
+- (void)setValue:(NSString *)_value {
+  ASSIGNCOPY(self->value, _value);
+}
+- (NSString *)value {
+  return self->value;
+}
+
+- (void)setPath:(NSString *)_path {
+  ASSIGNCOPY(self->path, _path);
+}
+- (NSString *)path {
+  return self->path;
+}
+
+- (void)setExpires:(NSDate *)_date {
+  ASSIGNCOPY(self->expireDate, _date);
+}
+- (NSDate *)expires {
+  return self->expireDate;
+}
+
+- (void)setDomain:(NSString *)_domain {
+  ASSIGNCOPY(self->domainName, _domain);
+}
+- (NSString *)domain {
+  return self->domainName;
+}
+
+- (void)setIsSecure:(BOOL)_flag {
+  self->onlyIfSecure = _flag ? YES : NO;
+}
+- (BOOL)isSecure {
+  return self->onlyIfSecure;
+}
+
+- (NSDate *)expireDate {
+  // DEPRECATED
+  return self->expireDate;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[WOCookie alloc] initWithName:self->name value:self->value 
+                          path:self->path domain:self->domainName
+                          expires:self->expireDate
+                          isSecure:self->onlyIfSecure];
+}
+
+/* description */
+
+- (NSString *)headerString {
+  return [@"set-cookie: " stringByAppendingString:[self stringValue]];
+}
+
+- (NSString *)stringValue {
+  NSMutableString *str;
+  
+  str = [NSMutableString stringWithCapacity:512];
+  [str appendString:[self->name stringByEscapingURL]];
+  [str appendString:@"="];
+  [str appendString:[[self->value stringValue] stringByEscapingURL]];
+  
+  if (self->expireDate) {
+    static NSTimeZone *gmt = nil;
+    NSString *s;
+    if (gmt == nil) 
+      gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+    
+    // TODO: replace, -descriptionWithCalendarFormat is *slow*
+    s = [self->expireDate descriptionWithCalendarFormat:cookieDateFormat
+                          timeZone:gmt
+                         locale:nil];
+    
+    [str appendString:@"; expires="];
+    [str appendString:s];
+  }
+  if (self->path) {
+    [str appendString:@"; path="];
+    [str appendString:self->path];
+  }
+  if (self->domainName) {
+    [str appendString:@"; domain="];
+    [str appendString:self->domainName];
+  }
+  if (self->onlyIfSecure)
+    [str appendString:@"; secure"];
+  
+  return str;
+}
+
+- (NSString *)description {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:128];
+  [str appendFormat:@"<%@[0x%08X]: name=%@ value=%@",
+         NSStringFromClass([self class]), self,
+         self->name, self->value];
+
+  if (self->expireDate) {
+    [str appendString:@" expires="];
+    [str appendString:[self->expireDate description]];
+  }
+  
+  if (self->path) {
+    [str appendString:@" path="];
+    [str appendString:self->path];
+  }
+  if (self->domainName) {
+    [str appendString:@" domain="];
+    [str appendString:self->domainName];
+  }
+  if (self->onlyIfSecure)
+    [str appendString:@" secure"];
+
+  [str appendString:@">"];
+  
+  return str;
+}
+
+/* cookie parsing */
+
+static WOCookie *_parseCookie(const char *_bytes, unsigned _len) {
+  WOCookie *cookie   = nil;
+  unsigned pos, toGo;
+  
+  for (pos = 0, toGo = _len; (toGo > 0) && (_bytes[pos] != '='); toGo--, pos++)
+    ;
+
+  if (toGo > 0) {
+    NSString *name   = nil;
+    NSString *value  = nil;
+
+    // NSLog(@"pos=%i toGo=%i", pos, toGo);
+    
+    name  = [[NSString alloc]
+                       initWithCString:_bytes
+                       length:pos];
+    value = [[NSString alloc]
+                       initWithCString:&(_bytes[pos + 1])
+                       length:(toGo - 1)];
+    
+    //NSLog(@"pair='%@'", [NSString stringWithCString:_bytes length:_len]);
+    //NSLog(@"name='%@' value='%@'", name, value);
+    
+    if ((name == nil) || (value == nil)) {
+      NSLog(@"ERROR: invalid cookie pair%s%s: %@",
+            value ? "" : ", no value",
+            name  ? "" : ", no name",
+            [NSString stringWithCString:_bytes length:_len]);
+      [name  release];
+      [value release];
+      return nil;
+    }
+    else {
+      cookie = [WOCookie cookieWithName:[name stringByUnescapingURL]
+                         value:[value stringByUnescapingURL]];
+    }
+    
+    [name  release];  name  = nil;
+    [value release]; value = nil;
+  }
+#if DEBUG
+  else {
+    NSLog(@"ERROR(%s:%i): invalid cookie pair: %@",
+          __PRETTY_FUNCTION__, __LINE__,
+          [NSString stringWithCString:_bytes length:_len]);
+  }
+#endif
+  return cookie;
+}
+
+@end /* WOCookie */
diff --git a/skyrix-sope/NGObjWeb/WOCoreApplication+Bundle.m b/skyrix-sope/NGObjWeb/WOCoreApplication+Bundle.m
new file mode 100644 (file)
index 0000000..898c31a
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOCoreApplication.h>
+#include "common.h"
+
+@implementation WOCoreApplication(Bundle)
+
++ (BOOL)didLoadDaemonBundle:(NSBundle *)_bundle {
+  return YES;
+}
+
++ (int)loadApplicationBundle:(NSString *)_bundleName
+  domainPath:(NSString *)_domain
+{
+  NSFileManager  *fm;
+  NSString       *bp;
+  NSBundle       *bundle;
+  NSMutableArray *chkPathes;
+  NSEnumerator   *e;
+
+  fm = [NSFileManager defaultManager];
+  
+  if ([[_bundleName pathExtension] length] == 0)
+    _bundleName = [_bundleName stringByAppendingPathExtension:@"sxa"];
+  
+  chkPathes = [NSMutableArray arrayWithCapacity:16];
+  
+  if ([_bundleName isAbsolutePath]) {
+    [chkPathes addObject:_bundleName];
+  }
+  else {
+    NSDictionary *env;
+    
+    env = [[NSProcessInfo processInfo] environment];
+  
+    [chkPathes addObject:@"."];
+#if COCOA_FRAMEWORK
+    bp = [env objectForKey:@"HOME"];
+    bp = [bp stringByAppendingPathComponent:@"Library"];
+    bp = [bp stringByAppendingPathComponent:_domain];
+    [chkPathes addObject:bp];
+    bp = @"/Library";
+    bp = [bp stringByAppendingPathComponent:_domain];
+    [chkPathes addObject:bp];
+    bp = @"/System/Library";
+    bp = [bp stringByAppendingPathComponent:_domain];
+    [chkPathes addObject:bp];
+#else
+    bp = [env objectForKey:@"GNUSTEP_USER_ROOT"];
+    bp = [bp stringByAppendingPathComponent:@"Library"];
+    bp = [bp stringByAppendingPathComponent:_domain];
+    [chkPathes addObject:bp];
+    bp = [env objectForKey:@"GNUSTEP_LOCAL_ROOT"];
+    bp = [bp stringByAppendingPathComponent:@"Library"];
+    bp = [bp stringByAppendingPathComponent:_domain];
+    [chkPathes addObject:bp];
+    bp = [env objectForKey:@"GNUSTEP_SYSTEM_ROOT"];
+    bp = [bp stringByAppendingPathComponent:@"Library"];
+    bp = [bp stringByAppendingPathComponent:_domain];
+    [chkPathes addObject:bp];
+#endif
+  }
+  
+  e = [chkPathes objectEnumerator];
+  while ((bp = [e nextObject])) {
+    BOOL isDir;
+    bp = [bp stringByAppendingPathComponent:_bundleName];
+    if (![fm fileExistsAtPath:bp isDirectory:&isDir]) continue;
+    if (!isDir) continue;
+    break; /* found */
+  }
+  
+  if ([bp length] == 0) {
+    NSLog(@"%s: did not find the bundle '%@' in search list %@",
+          __PRETTY_FUNCTION__, _bundleName, chkPathes);
+    return 1;
+  }
+  
+  if ((bundle = [NGBundle bundleWithPath:bp]) == nil) {
+    NSLog(@"%s: did not find %@ at %@ ...", __PRETTY_FUNCTION__, _bundleName, bp);
+    //return 1;
+  }
+  
+  if (![bundle load]) {
+    NSLog(@"%s: could not load %@ %@ (path=%@)...", __PRETTY_FUNCTION__, 
+          _bundleName, bundle, bp);
+    //return 2;
+  }
+
+  if (![self didLoadDaemonBundle:bundle]) {
+    //return 3;
+  }
+  
+  NSLog(@"hosting bundle: %@", [bundle bundleName]);
+  
+  return 0;
+}
+
++ (int)runApplicationBundle:(NSString *)_bundleName
+  domainPath:(NSString *)_p
+  arguments:(void *)_argv count:(int)_argc
+{
+  NSAutoreleasePool *pool = nil;
+  int               rc;
+  NSString          *appClassName, *bundleName;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+#if LIB_FOUNDATION_LIBRARY
+  {
+    extern char **environ;
+    [NSProcessInfo initializeWithArguments:_argv
+                   count:_argc
+                   environment:environ];
+  }
+#endif
+  
+  if ((rc = [self loadApplicationBundle:_bundleName
+                  domainPath:_p]) != 0)
+    exit(rc);
+  
+  bundleName = [_bundleName lastPathComponent];
+  bundleName = [bundleName stringByDeletingPathExtension];
+  
+  appClassName = [bundleName stringByAppendingString:@"Application"];
+  
+  rc = WOWatchDogApplicationMain(appClassName, _argc, _argv);
+  
+  RELEASE(pool); pool = nil;
+
+  return rc;
+}
+
++ (int)runApplicationBundle:(NSString *)_bundleName
+  arguments:(void *)_args count:(int)_argc
+{
+  return [self runApplicationBundle:_bundleName
+               domainPath:@"SxApps"
+               arguments:_args count:_argc];
+}
+
+@end /* WOApplication */
diff --git a/skyrix-sope/NGObjWeb/WOCoreApplication.m b/skyrix-sope/NGObjWeb/WOCoreApplication.m
new file mode 100644 (file)
index 0000000..4f2f9a1
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOCoreApplication.h>
+#include <NGObjWeb/WOAdaptor.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WORequestHandler.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOContext.h>
+#include <EOControl/EOControl.h>
+#include "WORunLoop.h"
+#include "common.h"
+
+#if LIB_FOUNDATION_LIBRARY
+#  import <Foundation/UnixSignalHandler.h>
+#else
+#  include "UnixSignalHandler.h"
+#endif
+
+NGObjWeb_DECLARE NSString *WOApplicationDidFinishLaunchingNotification =
+  @"WOApplicationDidFinishLaunching";
+NGObjWeb_DECLARE NSString *WOApplicationWillFinishLaunchingNotification =
+  @"WOApplicationWillFinishLaunching";
+NGObjWeb_DECLARE NSString *WOApplicationWillTerminateNotification =
+  @"WOApplicationWillTerminate";
+NGObjWeb_DECLARE NSString *WOApplicationDidTerminateNotification =
+  @"WOApplicationDidTerminate";
+
+@interface WOCoreApplication(PrivateMethods)
++ (void)_initDefaults;
+- (NSDictionary *)memoryStatistics;
+- (WOResponse *)handleException:(NSException *)_exc;
+@end
+
+#if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(KVCWarn)
++ (void)suppressCapitalizedKeyWarning;
+- (void)notImplemented:(SEL)cmd;
+@end
+#endif
+
+@implementation WOCoreApplication
+
+static BOOL  perflog          = NO;
+static BOOL  outputValidateOn = NO;
+static Class NSDateClass      = Nil;
+
++ (int)version {
+  return 1;
+}
+
+NGObjWeb_DECLARE id WOApp = nil;
+static NSMutableArray *activeApps = nil; // THREAD
+
++ (id)application {
+  if (WOApp == nil) {
+    NSLog(@"WARNING(%s): some code called +application without "
+          @"an active app !", __PRETTY_FUNCTION__);
+#if DEBUG && 0
+#  warning REMOVE THAT ABORT IN PRODUCTION CODE !!!
+    abort();
+#endif
+  }
+  return WOApp;
+}
+- (void)activateApplication {
+  if (WOApp) {
+    if (activeApps == nil)
+      activeApps = [[NSMutableArray alloc] init];
+    [activeApps addObject:WOApp];
+  }
+  ASSIGN(WOApp, self);
+}
+- (void)deactivateApplication {
+  unsigned idx;
+  
+  if (WOApp != self) {
+    [self logWithFormat:
+            @"tried to deactivate inactive application !\n"
+            @"  self:   %@\n"
+            @"  active: %@",
+            self, WOApp];
+    return;
+  }
+  [self autorelease];
+  WOApp = nil;
+  
+  if ((idx = [activeApps count]) > 0) {
+    idx--;
+    WOApp = [[activeApps objectAtIndex:idx] retain];
+    [activeApps removeObjectAtIndex:idx];
+  }
+}
+
++ (void)_initializeClass {
+  /*
+    this must be called in -init, since the environment is not setup
+    properly if this is called first.
+  */
+  static BOOL didInit = NO;
+  NSUserDefaults *ud;
+  if (didInit) return;
+  didInit = YES;
+  [self _initDefaults];
+  
+  ud = [NSUserDefaults standardUserDefaults];
+  perflog          = [ud boolForKey:@"WOProfileApplication"];
+  outputValidateOn = [ud boolForKey:@"WOOutputValidationEnabled"];
+  NSDateClass      = [NSDate class];
+}
+
+- (id)init {
+  [[self class] _initializeClass];
+#if COCOA_Foundation_LIBRARY
+  /*
+    NSKeyBinding Warning: <Application 0xc1f70> was accessed using a capitalized key
+    'NSFileSubject'.  Keys should normally start with a lowercase character.  A
+    typographical error like this could cause a crash or an infinite loop.  Use
+    +[NSKeyBinding suppressCapitalizedKeyWarning] to suppress this warning.
+  */
+  [NSClassFromString(@"NSKeyBinding") suppressCapitalizedKeyWarning];
+#endif
+  
+  if ((self = [super init])) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
+    [self activateApplication];
+    
+    if ([[ud objectForKey:@"WORunMultithreaded"] boolValue]) {
+      self->lock        = [[NSRecursiveLock alloc] init];
+      self->requestLock = [[NSLock alloc] init];
+    }
+    
+    /* handle signals */
+#if !defined(__MINGW32__) && !defined(NeXT_Foundation_LIBRARY)
+    {
+      UnixSignalHandler *us = [UnixSignalHandler sharedHandler];
+      
+      [us addObserver:self selector:@selector(terminateOnSignal:)
+          forSignal:SIGTERM immediatelyNotifyOnSignal:YES];
+      [us addObserver:self selector:@selector(terminateOnSignal:)
+          forSignal:SIGINT immediatelyNotifyOnSignal:YES];
+      [us addObserver:self selector:@selector(terminateOnSignal:)
+          forSignal:SIGQUIT immediatelyNotifyOnSignal:YES];
+      [us addObserver:self selector:@selector(terminateOnSignal:)
+          forSignal:SIGILL immediatelyNotifyOnSignal:YES];
+      
+      [us addObserver:self selector:@selector(processHupSignal:)
+          forSignal:SIGHUP immediatelyNotifyOnSignal:NO];
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+#if !defined(__MINGW32__) && !defined(NeXT_Foundation_LIBRARY)
+  [[UnixSignalHandler sharedHandler] removeObserver:self];
+#endif
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [self->adaptors    release];
+  [self->requestLock release];
+  [self->lock        release];
+  [super dealloc];
+}
+
+/* signals */
+
+- (void)processHupSignal:(int)_signal {
+  /* this isn't called immediatly */
+}
+
+- (void)terminateOnSignal:(int)_signal {
+  /* STDIO is forbidden in signal handlers !!! no malloc !!! */
+#if 1
+  self->cappFlags.isTerminating = 1;
+#else
+  static int termCount = 0;
+  unsigned pid;
+  
+#ifdef __MINGW32__
+  pid = (unsigned)GetCurrentProcessId();
+#else
+  pid = (unsigned)getpid();
+#endif
+  
+  if ([self isTerminating]) {
+#if 0
+    termCount++;
+    if (termCount > 2);
+#endif
+    fflush(stderr);
+    fprintf(stderr, "%d: forcing termination because of signal %i\n",
+           pid, _signal);
+    fflush(stderr);
+    exit(20);
+  }
+  termCount = 0;
+  
+  fflush(stderr);
+  fprintf(stderr, "%i: terminating because of signal %i\n", pid, _signal);
+  fflush(stderr);
+  
+  [self terminate];
+#endif
+}
+
+/* adaptors */
+
+- (NSArray *)adaptors {
+  return self->adaptors;
+}
+- (WOAdaptor *)adaptorWithName:(NSString *)_name
+  arguments:(NSDictionary *)_args
+{
+  Class     adaptorClass = Nil;
+  WOAdaptor *adaptor     = nil;
+
+  adaptorClass = NSClassFromString(_name);
+  if (adaptorClass == Nil) {
+    [self logWithFormat:@"ERROR: did not find adaptor class %@", _name];
+    return nil;
+  }
+
+  adaptor = [[adaptorClass allocWithZone:[self zone]]
+                           initWithName:_name
+                           arguments:_args
+                           application:self];
+  
+  return [adaptor autorelease];
+}
+
+- (BOOL)allowsConcurrentRequestHandling {
+  return NO;
+}
+- (BOOL)adaptorsDispatchRequestsConcurrently {
+  return NO;
+}
+
+/* request recording */
+
+- (void)setRecordingPath:(NSString *)_path {
+  [self notImplemented:_cmd];
+}
+- (NSString *)recordingPath {
+  static NSString *rp = nil;
+  if (rp == nil) {
+    rp = [[[NSUserDefaults standardUserDefaults]
+                           stringForKey:@"WORecordingPath"]
+                           copy];
+  }
+  return rp;
+}
+
+/* exceptions */
+
+- (NSString *)name {
+  return NSStringFromClass([self class]);
+}
+
+- (WOResponse *)handleException:(NSException *)_exc
+  inContext:(WOContext *)_ctx
+{
+  WORequest  *rq = [_ctx request];
+  WOResponse *r  = nil;
+  
+  if ([self respondsToSelector:@selector(handleException:)]) {
+    NSLog(@"WARNING: calling deprecated -handleException method !");
+    return [self handleException:_exc];
+  }
+  
+#if 0 && DEBUG
+  [self logWithFormat:@"%@: caught (without context):\n  %@.", self, _exc];
+  abort();
+#endif
+  
+  if (_ctx == nil) {
+    [self logWithFormat:@"%@: caught (without context):\n  %@.", self, _exc];
+    [self terminate];
+  }
+  else if (rq == nil) {
+    [self logWithFormat:@"%@: caught (without request):\n  %@.", self, _exc];
+    [self terminate];
+  }
+  else {
+    [self logWithFormat:@"%@: caught:\n  %@\nin context:\n  %@.",
+            self, _exc, _ctx];
+    
+  }
+  
+  if ((r = [WOResponse responseWithRequest:rq]) == nil)
+    [self logWithFormat:@"could not create response !"];
+    
+  [r setStatus:500];
+  return r;
+}
+
+/* multithreading */
+
+- (void)lock {
+  [self->lock lock];
+}
+- (void)unlock {
+  [self->lock unlock];
+}
+- (BOOL)tryLock {
+  return [self->lock tryLock];
+}
+
+- (void)lockRequestHandling {
+  [self->requestLock lock];
+}
+- (void)unlockRequestHandling {
+  [self->requestLock unlock];
+}
+
+/* notifications */
+
+- (void)awake {
+}
+- (void)sleep {
+}
+
+/* runloop */
+
+- (void)_loadAdaptors {
+  NSMutableArray *ads = nil;
+  NSArray *args;
+  int     i, count;
+      
+  args = [[NSProcessInfo processInfo] arguments];
+      
+  for (i = 0, count = [args count]; i < count; i++) {
+    NSString *arg;
+        
+    arg = [args objectAtIndex:i];
+        
+    if ([arg isEqualToString:@"-a"] && ((i + 1) < count)) {
+      // found adaptor
+      NSString            *adaptorName = nil;
+      NSMutableDictionary *arguments   = nil;
+      WOAdaptor           *adaptor     = nil;
+
+      i++; // skip '-a' option
+      adaptorName = [args objectAtIndex:i];
+      i++; // skip adaptor name
+
+      if (i < count) { // search for arguments
+        NSString *key = nil;
+            
+        arguments = [NSMutableDictionary dictionaryWithCapacity:10];
+        for (; i < count; i++) {
+          arg = [args objectAtIndex:i];
+          if ([arg isEqualToString:@"-a"] ||
+              [arg isEqualToString:@"-c"] ||
+              [arg isEqualToString:@"-d"]) {
+            i--;
+            break;
+          }
+          if (key == nil)
+            key = arg;
+          else {
+            [arguments setObject:arg forKey:key];
+            key = nil;
+          }
+        }
+      }
+
+      adaptor = [self adaptorWithName:adaptorName
+                      arguments:[[arguments copy] autorelease]];
+      if (adaptor) {
+        if (ads == nil) ads = [[NSMutableArray alloc] initWithCapacity:8];
+        [ads addObject:adaptor];
+      }
+    }
+  }
+
+  self->adaptors = [ads copy];
+  [ads release]; ads = nil;
+      
+  if ([self->adaptors count] == 0) {
+    id      defaultAdaptor;
+    NSArray *moreAdaptors;
+        
+    defaultAdaptor = [[self class] adaptor];
+    defaultAdaptor = [self adaptorWithName:defaultAdaptor arguments:nil];
+    if (defaultAdaptor) {
+      self->adaptors = [[NSArray alloc] initWithObjects:defaultAdaptor, nil];
+    }
+
+    moreAdaptors = [[self class] additionalAdaptors];
+    if ([moreAdaptors count] > 0) {
+      unsigned i, count;
+      NSMutableArray *newArray;
+
+      newArray = nil;
+      
+      for (i = 0, count = [moreAdaptors count]; i < count; i++) {
+        WOAdaptor *adaptor;
+
+        adaptor = [self adaptorWithName:[moreAdaptors objectAtIndex:i]
+                        arguments:nil];
+        if (adaptor == nil) {
+          [self logWithFormat:@"could not find WOAdaptor '%@' !",
+                [moreAdaptors objectAtIndex:i]];
+          continue;
+        }
+
+        if (newArray == nil) {
+          newArray = [self->adaptors mutableCopy];
+          [newArray addObject:adaptor];
+        }
+      }
+      [self->adaptors release];
+      self->adaptors = [newArray shallowCopy];
+      [newArray release]; newArray = nil;
+    }
+  }
+}
+
+- (void)_setupAdaptors {
+  // register adaptors
+  NSEnumerator *ads;
+  WOAdaptor    *adaptor;
+
+  if ([self->adaptors count] == 0)
+    [self _loadAdaptors];
+  
+  ads = [self->adaptors objectEnumerator];
+  while ((adaptor = [ads nextObject]))
+    [adaptor registerForEvents];
+}
+- (void)_tearDownAdaptors {
+  // unregister adaptors
+  NSEnumerator *ads;
+  WOAdaptor    *adaptor;
+  
+  ads = [self->adaptors objectEnumerator];
+  while ((adaptor = [ads nextObject]))
+    [adaptor unregisterForEvents];
+  
+  [self->adaptors release]; self->adaptors = nil;
+}
+
+- (NSRunLoop *)runLoop { // deprecated in WO4
+  IS_DEPRECATED;
+  return [self mainThreadRunLoop];
+}
+- (NSRunLoop *)mainThreadRunLoop {
+  // wrong, should remove main thread runloop
+  return [WORunLoop currentRunLoop];
+}
+
+- (BOOL)shouldTerminate {
+  return NO;
+}
+- (void)run {
+  [self activateApplication];
+  {
+    [self _setupAdaptors];
+    
+    [[NSNotificationCenter defaultCenter]
+                           postNotificationName:
+                             WOApplicationDidFinishLaunchingNotification
+                           object:self];
+  }
+  [self deactivateApplication];
+  
+  while (![self isTerminating]) {
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    
+    if ([self shouldTerminate]) {
+      /* check whether we should still process requests */
+      [self terminate];
+    }
+    else {
+      NSRunLoop *loop;
+      NSDate *limitDate = nil;
+      
+      loop = [self mainThreadRunLoop];
+      
+      limitDate = [loop limitDateForMode:NSDefaultRunLoopMode];
+      
+      if ([self isTerminating])
+        break;
+      
+      [self activateApplication];
+      [loop runMode:NSDefaultRunLoopMode beforeDate:limitDate];
+      [self deactivateApplication];
+    }
+    
+    [pool release];
+  }
+
+  [self debugWithFormat:@"application finished runloop."];
+
+  [self activateApplication];
+  {
+    [[NSNotificationCenter defaultCenter]
+                           postNotificationName:
+                             WOApplicationWillTerminateNotification
+                           object:self];
+  
+    [self _tearDownAdaptors];
+  
+    self->cappFlags.isTerminating = 1;
+
+    [[NSNotificationCenter defaultCenter]
+                           postNotificationName:
+                             WOApplicationDidTerminateNotification
+                           object:self];
+  }
+  [self deactivateApplication];
+}
+
+- (void)terminate {
+  self->cappFlags.isTerminating = 1;
+}
+- (BOOL)isTerminating {
+  return self->cappFlags.isTerminating ? YES : NO;
+}
+
+- (void)_terminateNow:(id)_dummy {
+  [self terminate];
+}
+- (void)terminateAfterTimeInterval:(NSTimeInterval)_interval {
+  [[NSRunLoop currentRunLoop] cancelPerformSelector:@selector(_terminateNow:)
+                              target:self argument:nil];
+  [self performSelector:@selector(_terminateNow:) withObject:nil
+        afterDelay:_interval];
+}
+
+/* output validation */
+
+- (void)setPrintsHTMLParserDiagnostics:(BOOL)_flag {
+  [[NSUserDefaults standardUserDefaults] setBool:_flag 
+                                         forKey:@"WOOutputValidationEnabled"];
+  outputValidateOn = _flag;
+}
+- (BOOL)printsHTMLParserDiagnostics {
+  return outputValidateOn;
+}
+
+- (void)_logWarningOnOutputValidation {
+  static BOOL didWarn = NO;
+
+  if (!didWarn) {
+    [self logWithFormat:
+            @"WARNING: output validation is enabled, this will "
+            @"slow down request processing!"];
+    didWarn = YES;
+  }
+}
+
+- (BOOL)hideValidationIssue:(NSException *)_issue {
+  /* to deal with some non-standard HTML ... */
+  return NO;
+}
+
+- (void)validateOutputOfResponse:(WOResponse *)_response {
+  NSArray      *issues;
+  NSEnumerator *e;
+  id           issue;
+  
+  [self _logWarningOnOutputValidation];
+  
+  if (_response == nil) {
+    [self logWithFormat:@"validate-output: no response returned by handler."];
+    return;
+  }
+  
+  if (![_response respondsToSelector:@selector(validateContent)]) {
+    [self logWithFormat:@"response does not support content validation!"];
+    return;
+  }
+  if ((issues = [_response validateContent]) == nil)
+    return;
+  
+  e = [issues objectEnumerator];
+  while ((issue = [e nextObject])) {
+    if ([issue isKindOfClass:[NSException class]]) {
+      if ([self hideValidationIssue:issue])
+        continue;
+      [self logWithFormat:@"validate-output[%@]: %@",
+             [(NSException *)issue name], [issue reason]];
+      continue;
+    }
+    
+    [self logWithFormat:@"validate-output: %@", [issue stringValue]];
+  }
+}
+
+/* request handling */
+
+- (WORequestHandler *)handlerForRequest:(WORequest *)_request {
+  return nil;
+}
+
+- (WOResponse *)dispatchRequest:(WORequest *)_request
+  usingHandler:(WORequestHandler *)handler
+{
+  WOResponse     *response = nil;
+  NSTimeInterval startDispatch = 0.0;
+  
+  if (perflog)
+    startDispatch = [[NSDateClass date] timeIntervalSince1970];
+  
+  /* let request handler process the request */
+  {
+    NSTimeInterval startDispatch = 0.0;
+    
+    if (perflog)
+      startDispatch = [[NSDateClass date] timeIntervalSince1970];
+    
+    /* the call ;-) */
+    response = [handler handleRequest:_request];
+    
+    if (perflog) {
+      NSTimeInterval rt;
+      rt = [[NSDateClass date] timeIntervalSince1970] - startDispatch;
+      NSLog(@"  [woapp-rq]: request handler took %4.3fs.",
+            rt < 0.0 ? -1.0 : rt);
+    }
+  }
+  
+  response = [[response retain] autorelease];
+
+  if (outputValidateOn)
+    [self validateOutputOfResponse:response];
+  
+  if (perflog) {
+    NSTimeInterval rt;
+    rt = [[NSDateClass date] timeIntervalSince1970] - startDispatch;
+    NSLog(@"[woapp]: dispatchRequest took %4.3fs.",
+          rt < 0.0 ? -1.0 : rt);
+  }
+  
+  return response;
+}
+- (WOResponse *)dispatchRequest:(WORequest *)_request {
+  WORequestHandler *handler;
+  
+  if ([self respondsToSelector:@selector(handleRequest:)]) {
+    [self logWithFormat:
+            @"WARNING: calling deprecated -handleRequest: method .."];
+    return [self handleRequest:_request];
+  }
+  
+  /* find request handler for request */
+  if ((handler = [self handlerForRequest:_request]) == nil) {
+    [self logWithFormat:@"ERROR: got no request handler for request: %@ !",
+           _request];
+    return nil;
+  }
+  
+  return [self dispatchRequest:_request usingHandler:handler];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: %@>",
+                     NSStringFromClass([self class]), self,
+                     [self isTerminating] ? @" terminating" : @""
+                   ];
+}
+
+@end /* WOCoreApplication */
+
+@implementation WOCoreApplication(Defaults)
+
++ (void)_initDefaults {
+  static BOOL didInit = NO;
+#if !COMPILE_AS_FRAMEWORK
+  NSFileManager *fm;
+  NSDictionary  *env;
+  NSString      *relPath;
+#else
+  NSBundle *bundle;
+#endif
+  NSDictionary  *owDefaults = nil;
+  NSString      *apath;
+  
+  if (didInit) return;
+  didInit = YES;
+  
+#if COMPILE_AS_FRAMEWORK
+  bundle = [NSBundle bundleForClass:[WOCoreApplication class]];
+  apath  = [bundle pathForResource:@"Defaults" ofType:@"plist"];
+      
+  if (apath == nil) {
+    NSLog(@"ERROR: cannot find Defaults.plist "
+              @"resource of NGObjWeb framework (%@) !", bundle);
+  }
+#else
+  fm   = [NSFileManager defaultManager];
+  env  = [[NSProcessInfo processInfo] environment];
+
+  /* 
+       TODO: the following is a dirty hack because GNUstep people decided
+             to change the directory structure. SIGH!
+  */
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY || GNUSTEP_BASE_LIBRARY
+  relPath = @"Library/Libraries";
+#else    
+  relPath = @"Libraries";
+#endif
+  relPath = [relPath stringByAppendingPathComponent:@"Resources"];
+  relPath = [relPath stringByAppendingPathComponent:@"NGObjWeb"];
+  relPath = [relPath stringByAppendingPathComponent:@"Defaults.plist"];
+  
+  apath = [env objectForKey:@"GNUSTEP_USER_ROOT"];
+  apath = [apath stringByAppendingPathComponent:relPath];
+  if (![fm fileExistsAtPath:apath]) {
+      apath = [env objectForKey:@"GNUSTEP_LOCAL_ROOT"];
+      apath = [apath stringByAppendingPathComponent:relPath];
+  }
+  if (![fm fileExistsAtPath:apath]) {
+    apath = [env objectForKey:@"GNUSTEP_SYSTEM_ROOT"];
+    apath = [apath stringByAppendingPathComponent:relPath];
+  }
+  if (![fm fileExistsAtPath:apath]) {
+    apath = relPath;
+  }
+  if (![fm fileExistsAtPath:apath]) {
+    NSLog(@"ERROR: cannot find Defaults.plist "
+         @"resource of NGObjWeb library !");
+  }
+#endif
+  owDefaults = [NSDictionary dictionaryWithContentsOfFile:apath];
+  
+  if (owDefaults) {
+    [[NSUserDefaults standardUserDefaults] registerDefaults:owDefaults];
+#if HEAVY_DEBUG
+    [self logWithFormat:@"did register NGObjWeb defaults: %@\n%@", 
+           apath, owDefaults];
+#endif
+  }
+  else {
+    [self logWithFormat:@"ERROR: could not load NGObjWeb defaults: '%@'",
+           apath];
+  }
+}
+
++ (NSUserDefaults *)userDefaults {
+  return [NSUserDefaults standardUserDefaults];
+}
+
+/* WOAdaptor */
+
++ (void)setAdaptor:(NSString *)_key {
+  [[self userDefaults] setObject:_key forKey:@"WOAdaptor"];
+}
++ (NSString *)adaptor {
+  return [[self userDefaults] stringForKey:@"WOAdaptor"];
+}
+
++ (void)setAdditionalAdaptors:(NSArray *)_names {
+  [[self userDefaults] setObject:_names forKey:@"WOAdditionalAdaptors"];
+}
++ (NSArray *)additionalAdaptors {
+  return [[self userDefaults] arrayForKey:@"WOAdditionalAdaptors"];
+}
+
+/* WOPort */
+
++ (void)setPort:(NSNumber *)_port {
+  [[self userDefaults] setObject:_port forKey:@"WOPort"];
+}
++ (NSNumber *)port {
+  id woport;
+  id addr;
+  
+  woport = [[self userDefaults] objectForKey:@"WOPort"];
+  if ([woport isKindOfClass:[NSNumber class]])
+    return woport;
+  
+  woport = [woport stringValue];
+  addr   = NGSocketAddressFromString(woport);
+  
+  if ([addr isKindOfClass:[NGInternetSocketAddress class]])
+    return [NSNumber numberWithInt:[(NGInternetSocketAddress *)addr port]];
+  
+  return nil;
+}
+
+/* WOWorkerThreadCount */
+
++ (NSNumber *)workerThreadCount {
+  static NSNumber *s = nil;
+  if (s == nil) {
+    int i;
+    i = [[self userDefaults] integerForKey:@"WOWorkerThreadCount"];
+    s = [[NSNumber numberWithInt:i] retain];
+  }
+  return s;
+}
+
+/* WOListenQueueSize */
+
++ (NSNumber *)listenQueueSize {
+  static NSNumber *s = nil;
+  if (s == nil) {
+    int i;
+    i = [[self userDefaults] integerForKey:@"WOListenQueueSize"];
+    s = [[NSNumber numberWithInt:i] retain];
+  }
+  return s;
+}
+
+@end /* WOCoreApplication(Defaults) */
diff --git a/skyrix-sope/NGObjWeb/WODirectAction.m b/skyrix-sope/NGObjWeb/WODirectAction.m
new file mode 100644 (file)
index 0000000..5e5fc15
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODirectAction.h>
+#include "NSObject+WO.h"
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOSessionStore.h>
+#include "common.h"
+
+@implementation WODirectAction
+
++ (int)version {
+  return 4;
+}
+
+- (id)initWithRequest:(WORequest *)_request {
+  if ((self = [super init])) {
+  }
+  return self;
+}
+- (id)initWithContext:(WOContext *)_ctx {
+  if ((self = [self initWithRequest:[_ctx request]])) {
+    self->context = [_ctx retain];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithRequest:nil];
+}
+
+- (void)dealloc {
+  [self->context release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOContext *)context {
+  if (self->context == nil)
+    self->context = [[[WOApplication application] context] retain];
+  return self->context;
+}
+
+- (WORequest *)request {
+  return [[self context] request];
+}
+
+- (WOSession *)session {
+  return [[self context] session];
+}
+
+- (WOSession *)existingSession {
+  WOContext *ctx = [self context];
+  
+  /* check whether the context has a session */
+  
+  return [ctx hasSession] ? [ctx session] : nil;
+}
+
+/* perform actions */
+
+- (id<WOActionResults>)performActionNamed:(NSString *)_actionName {
+  SEL actionSel;
+  NSRange rng;
+
+  /* discard everything after a point in the URL */
+  rng = [_actionName rangeOfString:@"."];
+  if (rng.length > 0)
+    _actionName = [_actionName substringToIndex:rng.location];
+
+  _actionName = [_actionName stringByAppendingString:@"Action"];
+  actionSel   = NSSelectorFromString(_actionName);
+  
+  if ([self respondsToSelector:actionSel]) 
+    return [self performSelector:actionSel];
+  else {
+    [self logWithFormat:@"DirectAction class %@ cannot handle action %@",
+            NSStringFromClass([self class]), _actionName];
+    return nil;
+  }
+}
+
+/* applying form values */
+
+- (void)takeFormValuesForKeyArray:(NSArray *)_keys {
+  NSEnumerator *keys;
+  NSString     *key;
+  WORequest    *rq;
+
+  rq   = [self request];
+  keys = [_keys objectEnumerator];
+
+  while ((key = [keys nextObject])) {
+    NSString *value;
+
+    value = [rq formValueForKey:key];
+    
+    [self takeValue:value forKey:key];
+  }
+}
+- (void)takeFormValuesForKeys:(NSString *)_key1,... {
+  va_list   va;
+  NSString  *key;
+  WORequest *rq;
+
+  rq = [self request];
+
+  va_start(va, _key1);
+  {  
+    for (key = _key1; key; key = va_arg(va, NSString *)) {
+      NSString *value;
+
+      value = [rq formValueForKey:key];
+      [self takeValue:value forKey:key];
+    }
+  }
+  va_end(va);
+}
+
+- (void)takeFormValueArraysForKeyArray:(NSArray *)_keys {
+  NSEnumerator *keys;
+  NSString     *key;
+  WORequest    *rq;
+
+  rq   = [self request];
+  keys = [_keys objectEnumerator];
+
+  while ((key = [keys nextObject])) {
+    NSArray *value;
+
+    value = [rq formValuesForKey:key];
+    [self takeValue:value forKey:key];
+  }
+}
+- (void)takeFormValueArraysForKeys:(NSString *)_key1,... {
+  va_list   va;
+  NSString  *key;
+  WORequest *rq;
+
+  rq = [self request];
+  
+  va_start(va, _key1);
+  {  
+    for (key = _key1; key; key = va_arg(va, NSString *)) {
+      NSArray *value;
+
+      value = [rq formValuesForKey:key];
+      [self takeValue:value forKey:key];
+    }
+  }
+  va_end(va);
+}
+
+/* pages */
+
+- (WOComponent *)pageWithName:(NSString *)_name {
+  return [[WOApplication application]
+                         pageWithName:_name
+                         inContext:[self context]];
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@">%@>", NSStringFromClass([self class])];
+}
+- (BOOL)isDebuggingEnabled {
+  static char showDebug = 2;
+  
+  if (showDebug == 2)
+    showDebug = [WOApplication isDebuggingEnabled] ? 1 : 0;
+  return showDebug ? YES : NO;
+}
+
+/* Key-Value coding */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  if (!WOSetKVCValueUsingMethod(self, _key, _value))
+    [self handleTakeValue:_value forUnboundKey:_key];
+}
+- (id)valueForKey:(NSString *)_key {
+  return WOGetKVCValueUsingMethod(self, _key);
+}
+
+@end /* WODirectAction */
diff --git a/skyrix-sope/NGObjWeb/WODirectActionRequestHandler.h b/skyrix-sope/NGObjWeb/WODirectActionRequestHandler.h
new file mode 100644 (file)
index 0000000..8c704db
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WODirectActionRequestHandler_H__
+#define __NGObjWeb_WODirectActionRequestHandler_H__
+
+#include <NGObjWeb/WORequestHandler.h>
+
+@interface WODirectActionRequestHandler : WORequestHandler
+@end
+
+#endif /* __NGObjWeb_WORequestHandler_H__ */
diff --git a/skyrix-sope/NGObjWeb/WODirectActionRequestHandler.m b/skyrix-sope/NGObjWeb/WODirectActionRequestHandler.m
new file mode 100644 (file)
index 0000000..e536df7
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WODirectActionRequestHandler.h"
+#include "WORequestHandler+private.h"
+#include "WOContext+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WODirectAction.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOSessionStore.h>
+#include <NGObjWeb/WOStatisticsStore.h>
+#include "common.h"
+
+#if APPLE_RUNTIME || NeXT_RUNTIME
+#  include <objc/objc-class.h>
+#endif
+
+static BOOL  perflog = NO;
+static Class NSDateClass = Nil;
+
+//#define USE_POOLS 1
+
+@implementation WODirectActionRequestHandler
+
++ (int)version {
+  return [super version] + 0 /* 2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+
+  NSDateClass = [NSDate class];
+  perflog = [[NSUserDefaults standardUserDefaults]
+                             boolForKey:@"WOProfileDirectActionRequestHandler"];
+}
+
+- (NSString *)loggingPrefix {
+  return @"[da-handler]";
+}
+
+/*
+  The request handler part of a direct action URI looks like this:
+
+    [actionClass/]actionName[?key=value&key=value&...]
+*/
+
+- (BOOL)isComponentClass:(Class)_clazz {
+  if (_clazz == Nil) 
+    return NO;
+  while ((_clazz = _clazz->super_class)) {
+    if (_clazz == [WOComponent    class]) return YES;
+    if (_clazz == [WODirectAction class]) return NO;
+    if (_clazz == [NSObject       class]) return NO;
+  }
+  return NO;
+}
+
+- (id)instantiateObjectForActionClass:(Class)actionClass
+  inContext:(WOContext *)context
+  application:(WOApplication *)app
+{
+  WOComponent *component;
+  
+  if (actionClass == Nil)
+    return nil;
+  if (![self isComponentClass:actionClass]) {
+    /* create direct action object */
+    id actionObject;
+    
+    if (![actionClass instancesRespondToSelector:
+                       @selector(initWithContext:)]) {
+      [self logWithFormat:@"tried to use class '%@' as a direct-action class",
+             NSStringFromClass(actionClass)];
+      return nil;
+    }
+    
+    actionObject =
+      [(WODirectAction *)[actionClass alloc] initWithContext:context];
+    actionObject = [actionObject autorelease];
+    return actionObject;
+  }
+  
+  /* special initialization for WOComponents used as direct actions */
+    
+  component = [app pageWithName:NSStringFromClass(actionClass)
+                  inContext:context];
+  [context setPage:(id)component];
+  
+  /* TODO: why was that commented out? */
+  if ([component shouldTakeValuesFromRequest:[context request]
+                inContext:context])
+    [app takeValuesFromRequest:[context request] inContext:context];
+  
+  return component;
+}
+
+- (WOResponse *)handleRequest:(WORequest *)_request
+  inContext:(WOContext *)context
+  session:(WOSession *)session
+  application:(WOApplication *)app
+{
+#if USE_POOLS
+  NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];
+#endif
+  NSString      *actionClassName;
+  NSString      *actionName;
+  WOResponse    *response;
+  NSArray       *handlerPath;
+  Class         actionClass = Nil;
+  WODirectAction      *actionObject = nil;
+  id<WOActionResults> result = nil;
+  
+  *(&result) = nil;
+  *(&response)        = nil;
+  *(&actionClassName) = nil;
+  *(&actionName)      = nil;
+  *(&handlerPath)     = nil;
+  
+  /* process path */
+  
+  handlerPath = [_request requestHandlerPathArray];
+
+#if DEBUG_DIRECT_ACTION
+  [self debugWithFormat:@"path=%@ array=%@",
+          [_request requestHandlerPath], handlerPath];
+#endif
+
+  switch ([handlerPath count]) {
+    case 0:
+      actionClassName = @"DirectAction";
+      actionName      = @"default";
+      break;
+    case 1:
+      actionClassName = @"DirectAction";
+      actionName      = [handlerPath objectAtIndex:0];
+      break;
+    case 2:
+      actionClassName = [handlerPath objectAtIndex:0];
+      actionName      = [handlerPath objectAtIndex:1];
+      break;
+
+    default:
+      actionClassName = [handlerPath objectAtIndex:0];
+      actionName      = [handlerPath objectAtIndex:1];
+#if 0
+      NSLog(@"invalid direction action URL: %@",
+              [_request requestHandlerPath]);
+#endif
+      break;
+  }
+
+  if ([actionName length] == 0)
+    actionName = @"default";
+
+  if ((*(&actionClass) = NSClassFromString(actionClassName)) == Nil) {
+    [self logWithFormat:@"ERROR: did not find direct action class %@",
+            actionClassName];
+    actionClass = [WODirectAction class];
+  }
+  
+#if DEBUG_DIRECT_ACTION
+  [self debugWithFormat:
+          @"[direct action request handler] class=%@ action=%@ ..",
+          actionClassName, actionName];
+#endif
+  
+  /* process request */
+  
+  actionObject = [self instantiateObjectForActionClass:actionClass
+                      inContext:context
+                      application:app];
+  
+  if (actionObject == nil) {
+    [self logWithFormat:
+            @"ERROR: could not create direct action object of class %@",
+            actionClassName];
+    actionObject = nil;
+  }
+  else {
+    static Class WOComponentClass = Nil;
+    
+    if (WOComponentClass == Nil)
+      WOComponentClass = [WOComponent class];
+    
+    result = [(id)[actionObject performActionNamed:actionName] retain];
+    
+    if (result == nil) result = [[context page] retain];
+    
+    if ([(id)result isKindOfClass:WOComponentClass]) {
+      [(id)result _awakeWithContext:context];
+      [context setPage:(WOComponent *)result];
+      
+      response = [self generateResponseForComponent:(WOComponent *)result
+                       inContext:context
+                       application:app];
+      
+      if ([context hasSession]) {
+        if ([context savePageRequired])
+          [[context session] savePage:(WOComponent *)result];
+      }
+      
+      response = [response retain];
+    }
+    else {
+      /* generate response */
+      response = [[result generateResponse] retain];
+    }
+              
+    [context sleepComponents];
+    
+    [(id)result release]; result = nil;
+    
+    /* check whether a session was created */
+    if ((session == nil) && [context hasSession]) {
+      session = [[[context session] retain] autorelease];
+      [session lock];
+    }
+    
+#if USE_POOLS
+    session = [session retain];
+    [pool2 release]; pool2 = nil;
+    session = [session autorelease];
+#endif
+    response = [response autorelease];
+  }
+  
+  return response;
+}
+
+@end /* WODirectActionRequestHandler */
diff --git a/skyrix-sope/NGObjWeb/WODisplayGroup.m b/skyrix-sope/NGObjWeb/WODisplayGroup.m
new file mode 100644 (file)
index 0000000..b2e3c26
--- /dev/null
@@ -0,0 +1,946 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODisplayGroup.h>
+#import <EOControl/EOControl.h>
+#import <Foundation/Foundation.h>
+#import <Foundation/NSNotification.h>
+#include "common.h"
+
+@interface EODataSource(DGQualifierSetting)
+- (void)setAuxiliaryQualifier:(EOQualifier *)_q;
+- (void)setQualifier:(EOQualifier *)_q;
+- (void)setQualifierBindings:(NSDictionary *)_bindings;
+@end
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (void)notImplemented:(SEL)cmd;
+@end
+#endif
+
+@implementation WODisplayGroup
+
+static NSNumber *uint0 = nil;
+static NSArray  *uint0Array = nil;
+
++ (void)initialize {
+  if (uint0 == nil)
+    uint0 = [[NSNumber alloc] initWithUnsignedInt:0];
+  if (uint0Array == nil)
+    uint0Array = [[NSArray alloc] initWithObjects:&uint0 count:1];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    [self setDefaultStringMatchFormat:
+            [[self class] globalDefaultStringMatchFormat]];
+    [self setDefaultStringMatchOperator:
+            [[self class] globalDefaultStringMatchOperator]];
+    self->currentBatchIndex = 1;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [self setDataSource:nil];
+
+  RELEASE(self->_queryMatch);
+  RELEASE(self->_queryMin);
+  RELEASE(self->_queryMax);
+  RELEASE(self->_queryOperator);
+  RELEASE(self->_queryBindings);
+  RELEASE(self->defaultStringMatchFormat);
+  RELEASE(self->defaultStringMatchOperator);
+  RELEASE(self->qualifier);
+  RELEASE(self->objects);
+  RELEASE(self->displayObjects);
+  RELEASE(self->selectionIndexes);
+  RELEASE(self->sortOrderings);
+  RELEASE(self->insertedObjectDefaults);
+  [super dealloc];
+}
+
+/* notifications */
+
+- (void)_objectsChangedInEC:(NSNotification *)_notification {
+  id d;
+  BOOL doRedisplay;
+
+  doRedisplay = YES;
+  if ((d = [self delegate])) {
+    if ([d respondsToSelector:
+           @selector(displayGroup:shouldRedisplayForChangesInEditingContext:)]) {
+      doRedisplay = [d displayGroup:self
+                       shouldRedisplayForEditingContextChangeNotification:
+                         _notification];
+    }
+  }
+
+  if (doRedisplay)
+    [self redisplay];
+}
+
+/* display */
+
+- (void)redisplay {
+  /* contents changed notification ??? */
+}
+
+/* accessors */
+
+- (void)setDelegate:(id)_delegate {
+  self->delegate = _delegate;
+}
+- (id)delegate {
+  return self->delegate;
+}
+
+- (void)setDataSource:(EODataSource *)_ds {
+  if (_ds != self->dataSource) {
+#if WITH_EC
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+
+    id ec;
+
+    if ((ec = [self->dataSource editingContext])) {
+      [ec removeEditor:self];
+      if ([ec messageHandler] == self)
+        [ec setMessageHandler:nil];
+    
+      [nc removeObserver:self
+          name:@"EOObjectsChangedInEditingContext"
+          object:ec];
+    }
+#endif
+    
+    ASSIGN(self->dataSource, _ds);
+
+#if WITH_EC
+    if ((ec = [_ds editingContext])) {
+      [ec addEditor:self];
+      if ([ec messageHandler] == nil)
+        [ec setMessageHandler:self];
+      
+      [nc addObserver:self
+          selector:@selector(_objectsChangedInEC:)
+          name:@"EOObjectsChangedInEditingContext"
+          object:ec];
+    }
+#endif
+    
+    if ([self->delegate respondsToSelector:
+               @selector(displayGroupDidChangeDataSource:)])
+      [self->delegate displayGroupDidChangeDataSource:self];
+  }
+}
+- (EODataSource *)dataSource {
+  return self->dataSource;
+}
+
+- (void)setSortOrderings:(NSArray *)_orderings {
+  id tmp = self->sortOrderings;
+  self->sortOrderings = [_orderings copy];
+  RELEASE(tmp);
+}
+- (NSArray *)sortOrderings {
+  return self->sortOrderings;
+}
+
+- (void)setFetchesOnLoad:(BOOL)_flag {
+  self->flags.fetchesOnLoad = _flag ? 1 : 0;
+}
+- (BOOL)fetchesOnLoad {
+  return self->flags.fetchesOnLoad ? YES : NO;
+}
+
+- (void)setInsertedObjectDefaultValues:(NSDictionary *)_values {
+  id tmp = self->insertedObjectDefaults;
+  self->insertedObjectDefaults = [_values copy];
+  RELEASE(tmp);
+}
+- (NSDictionary *)insertedObjectDefaultValues {
+  return self->insertedObjectDefaults;
+}
+
+- (void)setNumberOfObjectsPerBatch:(unsigned)_count {
+  self->numberOfObjectsPerBatch = _count;
+}
+- (unsigned)numberOfObjectsPerBatch {
+  return self->numberOfObjectsPerBatch;
+}
+
+- (void)setSelectsFirstObjectAfterFetch:(BOOL)_flag {
+  self->flags.selectFirstAfterFetch = _flag ? 1 : 0;
+}
+- (BOOL)selectsFirstObjectAfterFetch {
+  return self->flags.selectFirstAfterFetch ? YES : NO;
+}
+
+- (void)setValidatesChangesImmediatly:(BOOL)_flag {
+  self->flags.validatesChangesImmediatly = _flag ? 1 : 0;
+}
+- (BOOL)validatesChangesImmediatly {
+  return self->flags.validatesChangesImmediatly ? YES : NO;
+}
+
+/* batches */
+
+- (BOOL)hasMultipleBatches {
+  return [self batchCount] > 1 ? YES : NO;
+}
+- (unsigned)batchCount {
+  unsigned doc, nob;
+  
+  doc = [[self allObjects] count];
+  nob = [self numberOfObjectsPerBatch];
+  
+  return (nob == 0)
+    ? 1
+    : doc / nob + ((doc % nob) ? 1 : 0) ;
+}
+
+- (void)setCurrentBatchIndex:(unsigned)_index {
+  self->currentBatchIndex = (_index <= [self batchCount]) ? _index : 1;
+}
+- (unsigned)currentBatchIndex {
+  if (self->currentBatchIndex > [self batchCount])
+    self->currentBatchIndex = 1;
+  return self->currentBatchIndex;
+}
+
+- (unsigned)indexOfFirstDisplayedObject {
+  return ([self currentBatchIndex] - 1) * [self numberOfObjectsPerBatch];
+}
+
+- (unsigned)indexOfLastDisplayedObject {
+  unsigned nob = [self numberOfObjectsPerBatch];
+  unsigned cnt = [[self allObjects] count];
+
+  if (nob == 0)
+    return cnt-1;
+  else
+    return (([self indexOfFirstDisplayedObject] + nob) < cnt)
+      ? ([self indexOfFirstDisplayedObject] + nob) - 1
+      : cnt-1;
+}
+
+- (id)displayNextBatch {
+  [self clearSelection];
+  
+  self->currentBatchIndex++;
+  if (self->currentBatchIndex > [self batchCount])
+    self->currentBatchIndex = 1;
+
+  [self updateDisplayedObjects];
+  
+  return nil;
+}
+- (id)displayPreviousBatch {
+  [self clearSelection];
+
+  self->currentBatchIndex--;
+  if ([self currentBatchIndex] <= 0)
+    self->currentBatchIndex = [self batchCount];
+  
+  [self updateDisplayedObjects];
+  
+  return nil;
+}
+- (id)displayBatchContainingSelectedObject {
+  NSLog(@"WARNING: %s not implemenented", __PRETTY_FUNCTION__);
+  [self updateDisplayedObjects];
+  return nil;
+}
+
+/* selection */
+
+- (BOOL)setSelectionIndexes:(NSArray *)_selection {
+  BOOL ok;
+  id   d;
+  NSSet *before, *after;
+
+  ok = YES;
+  if ((d = [self delegate])) {
+    if ([d respondsToSelector:
+             @selector(displayGroup:shouldChangeSelectionToIndexes:)]) {
+      ok = [d displayGroup:self shouldChangeSelectionToIndexes:_selection];
+    }
+  }
+  if (!ok)
+    return NO;
+  
+  /* apply selection */
+
+  before = [NSSet setWithArray:self->selectionIndexes];
+  after  = [NSSet setWithArray:_selection];
+  
+  ASSIGN(self->selectionIndexes, _selection);
+  
+  if (![before isEqual:after]) {
+    [d displayGroupDidChangeSelection:self];
+    [d displayGroupDidChangeSelectedObjects:self];
+  }
+  return YES;
+}
+- (NSArray *)selectionIndexes {
+  return self->selectionIndexes;
+}
+
+- (BOOL)clearSelection {
+  static NSArray *emptyArray = nil;
+  if (emptyArray == nil) emptyArray = [[NSArray alloc] init];
+  return [self setSelectionIndexes:emptyArray];
+}
+
+- (id)selectNext {
+  unsigned int idx;
+  
+  if ([self->displayObjects count] == 0)
+    return nil;
+  
+  if ([self->selectionIndexes count] == 0) {
+    [self setSelectionIndexes:uint0Array];
+    return nil;
+  }
+  
+  idx = [[self->selectionIndexes lastObject] unsignedIntValue];
+  if (idx >= ([self->displayObjects count] - 1)) {
+    /* last object is already selected, select first one */
+    [self setSelectionIndexes:uint0Array];
+    return nil;
+  }
+  
+  /* select next object .. */
+  [self setSelectionIndexes:
+          [NSArray arrayWithObject:[NSNumber numberWithUnsignedInt:(idx + 1)]]];
+  return nil;
+}
+
+- (id)selectPrevious {
+  unsigned int idx;
+  
+  if ([self->displayObjects count] == 0)
+    return nil;
+  
+  if ([self->selectionIndexes count] == 0) {
+    [self setSelectionIndexes:uint0Array];
+    return nil;
+  }
+  
+  idx = [[self->selectionIndexes objectAtIndex:0] unsignedIntValue];
+  if (idx == 0) {
+    /* first object is selected, now select last one */
+    NSNumber *sidx;
+    sidx = [NSNumber numberWithUnsignedInt:([self->displayObjects count] - 1)];
+    [self setSelectionIndexes:[NSArray arrayWithObject:sidx]];
+  }
+  
+  /* select previous object .. */
+  [self setSelectionIndexes:
+          [NSArray arrayWithObject:[NSNumber numberWithUnsignedInt:(idx - 1)]]];
+  return nil;
+}
+
+- (void)setSelectedObject:(id)_obj {
+  NSLog(@"WARNING: %s not implemented.", __PRETTY_FUNCTION__);
+}
+- (id)selectedObject {
+  return nil;
+}
+
+- (void)setSelectedObjects:(NSArray *)_objs {
+  [self selectObjectsIdenticalTo:_objs];
+  //  NSLog(@"WARNING: %s not implemented.", __PRETTY_FUNCTION__);
+}
+- (NSArray *)selectedObjects {
+  NSMutableArray *result;
+  unsigned int i, sCount, oCount;
+
+  sCount = [self->selectionIndexes count];
+  oCount = [self->objects count];
+  result = [NSMutableArray arrayWithCapacity:sCount];
+  
+  for (i=0; i<sCount; i++) {
+    unsigned int idx;
+
+    idx = [[self->selectionIndexes objectAtIndex:i] unsignedIntValue];
+    if (idx < oCount)
+      [result addObject:[self->objects objectAtIndex:idx]];
+  }
+  return result;
+}
+
+/* returns YES if displayedObjects contains _obj otherwise NO */
+- (BOOL)selectObject:(id)_obj {
+  NSNumber *idxNumber;
+  unsigned idx;
+  
+  if (![self->displayObjects containsObject:_obj])
+    return NO;
+
+  idx = [self->displayObjects indexOfObject:_obj];
+  idxNumber = [NSNumber numberWithUnsignedInt:idx];
+  
+  if ([self->selectionIndexes containsObject:idxNumber])
+    return YES;
+  else {
+    NSMutableArray *tmp;
+
+    tmp = [NSMutableArray arrayWithObjects:self->selectionIndexes];
+    [tmp addObject:idxNumber];
+    [self setSelectionIndexes:tmp];
+    return YES;
+  }
+}
+
+
+/* returns YES if at least one obj matches otherwise NO */
+- (BOOL)selectObjectsIdenticalTo:(NSArray *)_objs {
+  NSMutableArray *newIndexes;
+  unsigned       i, cnt;
+  BOOL           ok = NO;
+
+  cnt = [_objs count];
+  
+  if (cnt == 0)
+    return NO;
+
+  newIndexes = [NSMutableArray arrayWithCapacity:cnt];
+  
+  for (i=0; i<cnt; i++) {
+    NSNumber *idxNumber;
+    unsigned idx;
+    id       obj;
+
+    obj = [_objs objectAtIndex:i];
+    if (![self->objects containsObject:obj])
+      continue;
+
+    ok = YES;
+    idx = [self->objects indexOfObject:obj];
+    idxNumber = [NSNumber numberWithUnsignedInt:idx];
+    
+    if ([self->selectionIndexes containsObject:idxNumber])
+      continue;
+
+    [newIndexes addObject:idxNumber];
+  }
+  if (!ok)
+    return NO;
+
+  [newIndexes addObjectsFromArray:self->selectionIndexes];
+  [self setSelectionIndexes:newIndexes];
+  
+  return YES;
+}
+
+- (BOOL)selectObjectsIdenticalTo:(NSArray *)_objs
+            selectFirstOnNoMatch:(BOOL)_flag
+{
+  if ([self selectObjectsIdenticalTo:_objs])
+    return YES;
+  
+  if (_flag)
+    return [self selectObject:[self->displayObjects objectAtIndex:0]];
+  else
+    return NO;
+}
+
+/* objects */
+
+- (void)setObjectArray:(NSArray *)_objects {
+  ASSIGN(self->objects, _objects);
+  
+  /* should try to restore selection */
+  [self clearSelection];
+  if ([_objects count] > 0 && [self selectsFirstObjectAfterFetch]) {
+    [self setSelectionIndexes:uint0Array];
+  }
+}
+- (NSArray *)allObjects {
+  return self->objects;
+}
+
+- (NSArray *)displayedObjects {
+  return self->displayObjects;
+}
+
+- (id)fetch {
+  NSArray *objs;
+  
+  if ([self->delegate respondsToSelector:@selector(displayGroupShouldFetch:)]) {
+    if (![self->delegate displayGroupShouldFetch:self])
+      /* delegate rejected fetch-request */
+      return nil;
+  }
+
+  objs = [[self dataSource] fetchObjects];
+
+  [self setObjectArray:objs];
+
+  if ([self->delegate respondsToSelector:
+           @selector(displayGroup:didFetchObjects:)]) {
+    [self->delegate displayGroup:self didFetchObjects:objs];
+  }
+
+  [self updateDisplayedObjects];
+
+  if ([self selectsFirstObjectAfterFetch]) {
+    [self clearSelection];
+    
+    if ([objs count] > 0)
+      [self setSelectedObject:[objs objectAtIndex:0]];
+  }  
+  return nil;
+}
+- (void)updateDisplayedObjects {
+  NSArray *darray; // display  objects
+  NSArray *sarray; // selected objects
+
+  sarray = [self selectedObjects];
+  
+  if ([self->delegate respondsToSelector:
+           @selector(displayGroup:displayArrayForObjects:)]) {
+    darray = [self->delegate displayGroup:self
+                             displayArrayForObjects:[self allObjects]];
+
+    darray = [darray copy];
+    RELEASE(self->displayObjects);
+    self->displayObjects = darray;
+
+    return;
+  }
+  else {
+//    EOQualifier *q;
+    NSArray     *so, *ao;
+    
+    ao = [self allObjects];
+
+    /* apply qualifier */
+#if 0
+    if ((q = [self qualifier]))
+      ao = [ao filteredArrayUsingQualifier:q];
+#endif // should be done in qualifyDisplayGroup
+
+    /* apply sort orderings */
+    if ((so = [self sortOrderings]))
+      ao = [ao sortedArrayUsingKeyOrderArray:so];
+
+    if (ao != self->objects)
+      [self setObjectArray:ao];
+
+    darray = ao;
+
+    /* apply batch */
+    if ([self batchCount] > 1) {
+      unsigned first = [self indexOfFirstDisplayedObject];
+      unsigned last  = [self indexOfLastDisplayedObject];
+
+      darray = [darray subarrayWithRange:NSMakeRange(first, last-first+1)];
+    }
+  }
+  
+  darray = [darray copy];
+  RELEASE(self->displayObjects);
+  self->displayObjects = darray;
+
+  [self selectObjectsIdenticalTo:sarray];
+}
+
+/* query */
+
+- (void)setInQueryMode:(BOOL)_flag {
+  self->flags.inQueryMode = _flag ? 1 : 0;
+}
+- (BOOL)inQueryMode {
+  return self->flags.inQueryMode ? YES : NO;
+}
+
+- (EOQualifier *)qualifierFromQueryValues {
+  NSMutableDictionary *qm, *qmin, *qmax, *qop;
+  NSMutableArray *quals;
+  NSEnumerator   *keys;
+  NSString       *key;
+  
+  qm   = [self queryMatch];
+  qmin = [self queryMin];
+  qmax = [self queryMax];
+  qop  = [self queryOperator];
+  
+  quals = [NSMutableArray arrayWithCapacity:[qm count]];
+  
+  /* construct qualifier for all query-match entries */
+  
+  keys = [qm keyEnumerator];
+  while ((key = [keys nextObject])) {
+    NSString *op;
+    SEL      ops;
+    id       value;
+    EOQualifier *q;
+    
+    value = [qm objectForKey:key];
+    
+    if ((op = [qop objectForKey:key]) == nil) {
+      /* default operator is equality */
+      op  = @"=";
+      ops = EOQualifierOperatorEqual;
+    }
+    else if ([value isKindOfClass:[NSString class]]) {
+      /* strings are treated in a special way */
+      NSString *fmt;
+
+      fmt = [self defaultStringMatchFormat];
+      op  = [self defaultStringMatchOperator];
+      ops = [EOQualifier operatorSelectorForString:op];
+      
+      value = [NSString stringWithFormat:fmt, value];
+    }
+    else {
+      ops = [EOQualifier operatorSelectorForString:op];
+    }
+
+    q = [[EOKeyValueQualifier alloc]
+                              initWithKey:key
+                              operatorSelector:ops
+                              value:value];
+    [quals addObject:q];
+    RELEASE(q); q = nil;
+  }
+  
+  /* construct min qualifiers */
+
+  keys = [qmin keyEnumerator];
+  while ((key = [keys nextObject])) {
+    EOQualifier *q;
+    id value;
+    
+    value = [qmin objectForKey:key];
+
+    q = [[EOKeyValueQualifier alloc]
+                              initWithKey:key
+                              operatorSelector:EOQualifierOperatorGreaterThan
+                              value:value];
+    [quals addObject:q];
+    RELEASE(q);
+  }
+
+  /* construct max qualifiers */
+
+  keys = [qmax keyEnumerator];
+  while ((key = [keys nextObject])) {
+    EOQualifier *q;
+    id value;
+    
+    value = [qmin objectForKey:key];
+
+    q = [[EOKeyValueQualifier alloc]
+                              initWithKey:key
+                              operatorSelector:EOQualifierOperatorLessThan
+                              value:value];
+    [quals addObject:q];
+    RELEASE(q);
+  }
+
+  if ([quals count] == 0)
+    return nil;
+  else if ([quals count] == 1)
+    return [quals objectAtIndex:0];
+  else
+    return AUTORELEASE([[EOAndQualifier alloc] initWithQualifierArray:quals]);
+}
+
+- (NSMutableDictionary *)queryBindings {
+  if (self->_queryBindings == nil)
+    self->_queryBindings = [[NSMutableDictionary alloc] init];
+  return self->_queryBindings;
+}
+- (NSMutableDictionary *)queryMatch {
+  if (self->_queryMatch == nil)
+    self->_queryMatch = [[NSMutableDictionary alloc] init];
+  return self->_queryMatch;
+}
+- (NSMutableDictionary *)queryMin {
+  if (self->_queryMin == nil)
+    self->_queryMin = [[NSMutableDictionary alloc] init];
+  return self->_queryMin;
+}
+- (NSMutableDictionary *)queryMax {
+  if (self->_queryMax == nil)
+    self->_queryMax = [[NSMutableDictionary alloc] init];
+  return self->_queryMax;
+}
+- (NSMutableDictionary *)queryOperator {
+  if (self->_queryOperator == nil)
+    self->_queryOperator = [[NSMutableDictionary alloc] init];
+  return self->_queryOperator;
+}
+
+- (void)setDefaultStringMatchFormat:(NSString *)_tmp {
+  ASSIGN(self->defaultStringMatchFormat, _tmp);
+}
+- (NSString *)defaultStringMatchFormat {
+  return self->defaultStringMatchFormat;
+}
+- (void)setDefaultStringMatchOperator:(NSString *)_tmp {
+  ASSIGN(self->defaultStringMatchOperator, _tmp);
+}
+- (NSString *)defaultStringMatchOperator {
+  return self->defaultStringMatchOperator;
+}
++ (NSString *)globalDefaultStringMatchFormat {
+  return @"%@*";
+}
++ (NSString *)globalDefaultStringMatchOperator {
+  return @"caseInsensitiveLike";
+}
+
+
+/* qualfiers */
+
+- (void)setQualifier:(EOQualifier *)_q {
+  ASSIGN(self->qualifier, _q);
+}
+- (EOQualifier *)qualifier {
+  return self->qualifier;
+}
+
+- (NSArray *)allQualifierOperators {
+  static NSArray *quals = nil;
+  if (quals == nil) {
+    quals = [[NSArray alloc] initWithObjects:
+                               @"=", @"!=", @"<", @"<=", @">", @">=",
+                               @"like", @"caseInsensitiveLike", nil];
+  }
+  return quals;
+}
+- (NSArray *)stringQualifierOperators {
+  static NSArray *quals = nil;
+  if (quals == nil) {
+    quals = [[NSArray alloc] initWithObjects:
+                               @"starts with",
+                               @"contains",
+                               @"ends with",
+                               @"is",
+                               @"like",
+                               nil];
+  }
+  return quals;
+}
+- (NSArray *)relationalQualifierOperators {
+  static NSArray *quals = nil;
+  if (quals == nil) {
+    quals = [[NSArray alloc] initWithObjects:
+                               @"=", @"!=", @"<", @"<=", @">", @">=", nil];
+  }
+  return quals;
+}
+
+- (void)qualifyDisplayGroup {
+  EOQualifier *q;
+
+  if ((q = [self qualifierFromQueryValues]))
+    [self setQualifier:q];
+  
+  [self updateDisplayedObjects];
+  
+  if ([self inQueryMode])
+    [self setInQueryMode:NO];
+}
+
+- (void)qualifyDataSource {
+  EODataSource *ds;
+  EOQualifier  *q;
+
+  ds = [self dataSource];
+  
+  if ((q = [self qualifierFromQueryValues]))
+    [self setQualifier:q];
+
+  if ([ds respondsToSelector:@selector(setAuxiliaryQualifier:)])
+    [ds setAuxiliaryQualifier:[self qualifier]];
+  else if ([ds respondsToSelector:@selector(setQualifier:)])
+    [ds setQualifier:[self qualifier]];
+  else {
+    /* could not qualify ds */
+  }
+  
+  if ([ds respondsToSelector:@selector(setQualifierBindings:)])
+    [ds setQualifierBindings:[self queryBindings]];
+  
+  [self fetch];
+  
+  if ([self inQueryMode])
+    [self setInQueryMode:NO];
+}
+
+/* KVC */
+
+- (void)takeValue:(id)_value forKeyPath:(NSString *)_keyPath {
+  if([_keyPath hasPrefix:@"queryMatch."]) {
+    [[self queryMatch] takeValue:_value 
+                      forKey:[_keyPath substringFromIndex:11]];
+  }
+  else if([_keyPath hasPrefix:@"queryMax."])
+    [[self queryMax] takeValue:_value forKey:[_keyPath substringFromIndex:9]];
+  else if([_keyPath hasPrefix:@"queryMin."])
+    [[self queryMin] takeValue:_value forKey:[_keyPath substringFromIndex:9]];
+  else if([_keyPath hasPrefix:@"queryOperator."]) {
+    [[self queryOperator] takeValue:_value 
+                         forKey:[_keyPath substringFromIndex:14]];
+  }
+  else
+    [super takeValue:_value forKeyPath:_keyPath];
+}
+- (id)valueForKeyPath:(NSString *)_keyPath {
+  if ([_keyPath hasPrefix:@"queryMatch."])
+    return [[self queryMatch] valueForKey:[_keyPath substringFromIndex:11]];
+  if ([_keyPath hasPrefix:@"queryMax."])
+    return [[self queryMax] valueForKey:[_keyPath substringFromIndex:9]];
+  if ([_keyPath hasPrefix:@"queryMin."])
+    return [[self queryMin] valueForKey:[_keyPath substringFromIndex:9]];
+  if ([_keyPath hasPrefix:@"queryOperator."])
+    return [[self queryOperator] valueForKey:[_keyPath substringFromIndex:14]];
+
+  return [super valueForKeyPath:_keyPath];
+}
+
+/* NSCoding */
+
+- (id)initWithCoder:(NSCoder *)_coder {
+  self->dataSource                 = [[_coder decodeObject] retain];
+  self->delegate                   = [_coder decodeObject];
+  self->sortOrderings              = [[_coder decodeObject] copy];
+  self->insertedObjectDefaults     = [[_coder decodeObject] copy];
+  self->qualifier                  = [[_coder decodeObject] copy];
+  self->defaultStringMatchFormat   = [[_coder decodeObject] copy];
+  self->defaultStringMatchOperator = [[_coder decodeObject] copy];
+  self->_queryBindings             = [[_coder decodeObject] copy];
+  self->_queryMatch                = [[_coder decodeObject] copy];
+  self->_queryMin                  = [[_coder decodeObject] copy];
+  self->_queryMax                  = [[_coder decodeObject] copy];
+  self->_queryOperator             = [[_coder decodeObject] copy];
+  
+  return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->dataSource];
+  [_coder encodeObject:self->delegate];
+  [_coder encodeObject:self->sortOrderings];
+  [_coder encodeObject:self->insertedObjectDefaults];
+  [_coder encodeObject:self->qualifier];
+  [_coder encodeObject:self->defaultStringMatchFormat];
+  [_coder encodeObject:self->defaultStringMatchOperator];
+  [_coder encodeObject:self->_queryBindings];
+  [_coder encodeObject:self->_queryMatch];
+  [_coder encodeObject:self->_queryMin];
+  [_coder encodeObject:self->_queryMax];
+  [_coder encodeObject:self->_queryOperator];
+  
+  [self notImplemented:_cmd];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X %@: ds=%@>",
+                     self, NSStringFromClass([self class]),
+                     [self dataSource]];
+}
+
+@end /* WODisplayGroup */
+
+@implementation WODisplayGroup(KVCArchiving)
+
+- (id)initWithKeyValueUnarchiver:(EOKeyValueUnarchiver *)_unarchiver {
+  if ((self = [self init])) {
+    id tmp;
+    
+    if ((tmp = [_unarchiver decodeObjectForKey:@"formatForLikeQualifier"]))
+      [self setDefaultStringMatchFormat:tmp];
+    
+    if ((tmp = [_unarchiver decodeObjectForKey:@"dataSource"]))
+      [self setDataSource:tmp];
+
+    if ((tmp = [_unarchiver decodeObjectForKey:@"numberOfObjectsPerBatch"]))
+      [self setNumberOfObjectsPerBatch:[tmp intValue]];
+    
+    [self setFetchesOnLoad:[_unarchiver decodeBoolForKey:@"fetchesOnLoad"]];
+    [self setSelectsFirstObjectAfterFetch:
+          [_unarchiver decodeBoolForKey:@"selectsFirstObjectAfterFetch"]];
+  }
+  return self;
+}
+
+- (void)encodeWithKeyValueArchiver:(EOKeyValueArchiver *)_archiver {
+  [_archiver encodeObject:[self defaultStringMatchFormat]
+             forKey:@"formatForLikeQualifier"];
+  [_archiver encodeObject:[self dataSource]
+             forKey:@"dataSource"];
+  [_archiver encodeObject:
+               [NSNumber numberWithUnsignedInt:[self numberOfObjectsPerBatch]]
+             forKey:@"numberOfObjectsPerBatch"];
+  [_archiver encodeBool:[self fetchesOnLoad]
+             forKey:@"fetchesOnLoad"];
+  [_archiver encodeBool:[self selectsFirstObjectAfterFetch]
+             forKey:@"selectFirstAfterFetch"];
+}
+
+@end /* KVCArchiving */
+
+@implementation WODisplayGroup(EOEditorsImpl)
+
+#if 0
+
+- (void)editingContextWillSaveChanges:(id)_ec {
+}
+- (BOOL)editorHasChangesForEditingContext:(id)_ec {
+  return NO;
+}
+
+#endif
+
+@end /* WODisplayGroup(EOEditorsImpl) */
+
+@implementation WODisplayGroup(EOMessageHandlersImpl)
+
+#if 0
+
+- (void)editingContext:(id)_ec
+  presentErrorMessage:(NSString *)_msg
+{
+}
+
+- (BOOL)editingContext:(id)_ec
+  shouldContinueFetchingWithCurrentObjectCount:(unsigned)_oc
+  originalLimit:(unsigned)_olimit
+  objectStore:(EOObjectStore *)_store
+{
+  return NO;
+}
+
+#endif
+
+@end /* WODisplayGroup(EOMessageHandlersImpl) */
diff --git a/skyrix-sope/NGObjWeb/WODynamicElement.m b/skyrix-sope/NGObjWeb/WODynamicElement.m
new file mode 100644 (file)
index 0000000..d62bd82
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+#include "WOElement+private.h"
+#include "WOCompoundElement.h"
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+typedef struct _WOExtraAttrItem  {
+  NSString      *key;
+  WOAssociation *value;
+  NSString      *(*valQuery)(id,SEL,WOComponent *c);
+} WOExtraAttrItem;
+
+typedef struct _WOExtraAttrStruct  {
+  WOExtraAttrItem *items;
+  NSString        *extraString;
+  unsigned char   count;
+} WOExtraAttrs;
+
+@implementation WODynamicElement
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
+
+static Class FormClass        = Nil;
+static Class FormElementClass = Nil;
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  if (!isInitialized) {
+    isInitialized = YES;
+
+    FormClass        = NSClassFromString(@"WOForm");
+    FormElementClass = NSClassFromString(@"WOInput");
+  }
+}
+
+//static int i = 0;
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  template:(WOElement *)_rootChild
+{
+  if ((self = [super init])) {
+    WOAssociation *t;
+    
+    self->otherTagString = OWGetProperty(_associations, @"otherTagString");
+    
+    t = OWGetProperty(_associations, @"debug");
+    self->debug = [t boolValueInComponent:nil];
+    [t release]; t = nil;
+  }
+  return self;
+}
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_associations
+  contentElements:(NSArray *)_contents
+{
+  /* this method was discovered in SSLContainer.h and may not be public */
+  WOCompoundElement *template;
+  int count;
+  
+  count = [_contents count];
+  
+  if (count == 0) {
+    template = nil;
+  }
+  else if (count == 1) {
+    template = [_contents objectAtIndex:0];
+  }
+  else {
+    template = [[WOCompoundElement allocForCount:[_contents count]
+                                   zone:[self zone]]
+                                   initWithContentElements:_contents];
+  }
+  
+  return [self initWithName:_name
+               associations:_associations
+               template:template];
+}
+
+- (id)init {
+  return [self initWithName:[NSString stringWithFormat:@"0x%08X", self]
+               associations:nil
+               template:nil];
+}
+
+- (void)dealloc {
+  register WOExtraAttrs *ea;
+  
+  [self->otherTagString release];
+
+  if ((ea = self->extraAttributes)) { // GC
+    register unsigned short i;
+    
+    [ea->extraString release];
+    for (i = 0; i < ea->count; i++) {
+      [ea->items[i].key   release];
+      [ea->items[i].value release];
+    }
+    if (ea->items)
+      free(ea->items);
+    
+    free(self->extraAttributes);
+    self->extraAttributes = ea = NULL;
+  }
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)elementID {
+  return [[[WOApplication application] context] elementID];
+}
+
+- (void)setExtraAttributes:(NSDictionary *)_extras {
+  register WOExtraAttrs *ea;
+  NSEnumerator    *ke;
+  NSString        *key;
+  NSMutableString *es;
+  
+  if ([_extras count] == 0)
+    /* no extra attributes ... */
+    return;
+  
+  if (self->extraAttributes) {
+    NSLog(@"ERROR(%s): tried to reset extra attributes (access denied) !!!",
+          __PRETTY_FUNCTION__);
+    return;
+  }
+  
+  /* setup structure */
+
+  ea = calloc(1, sizeof(WOExtraAttrs));
+  ea->count = 0;
+  ea->items = calloc([_extras count], sizeof(WOExtraAttrItem));
+  
+  /* fill structure */
+  
+  es = nil;
+  ke = [_extras keyEnumerator];
+  while ((key = [ke nextObject])) {
+    WOAssociation *value;
+
+    //key   = [key lowercaseString];
+    value = [_extras objectForKey:key];
+    
+    if ([value isValueConstant]) {
+      /* static value (calculated *now*) */
+      NSString *s;
+      
+      if (es == nil)
+        es = [[NSMutableString alloc] initWithCapacity:128];
+      
+      /* query value */
+      s = [value stringValueInComponent:nil];
+      
+      /* HTML escape value ... */
+      s = [s stringByEscapingHTMLAttributeValue];
+      
+      /* add to static string */
+      [es appendString:@" "];
+      [es appendString:key];
+      [es appendString:@"=\""];
+      [es appendString:s];
+      [es appendString:@"\""];
+    }
+    else {
+      /* dynamic value (calculated at runtime) */
+      register WOExtraAttrItem *item;
+      
+      item = &(ea->items[ea->count]);
+      item->key   = [key copy];
+      item->value = RETAIN(value);
+      item->valQuery = /* cache method IMP */
+        (void*)[value methodForSelector:@selector(stringValueInComponent:)];
+      ea->count++;
+    }
+  }
+  
+  /* check results for static vs dynamic ... */
+  
+  if (ea->count == 0) {
+    /* no dynamic attributes, free items structure ... */
+    free(ea->items);
+    ea->items = NULL;
+  }
+  if ([es length] > 0) ea->extraString = [es copy];
+  [es release]; es = nil;
+  
+  /* finish */
+  self->extraAttributes = ea;
+}
+
+- (WOElement *)template {
+  return nil;
+}
+
++ (BOOL)isDynamicElement {
+  return YES;
+}
+
+/* description */
+
+- (void)appendExtraAttributesToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if (self->extraAttributes) {
+    register WOExtraAttrs *ea;
+    
+    ea = self->extraAttributes;
+    
+    if (ea->count > 0) {
+      /* has dynamic attributes */
+      WOComponent *sComponent;
+      register unsigned short i;
+      
+      sComponent = [_ctx component];
+      
+      for (i = 0; i < ea->count; i++) {
+        register WOExtraAttrItem *item;
+        NSString *value;
+        
+        item = &(ea->items[i]);
+        
+        if (item->valQuery) {
+          /* use cached selector implementation */
+          value = item->valQuery(item->value,@selector(stringValueInComponent:),
+                                 sComponent);
+        }
+        else {
+          value = [item->value stringValueInComponent:sComponent];
+        }
+        
+        WOResponse_AddChar(_response, ' ');
+        WOResponse_AddString(_response, item->key);
+        WOResponse_AddCString(_response, "=\"");
+        [_response appendContentHTMLAttributeValue:value];
+        WOResponse_AddChar(_response, '"');
+      }
+    }
+    
+    /* add static string */
+    if (ea->extraString)
+      WOResponse_AddString(_response, ea->extraString);
+  }
+}
+
+- (NSString *)associationDescription {
+#if 1
+  return nil;
+#else
+  if (self->extraAttributes) {
+    NSMutableString *ad;
+    NSEnumerator *keys;
+    NSString     *key;
+
+    ad = [NSMutableString stringWithCapacity:32];
+    keys = [self->extraAttributes keyEnumerator];
+    while ((key = [keys nextObject])) {
+      WOAssociation *value;
+      
+      value = [self->extraAttributes objectForKey:key];
+      
+      [ad appendString:@" "];
+      [ad appendString:key];
+      [ad appendString:@"="];
+      [ad appendString:[value description]];
+    }
+    return ad;
+  }
+  else
+    return nil;
+#endif
+}
+
+- (NSString *)description {
+  NSMutableString *desc      = [NSMutableString stringWithCapacity:100];
+  NSString        *assocDesc = [self associationDescription];
+
+  [desc appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
+  if (assocDesc) [desc appendString:assocDesc];
+  [desc appendString:@">"];
+
+  return desc;
+}
+
+@end /* WODynamicElement */
+
+#include <DOM/EDOM.h>
+#include <NGObjWeb/NGObjWeb.h>
+#include <NGObjWeb/WOxElemBuilder.h>
+#include <SaxObjC/XMLNamespaces.h>
+#include "common.h"
+
+/*
+  The new DOM element init function for elements constructed from DOM element
+  nodes.
+
+  The default method is defined on NSObject instead of WOElement, since some dynamic
+  elements are class clusters, which use temporary non-WOElement classes during
+  construction.
+
+  The default construction process requires no support from existing NGObjWeb elements.
+  It maps all tag attributes to element associations and all child nodes to subelements.
+  The tagname is used as the dynamic element name.
+*/
+
+@implementation NSObject(InitElement)
+
+- (id)initWithElement:(id<DOMElement>)_element
+  templateBuilder:(WOxElemBuilder *)_builder
+{
+  NSString            *name;
+  NSMutableDictionary *assocs;
+  NSArray             *children;
+  id<NSObject,DOMNamedNodeMap> attrs;
+  unsigned count;
+  
+  name = [_element tagName];
+  
+  /* construct associations */
+  
+  assocs = nil;
+  attrs = [_element attributes];
+  if ((count = [attrs length]) > 0)
+    assocs = [_builder associationsForAttributes:attrs];
+  
+  /* construct child elements */
+  
+  if ([_element hasChildNodes]) {
+    /* look for var:binding tags ... */
+    
+    children = [_builder buildNodes:[_element childNodes]
+                         templateBuilder:_builder];
+  }
+  else
+    children = nil;
+  
+  /* construct self ... */
+  
+  self = [(WODynamicElement *)self initWithName:name 
+                                   associations:assocs 
+                                   contentElements:children];
+  [(id)self setExtraAttributes:assocs];
+  return self;
+}
+
+@end /* NSObject(InitElement) */
diff --git a/skyrix-sope/NGObjWeb/WOElement+private.h b/skyrix-sope/NGObjWeb/WOElement+private.h
new file mode 100644 (file)
index 0000000..5ae04fa
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOElement_private_H__
+#define __NGObjWeb_WOElement_private_H__
+
+#include <NGObjWeb/WOElement.h>
+#include <NGObjWeb/WOAssociation.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSession.h>
+#include "WOResponse+private.h"
+
+@class WOComponent, WOForm;
+
+@interface WOElement(PrivateMethods)
+
+/* naming */
+
+- (NSString *)stringForInt:(int)_i;
+
+/* typing */
+
++ (BOOL)isDynamicElement;
+
+/* tree output */
+
+- (NSString *)indentString:(int)_indent;
+- (NSString *)elementTreeWithIndent:(int)_indent;
+- (NSString *)elementTree;
+
+@end
+
+@interface WOElement(QueryString)
+
+- (NSString *)queryStringForQueryDictionary:(NSDictionary *)_queryDict
+  andQueryParameters:(NSDictionary *)_paras
+  inContext:(WOContext *)_ctx;
+
+@end
+
+@interface WOElement(DynamicForms)
+
+- (void)_containsForm; // notifies the element that a form was added
+
+@end
+
+#endif /* __NGObjWeb_WOElement_private_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOElement.m b/skyrix-sope/NGObjWeb/WOElement.m
new file mode 100644 (file)
index 0000000..6b745b9
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOElement.h>
+#include "WOElement+private.h"
+#include <NGObjWeb/WOComponent.h>
+#include "common.h"
+
+@implementation WOElement
+
++ (int)version {
+  return 2;
+}
+
+static id numStrings[100];
+
++ (void)initialize {
+  static BOOL didInitialize = NO;
+
+  if (!didInitialize) {
+    int cnt;
+    
+    didInitialize = YES;
+    
+    for (cnt = 0; cnt < 100; cnt++) {
+      char buf[8];
+
+      sprintf(buf, "%i", cnt);
+      numStrings[cnt] = [[NSString alloc] initWithCString:buf];
+    }
+  }
+}
+
+- (id)init {
+  if ((self = [super init])) {
+#if !NO_METHOD_CACHING
+    self->takeValues = (OWTakeValuesMethod)
+      [self methodForSelector:@selector(takeValuesFromRequest:inContext:)];
+    self->appendResponse = (OWAppendResponseMethod)
+      [self methodForSelector:@selector(appendToResponse:inContext:)];
+#else
+#  warning methods are not cached !
+#endif
+  }
+  return self;
+}
+
+/* element IDs */
+
+- (NSString *)stringForInt:(int)_i {
+  NSString *s = nil;
+  
+  if ((_i < 100) && (_i >= 0)) {
+    // MT flaw, should be locked
+    s = numStrings[_i];
+    if (s == nil) {
+      char buf[16];
+      sprintf(buf, "%i", _i);
+      s = [NSString stringWithCString:buf];
+      numStrings[_i] = RETAIN(s);
+    }
+  }
+  else {
+    char buf[16];
+    sprintf(buf, "%i", _i);
+    s = [NSString stringWithCString:buf];
+  }
+  return s;
+}
+
+- (NSString *)elementID {
+  return nil;
+}
+
+/* OWResponder */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+}
+
+/* forms */
+
++ (BOOL)isDynamicElement {
+  return NO;
+}
+
+// description
+
+- (NSString *)indentString:(int)_indent {
+  switch (_indent) {
+    case  0: return @"";
+    case  2: return @"  ";
+    case  4: return @"    ";
+    case  6: return @"      ";
+    case  8: return @"        ";
+    case 10: return @"          ";
+    case 12: return @"            ";
+    case 14: return @"              ";
+
+    default: {
+      int cnt;
+      NSMutableString *str = [[NSMutableString alloc] init];
+      for (cnt = 0; cnt < _indent; cnt++)
+        [str appendString:@" "];
+      return AUTORELEASE(str);
+    }
+  }
+}
+
+- (NSString *)elementTreeWithIndent:(int)_indent {
+  NSMutableString *str = [[NSMutableString alloc] init];
+
+  [str appendString:[self indentString:_indent]];
+  [str appendString:[self description]];
+  [str appendString:@"\n"];
+
+  return AUTORELEASE(str);
+}
+
+- (NSString *)elementTree {
+  return [self elementTreeWithIndent:2];
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]>",
+                     NSStringFromClass([self class]), self];
+}
+
+@end /* WOElement */
+
+@implementation WOElement(QueryString)
+
+- (NSString *)queryStringForQueryDictionary:(NSDictionary *)_queryDict
+  andQueryParameters:(NSDictionary *)_paras
+  inContext:(WOContext *)_ctx
+{
+  NSMutableString *str;
+  NSEnumerator    *keys;
+  NSString        *key;
+  NSString        *value;
+  BOOL            isFirst;
+  WOComponent     *sComponent;
+
+  if ((_queryDict == nil) && (_paras == nil))
+    return nil;
+
+  str = [NSMutableString stringWithCapacity:128];
+  sComponent = [_ctx component];
+  
+  keys = [_queryDict keyEnumerator];
+  isFirst = YES;
+  while ((key = [keys nextObject])) {
+    value = [[_queryDict objectForKey:key] stringValue];
+    value = value ? [value stringByEscapingURL] : @"";
+    key   = key   ? [key   stringByEscapingURL] : @"";
+
+    if (isFirst) isFirst = NO;
+    else [str appendString:@"&"];
+
+    [str appendString:key];
+    [str appendString:@"="];
+    [str appendString:value];
+  }
+
+  /* ?style parameters */
+  
+  keys = [_paras keyEnumerator];
+  isFirst = YES;
+  while ((key = [keys nextObject])) {
+    value = [[_paras objectForKey:key] stringValueInComponent:sComponent];
+    value = value ? [value stringByEscapingURL] : @"";
+    key   = key   ? [key   stringByEscapingURL] : @"";
+
+    if (isFirst) isFirst = NO;
+    else [str appendString:@"&"];
+
+    [str appendString:key];
+    [str appendString:@"="];
+    [str appendString:value];
+  }
+  
+  return [str length] > 0 ? str : nil;
+}
+
+@end /* WOElement(QueryString) */
+
+NGObjWeb_DECLARE id OWGetProperty(NSDictionary *_set, NSString *_name) {
+  id propValue = [_set objectForKey:_name];
+
+  if (propValue) {
+    propValue = RETAIN(propValue);
+    [(id)_set removeObjectForKey:_name];
+  }
+  return propValue;
+}
diff --git a/skyrix-sope/NGObjWeb/WOElementID.h b/skyrix-sope/NGObjWeb/WOElementID.h
new file mode 100644 (file)
index 0000000..76d5889
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOElementID_H__
+#define __NGObjWeb_WOElementID_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  WOElementID
+  
+  This object is used to keep efficient representations of a NGObjWeb
+  element-id. An element id is a "path" to an object kept in a tree.
+*/
+
+#define NGObjWeb_MAX_ELEMENT_ID_COUNT 100
+
+@class NSString, NSMutableString;
+
+typedef struct {
+  NSString     *string;
+  unsigned int number;
+  NSString     *fqn;
+} WOElementIDPart;
+
+@interface WOElementID : NSObject
+{
+@public
+  WOElementIDPart elementId[NGObjWeb_MAX_ELEMENT_ID_COUNT + 1];
+  char elementIdCount;
+  char idPos;
+  
+  /* keep a mutable string around ... */
+  NSMutableString *cs;
+  IMP addStr;
+}
+
+- (id)initWithString:(NSString *)_s;
+
+/* methods */
+
+- (NSString *)elementID;
+
+- (void)appendElementIDComponent:(NSString *)_eid;
+- (void)deleteAllElementIDComponents;
+
+- (void)appendZeroElementIDComponent;
+- (void)deleteLastElementIDComponent;
+- (void)incrementLastElementIDComponent;
+- (void)appendIntElementIDComponent:(int)_eid;
+
+/* request ID processing */
+
+- (id)currentElementID;
+- (id)consumeElementID;
+
+@end
+
+#endif /* __NGObjWeb_WOElementID_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOElementID.m b/skyrix-sope/NGObjWeb/WOElementID.m
new file mode 100644 (file)
index 0000000..2c06e2c
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOElementID.h"
+#include "common.h"
+
+// TODO: do not keep the array in the ivars, but use malloc
+
+//#define PROF_ELEMID 1
+
+@implementation WOElementID
+
+- (id)initWithString:(NSString *)_rid {  
+  NSArray *reid;
+  int     i;
+  
+  reid = [_rid componentsSeparatedByString:@"."];
+  if ((self->elementIdCount = [reid count]) == 0) {
+    [self release];
+    return nil;
+  }
+  if (self->elementIdCount > NGObjWeb_MAX_ELEMENT_ID_COUNT) {
+    [self logWithFormat:@"ERROR: request element ID is too long (%i parts)",
+            self->elementIdCount];
+    [self release];
+    return nil;
+  }
+  for (i = 0; i < self->elementIdCount; i++)
+    self->elementId[i].string = [[reid objectAtIndex:i] copy];
+  return self;
+}
+
+- (void)dealloc {
+  int i;
+  
+  [self->cs release];
+  for (i = 0; i < self->elementIdCount; i++) {
+    [self->elementId[i].string release];
+    [self->elementId[i].fqn    release];
+  }
+  [super dealloc];
+}
+
+/* methods */
+
+#if PROF_ELEMID
+static int prioCacheHit    = 0;
+static int prioStrCacheHit = 0;
+static int prioConstruct   = 0;
+static int callCount       = 0;
+#endif
+
+- (NSString *)elementID {
+  /* 
+    TODO: increase performance (~24% of -componentActionURL [was 50%]) 
+    Prof: 1.9% -appendString
+          18%  -stringByAppendingString
+          1.9% -copy
+  */
+  static NSString *nums[30] = {
+    @".0", @".1", @".2", @".3", @".4", @".5", @".6", @".7", @".8", @".9",
+    @".10", @".11", @".12", @".13", @".14", 
+    @".15", @".16", @".17", @".18", @".19",
+    @".20", @".21", @".22", @".23", @".24", 
+    @".25", @".26", @".27", @".28", @".29",
+  };
+  NSString *e;
+  int i;
+#if PROF_ELEMID
+  if (callCount % 10 == 0) {
+    printf("ElementIDProfing: #calls=%i "
+           "#priohits=%i(string=%i), #prioconstructs=%i\n",
+           callCount, prioCacheHit, prioStrCacheHit, prioConstruct);
+  }
+  callCount++;
+#endif
+  
+  if (self->elementIdCount == 0) {
+    return nil;
+  }
+  else if (self->elementIdCount == 1) {
+    /* a single part in element id (the ctx-id) ... (rare case ...) */
+    if ((e = self->elementId[0].string))
+      return e;
+    
+    return [NSString stringWithFormat:@"%d", self->elementId[0].number];
+  }
+  else if ((e = self->elementId[(self->elementIdCount - 2)].fqn)) {
+    /* the prior part has a cached fqn */
+    /* TODO cache prior string as C-string ! */
+    NSString *o;
+#if PROF_ELEMID
+    prioCacheHit++;
+#endif
+    
+    if ((o = self->elementId[self->elementIdCount - 1].string)) {
+      NSMutableString *eid;
+#if PROF_ELEMID
+      prioStrCacheHit++;
+#endif
+      eid = [e mutableCopy];
+      [eid appendString:@"."];
+      [eid appendString:o];
+      return [eid autorelease];
+    }
+    else {
+      i = self->elementId[self->elementIdCount - 1].number;
+      if (i >= 0 && i < 30)
+        return [e stringByAppendingString:nums[i]];
+      return [e stringByAppendingFormat:@".%i", i];
+    }
+  }
+  if (self->cs == nil) {
+    self->cs = [[NSMutableString alloc] initWithCapacity:64];
+    self->addStr = [self->cs methodForSelector:@selector(appendString:)];
+  }
+  else
+    [self->cs setString:@""];
+
+  for (i = 0; i < self->elementIdCount; i++) {
+    register id o;
+    
+    if (i == (self->elementIdCount - 1)) {
+      /* the last iteration, cache the fqn of the *prior* element ! */
+      self->elementId[i - 1].fqn = [self->cs copy];
+#if PROF_ELEMID
+      prioConstruct++;
+#endif
+    }
+    
+    if ((o = self->elementId[i].string)) {
+      /* some identity comparison for faster NSNumber->NSString conversion */
+      if (i != 0) addStr(self->cs, @selector(appendString:), @".");
+      addStr(self->cs, @selector(appendString:), o);
+    }
+    else {
+      register int n;
+      
+      n = self->elementId[i].number;
+      if (n >= 0 && n < 30) {
+        if (i != 0)
+          addStr(self->cs, @selector(appendString:), nums[n]);
+        else
+          /* very rare, the first id is almost always a string (ctx-id!) */
+          [self->cs appendFormat:@"%i", n];
+      }
+      else {
+        [self->cs appendFormat:(i != 0 ? @".%i" : @"%i"), n];
+      }
+    }
+  }
+  return [[self->cs copy] autorelease];
+}
+
+- (void)appendElementIDComponent:(NSString *)_eid {
+  self->elementId[(int)self->elementIdCount].string = [_eid copy];
+  self->elementIdCount++;
+  NSAssert(self->elementIdCount < NGObjWeb_MAX_ELEMENT_ID_COUNT,
+           @"element id size exceeded !");
+}
+- (void)appendIntElementIDComponent:(int)_eid {
+  self->elementId[(int)self->elementIdCount].number = _eid;
+  self->elementIdCount++;
+  NSAssert(self->elementIdCount < NGObjWeb_MAX_ELEMENT_ID_COUNT,
+           @"element id size exceeded !");
+}
+
+- (void)appendZeroElementIDComponent {
+  self->elementId[(int)self->elementIdCount].number = 0;
+  self->elementIdCount++;
+  NSAssert(self->elementIdCount < NGObjWeb_MAX_ELEMENT_ID_COUNT,
+           @"element id size exceeded !");
+}
+
+- (void)deleteAllElementIDComponents {
+  int i;
+  for (i = 0; i < self->elementIdCount; i++) {
+    [self->elementId[i].string release];
+    self->elementId[i].string = nil;
+    [self->elementId[i].fqn release];
+    self->elementId[i].fqn = nil;
+  }
+  self->elementIdCount = 0;
+}
+
+- (void)deleteLastElementIDComponent {
+  if (self->elementIdCount == 0)
+    return;
+  
+  self->elementIdCount--;
+  [self->elementId[(int)self->elementIdCount].string release];
+  self->elementId[(int)(self->elementIdCount)].string = nil;
+  [self->elementId[(int)self->elementIdCount].fqn release];
+  self->elementId[(int)(self->elementIdCount)].fqn = nil;
+}
+
+- (void)incrementLastElementIDComponent {
+  register WOElementIDPart *p;
+  id v;
+  
+  if (self->elementIdCount < 1) {
+    [self logWithFormat:
+           @"WARNING: tried to increment a non-existing element-id"];
+    return;
+  }
+  else if (self->elementIdCount >= NGObjWeb_MAX_ELEMENT_ID_COUNT) {
+    [self logWithFormat:
+           @"ERROR: exceeded element-id restriction (max=%i)", 
+           NGObjWeb_MAX_ELEMENT_ID_COUNT];
+    return;
+  }
+  
+  // TODO: range check ?
+  p = &(self->elementId[(int)(self->elementIdCount - 1)]);
+  
+  [p->fqn release]; p->fqn = nil;
+  if ((v = p->string)) {
+    p->number = [v intValue] + 1;
+    [p->string release]; p->string = nil;
+  }
+  else
+    p->number++;
+}
+
+/* request ID processing */
+
+- (id)currentElementID {
+  return (self->idPos >= self->elementIdCount)
+    ? nil
+    : self->elementId[(int)self->idPos].string;
+}
+- (id)consumeElementID {
+  (self->idPos)++;
+  return [self currentElementID];
+}
+
+@end /* WOElementID */
diff --git a/skyrix-sope/NGObjWeb/WOFileSessionStore.m b/skyrix-sope/NGObjWeb/WOFileSessionStore.m
new file mode 100644 (file)
index 0000000..e271095
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOSessionStore.h>
+
+/*
+  This store keeps all sessions as archived files inside of a directory.
+  It provides session fail-over, but restoring/saving a session takes some
+  time ...
+
+  Storage format:
+    session-directory/
+      sessionid.session
+      sessionid.session
+
+  The session-directory can be selected using the WOFileSessionPath default.
+
+  Note: it doesn't provide session distribution between instances, since the
+  store doesn't lock the session files.
+*/
+
+@class NSString, NSFileManager;
+
+@interface WOFileSessionStore : WOSessionStore
+{
+  NSFileManager *fileManager;
+  NSString      *snPath;
+}
+@end
+
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+@implementation WOFileSessionStore
+
+static BOOL logExpire = YES;
+
++ (int)version {
+  return [super version] + 0;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithSessionPath:(NSString *)_path {
+  NSFileManager *fm;
+  BOOL isDir;
+  
+  if ([_path length] == 0) {
+    [self release];
+    return nil;
+  }
+  
+  fm = [NSFileManager defaultManager];
+  if (![fm fileExistsAtPath:_path isDirectory:&isDir]) {
+    if (![fm createDirectoryAtPath:_path attributes:nil]) {
+      NSLog(@"%s: could not create a directory at path: %@",
+            __PRETTY_FUNCTION__, _path);
+      [self release];
+      return nil;
+    }
+  }
+  else if (!isDir) {
+    NSLog(@"%s: not a directory path: %@", __PRETTY_FUNCTION__, _path);
+    [self release];
+    return nil;
+  }
+  
+  if ((self = [super init])) {
+    self->snPath = [_path copy];
+    self->fileManager = [fm retain];
+  }
+  return self;
+}
+- (id)init {
+  NSString *p;
+  p = [[NSUserDefaults standardUserDefaults]
+       stringForKey:@"WOFileSessionPath"];
+  return [self initWithSessionPath:p];
+}
+
+- (void)dealloc {
+  [self->fileManager release];
+  [self->snPath      release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (int)activeSessionsCount {
+  return 0;
+  //return [[self->fileManager directoryContentsAtPath:self->snPath] count];
+}
+
+/* store */
+
+- (NSString *)pathForSessionID:(NSString *)_sid {
+  return [self->snPath stringByAppendingPathComponent:_sid];
+}
+
+- (void)saveSessionForContext:(WOContext *)_context {
+  WOSession *sn;
+  NSString *snp;
+  
+  if (![_context hasSession])
+    return;
+  
+  sn  = [_context session];
+  snp = [self pathForSessionID:[sn sessionID]];
+  
+  if ([sn isTerminating]) {
+    sn = RETAIN(sn);
+        
+    // TODO: NOT IMPLEMENTED (serialized-session termination)
+    //NSMapRemove(self->idToSession, [sn sessionID]);
+    
+    NSLog(@"session %@ terminated at %@ ..",
+          [sn sessionID], [NSCalendarDate calendarDate]);
+    [sn release];
+  }
+  else {
+    NSData *data;
+    
+    data = [NSArchiver archivedDataWithRootObject:sn];
+    
+    if (data) {
+      if (![data writeToFile:snp atomically:YES]) {
+        [self logWithFormat:
+               @"could not write data of session %@ to file: '%@'", sn, snp];
+      }
+    }
+    else
+      [self logWithFormat:@"could not archive session: '%@'", sn];
+  }
+}
+
+- (WOSession *)restoreSessionWithID:(NSString *)_sid
+  request:(WORequest *)_request
+{
+  NSAutoreleasePool *pool;
+  NSString *snp;
+  WOSession *session = nil;
+
+  if ([_sid length] == 0)
+    return nil;
+  
+  if (![_sid isKindOfClass:[NSString class]]) {
+    NSLog(@"WARNING(%s): got invalid session id (expected string !): %@",
+          __PRETTY_FUNCTION__, _sid);
+    return nil;
+  }
+  
+  if ([_sid isEqualToString:@"expired"])
+    return nil;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    snp = [self pathForSessionID:_sid];
+    
+    if ([self->fileManager fileExistsAtPath:snp]) {
+      NSData *data;
+      
+      if ((data = [self->fileManager contentsAtPath:snp])) {
+        session = [NSUnarchiver unarchiveObjectWithData:data];
+        // NSLog(@"unarchived session: %@", session);
+        
+        if (![session isKindOfClass:[WOSession class]]) {
+          NSLog(@"object unarchived from %@ isn't a WOSession: %@ ...",
+                snp, session);
+          session = nil;
+        }
+      }
+      else {
+        [self logWithFormat:@"could not read sn file: '%@'", snp];
+        session = nil;
+      }
+    }
+    else {
+      [self logWithFormat:@"session file does not exist: '%@'", snp];
+      session = nil;
+    }
+
+    [session retain];
+  }
+  [pool release];
+  
+  if (logExpire) {
+    if (session == nil)
+      [self logWithFormat:@"session with id %@ expired.", _sid];
+  }
+  
+  return [session autorelease];
+}
+
+/* termination */
+
+- (void)sessionExpired:(NSString *)_sessionID {
+  [self->lock lock];
+  {
+    // TODO: NOT IMPLEMENTED (serialized session expiration)
+    NSLog(@"%@ expired.", _sessionID);
+    // NSMapRemove(self->idToSession, _sessionID);
+  }
+  [self->lock unlock];
+}
+
+- (void)sessionTerminated:(WOSession *)_session {
+  _session = RETAIN(_session);
+  [self->lock lock];
+  {
+    // TODO: NOT IMPLEMENTED (serialized session termination)
+    NSLog(@"%@ terminated.", [_session sessionID]);
+    // NSMapRemove(self->idToSession, [_session sessionID]);
+  }
+  [self->lock unlock];
+  RELEASE(_session);
+  
+  [[WOApplication application]
+                  logWithFormat:
+                    @"WOFileSessionStore: session %@ terminated.",
+                    [_session sessionID]];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: path=%@>",
+                     NSStringFromClass([self class]), self, self->snPath];
+}
+
+@end /* WOFileSessionStore */
diff --git a/skyrix-sope/NGObjWeb/WOHTTPConnection.m b/skyrix-sope/NGObjWeb/WOHTTPConnection.m
new file mode 100644 (file)
index 0000000..e3926cd
--- /dev/null
@@ -0,0 +1,873 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOHTTPConnection.h>
+#include <NGObjWeb/WOCookie.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOCookie.h>
+#include <NGObjWeb/WORunLoop.h>
+#include <NGStreams/NGStreams.h>
+#include <NGStreams/NGCTextStream.h>
+#include <NGStreams/NGBufferedStream.h>
+#include <NGStreams/NGNet.h>
+#include <NGHttp/NGHttp.h>
+#include <NGMime/NGMime.h>
+#import <Foundation/Foundation.h>
+#include "WOSimpleHTTPParser.h"
+#include "WOHttpAdaptor/WORecordRequestStream.h"
+
+@interface WOHTTPConnection(Privates)
+- (BOOL)_connect;
+- (void)_disconnect;
+- (void)_unregisterNotification;
+@end
+
+@interface WOCookie(Privates)
++ (id)cookieWithString:(NSString *)_string;
+@end
+
+NSString *WOHTTPConnectionCanReadResponse = @"WOHTTPConnectionCanReadResponse";
+
+@interface NSURL(SocketAddress)
+- (id)socketAddressForURL;
+- (BOOL)shouldUseWOProxyServer;
+@end
+
+@interface WOHTTPConnection(Privates2)
++ (NSString *)proxyServer;
++ (NSURL *)proxyServerURL;
++ (NSArray *)noProxySuffixes;
+@end
+
+@implementation WOHTTPConnection
+
+static Class SSLSocketClass  = Nil;
+static BOOL  useSimpleParser = YES;
+static NSString *proxyServer = nil;
+static NSArray  *noProxy     = nil;
+static BOOL doDebug   = NO;
+static BOOL logStream = NO;
+
++ (int)version {
+  return 3;
+}
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+    
+  useSimpleParser = [ud boolForKey:@"WOHTTPConnectionUseSimpleParser"];
+  proxyServer     = [ud stringForKey:@"WOProxyServer"];
+  noProxy         = [ud arrayForKey:@"WONoProxySuffixes"];
+  doDebug         = [ud boolForKey:@"WODebugHTTPConnection"];
+  logStream       = [ud boolForKey:@"WODebugHTTPConnectionLogStream"];
+}
+
++ (NSString *)proxyServer {
+  return proxyServer;
+}
++ (NSURL *)proxyServerURL {
+  NSString *ps;
+
+  ps = [self proxyServer];
+  if ([ps length] == 0)
+    return nil;
+  
+  return [NSURL URLWithString:ps];
+}
++ (NSArray *)noProxySuffixes {
+  return noProxy;
+}
+
+- (id)initWithNSURL:(NSURL *)_url {
+  if ((self = [super init])) {
+    self->url      = [_url retain];
+    self->useSSL   = [[_url scheme] isEqualToString:@"https"];
+    self->useProxy = [_url shouldUseWOProxyServer];
+    
+    if (self->useSSL) {
+      static BOOL didCheck = NO;
+      if (!didCheck) {
+       didCheck = YES;
+       SSLSocketClass = NSClassFromString(@"NGActiveSSLSocket");
+      }
+    }
+  }
+  return self;
+}
+
+- (id)initWithURL:(id)_url {
+  NSURL *lurl;
+  
+  /* create an NSURL object if necessary */
+  lurl = [_url isKindOfClass:[NSURL class]]
+    ? _url
+    : [NSURL URLWithString:[_url stringValue]];
+  if (lurl == nil) {
+    if (doDebug)
+      [self logWithFormat:@"could not construct URL from object '%@' !", _url];
+    [self release];
+    return nil;
+  }
+  if (doDebug)
+    [self logWithFormat:@"init with URL: %@", lurl];
+  return [self initWithNSURL:lurl];
+}
+
+- (id)initWithHost:(NSString *)_hostName onPort:(unsigned int)_port 
+  secure:(BOOL)_flag
+{
+  NSString *s;
+  
+  s = [NSString stringWithFormat:@"http%s://%@:%i/",
+                 _flag ? "s" : "", _hostName, 
+                 _port == 0 ? (_flag?443:80) : _port];
+  return [self initWithURL:s];
+}
+- (id)initWithHost:(NSString *)_hostName onPort:(unsigned int)_port {
+  return [self initWithHost:_hostName onPort:_port secure:NO];
+}
+- (id)init {
+  return [self initWithHost:@"localhost" onPort:80 secure:NO];
+}
+
+- (void)dealloc {
+  [self _unregisterNotification];
+  [self->lastException release];
+  [self->log      release];
+  [self->io       release];
+  [self->socket   release];
+  [self->url      release];
+  [super dealloc];
+}
+
+/* error handling */
+
+- (NSException *)lastException {
+  return self->lastException;
+}
+
+- (BOOL)isDebuggingEnabled {
+  return doDebug ? YES : NO;
+}
+- (NSString *)loggingPrefix {
+  /* improve perf ... */
+  if (self->url) {
+    return [NSString stringWithFormat:@"WOHTTP[0x%08X]<%@>", 
+                      self, [self->url absoluteString]];
+  }
+  else
+    return [NSString stringWithFormat:@"WOHTTP[0x%08X]", self];
+}
+
+/* accessors */
+
+- (NSString *)hostName {
+  return [self->url host];
+}
+
+/* IO */
+
+- (BOOL)_connect {
+  id<NGSocketAddress> address;
+  
+  [self _disconnect];
+  
+#if DEBUG
+  NSAssert(self->socket == nil, @"socket still available after disconnect");
+  NSAssert(self->io == nil,     @"IO stream still available after disconnect");
+#endif
+  
+  if (self->useSSL) {
+    if (SSLSocketClass == Nil) {
+      /* no SSL support is available */
+      static BOOL didLog = NO;
+      if (!didLog) {
+       didLog = YES;
+       NSLog(@"NOTE: SSL support is not available !");
+      }
+      return NO;
+    }
+  }
+  
+  if (self->useProxy) {
+    NSURL *purl;
+    
+    purl = [[self class] proxyServerURL];
+    address = [purl socketAddressForURL];
+  }
+  else {
+    address = [self->url socketAddressForURL];
+  }
+  if (address == nil) {
+    [self debugWithFormat:@"got no address for connect .."];
+    return NO;
+  }
+  
+  NS_DURING {
+    self->socket = self->useSSL
+      ? [SSLSocketClass socketConnectedToAddress:address]
+      : [NGActiveSocket socketConnectedToAddress:address];
+  }
+  NS_HANDLER {
+#if 0
+    fprintf(stderr, "couldn't create socket: %s\n",
+            [[localException description] cString]);
+#endif
+    ASSIGN(self->lastException, localException);
+    self->socket = nil;
+  }
+  NS_ENDHANDLER;
+  
+  if (self->socket == nil) {
+    [self debugWithFormat:@"socket is not setup: %@", [self lastException]];
+    return NO;
+  }
+  
+  if (![self->socket isConnected]) {
+    self->socket = nil;
+    [self debugWithFormat:@"socket is not connected .."];
+    return NO;
+  }
+  
+  self->socket = [self->socket retain];
+  
+  [(NGActiveSocket *)self->socket setSendTimeout:[self sendTimeout]];
+  [(NGActiveSocket *)self->socket setReceiveTimeout:[self receiveTimeout]];
+  
+  if (self->socket) {
+    id bStr;
+    
+    bStr = [[NGBufferedStream alloc] initWithSource:self->socket];
+    if (logStream)
+      self->log = [[WORecordRequestStream alloc] initWithSource:bStr];
+    else
+      self->log = nil;
+    
+    self->io = 
+      [[NGCTextStream alloc] initWithSource:(id)(self->log?self->log:bStr)];
+    [bStr release]; bStr = nil;
+  }
+  
+  return YES;
+}
+- (void)_disconnect {
+  [self->log release]; self->log = nil;
+  [self->io  release]; self->io  = nil;
+  
+  NS_DURING
+    (void)[self->socket shutdown];
+  NS_HANDLER {}
+  NS_ENDHANDLER;
+  
+  [self->socket release]; self->socket = nil;
+}
+
+/* runloop based IO */
+
+- (NSNotificationCenter *)notificationCenter {
+  return [NSNotificationCenter defaultCenter];
+}
+- (NSRunLoop *)runLoop {
+  return [NSRunLoop currentRunLoop];
+}
+- (NSString *)runLoopMode {
+  return NSDefaultRunLoopMode;
+}
+
+- (void)_socketActivated:(NSNotification *)_n {
+  if ([_n object] != self->socket)
+    return;
+
+#if DEBUG && 0  
+  [self debugWithFormat:@"socket activated ..."];
+#endif
+  
+  [[self notificationCenter]
+         postNotificationName:WOHTTPConnectionCanReadResponse
+         object:self];
+}
+
+- (void)_registerForNotification {
+  NSRunLoop *rl;
+  
+  if (self->didRegisterForNotification)
+    return;
+
+  [[self notificationCenter]
+         addObserver:self selector:@selector(_socketActivated:)
+         name:NSFileObjectBecameActiveNotificationName
+         object:self->socket];
+  
+  rl = [self runLoop];
+  [rl addFileObject:self->socket
+      activities:(NSPosixReadableActivity|NSPosixExceptionalActivity)
+      forMode:[self runLoopMode]];
+}
+- (void)_unregisterNotification {
+  if (!self->didRegisterForNotification)
+    return;
+  
+  [[self notificationCenter] removeObserver:self];
+  
+  [[self runLoop] removeFileObject:self->socket
+                  forMode:[self runLoopMode]];
+}
+
+/* logging IO */
+
+- (void)logRequest:(WORequest *)_response data:(NSData *)_data {
+  if (_data == nil) return;
+  
+#if 1
+  NSLog(@"request is\n");
+  fflush(stderr);
+  fwrite([_data bytes], 1, [_data length], stderr);
+  fflush(stderr);
+  fprintf(stderr,"\n");
+  fflush(stderr);
+#endif
+}
+- (void)logResponse:(WOResponse *)_response data:(NSData *)_data {
+  if (_data == nil) return;
+  
+#if 1
+  NSLog(@"response is\n");
+  fflush(stderr);
+  fwrite([_data bytes], 1, [_data length], stderr);
+  fflush(stderr);
+  fprintf(stderr,"\n");
+  fflush(stderr);
+#endif
+}
+
+/* sending/receiving HTTP */
+
+- (BOOL)sendRequest:(WORequest *)_request {
+  NSData *content;
+  BOOL isok = YES;
+  
+  if (doDebug)
+    [self debugWithFormat:@"send request: %@", _request];
+  
+  if (![self->socket isConnected]) {
+    if (![self _connect]) {
+      /* could not connect */
+      if (doDebug)
+        [self debugWithFormat:@"  could not connect socket"];
+      return NO;
+    }
+    /* now connected */
+  }
+  
+  content = [_request content];
+  
+  /* write request line (eg 'GET / HTTP/1.0') */
+  if (doDebug)
+    [self debugWithFormat:@"  method: %@", [_request method]];
+  
+  if (isok) isok = [self->io writeString:[_request method]];
+  if (isok) isok = [self->io writeString:@" "];
+  
+  if (self->useProxy) {
+    if (isok)
+      // TODO: check whether this produces a '//' (may need to strip uri)
+      isok = [self->io writeString:[self->url absoluteString]];
+    [self debugWithFormat:@"  wrote proxy start ..."];
+  }
+  if (isok) isok = [self->io writeString:[_request uri]];
+  
+  if (isok) isok = [self->io writeString:@" "];
+  if (isok) isok = [self->io writeString:[_request httpVersion]];
+  if (isok) isok = [self->io writeString:@"\r\n"];
+
+  /* set content-length header */
+  
+  if ([content length] > 0) {
+    [_request setHeader:[NSString stringWithFormat:@"%d", [content length]]
+              forKey:@"content-length"];
+  }
+
+  if ([[self->url scheme] hasPrefix:@"http"]) {
+    /* host header */
+    
+    if (isok) isok = [self->io writeString:@"Host: "];
+    if (isok) isok = [self->io writeString:[self hostName]];
+    if (isok) isok = [self->io writeString:@"\r\n"];
+    [self debugWithFormat:@"  wrote host header: %@", [self hostName]];
+  }
+  
+  /* write request headers */
+
+  if (isok) {
+    NSEnumerator *fields;
+    NSString *fieldName;
+    int cnt;
+    
+    fields = [[_request headerKeys] objectEnumerator];
+    cnt = 0;
+    while (isok && (fieldName = [fields nextObject])) {
+      NSEnumerator *values;
+      id value;
+
+      if ([fieldName length] == 4) {
+       if ([fieldName isEqualToString:@"host"])
+         /* did already write host ... */
+         continue;
+       if ([fieldName isEqualToString:@"Host"])
+         /* did already write host ... */
+         continue;
+      }
+      
+      values = [[_request headersForKey:fieldName] objectEnumerator];
+        
+      while ((value = [values nextObject]) && isok) {
+        if (isok) isok = [self->io writeString:fieldName];
+        if (isok) isok = [self->io writeString:@": "];
+        if (isok) isok = [self->io writeString:value];
+        if (isok) isok = [self->io writeString:@"\r\n"];
+        cnt++;
+      }
+    }
+    [self debugWithFormat:@"  wrote %i request headers ...", cnt];
+  }
+  
+  /* write some required headers */
+  
+  if ([_request headerForKey:@"accept"] == nil) {
+    if (isok) isok = [self->io writeString:@"Accept: */*\r\n"];
+    [self debugWithFormat:@"  wrote accept header ..."];
+  }
+  if ([_request headerForKey:@"user-agent"] == nil) {
+    if (isok) isok = [self->io writeString:@"User-Agent: SOPE/4.2\r\n"];
+    [self debugWithFormat:@"  wrote user-agent header ..."];
+  }
+  
+  /* write cookie headers */
+  
+  if ([[_request cookies] count] > 0 && isok) {
+    NSEnumerator *cookies;
+    WOCookie     *cookie;
+    BOOL         isFirst;
+    int cnt;
+    
+    [self->io writeString:@"set-cookie: "];
+    cnt = 0;
+    cookies = [[_request cookies] objectEnumerator];
+    isFirst = YES;
+    while (isok && (cookie = [cookies nextObject])) {
+      if (isFirst) isFirst = NO;
+      else if (isok) isok = [self->io writeString:@"; "];
+      
+      if (isok) isok = [self->io writeString:[cookie stringValue]];
+      cnt ++;
+    }
+    if (isok) isok = [self->io writeString:@"\r\n"];
+    [self debugWithFormat:@"  wrote %i cookies ...", cnt];
+  }
+  
+  /* flush request header on socket */
+  
+  if (isok) isok = [self->io writeString:@"\r\n"];
+  if (isok) isok = [self->io flush];
+  [self debugWithFormat:@"  flushed HTTP header."];
+  
+  /* write content */
+
+  if ([content length] > 0) {
+    [self debugWithFormat:@"  writing HTTP entity (length=%i).", 
+            [content length]];
+    
+    if ([content isKindOfClass:[NSString class]]) {
+      if (isok) isok = [self->io writeString:(NSString *)content];
+    }
+    else if ([content isKindOfClass:[NSData class]]) {
+      if (isok) isok = [[self->io source]
+                         safeWriteBytes:[content bytes]
+                         count:[content length]];
+    }
+    else {
+      if (isok) isok = [self->io writeString:[content description]];
+    }
+    if (isok) isok = [self->io flush];
+  }
+  else if (doDebug) {
+    [self debugWithFormat:@"  no HTTP entity to write ..."];
+  }
+  
+  if (logStream)
+    [self logRequest:_request data:[self->log writeLog]];
+  [self->log resetWriteLog];
+  
+  [self debugWithFormat:@"=> finished:\n  url:  %@\n  sock: %@", 
+          self->url, self->socket];
+  if (!isok) {
+    ASSIGN(self->lastException, [self->socket lastException]);
+    [self->socket shutdown];
+    return NO;
+  }
+  
+  if (![self->socket isConnected])
+    return NO;
+  
+  [self _registerForNotification];
+  
+  return YES;
+}
+
+- (NSException *)handleResponseParsingError:(NSException *)_exception {
+    fprintf(stderr, "%s: caught: %s\n",
+            __PRETTY_FUNCTION__,
+            [[_exception description] cString]);
+    return nil;
+}
+
+- (WOResponse *)readResponse {
+  /* TODO: split up method */
+  WOResponse *response;
+  
+  *(&response) = nil;
+  [self _unregisterNotification];
+  
+  if (self->socket == nil) {
+    [self debugWithFormat:@"no socket available for reading response ..."];
+    return nil;
+  }
+  
+  [self debugWithFormat:@"parsing response from socket: %@", self->socket];
+  
+  if (useSimpleParser) {
+    WOSimpleHTTPParser *parser;
+    
+    [self debugWithFormat:@"  using simple HTTP parser ..."];
+    
+    parser = [[WOSimpleHTTPParser alloc] initWithStream:[self->io source]];
+    if (parser == nil)
+      return nil;
+    parser = [parser autorelease];
+    
+    if ((response = [parser parseResponse]) == nil) {
+      if (doDebug)
+        [self debugWithFormat:@"parsing failed: %@", [parser lastException]];
+    }
+  }
+  else {
+    NGHttpMessageParser *parser;
+    NGHttpResponse *mresponse;
+    NGMimeType     *ctype;
+    id body;
+    
+    *(&mresponse) = nil;
+    
+    if ((parser = [[[NGHttpMessageParser alloc] init] autorelease]) == nil)
+      return nil;
+    
+    [self debugWithFormat:@"  using MIME HTTP parser (complex parser) ..."];
+    
+    NS_DURING {
+      [parser setDelegate:self];
+      mresponse = [parser parseResponseFromStream:self->socket];
+    }
+    NS_HANDLER
+      [[self handleResponseParsingError:localException] raise];
+    NS_ENDHANDLER;
+    
+    [self debugWithFormat:@"finished parsing response: %@", mresponse];
+    
+    /* transform parsed MIME response to WOResponse */
+    
+    body = [mresponse body];
+    if (body == nil) body = [NSData data];
+    
+    response = [[[WOResponse alloc] init] autorelease];
+    [response setHTTPVersion:[mresponse httpVersion]];
+    [response setStatus:[mresponse statusCode]];
+    [response setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+                                          self,      @"NGHTTPConnection",
+                                          mresponse, @"NGMimeResponse",
+                                          body,      @"NGMimeBody",
+                                          nil]];
+  
+    { /* check content-type */
+      id value;
+      
+      value = [[mresponse valuesOfHeaderFieldWithName:@"content-type"] 
+                       nextObject];
+      if (value) {
+        NSString *charset;
+        
+        ctype = [NGMimeType mimeType:[value stringValue]];
+        charset = [[ctype valueOfParameter:@"charset"] lowercaseString];
+        
+        if ([charset length] == 0) {
+          /* autodetect charset ... */
+          
+          if ([[ctype type] isEqualToString:@"text"]) {
+            if ([[ctype subType] isEqualToString:@"xml"]) {
+              /* default XML encoding is UTF-8 */
+              [response setContentEncoding:NSUTF8StringEncoding];
+            }
+          }
+        }
+        else {
+          NSStringEncoding enc;
+          
+          enc = [NGMimeType stringEncodingForCharset:charset];
+          [response setContentEncoding:enc];
+        }
+        
+        [response setHeader:[ctype stringValue] forKey:@"content-type"];
+        
+      }
+      else {
+        ctype = [NGMimeType mimeType:@"application/octet-stream"];
+      }
+    }
+  
+    /* check content */
+    
+    if ([body isKindOfClass:[NSData class]]) {
+      [response setContent:body];
+    }
+    else if ([body isKindOfClass:[NSString class]]) {
+      NSData *data;
+      
+      data = [body dataUsingEncoding:[response contentEncoding]];
+      if (data)
+        [response setContent:data];
+    }
+    else if (body) {
+      /* generate data from structured body .. */
+      NGMimeBodyGenerator *gen;
+      NSData *data;
+      
+      gen = [[[NGMimeBodyGenerator alloc] init] autorelease];
+      data = [gen generateBodyOfPart:body
+                  additionalHeaders:nil
+                  delegate:self];
+      [response setContent:data];
+    }
+    
+    { /* transfer headers */
+      NSEnumerator *names;
+      NSString     *name;
+      
+      names = [mresponse headerFieldNames];
+      while ((name = [names nextObject])) {
+        NSEnumerator *values;
+        id           value;
+        
+        if ([name isEqualToString:@"content-type"])
+          continue;
+        if ([name isEqualToString:@"set-cookie"])
+          continue;
+        
+        values = [mresponse valuesOfHeaderFieldWithName:name];
+        while ((value = [values nextObject])) {
+          value = [value stringValue];
+          [response appendHeader:value forKey:name];
+        }
+      }
+    }
+    
+    { /* transfer cookies */
+      NSEnumerator *cookies;
+      NGHttpCookie *mcookie;
+  
+      cookies = [mresponse valuesOfHeaderFieldWithName:@"set-cookie"];
+      
+      while ((mcookie = [cookies nextObject])) {
+        WOCookie *woCookie;
+        
+        if (![mcookie isKindOfClass:[NGHttpCookie class]]) {
+          /* parse cookie */
+          woCookie = [WOCookie cookieWithString:[mcookie stringValue]];
+        }
+        else {
+          woCookie = [WOCookie cookieWithName:[mcookie cookieName]
+                               value:[mcookie value]
+                               path:[mcookie path]
+                               domain:[mcookie domainName]
+                               expires:[mcookie expireDate]
+                               isSecure:[mcookie needsSecureChannel]];
+        }
+        if (woCookie == nil) {
+          [self logWithFormat:
+                 @"Couldn't create WOCookie from NGHttp cookie: %@",
+                  mcookie];
+          // could not create cookie
+          continue;
+        }
+        
+        [self debugWithFormat:@"adding cookie: %@", woCookie];
+        
+        [response addCookie:woCookie];
+      }
+    }
+  }
+  
+  if (logStream)
+    [self logResponse:response data:[self->log readLog]];
+  [self->log resetReadLog];
+  
+  if (doDebug)
+    [self debugWithFormat:@"processed response: %@", response];
+  
+  /* check keep-alive */
+  {
+    NSString *conn;
+    
+    conn = [response headerForKey:@"connection"];
+    conn = [conn lowercaseString];
+    
+    if ([conn isEqualToString:@"close"]) {
+      [self setKeepAliveEnabled:NO];
+      [self _disconnect];
+    }
+    else if ([conn isEqualToString:@"keep-alive"]) {
+      [self setKeepAliveEnabled:YES];
+    }
+    else {
+      [self setKeepAliveEnabled:NO];
+      [self _disconnect];
+    }
+  }
+  
+  return response;
+}
+
+- (void)setKeepAliveEnabled:(BOOL)_flag {
+  self->keepAlive = _flag;
+}
+- (BOOL)keepAliveEnabled {
+  return self->keepAlive;
+}
+
+/* timeouts */
+
+- (void)setConnectTimeout:(int)_seconds {
+  self->connectTimeout = _seconds;
+}
+- (int)connectTimeout {
+  return self->connectTimeout;
+}
+
+- (void)setReceiveTimeout:(int)_seconds {
+  self->receiveTimeout = _seconds;
+}
+- (int)receiveTimeout {
+  return self->receiveTimeout;
+}
+
+- (void)setSendTimeout:(int)_seconds {
+  self->sendTimeout = _seconds;
+}
+- (int)sendTimeout {
+  return self->sendTimeout;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *str;
+  
+  str = [NSMutableString stringWithCapacity:128];
+  [str appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
+  
+  if (self->url)      [str appendFormat:@" url=%@", self->url];
+  if (self->useProxy) [str appendString:@" proxy"];
+  if (self->useSSL)   [str appendString:@" SSL"];
+
+  if (self->socket) [str appendFormat:@" socket=%@", self->socket];
+  
+  [str appendString:@">"];
+  return str;
+}
+
+@end /* WOHTTPConnection */
+
+@implementation NSURL(SocketAddress)
+
+- (id)socketAddressForURL {
+  NSString *s;
+  
+  s = [self scheme];
+  
+  if ([s isEqualToString:@"http"]) {
+    int p;
+    
+    s = [self host];
+    if ([s length] == 0) s = @"localhost";
+    p = [[self port] intValue];
+    
+    return [NGInternetSocketAddress addressWithPort:p == 0 ? 80 : p onHost:s];
+  }
+  else if ([s isEqualToString:@"https"]) {
+    int p;
+    
+    s = [self host];
+    if ([s length] == 0) s = @"localhost";
+    p = [[self port] intValue];
+    
+    return [NGInternetSocketAddress addressWithPort:p == 0 ? 443 : p onHost:s];
+  }
+  else if ([s isEqualToString:@"unix"] || [s isEqualToString:@"file"]) {
+    return [NGLocalSocketAddress addressWithPath:[self path]];
+  }
+  return nil;
+}
+
+- (BOOL)shouldUseWOProxyServer {
+  if ([[self scheme] hasPrefix:@"http"]) {
+    NSString *h;
+    
+    if ((h = [self host]) == nil)
+      return NO;
+    
+    if ([h isEqualToString:@"127.0.0.1"])
+      return NO;
+    if ([h isEqualToString:@"localhost"])
+      return NO;
+    
+    if ([[WOHTTPConnection proxyServer] length] > 0) {
+      NSEnumerator *e;
+      NSString *suffix;
+      BOOL     useProxy;
+      
+      useProxy = YES;
+      e = [[WOHTTPConnection noProxySuffixes] objectEnumerator];
+      while ((suffix = [e nextObject])) {
+        if ([h hasSuffix:suffix]) {
+          useProxy = NO;
+          break;
+        }
+      }
+      return useProxy;
+    }
+  }
+  return NO;
+}
+
+@end /* NSURL(SocketAddress) */
diff --git a/skyrix-sope/NGObjWeb/WOHTTPURLHandle.m b/skyrix-sope/NGObjWeb/WOHTTPURLHandle.m
new file mode 100644 (file)
index 0000000..9a2e6f7
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/NSObject.h> // required by gstep-base
+#import <Foundation/NSURLHandle.h>
+#import <Foundation/NSURL.h>
+
+@class WOResponse;
+
+/*
+  An URLHandle class which uses WO classes (WOHTTPConnection, WORequest, ..)
+  to get/set HTTP resources.
+*/
+
+@interface WOHTTPURLHandle : NSURLHandle
+{
+  NSURL             *url;
+  BOOL              shallCache;
+  WOResponse        *cachedResponse;
+  NSURLHandleStatus status;
+}
+@end
+
+#include <NGObjWeb/WOHTTPConnection.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+@implementation WOHTTPURLHandle
+
++ (BOOL)canInitWithURL:(NSURL *)_url {
+  return [[_url scheme] isEqualToString:@"http"];
+}
+
+- (id)initWithURL:(NSURL *)_url cached:(BOOL)_flag {
+  if (![[_url scheme] isEqualToString:@"http"]) {
+    NSLog(@"%s: invalid URL scheme %@ for WOHTTPURLHandle !",
+          __PRETTY_FUNCTION__, [_url scheme]);
+    RELEASE(self);
+    return nil;
+  }
+  
+  self->shallCache = _flag;
+  self->url        = [_url copy];
+  self->status     = NSURLHandleNotLoaded;
+  return self;
+}
+- (void)dealloc {
+  RELEASE(self->cachedResponse);
+  RELEASE(self->url);
+  [super dealloc];
+}
+
+- (WOResponse *)_fetchURL:(NSURL *)_url {
+  WOHTTPConnection *connection;
+  WORequest        *request;
+  WOResponse       *response = nil;
+  
+  connection = [[WOHTTPConnection alloc] initWithHost:[_url host]
+                                         onPort:[[_url port] intValue]];
+  if (connection == nil) {
+    self->status = NSURLHandleLoadFailed;
+    return nil;
+  }
+
+  request = [[WORequest alloc] initWithMethod:@"GET"
+                               uri:[_url path]
+                               httpVersion:@"HTTP/1.0"
+                               headers:nil
+                               content:nil
+                               userInfo:nil];
+  if (request == nil) {
+    RELEASE(connection);
+    self->status = NSURLHandleLoadFailed;
+    return nil;
+  }
+  
+  if ([connection sendRequest:request]) {
+    if ((response = [connection readResponse])) {
+      if (self->shallCache)
+        ASSIGN(self->cachedResponse, response);
+      self->status = NSURLHandleLoadSucceeded;
+      RETAIN(response);
+    }
+    else
+      self->status = NSURLHandleLoadFailed;
+  }
+  else {
+    self->status = NSURLHandleLoadFailed;
+  }
+  
+  RELEASE(request);
+  RELEASE(connection);
+  
+  return AUTORELEASE(response);
+}
+
+- (NSData *)loadInForeground {
+  WOResponse *response;
+  NSData     *data;
+  
+  response = [self _fetchURL:self->url];
+  data = [response content];
+  RETAIN(data);
+  return AUTORELEASE(data);
+}
+- (void)loadInBackground {
+  [self loadInForeground];
+}
+
+- (void)flushCachedData {
+  RELEASE(self->cachedResponse);
+  self->cachedResponse = nil;
+}
+
+- (NSData *)resourceData {
+  if (self->cachedResponse) {
+    NSData *data;
+
+    data = [self->cachedResponse content];
+    RETAIN(data);
+    return AUTORELEASE(data);
+  }
+
+  return [self loadInForeground];
+}
+- (NSData *)availableResourceData {
+  NSData *data;
+
+  data = [self->cachedResponse content];
+  RETAIN(data);
+  return AUTORELEASE(data);
+}
+
+- (NSURLHandleStatus)status {
+  return self->status;
+}
+- (NSString *)failureReason {
+  if (self->status != NSURLHandleLoadFailed)
+    return nil;
+
+  return @"loading of HTTP URL failed";
+}
+
+/* properties */
+
+- (id)propertyForKey:(NSString *)_key {
+  WOResponse *response;
+  
+  if (self->cachedResponse)
+    return [self->cachedResponse headerForKey:_key];
+  
+  response = [self _fetchURL:self->url];
+  return [response headerForKey:_key];
+}
+- (id)propertyForKeyIfAvailable:(NSString *)_key {
+  return [self->cachedResponse headerForKey:_key];
+}
+
+/* writing */
+
+- (BOOL)writeData:(NSData *)__data {
+  WOHTTPConnection *connection;
+  WORequest        *request;
+  WOResponse       *response;
+  
+  [self flushCachedData];
+  
+  connection = [[WOHTTPConnection alloc] initWithHost:[self->url host]
+                                         onPort:[[self->url port] intValue]];
+  if (connection == nil)
+    return NO;
+  
+  request = [[WORequest alloc] initWithMethod:@"PUT"
+                               uri:[self->url path]
+                               httpVersion:@"HTTP/1.0"
+                               headers:nil
+                               content:__data
+                               userInfo:nil];
+  if (request == nil) {
+    RELEASE(connection);
+    return NO;
+  }
+  
+  if ([connection sendRequest:request])
+    response = [connection readResponse];
+  else
+    response = nil;
+  
+  if (response) {
+    if ([response status] != 200)
+      response = nil;
+  }
+  
+  RELEASE(request);
+  RELEASE(connection);
+  
+  return response ? YES : NO;
+}
+
+@end /* WOHTTPURLHandle */
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/.cvsignore b/skyrix-sope/NGObjWeb/WOHttpAdaptor/.cvsignore
new file mode 100644 (file)
index 0000000..86762c6
--- /dev/null
@@ -0,0 +1,3 @@
+
+Resources
+shared_debug_obj
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/GNUmakefile b/skyrix-sope/NGObjWeb/WOHttpAdaptor/GNUmakefile
new file mode 100644 (file)
index 0000000..1560a15
--- /dev/null
@@ -0,0 +1,16 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = WOHttpAdaptor
+
+WOHttpAdaptor_OBJC_FILES = \
+       WOHttpAdaptor.m         \
+       WORecordRequestStream.m \
+       WOHttpTransaction.m     \
+       WORequest+Adaptor.m     \
+       WORequestParser.m       \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/GNUmakefile.preamble b/skyrix-sope/NGObjWeb/WOHttpAdaptor/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..6f95f19
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id$
+
+ADDITIONAL_CPPFLAGS += -pipe -Wall
+ADDITIONAL_CPPFLAGS += -DCOMPILING_NGOBJWEB=1
+
+WOHttpAdaptor_INCLUDE_DIRS += \
+       -I.. -I. -I../..                        \
+       -I../../../skyrix-core                  \
+       -I../../../skyrix-core/NGStreams        \
+       -I../../../skyrix-core/NGExtensions     \
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.h b/skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.h
new file mode 100644 (file)
index 0000000..c55c522
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOHttpAdaptor_H__
+#define __WOHttpAdaptor_H__
+
+#include <NGObjWeb/WOAdaptor.h>
+#import <Foundation/NSDate.h>
+#import <Foundation/NSLock.h>
+#include <NGStreams/NGPassiveSocket.h>
+
+@class NSMutableArray;
+
+@interface WOHttpAdaptor : WOAdaptor
+{
+@protected
+  id<NGPassiveSocket>    socket;
+  NSTimeInterval         sendTimeout;
+  NSTimeInterval         receiveTimeout;
+
+  unsigned short         maxThreadCount;
+  unsigned short         activeThreadCount;
+  id<NSObject,NSLocking> lock;
+  BOOL                   isTerminated;
+
+  id<NGSocketAddress>    address;
+
+  NSMutableArray         *delayedResponses;
+}
+
++ (BOOL)optionLogStream;
++ (BOOL)optionLogPerf;
+
+@end
+
+#endif /* __WOHttpAdaptor_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.m b/skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.m
new file mode 100644 (file)
index 0000000..7437583
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOAdaptor.h>
+#include <NGObjWeb/WOCoreApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOCookie.h>
+
+#include "common.h"
+#include "WORunLoop.h"
+#include "NGHttp+WO.h"
+
+#if LIB_FOUNDATION_LIBRARY
+#  import <Foundation/UnixSignalHandler.h>
+#else
+#  include "UnixSignalHandler.h"
+#endif
+
+//#define USE_POOLS 1
+
+#if USE_POOLS
+#  warning extensive pools are enabled ...
+#endif
+
+static BOOL HTTP_PERFLOG = NO;
+
+#include "WOHttpAdaptor.h"
+#include "WORecordRequestStream.h"
+#include "WOHttpTransaction.h"
+
+@interface WOHttpAdaptor(Server)
+
+/* accessors */
+
+- (id<NGPassiveSocket>)socket;
+- (id<NGSocketAddress>)serverAddress;
+
+- (void)setSendTimeout:(NSTimeInterval)_timeout;
+- (NSTimeInterval)sendTimeout;
+- (void)setReceiveTimeout:(NSTimeInterval)_timeout;
+- (NSTimeInterval)receiveTimeout;
+
+@end /* WOHttpAdaptor */
+
+@interface WOHttpAdaptor(PrivateMethods2)
+
+- (void)logWithFormat:(NSString *)_format, ...;
+
+@end
+
+@implementation WOHttpAdaptor
+
+static BOOL     WOHttpAdaptor_LogStream      = NO;
+static BOOL     WOContactSNS                 = NO;
+static BOOL     WOCoreOnHTTPAdaptorException = NO;
+static NSString *WOPort      = nil;
+static int      WOHttpAdaptorSendTimeout    = 10;
+static int      WOHttpAdaptorReceiveTimeout = 10;
+static id       allow   = nil;
+static BOOL     debugOn = NO;
+
++ (BOOL)optionLogStream {
+  return WOHttpAdaptor_LogStream;
+}
++ (BOOL)optionLogPerf {
+  return HTTP_PERFLOG;
+}
+
++ (int)version {
+  return [super version] + 1 /* v2 */;
+}
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  NSAssert2([super version] == 1,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  WOHttpAdaptor_LogStream = [ud boolForKey:@"WOHttpAdaptor_LogStream"];
+  HTTP_PERFLOG = [[ud objectForKey:@"WOProfileHttpAdaptor"] boolValue];
+  WOPort       = [[ud stringForKey:@"WOPort"] copy];
+  WOContactSNS = [[ud objectForKey:@"WOContactSNS"] boolValue];
+
+  WOCoreOnHTTPAdaptorException = 
+    [[ud objectForKey:@"WOCoreOnHTTPAdaptorException"] boolValue] ? 1 : 0;
+  
+  WOHttpAdaptorSendTimeout    = 
+    [ud integerForKey:@"WOHttpAdaptorSendTimeout"];
+  WOHttpAdaptorReceiveTimeout = 
+    [ud integerForKey:@"WOHttpAdaptorReceiveTimeout"];
+  
+  if (allow == nil) {
+    allow = [ud objectForKey:@"WOHttpAllowHost"];
+    if (allow == nil) {
+      allow = [NSArray arrayWithObjects:
+                         @"localhost", @"localhost.localdomain", nil];
+    }
+      
+    if (![allow isKindOfClass:[NSArray class]])
+      allow = [NSArray arrayWithObject:allow];
+      
+    allow = [allow copy];
+  }
+  
+  if (WOCoreOnHTTPAdaptorException)
+    NSLog(@"WARNING: will dump core on HTTP adaptor exception!");
+}
+
+- (id)autoBindAddress {
+  NGInternetSocketAddress *addr;
+  addr = [[NGInternetSocketAddress alloc] initWithPort:0 onHost:@"127.0.0.1"];
+  return [addr autorelease];
+}
+
+- (id)initWithName:(NSString *)_name
+  arguments:(NSDictionary *)_args
+  application:(WOCoreApplication *)_application
+{
+  if ((self = [super initWithName:_name
+                     arguments:_args
+                     application:_application])) {
+    id arg = nil;
+    
+    if ([[_application recordingPath] length] > 0)
+      WOHttpAdaptor_LogStream = YES;
+    
+#if !defined(__MINGW32__)
+    {
+      UnixSignalHandler *us = [UnixSignalHandler sharedHandler];
+      
+      [us addObserver:self selector:@selector(handleSIGPIPE:)
+          forSignal:SIGPIPE
+          immediatelyNotifyOnSignal:NO];
+    }
+#endif
+    
+    if ([_args count] < 1) {
+      NSString   *arg;
+      const char *cstr;
+      
+      arg = WOPort;
+      
+      self->address = nil;
+      
+      if ([arg isEqualToString:@"auto"]) {
+        self->address = [self autoBindAddress];
+      }
+      
+      if ((self->address == nil) && (cstr = [arg cString])) {
+        if (isdigit(*cstr)) {
+          self->address =
+            [NGInternetSocketAddress wildcardAddressWithPort:[arg intValue]];
+        }
+      }
+      if (self->address == nil)
+        self->address = NGSocketAddressFromString(arg);
+    }
+    else {
+      NSString *arg = nil;
+      
+      if ((arg = [_args objectForKey:@"-p"])) {
+        self->address =
+          [NGInternetSocketAddress wildcardAddressWithPort:[arg intValue]];
+      }
+      else if ((arg = [_args objectForKey:@"-WOPort"])) {
+        const char *cstr;
+        
+        self->address = nil;
+        
+        if ([arg isEqualToString:@"auto"])
+          self->address = [self autoBindAddress];
+        
+        if ((self->address == nil) && (cstr = [arg cString])) {
+          if (isdigit(*cstr)) {
+            self->address =
+              [NGInternetSocketAddress wildcardAddressWithPort:[arg intValue]];
+          }
+        }
+        if (self->address == nil)
+          self->address = NGSocketAddressFromString(arg);
+      }
+    }
+    self->address = [self->address retain];
+    
+    if (self->address == nil) {
+      [_application logWithFormat:
+                      @"got no address for HTTP server (using arg '%@')", arg];
+      [self release];
+      return nil;
+    }
+    
+    if (!WOContactSNS) {
+      [_application logWithFormat:@"%@ listening on address %@",
+                      NSStringFromClass([self class]), self->address];
+    }
+    
+    self->lock = [[NSRecursiveLock alloc] init];
+    
+    self->maxThreadCount = [[WOCoreApplication workerThreadCount] intValue];
+    
+    [self setSendTimeout:WOHttpAdaptorSendTimeout];
+    [self setReceiveTimeout:WOHttpAdaptorReceiveTimeout];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[UnixSignalHandler    sharedHandler] removeObserver:self];
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [self->lock    release];
+  [self->socket  release];
+  [self->address release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id<NGSocketAddress>)socketAddress {
+  /* used by sns */
+  return self->address;
+}
+
+/* events */
+
+- (void)handleSIGPIPE:(int)_signal {
+  [self logWithFormat:@"caught SIGPIPE !"];
+}
+
+- (void)registerForEvents {
+  int backlog;
+  
+  backlog = [[WOCoreApplication listenQueueSize] intValue];
+  
+  if (backlog == 0)
+    backlog = 5;
+  
+  [self->socket release]; self->socket = nil;
+  
+  self->socket =
+    [[NGPassiveSocket alloc] initWithDomain:[self->address domain]];
+  
+  [self->socket bindToAddress:self->address];
+  
+  if ([[self->address domain] isEqual:[NGInternetSocketDomain domain]]) {
+    if ([(NGInternetSocketAddress *)self->address port] == 0) {
+      /* let the kernel choose an IP address */
+      
+      [self debugWithFormat:@"bound to wildcard: %@", self->address];
+      [self debugWithFormat:@"got local: %@", [self->socket localAddress]];
+      
+      self->address = [[self->socket localAddress] retain];
+      
+      [self logWithFormat:@"bound to kernel assigned address %@: %@",
+              self->address, self->socket];
+    }
+  }
+  
+  [self->socket listenWithBacklog:backlog];
+  
+  [[NSNotificationCenter defaultCenter]
+                         addObserver:self selector:@selector(acceptConnection:)
+                         name:NSFileObjectBecameActiveNotificationName
+                         object:self->socket];
+  [(WORunLoop *)[WORunLoop currentRunLoop]
+              addFileObject:self->socket
+              activities:NSPosixReadableActivity
+              forMode:NSDefaultRunLoopMode];
+}
+- (void)unregisterForEvents {
+  [(WORunLoop *)[WORunLoop currentRunLoop]
+              removeFileObject:self->socket forMode:NSDefaultRunLoopMode];
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  
+  [self->lock   release]; self->lock   = nil;
+  [self->socket release]; self->socket = nil;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: address=%@>",
+                     NSStringFromClass([self class]), self,
+                     self->address];
+}
+
+/* Server */
+
+/* accessors */
+
+- (id<NGPassiveSocket>)socket {
+  return self->socket;
+}
+- (id<NGSocketAddress>)serverAddress {
+  return [self->socket localAddress];
+}
+
+- (void)setSendTimeout:(NSTimeInterval)_timeout {
+  self->sendTimeout = _timeout;
+}
+- (NSTimeInterval)sendTimeout {
+  return self->sendTimeout;
+}
+
+- (void)setReceiveTimeout:(NSTimeInterval)_timeout {
+  self->receiveTimeout = _timeout;
+}
+- (NSTimeInterval)receiveTimeout {
+  return self->receiveTimeout;
+}
+
+- (void)setMaxThreadCount:(int)_count {
+  self->maxThreadCount = _count;
+}
+- (int)maxThreadCount {
+  return self->maxThreadCount;
+}
+
+/* logging */
+
+- (void)logWithFormat:(NSString *)_format, ... {
+  NSString *value = nil;
+  va_list  ap;
+
+  va_start(ap, _format);
+  value = [[NSString alloc] initWithFormat:_format arguments:ap];
+  va_end(ap);
+
+  NSLog(@"WOHttpAdaptor: %@", value);
+  [value release]; value = nil;
+}
+
+/* run-loop */
+
+- (void)_serverCatched:(NSException *)_exc {
+  [self logWithFormat:@"http server caught: %@", _exc];
+  if (WOCoreOnHTTPAdaptorException) abort();
+}
+
+- (BOOL)runConnection:(id<NGActiveSocket>)_socket {
+  WOHttpTransaction *tx;
+  
+  if (_socket == nil) {
+    [self logWithFormat:@"got no socket for transaction ??"];
+    return NO;
+  }
+  
+  tx = [[WOHttpTransaction alloc] initWithSocket:_socket
+                                  application:self->application];
+  
+  if (![tx run])
+    [self _serverCatched:[tx lastException]];
+  
+  [tx release];
+  
+  if ([self->application isTerminating])
+    self->isTerminated = YES;
+  
+  return YES;
+}
+
+- (void)_handleAcceptedConnection:(NGActiveSocket *)_connection {
+#if USE_POOLS
+  NSAutoreleasePool *pool = nil;
+#endif
+  NSTimeInterval t;
+  
+  if (HTTP_PERFLOG)
+    *(&t) = [[NSDate date] timeIntervalSince1970];
+  
+  [self->lock lock];
+  self->activeThreadCount++;
+  [self->lock unlock];
+  
+#if USE_POOLS
+  pool = [[NSAutoreleasePool alloc] init];
+#endif
+  {
+    [*(&_connection) autorelease];
+    
+    NS_DURING {
+      [_connection setReceiveTimeout:self->receiveTimeout];
+      [_connection setSendTimeout:self->sendTimeout];
+      
+      [self runConnection:_connection];
+    }
+    NS_HANDLER {
+      [self _serverCatched:localException];
+    }
+    NS_ENDHANDLER;
+  }
+#if USE_POOLS
+  [pool release]; pool = nil;
+#endif
+
+  [self->lock lock];
+  self->activeThreadCount--;
+  [self->lock unlock];
+
+  if (HTTP_PERFLOG) {
+    t = [[NSDate date] timeIntervalSince1970] - t;
+    [self logWithFormat:@"handling of request took %4.3fs.",
+            t < 0.0 ? -1.0 : t];
+  }
+}
+
+- (NSArray *)allowedHostNames {
+  return allow;
+}
+
+- (id<NGActiveSocket>)_checkAccessOnConnection:(id<NGActiveSocket>)_connection{
+  static NGInternetSocketDomain *ipDomain = nil;
+  id<NGSocketAddress> remote;
+
+  if ((remote = [_connection remoteAddress]) == nil) {
+    [self logWithFormat:
+            @"missing remote address for connection: %@",
+            _connection];
+    return nil;
+  }
+
+  if (ipDomain == nil)
+    ipDomain = [[NGInternetSocketDomain domain] retain];
+  
+  if ([[remote domain] isEqual:ipDomain]) {
+    /* check access */
+    NGInternetSocketAddress *ipAddr = (id)remote;
+    NSArray *allow = nil;
+    unsigned i, count;
+    NSString *rh, *ra;
+    
+    allow = [self allowedHostNames];
+    
+    rh = [ipAddr hostName];
+    ra = [ipAddr address];
+    
+    /* first check address */
+    
+    for (i = 0, count = [allow count]; i < count; i++) {
+      NSString *h;
+      
+      h = [[allow objectAtIndex:i] stringValue];
+      if ([h isEqualToString:ra])
+        return _connection;
+    }
+    
+    /* now check DNS names */
+    
+    for (i = 0, count = [allow count]; i < count; i++) {
+      NSString *h;
+      
+      h = [[allow objectAtIndex:i] stringValue];
+      if ([h isEqualToString:rh])
+        return _connection;
+    }
+    
+    [self logWithFormat:@"ACCESS DENIED: %@", ipAddr];
+    _connection = nil;
+  }
+  
+  return _connection;
+}
+
+- (void)acceptConnection:(id)_notification {
+#if USE_POOLS
+  NSAutoreleasePool *pool;
+  *(&pool) = [[NSAutoreleasePool alloc] init];
+#endif
+  {
+    NGActiveSocket *connection;
+    
+    NS_DURING {
+      *(&connection) = (NGActiveSocket *)[self->socket accept];
+      if (connection == nil)
+        [self _serverCatched:[self->socket lastException]];
+      else
+       [self debugWithFormat:@"accepted connection: %@", connection];
+    }
+    NS_HANDLER {
+      connection = nil;
+      [self _serverCatched:localException];
+    }
+    NS_ENDHANDLER;
+    
+    connection = (NGActiveSocket *)[self _checkAccessOnConnection:connection];
+    
+    if (connection != nil) {
+      if (self->maxThreadCount <= 1) {
+        NS_DURING
+          [self _handleAcceptedConnection:[connection retain]];
+        NS_HANDLER
+          [self _serverCatched:localException];
+        NS_ENDHANDLER;
+      }
+      else {
+        [NSThread detachNewThreadSelector:@selector(_handleAcceptedConnection:)
+                  toTarget:self
+                  withObject:[connection retain]];
+        [self logWithFormat:@"detached new thread for request."];
+        //[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
+      }
+      connection = nil;
+    }
+  }
+#if USE_POOLS
+  [pool release]; pool = nil;
+#endif
+  
+  if (self->isTerminated) {
+    if (self->socket) {
+      [[NSNotificationCenter defaultCenter]
+                             removeObserver:self
+                             name:NSFileObjectBecameActiveNotificationName
+                             object:self->socket];
+      [self->socket close];
+      [self->socket release]; self->socket = nil;
+    }
+    NSLog(@"adaptor stops application: %@ ...", self->application);
+    exit(0);
+  }
+}
+
+@end /* WOHttpAdaptor */
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.h b/skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.h
new file mode 100644 (file)
index 0000000..cfab2b7
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOHttpTransaction_H__
+#define __WOHttpTransaction_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSDate.h>
+#include <NGStreams/NGActiveSocket.h>
+#include <NGStreams/NGBufferedStream.h>
+
+@class NSException, NSNotificationCenter;
+@class NGHttpRequest;
+@class WOCoreApplication, WORequest, WOResponse;
+@class WORecordRequestStream;
+
+/*
+  This object represents a single HTTP transaction (request+response).
+  
+  Note that multiple HTTP transactions can be active at a single point of
+  time, this isn't done by threading, but by using the runloop.
+  
+  Since WOApplications are synchronous by nature, we define a "special" HTTP
+  response with status code "20001" meaning "response not yet ready". If
+  the transaction gets this response, it puts itself into a pending state
+  and waits for a notification targetting the async-object token given in
+  the user-info of the response.
+  (Eg this is used in the skysystemd to be able to fork and process multiple
+  system commands at the same time)
+*/
+
+extern int      WOAsyncResponseStatus;
+extern NSString *WOAsyncResponseTokenKey;
+extern NSString *WOAsyncResponseReadyNotificationName;
+
+@interface WOHttpTransaction : NSObject
+{
+@public
+  WOCoreApplication     *application;
+  id<NGActiveSocket>    socket;
+  WORecordRequestStream *log;
+  NGBufferedStream      *io;
+  WORequest      *woRequest;
+  WOResponse     *woResponse;
+  NSTimeInterval t;
+  NSDate         *startDate;
+  NSException    *lastException;
+  NSTimeInterval requestFinishTime;
+  NSTimeInterval dispatchFinishTime;
+  NSString       *asyncResponseToken;
+}
+
+- (id)initWithSocket:(id<NGActiveSocket>)_socket
+  application:(WOCoreApplication *)_app;
+
+- (void)reset;
+
+/* running */
+
+- (NSException *)lastException;
+- (BOOL)run;
+- (NSNotificationCenter *)notificationCenter;
+
+/* event handler stuff */
+
+- (NGHttpRequest *)parseRequestFromStream:(id<NGStream>)_in;
+- (void)deliverResponse:(WOResponse *)_response
+  toRequest:(WORequest *)_request
+  onStream:(id<NGStream>)_out;
+- (void)logResponse:(WOResponse *)_response
+  toRequest:(WORequest *)_request
+  connection:(id<NGActiveSocket>)_connection;
+
+@end
+
+#endif /* __WOHttpTransaction_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m b/skyrix-sope/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m
new file mode 100644 (file)
index 0000000..115bec1
--- /dev/null
@@ -0,0 +1,988 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOHttpTransaction.h"
+#include "WORecordRequestStream.h"
+#include "WOHttpAdaptor.h"
+#include "WORequest+Adaptor.h"
+#include "NGHttp+WO.h"
+#include "WOSimpleHTTPParser.h"
+#include <NGObjWeb/WOCoreApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOCookie.h>
+#include <NGExtensions/NSData+gzip.h>
+#include <NGHttp/NGHttp.h>
+#include "common.h"
+
+#include <sys/time.h>
+
+int      WOAsyncResponseStatus = 20001;
+NSString *WOAsyncResponseTokenKey = @"WOAsyncResponseToken";
+NSString *WOAsyncResponseReadyNotificationName =
+  @"WOAsyncResponseReadyNotification";
+NSString *WOAsyncResponse = @"WOAsyncResponse";
+
+static int HTTP_PERFLOG = -1;
+
+@implementation WOHttpTransaction
+
+static NSMutableDictionary *pendingTransactions = nil; // THREAD
+static BOOL useSimpleParser = YES;
+static int  debugOn = -1;
+static int  doCore  = -1;
+static NSString *adLogPath = nil;
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    
+    useSimpleParser = [ud boolForKey:@"WOHttpTransactionUseSimpleParser"];
+    debugOn = [[ud objectForKey:@"WODebugHttpTransaction"] boolValue] ? 1 : 0;
+    doCore = [[ud objectForKey:@"WOCoreOnHTTPAdaptorException"] boolValue]?1:0;
+    
+    adLogPath = [[ud stringForKey:@"WOAdaptorLogPath"] copy];
+    if (adLogPath == nil)
+      adLogPath = @"";
+  }
+}
+
+- (BOOL)optionLogStream {
+  return [WOHttpAdaptor optionLogStream];
+}
+- (BOOL)optionLogPerf {
+  return HTTP_PERFLOG;
+}
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn ? YES : NO;
+}
+
+- (id)initWithSocket:(id<NGActiveSocket>)_socket
+  application:(WOCoreApplication *)_app
+{
+  if (HTTP_PERFLOG == -1)
+    HTTP_PERFLOG = [WOHttpAdaptor optionLogPerf] ? 1 : 0;
+  
+  NSAssert(_socket, @"missing socket ...");
+  NSAssert(_app,    @"missing application ...");
+  self->socket      = [_socket retain];
+  self->application = [_app    retain];
+  return self;
+}
+
+- (void)dealloc {
+  //[self debugWithFormat:@"dealloc ..."];
+  [self reset];
+  [self->socket        release];
+  [self->lastException release];
+  [self->application   release];
+  [super dealloc];
+}
+
+- (void)reset {
+  if (self->asyncResponseToken) {
+    [self logWithFormat:
+            @"WARNING: resetting while async response pending ... (%@)",
+            self->asyncResponseToken];
+    abort();
+    
+    [[self notificationCenter] removeObserver:self];
+  }
+  [self->asyncResponseToken release]; self->asyncResponseToken = nil;
+  [self->io         release]; self->io         = nil;
+  [self->log        release]; self->log        = nil;
+  [self->startDate  release]; self->startDate  = nil;
+  [self->woRequest  release]; self->woRequest  = nil;
+  [self->woResponse release]; self->woResponse = nil;
+}
+
+- (BOOL)closeConnectionAfterDelivery {
+  return YES;
+}
+
+- (void)start {
+  self->startDate = [[NSDate alloc] init];
+  self->t = [self->startDate timeIntervalSince1970];
+}
+- (void)finish {
+  if (self->woResponse) {
+    [self logResponse:self->woResponse
+          toRequest:self->woRequest
+          connection:self->socket];
+    
+    if (HTTP_PERFLOG) {
+      struct timeval tv;
+      gettimeofday(&tv, NULL);
+      self->t = (((double)tv.tv_sec) * ((double)tv.tv_usec) / 1000.0)  - 
+       self->t;
+      NSLog(@"processing of request took %4.3fs.", self->t < 0.0 ? -1.0 : t);
+    }
+  }
+}
+
+- (BOOL)_setupStreamsForSocket {
+  if ([self optionLogStream]) {
+    self->log = [(WORecordRequestStream *)[WORecordRequestStream alloc] 
+      initWithSource:self->socket];
+    self->io  = [(NGBufferedStream *)[NGBufferedStream alloc] 
+      initWithSource:self->log];
+  }
+  else {
+    self->log = nil;
+    self->io = [(NGBufferedStream *)[NGBufferedStream alloc] 
+      initWithSource:self->socket];
+  }
+  return self->io != nil ? YES : NO;
+}
+static int logCounter = 0;
+
+- (NSString *)currentRecordingPath:(NSString *)_suffix {
+  static NSString *s = nil;
+  NSString *p;
+  if (s == nil) {
+    s = [[self->application recordingPath] copy];
+    if (s == nil) s = @"";
+  }
+  if ([s length] == 0) return nil;
+  
+  p = [NSString stringWithFormat:@"%04i-%@", logCounter, _suffix];
+  return [s stringByAppendingPathComponent:p];
+}
+
+- (void)logRequestData:(NSData *)_data {
+  NSString *logPath = nil;
+  
+  if (![self optionLogStream]) return;
+  logCounter++;
+  
+  if ([adLogPath length] > 0)
+    logPath = adLogPath;
+  else if ([logPath length] == 0)
+    logPath = [self currentRecordingPath:@"request"];
+  
+  if ([logPath length] == 0)
+    logPath = @"/tmp/woadaptor.log";
+  
+  [_data writeToFile:logPath atomically:NO];
+  
+#if 1
+  NSLog(@"request is\n");
+  fflush(stderr);
+  fwrite([_data bytes], 1, [_data length], stderr);
+  fflush(stderr);
+  fprintf(stderr,"\n");
+  fflush(stderr);
+#endif
+}
+
+- (void)logResponse:(WOResponse *)_response
+  toRequest:(WORequest *)_request
+  data:(NSData *)_data
+{
+  NSString *logPath;
+  
+  if (_data == nil) return;
+  
+  if ((int)[_response status] == (int)WOAsyncResponseStatus)
+    return;
+  
+#if 1
+  NSLog(@"response is\n");
+  fflush(stderr);
+  fwrite([_data bytes], 1, [_data length], stderr);
+  fflush(stderr);
+  fprintf(stderr,"\n");
+  fflush(stderr);
+#endif
+  
+  if ((logPath = [self currentRecordingPath:@"response"]) == nil)
+    return;
+  
+  [_data writeToFile:logPath atomically:NO];
+}
+
+- (void)applyAdaptorHeadersWithHttpRequest:(NGHttpRequest *)request {
+  /* apply some adaptor headers in direct-connect mode  */
+
+  if (woRequest == nil) return;
+  
+  if ([woRequest headerForKey:@"x-webobjects-server-url"] == nil) {
+    NSString *tmp;
+    
+    if ((tmp = [woRequest headerForKey:@"host"])) {
+      if ([tmp hasSuffix:@":0"] && ([tmp length] > 2)) // TODO: bad bad bad
+       tmp = [tmp substringToIndex:([tmp length] - 2)];
+      tmp = [@"http://" stringByAppendingString:tmp];
+      [woRequest setHeader:tmp forKey:@"x-webobjects-server-url"];
+    }
+  }
+  if ([woRequest headerForKey:@"x-webobjects-server-name"] == nil) {
+    NSString *tmp;
+    
+    if ((tmp = [woRequest headerForKey:@"host"])) {
+      NSRange r = [tmp rangeOfString:@":"];
+      if (r.length > 0) tmp = [tmp substringToIndex:r.location];
+      [woRequest setHeader:tmp forKey:@"x-webobjects-server-name"];
+    }
+  }
+  if ([[woRequest headerForKey:@"x-webobjects-server-port"] intValue] < 1) {
+    id tmp;
+    
+    if ((tmp = [woRequest headerForKey:@"host"])) {
+      NSRange r = [tmp rangeOfString:@":"];
+      if (r.length > 0) tmp = [tmp substringFromIndex:r.location + r.length];
+      tmp = [NSNumber numberWithInt:[tmp intValue]];
+      [woRequest setHeader:tmp forKey:@"x-webobjects-server-port"];
+    }
+  }
+  
+  if ([woRequest headerForKey:@"x-webobjects-remote-host"] == nil) {
+    id<NGSocketAddress> remote = nil;
+    NSString *remoteHost = nil;
+    
+    remote = [self->socket remoteAddress];
+    
+    if ([remote isKindOfClass:[NGInternetSocketAddress class]])
+      remoteHost = [(NGInternetSocketAddress *)remote hostName];
+#if !defined(__MINGW32__)
+    else if ([remote isKindOfClass:[NGLocalSocketAddress class]])
+      remoteHost = @"local";
+#endif
+
+    if ([remoteHost length] > 0)
+      [woRequest setHeader:remoteHost forKey:@"x-webobjects-remote-host"];
+  }
+        
+  if ([woRequest headerForKey:@"x-webobjects-remote-user"] == nil) {
+    id auth;
+          
+    auth = [[request valuesOfHeaderFieldWithName:@"authorization"]
+                     nextObject];
+    if (auth) {
+      if (![auth isKindOfClass:[NGHttpCredentials class]]) {
+        auth =
+          [NGHttpCredentials credentialsWithString:[auth stringValue]];
+      }
+            
+      [woRequest setHeader:[auth userName]
+                 forKey:@"x-webobjects-remote-user"];
+      [woRequest setHeader:[auth scheme]
+                 forKey:@"x-webobjects-auth-type"];
+    }
+  }
+}
+
+- (WOResponse *)generateMissingResponse {
+  WOResponse *mr;
+  NSString   *accept;
+
+  mr = [WOResponse alloc];
+  mr = [mr initWithRequest:self->woRequest];
+  [mr setHTTPVersion:[woRequest httpVersion]];
+  [mr setStatus:500];
+  
+  accept = [woRequest headerForKey:@"accept"];
+  
+  if ([accept rangeOfString:@"text/html"].length > 0) {
+    const unsigned char *txt = "could not perform request !<br />";
+    [mr setHeader:@"text/html" forKey:@"content-type"];
+    [mr setContent:[NSData dataWithBytes:txt length:strlen(txt)]];
+  }
+  return [mr autorelease];
+}
+
+- (BOOL)_readRequest {
+  id request = nil;
+
+  if (self->woRequest)
+    [self logWithFormat:@"WARNING: woRequest already set ???"];
+  
+  if (useSimpleParser) {
+    WOSimpleHTTPParser *parser;
+    
+    parser = [[WOSimpleHTTPParser alloc] initWithStream:self->io];
+    self->woRequest = [[parser parseRequest] retain];
+    
+    if (self->woRequest == nil) {
+      ASSIGN(self->lastException, [parser lastException]);
+      [self logWithFormat:@"failed to parse request: %@", self->lastException];
+    }
+    [parser release];
+  }
+  else {
+    if ((request = [self parseRequestFromStream:self->io]) == nil)
+      return NO;
+    
+#if DEBUG
+    NSAssert([request isKindOfClass:[NGHttpRequest class]],
+            @"invalid request class");
+#endif
+    self->woRequest = [[request woRequest] retain];
+  }
+  [self logRequestData:[log readLog]];
+  [log resetReadLog];
+  
+  if ([self->woRequest isCodeRedAttack]) {
+    NSLog(@"WOHttpAdaptor: detected 'Code Red' request: '%@', blocking.",
+          [self->woRequest uri]);
+    ASSIGN(self->woRequest, (id)nil);
+    return NO;
+  }
+  
+  [self->woRequest takeStartDate:self->startDate];
+  
+  /* apply some adaptor headers in direct-connect mode  */
+  [self applyAdaptorHeadersWithHttpRequest:request];
+  
+  if (HTTP_PERFLOG) {
+    NSTimeInterval rt;
+    self->requestFinishTime = [[NSDate date] timeIntervalSince1970];
+    rt = self->requestFinishTime - self->t;
+    NSLog(@"[httpperf]: decoding of request took %4.3fs.",
+          rt < 0.0 ? -1.0 : rt);
+  }
+  
+  return self->woRequest ? YES : NO;
+}
+
+- (BOOL)_sendResponse {
+  if (HTTP_PERFLOG) {
+    NSTimeInterval rt;
+    self->dispatchFinishTime = [[NSDate date] timeIntervalSince1970];
+    rt = self->dispatchFinishTime - self->requestFinishTime;
+    NSLog(@"[httpperf]: dispatch of request took %4.3fs.",
+          rt < 0.0 ? -1.0 : rt);
+  }
+  
+  if (self->woResponse) {
+    [self deliverResponse:self->woResponse
+          toRequest:self->woRequest
+          onStream:self->io];
+    
+    if (HTTP_PERFLOG) {
+      NSTimeInterval rt;
+      rt = [[NSDate date] timeIntervalSince1970] - dispatchFinishTime;
+      NSLog(@"[httpperf]: delivery of request took %4.3fs.",
+            rt < 0.0 ? -1.0 : rt);
+    }
+  }
+  else if (self->woRequest) {
+    [self logWithFormat:
+            @"ERROR: got no response for request %@ ..",
+            self->woRequest];
+      
+    self->woResponse = [[self generateMissingResponse] retain];
+    
+    [self deliverResponse:self->woResponse
+          toRequest:self->woRequest
+          onStream:self->io];
+  }
+  
+  if (![self->io flush]) {
+    ASSIGN(self->lastException, [self->io lastException]);
+    return NO;
+  }
+  
+  if ([self closeConnectionAfterDelivery]) {
+    [self debugWithFormat:@"close connection: %@", self->io];
+    if (![self->io close]) {
+      ASSIGN(self->lastException, [self->io lastException]);
+      [self debugWithFormat:@"close failed: %@", self->lastException];
+      return NO;
+    }
+  }
+  else
+    [self debugWithFormat:@"not closing connection ..."];
+  
+  return YES;
+}
+
+- (NSNotificationCenter *)notificationCenter {
+  return [NSNotificationCenter defaultCenter];
+}
+
+- (void)responseReady:(NSNotification *)_notification {
+  WOResponse *response;
+  
+  if ([self->asyncResponseToken length] == 0) {
+    [self logWithFormat:
+            @"got response ready notification (%@), "
+            @"but no async HTTP transaction is in progress ...",
+            _notification];
+    return;
+  }
+  if (![self->asyncResponseToken isEqual:[_notification object]]) {
+    [self logWithFormat:
+            @"got response ready notification (%@) for a different "
+            @"token (%@ vs %@) !",
+            _notification, self->asyncResponseToken, [_notification object]];
+    return;
+  }
+  
+  /* OK, everything seems to be correct, so we received a response .. */
+  
+  [[self retain] autorelease];
+  [pendingTransactions removeObjectForKey:self->asyncResponseToken];
+  
+  response = [[_notification userInfo] objectForKey:WOAsyncResponse];
+  ASSIGN(self->woResponse, response);
+  
+  [[self notificationCenter] removeObserver:self];
+  [self->asyncResponseToken release]; self->asyncResponseToken = nil;
+  
+  /* send response */
+  
+  [self debugWithFormat:@"sending async response: %@", self->woResponse];
+  [self _sendResponse];
+  
+  [self debugWithFormat:@"logging async response: %@", self->woResponse];
+  [self logResponse:self->woResponse
+        toRequest:self->woRequest
+        data:[log writeLog]];
+  [log resetWriteLog];
+  
+  [self finish];
+  [self reset];
+
+  [self->io  release]; self->io  = nil;
+  [self->log release]; self->log = nil;
+}
+
+- (BOOL)_enterAsyncMode:(WOResponse *)_response {
+  NSString *token;
+  
+  [self debugWithFormat:@"enter async mode ..."];
+  
+  if (pendingTransactions == nil)
+    pendingTransactions = [[NSMutableDictionary alloc] initWithCapacity:16];
+  
+  [self debugWithFormat:@"PENDING: %@", pendingTransactions];
+  
+  NSAssert1((int)[_response status] == (int)WOAsyncResponseStatus,
+            @"passed in an invalid response %@ ...", _response);
+  
+  token = [[_response userInfo] objectForKey:WOAsyncResponseTokenKey];
+  if ([token length] == 0) {
+    [self logWithFormat:@"missing async response token in response %@",
+            _response];
+    return NO;
+  }
+
+  [self debugWithFormat:@"using token: %@", token];
+  ASSIGN(self->asyncResponseToken, token);
+  
+  [pendingTransactions setObject:self forKey:self->asyncResponseToken];
+  
+  [[self notificationCenter]
+         addObserver:self selector:@selector(responseReady:)
+         name:WOAsyncResponseReadyNotificationName
+         object:self->asyncResponseToken];
+  
+  return YES;
+}
+
+- (BOOL)_run {
+  if (![self _setupStreamsForSocket])
+    return NO;
+  
+  if (![self _readRequest])
+    return NO;
+  
+  /* dispatch request */
+  
+  if (self->woRequest)
+    self->woResponse = [[self->application dispatchRequest:woRequest] retain];
+  else
+    self->woResponse = nil;
+  
+  if (self->woResponse) {
+    if ((int)[self->woResponse status] == (int)WOAsyncResponseStatus) {
+      /* switch to async mode ... */
+      if ([self _enterAsyncMode:self->woResponse]) {
+        [self logResponse:self->woResponse
+              toRequest:self->woRequest
+              data:nil];
+        return YES;
+      }
+    }
+  }
+  
+  /* send response */
+  
+  [self _sendResponse];
+  
+  [self logResponse:self->woResponse
+        toRequest:self->woRequest
+        data:[self->log writeLog]];
+  [self->log resetWriteLog];
+    
+  [self->io  release]; self->io  = nil;
+  [self->log release]; self->log = nil;
+  return YES;
+}
+
+- (NSException *)lastException {
+  return self->lastException;
+}
+
+- (BOOL)_catchedException:(NSException *)localException {
+  if ([localException isKindOfClass:[NGSocketShutdownException class]])
+    return YES;
+  
+  ASSIGN(self->lastException, localException);
+  
+#if DEBUG
+  if (doCore) abort();
+#endif
+  return NO;
+}
+
+- (BOOL)run {
+  BOOL ok = YES;
+  
+  [self reset];
+  [self start];
+  
+  NS_DURING {
+    if (![self _run])
+      ok = NO;
+  }
+  NS_HANDLER
+    ok = [self _catchedException:localException];
+  NS_ENDHANDLER;
+  
+  if (self->asyncResponseToken == nil) {
+    [self finish];
+    [self reset];
+  }
+  
+  return ok;
+}
+
+- (NGHttpRequest *)parseRequestFromStream:(id<NGStream>)_in {
+  NGHttpMessageParser *parser = nil;
+  volatile id request = nil;
+  NSString *format = @"parsing of request failed with exception: %@";
+  
+  NS_DURING {
+    *(&parser) = [[NGHttpMessageParser alloc] init];
+    [parser setDelegate:self];
+    
+    request = [parser parseRequestFromStream:_in];
+    
+    [parser release]; parser = nil;
+  }
+  NS_HANDLER {
+    [self logWithFormat:format, localException];
+    [parser release]; parser = nil;
+    [localException raise];
+  }
+  NS_ENDHANDLER;
+
+  return request;
+}
+
+- (const unsigned char *)_reasonForStatus:(unsigned int)_status {
+  const unsigned char *reason;
+  
+  switch (_status) {
+    case 200: reason = "Ok";           break;
+    case 201: reason = "Created";      break;
+    case 204: reason = "No Content";   break;
+    case 207: reason = "Multi-Status"; break;
+    
+    case 302: reason = "Found"; break;
+      
+    case 401: reason = "Authorization Required"; break;
+    case 402: reason = "Payment Required";       break;
+    case 403: reason = "Forbidden";              break;
+    case 404: reason = "Not found";              break;
+    case 405: reason = "Method not allowed";     break;
+    case 409: reason = "Conflict";               break;
+    case 412: reason = "Precondition Failed";    break;
+    case 415: reason = "Unsupported Media Type"; break;
+    case 424: reason = "Failed Dependency";      break;
+    
+    case 507: reason = "Insufficient Storage";   break;
+    
+    default:
+      if (_status < 300)
+        reason = "Request was sucessful";
+      else
+        reason = "Request failed";
+      break;
+  }
+  return reason;
+}
+
+- (void)_httpValidateResponse:(WOResponse *)_response {
+  /* check HTTP validity */
+  if ([_response status] == NGHttpStatusCode_Unauthorized) {
+    if ([_response headerForKey:@"www-authenticate"] == nil) {
+      [self logWithFormat:
+              @"WARNING: response is %i, "
+              @"but no www-authenticate header is set.",
+              NGHttpStatusCode_Unauthorized];
+    }
+  }
+}
+
+- (void)deliverResponse:(WOResponse *)_response
+  toRequest:(WORequest *)_request
+  onStream:(id<NGStream>)_out
+{
+  /*
+    Profiling OSX: - takes 29% of tx -run
+      12% CTextStream writeString
+        ... to sendto 5.1% (half+ of the performance lost on the way)
+      4.6% WOMessage   headersForKey
+      4.4% TextStream  writeFormat
+    => TODO(perf) reduce usage of writeFormat/writeString
+  */
+  NGCTextStream *out;
+  static NSString *disconnectError =
+    @"client disconnected during delivery of response for %@ (len=%i): %@";
+  static NSString *deliveryError =
+    @"delivering of response failed with exception: %@";
+
+  *(&out) = nil;
+  
+  [self _httpValidateResponse:_response];
+  
+  out = [(NGCTextStream *)[NGCTextStream alloc] initWithSource:_out];
+  
+  NS_DURING {
+    unsigned char buf[1024];
+    NSString *t1;
+    id   body;
+    BOOL doZip;
+    BOOL isok = YES;
+    
+    doZip = [_response shouldZipResponseToRequest:_request];
+    
+    /* response line */
+    if (isok) {
+      unsigned int slen, rlen;
+      const unsigned char *r;
+      int s = [_response status];
+      t1 = [_response httpVersion];
+      r  = [self _reasonForStatus:s];
+      
+      slen = [t1 cStringLength];
+      rlen = strlen(r);
+      if ((slen + rlen + 8) < 1000) {
+        [t1 getCString:buf];
+        sprintf(&(buf[slen]), " %i %s\r\n", s, r);
+        isok = [_out safeWriteBytes:buf count:strlen(buf)];
+      }
+      else
+        isok = [out writeFormat:@"%@ %i %s\r\n", t, s, r];
+    }
+    if (isok) isok = [out flush];
+    
+    /* zip */
+    body = (doZip) 
+      ? [_response zipResponse]
+      : [_response content];
+    
+    /* add content length header */
+    
+    sprintf(buf, "%d", [body length]);
+    t1 = [[NSString alloc] initWithCString:buf];
+    [_response setHeader:t1 forKey:@"content-length"];
+    [t1 release]; t1 = nil;
+    
+    /* write headers */
+    if (isok) {
+      /* collect in string to reduce string IO */
+      NSEnumerator    *fields;
+      NSString        *fieldName;
+      NSMutableString *header;
+      BOOL hasConnectionHeader;
+      IMP  addStr;
+      
+      hasConnectionHeader = NO;
+      header = [[NSMutableString alloc] initWithCapacity:4096];
+      addStr = [header methodForSelector:@selector(appendString:)];
+      fields = [[_response headerKeys] objectEnumerator];
+      
+      while ((fieldName = [fields nextObject]) && isok) {
+        NSEnumerator *values;
+        NSString *value;
+       
+       if (!hasConnectionHeader) {
+         if ([fieldName caseInsensitiveCompare:@"connection"]==NSOrderedSame)
+           hasConnectionHeader = YES;
+       }
+       
+        values = [[_response headersForKey:fieldName] objectEnumerator];
+       
+        while ((value = [values nextObject]) && isok) {
+          addStr(header, @selector(appendString:), fieldName);
+          addStr(header, @selector(appendString:), @": ");
+          addStr(header, @selector(appendString:), value);
+          addStr(header, @selector(appendString:), @"\r\n");
+        }
+      }
+      isok = [out writeString:header];
+      [header release];
+
+#if 0
+#warning TODO: experimental, need to check for direct connect
+      if (!hasConnectionHeader && isok)
+       isok = [out writeString:@"connection: close\r\n"];
+#endif
+    }
+    
+    /* write cookie headers */
+    if (isok) {
+      NSEnumerator *cookies;
+      WOCookie     *cookie;
+      
+      cookies = [[_response cookies] objectEnumerator];
+      while ((cookie = [cookies nextObject]) && isok) {
+        unsigned clen;
+        
+        t1   = [cookie stringValue];
+        clen = [t1 cStringLength];
+        
+        if (isok) isok = [_out safeWriteBytes:"set-cookie: " count:12];
+        if (isok) {
+          if (clen > 1000)
+            isok = [out writeString:t1];
+          else {
+            [t1 getCString:buf];
+            [_out safeWriteBytes:buf count:clen];
+          }
+        }
+        if (isok) isok = [_out safeWriteBytes:"\r\n" count:2];
+      }
+    }
+    
+    if (isok) isok = [_out safeWriteBytes:"\r\n" count:2];
+    if (isok) isok = [out flush];
+    
+    /* write body */
+    
+    if (![[_request method] isEqualToString:@"HEAD"] && isok) {
+      if ((body != nil) && isok) {
+        if (![body isKindOfClass:[NSData class]]) {
+          if (![body isKindOfClass:[NSString class]])
+            body = [body description];
+          
+          body = [body dataUsingEncoding:[_response contentEncoding]
+                       allowLossyConversion:NO];
+        }
+        isok = [_out safeWriteBytes:[body bytes] count:[body length]];
+        if (isok) isok = [_out flush];
+      }
+    }
+    
+    if (!isok) {
+      NSException *e;
+      
+      e = [out lastException];
+      if ([e isKindOfClass:[NGSocketShutdownException class]]) {
+        [self logWithFormat:disconnectError,
+              _request,
+              [[_response content] length],
+              [e reason]];
+      }
+      else
+        [e raise];
+    }
+  }
+  NS_HANDLER {
+    if ([localException isKindOfClass:[NGSocketShutdownException class]]) {
+      [self logWithFormat:disconnectError,
+              _request,
+              [[_response content] length],
+              [localException reason]];
+    }
+    else {
+      [self logWithFormat:deliveryError, localException];
+      [out release]; out = nil; // the buffer will be flushed ..
+
+      [localException raise];
+    }
+  }
+  NS_ENDHANDLER;
+  
+  [out release]; out = nil; // the buffer will be flushed ..
+}
+
+static __inline__ const unsigned char *monthAbbr(int m) {
+  switch (m) {
+    case  1:  return "Jan"; case  2:  return "Feb"; case  3:  return "Mar";
+    case  4:  return "Apr"; case  5:  return "May"; case  6:  return "Jun";
+    case  7:  return "Jul"; case  8:  return "Aug"; case  9:  return "Sep";
+    case 10:  return "Oct"; case 11:  return "Nov"; case 12:  return "Dec";
+    default: return "UNKNOWN MONTH !";
+  }
+}
+
+- (void)logResponse:(WOResponse *)_response
+  toRequest:(WORequest *)_request
+  connection:(id<NGActiveSocket>)_connection
+{
+  /* 
+    Profiling: this method takes 0.95% of -run if the output is piped to
+    /dev/null on OSX, morphing caldate to string is 0.79% of that.
+  */
+  NSString       *remoteHost = @"-";
+  NSNumber       *zippedLen;
+  NSCalendarDate *now;
+  NSDate         *lstartDate;
+  NSDictionary   *startStats;
+  
+  lstartDate = [[_request  userInfo] objectForKey:@"WORequestStartDate"];
+  startStats =
+    [[_request userInfo] objectForKey:@"WORequestStartProcStatistics"];
+  zippedLen = [[_response userInfo] objectForKey:@"WOResponseZippedLength"];
+  
+  // host and date
+  if ((remoteHost = [_request headerForKey:@"x-webobjects-remote-host"]))
+    ;
+  else if ((remoteHost = [_request headerForKey:@"x-webobjects-remote-addr"]))
+    ;
+  else {
+    id<NGSocketAddress> remote = nil;
+
+    remote = [_connection remoteAddress];
+
+    if ([remote isKindOfClass:[NGInternetSocketAddress class]])
+      remoteHost = [(NGInternetSocketAddress *)remote hostName];
+#if !defined(__MINGW32__)
+    else if ([remote isKindOfClass:[NGLocalSocketAddress class]])
+      remoteHost = @"local";
+#endif
+  }
+  
+  // this is supposed to be in GMT ! TODO: explicitly set GMT
+  now = [NSCalendarDate calendarDate];
+  
+  /* print standard info */
+  printf("%s - - [%02i/%s/%04i:%02i:%02i:%02i GMT] \"%s %s %s\" %i %i",
+         remoteHost ? [remoteHost cString] : "-",
+         [now dayOfMonth],
+         monthAbbr([now monthOfYear]),
+         [now yearOfCommonEra],
+         [now hourOfDay], [now minuteOfHour], [now secondOfMinute],
+         [[_request method] cString],
+         [[_request uri] cString],
+         [[_request httpVersion] cString],
+         [_response status],
+         [[_response content] length]);
+  
+  /* print duration */
+  if (lstartDate)
+    printf(" %.3f", [now timeIntervalSinceDate:lstartDate]);
+  else
+    printf(" -");
+  
+  /* print zip level */
+  if (zippedLen) {
+    double p;
+    double unzippedLen;
+    
+    unzippedLen = 
+      [[[_response userInfo] objectForKey:@"WOResponseUnzippedLength"] 
+                  unsignedIntValue];
+    
+    printf(" %d", (unsigned int)unzippedLen);
+
+    if ([zippedLen unsignedIntValue] == unzippedLen) {
+      printf(" -");
+    }
+    else {
+      p = unzippedLen / 100.0; // one percent
+      p = [zippedLen doubleValue] / p;
+      p = 100.0 - p;
+      printf(" %-2d%%", (unsigned int)p);
+    }
+  }
+  else {
+    /* content was not zipped */
+    printf(" - -");
+  }
+  
+  /* print statistics */
+  
+  if (startStats) {
+    static NSProcessInfo *pi = nil;
+    NSDictionary *currentStats;
+    
+    if (pi == nil) pi = [[NSProcessInfo processInfo] retain];
+    
+    if ((currentStats = [pi procStatDictionary])) {
+      int old, new, diff;
+      
+      old = [[startStats   objectForKey:@"rss"] intValue];
+      new = [[currentStats objectForKey:@"rss"] intValue];
+      diff = new - old; /* number of pages (4KB on ix86 ..) */
+      
+      diff *= 4; /* in KB */
+      if (diff == 0)
+       printf(" 0");
+      else if (diff > 999)
+       printf(" %iM", diff / 1024);
+      else
+       printf(" %iK", diff);
+    }
+    else
+      printf(" ?");
+  }
+  else
+    printf(" -");
+  
+  /* flush log */
+  puts("");
+  fflush(stdout);
+}
+
+@end /* WOHttpTransaction */
+
+@implementation WOHttpTransaction(NGHttpMessageParserDelegate)
+
+- (BOOL)httpParserWillParseRequest:(NGHttpMessageParser *)_parser {
+  return YES;
+}
+- (void)httpParser:(NGHttpMessageParser *)_parser
+  didParseRequest:(NGHttpRequest *)_request {
+}
+
+- (BOOL)parser:(NGMimePartParser *)_parser
+  keepHeaderField:(NSString *)_name
+  value:(id)_value
+{
+  return YES;
+}
+- (void)parser:(NGMimePartParser *)_parser didParseHeader:(NGHashMap *)_header {
+}
+
+@end /* WOHttpAdaptor(NGHttpMessageParserDelegate) */
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORecordRequestStream.h b/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORecordRequestStream.h
new file mode 100644 (file)
index 0000000..b65b23c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WORecordRequestStream_H__
+#define __WORecordRequestStream_H__
+
+#include <NGStreams/NGFilterStream.h>
+
+@class NSData, NSMutableData;
+
+@interface WORecordRequestStream : NGFilterStream
+{
+  NSMutableData *readLog;
+  NSMutableData *writeLog;
+}
+
+- (NSData *)readLog;
+- (NSData *)writeLog;
+- (void)reset;
+- (void)resetReadLog;
+- (void)resetWriteLog;
+
+@end
+
+#endif /* __WORecordRequestStream_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORecordRequestStream.m b/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORecordRequestStream.m
new file mode 100644 (file)
index 0000000..130f2c9
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WORecordRequestStream.h"
+#include "common.h"
+
+#define ReadLogInitSize  1024
+#define WriteLogInitSize 128*1024
+
+@implementation WORecordRequestStream
+
+- (id)initWithSource:(id<NGStream>)_source {
+  if ((self = [super initWithSource:_source])) {
+    self->readLog  = [[NSMutableData alloc] initWithCapacity:ReadLogInitSize];
+    self->writeLog = [[NSMutableData alloc] initWithCapacity:WriteLogInitSize];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->readLog  release];
+  [self->writeLog release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSData *)readLog {
+  return self->readLog;
+}
+- (NSData *)writeLog {
+  return self->writeLog;
+}
+
+- (void)resetReadLog {
+  [self->readLog setLength:0];
+}
+- (void)resetWriteLog {
+  [self->writeLog setLength:0];
+}
+- (void)reset {
+  [self resetReadLog];
+  [self resetWriteLog];
+}
+
+/* implementation */
+
+- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
+  unsigned len;
+  
+  len = [super readBytes:_buf count:_len];
+  if (len == NGStreamError)
+    return NGStreamError;
+  
+  [self->readLog appendBytes:_buf length:len];
+  return len;
+}
+- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
+  unsigned len;
+  
+  len = [super writeBytes:_buf count:_len];
+  if (len == NGStreamError)
+    return NGStreamError;
+  
+  [self->writeLog appendBytes:_buf length:len];
+  return len;
+}
+
+@end /* WORecordRequestStream */
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequest+Adaptor.h b/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequest+Adaptor.h
new file mode 100644 (file)
index 0000000..2fe72b2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WORequest_Adaptor_H__
+#define __WORequest_Adaptor_H__
+
+#include <NGObjWeb/WORequest.h>
+
+@class NSDate;
+
+#define CODE_RED_PREFIX  @"/default.ida?XXXXXXXXXXXXX"
+
+@interface WORequest(TakeStartDate)
+- (BOOL)isCodeRedAttack;
+- (void)takeStartDate:(NSDate *)_startDate;
+@end
+
+#endif /* __WORequest_Adaptor_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequest+Adaptor.m b/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequest+Adaptor.m
new file mode 100644 (file)
index 0000000..12bea1c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WORequest+Adaptor.h"
+#include "common.h"
+
+@implementation WORequest(TakeStartDate)
+
+- (BOOL)isCodeRedAttack {
+  return [[self uri] hasPrefix:CODE_RED_PREFIX];
+}
+
+- (void)takeStartDate:(NSDate *)_startDate {
+  NSMutableDictionary *ud;
+  static NSProcessInfo *pi = nil;
+  id tmp;
+  
+  if (pi == nil) pi = [[NSProcessInfo processInfo] retain];
+  
+  if ((ud = (id)[self userInfo]))
+    ud = [ud mutableCopy];
+  else
+    ud = [[NSMutableDictionary alloc] initWithCapacity:4];
+  
+  if (_startDate) [ud setObject:_startDate forKey:@"WORequestStartDate"];
+  
+  tmp = [pi procStatDictionary];
+  if (tmp) [ud setObject:tmp forKey:@"WORequestStartProcStatistics"];
+  
+  [self setUserInfo:ud];
+  [ud release];
+}
+
+@end /* WORequest(TakeStartDate) */
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequestParser.h b/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequestParser.h
new file mode 100644 (file)
index 0000000..eacb709
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOHttpAdaptor_WORequestParser_H__
+#define __WOHttpAdaptor_WORequestParser_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  WORequestParser (NOT FINISHED YET)
+  
+  A specialized parser for WO HTTP requests. It has some advanced features
+  like streaming large request bodies to disk and mapping them into memory
+  instead of keeping the whole thing in memory all the time.
+  It also correctly works with HTTP methods that have no content-length
+  specified (the NGHttpParser tries to parse till EOF by default).
+
+  Note: since the parser keep transient state in the ivars, you need to have
+  at least one parser per thread when running in a multithreaded environment.
+  
+  Note: if parsing fails you *need* to close the socket connection !
+*/
+
+@class NSException;
+@class NGBufferedStream;
+@class WORequest;
+
+@interface WORequestParser : NSObject
+{
+  NGBufferedStream *in;
+  NSException *lastException;
+  int (*readByte)(id,SEL);
+  
+  /* transient */
+  unsigned char pushBack;
+}
+
+- (id)initWithBufferedStream:(NGBufferedStream *)_in;
+
+/* parsing */
+
+- (WORequest *)parseNextRequest;
+- (NSException *)lastException;
+
+@end
+
+#endif /* __WOHttpAdaptor_WORequestParser_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequestParser.m b/skyrix-sope/NGObjWeb/WOHttpAdaptor/WORequestParser.m
new file mode 100644 (file)
index 0000000..605231b
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WORequestParser.h"
+#include <NGStreams/NGBufferedStream.h>
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+@implementation WORequestParser
+
+- (id)initWithBufferedStream:(NGBufferedStream *)_in {
+  if (_in == nil) {
+    [self release];
+    return nil;
+  }
+  
+  self->in = [_in retain];
+  self->readByte = (void *)[self->in methodForSelector:@selector(readByte)];
+  return self;
+}
+
+- (void)dealloc {
+  [self->lastException release];
+  [self->in            release];
+  [super dealloc];
+}
+
+/* parsing */
+
+- (void)takeLastException {
+  ASSIGN(self->lastException, [self->in lastException]);
+}
+
+static inline int nextChar(WORequestParser *self) {
+  int c;
+  if (self->pushBack != 0) {
+    c = self->pushBack;
+    self->pushBack = 0;
+    return c;
+  }
+  if ((c = self->readByte(self->in, @selector(readByte))) < 0)
+    [self takeLastException];
+  return c;
+}
+
+static inline int nextCharAfterSpaces(WORequestParser *self) {
+  int c;
+  
+  if (self->pushBack != 0) {
+    if (self->pushBack == ' ' || self->pushBack == '\t')
+      self->pushBack = 0;
+    else {
+      c = self->pushBack;
+      self->pushBack = 0;
+      return c;
+    }
+  }
+  
+  do {
+    c = self->readByte(self->in, @selector(readByte));
+    if (c < 0) {
+      [self takeLastException];
+      return c;
+    }
+  }
+  while ((c == ' ') || (c == '\t'));
+  return c;
+}
+static inline BOOL skipSpaces(WORequestParser *self) {
+  int c;
+  
+  if ((c = nextCharAfterSpaces(self)) > 0)
+    return NO;
+  self->pushBack = c;
+  return YES;
+}
+
+- (BOOL)readCRLF {
+  int c;
+  
+  c = nextChar(self);
+  if (c < 0)     return NO;
+  if (c == '\n') return YES;
+  if (c != '\r') return NO;
+  
+  c = nextChar(self);
+  if (c < 0)     return NO;
+  if (c == '\n') return YES;
+  return NO;
+}
+
+/* header line */
+
+- (NSString *)parseMethod {
+  unsigned count;
+  unsigned char m[32];
+  int c;
+  
+  count = 0;
+  for (c = nextChar(self); isalpha(c) && (count < 30); c = nextChar(self)) {
+    m[count] = c;
+    count++;
+  }
+  m[count] = '\0';
+  
+  if (count == 30) {
+    /* method name too long */
+    [self logWithFormat:@"method name got too long"];
+    return nil;
+  }
+  else if (count == 0) {
+    /* method name too short */
+    [self logWithFormat:@"method name got too short"];
+    return nil;
+  }
+  
+  return [NSString stringWithCString:m length:count];
+}
+
+- (NSString *)parseURI {
+  unsigned char *uri;
+  unsigned      count;
+  NSString      *s;
+  int c;
+  
+  if ((c = nextCharAfterSpaces(self)) < 0)
+    return nil;
+  
+  uri = calloc(4096, sizeof(unsigned char));
+  
+  for (count = 0; count < 4001 && (c > 0); count++) {
+    if (c == ' '  || c == '\t') break;
+    if (c == '\r' || c == '\n') break;
+    
+    uri[count] = c;
+    c = nextChar(self);
+  }
+  
+  if (c < 0) return nil;
+  if (count == 4001) {
+    [self logWithFormat:@"uri got too long (max 4000 chars)"];
+    return nil;
+  }
+  
+  /* feed last char to next parsing step */
+  self->pushBack = c;
+  
+  s = [NSString stringWithCString:uri length:count];
+  if (uri) free(uri);
+  return s;
+}
+
+- (NSString *)parseVersion {
+  unsigned count;
+  unsigned char m[16];
+  int c;
+  
+  c = nextCharAfterSpaces(self);
+  if (c == '\r' || c == '\n') {
+    /* no version specified */
+    self->pushBack = c;
+    return @"HTTP/0.9";
+  }
+  
+  count = 0;
+  for (; isprint(c) && (count < 15); c = nextChar(self)) {
+    m[count] = c;
+    count++;
+  }
+  m[count] = '\0';
+  
+  if (count == 15) {
+    /* version too long */
+    [self logWithFormat:@"http version got too long"];
+    return nil;
+  }
+  else if (count == 0) {
+    /* version too short, guessing HTTP/0.9 */
+    return @"HTTP/0.9";
+  }
+  
+  return [NSString stringWithCString:m length:count];
+}
+
+/* headers */
+
+- (NSDictionary *)parseHeaders {
+  return nil;
+}
+
+/* body */
+
+- (unsigned)ramDataSizeLimitation {
+  // 64KB TODO: make default
+  return (64 * 1064);
+}
+- (unsigned)spoolDataSizeLimitation {
+  // 64MB TODO: make default
+  return (64 * 1024 * 1064);
+}
+
+- (NSData *)readContentUntilEOF {
+  // TODO
+  return nil;
+}
+
+- (NSData *)readContentOfLength:(unsigned int)_count {
+  if (_count == 0) {
+    static NSData *emptyData = nil;
+    if (emptyData == nil) emptyData = [[NSData alloc] init];
+    return emptyData;
+  }
+  
+  if (_count <= [self ramDataSizeLimitation])
+    return [self->in safeReadDataOfLength:_count];
+  
+  // TODO
+  return nil;
+}
+
+/* full request */
+
+- (BOOL)isContentLessMethod:(NSString *)_method {
+  static NSMutableSet *methods = nil;
+  if (methods == nil) {
+    methods = [[NSMutableSet alloc] initWithObjects:nil];
+  }
+  return [methods containsObject:_method];
+}
+
+- (WORequest *)parseNextRequest {
+  NSString     *method, *uri, *v;
+  NSDictionary *headers;
+  NSData       *content;
+  WORequest    *result;
+
+  ASSIGN(self->lastException, (id)nil);
+  
+  /* request line */
+  
+  if ((method = [self parseMethod]) == nil)
+    return nil;
+  if ((uri = [self parseURI]) == nil)
+    return nil;
+  if ((v = [self parseVersion]) == nil)
+    return nil;
+  
+  if (![self readCRLF])
+    return nil;
+
+  [self debugWithFormat:@"stage 1: method=%@ uri=%@ version=%@",
+         method, uri, v];
+  
+  /* headers */
+  
+  if ((headers = [self parseHeaders]) == nil)
+    return nil;
+  
+  /* body */
+  
+  if (![self isContentLessMethod:method]) {
+    unsigned int clen;
+    
+    if ((clen = [[headers objectForKey:@"content-length"] intValue])) {
+      content = [self readContentOfLength:clen];
+    }
+    else {
+      /*
+        Two cases: 
+          HTTP/1.0, HTTP/0.9 - read till EOF if no content-length is set
+         HTTP/1.1 and above: if no content-length is set, body is empty
+      */
+      
+      if ([v hasPrefix:@"HTTP/0"])
+       content = [self readContentUntilEOF];
+      else if ([v hasPrefix:@"HTTP/1.0"])
+       content = [self readContentUntilEOF];
+      else
+       content = nil;
+    }
+  }
+  else
+    content = nil;
+  
+  /* construct */
+  
+  result = [[WORequest alloc] initWithMethod:method uri:uri httpVersion:v
+                             headers:headers content:content
+                             userInfo:nil];
+  return [result autorelease];
+}
+
+- (NSException *)lastException {
+  return self->lastException;
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return @"[http-parser]";
+}
+- (BOOL)isDebuggingEnabled {
+  static int debugOn = -1;
+  if (debugOn == -1) {
+    debugOn = [[NSUserDefaults standardUserDefaults]
+               boolForKey:@"WORequestParserDebugEnabled"] ? 1 : 0;
+  }
+  return debugOn ? YES : NO;
+}
+
+@end /* WORequestParser */
diff --git a/skyrix-sope/NGObjWeb/WOMailDelivery.m b/skyrix-sope/NGObjWeb/WOMailDelivery.m
new file mode 100644 (file)
index 0000000..d75a76f
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOMailDelivery.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@implementation WOMailDelivery
+
++ (int)version {
+  return 2;
+}
+
+WOMailDelivery *sharedInstance = nil;
+
++ (id)sharedInstance {
+  if (sharedInstance == nil)
+    sharedInstance = [[WOMailDelivery alloc] init];
+  return sharedInstance;
+}
+
+// composing mails
+
+- (id)composeEmailFrom:(NSString *)_senderAddress
+  to:(NSArray *)_receiverAddresses
+  cc:(NSArray *)_ccAddresses
+  subject:(NSString *)_subject
+  plainText:(NSString *)_text
+  send:(BOOL)_sendFlag
+{
+  NSMutableDictionary *email = [NSMutableDictionary dictionaryWithCapacity:16];
+  NSData *content;
+
+  if (_senderAddress == nil)          return nil;
+  if ([_receiverAddresses count] < 1) return nil;
+  
+  if (_subject == nil)     _subject = @"";
+  if (_text == nil)        _text    = @"";
+  if (_ccAddresses == nil) _ccAddresses = [NSArray array];
+  
+  [email setObject:_subject           forKey:@"subject"];
+  [email setObject:_receiverAddresses forKey:@"to"];
+  [email setObject:_ccAddresses       forKey:@"cc"];
+  [email setObject:_senderAddress     forKey:@"from"];
+  [email setObject:@"text/plain; charset=us-ascii" forKey:@"content-type"];
+
+  content = [NSData dataWithBytes:[_text cString] length:[_text cStringLength]];
+  [email setObject:content forKey:@"body"];
+  [email setObject:[NSNumber numberWithInt:[content length]]
+         forKey:@"content-length"];
+
+  if (_sendFlag) {
+    if (![self sendEmail:email])
+      return nil;
+  }
+  return email;
+}
+
+- (id)composeEmailFrom:(NSString *)_senderAddress
+  to:(NSArray *)_receiverAddresses
+  cc:(NSArray *)_ccAddresses
+  subject:(NSString *)_subject
+  component:(WOComponent *)_component
+  send:(BOOL)_sendFlag
+{
+  NSMutableDictionary *email = [NSMutableDictionary dictionaryWithCapacity:16];
+
+  if (_senderAddress == nil)          return nil;
+  if ([_receiverAddresses count] < 1) return nil;
+  if (_subject     == nil) _subject = @"";
+  if (_ccAddresses == nil) _ccAddresses = [NSArray array];
+
+  [email setObject:_subject           forKey:@"subject"];
+  [email setObject:_receiverAddresses forKey:@"to"];
+  [email setObject:_ccAddresses       forKey:@"cc"];
+  [email setObject:_senderAddress     forKey:@"from"];
+
+  /* gen response */
+  {
+    WOResponse *response;
+    NSString   *contentType;
+
+    response = [_component generateResponse];
+    if ([response status] != 200)
+      // could not generate response
+      return nil;
+
+    contentType = [response headerForKey:@"content-type"];
+    if (contentType == nil) contentType = @"text/html";
+    
+    [email setObject:contentType forKey:@"content-type"];
+    [email setObject:[response content] forKey:@"body"];
+    [email setObject:[NSNumber numberWithInt:[[response content] length]]
+           forKey:@"content-length"];
+  }
+
+  if (_sendFlag) {
+    if (![self sendEmail:email])
+      return nil;
+  }
+  return email;
+}
+
+// sending mails
+
+- (BOOL)sendEmail:(id)_email {
+  NSMutableString *sendmail = [NSMutableString stringWithCapacity:256];
+  NSArray *to, *cc;
+  FILE *toMail;
+
+  to = [_email objectForKey:@"to"];
+  cc = [_email objectForKey:@"cc"];
+
+  [sendmail appendString:[[NSUserDefaults standardUserDefaults]
+                                          stringForKey:@"WOSendMail"]];
+  [sendmail appendString:@" "];
+  [sendmail appendString:[to componentsJoinedByString:@" "]];
+  [sendmail appendString:@" "];
+  [sendmail appendString:[cc componentsJoinedByString:@" "]];
+
+  if ((toMail = popen([sendmail cString], "w"))) {
+    NSEnumerator *e = nil;
+    id entry;
+    NSString *tmp;
+    
+    if ((tmp = [[_email objectForKey:@"from"] stringValue])) {
+      if (fprintf(toMail, "Reply-To: %s\n", [tmp cString]) < 0)
+        goto failed;
+      if (fprintf(toMail, "From: %s\n", [tmp cString]) < 0)
+        goto failed;
+    }
+    
+    e = [to objectEnumerator];
+    while ((entry = [e nextObject])) {
+      if (fprintf(toMail, "To:%s\n", [[entry stringValue] cString]) < 0)
+        goto failed;
+    }
+
+    e = [cc objectEnumerator];
+    while ((entry = [e nextObject])) {
+      if (fprintf(toMail, "Cc:%s\n", [[entry stringValue] cString]) < 0)
+        goto failed;
+    }
+    
+    if ((tmp = [[_email objectForKey:@"subject"] stringValue])) {
+      if (fprintf(toMail, "Subject:%s\n", [tmp cString]) < 0)
+        goto failed;
+    }
+
+    if ((tmp = [[_email objectForKey:@"content-type"] stringValue])) {
+      if (fprintf(toMail, "Content-type:%s\n", [tmp cString]) < 0)
+        goto failed;
+    }
+    if ((tmp = [[_email objectForKey:@"content-length"] stringValue])) {
+      if (fprintf(toMail, "Content-length:%s\n", [tmp cString]) < 0)
+        goto failed;
+    }
+    
+    // end header
+    if (fprintf(toMail, "\n") < 0)
+      goto failed;
+
+    // write body
+    {
+      NSData *body = [_email objectForKey:@"body"];
+      if (fwrite([body bytes], [body length], 1, toMail) < 0)
+        goto failed;
+    }
+    fprintf(toMail, "\n");
+    pclose(toMail);
+
+    return YES;
+
+  failed:
+    pclose(toMail);
+    return NO;
+  }
+  return NO;
+}
+
+@end /* WOMailDelivery */
diff --git a/skyrix-sope/NGObjWeb/WOMessage+Validation.m b/skyrix-sope/NGObjWeb/WOMessage+Validation.m
new file mode 100644 (file)
index 0000000..74917af
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOMessage.h>
+#include <SaxObjC/SaxObjC.h>
+#include "common.h"
+
+@interface WOMessageSaxValidator : SaxDefaultHandler < SaxErrorHandler >
+{
+  id<NSObject,SaxXMLReader> parser;
+  NSMutableArray *issues;
+}
+
++ (id)validatorWithXmlReaderName:(NSString *)_name;
+
+- (NSArray *)validateContent:(NSData *)_content withType:(NSString *)_ctype;
+
+@end
+
+@implementation WOMessageSaxValidator
+
+static BOOL valDebugOn = NO;
+
+- (id)initWithXmlReaderName:(NSString *)_name {
+  if ((self = [super init])) {
+    SaxXMLReaderFactory *factory;
+    
+    factory = [SaxXMLReaderFactory standardXMLReaderFactory];
+    self->parser = [[factory createXMLReaderWithName:_name] retain];
+    if (self->parser == nil) {
+      [self release];
+      return nil;
+    }
+    
+    /* we are only interested in errors */
+    [self->parser setErrorHandler:self];
+  }
+  return self;
+}
++ (id)validatorWithXmlReaderName:(NSString *)_name {
+  return [[[self alloc] initWithXmlReaderName:_name] autorelease];
+}
+
+- (void)dealloc {
+  [self->issues release];
+  [self->parser release];
+  [super dealloc];
+}
+
+/* issues */
+
+- (void)addIssue:(id)_issue {
+  if (_issue == nil) return;
+  
+  if (self->issues == nil) 
+    self->issues = [[NSMutableArray alloc] initWithCapacity:16];
+  [self->issues addObject:_issue];
+}
+- (void)reset {
+  [self->issues removeAllObjects];
+}
+
+/* validation */
+
+- (void)warning:(SaxParseException *)_exception {
+  [self addIssue:_exception];
+}
+- (void)error:(SaxParseException *)_exception {
+  [self addIssue:_exception];
+}
+- (void)fatalError:(SaxParseException *)_exception {
+  [self addIssue:_exception];
+}
+
+- (NSArray *)validateContent:(NSData *)_content withType:(NSString *)_ctype {
+  NSArray *tmp;
+  
+  [self reset];
+  if (self->parser == nil) return nil;
+  
+  [self debugWithFormat:@"validate %@, content size %d",
+          _ctype, [_content length]];
+  
+  [self->parser parseFromSource:_content 
+                systemId:[@"validator://" stringByAppendingString:_ctype]];
+
+  tmp = [self->issues copy];
+  [self reset];
+
+  if (tmp == nil)
+    [self debugWithFormat:@"  no issues found :-)"];
+  else
+    [self debugWithFormat:@"  %d issues found :-|", [tmp count]];
+  return [tmp autorelease];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return valDebugOn;
+}
+
+@end /* WOMessageHTMLValidator */
+
+@implementation WOMessage(Validation)
+
+- (id)validatorForContentType:(NSString *)_ctype {
+  if ([_ctype hasPrefix:@"text/html"]) {
+    // Note: the HTML driver does not report invalid tags
+    return [WOMessageSaxValidator validatorWithXmlReaderName:
+                                    @"libxmlHTMLSAXDriver"];
+  }
+  
+  if ([_ctype hasPrefix:@"text/xml"]) {
+    return [WOMessageSaxValidator validatorWithXmlReaderName:
+                                    @"libxmlSAXDriver"];
+  }
+  
+  if ([_ctype hasPrefix:@"image/"])
+    return nil;
+  if ([_ctype hasPrefix:@"application/octet-stream"])
+    return nil;
+  if ([_ctype hasPrefix:@"text/plain"])
+    return nil;
+  
+  [self logWithFormat:@"no validator for type: %@", _ctype];
+  return nil;
+}
+
+- (NSArray *)validateContent {
+  NSString *ctype;
+  id validator;
+  
+#if 0
+  [self logWithFormat:@"should validate output"];
+#endif
+  
+  if ((ctype = [self headerForKey:@"content-type"]) == nil)
+    return [NSArray arrayWithObject:@"missing content type."];
+  
+  if ((validator = [self validatorForContentType:ctype]) == nil)
+    return nil;
+  
+  return [validator validateContent:[self content] withType:ctype];
+}
+
+@end /* WOMessage(Validation) */
diff --git a/skyrix-sope/NGObjWeb/WOMessage+XML.m b/skyrix-sope/NGObjWeb/WOMessage+XML.m
new file mode 100644 (file)
index 0000000..ac0eff5
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOMessage.h>
+//#include <DOM/EDOM.h>
+#include "common.h"
+
+@interface NSObject(DOMXML)
+- (void)outputDocument:(id)_document to:(id)_target;
+- (id)buildFromData:(NSData *)_data;
+- (id)documentElement;
+- (void)appendChild:(id)_child;
+@end
+
+@implementation WOMessage(XMLSupport)
+
+- (void)_rebuildDOMDataContent {
+  NSMutableString *ms;
+  id     outputter;
+  NSData *data;
+  id     dom;
+  
+  if ((dom = [[self userInfo] objectForKey:@"WODOMContent"]) == nil) {
+    [self setContent:nil];
+    return;
+  }
+  
+  outputter = [[NSClassFromString(@"DOMXMLOutputter") alloc] init];
+  AUTORELEASE(outputter);
+
+  ms = [NSMutableString stringWithCapacity:2048];
+  [outputter outputDocument:dom to:ms];
+    
+  data = [ms dataUsingEncoding:NSUTF8StringEncoding];
+
+  [self setContent:data];
+}
+
+- (void)setContentDOMDocument:(id)_dom {
+  if (_dom == nil) {
+    if ((_dom = [[self userInfo] objectForKey:@"WODOMContent"])) {
+      NSMutableDictionary *ui;
+
+      ui = [[self userInfo] mutableCopy];
+      [ui removeObjectForKey:@"WODOMContent"];
+      [self setUserInfo:ui];
+      RELEASE(ui); ui = nil;
+    }
+    [self _rebuildDOMDataContent];
+    return;
+  }
+  else {
+    NSMutableDictionary *ui;
+    
+    /* cache DOM structure in userInfo */
+    ui = [[self userInfo] mutableCopy];
+    if (ui == nil) ui = [[NSMutableDictionary alloc] initWithCapacity:2];
+    [ui setObject:_dom forKey:@"WODOMContent"];
+    [self setUserInfo:ui];
+    RELEASE(ui); ui = nil;
+
+    [self _rebuildDOMDataContent];
+  }
+}
+
+- (void)appendContentDOMDocumentFragment:(id)_domfrag {
+  id dom;
+  
+  if (_domfrag == nil)
+    return;
+  
+  if ((dom = [self contentAsDOMDocument])) {
+    [[dom documentElement] appendChild:_domfrag];
+    [self setContentDOMDocument:dom];
+  }
+  else {
+    [self setContentDOMDocument:_domfrag];
+  }
+}
+
+- (id)contentAsDOMDocument {
+  NSData *data;
+  id dom;
+  
+  if ((dom = [[self userInfo] objectForKey:@"WODOMContent"]))
+    return dom;
+  
+  if ((data = [self content])) {
+    id builder;
+    
+    builder = [[[NSClassFromString(@"DOMSaxBuilder") alloc] init] autorelease];
+    
+    dom = [[builder buildFromData:data] retain];
+  }
+  
+  /* cache DOM structure in userInfo */
+  if (dom) {
+    NSMutableDictionary *ui;
+    
+    ui = [[self userInfo] mutableCopy];
+    if (ui == nil) ui = [[NSMutableDictionary alloc] initWithCapacity:2];
+    [ui setObject:dom forKey:@"WODOMContent"];
+    [self setUserInfo:ui];
+    RELEASE(ui); ui = nil;
+  }
+  return dom;
+}
+
+@end /* WOMessage */
diff --git a/skyrix-sope/NGObjWeb/WOMessage.m b/skyrix-sope/NGObjWeb/WOMessage.m
new file mode 100644 (file)
index 0000000..3f9f66e
--- /dev/null
@@ -0,0 +1,603 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOMessage.h>
+#include <NGExtensions/NGHashMap.h>
+#include <NGExtensions/NSString+misc.h>
+#include "common.h"
+
+// #define STRIP_MULTIPLE_SPACES // this doesn't work with <pre> tags !
+
+@implementation WOMessage
+
+typedef struct _WOMessageProfileInfo {
+  unsigned append;
+  unsigned appendC;
+  unsigned appendChr;
+  unsigned appendXML;
+  unsigned appendHTML;
+} WOMessageProfileInfo;
+
+static Class            NSStringClass    = Nil;
+static BOOL             printProfile     = NO;
+static int              DEF_CONTENT_SIZE = 20000;
+static NSStringEncoding defaultEncoding  = 0;
+
+static WOMessageProfileInfo profile    = { 0, 0, 0, 0, 0 };
+static WOMessageProfileInfo profilemax = { 0, 0, 0, 0, 0 };
+static WOMessageProfileInfo profiletot = { 0, 0, 0, 0, 0 };
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  if (NSStringClass == Nil)
+    NSStringClass = [NSString class];
+  
+  printProfile = [ud boolForKey:@"WOProfileResponse"];
+
+#ifdef __APPLE__
+  //#warning default encoding is ISO Latin 1 ...
+  defaultEncoding = NSISOLatin1StringEncoding;
+#else
+  defaultEncoding = [NSStringClass defaultCStringEncoding];
+#endif
+}
+
+static inline void _ensureBody(WOMessage *self) {
+  if (self->content == nil) {
+    self->content = [[NSMutableData alloc] initWithCapacity:DEF_CONTENT_SIZE];
+    self->addBytes = (void *)
+      [self->content methodForSelector:@selector(appendBytes:length:)];
+  }
+}
+
+static __inline__ NSMutableData *_checkBody(WOMessage *self) {
+  if (self->content == nil) {
+    self->content = [[NSMutableData alloc] initWithCapacity:DEF_CONTENT_SIZE];
+    self->addBytes = (void *)
+      [self->content methodForSelector:@selector(appendBytes:length:)];
+  }
+  return self->content;
+}
+
++ (int)version {
+  return 4;
+}
+
++ (void)setDefaultEncoding:(NSStringEncoding)_encoding {
+  defaultEncoding = _encoding;
+}
++ (NSStringEncoding)defaultEncoding {
+  return defaultEncoding;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->contentEncoding = [[self class] defaultEncoding];
+    
+    self->addChar = (void*)
+      [self methodForSelector:@selector(appendContentCharacter:)];
+    self->addStr  = (void *)
+      [self methodForSelector:@selector(appendContentString:)];
+    self->addHStr = (void *)
+      [self methodForSelector:@selector(appendContentHTMLString:)];
+    self->addCStr = (void *)
+      [self methodForSelector:@selector(appendContentCString:)];
+    
+    self->header  = [[NGMutableHashMap allocWithZone:[self zone]] init];
+    self->version = @"HTTP/1.0";
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->contentStream release];
+  [self->cookies  release];
+  [self->version  release];
+  [self->content  release];
+  [self->header   release];
+  [self->userInfo release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setUserInfo:(NSDictionary *)_userInfo {
+  ASSIGN(self->userInfo, _userInfo);
+}
+- (NSDictionary *)userInfo {
+  return self->userInfo;
+}
+
+/* HTTP */
+
+- (void)setHTTPVersion:(NSString *)_httpVersion {
+  id old;
+  if (self->version == _httpVersion)
+    return;
+  old = self->version;
+  self->version = [_httpVersion copy];
+  [old release];
+  
+  if (self->version != nil && ![_httpVersion hasPrefix:@"HTTP/"]) {
+    [self logWithFormat:
+            @"WARNING: you apparently passed in an invalid HTTP version: '%@'",
+            _httpVersion];
+  }
+}
+- (void)setHttpVersion:(NSString *)_httpVersion {
+  // deprecated
+  [self setHTTPVersion:_httpVersion];
+}
+- (NSString *)httpVersion {
+  return self->version;
+}
+
+/* cookies (new in WO4) */
+
+- (void)addCookie:(WOCookie *)_cookie {
+  if (self->cookies == nil)
+    self->cookies = [[NSMutableArray allocWithZone:[self zone]] init];
+  [self->cookies addObject:_cookie];
+}
+
+- (void)removeCookie:(WOCookie *)_cookie {
+  [self->cookies removeObject:_cookie];
+}
+
+- (NSArray *)cookies {
+  return self->cookies;
+}
+
+/* header */
+
+- (void)setHeaders:(NSDictionary *)_headers {
+  NSEnumerator *keys;
+  NSString *key;
+
+  keys = [_headers keyEnumerator];
+  while ((key = [keys nextObject])) {
+    id value;
+    
+    value = [_headers objectForKey:key];
+    if ([value isKindOfClass:[NSArray class]]) {
+      NSEnumerator *e = [value objectEnumerator];
+
+      while ((value = [e nextObject]))
+       [self appendHeader:value forKey:key];
+    }
+    else
+      [self appendHeader:value forKey:key];
+  }
+}
+
+- (void)setHeader:(NSString *)_header forKey:(NSString *)_key {
+  [self->header setObject:[_header stringValue] forKey:_key];
+}
+- (NSString *)headerForKey:(NSString *)_key {
+  return [[self->header objectEnumeratorForKey:_key] nextObject];
+}
+
+- (void)appendHeader:(NSString *)_header forKey:(NSString *)_key {
+  [self->header addObject:_header forKey:_key];
+}
+- (void)appendHeaders:(NSArray *)_headers forKey:(NSString *)_key {
+  [self->header addObjects:_headers forKey:_key];
+}
+
+- (void)setHeaders:(NSArray *)_headers forKey:(NSString *)_key {
+  NSEnumerator *e;
+  id value;
+
+  e = [_headers objectEnumerator];
+
+  [self->header removeAllObjectsForKey:_key];
+  
+  while ((value = [e nextObject]))
+    [self->header addObject:value forKey:_key];
+}
+- (NSArray *)headersForKey:(NSString *)_key {
+  NSEnumerator *values;
+
+  if ((values = [self->header objectEnumeratorForKey:_key])) {
+    NSMutableArray *array = nil;
+    id value = nil;
+    
+    array = [[NSMutableArray allocWithZone:[self zone]] init];
+
+    while ((value = [values nextObject]))
+      [array addObject:value];
+
+    return [array autorelease];
+  }
+  return nil;
+}
+
+- (NSArray *)headerKeys {
+  NSEnumerator *values;
+
+  if ((values = [self->header keyEnumerator])) {
+    NSMutableArray *array  = nil;
+    id name = nil;
+    array = [[NSMutableArray alloc] init];
+    
+    while ((name = [values nextObject]))
+      [array addObject:name];
+
+    name = [array copy];
+    [array release];
+    
+    return [name autorelease];
+  }
+  return nil;
+}
+
+- (NSDictionary *)headers {
+  return [self->header asDictionary];
+}
+
+- (NSString *)headersAsString {
+  NSMutableString *ms;
+  NSEnumerator *keys;
+  NSString     *key;
+  
+  ms = [NSMutableString stringWithCapacity:1024];
+  
+  /* headers */
+  keys = [[self headerKeys] objectEnumerator];
+  while ((key = [keys nextObject])) {
+    NSEnumerator *vals;
+    id val;
+    
+    vals = [[self headersForKey:key] objectEnumerator];
+    while ((val = [vals nextObject])) {
+      [ms appendString:key];
+      [ms appendString:@": "];
+      [ms appendString:[val stringValue]];
+      [ms appendString:@"\r\n"];
+    }
+  }
+  return ms;
+}
+
+/* profiling */
+
+- (void)_printProfile {
+  if (profile.append + profile.appendC + profile.appendChr +
+      profile.appendXML + profile.appendHTML == 0)
+    return;
+  
+  /* calc max */
+  if (profile.append > profilemax.append)
+    profilemax.append = profile.append;
+  if (profile.appendC > profilemax.appendC) 
+    profilemax.appendC = profile.appendC;
+  if (profile.appendHTML > profilemax.appendHTML) 
+    profilemax.appendHTML = profile.appendHTML;
+  
+  /* calc total */
+  profiletot.append     += profile.append;
+  profiletot.appendC    += profile.appendC;
+  profiletot.appendChr  += profile.appendChr;
+  profiletot.appendHTML += profile.appendHTML;
+  profiletot.appendXML  += profile.appendXML;
+  
+  /* print */
+  
+  [self logWithFormat:@"PROFILE: WOResponse:\n"
+        @"  appendContentString:     %8i max %8i total %8i\n"
+        @"  appendContentCString:    %8i max %8i total %8i\n"
+        @"  appendContentCharacter:  %8i max %8i total %8i\n"
+        @"  appendContentXMLString:  %8i max %8i total %8i\n"
+        @"  appendContentHTMLString: %8i max %8i total %8i\n",
+        profile.append,     profilemax.append,     profiletot.append,
+        profile.appendC,    profilemax.appendC,    profiletot.appendC,
+        profile.appendChr,  profilemax.appendChr,  profiletot.appendChr,
+        profile.appendXML,  profilemax.appendXML,  profiletot.appendXML,
+        profile.appendHTML, profilemax.appendHTML, profiletot.appendHTML];
+  
+  /* reset profile */
+  memset(&profile, 0, sizeof(profile));
+}
+
+/* generic content */
+
+- (void)setContent:(NSData *)_data {
+  id old;
+  
+  if (self->content == (id)_data) 
+    return;
+  
+  old = self->content;
+  self->content = [_data mutableCopy];
+  [old release];
+}
+- (NSData *)content {
+  if (printProfile) [self _printProfile];
+  return self->content;
+}
+- (NSString *)contentAsString {
+  NSString *s;
+  NSData   *c;
+  
+  if ((c = [self content]) == nil)
+    return nil;
+
+  s = [[NSString alloc] initWithData:c encoding:[self contentEncoding]];
+  return [s autorelease];
+}
+- (BOOL)doesStreamContent {
+  return self->contentStream != nil ? YES : NO;
+}
+
+- (void)setContentEncoding:(NSStringEncoding)_encoding {
+  self->contentEncoding = _encoding;
+}  
+- (NSStringEncoding)contentEncoding {
+  return self->contentEncoding;
+}
+
+/* structured content */
+
+- (void)appendContentBytes:(const void *)_bytes length:(unsigned)_l {
+  if (_bytes == NULL || _l == 0) return;
+  if (self->content == nil) _ensureBody(self);
+  self->addBytes(self->content, @selector(appendBytes:length:), _bytes, _l);
+}
+
+- (void)appendContentCharacter:(unichar)_c {
+  unsigned char bc[2] = {0, 0};
+  
+  profile.appendChr++;
+  
+  *(&bc[0]) = _c;
+  if (self->content == nil) _ensureBody(self);
+  
+  switch (self->contentEncoding) {
+    case NSISOLatin1StringEncoding:
+    case NSASCIIStringEncoding:
+      /* those two encodings are == Unicode ... */
+      self->addBytes(self->content, @selector(appendBytes:length:), &(bc[0]), 1);
+      break;
+      
+    case NSUnicodeStringEncoding:
+      /* directly add 16-byte char ... */
+      self->addBytes(self->content, @selector(appendBytes:length:), 
+                     &_c, sizeof(_c));
+      break;
+      
+    case NSUTF8StringEncoding:
+      /* directly add a byte if 1-byte char (<127 in UTF-8) */
+      if (_c < 127) {
+        self->addBytes(self->content, @selector(appendBytes:length:), &(bc[0]), 1);
+        break;
+      }
+      /* *intended* fall-through !!! */
+      
+    default: {
+      /* otherwise create string for char and ask string to convert to data */
+      NSString *s;
+    
+#if DEBUG
+      [self logWithFormat:
+              @"WARNING: using NSString to add a character %i,0x%08X"
+              @"(slow, encoding=%i).", _c, _c, self->contentEncoding];
+#endif
+      
+      if ((s = [[NSStringClass alloc] initWithCharacters:&_c length:1])) {
+        self->addStr(self, @selector(appendContentString:), s);
+        [s release];
+      }
+      break;
+    }
+  }
+}
+- (void)appendContentData:(NSData *)_data {
+  if (_data == nil) return;
+  [_checkBody(self) appendData:_data];
+}
+
+- (void)appendContentHTMLAttributeValue:(NSString *)_value {
+  self->addStr(self, @selector(appendContentString:), 
+               [_value stringByEscapingHTMLAttributeValue]);
+  profile.appendHTML++;
+}
+- (void)appendContentHTMLString:(NSString *)_value {
+  self->addStr(self, @selector(appendContentString:), 
+               [_value stringByEscapingHTMLString]);
+  profile.appendHTML++;
+}
+
+- (void)appendContentXMLAttributeValue:(NSString *)_value {
+  self->addStr(self, @selector(appendContentString:), 
+               [_value stringByEscapingXMLAttributeValue]);
+  profile.appendXML++;
+}
+- (void)appendContentXMLString:(NSString *)_value {
+  if (_value == nil) return;
+  self->addStr(self, @selector(appendContentString:), 
+               [_value stringByEscapingXMLString]);
+  profile.appendXML++;
+}
+
+- (void)appendContentCString:(const unsigned char *)_value {
+  /* we assume that cString == ASCII !!! */
+  register unsigned len;
+
+  profile.appendC++;
+
+  if (self->content == nil) _ensureBody(self);
+  if ((len = _value ? strlen(_value) : 0) == 0)
+    return;
+  
+  switch (self->contentEncoding) {
+    case NSISOLatin1StringEncoding:
+    case NSASCIIStringEncoding:
+    case NSUTF8StringEncoding:
+      self->addBytes(self->content, @selector(appendBytes:length:), 
+                     _value, len);
+      return;
+    
+    case NSUnicodeStringEncoding:
+    default: {
+      /* worst case ... */
+      NSString *s;
+      
+      if ((s = [[NSString alloc] initWithCString:_value])) {
+        self->addStr(self, @selector(appendContentString:), s);
+        [s release];
+      }
+    }
+  }
+}
+
+- (void)appendContentString:(NSString *)_value {
+  NSData *cdata;
+  
+  profile.append++;
+  
+  if ([_value length] == 0)
+    return;
+  
+  cdata = [_value dataUsingEncoding:self->contentEncoding
+                  allowLossyConversion:NO];
+#if 0
+  if ([_value length] > 9000) {
+    char *cstr;
+    unsigned i, len;
+
+#if 0
+    cstr = [cdata bytes];
+    len  = [cdata length];
+#else
+    cstr = [_value cString];
+    len  = [_value cStringLength];
+#endif
+
+    printf("\n\n*** add contentstring (value-enc=%i,%i,%i) "
+           "(len=%i, dlen=%i): '",
+           [_value smallestEncoding],
+           [_value fastestEncoding],
+           self->contentEncoding,
+           [_value length], len);
+    fwrite(cstr, 1, len, stdout);
+    printf("'\n");
+    
+    for (i = len - 20; i < len; i++)
+      printf("%5i: 0x%08X %4i\n", i, cstr[i], cstr[i]);
+    fflush(stdout);
+  }
+#endif
+  if (cdata == NULL) {
+    NSLog(@"ERROR(%s): could not convert string non-lossy to encoding %i !",
+          __PRETTY_FUNCTION__, self->contentEncoding);
+    cdata = [_value dataUsingEncoding:self->contentEncoding
+                    allowLossyConversion:YES];
+  }
+  [self appendContentData:cdata];
+}
+
+@end /* WOMessage */
+
+@implementation WOMessage(Escaping)
+
+static inline void
+_escapeHtmlValue(unsigned char c, unsigned char *buf, int *pos)
+{
+  int j = *pos;
+  switch (c) {
+    case '&':
+      buf[j] = '&'; j++; buf[j] = 'a'; j++; buf[j] = 'm'; j++;
+      buf[j] = 'p'; j++; buf[j] = ';';
+      break;
+    case '"':
+      buf[j] = '&'; j++; buf[j] = 'q'; j++; buf[j] = 'u'; j++;
+      buf[j] = 'o'; j++; buf[j] = 't'; j++; buf[j] = ';';
+      break;
+    case '<':
+      buf[j] = '&'; j++; buf[j] = 'l'; j++; buf[j] = 't'; j++;
+      buf[j] = ';';
+      break;
+    case '>':
+      buf[j] = '&'; j++; buf[j] = 'g'; j++; buf[j] = 't'; j++;
+      buf[j] = ';';
+      break;
+
+    default:
+      buf[j] = c;
+      break;
+  }
+  *pos = j;
+}
+
+static inline void
+_escapeAttrValue(unsigned char c, unsigned char *buf, int *pos)
+{
+  int j = *pos;
+  switch (c) {
+    case '&':
+      buf[j] = '&'; j++; buf[j] = 'a'; j++; buf[j] = 'm'; j++;
+      buf[j] = 'p'; j++; buf[j] = ';';
+      break;
+    case '"':
+      buf[j] = '&'; j++; buf[j] = 'q'; j++; buf[j] = 'u'; j++;
+      buf[j] = 'o'; j++; buf[j] = 't'; j++; buf[j] = ';';
+      break;
+    case '<':
+      buf[j] = '&'; j++; buf[j] = 'l'; j++; buf[j] = 't'; j++;
+      buf[j] = ';';
+      break;
+    case '>':
+      buf[j] = '&'; j++; buf[j] = 'g'; j++; buf[j] = 't'; j++;
+      buf[j] = ';';
+      break;
+
+    case '\t':
+      buf[j] = '&'; j++; buf[j] = '#'; j++; buf[j] = '9'; j++;
+      buf[j] = ';';
+      break;
+    case '\n':
+      buf[j] = '&'; j++; buf[j] = '#'; j++; buf[j] = '1'; j++;
+      buf[j] = '0'; j++; buf[j] = ';';
+      break;
+    case '\r':
+      buf[j] = '&'; j++; buf[j] = '#'; j++; buf[j] = '1'; j++;
+      buf[j] = '3'; j++; buf[j] = ';';
+      break;
+          
+    default:
+      buf[j] = c;
+      break;
+  }
+  *pos = j;
+}
+
+
++ (NSString *)stringByEscapingHTMLString:(NSString *)_string {
+  return [_string stringByEscapingHTMLString];
+}
+
++ (NSString *)stringByEscapingHTMLAttributeValue:(NSString *)_string {
+  return [_string stringByEscapingHTMLAttributeValue];
+}
+
+@end /* WOMessage(Escaping) */
diff --git a/skyrix-sope/NGObjWeb/WOPageRequestHandler.m b/skyrix-sope/NGObjWeb/WOPageRequestHandler.m
new file mode 100644 (file)
index 0000000..8cdebd6
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WORequestHandler.h>
+
+@interface WOPageRequestHandler : WORequestHandler
+@end
+
+//#include "WOPageRequestHandler.h"
+#include "WORequestHandler+private.h"
+#include "WOContext+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WODirectAction.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WOSessionStore.h>
+#include <NGObjWeb/WOStatisticsStore.h>
+#include "common.h"
+
+static BOOL  perflog             = NO;
+static Class NSDateClass         = Nil;
+static BOOL  debugUnknownActions = NO;
+static BOOL  debugOn             = NO;
+
+@interface WOComponent(Privates)
+- (void)_awakeWithContext:(WOContext *)_ctx;
+- (id<WOActionResults>)performActionNamed:(NSString *)_actionName;
+@end
+
+@implementation WOPageRequestHandler
+
++ (int)version {
+  return [super version] + 0 /* 2 */;
+}
++ (void)initialize {
+  NSUserDefaults *ud;
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+
+  NSDateClass = [NSDate class];
+  ud = [NSUserDefaults standardUserDefaults];
+  perflog = [ud boolForKey:@"WOProfilePageRequestHandler"];
+  debugOn = [ud boolForKey:@"WOPageRequestHandlerDebugEnabled"];
+}
+
+/* debugging */
+
+- (NSString *)loggingPrefix {
+  return @"[pg-handler]";
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+/*
+  The request handler part of a direct action URI looks like this:
+
+    [actionClass/]actionName[?key=value&key=value&...]
+*/
+
+- (WOResponse *)handleRequest:(WORequest *)_request
+  inContext:(WOContext *)context
+  session:(WOSession *)session
+  application:(WOApplication *)app
+{
+  NSString      *actionName;
+  WOResponse    *response;
+  id<WOActionResults> result = nil;
+  NSString      *pageName;
+  WOComponent   *page;
+  
+  *(&result) = nil;
+  *(&response)        = nil;
+  *(&actionName)      = nil;
+  
+  /* process path */
+  if ((pageName = [_request headerForKey:@"x-httpd-pagename"]) == nil) {
+    NSArray *handlerPath;
+    
+    handlerPath = [_request requestHandlerPathArray];
+    switch ([handlerPath count]) {
+      case 0:
+        pageName   = @"Main";
+        actionName = @"default";
+        break;
+      case 1:
+        pageName   = [handlerPath objectAtIndex:0];
+        actionName = @"default";
+        break;
+      default:
+        pageName   = [handlerPath objectAtIndex:0];
+        actionName = [handlerPath objectAtIndex:1];
+        break;
+    }
+    
+    if (debugOn) {
+      [self debugWithFormat:@"path:   %@",   handlerPath];
+      [self debugWithFormat:@"page:   %@",   pageName];
+      [self debugWithFormat:@"action: %@", actionName];
+    }
+  }
+  else {
+    if (debugOn)
+      [self debugWithFormat:@"using httpd provided pagename: %@", pageName];
+  }
+  
+  if (pageName == nil)
+    pageName = @"Main";
+  
+  if ((page = [app pageWithName:pageName inContext:context]) == nil) {
+    [self logWithFormat:
+            @"ERROR: could not create page object with name %@", pageName];
+    return nil;
+  }
+  
+  [self debugWithFormat:@"created page: %@", page];
+  
+  /* setup page context */
+  [page _awakeWithContext:context];
+  [context setPage:page];
+  
+  /* take values phase */
+  
+  [app takeValuesFromRequest:_request inContext:context];
+  
+  /* perform a direct action like action */
+  
+  result = [page performActionNamed:actionName];
+
+  /* generate response */
+  
+  if (result != page && result != nil) {
+    if ([(id)result isKindOfClass:[WOComponent class]]) {
+      [(WOComponent *)result _awakeWithContext:context];
+      [context setPage:(WOComponent *)result];
+      
+      response = [self generateResponseForComponent:(WOComponent *)result
+                       inContext:context
+                       application:app];
+    }
+    else
+      response = [result generateResponse];
+  }
+  else {
+    result = page;
+    response = [self generateResponseForComponent:page
+                     inContext:context
+                     application:app];
+  }
+  
+  if ([context hasSession]) {
+    if ([context savePageRequired])
+      [[context session] savePage:(WOComponent *)result];
+  }
+  
+  /* check whether a session was created */
+  if ((session == nil) && [context hasSession]) {
+    session = [[[context session] retain] autorelease];
+    [session lock];
+  }
+  
+  /* add session cookies to response */
+  [self addCookiesForSession:session
+        toResponse:response
+        inContext:context];
+    
+  /* store session if one was active */
+  [self saveSession:session
+        inContext:context
+        withResponse:response
+        application:app];
+  
+  return response;
+}
+
+@end /* WOPageRequestHandler */
+
+@implementation WOComponent(DirectActionExtensions)
+
+/* taking form values */
+
+- (void)takeFormValuesForKeyArray:(NSArray *)_keys {
+  NSEnumerator *keys;
+  NSString     *key;
+  WORequest    *rq;
+
+  rq   = [[self context] request];
+  keys = [_keys objectEnumerator];
+
+  while ((key = [keys nextObject]))
+    [self takeValue:[rq formValueForKey:key] forKey:key];
+}
+- (void)takeFormValuesForKeys:(NSString *)_key1,... {
+  va_list   va;
+  NSString  *key;
+  WORequest *rq;
+  
+  rq = [[self context] request];
+  va_start(va, _key1);
+  for (key = _key1; key != nil; key = va_arg(va, NSString *))
+    [self takeValue:[rq formValueForKey:key] forKey:key];
+  va_end(va);
+}
+
+/* perform actions */
+
+- (id<WOActionResults>)defaultAction {
+  return self;
+}
+
+- (id<WOActionResults>)performActionNamed:(NSString *)_actionName {
+  SEL actionSel;
+  NSRange rng;
+  
+  /* discard everything after a point in the URL */
+  rng = [_actionName rangeOfString:@"."];
+  if (rng.length > 0)
+    _actionName = [_actionName substringToIndex:rng.location];
+  
+  _actionName = [_actionName stringByAppendingString:@"Action"];
+  
+  if ((actionSel = NSSelectorFromString(_actionName)) == NULL) {
+    [self debugWithFormat:@"did not find selector for action: %@", 
+           _actionName];
+    return [self defaultAction];
+  }
+  
+  if ([self respondsToSelector:actionSel]) 
+    return [self performSelector:actionSel];
+
+  if (debugUnknownActions) {
+    [self logWithFormat:@"Page class %@ cannot handle action %@",
+            NSStringFromClass([self class]), _actionName];
+  }
+  return [self defaultAction];
+}
+
+@end /* WOComponent(DirectActionExtensions) */
diff --git a/skyrix-sope/NGObjWeb/WOProxyRequestHandler.m b/skyrix-sope/NGObjWeb/WOProxyRequestHandler.m
new file mode 100644 (file)
index 0000000..655c888
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOProxyRequestHandler.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOHTTPConnection.h>
+#include "common.h"
+
+@implementation WOProxyRequestHandler
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithHost:(NSString *)_hostName onPort:(unsigned int)_port {
+  if ((self = [super init])) {
+    self->client = 
+      [[WOHTTPConnection alloc] initWithHost:_hostName onPort:_port];
+    
+    self->rewriteHost = YES;
+  }
+  return self;
+}
+
+- (id)init {
+  return [self initWithHost:nil onPort:0];
+}
+
+- (void)dealloc {
+  [self->logFilePrefix release];
+  [self->client release];
+  [super dealloc];
+}
+
+/* settings */
+
+- (void)enableRawLogging {
+  [self logWithFormat:@"enabling raw logging ..."];
+  self->rawLogRequest  = YES;
+  self->rawLogResponse = YES;
+}
+
+- (void)setLogFilePrefix:(NSString *)_p {
+  ASSIGNCOPY(self->logFilePrefix, _p);
+}
+
+/* logging */
+
+- (void)logMessage:(WOMessage *)_msg prefix:(NSString *)_p 
+  ext:(NSString *)_ext
+{
+  NSEnumerator *keys;
+  NSString     *key;
+  FILE *fh = NULL;
+  const unsigned char *s;
+  
+  if (self->logFilePrefix) {
+    NSString *fn;
+    
+    fn = [self->logFilePrefix stringByAppendingFormat:@"%04i.%@",
+             self->rqcount, _ext];
+    if ((fh = fopen([fn cString], "w")) == NULL)
+      [self logWithFormat:@"could not open: %@", fn];
+  }
+  
+  if (_p) {
+    printf("%s", [_p cString]);
+    if (fh) fprintf(fh, "%s", [_p cString]);
+  }
+  
+  /* headers */
+  keys = [[_msg headerKeys] objectEnumerator];
+  while ((key = [keys nextObject])) {
+    NSEnumerator *vals;
+    id val;
+    
+    vals = [[_msg headersForKey:key] objectEnumerator];
+    while ((val = [vals nextObject])) {
+      s = [[val stringValue] cString];
+      printf("%s: %s\n", [key cString], s);
+      if (fh) fprintf(fh, "%s: %s\r\n", [key cString], s);
+    }
+  }
+  
+  /* content */
+  if ((s = [[_msg contentAsString] cString])) {
+    printf("\n%s\n", s);
+    if (fh) fprintf(fh, "\r\n%s", s);
+  }
+  else {
+    printf("\n");
+    if (fh) fprintf(fh, "\r\n");
+  }
+  
+  if (fh) fclose(fh);
+}
+
+- (void)logRequest:(WORequest *)_rq {
+  NSString *rl;
+  printf("PROXY REQUEST:---\n");
+  
+  rl = [NSString stringWithFormat:@"%@ %@ %@\r\n", 
+                  [_rq method], [_rq uri], [_rq httpVersion]];
+  [self logMessage:_rq prefix:rl ext:@"http"];
+  printf("---\n");
+}
+
+- (void)logResponse:(WOResponse *)_r {
+  NSString *rl;
+  printf("PROXY RESPONSE:---\n");
+  
+  rl = [NSString stringWithFormat:@"%@ %i\r\n", [_r httpVersion], [_r status]];
+  [self logMessage:_r prefix:rl ext:@"http-rs"];
+  printf("---\n");
+}
+
+/* dispatching */
+
+- (WOResponse *)failedResponse:(NSString *)_txt forRequest:(WORequest *)_rq{
+  WOResponse *r;
+
+  r = [WOResponse responseWithRequest:_rq];
+  [r setStatus:500];
+  [r appendContentHTMLString:_txt];
+  return r;
+}
+
+- (WORequest *)fixupRequest:(WORequest *)_request {
+  return _request;
+}
+- (WOResponse *)fixupResponse:(WOResponse *)_r {
+  return _r;
+}
+
+- (WORequest *)makeProxyRequest:(WORequest *)_request url:(NSURL *)_url {
+  /* this is basically a copy with a modified URI ... */
+  WORequest *rq;
+  
+  rq = [[WORequest alloc]
+        initWithMethod:[_request method]
+        uri:[_url path]
+        httpVersion:[_request httpVersion]
+        headers:[_request headers]
+        content:[_request content]
+        userInfo:[_request userInfo]];
+  return [rq autorelease];
+}
+
+- (WOResponse *)handleRequest:(WORequest *)_request {
+  WOHTTPConnection *targetClient;
+  WOResponse *r;
+  
+  self->rqcount++;
+  targetClient = self->client;
+  
+  _request = [self fixupRequest:_request];
+  
+  if ([[_request uri] hasPrefix:@"http://"]) {
+    NSURL *purl;
+    
+    purl = [NSURL URLWithString:[_request uri]];
+    [self logWithFormat:@"got a proxy request: %@", purl];
+    
+    _request = [self makeProxyRequest:_request url:purl];
+    
+    targetClient = [[WOHTTPConnection alloc] initWithHost:[purl host]
+                                            onPort:[[purl port] intValue]];
+    targetClient = [targetClient autorelease];
+  }
+  
+  if (self->rawLogRequest)
+    [self logRequest:_request];
+  
+  /* force HTTP/1.0 ... */
+  [_request setHTTPVersion:@"HTTP/1.0"];
+  
+  if (![targetClient sendRequest:_request]) {
+    [self logWithFormat:@"forwarding request to client failed."];
+    return [self failedResponse:@"forwarding request to client failed."
+                forRequest:_request];
+  }
+  
+  if ((r = [targetClient readResponse]) == nil) {
+    [self logWithFormat:@"reading response from client failed."];
+    return [self failedResponse:@"reading response from client failed."
+                forRequest:_request];
+  }
+  
+  r = [self fixupResponse:r];
+  
+  if (self->rawLogResponse)
+    [self logResponse:r];
+  
+  return r;
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return @"[proxy-handler]";
+}
+
+@end /* WOProxyRequestHandler */
diff --git a/skyrix-sope/NGObjWeb/WORequest.m b/skyrix-sope/NGObjWeb/WORequest.m
new file mode 100644 (file)
index 0000000..ad78150
--- /dev/null
@@ -0,0 +1,733 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOCookie.h>
+#include <NGHttp/NGHttp.h>
+#include "NGHttp+WO.h"
+#include <NGExtensions/NSString+Ext.h>
+#include <time.h>
+#include "common.h"
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (id)notImplemented:(SEL)cmd;
+@end
+#endif
+
+NGObjWeb_DECLARE NSString *WORequestValueData       = @"wodata";
+NGObjWeb_DECLARE NSString *WORequestValueInstance   = @"woinst";
+NGObjWeb_DECLARE NSString *WORequestValuePageName   = @"wopage";
+NGObjWeb_DECLARE NSString *WORequestValueContextID  = @"_c";
+NGObjWeb_DECLARE NSString *WORequestValueSenderID   = @"_i";
+NGObjWeb_DECLARE NSString *WORequestValueSessionID  = @"wosid";
+NGObjWeb_DECLARE NSString *WONoSelectionString      = @"WONoSelectionString";
+
+@implementation WORequest
+
+static BOOL debugOn = NO;
+
++ (int)version {
+  return [super version] + 1 /* v5 */;
+}
+
++ (NSString *)lookupLanguagesPlist {
+  NSString *apath;
+#if !COMPILE_AS_FRAMEWORK
+  NSFileManager *fm = [NSFileManager defaultManager];
+  NSDictionary  *env;
+  NSString      *relPath;
+#else
+  NSBundle *bundle;
+#endif
+  
+#if COMPILE_AS_FRAMEWORK
+  bundle = [NSBundle bundleForClass:self];
+  apath  = [bundle pathForResource:@"Languages" ofType:@"plist"];
+#else
+  env  = [[NSProcessInfo processInfo] environment];
+
+  /* 
+       TODO: the following is a dirty hack because GNUstep people decided
+             to change the directory structure. SIGH!
+  */
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY || GNUSTEP_BASE_LIBRARY
+  relPath = @"Library/Libraries";
+#else    
+  relPath = @"Libraries";
+#endif
+  relPath = [relPath stringByAppendingPathComponent:@"Resources"];
+  relPath = [relPath stringByAppendingPathComponent:@"NGObjWeb"];
+  relPath = [relPath stringByAppendingPathComponent:@"Languages.plist"];
+    
+  apath = [env objectForKey:@"GNUSTEP_USER_ROOT"];
+  apath = [apath stringByAppendingPathComponent:relPath];
+  if (![fm fileExistsAtPath:apath]) {
+    apath = [env objectForKey:@"GNUSTEP_LOCAL_ROOT"];
+    apath = [apath stringByAppendingPathComponent:relPath];
+  }
+  if (![fm fileExistsAtPath:apath]) {
+    apath = [env objectForKey:@"GNUSTEP_SYSTEM_ROOT"];
+    apath = [apath stringByAppendingPathComponent:relPath];
+  }
+  if (![fm fileExistsAtPath:apath]) {
+    apath = relPath;
+  }
+  if (![fm fileExistsAtPath:apath]) {
+    NSLog(@"ERROR: cannot find Languages.plist resource "
+         @"of NGObjWeb library !");
+  }
+#endif
+  return apath;
+}
+
++ (void)initialize {
+  static BOOL isInitialized = NO;
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  NSDictionary   *langMap;
+  NSString       *apath;
+
+  if (isInitialized) return;
+  isInitialized = YES;
+  
+  NSAssert2([super version] == 4,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  debugOn = [WOApplication isDebuggingEnabled];
+    
+  /* apply defaults on some globals ... */
+    
+  apath = [ud stringForKey:@"WORequestValueSessionID"];
+  if ([apath length] > 0)
+    WORequestValueSessionID = [apath copy];
+  apath = [ud stringForKey:@"WORequestValueInstance"];
+  if ([apath length] > 0)
+    WORequestValueInstance = [apath copy];
+  apath = [ud stringForKey:@"WONoSelectionString"];
+  if ([apath length] > 0)
+    WONoSelectionString = [apath copy];
+  
+  /* load language mappings */
+    
+  apath = [self lookupLanguagesPlist];
+  langMap = [NSDictionary dictionaryWithContentsOfFile:apath];
+  
+  if (langMap) {
+    NSDictionary *defs;
+    
+    defs = [NSDictionary dictionaryWithObject:langMap
+                        forKey:@"WOBrowserLanguageMappings"];
+    [ud registerDefaults:defs];
+  }
+  else
+    NSLog(@"WARNING: did not register browser language mappings: %@", apath);
+}
+
+/* parse URI */
+
+- (void)_parseURI {
+  unsigned uriLen;
+  char     *uriBuf;
+  char     *uri;
+  NSString *serverUrl;
+
+  uriLen = [self->_uri cStringLength];
+  
+  uriBuf = uri = malloc(uriLen + 1);
+  [self->_uri getCString:uriBuf]; uriBuf[uriLen] = '\0';
+  
+  /* determine adaptor prefix */
+
+  if ((serverUrl = [self headerForKey:@"x-webobjects-adaptor-prefix"]))
+    self->adaptorPrefix = [serverUrl copyWithZone:[self zone]];
+  
+  if (self->adaptorPrefix == nil)
+    self->adaptorPrefix = @"";
+
+    /* new parse */
+  if (uri) {
+    const char *start = NULL;
+      
+    /* skip adaptor prefix */
+    if (self->adaptorPrefix)
+      uri += [self->adaptorPrefix cStringLength];
+    if (*uri == '\0') goto done;
+
+    /* parse application name */
+      
+    uri++; // skip '/'
+    start = uri;
+    while ((*uri != '\0') && (*uri != '/') && (*uri != '.'))
+      uri++;
+
+    if (*uri == '\0') {
+      self->appName =
+        [[NSString alloc] initWithCString:start length:(uri - start)];
+      goto done;
+    }
+    else if (*uri == '.') {
+      self->appName =
+        [[NSString alloc] initWithCString:start length:(uri - start)];
+
+      // skip appname trailer (eg .woa)
+      while ((*uri != '\0') && (*uri != '/'))
+        uri++;
+      if (*uri == '\0') goto done;
+      uri++; // skip '/'
+    }
+    else if (*uri == '/') {
+      self->appName =
+        [[NSString alloc] initWithCString:start length:(uri - start)];
+      uri++; // skip '/'
+    }
+    else
+      goto done; // invalid state !
+
+    if (*uri == '\0') goto done;
+    
+    /* parse request handler key */
+    
+    start = uri;
+    while ((*uri != '\0') && (*uri != '/') && (*uri != '?'))
+      uri++;
+    self->requestHandlerKey =
+      [[NSString alloc] initWithCString:start length:(uri - start)];
+    if (*uri == '\0') goto done;
+    if(*uri == '/'){
+      uri++; // skip '/'
+      /* parse request handler path */
+      
+      start = uri;
+      while (*uri != '\0' && (*uri != '?'))
+        uri++;
+      self->requestHandlerPath =
+        [[NSString alloc] initWithCString:start length:(uri - start)];
+    }
+    
+    /* parsing done (found '\0') */
+  done:
+    ; // required for MacOSX-S
+    if (uriBuf) free(uriBuf);
+  }
+}
+
+- (id)initWithMethod:(NSString *)_method
+  uri:(NSString *)__uri
+  httpVersion:(NSString *)_version
+  headers:(NSDictionary *)_headers
+  content:(NSData *)_body
+  userInfo:(NSDictionary *)_userInfo
+{
+  if ((self = [super init])) {
+    self->_uri   = [__uri   copy];
+    self->method = [_method copy];
+    [self _parseURI];
+    
+    /* WOMessage */
+    [self setHTTPVersion:_version];
+    [self setContent:_body];
+    [self setUserInfo:_userInfo];
+    [self setHeaders:_headers];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->method release];
+  [self->_uri   release];
+  
+  [self->adaptorPrefix      release];
+  [self->requestHandlerKey  release];
+  [self->requestHandlerPath release];
+  [self->appName            release];
+  
+  [self->formContent release];
+  [self->request     release];
+  [super dealloc];
+}
+
+/* privates */
+
+- (void)_setHttpRequest:(NGHttpRequest *)_request {
+  ASSIGN(self->request, _request);
+}
+- (NGHttpRequest *)httpRequest {
+  if (self->request == nil) {
+    /* construct request 'on-demand' */
+    self->request =
+      [[NSClassFromString(@"NGHttpRequest") alloc] initWithWORequest:self];
+  }
+  return self->request;
+}
+
+/* request handler */
+
+- (void)setRequestHandlerKey:(NSString *)_key {
+  ASSIGNCOPY(self->requestHandlerKey, _key);
+}
+- (NSString *)requestHandlerKey { // new in WO4
+  if ([self isProxyRequest])
+    return @"proxy";
+  return self->requestHandlerKey;
+}
+
+- (void)setRequestHandlerPath:(NSString *)_path {
+  ASSIGNCOPY(self->requestHandlerPath, _path);
+}
+- (NSString *)requestHandlerPath { // new in WO4
+  return self->requestHandlerPath;
+}
+
+- (NSArray *)requestHandlerPathArray { // new in WO4
+  NSMutableArray *array = nil;
+  unsigned       clen;
+  char           *cstrBuf;
+  register char  *cstr;
+  
+  clen   = [self->requestHandlerPath cStringLength];
+  if (clen == 0)
+    return nil;
+  
+  cstrBuf = cstr = malloc(clen + 1);
+  [self->requestHandlerPath getCString:cstrBuf]; cstrBuf[clen] = '\0';
+  
+  do {
+    NSString *component = nil;
+    register char *tmp = cstr;
+
+    while ((*tmp != '\0') && (*tmp != '?') && (*tmp != '/'))
+      tmp++;
+    
+    component = ((tmp - cstr) == 0)
+      ? @""
+      : [[NSString alloc] initWithCString:cstr length:(tmp - cstr)];
+
+    if (component) {
+      if (array == nil) array = [NSMutableArray arrayWithCapacity:64];
+      [array addObject:component];
+      [component release]; component = nil;
+    }
+
+    cstr = tmp;
+    if (*cstr == '/') cstr++; // skip '/'
+  }
+  while ((*cstr != '\0') && (*cstr != '?'));
+
+  free(cstrBuf);
+  return [[array copy] autorelease];
+}
+
+/* WO methods */
+
+- (BOOL)isFromClientComponent {
+  return NO;
+}
+
+- (NSString *)sessionID { // deprecated in WO4
+  return [self cookieValueForKey:self->appName];
+}
+- (NSString *)senderID { // deprecated in WO4
+  IS_DEPRECATED;
+  return [[[WOApplication application] context] senderID];
+}
+
+- (NSString *)contextID {
+  return [[[WOApplication application] context] contextID];
+  //return self->contextID;
+}
+
+- (NSString *)applicationName {
+  return self->appName;
+}
+- (NSString *)applicationHost {
+  return [[NSHost currentHost] name];
+}
+
+- (NSString *)adaptorPrefix {
+  return self->adaptorPrefix;
+}
+
+- (NSString *)method {
+  return self->method;
+}
+- (void)_hackSetURI:(NSString *)_vuri {
+  /* be careful, used by the WebDAV dispatcher for ZideLook range queries */
+  ASSIGNCOPY(self->_uri, _vuri);
+}
+- (NSString *)uri {
+  return self->_uri;
+}
+- (BOOL)isProxyRequest {
+  return [[self uri] isAbsoluteURL];
+}
+
+// ******************** Forms ********************
+
+- (NSStringEncoding)formValueEncoding {
+  return NSUTF8StringEncoding;
+}
+
+- (void)setDefaultFormValueEncoding:(NSStringEncoding)_enc {
+  if (_enc != NSUTF8StringEncoding || _enc != NSASCIIStringEncoding)
+    [self notImplemented:_cmd];
+}
+- (NSStringEncoding)defaultFormValueEncoding {
+  return NSUTF8StringEncoding;
+}
+
+- (void)setFormValueEncodingDetectionEnabled:(BOOL)_flag {
+  if (_flag) [self notImplemented:_cmd];
+}
+- (BOOL)isFormValueEncodingDetectionEnabled {
+  return NO;
+}
+
+- (void)_parseQueryParameters:(NSString *)_s intoMap:(NGMutableHashMap *)_map {
+  NSEnumerator *e;
+  NSString *part;
+  
+  e = [[_s componentsSeparatedByString:@"&"] objectEnumerator];
+  while ((part = [e nextObject])) {
+    NSRange  r;
+    NSString *key, *value;
+         
+    r = [part rangeOfString:@"="];
+    if (r.length == 0) {
+      /* missing value of query parameter */
+      key   = [part stringByUnescapingURL];
+      value = @"1";
+    }
+    else {
+      key   = [[part substringToIndex:r.location] stringByUnescapingURL];
+      value = [[part substringFromIndex:(r.location + r.length)] 
+                    stringByUnescapingURL];
+    }
+    
+    [self->formContent addObject:value forKey:key];
+  }
+}
+
+- (NGHashMap *)_getFormParameters {
+  if (self->formContent) 
+    return self->formContent;
+  
+  if (self->request == nil) {
+    /*
+      TODO: add parsing of form values
+      
+      contained in URL:
+        a/blah?name=login&pwd=j
+      
+      contained in body:
+        Content-Type: application/x-www-form-urlencoded
+        browserconfig=%7BisJavaScriptEnabled%3DYES%3B%7D&login=r&button=login
+    */
+    NSRange  r;
+    NSString *query;
+    NSString *ctype;
+    BOOL     isMultiPartContent = NO, isFormContent = NO;
+    
+    r = [self->_uri rangeOfString:@"?"];
+    query = (r.length > 0)
+      ? [self->_uri substringFromIndex:(r.location + r.length)]
+      : nil;
+    
+    if ((ctype = [self headerForKey:@"content-type"]) != nil) {
+      isFormContent = [ctype hasPrefix:@"application/x-www-form-urlencoded"];
+      if (!isFormContent)
+       isMultiPartContent = [ctype hasPrefix:@"multipart/form-data"];
+    }
+    
+    if (query != nil || isFormContent || isMultiPartContent) {
+      NSAutoreleasePool *pool;
+      
+      pool = [[NSAutoreleasePool alloc] init];
+      self->formContent = [[NGMutableHashMap alloc] init];
+      
+      /* parse query string */
+      if (query)
+       [self _parseQueryParameters:query intoMap:self->formContent];
+      
+      /* parse content (if form content) */
+      if (isFormContent) {
+       [self _parseQueryParameters:[self contentAsString]
+             intoMap:self->formContent];
+      }
+      else if (isMultiPartContent) {
+       [self logWithFormat:
+               @"ERROR: missing NGHttpRequest, cannot parse multipart"];
+      }
+      
+      [pool release];
+    }
+    else
+      self->formContent = [[NGHashMap alloc] init];
+  }
+  else
+    self->formContent = [[self->request formParameters] retain];
+  return self->formContent;
+}
+
+- (NSArray *)formValueKeys {
+  id paras = [self _getFormParameters];
+  
+  if ([paras respondsToSelector:@selector(allKeys)])
+    return [paras allKeys];
+  
+  return nil;
+}
+
+- (NSString *)formValueForKey:(NSString *)_key {
+  NSString *value;
+  id paras;
+  
+  value = nil;
+  paras = [self _getFormParameters];
+  if ([paras respondsToSelector:@selector(objectForKey:)])
+    value = [(NSDictionary *)paras objectForKey:_key];
+  
+  return value;
+}
+- (NSArray *)formValuesForKey:(NSString *)_key {
+  id paras = [self _getFormParameters];
+  return [paras respondsToSelector:@selector(objectsForKey:)]
+    ? [paras objectsForKey:_key]
+    : nil;
+}
+
+- (NSDictionary *)formValues {
+  id paras;
+  
+  if ((paras = [self _getFormParameters]) == nil)
+    return nil;
+  
+  /* check class, could change with different HTTP adaptor */
+  
+  if ([paras isKindOfClass:[NGHashMap class]])
+    return [paras asDictionaryWithArraysForValues];
+  if ([paras isKindOfClass:[NSDictionary class]])
+    return paras;
+  
+  [self logWithFormat:
+         @"ERROR(%s): don't know how to deal with form object: %@", paras];
+  return nil;
+}
+
+// ******************** Headers ******************
+
+- (NSString *)languageForBrowserLanguageCode:(NSString *)_e {
+  static NSDictionary *langMap = nil;
+  NSString *lang;
+  
+  if (_e == nil) return nil;
+  
+  if (langMap == nil) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    
+    langMap = [[ud dictionaryForKey:@"WOBrowserLanguageMappings"] copy];
+    if (langMap == nil) {
+      [self debugWithFormat:
+              @"WARNING: did not find browser language mappings!"];
+    }
+  }
+  
+  _e = [_e lowercaseString];
+  
+  lang = [langMap objectForKey:_e];
+  if (lang == nil && [_e length] > 2) {
+    /* process constructs like 'de-ch' */
+    if ([_e characterAtIndex:2] == '-') {
+      NSString *ek;
+      
+      ek = [_e substringToIndex:2];
+      lang = [langMap objectForKey:ek];
+    }
+  }
+  if (lang == nil && ![_e isEqualToString:@"*"]) {
+    [self debugWithFormat:@"did not find '%@' in map: %@", 
+           _e, [[langMap allKeys] componentsJoinedByString:@", "]];
+  }
+  return lang;
+}
+
+- (NSString *)_languageFromUserAgent {
+  /*
+    user-agent sometimes stores the browser-language,
+    eg: Opera/5.0 (Linux 2.2.18 i686; U)  [en]
+  */
+  NSString *ua;
+  NSRange  rng;
+  NSString *tmp;
+  
+  if ((ua = [self headerForKey:@"user-agent"]) == nil)
+    return nil;
+
+  rng = [ua rangeOfString:@"["];
+  if (rng.length == 0)
+    return nil;
+      
+  tmp = [ua substringFromIndex:(rng.location + rng.length)];
+  rng = [tmp rangeOfString:@"]"];
+  if (rng.length > 0)
+    tmp = [tmp substringToIndex:rng.location];
+
+  return [self languageForBrowserLanguageCode:tmp];
+}
+
+- (NSArray *)browserLanguages { /* new in WO4 */
+  static NSArray *defLangs = nil;
+  NSString       *hheader;
+  NSEnumerator   *e;
+  NSMutableArray *languages;
+  NSString       *language;
+  NSString       *tmp;
+  
+  languages = [NSMutableArray arrayWithCapacity:8];
+  
+  e = [[self headersForKey:@"accept-language"] objectEnumerator];
+  while ((hheader = [e nextObject])) {
+    NSEnumerator *le;
+    
+    le = [[hheader componentsSeparatedByString:@","] objectEnumerator];
+    while ((language = [le nextObject])) {
+      NSString *tmp;
+      NSRange  r;
+      
+      /* split off the quality (eg 'en;0.96') */
+      r = [language rangeOfString:@";"];
+      if (r.length > 0)
+       language = [language substringToIndex:r.location];
+      language = [language stringByTrimmingSpaces];
+      
+      /* check in map */
+      if ((tmp = [self languageForBrowserLanguageCode:language]))
+        language = tmp;
+      
+      if ([languages containsObject:language])
+       continue;
+      
+      [languages addObject:language];
+    }
+  }
+  
+  if ((tmp = [self _languageFromUserAgent]))
+    [languages addObject:tmp];
+  
+  if (defLangs == nil) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    defLangs = [[ud arrayForKey:@"WODefaultLanguages"] copy];
+  }
+  [languages addObjectsFromArray:defLangs];
+  
+  //[self debugWithFormat:@"languages: %@", languages];
+  return [[languages copy] autorelease];
+}
+
+/* cookies */
+
+- (NSArray *)cookieValuesForKey:(NSString *)_key {
+  NSEnumerator   *ecookies;
+  NSMutableArray *values;
+  WOCookie       *cookie;
+  
+  values  = [NSMutableArray arrayWithCapacity:8];
+  
+  ecookies = [[self cookies] objectEnumerator];
+  while ((cookie = [ecookies nextObject])) {
+    if ([_key isEqualToString:[cookie name]])
+      [values addObject:[cookie value]];
+  }
+  
+  return values;
+}
+
+- (NSString *)cookieValueForKey:(NSString *)_key {
+  NSEnumerator *ecookies;
+  WOCookie     *cookie;
+  
+  ecookies = [[self cookies] objectEnumerator];
+  while ((cookie = [ecookies nextObject])) {
+    if ([_key isEqualToString:[cookie name]])
+      return [cookie value];
+  }
+  return nil;
+}
+
+- (NSDictionary *)cookieValues {
+  NSEnumerator        *ecookies;
+  NSMutableDictionary *values;
+  WOCookie            *cookie;
+  
+  values  = [NSMutableDictionary dictionaryWithCapacity:8];
+  
+  ecookies = [[self cookies] objectEnumerator];
+  while ((cookie = [ecookies nextObject])) {
+    NSString       *name;
+    NSMutableArray *vArray;
+    
+    name   = [cookie name];
+    vArray = [values objectForKey:name];
+    
+    if (vArray == nil) {
+      vArray = [[NSMutableArray alloc] initWithCapacity:8];
+      [values setObject:vArray forKey:name];
+      [vArray release];
+    }
+    
+    [vArray addObject:[cookie value]];
+  }
+  
+  return values;
+}
+
+/* logging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@"|Rq:%@ 0x%08X|", 
+                     [self method], self];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:256];
+  [str appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
+  [str appendFormat:@" method=%@",   [self method]];
+  [str appendFormat:@" uri=%@",      [self uri]];
+  [str appendFormat:@" app=%@",      self->appName];
+  [str appendFormat:@" rqKey=%@",    [self requestHandlerKey]];
+  [str appendFormat:@" rqPath=%@",   [self requestHandlerPath]];
+  [str appendString:@">"];
+  return str;
+}
+
+@end /* WORequest */
diff --git a/skyrix-sope/NGObjWeb/WORequestHandler+private.h b/skyrix-sope/NGObjWeb/WORequestHandler+private.h
new file mode 100644 (file)
index 0000000..729ad2a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WORequestHandler_private_H__
+#define __NGObjWeb_WORequestHandler_private_H__
+
+#include <NGObjWeb/WORequestHandler.h>
+#include <NGObjWeb/WORequest.h>
+
+@class WOSession, WOResponse, WOContext, WOComponent;
+
+@interface WORequestHandler(Cookies)
+
+- (void)addCookiesForSession:(WOSession *)_sn
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+
+@end
+
+@interface WORequest(DblClickBrowser)
+
+/* returns whether the user agent is one, which does two clicks per request */
+- (BOOL)isDoubleClickBrowser;
+
+@end
+
+@interface WORequestHandler(SemiPrivate)
+
+- (WOResponse *)doubleClickResponseForContext:(WOContext *)_ctx;
+
+- (void)saveSession:(WOSession *)_session
+  inContext:(WOContext *)_ctx
+  withResponse:(WOResponse *)_response
+  application:(WOApplication *)_app;
+
+- (WOResponse *)generateResponseForComponent:(WOComponent *)_component
+  inContext:(WOContext *)_ctx
+  application:(WOApplication *)_app;
+
+@end
+
+#endif /* __NGObjWeb_WORequestHandler_private_H__ */
diff --git a/skyrix-sope/NGObjWeb/WORequestHandler.m b/skyrix-sope/NGObjWeb/WORequestHandler.m
new file mode 100644 (file)
index 0000000..5c7546c
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WORequestHandler+private.h"
+#include "WOApplication+private.h"
+#include "WOContext+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOStatisticsStore.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOCookie.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSession.h>
+#include "common.h"
+
+//#define USE_POOLS 1
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (id)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+@implementation WORequestHandler
+
+static BOOL  perflog = NO;
+static Class NSDateClass = Nil;
+
++ (int)version {
+  return 2;
+}
++ (void)initialize {
+  NSDateClass = [NSDate class];
+  perflog = [[NSUserDefaults standardUserDefaults]
+                             boolForKey:@"WOProfileRequestHandler"];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    if ([[[NSUserDefaults standardUserDefaults]
+                          objectForKey:@"WORunMultithreaded"]
+                          boolValue]) {
+      self->lock = [[NSRecursiveLock alloc] init];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->lock release];
+  [super dealloc];
+}
+
+/* request handling */
+
+- (BOOL)restoreSessionUsingIDs {
+  /* restore a session if an ID was given */
+  return YES;
+}
+- (BOOL)autocreateSessionForRequest:(WORequest *)_request {
+  /* autocreate a session if none was restored */
+  return NO;
+}
+- (BOOL)requiresSessionForRequest:(WORequest *)_request {
+  /* _ensure_ that a session is available */
+  return NO;
+}
+
+- (NSString *)sessionIDFromRequest:(WORequest *)_request
+  application:(WOApplication *)_app
+{
+  NSString *sid;
+  
+  if ((sid = [_app sessionIDFromRequest:_request]) == nil)
+    return nil;
+  
+#if DEBUG
+  NSAssert1([sid isKindOfClass:[NSString class]],
+            @"invalid session ID: %@", sid);
+#endif
+  return sid;
+}
+
+- (WOResponse *)handleRequest:(WORequest *)_request
+  inContext:(WOContext *)context
+  session:(WOSession *)session
+  application:(WOApplication *)app
+{
+  return [self subclassResponsibility:_cmd];
+}
+
+- (BOOL)doesRejectFavicon {
+  return YES;
+}
+
+- (WOResponse *)handleRequest:(WORequest *)_request {
+  NSTimeInterval    startHandling = 0.0;
+#if USE_POOLS
+  NSAutoreleasePool *pool = nil;
+#endif
+  WOApplication *app;
+  WOResponse    *response   = nil;
+  WOContext     *context    = nil;
+  NSThread      *thread;
+  NSMutableDictionary *threadDict;
+  NSString      *sessionId  = nil;
+  WOSession     *session    = nil;
+  NSString *uri;
+  
+  /* first check URI for favicon requests ... */
+  uri = [_request uri];
+  if ([self doesRejectFavicon] && uri != nil) {
+    if ([@"/favicon.ico" isEqualToString:uri]) {
+      response = [WOResponse responseWithRequest:_request];
+      [response setStatus:404 /* not found */];
+      [self debugWithFormat:@"rejected favicon request: %@", uri];
+      return response;
+    }
+  }
+  
+  if (perflog)
+    startHandling = [[NSDateClass date] timeIntervalSince1970];
+  
+  thread = [NSThread currentThread];
+  NSAssert(thread, @"missing current thread ...");
+  threadDict = [thread threadDictionary];
+  NSAssert(threadDict, @"missing current thread's dictionary ...");
+  
+  if (_request == nil) return nil;
+
+  *(&app) = nil;
+  app = [WOApplication application];
+  
+#if USE_POOLS
+  *(&pool) = [[NSAutoreleasePool alloc] init];
+#endif
+  {
+    /* setup context */
+    context = [WOContext contextWithRequest:_request];
+    NSAssert(context,    @"no context assigned ..");
+    NSAssert(threadDict, @"missing current thread's dictionary ...");
+    [threadDict setObject:context forKey:@"WOContext"];
+    
+    /* check session id */
+    *(&session)   = nil;
+    *(&sessionId) = [self sessionIDFromRequest:_request application:app];
+    
+    if ([sessionId length] == 0)
+      sessionId = nil;
+    else if ([sessionId isEqualToString:@"nil"])
+      sessionId = nil;
+    
+    NS_DURING {
+      [app awake];
+      
+      /* retrieve session */
+      if ([self restoreSessionUsingIDs]) {
+        SYNCHRONIZED(app) {
+          if (sessionId) {
+            session = [app restoreSessionWithID:sessionId
+                           inContext:context];
+            if (session == nil) {
+              response  = [app handleSessionRestorationErrorInContext:context];
+              sessionId = nil;
+            }
+          }
+        }
+        END_SYNCHRONIZED;
+        
+        [[session retain] autorelease];
+        
+        if (response)
+          /* some kind of error response from above ... */
+          goto responseDone;
+        
+        /* check double click browser cache ... */
+        if ((response = [self doubleClickResponseForContext:context]))
+          goto responseDone;
+        
+        if (session == nil) {
+          /* session autocreation .. */
+          if ([self autocreateSessionForRequest:_request]) {
+            if (![app isRefusingNewSessions]) {
+              session = [app _initializeSessionInContext:context];
+
+              [self logWithFormat:@"autocreated session: %@", session];
+              
+              if (session == nil)
+                response =[app handleSessionRestorationErrorInContext:context];
+            }
+            else { /* app refuses new sessions */
+              [self logWithFormat:@"app is refusing new sessions ..."];
+              response = [app handleSessionRestorationErrorInContext:context];
+            }
+          }
+          if (response)
+            /* some kind of error response from above ... */
+            goto responseDone;
+          
+          /* check whether session is required ... */
+          if ([self requiresSessionForRequest:_request] && (session == nil)) {
+            response = [app handleSessionCreationErrorInContext:context];
+            goto responseDone;
+          }
+        }
+      }
+      
+      [session lock];
+      
+      NS_DURING {
+        response = [self handleRequest:_request
+                         inContext:context
+                         session:session
+                         application:app];
+        
+        session = ([context hasSession])
+          ? [context session]
+          : nil;
+        
+        if (session) {
+          if ([session storesIDsInCookies]) {
+            [self addCookiesForSession:session
+                  toResponse:response
+                  inContext:context];
+          }
+          
+          [self saveSession:session
+                inContext:context
+                withResponse:response
+                application:app];
+        }
+      }
+      NS_HANDLER {
+        response = [app handleException:localException inContext:context];
+      }
+      NS_ENDHANDLER;
+      
+      [session unlock];
+      
+    responseDone:
+      [session _sleepWithContext:context];
+      response = [response retain];
+      
+      [app sleep];
+    }  
+    NS_HANDLER {
+      response = [app handleException:localException inContext:context];
+      response = [response retain];
+    }
+    NS_ENDHANDLER;
+    
+    NSAssert(threadDict, @"missing current thread's dictionary ...");
+    [threadDict removeObjectForKey:@"WOContext"];
+  }
+#if USE_POOLS
+  [pool release]; pool = nil;
+#endif
+
+  [app lock];
+  if ([app isRefusingNewSessions] &&
+      ([app activeSessionsCount] < [app minimumActiveSessionsCount])) {
+    [self debugWithFormat:
+            @"application terminates because it refuses new sessions and "
+            @"the active session count (%i) is below the minimum (%i).",
+            [app activeSessionsCount], [app minimumActiveSessionsCount]];
+    [app terminate];
+  }
+  [app unlock];
+  
+  if (perflog) {
+    NSTimeInterval rt;
+    rt = [[NSDateClass date] timeIntervalSince1970] - startHandling;
+    [self debugWithFormat:@"handleRequest took %4.3fs.", rt < 0.0 ? -1.0 : rt];
+  }
+  
+  return [response autorelease];
+}
+
+/* locking */
+
+- (void)lock {
+  [self->lock lock];
+}
+- (void)unlock {
+  [self->lock unlock];
+}
+
+/* KVC */
+
+- (id)valueForUndefinedKey:(NSString *)_key {
+  [self debugWithFormat:@"queried undefined KVC key (returning nil): '%@'",
+         _key];
+  return nil;
+}
+
+@end /* WORequestHandler */
+
+@implementation WORequestHandler(Cookies)
+
+- (void)addCookiesForSession:(WOSession *)_sn
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if ([_sn storesIDsInCookies]) {
+    WOApplication *app;
+    NSString *cookieName = nil;
+    WOCookie *cookie     = nil;
+    NSString *uri;
+    NSString *value;
+    
+    app        = [WOApplication application];
+    cookieName = [app name];
+
+    {
+      NSString *tmp;
+      
+      if ((uri = [[_ctx request] applicationName]) == nil)
+        uri = [app name];
+      uri = [@"/" stringByAppendingString:uri];
+      
+      if ((tmp = [[_ctx request] adaptorPrefix]))
+        uri = [tmp stringByAppendingString:uri];
+    }
+
+#if 0
+    uri = [_ctx urlSessionPrefix];
+    uri = [_ctx urlWithRequestHandlerKey:
+                  [WOApplication componentRequestHandlerKey]
+                path:@"/"
+                queryString:nil];
+#endif
+    
+    value = [_sn isTerminating]
+      ? (id)@"nil"
+      : [_sn sessionID];
+    
+    cookie = [WOCookie cookieWithName:cookieName
+                       value:value
+                       path:uri
+                       domain:[_sn domainForIDCookies]
+                       expires:[_sn expirationDateForIDCookies]
+                       isSecure:NO];
+    if (cookie)
+      [_response addCookie:cookie];
+  }
+}
+
+@end /* WORequestHandler(Cookies) */
+
+@implementation WORequest(DblClickBrowser)
+
+- (BOOL)isDoubleClickBrowser {
+  NSString *ua;
+  
+  if ((ua = [self headerForKey:@"user-agent"]) == nil)
+    return NO;
+
+  if ([ua rangeOfString:@"Konqueror"].length > 0)
+    return YES;
+  else if ([ua rangeOfString:@"MSIE"].length > 0)
+    return [ua rangeOfString:@"Mac"].length > 0 ? YES : NO;
+  else
+    return NO;
+}
+
+@end /* WORequest(DblClickBrowser) */
+
+@implementation WORequestHandler(Support)
+
+- (WOResponse *)doubleClickResponseForContext:(WOContext *)_ctx {
+  /* HACK check for duplicate requests send out by Konqueror and MacIE */
+  WORequest *rq;
+  NSArray *hack; /* 0: uri, 1: response */
+
+  rq = [_ctx request];
+  
+  if (![rq isDoubleClickBrowser])
+    return nil;
+
+  if (![_ctx hasSession])
+    return nil;
+  
+  /* look into page cache */
+  hack = [(WOSession *)[_ctx session] objectForKey:@"_lastResponseCacheHack"];
+  if (hack == nil)
+    return nil;
+  
+  if ([[hack objectAtIndex:0] isEqualToString:[rq uri]]) {
+    [[WOApplication application]
+                    logWithFormat:
+                      @"using response from dblclick cache hack ..."];
+    return [hack objectAtIndex:1];
+  }
+  
+  return nil;
+}
+
+- (void)saveSession:(WOSession *)_session
+  inContext:(WOContext *)_ctx
+  withResponse:(WOResponse *)_response
+  application:(WOApplication *)_app
+{
+  static BOOL perflog = NO;
+  NSTimeInterval startSaveSn = 0.0;
+  
+  if (_session == nil) return;
+
+  if (perflog)
+    startSaveSn = [[NSDate date] timeIntervalSince1970];
+  
+  [_app saveSessionForContext:_ctx];
+  
+  /* store response if strange double-click browser */
+  if (_response) {
+    if ([[_ctx request] isDoubleClickBrowser]) {
+      NSArray *hack; /* 0: uri, 1: response */
+      
+      hack = [NSArray arrayWithObjects:[[_ctx request] uri], _response, nil];
+      [_session setObject:hack forKey:@"_lastResponseCacheHack"];
+    }
+  }
+
+  if (perflog) {
+    NSTimeInterval rt;
+    rt = [[NSDate date] timeIntervalSince1970] - startSaveSn;
+    NSLog(@"[rq]: saving of session took %4.3fs.",
+          rt < 0.0 ? -1.0 : rt);
+  }
+}
+
+- (void)_fixupResponse:(WOResponse *)_response {
+  NSString *ctype;
+  NSString *cntype = nil;
+  
+  if ((ctype = [_response headerForKey:@"content-type"]) == nil) {
+    NSData *body;
+    
+    ctype = @"text/html";
+    
+    body = [_response content];
+    if ([body length] > 6) {
+      const unsigned char *bytes;
+
+      if ((bytes = [body bytes])) {
+        if ((bytes[0] == '<') && (bytes[1] == '?')) {
+          if ((bytes[2] == 'x') && (bytes[3] == 'm') && (bytes[4] == 'l'))
+            ctype = @"text/xml";
+        }
+      }
+    }
+    
+    [_response setHeader:ctype forKey:@"content-type"];
+  }
+
+  if ([ctype isEqualToString:@"text/html"]) {
+    switch ([_response contentEncoding]) {
+      case NSISOLatin1StringEncoding:
+        cntype = [ctype stringByAppendingString:@"; charset=iso-8859-1"];
+        break;
+      case NSUTF8StringEncoding:
+        cntype = [ctype stringByAppendingString:@"; charset=utf-8"];
+        break;
+       
+      default:
+        break;
+    }
+  }
+  if (cntype)
+    [_response setHeader:cntype forKey:@"content-type"];
+}
+
+- (WOResponse *)generateResponseForComponent:(WOComponent *)_component
+  inContext:(WOContext *)_ctx
+  application:(WOApplication *)_app
+{
+  WOResponse *response;
+  
+  if (_component == nil) return nil;
+  
+  /* make the component the "response page" */
+  [_ctx setPage:_component];
+  
+  if ([_ctx hasSession]) {
+    response = [_ctx response];
+    [_app appendToResponse:response inContext:_ctx];
+  }
+  else {
+    //[self logWithFormat:@"generating component using -generateResponse"];
+    response = [_component generateResponse];
+    
+    /* generate statistics */
+    [[_app statisticsStore]
+           recordStatisticsForResponse:response
+           inContext:_ctx];
+  }
+  
+  [self _fixupResponse:response];
+  return response;
+}
+
+@end /* WORequestHandler(Support) */
diff --git a/skyrix-sope/NGObjWeb/WOResourceManager.m b/skyrix-sope/NGObjWeb/WOResourceManager.m
new file mode 100644 (file)
index 0000000..b347b9a
--- /dev/null
@@ -0,0 +1,1124 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOResourceManager.h>
+#include "WOComponentDefinition.h"
+#include "WOComponent+private.h"
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+#import <Foundation/NSNull.h>
+#include "_WOStringTable.h"
+
+/*
+  Component Discovery and Page Creation
+
+    All WO code uses either directly or indirectly the WOResourceManager's
+    -pageWithName:languages: method to instantiate WO components.
+
+    This methods works in three steps:
+      
+      1. discovery of files associated with the component
+      
+      2. creation of a proper WOComponentDefinition, which is some kind
+         of 'blueprint' or 'class' for components
+      
+      3. component instantiation using the definition
+    
+    All the instantiation/setup work is done by a component definition, the
+    resource manager is only responsible for managing those 'blueprint'
+    resources.
+
+    If you want to customize component creation, you can supply your
+    own WOComponentDefinition in a subclass of WOResourceManager by
+    overriding:
+      - (WOComponentDefinition *)definitionForComponent:(id)_name
+        inFramework:(NSString *)_frameworkName
+        languages:(NSArray *)_languages
+*/
+
+/* 
+   Note: this was #if !COMPILE_FOR_GSTEP_MAKE - but there is no difference
+         between Xcode and gstep-make?!
+        The only possible difference might be that .wo wrappers are directly
+        in the bundle/framework root - but this doesn't relate to Resources.
+        
+        OK, this breaks gstep-make based template lookup which places .wo
+        wrappers in .woa/Resources/xxx.wo.
+        This is an issue because .wox are looked up in Contents/Resources
+        but .wo ones in just Resources.
+        
+        This issue should be fixed in recent woapp-gs.make ...
+*/
+#if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
+#  define RSRCDIR_CONTENTS 1
+#endif
+
+@implementation WOResourceManager
+
++ (int)version {
+  return 4;
+}
+
+static Class    UrlClass             = Nil;
+static NSString *resourcePrefix      = @"";
+static NSString *rapidTurnAroundPath = nil;
+static NSNull   *null                = nil;
+static BOOL     debugOn                 = NO;
+static BOOL     debugComponentLookup    = NO;
+static BOOL     debugResourceLookup     = NO;
+static BOOL     genMissingResourceLinks = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL isInitialized = NO;
+  NSDictionary *defs;
+  if (isInitialized) return;
+  isInitialized = YES;
+    
+  null = [[NSNull null] retain];
+  UrlClass = [NSURL class];
+  
+  defs = [NSDictionary dictionaryWithObjectsAndKeys:
+                         [NSArray arrayWithObject:@"wo"],
+                         @"WOComponentExtensions",
+                       nil];
+  [ud registerDefaults:defs];
+  debugOn                 = [WOApplication isDebuggingEnabled];
+  debugComponentLookup    = [ud boolForKey:@"WODebugComponentLookup"];
+  debugResourceLookup     = [ud boolForKey:@"WODebugResourceLookup"];
+  genMissingResourceLinks = [ud boolForKey:@"WOGenerateMissingResourceLinks"];
+  rapidTurnAroundPath     = [[ud stringForKey:@"WOProjectDirectory"] copy];
+}
+
+static inline BOOL
+_pathExists(WOResourceManager *self, NSFileManager *fm, NSString *path)
+{
+  BOOL doesExist;
+  
+  if (self->existingPathes && (path != nil)) {
+    int i;
+    
+    i = (int)NSMapGet(self->existingPathes, path);
+    if (i == 0) {
+      doesExist = [fm fileExistsAtPath:path];
+      NSMapInsert(self->existingPathes, path, (void*)(doesExist ? 1 : 0xFF));
+    }
+    else
+      doesExist = i == 1 ? YES : NO;
+  }
+  else
+    doesExist = [fm fileExistsAtPath:path];
+  return doesExist;
+}
+
++ (void)setResourcePrefix:(NSString *)_prefix {
+  [resourcePrefix autorelease];
+  resourcePrefix = [_prefix copy];
+}
+  
+- (id)initWithPath:(NSString *)_path {
+#if __APPLE__
+  if ([_path length] == 0) {
+    NSLog(@"ERROR(%s): missing path!", __PRETTY_FUNCTION__);
+    /* this doesn't work with subclasses which do not require a path ... */
+#if 0
+    [self release];
+    return nil;
+#endif
+  }
+#endif
+  
+  if ((self = [super init])) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    NSString *rprefix = nil;
+    NSString *tmp;
+    
+    self->componentDefinitions =
+      NSCreateMapTable(NSObjectMapKeyCallBacks,
+                       NSObjectMapValueCallBacks,
+                       128);
+    self->stringTables = 
+      NSCreateMapTable(NSObjectMapKeyCallBacks,
+                       NSObjectMapValueCallBacks,
+                       16);
+    
+    tmp = [_path stringByStandardizingPath];
+    if (tmp) _path = tmp;
+    
+    self->base = [_path copy];
+    
+    if ([WOApplication isCachingEnabled]) {
+      self->existingPathes = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                              NSIntMapValueCallBacks,
+                                              256);
+    }
+    
+    rprefix = [ud stringForKey:@"WOResourcePrefix"];
+    if (rprefix) [[self class] setResourcePrefix:rprefix];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithPath:[[NGBundle mainBundle] bundlePath]];
+}
+
+- (void)dealloc {
+  if (self->existingPathes)       NSFreeMapTable(self->existingPathes);
+  if (self->stringTables)         NSFreeMapTable(self->stringTables);
+  if (self->componentDefinitions) NSFreeMapTable(self->componentDefinitions);
+  if (self->keyedResources)       NSFreeMapTable(self->keyedResources);
+  [self->w3resources release];
+  [self->resources   release];
+  [self->base        release];
+  [super dealloc];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+/* path methods */
+
+- (NSFileManager *)fileManager {
+  static NSFileManager *fm = nil;
+  if (fm == nil)
+    fm = [[NSFileManager defaultManager] retain];
+  return fm;
+}
+
+- (NSString *)basePath {
+  return self->base;
+}
+
+- (NSString *)resourcesPath {
+  NSFileManager *fm;
+  
+  if (self->resources)
+    return self->resources;
+  
+  fm = [self fileManager];
+  if ([self->base length] > 0) {
+    if (![fm fileExistsAtPath:self->base]) {
+      NSLog(@"WARNING(%s): Resources base path '%@' does not exist !",
+            __PRETTY_FUNCTION__, self->base);
+      return nil;
+    }
+  }
+  
+#if RSRCDIR_CONTENTS
+  if ([rapidTurnAroundPath length] > 0) {
+    /* 
+      In rapid turnaround mode, first check for a Resources subdir in the
+      project directory, then directly in the project dir.
+      Note: you cannot have both! Either put stuff in a Resources subdir *or*
+            in the project dir.
+    */
+    NSString *tmp;
+    BOOL isDir;
+    
+    tmp = [rapidTurnAroundPath stringByAppendingPathComponent:@"Resources"];
+    if (![fm fileExistsAtPath:tmp isDirectory:&isDir])
+      isDir = NO;
+    if (!isDir)
+      tmp = rapidTurnAroundPath;
+    
+    self->resources = [tmp copy];
+  }
+  else {
+    self->resources =
+      [[[self->base stringByAppendingPathComponent:@"Contents"]
+                    stringByAppendingPathComponent:@"Resources"] 
+                    copy];
+  }
+#else
+  self->resources =
+    [[self->base stringByAppendingPathComponent:@"Resources"] copy];
+#endif
+  
+  if ([self->resources length] > 0) {
+    if (![fm fileExistsAtPath:self->resources]) {
+      [self debugWithFormat:
+              @"WARNING(%s): Resources path %@ does not exist !",
+              __PRETTY_FUNCTION__, self->resources];
+      [self->resources release]; self->resources = nil;
+    }
+    else if (self->existingPathes && (self->resources != nil))
+      NSMapInsert(self->existingPathes, self->resources, (void*)1);
+  }
+  return self->resources;
+}
+
+- (NSString *)resourcesPathForFramework:(NSString *)_fw {
+  if (_fw == nil) 
+    return [self resourcesPath];
+  
+#if RSRCDIR_CONTENTS
+  return [[_fw stringByAppendingPathComponent:@"Contents"]
+               stringByAppendingPathComponent:@"Resources"];
+#else
+  return [_fw stringByAppendingPathComponent:@"Resources"];
+#endif
+}
+
+- (NSString *)webServerResourcesPath {
+  NSFileManager *fm;
+  
+  if (self->w3resources)
+    return self->w3resources;
+
+#if GNUSTEP_BASE_LIBRARY && 0
+  self->w3resources =
+    [[self->base stringByAppendingPathComponent:@"Resources/WebServer"] copy];
+#else  
+  self->w3resources =
+    [[self->base stringByAppendingPathComponent:@"WebServerResources"] copy];
+#endif
+  
+  fm = [self fileManager];
+  if ([self->w3resources length] == 0)
+    return nil;
+  
+  if (![fm fileExistsAtPath:self->w3resources]) {
+    static BOOL didLog = NO;
+    if (!didLog) {
+      didLog = YES;
+      [self debugWithFormat:
+              @"WARNING(%s): WebServerResources path '%@' does not exist !",
+              __PRETTY_FUNCTION__, self->w3resources];
+    }
+    [self->w3resources release]; self->w3resources = nil;
+  }
+  else if (self->existingPathes && (self->w3resources != nil))
+    NSMapInsert(self->existingPathes, self->w3resources, (void*)1);
+  
+  if (debugResourceLookup)
+    [self logWithFormat:@"WebServerResources: '%@'", self->w3resources];
+  return self->w3resources;
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages
+{
+  NSFileManager *fm;
+  NSString      *resource = nil;
+  unsigned      langCount;
+  NSString      *w3rp, *rp;
+  
+  if (debugResourceLookup) {
+    [self logWithFormat:@"lookup '%@' bundle=%@ languages=%@", 
+          _name, _frameworkName, [_languages componentsJoinedByString:@","]];
+  }
+  
+  fm        = [self fileManager];
+  langCount = [_languages count];
+  
+  if ((w3rp = [self webServerResourcesPath])) {
+    NSString *langPath = nil;
+    unsigned i;
+    
+    // first check Language.lproj in WebServerResources
+    for (i = 0; i < langCount; i++) {
+      langPath = [_languages objectAtIndex:i];
+      langPath = [langPath stringByAppendingPathExtension:@"lproj"];
+      langPath = [w3rp stringByAppendingPathComponent:langPath];
+      
+      if (!_pathExists(self, fm, langPath)) {
+        if (debugResourceLookup) {
+          [self logWithFormat:
+                  @"  no language project for '%@' in WebServerResources: %@",
+                  [_languages objectAtIndex:i],resource];
+        }
+        continue;
+      }
+      
+      resource = [langPath stringByAppendingPathComponent:_name];
+      
+      if (debugResourceLookup) 
+        [self logWithFormat:@"  check in WebServerResources: %@", resource];
+      if (_pathExists(self, fm, resource))
+        return resource;
+    }
+    
+    /* next check in WebServerResources itself */
+    resource = [w3rp stringByAppendingPathComponent:_name];
+    if (debugResourceLookup) 
+      [self logWithFormat:@"  check in WebServerResources-flat: %@", resource];
+    if (_pathExists(self, fm, resource))
+      return resource;
+  }
+  
+  if ((rp = [self resourcesPathForFramework:_frameworkName])) {
+    NSString *langPath = nil;
+    unsigned i;
+    
+    if (debugResourceLookup) [self logWithFormat:@"  path %@", rp];
+    
+    // first check Language.lproj in Resources
+    for (i = 0; i < langCount; i++) {
+      langPath = [_languages objectAtIndex:i];
+      langPath = [langPath stringByAppendingPathExtension:@"lproj"];
+      langPath = [rp stringByAppendingPathComponent:langPath];
+      
+      if (_pathExists(self, fm, langPath)) {
+        resource = [langPath stringByAppendingPathComponent:_name];
+
+        if (debugResourceLookup) 
+          [self logWithFormat:@"  check in Resources: %@", resource];
+        if (_pathExists(self, fm, resource))
+          return resource;
+      }
+    }
+    
+    // next check in Resources itself
+    resource = [rp stringByAppendingPathComponent:_name];
+    if (debugResourceLookup) 
+      [self logWithFormat:@"  check in Resources-flat: %@", resource];
+    if (_pathExists(self, fm, resource))
+      return resource;
+  }
+  
+  /* and last check in the application directory */
+  if (_pathExists(self, fm, self->base)) {
+    resource = [self->base stringByAppendingPathComponent:_name];
+    if (_pathExists(self, fm, resource))
+      return resource;
+  }
+  return nil;
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name {
+  IS_DEPRECATED;
+  return [self pathForResourceNamed:_name inFramework:nil languages:nil];
+}
+
+- (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
+  _name = [_name stringByAppendingPathExtension:_type];
+  return [self pathForResourceNamed:_name];
+}
+
+/* URL methods */
+
+- (NSString *)urlForResourceNamed:(NSString *)_name
+  inFramework:(NSString *)_frameworkName
+  languages:(NSArray *)_languages
+  request:(WORequest *)_request
+{
+  WOApplication *app;
+  NSString *resource = nil, *tmp;
+  
+  app = [WOApplication application];
+  
+  if (_languages == nil)
+    _languages = [_request browserLanguages];
+  
+  resource = [self pathForResourceNamed:_name
+                   inFramework:_frameworkName
+                   languages:_languages];
+#if RSRCDIR_CONTENTS
+  if ([resource rangeOfString:@"/Contents/"].length > 0) {
+    resource = [resource stringByReplacingString:@"/Contents"
+                         withString:@""];
+  }
+#endif
+#if 0
+  tmp = [resource stringByStandardizingPath];
+  if (tmp) resource = tmp;
+#endif
+  
+  if (resource) {
+    NSString *path = nil, *sbase;
+    unsigned len;
+    
+    sbase = self->base;
+    tmp  = [sbase commonPrefixWithString:resource options:0];
+    
+    len  = [tmp length];
+    path = [sbase    substringFromIndex:len];
+    tmp  = [resource substringFromIndex:len];
+    if (([path length] > 0) && ![tmp hasPrefix:@"/"] && ![tmp hasPrefix:@"\\"])
+      path = [path stringByAppendingString:@"/"];
+    path = [path stringByAppendingString:tmp];
+
+#ifdef __WIN32__
+    {
+      NSArray *cs;
+      cs   = [path componentsSeparatedByString:@"\\"];
+      path = [cs componentsJoinedByString:@"/"];
+    }
+#endif
+    
+    if (path) {
+      static NSString *suffix = nil;
+      NSMutableString *url = nil;
+
+      if (suffix == nil) {
+       NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+        suffix = [ud stringForKey:@"WOApplicationSuffix"];
+      }
+      
+      url = [[NSMutableString alloc] initWithCapacity:256];
+#if 0
+      [url appendString:[_request adaptorPrefix]];
+#endif
+      if (resourcePrefix)
+        [url appendString:resourcePrefix];
+      if (![url hasSuffix:@"/"]) [url appendString:@"/"];
+      [url appendString:app ? [app name] : [_request applicationName]];
+      [url appendString:suffix];
+      if (![path hasPrefix:@"/"]) [url appendString:@"/"];
+      [url appendString:path];
+      
+      path = [url copy];
+      [url release];
+      
+      return [path autorelease];
+    }
+  }
+  
+  if (genMissingResourceLinks) {
+    return [NSString stringWithFormat:
+                       @"/missingresource?name=%@&application=%@",
+                       _name, app ? [app name] : [_request applicationName]];
+  }
+  return nil;
+}
+
+- (NSString *)urlForResourceNamed:(NSString *)_name {
+  IS_DEPRECATED;
+  return [self urlForResourceNamed:_name
+               inFramework:nil
+               languages:nil
+               request:nil];
+}
+- (NSString *)urlForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
+  return [self urlForResourceNamed:
+                 [_name stringByAppendingPathExtension:_type]];
+}
+
+/* string tables */
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_defaultValue
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_languages;
+{
+  NSFileManager  *fm;
+  _WOStringTable *table     = nil;
+  NSString       *path      = nil;
+  
+  fm = [self fileManager];
+  
+  if (_tableName == nil)
+    _tableName = @"default";
+
+  /* take a look whether a matching table is already loaded */
+  
+  path = [_tableName stringByAppendingPathExtension:@"strings"];
+  path = [self pathForResourceNamed:path inFramework:_framework 
+               languages:_languages];
+  
+  if (path != nil) {
+    if ((table = NSMapGet(self->stringTables, path)) == NULL) {
+      if ([fm fileExistsAtPath:path]) {
+       table = [_WOStringTable allocWithZone:[self zone]]; /* for gcc */
+        table = [table initWithPath:path];
+        NSMapInsert(self->stringTables, path, table);
+        [table release];
+      }
+    }
+    if (table != nil)
+      return [table stringForKey:_key withDefaultValue:_defaultValue];
+  }
+  /* didn't found table in cache */
+  
+  return _defaultValue;
+}
+
+- (NSString *)stringForKey:(NSString *)_key
+  inTableNamed:(NSString *)_tableName
+  withDefaultValue:(NSString *)_default
+  languages:(NSArray *)_languages
+{
+  return [self stringForKey:_key inTableNamed:_tableName
+               withDefaultValue:_default
+               inFramework:nil
+               languages:_languages];
+}
+
+
+/* NSLocking */
+
+- (void)lock {
+}
+- (void)unlock {
+}
+
+/* component definitions */
+
+- (NSString *)pathToComponentNamed:(NSString *)_name
+  inFramework:(NSString *)_framework
+{
+  /* search for component wrapper .. */
+  NSEnumerator *e;
+  NSString     *ext;
+  
+  if (_name == nil) {
+#if DEBUG
+    NSLog(@"WARNING(%s): tried to get path to component with <nil> name !",
+          __PRETTY_FUNCTION__);
+#endif
+    return nil;
+  }
+  
+  /* scan for name.$ext resource ... */
+  e = [[[NSUserDefaults standardUserDefaults]
+                        arrayForKey:@"WOComponentExtensions"]
+                        objectEnumerator];
+    
+  while ((ext = [e nextObject])) {
+    NSString *specName;
+    NSString *path;
+      
+    specName = [_name stringByAppendingPathExtension:ext];
+      
+    path = [self pathForResourceNamed:specName
+                 inFramework:_framework
+                 languages:nil];
+    if (path) return path;
+  }
+  return nil;
+}
+
+- (NSString *)pathToComponentNamed:(NSString *)_name
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_langs
+{
+  return [self pathToComponentNamed:_name inFramework:_framework];
+}
+
+- (WOComponentDefinition *)_definitionForPathlessComponent:(NSString *)_name
+  languages:(NSArray *)_languages
+{
+  /* definition factory */
+  WOComponentDefinition *cdef;
+  
+  cdef = [[WOComponentDefinition allocWithZone:[self zone]]
+                                 initWithName:_name
+                                 path:nil
+                                 baseURL:nil
+                                 frameworkName:nil];
+  
+  return [cdef autorelease];
+}
+
+- (WOComponentDefinition *)_definitionWithName:(NSString *)_name
+  url:(NSURL *)_url
+  baseURL:(NSURL *)_baseURL
+  frameworkName:(NSString *)_fwname
+{
+  /* definition factory */
+  static Class DefClass;
+  id cdef;
+  
+  if (DefClass == Nil)
+    DefClass = [WOComponentDefinition class];
+  
+  cdef = [[DefClass alloc] initWithName:_name
+                           path:[_url path]
+                           baseURL:_baseURL frameworkName:_fwname];
+  return cdef;
+}
+- (WOComponentDefinition *)_definitionWithName:(NSString *)_name
+  path:(NSString *)_path
+  baseURL:(NSURL *)_baseURL
+  frameworkName:(NSString *)_fwname
+{
+  NSURL *url;
+  
+  url = ([_path length] > 0)
+    ? [[[NSURL alloc] initFileURLWithPath:_path] autorelease]
+    : nil;
+  
+  return [self _definitionWithName:_name url:url
+               baseURL:_baseURL frameworkName:_fwname];
+}
+
+- (WOComponentDefinition *)_cachedDefinitionForComponent:(id)_name
+  languages:(NSArray *)_languages
+{
+  NSArray *cacheKey;
+  id      cdef;
+
+  if (self->componentDefinitions == NULL)
+    return nil;
+  if (![[WOApplication application] isCachingEnabled])
+    return nil;
+  
+  cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
+  cdef     = NSMapGet(self->componentDefinitions, cacheKey);
+  
+  return cdef;
+}
+- (WOComponentDefinition *)_cacheDefinition:(id)_cdef
+  forComponent:(id)_name
+  languages:(NSArray *)_languages
+{
+  NSArray *cacheKey;
+
+  if (self->componentDefinitions == NULL)
+    return _cdef;
+  if (![[WOApplication application] isCachingEnabled])
+    return _cdef;
+  
+  cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
+  NSMapInsert(self->componentDefinitions, cacheKey, _cdef ? _cdef : null);
+
+  return _cdef;
+}
+
+- (NSString *)resourceNameForComponentNamed:(NSString *)_name {
+  return [_name stringByAppendingPathExtension:@"wox"];
+}
+
+- (WOComponentDefinition *)definitionForComponent:(id)_name
+  inFramework:(NSString *)_framework
+  languages:(NSArray *)_languages
+{
+  WOApplication         *app;
+  NSFileManager         *fm            = nil;
+  NSEnumerator          *languages     = nil;
+  NSString              *language      = nil;
+  WOComponentDefinition *cdef          = nil;
+  NSString              *sname         = nil;
+  NSURL                 *componentURL;
+  NSURL                 *appUrl;
+  BOOL                  doesCache, isDir;
+  
+  app       = [WOApplication application];
+  doesCache = [app isCachingEnabled];
+  
+  /* lookup component path */
+  
+  if ([_name isKindOfClass:UrlClass]) {
+    componentURL = _name;
+    _name = [componentURL path];
+    if (debugComponentLookup) {
+      [self debugWithFormat:@"using URL %@ for component %@",
+              componentURL, _name];
+    }
+  }
+  else {
+    NSString *path;
+    
+    if (_framework == nil && _name != nil) {
+      Class clazz;
+      
+      /* 
+         Note: this is a bit of a hack ..., actually this method should never
+         be called without a framework and pages shouldn't be instantiated
+         without specifying their framework.
+         But for legacy reasons this needs to be done and seems to work without
+         problems. It is required for loading components from bundles.
+      */
+      if ((_framework = rapidTurnAroundPath) == nil) {
+        if ((clazz = NSClassFromString(_name)))
+          _framework = [[NSBundle bundleForClass:clazz] bundlePath];
+      }
+    }
+    
+    if (debugComponentLookup) {
+      [self logWithFormat:@"component '%@' in framework '%@'", 
+              _name, _framework];
+    }
+    
+    /* look for .wox component */
+    
+    path = [self pathForResourceNamed:
+                   [self resourceNameForComponentNamed:_name]
+                 inFramework:_framework
+                 languages:_languages];
+    
+    if (debugComponentLookup)
+      [self logWithFormat:@"  path: '%@'", path];
+    
+    /* look for .wo component */
+    
+    if ([path length] == 0) {
+      path = [self pathToComponentNamed:_name
+                   inFramework:_framework
+                   languages:_languages];
+      if (debugComponentLookup)
+        [self logWithFormat:@"  path: '%@'", path];
+    }
+    
+    /* make URL from path */
+    
+    componentURL = ([path length] > 0)
+      ? [[[UrlClass alloc] initFileURLWithPath:path] autorelease]
+      : nil;
+  }
+  
+  if (debugComponentLookup) {
+    [self logWithFormat:@"  component='%@' in framework='%@': url='%@'", 
+            _name, _framework, componentURL];
+  }
+  
+  appUrl = [app baseURL];
+  
+  /* check whether it's a 'template-less' component ... */
+  
+  if (componentURL == nil) {
+    /* did not find component wrapper ! */
+    [app debugWithFormat:@"  component '%@' has no template !", _name];
+    
+    cdef = [self _definitionForPathlessComponent:_name languages:_languages];
+    return cdef;
+  }
+  
+  fm = [self fileManager];
+  
+  /* ensure that the component exists */
+
+  if ([componentURL isFileURL]) {
+    NSString *componentPath;
+    
+    componentPath = [componentURL path];
+    
+    if (![fm fileExistsAtPath:componentPath isDirectory:&isDir]) {
+      [[WOApplication application]
+                      debugWithFormat:
+                        @"%s: did not find component '%@' at path '%@' !",
+                        __PRETTY_FUNCTION__,
+                        _name, componentPath];
+      return cdef;
+    }
+  
+    /* if the component spec is a directory (eg a .wo), scan inside for stuff */
+    
+    if (isDir) {
+      languages = [_languages objectEnumerator];
+      
+      while ((language = [languages nextObject])) {
+        NSString *compoundKey  = nil;
+        NSString *languagePath = nil;
+        BOOL     isDirectory   = NO;
+        
+        if (sname == nil) sname = [_name stringByAppendingString:@"\t"];
+        compoundKey = [sname stringByAppendingString:language];
+        
+        if (doesCache) {
+          cdef = NSMapGet(self->componentDefinitions, compoundKey);
+          
+          if (cdef == (id)null)
+            /* resource does not exist */
+            continue;
+          
+          [cdef touch];
+          if (cdef) return cdef; // found definition in cache
+        }
+        
+        /* take a look into the file system */
+        languagePath = [language stringByAppendingPathExtension:@"lproj"];
+        languagePath = [componentPath stringByAppendingPathComponent:languagePath];
+        
+        if ([fm fileExistsAtPath:languagePath isDirectory:&isDirectory]) {
+          NSString *baseUrl = nil;
+          
+          if (!isDirectory) {
+            NSLog(@"WARNING(%s): language entry %@ is not a directory !",
+                  __PRETTY_FUNCTION__, languagePath);
+            if (doesCache && (compoundKey != nil)) {
+              // register null in cache, so that we know it's non-existent
+              NSMapInsert(self->componentDefinitions, compoundKey, null);
+            }
+            continue;
+          }
+          
+          baseUrl = [NSString stringWithFormat:@"%@/%@.lproj/%@.wo",
+                                [appUrl absoluteString], language, _name];
+          
+          /* found appropriate language project */
+          cdef = [self _definitionWithName:_name
+                       path:languagePath
+                       baseURL:[NSURL URLWithString:baseUrl]
+                       frameworkName:nil];
+          if (cdef == nil) {
+            NSLog(@"WARNING(%s): could not load component definition of "
+                  @"'%@' from language project: %@", 
+                  __PRETTY_FUNCTION__, _name, languagePath);
+            if (doesCache && (compoundKey != nil)) {
+              // register null in cache, so that we know it's non-existent
+              NSMapInsert(self->componentDefinitions, compoundKey, null);
+            }
+            continue;
+          }
+    
+          if (doesCache && (compoundKey != nil)) {
+            // register in cache
+            NSMapInsert(self->componentDefinitions, compoundKey, cdef);
+            [cdef release];
+          }
+          else {
+            // don't register in cache
+            cdef = [cdef autorelease];
+          }
+
+          return cdef;
+        }
+        else {
+          if (doesCache) {
+            // register null in cache, so that we know it's non-existent
+            NSMapInsert(self->componentDefinitions, compoundKey, null);
+          }
+        }
+      }
+    }
+  }
+  
+  /* look flat */
+    
+  if (doesCache) {
+    cdef = NSMapGet(self->componentDefinitions, componentURL);
+      
+    if (cdef == (id)null)
+      /* resource does not exist */
+      return nil;
+    [cdef touch];
+      
+    if (cdef) return cdef; // found definition in cache
+  }
+  
+  /* take a look into the file system */
+  {
+    NSString *baseUrl = nil;
+    
+    baseUrl = [NSString stringWithFormat:@"%@/%@",
+                          [appUrl absoluteString], [_name lastPathComponent]];
+    
+    cdef = [self _definitionWithName:_name
+                 url:componentURL
+                 baseURL:[NSURL URLWithString:baseUrl]
+                 frameworkName:nil];
+    if (cdef == nil) {
+      NSLog(@"WARNING(%s): could not load component definition of '%@' from "
+            @"component wrapper: '%@'", 
+            __PRETTY_FUNCTION__, _name, componentURL);
+      if (doesCache) {
+        /* register null in cache, so that we know it's non-existent */
+        NSMapInsert(self->componentDefinitions, componentURL, null);
+      }
+      return nil;
+    }
+    
+    if (doesCache) {
+      /* register in cache */
+      NSMapInsert(self->componentDefinitions, componentURL, cdef);
+      [cdef release];
+    }
+    else
+      /* don't register in cache, does not cache */
+      cdef = [cdef autorelease];
+
+    return cdef;
+  }
+  
+  /* did not find component */
+  return nil;
+}
+- (WOComponentDefinition *)definitionForComponent:(id)_name
+  languages:(NSArray *)_langs
+{
+  return [self definitionForComponent:_name inFramework:nil languages:_langs];
+}
+
+- (WOComponentDefinition *)__definitionForComponent:(id)_name
+  languages:(NSArray *)_languages
+{
+  WOComponentDefinition *cdef;
+  
+  /* look into cache */
+  
+  cdef = [self _cachedDefinitionForComponent:_name languages:_languages];
+  if (cdef) {
+    if (cdef == (id)null)
+      /* component does not exist */
+      return nil;
+
+    if ([cdef respondsToSelector:@selector(touch)])
+      [cdef touch];
+    return cdef;
+  }
+  
+  /* not cached, create a definition */
+  
+  cdef = [self definitionForComponent:_name languages:_languages];
+
+  /* cache created definition */
+  
+  return [self _cacheDefinition:cdef forComponent:_name languages:_languages];
+}
+
+- (WOElement *)templateWithName:(NSString *)_name
+  languages:(NSArray *)_languages
+{
+  WOComponentDefinition *cdef;
+  
+  cdef = [self __definitionForComponent:_name languages:_languages];
+  if (cdef == nil) return nil;
+  
+  return (WOElement *)[cdef template];
+}
+
+- (WOComponent *)pageWithName:(NSString *)_name
+  languages:(NSArray *)_languages
+{
+  /* 
+     TODO: this appears to be deprecated since the WOComponent initializer
+           is now -initWithContext: and we have no context here ...
+  */
+  NSAutoreleasePool     *pool      = nil;
+  WOComponentDefinition *cdef      = nil;
+  WOComponent           *component = nil;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    cdef = [self __definitionForComponent:_name languages:_languages];
+    if (cdef) {
+      component =
+        [cdef instantiateWithResourceManager:self languages:_languages];
+      component = [component retain];
+    }
+  }
+  [pool release];
+  
+  return [component autorelease];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: path=%@>",
+                     [self class], self, self->base];
+                   
+}
+
+@end /* WOResourceManager */
+
+@implementation WOResourceManager(KeyedData)
+
+- (void)setData:(NSData *)_data
+  forKey:(NSString *)_key
+  mimeType:(NSString *)_type
+  session:(WOSession *)_session
+{
+  if ((_key == nil) || (_data == nil))
+    return;
+  if (_type == nil)
+    _type = @"application/octet-stream";
+  
+  [self lock];
+  
+  if (self->keyedResources == NULL) {
+    self->keyedResources = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                            NSObjectMapValueCallBacks,
+                                            128);
+  }
+
+  NSMapInsert(self->keyedResources,
+              _key,
+              [NSDictionary dictionaryWithObjectsAndKeys:
+                              _type, @"mimeType",
+                              _key,  @"key",
+                              _data, @"data",
+                            nil]);
+  
+  [self unlock];
+}
+
+- (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid {
+  id tmp;
+
+  [self lock];
+  
+  if (self->keyedResources)
+    tmp = NSMapGet(self->keyedResources, _key);
+  else
+    tmp = nil;
+  
+  tmp = [[tmp retain] autorelease];
+  
+  [self unlock];
+
+  return tmp;
+}
+
+- (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session {
+  [self lock];
+  
+  if (self->keyedResources)
+    NSMapRemove(self->keyedResources, _key);
+  
+  [self unlock];
+}
+
+- (void)flushDataCache {
+  [self lock];
+
+  if (self->keyedResources) {
+    NSFreeMapTable(self->keyedResources);
+    self->keyedResources = NULL;
+  }
+  
+  [self unlock];
+}
+
+@end /* WOResourceManager(KeyedData) */
+
+@implementation WOResourceManager(JavaScript)
+
+- (id)_jsfunc_pathForResourceNamed:(NSArray *)_args {
+  unsigned argc = [_args count];
+  
+  return [self pathForResourceNamed:
+                 argc > 0 ? [_args objectAtIndex:0] : nil
+               inFramework:argc > 1 ? [_args objectAtIndex:1] : nil
+               languages:argc > 2 ? [_args objectAtIndex:2] : nil];
+}
+
+- (id)_jsfunc_loadPropertyListNamed:(NSArray *)_args {
+  NSString *s;
+  
+  if ((s = [self _jsfunc_pathForResourceNamed:_args]) == nil)
+    return nil;
+  
+  if ((s = [NSString stringWithContentsOfFile:s]) == nil)
+    return nil;
+
+  return [s propertyList];
+}
+
+@end /* WOResourceManager(JavaScript) */
diff --git a/skyrix-sope/NGObjWeb/WOResourceRequestHandler.m b/skyrix-sope/NGObjWeb/WOResourceRequestHandler.m
new file mode 100644 (file)
index 0000000..ef6d526
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WORequestHandler.h>
+
+@interface WOResourceRequestHandler : WORequestHandler
+@end
+
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include "common.h"
+
+@interface WOResourceManager(PrivateKeyedAccess)
+
+- (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid;
+
+@end
+
+@implementation WOResourceRequestHandler
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (WOResponse *)_handleWebServerResourcesRequest:(WORequest *)_request {
+  WOApplication *app;
+  NSArray       *handlerPath = nil;
+  WOResponse    *response   = nil;
+  NSArray       *languages;
+  NSString      *resourceName;
+  NSString      *resourcePath;
+  NSData        *data;
+  
+  if (_request == nil) return nil;
+  
+  *(&app)     = [WOApplication application];
+  handlerPath = [_request requestHandlerPathArray];
+  
+  /* check for WebServerResources requests ... */
+  
+  if ([handlerPath count] < 1)
+    return nil;
+  
+  /* ok, found a resource request */
+
+  if ([handlerPath count] > 1) {
+    NSString *lang;
+    
+    lang      = [handlerPath objectAtIndex:0];
+    lang      = [lang stringByDeletingPathExtension];
+    languages = [NSArray arrayWithObject:lang];
+    languages = [languages arrayByAddingObjectsFromArray:languages];
+    
+    resourceName = [handlerPath objectAtIndex:1];
+  }
+  else {
+    languages    = [_request browserLanguages];
+    resourceName = [handlerPath objectAtIndex:0];
+  }
+  
+  resourcePath = [[app resourceManager]
+                       pathForResourceNamed:resourceName
+                       inFramework:nil
+                       languages:languages];
+
+  data = resourcePath
+    ? [NSData dataWithContentsOfFile:resourcePath]
+    : nil;
+  
+  if (data == nil) {
+    response = [WOResponse responseWithRequest:_request];
+    [response setStatus:404]; /* not found */
+    return nil;
+  }
+  
+  //NSLog(@"shall deliver %@", resourcePath);
+  
+  response = [WOResponse responseWithRequest:_request];
+  
+  /* determine content-type */
+  {
+    NSString *ctype;
+    NSString *pathExtension;
+    
+    pathExtension = [resourcePath pathExtension];
+    ctype         = @"application/octet-stream";
+    
+    if ([pathExtension isEqualToString:@"html"])
+      ctype = @"text/html";
+    else if ([pathExtension isEqualToString:@"gif"])
+      ctype = @"image/gif";
+    
+    [response setHeader:ctype forKey:@"content-type"];
+  }
+  
+  [response setContent:data];
+  
+  return response;
+}
+
+- (WOResponse *)handleRequest:(WORequest *)_request {
+  NSArray *handlerPath = nil;
+  
+  if ([[_request requestHandlerKey] isEqualToString:@"WebServerResources"])
+    return [self _handleWebServerResourcesRequest:_request];
+
+  handlerPath = [_request requestHandlerPathArray];
+  
+  if ([handlerPath count] > 0) {
+    NSString *rmkey;
+    
+    rmkey = [handlerPath objectAtIndex:0];
+    if ([rmkey length] > 0) {
+      WOResourceManager *rm;
+      id data;
+      
+      rm = [[WOApplication application] resourceManager];
+      
+      if ((data = [rm _dataForKey:rmkey sessionID:nil])) {
+        WOResponse *response;
+        
+        response = [WOResponse responseWithRequest:_request];
+        [response setHeader:[data objectForKey:@"mimeType"]
+                  forKey:@"content-type"];
+        [response setContent:[data objectForKey:@"data"]];
+        return response;
+      }
+      else {
+        [[WOApplication application]
+                        logWithFormat:@"WOResourceRequestHandler: "
+                          @"didn't find data for resource key '%@'",
+                          rmkey];
+      }
+    }
+  }
+  
+  /* if everything fails, try locating resource in WebServerResources */
+  return [self _handleWebServerResourcesRequest:_request];
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return @"[resource-handler]";
+}
+
+@end /* WOResourceRequestHandler */
diff --git a/skyrix-sope/NGObjWeb/WOResponse+private.h b/skyrix-sope/NGObjWeb/WOResponse+private.h
new file mode 100644 (file)
index 0000000..0271353
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WOResponse_private_H__
+#define __NGObjWeb_WOResponse_private_H__
+
+#include <NGObjWeb/WOResponse.h>
+
+// fast inline functions (non-WO)
+
+#define WOResponse_AddChar(__R__,__C__) \
+  if (__R__) {__R__->addChar(__R__, @selector(appendContentCharacter:), __C__);}
+
+#define WOResponse_AddString(__R__,__C__) \
+  if (__R__) {__R__->addStr(__R__, @selector(appendContentString:), __C__);}
+#define WOResponse_AddCString(__R__,__C__) \
+  if (__R__) {__R__->addCStr(__R__, @selector(appendContentCString:), __C__);}
+
+#define WOResponse_AddHtmlString(__R__,__C__) \
+  if (__R__) {__R__->addHStr(__R__, @selector(appendContentHTMLString:), __C__);}
+
+// TODO: performance ! - use static buffer and appendContentCString !
+
+#define WOResponse_AddUInt(__R__,__C__) \
+  if (__R__) {\
+    switch(__C__) {\
+      case 0: __R__->addCStr(__R__, @selector(appendContentCString:),"0");break;\
+      case 1: __R__->addCStr(__R__, @selector(appendContentCString:),"1");break;\
+      case 2: __R__->addCStr(__R__, @selector(appendContentCString:),"2");break;\
+      case 3: __R__->addCStr(__R__, @selector(appendContentCString:),"3");break;\
+      case 4: __R__->addCStr(__R__, @selector(appendContentCString:),"4");break;\
+      default: {\
+        char buf[12]; sprintf(buf,"%d", __C__); \
+        __R__->addCStr(__R__, @selector(appendContentCString:), buf);}\
+    }\
+  }
+
+#define WOResponse_AddInt(__R__,__C__) \
+  if (__R__) {\
+    switch(__C__) {\
+      case 0: __R__->addCStr(__R__, @selector(appendContentCString:),"0");break;\
+      case 1: __R__->addCStr(__R__, @selector(appendContentCString:),"1");break;\
+      case 2: __R__->addCStr(__R__, @selector(appendContentCString:),"2");break;\
+      case 3: __R__->addCStr(__R__, @selector(appendContentCString:),"3");break;\
+      case 4: __R__->addCStr(__R__, @selector(appendContentCString:),"4");break;\
+      default: {\
+        char buf[12]; sprintf(buf,"%i", __C__); \
+        __R__->addCStr(__R__, @selector(appendContentCString:), buf);}\
+    }\
+  }
+
+#endif /* __NGObjWeb_WOResponse_private_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOResponse.m b/skyrix-sope/NGObjWeb/WOResponse.m
new file mode 100644 (file)
index 0000000..411bcb0
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOCookie.h>
+#include <NGExtensions/NSData+gzip.h>
+#include <EOControl/EOControl.h>
+#include "common.h"
+
+@implementation WOResponse
+
+static Class         NSStringClass = Nil;
+static unsigned char OWDefaultZipLevel = 3;
+static unsigned int  OWMinimumZipSize  = 1024;
+static BOOL          dontZip  = NO;
+static BOOL          debugZip = NO;
+
++ (int)version {
+  return [super version] + 1 /* v5 */;
+}
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  NSAssert2([super version] == 4,
+           @"invalid superclass (%@) version %i !",
+           NSStringFromClass([self superclass]), [super version]);
+  
+  dontZip  = [ud boolForKey:@"WODontZipResponse"];
+  debugZip = [ud boolForKey:@"WODebugZipResponse"];
+}
+
++ (WOResponse *)responseWithRequest:(WORequest *)_request {
+  return [[(WOResponse *)[self alloc] initWithRequest:_request] autorelease];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    [self setStatus:200];
+    [self setHTTPVersion:@"HTTP/1.0"];
+    //[self setHeader:@"text/html" forKey:@"content-type"];
+  }
+  return self;
+}
+
+- (id)initWithRequest:(WORequest *)_request {
+  if ((self = [self init])) {
+    // don't fake being the request protocol, but rather stay to the truth ;-)
+    // [self setHTTPVersion:[_request httpVersion]];
+  }
+  return self;
+}
+
+/* HTTP */
+
+- (void)setStatus:(unsigned int)_status {
+  self->status = _status;
+}
+- (unsigned int)status {
+  return self->status;
+}
+
+/* client caching */
+
+static __inline__ unsigned char *weekdayName(int dow) {
+  switch (dow) {
+    case 0: return "Sun"; case 1: return "Mon"; case 2: return "Tue";
+    case 3: return "Wed"; case 4: return "Thu"; case 5: return "Fri";
+    case 6: return "Sat"; case 7: return "Sun";
+    default: return "UNKNOWN DAY OF WEEK !";
+  }
+}
+static __inline__ unsigned char *monthName(int m) {
+  switch (m) {
+    case  1:  return "Jan"; case  2:  return "Feb"; case  3:  return "Mar";
+    case  4:  return "Apr"; case  5:  return "May"; case  6:  return "Jun";
+    case  7:  return "Jul"; case  8:  return "Aug"; case  9:  return "Sep";
+    case 10:  return "Oct"; case 11:  return "Nov"; case 12:  return "Dec";
+    default: return "UNKNOWN MONTH !";
+  }
+}
+
+- (void)disableClientCaching {
+  /*
+    OSX Prof: 7.1% of WOSession -appendToResponse !
+  */
+  /* HTTP/1.1 caching directive, prevents browser from caching dynamic pages */
+  static NSTimeZone *gmt = nil;
+  
+  if (gmt == nil) gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+#if DEBUG && 0
+  [self logWithFormat:@"disabled client caching: %@ ..", self];
+#endif
+  
+  /*
+    Set expire time to one hour before now to catch inconsitencies between
+    client and server time. Not using -description of NSCalendarDate to
+    avoid locales and to improve performance.
+  */
+  {
+    NSCalendarDate *now;
+    NSString *s;
+    unsigned char buf[32];
+    
+    now = [[NSCalendarDate alloc] initWithTimeIntervalSinceNow:-3600.0];
+    [now setTimeZone:gmt];
+    
+    sprintf(buf, "%s, %02i %s %04i %02i:%02i:%02i GMT",
+            weekdayName([now dayOfWeek]),
+            [now dayOfMonth], 
+            monthName([now monthOfYear]),
+            [now yearOfCommonEra],
+            [now hourOfDay], [now minuteOfHour], [now secondOfMinute]);
+    [now release];
+    
+    s = [[NSString alloc] initWithCString:buf];
+    [self setHeader:s forKey:@"expires"];
+    [s release];
+  }
+  [self setHeader:@"no-cache" forKey:@"cache-control"];
+  [self setHeader:@"no-cache" forKey:@"pragma"];
+}
+
+/* WO methods */
+
+- (NSString *)contentString {
+  NSString *s;
+  
+  if (NSStringClass == Nil)
+    NSStringClass = [NSString class];
+  
+  s = [[NSStringClass alloc] initWithData:[self content]
+                             encoding:[self contentEncoding]];
+  return [s autorelease];
+}
+
+/* WOActionResults */
+
+- (WOResponse *)generateResponse {
+  return self;
+}
+
+/* zipping */
+
+- (BOOL)shouldZipResponseToRequest:(WORequest *)_rq {
+  NSString *contentType;
+  NSString *acceptEncoding;
+  id       body;
+  
+  if (dontZip) {
+    if (debugZip) [self logWithFormat:@"Zipping of response disabled"];
+    return NO;
+  }
+  
+  if ((body = [self content]) == nil)  
+    return NO;
+  if (![body isKindOfClass:[NSData class]])
+    return NO;
+  if ([body length] < OWMinimumZipSize) {
+    if (debugZip) {
+      [self logWithFormat:
+             @"content length is below minimum size for zipping (%i vs %i)",
+             [body length], OWMinimumZipSize];
+    }
+    return NO;
+  }
+  
+  contentType = [self headerForKey:@"content-type"];
+  
+  if ([self headerForKey:@"content-encoding"] != nil) {
+    /* already applied some content-encoding */
+    if (debugZip)
+      [self logWithFormat:@"Do not zip, already has a 'content-encoding'!"];
+    return NO;
+  }
+  if ([contentType hasPrefix:@"application"]) {
+    /* browser often seem to have problems with zipped bodies */
+    if (debugZip)
+      [self logWithFormat:@"Do not zip, is 'application/' MIME type."];
+    return NO;
+  }
+  if ([contentType hasPrefix:@"image"]) {
+    /* do not zip images (usually already compressed ...) */
+    if (debugZip)
+      [self logWithFormat:@"Do not zip, is an image."];
+    return NO;
+  }
+  
+  if (_rq == nil)
+    return YES;
+  
+  acceptEncoding = [[_rq headerForKey:@"accept-encoding"] stringValue];
+  if (acceptEncoding == nil) {
+    if (debugZip) {
+      [self logWithFormat:
+             @"Do not zip, browser sent no 'accept-encoding' header."];
+    }
+    return NO;
+  }
+  // TODO: improve naive parsing of accept header
+  if ([acceptEncoding rangeOfString:@"gzip"].length == 0) {
+    if (debugZip) {
+      [self logWithFormat:
+             @"Do not zip, browser does not understand 'gzip' encoding: %@",
+             acceptEncoding];
+    }
+    return NO;
+  }
+  return YES;
+}
+
+- (NSData *)zipResponse {
+  NSMutableDictionary *ui;
+  NSNumber *zlen;
+  NSData *zipped = nil;
+  int    len;
+  id     body;
+  
+  if ((body = [self content]) == nil) return nil;
+  
+  len = [body length];
+
+  /* zip body data */
+  
+  if ((zipped = [body gzipWithLevel:OWDefaultZipLevel]) == nil) {
+    if (debugZip)
+      [self logWithFormat:@"gzip refused to zip body ..."];
+    return body;
+  }
+  
+  /* check if it's smaller */
+  if ((int)[zipped length] >= len) {
+    if (debugZip) {
+      [self logWithFormat:
+             @"zipped length is larger than raw length (%i vs %i)",
+             [zipped length], len];
+    }
+    return body; /* it's not */
+  }
+  
+  /* it is smaller .. */
+      
+  if (debugZip) {
+    [self logWithFormat:
+           @"zipped content %i => %i bytes (gain: %-.2g%%).",
+           len, [zipped length],
+            (double)(100.0 - (((double)[zipped length]) /
+                              (((double)len) / 100.0)))];
+  }
+  
+  body = zipped;
+  [self setHeader:@"gzip" forKey:@"content-encoding"];
+
+  /* statistics */
+  
+  if ((ui = [[self userInfo] mutableCopy]) == nil)
+    ui = [[NSMutableDictionary alloc] initWithCapacity:2];
+  
+  [ui setObject:zipped forKey:@"WOZippedContent"];
+  zlen = [NSNumber numberWithUnsignedInt:len];
+  [ui setObject:zlen   forKey:@"WOResponseUnzippedLength"];
+  zlen = [NSNumber numberWithUnsignedInt:[zipped length]];
+  [ui setObject:zlen   forKey:@"WOResponseZippedLength"];
+  
+  [self setUserInfo:ui];
+  [ui release]; ui = nil;
+  [self setContent:zipped];
+  
+  return zipped;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  NSData *data;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self,
+        NSStringFromClass((Class)*(void**)self)];
+  
+  [ms appendFormat:@" status=%i",  [self status]];
+  [ms appendFormat:@" headers=%@", [self headers]];
+
+  if ((data = [self content])) {
+    if ([data length] == 0)
+      [ms appendString:@" empty-content"];
+    else
+      [ms appendFormat:@" content-size=%i", [data length]];
+  }
+  else
+    [ms appendString:@" no-content"];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* WOResponse */
diff --git a/skyrix-sope/NGObjWeb/WORunLoop.h b/skyrix-sope/NGObjWeb/WORunLoop.h
new file mode 100644 (file)
index 0000000..06d9cd6
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_WORunLoop_H__
+#define __NGObjWeb_WORunLoop_H__
+
+#import <Foundation/Foundation.h>
+
+#if LIB_FOUNDATION_LIBRARY
+
+#define WORunLoop NSRunLoop
+
+#else
+
+#include <NGExtensions/NSRunLoop+FileObjects.h>
+#define WORunLoop NSRunLoop
+
+#endif
+
+#endif /* __NGObjWeb_WORunLoop_H__ */
diff --git a/skyrix-sope/NGObjWeb/WORunLoop.m b/skyrix-sope/NGObjWeb/WORunLoop.m
new file mode 100644 (file)
index 0000000..68a2139
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WORunLoop.h"
+#include "common.h"
+
+#if 0
+#if !LIB_FOUNDATION_LIBRARY && !APPLE_Foundation_LIBRARY && !NeXT_Foundation_LIBRARY
+
+#ifndef CREATE_AUTORELEASE_POOL
+#  define CREATE_AUTORELEASE_POOL(pool) \
+            id pool = [[NSAutoreleasePool alloc] init]
+#endif
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <errno.h>
+
+#include <sys/time.h>  /* for struct timeval */
+#include <string.h>
+#include <memory.h>
+#include <libc.h>
+#include <unistd.h>
+#include <sys/select.h>
+
+#include "WORunLoop.h"
+#import <Foundation/Foundation.h>
+
+#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY
+#  include <FoundationExt/objc-runtime.h>
+#else
+#  include <extensions/objc-runtime.h>
+#endif
+
+#if 0
+#warning breaks AppKit, should *extend* NSRunLoop on MacOSX
+@implementation NSRunLoop(Override)
++ (NSRunLoop *)currentRunLoop {
+  return [WORunLoop currentRunLoop];
+}
+@end
+#endif
+
+#if 0
+typedef enum {
+    NSPosixNoActivity = 0,
+    NSPosixReadableActivity = 1,
+    NSPosixWritableActivity = 2,
+    NSPosixExceptionalActivity = 4
+} NSPosixFileActivities;
+#endif
+
+NSString* NSFileObjectBecameActiveNotificationName =
+  @"NSFileObjectBecameActiveNotificationName";
+
+static char *activityDesc[8] = {
+    "---", // 0
+    "--R", // 1
+    "-W-", // 2
+    "-WR", // 3
+    "E--", // 4
+    "E-R", // 5
+    "EW-", // 6
+    "EWR"  // 7
+};
+
+@interface WORunLoopFileObjectInfo : NSObject
+{
+    id                    fileObject;
+    NSPosixFileActivities watchedActivities;
+    BOOL                  canCheckAlive;
+}
+
+- (id)initWithFileObject:(id)_fileObject
+  activities:(NSPosixFileActivities)_activities;
+
+- (BOOL)isAlive;
+- (int)fileDescriptor;
+- (NSPosixFileActivities)watchedActivities;
+
+- (void)activity:(NSPosixFileActivities)_activity onDescriptor:(int)_fd;
+
+@end
+
+@implementation WORunLoopFileObjectInfo
+
+- (id)initWithFileObject:(id)_fileObject
+  activities:(NSPosixFileActivities)_activities
+{
+  self->fileObject        = RETAIN(_fileObject);
+  self->watchedActivities = _activities;
+  self->canCheckAlive     = [_fileObject respondsToSelector:@selector(isAlive)];
+  return self;
+}
+- (id)init
+{
+      NSLog(@"ERROR: do not use init with WORunLoopFileObjectInfo ..");
+      AUTORELEASE(self);
+      return nil;
+}
+
+- (void)dealloc
+{
+    RELEASE(self->fileObject); self->fileObject = nil;
+    [super dealloc];
+}
+
+- (BOOL)isEqual:(WORunLoopFileObjectInfo*)otherInfo
+{
+    return [self->fileObject isEqual:otherInfo->fileObject];
+}
+
+- (BOOL)isAlive {
+    return (self->canCheckAlive) ? [self->fileObject isAlive] : YES;
+}
+- (int)fileDescriptor
+{
+    return [self->fileObject fileDescriptor];
+}
+
+- (NSPosixFileActivities)watchedActivities
+{
+    return self->watchedActivities;
+}
+
+- (void)activity:(NSPosixFileActivities)_activity onDescriptor:(int)_fd
+{
+    //NSLog(@"FileObject %@ was active ..", self->fileObject);
+    
+    [[NSNotificationCenter defaultCenter]
+                           postNotificationName:
+                             NSFileObjectBecameActiveNotificationName
+                           object:self->fileObject];
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:
+                       @"<%@[0x%08X]: object=%@ actitivity=%s>",
+                       NSStringFromClass([self class]), self,
+                       self->fileObject,
+                       activityDesc[self->watchedActivities]
+                     ];
+}
+
+@end
+
+@interface WORunLoopTimerInfo : NSObject
+{
+    NSTimer* timer;
+    NSDate* fireDate;
+}
+
++ (WORunLoopTimerInfo*)infoWithTimer:(NSTimer*)timer;
+- (void)recomputeFireDate;
+- (NSComparisonResult)compare:(WORunLoopTimerInfo*)anObject;
+- (NSTimer*)timer;
+- (NSDate*)fireDate;
+@end
+
+@implementation WORunLoopTimerInfo
+
++ (WORunLoopTimerInfo*)infoWithTimer:(NSTimer*)aTimer
+{
+    WORunLoopTimerInfo* info = [self new];
+
+    info->timer    = RETAIN(aTimer);
+    info->fireDate = RETAIN([aTimer fireDate]);
+    return AUTORELEASE(info);
+}
+
+- (void)dealloc
+{
+    RELEASE(timer);
+    RELEASE(fireDate);
+    [super dealloc];
+}
+
+- (void)recomputeFireDate
+{
+  if ([timer isValid]) {
+    id tmp = [timer fireDate];
+    ASSIGN(fireDate, tmp);
+  }
+}
+
+- (NSComparisonResult)compare:(WORunLoopTimerInfo*)anObject
+{
+    return [fireDate compare:anObject->fireDate];
+}
+
+- (NSTimer*)timer                      { return timer; }
+- (NSDate*)fireDate                    { return fireDate; }
+
+@end
+
+@interface WORunLoopActionHolder : NSObject
+{
+    id target;
+    id argument;
+    SEL action;
+    int order;
+}
++ objectWithTarget:(id)target
+  argument:(id)argument
+  selector:(SEL)action
+  order:(int)order;
+- (BOOL)isEqual:(id)anotherHolder;
+- (void)execute;
+@end
+
+@implementation WORunLoopActionHolder
+
++ objectWithTarget:(id)_target
+  argument:(id)_argument
+  selector:(SEL)_action
+  order:(int)_order
+{
+    WORunLoopActionHolder* holder = AUTORELEASE([self alloc]);
+
+    holder->target = RETAIN(_target);
+    holder->argument = RETAIN(_argument);
+    holder->action = _action;
+    holder->order = _order;
+
+    return holder;
+}
+
+- (unsigned)hash
+{
+  return [(NSObject*)target hash];
+}
+
+- (BOOL)isEqual:(WORunLoopActionHolder*)anotherHolder
+{
+    return [target isEqual:anotherHolder->target]
+           && [argument isEqual:anotherHolder->argument]
+           && SEL_EQ(action, anotherHolder->action);
+}
+
+- (void)execute
+{
+    [target performSelector:action withObject:argument];
+}
+
+- (NSComparisonResult)compare:(WORunLoopActionHolder*)anotherHolder
+{
+    return order - anotherHolder->order;
+}
+
+@end
+
+
+@interface WORunLoopInputManager : NSObject
+{
+    NSMutableArray* fileObjects;
+    NSMutableArray* timers;
+    NSMutableArray* otherOperations;
+}
+
+- (void)addFileObject:(id)_fileObject
+  activities:(NSPosixFileActivities)_activities;
+- (void)removeFileObject:(id)_fileObject;
+
+- (void)addTimer:(NSTimer*)aTimer;
+
+- (NSMutableArray*)fileObjects;
+- (NSMutableArray*)timers;
+
+- (void)addOperation:(WORunLoopActionHolder*)holder;
+- (void)removeOperation:(WORunLoopActionHolder*)holder;
+- (void)performAdditionalOperations;
+@end
+
+
+@implementation WORunLoopInputManager
+
+- init
+{
+    fileObjects     = [NSMutableArray new];
+    timers          = [NSMutableArray new];
+    otherOperations = [NSMutableArray new];
+    return [super init];
+}
+
+- (void)dealloc
+{
+    RELEASE(fileObjects);
+    RELEASE(timers);
+    RELEASE(otherOperations);
+    [super dealloc];
+}
+
+- (void)addFileObject:(id)_fileObject
+  activities:(NSPosixFileActivities)_activities
+{
+    WORunLoopFileObjectInfo *info = nil;
+    //NSAssert(_activities, @"no activity to watch ?!");
+    info = [[WORunLoopFileObjectInfo allocWithZone:[self zone]]
+                                     initWithFileObject:_fileObject
+                                     activities:_activities];
+    [self->fileObjects addObject:info];
+    //NSLog(@"file objects now: %@", self->fileObjects);
+    RELEASE(info); info = nil;
+}
+- (void)removeFileObject:(id)_fileObject
+{
+    WORunLoopFileObjectInfo *info = nil;
+    info = [[WORunLoopFileObjectInfo allocWithZone:[self zone]]
+                                     initWithFileObject:_fileObject
+                                     activities:0];
+    [self->fileObjects removeObject:info];
+    //NSLog(@"file objects now: %@", self->fileObjects);
+    RELEASE(info); info = nil;
+}
+
+- (void)addTimer:(NSTimer*)aTimer
+{
+    [timers addObject:[WORunLoopTimerInfo infoWithTimer:aTimer]];
+}
+
+- (void)addOperation:(WORunLoopActionHolder*)holder
+{
+    [otherOperations addObject:holder];
+    [otherOperations sortUsingSelector:@selector(compare:)];
+}
+
+- (void)removeOperation:(WORunLoopActionHolder*)holder
+{
+    [otherOperations removeObject:holder];
+}
+
+- (void)performAdditionalOperations
+{
+    [otherOperations makeObjectsPerformSelector:@selector(execute)];
+}
+
+- (NSMutableArray*)fileObjects { return fileObjects; }
+- (NSMutableArray*)timers      { return timers; }
+
+@end /* WORunLoopInputManager */
+
+@implementation WORunLoop
+
+/* Class variable */
+static WORunLoop *currentRunLoop = nil;
+static BOOL      taskIsMultithreaded = NO;
+
++ (void)error:(id)_o {
+  NSLog(@"ERROR:");
+  NSLog(@"  %@", _o);
+}
+
++ (NSRunLoop *)currentRunLoop
+{
+    if (taskIsMultithreaded) {
+        NSLog(@"WORunLoop does not work multithreaded, exit ..");
+        return nil;
+    }
+    else {
+       if (!currentRunLoop)
+           currentRunLoop = [[self alloc] init];
+       return currentRunLoop;
+    }
+}
+
+- (id)init {
+  self->inputsForMode = [[NSMutableDictionary allocWithZone:[self zone]] init];
+  self->mode = RETAIN(NSDefaultRunLoopMode);
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->inputsForMode);
+  RELEASE(self->mode);
+  [super dealloc];
+}
+
+- (NSString *)currentMode {
+    return self->mode;
+}
+
+static inline WORunLoopInputManager*
+_getInputManager(WORunLoop *self, NSString *_mode)
+{
+  WORunLoopInputManager* inputManager;
+
+  inputManager = [self->inputsForMode objectForKey:_mode];
+  if (inputManager == nil) {
+    inputManager = [WORunLoopInputManager new];
+    [self->inputsForMode setObject:inputManager forKey:_mode];
+    RELEASE(inputManager);
+  }
+  return inputManager;
+}
+
+static int compare_fire_dates(id timer1, id timer2, void* userData)
+{
+  return [[timer1 fireDate] compare:[timer2 fireDate]];
+}
+
+- (NSDate*)limitDateForMode:(NSString*)aMode
+{
+    NSString       *format = @"%s: Caught exception %@ with reason %@ ";
+    NSMutableArray *timers = [[inputsForMode objectForKey:aMode] timers];
+    volatile int   i, count;
+    NSMutableArray *copyOfTimers;
+
+    ASSIGN(mode, aMode);
+
+    /* Remove invalid timers */
+    for(count = [timers count], i = count - 1; i >= 0; i--)
+        if(![[[timers objectAtIndex:i] timer] isValid]) {
+            [timers removeObjectAtIndex:i];
+           count--;
+        }
+
+    /* Currently only timers have limit dates associated with them */
+    if(!count)
+        return nil;
+
+    copyOfTimers = [timers mutableCopy];
+
+    /* Sort the timers based on their fire date */
+    [copyOfTimers sortUsingFunction:compare_fire_dates context:NULL];
+
+    /* Fire all the timers with their fire date expired */
+    for(i = 0; i < count; i++) {
+        WORunLoopTimerInfo* timerInfo = [copyOfTimers objectAtIndex:i];
+        NSDate* fireDate = [timerInfo fireDate];
+        NSDate* currentDate = [NSDate date];
+
+        if([fireDate earlierDate:currentDate] == fireDate
+          || [fireDate isEqualToDate:currentDate]) {
+            NSTimer* timer = [timerInfo timer];
+            NS_DURING
+             [timer fire];
+            NS_HANDLER
+             NSLog(format, __PRETTY_FUNCTION__,
+                    [localException name], [localException reason]);
+            NS_ENDHANDLER;
+
+#if 0
+#warning no repeated timers !
+            if(![timer repeats])
+#endif
+                [timer invalidate];
+        }
+    }
+
+    RELEASE(copyOfTimers);
+
+    /* Recompute the fire dates for this cycle */
+    [timers makeObjectsPerformSelector:@selector(recomputeFireDate)];
+
+    /* Sort the timers based on their fire date */
+    [timers sortUsingFunction:compare_fire_dates context:NULL];
+
+    return [timers count] ? [[timers objectAtIndex:0] fireDate] : nil;
+}
+
+- (void)addTimer:(NSTimer*)aTimer
+       forMode:(NSString*)aMode
+{
+    [_getInputManager(self, aMode) addTimer:aTimer];
+}
+
+- (BOOL)runMode:(NSString*)aMode
+       beforeDate:(NSDate*)limitDate
+{
+    id inputManager, fileObjects;
+    NSArray* timers;
+    NSDate* date;
+
+    /* Retain the limitDate so it doesn't get released by limitDateForMode:
+       if it fires a timer that has as fireDate the limitDate.
+       (bug report from Benhur Stein <Benhur-de-Oliveira.Stein@imag.fr>)
+      */
+    (void)RETAIN(limitDate);
+
+    inputManager = [inputsForMode objectForKey:aMode];
+    timers       = [inputManager timers];
+    fileObjects  = [inputManager fileObjects];
+
+    if (([timers count] != 0) || ([fileObjects count] != 0)) {
+       CREATE_AUTORELEASE_POOL(pool);
+
+       date = [self limitDateForMode:aMode];
+       date = date ? [date earlierDate:limitDate] : limitDate;
+       [self acceptInputForMode:aMode beforeDate:date];
+       RELEASE(pool);
+       RELEASE(limitDate);
+       return YES;
+    }
+
+    RELEASE(limitDate);
+    return NO;
+}
+
+/*  Runs the loop until limitDate or until the earliest limit date for input
+    sources in the specified mode. */
+- (void)acceptInputForMode:(NSString*)aMode
+       beforeDate:(NSDate*)limitDate
+{
+    id              inputManager, fileObjects;
+    struct timeval  tp = { 0, 0 };
+    struct timeval* timeout = NULL;
+    NSTimeInterval  delay = 0;
+    fd_set          readSet, writeSet, exceptionsSet;
+    volatile int    i, r, count;
+
+    ASSIGN(mode, aMode);
+
+    if(limitDate == nil) // delay = 0
+       limitDate = [NSDate distantFuture];
+    else {
+       delay = [limitDate timeIntervalSinceNow];
+           /* delay > 0 means a future date */
+
+       /* If limitDate is in the past return */
+       if(delay < 0)
+           return;
+    }
+
+    inputManager = [inputsForMode objectForKey:aMode];
+    fileObjects  = [inputManager fileObjects];
+
+    /* Compute the timeout for select */
+    if([limitDate isEqual:[NSDate distantFuture]])
+       timeout = NULL;
+    else {
+       tp.tv_sec = delay;
+       tp.tv_usec = (delay - (NSTimeInterval)tp.tv_sec) * 1000000.0;
+       timeout = &tp;
+    }
+
+    ASSIGN(mode, aMode);
+
+    FD_ZERO(&readSet);
+    FD_ZERO(&writeSet);
+    FD_ZERO(&exceptionsSet);
+
+    do {
+        count = [fileObjects count];
+        for (i = 0; i < count; i++) {
+            WORunLoopFileObjectInfo *info;
+            NSPosixFileActivities   fileActivity;
+            int                     fd;
+
+            info = [fileObjects objectAtIndex:i];
+            if (![info isAlive])
+                continue;
+
+            fileActivity = [info watchedActivities];
+            fd           = [info fileDescriptor];
+            
+            if (fd >= 0) {
+#if !defined(__MINGW32__) /* on Windows descriptors can be BIG */
+                if (fd >= FD_SETSIZE) {
+                    NSLog(@"%s: fd %i of %@ exceeds select size %i",
+                          __PRETTY_FUNCTION__,
+                          fd, info, FD_SETSIZE);
+                    continue;
+                }
+#endif /* !defined(__MINGW32__) */
+
+                //NSLog(@"registering activity %s for fd %i ..",
+                //      activityDesc[fileActivity], fd);
+
+                if (fileActivity & NSPosixReadableActivity)
+                    FD_SET(fd, &readSet);
+                if (fileActivity & NSPosixWritableActivity)
+                    FD_SET(fd, &writeSet);
+                if (fileActivity & NSPosixExceptionalActivity)
+                    FD_SET(fd, &exceptionsSet);
+            }
+        }
+
+        // ???: errno = 0; What is this good for ?
+       r = select(FD_SETSIZE, &readSet, &writeSet, &exceptionsSet, timeout);
+       if (r == -1) {
+           if (errno == EINTR) {
+               /* Interrupt occured; break the loop to give a chance to
+                  UnixSignalHandler to handle the signals. */
+               errno = 0;
+               break;
+           }
+           else {
+               NSLog(@"%s: select() error: '%s'",
+                      __PRETTY_FUNCTION__, strerror (errno));
+                break;
+            }
+           errno = 0;
+       }
+    } while (r == -1);
+
+    if(r > 0) {
+        id fileObjectsCopy;
+       NSString* format = @"%s: Caught exception %@ with reason %@ ";
+
+        *(&fileObjectsCopy) = nil;
+
+       NS_DURING {
+            // made copy, so that modifications in the delegate don't
+            // alter the loop
+            fileObjectsCopy = [fileObjects copyWithZone:[self zone]];
+            count           = [fileObjectsCopy count];
+            
+            for (i = 0; (i < count) && (r > 0); i++) {
+                WORunLoopFileObjectInfo *info;
+                NSPosixFileActivities   activity = 0;
+                int fd;
+
+                info = [fileObjectsCopy objectAtIndex:i];
+                fd   = [info fileDescriptor];
+
+                if (fd >= 0) {
+                    //NSLog(@"checking activity for %i info %@ ..", fd, info);
+                
+                    if (FD_ISSET(fd, &readSet)) {
+                        activity |= NSPosixReadableActivity;
+                        r--;
+                    }
+                    if (FD_ISSET(fd, &writeSet)) {
+                        activity |= NSPosixWritableActivity;
+                        r--;
+                    }
+                    if (FD_ISSET(fd, &exceptionsSet)) {
+                        activity |= NSPosixExceptionalActivity;
+                        r--;
+                    }
+
+                    if (activity != 0)
+                        [info activity:activity onDescriptor:fd];
+                }
+            }
+            if (r > 0) {
+                NSLog(@"WARNING: could not resolve all activities (%i) ..",
+                      r);
+            }
+       }
+        NS_HANDLER {
+         NSLog(format, __PRETTY_FUNCTION__,
+                [localException name], [localException reason]);
+       }
+        NS_ENDHANDLER;
+
+       RELEASE(fileObjectsCopy); fileObjectsCopy = nil;
+    }
+
+    [inputManager performAdditionalOperations];
+#if !NeXT_Foundation_LIBRARY
+    [NSNotificationQueue runLoopASAP];
+#endif
+}
+
+- (void)runUntilDate:(NSDate*)limitDate
+{
+    BOOL shouldContinue = YES;
+
+    if(!limitDate)
+       limitDate = [NSDate distantFuture];
+    else {
+       /* If limitDate is in the past return */
+       if([limitDate timeIntervalSinceNow] < 0)
+           return;
+    }
+
+    while (shouldContinue) {
+        CREATE_AUTORELEASE_POOL(pool);
+
+        if ([limitDate laterDate:[NSDate date]] == limitDate) {
+           if([self runMode:NSDefaultRunLoopMode beforeDate:limitDate] == NO)
+               shouldContinue = NO;
+        }
+       else
+           shouldContinue = NO;
+        RELEASE(pool);
+    }
+}
+
+- (void)run
+{
+    [self runUntilDate:[NSDate distantFuture]];
+}
+
+- (void)performSelector:(SEL)aSelector
+  target:(id)target
+  argument:(id)anArgument
+  order:(unsigned)order
+  modes:(NSArray*)modes
+{
+    id holder = [WORunLoopActionHolder objectWithTarget:target
+                                       argument:anArgument
+                                       selector:aSelector
+                                       order:order];
+    int i, count = [modes count];
+
+    for (i = 0; i < count; i++)
+       [[inputsForMode objectForKey:[modes objectAtIndex:i]]
+           addOperation:holder];
+}
+
+- (void)cancelPerformSelector:(SEL)aSelector
+  target:(id)target
+  argument:(id)anArgument
+{
+    id holder = [WORunLoopActionHolder objectWithTarget:target
+                                       argument:anArgument
+                                       selector:aSelector
+                                       order:0];
+    id enumerator = [inputsForMode keyEnumerator];
+    id aMode;
+
+    while ((aMode = [enumerator nextObject]))
+       [[inputsForMode objectForKey:aMode] removeOperation:holder];
+}
+
+/* Monitoring file objects */
+
+- (void)addFileObject:(id)_fileObject
+  activities:(NSPosixFileActivities)_activities
+  forMode:(NSString *)_mode
+{
+    [_getInputManager(self, _mode) addFileObject:_fileObject
+                                   activities:_activities];
+}
+
+- (void)removeFileObject:(id)_fileObject
+  forMode:(NSString *)_mode
+{
+    [_getInputManager(self, _mode) removeFileObject:_fileObject];
+}
+
+@end /* WORunLoop */
+
+#endif /* !LIB_FOUNDATION_LIBRARY */
+#endif // 0
diff --git a/skyrix-sope/NGObjWeb/WOScriptedComponent.h b/skyrix-sope/NGObjWeb/WOScriptedComponent.h
new file mode 100644 (file)
index 0000000..089b2c5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __WOScriptedComponent_H__
+#define __WOScriptedComponent_H__
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NGScriptLanguage;
+@class WOComponentScript, WOTemplate;
+
+@interface WOScriptedComponent : WOComponent
+{
+  WOComponentScript *script;
+  WOTemplate        *template;
+  NGScriptLanguage  *language;
+  id shadow;
+}
+
+@end
+
+#endif /* __WOScriptedComponent_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOScriptedComponent.m b/skyrix-sope/NGObjWeb/WOScriptedComponent.m
new file mode 100644 (file)
index 0000000..5e47eaa
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WOScriptedComponent.h"
+#include <NGObjWeb/WOTemplateBuilder.h>
+#include <NGScripting/NGScriptLanguage.h>
+#include "common.h"
+
+@interface NSObject(misc)
+- (void)applyStandardClasses;
+- (BOOL)isScriptFunction;
+
+- (id)callScriptFunction:(NSString *)_name withObject:(id)_arg0;
+- (id)evaluateScript:(NSString *)_script source:(NSString *)_s line:(int)_line;
+
+@end
+
+@interface WOComponent(UsedPrivates)
+- (id)initWithName:(NSString *)_cname
+  template:(WOTemplate *)_template
+  inContext:(WOContext *)_ctx;
+@end
+
+@interface WOComponentScript(UsedPrivates)
+- (id)initScriptWithComponent:(id)_comp;
+@end
+
+@implementation WOScriptedComponent
+
+static BOOL logScriptKVC     = NO;
+static BOOL logScriptInit    = NO;
+static BOOL logScriptDealloc = NO;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    logScriptKVC     = [ud boolForKey:@"WOLogScriptKVC"];
+    logScriptInit    = [ud boolForKey:@"WOLogScriptInit"];
+    logScriptDealloc = [ud boolForKey:@"WOLogScriptDealloc"];
+  }
+}
+
+- (id)initWithName:(NSString *)_cname
+  template:(WOTemplate *)_template
+  inContext:(WOContext *)_ctx
+{
+  if ((self = [super initWithName:_cname template:_template inContext:_ctx])) {
+    self->script = [[_template componentScript] retain];
+
+    self->language = 
+      [[NGScriptLanguage languageWithName:[self->script language]] retain];
+    if (self->language == nil) {
+      [self logWithFormat:
+              @"did not find engine for script language %@", 
+             [self->script language]];
+      RELEASE(self);
+      return nil;
+    }
+    
+    if ((self->shadow = [self->language createShadowForMaster:self]) == nil) {
+      [self logWithFormat:
+              @"could not create shadow for component in language %@", 
+             self->language];
+      RELEASE(self);
+      return nil;
+    }
+    
+    if ([self->shadow respondsToSelector:@selector(applyStandardClasses)])
+      [(id)self->shadow applyStandardClasses];
+    
+    [self->script initScriptWithComponent:self];
+    
+    if (logScriptInit)
+      [self logWithFormat:@"created scripted component: %@", self];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (logScriptDealloc)
+    [self logWithFormat:@"will dealloc scripted component: %@", self];
+  
+  [self->shadow invalidateShadow]; /* ensure shadow is dead ;-) */
+  RELEASE(self->shadow);
+  RELEASE(self->language);
+  RELEASE(self->script);
+  RELEASE(self->template);
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setTemplate:(id)_template {
+  ASSIGN(self->template, _template);
+}
+- (WOElement *)_woComponentTemplate {
+  return self->template;
+}
+
+- (BOOL)isScriptedComponent {
+  return YES;
+}
+
+/* scripting */
+
+- (id)evaluateScript:(NSString *)_script language:(NSString *)_lang 
+  source:(NSString *)_src line:(unsigned)_line
+{
+  return [self->shadow evaluateScript:_script source:_src line:_line];
+}
+
+/* notification mapping */
+
+- (void)awake {
+  [super awake];
+  
+  if ([self->shadow hasFunctionNamed:@"awake"])
+    [self->shadow callScriptFunction:@"awake"];
+}
+- (void)sleep {
+  if ([self->shadow hasFunctionNamed:@"sleep"])
+    [self->shadow callScriptFunction:@"sleep"];
+  
+  //[self debugWithFormat:@"vars: %@", [self variableDictionary]];
+  [super sleep];
+}
+
+/* script properties */
+
+- (BOOL)takeValue:(id)_value forJSPropertyNamed:(NSString *)_key {
+  NSAssert1(self->shadow, @"missing shadow for component %@", self);
+  [self->shadow setObject:_value forKey:_key];
+  return YES;
+}
+- (id)valueForJSPropertyNamed:(NSString *)_key {
+  [self debugWithFormat:@"value for prop %@", _key];
+  NSAssert1(self->shadow, @"missing shadow for component %@", self);
+  return [self->shadow objectForKey:_key];
+}
+
+/* extra variables */
+
+- (void)setObject:(id)_obj forKey:(NSString *)_key {
+  //[self debugWithFormat:@"setObject:%@ forKey:%@", _obj, _key];
+  NSAssert1(self->shadow, @"missing shadow for component %@", self);
+  [self->shadow setObject:_obj forKey:_key];
+}
+- (id)objectForKey:(NSString *)_key {
+  NSAssert1(self->shadow, @"missing shadow for component %@", self);
+  return [self->shadow objectForKey:_key];
+}
+
+/* key-value coding */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  NSString *funcName;
+  id       func;
+  unsigned len;
+  unsigned char *buf;
+  
+  len = [_key cStringLength];
+  buf = malloc(len + 4);
+  [_key getCString:&(buf[3])];
+  buf[0] = 's'; buf[1] = 'e'; buf[2] = 't';
+  buf[len + 3] = '\0';
+  if (len > 0) buf[3] = toupper(buf[3]);
+  funcName = [NSString stringWithCString:buf length:(len + 3)];
+  free(buf);
+  
+  if ((func = [self->shadow objectForKey:funcName])) {
+    if ([func isScriptFunction]) {
+      id result;
+      
+      if (logScriptKVC) {
+       [self logWithFormat:@"KVC: for key %@ call %@(%@)", 
+               _key, funcName, _value];
+      }
+      
+      result = [self->shadow callScriptFunction:funcName withObject:_value];
+    }
+    else {
+      [self logWithFormat:
+             @"KVC: object stored at '%@' is not a function, "
+             @"could not set value for key %@ !",
+             funcName, _key];
+    }
+  }
+  else {
+    if (logScriptKVC) {
+      [self logWithFormat:@"KVC: assign %@=%@ (no func '%@')", 
+             _key, _value, funcName];
+    }
+    
+    [self->shadow setObject:_value forKey:_key];
+  }
+}
+
+- (id)valueForKey:(NSString *)_key {
+  id obj;
+  
+  //[self logWithFormat:@"script: valueForKey:%@", _key];
+  
+  if ((obj = [self->shadow objectForKey:_key])) {
+    if ([obj isScriptFunction]) {
+      if (logScriptKVC) {
+       [self logWithFormat:@"KVC: for key %@ call %@", 
+               _key, _key];
+      }
+      obj = [self->shadow callScriptFunction:_key];
+    }
+    else {
+      if (logScriptKVC) {
+       [self logWithFormat:@"KVC: valueForKey(%@): %@", 
+               _key, obj];
+      }
+    }
+    return obj;
+  }
+  else {
+    if (logScriptKVC) {
+      [self logWithFormat:@"KVC: get value for key %@ from WOComponent", 
+             _key];
+    }
+    return [super valueForKey:_key];
+  }
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@"script<%@>[0x%08X]", [self name], self];
+}
+
+@end /* WOScriptedComponent */
+
+@implementation WOScriptedComponent(JSSupport)
+
+- (id)_jsfunc_FileManager:(NSArray *)_args {
+  return [NSFileManager defaultManager];
+}
+
+@end /* WOScriptedComponent(JSSupport) */
+
+@implementation NSObject(ScriptFunc)
+
+- (BOOL)isScriptFunction {
+  return NO;
+}
+
+@end /* NSObject(ScriptFunc) */
diff --git a/skyrix-sope/NGObjWeb/WOServerSessionStore.m b/skyrix-sope/NGObjWeb/WOServerSessionStore.m
new file mode 100644 (file)
index 0000000..81f4f6e
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOSessionStore.h>
+
+/*
+  The default session store. It stores all the sessions in memory
+  (it's basically a simple hashmap of the session-id to the session object).
+
+  If the application goes down, all sessions will go down - this store
+  doesn't provide "session-failover".
+*/
+
+@interface WOServerSessionStore : WOSessionStore
+{
+  NSMapTable *idToSession;
+  NSMapTable *activeSessions;
+}
+@end
+
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOSession.h>
+#include "common.h"
+
+/* hh: moved in here from application, check whether it's required ... */
+@interface WOSessionInfo : NSObject
+{
+@private
+  NSString *sessionID;
+  NSDate   *timeoutDate;
+}
+
++ (WOSessionInfo *)infoForSession:(WOSession *)_session;
+
+- (NSString *)sessionID;
+- (NSDate *)timeoutDate;
+
+@end
+
+@implementation WOServerSessionStore
+
+static BOOL logExpiredSessions = NO;
+
++ (int)version {
+  return [super version] + 0;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->idToSession = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                         NSObjectMapValueCallBacks,
+                                         128);
+    self->activeSessions = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                            NSObjectMapValueCallBacks,
+                                            128);
+    self->checkedOutSessions = [[NSMutableSet allocWithZone:[self zone]]
+                                              initWithCapacity:64];
+    
+    if ([[[NSUserDefaults standardUserDefaults]
+                          objectForKey:@"WORunMultithreaded"]
+                          boolValue]) {
+      self->lock         = [[NSRecursiveLock allocWithZone:[self zone]] init];
+      self->checkoutLock = [[NSConditionLock allocWithZone:[self zone]]
+                                             initWithCondition:0];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (self->activeSessions) {
+    NSFreeMapTable(self->activeSessions);
+    self->activeSessions = NULL;
+  }
+  if (self->idToSession) {
+    NSFreeMapTable(self->idToSession);
+    self->idToSession = NULL;
+  }
+  [self->checkedOutSessions release];
+  [self->checkoutLock       release];
+  [self->lock               release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (int)activeSessionsCount {
+  int count;
+  
+  [self->lock lock];
+  count = NSCountMapTable(self->idToSession);
+  [self->lock unlock];
+
+  return count;
+}
+
+/* store */
+
+- (void)saveSessionForContext:(WOContext *)_context {
+  if (![_context hasSession])
+    return;
+  
+  [self->lock lock];
+  {
+    WOSession *sn = [_context session];
+      
+    if ([sn isTerminating]) {
+      sn = [sn retain];
+        
+      NSMapRemove(self->idToSession,    [sn sessionID]);
+      NSMapRemove(self->activeSessions, [sn sessionID]);
+        
+      NSLog(@"session %@ terminated at %@ ..",
+           [sn sessionID], [NSCalendarDate calendarDate]);
+        
+      [sn release]; sn = nil;
+    }
+    else {
+      WOSessionInfo *info;
+        
+      NSMapInsert(self->idToSession, [sn sessionID], sn);
+        
+      info = [WOSessionInfo infoForSession:sn];
+      NSMapInsert(self->activeSessions, [sn sessionID], info);
+    }
+  }
+  [self->lock unlock];
+}
+
+- (WOSession *)restoreSessionWithID:(NSString *)_sid
+  request:(WORequest *)_request
+{
+  WOSession *session = nil;
+
+  if ([_sid length] == 0)
+    return nil;
+  
+  if (![_sid isKindOfClass:[NSString class]]) {
+    [self logWithFormat:
+           @"WARNING(%s): got invalid session id (expected string !): %@",
+            __PRETTY_FUNCTION__, _sid];
+    return nil;
+  }
+  
+  if ([_sid isEqualToString:@"expired"])
+    return nil;
+
+  [self->lock lock];
+  session = NSMapGet(self->idToSession, _sid);
+  [self->lock unlock];
+
+  if (logExpiredSessions) {
+    if (session == nil)
+      [self logWithFormat:@"session with id %@ expired.", _sid];
+  }
+
+  return session;
+}
+
+/* termination */
+
+- (void)sessionExpired:(NSString *)_sessionID {
+  [self->lock lock];
+  NSMapRemove(self->idToSession, _sessionID);
+  [self->lock unlock];
+}
+
+- (void)sessionTerminated:(WOSession *)_session {
+  _session = [_session retain];
+  [self->lock lock];
+  NSMapRemove(self->idToSession, [_session sessionID]);
+  [self->lock unlock];
+  [_session release];
+  
+  [[WOApplication application]
+                  logWithFormat:
+                    @"WOServerSessionStore: session %@ terminated.",
+                    [_session sessionID]];
+}
+
+/* expiration check */
+
+- (void)performExpirationCheck:(NSTimer *)_timer {
+  NSNotificationCenter *nc;
+  NSMutableArray  *timedOut = nil;
+  NSMapEnumerator e;
+  NSString        *sid  = nil;
+  WOSessionInfo   *info = nil;
+  NSDate          *now;
+  unsigned cnt, count;
+    
+  //NSLog(@"%s: perform expiration check ...", __PRETTY_FUNCTION__);
+  
+  if (self->activeSessions == NULL)
+    count = 0;
+  else
+    count = NSCountMapTable(self->activeSessions);
+  
+  if (!(count > 0 && (self->activeSessions != NULL)))
+    return;
+  
+  e   = NSEnumerateMapTable(self->activeSessions);
+  now = [NSDate date];
+      
+  /* search for expired sessions */
+  while (NSNextMapEnumeratorPair(&e, (void **)&sid, (void **)&info)) {
+    NSDate *timeOutDate = [info timeoutDate];
+    
+    if (timeOutDate == nil) continue;
+
+    if ([now compare:timeOutDate] != NSOrderedAscending) {
+        [self logWithFormat:@"session %@ expired at %@.", sid, now];
+          
+        if (timedOut == nil)
+          timedOut = [NSMutableArray arrayWithCapacity:32];
+        [timedOut addObject:info];
+    }
+  }
+      
+  /* Expire sessions */
+  if (!timedOut)
+    return;
+
+  nc = [NSNotificationCenter defaultCenter];
+        
+  for (cnt = 0, count = [timedOut count]; cnt < count; cnt++) {
+    NSString *sid;
+          
+        info = [timedOut objectAtIndex:cnt];
+        sid  = [[info sessionID] copy];
+          
+        NSMapRemove(self->activeSessions, sid);
+        NSMapRemove(self->idToSession,    sid);
+          
+        [nc postNotificationName:WOSessionDidTimeOutNotification
+            object:sid];
+
+        [sid release];
+  }
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: active=%i>",
+                     NSStringFromClass([self class]), self,
+                     [self activeSessionsCount]
+                   ];
+}
+
+@end /* WOServerSessionStore */
+
+@implementation WOSessionInfo
+
+- (id)initWithSession:(WOSession *)_session {
+  self->sessionID = RETAIN([_session sessionID]);
+
+  if ([_session respondsToSelector:@selector(timeoutDate)]) {
+    self->timeoutDate = [(id)_session timeoutDate];
+  }
+  else {
+    NSTimeInterval timeOut = [_session timeOut];
+    
+    self->timeoutDate = (timeOut > 0.0)
+      ? [NSDate dateWithTimeIntervalSinceNow:(timeOut + 1.0)]
+      : [NSDate distantFuture];
+  }
+  self->timeoutDate = RETAIN(self->timeoutDate);
+  
+  return self;
+}
+
++ (WOSessionInfo *)infoForSession:(WOSession *)_session {
+  return AUTORELEASE([[self alloc] initWithSession:_session]);
+}
+
+- (void)dealloc {
+  [self->sessionID   release];
+  [self->timeoutDate release];
+  [super dealloc];
+}
+
+- (NSString *)sessionID {
+  return self->sessionID;
+}
+- (NSDate *)timeoutDate {
+  return self->timeoutDate;
+}
+
+@end /* WOSessionInfo */
diff --git a/skyrix-sope/NGObjWeb/WOSession+JS.m b/skyrix-sope/NGObjWeb/WOSession+JS.m
new file mode 100644 (file)
index 0000000..d5a84ac
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include <NGObjWeb/NGObjWeb.h>
+
+/*
+  WOSession JavaScript object
+
+  Properties
+
+    String sessionID
+    String domainForIDCookies
+    Date   expirationDateForIDCookies
+    bool   isDistributionEnabled
+    bool   isTerminating
+    Array  languages
+    Object statistics
+    Number timeOut
+    bool   storesIDsInCookies
+    bool   storesIDsInURLs
+
+  Methods
+
+    WOComponent restorePageForContextID(ctxid)
+                savePage(page)
+                savePageInPermanentCache(page)
+                terminate()
+                print(string [,..string])
+*/
+
+static NSNumber *nYes = nil;
+static NSNumber *nNo  = nil;
+
+@implementation WOSession(JSFunctions)
+
+- (id)_jsfunc_restorePageForContextID:(NSArray *)_args {
+  return [self restorePageForContextID:[[_args objectAtIndex:0] stringValue]];
+}
+- (id)_jsfunc_savePage:(NSArray *)_args {
+  [self savePage:[_args objectAtIndex:0]];
+  return self;
+}
+- (id)_jsfunc_savePageInPermanentCache:(NSArray *)_args {
+  [self savePageInPermanentCache:[_args objectAtIndex:0]];
+  return self;
+}
+- (id)_jsfunc_terminate:(NSArray *)_args {
+  [self terminate];
+  return self;
+}
+
+- (id)_jsfunc_print:(NSArray *)_args {
+  NSEnumerator    *e;
+  id              o;
+  BOOL            isFirst;
+  NSMutableString *ms;
+  
+  isFirst = YES;
+  ms = [NSMutableString stringWithCapacity:128];
+  
+  e = [_args objectEnumerator];
+  while ((o = [e nextObject])) {
+    NSString *s;
+
+    if (!isFirst) [ms appendString:@" "];
+    else isFirst = NO;
+    
+    s = [o stringValue];
+    [ms appendString:s];
+  }
+  
+  [self logWithFormat:@"%@", ms];
+  
+  return self;
+}
+
+@end
+
+@implementation WOSession(JSProperties)
+
++ (void)initialize {
+  if (nYes == nil) nYes = [[NSNumber alloc] initWithBool:YES];
+  if (nNo  == nil) nNo  = [[NSNumber alloc] initWithBool:NO];
+}
+
+- (id)_jsprop_sessionID {
+  return [self sessionID];
+}
+- (id)_jsprop_domainForIDCookies {
+  return [self domainForIDCookies];
+}
+- (id)_jsprop_expirationDateForIDCookies {
+  return [self expirationDateForIDCookies];
+}
+
+- (id)_jsprop_isDistributionEnabled:(id)_value {
+  [self setDistributionEnabled:[_value boolValue]];
+  return self;
+}
+- (id)_jsprop_isDistributionEnabled {
+  return [self isDistributionEnabled] ? nYes : nNo;
+}
+
+- (id)_jsprop_isTerminating {
+  return [self isTerminating] ? nYes : nNo;
+}
+
+- (id)_jsprop_languages:(id)_value {
+  [self setLanguages:_value];
+  return self;
+}
+- (id)_jsprop_languages {
+  return [self languages];
+}
+
+- (id)_jsprop_statistics {
+  return [self statistics];
+}
+
+- (id)_jsprop_timeOut:(id)_value {
+  [self setTimeOut:[_value doubleValue]];
+  return self;
+}
+- (id)_jsprop_timeOut {
+  return [NSNumber numberWithDouble:[self timeOut]];
+}
+
+- (id)_jsprop_storesIDsInCookies:(id)_value {
+  [self setStoresIDsInCookies:[_value boolValue]];
+  return self;
+}
+- (id)_jsprop_storesIDsInCookies {
+  return [self storesIDsInCookies] ? nYes : nNo;
+}
+
+- (id)_jsprop_storesIDsInURLs:(id)_value {
+  [self setStoresIDsInURLs:[_value boolValue]];
+  return self;
+}
+- (id)_jsprop_storesIDsInURLs {
+  return [self storesIDsInURLs] ? nYes : nNo;
+}
+
+@end /* WOSession(JSProperties) */
diff --git a/skyrix-sope/NGObjWeb/WOSession.m b/skyrix-sope/NGObjWeb/WOSession.m
new file mode 100644 (file)
index 0000000..d7053a0
--- /dev/null
@@ -0,0 +1,765 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOSession.h>
+#include "WOContext+private.h"
+#include "NSObject+WO.h"
+#include "WOComponent+private.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOStatisticsStore.h>
+#include <EOControl/EONull.h>
+#include "common.h"
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (id)notImplemented:(SEL)cmd;
+@end
+#endif
+
+struct WOSessionCacheEntry {
+  NSString    *contextID;
+  unsigned    ctxIdHash;
+  WOComponent *page;
+};
+
+NGObjWeb_DECLARE
+  NSString *WOSessionDidTimeOutNotification   = @"WOSessionDidTimeOut";
+NGObjWeb_DECLARE
+  NSString *WOSessionDidRestoreNotification   = @"WOSessionDidRestore";
+NGObjWeb_DECLARE
+  NSString *WOSessionDidCreateNotification    = @"WOSessionDidCreate";
+NGObjWeb_DECLARE
+  NSString *WOSessionDidTerminateNotification = @"WOSessionDidTerminate";
+
+@implementation WOSession
+
++ (int)version {
+  return 5;
+}
+
+static int   profileComponents = -1;
+static int   logPageCache      = -1;
+static Class NSDateClass = Nil;
+
++ (void)initialize {
+  if (NSDateClass == Nil)
+    NSDateClass = [NSDate class];
+}
+
+- (id)init {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  if (NSDateClass == Nil)
+    NSDateClass = [NSDate class];
+  
+  if (profileComponents == -1) {
+    profileComponents = 
+      [[ud objectForKey:@"WOProfileComponents"] boolValue] ? 1 : 0;
+  }
+  if (logPageCache == -1)
+    logPageCache = [[ud objectForKey:@"WOLogPageCache"] boolValue] ? 1 : 0;
+  
+  if ((self = [super init])) {
+    WOApplication *app = [WOApplication application];
+
+    if ([[ud objectForKey:@"WORunMultithreaded"] boolValue])
+      self->wosLock = [[NSRecursiveLock allocWithZone:[self zone]] init];
+    
+    /* setup page cache */
+
+    [self setStoresIDsInURLs:YES];
+    [self setStoresIDsInCookies:YES];
+    
+    self->pageCache.index = 0;
+    self->pageCache.size = [app pageCacheSize];
+
+    if (self->pageCache.size > 0) {
+      self->pageCache.entries =
+        NGMalloc(sizeof(struct WOSessionCacheEntry) * self->pageCache.size);
+      memset(self->pageCache.entries, 0,
+             sizeof(struct WOSessionCacheEntry) * self->pageCache.size);
+    }
+    
+    self->permanentPageCache.index = 0;
+    self->permanentPageCache.size = [app permanentPageCacheSize];
+
+    if (self->permanentPageCache.size > 0) {
+      self->permanentPageCache.entries =
+        NGMalloc(sizeof(struct WOSessionCacheEntry) *
+                    self->permanentPageCache.size);
+      memset(self->permanentPageCache.entries, 0,
+             sizeof(struct WOSessionCacheEntry) *
+             self->permanentPageCache.size);
+    }
+
+    /* setup misc */
+
+    self->wosLanguages  = [[ud arrayForKey:@"WODefaultLanguages"] copy];
+    self->isTerminating = NO;
+    
+    [self setTimeOut:[[WOApplication sessionTimeOut] intValue]];
+    
+    /* setup session ID */
+    
+    self->wosSessionId =
+      [[[WOApplication application] createSessionIDForSession:self] copy];
+    
+    if (self->wosSessionId == nil) {
+      /* session-id creation failed ... */
+      [self release];
+      return nil;
+    }
+    
+    /* misc logging */
+    
+    if (profileComponents)
+      [self logWithFormat:@"Component profiling is on."];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter]
+                         postNotificationName:@"WOSessionWillDeallocate"
+                         object:self];
+  [self->wosVariables release];
+  [self->wosSessionId release];
+  [self->wosLock      release];
+  [self->wosLanguages release];
+  [super dealloc];
+}
+
+/* session */
+
+- (NSString *)sessionID {
+  return self->wosSessionId;
+}
+
+- (void)setStoresIDsInURLs:(BOOL)_flag {
+  self->wosFlags.storesIDsInURLs = _flag ? 1 : 0;
+}
+- (BOOL)storesIDsInURLs {
+  return self->wosFlags.storesIDsInURLs ? YES : NO;
+}
+
+- (void)setStoresIDsInCookies:(BOOL)_flag {
+  self->wosFlags.storesIDsInCookies = _flag ? 1 : 0;
+}
+- (BOOL)storesIDsInCookies {
+  return self->wosFlags.storesIDsInCookies ? YES : NO;
+}
+
+- (NSString *)domainForIDCookies {
+  return nil;
+}
+- (NSDate *)expirationDateForIDCookies {
+  return [self isTerminating]
+    ? [NSDate dateWithTimeIntervalSinceNow:-15.0]
+    : [NSDate dateWithTimeIntervalSinceNow:([self timeOut] - 5.0)];
+}
+
+- (void)setDistributionEnabled:(BOOL)_flag {
+  [self notImplemented:_cmd];
+}
+- (BOOL)isDistributionEnabled {
+  return NO;
+}
+
+- (void)setTimeOut:(NSTimeInterval)_timeout {
+  self->wosTimeOut = _timeout;
+}
+- (NSTimeInterval)timeOut {
+  return self->wosTimeOut;
+}
+
+- (void)terminate {
+  self->isTerminating = YES;
+}
+- (BOOL)isTerminating {
+  return self->isTerminating;
+}
+
+- (WOApplication *)application {
+  if (self->application == nil)
+    self->application = [WOApplication application];
+  return self->application;
+}
+- (WOContext *)context {
+  if (self->context == nil) {
+    if (self->application == nil)
+      self->application = [WOApplication application];
+    self->context = [self->application context];
+  }
+  return self->context;
+}
+
+/* editing context */
+
+- (id)defaultEditingContext {
+  if (![WOApplication implementsEditingContexts])
+    return nil;
+  
+  if (self->wosDefaultEditingContext == nil) {
+    self->wosDefaultEditingContext = 
+      [[[WOApplication eoEditingContextClass] alloc] init];
+  }
+  return self->wosDefaultEditingContext;
+}
+
+/* pages */
+
+- (WOComponent *)restorePageForContextID:(NSString *)_contextID {
+  unsigned short i;
+  unsigned       ctxHash;
+  WOComponent    *page = nil;
+  
+  ctxHash = [_contextID hash];
+  
+  /* first scan permanent cache */
+
+  for (i = 0, page = nil;
+       (page == nil) && (i < self->permanentPageCache.size); i++) {
+    struct WOSessionCacheEntry *entry;
+
+    entry = &(self->permanentPageCache.entries[i]);
+    
+    if (ctxHash == entry->ctxIdHash) {
+      if ([_contextID isEqualToString:entry->contextID]) {
+        page = entry->page;
+        if (logPageCache) {
+          [self debugWithFormat:@"restored permanent page %@ for ctx %@",
+                  page ? [page name] : (id)@"<nil>",
+                  _contextID ? _contextID : (id)@"<nil>"];
+        }
+        break;
+      }
+    }
+  }
+
+  if (page)
+    return [[page retain] autorelease];
+  
+  /* now scan regular cache */
+  
+  for (i = 0, page = nil; (page == nil) && (i < self->pageCache.size); i++) {
+    struct WOSessionCacheEntry *entry;
+
+    entry = &(self->pageCache.entries[i]);
+    
+    if (ctxHash == entry->ctxIdHash) {
+      if ([_contextID isEqualToString:entry->contextID]) {
+        page = entry->page;
+        if (logPageCache) {
+          [self debugWithFormat:@"restored page %@<0x%08X> for ctx %@",
+                  [page name], page, _contextID];
+        }
+        break;
+      }
+    }
+  }
+  return [[page retain] autorelease];
+}
+
+- (void)savePage:(WOComponent *)_page {
+  NSString *cid;
+  struct WOSessionCacheEntry *entry;
+  
+  cid = [[self context] contextID];
+  if (logPageCache)
+    [self debugWithFormat:@"storing page %@ for ctx %@", [_page name], cid];
+    
+  /* go to next (fixed) queue entry */
+  self->pageCache.index++;
+  if (self->pageCache.index >= self->pageCache.size)
+    self->pageCache.index = 0;
+
+  entry = &(self->pageCache.entries[self->pageCache.index]);
+  
+  /* reset old queue entry */
+  entry->ctxIdHash = 0;
+  [entry->contextID release];
+  [entry->page      release];
+
+  /* assign new values */
+  entry->contextID = [cid copyWithZone:[self zone]];
+  entry->ctxIdHash = [entry->contextID hash];
+  entry->page = [_page retain];
+}
+
+- (void)savePageInPermanentCache:(WOComponent *)_page {
+  NSString *cid;
+  struct WOSessionCacheEntry *entry;
+    
+  cid = [[self context] contextID];
+  if (logPageCache) {
+    [self debugWithFormat:
+            @"permanently storing page %@ for ctx %@", [_page name], cid];
+  }
+    
+  /* go to next (fixed) queue entry */
+  self->permanentPageCache.index++;
+  if (self->permanentPageCache.index >= self->permanentPageCache.size)
+    self->permanentPageCache.index = 0;
+
+  entry = &(self->permanentPageCache.entries[self->permanentPageCache.index]);
+
+  /* reset old queue entry */
+  entry->ctxIdHash = 0;
+  [entry->contextID release];
+  [entry->page      release];
+  
+  /* assign new values */
+  entry->contextID = [cid copyWithZone:[self zone]];
+  entry->ctxIdHash = [entry->contextID hash];
+  entry->page = [_page retain];
+}
+
+// localization
+
+- (void)languageArrayDidChange {
+}
+
+- (void)setLanguages:(NSArray *)_langs {
+  if (![self->wosLanguages isEqual:_langs]) { // check whether they really differ
+    [self->wosLanguages release]; self->wosLanguages = nil;
+    self->wosLanguages = [_langs copyWithZone:[self zone]];
+    [self languageArrayDidChange];
+  }
+}
+- (NSArray *)languages {
+  return self->wosLanguages;
+}
+
+/* notifications */
+
+- (void)awake {
+}
+- (void)sleep {
+}
+
+- (void)_awakeWithContext:(WOContext *)_ctx {
+  if (self->context == nil)
+    self->context = _ctx;
+  if (self->application == nil)
+    self->application = [WOApplication application];
+
+  if (!self->wosFlags.isAwake) {
+    [self awake];
+    self->wosFlags.isAwake = 1;
+  }
+}
+- (void)_sleepWithContext:(WOContext *)_ctx {
+  if (self->wosFlags.isAwake) {
+    [self sleep];
+    self->wosFlags.isAwake = 0;
+  }
+  self->context     = nil;
+  self->application = nil;
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *senderID;
+  NSString *reqCtxId;
+  
+  self->context     = _ctx;
+  self->application = [WOApplication application];
+
+  senderID = [_ctx senderID];
+
+  if ([senderID length] == 0)
+    /* no element URL is available */
+    return;
+
+  if ([[_request method] isEqualToString:@"GET"]) {
+    NSRange r;
+    
+    r = [[_request uri] rangeOfString:@"?"];
+    if (r.length == 0)
+      /* no form content to apply */
+      return;
+  }
+
+  if ((reqCtxId = [_ctx currentElementID]) == nil)
+    reqCtxId = @"0";
+  
+  [_ctx appendElementIDComponent:reqCtxId];
+  {
+    WOComponent *page;
+
+    if ((page = [_ctx page])) {
+      NSTimeInterval st = 0.0;
+      
+      WOContext_enterComponent(_ctx, page, nil);
+      
+      if (profileComponents)
+        st = [[NSDateClass date] timeIntervalSince1970];
+      
+      [page takeValuesFromRequest:_request inContext:_ctx];
+      
+      if (profileComponents) {
+        NSTimeInterval diff;
+        
+        diff = [[NSDateClass date] timeIntervalSince1970] - st;
+        printf("prof[%s %s]: %0.3fs\n",
+               [[(WOComponent *)page name] cString], sel_get_name(_cmd), diff);
+      }
+      
+      WOContext_leaveComponent(_ctx, page);
+    }
+  }
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  NSString *reqCtxId;
+  BOOL     returnResult = NO;
+  id       result       = nil;
+  
+  self->context     = _ctx;
+  self->application = [WOApplication application];
+  
+  if ((reqCtxId = [_ctx currentElementID]) == nil)
+    /* no sender element ID */
+    return nil;
+  
+  [_ctx appendElementIDComponent:reqCtxId];
+  {
+    WOComponent *page;
+
+    if ((page = [_ctx page])) {
+      /*
+        -consumeElementID consumes the context id and returns the
+        id of the next element.
+        If there was no next element, the request wasn't active.
+      */
+      if (([_ctx consumeElementID])) {
+        NSTimeInterval st = 0.0;
+        
+        returnResult = YES;
+        WOContext_enterComponent(_ctx, page, nil);
+        
+        if (profileComponents)
+          st = [[NSDateClass date] timeIntervalSince1970];
+        
+        result = [page invokeActionForRequest:_request inContext:_ctx];
+      
+        if (profileComponents) {
+          NSTimeInterval diff;
+          
+          diff = [[NSDateClass date] timeIntervalSince1970] - st;
+          printf("prof[%s %s]: %0.3fs\n",
+                 [[page name] cString], sel_get_name(_cmd), diff);
+                 //[page name], sel_get_name(_cmd), diff);
+        }
+      
+        WOContext_leaveComponent(_ctx, page);
+      }
+    }
+  }
+  [_ctx deleteLastElementIDComponent];
+  return returnResult ? result : [_ctx page];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  self->context     = _ctx;
+  self->application = [WOApplication application];
+  
+  /* HTTP/1.1 caching directive, prevents browser from caching dynamic pages */
+  if ([self->application isPageRefreshOnBacktrackEnabled]) {
+    NSString *ctype;
+    
+    if ((ctype = [_response headerForKey:@"content-type"])) {
+      if ([ctype rangeOfString:@"html"].length > 0)
+       // profiling OSX: 3.1% of append...
+       [_response disableClientCaching];
+    }
+  }
+  
+  [_ctx deleteAllElementIDComponents];
+  [_ctx appendElementIDComponent:[_ctx contextID]];
+  {
+    WOComponent *page;
+
+    if ((page = [_ctx page])) {
+      /* let the page append it's content */
+      NSTimeInterval st = 0.0;
+      
+      WOContext_enterComponent(_ctx, page, nil);
+      
+      if (profileComponents)
+        st = [[NSDateClass date] timeIntervalSince1970];
+      
+      [page appendToResponse:_response inContext:_ctx];
+      
+      if (profileComponents) {
+        NSTimeInterval diff;
+        
+        diff = [[NSDateClass date] timeIntervalSince1970] - st;
+        printf("prof[%s %s]: %0.3fs\n",
+               [[page name] cString], sel_get_name(_cmd), diff);
+      }
+      
+      WOContext_leaveComponent(_ctx, page);
+    }
+    else {
+      [self logWithFormat:@"missing page in context for -appendToResponse: !"];
+    }
+  }
+  [_ctx deleteLastElementIDComponent];
+
+  /* generate statistics */
+  // profiling OSX: 3.1% of append... (seems to be NSDate!)
+  [[[self application] statisticsStore]
+          recordStatisticsForResponse:_response
+          inContext:_ctx];
+}
+
+// multithreading
+
+- (void)lock {
+  [self->wosLock lock];
+}
+- (void)unlock {
+  [self->wosLock unlock];
+}
+
+- (BOOL)tryLock {
+  return [self->wosLock tryLock];
+}
+
+/* session variables */
+
+- (void)setObject:(id)_obj forKey:(NSString *)_key {
+  if (self->wosVariables == nil)
+    self->wosVariables = [[NSMutableDictionary alloc] initWithCapacity:16];
+  
+  if (_obj)
+    [self->wosVariables setObject:_obj forKey:_key];
+  else
+    [self->wosVariables removeObjectForKey:_key];
+}
+- (id)objectForKey:(NSString *)_key {
+  return [self->wosVariables objectForKey:_key];
+}
+
+- (void)removeObjectForKey:(NSString *)_key {
+  [self->wosVariables removeObjectForKey:_key];
+}
+
+- (NSDictionary *)variableDictionary {
+  return self->wosVariables;
+}
+
+#if LIB_FOUNDATION_LIBRARY /* only override on libFoundation */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  if (WOSetKVCValueUsingMethod(self, _key, _value))
+    // method is used
+    return;
+  else if (WOGetKVCGetMethod(self, _key) == NULL) {
+    if (self->wosVariables == nil)
+      self->wosVariables = [[NSMutableDictionary alloc] initWithCapacity:16];
+    
+    if (_value) [self->wosVariables setObject:_value forKey:_key];
+    return;
+  }
+  else
+    // only a 'get' method is defined for _key !
+    [self handleTakeValue:_value forUnboundKey:_key];
+}
+- (id)valueForKey:(NSString *)_key {
+  id value;
+  
+  if ((value = WOGetKVCValueUsingMethod(self, _key)))
+    return value;
+  
+  return [self->wosVariables objectForKey:_key];
+}
+
+#else /* use fallback methods on other Foundation libraries */
+
+- (void)setValue:(id)_value forUndefinedKey:(NSString *)_key {
+  [self setObject:_value forKey:_key];
+}
+- (id)valueForUndefinedKey:(NSString *)_key {
+  return [self->wosVariables objectForKey:_key];
+}
+
+- (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
+  // deprecated: pre-Panther method
+  [self setValue:_value forUndefinedKey:_key];
+}
+- (id)handleQueryWithUnboundKey:(NSString *)_key {
+  // deprecated: pre-Panther method
+  return [self valueForUndefinedKey:_key];
+}
+
+#endif
+
+/* statistics */
+
+- (NSArray *)statistics {
+  return [NSArray array];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@[0x%08X]: id=%@>",
+                     NSStringFromClass([self class]), self,
+                     [self sessionID]];
+}
+
+@end /* WOSession */
+
+@implementation WOSession(NSCoding)
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  unsigned short i;
+  BOOL t;
+  
+  [_coder encodeObject:self->wosLanguages];
+  [_coder encodeObject:[self sessionID]];
+  [_coder encodeObject:self->wosVariables];
+  [_coder encodeValueOfObjCType:@encode(NSTimeInterval) at:&(self->wosTimeOut)];
+  t = [self storesIDsInURLs];
+  [_coder encodeValueOfObjCType:@encode(BOOL) at:&t];
+  t = [self storesIDsInCookies];
+  [_coder encodeValueOfObjCType:@encode(BOOL) at:&t];
+
+  /* store page caches */
+  
+  [_coder encodeValueOfObjCType:@encode(unsigned short)
+          at:&(self->pageCache.index)];
+  [_coder encodeValueOfObjCType:@encode(unsigned short)
+          at:&(self->pageCache.size)];
+  for (i = 0; i < self->pageCache.size; i++) {
+    [_coder encodeValueOfObjCType:@encode(unsigned)
+            at:&(self->pageCache.entries[i].ctxIdHash)];
+    [_coder encodeObject:self->pageCache.entries[i].contextID];
+    [_coder encodeObject:self->pageCache.entries[i].page];
+  }
+
+  [_coder encodeValueOfObjCType:@encode(unsigned short)
+          at:&(self->permanentPageCache.index)];
+  [_coder encodeValueOfObjCType:@encode(unsigned short)
+          at:&(self->permanentPageCache.size)];
+  for (i = 0; i < self->permanentPageCache.size; i++) {
+    [_coder encodeValueOfObjCType:@encode(unsigned)
+            at:&(self->permanentPageCache.entries[i].ctxIdHash)];
+    [_coder encodeObject:self->permanentPageCache.entries[i].contextID];
+    [_coder encodeObject:self->permanentPageCache.entries[i].page];
+  }
+}
+
+- (id)initWithCoder:(NSCoder *)_coder {
+  if ((self = [super init])) {
+    unsigned short i;
+    BOOL t;
+    
+    self->wosLanguages = [[_coder decodeObject] retain];
+    self->wosSessionId = [[_coder decodeObject] copyWithZone:[self zone]];
+    self->wosVariables = [[_coder decodeObject] copyWithZone:[self zone]];
+    [_coder decodeValueOfObjCType:@encode(NSTimeInterval) at:&(self->wosTimeOut)];
+    [_coder decodeValueOfObjCType:@encode(BOOL) at:&t];
+    [self setStoresIDsInURLs:t];
+    [_coder decodeValueOfObjCType:@encode(BOOL) at:&t];
+    [self setStoresIDsInCookies:t];
+
+    /* restore page caches */
+    
+    [_coder decodeValueOfObjCType:@encode(unsigned short)
+            at:&(self->pageCache.index)];
+    [_coder decodeValueOfObjCType:@encode(unsigned short)
+            at:&(self->pageCache.size)];
+    self->pageCache.entries =
+      NGMalloc(sizeof(struct WOSessionCacheEntry) * self->pageCache.size);
+    for (i = 0; i < self->pageCache.size; i++) {
+      [_coder decodeValueOfObjCType:@encode(unsigned)
+              at:&(self->pageCache.entries[i].ctxIdHash)];
+      self->pageCache.entries[i].contextID = [[_coder decodeObject] retain];
+      self->pageCache.entries[i].page      = [[_coder decodeObject] retain];
+    }
+
+    [_coder decodeValueOfObjCType:@encode(unsigned short)
+            at:&(self->permanentPageCache.index)];
+    [_coder decodeValueOfObjCType:@encode(unsigned short)
+            at:&(self->permanentPageCache.size)];
+    self->permanentPageCache.entries =
+      NGMalloc(sizeof(struct WOSessionCacheEntry) *
+                  self->permanentPageCache.size);
+    for (i = 0; i < self->permanentPageCache.size; i++) {
+      [_coder decodeValueOfObjCType:@encode(unsigned)
+              at:&(self->permanentPageCache.entries[i].ctxIdHash)];
+      self->permanentPageCache.entries[i].contextID =
+        [[_coder decodeObject] retain];
+      self->permanentPageCache.entries[i].page = [[_coder decodeObject] retain];
+    }
+    
+    self->wosLock = [[NSRecursiveLock allocWithZone:[self zone]] init];
+  }
+  return self;
+}
+
+@end /* WOSession(NSCoding) */
+
+@implementation WOSession(Logging2)
+
+- (BOOL)isDebuggingEnabled {
+  static char showDebug = 2;
+  
+  if (showDebug == 2)
+    showDebug = [WOApplication isDebuggingEnabled] ? 1 : 0;
+  return showDebug ? YES : NO;
+}
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@"(%@)", [self sessionID]];
+}
+
+@end /* WOSession(Logging) */
+
+NSString *OWSessionLanguagesDidChangeNotificationName =
+  @"OWSnLanguagesDidChangeNotification";
+
+@implementation WOSession(Misc)
+
+- (void)languageArrayDidChange {
+  WOComponent *c;
+
+  c = [[self context] page];
+  if ([c respondsToSelector:@selector(languageArrayDidChange)])
+    [(id)c languageArrayDidChange];
+  
+  [[NSNotificationCenter defaultCenter]
+                         postNotificationName:
+                           OWSessionLanguagesDidChangeNotificationName
+                         object:self];
+}
+
+@end /* WOSession(Misc) */
diff --git a/skyrix-sope/NGObjWeb/WOSessionStore.m b/skyrix-sope/NGObjWeb/WOSessionStore.m
new file mode 100644 (file)
index 0000000..8db14cb
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOSessionStore.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOSession.h>
+#include "common.h"
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (void)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+@implementation WOSessionStore
+
++ (int)version {
+  return 2;
+}
+
++ (WOSessionStore *)serverSessionStore {
+  return
+    [[[NSClassFromString(@"WOServerSessionStore") alloc] init] autorelease];
+}
+
+- (int)activeSessionsCount {
+  [self subclassResponsibility:_cmd];
+  return -1;
+}
+
+/* checkin/out */
+
+- (WOSession *)checkOutSessionWithSessionID:(NSString *)_sid
+  request:(WORequest *)_request
+{
+  WOSession *session;
+  *(&session) = nil;
+  
+  SYNCHRONIZED(self) { // this must become a condition lock !!!
+    if (![self->checkedOutSessions containsObject:_sid]) {
+      if ((session = [self restoreSessionWithID:_sid]))
+        [self->checkedOutSessions addObject:_sid];
+    }
+    else {
+    }
+  }
+  END_SYNCHRONIZED;
+  
+  return session;
+}
+
+- (void)checkInSessionForContext:(WOContext *)_context {
+  NSString *sid;
+  *(&sid) = [[_context session] sessionID];
+  
+  SYNCHRONIZED(self) { // this must become a condition lock !!!
+    [self saveSessionForContext:_context];
+    
+    if ([self->checkedOutSessions containsObject:sid])
+      [self->checkedOutSessions removeObject:sid];
+  }
+  END_SYNCHRONIZED;
+}
+
+/* deprecated store */
+
+- (void)saveSession:(WOSession *)_session {
+  IS_DEPRECATED;
+  [self saveSessionForContext:[_session context]];
+}
+- (WOSession *)restoreSessionWithID:(NSString *)_sid {
+  IS_DEPRECATED;
+  return [self restoreSessionWithID:_sid request:nil];
+}
+
+/* store (WO4) */
+
+- (void)saveSessionForContext:(WOContext *)_context {
+  [self subclassResponsibility:_cmd];
+}
+- (WOSession *)restoreSessionWithID:(NSString *)_sid
+  request:(WORequest *)_request
+{
+  [self subclassResponsibility:_cmd];
+  return nil;
+}
+
+@end /* WOSessionStore */
diff --git a/skyrix-sope/NGObjWeb/WOSimpleHTTPParser.h b/skyrix-sope/NGObjWeb/WOSimpleHTTPParser.h
new file mode 100644 (file)
index 0000000..ebc046c
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGObjWeb_WOSimpleHTTPParser_H__
+#define __NGObjWeb_WOSimpleHTTPParser_H__
+
+#import <Foundation/NSObject.h>
+#import <NGStreams/NGStreamProtocols.h>
+
+@class NSData, NSMutableDictionary, NSException, NSString;
+@class WORequest, WOResponse;
+
+/*
+  WOSimpleHTTPParser
+
+  This is a simplified HTTP parser, it only parses HTTP as emitted by the
+  ngobjweb module, for example it doesn't allow chunked content or folded
+  header lines.
+*/
+
+@interface WOSimpleHTTPParser : NSObject
+{
+  id<NGStream> io;
+  unsigned (*readBytes)(id, SEL, void *, unsigned);
+  
+  /* parsing results */
+  NSData              *content;
+  NSMutableDictionary *headers;
+  NSException         *lastException;
+  NSString            *httpVersion;
+  
+  /* parsing state */
+  unsigned char *lineBuffer;
+  unsigned int  lineBufSize;
+  int clen;
+}
+
+- (id)initWithStream:(id<NGStream>)_stream;
+
+/* transient state */
+
+- (void)reset;
+
+/* parsing */
+
+- (WORequest *)parseRequest;
+- (WOResponse *)parseResponse;
+- (NSException *)lastException;
+
+@end
+
+#endif /* __NGObjWeb_WOSimpleHTTPParser_H__ */
diff --git a/skyrix-sope/NGObjWeb/WOSimpleHTTPParser.m b/skyrix-sope/NGObjWeb/WOSimpleHTTPParser.m
new file mode 100644 (file)
index 0000000..25471b1
--- /dev/null
@@ -0,0 +1,941 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOSimpleHTTPParser.h"
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WORequest.h>
+#include "common.h"
+
+@implementation WOSimpleHTTPParser
+
+static Class NSStringClass  = Nil;
+static BOOL  debugOn        = NO;
+static BOOL  heavyDebugOn   = NO;
+static int   fileIOBoundary = 16384;
+static int   maxUploadSize  = 256 * 1024; /* 256MB */
+
++ (int)version {
+  return 1;
+}
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  debugOn        = [ud boolForKey:@"WOSimpleHTTPParserDebugEnabled"];
+  heavyDebugOn   = [ud boolForKey:@"WOSimpleHTTPParserHeavyDebugEnabled"];
+  fileIOBoundary = [ud integerForKey:@"WOSimpleHTTPParserFileIOBoundary"];
+  maxUploadSize  = [ud integerForKey:@"WOSimpleHTTPParserMaxUploadSizeInKB"];
+
+  if (debugOn) {
+    NSLog(@"WOSimpleHTTPParser: max-upload-size:  %dKB", maxUploadSize);
+    NSLog(@"WOSimpleHTTPParser: file-IO boundary: %d",   fileIOBoundary);
+  }
+}
+
+- (id)initWithStream:(id<NGStream>)_stream {
+  if (NSStringClass == Nil) NSStringClass = [NSString class];
+  
+  if ((self = [super init])) {
+    if ((self->io = [_stream retain]) == nil) {
+      [self release];
+      return nil;
+    }
+    
+    self->readBytes = (void *)
+      [(NSObject *)self->io methodForSelector:@selector(readBytes:count:)];
+    if (self->readBytes == NULL) {
+      NSLog(@"WARNING(%s): got invalid stream object: %@", __PRETTY_FUNCTION__,
+           self->io);
+      [self release];
+      return nil;
+    }
+  }
+  return self;
+}
+- (void)dealloc {
+  [self reset];
+  [self->io release];
+  [super dealloc];
+}
+
+/* transient state */
+
+- (void)reset {
+  self->clen = -1;
+  
+  [self->content       release]; self->content     = nil;
+  [self->lastException release]; self->lastException = nil;
+  [self->httpVersion   release]; self->httpVersion   = nil;
+  [self->headers removeAllObjects];
+
+  if (self->lineBuffer) {
+    free(self->lineBuffer);
+    self->lineBuffer = NULL;
+  }
+  self->lineBufSize = 0;
+}
+
+/* low-level reading */
+
+- (unsigned int)defaultLineSize {
+  return 512;
+}
+
+- (NSException *)readNextLine {
+  unsigned i;
+  
+  if (self->lineBuffer == NULL) {
+    self->lineBufSize = [self defaultLineSize];
+    self->lineBuffer  = malloc(self->lineBufSize + 10);
+  }
+  
+  for (i = 0; YES; i++) {
+    register unsigned rc;
+    unsigned char c;
+    
+    rc = self->readBytes(self->io, @selector(readBytes:count:), &c, 1);
+    if (rc != 1) {
+      if (debugOn) {
+       [self debugWithFormat:@"got result %u, exception: %@", 
+               rc, [self->io lastException]];
+      }
+      return [self->io lastException];
+    }
+    
+    /* check buffer capacity */
+    if ((i + 2) > self->lineBufSize) {
+      static int reallocCount = 0;
+      reallocCount++;
+      if (reallocCount > 1000) {
+       static BOOL didLog = NO;
+       if (!didLog) {
+         didLog = YES;
+         NSLog(@"WARNING(%s): reallocated the HTTP line buffer %i times, "
+               @"consider increasing the default line buffer size!",
+               __PRETTY_FUNCTION__, reallocCount);
+       }
+      }
+      
+      if (self->lineBufSize > (56 * 1024)) {
+       /* to avoid DOS attacks ... */
+       return [NSException exceptionWithName:@"HTTPParserHeaderSizeExceeded"
+                           reason:
+                             @"got a HTTP line of 100KB+ (DoS attack?)!"
+                           userInfo:nil];
+      }
+      
+      self->lineBufSize *= 2;
+      self->lineBuffer = realloc(self->lineBuffer, self->lineBufSize + 10);
+    }
+    
+    if (c == '\n') {
+      /* found EOL */
+      break;
+    }
+    else if (c == '\r') {
+      /* skip CR */
+      i--;
+      continue;
+    }
+    else {
+      /* store byte */
+      self->lineBuffer[i] = c;
+    }
+  }
+  self->lineBuffer[i] = 0; /* 0-terminate buffer */
+  
+  return nil /* nil means: everything OK */;
+}
+
+/* common HTTP parsing */
+
+static NSString *ContentLengthHeaderName = @"content-length";
+
+static NSString *stringForHeaderName(unsigned char *p) {
+  /* 
+     process header name
+     
+     we try to be smart to avoid creation of NSString objects ...
+  */
+  register unsigned len;
+  register unsigned char c1;
+  
+  if ((len = strlen(p)) == 0)
+    return @"";
+  c1 = *p;
+
+  switch (len) {
+  case 0:
+  case 1:
+    break;
+  case 2:
+    if (strcasecmp(p, "te") == 0) return @"te";
+    if (strcasecmp(p, "if") == 0) return @"if";
+    break;
+  case 3:
+    if (strcasecmp(p, "via") == 0)   return @"via";
+    if (strcasecmp(p, "age") == 0)   return @"age";
+    if (strcasecmp(p, "p3p") == 0)   return @"p3p";
+    break;
+  case 4: 
+    switch (c1) {
+    case 'd': case 'D':
+      if (strcasecmp(p, "date") == 0) return @"date";
+      break;
+    case 'e': case 'E':
+      if (strcasecmp(p, "etag") == 0) return @"etag";
+      break;
+    case 'f': case 'F':
+      if (strcasecmp(p, "from") == 0) return @"from";
+      break;
+    case 'h': case 'H':
+      if (strcasecmp(p, "host") == 0) return @"host";
+      break;
+    case 'v': case 'V':
+      if (strcasecmp(p, "vary") == 0) return @"vary";
+      break;
+    }
+    break;
+  case 5:
+    if (strcasecmp(p, "allow") == 0) return @"allow";
+    if (strcasecmp(p, "brief") == 0) return @"brief";
+    if (strcasecmp(p, "range") == 0) return @"range";
+    if (strcasecmp(p, "depth") == 0) return @"depth";
+    if (strcasecmp(p, "ua-os") == 0) return @"ua-os"; /* Entourage */
+    break;
+  case 6:
+    switch (c1) {
+    case 'a': case 'A':
+      if (strcasecmp(p, "accept") == 0)        return @"accept";
+      break;
+    case 'c': case 'C':
+      if (strcasecmp(p, "cookie") == 0)        return @"cookie";
+      break;
+    case 'e': case 'E':
+      if (strcasecmp(p, "expect") == 0) return @"expect";
+      break;
+    case 'p': case 'P':
+      if (strcasecmp(p, "pragma") == 0)        return @"pragma";
+      break;
+    case 's': case 'S':
+      if (strcasecmp(p, "server") == 0)        return @"server";
+      break;
+    case 'u': case 'U':
+      if (strcasecmp(p, "ua-cpu") == 0)        return @"ua-cpu"; /* Entourage */
+      break;
+    }
+    break;
+
+  default:
+    switch (c1) {
+    case 'a': case 'A': 
+      if (len > 10) {
+       if (p[6] == '-') {
+         if (strcasecmp(p, "accept-charset")  == 0) return @"accept-charset";
+         if (strcasecmp(p, "accept-encoding") == 0) return @"accept-encoding";
+         if (strcasecmp(p, "accept-language") == 0) return @"accept-language";
+         if (strcasecmp(p, "accept-ranges")   == 0) return @"accept-ranges";
+       }
+       else if (strcasecmp(p, "authorization") == 0)
+         return @"authorization";
+      }
+      break;
+      
+    case 'c': case 'C':
+      if (len > 8) {
+       if (p[7] == '-') {
+         if (strcasecmp(p, "content-length") == 0)  
+           return ContentLengthHeaderName;
+         
+         if (strcasecmp(p, "content-type") == 0)    return @"content-type";
+         if (strcasecmp(p, "content-md5") == 0)     return @"content-md5";
+         if (strcasecmp(p, "content-range") == 0)   return @"content-range";
+         
+         if (strcasecmp(p, "content-encoding") == 0)
+           return @"content-encoding";
+         if (strcasecmp(p, "content-language") == 0)
+           return @"content-language";
+
+         if (strcasecmp(p, "content-location") == 0)
+           return @"content-location";
+         if (strcasecmp(p, "content-class") == 0) /* Entourage */
+           return @"content-class";
+       }
+       else if (strcasecmp(p, "call-back") == 0)
+         return @"call-back";
+      }
+      
+      if (strcasecmp(p, "connection") == 0)    return @"connection";
+      if (strcasecmp(p, "cache-control") == 0) return @"cache-control";
+      
+      break;
+
+    case 'd': case 'D':
+      if (strcasecmp(p, "destination") == 0) return @"destination";
+      if (strcasecmp(p, "destroy")     == 0) return @"destroy";
+      break;
+
+    case 'e': case 'E':
+      if (strcasecmp(p, "expires")   == 0) return @"expires";
+      if (strcasecmp(p, "extension") == 0) return @"extension"; /* Entourage */
+      break;
+
+    case 'i': case 'I':
+      if (strcasecmp(p, "if-modified-since") == 0) 
+        return @"if-modified-since";
+      if (strcasecmp(p, "if-none-match") == 0) /* Entourage */
+        return @"if-none-match";
+      if (strcasecmp(p, "if-match") == 0) 
+        return @"if-match";
+      break;
+
+    case 'k': case 'K':
+      if (strcasecmp(p, "keep-alive") == 0) return @"keep-alive";
+      break;
+      
+    case 'l': case 'L':
+      if (strcasecmp(p, "last-modified") == 0) return @"last-modified";
+      if (strcasecmp(p, "location")      == 0) return @"location";
+      if (strcasecmp(p, "lock-token")    == 0) return @"lock-token";
+      break;
+
+    case 'm': case 'M':
+      if (strcasecmp(p, "ms-webstorage") == 0) return @"ms-webstorage";
+      if (strcasecmp(p, "max-forwards")  == 0) return @"max-forwards";
+      break;
+      
+    case 'n': case 'N':
+      if (len > 16) {
+       if (p[12] == '-') {
+         if (strcasecmp(p, "notification-delay") == 0)
+           return @"notification-delay";
+         if (strcasecmp(p, "notification-type") == 0)
+           return @"notification-type";
+       }
+      }
+      break;
+
+    case 'o': case 'O':
+      if (len == 9) {
+       if (strcasecmp(p, "overwrite") == 0) 
+         return @"overwrite";
+      }
+      break;
+      
+    case 'p': case 'P':
+      if (len == 16) {
+       if (strcasecmp(p, "proxy-connection") == 0) 
+         return @"proxy-connection";
+      }
+      break;
+      
+    case 'r': case 'R':
+      if (len == 7) {
+       if (strcasecmp(p, "referer") == 0) return @"referer";
+      }
+      break;
+      
+    case 's': case 'S':
+      switch (len) {
+      case 21:
+       if (strcasecmp(p, "subscription-lifetime") == 0)
+         return @"subscription-lifetime";
+        break;
+      case 15:
+       if (strcasecmp(p, "subscription-id") == 0)
+         return @"subscription-id";
+        break;
+      case 10:
+       if (strcasecmp(p, "set-cookie") == 0)
+         return @"set-cookie";
+        break;
+      }
+      break;
+      
+    case 't': case 'T':
+      if (strcasecmp(p, "transfer-encoding") == 0) return @"transfer-encoding";
+      if (strcasecmp(p, "translate") == 0)         return @"translate";
+      if (strcasecmp(p, "trailer") == 0)           return @"trailer";
+      if (strcasecmp(p, "timeout") == 0)           return @"timeout";
+      break;
+      
+    case 'u': case 'U':
+      if (strcasecmp(p, "user-agent") == 0) return @"user-agent";
+      break;
+      
+    case 'w': case 'W':
+      if (strcasecmp(p, "www-authenticate") == 0) return @"www-authenticate";
+      if (strcasecmp(p, "warning") == 0)          return @"warning";
+      break;
+      
+    case 'x': case 'X':
+      if ((p[2] == 'w') && (len > 22)) {
+       if (strstr(p, "x-webobjects-") == (void *)p) {
+         p += 13; /* skip x-webobjects- */
+         if (strcmp(p, "server-protocol") == 0)
+           return @"x-webobjects-server-protocol";
+         else if (strcmp(p, "server-protocol") == 0)
+           return @"x-webobjects-server-protocol";
+         else if (strcmp(p, "remote-addr") == 0)
+           return @"x-webobjects-remote-addr";
+         else if (strcmp(p, "remote-host") == 0)
+           return @"x-webobjects-remote-host";
+         else if (strcmp(p, "server-name") == 0)
+           return @"x-webobjects-server-name";
+         else if (strcmp(p, "server-port") == 0)
+           return @"x-webobjects-server-port";
+         else if (strcmp(p, "server-url") == 0)
+           return @"x-webobjects-server-url";
+       }
+      }
+      if (len == 7) {
+       if (strcasecmp(p, "x-cache") == 0)
+         return @"x-cache";
+      }
+      else if (len == 12) {
+       if (strcasecmp(p, "x-powered-by") == 0)
+         return @"x-powered-by";
+      }
+      if (strcasecmp(p, "x-zidestore-name") == 0)
+       return @"x-zidestore-name"; 
+      if (strcasecmp(p, "x-forwarded-for") == 0)
+       return @"x-forwarded-for";
+      if (strcasecmp(p, "x-forwarded-host") == 0)
+       return @"x-forwarded-host";
+      if (strcasecmp(p, "x-forwarded-server") == 0)
+       return @"x-forwarded-server";
+      break;
+    }
+  }
+  
+  if (debugOn)
+    NSLog(@"making custom header name '%s'!", p);
+  
+  /* make name lowercase (we own the buffer, so we can work on it) */
+  {
+    unsigned char *t;
+    
+    for (t = p; *t != '\0'; t++)
+      *t = tolower(*t);
+  }
+  return [[NSString alloc] initWithCString:p];
+}
+
+- (NSException *)parseHeader {
+  NSException *e = nil;
+  
+  while ((e = [self readNextLine]) == nil) {
+    unsigned char *p, *v;
+    unsigned int  idx;
+    NSString *headerName;
+    NSString *headerValue;
+    
+    if (heavyDebugOn)
+      printf("read header line: '%s'\n", self->lineBuffer);
+    
+    if (strlen(self->lineBuffer) == 0) {
+      /* found end of header */
+      break;
+    }
+    
+    p = self->lineBuffer;
+    
+    if (*p == ' ' || *p == '\t') {
+      // TODO: implement folding (remember last header-key, add string)
+      [self logWithFormat:
+              @"ERROR(%s): got a folded HTTP header line, cannot process!",
+             __PRETTY_FUNCTION__];
+      continue;
+    }
+    
+    /* find key/value separator */
+    if ((v = index(p, ':')) == NULL) {
+      [self logWithFormat:@"WARNING: got malformed header line: '%s'",
+             self->lineBuffer];
+      continue;
+    }
+    
+    *v = '\0'; v++; /* now 'p' points to name and 'v' to value */
+    
+    /* skip leading spaces */
+    while (*v != '\0' && (*v == ' ' || *v == '\t'))
+      v++;
+
+    if (*v != '\0') {
+      /* trim trailing spaces */
+      for (idx = strlen(v) - 1; idx >= 0; idx--) {
+        if ((v[idx] != ' ' && v[idx] != '\t'))
+          break;
+        
+        v[idx] = '\0';
+      }
+    }
+    
+    headerName  = stringForHeaderName(p);
+    headerValue = [[NSStringClass alloc] initWithCString:v];
+    
+    if (headerName == ContentLengthHeaderName)
+      self->clen = atoi(v);
+    
+    if (headerName != nil || headerValue != nil) {
+      if (self->headers == nil)
+       self->headers = [[NSMutableDictionary alloc] initWithCapacity:32];
+      
+      [self->headers setObject:headerValue forKey:headerName];
+    }
+    
+    [headerValue release];
+    [headerName  release];
+  }
+  
+  return e;
+}
+
+- (NSException *)parseEntityOfMethod:(NSString *)_method {
+  /*
+    TODO: several cases are caught:
+    a) content-length = 0   => empty data
+    b) content-length small => read into memory
+    c) content-length large => streamed into the filesystem to safe RAM
+    d) content-length unknown => ??
+  */
+  
+  if (self->clen == 0) {
+    /* nothing to do */
+  }
+  else if (self->clen < 0) {
+    /* I think HTTP/1.1 requires a content-length header to be present ? */
+    
+    if ([self->httpVersion isEqualToString:@"HTTP/1.0"] ||
+       [self->httpVersion isEqualToString:@"HTTP/0.9"]) {
+      /* content-length unknown, read till EOF */
+      BOOL readToEOF = YES;
+
+      if ([_method isEqualToString:@"HEAD"])
+       readToEOF = NO;
+      else if ([_method isEqualToString:@"GET"])
+       readToEOF = NO;
+      else if ([_method isEqualToString:@"DELETE"])
+       readToEOF = NO;
+      
+      if (readToEOF) {
+       [self logWithFormat:
+               @"WARNING: not processing entity of request "
+               @"without contentlen!"];
+      }
+    }
+  }
+  else if (self->clen > maxUploadSize*1024) {
+    /* entity is too large */
+    return [NSException exceptionWithName:@"LimitException"
+                       reason:
+                         @"the maximum HTTP transaction size was exceeded"
+                       userInfo:nil];
+  }
+  else if (self->clen > fileIOBoundary) {
+    /* we are streaming the content to a file and use a memory mapped data */
+    unsigned toGo;
+    NSString *fn;
+    char buf[4096];
+    BOOL ok = YES;
+    int  writeError = 0;
+    FILE *t;
+    
+    [self debugWithFormat:@"streaming %i bytes into file ...", self->clen];
+    
+    fn = [[NSProcessInfo processInfo] temporaryFileName];
+    
+    if ((t = fopen([fn cString], "w")) == NULL) {
+      [self logWithFormat:@"ERROR: could not open temporary file '%@'!", fn];
+      
+      /* read into memory as a fallback ... */
+      
+      self->content =
+       [[(NGStream *)self->io safeReadDataOfLength:self->clen] retain];
+      if (self->content == nil)
+       return [self->io lastException];
+      return nil;
+    }
+    
+    for (toGo = self->clen; toGo > 0; ) {
+      unsigned readCount, writeCount;
+      
+      /* read from socket */
+      readCount = [self->io readBytes:buf count:sizeof(buf)];
+      if (readCount == NGStreamError) {
+       /* an error */
+       ok = NO;
+       break;
+      }
+      toGo -= readCount;
+      
+      /* write to file */
+      if ((writeCount = fwrite(buf, readCount, 1, t)) != 1) {
+       /* an error */
+       ok = NO;
+       writeError = ferror(t);
+       break;
+      }
+    }
+    fclose(t);
+    
+    if (!ok) {
+      unlink([fn cString]); /* delete temporary file */
+      
+      if (writeError == 0) {
+       return [NSException exceptionWithName:@"SystemWriteError"
+                           reason:@"failed to write data to upload file"
+                           userInfo:nil];
+      }
+      
+      return [self->io lastException];
+    }
+    
+    self->content = [[NSData alloc] initWithContentsOfMappedFile:fn];
+    unlink([fn cString]); /* if the mmap disappears, the storage is freed */
+  }
+  else {
+    /* content-length known and small */
+    //[self logWithFormat:@"reading %i bytes of the entity", self->clen];
+    
+    self->content =
+      [[(NGStream *)self->io safeReadDataOfLength:self->clen] retain];
+    if (self->content == nil)
+      return [self->io lastException];
+    
+    //[self logWithFormat:@"read %i bytes.", [self->content length]];
+  }
+  
+  return nil;
+}
+
+/* handling expectations */
+
+- (BOOL)processContinueExpectation {
+  // TODO: this should check the credentials of a request before accepting the
+  //       body. The current implementation is far from optimal and only added
+  //       for Mono compatibility (and actually produces the same behaviour
+  //       like with HTTP/1.0 ...)
+  static unsigned char *contStatLine = 
+    "HTTP/1.0 100 Continue\r\n"
+    "content-length: 0\r\n"
+    "\r\n";
+  static unsigned char *failStatLine = 
+    "HTTP/1.0 417 Expectation Failed\r\n"
+    "content-length: 0\r\n"
+    "\r\n";
+  unsigned char *respline = NULL;
+  BOOL ok = YES;
+  
+  [self debugWithFormat:@"process 100 continue on IO: %@", self->io];
+  
+  if (self->clen > 0 && (self->clen > (maxUploadSize * 1024))) {
+    // TODO: return a 417 expectation failed
+    ok = NO;
+    respline = failStatLine;
+  }
+  else {
+    ok = YES;
+    respline = contStatLine;
+  }
+  
+  if (![self->io safeWriteBytes:respline count:strlen(respline)]) {
+    ASSIGN(self->lastException, [self->io lastException]);
+    return NO;
+  }
+  if (![self->io flush]) {
+    ASSIGN(self->lastException, [self->io lastException]);
+    return NO;
+  }
+  
+  return ok;
+}
+
+/* parsing */
+
+- (WORequest *)parseRequest {
+  NSException *e = nil;
+  WORequest   *r = nil;
+  NSString    *uri    = @"/";
+  NSString    *method = @"GET";
+  NSString    *expect;
+  
+  [self reset];
+  if (heavyDebugOn)
+    [self logWithFormat:@"HeavyDebug: parsing response ..."];
+  
+  /* process request line */
+  
+  if ((e = [self readNextLine])) {
+    ASSIGN(self->lastException, e);
+    return nil;
+  }
+  if (heavyDebugOn)
+    printf("read request line: '%s'\n", self->lineBuffer);
+  
+  {
+    /* sample line: "GET / HTTP/1.0" */
+    unsigned char *p, *t;
+    
+    /* parse method */
+    
+    p = self->lineBuffer;
+    if ((t = index(p, ' ')) == NULL) {
+      [self logWithFormat:@"got broken request line '%s'", self->lineBuffer];
+      return nil;
+    }
+    *t = '\0';
+    
+    switch (*p) {
+      /* intended fall-throughs ! */
+    case 'b': case 'B':
+      if (strcasecmp(p, "BPROPFIND")  == 0) { method = @"BPROPFIND";  break; }
+      if (strcasecmp(p, "BPROPPATCH") == 0) { method = @"BPROPPATCH"; break; }
+    case 'c': case 'C':
+      if (strcasecmp(p, "COPY")     == 0) { method = @"COPY";     break; }
+      if (strcasecmp(p, "CHECKOUT") == 0) { method = @"CHECKOUT"; break; }
+      if (strcasecmp(p, "CHECKIN")  == 0) { method = @"CHECKIN";  break; }
+    case 'd': case 'D':
+      if (strcasecmp(p, "DELETE")  == 0) { method = @"DELETE"; break; }
+    case 'h': case 'H':
+      if (strcasecmp(p, "HEAD")    == 0) { method = @"HEAD";   break; }
+    case 'l': case 'L':
+      if (strcasecmp(p, "LOCK")    == 0) { method = @"LOCK";   break; }
+    case 'g': case 'G':
+      if (strcasecmp(p, "GET")     == 0) { method = @"GET";    break; }
+    case 'm': case 'M':
+      if (strcasecmp(p, "MKCOL")   == 0) { method = @"MKCOL";  break; }
+      if (strcasecmp(p, "MOVE")    == 0) { method = @"MOVE";   break; }
+    case 'n': case 'N':
+      if (strcasecmp(p, "NOTIFY")  == 0) { method = @"NOTIFY"; break; }
+    case 'o': case 'O':
+      if (strcasecmp(p, "OPTIONS") == 0) { method = @"OPTIONS"; break; }
+    case 'p': case 'P':
+      if (strcasecmp(p, "PUT")       == 0) { method = @"PUT";       break; }
+      if (strcasecmp(p, "POST")      == 0) { method = @"POST";      break; }
+      if (strcasecmp(p, "PROPFIND")  == 0) { method = @"PROPFIND";  break; }
+      if (strcasecmp(p, "PROPPATCH") == 0) { method = @"PROPPATCH"; break; }
+      if (strcasecmp(p, "POLL")      == 0) { method = @"POLL";      break; }
+    case 'r': case 'R':
+      if (strcasecmp(p, "REPORT")    == 0) { method = @"REPORT";    break; }
+    case 's': case 'S':
+      if (strcasecmp(p, "SEARCH")    == 0) { method = @"SEARCH";    break; }
+      if (strcasecmp(p, "SUBSCRIBE") == 0) { method = @"SUBSCRIBE"; break; }
+    case 'u': case 'U':
+      if (strcasecmp(p, "UNLOCK")     == 0) { method = @"UNLOCK";      break; }
+      if (strcasecmp(p, "UNSUBSCRIBE")== 0) { method = @"UNSUBSCRIBE"; break; }
+      if (strcasecmp(p, "UNCHECKOUT") == 0) { method = @"UNCHECKOUT";  break; }
+    case 'v': case 'V':
+      if (strcasecmp(p, "VERSION-CONTROL") == 0) { 
+        method = @"VERSION-CONTROL";      
+        break; 
+      }
+      
+    default:
+      if (debugOn)
+        [self debugWithFormat:@"making custom HTTP method name: '%s'", p];
+      method = [NSString stringWithCString:p];
+      break;
+    }
+    
+    /* parse URI */
+    
+    p = t + 1; /* skip space */
+    while (*p != '\0' && (*p == ' ' || *p == '\t')) /* skip spaces */
+      p++;
+    
+    if (*p == '\0') {
+      [self logWithFormat:@"got broken request line '%s'", self->lineBuffer];
+      return nil;
+    }
+    
+    if ((t = index(p, ' ')) == NULL) {
+      /* the URI isn't followed by a HTTP version */
+      self->httpVersion = @"HTTP/0.9";
+      /* TODO: strip trailing spaces for better compliance */
+      uri = [NSString stringWithCString:p];
+    }
+    else {
+      *t = '\0';
+      uri = [NSString stringWithCString:p];
+
+      /* parse version */
+      
+      p = t + 1; /* skip space */
+      while (*p != '\0' && (*p == ' ' || *p == '\t')) /* skip spaces */
+       p++;
+      
+      if (*p == '\0')
+       self->httpVersion = @"HTTP/0.9";
+      else if (strcasecmp(p, "http/1.0") == 0)
+       self->httpVersion = @"HTTP/1.0";
+      else if (strcasecmp(p, "http/1.1") == 0)
+       self->httpVersion = @"HTTP/1.1";
+      else {
+       /* TODO: strip trailing spaces */
+       self->httpVersion = [[NSString alloc] initWithCString:p];
+      }
+    }
+  }
+  
+  /* process header */
+  
+  if ((e = [self parseHeader])) {
+    ASSIGN(self->lastException, e);
+    return nil;
+  }
+  if (heavyDebugOn)
+    [self logWithFormat:@"parsed header: %@", self->headers];
+  
+  /* check for expectations */
+  
+  if ((expect = [self->headers objectForKey:@"expect"])) {
+    if ([expect rangeOfString:@"100-continue" 
+                options:NSCaseInsensitiveSearch].length > 0) {
+      if (![self processContinueExpectation])
+        return nil;
+    }
+  }
+  
+  /* process body */
+  
+  if (clen != 0) {
+    if ((e = [self parseEntityOfMethod:method])) {
+      ASSIGN(self->lastException, e);
+      return nil;
+    }
+  }
+  
+  if (heavyDebugOn)
+    [self logWithFormat:@"HeavyDebug: got all .."];
+  
+  r = [[WORequest alloc] initWithMethod:method
+                        uri:uri
+                        httpVersion:self->httpVersion
+                        headers:self->headers
+                        content:self->content
+                        userInfo:nil];
+  [self reset];
+  
+  if (heavyDebugOn)
+    [self logWithFormat:@"HeavyDebug: request: %@", r];
+  
+  return [r autorelease];
+}
+
+- (WOResponse *)parseResponse {
+  NSException *e           = nil;
+  int         code         = 200;
+  WOResponse  *r = nil;
+  
+  [self reset];
+  if (heavyDebugOn)
+    [self logWithFormat:@"HeavyDebug: parsing response ..."];
+  
+  /* process response line */
+  
+  if ((e = [self readNextLine])) {
+    ASSIGN(self->lastException, e);
+    return nil;
+  }
+  if (heavyDebugOn)
+    printf("read response line: '%s'\n", self->lineBuffer);
+  
+  {
+    /* sample line: "HTTP/1.0 200 OK" */
+    unsigned char *p, *t;
+    
+    /* version */
+    
+    p = self->lineBuffer;
+    if ((t = index(p, ' ')) == NULL) {
+      [self logWithFormat:@"got broken response line '%s'", self->lineBuffer];
+      return nil;
+    }
+    
+    *t = '\0';
+    if (strcasecmp(p, "http/1.0") == 0)
+      self->httpVersion = @"HTTP/1.0";
+    else if (strcasecmp(p, "http/1.1") == 0)
+      self->httpVersion = @"HTTP/1.1";
+    else
+      self->httpVersion = [[NSString alloc] initWithCString:p];
+    
+    /* code */
+    
+    p = t + 1; /* skip space */
+    while (*p != '\0' && (*p == ' ' || *p == '\t')) /* skip spaces */
+      p++;
+    if (*p == '\0') {
+      [self logWithFormat:@"got broken response line '%s'", self->lineBuffer];
+      return nil;
+    }
+    code = atoi(p);
+    
+    /* we don't need to parse a reason ... */
+  }
+  
+  /* process header */
+  
+  if ((e = [self parseHeader])) {
+    ASSIGN(self->lastException, e);
+    return nil;
+  }
+  if (heavyDebugOn)
+    [self logWithFormat:@"parsed header: %@", self->headers];
+  
+  /* process body */
+  
+  if (clen != 0) {
+    if ((e = [self parseEntityOfMethod:nil /* parsing a response */])) {
+      ASSIGN(self->lastException, e);
+      return nil;
+    }
+  }
+  
+  if (heavyDebugOn)
+    [self logWithFormat:@"HeavyDebug: got all .."];
+  
+  r = [[[WOResponse alloc] init] autorelease];
+  [r setStatus:code];
+  [r setHTTPVersion:self->httpVersion];
+  [r setHeaders:self->headers];
+  [r setContent:self->content];
+  
+  [self reset];
+  
+  if (heavyDebugOn)
+    [self logWithFormat:@"HeavyDebug: response: %@", r];
+  
+  return r;
+}
+
+- (NSException *)lastException {
+  return self->lastException;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* WOSimpleHTTPParser */
diff --git a/skyrix-sope/NGObjWeb/WOStatisticsStore.m b/skyrix-sope/NGObjWeb/WOStatisticsStore.m
new file mode 100644 (file)
index 0000000..ed2e9e1
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOStatisticsStore.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOComponent.h>
+#include "common.h"
+
+@interface _WOPageStats : NSObject
+{
+@public
+  NSString       *pageName;
+  unsigned       totalResponseCount;
+  unsigned       totalResponseSize;
+  unsigned       zippedResponsesCount;
+  unsigned       totalZippedSize;
+  unsigned       largestResponseSize;
+  unsigned       smallestResponseSize;
+  NSTimeInterval minimumDuration;
+  NSTimeInterval maximumDuration;
+  NSTimeInterval totalDuration;
+}
+@end
+
+@implementation WOStatisticsStore
+
+static unsigned char *monthAbbr[13] = {
+  "Dec",
+  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+static NSTimeZone *gmt = nil;
+static Class NSNumberClass    = Nil;
+static Class NSStringClass    = Nil;
+static BOOL  runMultithreaded = NO;
+
++ (int)version {
+  return 1;
+}
+
++ (void)initialize {
+  NSNumberClass = [NSNumber class];
+  NSStringClass = [NSString class];
+
+  if (gmt == nil)
+    gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+
+  runMultithreaded = [[NSUserDefaults standardUserDefaults]
+                      boolForKey:@"WORunMultithreaded"];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->startTime = [[NSDate date] copy];
+    self->smallestResponseSize = -1;
+    self->totalDuration = 0.0;
+    
+    if (runMultithreaded)
+      self->lock = [[NSRecursiveLock alloc] init];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->pageStatistics release];
+  [self->startTime      release];
+  [self->lock           release];
+  [super dealloc];
+}
+
+/* query */
+
+static id mkuint(unsigned int i) {
+  return [NSNumberClass numberWithUnsignedInt:i];
+}
+static id mkdbl(double d) {
+#if 1
+  unsigned char buf[64];
+  sprintf(buf, "%.3f", d);
+  return [NSStringClass stringWithCString:buf];
+#else
+  return [NSNumberClass numberWithDouble:d];
+#endif
+}
+
+- (NSDictionary *)statisticsForPageNamed:(NSString *)_pageName {
+  // TODO: fix inefficient use of NSString
+  NSMutableDictionary *stats;
+  _WOPageStats        *pageStats;
+
+  if ((pageStats = [self->pageStatistics objectForKey:_pageName]) == nil)
+    return nil;
+
+  stats = [NSMutableDictionary dictionaryWithCapacity:16];
+
+  [stats setObject:mkuint(pageStats->totalResponseSize)
+         forKey:@"totalResponseSize"];
+  [stats setObject:mkuint(pageStats->totalResponseCount)
+         forKey:@"totalResponseCount"];
+  [stats setObject:mkdbl(pageStats->totalDuration)
+         forKey:@"totalDuration"];
+
+  if (pageStats->smallestResponseSize >= 0) {
+    [stats setObject:mkuint(pageStats->largestResponseSize)
+           forKey:@"largestResponseSize"];
+    [stats setObject:mkuint(pageStats->smallestResponseSize)
+           forKey:@"smallestResponseSize"];
+    [stats setObject:mkdbl(pageStats->minimumDuration)
+           forKey:@"minimumDuration"];
+    [stats setObject:mkdbl(pageStats->maximumDuration)
+           forKey:@"maximumDuration"];
+  }
+  
+  if (pageStats->totalResponseCount > 0) {
+    [stats setObject:
+             mkuint(pageStats->totalResponseSize / pageStats->totalResponseCount)
+           forKey:@"averageResponseSize"];
+    [stats setObject:
+             mkdbl(pageStats->totalDuration / pageStats->totalResponseCount)
+           forKey:@"averageDuration"];
+  }
+  
+  [stats setObject:mkuint(pageStats->zippedResponsesCount)
+         forKey:@"numberOfZippedResponses"];
+  [stats setObject:mkuint(pageStats->totalZippedSize)
+         forKey:@"totalZippedSize"];
+  
+  /* calc frequencies */
+  {
+    double d;
+    
+    d = ((double)self->totalResponseCount) / 100.0; // one percent
+    d = ((double)pageStats->totalResponseCount) / d; // percents of total
+    [stats setObject:[NSStringClass stringWithFormat:@"%.3f%%", d]
+           forKey:@"responseFrequency"];
+    
+    d = ((double)self->totalDuration) / 100.0; // one percent
+    d = ((double)pageStats->totalDuration) / d; // percents of total
+    [stats setObject:[NSStringClass stringWithFormat:@"%.3f%%", d]
+           forKey:@"relativeTimeConsumption"];
+    
+    d = ((double)self->pageResponseCount) / 100.0; // one percent
+    d = ((double)pageStats->totalResponseCount) / d; // percents of total
+    [stats setObject:[NSStringClass stringWithFormat:@"%.3f%%", d]
+           forKey:@"pageFrequency"];
+
+    
+    d = ((double)self->totalResponseSize) / 100.0; // one percent
+    d = ((double)pageStats->totalResponseSize) / d; // percents of total
+    [stats setObject:[NSStringClass stringWithFormat:@"%.3f%%", d]
+           forKey:@"pageDeliveryVolume"];
+  }
+  
+  return stats;
+}
+
+- (NSDictionary *)statistics {
+  NSMutableDictionary *stats;
+  NSDate   *now;
+  double   uptime;
+  
+  stats  = [NSMutableDictionary dictionaryWithCapacity:64];
+  now    = [NSDate date];
+  uptime = [now timeIntervalSinceDate:self->startTime];
+  
+  [stats setObject:mkuint(self->totalResponseSize)
+         forKey:@"totalResponseSize"];
+  [stats setObject:mkuint(self->totalResponseCount)
+         forKey:@"totalResponseCount"];
+  [stats setObject:mkdbl(self->totalDuration)
+         forKey:@"totalDuration"];
+  [stats setObject:mkuint(self->pageResponseCount)
+         forKey:@"pageResponseCount"];
+  if (self->smallestResponseSize >= 0) {
+    [stats setObject:mkuint(self->largestResponseSize)
+           forKey:@"largestResponseSize"];
+    [stats setObject:mkuint(self->smallestResponseSize)
+           forKey:@"smallestResponseSize"];
+    [stats setObject:mkdbl(self->minimumDuration)
+           forKey:@"minimumDuration"];
+    [stats setObject:mkdbl(self->maximumDuration)
+           forKey:@"maximumDuration"];
+  }
+
+  if ((self->totalDuration > 0) && (uptime > 0)) {
+    [stats setObject:
+             [NSStringClass stringWithFormat:@"%.3f%%",
+                         self->totalDuration / (uptime / 100.0)]
+           forKey:@"instanceLoad"];
+  }
+  
+  if (self->totalResponseCount > 0) {
+    [stats setObject:mkuint(self->totalResponseSize / self->totalResponseCount)
+           forKey:@"averageResponseSize"];
+    [stats setObject:mkdbl(self->totalDuration / self->totalResponseCount)
+           forKey:@"averageDuration"];
+  }
+  
+  [stats setObject:self->startTime forKey:@"instanceStartDate"];
+  [stats setObject:now             forKey:@"statisticsDate"];
+  [stats setObject:[NSStringClass stringWithFormat:@"%.3f", uptime]
+         forKey:@"instanceUptime"];
+  [stats setObject:[NSStringClass stringWithFormat:@"%.3f", uptime / 3600.0]
+         forKey:@"instanceUptimeInHours"];
+
+  [stats setObject:mkuint(self->zippedResponsesCount)
+         forKey:@"numberOfZippedResponses"];
+  [stats setObject:mkuint(self->totalZippedSize)
+         forKey:@"totalZippedSize"];
+  
+  /* page statistics */
+  {
+    NSEnumerator        *pageNames;
+    NSString            *pageName;
+    NSMutableDictionary *pageStats;
+
+    pageStats = [NSMutableDictionary dictionaryWithCapacity:16];
+    pageNames = [self->pageStatistics keyEnumerator];
+    while ((pageName = [pageNames nextObject])) {
+      NSDictionary *s;
+
+      s = [self statisticsForPageNamed:pageName];
+      if (s == nil)
+        continue;
+      
+      [pageStats setObject:s forKey:pageName];
+    }
+    
+    if (pageStats)
+      [stats setObject:pageStats forKey:@"pageStatistics"];
+  }
+  
+  return stats;
+}
+
+/* recording */
+
+- (void)recordStatisticsForResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  WOComponent    *page;
+  unsigned       size;
+  NSNumber       *zippedSize;
+  NSDate         *requestStartDate;
+  NSDate         *now;
+  NSTimeInterval duration;
+  
+  zippedSize = [[_response userInfo] objectForKey:@"WOResponseZippedLength"];
+  if (zippedSize) {
+    size = [[[_response userInfo] objectForKey:@"WOResponseUnzippedLength"]
+                                 unsignedIntValue];
+  }
+  else
+    size = [[_response content] length];
+  
+  requestStartDate =
+    [[[_context request] userInfo] objectForKey:@"WORequestStartDate"];
+  now = [NSDate date];
+  
+  duration = (requestStartDate)
+    ? [now timeIntervalSinceDate:requestStartDate]
+    : 0.0;
+  
+  self->totalResponseCount++;
+  self->totalResponseSize += size;
+  self->totalDuration     += duration;
+  
+  if (self->smallestResponseSize == -1) {
+    /* first request */
+    self->largestResponseSize  = size;
+    self->smallestResponseSize = size;
+    self->maximumDuration      = duration;
+    self->minimumDuration      = duration;
+  }
+  else {
+    if (size > self->largestResponseSize)  self->largestResponseSize = size;
+    if (size < self->smallestResponseSize) self->smallestResponseSize = size;
+    if (duration > self->maximumDuration)  self->maximumDuration = duration;
+    if (duration < self->minimumDuration)  self->minimumDuration = duration;
+  }
+  
+  if (zippedSize) {
+    self->zippedResponsesCount++;
+    self->totalZippedSize += [zippedSize unsignedIntValue];
+  }
+  
+  if ((page = [_context page])) {
+    _WOPageStats *pageStats;
+    
+    self->pageResponseCount++;
+    
+    if (self->pageStatistics == nil)
+      self->pageStatistics = [[NSMutableDictionary alloc] initWithCapacity:64];
+    
+    if ((pageStats = [self->pageStatistics objectForKey:[page name]]) == nil) {
+      pageStats = [[[_WOPageStats alloc] init] autorelease];
+      pageStats->pageName = [[page name] copy];
+
+      pageStats->largestResponseSize  = size;
+      pageStats->smallestResponseSize = size;
+      pageStats->maximumDuration      = duration;
+      pageStats->minimumDuration      = duration;
+      
+      [self->pageStatistics setObject:pageStats forKey:pageStats->pageName];
+    }
+    else {
+      if (size > pageStats->largestResponseSize)
+        pageStats->largestResponseSize = size;
+      if (size < pageStats->smallestResponseSize)
+        pageStats->smallestResponseSize = size;
+      if (duration > pageStats->maximumDuration)
+        pageStats->maximumDuration = duration;
+      if (duration < pageStats->minimumDuration)
+        pageStats->minimumDuration = duration;
+    }
+    
+    pageStats->totalResponseCount++;
+    pageStats->totalResponseSize += size;
+    pageStats->totalDuration     += duration;
+    
+    if (zippedSize) {
+      pageStats->zippedResponsesCount++;
+      pageStats->totalZippedSize += [zippedSize unsignedIntValue];
+    }
+  }
+}
+
+- (NSString *)descriptionForResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  NSString    *result;
+  WOComponent *page;
+
+  if ((page = [_context page]) == nil) {
+    return [NSStringClass stringWithFormat:
+                           @"<no page generated for context %@>",
+                           _context];
+  }
+  
+  result =
+    [page respondsToSelector:@selector(descriptionForResponse:inContext:)]
+    ? [page descriptionForResponse:_response inContext:_context]
+    : [page name];
+  return result;
+}
+
+/* formatting */
+
+- (NSString *)formatDescription:(NSString *)_description
+  forResponse:(WOResponse *)_response
+  inContext:(WOContext *)_context
+{
+  NSMutableString *result;
+  WORequest       *request;
+  NSString        *remoteHost = @"-";
+  NSCalendarDate  *now;
+  NSDate          *startDate;
+  NSString        *tmp;
+  unsigned char   buf[64];
+  
+  request = [_context request];
+  result  = [NSMutableString stringWithCapacity:256];
+  
+  /* remote host and date */
+
+  if ((remoteHost = [request headerForKey:@"x-webobjects-remote-host"]))
+    ;
+  else if ((remoteHost = [request headerForKey:@"x-webobjects-remote-addr"]))
+    ;
+  else
+    remoteHost = @"-";
+  
+  now = [NSCalendarDate date];
+  [now setTimeZone:gmt];
+  
+  [result appendString:remoteHost];
+  sprintf(buf, 
+         " - - [%02i/%s/%04i:%02i:%02i:%02i GMT] ",
+         [now dayOfMonth], monthAbbr[[now monthOfYear]], 
+         [now yearOfCommonEra],
+         [now hourOfDay], [now minuteOfHour], [now secondOfMinute]);
+  tmp = [[NSStringClass alloc] initWithCString:buf];
+  [result appendString:tmp];
+  [tmp release];
+  
+  /* request */
+  
+  [result appendString:@"\""];
+  [result appendString:[request method]];
+  [result appendString:@" "];
+  [result appendString:[request uri]];
+  [result appendString:@" "];
+  [result appendString:[request httpVersion]];
+  [result appendString:@"\" "];
+
+  /* response */
+  
+  [result appendFormat:@"%i %i",
+            [_response status], [[_response content] length]];
+  
+  startDate = [[request userInfo] objectForKey:@"WORequestStartDate"];
+  if (startDate) {
+    NSTimeInterval duration;
+    
+    duration = [now timeIntervalSinceDate:startDate];
+    sprintf(buf, " %.3f", duration);
+    tmp = [[NSStringClass alloc] initWithCString:buf];
+    [result appendString:tmp];
+    [tmp release];
+  }
+  
+  return result;
+}
+
+/* NSLocking */
+
+- (void)lock {
+  [self->lock lock];
+}
+- (void)unlock {
+  [self->lock unlock];
+}
+
+@end /* WOStatisticsStore */
+
+@implementation _WOPageStats
+
+- (id)init {
+  self->totalDuration   = 0.0;
+  self->minimumDuration = 0.0;
+  self->maximumDuration = 0.0;
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->pageName);
+  [super dealloc];
+}
+
+@end /* _WOPageStats */
diff --git a/skyrix-sope/NGObjWeb/WOStats.m b/skyrix-sope/NGObjWeb/WOStats.m
new file mode 100644 (file)
index 0000000..8311b85
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODirectAction.h>
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOResourceManager.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOSession.h>
+#include <NGObjWeb/WOStatisticsStore.h>
+#include "common.h"
+
+@interface WOApplication(MemoryStatistics)
+
+- (NSDictionary *)memoryStatistics;
+
+@end
+
+@implementation WOApplication(MemoryStatistics)
+
+- (NSDictionary *)memoryStatistics {
+#ifdef __linux__
+  FILE     *f;
+  char     buf[4096];
+  char     fname[256];
+  unsigned len;
+
+  sprintf(fname, "/proc/%d/status", getpid());
+  if ((f = fopen(fname, "r"))) {
+    id           d = nil;
+    NSString     *s;
+    NSEnumerator *lines;
+    
+    len = fread(buf, 1, sizeof(buf) - 1, f);
+    fclose(f);
+    buf[len] = '\0';
+
+    s = [NSString stringWithCString:buf];
+    lines = [[s componentsSeparatedByString:@"\n"] objectEnumerator];
+    while ((s = [lines nextObject])) {
+      NSString *key;
+      NSRange rng;
+
+      rng = [s rangeOfString:@":"];
+      if (rng.length <= 0)
+        continue;
+
+      key = [s substringToIndex:rng.location];
+
+      if ([key hasPrefix:@"Vm"]) {
+        const char *cstr;
+        id value;
+        
+        cstr = [s cString];
+        while (*cstr != '\0' && *cstr != ':') cstr++;
+        if (*cstr == '\0') continue;
+        cstr++;
+        while (*cstr != '\0' && isspace(*cstr)) cstr++;
+        value = [NSString stringWithCString:cstr];
+        
+        if ([value hasSuffix:@" kB"]) {
+          value = [value substringToIndex:[value length] - 3];
+          value = [NSNumber numberWithInt:[value intValue] * 1024];
+        }
+        
+        if (d == nil) d = [NSMutableDictionary dictionary];
+        [d setObject:value forKey:key];
+      }
+    }
+    return d;
+  }
+#endif
+  return nil;
+}
+
+@end /* WOApplication(MemoryStatistics) */
+
+@implementation WODirectAction(WOStats)
+
+- (id<WOActionResults>)WOStatsAction {
+  WOApplication *app;
+  WOResponse   *response;
+  NSDictionary *stats;
+  NSString     *xslPath;
+  NSArray      *languages;
+  static NSDictionary *keyToDataType = nil;
+  
+  if (keyToDataType == nil) {
+    keyToDataType =
+      [[NSDictionary alloc] initWithObjectsAndKeys:
+                                  @"number", @"averageDuration",
+                                  @"number", @"maximumDuration",
+                                  @"number", @"minimumDuration",
+                                  @"number", @"totalDuration",
+                                  @"number", @"instanceUptime",
+                                  @"number", @"instanceUptimeInHours",
+                                  @"number", @"instanceLoad",
+                                  @"number", @"pageResponseCount",
+                                  @"number", @"numberOfZippedResponses",
+                                  @"number", @"totalResponseCount",
+                                  @"number", @"pageFrequency",
+                                  @"number", @"pageDeliveryVolumne",
+                                  @"number", @"responseFrequency",
+                                  @"number", @"relativeTimeConsumption",
+                                  @"number", @"averageResponseSize",
+                                  @"number", @"totalResponseSize",
+                                  @"number", @"totalZippedSize",
+                                  @"number", @"smallestResponseSize",
+                                  @"number", @"largestResponseSize",
+                                  @"number", @"VmData",
+                                  @"number", @"VmExe",
+                                  @"number", @"VmRSS",
+                                  @"number", @"VmLib",
+                                  @"number", @"VmStk",
+                                  @"number", @"VmSize",
+                                  @"number", @"VmLck",
+                                  nil];
+  }
+  
+  app = [WOApplication application];
+
+  xslPath = [[NSUserDefaults standardUserDefaults]
+                             stringForKey:@"WOStatsStylesheetName"];
+  languages = [self existingSession] != nil
+    ? [[self session] languages]
+    : [[self request] browserLanguages];
+  xslPath = [[app resourceManager] urlForResourceNamed:xslPath
+                                   inFramework:nil
+                                   languages:languages
+                                   request:[self request]];
+  if ([xslPath hasPrefix:@"/missingresource"])
+    xslPath = nil;
+  
+  response = [WOResponse responseWithRequest:[self request]];
+  [response setHeader:@"text/xml" forKey:@"content-type"];
+  
+  stats = [[app statisticsStore] statistics];
+  
+  [response appendContentString:@"<?xml version='1.0'?>\n"];
+#if 1
+  if ([xslPath length] > 0) {
+    [response appendContentString:@"<?xml-stylesheet type='text/xsl' href='"];
+    [response appendContentString:xslPath];
+    [response appendContentString:@"'?>"];
+  }
+#endif
+  [response appendContentString:@"<application name='"];
+  [response appendContentString:[app name]];
+  [response appendContentString:@"'"];
+  [response appendContentString:
+              [NSString stringWithFormat:@" pid='%d'", getpid()]];
+  [response appendContentString:
+              @" xmlns:dt='urn:schemas-microsoft-com:datatypes'>\n"];
+  
+  {
+    NSEnumerator *e;
+    NSString *key;
+    NSDictionary *pageStatistics;
+    
+    /* application statistics */
+    
+    e = [stats keyEnumerator];
+    while ((key = [e nextObject])) {
+      id value;
+      NSString *dt;
+      
+      if ([key isEqualToString:@"pageStatistics"])
+        continue;
+
+      value = [stats objectForKey:key];
+      
+      [response appendContentString:@"  <"];
+      [response appendContentString:key];
+        
+      if ((dt = [keyToDataType objectForKey:key])) {
+        [response appendContentString:@" dt:dt='"];
+        [response appendContentString:dt];
+        [response appendContentString:@"'"];
+      }
+      
+      [response appendContentString:@">"];
+      
+      [response appendContentHTMLString:[value stringValue]];
+      
+      [response appendContentString:@"</"];
+      [response appendContentString:key];
+      [response appendContentString:@">\n"];
+    }
+
+    /* memory statistics */
+
+    {
+      NSDictionary *mem;
+      
+      mem = [app memoryStatistics];
+
+      if ([mem count] > 0) {
+        [response appendContentString:@"  <memory>\n"];
+        
+        e = [mem keyEnumerator];
+        while ((key = [e nextObject])) {
+          id       value;
+          NSString *dt;
+
+          value = [mem objectForKey:key];
+          
+          [response appendContentString:@"  <"];
+          [response appendContentString:key];
+        
+          if ((dt = [keyToDataType objectForKey:key])) {
+            [response appendContentString:@" dt:dt='"];
+            [response appendContentString:dt];
+            [response appendContentString:@"'"];
+          }
+      
+          [response appendContentString:@">"];
+      
+          [response appendContentHTMLString:[value stringValue]];
+      
+          [response appendContentString:@"</"];
+          [response appendContentString:key];
+          [response appendContentString:@">\n"];
+        }
+
+        [response appendContentString:@"  </memory>\n"];
+      }
+    }
+
+    /* page statistics */
+    
+    pageStatistics = [stats objectForKey:@"pageStatistics"];
+
+    [response appendContentString:@"  <pages>\n"];
+    
+    e = [pageStatistics keyEnumerator];
+    while ((key = [e nextObject])) {
+      NSDictionary *stats;
+      NSEnumerator *e2;
+      NSString     *key2;
+      
+      stats = [pageStatistics objectForKey:key];
+      e2    = [stats keyEnumerator];
+      
+      [response appendContentString:@"    <page name='"];
+      [response appendContentString:key];
+      [response appendContentString:@"'>\n"];
+      
+      while ((key2 = [e2 nextObject])) {
+        id value;
+        NSString *dt;
+
+        value = [stats objectForKey:key2];
+        
+        [response appendContentString:@"      <"];
+        [response appendContentString:key2];
+        
+        if ((dt = [keyToDataType objectForKey:key2])) {
+          [response appendContentString:@" dt:dt='"];
+          [response appendContentString:dt];
+          [response appendContentString:@"'"];
+        }
+        
+        [response appendContentString:@">"];
+        
+        [response appendContentHTMLString:[value stringValue]];
+        
+        [response appendContentString:@"</"];
+        [response appendContentString:key2];
+        [response appendContentString:@">\n"];
+      }
+      [response appendContentString:@"    </page>\n"];
+    }
+    
+    [response appendContentString:@"  </pages>\n"];
+  }
+  
+  [response appendContentString:@"</application>\n"];
+  
+  return response;
+}
+
+@end /* WODirectAction(WOStats) */
diff --git a/skyrix-sope/NGObjWeb/WOWatchDogApplicationMain.m b/skyrix-sope/NGObjWeb/WOWatchDogApplicationMain.m
new file mode 100644 (file)
index 0000000..28cce4e
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <Foundation/Foundation.h>
+#include <NGObjWeb/NGObjWeb.h>
+
+#if defined(__CYGWIN32__) || defined(__MINGW32__)
+
+int WOWatchDogApplicationMain
+(NSString *appName, int argc, const char *argv[])
+{
+  /* no watchdog support on Win* */
+  return WOApplicationMain(appName, argc, argv);
+}
+
+#else
+
+#ifdef __APPLE__
+#  include <unistd.h>
+#endif
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/unistd.h>
+#include <time.h>
+
+static pid_t    child = -1;
+static NSString *pidFile = nil;
+static time_t   lastFailExit = 0;
+static unsigned failExitCount = 0;
+static BOOL     killedChild = NO;
+
+static void killChild(void) {
+  if (child > 0) {
+    int status;
+    
+    fprintf(stderr, "watchdog[%i]: terminating child %i ..\n", getpid(), child);
+    
+    if (kill(child, SIGTERM) == 0) {
+      waitpid(child, &status, 0);
+      killedChild = YES;
+      
+      fprintf(stderr, "  terminated child %i",  child);
+      
+      if (WIFEXITED(status))
+        fprintf(stderr, " exit=%i", WEXITSTATUS(status));
+      if (WIFSIGNALED(status))
+        fprintf(stderr, " signal=%i", WTERMSIG(status));
+      
+      fprintf(stderr, ".\n");
+      fflush(stderr);
+      
+      child = -1;
+      return;
+    }
+    else if (kill(child, SIGKILL)) {
+      waitpid(child, &status, 0);
+      killedChild = YES;
+      
+      fprintf(stderr, "  killed child %i",  child);
+      
+      if (WIFEXITED(status))
+        fprintf(stderr, " exit=%i", WEXITSTATUS(status));
+      if (WIFSIGNALED(status))
+        fprintf(stderr, " signal=%i", WTERMSIG(status));
+      
+      fprintf(stderr, ".\n");
+      fflush(stderr);
+      
+      child = -1;
+      return;
+    }
+  }
+}
+
+static void _writePid(NSString *pidFile) {
+  if ([pidFile length] > 0) {
+    FILE *pf;
+      
+    if ((pf = fopen([pidFile cString], "w"))) {
+      fprintf(pf, "%i\n", getpid());
+      fflush(pf);
+      fclose(pf);
+    }
+  }
+}
+static void _delPid(void) {
+  if ([pidFile length] > 0) {
+    if (unlink([pidFile cString]) == 0)
+      pidFile = nil;
+  }
+}
+
+static void exitWatchdog(void) {
+  killChild();
+  _delPid();
+}
+
+static void wsignalHandler(int _signal) {
+  switch (_signal) {
+  case SIGINT:
+    /* Control-C */
+    fprintf(stderr, "[%i]: watchdog handling signal ctrl-c ..\n", getpid());
+    killChild();
+    exit(0);
+    /* shouldn't get here */
+    abort();
+
+  case SIGSEGV:
+    /* Coredump ! */
+    fprintf(stderr,
+            "[%i]: watchdog handling segmentation fault "
+            "(SERIOUS PROBLEM) ..\n",
+            getpid());
+    killChild();
+    exit(123);
+    /* shouldn't get here */
+    abort();
+
+  case SIGTERM:
+    /* TERM signal (kill 'pid') */
+    fprintf(stderr, "[%i]: watchdog handling SIGTERM ..\n", getpid());
+    killChild();
+    exit(0);
+    /* shouldn't get here */
+    abort();
+    
+  case SIGHUP:
+    /* HUP signal (restart children) */
+    fprintf(stderr, "[%i]: watchdog handling SIGHUP ..\n", getpid());
+    killChild();
+    killedChild = YES;
+    signal(_signal, wsignalHandler);
+    return;
+    
+  case SIGCHLD:
+    break;
+    
+  default:
+    fprintf(stderr, "[%i]: watchdog handling signal %i ..\n",
+            getpid(), _signal);
+    break;
+  }
+  fflush(stderr);
+  
+  switch (_signal) {
+    case SIGTERM:
+    case SIGINT:
+    case SIGKILL:
+    case SIGILL:
+      killChild();
+      exit(0);
+      break;
+      
+    case SIGHUP:
+      killChild();
+      break;
+      
+    case SIGCHLD: {
+      int   returnStatus;
+      pid_t result;
+      
+      //      NSLog(@"SIGNAL: SIGCHLD");
+      // fetch return state
+      
+      do {
+        result = waitpid(-1, &returnStatus, WNOHANG);
+        if (result > 0) {
+          fprintf(stderr, "[%i]: process %i exited with code %i",
+                  getpid(), (int)result, WEXITSTATUS(returnStatus));
+
+          if (WIFSIGNALED(returnStatus)) {
+            fprintf(stderr, " (terminated due to signal %i%s)",
+                    WTERMSIG(returnStatus),
+                    WCOREDUMP(returnStatus) ? ", coredump" : "");
+          }
+          if (WIFSTOPPED(returnStatus)) {
+            fprintf(stderr, " (stopped due to signal %i)",
+                    WSTOPSIG(returnStatus));
+          }
+          
+          fprintf(stderr, "\n");
+          fflush(stderr);
+        }
+      }
+      while (result > 0);
+      
+      break;
+    }
+    
+    default:
+      fprintf(stderr, "watchdog[%i]: caught signal %i\n", getpid(), _signal);
+      break;
+  }
+  signal(_signal, wsignalHandler);
+}
+
+static void signalHandler(int _signal) {
+  fprintf(stderr, "[%i]: handling signal %i ..\n",
+          getpid(), _signal);
+  fflush(stderr);
+  
+  switch (_signal) {
+    case SIGPIPE:
+      fprintf(stderr, "[%i]: caught signal SIGPIPE\n", getpid());
+      break;
+      
+    default:
+      fprintf(stderr, "[%i]: caught signal %i\n", getpid(), _signal);
+      break;
+  }
+  signal(_signal, signalHandler);
+}
+
+int WOWatchDogApplicationMain
+(NSString *appName, int argc, const char *argv[])
+{
+  NSAutoreleasePool *pool;
+  NSUserDefaults *ud;
+
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS)
+  {
+    extern char **environ;
+    [NSProcessInfo initializeWithArguments:(void*)argv count:argc
+                   environment:(void*)environ];
+  }
+#endif
+  
+  ud = [NSUserDefaults standardUserDefaults];
+  
+  if (![ud boolForKey:@"WOUseWatchDog"])
+    return WOApplicationMain(appName, argc, argv);
+  
+  /* watch dog */
+  {
+    int      failCount = 0;
+    int      forkCount = 0;
+    BOOL     repeat    = YES;
+    BOOL     isVerbose = NO;  
+    
+    isVerbose = [[ud objectForKey:@"watchdog_verbose"] boolValue];
+    pidFile   = [[[ud objectForKey:@"watchdog_pidfile"] stringValue] copy];
+    
+    /* write current pid to pidfile */
+    _writePid(pidFile);
+    
+    /* register exit handler */
+    atexit(exitWatchdog);
+    
+    /* register signal handlers of watch dog */
+    signal(SIGPIPE, wsignalHandler);
+    signal(SIGCHLD, wsignalHandler);
+    signal(SIGINT,  wsignalHandler);
+    signal(SIGTERM, wsignalHandler);
+    signal(SIGKILL, wsignalHandler);
+    signal(SIGHUP,  wsignalHandler);
+    
+    /* loop */
+    
+    while (repeat) {
+      time_t clientStartTime;
+      
+      clientStartTime = time(NULL);
+      killedChild = NO;
+      
+      if ((child = fork()) == -1) {
+        fprintf(stderr, "[%i]: fork failed: %s\n", getpid(), strerror(errno));
+        failCount++;
+        
+        if (failCount > 5) {
+          fprintf(stderr, "  fork failed %i times, sleeping 60 seconds ..\n",
+                  failCount);
+          sleep(60);
+        }
+        else {
+          sleep(1);
+        }
+      }
+      else {
+        if (child == 0) {
+          /* child process */
+          signal(SIGPIPE, SIG_DFL);
+          signal(SIGCHLD, SIG_DFL);
+          signal(SIGINT,  SIG_DFL);
+          signal(SIGTERM, SIG_DFL);
+          signal(SIGKILL, SIG_DFL);
+          
+          if (isVerbose)
+            fprintf(stderr, "starting child %i ..\n", getpid());
+
+          pidFile = [pidFile stringByAppendingPathExtension:@"child"];
+          _writePid(pidFile);
+          
+          atexit(_delPid);
+          
+          exit(WOApplicationMain(appName, argc, argv));
+          
+          /* shouldn't even get here ! */
+          fprintf(stderr, "internal server error !\n");
+          abort();
+        }
+        else {
+          /* parent (watch dog) */
+          int      status = 0;
+          pid_t    result = 0;
+          time_t   clientStopTime;
+          unsigned uptime;
+          
+          forkCount++;
+          
+          if (isVerbose) {
+            fprintf(stderr, "forked child process %i (#%i) ..\n",
+                    child, forkCount);
+          }
+          
+          failCount = 0;
+          status    = 0;
+          
+          if ((result = waitpid(child, &status, 0)) == -1) {
+            if (killedChild) {
+              killedChild = NO;
+              continue;
+            }
+            
+            fprintf(stderr,
+                    "### waiting for child %i (#%i) failed: %s\n",
+                    child, forkCount, strerror(errno));
+            continue;
+          }
+
+          clientStopTime = time(NULL);
+          uptime = clientStopTime - clientStartTime;
+          
+          if (WIFSIGNALED(status)) {
+            fprintf(stderr,
+                    "### child %i (#%i) was terminated by signal %i "
+                    "(uptime=%ds).\n",
+                    child, forkCount, WTERMSIG(status), uptime);
+            
+            lastFailExit  = time(NULL);
+            failExitCount++;
+          }
+          else if (WIFEXITED(status)) {
+            unsigned exitCode;
+            
+            if ((exitCode = WEXITSTATUS(status)) != 0) {
+              time_t now;
+              
+              now = time(NULL);
+
+              if (uptime < 3) {
+                if (failExitCount > 0) {
+                  unsigned secsSinceLastFail;
+                
+                  secsSinceLastFail = (now - lastFailExit);
+                
+                  if (secsSinceLastFail > 120) {
+                    /* reset fail count */
+                    failExitCount = 0;
+                  }
+                  else if (failExitCount > 20) {
+                    printf("### child %i (#%i) already failed %i times "
+                           "in the last %i seconds, stopping watchdog !\n",
+                           child, forkCount, failExitCount, secsSinceLastFail);
+                    repeat = NO;
+                  }
+                }
+              }              
+              failExitCount++;
+              lastFailExit  = now;
+              
+              fprintf(stderr,
+                      "### child %i (#%i) exited with status %i "
+                      "(#fails=%i, uptime=%ds).\n",
+                      child, forkCount, exitCode, failExitCount, uptime);
+            }
+            else {
+              fprintf(stderr,
+                      "### child %i (#%i) exited successfully (uptime=%ds).\n",
+                      child, forkCount, uptime);
+            }
+            
+            if (exitCode == 123) // ???
+              repeat = NO;
+          }
+          else {
+            fprintf(stderr,
+                    "### abnormal termination of child %i (#%i) status=%i"
+                    "(was not signaled nor exited).",
+                    child, forkCount, status);
+          }
+        }
+      }
+    }
+    return 0;
+  }
+}
+#endif
diff --git a/skyrix-sope/NGObjWeb/WebDAV/.cvsignore b/skyrix-sope/NGObjWeb/WebDAV/.cvsignore
new file mode 100644 (file)
index 0000000..743bf33
--- /dev/null
@@ -0,0 +1,3 @@
+Resources
+shared_debug_obj
+Nautilus.txt
diff --git a/skyrix-sope/NGObjWeb/WebDAV/DAVFetchSpec.txt b/skyrix-sope/NGObjWeb/WebDAV/DAVFetchSpec.txt
new file mode 100644 (file)
index 0000000..8c07c98
--- /dev/null
@@ -0,0 +1,45 @@
+# $Id: DAVFetchSpec.txt,v 1.1.1.1 2003/07/09 22:57:27 cvs Exp $
+
+Required Context
+
+  request-url => entity
+
+DAV PROPFIND
+
+  entity:
+    Request URL
+
+  scope:
+    0         - object
+    1         - collection children + collection
+    1,noroot  - collection children
+    infinity  - all children, deep
+
+  attribute selection
+    propnames  ([[obj soClass] -allKeysInContext:] ?)
+    allprops   (= SQL SELECT * FROM...)
+
+DAV SEARCH SQL
+  
+  entity:
+    traversal of "xxx" -> [requesturl relativeURL:xxx]
+    => only children allowed in FROM ?
+  
+  scope
+    shallow (= depth 1 or 1,noroot ??)
+      FROM Scope('shallow traversal of ""')
+      FROM scope('shallow traversal of "http://x:23000/a/ol/helge/Contacts"')
+
+    hierarchical (= depth infinity)    
+      from scope('hierarchical traversal of "/janb/"')
+  
+  attribute selection
+    named, fqn
+      "DAV:creationdate", 
+      "http://schemas.microsoft.com/mapi/email3addrtype", 
+      "urn:schemas:contacts:cn"
+    *
+
+
+WHERE:
+where "DAV:iscollection" = False and "DAV:ishidden" = False      order by "http://schemas.microsoft.com/mapi/proptag/x0e230003"
diff --git a/skyrix-sope/NGObjWeb/WebDAV/EOFetchSpecification+SoDAV.h b/skyrix-sope/NGObjWeb/WebDAV/EOFetchSpecification+SoDAV.h
new file mode 100644 (file)
index 0000000..f1838fe
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_EOFetchSpecification_SoDAV_H__
+#define __NGObjWeb_EOFetchSpecification_SoDAV_H__
+
+#import <EOControl/EOFetchSpecification.h>
+
+@class NSString, NSArray;
+
+/*
+  Additional WebDAV related methods for EOFetchSpecification. 
+  EOFetchSpecification is used to represent PROPFIND and SEARCH queries.
+  
+  If the selectedWebDAVPropertyNames (= the 'attributes' hint) is empty,
+  this designates that a "propall" query is to be done (a SELECT *).
+  
+  Note: the propertynames are given back as fully qualified XML names, eg
+    
+    {DAV:}getlastmodified
+    
+  The namespace is enclosed in the braces.
+  
+  Mapping of scope:
+                depth      from
+    flat      - 1,noroot - 'shallow traversal of'
+    flat+self - 1        - 
+    self      - 0        - 
+    deep      - infinity - 'hierarchical traversal of'
+
+  Used hints:
+    hint         method
+    scope          - scopeOfWebDAVQuery
+    attributes     - selectedWebDAVPropertyNames
+    namesOnly      - queryWebDAVPropertyNamesOnly
+    bulkTargetKeys - davBulkTargetKeys
+*/
+
+@interface EOFetchSpecification(SoDAV)
+
++ (EOFetchSpecification *)parseWebDAVSQLString:(NSString *)_s;
+
+- (NSArray *)selectedWebDAVPropertyNames;
+- (NSString *)scopeOfWebDAVQuery; /* flat, deep, self, flat+self */
+- (BOOL)queryWebDAVPropertyNamesOnly;
+- (NSArray *)davBulkTargetKeys;
+
+@end
+
+#endif /* __NGObjWeb_EOFetchSpecification_SoDAV_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/EOFetchSpecification+SoDAV.m b/skyrix-sope/NGObjWeb/WebDAV/EOFetchSpecification+SoDAV.m
new file mode 100644 (file)
index 0000000..78ef281
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "EOFetchSpecification+SoDAV.h"
+#include "SoDAVSQLParser.h"
+#include <EOControl/EOControl.h>
+#include "common.h"
+
+@implementation EOFetchSpecification(SoDAV)
+
++ (EOFetchSpecification *)parseWebDAVSQLString:(NSString *)_sql {
+  EOFetchSpecification *fs;
+  static SoDAVSQLParser *parser = nil;
+  
+  /* parse SQL */
+  
+  if (parser == nil)
+    parser = [[SoDAVSQLParser alloc] init];
+  
+  if ((fs = [parser parseSQLSelectStatement:_sql]) == nil)
+    return nil;
+  
+  /* morph attribute names ? */
+  return fs;
+}
+
+- (NSArray *)selectedWebDAVPropertyNames {
+  return [[self hints] objectForKey:@"attributes"];
+}
+
+- (NSString *)scopeOfWebDAVQuery {
+  NSString *scope;
+  
+  scope = [[self hints] objectForKey:@"scope"];
+  return [scope length] == 0 ? @"flat" : (id)scope;
+}
+
+- (BOOL)queryWebDAVPropertyNamesOnly {
+  id v;
+  if ((v = [[self hints] objectForKey:@"namesOnly"]))
+    return [v boolValue];
+  return NO;
+}
+
+- (NSArray *)davBulkTargetKeys {
+  return [[self hints] objectForKey:@"bulkTargetKeys"];
+}
+
+@end /* EOFetchSpecification(SoDAV) */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/GNUmakefile b/skyrix-sope/NGObjWeb/WebDAV/GNUmakefile
new file mode 100644 (file)
index 0000000..9ed6baa
--- /dev/null
@@ -0,0 +1,42 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = WebDAV
+
+WebDAV_HEADER_FILES_DIR         = .
+WebDAV_HEADER_FILES_INSTALL_DIR = /NGObjWeb
+
+WebDAV_HEADER_FILES = \
+       SoDAV.h                         \
+       EOFetchSpecification+SoDAV.h    \
+       SaxDAVHandler.h                 \
+       SoDAVLockManager.h              \
+       SoObject+SoDAV.h                \
+       SoObjectDataSource.h            \
+       SoObjectResultEntry.h           \
+       SoObjectWebDAVDispatcher.h      \
+       SoWebDAVRenderer.h              \
+       SoWebDAVValue.h                 \
+       SoSubscriptionManager.h         \
+       SoSubscription.h                \
+       SoDAVSQLParser.h                \
+
+WebDAV_OBJC_FILES = \
+       EOFetchSpecification+SoDAV.m    \
+       SaxDAVHandler.m                 \
+       SoDAVLockManager.m              \
+       SoObject+SoDAV.m                \
+       SoObject+SoDAVQuery.m           \
+       SoObjectDataSource.m            \
+       SoObjectWebDAVDispatcher.m      \
+       SoWebDAVRenderer.m              \
+       SoWebDAVValue.m                 \
+       SoObjectResultEntry.m           \
+       SoSubscriptionManager.m         \
+       SoSubscription.m                \
+       SoDAVSQLParser.m                \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGObjWeb/WebDAV/GNUmakefile.preamble b/skyrix-sope/NGObjWeb/WebDAV/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..87fc44a
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..                    \
+       -I../SoObjects/         \
+       -I../DynamicElements/   \
+       -I../..                 \
+       -I../../../skyrix-core                  \
+       -I../../../skyrix-core/NGStreams        \
+       -I../../../skyrix-core/NGExtensions     \
+       -I../../../skyrix-xml
diff --git a/skyrix-sope/NGObjWeb/WebDAV/README b/skyrix-sope/NGObjWeb/WebDAV/README
new file mode 100644 (file)
index 0000000..789b62c
--- /dev/null
@@ -0,0 +1,35 @@
+# $Id$
+
+NGObjWeb WebDAV Implementation for SoObjects
+============================================
+
+PROPFIND, TODO:
+"A client may choose not to submit a request body.  An empty PROPFIND request 
+ body MUST be treated as a request for the names and values of all properties."
+- means, an empty request is to be treated as allprop?
+
+DASL:
+  ---snip---
+  <?xml version="1.0" encoding="utf-8" ?>
+  <D:searchrequest xmlns:D="DAV:">
+    <D:basicsearch>
+      <D:select><D:allprop/></D:select>
+      <D:from>
+        <D:scope>
+          <D:href>/evo/dav/helge/Private.plist/</D:href>
+          <D:depth>infinity</D:depth>
+        </D:scope>
+      </D:from>
+      <D:where>
+        <D:eq>
+          <D:prop><D:sn/></D:prop>
+          <D:literal>Mueller</D:literal>
+        </D:eq>
+      </D:where>
+    </D:basicsearch>
+  </D:searchrequest>
+  ---snap---
+  SQL-search queries use
+    <D:searchrequest><D:sql>
+  instead of
+    <D:searchrequest><D:basicsearch>
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SaxDAVHandler.h b/skyrix-sope/NGObjWeb/WebDAV/SaxDAVHandler.h
new file mode 100644 (file)
index 0000000..031e866
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __codeon_SaxDAVHandler_H__
+#define __codeon_SaxDAVHandler_H__
+
+#include <SaxObjC/SaxDefaultHandler.h>
+
+/*
+  A SAX handler to parse WebDAV requests ...
+  
+  The delegate is used to parse (potentially long) responses.
+*/
+
+@class NSMutableString, NSMutableArray, NSArray, NSString, NSMutableDictionary;
+@class EOFetchSpecification;
+
+@interface SaxDAVHandler : SaxDefaultHandler
+{
+  id<NSObject,SaxLocator> locator;
+  id delegate; /* non-retained */
+  
+  /* results */
+  NSMutableArray *propNames;
+  BOOL           findAllProps;
+  BOOL           findPropNames;
+  NSMutableArray *responses;
+  NSString       *searchSQL;
+  NSMutableDictionary *propSet;
+  EOFetchSpecification *fspec;
+  
+  /* state */
+  id              response;
+  NSMutableString *cdata;
+  BOOL            ascending;
+  NSString        *lastLiteral;
+  NSString        *lastWherePropName;
+  NSString        *lastScopeHref;
+  NSString        *lastScopeDepth;
+  NSString        *lastHref;
+  NSMutableArray  *targets;
+  int             propValueNesting;
+  NSMutableArray  *qualifiers;
+  NSMutableArray  *compoundQualStack;
+  
+  /* active tags */
+  struct {
+    BOOL PropFind:1;
+    BOOL Response:1;
+    BOOL MultiStatus:1;
+    BOOL Href:1;
+    BOOL Status:1;
+    BOOL Prop:1;
+    BOOL PropStat:1;
+    BOOL PropertyUpdate:1;
+    BOOL Set:1;
+    BOOL Remove:1;
+    /* bulk */
+    BOOL target:1;
+    /* DASL */
+    BOOL SearchRequest:1;
+    BOOL SQL:1;
+    BOOL basicsearch:1;
+    BOOL select:1;
+    BOOL from:1;
+    BOOL scope:1;
+    BOOL depth:1;
+    BOOL where:1;
+    BOOL gt:1;
+    BOOL lt:1;
+    BOOL gte:1;
+    BOOL lte:1;
+    BOOL eq:1;
+    BOOL literal:1;
+    BOOL orderby:1;
+    BOOL order:1;
+    BOOL ascending:1;
+    BOOL like:1;
+  } in;
+}
+
+/* accessors */
+
+- (void)setDelegate:(id)_delegate;
+- (id)delegate;
+
+/* cleanup */
+
+- (void)reset;
+
+/* propfind results */
+
+- (BOOL)propFindAllProperties;
+- (BOOL)propFindPropertyNames;
+- (NSArray *)propFindQueriedNames;
+- (NSArray *)bpropFindTargets;
+
+/* proppatch results */
+
+- (NSArray *)propPatchPropertyNamesToRemove;
+- (NSDictionary *)propPatchValues;
+
+/* search query results */
+
+- (EOFetchSpecification *)searchFetchSpecification;
+
+@end
+
+@interface NSObject(SaxDAVHandlerDelegate)
+
+- (void)davHandler:(SaxDAVHandler *)_handler
+  receivedProperties:(NSDictionary *)_record
+  forURI:(NSString *)_uri;
+
+@end
+
+#endif /* __codeon_SaxDAVHandler_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SaxDAVHandler.m b/skyrix-sope/NGObjWeb/WebDAV/SaxDAVHandler.m
new file mode 100644 (file)
index 0000000..f40b8ad
--- /dev/null
@@ -0,0 +1,943 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SaxDAVHandler.h"
+#include "EOFetchSpecification+SoDAV.h"
+#include <SaxObjC/XMLNamespaces.h>
+#include <EOControl/EOQualifier.h>
+#include "common.h"
+
+/*
+  TODO: support parsing of DASL
+  basics are done, open are:
+    sort orderings
+
+  Breaks on SQL searches without Brief: T, which contain a 404 propstat:
+  ---
+  <a:propstat>...found args...</a:propstat>
+  <a:propstat><a:status>HTTP/1.1 404 Resource Not Found</a:status><a:prop><e:namesuffix/><e:telexnumber/><e:ttytddphone/><e:bday/><e:weddinganniversary/><h:x3A1D001E/><h:x3A1A001E/></a:prop></a:propstat>
+  ---
+  
+  a set tag can be either in a "propertyupdate" or in a "response"
+
+  <set><prop><a>1</a></prop><prop><b>2</b></prop>
+  <response><prop><a>1</a><b>2</b></prop></response>
+*/
+
+@implementation SaxDAVHandler
+
+static BOOL debugPropValue = NO;
+static BOOL heavyLog = NO;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+    didInit = YES;
+    debugPropValue = [ud boolForKey:@"DAVParserDebugProp"];
+    heavyLog       = [ud boolForKey:@"DAVParserHeavyLog"];
+  }
+}
+
+- (void)dealloc {
+  [self reset];
+  [self->locator   release];
+  [self->propNames release];
+  [self->responses release];
+  [self->cdata     release];
+  [super dealloc];
+}
+
+/* cleanup */
+
+- (void)parseReset {
+  if (heavyLog) [self logWithFormat:@"reset parser state"];
+  self->propValueNesting  = 0;
+  self->in.PropFind       = 0;
+  self->in.Prop           = 0;
+  self->in.Response       = 0;
+  self->in.MultiStatus    = 0;
+  self->in.Href           = 0;
+  self->in.Status         = 0;
+  self->in.PropStat       = 0;
+  self->in.PropertyUpdate = 0;
+  self->in.Set            = 0;
+  self->in.Remove         = 0;
+  self->in.SearchRequest  = 0;
+  self->in.basicsearch    = 0;
+  self->in.select         = 0;
+  self->in.from           = 0;
+  self->in.scope          = 0;
+  self->in.depth          = 0;
+  self->in.where          = 0;
+  self->in.gt             = 0;
+  self->in.lt             = 0;
+  self->in.gte            = 0;
+  self->in.lte            = 0;
+  self->in.eq             = 0;
+  self->in.literal        = 0;
+  self->in.orderby        = 0;
+  self->in.order          = 0;
+  self->in.ascending      = 0;
+  self->in.target         = 0;
+  
+  [self->response          release]; self->response          = nil;
+  [self->cdata             release]; self->cdata             = nil;
+  [self->lastLiteral       release]; self->lastLiteral       = nil;
+  [self->lastScopeHref     release]; self->lastScopeHref     = nil;
+  [self->lastHref          release]; self->lastHref          = nil;
+  [self->lastScopeDepth    release]; self->lastScopeDepth    = nil;
+  [self->lastWherePropName release]; self->lastWherePropName = nil;
+}
+- (void)reset {
+  if (heavyLog) [self logWithFormat:@"reset"];
+  [self parseReset];
+  self->findAllProps  = NO;
+  self->findPropNames = NO;
+  [self->propNames removeAllObjects];
+  [self->propSet   removeAllObjects];
+  [self->responses removeAllObjects];
+  [self->targets   removeAllObjects];
+  [self->compoundQualStack removeAllObjects];
+  [self->qualifiers release]; self->qualifiers = nil;
+  [self->searchSQL  release]; self->searchSQL  = nil;
+  [self->fspec      release]; self->fspec      = nil;
+}
+
+/* accessors */
+
+- (void)setDelegate:(id)_delegate {
+  self->delegate = _delegate;
+}
+- (id)delegate {
+  return self->delegate;
+}
+
+/* results */
+
+- (BOOL)propFindAllProperties {
+  return self->findAllProps;
+}
+- (BOOL)propFindPropertyNames {
+  return self->findPropNames;
+}
+- (NSArray *)propFindQueriedNames {
+  if ([self->propNames count] == 0) return nil;
+  return [[self->propNames copy] autorelease];
+}
+
+- (NSArray *)bpropFindTargets {
+  if ([self->targets count] == 0) return nil;
+  return [[self->targets copy] autorelease];
+}
+
+/* proppatch results */
+
+- (NSArray *)propPatchPropertyNamesToRemove {
+  if ([self->propNames count] == 0) return nil;
+  return [[self->propNames copy] autorelease];
+}
+- (NSDictionary *)propPatchValues {
+  if ([self->propSet count] == 0) return nil;
+  return [[self->propSet copy] autorelease];
+}
+
+/* search query results */
+
+- (EOFetchSpecification *)searchFetchSpecification {
+  EOFetchSpecification *fs;
+  
+  if (heavyLog) [self logWithFormat:@"build search fetchspec"];
+  
+  if (self->fspec) {
+    if (heavyLog) [self logWithFormat:@"  use parsed fetchspec"];
+    return self->fspec;
+  }
+  
+  if ([self->searchSQL length] == 0) {
+    if (heavyLog) [self logWithFormat:@"  no SQL to parse"];
+    return nil;
+  }
+  
+  fs = [EOFetchSpecification parseWebDAVSQLString:self->searchSQL];
+  if (fs == nil) {
+    [self logWithFormat:@"could not parse SQL: '%@'", self->searchSQL];
+    return nil;
+  }
+  if (heavyLog) [self logWithFormat:@"  parsed: %@", fs];
+  return fs;
+}
+
+/* positioning info */
+
+- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator {
+  ASSIGN(self->locator, _locator);
+}
+
+/* parsing */
+
+- (void)startDocument {
+  if (heavyLog) [self logWithFormat:@"start document"];
+  [self reset];
+}
+- (void)endDocument {
+  if (heavyLog) [self logWithFormat:@"end document"];
+  [self parseReset];
+}
+
+/* dav elements */
+
+- (void)startSQLElement {
+  self->in.SQL = 1;
+      
+  if (self->cdata) {
+    [self logWithFormat:@"some cdata collection already in progress ?"];
+  }
+  else
+    self->cdata = [[NSMutableString alloc] initWithCapacity:256];
+}
+- (void)endSQLElement {
+  /* TODO: could immediatly parse SQL into fetch-spec */
+  self->in.SQL = 0;
+  [self->searchSQL release]; self->searchSQL = nil;
+  self->searchSQL = [self->cdata copy];
+  [self->cdata release]; self->cdata = nil;
+}
+
+- (void)startLiteralElement {
+  self->in.literal = 1;
+  if (self->cdata)
+    [self logWithFormat:@"some cdata collection already in progress ?"];
+  else
+    self->cdata = [[NSMutableString alloc] initWithCapacity:256];
+}
+- (void)endLiteralElement {
+  self->in.literal = 0;
+  [self->lastLiteral release]; self->lastLiteral = nil;
+  self->lastLiteral = [self->cdata copy];
+  [self->cdata release]; self->cdata = nil;
+}
+
+- (void)startHrefElement {
+  self->in.Href = 1;
+  if (self->in.scope || self->in.target || self->in.Response) {
+    if (self->cdata)
+      [self logWithFormat:@"some cdata collection already in progress ?"];
+    else
+      self->cdata = [[NSMutableString alloc] initWithCapacity:256];
+  }
+}
+- (void)endHrefElement {
+  self->in.Href = 0;
+  if (self->in.scope) {
+    [self->lastScopeHref release]; self->lastScopeHref = nil;
+    self->lastScopeHref = [self->cdata copy];
+    [self->cdata release]; self->cdata = nil;
+  }
+  else if (self->in.target && self->cdata != nil) {
+    [self->targets addObject:self->cdata];
+    [self->cdata release]; self->cdata = nil;
+  }
+  else if (self->in.Response && self->cdata != nil) {
+    [self->lastHref release]; self->lastHref = nil;
+    self->lastHref = [self->cdata copy];
+    [self->cdata release]; self->cdata = nil;
+  }
+}
+
+- (void)startDepthElement {
+  self->in.depth = 1;
+  if (self->in.scope) {
+    if (self->cdata)
+      [self logWithFormat:@"some cdata collection already in progress ?"];
+    else
+      self->cdata = [[NSMutableString alloc] initWithCapacity:256];
+  }
+}
+- (void)endDepthElement {
+  self->in.depth = 0;
+  if (self->in.scope) {
+    [self->lastScopeDepth release]; self->lastScopeDepth = nil;
+    self->lastScopeDepth = [self->cdata copy];
+    [self->cdata release]; self->cdata = nil;
+  }
+}
+
+- (void)startBasicSearch {
+  self->in.basicsearch = 1;
+  if (self->fspec)
+    [self logWithFormat:@"basicsearch collection already in progress ?"];
+  else
+    self->fspec = [[EOFetchSpecification alloc] init];
+}
+
+- (void)startPropUpdate {
+  self->in.PropertyUpdate = 1;
+  if (self->propNames == nil)
+    self->propNames = [[NSMutableArray alloc] initWithCapacity:64];
+  if (self->propSet == nil)
+    self->propSet = [[NSMutableDictionary alloc] initWithCapacity:64];
+}
+
+- (void)startPropSet {
+  self->in.Set = 1;
+  if (self->propSet == nil)
+    self->propSet = [[NSMutableDictionary alloc] initWithCapacity:64];
+  if (debugPropValue)
+    [self logWithFormat:@"start <set> tag ..."];
+}
+- (void)endPropSet {
+  self->in.Set = 0;
+  if (debugPropValue) {
+    [self logWithFormat:@"end </set> tag (%i props in set) ...", 
+            [self->propSet count]];
+  }
+}
+
+- (void)startProp {
+  if (self->propSet == nil)
+    self->propSet = [[NSMutableDictionary alloc] initWithCapacity:64];
+  
+  self->in.Prop = 1;
+  if (debugPropValue)
+    [self logWithFormat:@"start <prop> tag ..."];
+}
+- (void)endProp {
+  self->in.Prop = 0;
+}
+
+- (void)startTarget {
+  self->in.target = 1;
+  [self->targets removeAllObjects];
+  if (self->targets == nil) 
+    self->targets = [[NSMutableArray alloc] initWithCapacity:16];
+}
+
+- (void)startPropFindSpec:(NSString *)_localName {
+  unsigned len;
+  unichar  c;
+  NSString *fqn;
+  
+  if ((len = [_localName length]) == 0)
+    return;
+  c = [_localName characterAtIndex:0];
+    
+  if (c == 'a' && len == 7) {
+    if ([_localName isEqualToString:@"allprop"]) {
+      self->findAllProps = 1;
+      return;
+    }
+  }
+  if (c == 'p' && len == 8) {
+    if ([_localName isEqualToString:@"propname"]) {
+      self->findPropNames = 1;
+      return;
+    }
+  }
+    
+  fqn = [[NSString alloc] initWithFormat:@"{%@}%@", XMLNS_WEBDAV, _localName];
+  [self->propNames addObject:fqn];
+  [fqn release];
+}
+
+- (void)startResponseElement {
+  self->in.Response = 1;
+  
+  if (heavyLog) [self logWithFormat:@"clearing property-set"];
+  [self->propSet removeAllObjects];
+}
+- (void)endResponseElement {
+  self->in.Response = 0;
+  
+  if ([self->delegate respondsToSelector:
+            @selector(davHandler:receivedProperties:forURI:)]) {
+    [self->delegate
+        davHandler:self
+        receivedProperties:self->propSet
+        forURI:self->lastHref];
+  }
+  else if (self->response)
+    [self->responses addObject:self->response];
+}
+
+- (void)endBasicSearch {
+  /* only works with a single 'from', 'where' and 'select' */
+  NSMutableDictionary *hints;
+  
+  self->in.basicsearch = 0;
+  
+  if (self->lastScopeHref)
+    [self->fspec setEntityName:self->lastScopeHref];
+  
+  // qualifier
+  
+  hints = [[NSMutableDictionary alloc] initWithCapacity:8];
+  
+  if (self->lastScopeDepth) {
+    if ([self->lastScopeDepth isEqualToString:@"infinity"])
+      [hints setObject:@"deep" forKey:@"scope"];
+    else if ([self->lastScopeDepth isEqualToString:@"1"])
+      [hints setObject:@"flat+self" forKey:@"scope"];
+    else if ([self->lastScopeDepth isEqualToString:@"1,noroot"])
+      [hints setObject:@"flat" forKey:@"scope"];
+    else if ([self->lastScopeDepth isEqualToString:@"0"])
+      [hints setObject:@"self" forKey:@"scope"];
+    else {
+      [self logWithFormat:@"unknown search depth '%@'", self->lastScopeDepth];
+      [hints setObject:self->lastScopeDepth forKey:@"scope"];
+    }
+  }
+  
+  if (self->findPropNames)
+    [hints setObject:[NSNumber numberWithBool:YES] forKey:@"namesOnly"];
+  if (self->propNames)
+    [hints setObject:self->propNames forKey:@"attributes"];
+  /* Note: "allprops" is "no attributes set" in fspec */
+  
+  [self->fspec setHints:hints];
+  [hints release];
+  
+  // [self logWithFormat:@"parsed spec: %@", fspec];
+}
+
+- (void)addParsedQualifier:(EOQualifier *)_qualifier {
+  if (self->qualifiers)
+    [self->qualifiers addObject:_qualifier];
+  else {
+    //[self logWithFormat:@"got root qualifier: %@", _qualifier];
+    [self->fspec setQualifier:_qualifier];
+  }
+}
+
+- (void)endComparisonQualifier:(SEL)_op {
+  /* 
+     collect:
+     <D:eq>
+       <D:prop><D:sn/></D:prop>
+       <D:literal>Mueller</D:literal>
+     </D:eq>
+  */
+  EOKeyValueQualifier *kv;
+  
+  kv = [[EOKeyValueQualifier alloc] initWithKey:self->lastWherePropName
+                                    operatorSelector:_op
+                                    value:self->lastLiteral];
+  [self addParsedQualifier:kv];
+  [kv release];
+  
+  [self->lastWherePropName release]; self->lastWherePropName = nil;
+  [self->lastLiteral       release]; self->lastLiteral = nil;
+}
+
+- (void)beginCompoundQualifier {
+  if (self->compoundQualStack == nil)
+    self->compoundQualStack = [[NSMutableArray alloc] initWithCapacity:16];
+  
+  self->qualifiers = [[NSMutableArray alloc] initWithCapacity:4];
+  [self->compoundQualStack addObject:self->qualifiers];
+}
+- (void)endCompoundQualifier:(NSString *)_localName {
+  EOQualifier *q;
+  unsigned stackSize;
+  
+  if ([_localName isEqualToString:@"not"]) {
+    unsigned cnt;
+    
+    if ((cnt = [self->qualifiers count]) == 0)
+      q = nil;
+    else {
+      q = [self->qualifiers objectAtIndex:0];
+      if (cnt != 1) {
+        [self logWithFormat:@"WARNING: to many subqualifiers in not !: %@",
+                self->qualifiers];
+      }
+    }
+    q = [[EONotQualifier alloc] initWithQualifier:q];
+  }
+  else {
+    Class qc = Nil;
+    
+    if ([_localName isEqualToString:@"and"])
+      qc = [EOAndQualifier class];
+    else if ([_localName isEqualToString:@"or"])
+      qc = [EOOrQualifier class];
+    else {
+      [self logWithFormat:@"unknown compound qualifier: '%@'", _localName];
+      qc = Nil;
+    }
+    
+    q = [[qc alloc] initWithQualifierArray:self->qualifiers];
+  }
+  [self->qualifiers release]; self->qualifiers = nil;
+  
+  if ((stackSize = [self->compoundQualStack count]) == 0) {
+    [self logWithFormat:@"ERROR: the qualifier stack is mixed up !"];
+  }
+  else if (stackSize > 1) {
+    /* this one was not the root qualifier */
+    [self->compoundQualStack removeObjectAtIndex:(stackSize - 1)];
+    self->qualifiers = [self->compoundQualStack objectAtIndex:(stackSize -2 )];
+  }
+  else
+    /* this one was the root qualifier */
+    [self->compoundQualStack removeObjectAtIndex:0];
+  
+  if (q) [self addParsedQualifier:q];
+  [q release];
+}
+
+- (void)startPropValueElement:(NSString *)_localName namespace:(NSString *)_ns {
+  self->propValueNesting++;
+  if (debugPropValue) {
+    [self debugWithFormat:@"start[%i]: {%@}%@", self->propValueNesting,
+           _ns, _localName];
+  }
+      
+  if (self->propValueNesting == 1) {
+    /* starting value */
+       
+    if (self->cdata) {
+      /* this can happen with nested tags ! */
+      [self logWithFormat:@"some cdata collection already in progress ?"];
+    }
+    else
+      self->cdata = [[NSMutableString alloc] initWithCapacity:256];
+  }
+  else {
+    /* add tag to value for later parsing */
+    [self->cdata appendString:@"<"];
+    [self->cdata appendString:@"V:"];
+    [self->cdata appendString:_localName];
+    [self->cdata appendString:@" xmlns:V=\""];
+    [self->cdata appendString:_ns];
+    [self->cdata appendString:@"\""];
+    [self->cdata appendString:@">"];
+  }
+}
+- (void)endPropValueElement:(NSString *)_localName namespace:(NSString *)_ns {
+  NSString *t;
+  NSString *fqn;
+  
+  if (debugPropValue) {
+    [self debugWithFormat:@"end[%i]: {%@}%@", self->propValueNesting,
+           _ns, _localName];
+  }
+  
+  if (self->propValueNesting == 1) {
+    fqn = [NSString stringWithFormat:@"{%@}%@", _ns, _localName];
+      
+    t = [self->cdata copy];
+    [self->cdata release]; self->cdata = nil;
+       
+    if (t) 
+      [self->propSet setObject:t forKey:fqn];
+    else {
+      [self->propSet setObject:[NSNull null] forKey:fqn];
+      [self logWithFormat:
+             @"ERROR: lost the parsing cdata (broken nesting) ?!"];
+    }
+    [t release];
+  }
+  else {
+    /* add tag to value for later parsing */
+    [self->cdata appendString:@"</"];
+    [self->cdata appendString:@"V:"];
+    [self->cdata appendString:_localName];
+    [self->cdata appendString:@">"];
+  }
+  
+  self->propValueNesting--;
+}
+
+/* dav element dispatcher */
+
+- (void)startDavElement:(NSString *)_localName {
+  unsigned len;
+  unichar c;
+
+  if ((len = [_localName length]) == 0)
+    return;
+  
+  if ((self->in.PropFind || self->in.select) && self->in.Prop) {
+    [self startPropFindSpec:_localName];
+    return;
+  }
+  if (self->in.where && self->in.Prop) {
+    /* a property in a where */
+    NSString *fqn;
+    fqn = [NSString stringWithFormat:@"{%@}%@", XMLNS_WEBDAV, _localName];
+    ASSIGNCOPY(self->lastWherePropName, fqn);
+    /* TODO: should return ? */
+  }
+  if (self->in.PropertyUpdate && self->in.Set && self->in.Prop) {
+    [self startPropValueElement:_localName namespace:XMLNS_WEBDAV];
+    return;
+  }
+  if (self->in.Response && self->in.PropStat && self->in.Prop) {
+    [self startPropValueElement:_localName namespace:XMLNS_WEBDAV];
+    return;
+  }
+  
+  c = [_localName characterAtIndex:0];
+  switch (c) {
+  case 'a':
+    if ([_localName isEqualToString:@"allprop"])
+      self->findAllProps = 1;
+    else if ([_localName isEqualToString:@"ascending"])
+      self->ascending = YES;
+    else if ([_localName isEqualToString:@"and"])
+      [self beginCompoundQualifier];
+    break;
+    
+  case 'b':
+    if ([_localName isEqualToString:@"basicsearch"])
+      [self startBasicSearch];
+    break;
+    
+  case 'd':
+    if ([_localName isEqualToString:@"depth"])
+      [self startDepthElement];
+    break;
+
+  case 'e':
+    if ([_localName isEqualToString:@"eq"])
+      self->in.eq = 1;
+    break;
+    
+  case 'f':
+    if ([_localName isEqualToString:@"from"])
+      self->in.from = 1;
+    break;
+    
+  case 'g':
+    if ([_localName isEqualToString:@"gt"])
+      self->in.gt = 1;
+    else if ([_localName isEqualToString:@"gte"])
+      self->in.gte = 1;
+    break;
+    
+  case 'h':
+    if ([_localName isEqualToString:@"href"])
+      [self startHrefElement];
+    break;
+    
+  case 'l':
+    if ([_localName isEqualToString:@"lt"])
+      self->in.lt = 1;
+    else if ([_localName isEqualToString:@"lte"])
+      self->in.lte = 1;
+    else if ([_localName isEqualToString:@"literal"])
+      [self startLiteralElement];
+    break;
+
+  case 'm':
+    if ([_localName isEqualToString:@"multistatus"]) {
+      self->in.MultiStatus = 1;
+      if (self->responses == nil)
+       self->responses = [[NSMutableArray alloc] initWithCapacity:64];
+    }
+    break;
+
+  case 'n':
+    if ([_localName isEqualToString:@"not"])
+      [self beginCompoundQualifier];
+    break;
+
+  case 'o':
+    if ([_localName isEqualToString:@"order"])
+      self->in.order = 1;
+    else if ([_localName isEqualToString:@"orderby"])
+      self->in.orderby = 1;
+    else if ([_localName isEqualToString:@"or"])
+      [self beginCompoundQualifier];
+    break;
+    
+  case 'p':
+    if ([_localName isEqualToString:@"propfind"]) {
+      if (self->propNames == nil)
+       self->propNames = [[NSMutableArray alloc] initWithCapacity:64];
+      self->in.PropFind = 1;
+    }
+    else if ([_localName isEqualToString:@"prop"])
+      [self startProp];
+    else if ([_localName isEqualToString:@"propstat"])
+      self->in.PropStat = 1;
+    else if ([_localName isEqualToString:@"propertyupdate"])
+      [self startPropUpdate];
+    else if ([_localName isEqualToString:@"propname"]) {
+      self->findPropNames = 1;
+    }
+    break;
+
+  case 'r':
+    if ([_localName isEqualToString:@"response"])
+      [self startResponseElement];
+    else if ([_localName isEqualToString:@"remove"])
+      self->in.Remove = 1;
+    break;
+
+  case 's':
+    if ([_localName isEqualToString:@"status"])
+      self->in.Status = 1;
+    else if ([_localName isEqualToString:@"set"])
+      [self startPropSet];
+    else if ([_localName isEqualToString:@"select"])
+      self->in.select = 1;
+    else if ([_localName isEqualToString:@"scope"])
+      self->in.scope = 1;
+    else if ([_localName isEqualToString:@"searchrequest"])
+      self->in.SearchRequest = 1;
+    else if ([_localName isEqualToString:@"sql"])
+      [self startSQLElement];
+    break;
+    
+  case 't':
+    if ([_localName isEqualToString:@"target"])
+      [self startTarget];
+    break;
+    
+  case 'w':
+    if ([_localName isEqualToString:@"where"])
+      self->in.where = 1;
+    break;
+    
+  default:
+    break;
+  }
+}
+- (void)endDavElement:(NSString *)_localName {
+  unsigned len;
+  unichar c;
+  
+  if ((len = [_localName length]) == 0)
+    return;
+  c = [_localName characterAtIndex:0];
+  
+  if (self->in.PropertyUpdate && self->in.Set && self->in.Prop) {
+    if (![_localName isEqualToString:@"prop"]) {
+      [self endPropValueElement:_localName namespace:XMLNS_WEBDAV];
+      return;
+    }
+  }
+  if (self->in.Response && self->in.PropStat && self->in.Prop) {
+    if (![_localName isEqualToString:@"prop"]) {
+      [self endPropValueElement:_localName namespace:XMLNS_WEBDAV];
+      return;
+    }
+  }
+  
+  switch (c) {
+  case 'a':
+    if ([_localName isEqualToString:@"and"])
+      [self endCompoundQualifier:@"and"];
+    break;
+  case 'b':
+    if ([_localName isEqualToString:@"basicsearch"])
+      [self endBasicSearch];
+    break;
+    
+  case 'd':
+    if ([_localName isEqualToString:@"depth"])
+      [self endDepthElement];
+    break;
+    
+  case 'e':
+    if ([_localName isEqualToString:@"eq"]) {
+      [self endComparisonQualifier:EOQualifierOperatorEqual];
+      self->in.eq = 0;
+    }
+    break;
+    
+  case 'f':
+    if ([_localName isEqualToString:@"from"])
+      self->in.from = 0;
+    break;
+
+  case 'g':
+    if ([_localName isEqualToString:@"gt"]) {
+      [self endComparisonQualifier:EOQualifierOperatorGreaterThan];
+      self->in.gt = 0;
+    }
+    else if ([_localName isEqualToString:@"gte"]) {
+      [self endComparisonQualifier:EOQualifierOperatorGreaterThanOrEqualTo];
+      self->in.gte = 0;
+    }
+    break;
+    
+  case 'h':
+    if ([_localName isEqualToString:@"href"])
+      [self endHrefElement];
+    break;
+    
+  case 'l':
+    if ([_localName isEqualToString:@"lt"]) {
+      [self endComparisonQualifier:EOQualifierOperatorLessThan];
+      self->in.lt = 0;
+    }
+    else if ([_localName isEqualToString:@"lte"]) {
+      [self endComparisonQualifier:EOQualifierOperatorLessThanOrEqualTo];
+      self->in.lte = 0;
+    }
+    else if ([_localName isEqualToString:@"literal"])
+      [self endLiteralElement];
+    break;
+    
+  case 'm':
+    if ([_localName isEqualToString:@"multistatus"])
+      self->in.MultiStatus = 0;
+    break;
+    
+  case 'n':
+    if ([_localName isEqualToString:@"not"])
+      [self endCompoundQualifier:@"not"];
+    break;
+
+  case 'o':
+    if ([_localName isEqualToString:@"order"])
+      self->in.order = 0;
+    else if ([_localName isEqualToString:@"orderby"])
+      self->in.orderby = 0;
+    else if ([_localName isEqualToString:@"or"])
+      [self endCompoundQualifier:@"or"];
+    break;
+    
+  case 'p':
+    if ([_localName isEqualToString:@"propfind"])
+      self->in.PropFind = 0;
+    else if ([_localName isEqualToString:@"prop"])
+      [self endProp];
+    else if ([_localName isEqualToString:@"propstat"])
+      self->in.PropStat = 0;
+    else if ([_localName isEqualToString:@"propertyupdate"])
+      self->in.PropertyUpdate = 0;
+    break;
+
+  case 'r':
+    if ([_localName isEqualToString:@"response"])
+      [self endResponseElement];
+    else if ([_localName isEqualToString:@"remove"])
+      self->in.Remove = 0;
+    break;
+
+  case 's':
+    if ([_localName isEqualToString:@"set"])
+      [self endPropSet];
+    else if ([_localName isEqualToString:@"select"])
+      self->in.select = 0;
+    else if ([_localName isEqualToString:@"scope"])
+      self->in.scope = 0;
+    else if ([_localName isEqualToString:@"searchrequest"])
+      self->in.SearchRequest = 0;
+    
+    else if ([_localName isEqualToString:@"sql"])
+      [self endSQLElement];
+    else if ([_localName isEqualToString:@"status"])
+      self->in.Status = 0;
+    break;
+
+  case 't':
+    if ([_localName isEqualToString:@"target"])
+      self->in.target = 0;
+    break;
+
+  case 'w':
+    if ([_localName isEqualToString:@"where"])
+      self->in.where = 0;
+    break;
+  }
+}
+
+/* element callbacks */
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attributes
+{
+  if (heavyLog) [self logWithFormat:@"START {%@}%@", _ns, _localName];
+  
+  if ([_ns isEqualToString:XMLNS_WEBDAV]) {
+    [self startDavElement:_localName];
+  }
+  else if (self->in.PropFind || self->in.select) {
+    NSString *fqn;
+    fqn = [NSString stringWithFormat:@"{%@}%@", _ns, _localName];
+    [self->propNames addObject:fqn];
+  }
+  else if (self->in.where && self->in.Prop) {
+    NSString *fqn;
+    fqn = [NSString stringWithFormat:@"{%@}%@", _ns, _localName];
+    ASSIGNCOPY(self->lastWherePropName, fqn);
+  }
+  else if (self->in.PropertyUpdate) {
+    if (self->in.Set) {
+      [self startPropValueElement:_localName namespace:_ns];
+    }
+    else if (self->in.Remove) {
+      NSString *fqn;
+    
+      fqn = [NSString stringWithFormat:@"{%@}%@", _ns, _localName];
+      [self->propNames addObject:fqn];
+    }
+  }
+  else if (self->in.Response && self->in.PropStat && self->in.Prop)
+    [self startPropValueElement:_localName namespace:_ns];
+}
+
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  if (heavyLog) [self logWithFormat:@"END {%@}%@", _ns, _localName];
+  
+  if ([_ns isEqualToString:XMLNS_WEBDAV]) {
+    [self endDavElement:_localName];
+  }
+  else if (self->in.PropFind) {
+    /* no close tags in propfind ... */
+  }
+  else if (self->in.PropertyUpdate) {
+    if (self->in.Set)
+      [self endPropValueElement:_localName namespace:_ns];
+    else if (self->in.Remove) {
+      /* no close tags in remove section ... */
+    }
+  }
+  else if (self->in.Response && self->in.PropStat && self->in.Prop)
+    [self endPropValueElement:_localName namespace:_ns];
+}
+
+/* CDATA */
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  if (heavyLog) [self logWithFormat:@"got %i chars", _len];
+  
+  if (_len > 0 && (self->cdata != nil)) {
+    NSString *s;
+    
+    s = [[NSString alloc] initWithCharacters:_chars length:_len];
+    [self->cdata appendString:s];
+    [s release];
+  }
+}
+
+@end /* SaxDAVHandler */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoDAV.h b/skyrix-sope/NGObjWeb/WebDAV/SoDAV.h
new file mode 100644 (file)
index 0000000..82c8758
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_SoDAV_H__
+#define __NGObjWeb_SoDAV_H__
+
+#include <NGObjWeb/EOFetchSpecification+SoDAV.h>
+#include <NGObjWeb/SaxDAVHandler.h>
+#include <NGObjWeb/SoDAVLockManager.h>
+#include <NGObjWeb/SoObject+SoDAV.h>
+#include <NGObjWeb/SoObjectDataSource.h>
+#include <NGObjWeb/SoObjectWebDAVDispatcher.h>
+#include <NGObjWeb/SoWebDAVRenderer.h>
+#include <NGObjWeb/SoWebDAVValue.h>
+
+#endif /* __NGObjWeb_SoDAV_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoDAVLockManager.h b/skyrix-sope/NGObjWeb/WebDAV/SoDAVLockManager.h
new file mode 100644 (file)
index 0000000..7cfb70f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoDAVLockManager_H__
+#define __SoObjects_SoDAVLockManager_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  A simple implementation of a WebDAV lock manager. Note that this only
+  works for single-process servers ... :-( Need some more powerful locking
+  class in practice, but for simple stuff which doesn't really need locking
+  this is sufficient.
+*/
+
+@class NSMutableDictionary;
+
+@interface SoDAVLockManager : NSObject
+{
+  NSMutableDictionary *uriToLockInfo;
+}
+
++ (id)sharedLockManager;
+
+- (id)lockURI:(NSString *)_uri timeout:(NSString *)_to 
+  scope:(NSString *)_scope type:(NSString *)_lockType
+  owner:(NSString *)_ownerURL;
+- (void)unlockURI:(NSString *)_uri token:(id)_token;
+
+- (id)lockTokenForURI:(NSString *)_uri;
+
+@end
+
+#endif /* __SoObjects_SoDAVLockManager_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoDAVLockManager.m b/skyrix-sope/NGObjWeb/WebDAV/SoDAVLockManager.m
new file mode 100644 (file)
index 0000000..08eced3
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoDAVLockManager.h"
+#include "common.h"
+
+@interface SoDAVLockInfo : NSObject
+{
+@public
+  NSString       *token;
+  NSCalendarDate *expireDate;
+}
+
+- (id)initWithToken:(NSString *)_token;
+- (BOOL)isValid;
+
+@end
+
+@implementation SoDAVLockManager
+
++ (id)sharedLockManager {
+  static SoDAVLockManager *lm = nil; // THREAD
+  if (lm == nil) lm = [[self alloc] init];
+  return lm;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->uriToLockInfo = [[NSMutableDictionary alloc] initWithCapacity:64];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->uriToLockInfo release];
+  [super dealloc];
+}
+
+- (id)lockURI:(NSString *)_uri timeout:(NSString *)_to 
+  scope:(NSString *)_scope type:(NSString *)_lockType
+  owner:(NSString *)_ownerURL
+{
+  SoDAVLockInfo *lockInfo;
+  
+  if ((lockInfo = [self->uriToLockInfo objectForKey:_uri])) {
+    if (![lockInfo isValid]) {
+      /* remove invalid lock */
+      [self->uriToLockInfo removeObjectForKey:_uri];
+      lockInfo = nil;
+    }
+  }
+  
+  if (lockInfo != nil)
+    /* already locked */
+    return nil;
+  
+  lockInfo = [[SoDAVLockInfo alloc] initWithToken:
+    [@"opaquelocktoken:" stringByAppendingString:
+       [[NSProcessInfo processInfo] globallyUniqueString]]];
+  [self->uriToLockInfo setObject:lockInfo forKey:_uri];
+  [lockInfo autorelease];
+  return lockInfo->token;
+}
+
+- (void)unlockURI:(NSString *)_uri token:(id)_token {
+  [self->uriToLockInfo removeObjectForKey:_uri];
+}
+
+- (id)lockTokenForURI:(NSString *)_uri {
+  SoDAVLockInfo *lockInfo;
+  
+  if ((lockInfo = [self->uriToLockInfo objectForKey:_uri])) {
+    if (![lockInfo isValid]) {
+      /* remove invalid lock */
+      [self->uriToLockInfo removeObjectForKey:_uri];
+      lockInfo = nil;
+    }
+  }
+  return lockInfo ? lockInfo->token : nil;
+}
+
+@end /* SoDAVLockManager */
+
+@implementation SoDAVLockInfo
+
+- (id)initWithToken:(NSString *)_token {
+  if ((self = [super init])) {
+    self->token = [_token copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->token      release];
+  [self->expireDate release];
+  [super dealloc];
+}
+
+- (BOOL)isValid {
+  return YES;
+}
+
+@end /* SoDAVLockInfo */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoDAVSQLParser.h b/skyrix-sope/NGObjWeb/WebDAV/SoDAVSQLParser.h
new file mode 100644 (file)
index 0000000..6bd389e
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WebDAV_SoDAVSQLParser_H__
+#define __WebDAV_SoDAVSQLParser_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+
+/*
+  This is parser can be used to parse simple SQL statements. It's not a full
+  SQL implementation, but should be sufficient for simple applications.
+
+  Additional hints:
+  - the selected attributes are added to the 'attributes' hint, if a
+    wildcard select is used (*), the hint is not set
+  - the depth of WebDAV scope from-queries are set in the depth-hint, valid
+    values are "deep", "flat", "flat+self", "self"
+  - if multiple entities are queried in the FROM, they are joined using ","
+    and set as the entityName of the fetch spec
+*/
+
+@class EOFetchSpecification, EOQualifier;
+
+@interface SoDAVSQLParser : NSObject
+{
+}
+
++ (id)sharedSQLParser;
+
+/* top level parser entry points */
+
+- (EOFetchSpecification *)parseSQLSelectStatement:(NSString *)_sql;
+- (EOQualifier *)parseSQLWhereExpression:(NSString *)_sql;
+
+/* parsing parts (exported for overloading in subclasses) */
+
+- (BOOL)parseSQL:(id *)result
+  from:(unichar **)pos length:(unsigned *)len
+  strict:(BOOL)beStrict;
+- (BOOL)parseToken:(const unsigned char *)tk
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume;
+- (BOOL)parseIdentifier:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume;
+- (BOOL)parseQualifier:(EOQualifier **)result
+  from:(unichar **)pos length:(unsigned *)len;
+- (BOOL)parseScope:(NSString **)_scope:(NSString **)_entity
+  from:(unichar **)pos length:(unsigned *)len;
+
+- (BOOL)parseColumnName:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume;
+- (BOOL)parseTableName:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume;
+- (BOOL)parseIdentifierList:(NSArray **)result
+  from:(unichar **)pos length:(unsigned *)len
+  selector:(SEL)_sel;
+
+@end
+
+#endif /* __WebDAV_SoDAVSQLParser_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoDAVSQLParser.m b/skyrix-sope/NGObjWeb/WebDAV/SoDAVSQLParser.m
new file mode 100644 (file)
index 0000000..abc4b54
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "SoDAVSQLParser.h"
+#include <EOControl/EOQualifier.h>
+#include <EOControl/EOFetchSpecification.h>
+#include <EOControl/EOSortOrdering.h>
+#include <EOControl/EOClassDescription.h>
+#include "common.h"
+
+// TODO: better error output
+
+@interface SoDAVSQLParser(Logging) /* this is available in NGExtensions */
+- (void)logWithFormat:(NSString *)_fmt,...;
+@end
+
+@interface EOSQLQualifierIdMapper : NSObject
+@end
+
+@implementation SoDAVSQLParser
+
++ (id)sharedSQLParser {
+  static SoDAVSQLParser *sharedParser = nil; // THREAD
+  if (sharedParser == nil)
+    sharedParser = [[SoDAVSQLParser alloc] init];
+  return sharedParser;
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* top level parsers */
+
+- (EOFetchSpecification *)parseSQLSelectStatement:(NSString *)_sql {
+  EOFetchSpecification *fs;
+  unichar  *us, *pos;
+  unsigned len, remainingLen;
+  
+  if ((len = [_sql length]) == 0) return nil;
+
+  us  = calloc(len + 10, sizeof(unichar));
+  [_sql getCharacters:us];
+  us[len] = 0;
+  pos = us;
+  remainingLen = len;
+  
+  if (![self parseSQL:&fs from:&pos length:&remainingLen strict:NO])
+    [self logWithFormat:@"parsing of SQL failed."];
+  
+  if (us) free(us);
+  
+  return [fs autorelease];
+}
+
+- (EOQualifier *)_parseSQLWhereExpression:(NSString *)_sql {
+  // TODO: process %=>* and %%, and $
+  unichar  *buf;
+  unsigned i, len;
+  BOOL     didReplace;
+  if ((len = [_sql length]) == 0) return nil;
+  
+  // TODO: improve, real parsing in qualifier parser !
+  
+  buf = calloc(len + 3, sizeof(unichar));
+  NSAssert(buf, @"could not allocate char buffer");
+  
+  [_sql getCharacters:buf];
+  for (i = 0, didReplace = NO; i < len; i++) {
+    if (buf[i] != '%') {
+      if (buf[i] == '*') {
+        NSLog(@"WARNING(%s): SQL string contains a '*': %@",
+              __PRETTY_FUNCTION__, _sql);
+      }
+      continue;
+    }
+    buf[i] = '%';    
+    didReplace = YES;
+  }
+  if (didReplace)
+    _sql = [NSString stringWithCharacters:buf length:len];
+  if (buf) free(buf);
+  
+  return [EOQualifier qualifierWithQualifierFormat:_sql];
+}
+
+/* parsing parts (exported for overloading in subclasses) */
+
+static inline BOOL
+uniIsCEq(unichar *haystack, const unsigned char *needle, unsigned len) 
+{
+  register unsigned idx;
+  for (idx = 0; idx < len; idx++) {
+    if (*needle == '\0')               return YES;
+    if (toupper(haystack[idx]) != needle[idx]) return NO;
+  }
+  return YES;
+}
+static inline void skipSpaces(unichar **pos, unsigned *len) {
+  while (*len > 0) {
+    if (!isspace(*pos[0])) return;
+    (*len)--;
+    (*pos)++;
+  }
+}
+static void printUniStr(unichar *pos, unsigned len) __attribute__((unused));
+static void printUniStr(unichar *pos, unsigned len) {
+  unsigned i;
+  for (i = 0; i < len && i < 80; i++)
+    putchar(pos[i]);
+  putchar('\n');
+}
+
+static inline BOOL isTokStopChar(unichar c) {
+  switch (c) {
+  case 0:
+  case ')': case '(': case '"': case '\'':
+    return YES;
+  default:
+    if (isspace(c)) return YES;
+    return NO;
+  }
+}
+
+- (BOOL)parseToken:(const unsigned char *)tk
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume
+{
+  /* ...[space] (strlen(tk)+1 chars) */
+  unichar  *scur;
+  unsigned slen, tlen;
+  
+  tlen = strlen(tk);
+  scur=*pos; slen=*len; // begin transaction
+  skipSpaces(&scur, &slen);
+  
+  if (slen < tlen)
+    return NO;
+  if (toupper(scur[0]) != tk[0])
+    return NO;
+  if (tlen < slen) { /* if tok is not at the end */
+    if (!isTokStopChar(scur[tlen]))
+      return NO; /* not followed by a token stopper */
+  }
+  if (!uniIsCEq(scur, tk, tlen)) 
+    return NO;
+  
+  scur+=tlen; slen-=tlen;
+  
+  if (consume) { *pos = scur; *len = slen; } // end tx
+  return YES;
+}
+
+- (BOOL)parseIdentifier:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume
+{
+  /* "attr" or attr (at least 1 char or 2 for ") */
+  unichar  *scur;
+  unsigned slen;
+  
+  if (result) *result = nil;
+  scur=*pos; slen=*len; // begin transaction
+  skipSpaces(&scur, &slen);
+  
+  if (*scur == '"') {
+    /* quoted attr */
+    unichar *start;
+    
+    //printf("try quoted attr\n");
+    if (slen < 2) return NO;
+    scur++; slen--; /* skip quote */
+    if (*scur == '"') {
+      /* empty name */
+      scur++; slen--;
+      if (consume) { *pos = scur; *len = slen; } // end transaction
+      *result = @"";
+      //printf("is empty quoted\n");
+      return YES;
+    }
+    if (slen < 2) return NO;
+    
+    start = scur;
+    while ((slen > 0) && (*scur != '"')) {
+      if (*scur == '\\' && (slen > 1)) {
+       /* quoted char */
+       scur++; slen--; // skip one more (still needs to be filtered in result
+      }
+      scur++; slen--;
+    }
+    if (slen > 0) { scur++; slen--; } /* skip quote */
+    
+    // TODO: xhandle contained quoted chars ?
+    *result = 
+      [[NSString alloc] initWithCharacters:start length:(scur-start-1)];
+    //NSLog(@"found qattr: %@", *result);
+  }
+  else {
+    /* non-quoted attr */
+    unichar *start;
+    
+    if (slen < 1) return NO;
+    
+    if ([self parseToken:"FROM" from:&scur length:&slen consume:NO]) {
+      /* not an attribute, the from starts ... */
+      // printf("rejected unquoted attr, is a FROM\n");
+      return NO;
+    }
+    if ([self parseToken:"WHERE" from:&scur length:&slen consume:NO]) {
+      /* not an attribute, the where starts ... */
+      // printf("rejected unquoted attr, is a WHERE\n");
+      return NO;
+    }
+    
+    start = scur;
+    while ((slen > 0) && !isspace(*scur) && (*scur != ',')) {
+      slen--;
+      scur++;
+    }
+    *result = [[NSString alloc] initWithCharacters:start length:(scur-start)];
+    //NSLog(@"found attr: %@ (len=%i)", *result, (scur-start));
+  }
+  if (consume && result) { *pos = scur; *len = slen; } // end transaction
+  return *result ? YES : NO;
+}
+
+- (BOOL)parseTableName:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume
+{
+  return [self parseIdentifier:result from:pos length:len consume:consume];
+}
+
+- (BOOL)parseIdentifierList:(NSArray **)result
+  from:(unichar **)pos length:(unsigned *)len
+  selector:(SEL)_sel
+{
+  /* attr[,attr] */
+  NSMutableArray *attrs = nil;
+  unichar  *scur;
+  unsigned slen;
+  id       attr;
+  BOOL (*parser)(id, SEL, NSString **, unichar **, unsigned *, BOOL);
+  
+  if (result) *result = nil;
+  scur=*pos; slen=*len; // begin transaction
+  skipSpaces(&scur, &slen);
+  parser = (void *)[self methodForSelector:_sel];
+  
+  if (slen < 1) return NO; // not enough chars
+  
+  if (*scur == '*') {
+    /* a wildcard list, return 'nil' as result */
+    //printf("try wildcard\n");
+    scur++; slen--; // skip '*'
+    if (!(slen == 0 || isspace(*scur))) {
+      /* not followed by space or at end */
+      return NO;
+    }
+    *pos = scur; *len = slen; // end transaction
+    *result = nil;
+    return YES;
+  }
+  
+  if (!parser(self, _sel, &attr,&scur,&slen,YES))
+    /* well, we need at least one attribute to make it a list */
+    return NO;
+  
+  attrs = [[NSMutableArray alloc] initWithCapacity:32];
+  [attrs addObject:attr]; [attr release];
+  
+  /* all the remaining attributes must be prefixed with a "," */
+  while (slen > 1) {
+    //printf("try next list attr comma\n");
+    skipSpaces(&scur, &slen);
+    if (slen < 2) break;
+    if (*scur != ',') break;
+    scur++; slen--; // skip ','
+    
+    //printf("try next list attr\n");
+    if (!parser(self, _sel, &attr,&scur,&slen,YES))
+      break;
+    
+    [attrs addObject:attr]; [attr release];
+  }
+  
+  *pos = scur; *len = slen; // end transaction
+  *result = attrs;
+  return YES;
+}
+
+- (BOOL)parseContainsQualifier:(EOQualifier **)q_
+  from:(unichar **)pos length:(unsigned *)len
+{
+  /* contains('"hh@"') [12+ chars] */
+  unichar  *scur;
+  unsigned slen;
+  NSString *s;
+  if (q_) *q_ = nil;
+  skipSpaces(&scur, &slen);
+  
+  if (slen < 12) return NO; // not enough chars
+  
+  if (![self parseToken:"CONTAINS" from:pos length:len consume:YES])
+    return NO;
+  skipSpaces(&scur, &slen);
+  [self parseToken:"('" from:&scur length:&slen consume:YES];
+  
+  if (![self parseIdentifier:&s from:&scur length:&slen consume:YES])
+    return NO;
+  
+  skipSpaces(&scur, &slen);
+  [self parseToken:"')" from:&scur length:&slen consume:YES];
+  
+  *q_ = [[EOQualifier qualifierWithQualifierFormat:
+                       @"contentAsString doesContain: %@", s] retain];
+  if (*q_) {
+    *pos = scur; *len = slen; // end transaction
+    return YES;
+  }
+  else
+    return NO;
+}
+
+- (BOOL)parseQualifier:(EOQualifier **)result
+  from:(unichar **)pos length:(unsigned *)len
+{
+  unichar  *scur;
+  unsigned slen;
+  
+  if (result) *result = nil;
+  scur=*pos; slen=*len; // begin transaction
+  skipSpaces(&scur, &slen);
+  
+  if (slen < 3) return NO; // not enough chars
+  
+  // for now should scan till we find either ORDER BY order GROUP BY
+  {
+    unichar *start = scur;
+    
+    while (slen > 0) {
+      if (*scur == 'O' || *scur == 'o') {
+       if ([self parseToken:"ORDER" from:&scur length:&slen consume:NO]) {
+         //printf("FOUND ORDER TOKEN ...\n");
+         break;
+       }
+      }
+      else if (*scur == 'G' || *scur == 'g') {
+       if ([self parseToken:"GROUP" from:&scur length:&slen consume:NO]) {
+         //printf("FOUND GROUP TOKEN ...\n");
+         break;
+       }
+      }
+      
+      scur++; slen--;
+    }
+
+    {
+      EOQualifier *q;
+      NSString *s;
+      
+      s = [[NSString alloc] initWithCharacters:start length:(scur-start)];
+      if ([s length] == 0) {
+       [s release];
+       return NO;
+      }
+      if ((q = [self parseSQLWhereExpression:s]) == nil) {
+       [s release];
+       return NO;
+      }
+      *result = [q retain];
+      [s release];
+    }
+  }
+  
+  *pos = scur; *len = slen; // end transaction
+  return YES;
+}
+
+- (BOOL)parseScope:(NSString **)_scope:(NSString **)_entity
+  from:(unichar **)pos length:(unsigned *)len
+{
+  /* 
+    "('shallow traversal of "..."')"
+    "('hierarchical traversal of "..."')"
+  */
+  unichar  *scur;
+  unsigned slen;
+  NSString *entityName;
+  BOOL isShallow = NO;
+  BOOL isDeep    = NO;
+  
+  if (_scope)  *_scope  = nil;
+  if (_entity) *_entity = nil;
+  scur=*pos; slen=*len; // begin transaction
+  skipSpaces(&scur, &slen);
+  if (slen < 14) return NO; // not enough chars
+  
+  if (*scur != '(') return NO; // does not start with '('
+  scur++; slen--; // skip '('
+  skipSpaces(&scur, &slen);
+  
+  if (*scur != '\'') return NO; // does not start with '(''
+  scur++; slen--; // skip single quote
+  
+  /* next the depth */
+  
+  if ([self parseToken:"SHALLOW" from:&scur length:&slen consume:YES])
+    isShallow = YES;
+  else if ([self parseToken:"HIERARCHICAL" from:&scur length:&slen consume:YES])
+    isDeep = YES;
+  else if ([self parseToken:"DEEP" from:&scur length:&slen consume:YES])
+    isDeep = YES;
+  else
+    /* unknown traveral key */
+    return NO;
+  
+  /* some syntactic sugar (not strict about that ...) */
+  [self parseToken:"TRAVERSAL" from:&scur length:&slen consume:YES];
+  [self parseToken:"OF"        from:&scur length:&slen consume:YES];
+  if (slen < 1) return NO; // not enough chars
+  
+  /* now the entity */
+  skipSpaces(&scur, &slen);
+  if (![self parseTableName:&entityName from:&scur length:&slen consume:YES])
+    return NO; // failed to parse entity from scope
+
+  /* trailer */
+  skipSpaces(&scur, &slen);
+  if (slen > 0 && *scur == '\'') {
+    scur++; slen--; // skip single quote
+  }
+  skipSpaces(&scur, &slen);
+  if (slen > 0 && *scur == ')') {
+    scur++; slen--; // skip ')'
+  }
+  
+  if (_scope)  *_scope  = isShallow ? @"flat" : @"deep";
+  if (_entity) *_entity = entityName;
+  *pos = scur; *len = slen; // end transaction
+  return YES;
+}
+
+- (BOOL)parseSELECT:(EOFetchSpecification **)result
+  from:(unichar **)pos length:(unsigned *)len
+  strict:(BOOL)beStrict
+{
+  EOFetchSpecification *fs;
+  NSMutableDictionary *lHints;
+  NSString *scope     = nil;
+  NSArray  *attrs     = nil;
+  NSArray  *fromList  = nil;
+  NSArray  *orderList = nil;
+  NSArray  *lSortOrderings = nil;
+  EOQualifier *q = nil;
+  BOOL hasSelect = NO;
+  BOOL hasFrom   = NO;
+  BOOL missingByOfOrder = NO;
+  BOOL missingByOfGroup = NO;
+  
+  *result = nil;
+  
+  if (![self parseToken:"SELECT" from:pos length:len consume:YES]) {
+    /* must begin with SELECT */
+    if (beStrict) return NO;
+  }
+  else
+    hasSelect = YES;
+  
+  if (![self parseIdentifierList:&attrs from:pos length:len
+            selector:@selector(parseColumnName:from:length:consume:)]) {
+    [self logWithFormat:@"missing ID list .."];
+    return NO;
+  }
+  //[self debugWithFormat:@"parsed attrs (%i): %@", [attrs count], attrs];
+  
+  /* now a from is expected */
+  if ([self parseToken:"FROM" from:pos length:len consume:YES])
+    hasFrom = YES;
+  else {
+    if (beStrict) return NO;
+  }
+  
+  /* check whether it's followed by a scope */
+  if ([self parseToken:"SCOPE" from:pos length:len consume:YES]) {
+    NSString *scopeEntity = nil;
+    
+    if (![self parseScope:&scope:&scopeEntity from:pos length:len]) {
+      if (beStrict) return NO;
+    }
+#if DEBUG_PARSING
+    else
+      [self logWithFormat:@"FOUND SCOPE: '%@'", scope];
+#endif
+    
+    if (scopeEntity)
+      fromList = [[NSArray alloc] initWithObjects:scopeEntity, nil];
+    [scopeEntity release];
+  }
+  else {
+    if (![self parseIdentifierList:&fromList from:pos length:len
+              selector:@selector(parseTableName:from:length:consume:)]) {
+      [self logWithFormat:@"missing from list .."];
+      return NO;
+    }
+#if DEBUG_PARSING
+    [self logWithFormat:@"parsed FROM list (%i): %@",
+         [fromList count], fromList];
+#endif
+  }
+  
+  /* check where */
+  if ([self parseToken:"WHERE" from:pos length:len consume:YES]) {
+    /* parse qualifier ... */
+    
+    if ([self parseToken:"CONTAINS" from:pos length:len consume:NO]) {
+      if (![self parseContainsQualifier:&q from:pos length:len]) {
+       if (beStrict) return NO;
+      }
+    }
+    else if (![self parseQualifier:&q from:pos length:len]) {
+      if (beStrict) return NO;
+    }
+#if DEBUG_PARSING
+    [self logWithFormat:@"FOUND Qualifier: '%@'", q];
+#endif
+  }
+  
+  /* check order-by */
+  if ([self parseToken:"ORDER" from:pos length:len consume:YES]) {
+    if (![self parseToken:"BY" from:pos length:len consume:YES]) {
+      if (beStrict) return NO;
+      missingByOfOrder = YES;
+    }
+    
+    if (![self parseIdentifierList:&orderList from:pos length:len
+              selector:@selector(parseColumnName:from:length:consume:)])
+      return NO;
+#if DEBUG_PARSING
+    [self logWithFormat:@"parsed ORDER list (%i): %@", 
+           [orderList count], orderList];
+#endif
+  }
+  
+  /* check group-by */
+  if ([self parseToken:"GROUP" from:pos length:len consume:YES]) {
+    if (![self parseToken:"BY" from:pos length:len consume:YES]) {
+      if (beStrict) return NO;
+      missingByOfGroup = YES;
+    }
+  }
+  
+  //printUniStr(*pos, *len); // DEBUG
+  
+  if (!hasSelect) [self logWithFormat:@"missing SELECT !"];
+  if (!hasFrom)   [self logWithFormat:@"missing FROM !"];
+  if (missingByOfOrder) [self logWithFormat:@"missing BY in ORDER BY !"];
+
+  /* build fetchspec */
+
+  lHints = [[NSMutableDictionary alloc] initWithCapacity:16];
+  
+  if (scope) {
+    [lHints setObject:scope forKey:@"scope"];
+    [scope release]; scope = nil;
+  }
+  if (attrs) {
+    [lHints setObject:attrs forKey:@"attributes"];
+    [attrs release]; attrs = nil;
+  }
+  if (orderList) {
+    NSMutableArray *ma;
+    unsigned i, len;
+    
+    len = [orderList count];
+    ma = [[NSMutableArray alloc] initWithCapacity:len];
+    for (i = 0; i < len; i++) {
+      EOSortOrdering *so;
+      
+      so = [EOSortOrdering sortOrderingWithKey:[orderList objectAtIndex:i]
+                          selector:EOCompareAscending];
+    }
+    lSortOrderings = [ma shallowCopy];
+    [ma release];
+    [orderList release]; orderList = nil;
+  }
+  
+  fs = [[EOFetchSpecification alloc]
+        initWithEntityName:[fromList componentsJoinedByString:@","]
+        qualifier:q
+        sortOrderings:lSortOrderings
+        usesDistinct:NO isDeep:NO hints:lHints];
+  [lHints release];
+  [q release];
+  [fromList release];
+  
+  *result = fs;
+  return fs ? YES : NO;
+}
+
+- (BOOL)parseSQL:(id *)result
+  from:(unichar **)pos length:(unsigned *)len
+  strict:(BOOL)beStrict
+{
+  if (*len < 1) return NO;
+  
+  if ([self parseToken:"SELECT" from:pos length:len consume:NO])
+    return [self parseSELECT:result from:pos length:len strict:beStrict];
+  
+  //if ([self parseToken:"UPDATE" from:pos length:len consume:NO])
+  //if ([self parseToken:"INSERT" from:pos length:len consume:NO])
+  //if ([self parseToken:"DELETE" from:pos length:len consume:NO])
+  
+  [self logWithFormat:@"tried to parse an unsupported SQL statement."];
+  return NO;
+}
+
+/* WebDAV specific */
+
+- (EOQualifier *)parseSQLWhereExpression:(NSString *)_sql {
+  // TODO: process %=>* and %%, and $
+  static EOSQLQualifierIdMapper *map = nil;
+  EOQualifier *q;
+
+  if ((q = [self _parseSQLWhereExpression:_sql]) == nil)
+    return nil;
+  
+  if (map == nil) map = [[EOSQLQualifierIdMapper alloc] init];
+  q = [q qualifierByApplyingKeyMap:(id)map];
+  return q;
+}
+
+- (BOOL)parseColumnName:(NSString **)result
+  from:(unichar **)pos length:(unsigned *)len
+  consume:(BOOL)consume
+{
+  BOOL ok;
+  
+  ok = [self parseIdentifier:result from:pos length:len consume:consume];
+  if (!ok) return NO;
+  
+  if (*result) {
+    /* heuristics to morph fully qualified name to namespace/localname */
+    NSRange r;
+    NSString *l, *ns;
+    
+    r = [*result rangeOfString:@"/" 
+                options:NSLiteralSearch|NSBackwardsSearch];
+    if (r.length == 0) {
+      r = [*result rangeOfString:@":" 
+                  options:NSLiteralSearch|NSBackwardsSearch];
+    }
+    if (r.length == 0)
+      return YES;
+    
+    l  = [*result substringFromIndex:(r.location + r.length)];
+    ns = [*result substringToIndex:(r.location + 1)];
+    
+    [*result autorelease];
+    *result = [[NSString alloc] initWithFormat:@"{%@}%@", ns, l];
+  }
+  return YES;
+}
+
+@end /* SoDAVSQLParser */
+
+@implementation SoDAVSQLParser(Tests)
+
++ (void)testDAVQuery {
+  EOFetchSpecification *fs;
+  NSString *sql;
+  
+  NSLog(@"testing: %@ --------------------", self);
+
+  sql = @"\n"
+  @"select \n"
+  @"  \"http://schemas.microsoft.com/mapi/proptag/x0e230003\",        \n"
+  @"  \"urn:schemas:mailheader:subject\",        \n"
+  @"  \"urn:schemas:mailheader:from\",\n"
+  @"  \"urn:schemas:mailheader:to\",        \n"
+  @"  \"urn:schemas:mailheader:cc\",        \n"
+  @"  \"urn:schemas:httpmail:read\",        \n"
+  @"  \"urn:schemas:httpmail:hasattachment\",        \n"
+  @"  \"DAV:getcontentlength\",        \n"
+  @"  \"urn:schemas:mailheader:date\",        \n"
+  @"  \"urn:schemas:httpmail:date\",      \n"
+  @"  \"urn:schemas:mailheader:received\",        \n"
+  @"  \"urn:schemas:mailheader:message-id\",        \n"
+  @"  \"urn:schemas:mailheader:in-reply-to\",        \n"
+  @"  \"urn:schemas:mailheader:references\"      \n"
+  @"from \n"
+  @"  scope('shallow traversal of \"http://127.0.0.1:9000/o/ol/helge/INBOX\"')\n"
+  @"where \n"
+  @"  \"DAV:iscollection\" = False \n"
+  @"  and \n"
+  @"  \"http://schemas.microsoft.com/mapi/proptag/x0c1e001f\" != 'SMTP'\n"
+  @"  and \n"
+  @"  \"http://schemas.microsoft.com/mapi/proptag/x0e230003\" > 0  \n"
+  @"  \n";
+  fs = [[self sharedSQLParser] parseSQLSelectStatement:sql];
+  
+  NSLog(@"  FS: %@", fs);
+  if (fs == nil) {
+    NSLog(@"  ERROR: could not parse SQL: %@", sql);
+  }
+  else {
+    EOQualifier *q;
+    NSString *scope;
+    NSArray  *props;
+    
+    if ((scope = [[fs hints] objectForKey:@"scope"]) == nil)
+      NSLog(@"  INVALID: got no scope !");
+    if (![scope isEqualToString:@"flat"])
+      NSLog(@"  INVALID: got scope %@, expected flat !", scope);
+
+#if 0    
+    if ([fs queryWebDAVPropertyNamesOnly])
+      NSLog(@"  INVALID: name query only, but queried several attrs !");
+#endif
+    
+    /* check qualifier */
+    if ((q = [fs qualifier]) == nil)
+      NSLog(@"  INVALID: got not qualifier (expected one) !");
+    else if (![q isKindOfClass:[EOAndQualifier class]]) {
+      NSLog(@"  INVALID: expected AND qualifier, got %@ !",
+           NSStringFromClass([q class]));
+    }
+    else if ([[(EOAndQualifier *)q qualifiers] count] != 3) {
+      NSLog(@"  INVALID: expected 3 subqualifiers, got %i !",
+           [[(EOAndQualifier *)q qualifiers] count]);
+    }
+
+    /* check sortordering */
+    if ([fs sortOrderings] != nil) {
+      NSLog(@"  INVALID: got sort orderings, specified none: %@ !",
+           [fs sortOrderings]);
+    }
+    
+    /* attributes */
+    if ((props = [[fs hints] objectForKey:@"attributes"]) == nil)
+      NSLog(@"  INVALID: got not attributes (expected some) !");
+    else if (![props isKindOfClass:[NSArray class]]) {
+      NSLog(@"  INVALID: attributes not delivered as array ?: %@",
+           NSStringFromClass([props class]));
+    }
+    else if ([props count] != 14) {
+      NSLog(@"  INVALID: invalid attribute count, expected 14, got %i.",
+           [props count]);
+    }
+  }
+  
+  NSLog(@"done test: %@ ------------------", self);
+}
+
+@end /* SoDAVSQLParser(Tests) */
+
+@implementation EOSQLQualifierIdMapper
+
+- (id)objectForKey:(NSString *)_key {
+  NSRange  r;
+  NSString *l, *ns;
+  
+  if (_key == nil) return nil;
+  
+  r = [_key rangeOfString:@"/" options:NSLiteralSearch|NSBackwardsSearch];
+  if (r.length == 0)
+    r = [_key rangeOfString:@":" options:NSLiteralSearch|NSBackwardsSearch];
+  if (r.length == 0)
+    return _key;
+  
+  l  = [_key substringFromIndex:(r.location + r.length)];
+  ns = [_key substringToIndex:(r.location + 1)];
+  
+  return [NSString stringWithFormat:@"{%@}%@", ns, l];
+}
+
+@end /* EOSQLQualifierIdMapper */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoObject+SoDAV.h b/skyrix-sope/NGObjWeb/WebDAV/SoObject+SoDAV.h
new file mode 100644 (file)
index 0000000..02f770b
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+  Copyright (C) 2002-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$
+
+#ifndef __WebDAV_SoObject_SoDAV_H__
+#define __WebDAV_SoObject_SoDAV_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoObject DAV Protocol
+  
+  This informal protocol contains methods that can be implemented by
+  SoObject's supporting WebDAV authoring. For most methods a default
+  implementation is provided.
+*/
+
+@class NSString, NSDate, NSEnumerator, NSException, NSDictionary, NSArray;
+@class EOFetchSpecification, EOGlobalID, EODataSource;
+@class SoDAVLockManager;
+
+@interface NSObject(SoObjectSoDAV)
+
+/*
+  This method is invoked on SoObjects if a WebDAV PROPFIND or SEARCH
+  request was issued.
+*/
+- (id)performWebDAVQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx;
+- (id)performWebDAVBulkQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx;
+- (NSEnumerator *)davChildKeysInContext:(id)_ctx;
+- (EODataSource *)contentDataSourceInContext:(id)_ctx;
+- (id)davQueryOnSelf:(EOFetchSpecification *)_fs inContext:(id)_ctx;
+
+- (NSArray *)defaultWebDAVPropertyNamesInContext:(id)_ctx;
+
+/*
+  Editing the object properties (PROPPATCH)
+*/
+- (NSException *)davSetProperties:(NSDictionary *)_setProps
+  removePropertiesNamed:(NSArray *)_delProps
+  inContext:(id)_ctx;
+- (id)davCreateObject:(NSString *)_name
+  properties:(NSDictionary *)_props
+  inContext:(id)_ctx;
+- (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx;
+
+- (NSException *)davMoveToTargetObject:(id)_target newName:(NSString *)_name
+  inContext:(id)_ctx;
+- (NSException *)davCopyToTargetObject:(id)_target newName:(NSString *)_name
+  inContext:(id)_ctx;
+
+/*
+  Use the attribute map to map WebDAV propery names to KVC keys for the
+  object. If the object returns a map, the SoObjectWebDAVDispatcher will
+  properly justify the EOFetchSpecification for queries.
+*/
+- (id)davAttributeMapInContext:(id)_ctx;
++ (id)defaultWebDAVAttributeMap;
+
+/*
+  WebDAV supports locking/unlocking of resources, you can override the
+  default locking mechanism used by implementing this method.
+*/
+- (SoDAVLockManager *)davLockManagerInContext:(id)_ctx;
+
+
+/* some DAV properties are mapped to some keys by default */
+
+- (BOOL)davIsCollection;  // tries -isCollection and NSFileType, otherwise NO
+- (BOOL)davIsFolder;      // same as -davIsCollection
+- (BOOL)davHasSubFolders; // same as -davIsFolder
+- (BOOL)davIsHidden;      // returns NO
+- (BOOL)davIsExecutable;  // returns NO
+
+- (id)davUid;             // tries -globalID, otherwise same as -davURL
+- (id)davEntityTag;
+- (id)davURL;             // tries -baseURLInContext:, -baseURL otherwise nil
+- (id)davContentLength;   // tries NSFileSize, -contentLength, otherwise 0
+- (NSString *)davContentType;
+
+- (NSDate *)davLastModified; // tries NSFileModificationDate, otherwise now
+// tries NSFileCreationDate, NSFileModificationDate, otherwise nil
+- (NSDate *)davCreationDate;
+
+// tries -displayName, NSFileSubject,NSFileName,NSFilePath, -path otherwise nil
+- (NSString *)davDisplayName;
+- (NSString *)davResourceType; // uses -davIsCollection
+
+// uses -davIsCollection (urn:content-class:folder or urn:content-class:item)
+- (NSString *)davContentClass;
+
+
+- (BOOL)davDenySubFolders;
+- (unsigned int)davChildCount;
+- (unsigned int)davObjectCount;
+- (unsigned int)davVisibleCount;
+
+@end
+
+#endif /* __WebDAV_SoObject_SoDAV_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoObject+SoDAV.m b/skyrix-sope/NGObjWeb/WebDAV/SoObject+SoDAV.m
new file mode 100644 (file)
index 0000000..e12ed35
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoObject+SoDAV.h"
+#include "SoObject.h"
+#include "NSException+HTTP.h"
+#include "SoDAVLockManager.h"
+#include <NGObjWeb/WOApplication.h>
+#include "common.h"
+
+/* informal interface for methods tried by the DAV key implementation */
+
+@interface NSObject(SoResourceObject)
+
+- (BOOL)isCollection;
+- (NSString *)displayName;
+- (NSString *)path;
+
+- (unsigned int)contentLength;
+- (EOGlobalID *)globalID;
+
+- (id)baseURL;
+- (id)baseURLInContext:(id)_ctx;
+
+@end
+
+@implementation NSObject(SoObjectSoDAVImp)
+
+- (NSArray *)defaultWebDAVPropertyNamesInContext:(id)_ctx {
+  static NSArray *defNames = nil;
+  if (defNames == nil) {
+    defNames = [[[NSUserDefaults standardUserDefaults] 
+                                arrayForKey:@"SoDefaultWebDAVPropertyNames"]
+                                copy];
+  }
+#if 0 /* TODO: check whether this would be better ... */
+  keys = [[self soClassDescription] attributeKeys];
+  [self debugWithFormat:@"using keys from description: %@", keys];
+#endif
+  return defNames;
+}
+
+/* attributes */
+
+- (BOOL)davIsCollection {
+  id v;
+  if ([self respondsToSelector:@selector(isCollection)])
+    return [self isCollection];
+  if ((v = [self valueForKey:@"NSFileType"])) {
+    if ([v isEqualToString:NSFileTypeDirectory])
+      return YES;
+    else
+      return NO;
+  }
+  return [[self toOneRelationshipKeys] count] > 0 ? YES : NO;
+}
+
+- (BOOL)davIsFolder {
+  return [self davIsCollection];
+}
+
+- (BOOL)davHasSubFolders {
+  NSEnumerator *e;
+  NSString *childName;
+  id       ctx;
+  
+  if (![self davIsCollection]) return NO;
+  ctx = [[WOApplication application] context];
+  
+  e = [self davChildKeysInContext:ctx];
+  while ((childName = [e nextObject])) {
+    if ([[self lookupName:childName inContext:ctx acquire:NO] davIsFolder])
+      return YES;
+  }
+  return NO;
+}
+
+- (BOOL)davDenySubFolders {
+  return [self davIsCollection] ? NO : YES;
+}
+
+- (unsigned int)davChildCount {
+  NSEnumerator *e;
+  unsigned int i;
+  
+  if (![self davIsCollection]) return 0;
+  e = [self davChildKeysInContext:[[WOApplication application] context]];
+  for (i = 0; [e nextObject]; i++)
+    ;
+  return i;
+}
+- (unsigned int)davObjectCount {
+  NSEnumerator *e;
+  unsigned int i;
+  NSString     *childName;
+  WOContext    *ctx;
+  
+  if (![self davIsCollection]) return 0;
+  
+  ctx = [[WOApplication application] context];
+  i = 0;
+  e = [self davChildKeysInContext:ctx];
+  while ((childName = [e nextObject])) {
+    if (![[self lookupName:childName inContext:ctx acquire:NO] davIsCollection])
+      i++;
+  }
+  return i;
+}
+- (unsigned int)davVisibleCount {
+  return [self davObjectCount];
+}
+
+- (BOOL)davIsHidden {
+  return NO;
+}
+
+- (id)davUid {
+  if ([self respondsToSelector:@selector(globalID)])
+    return [self globalID];
+  return [self davURL];
+}
+- (id)davEntityTag {
+  return [self davUid];
+}
+
+- (BOOL)davIsStructuredDocument {
+  return NO;
+}
+
+- (id)davURL {
+  id url;
+  
+  if ([self respondsToSelector:@selector(baseURLInContext:)]) {
+    url = [self baseURLInContext:[[WOApplication application] context]];
+  }
+  else if ([self respondsToSelector:@selector(baseURL)]) {
+    [self logWithFormat:@"object does not respond to baseURLInContext:?"];
+    url = [self baseURL];
+  }
+  else {
+    [self logWithFormat:
+            @"WARNING: unable to calculate davURL for this object !"];
+    url = nil;
+  }
+  if (url == nil)
+    [self logWithFormat:@"WARNING: got no davURL for this object !"];
+  
+  return url;
+}
+
+- (NSDate *)davLastModified {
+  id v;
+  if ((v = [self valueForKey:NSFileModificationDate])) return v;
+  return [NSDate date];
+}
+
+- (NSDate *)davCreationDate {
+  id v;
+  if ((v = [self valueForKey:@"NSFileCreationDate"]))  return v;
+  if ((v = [self valueForKey:NSFileModificationDate])) return v;
+  return nil;
+}
+
+- (NSString *)davContentType {
+  if ([self davIsFolder]) {
+    //return @"x-directory/webdav"; /* this is taken from Nautilus */
+    return @"httpd/unix-directory"; /* this is returned by Apache */
+  }
+  
+  return @"application/octet-stream";
+}
+
+- (id)davContentLength {
+  id v;
+  if ((v = [self valueForKey:NSFileSize])) return v;
+  if ([self respondsToSelector:@selector(contentLength)])
+    return [NSNumber numberWithUnsignedInt:[self contentLength]];
+  return 0;
+}
+- (NSString *)davDisplayName {
+  id v = nil;
+  
+  if ([self respondsToSelector:@selector(displayName)])
+    return [self displayName];
+#if COCOA_Foundation_LIBRARY
+  NS_DURING /* handle query for unbound key is easily triggered ... */
+    if ((v = [self valueForKey:@"NSFileSubject"])) ;
+    else if ((v = [self valueForKey:@"NSFileName"])) ;
+    else if ((v = [self valueForKey:@"NSFilePath"])) ;
+  NS_HANDLER
+    v = nil;
+  NS_ENDHANDLER;
+#else
+  if ((v = [self valueForKey:@"NSFileSubject"])) return v;
+  if ((v = [self valueForKey:@"NSFileName"])) return v;
+  if ((v = [self valueForKey:@"NSFilePath"])) return [v lastPathComponent];
+#endif
+  if ([self respondsToSelector:@selector(path)])
+    return [[self path] lastPathComponent];
+  return nil;
+}
+
+- (NSString *)davResourceType {
+  if ([self davIsCollection])
+    return @"collection";
+  return nil;
+}
+
+- (NSString *)davContentClass {
+  /* this doesn't return something really useful, override if necessary ! */
+  return ([self davIsFolder])
+    ? @"urn:content-classes:folder"
+    : @"urn:content-classes:item";
+}
+
+- (BOOL)davIsExecutable {
+  return NO;
+}
+
+/* lock manager */
+
+- (SoDAVLockManager *)davLockManagerInContext:(id)_ctx {
+  return [SoDAVLockManager sharedLockManager];
+}
+
+@end /* NSObject(SoObjectSoDAV) */
+
+@implementation NSObject(SoObjectDAVMaps)
+
++ (NSString *)lookupDefMapPlist {
+  NSString *apath;
+#if !COMPILE_AS_FRAMEWORK
+    NSFileManager *fm = [NSFileManager defaultManager];
+    NSDictionary  *env;
+    NSString      *relPath;
+#endif
+#if COMPILE_AS_FRAMEWORK
+    {
+      NSBundle *bundle;
+      
+      bundle = [NSBundle bundleForClass:self];
+      apath  = [bundle pathForResource:@"DAVPropMap" ofType:@"plist"];
+    }
+#else
+    env  = [[NSProcessInfo processInfo] environment];
+    relPath = @"Libraries";
+    relPath = [relPath stringByAppendingPathComponent:@"Resources"];
+    relPath = [relPath stringByAppendingPathComponent:@"NGObjWeb"];
+    relPath = [relPath stringByAppendingPathComponent:@"DAVPropMap.plist"];
+    
+    apath = [env objectForKey:@"GNUSTEP_USER_ROOT"];
+    apath = [apath stringByAppendingPathComponent:relPath];
+    if (![fm fileExistsAtPath:apath]) {
+      apath = [env objectForKey:@"GNUSTEP_LOCAL_ROOT"];
+      apath = [apath stringByAppendingPathComponent:relPath];
+    }
+    if (![fm fileExistsAtPath:apath]) {
+      apath = [env objectForKey:@"GNUSTEP_SYSTEM_ROOT"];
+      apath = [apath stringByAppendingPathComponent:relPath];
+    }
+    if (![fm fileExistsAtPath:apath]) {
+      apath = relPath;
+    }
+    if (![fm fileExistsAtPath:apath]) {
+      NSLog(@"ERROR: cannot find DAVPropMap.plist resource "
+            @"of NGObjWeb library !");
+    }
+#endif
+  return apath;
+}
+
++ (id)defaultWebDAVAttributeMap {
+  static NSDictionary *defMap = nil;
+  if (defMap == nil) {
+    NSString *path;
+    
+    if ((path = [self lookupDefMapPlist]))
+      defMap = [[NSDictionary alloc] initWithContentsOfFile:path];
+  }
+  return defMap;
+}
+
+- (id)davAttributeMapInContext:(id)_ctx {
+  /* default is: do map some DAV properties, pass through anything else */
+  return [[self class] defaultWebDAVAttributeMap];
+}
+
+@end /* NSObject(SoObjectDAVMaps) */
+
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequestHandler.h>
+
+@implementation WOCoreApplication(WebDAV)
+
+- (BOOL)davIsCollection {
+  return YES;
+}
+- (BOOL)davHasSubFolders {
+  return YES;
+}
+- (id)davUid {
+  return [self davURL];
+}
+- (id)davURL {
+  return [self baseURL];
+}
+- (NSDate *)davLastModified {
+  return [NSDate date];
+}
+- (NSDate *)davCreationDate {
+  return nil;
+}
+- (NSString *)davContentType {
+  return @"text/html";
+}
+- (id)davContentLength {
+  return 0;
+}
+- (NSString *)davDisplayName {
+  return @"ROOT";
+}
+
+@end /* WOCoreApplication(WebDAV) */
+
+@implementation WOApplication(WebDAV)
+
+- (NSString *)davDisplayName {
+  return [self name];
+}
+
+@end /* WOApplication(WebDAV) */
+
+@implementation WORequestHandler(WebDAV)
+
+- (BOOL)davIsCollection {
+  return YES;
+}
+- (BOOL)davHasSubFolders {
+  return YES;
+}
+
+- (id)davUid {
+  return [self davURL];
+}
+
+- (NSDate *)davLastModified {
+  return [NSDate date];
+}
+- (NSDate *)davCreationDate {
+  return nil;
+}
+
+- (NSString *)davContentType {
+  return @"text/html";
+}
+
+- (id)davContentLength {
+  return 0;
+}
+
+@end /* WORequestHandler(WebDAV) */
+
+#include "SoControlPanel.h"
+
+@implementation SoControlPanel(WebDAV)
+
+- (BOOL)davIsCollection {
+  return YES;
+}
+- (BOOL)davHasSubFolders {
+  return YES;
+}
+
+- (id)davUid {
+  return [self davURL];
+}
+
+- (NSDate *)davLastModified {
+  return [NSDate date];
+}
+- (NSDate *)davCreationDate {
+  return nil;
+}
+
+- (id)davContentLength {
+  return 0;
+}
+
+@end /* SoControlPanel(WebDAV) */
+
+@implementation NSObject(DavOperations)
+
+- (NSException *)davSetProperties:(NSDictionary *)_setProps
+  removePropertiesNamed:(NSArray *)_delProps
+  inContext:(id)_ctx
+{
+  return [NSException exceptionWithHTTPStatus:405 /* not allowed */
+                      reason:@"this object cannot edit object properties "
+                      @"via WebDAV"];
+}
+
+- (id)davCreateObject:(NSString *)_name
+  properties:(NSDictionary *)_props
+  inContext:(id)_ctx
+{
+  return [NSException exceptionWithHTTPStatus:405 /* not allowed */
+                      reason:@"this object cannot create child objects "
+                      @"via WebDAV"];
+}
+
+- (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx {
+  return [NSException exceptionWithHTTPStatus:405 /* not allowed */
+                      reason:@"this object cannot create subcollections "
+                      @"via WebDAV"];
+}
+
+- (NSException *)davMoveToTargetObject:(id)_target newName:(NSString *)_name
+  inContext:(id)_ctx
+{
+  return [NSException exceptionWithHTTPStatus:405 /* not allowed */
+                      reason:@"this object cannot be moved via WebDAV"];
+}
+
+- (NSException *)davCopyToTargetObject:(id)_target newName:(NSString *)_name
+  inContext:(id)_ctx
+{
+  return [NSException exceptionWithHTTPStatus:405 /* not allowed */
+                      reason:@"this object cannot be copied via WebDAV"];
+}
+
+@end /* NSObject(DavOperations) */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoObject+SoDAVQuery.m b/skyrix-sope/NGObjWeb/WebDAV/SoObject+SoDAVQuery.m
new file mode 100644 (file)
index 0000000..55c2f18
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoObject+SoDAV.h"
+#include "SoObject.h"
+#include "SoObjectDataSource.h"
+#include "EOFetchSpecification+SoDAV.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WEClientCapabilities.h>
+#include <EOControl/EOQualifier.h>
+#include <EOControl/EOSortOrdering.h>
+#include "common.h"
+
+@implementation NSObject(SoObjectDAVQueries)
+
+static int debugBulk = NO; // TODO: set to -1 and use defaults
+
+- (NSEnumerator *)davChildKeysInContext:(id)_ctx {
+  /*
+    This returns the names of the children of a collection.
+    Could return toOneRelationshipKeys+toManyRelationshipKeys ? 
+  */
+  NSClassDescription *cd;
+  
+  if ((cd = [self soClassDescription]))
+    return [[cd toOneRelationshipKeys] objectEnumerator];
+  
+  return [[self toOneRelationshipKeys] objectEnumerator];
+}
+
+- (EODataSource *)contentDataSourceInContext:(id)_ctx {
+  return [[[SoObjectDataSource alloc] initWithObject:self
+                                     inContext:_ctx] autorelease];
+}
+
+- (EODataSource *)davFlatDataSourceInContext:(id)_ctx {
+  [self logWithFormat:
+         @"%s: this method is deprecated,use -contentDataSourceInContext: !"];
+  return [self contentDataSourceInContext:_ctx];
+}
+
+- (NSArray *)davQueryOnSelf:(EOFetchSpecification *)_fs inContext:(id)_ctx {
+  id<EOQualifierEvaluation> q;
+  NSDictionary *values;
+  NSArray *keys;
+  
+  if ((q = (void *)[_fs qualifier])) {
+    if (![q evaluateWithObject:self]) {
+      [self debugWithFormat:@"  self doesn't match qualifier."];
+      return [NSArray array];
+    }
+  }
+  
+  if ((keys = [_fs selectedWebDAVPropertyNames]) == nil) {
+    /*
+      Note: this shouldn't happen anymore, a default-set will be used by
+      the dispatcher.
+    */
+    keys = [[self soClassDescription] attributeKeys];
+    [self debugWithFormat:@"using keys from description: %@", keys];
+  }
+  
+  /* ensure that the URL is added */
+  keys = [keys arrayByAddingObject:@"davURL"];
+  
+  if ([_fs queryWebDAVPropertyNamesOnly]) {
+    /* how does the renderer know, that these are the keys ? */
+    [self debugWithFormat:@"deliver keys only: %@", keys];
+    return [NSArray arrayWithObject:keys];
+  }
+  
+  if ((values = [self valuesForKeys:keys]) == nil)
+    return nil;
+  
+  return [NSArray arrayWithObject:values];
+}
+
+- (id)performWebDAVDeepQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx {
+  /* this just does a flat search :-(, maybe we should return 403 ? */
+  WEClientCapabilities *cc;
+  EODataSource *ds;
+  NSArray      *result;
+  NSString *scope;
+  BOOL     includeSelf, doDeep;
+  unsigned count;
+  
+  /* setup scope info */
+  
+  scope = [_fs scopeOfWebDAVQuery];
+  includeSelf = [scope rangeOfString:@"-self"].length == 0 ? NO : YES;
+  doDeep      = YES;
+  
+  /* do some user-agent specific tolerance */
+  
+  cc = [[(id <WOPageGenerationContext>)_ctx request] clientCapabilities];
+  if (includeSelf) {
+    NSString *ua;
+    
+    ua = [cc userAgentType];
+    if ([ua isEqualToString:@"Evolution"] || [ua isEqualToString:@"WebFolder"])
+      includeSelf = NO;
+    else {
+      [self logWithFormat:@"return self on UA: %@", ua];
+      includeSelf = YES;
+    }
+  }
+  doDeep = NO;
+  
+  /* perform deep query */
+  
+  ds = [self contentDataSourceInContext:_ctx];
+  [ds setFetchSpecification:_fs];
+  
+  if ((result = [ds fetchObjects]) == nil)
+    /* nil is error */
+    return nil;
+  
+  if ((count = [result count]) == 0) {
+    if (includeSelf)
+      return [self davQueryOnSelf:_fs inContext:_ctx];
+  }
+  else {
+    NSMutableArray *ma;
+    
+    ma = [NSMutableArray arrayWithCapacity:(count + 2)];
+    
+    if (includeSelf)
+      [ma addObjectsFromArray:[self davQueryOnSelf:_fs inContext:_ctx]];
+    
+    /* add flat results */
+    [ma addObjectsFromArray:result];
+    
+    if (doDeep) {
+      /* 
+        Should walk over each result and reperform the query with deep-self.
+        If the results came from SoObjectDataSource this is possible because
+        the "full" object is none in the SoObjectResultEntry.
+      */
+      [self logWithFormat:
+             @"WARNING: attempted deep-search, not supported yet."];
+    }    
+    result = ma;
+  }
+  return result;
+}
+
+- (id)performWebDAVBulkQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx {
+  NSAutoreleasePool    *pool;
+  EOFetchSpecification *subSpec;
+  NSMutableArray *results;
+  NSEnumerator *keys;
+  NSString     *key;
+
+  pool = [[NSAutoreleasePool alloc] init];
+  //[self debugWithFormat:@"perform bulk query ..."];
+  
+  /* create a sub-fetch-spec */
+  {
+    NSMutableDictionary *hints;
+    
+    hints = [[_fs hints] mutableCopy];
+    [hints removeObjectForKey:@"bulkTargetKeys"];
+    
+    subSpec = [[_fs copy] autorelease];
+    [subSpec setHints:hints];
+    [hints release];
+  }
+  
+  results = [NSMutableArray arrayWithCapacity:256];
+  keys = [[_fs davBulkTargetKeys] objectEnumerator];
+  while ((key = [keys nextObject])) {
+    id child;
+    id childResults;
+    
+    if (debugBulk)
+      [self debugWithFormat:@"  check bulk key: '%@'", key];
+    
+    /* lookup target */
+    
+    if ([key rangeOfString:@"/"].length == 0) {
+      /* simple key, just use -lookupName */
+      child = [self lookupName:key inContext:_ctx acquire:NO];
+      if (child == nil) {
+        [self logWithFormat:@"ERROR: did not find the BPROPFIND target '%@'",
+               key];
+        continue;
+      }
+    }
+    else {
+      /* complex key, try to traverse */
+      // TODO: pass auth parameters to traversal context !!
+      child = [self traversePath:key acquire:NO];
+      if (child == nil) {
+        [self logWithFormat:
+                @"ERROR: did not find the BPROPFIND target '%@' by traversing.",
+               key];
+        continue;
+      }
+      if ([child isKindOfClass:[NSException class]]) {
+        [self logWithFormat:@"traversing bulk path '%@', failed: %@", 
+                key, child];
+        continue;
+      }
+      [self logWithFormat:@"traversed bulk path '%@', got: %@", key, child];
+    }
+    
+    /* set entity name */
+    [subSpec setEntityName:
+              [[_fs entityName] stringByAppendingPathComponent:key]];
+    
+    /* perform subquery */
+    childResults = [child performWebDAVQuery:subSpec inContext:_ctx];
+    if (childResults) {
+      if ([childResults isKindOfClass:[NSArray class]])
+       [results addObjectsFromArray:childResults];
+      else
+       [results addObject:childResults];
+    }
+  }
+  
+  results = [results retain];
+  [pool release];
+  return [results autorelease];
+}
+
+- (id)performWebDAVQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx {
+  NSString *scope;
+  NSArray  *bulkQueryKeys;
+  
+  if (_fs == nil) return nil;
+
+  if ((bulkQueryKeys = [_fs davBulkTargetKeys]))
+    return [self performWebDAVBulkQuery:_fs inContext:_ctx];
+  
+  scope = [_fs scopeOfWebDAVQuery];
+  if ([scope hasPrefix:@"flat"]) {
+    EODataSource *ds;
+    NSArray *result;
+    
+    ds = [self contentDataSourceInContext:_ctx];
+    [ds setFetchSpecification:_fs];
+    if ((result = [ds fetchObjects]) == nil)
+      /* error */
+      return nil;
+    
+    if ([scope rangeOfString:@"+self"].length > 0) {
+      /* should include self */
+      unsigned len;
+      
+      // TODO: don't add self if we work on ZideLook or WebFolders !
+      
+      if ((len = [result count]) == 0)
+       result = [self davQueryOnSelf:_fs inContext:_ctx];
+      else {
+       NSMutableArray *ma;
+       
+       ma = [NSMutableArray arrayWithCapacity:(len + 2)];
+       [ma addObjectsFromArray:[self davQueryOnSelf:_fs inContext:_ctx]];
+       [ma addObjectsFromArray:result];
+       result = ma;
+      }
+    }
+    return result;
+  }
+
+  if ([scope hasPrefix:@"self"])
+    return [self davQueryOnSelf:_fs inContext:_ctx];
+  
+  if ([scope hasPrefix:@"deep"])
+    return [self performWebDAVDeepQuery:_fs inContext:_ctx];
+  
+  [self logWithFormat:@"ERROR: called with invalid scope '%@'", scope];
+  return nil;
+}
+
+@end /* NSObject(SoObjectDAVQueries) */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoObjectDataSource.h b/skyrix-sope/NGObjWeb/WebDAV/SoObjectDataSource.h
new file mode 100644 (file)
index 0000000..d310fce
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoObjectDataSource_H__
+#define __SoObjects_SoObjectDataSource_H__
+
+#include <EOControl/EODataSource.h>
+
+@class NSArray;
+@class EOFetchSpecification;
+
+@interface SoObjectDataSource : EODataSource
+{
+  EOFetchSpecification *fspec;
+  id object;
+  id context; /* non-retained ! */
+}
+
+- (id)initWithObject:(id)_object inContext:(id)_ctx;
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fs;
+- (EOFetchSpecification *)fetchSpecification;
+
+- (id)context;
+- (id)object;
+
+/* operations */
+
+- (NSArray *)fetchObjects;
+
+@end
+
+#endif /* __SoObjects_SoObjectDataSource_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoObjectDataSource.m b/skyrix-sope/NGObjWeb/WebDAV/SoObjectDataSource.m
new file mode 100644 (file)
index 0000000..abe6a50
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoObjectDataSource.h"
+#include "SoObjectResultEntry.h"
+#include "SoObject+SoDAV.h"
+#include "SoObject.h"
+#include "EOFetchSpecification+SoDAV.h"
+#include <EOControl/EOQualifier.h>
+#include <EOControl/EOSortOrdering.h>
+#include "common.h"
+
+@implementation SoObjectDataSource
+
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  debugOn = [[NSUserDefaults standardUserDefaults]
+             boolForKey:@"SoObjectDataSourceDebugEnabled"];
+}
+
+- (id)initWithObject:(id)_object inContext:(id)_ctx {
+  if ((self = [super init])) {
+    self->object  = [_object retain];
+    self->context = _ctx;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithObject:nil inContext:nil];
+}
+
+- (void)dealloc {
+  [self->object release];
+  [super dealloc];
+}
+
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fetchSpec {
+  if ([_fetchSpec isEqual:self->fspec]) return;
+  ASSIGN(self->fspec, _fetchSpec);
+  [self postDataSourceChangedNotification];
+}
+- (EOFetchSpecification *)fetchSpecification {
+  return self->fspec;
+}
+
+- (id)context {
+  return self->context;
+}
+- (id)object {
+  return self->object;
+}
+
+- (EOClassDescription *)classDescriptionForObjects {
+  if ([self->object respondsToSelector:_cmd])
+    /* forward to datasource owner if possible */
+    return [self->object performSelector:_cmd];
+  
+  return nil;
+}
+
+/* implementation */
+
+- (NSArray *)davFlatQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx {
+  /*
+    If you have a datasource for your children, consider to override this
+    method and use the DS to perform the query.
+  */
+  id<EOQualifierEvaluation> q;
+  NSMutableArray *ma;
+  NSArray      *result;
+  NSEnumerator *childKeys;
+  NSArray      *queriedAttrNames;
+  NSArray      *orderings;
+  NSString     *childKey;
+  BOOL         isBrief = YES; // do not encode "sub-errors", just omit the item
+  
+  [self debugWithFormat:@"performing flat query: %@", _fs];
+  
+  childKeys = [self->object davChildKeysInContext:_ctx];
+  
+  /* process */
+  
+  [self debugWithFormat:@"query keys: %@", childKeys];
+    
+  q  = (void *)[_fs qualifier];
+  ma = [NSMutableArray arrayWithCapacity:16];
+    
+  queriedAttrNames = [_fs selectedWebDAVPropertyNames];
+  
+  while ((childKey = [childKeys nextObject])) {
+    NSDictionary *rec;
+    NSException  *e;
+    NSString     *childHref;
+    id child = nil;
+      
+    /* 
+       TODO: question of the week, is it faster to filter on the record
+       dictionary or to filter on the object itself? Do WebDAV clients
+       always select all items they sort or filter? Hm.
+    */
+    rec = nil;
+    
+    if ((e = [self->object validateName:childKey inContext:_ctx])) {
+      /* security problem */
+      [self debugWithFormat:@"  child key '%@' did not validate:\n  %@", 
+             childKey, e];
+       
+      if (isBrief) // when the brief header is set, forget errors
+       e = nil;
+    }
+    else if ((child = [self->object lookupName:childKey inContext:_ctx acquire:NO])==nil) {
+      /* not found */
+      [self debugWithFormat:@"  did not find key '%@'", childKey];
+       
+      if (!isBrief) { // when the brief header is not set, encode status
+       NSDictionary *ui;
+         
+       ui = [NSDictionary dictionaryWithObject:@"404" /* not found */
+                          forKey:@"http-status"];
+       e = [NSException exceptionWithName:@"KeyError"
+                        reason:@"failed to lookup a WebDAV child resource"
+                        userInfo:ui];
+      }
+    }
+    else if ([child isKindOfClass:[NSException class]]) {
+      e = child;
+      child = nil;
+    }
+    else {
+      /* found a valid child */
+      //[self debugWithFormat:@"  found child for key '%@'", childKey];
+      
+      if (q != nil) {
+       if (![q evaluateWithObject:child]) {
+         /* object does not match the filter */
+          if (debugOn) {
+            [self debugWithFormat:@"  object did not match qualifier: %@", 
+                   child];
+          }
+         continue;
+       }
+      }
+      
+      /* passed */
+      // TODO: child can be SoHTTPException ?
+      rec = (queriedAttrNames == nil)
+       ? child
+       : [child valuesForKeys:queriedAttrNames];
+#if 0
+      [self logWithFormat:@"got values: %@ for keys: %@ from object: %@",
+           rec, queriedAttrNames, child];
+#endif
+    }
+      
+    /* calc URI */
+      
+    childHref = [childKey stringByEscapingURL];
+    childHref = [[_fs entityName] stringByAppendingPathComponent:childHref];
+    
+    /* add errors if required */
+    
+    if ((rec == nil) && (e != nil) && !isBrief) {
+      rec = [[SoObjectErrorEntry alloc] 
+             initWithURI:childHref object:child error:e];
+    }
+    else if (rec == nil) {
+      /* either brief or no error found */
+      continue;
+    }
+    else if (queriedAttrNames) {
+      rec = [[SoObjectResultEntry alloc] 
+             initWithURI:childHref object:child values:rec];
+    }
+    else
+      /* the child */
+      rec = [rec retain];
+    
+    /* add record to result */
+    [ma addObject:rec];
+    [rec release];
+  }
+  
+  /* sort result (note: you must select anything you want to sort ...) */
+  if ((orderings = [_fs sortOrderings]))
+    [ma sortUsingKeyOrderArray:orderings];
+  
+  result = ma;
+  
+  [self debugWithFormat:@"  got %i results\n%@", [result count], result];
+  return result;
+}
+
+/* operations */
+
+- (NSArray *)fetchObjects {
+  NSAutoreleasePool *pool;
+  id result;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    NSArray *keys;
+    
+    if ((keys = [[self fetchSpecification] davBulkTargetKeys])) {
+      [self logWithFormat:@"SoObjectDataSource cannot handle bulk queries !"];
+      return nil;
+    }
+    else {
+      result = [self davFlatQuery:[self fetchSpecification]
+                    inContext:[self context]];
+    }
+    result = [result retain];
+  }
+  [pool release];
+  return [result autorelease];;
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return @"[object-datasource]";
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* SoObjectDataSource */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoObjectResultEntry.h b/skyrix-sope/NGObjWeb/WebDAV/SoObjectResultEntry.h
new file mode 100644 (file)
index 0000000..1ed98fc
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __WebDAV_SoObjectResultEntry_H__
+#define __WebDAV_SoObjectResultEntry_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSDictionary, NSException;
+
+@interface SoObjectResultEntry : NSObject
+{
+  NSString     *href;
+  NSDictionary *values;
+  id object;
+}
+
+- (id)initWithURI:(NSString *)_href object:(id)_o values:(NSDictionary *)_d;
+
+@end
+
+@interface SoObjectErrorEntry : NSObject
+{
+  NSString    *href;
+  NSException *error;
+  id object;
+}
+
+- (id)initWithURI:(NSString *)_href object:(id)_o error:(NSException *)_e;
+
+@end
+
+#endif /* __WebDAV_SoObjectResultEntry_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoObjectResultEntry.m b/skyrix-sope/NGObjWeb/WebDAV/SoObjectResultEntry.m
new file mode 100644 (file)
index 0000000..05b5ff2
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoObjectResultEntry.h"
+#include "common.h"
+
+@implementation SoObjectResultEntry
+
+- (id)initWithURI:(NSString *)_href object:(id)_o values:(NSDictionary *)_d {
+  self->href   = [_href copy];
+  self->values = [_d retain];
+  self->object = [_o retain];
+  return self;
+}
+
+- (void)dealloc {
+  [self->href   release];
+  [self->values release];
+  [self->object release];
+  [super dealloc];
+}
+
+/* keys */
+
+- (NSArray *)attributeKeys {
+  return [self->values allKeys];
+}
+
+/* dict */
+
+- (NSArray *)allKeys {
+  return [self->values allKeys];
+}
+- (NSEnumerator *)keyEnumerator {
+  return [self->values keyEnumerator];
+}
+- (id)objectForKey:(id)_key {
+  return [self->values objectForKey:_key];
+}
+
+/* KVC */
+
+- (BOOL)kvcIsPreferredInKeyPath {
+  /*
+    This is difficult to grasp. It says, that the WOKeyPathAssociation
+    should *always* use -valueForKey:, even if the object has an accessors
+    method matching the key.
+    It's required for all "storage" type objects.
+  */
+  return YES;
+}
+
+- (id)valueForKey:(NSString *)_key {
+  if ([_key isEqualToString:@"{DAV:}href"])
+    return self->href;
+  else if ([_key isEqualToString:@"{DAV:}status"])
+    return nil;
+  else {
+#if 1
+    return [self->values objectForKey:_key];
+#else
+    id v = [self->values objectForKey:_key];
+    [self logWithFormat:@"key %@: %@", _key, v];
+    return v;
+#endif
+  }
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self,
+        NSStringFromClass((Class)*(void**)self)];
+  
+  if (self->href)
+    [ms appendFormat:@" uri=%@", self->href];
+
+  if (self->object) {
+    [ms appendFormat:@" obj=0x%08X[%@]", 
+         self->object, NSStringFromClass([self->object class])];
+  }
+  
+  if ([self->values count] > 0) {
+    NSEnumerator *e;
+    NSString *k;
+    
+    [ms appendString:@" values"];
+    e = [self->values keyEnumerator];
+    while ((k = [e nextObject]))
+      [ms appendFormat:@":%@=%@", k, [self->values objectForKey:k]];
+  }
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SoObjectResultEntry */
+
+@implementation SoObjectErrorEntry
+
+- (id)initWithURI:(NSString *)_href object:(id)_o error:(NSException *)_e {
+  self->href   = [_href copy];
+  self->error  = [_e retain];
+  self->object = [_o retain];
+  return self;
+}
+
+- (void)dealloc {
+  [self->object release];
+  [self->href   release];
+  [self->error  release];
+  [super dealloc];
+}
+
+/* dict */
+
+- (NSArray *)allKeys {
+  return nil;
+}
+- (NSEnumerator *)keyEnumerator {
+  return nil;
+}
+- (id)objectForKey:(id)_key {
+  return nil;
+}
+
+/* KVC */
+
+- (BOOL)kvcIsPreferredInKeyPath {
+  return YES;
+}
+
+- (id)valueForKey:(NSString *)_key {
+  if ([_key isEqualToString:@"{DAV:}href"])
+    return self->href;
+  else if ([_key isEqualToString:@"{DAV:}status"])
+    return self->error;
+  else
+    return nil;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self,
+        NSStringFromClass((Class)*(void**)self)];
+  
+  if (self->href)
+    [ms appendFormat:@" uri=%@", self->href];
+
+  if (self->object) {
+    [ms appendFormat:@" obj=0x%08X[%@]", 
+         self->object, NSStringFromClass([self->object class])];
+  }
+
+  if (self->error)
+    [ms appendFormat:@" error=%@", self->error];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SoObjectErrorEntry */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoObjectWebDAVDispatcher.h b/skyrix-sope/NGObjWeb/WebDAV/SoObjectWebDAVDispatcher.h
new file mode 100644 (file)
index 0000000..6052650
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoObjectWebDAVDispatcher_H__
+#define __SoObjects_SoObjectWebDAVDispatcher_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoObjectWebDAVDispatcher
+  
+  This request dispatcher is used to dispatch WebDAV calls to SoObjects. Eg
+  it translates WebDAV PROPFIND and SEARCH requests in a fetch specifications
+  that is passed to the SoObject.
+  For more information on the available callbacks, take a look at the 
+  SoObject+SoDAV protocols.
+
+  Methods:
+    PROPPATCH - performWebDAVQuery:
+    SEARCH    - performWebDAVQuery:
+    POST      - calls POST SoObject-method
+    PUT       - calls PUT SoObject-method
+    DELETE    - calls DELETE SoObject-method
+    GET       - calls -appendToResponse:inContext: [subject to change]
+*/
+
+@class WOContext;
+
+@interface SoObjectWebDAVDispatcher : NSObject
+{
+  id object;
+}
+
+- (id)initWithObject:(id)_object;
+
+/* perform dispatch */
+
+- (id)dispatchInContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoObjectWebDAVDispatcher_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoObjectWebDAVDispatcher.m b/skyrix-sope/NGObjWeb/WebDAV/SoObjectWebDAVDispatcher.m
new file mode 100644 (file)
index 0000000..ab731f5
--- /dev/null
@@ -0,0 +1,1602 @@
+/*
+  Copyright (C) 2002-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$
+
+#include "SoObjectWebDAVDispatcher.h"
+#include "SoObject.h"
+#include "SoObject+SoDAV.h"
+#include "SoSecurityManager.h"
+#include "SoPermissions.h"
+#include "SoObjectRequestHandler.h"
+#include "SoSubscriptionManager.h"
+#include "SaxDAVHandler.h"
+#include "SoDAVLockManager.h"
+#include "EOFetchSpecification+SoDAV.h"
+#include "WOContext+SoObjects.h"
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WEClientCapabilities.h>
+#include <SaxObjC/SaxObjC.h>
+#include <SaxObjC/XMLNamespaces.h>
+#include <NGExtensions/NSString+Ext.h>
+#include "common.h"
+
+@interface WORequest(HackURI)
+- (void)_hackSetURI:(NSString *)_vuri;
+@end
+
+@implementation SoObjectWebDAVDispatcher
+
+static int      debugOn = -1;
+static BOOL     debugBulkTarget = NO;
+static NSNumber *yesNum = nil;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  debugOn = [ud boolForKey:@"SoObjectDAVDispatcherDebugEnabled"] ? 1 : 0;
+  if (debugOn) NSLog(@"Note: WebDAV dispatcher debugging is enabled.");
+  if (yesNum == nil) yesNum = [[NSNumber numberWithBool:YES] retain];
+}
+
+// THREAD
+static id<NSObject,SaxXMLReader> xmlParser = nil;
+static SaxDAVHandler             *davsax   = nil;
+static NSTimeZone                *gmt      = nil;
+
+- (id)initWithObject:(id)_object {
+  if ((self = [super init])) {
+    self->object = [_object retain];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->object release];
+  [super dealloc];
+}
+
+/* parser */
+
+- (void)lockParser:(id)_sax {
+  [_sax reset];
+  [xmlParser setContentHandler:_sax];
+  [xmlParser setErrorHandler:_sax];
+}
+- (void)unlockParser:(id)_sax {
+  [xmlParser setContentHandler:nil];
+  [xmlParser setErrorHandler:nil];
+  [_sax reset];
+}
+
+/* common stuff */
+
+- (NSException *)httpException:(int)_status reason:(NSString *)_reason {
+  NSDictionary *ui;
+
+  ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                      self, @"dispatcher",
+                      [NSNumber numberWithInt:_status], @"http-status",
+                      nil];
+  return [NSException exceptionWithName:
+                       [NSString stringWithFormat:@"HTTP%i", _status]
+                     reason:_reason
+                     userInfo:ui];
+}
+
+- (NSArray *)allowedMethods {
+  static NSArray *defMethods = nil;
+  NSMutableArray *allow;
+
+  if (defMethods == nil) {
+    defMethods = [[[NSUserDefaults standardUserDefaults] 
+                                   arrayForKey:@"SoWebDAVDefaultAllowMethods"] 
+                                   copy];
+  }
+  
+  allow = [NSMutableArray arrayWithCapacity:16];
+  if (defMethods) [allow addObjectsFromArray:defMethods];
+  
+  if ([self->object 
+           respondsToSelector:@selector(performWebDAVQuery:inContext:)]) {
+    [allow addObject:@"PROPFIND"];
+    [allow addObject:@"SEARCH"];
+  }
+  if ([self->object respondsToSelector:
+            @selector(davSetProperties:removePropertiesNamed:)])
+    [allow addObject:@"PROPPATCH"];
+  
+  return allow;
+}
+
+- (NSString *)baseURLForContext:(WOContext *)_ctx {
+  /*
+    Note: Evolution doesn't correctly transfer the "Host:" header, it
+    misses the port argument :-(
+  */
+  NSString  *baseURL;
+  WORequest *rq;
+  NSString  *hostport;
+  id tmp;
+  
+  rq = [_ctx request];
+  
+  if ((tmp = [rq headerForKey:@"x-webobjects-server-name"])) {
+    hostport = tmp;
+    if ((tmp = [rq headerForKey:@"x-webobjects-server-port"]))
+      hostport = [NSString stringWithFormat:@"%@:%@", hostport, tmp];
+  }
+  else if ((tmp = [rq headerForKey:@"host"]))
+    hostport = tmp;
+  else
+    hostport = [[NSHost currentHost] name];
+  
+  baseURL = [NSString stringWithFormat:@"http://%@%@", hostport, [rq uri]];
+  return baseURL;
+}
+
+- (id)primaryCallWebDAVMethod:(NSString *)_name inContext:(WOContext *)_ctx {
+  id method;
+  
+  method = [self->object lookupName:_name inContext:_ctx acquire:NO];
+  if (method == nil) {
+    return [self httpException:501 /* Not Implemented */
+                reason:@"target object does not support requested operation"];
+  }
+  if ([method isKindOfClass:[NSException class]]) {
+    [self logWithFormat:@"could not lookup method, got exception: %@", method];
+    return method;
+  }
+  
+  [self debugWithFormat:@"  %@ method: %@", _name, method];
+  return [method callOnObject:self->object inContext:_ctx];
+}
+
+/* core HTTP methods */
+
+- (id)doGET:(WOContext *)_ctx {
+  NSException *e;
+  id methodObject;
+  
+  
+  if ((methodObject = 
+       [self->object lookupName:@"GET" inContext:_ctx acquire:NO]) == nil)
+    methodObject = [self->object lookupDefaultMethod];
+  else {
+    if ((e = [self->object validateName:@"GET" inContext:_ctx]))
+      return e;
+  }
+  
+  if (methodObject == nil)
+    return self->object;
+  if ([methodObject isKindOfClass:[NSException class]])
+    return methodObject;
+  
+  if ([methodObject respondsToSelector:
+                     @selector(takeValuesFromRequest:inContext:)])
+    [methodObject takeValuesFromRequest:[_ctx request] inContext:_ctx];
+  
+  return [methodObject callOnObject:self->object inContext:_ctx];
+}
+
+- (id)doPUT:(WOContext *)_ctx {
+  SoSecurityManager *sm;
+  NSException       *e;
+  NSString          *pathInfo;
+  
+  pathInfo = [_ctx pathInfo];
+  [self debugWithFormat:@"doPUT (pathinfo='%@')", pathInfo];
+  
+  /* check permissions */
+  
+  sm = [_ctx soSecurityManager];
+  e  = [sm validatePermission:
+            ([pathInfo length] > 0)
+            ? SoPerm_AddDocumentsImagesAndFiles
+            : SoPerm_ChangeImagesAndFiles
+          onObject:self->object
+          inContext:_ctx];
+  if (e) return e;
+  
+  if ((e = [self->object validateName:@"PUT" inContext:_ctx]))
+    return e;
+  
+  /* perform */
+  
+  if ([pathInfo length] > 0) {
+    /* check whether all the parent collections are available */
+    if ([pathInfo rangeOfString:@"/"].length > 0) {
+      return [self httpException:409 /* Conflict */
+                  reason:
+                    @"invalid WebDAV PUT request, first create all "
+                    @"parent collections !"];
+    }
+  }
+
+  return [self primaryCallWebDAVMethod:@"PUT" inContext:_ctx];
+}
+
+- (id)doPOST:(WOContext *)_ctx {
+  NSException *e;
+  
+  if ((e = [self->object validateName:@"POST" inContext:_ctx]))
+    return e;
+  
+  return [self primaryCallWebDAVMethod:@"POST" inContext:_ctx];
+}
+
+- (id)doDELETE:(WOContext *)_ctx {
+  SoSecurityManager *sm;
+  NSException       *e;
+  
+  /* check permissions */
+  
+  sm = [_ctx soSecurityManager];
+  e  = [sm validatePermission:SoPerm_DeleteObjects
+          onObject:self->object
+          inContext:_ctx];
+  if (e) return e;
+  if ((e = [self->object validateName:@"DELETE" inContext:_ctx]))
+    return e;
+
+  // TODO: IE WebFolders sent a "Destroy" header together with the
+  //       DELETE request, eg:
+  //       "Destroy: NoUndelete"
+  
+  return [self primaryCallWebDAVMethod:@"DELETE" inContext:_ctx];
+}
+
+- (id)doOPTIONS:(WOContext *)_ctx {
+  return [self allowedMethods];
+}
+
+- (id)doHEAD:(WOContext *)_ctx {
+  return [self doGET:_ctx];
+}
+
+/* core WebDAV methods */
+
+- (id)doMKCOL:(WOContext *)_ctx {
+  SoSecurityManager *sm;
+  NSException       *e;
+  NSString          *pathInfo;
+  
+  pathInfo = [_ctx pathInfo];
+  if ([pathInfo length] == 0) {
+    /* MKCOL target already exists ... */
+    WOResponse *r;
+
+    [self logWithFormat:@"MKCOL target exists !"];
+    
+    r = [_ctx response];
+    [r setStatus:405 /* method not allowed */];
+    [r appendContentString:@"collection already exists !"];
+    return r;
+  }
+  
+  /* check permissions */
+  
+  sm = [_ctx soSecurityManager];
+  e  = [sm validatePermission:SoPerm_AddFolders 
+          onObject:self->object
+          inContext:_ctx];
+  if (e) return e;
+
+  /* check whether all the parent collections are available */
+  if ([pathInfo rangeOfString:@"/"].length > 0) {
+    return [self httpException:409 /* Conflict */
+                 reason:
+                   @"invalid WebDAV MKCOL request, first create all "
+                  @"parent collections !"];
+  }
+  
+  /* check whether the object supports creating collections */
+
+  if (![self->object respondsToSelector:
+              @selector(davCreateCollection:inContext:)]) {
+    /* Note: this should never happen, as this is implemented on NSObject */
+    
+    [self logWithFormat:@"MKCOL: object '%@' path-info '%@'", 
+            self->object, pathInfo];
+    return [self httpException:405 /* not allowed */
+                 reason:
+                   @"this object cannot create a new collection with MKCOL"];
+  }
+  
+  if ((e = [self->object davCreateCollection:pathInfo inContext:_ctx])) {
+    [self debugWithFormat:@"creation of collection '%@' failed: %@",
+            pathInfo, e];
+    return e;
+  }
+  
+  [self debugWithFormat:@"created collection."];
+  return [NSNumber numberWithBool:YES];
+}
+
+- (NSString *)scopeForDepth:(NSString *)_depth inContext:(WOContext *)_ctx {
+  NSString *scope;
+  
+  if ([_depth hasPrefix:@"0"])
+    scope = @"self";
+  else if ([_depth hasPrefix:@"1,noroot"])
+    scope = @"flat";
+  else if ([_depth hasPrefix:@"1"]) {
+    NSString *ua;
+    
+    scope = @"flat+self";
+    
+    /* some special handling for IE ... */
+    if ((ua = [[[_ctx request] clientCapabilities] userAgentType])) {
+      if ([ua isEqualToString:@"Evolution"])
+       scope = @"flat";
+      else if ( [ua isEqualToString:@"WebFolder"])
+       scope = @"flat";
+    }
+  }
+  else if ([_depth hasPrefix:@"infinity"])
+    scope = @"deep";
+  else
+    scope = @"deep";
+
+  return scope;
+}
+
+- (NSMutableDictionary *)hintsWithScope:(NSString *)_scope
+  propNames:(NSArray *)_propNames
+  findAll:(BOOL)_findAll
+  namesOnly:(BOOL)_namesOnly
+{
+  NSMutableDictionary *hints;
+  
+  hints = [NSMutableDictionary dictionaryWithCapacity:4];
+
+  if (_scope)
+    [hints setObject:_scope forKey:@"scope"];
+  if (_propNames)
+    [hints setObject:_propNames forKey:@"attributes"];
+  // else if (_findAll) ; /* empty attributes */
+  
+  if (_namesOnly)
+    [hints setObject:[NSNumber numberWithBool:YES] forKey:@"namesOnly"];
+  return hints;
+}
+
+- (id)doPROPFIND:(WOContext *)_ctx {
+  SoSecurityManager    *sm;
+  NSException          *e;
+  EOFetchSpecification *fs;
+  WORequest *rq;
+  NSString  *uri;
+  NSString  *depth; /* 0, 1, 1,noroot or infinity */
+  NSArray   *propNames, *rtargets;
+  BOOL      findAll;
+  BOOL      findNames;
+  id        result;
+  NSRange   r;
+  
+  /* check permissions */
+  
+  sm = [_ctx soSecurityManager];
+  e  = [sm validatePermission:SoPerm_AccessContentsInformation 
+          onObject:self->object
+          inContext:_ctx];
+  if (e) return e;
+  
+  /* perform search */
+  
+  if (![self->object respondsToSelector:
+              @selector(performWebDAVQuery:inContext:)]) {
+    return [self httpException:405 /* not allowed */
+                reason:@"this object cannot not execute a PROPFIND query"];
+  }
+  
+  rq    = [_ctx request];
+  depth = [rq headerForKey:@"depth"];
+  uri   = [rq uri];
+  
+  if ([depth length] == 0) depth = @"infinity";
+  
+  [self lockParser:davsax];
+  {
+    [xmlParser parseFromSource:[rq content]];
+    propNames = [[davsax propFindQueriedNames] copy];
+    findAll   = [davsax  propFindAllProperties];
+    findNames = [davsax  propFindPropertyNames];
+  }
+  [self unlockParser:davsax];
+  propNames = [propNames autorelease];
+  
+  /* check query all properties */
+  
+  if (propNames == nil)
+    propNames = [self->object defaultWebDAVPropertyNamesInContext:_ctx];
+  
+  /* check for a ZideStore ranges query (a BPROPFIND "emulation") */
+  
+  if (debugOn) [self logWithFormat:@"request uri: %@", uri];
+  r = [uri rangeOfString:@"_range"];
+  if (r.length > 0) { /* ZideStore range query */
+    NSString *s;
+    NSArray  *ids;
+    
+    if (debugOn)
+      [self logWithFormat:@"  detected a ZideStore range query: '%@'", uri];
+    
+    s = [uri substringFromIndex:(r.location + r.length)];
+    if ([s hasSuffix:@"/"]) s = [s substringToIndex:([s length] - 1)];
+    if ([s hasPrefix:@"_"]) s = [s substringFromIndex:1];
+    
+    ids = ([s length] == 0)
+      ? [NSArray array]
+      : [s componentsSeparatedByString:@"_"];
+    
+    // TODO: should use -stringByUnescapingURL on IDs (not required for ints)
+    
+    rtargets = ids;
+    if (debugOn) 
+      [self logWithFormat:@"  IDs: %@", [ids componentsJoinedByString:@","]];
+    
+    /* patch URI, could have side-effects ? */
+    [self logWithFormat:
+            @"NOTE: hacked URI, _range_ part won't be visible in the HTTP "
+            @"access log:\n%@", uri];
+    [rq _hackSetURI:[uri substringToIndex:r.location]];
+  }
+  else
+    rtargets = nil;
+  
+  /* build the fetch-spec */
+  {
+    NSMutableDictionary *hints;
+    
+    hints = [self hintsWithScope:[self scopeForDepth:depth inContext:_ctx]
+                 propNames:propNames findAll:findAll namesOnly:findNames];
+    if (rtargets) /* range-query keys */
+      [hints setObject:rtargets forKey:@"bulkTargetKeys"];
+    
+    fs = [EOFetchSpecification alloc];
+    fs = [fs initWithEntityName:[self baseURLForContext:_ctx]
+            qualifier:nil
+            sortOrderings:nil
+            usesDistinct:NO isDeep:NO hints:hints];
+    fs = [fs autorelease];
+
+    if (debugOn) [self logWithFormat:@"  propfind fetchspec: %@", fs];
+  }
+  
+  [_ctx setObject:fs forKey:@"DAVFetchSpecification"];
+  
+  /* translate fetchspec if necessary */
+  {
+    NSDictionary *map;
+    
+    if ((map = [self->object davAttributeMapInContext:_ctx])) {
+      [_ctx setObject:map forKey:@"DAVPropertyMap"];
+      fs = [fs fetchSpecificationByApplyingKeyMap:map];
+      [_ctx setObject:fs  forKey:@"DAVMappedFetchSpecification"];
+    }
+  }
+  
+  /* perform */
+  
+  if ((result = [self->object performWebDAVQuery:fs inContext:_ctx]) == nil) {
+    return [self httpException:500 /* Server Error */
+                reason:@"could not perform query (object returned nil)"];
+  }
+  
+  if (debugOn) [self logWithFormat:@"  propfind result: %@", result];
+  
+  return result;
+}
+
+- (BOOL)allowDeletePropertiesOnNewObjectInContext:(WOContext *)_ctx {
+  NSString *ua;
+  
+  ua = [[_ctx request] headerForKey:@"user-agent"];
+  if ([ua hasPrefix:@"Evolution"]) {
+    /* if Evo creates tasks, it tries to delete some props at the same time */
+    return YES;
+  }
+  if ([ua hasPrefix:@"CFNetwork"]) {
+    /* iSync trying to create a record ... */
+    return YES;
+  }
+  
+  [self logWithFormat:@"do not allow delete properties on new object for: %@",
+         ua];
+  return NO;
+}
+
+- (id)doPROPPATCH:(WOContext *)_ctx {
+  SoSecurityManager *sm;
+  NSException       *e;
+  NSMutableArray    *resProps;
+  NSArray           *delProps;
+  NSDictionary      *setProps;
+  NSString          *pathInfo;
+  
+  pathInfo = [_ctx pathInfo];
+  
+  /* check permissions */
+  
+  sm = [_ctx soSecurityManager];
+  e  = [sm validatePermission:([pathInfo length] > 0)
+            ? SoPerm_AddDocumentsImagesAndFiles
+            : SoPerm_ChangeImagesAndFiles
+          onObject:self->object
+          inContext:_ctx];
+  if (e) return e;
+  
+  /* check for conflicts */
+
+  if ([pathInfo length] > 0) {
+    /* check whether all the parent collections are available */
+    if ([pathInfo rangeOfString:@"/"].length > 0) {
+      return [self httpException:409 /* Conflict */
+                  reason:
+                    @"invalid WebDAV PROPPATCH request, first create all "
+                    @"parent collections !"];
+    }
+  }
+  
+  /* check whether the object supports patching */
+
+  if ([pathInfo length] > 0) {
+    if (![self->object respondsToSelector:
+               @selector(davCreateObject:properties:inContext:)]) {
+      [self debugWithFormat:@"cannot create new object via DAV on %@",
+             self->object];
+      return [self httpException:405 /* not allowed */
+                  reason:
+                    @"this object cannot create a new object with PROPPATCH"];
+    }
+  }
+  else {
+    if (![self->object respondsToSelector:
+           @selector(davSetProperties:removePropertiesNamed:inContext:)]) {
+      [self debugWithFormat:@"cannot change object props via DAV on %@",
+             self->object];
+      return [self httpException:405 /* not allowed */
+                  reason:@"this object cannot PROPPATCH the attributes"];
+    }
+  }
+  
+  /* parse request */
+  
+  [self lockParser:davsax];
+  {
+    [xmlParser parseFromSource:[[_ctx request] content]];
+    delProps = [[davsax propPatchPropertyNamesToRemove] copy];
+    setProps = [[davsax propPatchValues] copy];
+  }
+  [self unlockParser:davsax];
+  delProps = [delProps autorelease];
+  setProps = [setProps autorelease];
+  
+  if (delProps == nil && setProps == nil) {
+    [self logWithFormat:@"WARNING: got no properties in PROPPATCH !"];
+    return [self httpException:400 /* bad request */
+                reason:@"got no properties in PROPPATCH !"];
+  }
+  
+  if ([pathInfo length] > 0) {
+    /* a create object cannot delete props ... */
+    if ([delProps count] > 0) {
+      if (![self allowDeletePropertiesOnNewObjectInContext:_ctx]) {
+        [self logWithFormat:@"shall delete props in new object '%@': %@",
+               pathInfo, delProps];
+        return [self httpException:400 /* bad request */
+                    reason:@"cannot delete properties of a new object"];
+      }
+      [self debugWithFormat:@"deleting properties on a new object: %@ ...",
+             delProps];
+    }
+  }
+  
+  resProps = [NSMutableArray arrayWithCapacity:16];
+  if (delProps) [resProps addObjectsFromArray:delProps];
+  if (setProps) [resProps addObjectsFromArray:[setProps allKeys]];
+  
+  /* map attributes */
+  {
+    NSDictionary *map;
+    
+    if ((map = [self->object davAttributeMapInContext:_ctx])) {
+      unsigned count;
+      
+      [_ctx setObject:map forKey:@"DAVPropertyMap"];
+      
+      if ((count = [delProps count]) > 0) {
+       NSMutableArray *mappedDelProps;
+       unsigned i;
+       
+       mappedDelProps = [NSMutableArray arrayWithCapacity:(count + 1)];
+       for (i = 0; i < count; i++) {
+         NSString *k, *tk;
+         
+         k  = [delProps objectAtIndex:i];
+         tk = [map valueForKey:k];
+         
+         [mappedDelProps addObject:(tk ? tk : k)];
+       }
+       delProps = mappedDelProps;
+      }
+      if ((count = [setProps count]) > 0) {
+       NSMutableDictionary *mappedSetProps;
+       NSEnumerator *keys;
+       NSString *k;
+       
+       mappedSetProps = [NSMutableDictionary dictionaryWithCapacity:count];
+       keys = [setProps keyEnumerator];
+       while ((k = [keys nextObject])) {
+         NSString *tk;
+         
+         tk = [map valueForKey:k];
+         [mappedSetProps setObject:[setProps objectForKey:k]
+                         forKey:(tk ? tk : k)];
+       }
+       setProps = mappedSetProps;
+      }
+    }
+  }
+  
+  if (debugOn) {
+    [self debugWithFormat:@"PROPPATCH '%@': delete=%@, set=%@",
+           pathInfo, delProps, setProps];
+  }
+  
+  if ([pathInfo length] == 0) {
+    /* edit an object */
+    NSException *e;
+    
+    e = [self->object 
+            davSetProperties:setProps
+            removePropertiesNamed:delProps
+            inContext:_ctx];
+    if (e) return e;
+  }
+  else {
+    /* create an object */
+    id newChild;
+    
+    newChild = [self->object 
+                   davCreateObject:pathInfo
+                   properties:setProps
+                   inContext:_ctx];
+    if ([newChild isKindOfClass:[NSException class]]) 
+      return newChild;
+    
+    [self debugWithFormat:@"created: %@", newChild];
+  }
+  
+  /* generate response */
+  return resProps;
+}
+
+- (id)doLOCK:(WOContext *)_ctx {
+  SoSecurityManager *sm;
+  NSException       *e;
+  SoDAVLockManager *lockManager;
+  WORequest  *rq;
+  WOResponse *r;
+  NSString   *ifValue, *lockDepth;
+  id token;
+  
+  /* check permissions */
+  
+  sm = [_ctx soSecurityManager];
+  e  = [sm validatePermission:SoPerm_WebDAVLockItems
+          onObject:self->object
+          inContext:_ctx];
+  if (e) return e;
+  
+  /* check lock manager */
+  
+  if ((lockManager = [self->object davLockManagerInContext:_ctx]) == nil) {
+    return [self httpException:405 /* method not allowed */
+                reason:@"target object does not support locking !"];
+  }
+  
+  rq = [_ctx request];
+  r  = [_ctx response];
+  
+  lockDepth = [rq headerForKey:@"depth"];
+  ifValue   = [rq headerForKey:@"if"];
+  
+  if (lockDepth != nil && ![lockDepth isEqualToString:@"0"]) {
+    [self logWithFormat:
+           @"WARNING: 'depth' locking not supported yet (depth=%@)!", 
+           lockDepth];
+  }
+  if (ifValue) {
+    [self logWithFormat:
+           @"WARNING: 'if' locking not supported yet, if: '%@'", ifValue];
+  }
+  
+  // need to parse lockinfo
+  
+  token = [lockManager lockURI:[rq uri]
+                      timeout:[rq headerForKey:@"timeout"]
+                      scope:@"exclusive"
+                      type:@"write"
+                      owner:nil];
+  if (token == nil) {
+    /* already locked */
+    return [self httpException:423 /* locked */
+                reason:@"object locked, lock manager did not provide token."];
+  }
+  
+  [self debugWithFormat:@"locked: %@ (token %@)", [[_ctx request] uri], token];
+  return token;
+}
+
+- (id)doUNLOCK:(WOContext *)_ctx {
+  SoSecurityManager *sm;
+  NSException       *e;
+  SoDAVLockManager  *lockManager;
+  NSString *token;
+  
+  /* check permissions */
+  
+  sm = [_ctx soSecurityManager];
+  e  = [sm validatePermission:SoPerm_WebDAVUnlockItems
+          onObject:self->object
+          inContext:_ctx];
+  if (e) return e;
+  
+  /* check lock manager */
+  
+  if ((lockManager = [self->object davLockManagerInContext:_ctx]) == nil) {
+    return [self httpException:405 /* method not allowed */
+                reason:@"target object does not support locking."];
+  }
+  
+  token = [[_ctx request] headerForKey:@"lock-token"];
+  
+  [lockManager unlockURI:[[_ctx request] uri] token:token];
+  
+  [self debugWithFormat:
+         @"unlocked: %@ (token %@)", [[_ctx request] uri], token];
+  
+  [[_ctx response] setStatus:204 /* fake ok */];
+  return [_ctx response];
+}
+
+- (NSException *)extractDestinationPath:(NSArray **)path_
+  fromContext:(WOContext *)_ctx
+{
+  NSString *absDestURL;
+  NSURL    *destURL, *srvURL;
+  
+  if (path_) *path_ = nil;
+  
+  /* TODO: check proper permission prior attempting a move */
+  
+  absDestURL = [[_ctx request] headerForKey:@"destination"];
+  if ([absDestURL length] == 0) {
+    return [self httpException:400 /* Bad Request */
+                reason:
+                  @"the destination WebDAV header was missing "
+                  @"for the MOVE/COPY operation"];
+  }
+  if ((destURL = [NSURL URLWithString:absDestURL]) == nil) {
+    [self logWithFormat:@"MOVE: got invalid destination URL: '%@'", 
+           absDestURL];
+    return [self httpException:400 /* Bad Request */
+                reason:@"the MOVE/COPY destination is not a valid URL!"];
+  }
+  
+  srvURL = [_ctx serverURL];
+  
+  [self debugWithFormat:@"move/copy:\n  to:    %@\n  server: %@)", 
+         [destURL absoluteString], [srvURL absoluteString]];
+  
+  /* check whether URL is on the same server ... */
+  if (![[srvURL host] isEqualToString:[destURL host]] ||
+      ![[srvURL port] isEqual:[destURL port]]) {
+    /* 
+       The WebDAV spec is not really clear on what we should return in this
+       case? Let me know if anybody has a suggestion ...
+    */
+    [self logWithFormat:@"tried to do a cross server move (%@ vs %@)",
+           [srvURL absoluteString], [destURL absoluteString]];
+    return [self httpException:403 /* Forbidden */
+                reason:@"MOVE destination is on a different host."];
+  }
+  
+  if (path_) {
+    NSMutableArray *ma;
+    unsigned i;
+    
+    /* TODO: hack hack hack */
+    ma = [[[destURL path] componentsSeparatedByString:@"/"] mutableCopy];
+    if ([ma count] > 0) // leading slash ("")
+      [ma removeObjectAtIndex:0];
+    if ([ma count] > 0) // the appname (eg zidestore)
+      [ma removeObjectAtIndex:0];
+    if ([ma count] > 0) // the request handler key (eg so)
+      [ma removeObjectAtIndex:0];
+    
+    /* unescape path components */
+    for (i = 0; i < [ma count]; i++) {
+      NSString *s = [ma objectAtIndex:i], *ns;
+      
+      ns = [s stringByUnescapingURL];
+      if (ns != s)
+        [ma replaceObjectAtIndex:i withObject:ns];
+    }
+    
+    *path_ = [ma copy];
+    [ma release];
+  }
+  return nil;
+}
+- (NSException *)lookupDestinationObject:(id *)target_ 
+  andNewName:(NSString **)name_
+  inContext:(WOContext *)_ctx
+{
+  NSException *error;
+  NSArray     *targetPath;
+  id          root;
+  
+  if ((error = [self extractDestinationPath:&targetPath fromContext:_ctx]))
+    return error;
+
+  if ((root = [_ctx application]) == nil)
+    root = [WOApplication application];
+  if (root == nil) {
+    return [self httpException:500 /* internal server error */
+                reason:@"did not find SOPE root object"];
+  }
+  
+  /* TODO: we should probably use a subcontext?! */
+  [_ctx setObject:yesNum forKey:@"isDestinationPathLookup"];
+  *target_ = [root traversePathArray:targetPath
+                  inContext:_ctx
+                  error:&error
+                  acquire:NO];
+  if (error) {
+    [self logWithFormat:@"could not resolve destination object (%@): %@",
+           [targetPath componentsJoinedByString:@" => "],
+           error];
+    return error;
+  }
+
+  if (name_) *name_ = [[[_ctx pathInfo] copy] autorelease];
+  
+  if (*target_ == nil) {
+    [self debugWithFormat:@"MOVE/COPY destination could not be found."];
+    return [self httpException:404 /* Not Found */
+                reason:@"did not find target object"];
+  }
+  
+  [self debugWithFormat:@"SOURCE: %@", self->object];
+  [self debugWithFormat:@"TARGET: %@ (PI %@)", *target_, [_ctx pathInfo]];
+  return nil;
+}
+
+- (id)doCOPY:(WOContext *)_ctx {
+  NSException *error;
+  NSString    *newName;
+  id          targetObject;
+  
+  /* TODO: check proper permission prior attempting a copy */
+  
+  error = [self lookupDestinationObject:&targetObject andNewName:&newName
+               inContext:_ctx];
+  if (error) return error;
+  
+  error = [self->object 
+              davCopyToTargetObject:targetObject newName:newName
+              inContext:_ctx];
+  if (error) {
+    [self debugWithFormat:@"WebDAV COPY operation failed: %@", error];
+    return error;
+  }
+  
+  return ([newName length] > 0)
+    ? [NSNumber numberWithBool:201 /* Created */]
+    : [NSNumber numberWithBool:204 /* No Content */];
+}
+
+- (id)doMOVE:(WOContext *)_ctx {
+  NSException *error;
+  NSString    *newName;
+  id          targetObject;
+  
+  /* TODO: check proper permission prior attempting a move */
+  
+  error = [self lookupDestinationObject:&targetObject andNewName:&newName
+               inContext:_ctx];
+  if (error) return error;
+  
+  /*
+    Note: more relevant headers:
+      overwrite: T|F      (overwrite target) [rc: 201 vs 204!]
+      depth:     infinity
+      and locking tokens of course ...
+  */
+  
+  // TODO: should we check in this place for some constraints,
+  //       eg moving a collection to a non-collection or something
+  //       like that?
+  
+  error = [self->object 
+              davMoveToTargetObject:targetObject newName:newName
+              inContext:_ctx];
+  if (error) {
+    [self debugWithFormat:@"WebDAV MOVE operation failed: %@", error];
+    return error;
+  }
+  
+  return ([newName length] > 0)
+    ? [NSNumber numberWithBool:201 /* Created */]
+    : [NSNumber numberWithBool:204 /* No Content */];
+}
+
+/* WebDAV search methods */
+
+- (id)doSEARCH:(WOContext *)_ctx {
+  SoSecurityManager    *sm;
+  NSException          *e;
+  EOFetchSpecification *fs;
+  NSString *baseURL;
+  id       result;
+  NSString *range;
+  
+  /* check permissions */
+  
+  sm = [_ctx soSecurityManager];
+  e  = [sm validatePermission:SoPerm_AccessContentsInformation 
+          onObject:self->object
+          inContext:_ctx];
+  if (e) return e;
+
+  /* perform search */
+  
+  if (![self->object 
+            respondsToSelector:@selector(performWebDAVQuery:inContext:)]) {
+    [[_ctx response] setStatus:405 /* not allowed */];
+    [[_ctx response] appendContentString:
+                      @"this object cannot not execute a SEARCH query"];
+    return [_ctx response];
+  }
+  
+  baseURL = [NSString stringWithFormat:@"http://%@%@",
+                       [[_ctx request] headerForKey:@"host"],
+                       [[_ctx request] uri]];
+  
+  [self lockParser:davsax];
+  {
+    [xmlParser parseFromSource:[[_ctx request] content]];
+    fs = [[davsax searchFetchSpecification] retain];
+  }
+  [self unlockParser:davsax];
+  
+  fs = [fs autorelease];
+  if (fs == nil) {
+    [[_ctx response] setStatus:400 /* Bad Request */];
+    [[_ctx response] appendContentString:
+                      @"could not process SEARCH query specification"];
+    return [_ctx response];
+  }
+
+  /* range */
+  if ((range = [[[_ctx request] headerForKey:@"range"] stringValue])) {
+    /* TODO: parse range header and add to fetch-specification */
+    NSRange r;
+    
+    r = [range rangeOfString:@"rows="];
+    if (r.length > 0) {
+      range = [range substringFromIndex:(r.location + r.length)];
+      [self debugWithFormat:
+              @"Note: got a row range header (ignored): '%@'", range];
+    }
+    else
+      [self logWithFormat:@"Note: got a range header (ignored): '%@'", range];
+  }
+  
+  /* override entity name ... (FROM xxx isn't yet parsed correctly) */
+  [fs setEntityName:baseURL];
+  
+  [self debugWithFormat:@"SEARCH: %@", fs];
+  
+  [_ctx setObject:fs forKey:@"DAVFetchSpecification"];
+
+  /* translate fetchspec if necessary */
+  {
+    NSDictionary *map;
+    
+    if ((map = [self->object davAttributeMapInContext:_ctx])) {
+      [_ctx setObject:map forKey:@"DAVPropertyMap"];
+      fs = [fs fetchSpecificationByApplyingKeyMap:map];
+      [_ctx setObject:fs forKey:@"DAVMappedFetchSpecification"];
+    }
+  }
+  
+  /* perform call */
+  
+  if ((result = [self->object performWebDAVQuery:fs inContext:_ctx]) == nil) {
+    return [self httpException:500 /* Server Error */
+                reason:@"could not execute SEARCH query (returned nil)"];
+  }
+  
+  return result;
+}
+
+/* Exchange WebDAV methods */
+
+- (id)doNOTIFY:(WOContext *)_ctx {
+  return [self httpException:403 reason:@"NOTIFY not yet implemented"];
+}
+
+- (id)doPOLL:(WOContext *)_ctx {
+  SoSubscriptionManager *sm;
+  WORequest  *rq;
+  NSString   *subscriptionID;
+  NSArray    *ids;
+  NSURL      *url;
+  
+  rq  = [_ctx request];
+  sm  = [SoSubscriptionManager sharedSubscriptionManager];
+  url = [NSURL URLWithString:[self->object baseURLInContext:_ctx]];
+  
+  if (url == nil) {
+    return [self httpException:500
+                 reason:@"could not calculate URL of WebDAV object !"];
+  }
+  
+  subscriptionID = [rq headerForKey:@"subscription-id"];
+  if ([subscriptionID length] == 0) {
+    return [self httpException:400 /* Bad Request */
+                 reason:@"did not find subscription-id header in POLL"];
+  }
+  
+  ids = [subscriptionID componentsSeparatedByString:@","];
+  
+  return [sm pollSubscriptions:ids onURL:url];
+}
+
+- (id)doSUBSCRIBE:(WOContext *)_ctx {
+  SoSubscriptionManager *sm;
+  WORequest  *rq;
+  WOResponse *r;
+  NSURL    *url;
+  id       callback;
+  NSString *notificationType;
+  NSString *notificationDelay;
+  NSString *lifetime;
+  NSString *subscriptionID;
+  
+  rq  = [_ctx request];
+  r   = [_ctx response];
+  sm  = [SoSubscriptionManager sharedSubscriptionManager];
+  url = [NSURL URLWithString:[self->object baseURLInContext:_ctx]];
+  
+  if (url == nil) {
+    return [self httpException:500
+                 reason:@"could not calculate URL of WebDAV object !"];
+  }
+  
+  subscriptionID = [rq headerForKey:@"subscription-id"];
+  
+  /* first check, whether it's an existing subscription to be renewed */
+  
+  if ([subscriptionID length] > 0) {
+    NSString *newId;
+    
+    if ((newId = [sm renewSubscription:subscriptionID onURL:url]) == nil) {
+      return [self httpException:412 /* precondition failed */
+                   reason:@"did not find provided subscription ID !"];
+    }
+    return newId;
+  }
+  
+  if ((callback = [rq headerForKey:@"call-back"])) {
+    NSURL *url;
+    
+    if ((url = [NSURL URLWithString:[callback stringValue]]) == nil) {
+      [self debugWithFormat:@"ERROR: could not parse callback URL '%@'", 
+              callback];
+      return [self httpException:400 /* Bad Request */
+                   reason:@"missing valid callback URL !"];
+    }
+    else
+      callback = url;
+  }
+  
+  /* TODO: add sanity checking of notification-type as described in docs */
+  /* TODO: check depth */
+  
+  notificationDelay = [rq headerForKey:@"notification-delay"];
+  notificationType  = [rq headerForKey:@"notification-type"];
+  lifetime          = [rq headerForKey:@"subscription-lifetime"];
+  
+  subscriptionID = [sm subscribeURL:url forObserver:callback
+                       type:notificationType 
+                       delay:notificationDelay
+                         ? [notificationDelay doubleValue] : 0.0
+                       lifetime:lifetime ? [lifetime doubleValue] : 0.0];
+  return subscriptionID;
+}
+- (id)doUNSUBSCRIBE:(WOContext *)_ctx {
+  SoSubscriptionManager *sm;
+  WORequest  *rq;
+  WOResponse *r;
+  NSString *subscriptionID;
+  NSURL    *url;
+  
+  rq  = [_ctx request];
+  r   = [_ctx response];
+  sm  = [SoSubscriptionManager sharedSubscriptionManager];
+  url = [NSURL URLWithString:[self->object baseURLInContext:_ctx]];
+  
+  if (url == nil) {
+    return [self httpException:500
+                 reason:@"could not calculate URL of WebDAV object !"];
+  }
+  
+  subscriptionID = [rq headerForKey:@"subscription-id"];
+  if ([subscriptionID length] == 0) {
+    return [self httpException:400 /* Bad Request */
+                reason:@"missing subscription id !"];
+  }
+  
+  if ([sm unsubscribeID:subscriptionID onURL:url]) {
+    [r setStatus:200];
+    return r;
+  }
+  else {
+    return [self httpException:400 /* Bad Request */
+                reason:@"unsubscribe failed (invalid or old id ?)"];
+  }
+}
+
+/* Exchange bulk methods */
+
+- (NSArray *)urlPartsForTargets:(NSArray *)_targets basePath:(NSString *)_base{
+  /*
+    Transform the target URLs given to the BPROPFIND operation. This is a
+    simplified implementation, for example we expect that the URLs are all
+    located in the same URL space (on same host and port).
+  */
+  NSMutableArray *ma;
+  unsigned i, count;
+  
+  if ((count = [_targets count]) == 0)
+    return [NSArray array];
+  
+  ma = [NSMutableArray arrayWithCapacity:count];
+  for (i = 0; i < count; i++) {
+    NSString *target;
+    
+    target = [_targets objectAtIndex:i];
+    if (debugBulkTarget)
+      [self logWithFormat:@"  MORPH target '%@'", target];
+    
+    /* extract the path from full URLs */
+    if ([target isAbsoluteURL]) {
+      NSURL *url;
+      
+      /* fix an Evolution bug, uses the 'unsafe' "@" in the URL ! */
+      if ([target rangeOfString:@"@"].length > 0) {
+       target = [target stringByReplacingString:@"@"
+                        withString:@"%40"];
+      }
+      
+      if ((url = [NSURL URLWithString:target])) {
+       if (debugBulkTarget) [self logWithFormat:@"got URL: %@", url];
+       target = [url path];
+       if (debugBulkTarget) [self logWithFormat:@"path: %@", target];
+      }
+      else {
+       [self logWithFormat:@"ERROR: could not parse BPROPFIND target '%@' !",
+               target];
+      }
+    }
+    
+    /* make the target name relative to the request URI */
+    if ([target hasPrefix:_base]) {
+      target = [target substringFromIndex:[_base length]];
+      if ([target hasPrefix:@"/"])
+       target = [target substringFromIndex:1];
+    }
+    
+    /* add the target */
+    target = [target stringByUnescapingURL];
+    if (debugBulkTarget) [self logWithFormat:@"  ADD target '%@'", target];
+    [ma addObject:target];
+  }
+  return ma;
+}
+
+- (id)doBPROPFIND:(WOContext *)_ctx {
+  /*
+    TODO: could optimize a BPROPFIND on a single target to use PROPFIND
+    
+    How are BPROPFINDs mapped ? BPROPFIND corresponds to SKYRiX 4.1
+    "fetch-by-globalids" commands, that is, a search gets passed a list
+    of primary keys to fetch.
+    BPROPFIND is implemented in a similiar way, the target URLs are converted
+    to be relative to the URI object and are passed to the query datasource
+    using the "bulkTargetKeys" fetch hint.
+    
+    Important: the URI object *must* support the "bulkTargetKeys" fetch hint,
+    otherwise the operation will run on the object itself.
+    
+    Note: Previously BPROPFIND was mapped to a set of individual requests,
+    but obviously this doesn't match SQL very well (resulting in an individual
+    SQL query for each entity ...)
+  */
+  SoSecurityManager    *sm;
+  NSException          *e;
+  EOFetchSpecification *fs;
+  WORequest *rq;
+  NSString  *depth; /* 0, 1, 1,noroot or infinity */
+  NSArray   *propNames;
+  NSArray   *targets, *rtargets;
+  BOOL      findAll;
+  BOOL      findNames;
+  id        result;
+  NSDictionary *map;
+  
+  /* check permissions */
+  
+  sm = [_ctx soSecurityManager];
+  e  = [sm validatePermission:SoPerm_AccessContentsInformation 
+          onObject:self->object
+          inContext:_ctx];
+  if (e) return e;
+
+  /* perform search */
+  
+  if (![self->object respondsToSelector:@selector(performWebDAVQuery:inContext:)]) {
+    return [self httpException:405 /* not allowed */
+                reason:@"this object cannot not execute a PROPFIND query"];
+  }
+  
+  rq = [_ctx request];
+  depth = [rq headerForKey:@"depth"];
+  if ([depth length] == 0) depth = @"infinity";
+  
+  [self lockParser:davsax];
+  {
+    [xmlParser parseFromSource:[rq content]];
+    propNames = [[davsax propFindQueriedNames] copy];
+    findAll   = [davsax  propFindAllProperties];
+    findNames = [davsax  propFindPropertyNames];
+    targets   = [[davsax  bpropFindTargets] copy];
+  }
+  [self unlockParser:davsax];
+  propNames = [propNames autorelease];
+  targets   = [targets   autorelease];
+  
+  if ([targets count] == 0)
+    return [NSArray array];
+  
+  /* check query all properties */
+  
+  if (propNames == nil)
+    propNames = [self->object defaultWebDAVPropertyNamesInContext:_ctx];
+  
+  /* morph targets */
+  
+  rtargets = [self urlPartsForTargets:targets
+                   basePath:[[rq uri] stringByUnescapingURL]];
+  
+  [self debugWithFormat:@"BPROPFIND targets: %@", rtargets];
+  
+  /* build the fetch-spec */
+  {
+    NSMutableDictionary *hints;
+    
+    hints = [self hintsWithScope:[self scopeForDepth:depth inContext:_ctx]
+                 propNames:propNames findAll:findAll namesOnly:findNames];
+    [hints setObject:rtargets forKey:@"bulkTargetKeys"];
+    
+    fs = [EOFetchSpecification alloc];
+    fs = [fs initWithEntityName:[self baseURLForContext:_ctx]
+            qualifier:nil
+            sortOrderings:nil
+            usesDistinct:NO isDeep:NO hints:hints];
+    fs = [fs autorelease];
+  }
+  
+  [_ctx setObject:fs forKey:@"DAVFetchSpecification"];
+  
+  /* 
+     translate fetchspec if necessary - we currently cannot allow a map
+     for each target, so we use the map of the queried target.
+  */
+  if ((map = [self->object davAttributeMapInContext:_ctx])) {
+    [_ctx setObject:map forKey:@"DAVPropertyMap"];
+    fs = [fs fetchSpecificationByApplyingKeyMap:map];
+    [_ctx setObject:fs  forKey:@"DAVMappedFetchSpecification"];
+  }
+
+  /* perform */
+  
+  if ((result = [self->object performWebDAVQuery:fs inContext:_ctx]) == nil) {
+    return [self httpException:500 /* Server Error */
+                reason:@"could not perform query (object returned nil)"];
+  }
+  
+  return result;
+#if 0  
+  /* now, for each BPROPFIND target ... */
+  {
+    NSEnumerator *e;
+    NSString *targetURL;
+    
+    result = [NSMutableArray arrayWithCapacity:32];
+    
+    e = [targets objectEnumerator];
+    while ((targetURL = [e nextObject])) {
+      NSAutoreleasePool *pool;
+      WOContext   *localContext;
+      WORequest   *localRequest;
+      NSException *e;
+      id targetObject;
+      id targetResult;
+      
+      pool = [[NSAutoreleasePool alloc] init];
+      
+      /* setup the "subrequest" */
+      
+      if ([targetURL isAbsoluteURL]) {
+       NSURL *url;
+       
+       if ((url = [NSURL URLWithString:targetURL]))
+         targetURL = [url path];
+       else {
+         [self logWithFormat:@"ERROR: could not parse target-url '%@'",
+                 targetURL];
+       }
+      }
+      
+      localRequest = [[WORequest alloc] initWithMethod:@"PROPFIND"
+                                       uri:targetURL
+                                       httpVersion:[rq httpVersion]
+                                       headers:[rq headers]
+                                       content:nil
+                                       userInfo:nil];
+      localContext = 
+       [[[WOContext alloc] initWithRequest:localRequest] autorelease];
+      [localRequest autorelease];
+      
+      /* resetup fetchspec */
+      [fs setEntityName:targetURL];
+      
+      /* traverse URL */
+      
+      targetObject = [_ctx traversalRoot];
+      targetObject = [targetObject traversePathArray:
+                                    [localRequest requestHandlerPathArray]
+                                  inContext:localContext
+                                  error:&e
+                                  acquire:NO];
+      if (targetObject == nil) {
+       [self logWithFormat:@"did not find BPROPFIND target: %@", targetURL];
+       [self logWithFormat:@"  root:   %@", [_ctx traversalRoot]];
+       [self logWithFormat:@"  path:   %@", 
+               [[localRequest requestHandlerPathArray] 
+                              componentsJoinedByString:@"/"]];
+       [self logWithFormat:@"  error:  %@", e];
+       targetResult = e;
+      }
+      else {
+       /* perform query */
+       
+       targetResult = [targetObject performWebDAVQuery:fs 
+                                    inContext:localContext];
+       if (targetResult == nil) {
+         targetResult = 
+           [self httpException:500 /* Server Error */
+                 reason:@"could not perform query (object returned nil)"];
+       }
+      }
+      
+      // do we need to distinguish the queries somehow ? (href generation)
+      if ([targetResult isKindOfClass:[NSArray class]])
+       [result addObjectsFromArray:targetResult];
+      else if (targetResult)
+       [result addObject:targetResult];
+      
+      [pool release];
+    }
+  }
+  
+  /* perform */
+  
+  if (result) return result;
+#endif
+}
+
+- (id)doBCOPY:(WOContext *)_ctx {
+  return [self httpException:403 /* forbidden */
+              reason:@"BCOPY not yet implemented."];
+}
+- (id)doBDELETE:(WOContext *)_ctx {
+  return [self httpException:403 /* forbidden */
+              reason:@"BDELETE not yet implemented."];
+}
+- (id)doBMOVE:(WOContext *)_ctx {
+  return [self httpException:403 /* forbidden */
+              reason:@"WebDAV operation not yet implemented."];
+}
+
+- (id)doBPROPPATCH:(WOContext *)_ctx {
+  return [self httpException:403 /* forbidden */
+              reason:@"WebDAV operation not yet implemented."];
+}
+
+/* DAV access control lists */
+
+- (id)doACL:(WOContext *)_ctx {
+  return [self httpException:405 /* method not allowed */
+              reason:@"WebDAV operation not yet implemented."];
+}
+
+/* DAV binding */
+
+- (id)doBIND:(WOContext *)_ctx {
+  return [self httpException:405 /* method not allowed */
+              reason:@"WebDAV operation not yet implemented."];
+}
+
+/* DAV ordering */
+
+- (id)doORDERPATCH:(WOContext *)_ctx {
+  return [self httpException:405 /* method not allowed */
+              reason:@"WebDAV operation not yet implemented."];
+}
+
+/* DAV deltav */
+
+- (id)doCHECKOUT:(WOContext *)_ctx {
+  return [self httpException:405 /* method not allowed */
+              reason:@"WebDAV operation not yet implemented."];
+}
+- (id)doUNCHECKOUT:(WOContext *)_ctx {
+  return [self httpException:405 /* method not allowed */
+              reason:@"WebDAV operation not yet implemented."];
+}
+- (id)doCHECKIN:(WOContext *)_ctx {
+  return [self httpException:405 /* method not allowed */
+              reason:@"WebDAV operation not yet implemented."];
+}
+- (id)doMKWORKSPACE:(WOContext *)_ctx {
+  return [self httpException:405 /* method not allowed */
+              reason:@"WebDAV operation not yet implemented."];
+}
+- (id)doUPDATE:(WOContext *)_ctx {
+  return [self httpException:405 /* method not allowed */
+              reason:@"WebDAV operation not yet implemented."];
+}
+- (id)doMERGE:(WOContext *)_ctx {
+  return [self httpException:405 /* method not allowed */
+              reason:@"WebDAV operation not yet implemented."];
+}
+- (id)doVERSIONCONTROL:(WOContext *)_ctx {
+  return [self httpException:405 /* method not allowed */
+              reason:@"WebDAV operation not yet implemented."];
+}
+
+/* perform dispatch */
+
+- (id)performMethod:(NSString *)_method inContext:(WOContext *)_ctx {
+  SoSecurityManager *sm;
+  NSException       *e;
+  NSString *s;
+  SEL      sel;
+  
+  /* check basic WebDAV permission */
+  
+  sm = [_ctx soSecurityManager];
+  e  = [sm validatePermission:SoPerm_WebDAVAccess
+          onObject:self->object
+          inContext:_ctx];
+  if (e) return e;
+  
+  /* perform search */
+  
+  _method = [_method uppercaseString];
+  _method = [_method stringByReplacingString:@"-" withString:@""];
+  s = [NSString stringWithFormat:@"do%@:", _method];
+  sel = NSSelectorFromString(s);
+  
+  if (![self respondsToSelector:sel]) {
+    [self logWithFormat:@"unknown WebDAV method: '%@'", _method];
+    [[_ctx response] setStatus:405 /* invalid method */];
+    return [_ctx response];
+  }
+  
+  return [self performSelector:sel withObject:_ctx];
+}
+
+- (BOOL)setupXmlParser {
+  if (xmlParser == nil) {
+    xmlParser =
+      [[[SaxXMLReaderFactory standardXMLReaderFactory] 
+                             createXMLReaderForMimeType:@"text/xml"]
+                             retain];
+    if (xmlParser == nil)
+      return NO;
+  }
+  if (davsax == nil) {
+    if ((davsax = [[SaxDAVHandler alloc] init]) == nil)
+      return NO;
+  }
+  return YES;
+}
+
+- (id)dispatchInContext:(WOContext *)_ctx {
+  NSAutoreleasePool *pool;
+  WOResponse *r;
+  id result;
+  
+  if (gmt == nil) gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+  
+  /* setup XML parser */
+  if (![self setupXmlParser]) {
+    r = [_ctx response];
+    [r setStatus:500 /* internal server error */];
+    [r appendContentString:@"did not find an XML parser, cannot process DAV."];
+    return r;
+  }
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  result = [[self performMethod:[[_ctx request] method] inContext:_ctx] retain];
+  [pool release];
+  return [result autorelease];
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return @"[obj-dav-dispatch]";
+}
+- (BOOL)isDebuggingEnabled {
+  return debugOn ? YES : NO;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self,
+        NSStringFromClass((Class)*(void**)self)];
+  
+  if (self->object)
+    [ms appendFormat:@" object=%@", self->object];
+  else
+    [ms appendString:@" <no object>"];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SoObjectWebDAVDispatcher */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoSubscription.h b/skyrix-sope/NGObjWeb/WebDAV/SoSubscription.h
new file mode 100644 (file)
index 0000000..7f4b158
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_SoSubscription_H__
+#define __NGObjWeb_SoSubscription_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSDate.h>
+
+/*
+  SoSubscription
+  
+  This class holds the information of a single subscription. Usually you
+  will never access SoSubscription objects directly.
+
+  Subscription Types:
+    update
+    delete
+    move
+    any
+    update/newmember
+    pragma/<http...newmail>
+*/
+
+@class NSString, NSURL, NSMutableDictionary;
+
+@interface SoSubscription : NSObject
+{
+  NSString       *sid;
+  NSURL          *object;
+  BOOL           trackChildren; /* depth header */
+  NSURL          *observer;
+  
+  NSTimeInterval delay;
+  NSTimeInterval lifetime;
+  NSDate         *expireDate;   /* now + lifetime */
+  NSString       *subscriptionType;
+  
+  unsigned       pending; /* keeps the number of events since last POLL */
+}
+
+- (id)initWithID:(NSString *)_sid
+  url:(NSURL *)_url observer:(NSURL *)_callback
+  type:(NSString *)_type delay:(NSTimeInterval)_delay
+  lifetime:(NSTimeInterval)_lifetime;
+
+/* accessors */
+
+- (NSDate *)expirationDate;
+- (NSString *)subscriptionID;
+- (BOOL)hasEventsPending;
+
+/* operations */
+
+- (BOOL)isValidForURL:(NSURL *)_url;
+- (BOOL)isExpired;
+- (BOOL)renewSubscription;
+- (void)resetEvents;
+
+@end
+
+#endif /* __NGObjWeb_SoSubscription_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoSubscription.m b/skyrix-sope/NGObjWeb/WebDAV/SoSubscription.m
new file mode 100644 (file)
index 0000000..f27ae11
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoSubscription.h"
+#include <NGStreams/NGDatagramPacket.h>
+#include <NGStreams/NGDatagramSocket.h>
+#include "common.h"
+
+@implementation SoSubscription
+
+static BOOL debugOn = YES;
+
+- (id)initWithID:(NSString *)_sid
+  url:(NSURL *)_url observer:(NSURL *)_callback
+  type:(NSString *)_type delay:(NSTimeInterval)_delay
+  lifetime:(NSTimeInterval)_lifetime
+{
+  if ((self = [super init])) {
+    self->subscriptionType = [_type copy];
+    self->sid      = [_sid      copy];
+    self->object   = [_url      retain];
+    self->observer = [_callback retain];
+    self->lifetime = _lifetime;
+    self->delay    = _delay;
+    
+    self->expireDate = [[NSDate alloc] initWithTimeIntervalSinceNow:_lifetime];
+  }
+  return self;
+}
+- (id)init {
+  [self release];
+  return nil;
+}
+
+- (void)dealloc {
+  [self->sid        release];
+  [self->object     release];
+  [self->observer   release];
+  [self->expireDate release];
+  [self->subscriptionType release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSDate *)expirationDate {
+  return self->expireDate;
+}
+- (NSString *)subscriptionID {
+  return self->sid;
+}
+
+- (BOOL)hasEventsPending {
+  return self->pending > 0 ? YES : NO;
+}
+
+/* operations */
+
+- (void)resetEvents {
+  self->pending = 0;
+}
+
+- (BOOL)isValidForURL:(NSURL *)_url {
+  return YES;
+}
+
+- (BOOL)isExpired {
+  NSDate *now;
+  
+  if (self->expireDate == nil) 
+    return NO;
+  
+  now = [NSDate date];
+  return [now timeIntervalSince1970] > [self->expireDate timeIntervalSince1970]
+    ? YES : NO;
+}
+
+- (BOOL)renewSubscription {
+  [self->expireDate release]; 
+  self->expireDate = nil;
+  
+  self->expireDate =
+    [[NSDate alloc] initWithTimeIntervalSinceNow:self->lifetime];
+  return YES;
+}
+
+/* send-notify */
+
+- (BOOL)sendNotification {
+  static NGDatagramSocket *socket = nil;
+  NGInternetSocketAddress *address;
+  NGDatagramPacket *packet;
+  NSMutableString  *ms;
+  NSData           *data;
+  
+  [self debugWithFormat:@"sending notification ..."];
+  
+  /* construct HTTP-over-UDP request */
+  
+  ms = [NSMutableString stringWithCapacity:16];
+  [ms appendString:@"NOTIFY "];
+  [ms appendString:[self->observer absoluteString]];
+  [ms appendString:@" HTTP/1.1\r\n"];
+  [ms appendString:@"Subscription-id: "];
+  [ms appendString:self->sid];
+  [ms appendString:@"\r\n"];
+  
+  /* send packet */
+  
+  data    = [ms dataUsingEncoding:NSUTF8StringEncoding];
+  packet  = (NGDatagramPacket *)[NGDatagramPacket packetWithData:data];
+  address = [NGInternetSocketAddress addressWithPort:
+                                       [[self->observer port] intValue]
+                                     onHost:
+                                       [self->observer host]];
+  
+  if (socket == nil) {
+    socket = [[NGDatagramSocket alloc] initWithDomain:
+                                         [NGInternetSocketDomain domain]];
+  }
+  [packet setReceiver:address];
+  
+  self->pending++;
+  
+  return [socket sendPacket:packet timeout:3.0];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* SoSubscription */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoSubscriptionManager.h b/skyrix-sope/NGObjWeb/WebDAV/SoSubscriptionManager.h
new file mode 100644 (file)
index 0000000..00d25c5
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_SoSubscriptionManager_H__
+#define __NGObjWeb_SoSubscriptionManager_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSDate.h>
+
+/*
+  SoSubscriptionManager
+  
+  This class (or singleton) is responsible for managing WebDAV URL
+  subscriptions as documented in the Exchange WebDAV API.
+*/
+
+@class NSString, NSURL, NSArray, NSMutableDictionary, NSTimer;
+
+@interface SoSubscriptionManager : NSObject
+{
+  NSMutableDictionary *idToSubscription;
+  NSTimer *timer;
+}
+
++ (id)sharedSubscriptionManager;
+
+/* managing subscriptions */
+
+- (NSString *)subscribeURL:(NSURL *)_url forObserver:(NSURL *)_callback
+  type:(NSString *)_type delay:(NSTimeInterval)_delay
+  lifetime:(NSTimeInterval)_lifetime;
+
+- (NSString *)renewSubscription:(NSString *)_sid onURL:(NSURL *)_url;
+- (BOOL)unsubscribeID:(NSString *)_sid           onURL:(NSURL *)_url;
+- (id)pollSubscriptions:(NSArray *)_sids         onURL:(NSURL *)_url;
+
+@end
+
+#endif /* __NGObjWeb_SoSubscriptionManager_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoSubscriptionManager.m b/skyrix-sope/NGObjWeb/WebDAV/SoSubscriptionManager.m
new file mode 100644 (file)
index 0000000..9534b20
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoSubscriptionManager.h"
+#include "SoSubscription.h"
+#include "SoObject.h"
+#include <EOControl/EOControl.h>
+#include "common.h"
+
+@implementation SoSubscriptionManager
+
+static BOOL           debugOn         = NO;
+static NSTimeInterval defaultLifeTime = 3600;
+static int            expirationInterval = 10 * 60 /* every 10 minutes */;
+
+static SoSubscriptionManager *sm = nil;
+
++ (id)sharedSubscriptionManager {
+  if (sm == nil) {
+    debugOn = [[NSUserDefaults standardUserDefaults] 
+                boolForKey:@"SoSubscriptionManagerDebugEnabled"];
+    
+    sm = [[SoSubscriptionManager alloc] init];
+  }
+  return sm;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->idToSubscription = [[NSMutableDictionary alloc] init];
+
+    [[NSNotificationCenter defaultCenter] 
+      addObserver:self selector:@selector(trackChange:)
+      name:@"SoObjectChanged" object:nil];
+  }
+  return self;
+}
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [self->idToSubscription release];
+  [super dealloc];
+}
+
+/* subscriptions */
+
+- (NSString *)nextSubscriptionID {
+  static int i = 1000;
+  i++;
+  return [NSString stringWithFormat:@"%i", i];
+}
+
+- (NSString *)subscribeURL:(NSURL *)_url forObserver:(NSURL *)_callback
+  type:(NSString *)_type delay:(NSTimeInterval)_delay
+  lifetime:(NSTimeInterval)_lifetime
+{
+  /* subscribe httpu://127.0.0.1:14970/ for 3600s (type update, delay 30s) */
+  SoSubscription *s;
+  NSString *sid;
+  
+  if (_lifetime == 0.0) _lifetime = defaultLifeTime;
+  sid = [self nextSubscriptionID];
+  
+  if (debugOn) {
+    [self debugWithFormat:@"subscribe url %@", _url];
+    [self debugWithFormat:@"  observer:   %@", _callback];
+    [self debugWithFormat:@"  type:       %@", _type];
+    [self debugWithFormat:@"  delay:      %i", (int)_delay];
+    [self debugWithFormat:@"SID:          %@", sid];
+  }
+  
+  s = [[SoSubscription alloc] initWithID:sid 
+                              url:_url observer:_callback type:_type
+                              delay:_delay lifetime:_lifetime];
+  [self->idToSubscription setObject:s forKey:sid];
+  [s autorelease];
+  
+  [self debugWithFormat:@"expires: %@", [s expirationDate]];
+
+  if (s != nil && self->timer == nil) {
+    self->timer = [[NSTimer scheduledTimerWithTimeInterval:expirationInterval
+                            target:self 
+                            selector:@selector(performExpirationCheck:)
+                            userInfo:nil
+                            repeats:YES]
+                            retain];
+  }
+  
+  return [s subscriptionID];
+}
+
+- (NSString *)renewSubscription:(NSString *)_sid onURL:(NSURL *)_url {
+  SoSubscription *s;
+  
+  if (debugOn)
+    [self debugWithFormat:@"renew subscription %@, url: %@", _sid, _url];
+  
+  if ((s = [self->idToSubscription objectForKey:_sid]) == nil) {
+    [self logWithFormat:
+            @"attempt to renew non-existing subscription '%@'", _sid];
+    return nil;
+  }
+  
+  if (![s isValidForURL:_url]) {
+    [self logWithFormat:
+            @"mismatch between subscription-id and subscribed resource"];
+    return nil;
+  }
+  
+  if (![s renewSubscription])
+    return _sid;
+  
+  return _sid;
+}
+
+- (BOOL)unsubscribeID:(NSString *)_sid onURL:(NSURL *)_url {
+  SoSubscription *s;
+  
+  if (_sid == nil) return NO;
+  if (_url == nil) return NO;
+
+  if ((s = [self->idToSubscription objectForKey:_sid]) == nil) {
+    [self debugWithFormat:@"no subscription with id '%@'", _sid];
+    return NO;
+  }
+  if (![s isValidForURL:_url]) {
+    [self logWithFormat:
+            @"mismatch between subscription-id and subscribed resource"];
+    return NO;
+  }
+  
+  [self->idToSubscription removeObjectForKey:_sid];
+  [self debugWithFormat:@"canceled subscription '%@'", _sid];
+  return YES;
+}
+
+- (id)pollSubscriptions:(NSArray *)_sids onURL:(NSURL *)_url {
+  NSEnumerator   *e;
+  NSMutableArray *pending  = nil;
+  NSMutableArray *inactive = nil;
+  NSString       *sid;
+  
+  e = [_sids objectEnumerator];
+  while ((sid = [e nextObject])) {
+    SoSubscription *s;
+    
+    if ((s = [self->idToSubscription objectForKey:sid]) == nil) {
+      [self debugWithFormat:@"no subscription with id '%@'", sid];
+      continue;
+    }
+    if (![s isValidForURL:_url]) {
+      [self debugWithFormat:@"subscription '%@' is not valid for given URL", 
+              sid];
+      continue;
+    }
+    
+    [s renewSubscription]; /* renew subscription on access ... */
+    
+    if ([s hasEventsPending]) {
+      [self debugWithFormat:@"events pending on sid '%@' ...", sid];
+      [s resetEvents];
+      if (pending == nil) pending = [[NSMutableArray alloc] init];
+      [pending addObject:sid];
+    }
+    else {
+      [self debugWithFormat:@"no events pending on sid '%@' ...", sid];
+      if (inactive == nil) inactive = [[NSMutableArray alloc] init];
+      [inactive addObject:sid];
+    }
+  }
+  
+  if (pending  == nil) pending  = [NSArray array];
+  if (inactive == nil) inactive = [NSArray array];
+  return [NSDictionary dictionaryWithObjectsAndKeys:
+                         pending,  @"pending",
+                         inactive, @"inactive",
+                         nil];
+}
+
+/* tracking changes */
+
+- (void)trackChangedURL:(NSURL *)_url {
+  [self debugWithFormat:@"url was changed: %@", _url];
+}
+- (void)trackChangedPath:(NSString *)_path {
+  [self debugWithFormat:@"path was changed: %@", _path];
+}
+- (void)trackChangedObject:(id)_object {
+  id url = nil;
+
+  if ((url = [_object baseURLInContext:nil]))
+    url = [NSURL URLWithString:url];
+  
+  if (url) {
+    [self debugWithFormat:@"object with URL was changed: %@", _object];
+    [self trackChangedURL:url];
+  }
+  else
+    [self debugWithFormat:@"object without URL was changed: %@", _object];
+}
+
+- (void)trackChange:(NSNotification *)_notification {
+  id object;
+  
+  if ((object = [_notification object]) == nil) {
+    [self logWithFormat:@"missing changed object in change notification ..."];
+    return;
+  }
+  
+  if ([object isKindOfClass:[NSURL class]])
+    [self trackChangedURL:object];
+  else if ([object isKindOfClass:[NSString class]])
+    [self trackChangedPath:object];
+  else
+    [self trackChangedObject:object];
+}
+
+/* expiration check */
+
+- (void)performExpirationCheck:(NSTimer *)_timer {
+  NSAutoreleasePool *pool;
+  NSArray        *subs;
+  NSEnumerator   *e;
+  SoSubscription *s;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  /* scan for expired subscriptions */
+  
+  subs = [[self->idToSubscription allValues] shallowCopy];
+  if (debugOn) {
+    [self debugWithFormat:@"perform expiration check (%i subscriptions) ...",
+            [subs count]];
+  }
+  
+  e = [subs objectEnumerator];
+  while ((s = [e nextObject])) {
+    if ([s isExpired]) {
+      if (debugOn)
+        [self debugWithFormat:@"  expired: %@", [s subscriptionID]];
+      [self->idToSubscription removeObjectForKey:[s subscriptionID]];
+    }
+  }
+  
+  /* remove timer if we have no subscriptions ... */
+  
+  if ([self->idToSubscription count] == 0) {
+    [self debugWithFormat:@"  no subscriptions left, removing timer .."];
+    [self->timer invalidate];
+    [self->timer release]; self->timer = nil;
+  }
+  
+  [pool release];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* SoSubscriptionManager */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoWebDAVRenderer.h b/skyrix-sope/NGObjWeb/WebDAV/SoWebDAVRenderer.h
new file mode 100644 (file)
index 0000000..d234a96
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SoObjects_SoWebDAVRenderer_H__
+#define __SoObjects_SoWebDAVRenderer_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoWebDAVRenderer
+  
+  An object which can render DAV responses of all kinds.
+*/
+
+@class NSException;
+@class WOContext;
+
+@interface SoWebDAVRenderer : NSObject
+{
+}
+
++ (id)sharedRenderer;
+
+/* master renderer */
+
+- (NSException *)renderObject:(id)_object inContext:(WOContext *)_ctx;
+- (BOOL)canRenderObject:(id)_object inContext:(WOContext *)_ctx;
+
+/* render individual response types, auto-selected by renderObject:inContext: */
+
+- (BOOL)renderSearchResult:(id)_object    inContext:(WOContext *)_ctx;
+- (BOOL)renderLockToken:(id)_object       inContext:(WOContext *)_ctx;
+- (BOOL)renderOptions:(id)_object         inContext:(WOContext *)_ctx;
+- (BOOL)renderSubscription:(id)_object    inContext:(WOContext *)_ctx;
+- (BOOL)renderPropPatchResult:(id)_object inContext:(WOContext *)_ctx;
+- (BOOL)renderDeleteResult:(id)_object    inContext:(WOContext *)_ctx;
+- (BOOL)renderUploadResult:(id)_object    inContext:(WOContext *)_ctx;
+- (BOOL)renderPollResult:(id)_object      inContext:(WOContext *)_ctx;
+- (BOOL)renderMkColResult:(id)_object     inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoWebDAVRenderer_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoWebDAVRenderer.m b/skyrix-sope/NGObjWeb/WebDAV/SoWebDAVRenderer.m
new file mode 100644 (file)
index 0000000..e78060b
--- /dev/null
@@ -0,0 +1,1087 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoWebDAVRenderer.h"
+#include "SoWebDAVValue.h"
+#include "SoObject+SoDAV.h"
+#include "EOFetchSpecification+SoDAV.h"
+#include "NSException+HTTP.h"
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOElement.h>
+#include <SaxObjC/XMLNamespaces.h>
+#include <NGExtensions/NSString+Ext.h>
+#include "common.h"
+
+/*
+  What HotMail uses for responses:
+    <?xml version="1.0" encoding="Windows-1252"?>
+    Headers:
+      Server:              Microsoft-IIS/5.0
+      X-Timestamp:         folders=1035823428, ACTIVE=1035813212
+      Client-Response-Num: 1
+      Client-Date:         <date>
+      Expires:             ...
+      P3P:                 BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo
+*/
+
+#define XMLNS_INTTASK \
+@"{http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-C000-000000000046}/}"
+
+@interface SoWebDAVRenderer(Privates)
+- (BOOL)renderStatusResult:(id)_object withDefaultStatus:(int)_defStatus
+  inContext:(WOContext *)_ctx; 
+@end
+
+@implementation SoWebDAVRenderer
+
+static NSDictionary *predefinedNamespacePrefixes = nil;
+static NSTimeZone   *gmt         = nil;
+static BOOL         debugOn      = NO;
+static BOOL         formatOutput = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  if (gmt == nil) 
+    gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+
+  if (predefinedNamespacePrefixes == nil) {
+    predefinedNamespacePrefixes = 
+      [[ud objectForKey:@"SoPreferredNamespacePrefixes"] copy];
+  }
+  formatOutput = [ud boolForKey:@"SoWebDAVFormatOutput"];
+  
+  if ((debugOn = [ud boolForKey:@"SoRendererDebugEnabled"]))
+    NSLog(@"enabled debugging in SoWebDAVRenderer (SoRendererDebugEnabled)");
+}
+
++ (id)sharedRenderer {
+  static SoWebDAVRenderer *r = nil; // THREAD
+  if (r == nil) r = [[SoWebDAVRenderer alloc] init];
+  return r;
+}
+
+- (NSString *)preferredPrefixForNamespace:(NSString *)_uri {
+  return [predefinedNamespacePrefixes objectForKey:_uri];
+}
+
+/* key render entry-point */
+
+- (void)_fixupResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  NSDate   *now;
+  NSString *nowHttpString;
+  id tmp;
+  
+  if ((tmp = [_r headerForKey:@"server"]) == nil) {
+    // TODO: add application name as primary name
+    [_r setHeader:@"SOPE 4.2/WebDAV" forKey:@"server"];
+  }
+  
+  [_r setHeader:@"close" forKey:@"connection"];
+  [_r setHeader:@"DAV"   forKey:@"Ms-Author-Via"];
+  
+  // what program uses that header ?
+  [_r setHeader:@"200 No error" forKey:@"X-Dav-Error"];
+
+  if ((tmp = [_r headerForKey:@"content-type"]) == nil)
+    [_r setHeader:@"text/xml" forKey:@"content-type"];
+    
+  now = [NSDate date];
+  nowHttpString = [now descriptionWithCalendarFormat:
+                        @"%a, %d %b %Y %H:%M:%S GMT"
+                      timeZone:gmt
+                      locale:nil];
+    
+  if ((tmp = [_r headerForKey:@"date"]) == nil)
+    [_r setHeader:nowHttpString forKey:@"date"];
+
+#if 0 /* currently none of the clients allows zipping, retry later ... */
+  /* try zipping */
+  if ([_r shouldZipResponseToRequest:nil]) {
+    [self logWithFormat:@"zipping DAV result ..."];
+    [_r zipResponse];
+  }
+#endif
+}
+
+- (NSString *)mimeTypeForData:(NSData *)_data inContext:(WOContext *)_ctx {
+  /* should check extension for MIME type */
+  return @"application/octet-stream";
+}
+- (NSString *)mimeTypeForString:(NSString *)_str inContext:(WOContext *)_ctx {
+  /* should check extension for MIME type */
+
+  if ([_str hasPrefix:@"<?xml"])
+    return @"text/xml; charset=\"utf-8\"";
+  if ([_str hasPrefix:@"<html"])
+    return @"text/html; charset=\"utf-8\"";
+  
+  return @"text/plain; charset=\"utf-8\"";
+}
+
+- (BOOL)renderObjectBodyResult:(id)_object inContext:(WOContext *)_ctx 
+  onlyHead:(BOOL)_onlyHead
+{
+  WOResponse *r = [_ctx response];
+  NSString *tmp;
+  
+  /*
+    TODO: implement proper etag support. This probably implies that we need
+          to pass in some structure or store the etag in the context?
+         We cannot use davEntityTag on the input parameter, since this is
+         usually the plain object.
+  */
+  tmp = @"0"; // fallback, cannot use the thing above
+  [r setHeader:tmp forKey:@"ETag"]; // required for WebFolder PUTs
+  
+  if ([_object isKindOfClass:[NSData class]]) {
+    [r setHeader:[self mimeTypeForData:_object inContext:_ctx]
+       forKey:@"content-type"];
+    
+    [r setHeader:[NSString stringWithFormat:@"%d", [_object length]]
+       forKey:@"content-length"];
+    if (!_onlyHead) [r setContent:_object];
+    return YES;
+  }
+
+  if ([_object isKindOfClass:[NSString class]]) {
+    NSData *data;
+    
+    [r setHeader:[self mimeTypeForString:_object inContext:_ctx]
+       forKey:@"content-type"];
+    
+    data = [_object dataUsingEncoding:NSUTF8StringEncoding];
+    [r setHeader:[NSString stringWithFormat:@"%d", [data length]]
+       forKey:@"content-length"];
+    [r setContent:data];
+    return YES;
+  }
+  
+  if ([_object respondsToSelector:@selector(appendToResponse:inContext:)]) {
+    unsigned len;
+    NSData   *data;
+    
+    [_object appendToResponse:r inContext:_ctx];
+    
+    data = [r content];
+    if ([[r headerForKey:@"content-type"] length] == 0) {
+      [r setHeader:[self mimeTypeForData:data inContext:_ctx]
+         forKey:@"content-type"];
+    }
+    len = [data length];
+    if (_onlyHead) [r setContent:nil];
+    data = nil;
+    [r setHeader:[NSString stringWithFormat:@"%d", len]
+       forKey:@"content-length"];
+    return YES;
+  }
+  
+  [self logWithFormat:@"ERROR: don't know how to render: %@", _object];
+  return NO;
+}
+
+- (NSException *)renderObject:(id)_object inContext:(WOContext *)_ctx {
+  NSString *m;
+  unichar  c1;
+  BOOL ok;
+  
+  if ([_object isKindOfClass:[WOResponse class]]) {
+    if (_object != [_ctx response]) {
+      [self logWithFormat:@"response mismatch"];
+      return [NSException exceptionWithHTTPStatus:500 /* internal error */];
+    }
+    [self _fixupResponse:_object inContext:_ctx];
+    return nil;
+  }
+  
+  m = [[_ctx request] method];
+  if ([m length] == 0) {
+    return [NSException exceptionWithHTTPStatus:400 /* bad request */
+                       reason:@"missing method name!"];
+  }
+  c1 = [m characterAtIndex:0];
+
+  ok = NO;
+  switch (c1) {
+  case 'B':
+    if ([m isEqualToString:@"BPROPFIND"])
+      ok = [self renderSearchResult:_object inContext:_ctx];
+    break;
+  case 'C':
+    if ([m isEqualToString:@"COPY"]) {
+      ok = [self renderStatusResult:_object 
+                withDefaultStatus:201 /* Created */
+                inContext:_ctx];
+    }
+    break;
+  case 'D':
+    if ([m isEqualToString:@"DELETE"])
+      ok = [self renderDeleteResult:_object inContext:_ctx];
+    break;
+  case 'G':
+    if ([m isEqualToString:@"GET"])
+      ok = [self renderObjectBodyResult:_object inContext:_ctx onlyHead:NO];
+    break;
+  case 'H':
+    if ([m isEqualToString:@"HEAD"])
+      ok = [self renderObjectBodyResult:_object inContext:_ctx onlyHead:YES];
+    break;
+  case 'L':
+    if ([m isEqualToString:@"LOCK"])
+      ok = [self renderLockToken:_object inContext:_ctx];
+    break;
+  case 'M':
+    if ([m isEqualToString:@"MKCOL"])
+      ok = [self renderMkColResult:_object inContext:_ctx];
+    else if ([m isEqualToString:@"MOVE"]) {
+      ok = [self renderStatusResult:_object 
+                withDefaultStatus:201 /* Created */
+                inContext:_ctx];
+    }
+    break;
+  case 'O':
+    if ([m isEqualToString:@"OPTIONS"])
+      ok = [self renderOptions:_object inContext:_ctx];
+    break;
+  case 'P':
+    if ([m isEqualToString:@"PUT"])
+      ok = [self renderUploadResult:_object inContext:_ctx];
+    else if ([m isEqualToString:@"PROPFIND"])
+      ok = [self renderSearchResult:_object inContext:_ctx];
+    else if ([m isEqualToString:@"PROPPATCH"])
+      ok = [self renderPropPatchResult:_object inContext:_ctx];
+    else if ([m isEqualToString:@"POLL"])
+      ok = [self renderPollResult:_object inContext:_ctx];
+    break;
+  case 'S':
+    if ([m isEqualToString:@"SEARCH"])
+      ok = [self renderSearchResult:_object inContext:_ctx];
+    else if ([m isEqualToString:@"SUBSCRIBE"])
+      ok = [self renderSubscription:_object inContext:_ctx];
+    break;
+    
+  default:
+    ok = NO;
+    break;
+  }
+  
+  if (ok) [self _fixupResponse:[_ctx response] inContext:_ctx];
+  return ok
+    ? nil
+    : [NSException exceptionWithHTTPStatus:500 /* server error */];
+}
+
+- (BOOL)canRenderObject:(id)_object inContext:(WOContext *)_ctx {
+  if ([_object isKindOfClass:[NSException class]])
+    return NO;
+  return YES;
+}
+
+- (NSString *)stringForValue:(id)_value ofProperty:(NSString *)_prop 
+  prefixes:(NSDictionary *)_prefixes
+{
+  /* seems like this is the default date value */
+  NSString *datefmt = @"%a, %d %b %Y %H:%M:%S GMT";
+  
+  if (_value == nil)
+    return nil;
+  if (![_value isNotNull])
+    return nil;
+  
+  /* special processing for some properties */
+  
+  if ([_prop isEqualToString:@"{DAV:}resourcetype"]) {
+    _value = [_value stringValue];
+    if ([_value length] == 0) return nil;
+    
+    return [NSString stringWithFormat:@"<%@:%@/>",
+                      [_prefixes objectForKey:@"DAV:"], _value];
+  }
+  else if ([_prop isEqualToString:@"{DAV:}creationdate"])
+    datefmt = @"%Y-%m-%dT%H:%M:%S%zZ";
+
+  /* special processing for some properties  */
+  
+  // TODO: move this to user-level code ! 
+  //   HH: what is that ? it does not do anything anyway ?
+  if ([_prop hasPrefix:XMLNS_INTTASK]) {
+    if ([_prop hasSuffix:@"}0x00008102"]) {
+    }
+  }
+  
+  /* special processing for some classes */
+  
+  if ([_value isKindOfClass:[NSString class]])
+    return [_value stringByEscapingXMLString];
+  
+  if ([_value isKindOfClass:[NSNumber class]])
+    return [_value stringValue];
+  
+  if ([_value isKindOfClass:[NSDate class]]) {
+    return [_value descriptionWithCalendarFormat:datefmt
+                  timeZone:gmt
+                  locale:nil];
+  }
+  
+  return [[_value stringValue] stringByEscapingXMLString];
+}
+
+- (NSString *)baseURLForContext:(WOContext *)_ctx {
+  /*
+    Note: Evolution doesn't correctly transfer the "Host:" header, it
+    misses the port argument :-(
+  */
+  NSString  *baseURL;
+  WORequest *rq;
+  NSString  *hostport;
+  id tmp;
+  
+  rq = [_ctx request];
+  
+  if ((tmp = [rq headerForKey:@"x-webobjects-server-name"])) {
+    hostport = tmp;
+    if ((tmp = [rq headerForKey:@"x-webobjects-server-port"]))
+      hostport = [NSString stringWithFormat:@"%@:%@", hostport, tmp];
+  }
+  else if ((tmp = [rq headerForKey:@"host"]))
+    hostport = tmp;
+  else
+    hostport = [[NSHost currentHost] name];
+  
+  baseURL = [NSString stringWithFormat:@"http://%@%@", hostport, [rq uri]];
+  return baseURL;
+}
+
+- (NSString *)tidyHref:(id)href baseURL:(id)baseURL {
+  href = [href stringValue];
+  if (href == nil) {
+    if (debugOn) {
+      [self logWithFormat:
+              @"WARNING: using baseURL for href, "
+              @"entry did not provide a URL: %@", baseURL];
+    }
+    href = [baseURL stringValue];
+  }
+  else if (![href isAbsoluteURL]) { // maybe only check for http[s]:// ?
+    // TODO: use "real" URL processing
+    href = [baseURL stringByAppendingPathComponent:href];
+  }
+  return href;
+}
+- (id)tidyStatus:(id)stat {
+  if (stat == nil)
+    stat = @"HTTP/1.1 200 OK";
+  else if ([stat isKindOfClass:[NSException class]]) {
+    int i;
+    
+    if ((i = [stat httpStatus]) > 0)
+      stat = [NSString stringWithFormat:@"HTTP/1.1 %i %@", i, [stat reason]];
+    else {
+      stat = [(NSException *)stat name];
+      stat = [@"HTTP/1.1 500 " stringByAppendingString:stat];
+    }
+  }
+  return stat;
+}
+
+- (void)renderSearchResultEntry:(id)entry inContext:(WOContext *)_ctx 
+  namesOnly:(BOOL)_namesOnly
+  attributes:(NSArray *)_attrs
+  propertyMap:(NSDictionary *)_propMap
+  baseURL:(NSString *)baseURL
+  tagToPrefix:(NSDictionary *)extNameCache
+  nsToPrefix:(NSDictionary *)nsToPrefix
+{
+  /* Note: the entry is an NSArray in case _namesOnly is requested! */
+  // TODO: use -valueForKey: to improve NSNull handling ?
+  WOResponse   *r;
+  NSEnumerator *keys;
+  NSString     *key;
+  id   href = nil;
+  id   stat = nil;
+  BOOL isBrief;
+  
+  r = [_ctx response];
+  isBrief = [[[_ctx request] headerForKey:@"brief"] hasPrefix:@"t"] ? YES : NO;
+  
+  if (debugOn) {
+    [self debugWithFormat:@"    render entry: 0x%08X<%@>%s%s",
+         entry, NSStringFromClass([entry class]),
+         isBrief    ? " brief"      : "",
+         _namesOnly ? " names-only" : ""];
+  }
+
+  /* we do not map these DAV properties because they are very special */
+  if (!_namesOnly) {
+    if ((href = [entry valueForKey:@"{DAV:}href"]) == nil) {
+      if ((key = [_propMap objectForKey:@"{DAV:}href"])) {
+        if ((href = [entry valueForKey:key]) == nil) {
+          if (debugOn) {
+            [self debugWithFormat:
+                 @"WARNING: no value for {DAV:}href key '%@': %@",
+                    key, entry];
+       }
+        }
+      }
+      else if (debugOn) {
+        [self debugWithFormat:
+             @"WARNING: no key for {DAV:}href in property map !"];
+      }
+    }
+    if ((stat = [entry valueForKey:@"{DAV:}status"]) == nil) {
+      if ((key = [_propMap objectForKey:@"{DAV:}status"]))
+        stat = [entry valueForKey:key];
+    }
+
+    /* tidy href */
+    href = [self tidyHref:href baseURL:baseURL];
+    
+    /* tidy status */
+    stat = [self tidyStatus:stat];
+  }
+  else { /* propnames only */
+    href = [baseURL stringValue];
+    stat = @"HTTP/1.1 200 OK";
+  }
+  
+  if (debugOn) {
+    [self debugWithFormat:@"    status: %@", stat];
+    [self debugWithFormat:@"    href:   %@", href];
+  }
+  
+  /* generate */
+  [r appendContentString:@"<D:response>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  
+  if (href) {
+    [r appendContentString:@"<D:href>"];
+    /*
+      TODO: need to find out what is appropriate! While Cadaver and ZideLook
+            (both Neon+Expat) seem to be fine with this, OSX reports invalid
+            characters (displayed as '#') for umlauts.
+            It might be that we are supposed to use *URL* escaping in any 
+            case! (notably entering a directory with an umlaut doesn't seem
+            to work in Cadaver either because of a URL mismatch!)
+      Note: we cannot apply URL encoding in this place, because it will encode
+            all URL special chars ... where are URLs escaped?
+      Note: we always need to apply XML escaping (even though higher-level
+            characters might be already encoded)!
+    */
+    [r appendContentXMLString:[href stringValue]];
+    [r appendContentString:@"</D:href>"];
+    if (formatOutput) [r appendContentCharacter:'\n'];
+  }
+      
+  [r appendContentString:@"<D:propstat>"];
+  if (stat) {
+    [r appendContentString:@"<D:status>"];
+    [r appendContentXMLString:[stat stringValue]];
+    [r appendContentString:@"</D:status>"];
+  }
+  
+  [r appendContentString:@"<D:prop>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  
+  /* now the properties */
+  
+  keys = [_attrs objectEnumerator] ;
+  while ((key = [keys nextObject])) {
+    NSString *extName;
+    NSString *okey;
+    id value;
+    
+#if 0 /* this filter probably doesn't make sense ? */
+    /* filter out predefined props */
+    if ([key isEqualToString:@"{DAV:}href"])   continue;
+    if ([key isEqualToString:@"{DAV:}status"]) continue;
+#endif
+    
+    extName = [extNameCache objectForKey:key];
+    
+    if (_namesOnly) {
+      [r appendContentCharacter:'<'];
+      [r appendContentString:extName];
+      [r appendContentString:@"/>"];
+      if (formatOutput) [r appendContentCharacter:'\n'];
+      continue;
+    }
+    
+    // TODO: we should support property status (eg encode 404 on NSNull)
+      
+    if ((okey = [_propMap objectForKey:key]) == nil)
+      okey = key;
+      
+    if ([key isEqualToString:@"{DAV:}href"])
+      value = href;
+    else
+      value = [entry valueForKey:okey];
+    
+    if ([value isNotNull]) {
+      NSString *s;
+       
+      if ([value isKindOfClass:[SoWebDAVValue class]]) {
+         s = [value stringForTag:key rawName:extName
+                    inContext:_ctx prefixes:nsToPrefix];
+         [r appendContentString:s];
+      }
+      else {
+         [r appendContentCharacter:'<'];
+         [r appendContentString:extName];
+         [r appendContentCharacter:'>'];
+          
+         s = [self stringForValue:value ofProperty:key prefixes:nsToPrefix];
+         [r appendContentString:s];
+          
+         [r appendContentString:@"</"];
+         [r appendContentString:extName];
+         [r appendContentString:@">"];
+          if (formatOutput) [r appendContentCharacter:'\n'];
+      }
+      continue;
+    }
+    
+    if (!isBrief) { 
+      /* 
+         Not sure whether this is correct, do we need to encode null attrs?
+         Seems like Evo gets confused on that.
+         TODO: probably add a 404 property status for that!
+      */
+      [r appendContentCharacter:'<'];
+      [r appendContentString:extName];
+      [r appendContentString:@"/>"];
+      if (formatOutput) [r appendContentCharacter:'\n'];
+    }
+  }
+      
+  [r appendContentString:@"</D:prop></D:propstat></D:response>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+}
+
+- (void)buildPrefixMapForAttributes:(NSArray *)_attrs
+  tagToExtName:(NSMutableDictionary *)_tagToExtName
+  nsToPrefix:(NSMutableDictionary *)_nsToPrefix
+{
+  unichar autoPrefix[2] = { ('a' - 1), 0 };
+  NSEnumerator *e;
+  NSString     *fqn;
+  
+  e = [_attrs objectEnumerator];
+  while ((fqn = [e nextObject])) {
+    NSString *ns, *localName, *prefix, *extName;
+    
+    if ([_tagToExtName objectForKey:fqn]) continue;
+    
+    if (![fqn xmlIsFQN]) {
+      /* hm, no namespace given :-(, using DAV */
+      ns        = @"DAV:";
+      localName = fqn;
+    }
+    else {
+      ns        = [fqn xmlNamespaceURI];
+      localName = [fqn xmlLocalName];
+    }
+    
+    if ((prefix = [_nsToPrefix objectForKey:ns]) == nil) {
+      if ((prefix = [self preferredPrefixForNamespace:ns]) == nil) {
+       (autoPrefix[0])++;
+       prefix = [NSString stringWithCharacters:&(autoPrefix[0]) length:1];
+      }
+      [_nsToPrefix setObject:prefix forKey:ns];
+    }
+    
+    extName = [NSString stringWithFormat:@"%@:%@", prefix, localName];
+    [_tagToExtName setObject:extName forKey:fqn];
+  }
+}
+
+- (NSString *)nsDeclsForMap:(NSDictionary *)_nsToPrefix {
+  NSMutableString *ms;
+  NSEnumerator *nse;
+  NSString *ns;
+  
+  ms = [NSMutableString stringWithCapacity:256];
+  nse = [_nsToPrefix keyEnumerator];
+  while ((ns = [nse nextObject])) {
+    [ms appendString:@" xmlns:"];
+    [ms appendString:[_nsToPrefix objectForKey:ns]];
+    [ms appendString:@"=\""];
+    [ms appendString:ns];
+    [ms appendString:@"\""];
+  }
+  return ms;
+}
+
+- (void)renderSearchResult:(id)_entries inContext:(WOContext *)_ctx 
+  namesOnly:(BOOL)_namesOnly
+  attributes:(NSArray *)_attrs
+  propertyMap:(NSDictionary *)_propMap
+{
+  NSMutableDictionary *extNameCache = nil;
+  NSMutableDictionary *nsToPrefix   = nil;
+  NSAutoreleasePool   *pool;
+  WOResponse *r;
+  unsigned   entryCount;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  r = [_ctx response];
+  
+  if (![_entries isKindOfClass:[NSEnumerator class]]) {
+    if ([_entries isKindOfClass:[NSArray class]]) {
+      [self debugWithFormat:@"  render %i entries", [_entries count]];
+      _entries = [_entries objectEnumerator];
+    }
+    else {
+      [self debugWithFormat:@"  render a single object ..."];
+      _entries = [[NSArray arrayWithObject:_entries] objectEnumerator];
+    }
+  }
+  
+  /* collect used namespaces */
+  
+  nsToPrefix = [NSMutableDictionary dictionaryWithCapacity:16];
+  [nsToPrefix setObject:@"D" forKey:XMLNS_WEBDAV];
+  
+  /* 
+     the extNameCache is used to map fully qualified tag names to their
+     prefixed external representation 
+  */
+  extNameCache = [NSMutableDictionary dictionaryWithCapacity:32];
+  
+  // TODO: only walk attrs, if available
+  /*
+    Walk all attributes of all entries to collect names. We might be able
+    to take a look at just the first record if it is guaranteed, that all
+    records have all properties (even if the value is NSNull) ?
+  */
+  [self buildPrefixMapForAttributes:_attrs
+       tagToExtName:extNameCache
+       nsToPrefix:nsToPrefix];
+  
+  /* generate multistatus */
+   
+  [r setStatus:207 /* multistatus */];
+  [r setHeader:@"no-cache" forKey:@"pragma"];
+  [r setHeader:@"no-cache" forKey:@"cache-control"];
+  
+  [r appendContentString:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"];
+  [r appendContentString:@"<D:multistatus"];
+  [r appendContentString:[self nsDeclsForMap:nsToPrefix]];
+  [r appendContentString:@">"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  {
+    NSString *baseURL;
+    NSString *range;
+    id entry;
+    
+    baseURL = [self baseURLForContext:_ctx];
+    [self debugWithFormat:@"  baseURL: %@", baseURL];
+    
+    entryCount = 0; /* Note: this will clash with streamed output later */
+    while ((entry = [_entries nextObject])) {
+      [self renderSearchResultEntry:entry inContext:_ctx
+           namesOnly:_namesOnly attributes:_attrs propertyMap:_propMap
+           baseURL:baseURL tagToPrefix:extNameCache nsToPrefix:nsToPrefix];
+      entryCount++;
+    }
+    [self debugWithFormat:@"  rendered %i entries", entryCount];
+    
+    /*
+      If we got a "rows" range header, we report back the actual rows
+      delivered. Since we do not really support ranges in the moment,
+      we just report all rows ... 
+      TODO: support for row ranges.
+    */
+    if ((range = [[[_ctx request] headerForKey:@"range"] stringValue])) {
+      /* sample: "Content-Range: rows 0-143; total=144" */
+      NSString *v;
+      
+      v = [[NSString alloc] initWithFormat:@"rows 0-%i; total=%i", 
+                              entryCount>0?(entryCount - 1):0, entryCount];
+      [r setHeader:v forKey:@"content-range"];
+      [v release];
+    }
+  }
+  [r appendContentString:@"</D:multistatus>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  
+  [pool release];
+}
+
+- (BOOL)renderSearchResult:(id)_object inContext:(WOContext *)_ctx {
+  EOFetchSpecification *fs;
+  NSDictionary *propMap;
+  
+  if ((fs = [_ctx objectForKey:@"DAVFetchSpecification"]) == nil)
+    return NO;
+  
+  if ((propMap = [_ctx objectForKey:@"DAVPropertyMap"]) == nil)
+    propMap = [_object davAttributeMapInContext:_ctx];
+
+  if (debugOn) {
+    [self debugWithFormat:@"render search result 0x%08X<%@>",
+            _object, NSStringFromClass([_object class])];
+  }
+  
+  [self renderSearchResult:_object inContext:_ctx
+       namesOnly:[fs queryWebDAVPropertyNamesOnly]
+       attributes:[fs selectedWebDAVPropertyNames]
+       propertyMap:propMap];
+  
+  if (debugOn) 
+    [self debugWithFormat:@"finished rendering."];
+  return YES;
+}
+
+- (BOOL)renderLockToken:(id)_object inContext:(WOContext *)_ctx {
+  /* TODO: this is a fake ! */
+  WOResponse *r;
+  
+  if (_object == nil) return NO;
+  
+  r = [_ctx response];
+  
+  [r setStatus:200];
+  [r setContentEncoding:NSUTF8StringEncoding];
+  [r setHeader:@"text/xml; charset=\"utf-8\"" forKey:@"content-type"];
+  [r appendContentString:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"];
+  [r appendContentString:@"<D:prop xmlns:D=\"DAV:\">"];
+  [r appendContentString:@"<D:lockdiscovery>"];
+  [r appendContentString:@"<D:activelock>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  
+  /* this is the href of the lock, not of the locked resource */
+  [r appendContentString:@"<D:locktoken><D:href>"];
+  [r appendContentString:[_object stringValue]];
+  [r appendContentString:@"</D:href></D:locktoken>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  
+  // TODO: locktype,  eg <D:locktype><D:write/></D:locktype>
+  // TODO: lockscope, eg <D:lockscope><D:exclusive/></D:lockscope>
+  // TODO: depth,     eg <D:depth>Infinitiy</D:depth>
+  // TODO: owner,     eg <D:owner><D:href>...</D:href></D:owner>
+  // TODO: timeout,   eg <D:timeout>Second-604800</D:timeout>
+  
+  [r appendContentString:@"</D:activelock>"];
+  [r appendContentString:@"</D:lockdiscovery>"];
+  [r appendContentString:@"</D:prop>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  return YES;
+}
+
+- (BOOL)renderOptions:(id)_object inContext:(WOContext *)_ctx {
+  WOResponse *r = [_ctx response];
+  
+  [r setStatus:200];
+  [r setHeader:@"1,2" forKey:@"DAV"]; // TODO: select protocol level
+  //[r setHeader:@"" forKey:@"Etag"]; 
+  [r setHeader:[_object componentsJoinedByString:@", "] forKey:@"allow"];
+  return YES;
+}
+
+- (BOOL)renderSubscription:(id)_object inContext:(WOContext *)_ctx {
+  // TODO: this is fake, mirrors request
+  WOResponse *r = [_ctx response];
+  WORequest  *rq;
+  NSString   *callback;
+  NSString   *notificationType;
+  NSString   *lifetime;
+  
+  rq                = [_ctx request];
+  callback          = [rq headerForKey:@"call-back"];
+  notificationType  = [rq headerForKey:@"notification-type"];
+  lifetime          = [rq headerForKey:@"subscription-lifetime"];
+  
+  [r setStatus:200];
+  if (notificationType)
+    [r setHeader:notificationType forKey:@"notification-type"];
+  if (lifetime)
+    [r setHeader:lifetime         forKey:@"subscription-lifetime"];
+  if (callback)
+    [r setHeader:callback         forKey:@"callback"];
+  [r setHeader:[self baseURLForContext:_ctx] forKey:@"content-location"];
+  [r setHeader:_object forKey:@"subscription-id"];
+  return YES;
+}
+
+- (BOOL)renderPropPatchResult:(id)_object inContext:(WOContext *)_ctx {
+  NSMutableDictionary *extNameCache = nil;
+  NSMutableDictionary *nsToPrefix   = nil;
+  WOResponse *r = [_ctx response];
+  
+  if (_object == nil) return NO;
+  
+  nsToPrefix = [NSMutableDictionary dictionaryWithCapacity:16];
+  [nsToPrefix setObject:@"D" forKey:XMLNS_WEBDAV];
+  extNameCache = [NSMutableDictionary dictionaryWithCapacity:32];
+  [self buildPrefixMapForAttributes:_object
+       tagToExtName:extNameCache
+       nsToPrefix:nsToPrefix];
+  
+  [r setStatus:207 /* multistatus */];
+  [r appendContentString:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"];
+  [r appendContentString:@"<D:multistatus"];
+  [r appendContentString:[self nsDeclsForMap:nsToPrefix]];
+  [r appendContentString:@">"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  
+  [r appendContentString:@"<D:response>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  [r appendContentString:@"<D:href>"];
+  [r appendContentString:[[_ctx request] uri]];
+  [r appendContentString:@"</D:href>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  [r appendContentString:@"<D:propstat><D:status>HTTP/1.1 200 OK</D:status>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  [r appendContentString:@"<D:prop>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  
+  /* encode properties */
+  {
+    NSEnumerator *e;
+    NSString *tag;
+    
+    e = [_object objectEnumerator];
+    while ((tag = [e nextObject])) {
+      NSString *extName;
+      
+      extName = [extNameCache objectForKey:tag];
+      [r appendContentCharacter:'<'];
+      [r appendContentString:extName];
+      [r appendContentString:@"/>"];
+      if (formatOutput) [r appendContentCharacter:'\n'];
+    }
+  }
+  
+  [r appendContentString:@"</D:prop></D:propstat></D:response>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  [r appendContentString:@"</D:multistatus>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  
+  return YES;
+}
+
+- (BOOL)renderDeleteResult:(id)_object inContext:(WOContext *)_ctx {
+  WOResponse *r = [_ctx response];
+  
+  if (_object == nil || [_object boolValue]) {
+    [r setStatus:204 /* no content */];
+    //[r appendContentString:@"object was deleted."];
+    return YES;
+  }
+  
+  if ([_object isKindOfClass:[NSNumber class]]) {
+    [r setStatus:[_object intValue]];
+    if ([r status] != 204 /* No Content */)
+      [r appendContentString:@"object could not be deleted."];
+  }
+  else {
+    [r setStatus:500 /* server error */];
+    [r appendContentString:@"object could not be deleted. reason: "];
+    [r appendContentHTMLString:[_object stringValue]];
+  }
+  return YES;
+}
+
+- (BOOL)renderStatusResult:(id)_object withDefaultStatus:(int)_defStatus
+  inContext:(WOContext *)_ctx 
+{
+  WOResponse *r = [_ctx response];
+  
+  if (_object == nil) {
+    [r setStatus:_defStatus /* no content */];
+    return YES;
+  }
+  
+  if ([_object isKindOfClass:[NSNumber class]]) {
+    if ([_object intValue] < 100) {
+      [r setStatus:_defStatus /* no content */];
+      return YES;
+    }
+    else {
+      [r setStatus:[_object intValue]];
+    }
+  }
+  else {
+    [r setStatus:_defStatus /* no content */];
+  }
+  return YES;
+}
+- (BOOL)renderUploadResult:(id)_object inContext:(WOContext *)_ctx {
+  WOResponse *r = [_ctx response];
+  
+  if (_object == nil) {
+    [r setStatus:204 /* no content */];
+    return YES;
+  }
+  
+  if ([_object isKindOfClass:[NSNumber class]]) {
+    if ([_object intValue] < 100) {
+      [r setStatus:204 /* no content */];
+      return YES;
+    }
+    
+    [r setStatus:[_object intValue]];
+    if ([_object intValue] >= 300) {
+      [r setHeader:@"text/html" forKey:@"content-type"];
+      [r appendContentString:@"object could not be stored."];
+    }
+    
+    return YES;
+  }
+  
+  [r setStatus:204 /* no content */];
+  return YES;
+}
+
+- (void)renderPollList:(NSArray *)_sids code:(int)_code
+  inContext:(WOContext *)_ctx 
+{
+  WOResponse   *r = [_ctx response];
+  NSEnumerator *e;
+  NSString *sid;
+  NSString *href;
+  
+  if ([_sids count] == 0) return;
+  href = [self baseURLForContext:_ctx];
+
+  [r appendContentString:@"<D:response>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  [r appendContentString:@"<D:href>"];
+  [r appendContentString:href];
+  [r appendContentString:@"</D:href>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  
+  [r appendContentString:@"<D:status>HTTP/1.1 "];
+  if (_code == 200)
+    [r appendContentString:@"200 OK"];
+  else if (_code == 204)
+    [r appendContentString:@"204 No Content"];
+  else {
+    NSString *s;
+    s = [NSString stringWithFormat:@"%i code%i"];
+    [r appendContentString:s];
+  }
+  [r appendContentString:@"</D:status>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  
+  [r appendContentString:@"<E:subscriptionID>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  e = [_sids objectEnumerator];
+  while ((sid = [e nextObject])) {
+    if (formatOutput) [r appendContentString:@"  "];
+    [r appendContentString:@"<li>"];
+    [r appendContentString:sid];
+    [r appendContentString:@"</li>"];
+    if (formatOutput) [r appendContentCharacter:'\n'];
+  }
+  [r appendContentString:@"</E:subscriptionID>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+  [r appendContentString:@"</D:response>"];
+  if (formatOutput) [r appendContentCharacter:'\n'];
+}
+
+- (BOOL)renderPollResult:(id)_object inContext:(WOContext *)_ctx {
+  WOResponse *r = [_ctx response];
+  
+  if (_object == nil) {
+    [r setStatus:204 /* no content */];
+    return YES;
+  }
+
+  if ([_object isKindOfClass:[NSDictionary class]]) {
+    NSArray  *pending, *inactive;
+    
+    pending  = [_object objectForKey:@"pending"];
+    inactive = [_object objectForKey:@"inactive"];
+    
+    [r setStatus:207 /* Multi-Status */];
+    [r setHeader:@"text/xml" forKey:@"content-type"];
+
+    [r appendContentString:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"];
+    [r appendContentString:@"<D:multistatus "];
+    [r appendContentString:@" xmlns:D=\"DAV:\""];
+    [r appendContentString:
+         @" xmlns:E=\"http://schemas.microsoft.com/Exchange/\""];
+    [r appendContentString:@">"];
+    if (formatOutput) [r appendContentCharacter:'\n'];
+    
+    [self renderPollList:pending  code:200 inContext:_ctx];
+    [self renderPollList:inactive code:204 inContext:_ctx];
+    
+    [r appendContentString:@"</D:multistatus>"];
+    if (formatOutput) [r appendContentCharacter:'\n'];
+  }
+  else if ([_object isKindOfClass:[NSArray class]]) {
+    [r setStatus:207 /* Multi-Status */];
+    [r setHeader:@"text/xml" forKey:@"content-type"];
+
+    [r appendContentString:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"];
+    [r appendContentString:@"<D:multistatus "];
+    [r appendContentString:@" xmlns:D=\"DAV:\""];
+    [r appendContentString:
+         @" xmlns:E=\"http://schemas.microsoft.com/Exchange/\""];
+    [r appendContentString:@">"];
+    if (formatOutput) [r appendContentCharacter:'\n'];
+    
+    [self renderPollList:_object code:200 inContext:_ctx];
+    
+    [r appendContentString:@"</D:multistatus>"];
+    if (formatOutput) [r appendContentCharacter:'\n'];
+  }
+  else {
+    [r setStatus:204 /* no content */];
+    //[r appendContentString:@"object was stored."];
+  }
+  return YES;
+}
+
+- (BOOL)renderMkColResult:(id)_object inContext:(WOContext *)_ctx {
+  WOResponse *r = [_ctx response];
+  
+  if (_object == nil || [_object boolValue]) {
+    [r setStatus:201 /* Created */];
+    return YES;
+  }
+  
+  if ([_object isKindOfClass:[NSNumber class]]) {
+    [r setStatus:[_object intValue]];
+    [r appendContentString:@"object could not be created."];
+  }
+  else {
+    [r setStatus:500 /* server error */];
+    [r appendContentString:@"object could not be deleted. reason: "];
+    [r appendContentHTMLString:[_object stringValue]];
+  }
+  return YES;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
+@end /* SoWebDAVRenderer */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoWebDAVValue.h b/skyrix-sope/NGObjWeb/WebDAV/SoWebDAVValue.h
new file mode 100644 (file)
index 0000000..2cea239
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __WebDAV_SoWebDAVValue_H__
+#define __WebDAV_SoWebDAVValue_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  SoWebDAVValue
+  
+  This class can be used for keeping together all information of complex
+  WebDAV values (eg namespaces of values, nested XML tags, etc).
+  
+  The default implementation allows you to associated attributes with the
+  generated property tag (eg value typing information).
+*/
+
+@class NSString, NSDictionary;
+
+@interface SoWebDAVValue : NSObject
+{
+  NSDictionary *attributes;
+  id object;
+}
+
++ (id)valueForObject:(id)_obj attributes:(NSDictionary *)_attrs;
+- (id)initWithObject:(id)_obj attributes:(NSDictionary *)_attrs;
+
+- (NSString *)stringForTag:(NSString *)_key rawName:(NSString *)_extName
+  inContext:(id)_ctx
+  prefixes:(NSDictionary *)_prefixes;
+
+@end
+
+#endif /* __WebDAV_SoWebDAVValue_H__ */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/SoWebDAVValue.m b/skyrix-sope/NGObjWeb/WebDAV/SoWebDAVValue.m
new file mode 100644 (file)
index 0000000..694c551
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoWebDAVValue.h"
+#include "common.h"
+
+@implementation SoWebDAVValue
+
++ (id)valueForObject:(id)_obj attributes:(NSDictionary *)_attrs {
+  return [[[self alloc] initWithObject:_obj attributes:_attrs] autorelease];
+}
+- (id)initWithObject:(id)_obj attributes:(NSDictionary *)_attrs {
+  if ((self = [super init])) {
+    self->object     = [_obj   retain];
+    self->attributes = [_attrs copy];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithObject:nil attributes:nil];
+}
+
+- (void)dealloc {
+  [self->object     release];
+  [self->attributes release];
+  [super dealloc];
+}
+
+- (NSString *)stringForTag:(NSString *)_key rawName:(NSString *)_extName
+  inContext:(id)_ctx
+  prefixes:(NSDictionary *)_prefixes
+{
+  NSMutableString *ms;
+  NSMutableDictionary *encNS = nil;
+  
+  ms = [NSMutableString stringWithCapacity:16];
+  
+  [ms appendString:@"<"];
+  [ms appendString:_extName];
+  
+  /* process attributes */
+  if (self->attributes) {
+    NSEnumerator *keys;
+    NSString *key;
+    
+    keys = [self->attributes keyEnumerator];
+    while ((key = [keys nextObject])) {
+      NSString *vs;
+      
+      vs = [[self->attributes objectForKey:key] stringValue];
+      
+      if ([key xmlIsFQN]) {
+       NSString *ns, *a, *p;
+       
+       if (encNS == nil)
+         encNS = [NSMutableDictionary dictionaryWithCapacity:16];
+       
+       a  = [key xmlLocalName];
+       ns = [key xmlNamespaceURI];
+       
+       if ((p = [encNS objectForKey:ns]) == nil) {
+         if ((p = [_prefixes objectForKey:ns]) == nil) {
+           p = [NSString stringWithFormat:@"a%i", [encNS count]];
+           [encNS setObject:p forKey:ns];
+           [ms appendString:@" xmlns:"];
+           [ms appendString:p];
+           [ms appendString:@"=\""];
+           [ms appendString:ns];
+           [ms appendString:@"\""];
+         }
+         else
+           [encNS setObject:p forKey:ns];
+       }
+       
+       [ms appendString:@" "];
+       [ms appendString:p];
+       [ms appendString:@":"];
+       [ms appendString:a];
+      }
+      else {
+       [ms appendString:@" "];
+       [ms appendString:key];
+      }
+      
+      [ms appendString:@"=\""];
+      [ms appendString:vs];
+      [ms appendString:@"\""];
+    }
+  }
+  if (self->object == nil) {
+    [ms appendString:@"/>"];
+    return ms;
+  }
+  
+  [ms appendString:@">"];
+  
+  //s = [self stringForValue:value ofProperty:key prefixes:nsToPrefix];
+  [ms appendString:[self->object stringValue]];
+  
+  [ms appendString:@"</"];
+  [ms appendString:_extName];
+  [ms appendString:@">"];
+  return ms;
+}
+
+/* description */
+
+- (NSString *)propertyListStringWithLocale:(id)_locale indent:(unsigned)_i {
+  return [self->object propertyListStringWithLocale:_locale indent:_i];
+}
+
+- (NSString *)stringValue {
+  return [self->object stringValue];
+}
+
+@end /* SoWebDAVValue */
diff --git a/skyrix-sope/NGObjWeb/WebDAV/TODO b/skyrix-sope/NGObjWeb/WebDAV/TODO
new file mode 100644 (file)
index 0000000..394698f
--- /dev/null
@@ -0,0 +1,31 @@
+# $Id: TODO,v 1.1 2003/11/15 00:27:45 helge Exp $
+
+SOPE WebDAV Todos
+=================
+
+- implement move
+
+- Proper handling of "If:" headers, WebDAV RFC 2518, 9.4.2
+  ---
+  If: <http://www.foo.bar/resource1> (<locktoken:a-write-lock-token>
+   [W/"A weak ETag"]) (["strong ETag"])
+   <http://www.bar.bar/random>(["another strong ETag"])
+  ---
+  Syntax seems to be:
+
+   <URL> (lock [etag]) ([etag2])
+
+  a url embedded in <>, then a set of () surrounded options which contain
+  some XML and optionally an etag.
+
+  Eg this is submitted by Cadaver for locking requests.
+
+- reverse mapping of keys->DAV names
+  - schema queries (propnames)          (partly done)
+  - queries on all attributes (propget) (partly done)
+
+- SUBSCRIBE/UNSUBSCRIBE (partly done in the meantime)
+  - subscription manager
+  - httpu:// implementation for WOHTTPConnection
+
+- DASL searching
diff --git a/skyrix-sope/NGObjWeb/WebDAV/WebDAV-Info.plist b/skyrix-sope/NGObjWeb/WebDAV/WebDAV-Info.plist
new file mode 100644 (file)
index 0000000..8e1e6d2
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>WebDAV</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.WebDAV</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/NGObjWeb/_WOStringTable.h b/skyrix-sope/NGObjWeb/_WOStringTable.h
new file mode 100644 (file)
index 0000000..0456ca5
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOStringTable_H__
+#define __WOStringTable_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSDictionary, NSDate;
+
+@interface _WOStringTable : NSObject
+{
+@protected
+  NSString     *path;
+  NSDictionary *data;
+  NSDate       *lastRead;
+}
+
+- (id)initWithPath:(NSString *)_path;
+
+- (NSString *)stringForKey:(NSString *)_key withDefaultValue:(NSString *)_def;
+
+@end
+
+#endif /* __WOStringTable_H__ */
diff --git a/skyrix-sope/NGObjWeb/_WOStringTable.m b/skyrix-sope/NGObjWeb/_WOStringTable.m
new file mode 100644 (file)
index 0000000..a22203c
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "_WOStringTable.h"
+#include "common.h"
+
+@implementation _WOStringTable
+
+- (id)initWithPath:(NSString *)_path {
+  if ((self = [super init])) {
+    self->path = [_path copyWithZone:[self zone]];
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithPath:nil];
+}
+
+- (void)dealloc {
+  [self->path     release];
+  [self->lastRead release];
+  [self->data     release];
+  [super dealloc];
+}
+
+/* loading */
+
+- (NSException *)_handlePropertyListParseException:(NSException *)_exception {
+  [self logWithFormat:@"could not load strings file file '%@': %@",
+          self->path, _exception];
+  self->data = nil;
+  return nil;
+}
+
+- (void)checkState {
+  NSString     *tmp;
+  NSDictionary *plist;
+  
+  if (self->data != nil)
+    return;
+
+#if !LIB_FOUNDATION_LIBRARY /* potentially effects OGo ;-) */
+  /*
+    For WO4.5 compatibility, we need first to try to open .strings file as a 
+    dictionary
+    Dictionary must be either in UTF-8 or UTF-16 encoding.
+    If we don't do that, then a dict in UTF-8 encoding will be opened as a 
+    dict using defaultCString encoding
+  */
+  plist = [NSDictionary dictionaryWithContentsOfFile:self->path];
+  if (plist != nil) {
+    self->data = [plist copy];
+    return;
+  }
+#endif
+  
+  /* If file was not a dictionary, then it's a standard strings file */
+  
+  if ((tmp = [NSString stringWithContentsOfFile:self->path]) == nil) {
+    self->data = nil;
+    return;
+  }
+  
+  NS_DURING {
+    if ((plist = [tmp propertyListFromStringsFileFormat]) == nil) {
+      NSLog(@"%s: could not load strings file '%@'",
+            __PRETTY_FUNCTION__,
+            self->path);
+    }
+    self->data = [plist copy];
+  }
+  NS_HANDLER
+    [[self _handlePropertyListParseException:localException] raise];
+  NS_ENDHANDLER;
+}
+
+/* access */
+
+- (NSString *)stringForKey:(NSString *)_key withDefaultValue:(NSString *)_def {
+  NSString *value;
+  
+  [self checkState];
+  value = [self->data objectForKey:_key];
+  return value != nil ? value : _def;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]: ", self, NSStringFromClass([self class])];
+  
+  if (self->path)     [ms appendFormat:@" path='%@'",   self->path];
+  if (self->data)     [ms appendFormat:@" strings=#%d", [self->data count]];
+  if (self->lastRead) [ms appendFormat:@" loaddate=%@", self->lastRead];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+  
+@end /* _WOStringTable */
diff --git a/skyrix-sope/NGObjWeb/common.h b/skyrix-sope/NGObjWeb/common.h
new file mode 100644 (file)
index 0000000..8de16c9
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjWeb_common_H__
+#define __NGObjWeb_common_H__
+
+// common include files
+
+#if !defined(__MINGW32__)
+#  include <strings.h>
+#endif
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#if LIB_FOUNDATION_LIBRARY
+#  import <Foundation/exceptions/GeneralExceptions.h>
+#endif
+
+#if NeXT_Foundation_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#  include <NGExtensions/NSString+Ext.h>
+#  include <NGExtensions/NSRunLoop+FileObjects.h>
+#  include "UnixSignalHandler.h"
+#endif
+
+#if !LIB_FOUNDATION_LIBRARY
+#  include <NGExtensions/NGPropertyListParser.h>
+#endif
+
+#include <objc/objc-api.h>
+#import <Foundation/Foundation.h>
+#import <Foundation/NSDateFormatter.h>
+#import <Foundation/NSNumberFormatter.h>
+#import <Foundation/NSHost.h>
+
+#include <NGExtensions/NGExtensions.h>
+#include <NGStreams/NGStreams.h>
+#include <NGStreams/NGNet.h>
+
+#include <NGMime/NGMime.h>
+
+#if NeXT_RUNTIME || APPLE_RUNTIME
+#  ifndef sel_get_name
+#    define sel_get_name(__XXX__)    sel_getName(__XXX__)
+#    define sel_get_any_uid(__XXX__) sel_getUid(__XXX__)
+#  endif
+#endif
+
+#define IS_DEPRECATED \
+  NSLog(@"WARNING: used deprecated method: %s:%i.", \
+        __PRETTY_FUNCTION__, __LINE__);
+
+#if PROFILE
+#  define BEGIN_PROFILE \
+     { NSTimeInterval __ti = [[NSDate date] timeIntervalSince1970],__last=__ti;
+
+#  define END_PROFILE \
+     __ti = [[NSDate date] timeIntervalSince1970] - __ti;\
+     if (__ti > 0.05) \
+       printf("***PROF[%s]: %0.3fs\n", __PRETTY_FUNCTION__, __ti);\
+     else if (__ti > 0.005) \
+       printf("PROF[%s]: %0.3fs\n", __PRETTY_FUNCTION__, __ti);\
+     }
+
+#  define PROFILE_CHECKPOINT(__key__) \
+     {\
+       NSTimeInterval __new = [[NSDate date] timeIntervalSince1970];\
+       printf("---PROF[%s] CP %s: %0.3fs %0.3fs\n", __PRETTY_FUNCTION__,\
+              __key__, __new - __ti, __new - __last);\
+       __last=__new; \
+     }
+
+#else
+#  define BEGIN_PROFILE {
+#  define END_PROFILE   }
+#  define PROFILE_CHECKPOINT(__key__)
+#endif
+
+@interface NSException(setUserInfo)
+- (id)setReason:(NSString *)_reason;
+- (id)setUserInfo:(NSDictionary *)_userInfo;
+@end
+
+#endif /* __NGObjWeb_common_H__ */
diff --git a/skyrix-sope/NGObjWeb/dummy.m b/skyrix-sope/NGObjWeb/dummy.m
new file mode 100644 (file)
index 0000000..90ae5c2
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/* required for linking bundles/frameworks without source files */
diff --git a/skyrix-sope/NGObjWeb/ngobjweb.make b/skyrix-sope/NGObjWeb/ngobjweb.make
new file mode 100644 (file)
index 0000000..31f0abd
--- /dev/null
@@ -0,0 +1,17 @@
+# $Id: ngobjweb.make,v 1.2 2004/06/14 17:06:06 helge Exp $
+
+WO_LDFLAGS =
+WO_LIBS    = -lNGObjWeb -lNGMime -lNGStreams -lNGExtensions        
+WO_DEFINE  = -DNGObjWeb_LIBRARY=1
+
+ifeq ($(FOUNDATION_LIB),nx)
+WO_LIBS += -lFoundationExt
+endif
+
+ifeq ($(FOUNDATION_LIB),apple)
+WO_LIBS += \
+       -lNGJavaScript -lNGScripting                    \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC                        \
+       -ljs
+endif
diff --git a/skyrix-sope/NGObjWeb/sope.m b/skyrix-sope/NGObjWeb/sope.m
new file mode 100644 (file)
index 0000000..1ec574e
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SoObjects/SoApplication.h"
+
+/*
+  An executable which can run a SoOFS based SOPE application. When started,
+  it takes the current-directory path for constructing the SoOFS root folder
+  of the SOPE application.
+  It also reads a file ".sope.plist" in the root-path to load site-local
+  configuration settings.
+  
+  TODO:
+  - load defaults from root-folder
+    DONE [".sope.plist" is loaded and registered]
+  - load products from root-folder
+  - load authenticator from root-folder
+*/
+
+@class NSString, NSFileManager;
+
+@interface SOPE : SoApplication
+{
+  NSFileManager *fm;
+  NSString *rootPath;
+}
+
+@end
+
+#include "SoObjects/SoClassSecurityInfo.h"
+#include "SoOFS/OFSFolder.h"
+#include "SoOFS/OFSFactoryContext.h"
+#include "common.h"
+
+NSString *SoRootFolder = @"SoRootFolder";
+
+@implementation SOPE
+
++ (void)initialize {
+  /* 
+     Since we are a tool, we have no bundle and need to declare security info
+     manually ...
+  */
+  SoClassSecurityInfo *si = [self soClassSecurityInfo];
+  [si declareObjectPublic];
+  [si setDefaultAccess:@"allow"];
+}
+
+- (void)loadLocalDefaults:(NSString *)_path {
+  NSDictionary *plist;
+
+  if ((plist = [[NSDictionary alloc] initWithContentsOfFile:_path]) == nil) {
+    [self logWithFormat:@"could not read SOPE config: %@", _path];
+    return;
+  }
+  /* 
+     TODO: we need a separate domain for this, this stuff doesn't make sense
+           at all ...
+  */
+  [[NSUserDefaults standardUserDefaults] registerDefaults:plist];
+  [self logWithFormat:@"registered site defaults: %@", _path];
+  [plist release];
+}
+
+- (BOOL)_bootstrap {
+  // TODO: create some bootstrap code to create initial user database,
+  //       defaults, control-panel, etc
+  return YES;
+}
+
+- (BOOL)_setupRoot {
+  BOOL     isDir;
+  NSString *p;
+
+  /* setup root path */
+  
+  if (self->fm == nil) {
+    [self logWithFormat:@"missing SOPE storage filemanager."];
+    return NO;
+  }
+  if ([self->rootPath length] == 0) {
+    [self logWithFormat:@"missing SOPE storage root-path."];
+    return NO;
+  }
+
+  if (![self->fm fileExistsAtPath:self->rootPath isDirectory:&isDir]) {
+    [self logWithFormat:@"SOPE storage root-path does not exist: %@", 
+            self->rootPath];
+    return NO;
+  }
+  if (!isDir) {
+    [self logWithFormat:@"SOPE storage root-path is not a directory: %@", 
+            self->rootPath];
+    return NO;
+  }
+  
+  /* bootstrap root if necessary */
+  
+  if (![self _bootstrap])
+    return NO;
+  
+  /* configure */
+  
+  [self logWithFormat:@"starting SOPE on OFS root: %@", self->rootPath];
+  
+  p = [self->rootPath stringByAppendingPathComponent:@".sope.plist"];
+  if ([self->fm isReadableFileAtPath:p])
+    [self loadLocalDefaults:p];
+  
+  return YES;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    // TODO: make root-path/fm configurable ?
+    self->fm       = [[NSFileManager defaultManager] retain];
+    self->rootPath = [[self->fm currentDirectoryPath] copy];
+
+    if (![self _setupRoot]) {
+      [self release];
+      return nil;
+    }
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->fm       release];
+  [self->rootPath release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id)fileManager {
+  return self->fm;
+}
+- (NSString *)rootPath {
+  return self->rootPath;
+}
+
+/* define the root SoObject */
+
+- (OFSFolder *)rootObjectInContext:(id)_ctx {
+  OFSFactoryContext *ctx;
+  OFSFolder *root;
+  
+  if ((root = [_ctx valueForKey:SoRootFolder]))
+    return root;
+  
+  ctx = [OFSFactoryContext contextWithFileManager:[self fileManager]
+                          storagePath:[self rootPath]];
+  
+  root = [[OFSFolder alloc] init];
+  [root takeStorageInfoFromContext:ctx];
+  [root awakeFromFetchInContext:ctx];
+  [_ctx takeValue:root forKey:SoRootFolder];
+  return [root autorelease];
+}
+
+/* security */
+
+- (id)authenticatorInContext:(id)_ctx {
+  id root;
+  id auth;
+  
+  root = [self rootObjectInContext:_ctx];
+  if ((auth = [root authenticatorInContext:_ctx]))
+    return auth;
+  
+  return [super authenticatorInContext:_ctx];
+}
+
+/* SMI */
+
+- (NSArray *)manageMenuChildNames {
+  NSMutableArray *ma;
+  id root;
+  
+  ma = [NSMutableArray arrayWithCapacity:16];
+  [ma addObject:@"ControlPanel"];
+  
+  root = [self rootObjectInContext:[self context]];
+  if (root != nil && (root != self)) 
+    [ma addObjectsFromArray:[root toOneRelationshipKeys]];
+  
+  return ma;
+}
+
+/* MacOSX support */
+
+- (id)handleQueryWithUnboundKey:(NSString *)key {
+  /* KVC on MacOSX throws an exception when an unbound key is queried ... */
+  return nil;
+}
+
+@end /* SOPE */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  WOWatchDogApplicationMain(@"SOPE", argc, (void*)argv);
+  
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-sope/NGObjWeb/woapp-gs.make b/skyrix-sope/NGObjWeb/woapp-gs.make
new file mode 100644 (file)
index 0000000..9335543
--- /dev/null
@@ -0,0 +1,384 @@
+#
+#   woapp.make
+#
+#   Makefile rules to build GNUstep web based applications.
+#
+#   Copyright (C) 2002 Free Software Foundation, Inc.
+#
+#   Author:  Nicola Pero <nicola@brainstorm.co.uk>
+#
+#   This file is part of the GNUstep Makefile Package.
+#
+#   This library 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
+#   of the License, or (at your option) any later version.
+#   
+#   You should have received a copy of the GNU General Public
+#   License along with this library; see the file COPYING.LIB.
+#   If not, write to the Free Software Foundation,
+#   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ifeq ($(GNUSTEP_INSTANCE),)
+ifeq ($(RULES_MAKE_LOADED),)
+include $(GNUSTEP_MAKEFILES)/rules.make
+endif
+
+# Determine the application directory extension
+WOAPP_EXTENSION=woa
+
+WOAPP_NAME := $(strip $(WOAPP_NAME))
+
+internal-all:: $(WOAPP_NAME:=.all.woapp.variables)
+
+internal-install:: $(WOAPP_NAME:=.install.woapp.variables)
+
+internal-uninstall:: $(WOAPP_NAME:=.uninstall.woapp.variables)
+
+internal-clean:: $(WOAPP_NAME:=.clean.woapp.subprojects)
+       rm -rf $(GNUSTEP_OBJ_DIR)
+ifeq ($(OBJC_COMPILER), NeXT)
+       rm -f *.iconheader
+       for f in *.$(WOAPP_EXTENSION); do \
+         rm -f $$f/`basename $$f .$(WOAPP_EXTENSION)`; \
+       done
+else
+ifeq ($(GNUSTEP_FLATTENED),)
+       rm -rf *.$(WOAPP_EXTENSION)/$(GNUSTEP_TARGET_LDIR)
+else
+       rm -rf *.$(WOAPP_EXTENSION)
+endif
+endif
+
+internal-distclean:: $(WOAPP_NAME:=.distclean.woapp.subprojects)
+       rm -rf shared_obj static_obj shared_debug_obj shared_profile_obj \
+         static_debug_obj static_profile_obj shared_profile_debug_obj \
+         static_profile_debug_obj *.woa *.debug *.profile *.iconheader
+
+$(WOAPP_NAME):
+       @$(MAKE) -f $(MAKEFILE_NAME) --no-print-directory \
+                   $@.all.woapp.variables
+else
+
+ifeq ($(GNUSTEP_TYPE),woapp)
+ifeq ($(RULES_MAKE_LOADED),)
+include $(GNUSTEP_MAKEFILES)/rules.make
+endif
+
+# FIXME/TODO - this file has not been updated to use
+# Instance/Shared/bundle.make because it is linking resources instead of
+# copying them.
+
+
+#
+# The name of the application is in the WOAPP_NAME variable.
+# The list of languages the app is localized in are in xxx_LANGUAGES <==
+# The list of application resource file are in xxx_RESOURCE_FILES
+# The list of localized application resource file are in 
+#  xxx_LOCALIZED_RESOURCE_FILES <==
+# The list of application resource directories are in xxx_RESOURCE_DIRS
+# The list of application web server resource directories are in 
+#  xxx_WEBSERVER_RESOURCE_DIRS <==
+# The list of localized application web server resource directories are in 
+#  xxx_LOCALIZED_WEBSERVER_RESOURCE_DIRS
+# where xxx is the application name <==
+
+COMPONENTS = $($(GNUSTEP_INSTANCE)_COMPONENTS)
+LANGUAGES = $($(GNUSTEP_INSTANCE)_LANGUAGES)
+WEBSERVER_RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_WEBSERVER_RESOURCE_FILES)
+LOCALIZED_WEBSERVER_RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_LOCALIZED_WEBSERVER_RESOURCE_FILES)
+WEBSERVER_RESOURCE_DIRS = $($(GNUSTEP_INSTANCE)_WEBSERVER_RESOURCE_DIRS)
+LOCALIZED_RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_LOCALIZED_RESOURCE_FILES)
+RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_RESOURCE_FILES)
+RESOURCE_DIRS = $($(GNUSTEP_INSTANCE)_RESOURCE_DIRS)
+
+ifeq ($(FOUNDATION_LIB),apple)
+WORSRCDIRINFIX:=Contents/Resources
+WORSRCLINKUP:=../../..
+else
+WORSRCDIRINFIX:=Resources
+WORSRCLINKUP:=../..
+endif
+
+# Determine the application directory extension
+WOAPP_EXTENSION = woa
+
+GNUSTEP_WOAPPS = $(GNUSTEP_INSTALLATION_DIR)/WOApps
+
+.PHONY: internal-woapp-all_ \
+        internal-woapp-install_ \
+        internal-woapp-uninstall_ \
+        woapp-components \
+        woapp-webresource-dir \
+        woapp-webresource-files \
+        woapp-localized-webresource-files \
+        woapp-resource-dir \
+        woapp-resource-files \
+        woapp-localized-resource-files
+
+# Libraries that go before the WO libraries
+ALL_WO_LIBS =                                                          \
+    $(shell $(WHICH_LIB_SCRIPT)                                                \
+       $(ALL_LIB_DIRS)                                                 \
+       $(ADDITIONAL_WO_LIBS) $(AUXILIARY_WO_LIBS) $(WO_LIBS)   \
+       $(ADDITIONAL_TOOL_LIBS) $(AUXILIARY_TOOL_LIBS)                  \
+       $(FND_LIBS) $(ADDITIONAL_OBJC_LIBS) $(AUXILIARY_OBJC_LIBS)      \
+        $(OBJC_LIBS) $(SYSTEM_LIBS) $(TARGET_SYSTEM_LIBS)              \
+       debug=$(debug) profile=$(profile) shared=$(shared)              \
+       libext=$(LIBEXT) shared_libext=$(SHARED_LIBEXT))
+
+
+# Don't include these definitions the first time make is invoked. This part is
+# included when make is invoked the second time from the %.build rule (see
+# rules.make).
+WOAPP_DIR_NAME = $(GNUSTEP_INSTANCE:=.$(WOAPP_EXTENSION))
+WOAPP_RESOURCE_DIRS =  $(foreach d, $(RESOURCE_DIRS), $(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX)/$(d))
+WOAPP_WEBSERVER_RESOURCE_DIRS =  $(foreach d, $(WEBSERVER_RESOURCE_DIRS), $(WOAPP_DIR_NAME)/WebServerResources/$(d))
+ifeq ($(strip $(LANGUAGES)),)
+  LANGUAGES="English"
+endif
+
+# Support building NeXT applications
+ifneq ($(OBJC_COMPILER), NeXT)
+WOAPP_FILE = \
+    $(WOAPP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR)/$(GNUSTEP_INSTANCE)$(EXEEXT)
+else
+WOAPP_FILE = $(WOAPP_DIR_NAME)/$(GNUSTEP_INSTANCE)$(EXEEXT)
+endif
+
+#
+# Internal targets
+#
+
+$(WOAPP_FILE): $(OBJ_FILES_TO_LINK)
+       $(LD) $(ALL_LDFLAGS) -o $(LDOUT)$@ $(OBJ_FILES_TO_LINK) \
+             $(ALL_WO_LIBS)
+
+ifeq ($(OBJC_COMPILER), NeXT)
+       @$(TRANSFORM_PATHS_SCRIPT) $(subst -L,,$(ALL_LIB_DIRS)) \
+               >$(WOAPP_DIR_NAME)/library_paths.openapp
+# This is a hack for OPENSTEP systems to remove the iconheader file
+# automatically generated by the makefile package.
+       rm -f $(GNUSTEP_INSTANCE).iconheader
+else
+       @$(TRANSFORM_PATHS_SCRIPT) $(subst -L,,$(ALL_LIB_DIRS)) \
+       >$(WOAPP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR)/library_paths.openapp
+endif
+
+#
+# Compilation targets
+#
+ifeq ($(OBJC_COMPILER), NeXT)
+internal-woapp-all_:: \
+       $(GNUSTEP_OBJ_DIR) $(WOAPP_DIR_NAME) $(WOAPP_FILE) \
+       woapp-components \
+       woapp-localized-webresource-files \
+       woapp-webresource-files \
+       woapp-localized-resource-files \
+       woapp-resource-files \
+       $(WOAPP_DIR_NAME)/$(GNUSTEP_INSTANCE).sh
+
+$(GNUSTEP_INSTANCE).iconheader:
+       @(echo "F       $(GNUSTEP_INSTANCE).$(WOAPP_EXTENSION)  $(GNUSTEP_INSTANCE)     $(WOAPP_EXTENSION)"; \
+         echo "F       $(GNUSTEP_INSTANCE)     $(GNUSTEP_INSTANCE)     app") >$@
+
+$(WOAPP_DIR_NAME):
+       mkdir $@
+else
+
+internal-woapp-all_:: \
+   $(GNUSTEP_OBJ_DIR) \
+   $(WOAPP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR) $(WOAPP_FILE) \
+   woapp-components \
+   woapp-localized-webresource-files \
+   woapp-webresource-files \
+   woapp-localized-resource-files \
+   woapp-resource-files \
+   $(WOAPP_DIR_NAME)/$(GNUSTEP_INSTANCE).sh
+
+$(WOAPP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR):
+       @$(MKDIRS) $(WOAPP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR)
+endif
+
+ifeq ($(GNUSTEP_INSTANCE)_GEN_SCRIPT,yes) #<==
+$(WOAPP_DIR_NAME)/$(GNUSTEP_INSTANCE).sh: $(WOAPP_DIR_NAME)
+       @(echo "#!/bin/sh"; \
+         echo '# Automatically generated, do not edit!'; \
+         echo '$${GNUSTEP_HOST_LDIR}/$(GNUSTEP_INSTANCE) $$1 $$2 $$3 $$4 $$5 $$6 $$7 $$8') >$@
+       chmod +x $@
+else
+$(WOAPP_DIR_NAME)/$(GNUSTEP_INSTANCE).sh:
+
+endif
+
+woapp-components:: $(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX)
+ifneq ($(strip $(COMPONENTS)),)
+       @ echo "Linking components into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX); \
+        for component in $(COMPONENTS); do \
+         if [ -d $(WORSRCLINKUP)/$$component ]; then \
+            $(LN_S) -f $(WORSRCLINKUP)/$$component ./;\
+         fi; \
+        done; \
+       echo "Linking localized components into the application wrapper..."; \
+        for l in $(LANGUAGES); do \
+         if [ -d $(WORSRCLINKUP)/$$l.lproj ]; then \
+           $(MKDIRS) $$l.lproj; \
+           cd $$l.lproj; \
+           for f in $(COMPONENTS); do \
+             if [ -d $(WORSRCLINKUP)/../$$l.lproj/$$f ]; then \
+               $(LN_S) -f $(WORSRCLINKUP)/../$$l.lproj/$$f .;\
+             fi;\
+            done;\
+           cd ..; \
+         fi;\
+       done
+endif
+
+# FIXME - this is behaving differently than in wobundle.make !
+# It's also not behaving consistently with xxx_RESOURCE_DIRS
+woapp-webresource-dir:: $(WOAPP_WEBSERVER_RESOURCE_DIRS)
+ifneq ($(strip $(WEBSERVER_RESOURCE_DIRS)),)
+       @ echo "Linking webserver Resource Dirs into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX); \
+        for dir in $(WEBSERVER_RESOURCE_DIRS); do \
+         if [ -d $(WORSRCLINKUP)/$$dir ]; then \
+            $(LN_S) -f $(WORSRCLINKUP)/$$dir ./;\
+         fi; \
+        done;
+endif
+
+$(WOAPP_WEBSERVER_RESOURCE_DIRS):
+       #@$(MKDIRS) $(WOAPP_WEBSERVER_RESOURCE_DIRS)
+
+woapp-webresource-files:: $(WOAPP_DIR_NAME)/WebServerResources \
+                           woapp-webresource-dir
+ifneq ($(strip $(WEBSERVER_RESOURCE_FILES)),)
+       @echo "Linking webserver resources into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/WebServerResources; \
+        for ff in $(WEBSERVER_RESOURCE_FILES); do \
+         $(LN_S) -f ../../$$ff .;\
+        done
+endif
+
+woapp-localized-webresource-files:: $(WOAPP_DIR_NAME)/WebServerResources woapp-webresource-dir
+ifneq ($(strip $(LOCALIZED_WEBSERVER_RESOURCE_FILES)),)
+       @ echo "Linking localized web resources into the application wrapper..."; \
+       cd $(WOAPP_DIR_NAME)/WebServerResources; \
+       for l in $(LANGUAGES); do \
+         if [ -d ../../WebServerResources/$$l.lproj ]; then \
+           $(MKDIRS) $$l.lproj;\
+           cd $$l.lproj; \
+           for f in $(LOCALIZED_WEBSERVER_RESOURCE_FILES); do \
+             if [ -f ../../../$$l.lproj/$$f ]; then \
+               if [ ! -r $$f ]; then \
+                 $(LN_S) ../../../$$l.lproj/$$f $$f;\
+               fi;\
+             fi;\
+           done;\
+           cd ..; \
+         else\
+          echo "Warning - WebServerResources/$$l.lproj not found - ignoring";\
+         fi;\
+       done
+endif
+
+# This is not consistent with what other projects do ... so it can't stay
+# this way.  Use COMPONENTS instead.
+woapp-resource-dir:: $(WOAPP_RESOURCE_DIRS)
+ifneq ($(strip $(RESOURCE_DIRS)),)
+       @ echo "Linking Resource Dirs into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX); \
+        for dir in $(RESOURCE_DIRS); do \
+         if [ -d $(WORSRCLINKUP)/$$dir ]; then \
+            $(LN_S) -f $(WORSRCLINKUP)/$$dir ./;\
+         fi; \
+        done;
+endif
+
+$(WOAPP_RESOURCE_DIRS):
+       #@$(MKDIRS) $(WOAPP_RESOURCE_DIRS)
+
+woapp-resource-files:: $(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX)/Info-gnustep.plist \
+                        woapp-resource-dir
+ifneq ($(strip $(RESOURCE_FILES)),)
+       @ echo "Linking resources into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX)/; \
+        for ff in $(RESOURCE_FILES); do \
+         $(LN_S) -f $(WORSRCLINKUP)/$$ff .;\
+        done
+endif
+
+woapp-localized-resource-files:: $(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX) \
+                                  woapp-resource-dir
+ifneq ($(strip $(LOCALIZED_RESOURCE_FILES)),)
+       @ echo "Linking localized resources into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX); \
+        for l in $(LANGUAGES); do \
+         if [ -d $(WORSRCLINKUP)/$$l.lproj ]; then \
+           $(MKDIRS) $$l.lproj; \
+           cd $$l.lproj; \
+           for f in $(LOCALIZED_RESOURCE_FILES); do \
+              if [ -f $(WORSRCLINKUP)/../$$l.lproj/$$f ]; then \
+               $(LN_S) -f $(WORSRCLINKUP)/../$$l.lproj/$$f .;\
+             fi;\
+           done;\
+           cd ..; \
+         else \
+          echo "Warning - $$l.lproj not found - ignoring";\
+         fi;\
+       done
+endif
+
+PRINCIPAL_CLASS = $(strip $($(GNUSTEP_INSTANCE)_PRINCIPAL_CLASS))
+
+ifeq ($(PRINCIPAL_CLASS),)
+  PRINCIPAL_CLASS = $(GNUSTEP_INSTANCE)
+endif
+
+HAS_WOCOMPONENTS = $($(GNUSTEP_INSTANCE)_HAS_WOCOMPONENTS)
+WOAPP_INFO_PLIST = $($(GNUSTEP_INSTANCE)_WOAPP_INFO_PLIST)
+MAIN_MODEL_FILE = $(strip $(subst .gmodel,,$(subst .gorm,,$(subst .nib,,$($(GNUSTEP_INSTANCE)_MAIN_MODEL_FILE)))))
+
+$(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX)/Info-gnustep.plist: $(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX)
+       @(echo "{"; echo '  NOTE = "Automatically generated, do not edit!";'; \
+         echo "  NSExecutable = \"$(GNUSTEP_INSTANCE)\";"; \
+         echo "  NSPrincipalClass = \"$(PRINCIPAL_CLASS)\";"; \
+         if [ "$(HAS_WOCOMPONENTS)" != "" ]; then \
+           echo "  HasWOComponents = \"$(HAS_WOCOMPONENTS)\";"; \
+         fi; \
+         echo "  NSMainNibFile = \"$(MAIN_MODEL_FILE)\";"; \
+         if [ -r "$(GNUSTEP_INSTANCE)Info.plist" ]; then \
+           cat $(GNUSTEP_INSTANCE)Info.plist; \
+         fi; \
+         if [ "$(WOAPP_INFO_PLIST)" != "" ]; then \
+           cat $(WOAPP_INFO_PLIST); \
+         fi; \
+         echo "}") >$@
+
+$(WOAPP_DIR_NAME)/$(WORSRCDIRINFIX):
+       @$(MKDIRS) $@
+
+$(WOAPP_DIR_NAME)/WebServerResources:
+       @$(MKDIRS) $@
+
+internal-woapp-install_::
+       @($(MKINSTALLDIRS) $(GNUSTEP_WOAPPS); \
+       rm -rf $(GNUSTEP_WOAPPS)/$(WOAPP_DIR_NAME); \
+       $(TAR) chf - --exclude=CVS --to-stdout $(WOAPP_DIR_NAME) | (cd $(GNUSTEP_WOAPPS); $(TAR) xf -))
+ifneq ($(CHOWN_TO),)
+       $(CHOWN) -R $(CHOWN_TO) $(GNUSTEP_WOAPPS)/$(WOAPP_DIR_NAME)
+endif
+ifeq ($(strip),yes)
+       $(STRIP) $(GNUSTEP_WOAPPS)/$(WOAPP_FILE) 
+endif
+
+internal-woapp-uninstall_::
+       (cd $(GNUSTEP_WOAPPS); rm -rf $(WOAPP_DIR_NAME))
+endif
+
+endif
+
+## Local variables:
+## mode: makefile
+## End:
diff --git a/skyrix-sope/NGObjWeb/woapp.make b/skyrix-sope/NGObjWeb/woapp.make
new file mode 100644 (file)
index 0000000..fd73d77
--- /dev/null
@@ -0,0 +1,368 @@
+#
+#   woapp.make
+#
+#   Makefile rules to build GNUstep web based applications.
+#
+#   Copyright (C) 2002 Free Software Foundation, Inc.
+#
+#   Author:  Nicola Pero <nicola@brainstorm.co.uk>
+#
+#   This file is part of the GNUstep Makefile Package.
+#
+#   This library 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
+#   of the License, or (at your option) any later version.
+#   
+#   You should have received a copy of the GNU General Public
+#   License along with this library; see the file COPYING.LIB.
+#   If not, write to the Free Software Foundation,
+#   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ifeq ($(GNUSTEP_INSTANCE),)
+ifeq ($(RULES_MAKE_LOADED),)
+include $(GNUSTEP_MAKEFILES)/rules.make
+endif
+
+# Determine the application directory extension
+WOAPP_EXTENSION=woa
+WOAPP_NAME := $(strip $(WOAPP_NAME))
+
+internal-all:: $(WOAPP_NAME:=.all.woapp.variables)
+
+internal-install:: $(WOAPP_NAME:=.install.woapp.variables)
+
+internal-uninstall:: $(WOAPP_NAME:=.uninstall.woapp.variables)
+
+internal-clean:: $(WOAPP_NAME:=.clean.woapp.subprojects)
+       rm -rf $(GNUSTEP_OBJ_DIR)
+ifeq ($(OBJC_COMPILER), NeXT)
+       rm -f *.iconheader
+       for f in *.$(WOAPP_EXTENSION); do \
+         rm -f $$f/`basename $$f .$(WOAPP_EXTENSION)`; \
+       done
+else
+ifeq ($(GNUSTEP_FLATTENED),)
+       rm -rf *.$(WOAPP_EXTENSION)/$(GNUSTEP_TARGET_LDIR)
+else
+       rm -rf *.$(WOAPP_EXTENSION)
+endif
+endif
+
+internal-distclean:: $(WOAPP_NAME:=.distclean.woapp.subprojects)
+       rm -rf shared_obj static_obj shared_debug_obj shared_profile_obj \
+         static_debug_obj static_profile_obj shared_profile_debug_obj \
+         static_profile_debug_obj *.woa *.debug *.profile *.iconheader
+
+$(WOAPP_NAME):
+       @$(MAKE) -f $(MAKEFILE_NAME) --no-print-directory \
+                   $@.all.woapp.variables
+else
+
+ifeq ($(GNUSTEP_TYPE),woapp)
+ifeq ($(RULES_MAKE_LOADED),)
+include $(GNUSTEP_MAKEFILES)/rules.make
+endif
+
+# FIXME/TODO - this file has not been updated to use
+# Instance/Shared/bundle.make because it is linking resources instead of
+# copying them.
+
+
+#
+# The name of the application is in the WOAPP_NAME variable.
+# The list of languages the app is localized in are in xxx_LANGUAGES <==
+# The list of application resource file are in xxx_RESOURCE_FILES
+# The list of localized application resource file are in 
+#  xxx_LOCALIZED_RESOURCE_FILES <==
+# The list of application resource directories are in xxx_RESOURCE_DIRS
+# The list of application web server resource directories are in 
+#  xxx_WEBSERVER_RESOURCE_DIRS <==
+# The list of localized application web server resource directories are in 
+#  xxx_LOCALIZED_WEBSERVER_RESOURCE_DIRS
+# where xxx is the application name <==
+
+COMPONENTS = $($(GNUSTEP_INSTANCE)_COMPONENTS)
+LANGUAGES = $($(GNUSTEP_INSTANCE)_LANGUAGES)
+WEBSERVER_RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_WEBSERVER_RESOURCE_FILES)
+LOCALIZED_WEBSERVER_RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_LOCALIZED_WEBSERVER_RESOURCE_FILES)
+WEBSERVER_RESOURCE_DIRS = $($(GNUSTEP_INSTANCE)_WEBSERVER_RESOURCE_DIRS)
+LOCALIZED_RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_LOCALIZED_RESOURCE_FILES)
+RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_RESOURCE_FILES)
+RESOURCE_DIRS = $($(GNUSTEP_INSTANCE)_RESOURCE_DIRS)
+
+
+# Determine the application directory extension
+WOAPP_EXTENSION = woa
+GNUSTEP_WOAPPS  = $(GNUSTEP_INSTALLATION_DIR)/WOApps
+
+.PHONY: internal-woapp-all \
+        internal-woapp-install \
+        internal-woapp-uninstall \
+        woapp-components \
+        woapp-webresource-dir \
+        woapp-webresource-files \
+        woapp-localized-webresource-files \
+        woapp-resource-dir \
+        woapp-resource-files \
+        woapp-localized-resource-files
+
+# Libraries that go before the WO libraries
+ALL_WO_LIBS =                                                          \
+    $(shell $(WHICH_LIB_SCRIPT)                                                \
+       $(ALL_LIB_DIRS)                                                 \
+       $(ADDITIONAL_WO_LIBS) $(AUXILIARY_WO_LIBS) $(WO_LIBS)   \
+       $(ADDITIONAL_TOOL_LIBS) $(AUXILIARY_TOOL_LIBS)                  \
+       $(FND_LIBS) $(ADDITIONAL_OBJC_LIBS) $(AUXILIARY_OBJC_LIBS)      \
+        $(OBJC_LIBS) $(SYSTEM_LIBS) $(TARGET_SYSTEM_LIBS)              \
+       debug=$(debug) profile=$(profile) shared=$(shared)              \
+       libext=$(LIBEXT) shared_libext=$(SHARED_LIBEXT))
+
+
+# Don't include these definitions the first time make is invoked. This part is
+# included when make is invoked the second time from the %.build rule (see
+# rules.make).
+WOAPP_DIR_NAME = $(GNUSTEP_INSTANCE:=.$(WOAPP_EXTENSION))
+WOAPP_RESOURCE_DIRS =  $(foreach d, $(RESOURCE_DIRS), $(WOAPP_DIR_NAME)/Resources/$(d))
+WOAPP_WEBSERVER_RESOURCE_DIRS =  $(foreach d, $(WEBSERVER_RESOURCE_DIRS), $(WOAPP_DIR_NAME)/WebServerResources/$(d))
+ifeq ($(strip $(LANGUAGES)),)
+  LANGUAGES="English"
+endif
+
+# Support building NeXT applications
+ifneq ($(OBJC_COMPILER), NeXT)
+WOAPP_FILE = \
+    $(WOAPP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR)/$(GNUSTEP_INSTANCE)$(EXEEXT)
+else
+WOAPP_FILE = $(WOAPP_DIR_NAME)/$(GNUSTEP_INSTANCE)$(EXEEXT)
+endif
+
+#
+# Internal targets
+#
+
+$(WOAPP_FILE): $(OBJ_FILES_TO_LINK)
+       $(LD) $(ALL_LDFLAGS) -o $(LDOUT)$@ $(OBJ_FILES_TO_LINK) \
+             $(ALL_WO_LIBS)
+
+ifeq ($(OBJC_COMPILER), NeXT)
+       @$(TRANSFORM_PATHS_SCRIPT) $(subst -L,,$(ALL_LIB_DIRS)) \
+               >$(WOAPP_DIR_NAME)/library_paths.openapp
+# This is a hack for OPENSTEP systems to remove the iconheader file
+# automatically generated by the makefile package.
+       rm -f $(GNUSTEP_INSTANCE).iconheader
+else
+       @$(TRANSFORM_PATHS_SCRIPT) $(subst -L,,$(ALL_LIB_DIRS)) \
+       >$(WOAPP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR)/library_paths.openapp
+endif
+
+#
+# Compilation targets
+#
+ifeq ($(OBJC_COMPILER), NeXT)
+internal-woapp-all:: \
+       before-$(GNUSTEP_INSTANCE)-all \
+       $(GNUSTEP_OBJ_DIR) $(WOAPP_DIR_NAME) $(WOAPP_FILE) \
+       woapp-components \
+       woapp-localized-webresource-files \
+       woapp-webresource-files \
+       woapp-localized-resource-files \
+       woapp-resource-files \
+       $(WOAPP_DIR_NAME)/$(GNUSTEP_INSTANCE).sh \
+       after-$(GNUSTEP_INSTANCE)-all
+
+$(GNUSTEP_INSTANCE).iconheader:
+       @(echo "F       $(GNUSTEP_INSTANCE).$(WOAPP_EXTENSION)  $(GNUSTEP_INSTANCE)     $(WOAPP_EXTENSION)"; \
+         echo "F       $(GNUSTEP_INSTANCE)     $(GNUSTEP_INSTANCE)     app") >$@
+
+$(WOAPP_DIR_NAME):
+       mkdir $@
+else
+
+internal-woapp-all:: \
+   before-$(GNUSTEP_INSTANCE)-all $(GNUSTEP_OBJ_DIR) \
+   $(WOAPP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR) $(WOAPP_FILE) \
+   woapp-components \
+   woapp-localized-webresource-files \
+   woapp-webresource-files \
+   woapp-localized-resource-files \
+   woapp-resource-files \
+   $(WOAPP_DIR_NAME)/$(GNUSTEP_INSTANCE).sh \
+   after-$(GNUSTEP_INSTANCE)-all
+
+$(WOAPP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR):
+       @$(MKDIRS) $(WOAPP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR)
+endif
+
+ifeq ($(GNUSTEP_INSTANCE)_GEN_SCRIPT,yes) #<==
+$(WOAPP_DIR_NAME)/$(GNUSTEP_INSTANCE).sh: $(WOAPP_DIR_NAME)
+       @(echo "#!/bin/sh"; \
+         echo '# Automatically generated, do not edit!'; \
+         echo '$${GNUSTEP_HOST_LDIR}/$(GNUSTEP_INSTANCE) $$1 $$2 $$3 $$4 $$5 $$6 $$7 $$8') >$@
+       chmod +x $@
+else
+$(WOAPP_DIR_NAME)/$(GNUSTEP_INSTANCE).sh:
+
+endif
+
+woapp-components:: $(WOAPP_DIR_NAME)/Resources
+ifneq ($(strip $(COMPONENTS)),)
+       @ echo "Linking components into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME); \
+        for component in $(COMPONENTS); do \
+         if [ ! -d ./$$component ]; then \
+           if [ -d ../$$component ]; then \
+             echo "linking ../$$component to ./ (pwd=$$PWD)";\
+             $(LN_S) -f ../$$component .;\
+           fi; \
+         fi;\
+        done
+endif
+
+# FIXME - this is behaving differently than in wobundle.make !
+# It's also not behaving consistently with xxx_RESOURCE_DIRS
+woapp-webresource-dir:: $(WOAPP_WEBSERVER_RESOURCE_DIRS)
+ifneq ($(strip $(WEBSERVER_RESOURCE_DIRS)),)
+       @ echo "Linking webserver Resource Dirs into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/Resources; \
+        for dir in $(WEBSERVER_RESOURCE_DIRS); do \
+         if [ -d ../../$$dir ]; then \
+            $(LN_S) -f ../../$$dir ./;\
+         fi; \
+        done;
+endif
+
+$(WOAPP_WEBSERVER_RESOURCE_DIRS):
+       #@$(MKDIRS) $(WOAPP_WEBSERVER_RESOURCE_DIRS)
+
+woapp-webresource-files:: $(WOAPP_DIR_NAME)/WebServerResources \
+                           woapp-webresource-dir
+ifneq ($(strip $(WEBSERVER_RESOURCE_FILES)),)
+       @echo "Linking webserver resources into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/WebServerResources; \
+        for ff in $(WEBSERVER_RESOURCE_FILES); do \
+         $(LN_S) -f ../../$$ff .;\
+        done
+endif
+
+woapp-localized-webresource-files:: $(WOAPP_DIR_NAME)/WebServerResources woapp-webresource-dir
+ifneq ($(strip $(LOCALIZED_WEBSERVER_RESOURCE_FILES)),)
+       @ echo "Linking localized web resources into the application wrapper..."; \
+       cd $(WOAPP_DIR_NAME)/WebServerResources; \
+       for l in $(LANGUAGES); do \
+         if [ -d ../../$$l.lproj ]; then \
+           $(MKDIRS) $$l.lproj;\
+           cd $$l.lproj; \
+           for f in $(LOCALIZED_WEBSERVER_RESOURCE_FILES); do \
+             if [ -f ../../../$$l.lproj/$$f ]; then \
+               if [ ! -r $$f ]; then \
+                 $(LN_S) ../../../$$l.lproj/$$f $$f;\
+               fi;\
+             fi;\
+           done;\
+           cd ..; \
+         else\
+          echo "Warning - WebServerResources/$$l.lproj not found - ignoring";\
+         fi;\
+       done
+endif
+
+# This is not consistent with what other projects do ... so it can't stay
+# this way.  Use COMPONENTS instead.
+woapp-resource-dir:: $(WOAPP_RESOURCE_DIRS)
+ifneq ($(strip $(RESOURCE_DIRS)),)
+       @ echo "Linking Resource Dirs into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/Resources; \
+        for dir in $(RESOURCE_DIRS); do \
+         if [ -d ../../$$dir ]; then \
+            $(LN_S) -f ../../$$dir ./;\
+         fi; \
+        done;
+endif
+
+$(WOAPP_RESOURCE_DIRS):
+       #@$(MKDIRS) $(WOAPP_RESOURCE_DIRS)
+
+woapp-resource-files:: $(WOAPP_DIR_NAME)/Resources/Info-gnustep.plist \
+                        woapp-resource-dir
+ifneq ($(strip $(RESOURCE_FILES)),)
+       @ echo "Linking resources into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/Resources/; \
+        for ff in $(RESOURCE_FILES); do \
+         $(LN_S) -f ../../$$ff .;\
+        done
+endif
+
+woapp-localized-resource-files:: $(WOAPP_DIR_NAME)/Resources \
+                                  woapp-resource-dir
+ifneq ($(strip $(LOCALIZED_RESOURCE_FILES)),)
+       @ echo "Linking localized resources into the application wrapper..."; \
+        cd $(WOAPP_DIR_NAME)/Resources; \
+        for l in $(LANGUAGES); do \
+         if [ -d ../../$$l.lproj ]; then \
+           $(MKDIRS) $$l.lproj; \
+           cd $$l.lproj; \
+           for f in $(LOCALIZED_RESOURCE_FILES); do \
+              if [ -f ../../../$$l.lproj/$$f ]; then \
+               $(LN_S) -f ../../../$$l.lproj/$$f .;\
+             fi;\
+           done;\
+           cd ..; \
+         else \
+          echo "Warning - $$l.lproj not found - ignoring";\
+         fi;\
+       done
+endif
+
+PRINCIPAL_CLASS = $(strip $($(GNUSTEP_INSTANCE)_PRINCIPAL_CLASS))
+
+ifeq ($(PRINCIPAL_CLASS),)
+  PRINCIPAL_CLASS = $(GNUSTEP_INSTANCE)
+endif
+
+HAS_WOCOMPONENTS = $($(GNUSTEP_INSTANCE)_HAS_WOCOMPONENTS)
+WOAPP_INFO_PLIST = $($(GNUSTEP_INSTANCE)_WOAPP_INFO_PLIST)
+MAIN_MODEL_FILE = $(strip $(subst .gmodel,,$(subst .gorm,,$(subst .nib,,$($(GNUSTEP_INSTANCE)_MAIN_MODEL_FILE)))))
+
+$(WOAPP_DIR_NAME)/Resources/Info-gnustep.plist: $(WOAPP_DIR_NAME)/Resources
+       @(echo "{"; echo '  NOTE = "Automatically generated, do not edit!";'; \
+         echo "  NSExecutable = \"$(GNUSTEP_INSTANCE)\";"; \
+         echo "  NSPrincipalClass = \"$(PRINCIPAL_CLASS)\";"; \
+         if [ "$(HAS_WOCOMPONENTS)" != "" ]; then \
+           echo "  HasWOComponents = \"$(HAS_WOCOMPONENTS)\";"; \
+         fi; \
+         echo "  NSMainNibFile = \"$(MAIN_MODEL_FILE)\";"; \
+         if [ -r "$(GNUSTEP_INSTANCE)Info.plist" ]; then \
+           cat $(GNUSTEP_INSTANCE)Info.plist; \
+         fi; \
+         if [ "$(WOAPP_INFO_PLIST)" != "" ]; then \
+           cat $(WOAPP_INFO_PLIST); \
+         fi; \
+         echo "}") >$@
+
+$(WOAPP_DIR_NAME)/Resources:
+       @$(MKDIRS) $@
+
+$(WOAPP_DIR_NAME)/WebServerResources:
+       @$(MKDIRS) $@
+
+internal-woapp-install::
+       @($(MKINSTALLDIRS) $(GNUSTEP_WOAPPS); \
+       rm -rf $(GNUSTEP_WOAPPS)/$(WOAPP_DIR_NAME); \
+       $(TAR) ch --exclude=CVS --to-stdout $(WOAPP_DIR_NAME) | (cd $(GNUSTEP_WOAPPS); $(TAR) xf -))
+ifneq ($(CHOWN_TO),)
+       $(CHOWN) -R $(CHOWN_TO) $(GNUSTEP_WOAPPS)/$(WOAPP_DIR_NAME)
+endif
+ifeq ($(strip),yes)
+       $(STRIP) $(GNUSTEP_WOAPPS)/$(WOAPP_FILE) 
+endif
+
+internal-woapp-uninstall::
+       (cd $(GNUSTEP_WOAPPS); rm -rf $(WOAPP_DIR_NAME))
+endif
+
+endif
+
+## Local variables:
+## mode: makefile
+## End:
diff --git a/skyrix-sope/NGObjWeb/wobundle-gs.make b/skyrix-sope/NGObjWeb/wobundle-gs.make
new file mode 100644 (file)
index 0000000..0d306f5
--- /dev/null
@@ -0,0 +1,306 @@
+#
+#   wobundle.make
+#
+#   Makefile rules to build GNUstep web bundles.
+#
+#   Copyright (C) 2002 Free Software Foundation, Inc.
+#
+#   Author:  Nicola Pero <nicola@brainstorm.co.uk>
+#
+#   This file is part of the GNUstep Makefile Package.
+#
+#   This library 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
+#   of the License, or (at your option) any later version.
+#   
+#   You should have received a copy of the GNU General Public
+#   License along with this library; see the file COPYING.LIB.
+#   If not, write to the Free Software Foundation,
+#   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ifeq ($(GNUSTEP_INSTANCE),)
+ifeq ($(RULES_MAKE_LOADED),)
+include $(GNUSTEP_MAKEFILES)/rules.make
+endif
+
+ifeq ($(strip $(WOBUNDLE_EXTENSION)),)
+WOBUNDLE_EXTENSION = .wobundle
+endif
+
+WOBUNDLE_NAME := $(strip $(WOBUNDLE_NAME))
+
+internal-all:: $(WOBUNDLE_NAME:=.all.wobundle.variables)
+
+internal-install:: $(WOBUNDLE_NAME:=.install.wobundle.variables)
+
+internal-uninstall:: $(WOBUNDLE_NAME:=.uninstall.wobundle.variables)
+
+internal-clean:: $(WOBUNDLE_NAME:=.clean.wobundle.subprojects)
+       rm -rf $(GNUSTEP_OBJ_DIR) \
+              $(addsuffix $(WOBUNDLE_EXTENSION),$(WOBUNDLE_NAME))
+
+internal-distclean:: $(WOBUNDLE_NAME:=.distclean.wobundle.subprojects)
+       rm -rf shared_obj static_obj shared_debug_obj shared_profile_obj \
+         static_debug_obj static_profile_obj shared_profile_debug_obj \
+         static_profile_debug_obj
+
+$(WOBUNDLE_NAME):
+       @$(MAKE) -f $(MAKEFILE_NAME) --no-print-directory \
+               $@.all.wobundle.variables
+else
+
+ifeq ($(GNUSTEP_TYPE),wobundle)
+ifeq ($(RULES_MAKE_LOADED),)
+include $(GNUSTEP_MAKEFILES)/rules.make
+endif
+
+# FIXME - this file has not been updated to use Shared/bundle.make
+# because it is using symlinks rather than copying resources.
+
+COMPONENTS = $($(GNUSTEP_INSTANCE)_COMPONENTS)
+LANGUAGES = $($(GNUSTEP_INSTANCE)_LANGUAGES)
+WEBSERVER_RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_WEBSERVER_RESOURCE_FILES)
+LOCALIZED_WEBSERVER_RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_LOCALIZED_WEBSERVER_RESOURCE_FILES)
+WEBSERVER_RESOURCE_DIRS = $($(GNUSTEP_INSTANCE)_WEBSERVER_RESOURCE_DIRS)
+LOCALIZED_RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_LOCALIZED_RESOURCE_FILES)
+RESOURCE_FILES = $($(GNUSTEP_INSTANCE)_RESOURCE_FILES)
+RESOURCE_DIRS = $($(GNUSTEP_INSTANCE)_RESOURCE_DIRS)
+
+include $(GNUSTEP_MAKEFILES)/Instance/Shared/headers.make
+
+ifeq ($(strip $(WOBUNDLE_EXTENSION)),)
+WOBUNDLE_EXTENSION = .wobundle
+endif
+
+WOBUNDLE_LD = $(BUNDLE_LD)
+WOBUNDLE_LDFLAGS = $(BUNDLE_LDFLAGS)
+
+ifeq ($(FOUNDATION_LIB),apple)
+WORSRCDIRINFIX:=Contents/Resources
+WORSRCLINKUP:=../../..
+else
+WORSRCDIRINFIX:=Resources
+WORSRCLINKUP:=../..
+endif
+
+ifeq ($(WOBUNDLE_INSTALL_DIR),)
+WOBUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Libraries
+endif
+# The name of the bundle is in the BUNDLE_NAME variable.
+# The list of languages the bundle is localized in are in xxx_LANGUAGES
+# The list of bundle resource file are in xxx_RESOURCE_FILES
+# The list of localized bundle resource file are in xxx_LOCALIZED_RESOURCE_FILES
+# The list of bundle resource directories are in xxx_RESOURCE_DIRS
+# The name of the principal class is xxx_PRINCIPAL_CLASS
+# The header files are in xxx_HEADER_FILES
+# The directory where the header files are located is xxx_HEADER_FILES_DIR
+# The directory where to install the header files inside the library
+# installation directory is xxx_HEADER_FILES_INSTALL_DIR
+# where xxx is the bundle name
+#  xxx_WEBSERVER_RESOURCE_DIRS <==
+# The list of localized application web server resource directories are in 
+#  xxx_LOCALIZED_WEBSERVER_RESOURCE_DIRS
+# where xxx is the application name <==
+
+.PHONY: internal-wobundle-all_ \
+        internal-wobundle-install_ \
+        internal-wobundle-uninstall_ \
+        build-bundle-dir \
+        build-bundle \
+        wobundle-components \
+        wobundle-resource-files \
+        wobundle-localized-resource-files \
+        wobundle-webresource-dir \
+        wobundle-webresource-files \
+        wobundle-localized-webresource-files
+
+# On Solaris we don't need to specifies the libraries the bundle needs.
+# How about the rest of the systems? ALL_BUNDLE_LIBS is temporary empty.
+TALL_WOBUNDLE_LIBS = $(ADDITIONAL_WO_LIBS) $(AUXILIARY_WO_LIBS) $(WO_LIBS) \
+       $(ADDITIONAL_BUNDLE_LIBS) $(AUXILIARY_BUNDLE_LIBS) \
+       $(FND_LIBS) $(ADDITIONAL_OBJC_LIBS) $(AUXILIARY_OBJC_LIBS) \
+       $(OBJC_LIBS) $(SYSTEM_LIBS) $(TARGET_SYSTEM_LIBS)
+#ALL_WOBUNDLE_LIBS = 
+ALL_WOBUNDLE_LIBS = \
+    $(shell $(WHICH_LIB_SCRIPT) $(ALL_LIB_DIRS) $(TALL_WOBUNDLE_LIBS) \
+       debug=$(debug) profile=$(profile) shared=$(shared) libext=$(LIBEXT) \
+       shared_libext=$(SHARED_LIBEXT))
+
+internal-wobundle-all_:: $(GNUSTEP_OBJ_DIR) \
+                          build-bundle-dir \
+                          build-bundle
+
+WOBUNDLE_DIR_NAME = $(GNUSTEP_INSTANCE:=$(WOBUNDLE_EXTENSION))
+WOBUNDLE_FILE = \
+    $(WOBUNDLE_DIR_NAME)/$(GNUSTEP_TARGET_LDIR)/$(GNUSTEP_INSTANCE)
+WOBUNDLE_RESOURCE_DIRS = $(foreach d, $(RESOURCE_DIRS), $(WOBUNDLE_DIR_NAME)/$(WORSRCDIRINFIX)/$(d))
+WOBUNDLE_WEBSERVER_RESOURCE_DIRS =  $(foreach d, $(WEBSERVER_RESOURCE_DIRS), $(WOBUNDLE_DIR_NAME)/Resources/WebServer/$(d))
+
+ifeq ($(strip $(LANGUAGES)),)
+  LANGUAGES="English"
+endif
+
+
+build-bundle-dir:: $(WOBUNDLE_DIR_NAME)/$(WORSRCDIRINFIX) \
+                   $(WOBUNDLE_DIR_NAME)/$(GNUSTEP_TARGET_LDIR) \
+                   $(WOBUNDLE_RESOURCE_DIRS)
+
+$(WOBUNDLE_DIR_NAME)/$(GNUSTEP_TARGET_LDIR):
+       @$(MKDIRS) $(WOBUNDLE_DIR_NAME)/$(GNUSTEP_TARGET_LDIR)
+
+$(WOBUNDLE_RESOURCE_DIRS):
+       @$(MKDIRS) $(WOBUNDLE_RESOURCE_DIRS)
+
+build-bundle:: $(WOBUNDLE_FILE) \
+               wobundle-components \
+               wobundle-resource-files \
+               wobundle-localized-resource-files \
+               wobundle-localized-webresource-files \
+               wobundle-webresource-files
+
+
+$(WOBUNDLE_FILE) : $(OBJ_FILES_TO_LINK)
+       $(WOBUNDLE_LD) $(WOBUNDLE_LDFLAGS) \
+                       $(ALL_LDFLAGS) -o $(LDOUT)$(WOBUNDLE_FILE) \
+                       $(OBJ_FILES_TO_LINK) \
+                       $(ALL_WOBUNDLE_LIBS)
+
+wobundle-components :: $(WOBUNDLE_DIR_NAME)
+ifneq ($(strip $(COMPONENTS)),)
+       @(echo "Linking components into the bundle wrapper..."; \
+        cd $(WOBUNDLE_DIR_NAME)/$(WORSRCDIRINFIX); \
+        for component in $(COMPONENTS); do \
+         if [ -d $(WORSRCLINKUP)/$$component ]; then \
+           $(LN_S) -f $(WORSRCLINKUP)/$$component ./;\
+         fi; \
+        done; \
+       echo "Linking localized components into the bundle wrapper..."; \
+        for l in $(LANGUAGES); do \
+         if [ -d $(WORSRCLINKUP)/$$l.lproj ]; then \
+           $(MKDIRS) $$l.lproj; \
+           cd $$l.lproj; \
+           for f in $(COMPONENTS); do \
+             if [ -d $(WORSRCLINKUP)/../$$l.lproj/$$f ]; then \
+               $(LN_S) -f $(WORSRCLINKUP)/../$$l.lproj/$$f .;\
+             fi;\
+           done;\
+           cd ..; \
+         fi;\
+       done)
+endif
+
+wobundle-resource-files:: $(WOBUNDLE_DIR_NAME)/bundle-info.plist \
+                           $(WOBUNDLE_DIR_NAME)/$(WORSRCDIRINFIX)/Info-gnustep.plist
+ifneq ($(strip $(RESOURCE_FILES)),)
+       @(echo "Linking resources into the bundle wrapper..."; \
+       cd $(WOBUNDLE_DIR_NAME)/$(WORSRCDIRINFIX)/; \
+       for ff in $(RESOURCE_FILES); do \
+         $(LN_S) -f $(WORSRCLINKUP)/$$ff .;\
+       done)
+endif
+
+wobundle-localized-resource-files:: $(WOBUNDLE_DIR_NAME)/$(WORSRCDIRINFIX)/Info-gnustep.plist
+ifneq ($(strip $(LOCALIZED_RESOURCE_FILES)),)
+       @(echo "Linking localized resources into the bundle wrapper..."; \
+       cd $(WOBUNDLE_DIR_NAME)/$(WORSRCDIRINFIX); \
+       for l in $(LANGUAGES); do \
+         if [ -d $(WORSRCLINKUP)/$$l.lproj ]; then \
+           $(MKDIRS) $$l.lproj; \
+           cd $$l.lproj; \
+           for f in $(LOCALIZED_RESOURCE_FILES); do \
+             if [ -f $(WORSRCLINKUP)/../$$l.lproj/$$f ]; then \
+               $(LN_S) -f $(WORSRCLINKUP)/../$$l.lproj/$$f .;\
+             fi;\
+           done;\
+           cd ..;\
+         else\
+          echo "Warning - $$l.lproj not found - ignoring";\
+         fi;\
+       done)
+endif
+
+wobundle-webresource-dir::
+       @$(MKDIRS) $(WOBUNDLE_WEBSERVER_RESOURCE_DIRS)
+
+wobundle-webresource-files:: $(WOBUNDLE_DIR_NAME)/Resources/WebServer \
+                              wobundle-webresource-dir
+ifneq ($(strip $(WEBSERVER_RESOURCE_FILES)),)
+       @(echo "Linking webserver resources into the application wrapper..."; \
+       cd $(WOBUNDLE_DIR_NAME)/Resources/WebServer; \
+       for ff in $(WEBSERVER_RESOURCE_FILES); do \
+         $(LN_S) -f ../../WebServerResources/$$ff .;\
+       done)
+endif
+
+wobundle-localized-webresource-files:: $(WOBUNDLE_DIR_NAME)/Resources/WebServer \
+                                        wobundle-webresource-dir
+ifneq ($(strip $(LOCALIZED_WEBSERVER_RESOURCE_FILES)),)
+       @(echo "Linking localized web resources into the application wrapper..."; \
+       cd $(WOBUNDLE_DIR_NAME)/Resources/WebServer; \
+       for l in $(LANGUAGES); do \
+         if [ -d ../../WebServerResources/$$l.lproj ]; then \
+           $(MKDIRS) $$l.lproj; \
+           cd $$l.lproj; \
+           for f in $(LOCALIZED_WEBSERVER_RESOURCE_FILES); do \
+             if [ -f ../../../WebServerResources/$$l.lproj/$$f ]; then \
+               if [ ! -r $$f ]; then \
+                 $(LN_S) ../../../WebServerResources/$$l.lproj/$$f $$f;\
+               fi;\
+             fi;\
+           done;\
+           cd ..; \
+         else \
+           echo "Warning - WebServerResources/$$l.lproj not found - ignoring";\
+         fi;\
+       done)
+endif
+
+PRINCIPAL_CLASS = $(strip $($(GNUSTEP_INSTANCE)_PRINCIPAL_CLASS))
+
+ifeq ($(PRINCIPAL_CLASS),)
+  PRINCIPAL_CLASS = $(GNUSTEP_INSTANCE)
+endif
+
+$(WOBUNDLE_DIR_NAME)/bundle-info.plist: $(WOBUNDLE_DIR_NAME)
+       @(cd $(WOBUNDLE_DIR_NAME); $(LN_S) -f ../bundle-info.plist .)
+
+HAS_WOCOMPONENTS = $($(GNUSTEP_INSTANCE)_HAS_WOCOMPONENTS)
+
+$(WOBUNDLE_DIR_NAME)/$(WORSRCDIRINFIX)/Info-gnustep.plist: $(WOBUNDLE_DIR_NAME)/$(WORSRCDIRINFIX)
+       @(echo "{"; echo '  NOTE = "Automatically generated, do not edit!";'; \
+         echo "  NSExecutable = \"$(GNUSTEP_INSTANCE)\";"; \
+         echo "  NSPrincipalClass = \"$(PRINCIPAL_CLASS)\";"; \
+         if [ "$(HAS_WOCOMPONENTS)" != "" ]; then \
+           echo "  HasWOComponents = \"$(HAS_WOCOMPONENTS)\";"; \
+         fi; \
+         echo "}") >$@
+
+$(WOBUNDLE_DIR_NAME)/$(WORSRCDIRINFIX):
+       @$(MKDIRS) $@
+
+$(WOBUNDLE_DIR_NAME)/Resources/WebServer:
+       @$(MKDIRS) $@
+
+internal-wobundle-install_:: $(WOBUNDLE_INSTALL_DIR) shared-instance-headers-install
+       rm -rf $(WOBUNDLE_INSTALL_DIR)/$(WOBUNDLE_DIR_NAME); \
+       $(TAR) chf - --exclude=CVS --to-stdout $(WOBUNDLE_DIR_NAME) | (cd $(WOBUNDLE_INSTALL_DIR); $(TAR) xf -)
+ifneq ($(CHOWN_TO),)
+       $(CHOWN) -R $(CHOWN_TO) $(WOBUNDLE_INSTALL_DIR)/$(WOBUNDLE_DIR_NAME)
+endif
+ifeq ($(strip),yes)
+       $(STRIP) $(WOBUNDLE_INSTALL_DIR)/$(WOBUNDLE_FILE) 
+endif
+
+$(WOBUNDLE_INSTALL_DIR)::
+       @$(MKINSTALLDIRS) $@
+
+internal-wobundle-uninstall_:: shared-instance-headers-uninstall
+       rm -rf $(WOBUNDLE_INSTALL_DIR)/$(WOBUNDLE_DIR_NAME)
+endif
+
+endif
+
+## Local variables:
+## mode: makefile
+## End:
diff --git a/skyrix-sope/NGObjWeb/wobundle.make b/skyrix-sope/NGObjWeb/wobundle.make
new file mode 100644 (file)
index 0000000..825bfb9
--- /dev/null
@@ -0,0 +1,34 @@
+#
+#   wobundle.make
+#
+#   Makefile rules to build GNUstep web bundles.
+#
+#   Copyright (C) 2002 Free Software Foundation, Inc.
+#
+#   Author:  Nicola Pero <nicola@brainstorm.co.uk>
+#
+#   This file is part of the GNUstep Makefile Package.
+#
+#   This library 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
+#   of the License, or (at your option) any later version.
+#   
+#   You should have received a copy of the GNU General Public
+#   License along with this library; see the file COPYING.LIB.
+#   If not, write to the Free Software Foundation,
+#   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ifeq ($(GNUSTEP_INSTANCE),)
+include $(GNUSTEP_MAKEFILES)/Master/wobundle.make
+else
+
+ifeq ($(GNUSTEP_TYPE),wobundle)
+include $(GNUSTEP_MAKEFILES)/Instance/wobundle.make
+endif
+
+endif
+
+## Local variables:
+## mode: makefile
+## End:
diff --git a/skyrix-sope/NGObjWeb/wod.m b/skyrix-sope/NGObjWeb/wod.m
new file mode 100644 (file)
index 0000000..8ea472e
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <Foundation/Foundation.h>
+#include "WODParser.h"
+
+@interface MyWODHandler : NSObject < WODParserHandler >
+@end
+
+@implementation MyWODHandler
+
+- (BOOL)parser:(id)_parser willParseDeclarationData:(NSData *)_data {
+  return YES;
+}
+- (void)parser:(id)_parser finishedParsingDeclarationData:(NSData *)_data
+  declarations:(NSDictionary *)_decls
+{
+}
+- (void)parser:(id)_parser failedParsingDeclarationData:(NSData *)_data
+  exception:(NSException *)_exception
+{
+  [_exception raise];
+}
+
+- (id)parser:(id)_parser makeAssociationWithValue:(id)_value {
+  return nil;
+}
+- (id)parser:(id)_parser makeAssociationWithKeyPath:(NSString *)_keyPath {
+  return nil;
+}
+- (id)parser:(id)_parser makeDefinitionForComponentNamed:(NSString *)_cname
+  associations:(id)_entry
+  elementName:(NSString *)_elemName
+{
+  return nil;
+}
+
+@end /* MyWODHandler */
+
+static void processFile(NSString *path) {
+  NSUserDefaults *ud;
+  NSData         *data;
+  NSDictionary   *mappings;
+  NSException    *e;
+  MyWODHandler   *wodHandler;
+
+  wodHandler = [[[MyWODHandler alloc] init] autorelease];
+  ud         = [NSUserDefaults standardUserDefaults];
+  mappings   = nil;
+  e          = nil;
+  
+  if ((data = [NSData dataWithContentsOfFile:path]) == nil) {
+    fprintf(stderr, "%s: could not open file.\n", [path cString]);
+    fflush(stderr);
+    return;
+  }
+  if ([data length] == 0)
+    /* no content */
+    return;
+  
+  NS_DURING {
+    id parser;
+
+    parser = [[[WODParser alloc] initWithHandler:(id)wodHandler] autorelease];
+    
+    mappings = [parser parseDeclarationData:data];
+  }
+  NS_HANDLER {
+    e = [localException retain];
+    //abort();
+  }
+  NS_ENDHANDLER;
+  
+  if (e) {
+    NSDictionary *ui;
+    int line = -1;
+    
+    if ((ui = [e userInfo]))
+      line = [[ui objectForKey:@"line"] intValue];
+
+    if (line > 0) {
+      fprintf(stderr, "%s:%i: %s\n",
+              [path cString], line,
+              [[e reason] cString]);
+    }
+    else {
+      fprintf(stderr, "%s: %s\n",
+              [path cString],
+              [[e reason] cString]);
+    }
+  }
+  
+  if ([ud objectForKey:@"print"]) {
+    NSEnumerator *e;
+    NSString *key;
+
+    e = [mappings keyEnumerator];
+    while ((key = [e nextObject])) {
+      id value;
+      
+      value = [mappings objectForKey:key];
+      printf("%s: %s\n", [key cString], [[value description] cString]);
+    }
+  }
+  
+  if ([ud objectForKey:@"list"]) {
+    id       keys;
+    NSString *key;
+
+    keys = [mappings allKeys];
+    keys = [keys sortedArrayUsingSelector:@selector(compare:)];
+    keys = [keys objectEnumerator];
+    
+    while ((key = [keys nextObject])) {
+      id value;
+      
+      value = [mappings objectForKey:key];
+      printf("%s: %s\n", [key cString], [[value description] cString]);
+    }
+  }
+}
+
+int main(int argc, char **argv, char **env) {
+  NSUserDefaults *ud;
+  NSAutoreleasePool *pool;
+  NSArray      *args;
+  id           paths;
+  NSString     *path;
+  int          i;
+  
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  pool = [[NSAutoreleasePool alloc] init];
+  args = [[NSProcessInfo processInfo] arguments];
+
+  if (argc < 1)
+    exit(0);
+  
+  ud    = [NSUserDefaults standardUserDefaults];
+  *(&paths) = [NSMutableArray array];
+
+  for (*(&i) = 1; i < argc; i++) {
+    if (argv[i][0] == '-') {
+      NS_DURING 
+        [ud setObject:[NSNumber numberWithBool:YES]
+            forKey:[NSString stringWithCString:&(argv[i][1])]];
+      NS_HANDLER
+        abort();
+      NS_ENDHANDLER;
+    }
+    else {
+      [paths addObject:[NSString stringWithCString:argv[i]]];
+    }
+  }
+  paths = [paths objectEnumerator];
+  
+  while ((path = [paths nextObject])) {
+    NSAutoreleasePool *pool2;
+
+    pool2 = [[NSAutoreleasePool alloc] init];
+    processFile(path);
+    [pool2 release];
+  }
+  
+  [pool release];
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-sope/NGObjWeb/xmlrpc_call.m b/skyrix-sope/NGObjWeb/xmlrpc_call.m
new file mode 100644 (file)
index 0000000..2adc614
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+  Copyright (C) 2000-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$
+
+/*
+  xmlrpc_call
+  
+  A neat tool to call XML-RPC servers from the shell.
+
+  Defaults:
+    login     - string
+    password  - string
+    forceauth - bool   - send the credentials in the first request!
+*/
+
+#include <NGXmlRpc/NGXmlRpcClient.h>
+#include "common.h"
+
+#include <NGExtensions/NSString+Ext.h>
+
+#if !LIB_FOUNDATION_LIBRARY
+#  include "UnixSignalHandler.h"
+#endif
+
+@class WOResponse;
+
+@interface NGXmlRpcClient(CallFailed)
+- (id)callFailed:(WOResponse *)_response;
+@end /* NGXmlRpcClient */
+
+@class HandleCredentialsClient;
+
+@interface XmlRpcClient : NSObject
+{
+  HandleCredentialsClient  *client;
+  NSString                 *methodName;
+  NSArray                  *parameters;
+}
+
+/* initialization */
+
+- (id)initWithArguments:(NSArray *)_arguments;
+- (void)initMethodCall:(NSArray *)_arguments;
+- (BOOL)initXmlRpcClientWithStringURL:(NSString *)_url;
+
+- (int)run;
+- (void)help:(NSString *)pn;
+
+- (void)printElement:(id)_element;
+- (void)printDictionary:(NSDictionary *)_dict;
+- (void)printArray:(NSArray *)_array;
+
+@end /* XmlRpcClient */
+
+@implementation NSObject(Printing)
+
+- (void)printWithTool:(XmlRpcClient *)_tool {
+  printf("%s\n", [[self description] cString]);
+}
+
+@end /* NSObject(Printing) */
+
+@implementation NSData(Printing)
+
+- (void)printWithTool:(XmlRpcClient *)_tool {
+  fwrite([self bytes], [self length], 1, stdout);
+}
+
+@end /* NSData(Printing) */
+
+@implementation NSDictionary(Printing)
+
+- (void)printWithTool:(XmlRpcClient *)_tool {
+  [_tool printDictionary:self];
+}
+
+@end /* NSDictionary(Printing) */
+
+@implementation NSArray(Printing)
+
+- (void)printWithTool:(XmlRpcClient *)_tool {
+  [_tool printArray:self];
+}
+
+@end /* NSArray(Printing) */
+
+@implementation NSException(Printing)
+
+- (void)printWithTool:(XmlRpcClient *)_tool {
+  printf("Exception caught\nName  : %s\nReason: %s\n",
+         [[self name] cString], [[self reason] cString]);
+}
+
+@end /* NSException(Printing) */
+
+@interface HandleCredentialsClient : NGXmlRpcClient
+{
+  NSString *defLogin;
+  NSString *defPassword;
+}
+
+/* accessors */
+
+- (void)setDefLogin:(NSString *)_login;
+- (void)setDefPassword:(NSString *)_pwd;
+
+@end /* HandleCredentialsClient */
+
+#include <unistd.h>
+#include <NGObjWeb/WOResponse.h>
+
+@implementation HandleCredentialsClient
+
+- (void)dealloc {
+  [self->defLogin    release];
+  [self->defPassword release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setDefLogin:(NSString *)_login {
+  ASSIGNCOPY(self->defLogin, _login);
+}
+- (void)setDefPassword:(NSString *)_pwd {
+  ASSIGNCOPY(self->defPassword, _pwd);
+}
+
+/* prompting */
+
+- (NSString *)prompt:(NSString *)_prompt {
+  NSString *login;
+  char clogin[256];
+  
+  fprintf(stderr, "%s", [_prompt cString]);
+  fflush(stderr);
+  fgets(clogin, 200, stdin);
+  clogin[strlen(clogin) - 1] = '\0';
+  login = [NSString stringWithCString:clogin];
+  return login;
+}
+
+- (NSString *)promptPassword:(NSString *)_prompt {
+  NSString *pwd;
+  char     *cpwd;
+
+  cpwd = getpass("password: ");
+  pwd = [NSString stringWithCString:cpwd];
+  return pwd;
+}
+
+- (id)callFailed:(WOResponse *)_response {
+  if ([_response status] == 401) {
+    NSString *wwwauth;
+    NSString *user;
+    NSString *pass;
+    
+    wwwauth = [_response headerForKey:@"www-authenticate"];
+    if ([[wwwauth lowercaseString] hasPrefix:@"digest"])
+      [self logWithFormat:@"Digest authentication:\n'%@'", wwwauth];
+
+    // TODO: test credentials of URL
+    
+    if (self->defLogin) {
+      user = [self->defLogin autorelease];
+      self->defLogin = nil;
+    }
+    else
+      user = [self prompt:@"login:    "];
+    
+    if (self->defPassword) {
+      pass = [self->defPassword autorelease];
+      self->defPassword = nil;
+    }
+    else
+      pass = [self promptPassword:@"password: "];
+    
+    [self setUserName:user];
+    [self setPassword:pass];
+    
+    /* this "should" return some kind of "need-pwd" object ... */
+    return nil;
+  }
+  else {
+    return [super callFailed:_response];
+  }
+}
+
+@end /* HandleCredentialsClient */
+
+#import <Foundation/NSObject.h>
+#include "common.h"
+
+#define EXIT_FAIL -1
+
+@implementation XmlRpcClient
+
+/* initialization */
+
+- (id)init {
+  return [self initWithArguments:nil];
+}
+
+- (id)initWithArguments:(NSArray *)_arguments {
+  if ((self = [super init])) {
+    NSUserDefaults *ud;
+    NSString *s;
+    int argc;
+
+    argc = [_arguments count];
+    if(argc == 1) {
+      [self help:[_arguments objectAtIndex:0]];
+      return nil;
+    }
+    
+    s = [_arguments objectAtIndex:1];
+    if (![self initXmlRpcClientWithStringURL:s]) {
+      printf("Error initializing the XML-RPC client\n");
+      [self release];
+      return nil;
+    }
+    
+    if (argc > 2) {
+      [self initMethodCall:_arguments];
+    }
+    else {
+      self->methodName = @"system.listMethods";
+      self->parameters = nil;
+    }
+    
+    ud = [NSUserDefaults standardUserDefaults];
+    if ([ud boolForKey:@"forceauth"]) {
+      [self->client setUserName:[ud stringForKey:@"login"]];
+      [self->client setPassword:[ud stringForKey:@"password"]];
+    }
+    else {
+      [self->client setDefLogin:[ud stringForKey:@"login"]];
+      [self->client setDefPassword:[ud stringForKey:@"password"]];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->client      release];
+  [self->methodName  release];
+  [self->parameters  release];
+  [super dealloc];
+}
+
+//
+
+- (BOOL)initXmlRpcClientWithStringURL:(NSString *)_url {
+  NSURL *url = nil;
+  
+  if (![_url isAbsoluteURL]) {
+    /* make a raw, Unix domain socket connection */
+    NGLocalSocketAddress *addr;
+    
+    addr = [NGLocalSocketAddress addressWithPath:_url];
+    self->client = [[HandleCredentialsClient alloc] initWithRawAddress:addr];
+    return YES;
+  }
+  
+  if ((url = [NSURL URLWithString:_url]) != nil) {
+#if 0
+    if ((uri = [url path]) == nil)
+      uri = @"/RPC2";
+#endif
+    
+    self->client = [[HandleCredentialsClient alloc] initWithURL:url];
+    return YES;
+
+  }
+  else {
+    printf("Invalid URL\n");
+    return NO;
+  }
+}
+
+- (void)initMethodCall:(NSArray *)_arguments {
+  self->methodName = [_arguments objectAtIndex:2];
+
+  if ([_arguments count] > 2) {
+    NSRange range = NSMakeRange(3, [_arguments count] - 3);
+    self->parameters = [[_arguments subarrayWithRange:range] retain];
+  }
+}
+
+- (void)printElement:(id)element {
+  [element printWithTool:self];
+}
+
+/* printing objects */
+
+- (void)printDictionary:(NSDictionary *)_dict {
+  NSEnumerator *dictEnum;
+  id dictKey;
+
+  dictEnum = [_dict keyEnumerator];
+
+  while((dictKey = [dictEnum nextObject])) {
+    printf("%s=", [dictKey cString]);    
+    [self printElement:[_dict objectForKey:dictKey]];
+  }
+}
+
+- (void)printArray:(NSArray *)_array {
+  NSEnumerator *arrayEnum;
+  id arrayElem;
+  
+  arrayEnum = [_array objectEnumerator];
+  while((arrayElem = [arrayEnum nextObject])) {
+    [self printElement:arrayElem];
+  }
+}
+
+- (void)help:(NSString *)pn {
+  fprintf(stderr,
+          "usage:    %s <url> [<method-name>] [<arg1>,...]\n"
+          "  sample: %s http://localhost:20000/RPC2 bc 1 2\n",
+          [pn cString], [pn cString]);
+}
+
+- (int)run {
+  int  exitCode  = 0;
+  int  loopCount = 0;
+  id   result;
+
+  if (self->client == nil) {
+    NSLog(@"missing XML-RPC client object ...");
+    return EXIT_FAIL;
+  }
+  
+  do {
+    result = [self->client
+                  invokeMethodNamed:self->methodName
+                  parameters:self->parameters];
+    loopCount++;
+  }
+  while ((result == nil) && loopCount < 20);
+
+  if (result == nil) {
+    NSLog(@"call failed, no result (looped %i times) ?!", loopCount);
+    return EXIT_FAIL;
+  }
+  
+  [self printElement:result];
+  
+  if ([result isKindOfClass:[NSException class]]) {
+    exitCode = 255;
+  }
+
+  return exitCode;
+}
+
+@end /* XmlRpcClient */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  XmlRpcClient      *client;
+  NSArray           *arguments;
+  int               exitCode;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS)
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  /* our sockets need to know, if the PIPE is broken */
+  signal(SIGPIPE, SIG_IGN);
+
+  arguments = [[NSProcessInfo processInfo] argumentsWithoutDefaults];
+  if ((client = [[XmlRpcClient alloc] initWithArguments:arguments]) == nil)
+    exitCode = 2;
+  else
+    exitCode =  [client run];
+  
+  [client release];
+  [pool   release];
+  
+  exit(exitCode);
+  return exitCode;
+}
diff --git a/skyrix-sope/NGScripting/.cvsignore b/skyrix-sope/NGScripting/.cvsignore
new file mode 100644 (file)
index 0000000..49a10b1
--- /dev/null
@@ -0,0 +1,2 @@
+shared_debug_obj
+shared_obj
diff --git a/skyrix-sope/NGScripting/COPYING b/skyrix-sope/NGScripting/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/NGScripting/ChangeLog b/skyrix-sope/NGScripting/ChangeLog
new file mode 100644 (file)
index 0000000..9e9aaa7
--- /dev/null
@@ -0,0 +1,41 @@
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile.preamble: added prebinding (v4.2.10)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.9)
+
+2003-07-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * applied GNUstep patches provided by Filip Van Raemdonck for improved
+         compilation with gstep-base (v4.2.8)
+
+2003-04-01  GNUstep User  <helge.hess@skyrix.com>
+
+       * common.h: fixed for gstep-base compilation (v4.2.7)
+
+2002-12-02  Helge Hess  <helge.hess@skyrix.com>
+       
+       * moved to skyrix-sope-42 (v4.2.6)
+       
+2002-08-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGScriptLanguage.m: added -copyWithZone: to make it possible to
+         add NGScriptLanguage objects to MacOSX Foundation collections
+
+       * NGObjectMappingContext.m: added debug logging of context stack
+         changes (v4.2.5)
+
+2002-08-20  Helge Hess  <helge.hess@skyrix.com>
+
+       * NGScriptLanguage, NGObjectMappingContext: added NSCoding to support
+         archiving in InterfaceBuilder
+
+Mon Jun 10 13:01:58 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * created ChangeLog
+
+
diff --git a/skyrix-sope/NGScripting/GNUmakefile b/skyrix-sope/NGScripting/GNUmakefile
new file mode 100644 (file)
index 0000000..58febd1
--- /dev/null
@@ -0,0 +1,28 @@
+# $Id$
+
+include ../common.make
+
+#ADDITIONAL_CPPFLAGS += -DTRACK_JSMEM=1 -DTRACK_JSMEM_RC=1
+
+LIBRARY_NAME = libNGScripting
+
+libNGScripting_HEADER_FILES_DIR         = .
+libNGScripting_HEADER_FILES_INSTALL_DIR = /NGScripting
+libNGScripting_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libNGScripting_HEADER_FILES = \
+       NSObject+Scripting.h                    \
+       NGObjectMappingContext.h                \
+       NGScriptLanguage.h                      \
+
+libNGScripting_OBJC_FILES = \
+       NSObject+Scripting.m            \
+       NGObjectMappingContext.m        \
+       NGScriptLanguage.m              \
+
+autodoc :
+       autodoc $(AUTODOC_FLAGS) -dest $(AUTODOC_DESTPATH)/NGScripting/ -proj .
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/NGScripting/GNUmakefile.preamble b/skyrix-sope/NGScripting/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..7e39eb0
--- /dev/null
@@ -0,0 +1,32 @@
+# $Id$
+
+ADDITIONAL_LIB_DIRS += -L$(GNUSTEP_OBJ_DIR)
+
+ADDITIONAL_CPPFLAGS += -Wall
+
+libNGScripting_LIBRARIES_DEPEND_UPON += \
+       -lNGExtensions -lEOControl      \
+       -lDOM -lSaxObjC
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/../../skyrix-core
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+libNGScripting_LIB_DIRS += \
+       -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+       -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)             \
+       -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+libNGScripting_LIB_DIRS += \
+       -L../NGExtensions/$(GNUSTEP_OBJ_DIR) \
+       -L../EOControl/$(GNUSTEP_OBJ_DIR)
+endif
+
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libNGScripting_PREBIND_ADDR="0xC3000000"
+libNGScripting_LDFLAGS += -seg1addr $(libNGScripting_PREBIND_ADDR)
+endif
diff --git a/skyrix-sope/NGScripting/NGObjectMappingContext.h b/skyrix-sope/NGScripting/NGObjectMappingContext.h
new file mode 100644 (file)
index 0000000..e9e72f7
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGObjectMappingContext_H__
+#define __NGObjectMappingContext_H__
+
+#import <Foundation/NSObject.h>
+
+@interface NGObjectMappingContext : NSObject < NSCoding >
+{
+@public
+  /* method cache */
+  id (*objForHandle)(id,SEL,void *);
+  void *(*handleForObj)(id,SEL,id);
+}
+
+/* mapping */
+
+- (void *)handleForObject:(id)_object;
+- (id)objectForHandle:(void *)_handle;
+
+- (void)forgetObject:(id)_object;
+- (void)forgetHandle:(void *)_handle;
+
+/* context stack */
+
++ (id)activeObjectMappingContext;
+
+- (void)pushContext;
+- (id)popContext;
+
+- (void)collectGarbage; /* can be run async (active ctx will match) */
+
+@end
+
+/* functions which operate on the current context */
+
+extern id   NGObjectMapping_GetObjectForHandle(void *_object);
+extern void *NGObjectMapping_GetHandleForObject(id _object);
+
+#endif /* __NGObjectMappingContext_H__ */
diff --git a/skyrix-sope/NGScripting/NGObjectMappingContext.m b/skyrix-sope/NGScripting/NGObjectMappingContext.m
new file mode 100644 (file)
index 0000000..4ccd0e8
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGObjectMappingContext.h"
+#include "common.h"
+
+#define MAX_CONTEXT_DEPTH 16
+
+@implementation NGObjectMappingContext
+
+- (id)init {
+  self->objForHandle =
+    (void *)[self methodForSelector:@selector(objectForHandle:)];
+  self->handleForObj =
+    (void *)[self methodForSelector:@selector(handleForObject:)];
+  return self;
+}
+
+/* mappings */
+
+- (void *)handleForObject:(id)_object {
+#if LIB_FOUNDATION_LIBRARY
+  return [self subclassResponsibility:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+  return NULL;
+#endif
+}
+- (id)objectForHandle:(void *)_handle {
+#if LIB_FOUNDATION_LIBRARY
+  return [self subclassResponsibility:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+#endif
+}
+
+- (void)forgetObject:(id)_object {
+}
+- (void)forgetHandle:(void *)_handle {
+}
+
+/* context stack */
+
+static NGObjectMappingContext **ctxs; // THREAD
+static unsigned currentContextDepth = 0;
+
++ (id)activeObjectMappingContext { // THREAD
+  return currentContextDepth > 0
+    ? ctxs[currentContextDepth - 1]
+    : nil;
+}
+
+- (void)pushContext { // THREAD
+  if (ctxs == NULL) ctxs = calloc(MAX_CONTEXT_DEPTH, sizeof(id));
+  ctxs[currentContextDepth] = [self retain];
+  currentContextDepth++;
+
+#if DEBUG_CTX_STACK
+  if (currentContextDepth == 1)
+    printf("PUSHED first 0x%08X\n", self);
+  else
+    printf("PUSHED[%i]: 0x%08X, prev 0x%08X", 
+           currentContextDepth, self, ctxs[currentContextDepth - 2]);
+  
+  NSAssert([[self class] activeObjectMappingContext] == self,
+           @"failed to push self as active mapping context !");
+#endif
+}
+- (id)popContext { // THREAD
+  NSAssert(currentContextDepth > 0,
+           @"no context is active !");
+  NSAssert2(ctxs[currentContextDepth - 1] == self,
+            @"current context is not the active context (%@ vs %@) !",
+            ctxs[currentContextDepth - 1], self);
+  
+#if DEBUG_CTX_STACK
+  if (currentContextDepth == 1)
+    printf("POP first 0x%08X\n", self);
+  else
+    printf("POP[%i]: 0x%08X, activate 0x%08X", 
+           currentContextDepth, self, ctxs[currentContextDepth - 2]);
+#endif
+  currentContextDepth--;
+  ctxs[currentContextDepth] = nil;
+  return [self autorelease];
+}
+
+- (void)collectGarbage {
+}
+
+/* NSCoding */
+
+- (id)initWithCoder:(NSCoder *)_coder {
+  id ctx;
+  
+  /* if an context is active, use that */
+  if ((ctx = [[self class] activeObjectMappingContext])) {
+    [self release];
+    return [ctx retain];
+  }
+  
+  /* otherwise init a new context ... */
+  return [self init];
+}
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  /* no ivars to encode ... */
+}
+
+@end /* NGObjectMappingContext */
+
+id NGObjectMapping_GetObjectForHandle(void *_handle) {
+  register NGObjectMappingContext *ctx;
+  
+  if (currentContextDepth < 1) return nil;
+  ctx = ctxs[currentContextDepth - 1];
+  
+  return ctx->objForHandle(ctx, @selector(objectForHandle:), _handle);
+}
+void *NGObjectMapping_GetHandleForObject(id _object) {
+  register NGObjectMappingContext *ctx;
+  
+  if (currentContextDepth < 1) return nil;
+  ctx = ctxs[currentContextDepth - 1];
+  
+  return ctx->handleForObj(ctx, @selector(handleForObject:), _object);
+}
diff --git a/skyrix-sope/NGScripting/NGScriptLanguage.h b/skyrix-sope/NGScripting/NGScriptLanguage.h
new file mode 100644 (file)
index 0000000..8711f82
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NGScriptLanguage_H__
+#define __NGScriptLanguage_H__
+
+#import <Foundation/NSObject.h>
+
+@class NGObjectMappingContext;
+
+@interface NGScriptLanguage : NSObject < NSCoding >
+
++ (id)languageWithName:(NSString *)_language;
+- (id)initWithLanguage:(NSString *)_language;
+
+/* evaluation */
+
+- (id)evaluateScript:(NSString *)_script onObject:(id)_object
+  source:(NSString *)_source line:(unsigned)_line;
+
+/* function calls */
+
+- (id)callFunction:(NSString *)_func onObject:(id)_object;
+- (id)callFunction:(NSString *)_func withArgument:(id)_arg0 onObject:(id)_o; 
+- (id)callFunction:(NSString *)_func
+  withArgument:(id)_arg0
+  withArgument:(id)_arg1
+  onObject:(id)_object;
+
+/* reflection */
+
+- (BOOL)object:(id)_object hasFunctionNamed:(NSString *)_name;
+
+/* shadow objects */
+
+- (id)createShadowForMaster:(id)_master; /* returns a retained object */
+
+/* object mapping */
+
+- (NGObjectMappingContext *)activeMappingContext;
+- (NGObjectMappingContext *)createMappingContext; // result is retained!
+
+@end
+
+/*
+  Shadow objects are always tied to a specific language ...
+*/
+
+@protocol NGScriptShadow
+
+- (void)invalidateShadow;
+
+- (id)evaluateScript:(NSString *)_script;
+- (id)callScriptFunction:(NSString *)_func;
+- (BOOL)hasFunctionNamed:(NSString *)_func;
+
+@end
+
+#endif /* __NGScriptLanguage_H__ */
diff --git a/skyrix-sope/NGScripting/NGScriptLanguage.m b/skyrix-sope/NGScripting/NGScriptLanguage.m
new file mode 100644 (file)
index 0000000..7600c92
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGScriptLanguage.h"
+#include "NSObject+Scripting.h"
+#include "NGObjectMappingContext.h"
+#include "common.h"
+
+@implementation NGScriptLanguage
+
+static id js = nil;
+
++ (id)languageWithName:(NSString *)_language {
+  if ([_language length] == 0) 
+    _language = [NSObject defaultScriptLanguage];
+
+  if (![_language hasPrefix:@"javascript"])
+    return nil;
+  
+  if (js == nil) {
+    js = [[NSClassFromString(@"NGJavaScriptLanguage") alloc] 
+            initWithLanguage:_language];
+  }
+  return js;
+}
+
+- (id)initWithLanguage:(NSString *)_language {
+  return self;
+}
+- (id)init {
+  return [self initWithLanguage:nil];
+}
+
+- (NSString *)language {
+  return nil;
+}
+
+/* evaluation */
+
+- (id)evaluateScript:(NSString *)_script onObject:(id)_object 
+  source:(NSString *)_source line:(unsigned)_line
+{
+#if LIB_FOUNDATION_LIBRARY
+  return [self subclassResponsibility:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+  return NULL;
+#endif
+}
+- (id)evaluateScript:(NSString *)_script onObject:(id)_object {
+  /* deprecated, use the method above */
+  return [self evaluateScript:_script onObject:_object
+              source:@"<string>" line:0];
+}
+
+/* function calls */
+
+- (id)callFunction:(NSString *)_func onObject:(id)_object {
+#if LIB_FOUNDATION_LIBRARY
+  return [self subclassResponsibility:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+  return NULL;
+#endif
+}
+- (id)callFunction:(NSString *)_func withArgument:(id)_arg0 onObject:(id)_o {
+#if LIB_FOUNDATION_LIBRARY
+  return [self subclassResponsibility:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+  return NULL;
+#endif
+}
+- (id)callFunction:(NSString *)_func
+  withArgument:(id)_arg0
+  withArgument:(id)_arg1
+  onObject:(id)_object
+{
+#if LIB_FOUNDATION_LIBRARY
+  return [self subclassResponsibility:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+  return NULL;
+#endif
+}
+
+/* reflection */
+
+- (BOOL)object:(id)_object hasFunctionNamed:(NSString *)_name {
+  return NO;
+}
+
+/* shadow objects */
+
+- (id)createShadowForMaster:(id)_master {
+#if LIB_FOUNDATION_LIBRARY
+  return [self subclassResponsibility:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+  return NULL;
+#endif
+}
+
+/* NSCoding */
+
+- (id)initWithCoder:(NSCoder *)_coder {
+  NSString *lang;
+  
+  [self autorelease];
+  
+  lang = [_coder decodeObject];
+  return [[NGScriptLanguage languageWithName:lang] retain];
+}
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:[self language]];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone { // to make Foundation happy
+  return [self retain];
+}
+
+/* object mapping */
+
+- (NGObjectMappingContext *)activeMappingContext {
+  return [NGObjectMappingContext activeObjectMappingContext];
+}
+- (NGObjectMappingContext *)createMappingContext {
+#if LIB_FOUNDATION_LIBRARY
+  return [self subclassResponsibility:_cmd];
+#else
+  [self doesNotRecognizeSelector:_cmd];
+  return NULL;
+#endif
+}
+
+@end /* NGScriptLanguage */
diff --git a/skyrix-sope/NGScripting/NGScripting-Info.plist b/skyrix-sope/NGScripting/NGScripting-Info.plist
new file mode 100644 (file)
index 0000000..642a350
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGScripting</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.NGScripting</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/NGScripting/NSObject+Scripting.h b/skyrix-sope/NGScripting/NSObject+Scripting.h
new file mode 100644 (file)
index 0000000..020aa31
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NSObject_Scripting_H__
+#define __NSObject_Scripting_H__
+
+#import <Foundation/NSObject.h>
+
+@interface NSObject(ScriptingSupport)
+
++ (NSString *)defaultScriptLanguage;
+
+/* evaluation with 'self' as JS 'this' */
+
+- (id)evaluateScript:(NSString *)_script language:(NSString *)_lang 
+  source:(NSString *)_src line:(unsigned)_line;
+- (id)evaluateScript:(NSString *)_script language:(NSString *)_lang;
+
+/* script functions */
+
+- (id)callScriptFunction:(NSString *)_func language:(NSString *)_language;
+- (id)callScriptFunction:(NSString *)_func language:(NSString *)_language
+  withObject:(id)_arg0;
+- (id)callScriptFunction:(NSString *)_func language:(NSString *)_language
+  withObject:(id)_arg0
+  withObject:(id)_arg1;
+
+@end
+
+#endif /* __NSObject_Scripting_H__ */
diff --git a/skyrix-sope/NGScripting/NSObject+Scripting.m b/skyrix-sope/NGScripting/NSObject+Scripting.m
new file mode 100644 (file)
index 0000000..ec3a95b
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NGScriptLanguage.h"
+#include "common.h"
+#import <EOControl/EOControl.h>
+
+@implementation NSObject(ScriptingSupport)
+
+/* evaluation */
+
++ (NSString *)defaultScriptLanguage {
+  return @"javascript";
+}
+
+- (id)evaluateScript:(NSString *)_script language:(NSString *)_lang 
+  source:(NSString *)_src line:(unsigned)_line 
+{
+  NGScriptLanguage *l;
+  
+  if ((l = [NGScriptLanguage languageWithName:_lang]) == nil) {
+    NSLog(@"%s: cannot evaluate script, language '%@' unknown",
+         __PRETTY_FUNCTION__, _lang);
+    return nil;
+  }
+  return [l evaluateScript:_script onObject:self source:_src line:_line];
+}
+- (id)evaluateScript:(NSString *)_script language:(NSString *)_lang {
+  return [self evaluateScript:_script language:_lang
+              source:@"<string>" line:0];
+}
+
+/* JavaScript functions */
+
+- (id)callScriptFunction:(NSString *)_func language:(NSString *)_lang {
+  NGScriptLanguage *l;
+  
+  if ((l = [NGScriptLanguage languageWithName:_lang]) == nil) {
+    NSLog(@"%s: cannot evaluate script, language '%@' unknown",
+         __PRETTY_FUNCTION__, _lang);
+    return nil;
+  }
+  return [l callFunction:_func onObject:self];
+}
+- (id)callScriptFunction:(NSString *)_func language:(NSString *)_lang
+  withObject:(id)_arg0
+{
+  NGScriptLanguage *l;
+  
+  if ((l = [NGScriptLanguage languageWithName:_lang]) == nil) {
+    NSLog(@"%s: cannot evaluate script, language '%@' unknown",
+         __PRETTY_FUNCTION__, _lang);
+    return nil;
+  }
+  return [l callFunction:_func withArgument:_arg0 onObject:self];
+}
+- (id)callScriptFunction:(NSString *)_func language:(NSString *)_lang
+  withObject:(id)_arg0
+  withObject:(id)_arg1
+{
+  NGScriptLanguage *l;
+  
+  if ((l = [NGScriptLanguage languageWithName:_lang]) == nil) {
+    NSLog(@"%s: cannot evaluate script, language '%@' unknown",
+         __PRETTY_FUNCTION__, _lang);
+    return nil;
+  }
+  return [l callFunction:_func
+           withArgument:_arg0
+           withArgument:_arg1 
+           onObject:self];
+}
+
+@end /* NSObject(JSSupport) */
diff --git a/skyrix-sope/NGScripting/Version b/skyrix-sope/NGScripting/Version
new file mode 100644 (file)
index 0000000..317960a
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=10
diff --git a/skyrix-sope/NGScripting/common.h b/skyrix-sope/NGScripting/common.h
new file mode 100644 (file)
index 0000000..4bd18ce
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NGScripting_common_H__
+#define __NGScripting_common_H__
+
+#import <Foundation/Foundation.h>
+#include <EOControl/EOControl.h>
+
+#if LIB_FOUNDATION_LIBRARY
+#  include <extensions/objc-runtime.h>
+#elif !GNUSTEP_BASE_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#endif
+
+#endif /* __NGScripting_common_H__ */
diff --git a/skyrix-sope/PROJECTLEAD b/skyrix-sope/PROJECTLEAD
new file mode 100644 (file)
index 0000000..ab0c70a
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+PROJECTLEAD=helge.hess@opengroupware.org
diff --git a/skyrix-sope/README b/skyrix-sope/README
new file mode 100644 (file)
index 0000000..e1c46ad
--- /dev/null
@@ -0,0 +1,59 @@
+$Id$
+
+SKYRiX Object Publishing Environment Version 4.2
+================================================
+
+This directory contains SOPE 4.2, formerly known
+as the SKYRiX 4 application server.
+
+Contained are these packages:
+- NGScripting
+- NGJavaScript
+- NGObjWeb
+- SxComponents
+- WEExtensions
+- WOExtensions
+- NGObjDOM
+
+NGScripting
+===========
+
+Some small categories, protocols and baseclasses for building bridges between
+Objective-C and a scripting language.
+
+NGJavaScript
+============
+
+Based on NGScripting, provides a JavaScript bridge based on the SpiderMonkey
+engine provided by the Mozilla project.
+
+NGObjWeb
+========
+
+Large framework for building web applications.
+
+SxComponents
+============
+
+NGObjWeb subsystem for building XML-RPC/SandStorm based services.
+
+WEExtensions
+============
+
+Various dynamic elements for NGObjWeb.
+
+WOExtensions
+============
+
+More dynamic elements for NGObjWeb.
+
+NGObjDOM
+========
+
+Extension to NGObjWeb to process DOM trees using the NGObjWeb API. Currently
+used by SKYRiX forms and SKYRiX publisher, which are going to be changed to
+use the WOX mechanism contained in NGObjWeb.
+
+In practice it's less useful for a "normal" templates, but might get 
+interesting when processing arbitary XML documents which do not really map
+1:1 to a dynamic NGObjWeb element.
diff --git a/skyrix-sope/README-OSX.txt b/skyrix-sope/README-OSX.txt
new file mode 100644 (file)
index 0000000..708e092
--- /dev/null
@@ -0,0 +1,171 @@
+# $Id$
+
+Building Notes
+==============
+
+Prerequisites:
+- Apple Developer Tools
+- skyrix-xml
+- skyrix-core
+- SpiderMonkey (as availably in OpenGroupware.org/ThirdParty/js-1.5/)
+
+There are two ways to build SOPE on MacOSX, either using the gnustep-make
+package or as native Xcode projects. The first option is usually used when
+you build SOPE for use with OGo, while the latter is more appropriate for
+SOPE:X applications.
+
+Building using gstep-make:
+==========================
+
+First install gnustep-make (eg v1.8), then ensure that GNUstep.sh is properly
+sources. For the build just enter:
+  make -s install
+or
+  make -s debug=yes install
+if you build with debug informations.
+
+Building using Xcode:
+=====================
+
+The Xcode build comes in two variants, one for development and the other for
+deployment.
+
+
+Development
+-----------
+Development usually means you're happily hacking away at your pet
+projects and sometimes want to update the SOPE frameworks. For this purpose
+use the "all" target and the accompanied "Development" build style. Later,
+you can narrow the target down to something more specific. For development we
+assume the destination for frameworks to be /Library/Frameworks. Once you are
+done building all the frameworks the loader commands of the frameworks will
+have that destination path built in. In order to use the frameworks you either
+have to install them (by copying them manually to their destination) or to
+prepare symlinks from /Library/Frameworks to the place where the built products
+are. I usually build everything in a central place (i.e. /Local/BuildArea) and
+have symlinks from /Library/Frameworks to /Local/BuildArea for each of the
+products.
+
+Also the following products are expected to be in the following locations:
+*.sax -> /Library/SaxDrivers
+*.sxp -> /Library/SoProducts
+
+Either copy them to the appropriate places or symlink them (my suggestion).
+
+
+Deployment
+----------
+Deployment in our terms means you want to copy all required SOPE products into
+an application's app wrapper. For this step all frameworks need to be built in
+a special fashion, as the "install_name" of the frameworks needs to be prepared
+to point to a relative path in the app wrapper. The situation is even more
+complicated as all frameworks during linking store the "install names" of other
+frameworks in their mach loader commands. In order for this step not to break
+we need to set up an environment which is clearly separated from the
+Development environment. I chose to use $(USER_LIBRARY_DIR)/EmbeddedFrameworks
+as the default destination for these builds. In order for your application to
+easily pick up the built products and copy them into its app wrapper this
+location needs to be fixed and easily accessible. Note that on my system
+~/Library/EmbeddedFrameworks is a symlink to /Library/EmbeddedFrameworks so
+even if you don't like the location at all it's very easy to point it to 
+somewhere else. As soon as you have set this up you can use the
+"Wrapper Contents" target with the accompanied "Wrapper" build style to build
+all wrapper contents in the appropriate fashion. When you're done you can copy
+all the wrapper products into your application's wrapper. The expected
+destination is the "Frameworks" directory in the wrappers "Contents" directory.
+For a complete list of what you need to copy into your application's wrapper
+see the "Direct Dependencies" of all "Wrapper Contents" targets in all SOPE
+related projects. At the time of this writing the complete list for SOPE
+consisted of the following:
+
+SxXML
+  SaxObjC.framework
+  DOM.framework
+  XmlRpc.framework
+
+SxCore
+  EOControl.framework
+  NGExtensions.framework
+  NGStreams.framework
+  NGMime.framework
+  NGImap4.framework
+  NGLdap.framework
+  NGMail.framework
+  NGiCal.framework
+
+SOPE
+  NGScripting.framework
+  NGJavaScript.framework
+  NGHttp.framework
+  WebDAV.framework
+  SoOFS.framework
+  NGXmlRpc.framework
+  WOExtensions.framework
+  WEExtensions.framework
+  NGObjDOM.framework
+  NGObjWeb.framework
+  js.framework (see NOTE)
+
+
+Note: js.framework is the Spidermonkey framework available in
+      OpenGroupware.org/ThirdParty/js-1.5/. Although being located in
+      ThirdParty this is technically considered to be a part of SOPE. This
+      project also has an appropriate "Wrapper" build style which can be used
+      for the "js" framework target.
+
+Note: "A word on umbrellas"
+      The general idea of umbrellas is to make life easier by providing a cover
+      for linking. In an ideal world we would provide a SOPE umbrella (we 
+      actually do that) and you just link against that and forget about the
+      complete list. However, with the "Wrapper" style things do not work that
+      way. Because the "install name"s of all frameworks are relative paths,
+      during linking the mach dyld cannot find the dependend frameworks
+      (because the path isn't absolute) and thus symbol checking fails. This
+      directly leads to prebinding to fail which we really don't want since we
+      have such a huge dependency tree and prebinding escpecially in our case
+      speeds up loading significantly. So, umbrellas do not really help with
+      "Wrapper" products - in fact they just add to the overall dependency
+      graph without providing any benefit. With the notable exception of the
+      "Development" build style umbrellas are totally useless. If you're
+      not planning to do a "Wrapper" deployment you might be happy to have
+      the umbrellas, however, that's why they are still here.
+
+Note: You cannot use the -buildAllTargets commandline argument for Xcode,
+      because the Xcode projects also contain a target to build in the
+      gstep-make environment (called GSM:all)
+
+
+Prebinding Notes
+================
+
+General technical information about prebinding is available from Apple at
+http://developer.apple.com/documentation/Performance/Conceptual/LaunchTime/Tasks/Prebinding.html#//apple_ref/doc/uid/20001858.
+
+OGo frameworks currently use the range from 0xC0000000 to 0xCFFFFFFF.
+
+Any questions and feedback regarding our use of this range should go to
+Marcus Müller <znek@mulle-kybernetik.com>.
+
+
+SOPE: 0xC3000000 - 0xC5FFFFFF
+=============================
+
+0xC3000000 NGScripting
+0xC3200000 NGJavaScript
+0xC3400000 NGHttp              [not available in gstep-make]
+0xC3700000 WebDAV              [not available in gstep-make]
+0xC3A00000 SoOFS               [not available in gstep-make]
+0xC3D00000 NGXmlRpc            [not available in gstep-make]
+0xC4000000 WEExtensions
+0xC4300000 WOExtensions
+0xC4600000 NGObjDOM
+0xC4900000 NGObjWeb
+0xC5B00000 WOXML
+0xC5E00000 js
+0xC5FF0000 SOPE
+
+Note:
+=====
+
+js.framework is in ThirdParty, required by NGJavaScript, hence we assign
+a prebinding address from our range.
\ No newline at end of file
diff --git a/skyrix-sope/SOPE-Info.plist b/skyrix-sope/SOPE-Info.plist
new file mode 100644 (file)
index 0000000..d599c97
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SOPE (Wrapper Umbrella)</string>
+       <key>CFBundleIdentifier</key>
+       <string>org.OpenGroupware.SOPE</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/SOPE.xcode/project.pbxproj b/skyrix-sope/SOPE.xcode/project.pbxproj
new file mode 100644 (file)
index 0000000..c89380a
--- /dev/null
@@ -0,0 +1,17404 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 39;
+       objects = {
+               AD06642806AD6CCB006525C9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOLabelAssociation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD06642906AD6CCB006525C9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOLabelAssociation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD06642A06AD6CCB006525C9 = {
+                       fileRef = AD06642806AD6CCB006525C9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD06642B06AD6CCB006525C9 = {
+                       fileRef = AD06642906AD6CCB006525C9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD06646C06AD6E2C006525C9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOKeyPathAssociationSystemKVC.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD06646E06AD6E2D006525C9 = {
+                       fileRef = AD06646C06AD6E2C006525C9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD0CE02305D95126004D9B87 = {
+                       explicitFileType = text;
+                       fileEncoding = 5;
+                       isa = PBXFileReference;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       tabWidth = 4;
+                       usesTabs = 1;
+               };
+               AD151C9A06ABDD52002375D2 = {
+                       children = (
+                               E817B810056B01AD005FDCF0,
+                       );
+                       isa = PBXGroup;
+                       name = ThirdParty;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1626FB05D91A1B00A7368D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1626FC05D91A1B00A7368D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1626FD05D91A1C00A7368D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = PROJECTLEAD;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1626FE05D91A1C00A7368D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1626FF05D91A1C00A7368D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD16270F05D91FB400A7368D = {
+                       fileEncoding = 5;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = "README-OSX.txt";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1627B505D93C3300A7368D = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       name = Foundation.framework;
+                       path = /System/Library/Frameworks/Foundation.framework;
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               AD1627B605D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627B705D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627B805D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627B905D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627BA05D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627BB05D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627BC05D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627BD05D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627BE05D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627BF05D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627C005D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627C105D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627C205D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627C305D93C3300A7368D = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD18022A0611D79400ED723F = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEQualifierConditional.m;
+                       path = WEExtensions/WEQualifierConditional.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD18022B0611D79400ED723F = {
+                       fileRef = AD18022A0611D79400ED723F;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD48832B0634249000D38EA7 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = _WOCommonStaticDAHyperlink.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD48832C0634249000D38EA7 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = _WOComplexHyperlink.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD48832D0634249000D38EA7 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = _WOSimpleActionHyperlink.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD48832E0634249000D38EA7 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = _WOTemporaryHyperlink.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD48832F0634249000D38EA7 = {
+                       fileRef = AD48832B0634249000D38EA7;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD4883300634249000D38EA7 = {
+                       fileRef = AD48832C0634249000D38EA7;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD4883310634249100D38EA7 = {
+                       fileRef = AD48832D0634249000D38EA7;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD4883320634249100D38EA7 = {
+                       fileRef = AD48832E0634249000D38EA7;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD488335063424E200D38EA7 = {
+                       children = (
+                               AD4883360634250C00D38EA7,
+                               E81EFC5B055DD96C006FE529,
+                               E81EFC5C055DD96C006FE529,
+                               E81EFC5D055DD96C006FE529,
+                               AD48832B0634249000D38EA7,
+                               AD48832C0634249000D38EA7,
+                               AD48832D0634249000D38EA7,
+                               AD48832E0634249000D38EA7,
+                       );
+                       isa = PBXGroup;
+                       name = WOHyperlink;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD4883360634250C00D38EA7 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOHyperlink.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD4883370634250C00D38EA7 = {
+                       fileRef = AD4883360634250C00D38EA7;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD48834F0634261C00D38EA7 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEPageLink.m;
+                       path = WEExtensions/WEPageLink.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD4883500634261C00D38EA7 = {
+                       fileRef = AD48834F0634261C00D38EA7;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD488362063427B300D38EA7 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = _WOConstResourceImage.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD488363063427B300D38EA7 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = _WOResourceImage.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD488364063427B300D38EA7 = {
+                       fileRef = AD488362063427B300D38EA7;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD488365063427B300D38EA7 = {
+                       fileRef = AD488363063427B300D38EA7;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD4883680634287100D38EA7 = {
+                       children = (
+                               E81EFC5F055DD96D006FE529,
+                               AD488363063427B300D38EA7,
+                               AD488362063427B300D38EA7,
+                       );
+                       isa = PBXGroup;
+                       name = WOImage;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD853BEC06A7FA4000727CA0 = {
+                       children = (
+                               E896325905697AB200E7D217,
+                               E896325405697AB200E7D217,
+                               E8FDB166056C40FB002DFB9D,
+                       );
+                       isa = PBXGroup;
+                       name = SxXML;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD853D8306A7FA5A00727CA0 = {
+                       children = (
+                               E896325505697AB200E7D217,
+                               E896325605697AB200E7D217,
+                               E896325805697AB200E7D217,
+                               E896325705697AB200E7D217,
+                               ADC7895C06A8352A00C608B2,
+                               ADC7895D06A8352A00C608B2,
+                               ADC7895E06A8352A00C608B2,
+                               ADC7894406A834DC00C608B2,
+                       );
+                       isa = PBXGroup;
+                       name = SxCore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD853F2906A7FA9500727CA0 = {
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "SOPE Umbrella Framework Contents";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       dependencies = (
+                               AD853F3606A7FB4200727CA0,
+                               AD853F3806A7FB4200727CA0,
+                               AD853F3A06A7FB4200727CA0,
+                               AD853F3C06A7FB4200727CA0,
+                               AD853F3E06A7FB4200727CA0,
+                               AD853F4006A7FB4200727CA0,
+                               AD853F4206A7FB4200727CA0,
+                               AD853F4406A7FB4200727CA0,
+                               AD853F4606A7FB4200727CA0,
+                               AD853F4806A7FB4200727CA0,
+                       );
+                       isa = PBXAggregateTarget;
+                       name = "Wrapper Contents";
+                       productName = "SOPE Umbrella Framework Contents";
+               };
+               AD853F3506A7FB4200727CA0 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF99E055DD578006FE529;
+                       remoteInfo = NGScripting;
+               };
+               AD853F3606A7FB4200727CA0 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF99E055DD578006FE529;
+                       targetProxy = AD853F3506A7FB4200727CA0;
+               };
+               AD853F3706A7FB4200727CA0 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9A7055DD582006FE529;
+                       remoteInfo = NGJavaScript;
+               };
+               AD853F3806A7FB4200727CA0 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9A7055DD582006FE529;
+                       targetProxy = AD853F3706A7FB4200727CA0;
+               };
+               AD853F3906A7FB4200727CA0 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81CBF540569ACF6006AECCE;
+                       remoteInfo = NGHttp;
+               };
+               AD853F3A06A7FB4200727CA0 = {
+                       isa = PBXTargetDependency;
+                       target = E81CBF540569ACF6006AECCE;
+                       targetProxy = AD853F3906A7FB4200727CA0;
+               };
+               AD853F3B06A7FB4200727CA0 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81CBF7B0569B09C006AECCE;
+                       remoteInfo = NGXmlRpc;
+               };
+               AD853F3C06A7FB4200727CA0 = {
+                       isa = PBXTargetDependency;
+                       target = E81CBF7B0569B09C006AECCE;
+                       targetProxy = AD853F3B06A7FB4200727CA0;
+               };
+               AD853F3D06A7FB4200727CA0 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E809D90D056B093D0041E20B;
+                       remoteInfo = WebDAV;
+               };
+               AD853F3E06A7FB4200727CA0 = {
+                       isa = PBXTargetDependency;
+                       target = E809D90D056B093D0041E20B;
+                       targetProxy = AD853F3D06A7FB4200727CA0;
+               };
+               AD853F3F06A7FB4200727CA0 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9AF055DD58B006FE529;
+                       remoteInfo = NGObjWeb;
+               };
+               AD853F4006A7FB4200727CA0 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9AF055DD58B006FE529;
+                       targetProxy = AD853F3F06A7FB4200727CA0;
+               };
+               AD853F4106A7FB4200727CA0 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8AC8BBF05ABBF07008C206D;
+                       remoteInfo = SoOFS;
+               };
+               AD853F4206A7FB4200727CA0 = {
+                       isa = PBXTargetDependency;
+                       target = E8AC8BBF05ABBF07008C206D;
+                       targetProxy = AD853F4106A7FB4200727CA0;
+               };
+               AD853F4306A7FB4200727CA0 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9B9055DD599006FE529;
+                       remoteInfo = WEExtensions;
+               };
+               AD853F4406A7FB4200727CA0 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9B9055DD599006FE529;
+                       targetProxy = AD853F4306A7FB4200727CA0;
+               };
+               AD853F4506A7FB4200727CA0 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9C1055DD5A1006FE529;
+                       remoteInfo = WOExtensions;
+               };
+               AD853F4606A7FB4200727CA0 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9C1055DD5A1006FE529;
+                       targetProxy = AD853F4506A7FB4200727CA0;
+               };
+               AD853F4706A7FB4200727CA0 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9C9055DD5AB006FE529;
+                       remoteInfo = NGObjDOM;
+               };
+               AD853F4806A7FB4200727CA0 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9C9055DD5AB006FE529;
+                       targetProxy = AD853F4706A7FB4200727CA0;
+               };
+               AD853F4906A7FB6B00727CA0 = {
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               DEPLOYMENT_LOCATION = NO;
+                               DEPLOYMENT_POSTPROCESSING = YES;
+                               DSTROOT = /;
+                               DYLIB_INSTALL_NAME_BASE = "@executable_path/../Frameworks";
+                               FRAMEWORK_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_OPTIMIZATION_LEVEL = 3;
+                               GCC_PREPROCESSOR_DEFINITIONS = "APPLE_RUNTIME=1 NeXT_Foundation_LIBRARY=1 COCOA_Foundation_LIBRARY=1 NeXT_RUNTIME=1 COMPILE_AS_FRAMEWORK=1";
+                               SKIP_INSTALL = YES;
+                               SYMROOT = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+                               TEMP_DIR = "$(SYMROOT)/$(PROJECT_NAME).build";
+                               UNSTRIPPED_PRODUCT = NO;
+                               ZERO_LINK = NO;
+                       };
+                       isa = PBXBuildStyle;
+                       name = Wrapper;
+               };
+               AD8540AF06A7FCE100727CA0 = {
+                       fileRef = E896325905697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8540B006A7FCE100727CA0 = {
+                       fileRef = E896325405697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85412206A8215D00727CA0 = {
+                       fileRef = E896325905697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85412306A8215D00727CA0 = {
+                       fileRef = E896325405697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85412406A821A900727CA0 = {
+                       fileRef = E896325905697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85412506A821A900727CA0 = {
+                       fileRef = E896325405697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85417C06A8220400727CA0 = {
+                       fileRef = E896325505697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85417D06A8220400727CA0 = {
+                       fileRef = E896325605697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85418806A8282C00727CA0 = {
+                       fileRef = E8FDB166056C40FB002DFB9D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8541E806A828C000727CA0 = {
+                       fileRef = E896325805697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8541E906A828C000727CA0 = {
+                       fileRef = E896325705697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8541EA06A828F600727CA0 = {
+                       fileRef = E8FDB166056C40FB002DFB9D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8541EB06A8290900727CA0 = {
+                       fileRef = E896325805697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8541EC06A8294E00727CA0 = {
+                       fileRef = E896325705697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8541ED06A829D400727CA0 = {
+                       fileRef = E81CBF550569ACF6006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8541EE06A829D400727CA0 = {
+                       fileRef = E81CBF7C0569B09C006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8541EF06A829F600727CA0 = {
+                       fileRef = E81EF99F055DD578006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8541F006A82A1700727CA0 = {
+                       fileRef = E81CBF7C0569B09C006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD8541F106A82A2800727CA0 = {
+                       fileRef = E81CBF550569ACF6006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85420406A82A5E00727CA0 = {
+                       fileRef = E896325905697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85420506A82A5E00727CA0 = {
+                       fileRef = E896325405697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85420606A82A5E00727CA0 = {
+                       fileRef = E8FDB166056C40FB002DFB9D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85420706A82A5E00727CA0 = {
+                       fileRef = E896325505697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85420806A82A5E00727CA0 = {
+                       fileRef = E896325605697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85420906A82A5E00727CA0 = {
+                       fileRef = E896325705697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85420A06A82A5E00727CA0 = {
+                       fileRef = E896325805697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85420B06A82A5E00727CA0 = {
+                       fileRef = E81CBF7C0569B09C006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85420C06A82A5E00727CA0 = {
+                       fileRef = E81CBF550569ACF6006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85422106A82CE100727CA0 = {
+                       fileRef = E896325905697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85422206A82CE100727CA0 = {
+                       fileRef = E8FDB166056C40FB002DFB9D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85422406A82CE100727CA0 = {
+                       fileRef = E81CBF7C0569B09C006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85422506A82CE100727CA0 = {
+                       fileRef = E81CBF550569ACF6006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85422906A82D4B00727CA0 = {
+                       fileRef = E896325705697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85422E06A82DAF00727CA0 = {
+                       fileRef = E896325805697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD85422F06A82DCC00727CA0 = {
+                       fileRef = E817B810056B01AD005FDCF0;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB59399061DFD540094D980 = {
+                       children = (
+                               ADB5939B061DFDB40094D980,
+                               ADB593D1061DFE0E0094D980,
+                               ADB593D4061DFE2C0094D980,
+                               ADB593D7061DFE3E0094D980,
+                       );
+                       isa = PBXGroup;
+                       name = WETableView;
+                       path = WEExtensions/WETableView;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB5939A061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB5939B061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB5939C061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WETableCell.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB5939D061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableCell.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB5939E061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableData.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB5939F061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableHeader.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593A0061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WETableView.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593A1061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableView.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593A2061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "WETableView+Grouping.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593A3061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WETableView+Grouping.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593A4061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableViewButtonMode.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593A5061DFDB40094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WETableViewColorConfig.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593A6061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableViewColorConfig.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593A7061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WETableViewConfigObject.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593A8061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableViewConfigObject.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593A9061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WETableViewDefines.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593AA061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableViewFooterMode.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593AB061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableViewGroupMode.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593AC061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WETableViewIconConfig.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593AD061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableViewIconConfig.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593AE061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WETableViewInfo.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593AF061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WETableViewLabelConfig.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593B0061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableViewLabelConfig.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593B1061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WETableViewState.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593B2061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableViewState.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593B3061DFDB50094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WETableViewTitleMode.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593B4061DFDB60094D980 = {
+                       fileRef = ADB5939A061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593B5061DFDB60094D980 = {
+                       fileRef = ADB5939B061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593B6061DFDB60094D980 = {
+                       fileRef = ADB5939C061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593B7061DFDB60094D980 = {
+                       fileRef = ADB5939D061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593B8061DFDB60094D980 = {
+                       fileRef = ADB5939E061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593B9061DFDB60094D980 = {
+                       fileRef = ADB5939F061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593BA061DFDB60094D980 = {
+                       fileRef = ADB593A0061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593BB061DFDB60094D980 = {
+                       fileRef = ADB593A1061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593BC061DFDB60094D980 = {
+                       fileRef = ADB593A2061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593BD061DFDB60094D980 = {
+                       fileRef = ADB593A3061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593BE061DFDB60094D980 = {
+                       fileRef = ADB593A4061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593BF061DFDB60094D980 = {
+                       fileRef = ADB593A5061DFDB40094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593C0061DFDB60094D980 = {
+                       fileRef = ADB593A6061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593C1061DFDB60094D980 = {
+                       fileRef = ADB593A7061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593C2061DFDB60094D980 = {
+                       fileRef = ADB593A8061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593C3061DFDB60094D980 = {
+                       fileRef = ADB593A9061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593C4061DFDB60094D980 = {
+                       fileRef = ADB593AA061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593C5061DFDB60094D980 = {
+                       fileRef = ADB593AB061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593C6061DFDB60094D980 = {
+                       fileRef = ADB593AC061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593C7061DFDB60094D980 = {
+                       fileRef = ADB593AD061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593C8061DFDB60094D980 = {
+                       fileRef = ADB593AE061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593C9061DFDB60094D980 = {
+                       fileRef = ADB593AF061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593CA061DFDB60094D980 = {
+                       fileRef = ADB593B0061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593CB061DFDB60094D980 = {
+                       fileRef = ADB593B1061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593CC061DFDB60094D980 = {
+                       fileRef = ADB593B2061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593CD061DFDB60094D980 = {
+                       fileRef = ADB593B3061DFDB50094D980;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADB593CE061DFDF20094D980 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.postamble;
+                       path = WEExtensions/GNUmakefile.postamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593D1061DFE0E0094D980 = {
+                       children = (
+                               ADB5939A061DFDB40094D980,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593D4061DFE2C0094D980 = {
+                       children = (
+                               ADB5939C061DFDB40094D980,
+                               ADB593A0061DFDB40094D980,
+                               ADB593A2061DFDB40094D980,
+                               ADB593A5061DFDB40094D980,
+                               ADB593A7061DFDB50094D980,
+                               ADB593A9061DFDB50094D980,
+                               ADB593AC061DFDB50094D980,
+                               ADB593AE061DFDB50094D980,
+                               ADB593AF061DFDB50094D980,
+                               ADB593B1061DFDB50094D980,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADB593D7061DFE3E0094D980 = {
+                       children = (
+                               ADB5939D061DFDB40094D980,
+                               ADB5939E061DFDB40094D980,
+                               ADB5939F061DFDB40094D980,
+                               ADB593A1061DFDB40094D980,
+                               ADB593A3061DFDB40094D980,
+                               ADB593A4061DFDB40094D980,
+                               ADB593A6061DFDB50094D980,
+                               ADB593A8061DFDB50094D980,
+                               ADB593AA061DFDB50094D980,
+                               ADB593AB061DFDB50094D980,
+                               ADB593AD061DFDB50094D980,
+                               ADB593B0061DFDB50094D980,
+                               ADB593B2061DFDB50094D980,
+                               ADB593B3061DFDB50094D980,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADC7894406A834DC00C608B2 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = NGiCal.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               ADC7895C06A8352A00C608B2 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = NGImap4.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               ADC7895D06A8352A00C608B2 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = NGLdap.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               ADC7895E06A8352A00C608B2 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = NGMail.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               ADCDE36306AD744A00BFCE2B = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSUserDefaults+KVC.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADCDE36406AD744A00BFCE2B = {
+                       fileRef = ADCDE36306AD744A00BFCE2B;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADCDE36506AD746E00BFCE2B = {
+                       explicitFileType = sourcecode.make;
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       path = GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       tabWidth = 4;
+               };
+               ADCEA325061AEF3D00361086 = {
+                       children = (
+                               ADCEA326061AEF7300361086,
+                               ADCEA327061AEF7400361086,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADCEA326061AEF7300361086 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WOExtensions.h;
+                       path = WOExtensions/WOExtensions.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADCEA327061AEF7400361086 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WORedirect.h;
+                       path = WOExtensions/WORedirect.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADCEA328061AEF7400361086 = {
+                       fileRef = ADCEA326061AEF7300361086;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               ADCEA329061AEF7400361086 = {
+                       fileRef = ADCEA327061AEF7400361086;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               ADCEA32C061AF02F00361086 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WERedirect.m;
+                       path = WEExtensions/WERedirect.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADCEA32D061AF02F00361086 = {
+                       fileRef = ADCEA32C061AF02F00361086;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB798305C0B141009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB798405C0B141009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB798505C0B141009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADDB7A6C05C0B327009DBFB4,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB798605C0B141009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADDB7A7105C0B369009DBFB4,
+                               ADDB7A7205C0B369009DBFB4,
+                               ADDB7AC605C0B3A6009DBFB4,
+                               ADDB7AC705C0B3A6009DBFB4,
+                               ADDB7AC805C0B3A6009DBFB4,
+                               ADDB7AC905C0B3A6009DBFB4,
+                               AD1627C005D93C3300A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB798705C0B141009DBFB4 = {
+                       buildPhases = (
+                               ADDB798305C0B141009DBFB4,
+                               ADDB798405C0B141009DBFB4,
+                               ADDB798505C0B141009DBFB4,
+                               ADDB798605C0B141009DBFB4,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "SOPE-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC5FF0000 -sub_umbrella NGJavaScript -sub_umbrella NGScripting -sub_umbrella NGObjDOM -sub_umbrella NGObjWeb -sub_umbrella WEExtensions -sub_umbrella WOExtensions -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = SOPE;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                               ADDB79D705C0B28E009DBFB4,
+                               ADDB79D905C0B28E009DBFB4,
+                               ADDB79DB05C0B28E009DBFB4,
+                               ADDB79DD05C0B28E009DBFB4,
+                               ADDB79DF05C0B28E009DBFB4,
+                               ADDB79E105C0B28E009DBFB4,
+                               ADDB79E305C0B28E009DBFB4,
+                               ADDB79E505C0B28E009DBFB4,
+                               ADDB79E705C0B28E009DBFB4,
+                               ADDB79E905C0B28E009DBFB4,
+                       );
+                       isa = PBXNativeTarget;
+                       name = "SOPE (Umbrella)";
+                       productName = SOPE;
+                       productReference = ADDB798805C0B141009DBFB4;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SOPE</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.SOPE</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               ADDB798805C0B141009DBFB4 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = SOPE.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               ADDB798905C0B142009DBFB4 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       path = "SOPE-Info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADDB79D305C0B18D009DBFB4 = {
+                       children = (
+                               E84DAB43056AEF0800355953,
+                               ADDB798905C0B142009DBFB4,
+                       );
+                       isa = PBXGroup;
+                       name = SOPE;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADDB79D405C0B26F009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = ADDB798705C0B141009DBFB4;
+                       remoteInfo = SOPE;
+               };
+               ADDB79D505C0B26F009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = ADDB798705C0B141009DBFB4;
+                       targetProxy = ADDB79D405C0B26F009DBFB4;
+               };
+               ADDB79D605C0B28E009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF99E055DD578006FE529;
+                       remoteInfo = NGScripting;
+               };
+               ADDB79D705C0B28E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF99E055DD578006FE529;
+                       targetProxy = ADDB79D605C0B28E009DBFB4;
+               };
+               ADDB79D805C0B28E009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9A7055DD582006FE529;
+                       remoteInfo = NGJavaScript;
+               };
+               ADDB79D905C0B28E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9A7055DD582006FE529;
+                       targetProxy = ADDB79D805C0B28E009DBFB4;
+               };
+               ADDB79DA05C0B28E009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81CBF540569ACF6006AECCE;
+                       remoteInfo = NGHttp;
+               };
+               ADDB79DB05C0B28E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81CBF540569ACF6006AECCE;
+                       targetProxy = ADDB79DA05C0B28E009DBFB4;
+               };
+               ADDB79DC05C0B28E009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81CBF7B0569B09C006AECCE;
+                       remoteInfo = NGXmlRpc;
+               };
+               ADDB79DD05C0B28E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81CBF7B0569B09C006AECCE;
+                       targetProxy = ADDB79DC05C0B28E009DBFB4;
+               };
+               ADDB79DE05C0B28E009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E809D90D056B093D0041E20B;
+                       remoteInfo = WebDAV;
+               };
+               ADDB79DF05C0B28E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E809D90D056B093D0041E20B;
+                       targetProxy = ADDB79DE05C0B28E009DBFB4;
+               };
+               ADDB79E005C0B28E009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9AF055DD58B006FE529;
+                       remoteInfo = NGObjWeb;
+               };
+               ADDB79E105C0B28E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9AF055DD58B006FE529;
+                       targetProxy = ADDB79E005C0B28E009DBFB4;
+               };
+               ADDB79E205C0B28E009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8AC8BBF05ABBF07008C206D;
+                       remoteInfo = SoOFS;
+               };
+               ADDB79E305C0B28E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E8AC8BBF05ABBF07008C206D;
+                       targetProxy = ADDB79E205C0B28E009DBFB4;
+               };
+               ADDB79E405C0B28E009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9B9055DD599006FE529;
+                       remoteInfo = WEExtensions;
+               };
+               ADDB79E505C0B28E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9B9055DD599006FE529;
+                       targetProxy = ADDB79E405C0B28E009DBFB4;
+               };
+               ADDB79E605C0B28E009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9C1055DD5A1006FE529;
+                       remoteInfo = WOExtensions;
+               };
+               ADDB79E705C0B28E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9C1055DD5A1006FE529;
+                       targetProxy = ADDB79E605C0B28E009DBFB4;
+               };
+               ADDB79E805C0B28E009DBFB4 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9C9055DD5AB006FE529;
+                       remoteInfo = NGObjDOM;
+               };
+               ADDB79E905C0B28E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9C9055DD5AB006FE529;
+                       targetProxy = ADDB79E805C0B28E009DBFB4;
+               };
+               ADDB7A6C05C0B327009DBFB4 = {
+                       fileRef = E84DAB43056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB7A7105C0B369009DBFB4 = {
+                       fileRef = E81EF99F055DD578006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB7A7205C0B369009DBFB4 = {
+                       fileRef = E81EF9A8055DD582006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB7AC605C0B3A6009DBFB4 = {
+                       fileRef = E81EF9B0055DD58B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB7AC705C0B3A6009DBFB4 = {
+                       fileRef = E81EF9BA055DD599006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB7AC805C0B3A6009DBFB4 = {
+                       fileRef = E81EF9C2055DD5A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB7AC905C0B3A6009DBFB4 = {
+                       fileRef = E81EF9CA055DD5AB006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A13063FD6200050249C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADE23A3D063FDF530050249C,
+                               ADE23A3E063FDF530050249C,
+                               ADE23A3F063FDF530050249C,
+                               ADE23A41063FDF530050249C,
+                               ADE23A43063FDF530050249C,
+                               ADE23A45063FDF530050249C,
+                               ADE23A47063FDF530050249C,
+                               ADE23A49063FDF530050249C,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADE23A14063FD6200050249C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADE23A25063FDED90050249C,
+                               ADE23A26063FDED90050249C,
+                               ADE23A27063FDED90050249C,
+                               ADE23A2A063FDED90050249C,
+                               ADE23A2B063FDED90050249C,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADE23A15063FD6200050249C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADE23A40063FDF530050249C,
+                               ADE23A42063FDF530050249C,
+                               ADE23A44063FDF530050249C,
+                               ADE23A46063FDF530050249C,
+                               ADE23A48063FDF530050249C,
+                               ADE23A4A063FDF530050249C,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADE23A16063FD6200050249C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADE23A59063FE15E0050249C,
+                               ADE23A58063FE1540050249C,
+                               ADE23A57063FE14E0050249C,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADE23A17063FD6200050249C = {
+                       buildPhases = (
+                               ADE23A13063FD6200050249C,
+                               ADE23A14063FD6200050249C,
+                               ADE23A15063FD6200050249C,
+                               ADE23A16063FD6200050249C,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "WOXML/WOXML-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "-DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1 -DNeXT_Foundation_LIBRARY=1";
+                               OTHER_LDFLAGS = "-seg1addr 0xC5B00000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = WOXML;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = WOXML;
+                       productName = WOXML;
+                       productReference = ADE23A18063FD6200050249C;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>WOXML</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.WOXML</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               ADE23A18063FD6200050249C = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = WOXML.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               ADE23A1D063FDE730050249C = {
+                       children = (
+                               ADE23A23063FDED90050249C,
+                               ADE23A1F063FDED80050249C,
+                               ADE23A20063FDED80050249C,
+                               ADE23A1E063FDED80050249C,
+                               ADE23A24063FDED90050249C,
+                               ADE23A2E063FDF010050249C,
+                               ADE23A4D063FDF630050249C,
+                               ADE23A50063FDF6C0050249C,
+                               ADE23A51063FE02C0050249C,
+                       );
+                       isa = PBXGroup;
+                       path = WOXML;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A1E063FDED80050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       usesTabs = 1;
+               };
+               ADE23A1F063FDED80050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A20063FDED80050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A21063FDED90050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       usesTabs = 1;
+               };
+               ADE23A22063FDED90050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       usesTabs = 1;
+               };
+               ADE23A23063FDED90050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A24063FDED90050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A25063FDED90050249C = {
+                       fileRef = ADE23A1E063FDED80050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A26063FDED90050249C = {
+                       fileRef = ADE23A1F063FDED80050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A27063FDED90050249C = {
+                       fileRef = ADE23A20063FDED80050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A2A063FDED90050249C = {
+                       fileRef = ADE23A23063FDED90050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A2B063FDED90050249C = {
+                       fileRef = ADE23A24063FDED90050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A2E063FDF010050249C = {
+                       children = (
+                               ADE23A21063FDED90050249C,
+                               ADE23A22063FDED90050249C,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A2F063FDF520050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A30063FDF520050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOXML.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A31063FDF520050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOXMLDecoder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A32063FDF520050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOXMLDecoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A33063FDF520050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOXMLMapDecoder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A34063FDF520050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOXMLMapDecoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A35063FDF520050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOXMLMappingEntity.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A36063FDF520050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOXMLMappingEntity.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A37063FDF520050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOXMLMappingModel.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A38063FDF530050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOXMLMappingModel.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A39063FDF530050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOXMLMappingProperty.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A3A063FDF530050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOXMLMappingProperty.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A3B063FDF530050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOXMLSaxModelHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A3C063FDF530050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOXMLSaxModelHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A3D063FDF530050249C = {
+                       fileRef = ADE23A2F063FDF520050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A3E063FDF530050249C = {
+                       fileRef = ADE23A30063FDF520050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               ADE23A3F063FDF530050249C = {
+                       fileRef = ADE23A31063FDF520050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               ADE23A40063FDF530050249C = {
+                       fileRef = ADE23A32063FDF520050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A41063FDF530050249C = {
+                       fileRef = ADE23A33063FDF520050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A42063FDF530050249C = {
+                       fileRef = ADE23A34063FDF520050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A43063FDF530050249C = {
+                       fileRef = ADE23A35063FDF520050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A44063FDF530050249C = {
+                       fileRef = ADE23A36063FDF520050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A45063FDF530050249C = {
+                       fileRef = ADE23A37063FDF520050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               ADE23A46063FDF530050249C = {
+                       fileRef = ADE23A38063FDF530050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A47063FDF530050249C = {
+                       fileRef = ADE23A39063FDF530050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A48063FDF530050249C = {
+                       fileRef = ADE23A3A063FDF530050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A49063FDF530050249C = {
+                       fileRef = ADE23A3B063FDF530050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A4A063FDF530050249C = {
+                       fileRef = ADE23A3C063FDF530050249C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A4D063FDF630050249C = {
+                       children = (
+                               ADE23A2F063FDF520050249C,
+                               ADE23A30063FDF520050249C,
+                               ADE23A31063FDF520050249C,
+                               ADE23A33063FDF520050249C,
+                               ADE23A35063FDF520050249C,
+                               ADE23A37063FDF520050249C,
+                               ADE23A39063FDF530050249C,
+                               ADE23A3B063FDF530050249C,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A50063FDF6C0050249C = {
+                       children = (
+                               ADE23A32063FDF520050249C,
+                               ADE23A34063FDF520050249C,
+                               ADE23A36063FDF520050249C,
+                               ADE23A38063FDF530050249C,
+                               ADE23A3A063FDF530050249C,
+                               ADE23A3C063FDF530050249C,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A51063FE02C0050249C = {
+                       children = (
+                               ADE23A52063FE02C0050249C,
+                       );
+                       isa = PBXGroup;
+                       path = samples;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADE23A52063FE02C0050249C = {
+                       children = (
+                               ADE23A53063FE02C0050249C,
+                               ADE23A54063FE02C0050249C,
+                               ADE23A56063FE02C0050249C,
+                               ADE23A55063FE02C0050249C,
+                       );
+                       isa = PBXGroup;
+                       name = slashdot;
+                       path = "/private/var/automount/Network/Users/znek/Projects/OGo/OpenGroupware.org/SOPE/skyrix-sope/WOXML/samples/slashdot";
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               ADE23A53063FE02C0050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = "/private/var/automount/Network/Users/znek/Projects/OGo/OpenGroupware.org/SOPE/skyrix-sope/WOXML/samples/slashdot/GNUmakefile";
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               ADE23A54063FE02C0050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = SlashDotStory.m;
+                       path = "/private/var/automount/Network/Users/znek/Projects/OGo/OpenGroupware.org/SOPE/skyrix-sope/WOXML/samples/slashdot/SlashDotStory.m";
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               ADE23A55063FE02C0050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       name = slashdot.xmlmodel;
+                       path = "/private/var/automount/Network/Users/znek/Projects/OGo/OpenGroupware.org/SOPE/skyrix-sope/WOXML/samples/slashdot/slashdot.xmlmodel";
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               ADE23A56063FE02C0050249C = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = woslash.m;
+                       path = "/private/var/automount/Network/Users/znek/Projects/OGo/OpenGroupware.org/SOPE/skyrix-sope/WOXML/samples/slashdot/woslash.m";
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               ADE23A57063FE14E0050249C = {
+                       fileRef = E896325405697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A58063FE1540050249C = {
+                       fileRef = E896325905697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A59063FE15E0050249C = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADE23A5A063FE1FF0050249C = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = ADE23A17063FD6200050249C;
+                       remoteInfo = WOXML;
+               };
+               ADE23A5B063FE1FF0050249C = {
+                       isa = PBXTargetDependency;
+                       target = ADE23A17063FD6200050249C;
+                       targetProxy = ADE23A5A063FE1FF0050249C;
+               };
+               ADF834DB0657F03400B8881A = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADF834DC0657F03400B8881A = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADF835A30657F44400B8881A,
+                               ADF835A40657F46A00B8881A,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADF834DD0657F03400B8881A = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADF835A20657F3D800B8881A,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADF834DE0657F03400B8881A = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADF835A70657F53000B8881A,
+                               ADF835A60657F50D00B8881A,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADF834DF0657F03400B8881A = {
+                       buildPhases = (
+                               ADF834DB0657F03400B8881A,
+                               ADF834DC0657F03400B8881A,
+                               ADF834DD0657F03400B8881A,
+                               ADF834DE0657F03400B8881A,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGObjWeb/SoObjects/SoCore-SXP-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/SoProducts";
+                               OTHER_CFLAGS = "-I.. -DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1 -DCOMPILE_AS_FRAMEWORK=1 -DNeXT_Foundation_LIBRARY=1";
+                               PRODUCT_NAME = SoCore;
+                               WARNING_CFLAGS = "-Wmost";
+                               WRAPPER_EXTENSION = sxp;
+                       };
+                       dependencies = (
+                               ADF835C10657F95200B8881A,
+                       );
+                       isa = PBXNativeTarget;
+                       name = "SoCore (SXP)";
+                       productName = SoCore;
+                       productReference = ADF834E00657F03400B8881A;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SoCore</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.SoCore</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.bundle";
+               };
+               ADF834E00657F03400B8881A = {
+                       explicitFileType = wrapper.cfbundle;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = SoCore.sxp;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               ADF835A10657F3D800B8881A = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = SoCoreProduct.m;
+                       path = ../SoCoreProduct.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADF835A20657F3D800B8881A = {
+                       fileRef = ADF835A10657F3D800B8881A;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADF835A30657F44400B8881A = {
+                       fileRef = E81EFDB1055DD986006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADF835A40657F46A00B8881A = {
+                       fileRef = E81EFEE7055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADF835A60657F50D00B8881A = {
+                       fileRef = ADDB798805C0B141009DBFB4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADF835A70657F53000B8881A = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADF835AA0657F59500B8881A = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADF835AB0657F59500B8881A = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADF835BE0657F92300B8881A,
+                               ADF835BF0657F92D00B8881A,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADF835AC0657F59500B8881A = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADF835B20657F6DF00B8881A,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADF835AD0657F59500B8881A = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADF835BC0657F8F500B8881A,
+                               ADF835BD0657F90300B8881A,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADF835AE0657F59500B8881A = {
+                       buildPhases = (
+                               ADF835AA0657F59500B8881A,
+                               ADF835AB0657F59500B8881A,
+                               ADF835AC0657F59500B8881A,
+                               ADF835AD0657F59500B8881A,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGObjWeb/SoOFS/SoOFS-SXP-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/SoProducts";
+                               OTHER_CFLAGS = "-I.. -DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1 -DCOMPILE_AS_FRAMEWORK=1 -DNeXT_Foundation_LIBRARY=1";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = SoOFS;
+                               WARNING_CFLAGS = "-Wmost";
+                               WRAPPER_EXTENSION = sxp;
+                       };
+                       dependencies = (
+                               ADF835C30657F96400B8881A,
+                       );
+                       isa = PBXNativeTarget;
+                       name = "SoOFS (SXP)";
+                       productName = "SoOFS-p";
+                       productReference = ADF835AF0657F59500B8881A;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SoOFS-p</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.SoOFS_p</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.bundle";
+               };
+               ADF835AF0657F59500B8881A = {
+                       explicitFileType = wrapper.cfbundle;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = SoOFS.sxp;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               ADF835B10657F6DF00B8881A = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = SoOFSProduct.m;
+                       path = ../SoOFSProduct.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADF835B20657F6DF00B8881A = {
+                       fileRef = ADF835B10657F6DF00B8881A;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADF835B80657F8BE00B8881A = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = ADF834DF0657F03400B8881A;
+                       remoteInfo = "SoCore (SXP)";
+               };
+               ADF835B90657F8BE00B8881A = {
+                       isa = PBXTargetDependency;
+                       target = ADF834DF0657F03400B8881A;
+                       targetProxy = ADF835B80657F8BE00B8881A;
+               };
+               ADF835BA0657F8BE00B8881A = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = ADF835AE0657F59500B8881A;
+                       remoteInfo = "SoOFS (SXP)";
+               };
+               ADF835BB0657F8BE00B8881A = {
+                       isa = PBXTargetDependency;
+                       target = ADF835AE0657F59500B8881A;
+                       targetProxy = ADF835BA0657F8BE00B8881A;
+               };
+               ADF835BC0657F8F500B8881A = {
+                       fileRef = AD1627B505D93C3300A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADF835BD0657F90300B8881A = {
+                       fileRef = ADDB798805C0B141009DBFB4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADF835BE0657F92300B8881A = {
+                       fileRef = E81EFE7C055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADF835BF0657F92D00B8881A = {
+                       fileRef = E81EFEE7055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADF835C00657F95200B8881A = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = ADDB798705C0B141009DBFB4;
+                       remoteInfo = "SOPE (Umbrella)";
+               };
+               ADF835C10657F95200B8881A = {
+                       isa = PBXTargetDependency;
+                       target = ADDB798705C0B141009DBFB4;
+                       targetProxy = ADF835C00657F95200B8881A;
+               };
+               ADF835C20657F96400B8881A = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = ADDB798705C0B141009DBFB4;
+                       remoteInfo = "SOPE (Umbrella)";
+               };
+               ADF835C30657F96400B8881A = {
+                       isa = PBXTargetDependency;
+                       target = ADDB798705C0B141009DBFB4;
+                       targetProxy = ADF835C20657F96400B8881A;
+               };
+               ADFC4758064BC58100092231 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "WOMessage+Validation.m";
+                       path = "NGObjWeb/WOMessage+Validation.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADFC4759064BC58100092231 = {
+                       fileRef = ADFC4758064BC58100092231;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+//AD0
+//AD1
+//AD2
+//AD3
+//AD4
+//E80
+//E81
+//E82
+//E83
+//E84
+               E809D8E5056B07DD0041E20B = {
+                       children = (
+                               E81EFD6E055DD982006FE529,
+                               E81EFDF4055DD989006FE529,
+                               E81EFDF6055DD98A006FE529,
+                               E81EFDF8055DD98A006FE529,
+                               E81EFDFA055DD98A006FE529,
+                               E81EFDFC055DD98A006FE529,
+                               E81EFDFE055DD98A006FE529,
+                               E81EFE00055DD98A006FE529,
+                               E81EFE02055DD98B006FE529,
+                               E81EFE04055DD98B006FE529,
+                               E81EFE06055DD98B006FE529,
+                               E81EFE09055DD98B006FE529,
+                               E81EFE0B055DD98B006FE529,
+                               E81EFE0D055DD98B006FE529,
+                               E81EFE0F055DD98B006FE529,
+                               E81EFE10055DD98B006FE529,
+                               E81EFE12055DD98B006FE529,
+                               E81EFE14055DD98C006FE529,
+                               E81EFE16055DD98C006FE529,
+                               E81EFE18055DD98C006FE529,
+                               E81EFE1A055DD98C006FE529,
+                               E81EFE1C055DD98C006FE529,
+                               E81EFE1E055DD98C006FE529,
+                               E81EFE20055DD98C006FE529,
+                               E81EFE22055DD98C006FE529,
+                               E81EFE24055DD98D006FE529,
+                               E81EFE26055DD98D006FE529,
+                               E81EFE28055DD98D006FE529,
+                               E81EFE2B055DD98D006FE529,
+                               E81EFE2F055DD98D006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E809D8E8056B07FD0041E20B = {
+                       children = (
+                               E81EFD6F055DD982006FE529,
+                               E81EFDF5055DD989006FE529,
+                               E81EFDF7055DD98A006FE529,
+                               E81EFDF9055DD98A006FE529,
+                               E81EFDFB055DD98A006FE529,
+                               E81EFDFD055DD98A006FE529,
+                               E81EFDFF055DD98A006FE529,
+                               E81EFE01055DD98B006FE529,
+                               E81EFE03055DD98B006FE529,
+                               E81EFE05055DD98B006FE529,
+                               E81EFE07055DD98B006FE529,
+                               E81EFE08055DD98B006FE529,
+                               E81EFE0A055DD98B006FE529,
+                               E81EFE0C055DD98B006FE529,
+                               E81EFE0E055DD98B006FE529,
+                               E81EFE11055DD98B006FE529,
+                               E81EFE13055DD98B006FE529,
+                               E81EFE15055DD98C006FE529,
+                               E81EFE17055DD98C006FE529,
+                               E81EFE19055DD98C006FE529,
+                               E81EFE1B055DD98C006FE529,
+                               E81EFE1D055DD98C006FE529,
+                               E81EFE1F055DD98C006FE529,
+                               E81EFE21055DD98C006FE529,
+                               E81EFE23055DD98C006FE529,
+                               E81EFE25055DD98D006FE529,
+                               E81EFE27055DD98D006FE529,
+                               E81EFE29055DD98D006FE529,
+                               E81EFE2C055DD98D006FE529,
+                               E81EFE2D055DD98D006FE529,
+                               E81EFE2E055DD98D006FE529,
+                               E81EFE30055DD98D006FE529,
+                               ADF835A10657F3D800B8881A,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E809D8EB056B08310041E20B = {
+                       children = (
+                               E81EFE59055DD990006FE529,
+                               E81EFE5B055DD990006FE529,
+                               E81EFE5D055DD991006FE529,
+                               E81EFE5F055DD991006FE529,
+                               E81EFE61055DD991006FE529,
+                               E81EFE63055DD991006FE529,
+                               E81EFE66055DD991006FE529,
+                               E81EFE68055DD991006FE529,
+                               E81EFE6A055DD991006FE529,
+                               E81EFE6C055DD991006FE529,
+                               E81EFE6E055DD992006FE529,
+                               E81EFE70055DD992006FE529,
+                               E81EFE72055DD992006FE529,
+                               E81EFE74055DD992006FE529,
+                               E81EFE76055DD992006FE529,
+                               E81EFE78055DD992006FE529,
+                               E81EFE7A055DD992006FE529,
+                               E81EFEA2055DD994006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E809D8EE056B084D0041E20B = {
+                       children = (
+                               E81EFE33055DD98D006FE529,
+                               E81EFE5A055DD990006FE529,
+                               E81EFE5C055DD991006FE529,
+                               E81EFE5E055DD991006FE529,
+                               E81EFE60055DD991006FE529,
+                               E81EFE62055DD991006FE529,
+                               E81EFE64055DD991006FE529,
+                               E81EFE65055DD991006FE529,
+                               E81EFE67055DD991006FE529,
+                               E81EFE69055DD991006FE529,
+                               E81EFE6B055DD991006FE529,
+                               E81EFE6D055DD991006FE529,
+                               E81EFE6F055DD992006FE529,
+                               E81EFE71055DD992006FE529,
+                               E81EFE73055DD992006FE529,
+                               E81EFE75055DD992006FE529,
+                               E81EFE77055DD992006FE529,
+                               E81EFE79055DD992006FE529,
+                               E81EFE7B055DD992006FE529,
+                               ADF835B10657F6DF00B8881A,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E809D8F1056B08700041E20B = {
+                       children = (
+                               E81EFED6055DD997006FE529,
+                               E81EFED8055DD997006FE529,
+                               E81EFEDD055DD997006FE529,
+                               E81EFEE1055DD998006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E809D8F4056B088A0041E20B = {
+                       children = (
+                               E81EFED4055DD997006FE529,
+                               E81EFED5055DD997006FE529,
+                               E81EFED7055DD997006FE529,
+                               E81EFED9055DD997006FE529,
+                               E81EFEDA055DD997006FE529,
+                               E81EFEDB055DD997006FE529,
+                               E81EFEDC055DD997006FE529,
+                               E81EFEDE055DD997006FE529,
+                               E81EFEDF055DD998006FE529,
+                               E81EFEE0055DD998006FE529,
+                               E81EFEE2055DD998006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E809D8F7056B08AF0041E20B = {
+                       children = (
+                               E81EFEEB055DD998006FE529,
+                               E81EFF09055DD99A006FE529,
+                               E81EFF25055DD99C006FE529,
+                               E81EFF26055DD99C006FE529,
+                               E857FDB205FC9C090026154C,
+                               E81EFF28055DD99C006FE529,
+                               E81EFF2B055DD99C006FE529,
+                               E81EFF2D055DD99C006FE529,
+                               E81EFF2F055DD99C006FE529,
+                               E81EFF31055DD99C006FE529,
+                               E81EFF33055DD99D006FE529,
+                               E81EFF35055DD99D006FE529,
+                               E81EFF37055DD99D006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E809D8FA056B08BD0041E20B = {
+                       children = (
+                               E81EFEEC055DD998006FE529,
+                               E81EFF0A055DD99A006FE529,
+                               E81EFF27055DD99C006FE529,
+                               E857FDB305FC9C090026154C,
+                               E81EFF29055DD99C006FE529,
+                               E81EFF2A055DD99C006FE529,
+                               E81EFF2C055DD99C006FE529,
+                               E81EFF2E055DD99C006FE529,
+                               E81EFF30055DD99C006FE529,
+                               E81EFF32055DD99D006FE529,
+                               E81EFF34055DD99D006FE529,
+                               E81EFF36055DD99D006FE529,
+                               E81EFF38055DD99D006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E809D8FD056B08D80041E20B = {
+                       children = (
+                               E81EFF7A055DD9A1006FE529,
+                               E81EFF7C055DD9A1006FE529,
+                               E81EFF7E055DD9A1006FE529,
+                               E81EFF80055DD9A1006FE529,
+                               E81EFF82055DD9A1006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E809D900056B08E80041E20B = {
+                       children = (
+                               E81EFF7B055DD9A1006FE529,
+                               E81EFF7D055DD9A1006FE529,
+                               E81EFF7F055DD9A1006FE529,
+                               E81EFF81055DD9A1006FE529,
+                               E81EFF83055DD9A1006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E809D909056B093D0041E20B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E809D90F056B09550041E20B,
+                               E809D910056B09570041E20B,
+                               E809D911056B09590041E20B,
+                               E809D912056B095A0041E20B,
+                               E809D913056B095F0041E20B,
+                               E809D914056B09620041E20B,
+                               E809D916056B09690041E20B,
+                               E809D917056B096C0041E20B,
+                               E809D918056B096E0041E20B,
+                               E809D919056B09720041E20B,
+                               E809D91A056B09730041E20B,
+                               E809D91B056B09760041E20B,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E809D90A056B093D0041E20B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E809D90B056B093D0041E20B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8FDB122056C3E42002DFB9D,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E809D90C056B093D0041E20B = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627BA05D93C3300A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E809D90D056B093D0041E20B = {
+                       buildPhases = (
+                               E809D909056B093D0041E20B,
+                               E809D90A056B093D0041E20B,
+                               E809D90B056B093D0041E20B,
+                               E809D90C056B093D0041E20B,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGObjWeb/WebDAV/WebDAV-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC3700000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = WebDAV;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = WebDAV;
+                       productName = WebDAV;
+                       productReference = E809D90E056B093D0041E20B;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>WebDAV</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.WebDAV</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E809D90E056B093D0041E20B = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = WebDAV.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E809D90F056B09550041E20B = {
+                       fileRef = E81EFEEB055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D910056B09570041E20B = {
+                       fileRef = E81EFF09055DD99A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D911056B09590041E20B = {
+                       fileRef = E81EFF25055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D912056B095A0041E20B = {
+                       fileRef = E81EFF26055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D913056B095F0041E20B = {
+                       fileRef = E81EFF28055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D914056B09620041E20B = {
+                       fileRef = E81EFF2B055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D916056B09690041E20B = {
+                       fileRef = E81EFF2D055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D917056B096C0041E20B = {
+                       fileRef = E81EFF2F055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D918056B096E0041E20B = {
+                       fileRef = E81EFF31055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D919056B09720041E20B = {
+                       fileRef = E81EFF33055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D91A056B09730041E20B = {
+                       fileRef = E81EFF35055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D91B056B09760041E20B = {
+                       fileRef = E81EFF37055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E809D91E056B09A20041E20B = {
+                       fileRef = E81CBF7C0569B09C006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E809D91F056B09A70041E20B = {
+                       fileRef = E81CBF550569ACF6006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E809D920056B09B00041E20B = {
+                       fileRef = E81EF99F055DD578006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80D74BE05EE9B56008CFE96 = {
+                       children = (
+                               E81EFF43055DD99D006FE529,
+                               E81EFF44055DD99D006FE529,
+                               E81EFF45055DD99D006FE529,
+                               E81EFF46055DD99D006FE529,
+                               E81EFF47055DD99D006FE529,
+                               E81EFF48055DD99E006FE529,
+                               E81EFF49055DD99E006FE529,
+                               E81EFF4A055DD99E006FE529,
+                               E81EFF4B055DD99E006FE529,
+                               E81EFF4C055DD99E006FE529,
+                               E81EFF94055DD9A2006FE529,
+                               E81EFF95055DD9A2006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = WOComponent;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D74BF05EE9B69008CFE96 = {
+                       children = (
+                               E81EFF52055DD99E006FE529,
+                               E81EFF53055DD99E006FE529,
+                               E81EFF3D055DD99D006FE529,
+                               E81EFF3E055DD99D006FE529,
+                               E81EFF3F055DD99D006FE529,
+                               E81EFF40055DD99D006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = WOApplication;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D74C005EE9B95008CFE96 = {
+                       children = (
+                               E81EFF8C055DD9A1006FE529,
+                               E81EFF8D055DD9A1006FE529,
+                               E81EFD66055DD982006FE529,
+                               E81EFF4D055DD99E006FE529,
+                               E81EFF4E055DD99E006FE529,
+                               E81EFF56055DD99E006FE529,
+                               E81EFF57055DD99E006FE529,
+                               E81EFF89055DD9A1006FE529,
+                               E81EFF8A055DD9A1006FE529,
+                               E81EFF8F055DD9A2006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "Request Handlers";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D74C105EE9BCB008CFE96 = {
+                       children = (
+                               E81EFF5E055DD99F006FE529,
+                               E81EFF96055DD9A2006FE529,
+                               E81EFF97055DD9A2006FE529,
+                               E81EFF98055DD9A2006FE529,
+                               E81EFF99055DD9A2006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Sessions;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D74C205EE9BDF008CFE96 = {
+                       children = (
+                               E81EFF59055DD99E006FE529,
+                               E81EFF5A055DD99F006FE529,
+                               E81EFF5B055DD99F006FE529,
+                               E81EFF5C055DD99F006FE529,
+                               E81EFF5D055DD99F006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Elements;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D74C305EE9BF8008CFE96 = {
+                       children = (
+                               E81EFF87055DD9A1006FE529,
+                               ADFC4758064BC58100092231,
+                               E81EFF88055DD9A1006FE529,
+                               E81EFF8B055DD9A1006FE529,
+                               E81EFF90055DD9A2006FE529,
+                               E81EFF91055DD9A2006FE529,
+                               E81EFF84055DD9A1006FE529,
+                               E81EFF85055DD9A1006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "HTTP Messages";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80D74C405EE9C6E008CFE96 = {
+                       children = (
+                               E81EFEE5055DD998006FE529,
+                               E81EFEE6055DD998006FE529,
+                               E81EFF92055DD9A2006FE529,
+                               E81EFF93055DD9A2006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "MacOSX Extensions";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8147B690569324E00370F87 = {
+                       children = (
+                               E81EFEA4055DD994006FE529,
+                               E81EFF54055DD99E006FE529,
+                               E81EFF9F055DD9A3006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Tools;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8147B6A0569327300370F87 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF99E055DD578006FE529;
+                       remoteInfo = NGScripting;
+               };
+               E8147B6B0569327300370F87 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF99E055DD578006FE529;
+                       targetProxy = E8147B6A0569327300370F87;
+               };
+               E8147B6C0569327300370F87 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9A7055DD582006FE529;
+                       remoteInfo = NGJavaScript;
+               };
+               E8147B6D0569327300370F87 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9A7055DD582006FE529;
+                       targetProxy = E8147B6C0569327300370F87;
+               };
+               E8147B6E0569327300370F87 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9AF055DD58B006FE529;
+                       remoteInfo = NGObjWeb;
+               };
+               E8147B6F0569327300370F87 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9AF055DD58B006FE529;
+                       targetProxy = E8147B6E0569327300370F87;
+               };
+               E8147B700569327300370F87 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9B9055DD599006FE529;
+                       remoteInfo = WEExtensions;
+               };
+               E8147B710569327300370F87 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9B9055DD599006FE529;
+                       targetProxy = E8147B700569327300370F87;
+               };
+               E8147B720569327300370F87 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9C1055DD5A1006FE529;
+                       remoteInfo = WOExtensions;
+               };
+               E8147B730569327300370F87 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9C1055DD5A1006FE529;
+                       targetProxy = E8147B720569327300370F87;
+               };
+               E8147B740569327300370F87 = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81EF9C9055DD5AB006FE529;
+                       remoteInfo = NGObjDOM;
+               };
+               E8147B750569327300370F87 = {
+                       isa = PBXTargetDependency;
+                       target = E81EF9C9055DD5AB006FE529;
+                       targetProxy = E8147B740569327300370F87;
+               };
+               E817B810056B01AD005FDCF0 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = js.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E817B811056B01AE005FDCF0 = {
+                       fileRef = E817B810056B01AD005FDCF0;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E817B839056B033E005FDCF0 = {
+                       children = (
+                               E81EF9FF055DD69E006FE529,
+                               E81EFA08055DD69F006FE529,
+                               E81EFA0A055DD69F006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E817B83C056B0355005FDCF0 = {
+                       children = (
+                               E81EF9FE055DD69E006FE529,
+                               E81EFA00055DD69E006FE529,
+                               E81EFA01055DD69F006FE529,
+                               E81EFA03055DD69F006FE529,
+                               E81EFA04055DD69F006FE529,
+                               E81EFA05055DD69F006FE529,
+                               E81EFA06055DD69F006FE529,
+                               E81EFA07055DD69F006FE529,
+                               E81EFA09055DD69F006FE529,
+                               E81EFA0B055DD69F006FE529,
+                               E81EFA0C055DD69F006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81CBF500569ACF6006AECCE = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81CBF5C0569AD2C006AECCE,
+                               E81CBF5D0569AD2C006AECCE,
+                               E81CBF5E0569AD2D006AECCE,
+                               E81CBF5F0569AD2D006AECCE,
+                               E81CBF600569AD2E006AECCE,
+                               E81CBF610569AD30006AECCE,
+                               E81CBF620569AD31006AECCE,
+                               E81CBF630569AD31006AECCE,
+                               E81CBF640569AD32006AECCE,
+                               E81CBF650569AD33006AECCE,
+                               E81CBF660569AD34006AECCE,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81CBF510569ACF6006AECCE = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81CBF520569ACF6006AECCE = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8FDB123056C3E48002DFB9D,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81CBF530569ACF6006AECCE = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627B805D93C3300A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81CBF540569ACF6006AECCE = {
+                       buildPhases = (
+                               E81CBF500569ACF6006AECCE,
+                               E81CBF510569ACF6006AECCE,
+                               E81CBF520569ACF6006AECCE,
+                               E81CBF530569ACF6006AECCE,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGObjWeb/NGHttp/NGHttp-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC3400000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGHttp;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGHttp;
+                       productName = NGHttp;
+                       productReference = E81CBF550569ACF6006AECCE;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGHttp</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGHttp</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81CBF550569ACF6006AECCE = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGHttp.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81CBF580569AD11006AECCE = {
+                       children = (
+                               E81EFC83055DD971006FE529,
+                               E81EFC85055DD971006FE529,
+                               E81EFC87055DD971006FE529,
+                               E81EFC89055DD971006FE529,
+                               E81EFC8A055DD971006FE529,
+                               E81EFC8C055DD971006FE529,
+                               E81EFC8E055DD971006FE529,
+                               E81EFC90055DD972006FE529,
+                               E81EFC92055DD972006FE529,
+                               E81EFC94055DD972006FE529,
+                               E81EFC96055DD972006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81CBF5B0569AD1E006AECCE = {
+                       children = (
+                               E81EFC81055DD971006FE529,
+                               E81EFC84055DD971006FE529,
+                               E81EFC86055DD971006FE529,
+                               E81EFC88055DD971006FE529,
+                               E81EFC8B055DD971006FE529,
+                               E81EFC8D055DD971006FE529,
+                               E81EFC8F055DD971006FE529,
+                               E81EFC91055DD972006FE529,
+                               E81EFC93055DD972006FE529,
+                               E81EFC95055DD972006FE529,
+                               E81EFC97055DD972006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81CBF5C0569AD2C006AECCE = {
+                       fileRef = E81EFC83055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF5D0569AD2C006AECCE = {
+                       fileRef = E81EFC85055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF5E0569AD2D006AECCE = {
+                       fileRef = E81EFC87055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF5F0569AD2D006AECCE = {
+                       fileRef = E81EFC89055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF600569AD2E006AECCE = {
+                       fileRef = E81EFC8A055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF610569AD30006AECCE = {
+                       fileRef = E81EFC92055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF620569AD31006AECCE = {
+                       fileRef = E81EFC8C055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF630569AD31006AECCE = {
+                       fileRef = E81EFC8E055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF640569AD32006AECCE = {
+                       fileRef = E81EFC90055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF650569AD33006AECCE = {
+                       fileRef = E81EFC94055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF660569AD34006AECCE = {
+                       fileRef = E81EFC96055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF770569B09C006AECCE = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81CBF970569B113006AECCE,
+                               E81CBF980569B114006AECCE,
+                               E81CBF990569B114006AECCE,
+                               E81CBF9A0569B115006AECCE,
+                               E81CBF9B0569B115006AECCE,
+                               E81CBF9C0569B116006AECCE,
+                               E81CBF9D0569B117006AECCE,
+                               E81CBF9E0569B117006AECCE,
+                               E81CBF9F0569B118006AECCE,
+                               E81CBFA00569B119006AECCE,
+                               E81CBFA10569B11A006AECCE,
+                               E81CBFA20569B11A006AECCE,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81CBF780569B09C006AECCE = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81CBF790569B09C006AECCE = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8FDB121056C3E3C002DFB9D,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81CBF7A0569B09C006AECCE = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627B905D93C3300A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81CBF7B0569B09C006AECCE = {
+                       buildPhases = (
+                               E81CBF770569B09C006AECCE,
+                               E81CBF780569B09C006AECCE,
+                               E81CBF790569B09C006AECCE,
+                               E81CBF7A0569B09C006AECCE,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGObjWeb/NGXmlRpc/NGXmlRpc-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC3D00000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGXmlRpc;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGXmlRpc;
+                       productName = NGXmlRpc;
+                       productReference = E81CBF7C0569B09C006AECCE;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGXmlRpc</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGXmlRpc</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81CBF7C0569B09C006AECCE = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGXmlRpc.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81CBF7F0569B0CE006AECCE = {
+                       children = (
+                               E81EFCF5055DD97A006FE529,
+                               E81EFCF7055DD97A006FE529,
+                               E81EFCF9055DD97A006FE529,
+                               E81EFCFB055DD97A006FE529,
+                               E81EFCFD055DD97A006FE529,
+                               E81EFCFF055DD97A006FE529,
+                               E81EFD01055DD97A006FE529,
+                               E81EFD03055DD97B006FE529,
+                               E81EFD59055DD981006FE529,
+                               E81EFD5B055DD981006FE529,
+                               E81EFD60055DD982006FE529,
+                               E81EFD62055DD982006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81CBF930569B0F6006AECCE = {
+                       children = (
+                               E81EFCEF055DD979006FE529,
+                               E81EFCF0055DD979006FE529,
+                               E81EFCF1055DD979006FE529,
+                               E81EFCF2055DD979006FE529,
+                               E81EFCF3055DD979006FE529,
+                               E81EFD5D055DD981006FE529,
+                               E81EFD5E055DD981006FE529,
+                               E81EFD5F055DD981006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "XML-RPC Coding";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81CBF960569B106006AECCE = {
+                       children = (
+                               E81EFCF6055DD97A006FE529,
+                               E81EFCF8055DD97A006FE529,
+                               E81EFCFA055DD97A006FE529,
+                               E81EFCFC055DD97A006FE529,
+                               E81EFCFE055DD97A006FE529,
+                               E81EFD00055DD97A006FE529,
+                               E81EFD02055DD97A006FE529,
+                               E81EFD04055DD97B006FE529,
+                               E81EFD5A055DD981006FE529,
+                               E81EFD5C055DD981006FE529,
+                               E81EFD61055DD982006FE529,
+                               E81EFD63055DD982006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81CBF970569B113006AECCE = {
+                       fileRef = E81EFCF5055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF980569B114006AECCE = {
+                       fileRef = E81EFCF7055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF990569B114006AECCE = {
+                       fileRef = E81EFCF9055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF9A0569B115006AECCE = {
+                       fileRef = E81EFCFB055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF9B0569B115006AECCE = {
+                       fileRef = E81EFCFD055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF9C0569B116006AECCE = {
+                       fileRef = E81EFCFF055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF9D0569B117006AECCE = {
+                       fileRef = E81EFD01055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF9E0569B117006AECCE = {
+                       fileRef = E81EFD03055DD97B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBF9F0569B118006AECCE = {
+                       fileRef = E81EFD59055DD981006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBFA00569B119006AECCE = {
+                       fileRef = E81EFD5B055DD981006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBFA10569B11A006AECCE = {
+                       fileRef = E81EFD60055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CBFA20569B11A006AECCE = {
+                       fileRef = E81EFD62055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81CF247056C2868006EAE6F = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81CBF540569ACF6006AECCE;
+                       remoteInfo = NGHttp;
+               };
+               E81CF248056C2868006EAE6F = {
+                       isa = PBXTargetDependency;
+                       target = E81CBF540569ACF6006AECCE;
+                       targetProxy = E81CF247056C2868006EAE6F;
+               };
+               E81CF249056C2868006EAE6F = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E81CBF7B0569B09C006AECCE;
+                       remoteInfo = NGXmlRpc;
+               };
+               E81CF24A056C2868006EAE6F = {
+                       isa = PBXTargetDependency;
+                       target = E81CBF7B0569B09C006AECCE;
+                       targetProxy = E81CF249056C2868006EAE6F;
+               };
+               E81CF24B056C2868006EAE6F = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E809D90D056B093D0041E20B;
+                       remoteInfo = WebDAV;
+               };
+               E81CF24C056C2868006EAE6F = {
+                       isa = PBXTargetDependency;
+                       target = E809D90D056B093D0041E20B;
+                       targetProxy = E81CF24B056C2868006EAE6F;
+               };
+               E81E0080055DD9A6006FE529 = {
+                       fileRef = E81EFC41055DD96A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0081055DD9A6006FE529 = {
+                       fileRef = E81EFC42055DD96A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0082055DD9A6006FE529 = {
+                       fileRef = E81EFC43055DD96A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0083055DD9A6006FE529 = {
+                       fileRef = E81EFC44055DD96A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0084055DD9A6006FE529 = {
+                       fileRef = E81EFC45055DD96A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0085055DD9A6006FE529 = {
+                       fileRef = E81EFC46055DD96A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0086055DD9A6006FE529 = {
+                       fileRef = E81EFC47055DD96A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0087055DD9A6006FE529 = {
+                       fileRef = E81EFC48055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0088055DD9A6006FE529 = {
+                       fileRef = E81EFC49055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0089055DD9A6006FE529 = {
+                       fileRef = E81EFC4A055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E008A055DD9A6006FE529 = {
+                       fileRef = E81EFC4B055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E008B055DD9A6006FE529 = {
+                       fileRef = E81EFC4C055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E008C055DD9A6006FE529 = {
+                       fileRef = E81EFC4D055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E008D055DD9A6006FE529 = {
+                       fileRef = E81EFC4E055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E008E055DD9A6006FE529 = {
+                       fileRef = E81EFC4F055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E008F055DD9A6006FE529 = {
+                       fileRef = E81EFC50055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0090055DD9A6006FE529 = {
+                       fileRef = E81EFC51055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0091055DD9A6006FE529 = {
+                       fileRef = E81EFC52055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0092055DD9A6006FE529 = {
+                       fileRef = E81EFC53055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0093055DD9A6006FE529 = {
+                       fileRef = E81EFC54055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0094055DD9A6006FE529 = {
+                       fileRef = E81EFC55055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0095055DD9A6006FE529 = {
+                       fileRef = E81EFC56055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0096055DD9A6006FE529 = {
+                       fileRef = E81EFC57055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0097055DD9A6006FE529 = {
+                       fileRef = E81EFC58055DD96B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0098055DD9A6006FE529 = {
+                       fileRef = E81EFC59055DD96C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0099055DD9A6006FE529 = {
+                       fileRef = E81EFC5A055DD96C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E009A055DD9A6006FE529 = {
+                       fileRef = E81EFC5B055DD96C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E009B055DD9A6006FE529 = {
+                       fileRef = E81EFC5C055DD96C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E009C055DD9A6006FE529 = {
+                       fileRef = E81EFC5D055DD96C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E009D055DD9A6006FE529 = {
+                       fileRef = E81EFC5E055DD96C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E009E055DD9A6006FE529 = {
+                       fileRef = E81EFC5F055DD96D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E009F055DD9A6006FE529 = {
+                       fileRef = E81EFC60055DD96D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00A0055DD9A6006FE529 = {
+                       fileRef = E81EFC61055DD96D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00A1055DD9A6006FE529 = {
+                       fileRef = E81EFC62055DD96D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00A2055DD9A6006FE529 = {
+                       fileRef = E81EFC63055DD96D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00A3055DD9A6006FE529 = {
+                       fileRef = E81EFC64055DD96D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00A4055DD9A6006FE529 = {
+                       fileRef = E81EFC65055DD96D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00A5055DD9A6006FE529 = {
+                       fileRef = E81EFC66055DD96E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00A7055DD9A6006FE529 = {
+                       fileRef = E81EFC68055DD96E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00A8055DD9A6006FE529 = {
+                       fileRef = E81EFC69055DD96E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00A9055DD9A6006FE529 = {
+                       fileRef = E81EFC6A055DD96E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00AA055DD9A6006FE529 = {
+                       fileRef = E81EFC6B055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00AB055DD9A6006FE529 = {
+                       fileRef = E81EFC6C055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00AC055DD9A6006FE529 = {
+                       fileRef = E81EFC6D055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00AD055DD9A6006FE529 = {
+                       fileRef = E81EFC6E055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00AE055DD9A6006FE529 = {
+                       fileRef = E81EFC6F055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00AF055DD9A6006FE529 = {
+                       fileRef = E81EFC70055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00B0055DD9A6006FE529 = {
+                       fileRef = E81EFC71055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00B1055DD9A6006FE529 = {
+                       fileRef = E81EFC72055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00B2055DD9A6006FE529 = {
+                       fileRef = E81EFC73055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00B3055DD9A6006FE529 = {
+                       fileRef = E81EFC74055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00B4055DD9A6006FE529 = {
+                       fileRef = E81EFC75055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00B5055DD9A6006FE529 = {
+                       fileRef = E81EFC76055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00B6055DD9A6006FE529 = {
+                       fileRef = E81EFC77055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00B7055DD9A6006FE529 = {
+                       fileRef = E81EFC78055DD96F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00B8055DD9A6006FE529 = {
+                       fileRef = E81EFC79055DD970006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00BC055DD9A6006FE529 = {
+                       fileRef = E81EFC7D055DD970006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00BE055DD9A6006FE529 = {
+                       fileRef = E81EFC80055DD970006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00BF055DD9A6006FE529 = {
+                       fileRef = E81EFC81055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00C1055DD9A6006FE529 = {
+                       fileRef = E81EFC83055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00C2055DD9A6006FE529 = {
+                       fileRef = E81EFC84055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00C3055DD9A6006FE529 = {
+                       fileRef = E81EFC85055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00C4055DD9A6006FE529 = {
+                       fileRef = E81EFC86055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00C5055DD9A6006FE529 = {
+                       fileRef = E81EFC87055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00C6055DD9A6006FE529 = {
+                       fileRef = E81EFC88055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00C7055DD9A6006FE529 = {
+                       fileRef = E81EFC89055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00C8055DD9A6006FE529 = {
+                       fileRef = E81EFC8A055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00C9055DD9A6006FE529 = {
+                       fileRef = E81EFC8B055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00CA055DD9A6006FE529 = {
+                       fileRef = E81EFC8C055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00CB055DD9A6006FE529 = {
+                       fileRef = E81EFC8D055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00CC055DD9A6006FE529 = {
+                       fileRef = E81EFC8E055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00CD055DD9A6006FE529 = {
+                       fileRef = E81EFC8F055DD971006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00CE055DD9A6006FE529 = {
+                       fileRef = E81EFC90055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00CF055DD9A6006FE529 = {
+                       fileRef = E81EFC91055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00D0055DD9A6006FE529 = {
+                       fileRef = E81EFC92055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00D1055DD9A6006FE529 = {
+                       fileRef = E81EFC93055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00D2055DD9A6006FE529 = {
+                       fileRef = E81EFC94055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00D3055DD9A6006FE529 = {
+                       fileRef = E81EFC95055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E00D4055DD9A6006FE529 = {
+                       fileRef = E81EFC96055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E00D5055DD9A6006FE529 = {
+                       fileRef = E81EFC97055DD972006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0101055DD9A6006FE529 = {
+                       fileRef = E81EFCC5055DD976006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0102055DD9A6006FE529 = {
+                       fileRef = E81EFCC6055DD976006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0103055DD9A6006FE529 = {
+                       fileRef = E81EFCC8055DD976006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0104055DD9A6006FE529 = {
+                       fileRef = E81EFCC9055DD976006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0105055DD9A6006FE529 = {
+                       fileRef = E81EFCCA055DD976006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0106055DD9A6006FE529 = {
+                       fileRef = E81EFCCB055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0107055DD9A6006FE529 = {
+                       fileRef = E81EFCCC055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0108055DD9A6006FE529 = {
+                       fileRef = E81EFCCD055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0109055DD9A6006FE529 = {
+                       fileRef = E81EFCCE055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E010A055DD9A6006FE529 = {
+                       fileRef = E81EFCCF055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E010B055DD9A6006FE529 = {
+                       fileRef = E81EFCD0055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E010C055DD9A6006FE529 = {
+                       fileRef = E81EFCD1055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E010D055DD9A6006FE529 = {
+                       fileRef = E81EFCD2055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E010E055DD9A6006FE529 = {
+                       fileRef = E81EFCD3055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E010F055DD9A6006FE529 = {
+                       fileRef = E81EFCD4055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0110055DD9A6006FE529 = {
+                       fileRef = E81EFCD5055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0111055DD9A6006FE529 = {
+                       fileRef = E81EFCD6055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0112055DD9A6006FE529 = {
+                       fileRef = E81EFCD7055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0113055DD9A6006FE529 = {
+                       fileRef = E81EFCD8055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0114055DD9A6006FE529 = {
+                       fileRef = E81EFCD9055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0115055DD9A6006FE529 = {
+                       fileRef = E81EFCDA055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0116055DD9A6006FE529 = {
+                       fileRef = E81EFCDB055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0117055DD9A6006FE529 = {
+                       fileRef = E81EFCDC055DD977006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0118055DD9A6006FE529 = {
+                       fileRef = E81EFCDD055DD978006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0119055DD9A6006FE529 = {
+                       fileRef = E81EFCDE055DD978006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E011A055DD9A6006FE529 = {
+                       fileRef = E81EFCDF055DD978006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E011B055DD9A6006FE529 = {
+                       fileRef = E81EFCE0055DD978006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E011C055DD9A6006FE529 = {
+                       fileRef = E81EFCE1055DD978006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E011D055DD9A6006FE529 = {
+                       fileRef = E81EFCE2055DD978006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E011E055DD9A6006FE529 = {
+                       fileRef = E81EFCE3055DD978006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E011F055DD9A6006FE529 = {
+                       fileRef = E81EFCE4055DD978006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0120055DD9A6006FE529 = {
+                       fileRef = E81EFCE5055DD978006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0121055DD9A6006FE529 = {
+                       fileRef = E81EFCE6055DD978006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0122055DD9A6006FE529 = {
+                       fileRef = E81EFCE7055DD979006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0123055DD9A6006FE529 = {
+                       fileRef = E81EFCE8055DD979006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0124055DD9A6006FE529 = {
+                       fileRef = E81EFCE9055DD979006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0125055DD9A6006FE529 = {
+                       fileRef = E81EFCEA055DD979006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0128055DD9A6006FE529 = {
+                       fileRef = E81EFCEE055DD979006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0129055DD9A6006FE529 = {
+                       fileRef = E81EFCEF055DD979006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E012A055DD9A6006FE529 = {
+                       fileRef = E81EFCF0055DD979006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E012B055DD9A6006FE529 = {
+                       fileRef = E81EFCF1055DD979006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E012C055DD9A6006FE529 = {
+                       fileRef = E81EFCF2055DD979006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E012D055DD9A6006FE529 = {
+                       fileRef = E81EFCF3055DD979006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E012F055DD9A6006FE529 = {
+                       fileRef = E81EFCF5055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0130055DD9A6006FE529 = {
+                       fileRef = E81EFCF6055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0131055DD9A6006FE529 = {
+                       fileRef = E81EFCF7055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0132055DD9A6006FE529 = {
+                       fileRef = E81EFCF8055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0133055DD9A6006FE529 = {
+                       fileRef = E81EFCF9055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0134055DD9A6006FE529 = {
+                       fileRef = E81EFCFA055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0135055DD9A6006FE529 = {
+                       fileRef = E81EFCFB055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0136055DD9A6006FE529 = {
+                       fileRef = E81EFCFC055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0137055DD9A6006FE529 = {
+                       fileRef = E81EFCFD055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0138055DD9A6006FE529 = {
+                       fileRef = E81EFCFE055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0139055DD9A6006FE529 = {
+                       fileRef = E81EFCFF055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E013A055DD9A6006FE529 = {
+                       fileRef = E81EFD00055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E013B055DD9A6006FE529 = {
+                       fileRef = E81EFD01055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E013C055DD9A6006FE529 = {
+                       fileRef = E81EFD02055DD97A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E013D055DD9A6006FE529 = {
+                       fileRef = E81EFD03055DD97B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E013E055DD9A6006FE529 = {
+                       fileRef = E81EFD04055DD97B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0191055DD9A7006FE529 = {
+                       fileRef = E81EFD59055DD981006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0192055DD9A7006FE529 = {
+                       fileRef = E81EFD5A055DD981006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0193055DD9A7006FE529 = {
+                       fileRef = E81EFD5B055DD981006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0194055DD9A7006FE529 = {
+                       fileRef = E81EFD5C055DD981006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0195055DD9A7006FE529 = {
+                       fileRef = E81EFD5D055DD981006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0196055DD9A7006FE529 = {
+                       fileRef = E81EFD5E055DD981006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0197055DD9A7006FE529 = {
+                       fileRef = E81EFD5F055DD981006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0198055DD9A7006FE529 = {
+                       fileRef = E81EFD60055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0199055DD9A7006FE529 = {
+                       fileRef = E81EFD61055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E019A055DD9A7006FE529 = {
+                       fileRef = E81EFD62055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E019B055DD9A7006FE529 = {
+                       fileRef = E81EFD63055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E019C055DD9A7006FE529 = {
+                       fileRef = E81EFD64055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E019D055DD9A7006FE529 = {
+                       fileRef = E81EFD65055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E019E055DD9A7006FE529 = {
+                       fileRef = E81EFD66055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E01A0055DD9A7006FE529 = {
+                       fileRef = E81EFD68055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E01A1055DD9A7006FE529 = {
+                       fileRef = E81EFD69055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E01A5055DD9A7006FE529 = {
+                       fileRef = E81EFD6E055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E01A6055DD9A7006FE529 = {
+                       fileRef = E81EFD6F055DD982006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E01E7055DD9A8006FE529 = {
+                       fileRef = E81EFDB1055DD986006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0229055DD9A8006FE529 = {
+                       fileRef = E81EFDF4055DD989006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E022A055DD9A8006FE529 = {
+                       fileRef = E81EFDF5055DD989006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E022B055DD9A8006FE529 = {
+                       fileRef = E81EFDF6055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E022C055DD9A8006FE529 = {
+                       fileRef = E81EFDF7055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E022D055DD9A8006FE529 = {
+                       fileRef = E81EFDF8055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E022E055DD9A8006FE529 = {
+                       fileRef = E81EFDF9055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E022F055DD9A8006FE529 = {
+                       fileRef = E81EFDFA055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0230055DD9A8006FE529 = {
+                       fileRef = E81EFDFB055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0231055DD9A8006FE529 = {
+                       fileRef = E81EFDFC055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0232055DD9A8006FE529 = {
+                       fileRef = E81EFDFD055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0233055DD9A8006FE529 = {
+                       fileRef = E81EFDFE055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0234055DD9A8006FE529 = {
+                       fileRef = E81EFDFF055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0235055DD9A8006FE529 = {
+                       fileRef = E81EFE00055DD98A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0236055DD9A8006FE529 = {
+                       fileRef = E81EFE01055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0237055DD9A8006FE529 = {
+                       fileRef = E81EFE02055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0238055DD9A8006FE529 = {
+                       fileRef = E81EFE03055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0239055DD9A8006FE529 = {
+                       fileRef = E81EFE04055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E023A055DD9A8006FE529 = {
+                       fileRef = E81EFE05055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E023B055DD9A8006FE529 = {
+                       fileRef = E81EFE06055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E023C055DD9A8006FE529 = {
+                       fileRef = E81EFE07055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E023D055DD9A8006FE529 = {
+                       fileRef = E81EFE08055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E023E055DD9A8006FE529 = {
+                       fileRef = E81EFE09055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E023F055DD9A8006FE529 = {
+                       fileRef = E81EFE0A055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0240055DD9A8006FE529 = {
+                       fileRef = E81EFE0B055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0241055DD9A8006FE529 = {
+                       fileRef = E81EFE0C055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0242055DD9A8006FE529 = {
+                       fileRef = E81EFE0D055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0243055DD9A8006FE529 = {
+                       fileRef = E81EFE0E055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0244055DD9A8006FE529 = {
+                       fileRef = E81EFE0F055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0245055DD9A8006FE529 = {
+                       fileRef = E81EFE10055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0246055DD9A8006FE529 = {
+                       fileRef = E81EFE11055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0247055DD9A8006FE529 = {
+                       fileRef = E81EFE12055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0248055DD9A8006FE529 = {
+                       fileRef = E81EFE13055DD98B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0249055DD9A8006FE529 = {
+                       fileRef = E81EFE14055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E024A055DD9A8006FE529 = {
+                       fileRef = E81EFE15055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E024B055DD9A8006FE529 = {
+                       fileRef = E81EFE16055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E024C055DD9A8006FE529 = {
+                       fileRef = E81EFE17055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E024D055DD9A8006FE529 = {
+                       fileRef = E81EFE18055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E024E055DD9A8006FE529 = {
+                       fileRef = E81EFE19055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E024F055DD9A8006FE529 = {
+                       fileRef = E81EFE1A055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0250055DD9A8006FE529 = {
+                       fileRef = E81EFE1B055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0251055DD9A8006FE529 = {
+                       fileRef = E81EFE1C055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0252055DD9A8006FE529 = {
+                       fileRef = E81EFE1D055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0253055DD9A8006FE529 = {
+                       fileRef = E81EFE1E055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0254055DD9A8006FE529 = {
+                       fileRef = E81EFE1F055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0255055DD9A8006FE529 = {
+                       fileRef = E81EFE20055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0256055DD9A8006FE529 = {
+                       fileRef = E81EFE21055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0257055DD9A8006FE529 = {
+                       fileRef = E81EFE22055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0258055DD9A8006FE529 = {
+                       fileRef = E81EFE23055DD98C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0259055DD9A8006FE529 = {
+                       fileRef = E81EFE24055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E025A055DD9A8006FE529 = {
+                       fileRef = E81EFE25055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E025B055DD9A8006FE529 = {
+                       fileRef = E81EFE26055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E025C055DD9A8006FE529 = {
+                       fileRef = E81EFE27055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E025D055DD9A8006FE529 = {
+                       fileRef = E81EFE28055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E025E055DD9A8006FE529 = {
+                       fileRef = E81EFE29055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0260055DD9A8006FE529 = {
+                       fileRef = E81EFE2B055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0261055DD9A8006FE529 = {
+                       fileRef = E81EFE2C055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0262055DD9A8006FE529 = {
+                       fileRef = E81EFE2D055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0263055DD9A8006FE529 = {
+                       fileRef = E81EFE2E055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0264055DD9A8006FE529 = {
+                       fileRef = E81EFE2F055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0265055DD9A9006FE529 = {
+                       fileRef = E81EFE30055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0267055DD9A9006FE529 = {
+                       fileRef = E81EFE33055DD98D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E028C055DD9A9006FE529 = {
+                       fileRef = E81EFE59055DD990006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E028D055DD9A9006FE529 = {
+                       fileRef = E81EFE5A055DD990006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E028E055DD9A9006FE529 = {
+                       fileRef = E81EFE5B055DD990006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E028F055DD9A9006FE529 = {
+                       fileRef = E81EFE5C055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0290055DD9A9006FE529 = {
+                       fileRef = E81EFE5D055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0291055DD9A9006FE529 = {
+                       fileRef = E81EFE5E055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0292055DD9A9006FE529 = {
+                       fileRef = E81EFE5F055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0293055DD9A9006FE529 = {
+                       fileRef = E81EFE60055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0294055DD9A9006FE529 = {
+                       fileRef = E81EFE61055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0295055DD9A9006FE529 = {
+                       fileRef = E81EFE62055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0296055DD9A9006FE529 = {
+                       fileRef = E81EFE63055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0297055DD9A9006FE529 = {
+                       fileRef = E81EFE64055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0298055DD9A9006FE529 = {
+                       fileRef = E81EFE65055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0299055DD9A9006FE529 = {
+                       fileRef = E81EFE66055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E029A055DD9A9006FE529 = {
+                       fileRef = E81EFE67055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E029B055DD9A9006FE529 = {
+                       fileRef = E81EFE68055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E029C055DD9A9006FE529 = {
+                       fileRef = E81EFE69055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E029D055DD9A9006FE529 = {
+                       fileRef = E81EFE6A055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E029E055DD9A9006FE529 = {
+                       fileRef = E81EFE6B055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E029F055DD9A9006FE529 = {
+                       fileRef = E81EFE6C055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E02A0055DD9A9006FE529 = {
+                       fileRef = E81EFE6D055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E02A1055DD9A9006FE529 = {
+                       fileRef = E81EFE6E055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E02A2055DD9A9006FE529 = {
+                       fileRef = E81EFE6F055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E02A3055DD9A9006FE529 = {
+                       fileRef = E81EFE70055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E02A4055DD9A9006FE529 = {
+                       fileRef = E81EFE71055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E02A5055DD9A9006FE529 = {
+                       fileRef = E81EFE72055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E02A6055DD9A9006FE529 = {
+                       fileRef = E81EFE73055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E02A7055DD9A9006FE529 = {
+                       fileRef = E81EFE74055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E02A8055DD9A9006FE529 = {
+                       fileRef = E81EFE75055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E02A9055DD9A9006FE529 = {
+                       fileRef = E81EFE76055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E02AA055DD9A9006FE529 = {
+                       fileRef = E81EFE77055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E02AB055DD9A9006FE529 = {
+                       fileRef = E81EFE78055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E02AC055DD9A9006FE529 = {
+                       fileRef = E81EFE79055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E02AD055DD9A9006FE529 = {
+                       fileRef = E81EFE7A055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E02AE055DD9A9006FE529 = {
+                       fileRef = E81EFE7B055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E02AF055DD9A9006FE529 = {
+                       fileRef = E81EFE7C055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E02D4055DD9A9006FE529 = {
+                       fileRef = E81EFEA2055DD994006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0303055DD9AA006FE529 = {
+                       fileRef = E81EFED4055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0304055DD9AA006FE529 = {
+                       fileRef = E81EFED5055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0305055DD9AA006FE529 = {
+                       fileRef = E81EFED6055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0306055DD9AA006FE529 = {
+                       fileRef = E81EFED7055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0307055DD9AA006FE529 = {
+                       fileRef = E81EFED8055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0308055DD9AA006FE529 = {
+                       fileRef = E81EFED9055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0309055DD9AA006FE529 = {
+                       fileRef = E81EFEDA055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E030A055DD9AA006FE529 = {
+                       fileRef = E81EFEDB055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E030B055DD9AA006FE529 = {
+                       fileRef = E81EFEDC055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E030C055DD9AA006FE529 = {
+                       fileRef = E81EFEDD055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E030D055DD9AA006FE529 = {
+                       fileRef = E81EFEDE055DD997006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E030E055DD9AA006FE529 = {
+                       fileRef = E81EFEDF055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E030F055DD9AA006FE529 = {
+                       fileRef = E81EFEE0055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0310055DD9AA006FE529 = {
+                       fileRef = E81EFEE1055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0311055DD9AA006FE529 = {
+                       fileRef = E81EFEE2055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0314055DD9AA006FE529 = {
+                       fileRef = E81EFEE5055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0315055DD9AA006FE529 = {
+                       fileRef = E81EFEE6055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0316055DD9AA006FE529 = {
+                       fileRef = E81EFEE7055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0319055DD9AA006FE529 = {
+                       fileRef = E81EFEEB055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E031A055DD9AA006FE529 = {
+                       fileRef = E81EFEEC055DD998006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0336055DD9AA006FE529 = {
+                       fileRef = E81EFF09055DD99A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0337055DD9AA006FE529 = {
+                       fileRef = E81EFF0A055DD99A006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0351055DD9AA006FE529 = {
+                       fileRef = E81EFF25055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0352055DD9AA006FE529 = {
+                       fileRef = E81EFF26055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0353055DD9AA006FE529 = {
+                       fileRef = E81EFF27055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0354055DD9AA006FE529 = {
+                       fileRef = E81EFF28055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0355055DD9AA006FE529 = {
+                       fileRef = E81EFF29055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0356055DD9AA006FE529 = {
+                       fileRef = E81EFF2A055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0357055DD9AA006FE529 = {
+                       fileRef = E81EFF2B055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0358055DD9AA006FE529 = {
+                       fileRef = E81EFF2C055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0359055DD9AA006FE529 = {
+                       fileRef = E81EFF2D055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E035A055DD9AA006FE529 = {
+                       fileRef = E81EFF2E055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E035B055DD9AA006FE529 = {
+                       fileRef = E81EFF2F055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E035C055DD9AA006FE529 = {
+                       fileRef = E81EFF30055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E035D055DD9AA006FE529 = {
+                       fileRef = E81EFF31055DD99C006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E035E055DD9AA006FE529 = {
+                       fileRef = E81EFF32055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E035F055DD9AA006FE529 = {
+                       fileRef = E81EFF33055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0360055DD9AA006FE529 = {
+                       fileRef = E81EFF34055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0361055DD9AA006FE529 = {
+                       fileRef = E81EFF35055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0362055DD9AA006FE529 = {
+                       fileRef = E81EFF36055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0363055DD9AA006FE529 = {
+                       fileRef = E81EFF37055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0364055DD9AA006FE529 = {
+                       fileRef = E81EFF38055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0365055DD9AA006FE529 = {
+                       fileRef = E81EFF39055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0366055DD9AA006FE529 = {
+                       fileRef = E81EFF3A055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0369055DD9AA006FE529 = {
+                       fileRef = E81EFF3D055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E036A055DD9AA006FE529 = {
+                       fileRef = E81EFF3E055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E036B055DD9AA006FE529 = {
+                       fileRef = E81EFF3F055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                               );
+                       };
+               };
+               E81E036C055DD9AA006FE529 = {
+                       fileRef = E81EFF40055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E036F055DD9AA006FE529 = {
+                       fileRef = E81EFF43055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0370055DD9AA006FE529 = {
+                       fileRef = E81EFF44055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0371055DD9AA006FE529 = {
+                       fileRef = E81EFF45055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0372055DD9AA006FE529 = {
+                       fileRef = E81EFF46055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0373055DD9AA006FE529 = {
+                       fileRef = E81EFF47055DD99D006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0374055DD9AA006FE529 = {
+                       fileRef = E81EFF48055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0375055DD9AA006FE529 = {
+                       fileRef = E81EFF49055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0376055DD9AA006FE529 = {
+                       fileRef = E81EFF4A055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0377055DD9AA006FE529 = {
+                       fileRef = E81EFF4B055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0378055DD9AA006FE529 = {
+                       fileRef = E81EFF4C055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0379055DD9AA006FE529 = {
+                       fileRef = E81EFF4D055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E037A055DD9AA006FE529 = {
+                       fileRef = E81EFF4E055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E037B055DD9AA006FE529 = {
+                       fileRef = E81EFF4F055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E037C055DD9AA006FE529 = {
+                       fileRef = E81EFF50055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E037D055DD9AA006FE529 = {
+                       fileRef = E81EFF51055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E037E055DD9AA006FE529 = {
+                       fileRef = E81EFF52055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E037F055DD9AA006FE529 = {
+                       fileRef = E81EFF53055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0381055DD9AA006FE529 = {
+                       fileRef = E81EFF55055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0382055DD9AA006FE529 = {
+                       fileRef = E81EFF56055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0383055DD9AA006FE529 = {
+                       fileRef = E81EFF57055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0384055DD9AA006FE529 = {
+                       fileRef = E81EFF58055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0385055DD9AA006FE529 = {
+                       fileRef = E81EFF59055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0386055DD9AA006FE529 = {
+                       fileRef = E81EFF5A055DD99F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0387055DD9AA006FE529 = {
+                       fileRef = E81EFF5B055DD99F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E0388055DD9AA006FE529 = {
+                       fileRef = E81EFF5C055DD99F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E0389055DD9AA006FE529 = {
+                       fileRef = E81EFF5D055DD99F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E038A055DD9AA006FE529 = {
+                       fileRef = E81EFF5E055DD99F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03A3055DD9AB006FE529 = {
+                       fileRef = E81EFF7A055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E03A4055DD9AB006FE529 = {
+                       fileRef = E81EFF7B055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03A5055DD9AB006FE529 = {
+                       fileRef = E81EFF7C055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E03A6055DD9AB006FE529 = {
+                       fileRef = E81EFF7D055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03A7055DD9AB006FE529 = {
+                       fileRef = E81EFF7E055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E03A8055DD9AB006FE529 = {
+                       fileRef = E81EFF7F055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03A9055DD9AB006FE529 = {
+                       fileRef = E81EFF80055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E03AA055DD9AB006FE529 = {
+                       fileRef = E81EFF81055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03AB055DD9AB006FE529 = {
+                       fileRef = E81EFF82055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E03AC055DD9AB006FE529 = {
+                       fileRef = E81EFF83055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03AD055DD9AB006FE529 = {
+                       fileRef = E81EFF84055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03AE055DD9AB006FE529 = {
+                       fileRef = E81EFF85055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03AF055DD9AB006FE529 = {
+                       fileRef = E81EFF86055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03B0055DD9AB006FE529 = {
+                       fileRef = E81EFF87055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03B1055DD9AB006FE529 = {
+                       fileRef = E81EFF88055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03B2055DD9AB006FE529 = {
+                       fileRef = E81EFF89055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03B3055DD9AB006FE529 = {
+                       fileRef = E81EFF8A055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03B4055DD9AB006FE529 = {
+                       fileRef = E81EFF8B055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03B5055DD9AB006FE529 = {
+                       fileRef = E81EFF8C055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03B6055DD9AB006FE529 = {
+                       fileRef = E81EFF8D055DD9A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03B7055DD9AB006FE529 = {
+                       fileRef = E81EFF8E055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03B8055DD9AB006FE529 = {
+                       fileRef = E81EFF8F055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03B9055DD9AB006FE529 = {
+                       fileRef = E81EFF90055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03BA055DD9AB006FE529 = {
+                       fileRef = E81EFF91055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03BB055DD9AB006FE529 = {
+                       fileRef = E81EFF92055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E03BC055DD9AB006FE529 = {
+                       fileRef = E81EFF93055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03BD055DD9AB006FE529 = {
+                       fileRef = E81EFF94055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E03BE055DD9AB006FE529 = {
+                       fileRef = E81EFF95055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03BF055DD9AB006FE529 = {
+                       fileRef = E81EFF96055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03C0055DD9AB006FE529 = {
+                       fileRef = E81EFF97055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03C1055DD9AB006FE529 = {
+                       fileRef = E81EFF98055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03C2055DD9AB006FE529 = {
+                       fileRef = E81EFF99055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03C3055DD9AB006FE529 = {
+                       fileRef = E81EFF9A055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81E03C4055DD9AB006FE529 = {
+                       fileRef = E81EFF9B055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03C5055DD9AB006FE529 = {
+                       fileRef = E81EFF9C055DD9A2006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03C6055DD9AB006FE529 = {
+                       fileRef = E81EFF9D055DD9A3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03C7055DD9AB006FE529 = {
+                       fileRef = E81EFF9E055DD9A3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81E03CB055DDA4C006FE529 = {
+                       children = (
+                               E81EFC7A055DD970006FE529,
+                               E81EFC7B055DD970006FE529,
+                               E81EFC7C055DD970006FE529,
+                               E81EFCEB055DD979006FE529,
+                               E81EFF3B055DD99D006FE529,
+                               E81EFF3C055DD99D006FE529,
+                               E81EFF41055DD99D006FE529,
+                               E81EFF42055DD99D006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E03CE055DDA6A006FE529 = {
+                       children = (
+                               E81EFB7D055DD960006FE529,
+                               E81EFB7E055DD960006FE529,
+                               E81EFC7D055DD970006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Resources;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81E03D3055DDB0B006FE529 = {
+                       children = (
+                               E80D74BF05EE9B69008CFE96,
+                               E80D74BE05EE9B56008CFE96,
+                               E80D74C005EE9B95008CFE96,
+                               E80D74C105EE9BCB008CFE96,
+                               E80D74C205EE9BDF008CFE96,
+                               E80D74C305EE9BF8008CFE96,
+                               E80D74C405EE9C6E008CFE96,
+                               E81EFB5B055DD95E006FE529,
+                               E81EFB5C055DD95E006FE529,
+                               E81EFB7A055DD960006FE529,
+                               E81EFB7F055DD960006FE529,
+                               E81EFCC5055DD976006FE529,
+                               E81EFCC6055DD976006FE529,
+                               E81EFCEA055DD979006FE529,
+                               E81EFD64055DD982006FE529,
+                               E81EFD65055DD982006FE529,
+                               E81EFD68055DD982006FE529,
+                               E81EFD69055DD982006FE529,
+                               E81EFF39055DD99D006FE529,
+                               E81EFF3A055DD99D006FE529,
+                               E81EFF4F055DD99E006FE529,
+                               E81EFF50055DD99E006FE529,
+                               E81EFF51055DD99E006FE529,
+                               E81EFF55055DD99E006FE529,
+                               E81EFF58055DD99E006FE529,
+                               E81EFF86055DD9A1006FE529,
+                               E81EFF8E055DD9A2006FE529,
+                               E81EFF9A055DD9A2006FE529,
+                               E81EFF9B055DD9A2006FE529,
+                               E81EFF9C055DD9A2006FE529,
+                               E81EFF9D055DD9A3006FE529,
+                               E81EFF9E055DD9A3006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF985055DD52B006FE529 = {
+                       children = (
+                               AD1626FE05D91A1C00A7368D,
+                               AD16270F05D91FB400A7368D,
+                               AD1626FB05D91A1B00A7368D,
+                               AD1626FC05D91A1B00A7368D,
+                               AD1626FD05D91A1C00A7368D,
+                               AD0CE02305D95126004D9B87,
+                               AD1626FF05D91A1C00A7368D,
+                               E81EF995055DD551006FE529,
+                               E81EF994055DD54E006FE529,
+                               E81EF993055DD549006FE529,
+                               E81EF992055DD545006FE529,
+                               E81EF991055DD541006FE529,
+                               ADE23A1D063FDE730050249C,
+                               E81EF990055DD53B006FE529,
+                               ADDB79D305C0B18D009DBFB4,
+                               E896325105697A7C00E7D217,
+                               E81EF9A0055DD578006FE529,
+                       );
+                       isa = PBXGroup;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF987055DD52B006FE529 = {
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = "APPLE_RUNTIME=1 NeXT_Foundation_LIBRARY=1 COCOA_Foundation_LIBRARY=1 NeXT_RUNTIME=1 COMPILE_AS_FRAMEWORK=1 DEBUG=1";
+                       };
+                       isa = PBXBuildStyle;
+                       name = Development;
+               };
+               E81EF989055DD52B006FE529 = {
+                       buildSettings = {
+                       };
+                       buildStyles = (
+                               E81EF987055DD52B006FE529,
+                               AD853F4906A7FB6B00727CA0,
+                       );
+                       hasScannedForEncodings = 1;
+                       isa = PBXProject;
+                       mainGroup = E81EF985055DD52B006FE529;
+                       productRefGroup = E81EF9A0055DD578006FE529;
+                       projectDirPath = "";
+                       targets = (
+                               E81EF99E055DD578006FE529,
+                               E81EF9A7055DD582006FE529,
+                               E81CBF540569ACF6006AECCE,
+                               E809D90D056B093D0041E20B,
+                               E8AC8BBF05ABBF07008C206D,
+                               E81CBF7B0569B09C006AECCE,
+                               E81EF9C1055DD5A1006FE529,
+                               E81EF9B9055DD599006FE529,
+                               E81EF9C9055DD5AB006FE529,
+                               E81EF9AF055DD58B006FE529,
+                               ADE23A17063FD6200050249C,
+                               ADDB798705C0B141009DBFB4,
+                               AD853F2906A7FA9500727CA0,
+                               ADF834DF0657F03400B8881A,
+                               ADF835AE0657F59500B8881A,
+                               E839D7D6056966FC00C2567C,
+                               E839D7DE0569670800C2567C,
+                               E839D7E90569671D00C2567C,
+                               E81EF9CD055DD5B5006FE529,
+                               E81EF9D0055DD5BE006FE529,
+                       );
+               };
+               E81EF990055DD53B006FE529 = {
+                       children = (
+                               E84DABC2056AF1A100355953,
+                               E84DABC4056AF1A100355953,
+                               E84DAB7B056AF19C00355953,
+                               E84DAB7C056AF19C00355953,
+                               E84DABA5056AF19F00355953,
+                               E84DABA6056AF19F00355953,
+                               E84DAB7E056AF19C00355953,
+                               E84DAB7F056AF19C00355953,
+                               E84DAB81056AF19C00355953,
+                               E84DABC8056AF1A100355953,
+                               E84DABE9056AF1A400355953,
+                               E84DACA2056AF22F00355953,
+                               E84DACA5056AF25A00355953,
+                       );
+                       isa = PBXGroup;
+                       name = NGObjDOM;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF991055DD541006FE529 = {
+                       children = (
+                               E84DAB3E056AEF0800355953,
+                               E84DAB41056AEF0800355953,
+                               E84DAB42056AEF0800355953,
+                               E84DAB4D056AEF0900355953,
+                               E84DAB3D056AEF0800355953,
+                               E84DAB78056AF15500355953,
+                               ADCEA325061AEF3D00361086,
+                               E84DAB75056AF13C00355953,
+                       );
+                       isa = PBXGroup;
+                       name = WOExtensions;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF992055DD545006FE529 = {
+                       children = (
+                               E84DAAA5056AEE4000355953,
+                               E84DAAA1056AEE3F00355953,
+                               E84DAAA7056AEE4000355953,
+                               E84DAAA8056AEE4000355953,
+                               E84DAAB3056AEE4000355953,
+                               E8AC8B6605ABAD45008C206D,
+                               E8AC8B6505ABAD1A008C206D,
+                               E8AC8B6705ABAD5A008C206D,
+                               ADB59399061DFD540094D980,
+                       );
+                       isa = PBXGroup;
+                       name = WEExtensions;
+                       path = "";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF993055DD549006FE529 = {
+                       children = (
+                               E81EFD67055DD982006FE529,
+                               E81EFB79055DD960006FE529,
+                               E81EFB7B055DD960006FE529,
+                               E81EFB7C055DD960006FE529,
+                               E81EFEE3055DD998006FE529,
+                               E81EFEE4055DD998006FE529,
+                               E81EFEE7055DD998006FE529,
+                               E81E03CB055DDA4C006FE529,
+                               E8147B690569324E00370F87,
+                               E81E03CE055DDA6A006FE529,
+                               E81EFCC7055DD976006FE529,
+                               E81E03D3055DDB0B006FE529,
+                               E81EFB5D055DD95E006FE529,
+                               E81EFB80055DD960006FE529,
+                               E81EFC7E055DD970006FE529,
+                               E81EFCEC055DD979006FE529,
+                               E81EFD6A055DD982006FE529,
+                               E81EFE31055DD98D006FE529,
+                               E81EFEA5055DD994006FE529,
+                               E81EFEE8055DD998006FE529,
+                               E81EFF5F055DD99F006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = NGObjWeb;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF994055DD54E006FE529 = {
+                       children = (
+                               E81EFA5C055DD6A1006FE529,
+                               E81EF9F9055DD69E006FE529,
+                               E81EF9FB055DD69E006FE529,
+                               E81EFA75055DD6A1006FE529,
+                               E81EFA76055DD6A1006FE529,
+                               E81EFA5D055DD6A1006FE529,
+                               E81EFA65055DD6A1006FE529,
+                               E81EFAF1055DD6C2006FE529,
+                               E81EFAF8055DD6EC006FE529,
+                               E81EFAFB055DD6FA006FE529,
+                               E81EF9FC055DD69E006FE529,
+                               E81EFA66055DD6A1006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = NGJavaScript;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF995055DD551006FE529 = {
+                       children = (
+                               E81EF9DC055DD671006FE529,
+                               E81EF9DE055DD671006FE529,
+                               E81EF9E7055DD671006FE529,
+                               E81EF9F6055DD679006FE529,
+                               E81EF9DD055DD671006FE529,
+                               E81EF9E1055DD671006FE529,
+                               E81EF9E2055DD671006FE529,
+                               E81EF9E3055DD671006FE529,
+                               E81EF9E4055DD671006FE529,
+                               E81EF9E5055DD671006FE529,
+                               E81EF9E6055DD671006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = NGScripting;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF99A055DD578006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EF9E9055DD671006FE529,
+                               E81EF9ED055DD671006FE529,
+                               E81EF9EF055DD671006FE529,
+                               E81EF9F1055DD671006FE529,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF99B055DD578006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EF9E8055DD671006FE529,
+                               E81EF9EA055DD671006FE529,
+                               E81EF9EB055DD671006FE529,
+                               E81EF9EC055DD671006FE529,
+                               E81EF9F3055DD671006FE529,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF99C055DD578006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EF9EE055DD671006FE529,
+                               E81EF9F0055DD671006FE529,
+                               E81EF9F2055DD671006FE529,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF99D055DD578006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627B605D93C3300A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF99E055DD578006FE529 = {
+                       buildPhases = (
+                               E81EF99A055DD578006FE529,
+                               E81EF99B055DD578006FE529,
+                               E81EF99C055DD578006FE529,
+                               E81EF99D055DD578006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGScripting/NGScripting-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "-DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1";
+                               OTHER_LDFLAGS = "-seg1addr 0xC3000000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGScripting;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGScripting;
+                       productName = NGScripting;
+                       productReference = E81EF99F055DD578006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGScripting</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGScripting</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF99F055DD578006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGScripting.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF9A0055DD578006FE529 = {
+                       children = (
+                               E81EF99F055DD578006FE529,
+                               E81EF9A8055DD582006FE529,
+                               E81CBF550569ACF6006AECCE,
+                               E809D90E056B093D0041E20B,
+                               E8AC8BC005ABBF07008C206D,
+                               E81CBF7C0569B09C006AECCE,
+                               E81EF9C2055DD5A1006FE529,
+                               E81EF9BA055DD599006FE529,
+                               E81EF9CA055DD5AB006FE529,
+                               E81EF9B0055DD58B006FE529,
+                               ADE23A18063FD6200050249C,
+                               ADDB798805C0B141009DBFB4,
+                               ADF834E00657F03400B8881A,
+                               ADF835AF0657F59500B8881A,
+                               E839D7D7056966FC00C2567C,
+                               E839D7DF0569670800C2567C,
+                               E839D7EA0569671D00C2567C,
+                       );
+                       isa = PBXGroup;
+                       name = Products;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9A3055DD582006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EFA78055DD6A1006FE529,
+                               E81EFA7C055DD6A1006FE529,
+                               E81EFA85055DD6A1006FE529,
+                               E81EFA87055DD6A1006FE529,
+                               E81EFAB9055DD6A2006FE529,
+                               E81EFABF055DD6A2006FE529,
+                               E81EFAC1055DD6A2006FE529,
+                               E81EFAC3055DD6A2006FE529,
+                               E81EFAC5055DD6A2006FE529,
+                               E81EFAC6055DD6A2006FE529,
+                               E81EFAC8055DD6A2006FE529,
+                               E81EFACB055DD6A2006FE529,
+                               E81EFACD055DD6A2006FE529,
+                               E81EFACF055DD6A2006FE529,
+                               E81EFAD1055DD6A2006FE529,
+                               E81EFAD3055DD6A2006FE529,
+                               E81EFAD5055DD6A2006FE529,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9A4055DD582006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EFA79055DD6A1006FE529,
+                               E81EFA7A055DD6A1006FE529,
+                               E81EFABC055DD6A2006FE529,
+                               E81EFAD7055DD6A2006FE529,
+                               E81EFAD8055DD6A2006FE529,
+                               E81EFAED055DD6A2006FE529,
+                               E8C21635056B061A00073655,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9A5055DD582006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EFA7B055DD6A1006FE529,
+                               E81EFA7D055DD6A1006FE529,
+                               E81EFA7E055DD6A1006FE529,
+                               E81EFA80055DD6A1006FE529,
+                               E81EFA81055DD6A1006FE529,
+                               E81EFA82055DD6A1006FE529,
+                               E81EFA83055DD6A1006FE529,
+                               E81EFA84055DD6A1006FE529,
+                               E81EFA86055DD6A1006FE529,
+                               E81EFA88055DD6A1006FE529,
+                               E81EFA89055DD6A1006FE529,
+                               E81EFABA055DD6A2006FE529,
+                               E81EFAC0055DD6A2006FE529,
+                               E81EFAC2055DD6A2006FE529,
+                               E81EFAC4055DD6A2006FE529,
+                               E81EFAC7055DD6A2006FE529,
+                               E81EFAC9055DD6A2006FE529,
+                               E81EFACA055DD6A2006FE529,
+                               E81EFACC055DD6A2006FE529,
+                               E81EFACE055DD6A2006FE529,
+                               E81EFAD0055DD6A2006FE529,
+                               E81EFAD2055DD6A2006FE529,
+                               E81EFAD4055DD6A2006FE529,
+                               E81EFAD6055DD6A2006FE529,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9A6055DD582006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627B705D93C3300A7368D,
+                               E817B811056B01AE005FDCF0,
+                               E8C2162A056B050300073655,
+                               E8C21663056B066500073655,
+                               E8C21664056B067500073655,
+                               AD8540AF06A7FCE100727CA0,
+                               AD8540B006A7FCE100727CA0,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9A7055DD582006FE529 = {
+                       buildPhases = (
+                               E81EF9A3055DD582006FE529,
+                               E81EF9A4055DD582006FE529,
+                               E81EF9A5055DD582006FE529,
+                               E81EF9A6055DD582006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGJavaScript/NGJavaScript-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "-DXP_UNIX=1 -DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1";
+                               OTHER_LDFLAGS = "-seg1addr 0xC3200000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGJavaScript;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGJavaScript;
+                       productName = NGJavaScript;
+                       productReference = E81EF9A8055DD582006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGJavaScript</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGJavaScript</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF9A8055DD582006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGJavaScript.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF9AB055DD58B006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EFFA0055DD9A5006FE529,
+                               E81EFFB5055DD9A5006FE529,
+                               E81EFFB7055DD9A5006FE529,
+                               E81EFFB9055DD9A5006FE529,
+                               E81EFFBC055DD9A5006FE529,
+                               E81EFFC3055DD9A5006FE529,
+                               E81E0086055DD9A6006FE529,
+                               E81E0088055DD9A6006FE529,
+                               E81E008A055DD9A6006FE529,
+                               E81E0090055DD9A6006FE529,
+                               E81E0094055DD9A6006FE529,
+                               E81E0098055DD9A6006FE529,
+                               E81E009B055DD9A6006FE529,
+                               E81E00A0055DD9A6006FE529,
+                               E81E00BF055DD9A6006FE529,
+                               E81E00C1055DD9A6006FE529,
+                               E81E00C3055DD9A6006FE529,
+                               E81E00C5055DD9A6006FE529,
+                               E81E00C7055DD9A6006FE529,
+                               E81E00C8055DD9A6006FE529,
+                               E81E00CA055DD9A6006FE529,
+                               E81E00CC055DD9A6006FE529,
+                               E81E00CE055DD9A6006FE529,
+                               E81E00D0055DD9A6006FE529,
+                               E81E00D2055DD9A6006FE529,
+                               E81E00D4055DD9A6006FE529,
+                               E81E0101055DD9A6006FE529,
+                               E81E0103055DD9A6006FE529,
+                               E81E0104055DD9A6006FE529,
+                               E81E0105055DD9A6006FE529,
+                               E81E0106055DD9A6006FE529,
+                               E81E0107055DD9A6006FE529,
+                               E81E0108055DD9A6006FE529,
+                               E81E0109055DD9A6006FE529,
+                               E81E010A055DD9A6006FE529,
+                               E81E010B055DD9A6006FE529,
+                               E81E010C055DD9A6006FE529,
+                               E81E010D055DD9A6006FE529,
+                               E81E010E055DD9A6006FE529,
+                               E81E010F055DD9A6006FE529,
+                               E81E0110055DD9A6006FE529,
+                               E81E0111055DD9A6006FE529,
+                               E81E0112055DD9A6006FE529,
+                               E81E0113055DD9A6006FE529,
+                               E81E0114055DD9A6006FE529,
+                               E81E0115055DD9A6006FE529,
+                               E81E0116055DD9A6006FE529,
+                               E81E0117055DD9A6006FE529,
+                               E81E0118055DD9A6006FE529,
+                               E81E0119055DD9A6006FE529,
+                               E81E011A055DD9A6006FE529,
+                               E81E011B055DD9A6006FE529,
+                               E81E011C055DD9A6006FE529,
+                               E81E011D055DD9A6006FE529,
+                               E81E011E055DD9A6006FE529,
+                               E81E011F055DD9A6006FE529,
+                               E81E0120055DD9A6006FE529,
+                               E81E0121055DD9A6006FE529,
+                               E81E0122055DD9A6006FE529,
+                               E81E0123055DD9A6006FE529,
+                               E81E0124055DD9A6006FE529,
+                               E81E012F055DD9A6006FE529,
+                               E81E0131055DD9A6006FE529,
+                               E81E0133055DD9A6006FE529,
+                               E81E0135055DD9A6006FE529,
+                               E81E0137055DD9A6006FE529,
+                               E81E0139055DD9A6006FE529,
+                               E81E013B055DD9A6006FE529,
+                               E81E013D055DD9A6006FE529,
+                               E81E0191055DD9A7006FE529,
+                               E81E0193055DD9A7006FE529,
+                               E81E0198055DD9A7006FE529,
+                               E81E019A055DD9A7006FE529,
+                               E81E019C055DD9A7006FE529,
+                               E81E01A0055DD9A7006FE529,
+                               E81E01A5055DD9A7006FE529,
+                               E81E0229055DD9A8006FE529,
+                               E81E022B055DD9A8006FE529,
+                               E81E022D055DD9A8006FE529,
+                               E81E022F055DD9A8006FE529,
+                               E81E0231055DD9A8006FE529,
+                               E81E0233055DD9A8006FE529,
+                               E81E0235055DD9A8006FE529,
+                               E81E0237055DD9A8006FE529,
+                               E81E0239055DD9A8006FE529,
+                               E81E023B055DD9A8006FE529,
+                               E81E023E055DD9A8006FE529,
+                               E81E0240055DD9A8006FE529,
+                               E81E0242055DD9A8006FE529,
+                               E81E0244055DD9A8006FE529,
+                               E81E0245055DD9A8006FE529,
+                               E81E0247055DD9A8006FE529,
+                               E81E0249055DD9A8006FE529,
+                               E81E024B055DD9A8006FE529,
+                               E81E024D055DD9A8006FE529,
+                               E81E024F055DD9A8006FE529,
+                               E81E0251055DD9A8006FE529,
+                               E81E0253055DD9A8006FE529,
+                               E81E0255055DD9A8006FE529,
+                               E81E0257055DD9A8006FE529,
+                               E81E0259055DD9A8006FE529,
+                               E81E025B055DD9A8006FE529,
+                               E81E025D055DD9A8006FE529,
+                               E81E0260055DD9A8006FE529,
+                               E81E0264055DD9A8006FE529,
+                               E81E0267055DD9A9006FE529,
+                               E81E028C055DD9A9006FE529,
+                               E81E028E055DD9A9006FE529,
+                               E81E0290055DD9A9006FE529,
+                               E81E0292055DD9A9006FE529,
+                               E81E0294055DD9A9006FE529,
+                               E81E0296055DD9A9006FE529,
+                               E81E0299055DD9A9006FE529,
+                               E81E029B055DD9A9006FE529,
+                               E81E029D055DD9A9006FE529,
+                               E81E029F055DD9A9006FE529,
+                               E81E02A1055DD9A9006FE529,
+                               E81E02A3055DD9A9006FE529,
+                               E81E02A5055DD9A9006FE529,
+                               E81E02A7055DD9A9006FE529,
+                               E81E02A9055DD9A9006FE529,
+                               E81E02AB055DD9A9006FE529,
+                               E81E02AD055DD9A9006FE529,
+                               E81E02D4055DD9A9006FE529,
+                               E81E0305055DD9AA006FE529,
+                               E81E0307055DD9AA006FE529,
+                               E81E030C055DD9AA006FE529,
+                               E81E0310055DD9AA006FE529,
+                               E81E0314055DD9AA006FE529,
+                               E81E0319055DD9AA006FE529,
+                               E81E0336055DD9AA006FE529,
+                               E81E0351055DD9AA006FE529,
+                               E81E0352055DD9AA006FE529,
+                               E81E0354055DD9AA006FE529,
+                               E81E0357055DD9AA006FE529,
+                               E81E0359055DD9AA006FE529,
+                               E81E035B055DD9AA006FE529,
+                               E81E035D055DD9AA006FE529,
+                               E81E035F055DD9AA006FE529,
+                               E81E0361055DD9AA006FE529,
+                               E81E0363055DD9AA006FE529,
+                               E81E036B055DD9AA006FE529,
+                               E81E036F055DD9AA006FE529,
+                               E81E0373055DD9AA006FE529,
+                               E81E0375055DD9AA006FE529,
+                               E81E0377055DD9AA006FE529,
+                               E81E0379055DD9AA006FE529,
+                               E81E037C055DD9AA006FE529,
+                               E81E0382055DD9AA006FE529,
+                               E81E0387055DD9AA006FE529,
+                               E81E0388055DD9AA006FE529,
+                               E81E03A3055DD9AB006FE529,
+                               E81E03A5055DD9AB006FE529,
+                               E81E03A7055DD9AB006FE529,
+                               E81E03A9055DD9AB006FE529,
+                               E81E03AB055DD9AB006FE529,
+                               E81E03B6055DD9AB006FE529,
+                               E81E03BA055DD9AB006FE529,
+                               E81E03BB055DD9AB006FE529,
+                               E81E03BD055DD9AB006FE529,
+                               E81E03C3055DD9AB006FE529,
+                               E899919105EE858500874B24,
+                               E857FDB405FC9C090026154C,
+                               AD4883370634250C00D38EA7,
+                               AD06642A06AD6CCB006525C9,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9AC055DD58B006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EFFBB055DD9A5006FE529,
+                               E81EFFBD055DD9A5006FE529,
+                               E81EFFBE055DD9A5006FE529,
+                               E81EFFC0055DD9A5006FE529,
+                               E81E00BC055DD9A6006FE529,
+                               E81E00BE055DD9A6006FE529,
+                               E81E0128055DD9A6006FE529,
+                               E81E01E7055DD9A8006FE529,
+                               E81E02AF055DD9A9006FE529,
+                               E81E0316055DD9AA006FE529,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9AD055DD58B006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E81EFFA1055DD9A5006FE529,
+                               E81EFFB4055DD9A5006FE529,
+                               E81EFFB6055DD9A5006FE529,
+                               E81EFFB8055DD9A5006FE529,
+                               E81EFFBA055DD9A5006FE529,
+                               E81EFFC1055DD9A5006FE529,
+                               E81E0080055DD9A6006FE529,
+                               E81E0081055DD9A6006FE529,
+                               E81E0082055DD9A6006FE529,
+                               E81E0083055DD9A6006FE529,
+                               E81E0084055DD9A6006FE529,
+                               E81E0085055DD9A6006FE529,
+                               E81E0087055DD9A6006FE529,
+                               E81E0089055DD9A6006FE529,
+                               E81E008B055DD9A6006FE529,
+                               E81E008C055DD9A6006FE529,
+                               E81E008D055DD9A6006FE529,
+                               E81E008E055DD9A6006FE529,
+                               E81E008F055DD9A6006FE529,
+                               E81E0091055DD9A6006FE529,
+                               E81E0092055DD9A6006FE529,
+                               E81E0093055DD9A6006FE529,
+                               E81E0095055DD9A6006FE529,
+                               E81E0096055DD9A6006FE529,
+                               E81E0097055DD9A6006FE529,
+                               E81E0099055DD9A6006FE529,
+                               E81E009A055DD9A6006FE529,
+                               E81E009C055DD9A6006FE529,
+                               E81E009D055DD9A6006FE529,
+                               E81E009E055DD9A6006FE529,
+                               E81E009F055DD9A6006FE529,
+                               E81E00A1055DD9A6006FE529,
+                               E81E00A2055DD9A6006FE529,
+                               E81E00A3055DD9A6006FE529,
+                               E81E00A4055DD9A6006FE529,
+                               E81E00A5055DD9A6006FE529,
+                               E81E00A7055DD9A6006FE529,
+                               E81E00A8055DD9A6006FE529,
+                               E81E00A9055DD9A6006FE529,
+                               E81E00AA055DD9A6006FE529,
+                               E81E00AB055DD9A6006FE529,
+                               E81E00AC055DD9A6006FE529,
+                               E81E00AD055DD9A6006FE529,
+                               E81E00AE055DD9A6006FE529,
+                               E81E00AF055DD9A6006FE529,
+                               E81E00B0055DD9A6006FE529,
+                               E81E00B1055DD9A6006FE529,
+                               E81E00B2055DD9A6006FE529,
+                               E81E00B3055DD9A6006FE529,
+                               E81E00B4055DD9A6006FE529,
+                               E81E00B5055DD9A6006FE529,
+                               E81E00B6055DD9A6006FE529,
+                               E81E00B7055DD9A6006FE529,
+                               E81E00B8055DD9A6006FE529,
+                               E81E00C2055DD9A6006FE529,
+                               E81E00C4055DD9A6006FE529,
+                               E81E00C6055DD9A6006FE529,
+                               E81E00C9055DD9A6006FE529,
+                               E81E00CB055DD9A6006FE529,
+                               E81E00CD055DD9A6006FE529,
+                               E81E00CF055DD9A6006FE529,
+                               E81E00D1055DD9A6006FE529,
+                               E81E00D3055DD9A6006FE529,
+                               E81E00D5055DD9A6006FE529,
+                               E81E0102055DD9A6006FE529,
+                               E81E0125055DD9A6006FE529,
+                               E81E0129055DD9A6006FE529,
+                               E81E012A055DD9A6006FE529,
+                               E81E012B055DD9A6006FE529,
+                               E81E012C055DD9A6006FE529,
+                               E81E012D055DD9A6006FE529,
+                               E81E0130055DD9A6006FE529,
+                               E81E0132055DD9A6006FE529,
+                               E81E0134055DD9A6006FE529,
+                               E81E0136055DD9A6006FE529,
+                               E81E0138055DD9A6006FE529,
+                               E81E013A055DD9A6006FE529,
+                               E81E013C055DD9A6006FE529,
+                               E81E013E055DD9A6006FE529,
+                               E81E0192055DD9A7006FE529,
+                               E81E0194055DD9A7006FE529,
+                               E81E0195055DD9A7006FE529,
+                               E81E0196055DD9A7006FE529,
+                               E81E0197055DD9A7006FE529,
+                               E81E0199055DD9A7006FE529,
+                               E81E019B055DD9A7006FE529,
+                               E81E019D055DD9A7006FE529,
+                               E81E019E055DD9A7006FE529,
+                               E81E01A1055DD9A7006FE529,
+                               E81E01A6055DD9A7006FE529,
+                               E81E022A055DD9A8006FE529,
+                               E81E022C055DD9A8006FE529,
+                               E81E022E055DD9A8006FE529,
+                               E81E0230055DD9A8006FE529,
+                               E81E0232055DD9A8006FE529,
+                               E81E0234055DD9A8006FE529,
+                               E81E0236055DD9A8006FE529,
+                               E81E0238055DD9A8006FE529,
+                               E81E023A055DD9A8006FE529,
+                               E81E023C055DD9A8006FE529,
+                               E81E023D055DD9A8006FE529,
+                               E81E023F055DD9A8006FE529,
+                               E81E0241055DD9A8006FE529,
+                               E81E0243055DD9A8006FE529,
+                               E81E0246055DD9A8006FE529,
+                               E81E0248055DD9A8006FE529,
+                               E81E024A055DD9A8006FE529,
+                               E81E024C055DD9A8006FE529,
+                               E81E024E055DD9A8006FE529,
+                               E81E0250055DD9A8006FE529,
+                               E81E0252055DD9A8006FE529,
+                               E81E0254055DD9A8006FE529,
+                               E81E0256055DD9A8006FE529,
+                               E81E0258055DD9A8006FE529,
+                               E81E025A055DD9A8006FE529,
+                               E81E025C055DD9A8006FE529,
+                               E81E025E055DD9A8006FE529,
+                               E81E0261055DD9A8006FE529,
+                               E81E0262055DD9A8006FE529,
+                               E81E0263055DD9A8006FE529,
+                               E81E0265055DD9A9006FE529,
+                               E81E028D055DD9A9006FE529,
+                               E81E028F055DD9A9006FE529,
+                               E81E0291055DD9A9006FE529,
+                               E81E0293055DD9A9006FE529,
+                               E81E0295055DD9A9006FE529,
+                               E81E0297055DD9A9006FE529,
+                               E81E0298055DD9A9006FE529,
+                               E81E029A055DD9A9006FE529,
+                               E81E029C055DD9A9006FE529,
+                               E81E029E055DD9A9006FE529,
+                               E81E02A0055DD9A9006FE529,
+                               E81E02A2055DD9A9006FE529,
+                               E81E02A4055DD9A9006FE529,
+                               E81E02A6055DD9A9006FE529,
+                               E81E02A8055DD9A9006FE529,
+                               E81E02AA055DD9A9006FE529,
+                               E81E02AC055DD9A9006FE529,
+                               E81E02AE055DD9A9006FE529,
+                               E81E0303055DD9AA006FE529,
+                               E81E0304055DD9AA006FE529,
+                               E81E0306055DD9AA006FE529,
+                               E81E0308055DD9AA006FE529,
+                               E81E0309055DD9AA006FE529,
+                               E81E030A055DD9AA006FE529,
+                               E81E030B055DD9AA006FE529,
+                               E81E030D055DD9AA006FE529,
+                               E81E030E055DD9AA006FE529,
+                               E81E030F055DD9AA006FE529,
+                               E81E0311055DD9AA006FE529,
+                               E81E0315055DD9AA006FE529,
+                               E81E031A055DD9AA006FE529,
+                               E81E0337055DD9AA006FE529,
+                               E81E0353055DD9AA006FE529,
+                               E81E0355055DD9AA006FE529,
+                               E81E0356055DD9AA006FE529,
+                               E81E0358055DD9AA006FE529,
+                               E81E035A055DD9AA006FE529,
+                               E81E035C055DD9AA006FE529,
+                               E81E035E055DD9AA006FE529,
+                               E81E0360055DD9AA006FE529,
+                               E81E0362055DD9AA006FE529,
+                               E81E0364055DD9AA006FE529,
+                               E81E0365055DD9AA006FE529,
+                               E81E0366055DD9AA006FE529,
+                               E81E0369055DD9AA006FE529,
+                               E81E036A055DD9AA006FE529,
+                               E81E036C055DD9AA006FE529,
+                               E81E0370055DD9AA006FE529,
+                               E81E0371055DD9AA006FE529,
+                               E81E0372055DD9AA006FE529,
+                               E81E0374055DD9AA006FE529,
+                               E81E0376055DD9AA006FE529,
+                               E81E0378055DD9AA006FE529,
+                               E81E037A055DD9AA006FE529,
+                               E81E037B055DD9AA006FE529,
+                               E81E037D055DD9AA006FE529,
+                               E81E037E055DD9AA006FE529,
+                               E81E037F055DD9AA006FE529,
+                               E81E0381055DD9AA006FE529,
+                               E81E0383055DD9AA006FE529,
+                               E81E0384055DD9AA006FE529,
+                               E81E0385055DD9AA006FE529,
+                               E81E0386055DD9AA006FE529,
+                               E81E0389055DD9AA006FE529,
+                               E81E038A055DD9AA006FE529,
+                               E81E03A4055DD9AB006FE529,
+                               E81E03A6055DD9AB006FE529,
+                               E81E03A8055DD9AB006FE529,
+                               E81E03AA055DD9AB006FE529,
+                               E81E03AC055DD9AB006FE529,
+                               E81E03AD055DD9AB006FE529,
+                               E81E03AE055DD9AB006FE529,
+                               E81E03AF055DD9AB006FE529,
+                               E81E03B0055DD9AB006FE529,
+                               E81E03B1055DD9AB006FE529,
+                               E81E03B2055DD9AB006FE529,
+                               E81E03B3055DD9AB006FE529,
+                               E81E03B4055DD9AB006FE529,
+                               E81E03B5055DD9AB006FE529,
+                               E81E03B7055DD9AB006FE529,
+                               E81E03B8055DD9AB006FE529,
+                               E81E03B9055DD9AB006FE529,
+                               E81E03BC055DD9AB006FE529,
+                               E81E03BE055DD9AB006FE529,
+                               E81E03BF055DD9AB006FE529,
+                               E81E03C0055DD9AB006FE529,
+                               E81E03C1055DD9AB006FE529,
+                               E81E03C2055DD9AB006FE529,
+                               E81E03C4055DD9AB006FE529,
+                               E81E03C5055DD9AB006FE529,
+                               E81E03C6055DD9AB006FE529,
+                               E81E03C7055DD9AB006FE529,
+                               E899919205EE858500874B24,
+                               E857FDB505FC9C090026154C,
+                               AD48832F0634249000D38EA7,
+                               AD4883300634249000D38EA7,
+                               AD4883310634249100D38EA7,
+                               AD4883320634249100D38EA7,
+                               AD488364063427B300D38EA7,
+                               AD488365063427B300D38EA7,
+                               ADFC4759064BC58100092231,
+                               AD06642B06AD6CCB006525C9,
+                               AD06646E06AD6E2D006525C9,
+                               ADCDE36406AD744A00BFCE2B,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9AE055DD58B006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627BB05D93C3300A7368D,
+                               E896325F05697AB200E7D217,
+                               E896325A05697AB200E7D217,
+                               E8FDB167056C40FB002DFB9D,
+                               E896325B05697AB200E7D217,
+                               E896325C05697AB200E7D217,
+                               E896325D05697AB200E7D217,
+                               E896325E05697AB200E7D217,
+                               E809D91E056B09A20041E20B,
+                               E809D91F056B09A70041E20B,
+                               E809D920056B09B00041E20B,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9AF055DD58B006FE529 = {
+                       buildPhases = (
+                               E81EF9AB055DD58B006FE529,
+                               E81EF9AC055DD58B006FE529,
+                               E81EF9AD055DD58B006FE529,
+                               E81EF9AE055DD58B006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = NGObjWeb;
+                               INFOPLIST_FILE = "NGObjWeb/NGObjWeb-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "-I.. -DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1 -DCOMPILE_AS_FRAMEWORK=1 -DNeXT_Foundation_LIBRARY=1";
+                               OTHER_LDFLAGS = "-seg1addr 0xC4900000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGObjWeb;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                               E81CF248056C2868006EAE6F,
+                               E81CF24A056C2868006EAE6F,
+                               E81CF24C056C2868006EAE6F,
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGObjWeb;
+                       productName = NGObjWeb;
+                       productReference = E81EF9B0055DD58B006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGObjWeb</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGObjWeb</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF9B0055DD58B006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGObjWeb.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF9B5055DD599006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E84DAAE5056AEE4300355953,
+                               E84DAAED056AEE4300355953,
+                               E84DAAEF056AEE4300355953,
+                               E84DAAF4056AEE4300355953,
+                               E84DAAF6056AEE4300355953,
+                               E84DAAF9056AEE4300355953,
+                               E84DAAFF056AEE4300355953,
+                               E84DAB09056AEE4300355953,
+                               E84DAB16056AEE4300355953,
+                               E8AC8B7005ABADF1008C206D,
+                               E8AC8B7305ABADF1008C206D,
+                               ADB593B6061DFDB60094D980,
+                               ADB593BA061DFDB60094D980,
+                               ADB593BC061DFDB60094D980,
+                               ADB593BF061DFDB60094D980,
+                               ADB593C1061DFDB60094D980,
+                               ADB593C3061DFDB60094D980,
+                               ADB593C6061DFDB60094D980,
+                               ADB593C8061DFDB60094D980,
+                               ADB593C9061DFDB60094D980,
+                               ADB593CB061DFDB60094D980,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9B6055DD599006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E84DAAE0056AEE4300355953,
+                               E84DAAE1056AEE4300355953,
+                               E84DAAE2056AEE4300355953,
+                               E84DAAE4056AEE4300355953,
+                               E84DAAE6056AEE4300355953,
+                               E84DAAE7056AEE4300355953,
+                               E84DAAE9056AEE4300355953,
+                               E84DAAEA056AEE4300355953,
+                               E84DAAEB056AEE4300355953,
+                               E84DAAF2056AEE4300355953,
+                               E84DAB00056AEE4300355953,
+                               E84DAB01056AEE4300355953,
+                               ADB593B4061DFDB60094D980,
+                               ADB593B5061DFDB60094D980,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9B7055DD599006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E84DAAE3056AEE4300355953,
+                               E84DAAE8056AEE4300355953,
+                               E84DAAEC056AEE4300355953,
+                               E84DAAEE056AEE4300355953,
+                               E84DAAF0056AEE4300355953,
+                               E84DAAF1056AEE4300355953,
+                               E84DAAF3056AEE4300355953,
+                               E84DAAF5056AEE4300355953,
+                               E84DAAF7056AEE4300355953,
+                               E84DAAF8056AEE4300355953,
+                               E84DAAFA056AEE4300355953,
+                               E84DAAFB056AEE4300355953,
+                               E84DAAFC056AEE4300355953,
+                               E84DAAFD056AEE4300355953,
+                               E84DAAFE056AEE4300355953,
+                               E84DAB02056AEE4300355953,
+                               E84DAB03056AEE4300355953,
+                               E84DAB04056AEE4300355953,
+                               E84DAB05056AEE4300355953,
+                               E84DAB06056AEE4300355953,
+                               E84DAB07056AEE4300355953,
+                               E84DAB08056AEE4300355953,
+                               E84DAB0A056AEE4300355953,
+                               E84DAB0F056AEE4300355953,
+                               E84DAB10056AEE4300355953,
+                               E84DAB11056AEE4300355953,
+                               E84DAB17056AEE4300355953,
+                               E84DAB18056AEE4300355953,
+                               E84DAB19056AEE4300355953,
+                               E84DAB1A056AEE4300355953,
+                               E84DAB1B056AEE4300355953,
+                               E84DAB1C056AEE4300355953,
+                               E84DAB1D056AEE4300355953,
+                               E84DAB1E056AEE4300355953,
+                               E8AC8B7105ABADF1008C206D,
+                               E8AC8B7205ABADF1008C206D,
+                               E8AC8B7405ABADF1008C206D,
+                               AD18022B0611D79400ED723F,
+                               ADCEA32D061AF02F00361086,
+                               ADB593B7061DFDB60094D980,
+                               ADB593B8061DFDB60094D980,
+                               ADB593B9061DFDB60094D980,
+                               ADB593BB061DFDB60094D980,
+                               ADB593BD061DFDB60094D980,
+                               ADB593BE061DFDB60094D980,
+                               ADB593C0061DFDB60094D980,
+                               ADB593C2061DFDB60094D980,
+                               ADB593C4061DFDB60094D980,
+                               ADB593C5061DFDB60094D980,
+                               ADB593C7061DFDB60094D980,
+                               ADB593CA061DFDB60094D980,
+                               ADB593CC061DFDB60094D980,
+                               ADB593CD061DFDB60094D980,
+                               AD4883500634261C00D38EA7,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9B8055DD599006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627BD05D93C3300A7368D,
+                               AD85412206A8215D00727CA0,
+                               AD85412306A8215D00727CA0,
+                               AD8541EA06A828F600727CA0,
+                               E8AC8B6205ABAC86008C206D,
+                               E8AC8B6305ABAC88008C206D,
+                               AD8541EC06A8294E00727CA0,
+                               AD8541EB06A8290900727CA0,
+                               E8AC8B6405ABAC92008C206D,
+                               E83FAEE205B6F991003836D9,
+                               AD8541F006A82A1700727CA0,
+                               AD8541F106A82A2800727CA0,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9B9055DD599006FE529 = {
+                       buildPhases = (
+                               E81EF9B5055DD599006FE529,
+                               E81EF9B6055DD599006FE529,
+                               E81EF9B7055DD599006FE529,
+                               E81EF9B8055DD599006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "WEExtensions/WEExtensions-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "-DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1 -DNeXT_Foundation_LIBRARY=1";
+                               OTHER_LDFLAGS = "-seg1addr 0xC4000000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = WEExtensions;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = WEExtensions;
+                       productName = WEExtensions;
+                       productReference = E81EF9BA055DD599006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>WEExtensions</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.WEExtensions</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF9BA055DD599006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = WEExtensions.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF9BD055DD5A1006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E84DAB5A056AEF0A00355953,
+                               ADCEA328061AEF7400361086,
+                               ADCEA329061AEF7400361086,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9BE055DD5A1006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E84DAB58056AEF0A00355953,
+                               E84DAB59056AEF0A00355953,
+                               E84DAB5C056AEF0A00355953,
+                               E84DAB5D056AEF0A00355953,
+                               E84DAB5F056AEF0A00355953,
+                               E84DAB60056AEF0A00355953,
+                               E84DAB68056AEF0A00355953,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9BF055DD5A1006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E84DAB5B056AEF0A00355953,
+                               E84DAB5E056AEF0A00355953,
+                               E84DAB61056AEF0A00355953,
+                               E84DAB62056AEF0A00355953,
+                               E84DAB63056AEF0A00355953,
+                               E84DAB64056AEF0A00355953,
+                               E84DAB65056AEF0A00355953,
+                               E84DAB66056AEF0A00355953,
+                               E84DAB67056AEF0A00355953,
+                               E84DAB69056AEF0A00355953,
+                               E84DAB6A056AEF0A00355953,
+                               E84DAB6B056AEF0A00355953,
+                               E84DAB6C056AEF0A00355953,
+                               E84DAB6D056AEF0A00355953,
+                               E84DAB6E056AEF0A00355953,
+                               E84DAB6F056AEF0A00355953,
+                               E84DAB70056AEF0A00355953,
+                               E84DAB71056AEF0A00355953,
+                               E84DAB72056AEF0A00355953,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9C0055DD5A1006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627BE05D93C3300A7368D,
+                               AD85420406A82A5E00727CA0,
+                               AD85420506A82A5E00727CA0,
+                               AD85420606A82A5E00727CA0,
+                               AD85420706A82A5E00727CA0,
+                               AD85420806A82A5E00727CA0,
+                               AD85420906A82A5E00727CA0,
+                               AD85420A06A82A5E00727CA0,
+                               E8AC8B7605ABB6F0008C206D,
+                               E83FAEFB05B6FA1B003836D9,
+                               AD85420B06A82A5E00727CA0,
+                               AD85420C06A82A5E00727CA0,
+                               E8AC8B7705ABB6FA008C206D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9C1055DD5A1006FE529 = {
+                       buildPhases = (
+                               E81EF9BD055DD5A1006FE529,
+                               E81EF9BE055DD5A1006FE529,
+                               E81EF9BF055DD5A1006FE529,
+                               E81EF9C0055DD5A1006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "WOExtensions/WOExtensions-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC4300000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = WOExtensions;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = WOExtensions;
+                       productName = WOExtensions;
+                       productReference = E81EF9C2055DD5A1006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>WOExtensions</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.WOExtensions</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF9C2055DD5A1006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = WOExtensions.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF9C5055DD5AB006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E84DAC11056AF1A800355953,
+                               E84DAC19056AF1A800355953,
+                               E84DAC21056AF1A800355953,
+                               E84DAC28056AF1A800355953,
+                               E84DAC2C056AF1A800355953,
+                               E84DAC30056AF1A800355953,
+                               E84DAC38056AF1A800355953,
+                               E84DAC3A056AF1A800355953,
+                               E84DAC3B056AF1A800355953,
+                               E84DAC3D056AF1A800355953,
+                               E84DAC3F056AF1A800355953,
+                               E84DAC41056AF1A800355953,
+                               E84DAC43056AF1A800355953,
+                               E84DAC44056AF1A800355953,
+                               E84DAC45056AF1A800355953,
+                               E84DAC46056AF1A800355953,
+                               E84DAC47056AF1A800355953,
+                               E84DAC48056AF1A800355953,
+                               E84DAC4A056AF1A800355953,
+                               E84DAC4C056AF1A800355953,
+                               E84DAC4E056AF1A800355953,
+                               E84DAC50056AF1A800355953,
+                               E84DAC54056AF1A800355953,
+                               E84DAC56056AF1A800355953,
+                               E84DAC57056AF1A800355953,
+                               E84DAC67056AF1A800355953,
+                               E84DAC69056AF1A800355953,
+                               E84DAC77056AF1A800355953,
+                               E84DAC85056AF1A800355953,
+                               E84DAC87056AF1A800355953,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9C6055DD5AB006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E84DAC0F056AF1A800355953,
+                               E84DAC10056AF1A800355953,
+                               E84DAC12056AF1A800355953,
+                               E84DAC13056AF1A800355953,
+                               E84DAC15056AF1A800355953,
+                               E84DAC16056AF1A800355953,
+                               E84DAC17056AF1A800355953,
+                               E84DAC18056AF1A800355953,
+                               E84DAC36056AF1A800355953,
+                               E84DAC37056AF1A800355953,
+                               E84DAC53056AF1A800355953,
+                               E84DAC55056AF1A800355953,
+                               E84DAC59056AF1A800355953,
+                               E84DAC5A056AF1A800355953,
+                               E84DAC5B056AF1A800355953,
+                               E84DAC5C056AF1A800355953,
+                               E84DAC5D056AF1A800355953,
+                               E84DAC5E056AF1A800355953,
+                               E84DAC72056AF1A800355953,
+                               E84DAC73056AF1A800355953,
+                               E84DAC74056AF1A800355953,
+                               E84DAC75056AF1A800355953,
+                               E84DAC76056AF1A800355953,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9C7055DD5AB006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E84DAC14056AF1A800355953,
+                               E84DAC1A056AF1A800355953,
+                               E84DAC1B056AF1A800355953,
+                               E84DAC1C056AF1A800355953,
+                               E84DAC1D056AF1A800355953,
+                               E84DAC1E056AF1A800355953,
+                               E84DAC1F056AF1A800355953,
+                               E84DAC20056AF1A800355953,
+                               E84DAC23056AF1A800355953,
+                               E84DAC24056AF1A800355953,
+                               E84DAC25056AF1A800355953,
+                               E84DAC26056AF1A800355953,
+                               E84DAC27056AF1A800355953,
+                               E84DAC29056AF1A800355953,
+                               E84DAC2A056AF1A800355953,
+                               E84DAC2B056AF1A800355953,
+                               E84DAC2D056AF1A800355953,
+                               E84DAC2E056AF1A800355953,
+                               E84DAC2F056AF1A800355953,
+                               E84DAC31056AF1A800355953,
+                               E84DAC32056AF1A800355953,
+                               E84DAC33056AF1A800355953,
+                               E84DAC34056AF1A800355953,
+                               E84DAC35056AF1A800355953,
+                               E84DAC39056AF1A800355953,
+                               E84DAC3C056AF1A800355953,
+                               E84DAC3E056AF1A800355953,
+                               E84DAC40056AF1A800355953,
+                               E84DAC42056AF1A800355953,
+                               E84DAC49056AF1A800355953,
+                               E84DAC4B056AF1A800355953,
+                               E84DAC4D056AF1A800355953,
+                               E84DAC4F056AF1A800355953,
+                               E84DAC51056AF1A800355953,
+                               E84DAC52056AF1A800355953,
+                               E84DAC58056AF1A800355953,
+                               E84DAC5F056AF1A800355953,
+                               E84DAC60056AF1A800355953,
+                               E84DAC61056AF1A800355953,
+                               E84DAC62056AF1A800355953,
+                               E84DAC63056AF1A800355953,
+                               E84DAC64056AF1A800355953,
+                               E84DAC65056AF1A800355953,
+                               E84DAC66056AF1A800355953,
+                               E84DAC68056AF1A800355953,
+                               E84DAC6A056AF1A800355953,
+                               E84DAC78056AF1A800355953,
+                               E84DAC79056AF1A800355953,
+                               E84DAC7A056AF1A800355953,
+                               E84DAC7B056AF1A800355953,
+                               E84DAC7C056AF1A800355953,
+                               E84DAC7D056AF1A800355953,
+                               E84DAC7E056AF1A800355953,
+                               E84DAC7F056AF1A800355953,
+                               E84DAC80056AF1A800355953,
+                               E84DAC81056AF1A800355953,
+                               E84DAC82056AF1A800355953,
+                               E84DAC83056AF1A800355953,
+                               E84DAC84056AF1A800355953,
+                               E84DAC86056AF1A800355953,
+                               E84DAC88056AF1A800355953,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9C8055DD5AB006FE529 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627BF05D93C3300A7368D,
+                               AD85422106A82CE100727CA0,
+                               E8AC8BAF05ABB959008C206D,
+                               AD85422206A82CE100727CA0,
+                               E8AC8BB005ABB963008C206D,
+                               E8AC8BAD05ABB93F008C206D,
+                               E8AC8B7905ABB7A7008C206D,
+                               E83FAF0805B6FAB0003836D9,
+                               E8AC8B7805ABB7A5008C206D,
+                               AD85422F06A82DCC00727CA0,
+                               AD85422406A82CE100727CA0,
+                               AD85422506A82CE100727CA0,
+                               AD85422906A82D4B00727CA0,
+                               AD85422E06A82DAF00727CA0,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E81EF9C9055DD5AB006FE529 = {
+                       buildPhases = (
+                               E81EF9C5055DD5AB006FE529,
+                               E81EF9C6055DD5AB006FE529,
+                               E81EF9C7055DD5AB006FE529,
+                               E81EF9C8055DD5AB006FE529,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGObjDOM/NGObjDOM-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "-DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1 -DNeXT_Foundation_LIBRARY=1";
+                               OTHER_LDFLAGS = "-seg1addr 0xC4600000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = NGObjDOM;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = NGObjDOM;
+                       productName = NGObjDOM;
+                       productReference = E81EF9CA055DD5AB006FE529;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>NGObjDOM</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.NGObjDOM</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E81EF9CA055DD5AB006FE529 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = NGObjDOM.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E81EF9CD055DD5B5006FE529 = {
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = all;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       dependencies = (
+                               E8147B6B0569327300370F87,
+                               E8147B6D0569327300370F87,
+                               E8147B6F0569327300370F87,
+                               E8AC8BC305ABBF53008C206D,
+                               E8147B710569327300370F87,
+                               E8147B730569327300370F87,
+                               E8147B750569327300370F87,
+                               ADDB79D505C0B26F009DBFB4,
+                               ADF835B90657F8BE00B8881A,
+                               ADF835BB0657F8BE00B8881A,
+                               E8AC8BB405ABBEC4008C206D,
+                               E8AC8BB605ABBEC4008C206D,
+                               E8AC8BB805ABBEC4008C206D,
+                               ADE23A5B063FE1FF0050249C,
+                       );
+                       isa = PBXAggregateTarget;
+                       name = all;
+                       productName = all;
+               };
+               E81EF9D0055DD5BE006FE529 = {
+                       buildArgumentsString = "$(ACTION)";
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "GSM: all";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       buildToolPath = /usr/bin/make;
+                       dependencies = (
+                       );
+                       isa = PBXLegacyTarget;
+                       name = "GSM: all";
+                       passBuildSettingsInEnvironment = 1;
+                       productName = "GSM: all";
+               };
+               E81EF9DC055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = NGScripting/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9DD055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = NGScripting/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9DE055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = NGScripting/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9DF055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = NGScripting/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9E0055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = NGScripting/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9E1055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGObjectMappingContext.h;
+                       path = NGScripting/NGObjectMappingContext.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9E2055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGObjectMappingContext.m;
+                       path = NGScripting/NGObjectMappingContext.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9E3055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGScriptLanguage.h;
+                       path = NGScripting/NGScriptLanguage.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9E4055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGScriptLanguage.m;
+                       path = NGScripting/NGScriptLanguage.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9E5055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NSObject+Scripting.h";
+                       path = "NGScripting/NSObject+Scripting.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9E6055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSObject+Scripting.m";
+                       path = "NGScripting/NSObject+Scripting.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9E7055DD671006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = NGScripting/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9E8055DD671006FE529 = {
+                       fileRef = E81EF9DC055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF9E9055DD671006FE529 = {
+                       fileRef = E81EF9DD055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF9EA055DD671006FE529 = {
+                       fileRef = E81EF9DE055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF9EB055DD671006FE529 = {
+                       fileRef = E81EF9DF055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF9EC055DD671006FE529 = {
+                       fileRef = E81EF9E0055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF9ED055DD671006FE529 = {
+                       fileRef = E81EF9E1055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF9EE055DD671006FE529 = {
+                       fileRef = E81EF9E2055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF9EF055DD671006FE529 = {
+                       fileRef = E81EF9E3055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF9F0055DD671006FE529 = {
+                       fileRef = E81EF9E4055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF9F1055DD671006FE529 = {
+                       fileRef = E81EF9E5055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EF9F2055DD671006FE529 = {
+                       fileRef = E81EF9E6055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF9F3055DD671006FE529 = {
+                       fileRef = E81EF9E7055DD671006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EF9F6055DD679006FE529 = {
+                       children = (
+                               E81EF9DF055DD671006FE529,
+                               E81EF9E0055DD671006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9F9055DD69E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = NGJavaScript/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9FA055DD69E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = NGJavaScript/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9FB055DD69E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = NGJavaScript/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9FC055DD69E006FE529 = {
+                       children = (
+                               E81EF9FD055DD69E006FE529,
+                               E81EFA02055DD69F006FE529,
+                               E817B839056B033E005FDCF0,
+                               E817B83C056B0355005FDCF0,
+                       );
+                       isa = PBXGroup;
+                       name = "Core JS";
+                       path = "NGJavaScript/Core+JS.subproj";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9FD055DD69E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9FE055DD69E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EODataSource+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EF9FF055DD69E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = EOJavaScriptGrouping.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA00055DD69E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = EOJavaScriptGrouping.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA01055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EONull+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA02055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA03055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NGFileManager+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA04055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSArray+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA05055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSDate+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA06055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSDictionary+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA07055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSNumber+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA08055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSObject+JS.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA09055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSObject+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA0A055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSString+JS.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA0B055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA0C055DD69F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSUserDefaults+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA3D055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = dummy.m;
+                       path = NGJavaScript/dummy.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA3E055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = globals.h;
+                       path = NGJavaScript/globals.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA3F055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = globals.m;
+                       path = NGJavaScript/globals.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA40055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = NGJavaScript/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA41055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = NGJavaScript/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA42055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSObjectOps.m;
+                       path = NGJavaScript/JSObjectOps.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA43055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = jsobjops.m;
+                       path = NGJavaScript/jsobjops.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA44055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScript.h;
+                       path = NGJavaScript/NGJavaScript.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA45055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptArray.m;
+                       path = NGJavaScript/NGJavaScriptArray.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA46055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptCallable.h;
+                       path = NGJavaScript/NGJavaScriptCallable.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA47055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptCallable.m;
+                       path = NGJavaScript/NGJavaScriptCallable.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA48055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptContext.h;
+                       path = NGJavaScript/NGJavaScriptContext.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA49055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptContext.m;
+                       path = NGJavaScript/NGJavaScriptContext.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA4A055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptDecls.h;
+                       path = NGJavaScript/NGJavaScriptDecls.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA4B055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptError.h;
+                       path = NGJavaScript/NGJavaScriptError.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA4C055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptError.m;
+                       path = NGJavaScript/NGJavaScriptError.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA4D055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptFunction.h;
+                       path = NGJavaScript/NGJavaScriptFunction.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA4E055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptFunction.m;
+                       path = NGJavaScript/NGJavaScriptFunction.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA4F055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptLanguage.m;
+                       path = NGJavaScript/NGJavaScriptLanguage.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA50055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptObjCClassInfo.h;
+                       path = NGJavaScript/NGJavaScriptObjCClassInfo.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA51055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptObjCClassInfo.m;
+                       path = NGJavaScript/NGJavaScriptObjCClassInfo.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA52055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptObject.h;
+                       path = NGJavaScript/NGJavaScriptObject.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA53055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptObject.m;
+                       path = NGJavaScript/NGJavaScriptObject.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA54055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptObjectHandler.h;
+                       path = NGJavaScript/NGJavaScriptObjectHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA55055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptObjectHandler.m;
+                       path = NGJavaScript/NGJavaScriptObjectHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA56055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptObjectMappingContext.h;
+                       path = NGJavaScript/NGJavaScriptObjectMappingContext.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA57055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptObjectMappingContext.m;
+                       path = NGJavaScript/NGJavaScriptObjectMappingContext.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA58055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptRuntime.h;
+                       path = NGJavaScript/NGJavaScriptRuntime.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA59055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptRuntime.m;
+                       path = NGJavaScript/NGJavaScriptRuntime.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA5A055DD6A0006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGJavaScriptShadow.h;
+                       path = NGJavaScript/NGJavaScriptShadow.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA5B055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGJavaScriptShadow.m;
+                       path = NGJavaScript/NGJavaScriptShadow.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA5C055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = NGJavaScript/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA5D055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = ScriptLanguages.plist;
+                       path = NGJavaScript/ScriptLanguages.plist;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA65055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = testjs.m;
+                       path = NGJavaScript/testjs.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA66055DD6A1006FE529 = {
+                       children = (
+                               E81EFA67055DD6A1006FE529,
+                               E81EFAFE055DD716006FE529,
+                               E81EFA68055DD6A1006FE529,
+                               E81EFA69055DD6A1006FE529,
+                               E81EFA6A055DD6A1006FE529,
+                               E81EFA6B055DD6A1006FE529,
+                               E81EFA6D055DD6A1006FE529,
+                               E81EFA6E055DD6A1006FE529,
+                               E81EFA6F055DD6A1006FE529,
+                               E81EFA70055DD6A1006FE529,
+                               E81EFA71055DD6A1006FE529,
+                               E81EFA72055DD6A1006FE529,
+                               E81EFA73055DD6A1006FE529,
+                               E81EFA74055DD6A1006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = tests;
+                       path = NGJavaScript/tests;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA67055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA68055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = Blah.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA69055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = Blah.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA6A055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = Combined.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA6B055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = Combined.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA6C055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA6D055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = JSArchivingTests.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA6E055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = JSArchivingTests.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA6F055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = JSBridgeTests.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA70055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = JSBridgeTests.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA71055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = JSTest.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA72055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = JSTest.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA73055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = MyNum.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA74055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = MyNum.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA75055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = TODO;
+                       path = NGJavaScript/TODO;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA76055DD6A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = NGJavaScript/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFA78055DD6A1006FE529 = {
+                       fileRef = E81EF9FA055DD69E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA79055DD6A1006FE529 = {
+                       fileRef = E81EF9FB055DD69E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA7A055DD6A1006FE529 = {
+                       fileRef = E81EF9FD055DD69E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA7B055DD6A1006FE529 = {
+                       fileRef = E81EF9FE055DD69E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA7C055DD6A1006FE529 = {
+                       fileRef = E81EF9FF055DD69E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFA7D055DD6A1006FE529 = {
+                       fileRef = E81EFA00055DD69E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA7E055DD6A1006FE529 = {
+                       fileRef = E81EFA01055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA80055DD6A1006FE529 = {
+                       fileRef = E81EFA03055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA81055DD6A1006FE529 = {
+                       fileRef = E81EFA04055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA82055DD6A1006FE529 = {
+                       fileRef = E81EFA05055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA83055DD6A1006FE529 = {
+                       fileRef = E81EFA06055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA84055DD6A1006FE529 = {
+                       fileRef = E81EFA07055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA85055DD6A1006FE529 = {
+                       fileRef = E81EFA08055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFA86055DD6A1006FE529 = {
+                       fileRef = E81EFA09055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA87055DD6A1006FE529 = {
+                       fileRef = E81EFA0A055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFA88055DD6A1006FE529 = {
+                       fileRef = E81EFA0B055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFA89055DD6A1006FE529 = {
+                       fileRef = E81EFA0C055DD69F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAB9055DD6A2006FE529 = {
+                       fileRef = E81EFA3E055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFABA055DD6A2006FE529 = {
+                       fileRef = E81EFA3F055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFABC055DD6A2006FE529 = {
+                       fileRef = E81EFA41055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFABF055DD6A2006FE529 = {
+                       fileRef = E81EFA44055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFAC0055DD6A2006FE529 = {
+                       fileRef = E81EFA45055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAC1055DD6A2006FE529 = {
+                       fileRef = E81EFA46055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFAC2055DD6A2006FE529 = {
+                       fileRef = E81EFA47055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAC3055DD6A2006FE529 = {
+                       fileRef = E81EFA48055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFAC4055DD6A2006FE529 = {
+                       fileRef = E81EFA49055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAC5055DD6A2006FE529 = {
+                       fileRef = E81EFA4A055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFAC6055DD6A2006FE529 = {
+                       fileRef = E81EFA4B055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFAC7055DD6A2006FE529 = {
+                       fileRef = E81EFA4C055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAC8055DD6A2006FE529 = {
+                       fileRef = E81EFA4D055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFAC9055DD6A2006FE529 = {
+                       fileRef = E81EFA4E055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFACA055DD6A2006FE529 = {
+                       fileRef = E81EFA4F055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFACB055DD6A2006FE529 = {
+                       fileRef = E81EFA50055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFACC055DD6A2006FE529 = {
+                       fileRef = E81EFA51055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFACD055DD6A2006FE529 = {
+                       fileRef = E81EFA52055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFACE055DD6A2006FE529 = {
+                       fileRef = E81EFA53055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFACF055DD6A2006FE529 = {
+                       fileRef = E81EFA54055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFAD0055DD6A2006FE529 = {
+                       fileRef = E81EFA55055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAD1055DD6A2006FE529 = {
+                       fileRef = E81EFA56055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFAD2055DD6A2006FE529 = {
+                       fileRef = E81EFA57055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAD3055DD6A2006FE529 = {
+                       fileRef = E81EFA58055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFAD4055DD6A2006FE529 = {
+                       fileRef = E81EFA59055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAD5055DD6A2006FE529 = {
+                       fileRef = E81EFA5A055DD6A0006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFAD6055DD6A2006FE529 = {
+                       fileRef = E81EFA5B055DD6A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAD7055DD6A2006FE529 = {
+                       fileRef = E81EFA5C055DD6A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAD8055DD6A2006FE529 = {
+                       fileRef = E81EFA5D055DD6A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAED055DD6A2006FE529 = {
+                       fileRef = E81EFA76055DD6A1006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFAF1055DD6C2006FE529 = {
+                       children = (
+                               E81EFA40055DD6A0006FE529,
+                               E81EFA41055DD6A0006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFAF8055DD6EC006FE529 = {
+                       children = (
+                               E81EFA44055DD6A0006FE529,
+                               E81EFA46055DD6A0006FE529,
+                               E81EFA48055DD6A0006FE529,
+                               E81EFA4A055DD6A0006FE529,
+                               E81EFA4B055DD6A0006FE529,
+                               E81EFA4D055DD6A0006FE529,
+                               E81EFA50055DD6A0006FE529,
+                               E81EFA52055DD6A0006FE529,
+                               E81EFA54055DD6A0006FE529,
+                               E81EFA56055DD6A0006FE529,
+                               E81EFA58055DD6A0006FE529,
+                               E81EFA5A055DD6A0006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFAFB055DD6FA006FE529 = {
+                       children = (
+                               E81EF9FA055DD69E006FE529,
+                               E81EFA3D055DD6A0006FE529,
+                               E81EFA3E055DD6A0006FE529,
+                               E81EFA3F055DD6A0006FE529,
+                               E81EFA42055DD6A0006FE529,
+                               E81EFA43055DD6A0006FE529,
+                               E81EFA45055DD6A0006FE529,
+                               E81EFA47055DD6A0006FE529,
+                               E81EFA49055DD6A0006FE529,
+                               E81EFA4C055DD6A0006FE529,
+                               E81EFA4E055DD6A0006FE529,
+                               E81EFA4F055DD6A0006FE529,
+                               E81EFA51055DD6A0006FE529,
+                               E81EFA53055DD6A0006FE529,
+                               E81EFA55055DD6A0006FE529,
+                               E81EFA57055DD6A0006FE529,
+                               E81EFA59055DD6A0006FE529,
+                               E81EFA5B055DD6A1006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFAFE055DD716006FE529 = {
+                       children = (
+                               E81EFA6C055DD6A1006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB5B055DD95E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = _WOStringTable.h;
+                       path = NGObjWeb/_WOStringTable.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB5C055DD95E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = _WOStringTable.m;
+                       path = NGObjWeb/_WOStringTable.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB5D055DD95E006FE529 = {
+                       children = (
+                               E81EFB5E055DD95E006FE529,
+                               E81EFB5F055DD95F006FE529,
+                               ADCDE36506AD746E00BFCE2B,
+                               E81EFB72055DD95F006FE529,
+                               E81EFB73055DD95F006FE529,
+                               E81EFB74055DD95F006FE529,
+                               AD06646C06AD6E2C006525C9,
+                               ADCDE36306AD744A00BFCE2B,
+                               E81EFB75055DD95F006FE529,
+                               E81EFB76055DD95F006FE529,
+                               E81EFB77055DD95F006FE529,
+                               E81EFB78055DD95F006FE529,
+                               E899918F05EE858500874B24,
+                               E899919005EE858500874B24,
+                               AD06642806AD6CCB006525C9,
+                               AD06642906AD6CCB006525C9,
+                       );
+                       isa = PBXGroup;
+                       name = Associations;
+                       path = NGObjWeb/Associations;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB5E055DD95E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB5F055DD95F006FE529 = {
+                       explicitFileType = sourcecode.make;
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       tabWidth = 4;
+               };
+               E81EFB72055DD95F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOAssociation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB73055DD95F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOKeyPathAssociation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB74055DD95F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOKeyPathAssociation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB75055DD95F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOScriptAssociation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB76055DD95F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOScriptAssociation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB77055DD95F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOValueAssociation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB78055DD95F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOValueAssociation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB79055DD960006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = NGObjWeb/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB7A055DD960006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = NGObjWeb/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB7B055DD960006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = NGObjWeb/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB7C055DD960006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = NGObjWeb/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB7D055DD960006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = DAVPropMap.plist;
+                       path = NGObjWeb/DAVPropMap.plist;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB7E055DD960006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = Defaults.plist;
+                       path = NGObjWeb/Defaults.plist;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB7F055DD960006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = dummy.m;
+                       path = NGObjWeb/dummy.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB80055DD960006FE529 = {
+                       children = (
+                               E81EFBE2055DD965006FE529,
+                               E865265705EEA65100C9C768,
+                               E865265805EEA67B00C9C768,
+                               E865265605EEA62D00C9C768,
+                               E865265505EEA5F300C9C768,
+                               E81EFB82055DD960006FE529,
+                               E81EFC41055DD96A006FE529,
+                               E81EFC42055DD96A006FE529,
+                               E81EFC43055DD96A006FE529,
+                               E81EFC44055DD96A006FE529,
+                               E81EFC47055DD96A006FE529,
+                               E81EFC48055DD96B006FE529,
+                               E81EFC49055DD96B006FE529,
+                               E81EFC4A055DD96B006FE529,
+                               E81EFC4B055DD96B006FE529,
+                               E81EFC4C055DD96B006FE529,
+                               E81EFC4E055DD96B006FE529,
+                               E81EFC4F055DD96B006FE529,
+                               E81EFC53055DD96B006FE529,
+                               E81EFC54055DD96B006FE529,
+                               E81EFC55055DD96B006FE529,
+                               E81EFC56055DD96B006FE529,
+                               E81EFC58055DD96B006FE529,
+                               E81EFC59055DD96C006FE529,
+                               E81EFC5A055DD96C006FE529,
+                               AD488335063424E200D38EA7,
+                               E81EFC5E055DD96C006FE529,
+                               AD4883680634287100D38EA7,
+                               E81EFC63055DD96D006FE529,
+                               E81EFC64055DD96D006FE529,
+                               E81EFC65055DD96D006FE529,
+                               E81EFC69055DD96E006FE529,
+                               E81EFC6E055DD96F006FE529,
+                               E81EFC70055DD96F006FE529,
+                               E81EFC72055DD96F006FE529,
+                               E81EFC75055DD96F006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = DynamicElements;
+                       path = NGObjWeb/DynamicElements;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB81055DD960006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB82055DD960006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFB83055DD960006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFBE2055DD965006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC41055DD96A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOActionURL.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC42055DD96A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOActiveImage.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC43055DD96A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOBody.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC44055DD96A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOBrowser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC45055DD96A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOCheckBox.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC46055DD96A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOCheckBoxList.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC47055DD96A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOComponentContent.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC48055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOComponentContent.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC49055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOComponentReference.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC4A055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOComponentReference.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC4B055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOCompoundElement.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC4C055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOCompoundElement.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC4D055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOConditional.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC4E055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOEmbeddedObject.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC4F055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOEntity.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC50055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOFileUpload.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC51055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOForm.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC52055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOForm.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC53055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOFrame.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC54055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOGenericContainer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC55055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOGenericElement.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC56055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOGenericElement.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC57055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOHiddenField.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC58055DD96B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOHtml.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC59055DD96C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOHTMLDynamicElement.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC5A055DD96C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOHTMLDynamicElement.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC5B055DD96C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOHyperlink.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC5C055DD96C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOHyperlinkInfo.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC5D055DD96C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOHyperlinkInfo.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC5E055DD96C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOIFrame.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC5F055DD96D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOImage.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC60055DD96D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOImageButton.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC61055DD96D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOInput.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC62055DD96D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOInput.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC63055DD96D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOJavaScript.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC64055DD96D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOMetaRefresh.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC65055DD96D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WONestedList.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC66055DD96E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOPasswordField.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC68055DD96E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOPopUpButton.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC69055DD96E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOQuickTime.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC6A055DD96E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WORadioButton.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC6B055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WORadioButtonList.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC6C055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WORepetition.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC6D055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOResetButton.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC6E055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOResourceURL.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC6F055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOSetCursor.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC70055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOString.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC71055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOSubmitButton.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC72055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOSwitchComponent.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC73055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOText.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC74055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOTextField.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC75055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOVBScript.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC76055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOxControlElemBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC77055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOxHTMLElemBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC78055DD96F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOxMiscElemBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC79055DD970006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOxXULElemBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC7A055DD970006FE529 = {
+                       explicitFileType = sourcecode.make;
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = GNUmakefile;
+                       path = NGObjWeb/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       tabWidth = 4;
+               };
+               E81EFC7B055DD970006FE529 = {
+                       explicitFileType = sourcecode.make;
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = GNUmakefile.postamble;
+                       path = NGObjWeb/GNUmakefile.postamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       tabWidth = 4;
+               };
+               E81EFC7C055DD970006FE529 = {
+                       explicitFileType = sourcecode.make;
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = GNUmakefile.preamble;
+                       path = NGObjWeb/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       tabWidth = 4;
+               };
+               E81EFC7D055DD970006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = Languages.plist;
+                       path = NGObjWeb/Languages.plist;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC7E055DD970006FE529 = {
+                       children = (
+                               E81EFCAE055DD975006FE529,
+                               E81EFC7F055DD970006FE529,
+                               E81EFC80055DD970006FE529,
+                               E81EFC82055DD971006FE529,
+                               E81CBF580569AD11006AECCE,
+                               E81CBF5B0569AD1E006AECCE,
+                       );
+                       isa = PBXGroup;
+                       name = NGHttp;
+                       path = NGObjWeb/NGHttp;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC7F055DD970006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC80055DD970006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC81055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC82055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC83055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHttp.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC84055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGHttp.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC85055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHttpBodyParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC86055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGHttpBodyParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC87055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHttpCookie.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC88055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGHttpCookie.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC89055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHttpDecls.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC8A055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHttpHeaderFieldParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC8B055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGHttpHeaderFieldParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC8C055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHttpHeaderFields.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC8D055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGHttpHeaderFields.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC8E055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHttpMessage.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC8F055DD971006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGHttpMessage.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC90055DD972006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHttpMessageParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC91055DD972006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGHttpMessageParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC92055DD972006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHttpRequest.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC93055DD972006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGHttpRequest.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC94055DD972006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGHttpResponse.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC95055DD972006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGHttpResponse.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC96055DD972006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGUrlFormCoder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFC97055DD972006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGUrlFormCoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCAE055DD975006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCC5055DD976006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NGHttp+WO.h";
+                       path = "NGObjWeb/NGHttp+WO.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCC6055DD976006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NGHttp+WO.m";
+                       path = "NGObjWeb/NGHttp+WO.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCC7055DD976006FE529 = {
+                       children = (
+                               E81EFCC8055DD976006FE529,
+                               E81EFCC9055DD976006FE529,
+                               E81EFCCA055DD976006FE529,
+                               E81EFCCB055DD977006FE529,
+                               E81EFCCC055DD977006FE529,
+                               E81EFCCD055DD977006FE529,
+                               E81EFCCE055DD977006FE529,
+                               E81EFCCF055DD977006FE529,
+                               E81EFCD0055DD977006FE529,
+                               E81EFCD1055DD977006FE529,
+                               E81EFCD2055DD977006FE529,
+                               E81EFCD3055DD977006FE529,
+                               E81EFCD4055DD977006FE529,
+                               E81EFCD5055DD977006FE529,
+                               E81EFCD6055DD977006FE529,
+                               E81EFCD7055DD977006FE529,
+                               E81EFCD8055DD977006FE529,
+                               E81EFCD9055DD977006FE529,
+                               E81EFCDA055DD977006FE529,
+                               E81EFCDB055DD977006FE529,
+                               E81EFCDC055DD977006FE529,
+                               E81EFCDD055DD978006FE529,
+                               E81EFCDE055DD978006FE529,
+                               E81EFCDF055DD978006FE529,
+                               E81EFCE0055DD978006FE529,
+                               E81EFCE1055DD978006FE529,
+                               E81EFCE2055DD978006FE529,
+                               E81EFCE3055DD978006FE529,
+                               E81EFCE4055DD978006FE529,
+                               E81EFCE5055DD978006FE529,
+                               E81EFCE6055DD978006FE529,
+                               E81EFCE7055DD979006FE529,
+                               E81EFCE8055DD979006FE529,
+                               E81EFCE9055DD979006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       path = NGObjWeb/NGObjWeb;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCC8055DD976006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGObjWeb.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCC9055DD976006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGObjWebDecls.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCCA055DD976006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OWResponder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCCB055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OWViewRequestHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCCC055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WEClientCapabilities.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCCD055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOActionResults.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCCE055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOAdaptor.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCCF055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOApplication.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCD0055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOAssociation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCD1055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOComponent.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCD2055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOComponentScript.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCD3055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOContext.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCD4055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOCookie.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCD5055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOCoreApplication.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCD6055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WODirectAction.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCD7055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WODisplayGroup.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCD8055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WODynamicElement.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCD9055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOElement.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCDA055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOElementTrackingContext.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCDB055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOHTTPConnection.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCDC055DD977006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOMailDelivery.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCDD055DD978006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOMessage.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCDE055DD978006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOPageGenerationContext.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCDF055DD978006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOProxyRequestHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCE0055DD978006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WORequest.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCE1055DD978006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WORequestHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCE2055DD978006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOResourceManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCE3055DD978006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOResponse.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCE4055DD978006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOSession.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCE5055DD978006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOSessionStore.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCE6055DD978006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOStatisticsStore.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCE7055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOTemplate.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCE8055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOTemplateBuilder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCE9055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOxElemBuilder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCEA055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGObjWeb.m;
+                       path = NGObjWeb/NGObjWeb.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCEB055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ngobjweb.make;
+                       path = NGObjWeb/ngobjweb.make;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCEC055DD979006FE529 = {
+                       children = (
+                               E81EFCED055DD979006FE529,
+                               E81EFCEE055DD979006FE529,
+                               E81EFCF4055DD97A006FE529,
+                               E81CBF7F0569B0CE006AECCE,
+                               E81CBF930569B0F6006AECCE,
+                               E81CBF960569B106006AECCE,
+                       );
+                       isa = PBXGroup;
+                       name = NGXmlRpc;
+                       path = NGObjWeb/NGXmlRpc;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCED055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCEE055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCEF055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EOFetchSpecification+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCF0055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EOKeyGlobalID+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCF1055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EONull+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCF2055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EOQualifier+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCF3055DD979006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EOSortOrdering+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCF4055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCF5055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGAsyncResultProxy.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCF6055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGAsyncResultProxy.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCF7055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGXmlRpc.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCF8055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NGXmlRpcAction+Registry.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCF9055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGXmlRpcAction.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCFA055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGXmlRpcAction.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCFB055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGXmlRpcClient.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCFC055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGXmlRpcClient.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCFD055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGXmlRpcInvocation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCFE055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGXmlRpcInvocation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFCFF055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGXmlRpcMethodSignature.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD00055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGXmlRpcMethodSignature.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD01055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = NGXmlRpcRequestHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD02055DD97A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = NGXmlRpcRequestHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD03055DD97B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSObject+Reflection.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD04055DD97B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSObject+Reflection.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD59055DD981006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "WODirectAction+XmlRpc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD5A055DD981006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WODirectAction+XmlRpc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD5B055DD981006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "WODirectAction+XmlRpcIntrospection.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD5C055DD981006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WODirectAction+XmlRpcIntrospection.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD5D055DD981006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WOMessage+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD5E055DD981006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WORequest+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD5F055DD981006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WOResponse+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD60055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "XmlRpcMethodCall+WO.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD61055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "XmlRpcMethodCall+WO.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD62055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "XmlRpcMethodResponse+WO.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD63055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "XmlRpcMethodResponse+WO.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD64055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NSObject+WO.h";
+                       path = "NGObjWeb/NSObject+WO.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD65055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSObject+WO.m";
+                       path = "NGObjWeb/NSObject+WO.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD66055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = OWViewRequestHandler.m;
+                       path = NGObjWeb/OWViewRequestHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD67055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = NGObjWeb/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD68055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = SNSConnection.h;
+                       path = NGObjWeb/SNSConnection.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD69055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = SNSConnection.m;
+                       path = NGObjWeb/SNSConnection.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD6A055DD982006FE529 = {
+                       children = (
+                               E81EFDB2055DD986006FE529,
+                               E81EFD6B055DD982006FE529,
+                               E81EFE2A055DD98D006FE529,
+                               E81EFD6D055DD982006FE529,
+                               E81EFDB1055DD986006FE529,
+                               E81EFD6C055DD982006FE529,
+                               E809D8E5056B07DD0041E20B,
+                               E809D8E8056B07FD0041E20B,
+                       );
+                       isa = PBXGroup;
+                       name = SoObjects;
+                       path = NGObjWeb/SoObjects;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD6B055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD6C055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD6D055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = NOTES;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD6E055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSException+HTTP.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFD6F055DD982006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSException+HTTP.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDB1055DD986006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       path = product.plist;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDB2055DD986006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDF4055DD989006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoApplication.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDF5055DD989006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoApplication.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDF6055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoClass.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDF7055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoClass.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDF8055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoClassRegistry.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDF9055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoClassRegistry.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDFA055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoClassSecurityInfo.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDFB055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoClassSecurityInfo.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDFC055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoComponent.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDFD055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoComponent.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDFE055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoControlPanel.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFDFF055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoControlPanel.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE00055DD98A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoDefaultRenderer.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE01055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoDefaultRenderer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE02055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoHTTPAuthenticator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE03055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoHTTPAuthenticator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE04055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoLookupAssociation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE05055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoLookupAssociation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE06055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoObjCClass.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE07055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoObjCClass.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE08055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "SoObject+Traversal.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE09055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoObject.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE0A055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoObject.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE0B055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoObjectMethodDispatcher.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE0C055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoObjectMethodDispatcher.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE0D055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoObjectRequestHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE0E055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoObjectRequestHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE0F055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoObjects.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE10055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoObjectXmlRpcDispatcher.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE11055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoObjectXmlRpcDispatcher.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE12055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoPageInvocation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE13055DD98B006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoPageInvocation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE14055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoPermissions.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE15055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoPermissions.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE16055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoProduct.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE17055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoProduct.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE18055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoProductClassInfo.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE19055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoProductClassInfo.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE1A055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoProductRegistry.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE1B055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoProductRegistry.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE1C055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoProductResourceManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE1D055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoProductResourceManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE1E055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoSecurityException.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE1F055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoSecurityException.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE20055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoSecurityManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE21055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoSecurityManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE22055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoSelectorInvocation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE23055DD98C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoSelectorInvocation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE24055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoSubContext.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE25055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoSubContext.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE26055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoTemplateRenderer.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE27055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoTemplateRenderer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE28055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoUser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE29055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoUser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE2A055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = TODO;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE2B055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "WOContext+SoObjects.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE2C055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WOContext+SoObjects.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE2D055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WODirectAction+SoObjects.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE2E055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WODirectActionRequestHandler+SoObjects.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE2F055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "WORequest+So.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE30055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WORequest+So.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE31055DD98D006FE529 = {
+                       children = (
+                               E81EFE32055DD98D006FE529,
+                               E81EFE7C055DD992006FE529,
+                               E81EFE7D055DD992006FE529,
+                               E81EFEA3055DD994006FE529,
+                               E81EFE34055DD98D006FE529,
+                               E809D8EB056B08310041E20B,
+                               E809D8EE056B084D0041E20B,
+                       );
+                       isa = PBXGroup;
+                       name = SoOFS;
+                       path = NGObjWeb/SoOFS;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE32055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE33055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE34055DD98D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE59055DD990006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSBaseObject.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE5A055DD990006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSBaseObject.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE5B055DD990006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSChangeLog.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE5C055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSChangeLog.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE5D055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSFactoryContext.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE5E055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSFactoryContext.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE5F055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSFactoryRegistry.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE60055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSFactoryRegistry.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE61055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSFile.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE62055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSFile.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE63055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSFileRenderer.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE64055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSFileRenderer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE65055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "OFSFolder+SoDAV.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE66055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSFolder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE67055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSFolder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE68055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSFolderClassDescription.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE69055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSFolderClassDescription.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE6A055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSFolderDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE6B055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSFolderDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE6C055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSHttpPasswd.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE6D055DD991006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSHttpPasswd.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE6E055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSImage.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE6F055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSImage.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE70055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSPropertyListObject.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE71055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSPropertyListObject.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE72055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSResourceManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE73055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSResourceManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE74055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSWebDocument.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE75055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSWebDocument.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE76055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSWebMethod.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE77055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSWebMethod.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE78055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSWebMethodRenderer.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE79055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSWebMethodRenderer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE7A055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = OFSWebTemplate.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE7B055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = OFSWebTemplate.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE7C055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       path = product.plist;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFE7D055DD992006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEA2055DD994006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoOFS.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEA3055DD994006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = TODO;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEA4055DD994006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = sope.m;
+                       path = NGObjWeb/sope.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEA5055DD994006FE529 = {
+                       children = (
+                               E865265405EEA5DD00C9C768,
+                               E809D8F1056B08700041E20B,
+                               E809D8F4056B088A0041E20B,
+                       );
+                       isa = PBXGroup;
+                       name = Templates;
+                       path = NGObjWeb/Templates;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEA6055DD994006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEA7055DD994006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFED4055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOComponentScript.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFED5055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOComponentScriptPart.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFED6055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WODParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFED7055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WODParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFED8055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOHTMLParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFED9055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOHTMLParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEDA055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOSubcomponentInfo.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEDB055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOTemplate.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEDC055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOTemplateBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEDD055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOWrapperTemplateBuilder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEDE055DD997006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOWrapperTemplateBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEDF055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOxComponentElemBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEE0055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOxElemBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEE1055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOxTemplateBuilder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEE2055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOxTemplateBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEE3055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = TODO;
+                       path = NGObjWeb/TODO;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEE4055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = TROUBLESHOOTING;
+                       path = NGObjWeb/TROUBLESHOOTING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEE5055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = UnixSignalHandler.h;
+                       path = NGObjWeb/UnixSignalHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEE6055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = UnixSignalHandler.m;
+                       path = NGObjWeb/UnixSignalHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEE7055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = NGObjWeb/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEE8055DD998006FE529 = {
+                       children = (
+                               E81EFF08055DD99A006FE529,
+                               E81EFEED055DD998006FE529,
+                               E81EFEE9055DD998006FE529,
+                               E81EFEEA055DD998006FE529,
+                               E809D8F7056B08AF0041E20B,
+                               E809D8FA056B08BD0041E20B,
+                       );
+                       isa = PBXGroup;
+                       name = WebDAV;
+                       path = NGObjWeb/WebDAV;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEE9055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEEA055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = DAVFetchSpec.txt;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEEB055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "EOFetchSpecification+SoDAV.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEEC055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "EOFetchSpecification+SoDAV.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFEED055DD998006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF08055DD99A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF09055DD99A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxDAVHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF0A055DD99A006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxDAVHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF25055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoDAV.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF26055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoDAVLockManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF27055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoDAVLockManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF28055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "SoObject+SoDAV.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF29055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "SoObject+SoDAV.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF2A055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "SoObject+SoDAVQuery.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF2B055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoObjectDataSource.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF2C055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoObjectDataSource.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF2D055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoObjectResultEntry.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF2E055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoObjectResultEntry.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF2F055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoObjectWebDAVDispatcher.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF30055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoObjectWebDAVDispatcher.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF31055DD99C006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoSubscription.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF32055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoSubscription.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF33055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoSubscriptionManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF34055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoSubscriptionManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF35055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoWebDAVRenderer.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF36055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoWebDAVRenderer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF37055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoWebDAVValue.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF38055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoWebDAVValue.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF39055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEClientCapabilities.m;
+                       path = NGObjWeb/WEClientCapabilities.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF3A055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOAdaptor.m;
+                       path = NGObjWeb/WOAdaptor.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF3B055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = "woapp-gs.make";
+                       path = "NGObjWeb/woapp-gs.make";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF3C055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = woapp.make;
+                       path = NGObjWeb/woapp.make;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF3D055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOApplication.m;
+                       path = NGObjWeb/WOApplication.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF3E055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "WOApplication+defaults.m";
+                       path = "NGObjWeb/WOApplication+defaults.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF3F055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "WOApplication+private.h";
+                       path = "NGObjWeb/WOApplication+private.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF40055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOApplicationMain.m;
+                       path = NGObjWeb/WOApplicationMain.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF41055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = "wobundle-gs.make";
+                       path = "NGObjWeb/wobundle-gs.make";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF42055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = wobundle.make;
+                       path = NGObjWeb/wobundle.make;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF43055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WOChildComponentReference.h;
+                       path = NGObjWeb/WOChildComponentReference.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF44055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOChildComponentReference.m;
+                       path = NGObjWeb/WOChildComponentReference.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF45055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOComponent.m;
+                       path = NGObjWeb/WOComponent.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF46055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "WOComponent+JS.m";
+                       path = "NGObjWeb/WOComponent+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF47055DD99D006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "WOComponent+private.h";
+                       path = "NGObjWeb/WOComponent+private.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF48055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "WOComponent+Sync.m";
+                       path = "NGObjWeb/WOComponent+Sync.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF49055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WOComponentDefinition.h;
+                       path = NGObjWeb/WOComponentDefinition.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF4A055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOComponentDefinition.m;
+                       path = NGObjWeb/WOComponentDefinition.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF4B055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WOComponentFault.h;
+                       path = NGObjWeb/WOComponentFault.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF4C055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOComponentFault.m;
+                       path = NGObjWeb/WOComponentFault.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF4D055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WOComponentRequestHandler.h;
+                       path = NGObjWeb/WOComponentRequestHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF4E055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOComponentRequestHandler.m;
+                       path = NGObjWeb/WOComponentRequestHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF4F055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOContext.m;
+                       path = NGObjWeb/WOContext.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF50055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "WOContext+private.h";
+                       path = "NGObjWeb/WOContext+private.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF51055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOCookie.m;
+                       path = NGObjWeb/WOCookie.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF52055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOCoreApplication.m;
+                       path = NGObjWeb/WOCoreApplication.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF53055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "WOCoreApplication+Bundle.m";
+                       path = "NGObjWeb/WOCoreApplication+Bundle.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF54055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = wod.m;
+                       path = NGObjWeb/wod.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF55055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WODirectAction.m;
+                       path = NGObjWeb/WODirectAction.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF56055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WODirectActionRequestHandler.h;
+                       path = NGObjWeb/WODirectActionRequestHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF57055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WODirectActionRequestHandler.m;
+                       path = NGObjWeb/WODirectActionRequestHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF58055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WODisplayGroup.m;
+                       path = NGObjWeb/WODisplayGroup.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF59055DD99E006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WODynamicElement.m;
+                       path = NGObjWeb/WODynamicElement.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF5A055DD99F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOElement.m;
+                       path = NGObjWeb/WOElement.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF5B055DD99F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "WOElement+private.h";
+                       path = "NGObjWeb/WOElement+private.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF5C055DD99F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WOElementID.h;
+                       path = NGObjWeb/WOElementID.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF5D055DD99F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOElementID.m;
+                       path = NGObjWeb/WOElementID.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF5E055DD99F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOFileSessionStore.m;
+                       path = NGObjWeb/WOFileSessionStore.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF5F055DD99F006FE529 = {
+                       children = (
+                               E81EFF60055DD99F006FE529,
+                               E81EFF61055DD99F006FE529,
+                               E809D8FD056B08D80041E20B,
+                               E809D900056B08E80041E20B,
+                       );
+                       isa = PBXGroup;
+                       name = WOHttpAdaptor;
+                       path = NGObjWeb/WOHttpAdaptor;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF60055DD99F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF61055DD99F006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF7A055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOHttpAdaptor.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF7B055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOHttpAdaptor.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF7C055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOHttpTransaction.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF7D055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOHttpTransaction.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF7E055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WORecordRequestStream.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF7F055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WORecordRequestStream.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF80055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "WORequest+Adaptor.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF81055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "WORequest+Adaptor.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF82055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WORequestParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF83055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WORequestParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF84055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOHTTPConnection.m;
+                       path = NGObjWeb/WOHTTPConnection.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF85055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOHTTPURLHandle.m;
+                       path = NGObjWeb/WOHTTPURLHandle.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF86055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOMailDelivery.m;
+                       path = NGObjWeb/WOMailDelivery.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF87055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOMessage.m;
+                       path = NGObjWeb/WOMessage.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF88055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "WOMessage+XML.m";
+                       path = "NGObjWeb/WOMessage+XML.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF89055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOPageRequestHandler.m;
+                       path = NGObjWeb/WOPageRequestHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF8A055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOProxyRequestHandler.m;
+                       path = NGObjWeb/WOProxyRequestHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF8B055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WORequest.m;
+                       path = NGObjWeb/WORequest.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF8C055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WORequestHandler.m;
+                       path = NGObjWeb/WORequestHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF8D055DD9A1006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "WORequestHandler+private.h";
+                       path = "NGObjWeb/WORequestHandler+private.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF8E055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOResourceManager.m;
+                       path = NGObjWeb/WOResourceManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF8F055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOResourceRequestHandler.m;
+                       path = NGObjWeb/WOResourceRequestHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF90055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOResponse.m;
+                       path = NGObjWeb/WOResponse.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF91055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "WOResponse+private.h";
+                       path = "NGObjWeb/WOResponse+private.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF92055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WORunLoop.h;
+                       path = NGObjWeb/WORunLoop.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF93055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WORunLoop.m;
+                       path = NGObjWeb/WORunLoop.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF94055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WOScriptedComponent.h;
+                       path = NGObjWeb/WOScriptedComponent.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF95055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOScriptedComponent.m;
+                       path = NGObjWeb/WOScriptedComponent.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF96055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOServerSessionStore.m;
+                       path = NGObjWeb/WOServerSessionStore.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF97055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOSession.m;
+                       path = NGObjWeb/WOSession.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF98055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "WOSession+JS.m";
+                       path = "NGObjWeb/WOSession+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF99055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOSessionStore.m;
+                       path = NGObjWeb/WOSessionStore.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF9A055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WOSimpleHTTPParser.h;
+                       path = NGObjWeb/WOSimpleHTTPParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF9B055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOSimpleHTTPParser.m;
+                       path = NGObjWeb/WOSimpleHTTPParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF9C055DD9A2006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOStatisticsStore.m;
+                       path = NGObjWeb/WOStatisticsStore.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF9D055DD9A3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOStats.m;
+                       path = NGObjWeb/WOStats.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF9E055DD9A3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOWatchDogApplicationMain.m;
+                       path = NGObjWeb/WOWatchDogApplicationMain.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFF9F055DD9A3006FE529 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = xmlrpc_call.m;
+                       path = NGObjWeb/xmlrpc_call.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E81EFFA0055DD9A5006FE529 = {
+                       fileRef = E81EFB5B055DD95E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFA1055DD9A5006FE529 = {
+                       fileRef = E81EFB5C055DD95E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFB4055DD9A5006FE529 = {
+                       fileRef = E81EFB72055DD95F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFB5055DD9A5006FE529 = {
+                       fileRef = E81EFB73055DD95F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFFB6055DD9A5006FE529 = {
+                       fileRef = E81EFB74055DD95F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFB7055DD9A5006FE529 = {
+                       fileRef = E81EFB75055DD95F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFFB8055DD9A5006FE529 = {
+                       fileRef = E81EFB76055DD95F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFB9055DD9A5006FE529 = {
+                       fileRef = E81EFB77055DD95F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E81EFFBA055DD9A5006FE529 = {
+                       fileRef = E81EFB78055DD95F006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFBB055DD9A5006FE529 = {
+                       fileRef = E81EFB79055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFBC055DD9A5006FE529 = {
+                       fileRef = E81EFB7A055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFBD055DD9A5006FE529 = {
+                       fileRef = E81EFB7B055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFBE055DD9A5006FE529 = {
+                       fileRef = E81EFB7C055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFC0055DD9A5006FE529 = {
+                       fileRef = E81EFB7E055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFC1055DD9A5006FE529 = {
+                       fileRef = E81EFB7F055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E81EFFC3055DD9A5006FE529 = {
+                       fileRef = E81EFB82055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E839D7D3056966FC00C2567C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E839D7D4056966FC00C2567C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E839D7ED0569673400C2567C,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E839D7D5056966FC00C2567C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8AC8BDD05ABBFE0008C206D,
+                               E8AC8BDE05ABBFE1008C206D,
+                               E8AC8BDF05ABBFE5008C206D,
+                               E8AC8BE005ABBFFD008C206D,
+                               AD1627C105D93C3300A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E839D7D6056966FC00C2567C = {
+                       buildPhases = (
+                               E839D7D3056966FC00C2567C,
+                               E839D7D4056966FC00C2567C,
+                               E839D7D5056966FC00C2567C,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "-DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1 -DNeXT_Foundation_LIBRARY=1";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = sope;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = sope;
+                       productName = sope;
+                       productReference = E839D7D7056966FC00C2567C;
+                       productType = "com.apple.product-type.tool";
+               };
+               E839D7D7056966FC00C2567C = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = sope;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E839D7DB0569670800C2567C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E839D7DC0569670800C2567C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E839D7EE0569673800C2567C,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E839D7DD0569670800C2567C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8AC8BE105ABC00E008C206D,
+                               E8AC8BE205ABC013008C206D,
+                               E83FAF1005B6FAD5003836D9,
+                               AD1627C205D93C3300A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E839D7DE0569670800C2567C = {
+                       buildPhases = (
+                               E839D7DB0569670800C2567C,
+                               E839D7DC0569670800C2567C,
+                               E839D7DD0569670800C2567C,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = wod;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = wod;
+                       productName = wod;
+                       productReference = E839D7DF0569670800C2567C;
+                       productType = "com.apple.product-type.tool";
+               };
+               E839D7DF0569670800C2567C = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = wod;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E839D7E50569671D00C2567C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E839D7E60569671D00C2567C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E839D7EF0569673A00C2567C,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E839D7E70569671D00C2567C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXRezBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E839D7E80569671D00C2567C = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8AC8BE305ABC01B008C206D,
+                               E8AC8BE405ABC01C008C206D,
+                               E8AC8BE505ABC054008C206D,
+                               E8AC8BE605ABC056008C206D,
+                               E83FAF1D05B6FB24003836D9,
+                               AD1627C305D93C3300A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E839D7E90569671D00C2567C = {
+                       buildPhases = (
+                               E839D7E50569671D00C2567C,
+                               E839D7E60569671D00C2567C,
+                               E839D7E70569671D00C2567C,
+                               E839D7E80569671D00C2567C,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "-DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1 -DNeXT_Foundation_LIBRARY=1";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = xmlrpc_call;
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = xmlrpc_call;
+                       productName = xmlrpc_call;
+                       productReference = E839D7EA0569671D00C2567C;
+                       productType = "com.apple.product-type.tool";
+               };
+               E839D7EA0569671D00C2567C = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = xmlrpc_call;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E839D7ED0569673400C2567C = {
+                       fileRef = E81EFEA4055DD994006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E839D7EE0569673800C2567C = {
+                       fileRef = E81EFF54055DD99E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E839D7EF0569673A00C2567C = {
+                       fileRef = E81EFF9F055DD9A3006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E83FAEE205B6F991003836D9 = {
+                       fileRef = E81EF99F055DD578006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E83FAEFB05B6FA1B003836D9 = {
+                       fileRef = E81EF99F055DD578006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E83FAF0805B6FAB0003836D9 = {
+                       fileRef = E81EF99F055DD578006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E83FAF1005B6FAD5003836D9 = {
+                       fileRef = E81EF99F055DD578006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E83FAF1D05B6FB24003836D9 = {
+                       fileRef = E81EF99F055DD578006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAA1056AEE3F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = "bundle-info.plist";
+                       path = "WEExtensions/bundle-info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAA2056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.javascript;
+                       name = calendar.js;
+                       path = WEExtensions/calendar.js;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAA3056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = calendar.jsm;
+                       path = WEExtensions/calendar.jsm;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAA4056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = calendar.m;
+                       path = WEExtensions/calendar.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAA5056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = WEExtensions/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAA6056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = WEExtensions/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAA7056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = WEExtensions/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAA8056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = WEExtensions/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAA9056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = dummy.m;
+                       path = WEExtensions/dummy.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAAA056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = WEExtensions/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAAB056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = WEExtensions/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAAC056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.script.sh;
+                       name = js2m.sh;
+                       path = WEExtensions/js2m.sh;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAAD056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSClipboard.m;
+                       path = WEExtensions/JSClipboard.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAAE056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = JSMenu.h;
+                       path = WEExtensions/JSMenu.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAAF056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSMenu.m;
+                       path = WEExtensions/JSMenu.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAB0056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = JSMenuItem.h;
+                       path = WEExtensions/JSMenuItem.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAB1056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSMenuItem.m;
+                       path = WEExtensions/JSMenuItem.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAB2056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSShiftClick.m;
+                       path = WEExtensions/JSShiftClick.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAB3056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = WEExtensions/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAB4056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEBrowser.m;
+                       path = WEExtensions/WEBrowser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAB5056AEE4000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WECalendarField.h;
+                       path = WEExtensions/WECalendarField.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAB6056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WECalendarField.m;
+                       path = WEExtensions/WECalendarField.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAB7056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WEClientCapabilities.h;
+                       path = WEExtensions/WEClientCapabilities.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAB8056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WECollapsibleComponentContent.m;
+                       path = WEExtensions/WECollapsibleComponentContent.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAB9056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEComponentValue.m;
+                       path = WEExtensions/WEComponentValue.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAABA056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WEContextConditional.h;
+                       path = WEExtensions/WEContextConditional.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAABB056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEContextConditional.m;
+                       path = WEExtensions/WEContextConditional.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAABC056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEContextKey.m;
+                       path = WEExtensions/WEContextKey.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAABD056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEDateField.m;
+                       path = WEExtensions/WEDateField.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAABE056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEDragContainer.m;
+                       path = WEExtensions/WEDragContainer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAABF056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEDropContainer.m;
+                       path = WEExtensions/WEDropContainer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAC0056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WEDropScript.h;
+                       path = WEExtensions/WEDropScript.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAC1056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.javascript;
+                       name = WEDropScript.js;
+                       path = WEExtensions/WEDropScript.js;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAC2056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = WEDropScript.jsm;
+                       path = WEExtensions/WEDropScript.jsm;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAC3056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEEpozEditor.m;
+                       path = WEExtensions/WEEpozEditor.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAC4056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEExtensionsBundle.m;
+                       path = WEExtensions/WEExtensionsBundle.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAC5056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEMonthOverview.m;
+                       path = WEExtensions/WEMonthOverview.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAC6056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEPageView.m;
+                       path = WEExtensions/WEPageView.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAC7056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WERichString.m;
+                       path = WEExtensions/WERichString.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAC8056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WESwitch.m;
+                       path = WEExtensions/WESwitch.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAC9056AEE4100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETabItem.m;
+                       path = WEExtensions/WETabItem.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAACA056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WETableCalcMatrix.h;
+                       path = WEExtensions/WETableCalcMatrix.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAACB056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETableCalcMatrix.m;
+                       path = WEExtensions/WETableCalcMatrix.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAD0056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETableMatrix.m;
+                       path = WEExtensions/WETableMatrix.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAD1056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETableMatrixContent.m;
+                       path = WEExtensions/WETableMatrixContent.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAD2056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETableMatrixLabel.m;
+                       path = WEExtensions/WETableMatrixLabel.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAD7056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WETabView.h;
+                       path = WEExtensions/WETabView.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAD8056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETabView.m;
+                       path = WEExtensions/WETabView.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAD9056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETimeField.m;
+                       path = WEExtensions/WETimeField.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAADA056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETreeView.m;
+                       path = WEExtensions/WETreeView.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAADB056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEWeekColumnView.m;
+                       path = WEExtensions/WEWeekColumnView.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAADC056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WEWeekOverview.m;
+                       path = WEExtensions/WEWeekOverview.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAADD056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WExCalElemBuilder.m;
+                       path = WEExtensions/WExCalElemBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAADE056AEE4200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WExDnDElemBuilder.m;
+                       path = WEExtensions/WExDnDElemBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAADF056AEE4300355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WExExtElemBuilder.m;
+                       path = WEExtensions/WExExtElemBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAAE0056AEE4300355953 = {
+                       fileRef = E84DAAA1056AEE3F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAE1056AEE4300355953 = {
+                       fileRef = E84DAAA2056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAE2056AEE4300355953 = {
+                       fileRef = E84DAAA3056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAE3056AEE4300355953 = {
+                       fileRef = E84DAAA4056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAE4056AEE4300355953 = {
+                       fileRef = E84DAAA5056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAE5056AEE4300355953 = {
+                       fileRef = E84DAAA6056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAE6056AEE4300355953 = {
+                       fileRef = E84DAAA7056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAE7056AEE4300355953 = {
+                       fileRef = E84DAAA8056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAE8056AEE4300355953 = {
+                       fileRef = E84DAAA9056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAE9056AEE4300355953 = {
+                       fileRef = E84DAAAA056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAEA056AEE4300355953 = {
+                       fileRef = E84DAAAB056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAEB056AEE4300355953 = {
+                       fileRef = E84DAAAC056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAEC056AEE4300355953 = {
+                       fileRef = E84DAAAD056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAED056AEE4300355953 = {
+                       fileRef = E84DAAAE056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAEE056AEE4300355953 = {
+                       fileRef = E84DAAAF056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAEF056AEE4300355953 = {
+                       fileRef = E84DAAB0056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAF0056AEE4300355953 = {
+                       fileRef = E84DAAB1056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAF1056AEE4300355953 = {
+                       fileRef = E84DAAB2056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAF2056AEE4300355953 = {
+                       fileRef = E84DAAB3056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAF3056AEE4300355953 = {
+                       fileRef = E84DAAB4056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAF4056AEE4300355953 = {
+                       fileRef = E84DAAB5056AEE4000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAF5056AEE4300355953 = {
+                       fileRef = E84DAAB6056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAF6056AEE4300355953 = {
+                       fileRef = E84DAAB7056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAF7056AEE4300355953 = {
+                       fileRef = E84DAAB8056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAF8056AEE4300355953 = {
+                       fileRef = E84DAAB9056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAF9056AEE4300355953 = {
+                       fileRef = E84DAABA056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAFA056AEE4300355953 = {
+                       fileRef = E84DAABB056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAFB056AEE4300355953 = {
+                       fileRef = E84DAABC056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAFC056AEE4300355953 = {
+                       fileRef = E84DAABD056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAFD056AEE4300355953 = {
+                       fileRef = E84DAABE056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAFE056AEE4300355953 = {
+                       fileRef = E84DAABF056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAAFF056AEE4300355953 = {
+                       fileRef = E84DAAC0056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB00056AEE4300355953 = {
+                       fileRef = E84DAAC1056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB01056AEE4300355953 = {
+                       fileRef = E84DAAC2056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB02056AEE4300355953 = {
+                       fileRef = E84DAAC3056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB03056AEE4300355953 = {
+                       fileRef = E84DAAC4056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB04056AEE4300355953 = {
+                       fileRef = E84DAAC5056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB05056AEE4300355953 = {
+                       fileRef = E84DAAC6056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB06056AEE4300355953 = {
+                       fileRef = E84DAAC7056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB07056AEE4300355953 = {
+                       fileRef = E84DAAC8056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB08056AEE4300355953 = {
+                       fileRef = E84DAAC9056AEE4100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB09056AEE4300355953 = {
+                       fileRef = E84DAACA056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB0A056AEE4300355953 = {
+                       fileRef = E84DAACB056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB0F056AEE4300355953 = {
+                       fileRef = E84DAAD0056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB10056AEE4300355953 = {
+                       fileRef = E84DAAD1056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB11056AEE4300355953 = {
+                       fileRef = E84DAAD2056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB16056AEE4300355953 = {
+                       fileRef = E84DAAD7056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB17056AEE4300355953 = {
+                       fileRef = E84DAAD8056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB18056AEE4300355953 = {
+                       fileRef = E84DAAD9056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB19056AEE4300355953 = {
+                       fileRef = E84DAADA056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB1A056AEE4300355953 = {
+                       fileRef = E84DAADB056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB1B056AEE4300355953 = {
+                       fileRef = E84DAADC056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB1C056AEE4300355953 = {
+                       fileRef = E84DAADD056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB1D056AEE4300355953 = {
+                       fileRef = E84DAADE056AEE4200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB1E056AEE4300355953 = {
+                       fileRef = E84DAADF056AEE4300355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB3D056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = "bundle-info.plist";
+                       path = "WOExtensions/bundle-info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB3E056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = WOExtensions/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB3F056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = WOExtensions/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB40056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = compat.m;
+                       path = WOExtensions/compat.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB41056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = WOExtensions/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB42056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = WOExtensions/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB43056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = dummy.m;
+                       path = WOExtensions/dummy.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB44056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = WOExtensions/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB45056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = WOExtensions/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB46056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSAlertPanel.m;
+                       path = WOExtensions/JSAlertPanel.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB47056AEF0800355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSConfirmPanel.m;
+                       path = WOExtensions/JSConfirmPanel.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB48056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSImageFlyover.m;
+                       path = WOExtensions/JSImageFlyover.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB49056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSKeyHandler.m;
+                       path = WOExtensions/JSKeyHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB4A056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSModalWindow.m;
+                       path = WOExtensions/JSModalWindow.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB4B056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSTextFlyover.m;
+                       path = WOExtensions/JSTextFlyover.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB4C056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = JSValidatedField.m;
+                       path = WOExtensions/JSValidatedField.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB4D056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = WOExtensions/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB4E056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOCheckBoxMatrix.m;
+                       path = WOExtensions/WOCheckBoxMatrix.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB4F056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOCollapsibleComponentContent.m;
+                       path = WOExtensions/WOCollapsibleComponentContent.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB50056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WODictionaryRepetition.m;
+                       path = WOExtensions/WODictionaryRepetition.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB51056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOKeyValueConditional.m;
+                       path = WOExtensions/WOKeyValueConditional.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB52056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WORadioButtonMatrix.m;
+                       path = WOExtensions/WORadioButtonMatrix.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB53056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WORedirect.m;
+                       path = WOExtensions/WORedirect.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB54056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOTable.m;
+                       path = WOExtensions/WOTable.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB55056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOTabPanel.m;
+                       path = WOExtensions/WOTabPanel.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB56056AEF0900355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOThresholdColoredNumber.m;
+                       path = WOExtensions/WOThresholdColoredNumber.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB57056AEF0A00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WOxExtElemBuilder.m;
+                       path = WOExtensions/WOxExtElemBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB58056AEF0A00355953 = {
+                       fileRef = E84DAB3D056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB59056AEF0A00355953 = {
+                       fileRef = E84DAB3E056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB5A056AEF0A00355953 = {
+                       fileRef = E84DAB3F056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB5B056AEF0A00355953 = {
+                       fileRef = E84DAB40056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB5C056AEF0A00355953 = {
+                       fileRef = E84DAB41056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB5D056AEF0A00355953 = {
+                       fileRef = E84DAB42056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB5E056AEF0A00355953 = {
+                       fileRef = E84DAB43056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB5F056AEF0A00355953 = {
+                       fileRef = E84DAB44056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB60056AEF0A00355953 = {
+                       fileRef = E84DAB45056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB61056AEF0A00355953 = {
+                       fileRef = E84DAB46056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB62056AEF0A00355953 = {
+                       fileRef = E84DAB47056AEF0800355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB63056AEF0A00355953 = {
+                       fileRef = E84DAB48056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB64056AEF0A00355953 = {
+                       fileRef = E84DAB49056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB65056AEF0A00355953 = {
+                       fileRef = E84DAB4A056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB66056AEF0A00355953 = {
+                       fileRef = E84DAB4B056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB67056AEF0A00355953 = {
+                       fileRef = E84DAB4C056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB68056AEF0A00355953 = {
+                       fileRef = E84DAB4D056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB69056AEF0A00355953 = {
+                       fileRef = E84DAB4E056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB6A056AEF0A00355953 = {
+                       fileRef = E84DAB4F056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB6B056AEF0A00355953 = {
+                       fileRef = E84DAB50056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB6C056AEF0A00355953 = {
+                       fileRef = E84DAB51056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB6D056AEF0A00355953 = {
+                       fileRef = E84DAB52056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB6E056AEF0A00355953 = {
+                       fileRef = E84DAB53056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB6F056AEF0A00355953 = {
+                       fileRef = E84DAB54056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB70056AEF0A00355953 = {
+                       fileRef = E84DAB55056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB71056AEF0A00355953 = {
+                       fileRef = E84DAB56056AEF0900355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB72056AEF0A00355953 = {
+                       fileRef = E84DAB57056AEF0A00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAB75056AF13C00355953 = {
+                       children = (
+                               E84DAB3F056AEF0800355953,
+                               E84DAB40056AEF0800355953,
+                               E84DAB46056AEF0800355953,
+                               E84DAB47056AEF0800355953,
+                               E84DAB48056AEF0900355953,
+                               E84DAB49056AEF0900355953,
+                               E84DAB4A056AEF0900355953,
+                               E84DAB4B056AEF0900355953,
+                               E84DAB4C056AEF0900355953,
+                               E84DAB4E056AEF0900355953,
+                               E84DAB4F056AEF0900355953,
+                               E84DAB50056AEF0900355953,
+                               E84DAB51056AEF0900355953,
+                               E84DAB52056AEF0900355953,
+                               E84DAB53056AEF0900355953,
+                               E84DAB54056AEF0900355953,
+                               E84DAB55056AEF0900355953,
+                               E84DAB56056AEF0900355953,
+                               E84DAB57056AEF0A00355953,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB78056AF15500355953 = {
+                       children = (
+                               E84DAB44056AEF0800355953,
+                               E84DAB45056AEF0800355953,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB7B056AF19C00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = "bundle-info.plist";
+                       path = "NGObjDOM/bundle-info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB7C056AF19C00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = NGObjDOM/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB7D056AF19C00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = NGObjDOM/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB7E056AF19C00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = NGObjDOM/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB7F056AF19C00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = NGObjDOM/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB80056AF19C00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = dummy.m;
+                       path = NGObjDOM/dummy.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB81056AF19C00355953 = {
+                       children = (
+                               E84DAB82056AF19D00355953,
+                               E84DAB83056AF19D00355953,
+                               E84DAB84056AF19D00355953,
+                               E84DAB85056AF19D00355953,
+                               E84DAB86056AF19D00355953,
+                               E84DAB87056AF19D00355953,
+                               E84DAB88056AF19D00355953,
+                               E84DAB89056AF19D00355953,
+                               E84DAB8A056AF19D00355953,
+                               E84DAB8B056AF19D00355953,
+                               E84DAB8C056AF19D00355953,
+                               E84DAB8D056AF19D00355953,
+                               E84DAB8E056AF19D00355953,
+                               E84DAB8F056AF19D00355953,
+                               E84DAB90056AF19D00355953,
+                               E84DAB91056AF19D00355953,
+                               E84DAB92056AF19E00355953,
+                               E84DAB93056AF19E00355953,
+                               E84DAB94056AF19E00355953,
+                               E84DAB95056AF19E00355953,
+                               E84DAB96056AF19E00355953,
+                               E84DAB97056AF19E00355953,
+                               E84DAB98056AF19E00355953,
+                               E84DAB99056AF19E00355953,
+                               E84DAB9A056AF19E00355953,
+                               E84DAB9B056AF19E00355953,
+                               E84DAB9C056AF19E00355953,
+                               E84DAB9D056AF19E00355953,
+                               E84DAB9E056AF19E00355953,
+                               E84DAB9F056AF19E00355953,
+                               E84DABA0056AF19E00355953,
+                               E84DABA1056AF19F00355953,
+                               E84DABA2056AF19F00355953,
+                       );
+                       isa = PBXGroup;
+                       name = Dynamic.subproj;
+                       path = NGObjDOM/Dynamic.subproj;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB82056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB83056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB84056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB85056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB86056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = ODBindNodeRenderFactory.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB87056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODBindNodeRenderFactory.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB88056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_checkbox.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB89056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_collapsible.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB8A056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_datefield.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB8B056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_fieldset.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB8C056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_foreach.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB8D056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_form.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB8E056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = ODR_bind_groupings.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB8F056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_groupings.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB90056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_if.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB91056AF19D00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_multiselection.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB92056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_nbsp.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB93056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_popupbutton.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB94056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_radiobutton.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB95056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = ODR_bind_sortorderings.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB96056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_sortorderings.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB97056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_string.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB98056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_switch.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB99056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = ODR_bind_tablecell.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB9A056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_tablecell.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB9B056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_tabledata.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB9C056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_tableheader.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB9D056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "ODR_bind_tableview+Private.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB9E056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "ODR_bind_tableview+Private.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAB9F056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_tableview.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABA0056AF19E00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_tabview.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABA1056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_viewertitle.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABA2056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_bind_with.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABA5056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = NGObjDOM/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABA6056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = NGObjDOM/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABA7056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = NGObjDOM.h;
+                       path = NGObjDOM/NGObjDOM.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABA8056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = NGObjDOMModule.m;
+                       path = NGObjDOM/NGObjDOMModule.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABA9056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODNamespaces.h;
+                       path = NGObjDOM/ODNamespaces.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABAA056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODNodeRenderer.h;
+                       path = NGObjDOM/ODNodeRenderer.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABAB056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ODNodeRenderer.m;
+                       path = NGObjDOM/ODNodeRenderer.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABAC056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "ODNodeRenderer+attributes.h";
+                       path = "NGObjDOM/ODNodeRenderer+attributes.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABAD056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "ODNodeRenderer+attributes.m";
+                       path = "NGObjDOM/ODNodeRenderer+attributes.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABAE056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODNodeRendererFactory.h;
+                       path = NGObjDOM/ODNodeRendererFactory.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABAF056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ODNodeRendererFactory.m;
+                       path = NGObjDOM/ODNodeRendererFactory.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABB0056AF19F00355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODNodeRendererFactorySet.h;
+                       path = NGObjDOM/ODNodeRendererFactorySet.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABB1056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ODNodeRendererFactorySet.m;
+                       path = NGObjDOM/ODNodeRendererFactorySet.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABB2056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODR_bind_collapsible.h;
+                       path = NGObjDOM/ODR_bind_collapsible.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABB3056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODR_bind_fieldset.h;
+                       path = NGObjDOM/ODR_bind_fieldset.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABB4056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODR_bind_tableview.h;
+                       path = NGObjDOM/ODR_bind_tableview.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABB5056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODR_bind_tabview.h;
+                       path = NGObjDOM/ODR_bind_tabview.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABB6056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODR_bind_viewertitle.h;
+                       path = NGObjDOM/ODR_bind_viewertitle.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABB7056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODREmbedComponent.h;
+                       path = NGObjDOM/ODREmbedComponent.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABB8056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ODREmbedComponent.m;
+                       path = NGObjDOM/ODREmbedComponent.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABB9056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODResourceManager.h;
+                       path = NGObjDOM/ODResourceManager.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABBA056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ODResourceManager.m;
+                       path = NGObjDOM/ODResourceManager.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABBB056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODRGenericTag.h;
+                       path = NGObjDOM/ODRGenericTag.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABBC056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ODRGenericTag.m;
+                       path = NGObjDOM/ODRGenericTag.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABBD056AF1A000355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODRNodeText.h;
+                       path = NGObjDOM/ODRNodeText.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABBE056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ODRNodeText.m;
+                       path = NGObjDOM/ODRNodeText.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABBF056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ODRWebObject.h;
+                       path = NGObjDOM/ODRWebObject.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABC0056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ODRWebObject.m;
+                       path = NGObjDOM/ODRWebObject.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABC1056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = ODWONodeRenderFactory.m;
+                       path = NGObjDOM/ODWONodeRenderFactory.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABC2056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = NGObjDOM/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABC3056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = used_privates.h;
+                       path = NGObjDOM/used_privates.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABC4056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = NGObjDOM/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABC5056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "WOContext+Cursor.h";
+                       path = "NGObjDOM/WOContext+Cursor.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABC6056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WORenderDOM.h;
+                       path = NGObjDOM/WORenderDOM.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABC7056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WORenderDOM.m;
+                       path = NGObjDOM/WORenderDOM.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABC8056AF1A100355953 = {
+                       children = (
+                               E84DABC9056AF1A100355953,
+                               E84DABCA056AF1A100355953,
+                               E84DABCB056AF1A100355953,
+                               E84DABCC056AF1A100355953,
+                               E84DABCD056AF1A100355953,
+                               E84DABCE056AF1A200355953,
+                               E84DABCF056AF1A200355953,
+                               E84DABD0056AF1A200355953,
+                               E84DABD1056AF1A200355953,
+                               E84DABD2056AF1A200355953,
+                               E84DABD3056AF1A200355953,
+                               E84DABD4056AF1A200355953,
+                               E84DABD5056AF1A200355953,
+                               E84DABD6056AF1A200355953,
+                               E84DABD7056AF1A200355953,
+                               E84DABD8056AF1A200355953,
+                               E84DABD9056AF1A200355953,
+                               E84DABDA056AF1A200355953,
+                       );
+                       isa = PBXGroup;
+                       name = XHTML.subproj;
+                       path = NGObjDOM/XHTML.subproj;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABC9056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABCA056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       path = "bundle-info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABCB056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABCC056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABCD056AF1A100355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABCE056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABCF056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XHTML_a.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABD0056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XHTML_button.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABD1056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XHTML_form.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABD2056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XHTML_img.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABD3056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XHTML_input.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABD4056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XHTML_option.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABD5056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XHTML_select.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABD6056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XHTML_textarea.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABD7056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = ODRDynamicXHTMLTag.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABD8056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODRDynamicXHTMLTag.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABD9056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = ODXHTMLNodeRenderFactory.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABDA056AF1A200355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODXHTMLNodeRenderFactory.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABE9056AF1A400355953 = {
+                       children = (
+                               E84DABEA056AF1A400355953,
+                               E84DABEB056AF1A400355953,
+                               E84DABEC056AF1A400355953,
+                               E84DABED056AF1A400355953,
+                               E84DABEE056AF1A400355953,
+                               E84DABEF056AF1A400355953,
+                               E84DABF0056AF1A400355953,
+                               E84DABF1056AF1A400355953,
+                               E84DABF2056AF1A400355953,
+                               E84DABF3056AF1A400355953,
+                               E84DABF4056AF1A400355953,
+                               E84DABF5056AF1A400355953,
+                               E84DABF6056AF1A400355953,
+                               E84DABF7056AF1A400355953,
+                               E84DABF8056AF1A400355953,
+                               E84DABF9056AF1A400355953,
+                               E84DABFA056AF1A500355953,
+                               E84DABFB056AF1A500355953,
+                               E84DABFC056AF1A500355953,
+                               E84DABFD056AF1A500355953,
+                               E84DABFE056AF1A500355953,
+                               E84DABFF056AF1A500355953,
+                               E84DAC00056AF1A500355953,
+                       );
+                       isa = PBXGroup;
+                       name = XUL.subproj;
+                       path = NGObjDOM/XUL.subproj;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABEA056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABEB056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       path = "bundle-info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABEC056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABED056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABEE056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABEF056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = ODR_XUL_box.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABF0056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_box.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABF1056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_button.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABF2056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_column.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABF3056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_columns.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABF4056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_grid.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABF5056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_image.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABF6056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_spring.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABF7056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_tab.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABF8056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_text.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABF9056AF1A400355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_textfield.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABFA056AF1A500355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_title.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABFB056AF1A500355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_titledbox.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABFC056AF1A500355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODR_XUL_window.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABFD056AF1A500355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = ODRDynamicXULTag.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABFE056AF1A500355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODRDynamicXULTag.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DABFF056AF1A500355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = ODXULNodeRenderFactory.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAC00056AF1A500355953 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = ODXULNodeRenderFactory.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DAC0F056AF1A800355953 = {
+                       fileRef = E84DAB7B056AF19C00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC10056AF1A800355953 = {
+                       fileRef = E84DAB7C056AF19C00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC11056AF1A800355953 = {
+                       fileRef = E84DAB7D056AF19C00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC12056AF1A800355953 = {
+                       fileRef = E84DAB7E056AF19C00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC13056AF1A800355953 = {
+                       fileRef = E84DAB7F056AF19C00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC14056AF1A800355953 = {
+                       fileRef = E84DAB80056AF19C00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC15056AF1A800355953 = {
+                       fileRef = E84DAB82056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC16056AF1A800355953 = {
+                       fileRef = E84DAB83056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC17056AF1A800355953 = {
+                       fileRef = E84DAB84056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC18056AF1A800355953 = {
+                       fileRef = E84DAB85056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC19056AF1A800355953 = {
+                       fileRef = E84DAB86056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC1A056AF1A800355953 = {
+                       fileRef = E84DAB87056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC1B056AF1A800355953 = {
+                       fileRef = E84DAB88056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC1C056AF1A800355953 = {
+                       fileRef = E84DAB89056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC1D056AF1A800355953 = {
+                       fileRef = E84DAB8A056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC1E056AF1A800355953 = {
+                       fileRef = E84DAB8B056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC1F056AF1A800355953 = {
+                       fileRef = E84DAB8C056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC20056AF1A800355953 = {
+                       fileRef = E84DAB8D056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC21056AF1A800355953 = {
+                       fileRef = E84DAB8E056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC23056AF1A800355953 = {
+                       fileRef = E84DAB90056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC24056AF1A800355953 = {
+                       fileRef = E84DAB91056AF19D00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC25056AF1A800355953 = {
+                       fileRef = E84DAB92056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC26056AF1A800355953 = {
+                       fileRef = E84DAB93056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC27056AF1A800355953 = {
+                       fileRef = E84DAB94056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC28056AF1A800355953 = {
+                       fileRef = E84DAB95056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC29056AF1A800355953 = {
+                       fileRef = E84DAB96056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC2A056AF1A800355953 = {
+                       fileRef = E84DAB97056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC2B056AF1A800355953 = {
+                       fileRef = E84DAB98056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC2C056AF1A800355953 = {
+                       fileRef = E84DAB99056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC2D056AF1A800355953 = {
+                       fileRef = E84DAB9A056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC2E056AF1A800355953 = {
+                       fileRef = E84DAB9B056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC2F056AF1A800355953 = {
+                       fileRef = E84DAB9C056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC30056AF1A800355953 = {
+                       fileRef = E84DAB9D056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC31056AF1A800355953 = {
+                       fileRef = E84DAB9E056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC32056AF1A800355953 = {
+                       fileRef = E84DAB9F056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC33056AF1A800355953 = {
+                       fileRef = E84DABA0056AF19E00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC34056AF1A800355953 = {
+                       fileRef = E84DABA1056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC35056AF1A800355953 = {
+                       fileRef = E84DABA2056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC36056AF1A800355953 = {
+                       fileRef = E84DABA5056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC37056AF1A800355953 = {
+                       fileRef = E84DABA6056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC38056AF1A800355953 = {
+                       fileRef = E84DABA7056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC39056AF1A800355953 = {
+                       fileRef = E84DABA8056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC3A056AF1A800355953 = {
+                       fileRef = E84DABA9056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC3B056AF1A800355953 = {
+                       fileRef = E84DABAA056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC3C056AF1A800355953 = {
+                       fileRef = E84DABAB056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC3D056AF1A800355953 = {
+                       fileRef = E84DABAC056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC3E056AF1A800355953 = {
+                       fileRef = E84DABAD056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC3F056AF1A800355953 = {
+                       fileRef = E84DABAE056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC40056AF1A800355953 = {
+                       fileRef = E84DABAF056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC41056AF1A800355953 = {
+                       fileRef = E84DABB0056AF19F00355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC42056AF1A800355953 = {
+                       fileRef = E84DABB1056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC43056AF1A800355953 = {
+                       fileRef = E84DABB2056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC44056AF1A800355953 = {
+                       fileRef = E84DABB3056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC45056AF1A800355953 = {
+                       fileRef = E84DABB4056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC46056AF1A800355953 = {
+                       fileRef = E84DABB5056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC47056AF1A800355953 = {
+                       fileRef = E84DABB6056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC48056AF1A800355953 = {
+                       fileRef = E84DABB7056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC49056AF1A800355953 = {
+                       fileRef = E84DABB8056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC4A056AF1A800355953 = {
+                       fileRef = E84DABB9056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC4B056AF1A800355953 = {
+                       fileRef = E84DABBA056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC4C056AF1A800355953 = {
+                       fileRef = E84DABBB056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC4D056AF1A800355953 = {
+                       fileRef = E84DABBC056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC4E056AF1A800355953 = {
+                       fileRef = E84DABBD056AF1A000355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC4F056AF1A800355953 = {
+                       fileRef = E84DABBE056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC50056AF1A800355953 = {
+                       fileRef = E84DABBF056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC51056AF1A800355953 = {
+                       fileRef = E84DABC0056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC52056AF1A800355953 = {
+                       fileRef = E84DABC1056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC53056AF1A800355953 = {
+                       fileRef = E84DABC2056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC54056AF1A800355953 = {
+                       fileRef = E84DABC3056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC55056AF1A800355953 = {
+                       fileRef = E84DABC4056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC56056AF1A800355953 = {
+                       fileRef = E84DABC5056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC57056AF1A800355953 = {
+                       fileRef = E84DABC6056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC58056AF1A800355953 = {
+                       fileRef = E84DABC7056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC59056AF1A800355953 = {
+                       fileRef = E84DABC9056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC5A056AF1A800355953 = {
+                       fileRef = E84DABCA056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC5B056AF1A800355953 = {
+                       fileRef = E84DABCB056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC5C056AF1A800355953 = {
+                       fileRef = E84DABCC056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC5D056AF1A800355953 = {
+                       fileRef = E84DABCD056AF1A100355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC5E056AF1A800355953 = {
+                       fileRef = E84DABCE056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC5F056AF1A800355953 = {
+                       fileRef = E84DABCF056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC60056AF1A800355953 = {
+                       fileRef = E84DABD0056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC61056AF1A800355953 = {
+                       fileRef = E84DABD1056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC62056AF1A800355953 = {
+                       fileRef = E84DABD2056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC63056AF1A800355953 = {
+                       fileRef = E84DABD3056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC64056AF1A800355953 = {
+                       fileRef = E84DABD4056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC65056AF1A800355953 = {
+                       fileRef = E84DABD5056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC66056AF1A800355953 = {
+                       fileRef = E84DABD6056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC67056AF1A800355953 = {
+                       fileRef = E84DABD7056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC68056AF1A800355953 = {
+                       fileRef = E84DABD8056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC69056AF1A800355953 = {
+                       fileRef = E84DABD9056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC6A056AF1A800355953 = {
+                       fileRef = E84DABDA056AF1A200355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC72056AF1A800355953 = {
+                       fileRef = E84DABEA056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC73056AF1A800355953 = {
+                       fileRef = E84DABEB056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC74056AF1A800355953 = {
+                       fileRef = E84DABEC056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC75056AF1A800355953 = {
+                       fileRef = E84DABED056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC76056AF1A800355953 = {
+                       fileRef = E84DABEE056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC77056AF1A800355953 = {
+                       fileRef = E84DABEF056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC78056AF1A800355953 = {
+                       fileRef = E84DABF0056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC79056AF1A800355953 = {
+                       fileRef = E84DABF1056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC7A056AF1A800355953 = {
+                       fileRef = E84DABF2056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC7B056AF1A800355953 = {
+                       fileRef = E84DABF3056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC7C056AF1A800355953 = {
+                       fileRef = E84DABF4056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC7D056AF1A800355953 = {
+                       fileRef = E84DABF5056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC7E056AF1A800355953 = {
+                       fileRef = E84DABF6056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC7F056AF1A800355953 = {
+                       fileRef = E84DABF7056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC80056AF1A800355953 = {
+                       fileRef = E84DABF8056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC81056AF1A800355953 = {
+                       fileRef = E84DABF9056AF1A400355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC82056AF1A800355953 = {
+                       fileRef = E84DABFA056AF1A500355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC83056AF1A800355953 = {
+                       fileRef = E84DABFB056AF1A500355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC84056AF1A800355953 = {
+                       fileRef = E84DABFC056AF1A500355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC85056AF1A800355953 = {
+                       fileRef = E84DABFD056AF1A500355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC86056AF1A800355953 = {
+                       fileRef = E84DABFE056AF1A500355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC87056AF1A800355953 = {
+                       fileRef = E84DABFF056AF1A500355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DAC88056AF1A800355953 = {
+                       fileRef = E84DAC00056AF1A500355953;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E84DACA2056AF22F00355953 = {
+                       children = (
+                               E84DABA7056AF19F00355953,
+                               E84DABA9056AF19F00355953,
+                               E84DABAC056AF19F00355953,
+                               E84DABAE056AF19F00355953,
+                               E84DABB0056AF19F00355953,
+                               E84DABB2056AF1A000355953,
+                               E84DABB3056AF1A000355953,
+                               E84DABB4056AF1A000355953,
+                               E84DABB5056AF1A000355953,
+                               E84DABB6056AF1A000355953,
+                               E84DABB7056AF1A000355953,
+                               E84DABB9056AF1A000355953,
+                               E84DABBB056AF1A000355953,
+                               E84DABBD056AF1A000355953,
+                               E84DABBF056AF1A100355953,
+                               E84DABC5056AF1A100355953,
+                               E84DABC6056AF1A100355953,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E84DACA5056AF25A00355953 = {
+                       children = (
+                               E84DAB7D056AF19C00355953,
+                               E84DABC3056AF1A100355953,
+                               E84DAB80056AF19C00355953,
+                               E84DABA8056AF19F00355953,
+                               E84DABAA056AF19F00355953,
+                               E84DABAB056AF19F00355953,
+                               E84DABAD056AF19F00355953,
+                               E84DABAF056AF19F00355953,
+                               E84DABB1056AF1A000355953,
+                               E84DABB8056AF1A000355953,
+                               E84DABBA056AF1A000355953,
+                               E84DABBC056AF1A000355953,
+                               E84DABBE056AF1A100355953,
+                               E84DABC0056AF1A100355953,
+                               E84DABC1056AF1A100355953,
+                               E84DABC7056AF1A100355953,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E857FDB205FC9C090026154C = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SoDAVSQLParser.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E857FDB305FC9C090026154C = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SoDAVSQLParser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E857FDB405FC9C090026154C = {
+                       fileRef = E857FDB205FC9C090026154C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E857FDB505FC9C090026154C = {
+                       fileRef = E857FDB305FC9C090026154C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E865265405EEA5DD00C9C768 = {
+                       children = (
+                               E81EFEA6055DD994006FE529,
+                               E81EFEA7055DD994006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E865265505EEA5F300C9C768 = {
+                       children = (
+                               E81EFC76055DD96F006FE529,
+                               E81EFC77055DD96F006FE529,
+                               E81EFC78055DD96F006FE529,
+                               E81EFC79055DD970006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "Element Builders";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E865265605EEA62D00C9C768 = {
+                       children = (
+                               E81EFC45055DD96A006FE529,
+                               E81EFC46055DD96A006FE529,
+                               E81EFC50055DD96B006FE529,
+                               E81EFC51055DD96B006FE529,
+                               E81EFC52055DD96B006FE529,
+                               E81EFC57055DD96B006FE529,
+                               E81EFC60055DD96D006FE529,
+                               E81EFC61055DD96D006FE529,
+                               E81EFC62055DD96D006FE529,
+                               E81EFC66055DD96E006FE529,
+                               E81EFC68055DD96E006FE529,
+                               E81EFC6A055DD96E006FE529,
+                               E81EFC6B055DD96F006FE529,
+                               E81EFC6D055DD96F006FE529,
+                               E81EFC71055DD96F006FE529,
+                               E81EFC73055DD96F006FE529,
+                               E81EFC74055DD96F006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "Form Elements";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E865265705EEA65100C9C768 = {
+                       children = (
+                               E81EFB81055DD960006FE529,
+                               E81EFB83055DD960006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E865265805EEA67B00C9C768 = {
+                       children = (
+                               E81EFC4D055DD96B006FE529,
+                               E81EFC6C055DD96F006FE529,
+                               E81EFC6F055DD96F006FE529,
+                       );
+                       isa = PBXGroup;
+                       name = "Control Elements";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E896325105697A7C00E7D217 = {
+                       children = (
+                               AD1627B505D93C3300A7368D,
+                               AD853BEC06A7FA4000727CA0,
+                               AD853D8306A7FA5A00727CA0,
+                               AD151C9A06ABDD52002375D2,
+                       );
+                       isa = PBXGroup;
+                       name = "Linked Frameworks";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E896325405697AB200E7D217 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = DOM.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E896325505697AB200E7D217 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = EOControl.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E896325605697AB200E7D217 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = NGExtensions.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E896325705697AB200E7D217 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = NGMime.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E896325805697AB200E7D217 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = NGStreams.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E896325905697AB200E7D217 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = SaxObjC.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E896325A05697AB200E7D217 = {
+                       fileRef = E896325405697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E896325B05697AB200E7D217 = {
+                       fileRef = E896325505697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E896325C05697AB200E7D217 = {
+                       fileRef = E896325605697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E896325D05697AB200E7D217 = {
+                       fileRef = E896325705697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E896325E05697AB200E7D217 = {
+                       fileRef = E896325805697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E896325F05697AB200E7D217 = {
+                       fileRef = E896325905697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E899918F05EE858500874B24 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WOResourceURLAssociation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E899919005EE858500874B24 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WOResourceURLAssociation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E899919105EE858500874B24 = {
+                       fileRef = E899918F05EE858500874B24;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E899919205EE858500874B24 = {
+                       fileRef = E899919005EE858500874B24;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B6205ABAC86008C206D = {
+                       fileRef = E896325505697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B6305ABAC88008C206D = {
+                       fileRef = E896325605697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B6405ABAC92008C206D = {
+                       fileRef = E81EF9B0055DD58B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B6505ABAD1A008C206D = {
+                       children = (
+                               E84DAAAE056AEE4000355953,
+                               E84DAAB0056AEE4000355953,
+                               E84DAAB5056AEE4000355953,
+                               E84DAAB7056AEE4100355953,
+                               E84DAABA056AEE4100355953,
+                               E84DAAC0056AEE4100355953,
+                               E84DAACA056AEE4200355953,
+                               E84DAAD7056AEE4200355953,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B6605ABAD45008C206D = {
+                       children = (
+                               E84DAAAA056AEE4000355953,
+                               E84DAAAB056AEE4000355953,
+                               ADB593CE061DFDF20094D980,
+                               E84DAAAC056AEE4000355953,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B6705ABAD5A008C206D = {
+                       children = (
+                               E84DAAA2056AEE4000355953,
+                               E84DAAA3056AEE4000355953,
+                               E84DAAA4056AEE4000355953,
+                               E84DAAA6056AEE4000355953,
+                               E84DAAA9056AEE4000355953,
+                               E84DAAAD056AEE4000355953,
+                               E84DAAAF056AEE4000355953,
+                               E84DAAB1056AEE4000355953,
+                               E84DAAB2056AEE4000355953,
+                               E84DAAB4056AEE4000355953,
+                               E84DAAB6056AEE4100355953,
+                               E84DAAB8056AEE4100355953,
+                               E84DAAB9056AEE4100355953,
+                               E84DAABB056AEE4100355953,
+                               E84DAABC056AEE4100355953,
+                               E84DAABD056AEE4100355953,
+                               AD48834F0634261C00D38EA7,
+                               AD18022A0611D79400ED723F,
+                               ADCEA32C061AF02F00361086,
+                               E8AC8B6905ABAD87008C206D,
+                               E84DAAC3056AEE4100355953,
+                               E84DAAC4056AEE4100355953,
+                               E84DAAC5056AEE4100355953,
+                               E84DAAC6056AEE4100355953,
+                               E84DAAC7056AEE4100355953,
+                               E84DAAC8056AEE4100355953,
+                               E84DAAC9056AEE4100355953,
+                               E84DAACB056AEE4200355953,
+                               E8AC8B6805ABAD70008C206D,
+                               E84DAAD8056AEE4200355953,
+                               E84DAAD9056AEE4200355953,
+                               E8AC8B7505ABAE02008C206D,
+                               E84DAADB056AEE4200355953,
+                               E84DAADC056AEE4200355953,
+                               E8AC8B6A05ABAD95008C206D,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B6805ABAD70008C206D = {
+                       children = (
+                               E84DAAD0056AEE4200355953,
+                               E84DAAD1056AEE4200355953,
+                               E84DAAD2056AEE4200355953,
+                       );
+                       isa = PBXGroup;
+                       name = TableMatrix;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B6905ABAD87008C206D = {
+                       children = (
+                               E84DAABE056AEE4100355953,
+                               E84DAABF056AEE4100355953,
+                               E84DAAC1056AEE4100355953,
+                               E84DAAC2056AEE4100355953,
+                       );
+                       isa = PBXGroup;
+                       name = DnD;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B6A05ABAD95008C206D = {
+                       children = (
+                               E84DAADD056AEE4200355953,
+                               E84DAADE056AEE4200355953,
+                               E84DAADF056AEE4300355953,
+                       );
+                       isa = PBXGroup;
+                       name = "Element Builders";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B6B05ABADF0008C206D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WETreeContextKeys.h;
+                       path = WEExtensions/WETreeContextKeys.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B6C05ABADF0008C206D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETreeData.m;
+                       path = WEExtensions/WETreeData.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B6D05ABADF0008C206D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETreeHeader.m;
+                       path = WEExtensions/WETreeHeader.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B6E05ABADF0008C206D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = WETreeMatrixElement.h;
+                       path = WEExtensions/WETreeMatrixElement.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B6F05ABADF0008C206D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = WETreeMatrixElement.m;
+                       path = WEExtensions/WETreeMatrixElement.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B7005ABADF1008C206D = {
+                       fileRef = E8AC8B6B05ABADF0008C206D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B7105ABADF1008C206D = {
+                       fileRef = E8AC8B6C05ABADF0008C206D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B7205ABADF1008C206D = {
+                       fileRef = E8AC8B6D05ABADF0008C206D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B7305ABADF1008C206D = {
+                       fileRef = E8AC8B6E05ABADF0008C206D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B7405ABADF1008C206D = {
+                       fileRef = E8AC8B6F05ABADF0008C206D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B7505ABAE02008C206D = {
+                       children = (
+                               E84DAADA056AEE4200355953,
+                               E8AC8B6B05ABADF0008C206D,
+                               E8AC8B6C05ABADF0008C206D,
+                               E8AC8B6D05ABADF0008C206D,
+                               E8AC8B6E05ABADF0008C206D,
+                               E8AC8B6F05ABADF0008C206D,
+                       );
+                       isa = PBXGroup;
+                       name = TreeView;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8AC8B7605ABB6F0008C206D = {
+                       fileRef = E81EF9B0055DD58B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B7705ABB6FA008C206D = {
+                       fileRef = E81EF9BA055DD599006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B7805ABB7A5008C206D = {
+                       fileRef = E81EF9A8055DD582006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8B7905ABB7A7008C206D = {
+                       fileRef = E81EF9B0055DD58B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BAD05ABB93F008C206D = {
+                       fileRef = E896325605697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BAF05ABB959008C206D = {
+                       fileRef = E896325405697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BB005ABB963008C206D = {
+                       fileRef = E896325505697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BB305ABBEC4008C206D = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E839D7D6056966FC00C2567C;
+                       remoteInfo = sope;
+               };
+               E8AC8BB405ABBEC4008C206D = {
+                       isa = PBXTargetDependency;
+                       target = E839D7D6056966FC00C2567C;
+                       targetProxy = E8AC8BB305ABBEC4008C206D;
+               };
+               E8AC8BB505ABBEC4008C206D = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E839D7DE0569670800C2567C;
+                       remoteInfo = wod;
+               };
+               E8AC8BB605ABBEC4008C206D = {
+                       isa = PBXTargetDependency;
+                       target = E839D7DE0569670800C2567C;
+                       targetProxy = E8AC8BB505ABBEC4008C206D;
+               };
+               E8AC8BB705ABBEC4008C206D = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E839D7E90569671D00C2567C;
+                       remoteInfo = xmlrpc_call;
+               };
+               E8AC8BB805ABBEC4008C206D = {
+                       isa = PBXTargetDependency;
+                       target = E839D7E90569671D00C2567C;
+                       targetProxy = E8AC8BB705ABBEC4008C206D;
+               };
+               E8AC8BBB05ABBF07008C206D = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8AC8BC605ABBF71008C206D,
+                               E8AC8BC705ABBF74008C206D,
+                               E8AC8BC805ABBF76008C206D,
+                               E8AC8BC905ABBF77008C206D,
+                               E8AC8BCA05ABBF79008C206D,
+                               E8AC8BCB05ABBF7D008C206D,
+                               E8AC8BCC05ABBF7F008C206D,
+                               E8AC8BCD05ABBF81008C206D,
+                               E8AC8BCE05ABBF84008C206D,
+                               E8AC8BCF05ABBF87008C206D,
+                               E8AC8BD005ABBF88008C206D,
+                               E8AC8BD105ABBF8A008C206D,
+                               E8AC8BD205ABBF8E008C206D,
+                               E8AC8BD305ABBF8F008C206D,
+                               E8AC8BD405ABBF92008C206D,
+                               E8AC8BD505ABBF94008C206D,
+                               E8AC8BD605ABBF96008C206D,
+                               E8AC8BD705ABBF99008C206D,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8AC8BBC05ABBF07008C206D = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8AC8BD805ABBF9B008C206D,
+                               E8AC8BD905ABBF9B008C206D,
+                               E8AC8BDA05ABBF9D008C206D,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8AC8BBD05ABBF07008C206D = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8AC8BDB05ABBFAD008C206D,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8AC8BBE05ABBF07008C206D = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627BC05D93C3300A7368D,
+                               AD85412406A821A900727CA0,
+                               AD85412506A821A900727CA0,
+                               AD85418806A8282C00727CA0,
+                               AD85417C06A8220400727CA0,
+                               AD85417D06A8220400727CA0,
+                               AD8541E906A828C000727CA0,
+                               AD8541E806A828C000727CA0,
+                               AD8541EF06A829F600727CA0,
+                               E8AC8BC505ABBF6A008C206D,
+                               AD8541ED06A829D400727CA0,
+                               AD8541EE06A829D400727CA0,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8AC8BBF05ABBF07008C206D = {
+                       buildPhases = (
+                               E8AC8BBB05ABBF07008C206D,
+                               E8AC8BBC05ABBF07008C206D,
+                               E8AC8BBD05ABBF07008C206D,
+                               E8AC8BBE05ABBF07008C206D,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "NGObjWeb/SoOFS/SoOFS-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "-DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DCOCOA_Foundation_LIBRARY=1 -DNeXT_Foundation_LIBRARY=1";
+                               OTHER_LDFLAGS = "-seg1addr 0xC3A00000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = SoOFS;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = SoOFS;
+                       productName = SoOFS;
+                       productReference = E8AC8BC005ABBF07008C206D;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SoOFS</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.SoOFS</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E8AC8BC005ABBF07008C206D = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = SoOFS.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8AC8BC205ABBF53008C206D = {
+                       containerPortal = E81EF989055DD52B006FE529;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8AC8BBF05ABBF07008C206D;
+                       remoteInfo = SoOFS;
+               };
+               E8AC8BC305ABBF53008C206D = {
+                       isa = PBXTargetDependency;
+                       target = E8AC8BBF05ABBF07008C206D;
+                       targetProxy = E8AC8BC205ABBF53008C206D;
+               };
+               E8AC8BC505ABBF6A008C206D = {
+                       fileRef = E81EF9B0055DD58B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BC605ABBF71008C206D = {
+                       fileRef = E81EFE59055DD990006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BC705ABBF74008C206D = {
+                       fileRef = E81EFE5B055DD990006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BC805ABBF76008C206D = {
+                       fileRef = E81EFE5D055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BC905ABBF77008C206D = {
+                       fileRef = E81EFE5F055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BCA05ABBF79008C206D = {
+                       fileRef = E81EFE61055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BCB05ABBF7D008C206D = {
+                       fileRef = E81EFE63055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BCC05ABBF7F008C206D = {
+                       fileRef = E81EFE66055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BCD05ABBF81008C206D = {
+                       fileRef = E81EFE68055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BCE05ABBF84008C206D = {
+                       fileRef = E81EFE6A055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BCF05ABBF87008C206D = {
+                       fileRef = E81EFE6C055DD991006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BD005ABBF88008C206D = {
+                       fileRef = E81EFE6E055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BD105ABBF8A008C206D = {
+                       fileRef = E81EFE70055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BD205ABBF8E008C206D = {
+                       fileRef = E81EFE72055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BD305ABBF8F008C206D = {
+                       fileRef = E81EFE74055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BD405ABBF92008C206D = {
+                       fileRef = E81EFE76055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BD505ABBF94008C206D = {
+                       fileRef = E81EFE78055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BD605ABBF96008C206D = {
+                       fileRef = E81EFE7A055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BD705ABBF99008C206D = {
+                       fileRef = E81EFEA2055DD994006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8AC8BD805ABBF9B008C206D = {
+                       fileRef = E81EFE7D055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BD905ABBF9B008C206D = {
+                       fileRef = E81EFE7C055DD992006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BDA05ABBF9D008C206D = {
+                       fileRef = E81EFEA3055DD994006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BDB05ABBFAD008C206D = {
+                       fileRef = E81EFB7F055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BDD05ABBFE0008C206D = {
+                       fileRef = E81EF9B0055DD58B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BDE05ABBFE1008C206D = {
+                       fileRef = E8AC8BC005ABBF07008C206D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BDF05ABBFE5008C206D = {
+                       fileRef = E81EF99F055DD578006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BE005ABBFFD008C206D = {
+                       fileRef = E896325805697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BE105ABC00E008C206D = {
+                       fileRef = E896325805697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BE205ABC013008C206D = {
+                       fileRef = E81EF9B0055DD58B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BE305ABC01B008C206D = {
+                       fileRef = E81EF9B0055DD58B006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BE405ABC01C008C206D = {
+                       fileRef = E81CBF7C0569B09C006AECCE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BE505ABC054008C206D = {
+                       fileRef = E896325505697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8AC8BE605ABC056008C206D = {
+                       fileRef = E896325805697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8C2162A056B050300073655 = {
+                       fileRef = E81EF99F055DD578006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8C21635056B061A00073655 = {
+                       fileRef = E81EF9F9055DD69E006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8C21663056B066500073655 = {
+                       fileRef = E896325505697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8C21664056B067500073655 = {
+                       fileRef = E896325605697AB200E7D217;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FDB121056C3E3C002DFB9D = {
+                       fileRef = E81EFB7F055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FDB122056C3E42002DFB9D = {
+                       fileRef = E81EFB7F055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FDB123056C3E48002DFB9D = {
+                       fileRef = E81EFB7F055DD960006FE529;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FDB166056C40FB002DFB9D = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = XmlRpc.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8FDB167056C40FB002DFB9D = {
+                       fileRef = E8FDB166056C40FB002DFB9D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+       };
+       rootObject = E81EF989055DD52B006FE529;
+}
diff --git a/skyrix-sope/SxComponents/.cvsignore b/skyrix-sope/SxComponents/.cvsignore
new file mode 100644 (file)
index 0000000..49a10b1
--- /dev/null
@@ -0,0 +1,2 @@
+shared_debug_obj
+shared_obj
diff --git a/skyrix-sope/SxComponents/COPYING b/skyrix-sope/SxComponents/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/SxComponents/ChangeLog b/skyrix-sope/SxComponents/ChangeLog
new file mode 100644 (file)
index 0000000..5c5c6cd
--- /dev/null
@@ -0,0 +1,253 @@
+2004-06-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile.preamble: added prebinding (v4.2.27)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.26)
+
+2004-05-04  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile.preamble (ADDITIONAL_TOOL_LIBS): added missing 
+         dependencies on Panther (v4.2.25)
+
+2004-03-10  Donald Duck  <helge.hess@opengroupware.org>
+
+       * SxXmlRpcRegBackend.m: fixed a minor compilation warning when 
+         compiling with gstep-base (v4.2.24)
+
+2004-02-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SxXmlRpcRegBackend.m: use NGXmlRpcClient -initWithURL: method instead
+         of using the now deprecated -initWithHost:.. API (v4.2.23)
+
+Tue Dec  9 20:28:35 2003  Nicola Pero  <n.pero@mi.flashnet.it>
+
+       * v4.2.22
+
+       * GNUmakefile (autodoc): Moved autodoc rule in the postamble.
+
+       * SxComponentInvocation.m: Removed usage of NSString
+         -stringWithoutPrefix:.
+
+2003-10-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.21
+       
+       * SxComponent.m: fixed MacOSX compilation warning
+
+       * GNUmakefile.preamble (libSxComponents_LIBRARIES_DEPEND_UPON): added
+         all the explicit dependencies required for MacOSX
+         
+       * common.h: made independend of FoundationExt
+
+2003-09-06  Helge Hess  <helge.hess@skyrix.com>
+
+        * SxXmlRpcRegBackend.m: fixed some MacOSX warnings (v4.2.20)
+
+2003-07-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * applied rangeOfString patches provided by Filip Van Raemdonck for 
+         improved compilation with gstep-base (v4.2.19)
+       
+       * applied GNUstep patches provided by Filip Van Raemdonck for improved
+         compilation with gstep-base (v4.2.18)
+
+2003-02-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxComponentInvocation.m, SxXmlRpcInvocation.m: replaced some RETAIN
+         macros (v4.2.17)
+
+2002-12-02  Helge Hess  <helge.hess@skyrix.com>
+       
+       * moved to skyrix-sope-42 (v4.2.16)
+       
+Thu Oct 10 12:34:16 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * SxXmlRpcComponent.m: added defaults for retry count and time
+         between retries (v4.2.15)
+
+Tue Oct  8 18:10:37 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * SxXmlRpcComponent.m: added retry on NGCouldNotConnectException
+       * SxComponentRegistry.m: added method to remove component
+         from lookup cache
+         (v4.2.14)
+
+2002-08-31  Helge Hess  <helge.hess@skyrix.com>
+
+       * added a default for SxComponentRegistryURL, some smaller
+          changes for MacOSX (v4.2.13)
+
+2002-08-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcInvocation.m: fixed a small MacOSX compilation issue 
+         (v4.2.12)
+
+Thu Aug 15 13:25:12 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * SxXmlRpcComponent.m: don't add component namespace
+         to system methods (libSxComponents.4.2.11)
+
+Tue Aug 13 15:51:48 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * added namespace support to components (component name and
+         namespace are now separated from each other)
+
+Thu Aug  8 13:32:50 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcInvocation.m: be less strict regarding HTTP response content
+         types because some servers return text/plain as the result type ...
+
+2002-07-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcInvocation.m: fixed a retain bug introduced during the
+         async support changes
+
+2002-07-05  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcInvocation.m: major restruction to support async call
+
+2002-07-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * sxc_call.m: added login and password defaults, so that the prompt
+         can be avoided (of course it's not recommended to write passwords
+         into the defaults database
+
+2002-07-02  Helge Hess  <helge.hess@skyrix.com>
+       
+       * sxc_call.m: added coercion for most types
+       
+Tue Jul  2 17:35:14 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * SxXmlRpcRegBackend.m: cleaned up registryd API
+
+Tue Jul  2 11:05:16 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * sxc_call.m: fixed error description output when an
+         exception occurs
+
+Thu May 23 18:23:32 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * SxComponentInvocation.m: added KVC
+
+Fri May 17 11:10:11 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcComponent.m: improved logging of errors ..
+
+Fri May 10 16:51:30 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * sxc_call.m: sort results of listMethods
+
+       * sxc_ls.m: cleanup
+
+Wed May  8 13:57:38 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * sxc_call.m: fixed trailing newline
+
+Sun May  5 14:30:49 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed linking against NGXmlRpc (which is moved to libNGObjWeb)
+
+Thu May  2 11:10:32 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * sxc_call.m: fixed some formatting bug
+
+       * sxc_call.m: do not log full executable path in usage
+
+Mon Apr 29 16:02:45 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcComponent.m: catch incorrect results returned by XML-RPC
+         server's system.methodSignature
+
+Mon Apr 29 13:31:37 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcRegBackend.m: created component using new initializer
+         (construct and pass a NSURL)
+
+       * SxXmlRpcComponent.m: changed initializer, init with an NSURL,
+         removed 'uri' ivar (this is the -path of the URL ?), fixed a memory
+         bug ('url' ivar wasn't deallocated)
+
+Mon Apr 29 12:35:50 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * sxc_call.m, sxc_ls.m: use -argumentsWithoutDefaults from NGExtensions
+
+Fri Apr 26 20:31:11 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcInvocation.m: added debugging capabilities
+
+       * SxXmlRpcComponent.m: improved -description
+
+       * SxComponent.m: started support for subcomponents/component
+         collections
+
+Fri Apr 19 18:02:14 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * sxc_call.m: new output formatting for dictionaries
+         and arrays added
+
+Sun Apr 14 16:55:00 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added authorization support in several places
+
+Fri Apr 12 23:18:40 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcInvocation.m: fixed error handling ...
+
+Fri Apr 12 11:15:34 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxComponentRegistry.m: added listMethods cache
+
+Thu Apr 11 16:28:43 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcRegBackend.m: improved fail-over
+
+       * SxComponent.m: implemented introspection methods using
+         registry
+
+Fri Mar  1 13:42:44 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxComponentInvocation.m: added call indirection to allow
+         subclasses to call a component themselves
+
+Wed Feb 27 19:06:01 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxComponentInvocation.m: fixed bug in exception handling
+
+Wed Feb 27 13:01:57 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcComponent.m: fixed -signaturesForMethodNamed: (recursive
+         call)
+
+Wed Feb 27 12:28:11 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcComponent.m: added method to create an invocation using
+         name and arguments
+
+       * SxComponentInvocation.m: added -setArguments:,-arguments, use
+         call: instead of _call:
+
+Wed Feb 27 11:32:14 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxComponent.m: removed _call:...
+
+Mon Feb 25 19:02:20 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcComponent.m: added _call method (calling XML-RPC methods
+         without namespace ..)
+
+Tue Feb 19 18:08:20 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SxXmlRpcComponent.m: improved error handling for failed connects
+
+Thu Feb 14 12:17:58 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * started credentials system
+
+Wed Jan 30 16:49:35 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * created ChangeLog
+
diff --git a/skyrix-sope/SxComponents/GNUmakefile b/skyrix-sope/SxComponents/GNUmakefile
new file mode 100644 (file)
index 0000000..73d1947
--- /dev/null
@@ -0,0 +1,42 @@
+# $Id$
+
+include ../common.make
+
+LIBRARY_NAME = libSxComponents
+TOOL_NAME = sxc_ls sxc_call
+
+libSxComponents_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libSxComponents_HEADER_FILES_DIR         = .
+libSxComponents_HEADER_FILES_INSTALL_DIR = /SxComponents
+
+libSxComponents_HEADER_FILES =         \
+       SxComponents.h                  \
+       SxComponent.h                   \
+       SxComponentRegistry.h           \
+       SxXmlRpcComponent.h             \
+        SxComponentInvocation.h        \
+       SxComponentMethodSignature.h    \
+       SxBasicAuthCredentials.h        \
+       SxComponentException.h          \
+
+libSxComponents_OBJC_FILES =           \
+       SxComponent.m                   \
+       SxComponentRegistry.m           \
+        SxComponentInvocation.m        \
+       SxComponentMethodSignature.m    \
+       \
+       SxXmlRpcRegBackend.m            \
+       SxXmlRpcComponent.m             \
+       SxXmlRpcInvocation.m            \
+       SxBasicAuthCredentials.m        \
+       SxComponentException.m          \
+       NSObject+SxXmlRpcValue.m        \
+
+sxc_ls_OBJC_FILES   = sxc_ls.m
+sxc_call_OBJC_FILES = sxc_call.m
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+include $(GNUSTEP_MAKEFILES)/tool.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/SxComponents/GNUmakefile.preamble b/skyrix-sope/SxComponents/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..3931e40
--- /dev/null
@@ -0,0 +1,41 @@
+# $Id$
+
+libSxComponents_LIBRARIES_DEPEND_UPON = \
+       -lNGObjWeb -lXmlRpc -lNGJavaScript -lNGScripting \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lDOM -lSaxObjC
+
+ADDITIONAL_TOOL_LIBS += \
+       -lSxComponents -lNGObjWeb -lNGMime \
+        -lNGJavaScript -lNGScripting \
+       -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC
+
+ADDITIONAL_INCLUDE_DIRS += -I../NGObjWeb
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_JS=$(GNUSTEP_BUILD_DIR)/../../../ThirdParty/js-1.5
+RELBUILD_DIR_SOPE=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/../../skyrix-core
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                                            \
+       -L$(RELBUILD_DIR_SOPE)/NGObjWeb/$(GNUSTEP_OBJ_DIR_NAME)         \
+       -L$(RELBUILD_DIR_SOPE)/NGJavaScript/$(GNUSTEP_OBJ_DIR_NAME)     \
+       -L$(RELBUILD_DIR_SOPE)/NGScripting/$(GNUSTEP_OBJ_DIR_NAME)      \
+       -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += \
+       -L./$(GNUSTEP_OBJ_DIR)               \
+       -L../NGObjWeb/$(GNUSTEP_OBJ_DIR)     \
+       -L../NGJavaScript/$(GNUSTEP_OBJ_DIR) \
+       -L../NGScripting/$(GNUSTEP_OBJ_DIR)
+endif
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libSxComponents_PREBIND_ADDR="0xC4900000"
+libSxComponents_LDFLAGS += -seg1addr $(libSxComponents_PREBIND_ADDR)
+endif
diff --git a/skyrix-sope/SxComponents/NSObject+SxXmlRpcValue.m b/skyrix-sope/SxComponents/NSObject+SxXmlRpcValue.m
new file mode 100644 (file)
index 0000000..2ec83fb
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+
+@implementation NSObject(SxXmlRpcValue)
+
+- (NSArray *)asXmlRpcArray {
+  if ([self respondsToSelector:@selector(objectEnumerator)]) {
+    return [[[NSArray alloc]
+                      initWithObjectsFromEnumerator:
+                        [(id)self objectEnumerator]]
+                      autorelease];
+  }
+  return nil;
+}
+
+- (NSDictionary *)asXmlRpcStruct {
+  return [self valuesForKeys:[[self classDescription] attributeKeys]];
+}
+
+- (NSString *)asXmlRpcString {
+  return [self stringValue];
+}
+- (int)asXmlRpcInt {
+  return [self intValue];
+}
+
+- (NSData *)asXmlRpcBase64 {
+  return [[self stringValue] dataUsingEncoding:NSUTF8StringEncoding];
+}
+- (NSDate *)asXmlRpcDateTime {
+  return [[[NSDate alloc] initWithString:[self stringValue]] autorelease];
+}
+
+- (id)asXmlRpcValueOfType:(NSString *)_xmlRpcValueType {
+  unsigned len;
+  
+  if ((len = [_xmlRpcValueType length]) == 0)
+    return self;
+
+  if ([_xmlRpcValueType isEqualToString:@"string"])
+    return [self asXmlRpcString];
+  if ([_xmlRpcValueType isEqualToString:@"int"])
+    return [NSNumber numberWithInt:[self asXmlRpcInt]];
+  if ([_xmlRpcValueType isEqualToString:@"array"])
+    return [self asXmlRpcArray];
+  if ([_xmlRpcValueType isEqualToString:@"struct"])
+    return [self asXmlRpcStruct];
+  if ([_xmlRpcValueType isEqualToString:@"datetime"])
+    return [self asXmlRpcDateTime];
+  if ([_xmlRpcValueType isEqualToString:@"base64"])
+    return [self asXmlRpcBase64];
+  
+  return self;
+}
+
+@end /* NSObject(SxXmlRpcValue) */
+
+@implementation NSArray(SxXmlRpcValue)
+
+- (NSArray *)asXmlRpcArray {
+  return self;
+}
+
+- (id)asXmlRpcValueOfType:(NSString *)_xmlRpcValueType {
+  return self;
+}
+
+@end /* NSArray(SxXmlRpcValue) */
+
+@implementation NSDictionary(SxXmlRpcValue)
+
+- (NSArray *)asXmlRpcArray {
+  return [self allValues];
+}
+
+- (NSDictionary *)asXmlRpcStruct {
+  return self;
+}
+
+@end /* NSDictionary(SxXmlRpcValue) */
+
+@implementation NSDate(SxXmlRpcValue)
+
+- (NSDate *)asXmlRpcDateTime {
+  return self;
+}
+
+@end /* NSDate(SxXmlRpcValue) */
+
+@implementation NSData(SxXmlRpcValue)
+
+- (NSData *)asXmlRpcBase64 {
+  return self;
+}
+
+@end /* NSCalendarDate(SxXmlRpcValue) */
diff --git a/skyrix-sope/SxComponents/README b/skyrix-sope/SxComponents/README
new file mode 100644 (file)
index 0000000..77aefab
--- /dev/null
@@ -0,0 +1,40 @@
+# $Id$
+
+This implements the client interfaces to a SandStorm like
+XML-RPC based component system.
+
+Auth-Handling
+=============
+If you make a call which requires authentication, a somewhat
+complex process is initiated ... ;-)
+This is to be described here ...
+
+Failover
+========
+The components support some kind of 'transparent application failover'.
+When a daemon crashes, it gets restarted by the skymasterd, but on
+a new port as the ports are assigned by the kernel. When the component
+can't connect to the server anymore, cause it only knows the old port
+the server ran on before it crashed, it queries the new data from the
+registry and runs the method on the server with the new IP and port.
+The retry count and the time between the retries can be handled with
+the defaults described below. If it can't connect within the retry count
+given, the exception is passed as result (which can then be handled by the
+UI). 
+
+Defaults
+========
+  
+  SxComponentRegistryBackends - ( SxXmlRpcRegBackend )
+  SxComponentRegistryURL      - "http://127.0.0.1:14042/RPC2"
+
+  SxComponentRetriesOnError   - how many retries should be run
+                                when the component couldn't connect
+                                to the server (Default: 3)
+
+  SxComponentRetryTime        - how long should be waited between
+                                the retries - this one gets multiplied
+                                with the retry count, so the first retry
+                                is run immediately, the second after
+                                1*retryTime, the third after 2*retryTime etc.
+                                (Default: 5)
\ No newline at end of file
diff --git a/skyrix-sope/SxComponents/SxBasicAuthCredentials.h b/skyrix-sope/SxComponents/SxBasicAuthCredentials.h
new file mode 100644 (file)
index 0000000..5ba9b12
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SxComponents_SxBasicAuthCredentials_H__
+#define __SxComponents_SxBasicAuthCredentials_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+@class WOResponse, WORequest;
+
+/*
+  HTTP Basic Authentication
+  
+  Credentials with an empty realm will be applied to any basic request !!
+  (more convenient, but [much] less secure !!!)
+*/
+
+@interface SxBasicAuthCredentials : NSObject
+{
+  NSString *realm;
+  NSString *userName;
+  NSString *httpCred;
+}
+
+- (id)initWithRealm:(NSString *)_realm
+  userName:(NSString *)_userName
+  password:(NSString *)_pwd;
+
+/* basic auth info */
+
+- (NSString *)realm;
+- (NSString *)userName;
+
+/* accessor methods to fill out credentials within an exception object */
+- (void)setCredentials:(NSString *)_username password:(NSString *)_password;
+
+/* backend */
+
+- (BOOL)usableWithHttpResponse:(WOResponse *)_response;
+- (void)applyOnRequest:(WORequest *)_request;
+
+@end
+
+#endif /* __SxComponents_SxBasicAuthCredentials_H__ */
diff --git a/skyrix-sope/SxComponents/SxBasicAuthCredentials.m b/skyrix-sope/SxComponents/SxBasicAuthCredentials.m
new file mode 100644 (file)
index 0000000..715649b
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SxBasicAuthCredentials.h"
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include "common.h"
+
+@implementation SxBasicAuthCredentials
+
+- (id)initWithRealm:(NSString *)_realm
+  userName:(NSString *)_userName
+  password:(NSString *)_pwd
+{
+  NSString *s;
+  
+  self->realm    = [_realm    copy];
+  self->userName = [_userName copy];
+
+  s = [NSString stringWithFormat:@"%@:%@", _userName, _pwd];
+  s = [s stringByEncodingBase64];
+  self->httpCred = [s copy];
+  return self;
+}
+- (id)init {
+  return [self initWithRealm:nil userName:nil password:nil];
+}
+
+- (void)dealloc {
+  RELEASE(self->userName);
+  RELEASE(self->realm);
+  RELEASE(self->httpCred);
+  [super dealloc];
+}
+
+/* basic auth info */
+
+- (NSString *)realm {
+  return self->realm;
+}
+- (void)setUserName:(NSString *)_username {
+  ASSIGNCOPY(self->userName, _username);
+}
+- (NSString *)userName {
+  return self->userName;
+}
+
+- (void)setHttpCred:(NSString *)_cred {
+  ASSIGNCOPY(self->httpCred, _cred);
+}
+
+- (void)setCredentials:(NSString *)_username password:(NSString *)_password {
+  [self setUserName:_username];
+  [self setHttpCred:[[NSString stringWithFormat:@"%@:%@", _username, _password] 
+        stringByEncodingBase64]];
+}
+
+/* support XML-RPC backend ... */
+
+- (BOOL)usableWithHttpResponse:(WOResponse *)_response {
+  NSString *authHeader;
+  
+  authHeader = [_response headerForKey:@"www-authenticate"];
+  if ([authHeader length] == 0)
+    return NO;
+  
+  if (self->httpCred == nil)
+    /* no credentials set ... */
+    return NO;
+  
+  /* check realm !!! */
+  
+  return YES;
+}
+
+- (void)applyOnRequest:(WORequest *)_request {
+  NSAssert([self->httpCred length] > 0, @"no credentials set !");
+  
+  [_request setHeader:[@"basic " stringByAppendingString:self->httpCred]
+            forKey:@"authorization"];
+}
+
+/* equality */
+
+- (BOOL)isEqualToBasicCredentials:(SxBasicAuthCredentials *)_otherObj {
+  if (![[_otherObj realm] isEqualToString:[self realm]])
+    return NO;
+  
+  return [_otherObj->httpCred isEqualToString:self->httpCred];
+}
+
+- (BOOL)isEqual:(id)_otherObj {
+  if (_otherObj == self)
+    return YES;
+  if ([_otherObj class] == [self class])
+    return [self isEqualToBasicCredentials:_otherObj];
+  return NO;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X[%@]: realm=%@ user=%@>",
+                     self, NSStringFromClass([self class]),
+                     [self realm], [self userName]];
+}
+
+@end /* SxBasicAuthCredentials */
diff --git a/skyrix-sope/SxComponents/SxComponent.h b/skyrix-sope/SxComponents/SxComponent.h
new file mode 100644 (file)
index 0000000..403d5b3
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SxComponent_H__
+#define __SxComponent_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  This is the abstract superclass representing a component
+  as registered in the SxComponentRegistry.
+  
+  Feature: Components sometimes support asynchronous invocation
+  of methods. You can choose from two options to wait for a result:
+  
+  a) polling (easy ;-):
+    id r = [component asyncCall:@"system.tar", @"/", nil];
+    while ([r isAsyncResultPending])
+      sleep(1); // check once per second for result .. 
+    if ([r asyncCallFailed]) [[r asyncResult] raise];
+    r = [r asyncResult]; // turn into "real" result
+  
+  b) notification (more difficult ...):
+    id r = [component asyncCall:@"system.tar", @"/", nil];
+    if ([r isAsyncResultPending]) {
+      // component only posts, if result couldn't be resolved immediatly !!!
+      [[component notificationCenter]
+                  addObserver:self selector:@selector(asyncResult:)
+                  notificationName:SxAsyncResultReadyNotificationName
+                  object:r];
+    }
+    else
+      [self setResult:r]; // should check for errors
+    
+    - (void)asyncResult:(NSNotification *)_n {
+      id r = [_n object];
+      if ([r asyncCallFailed]) [[r asyncResult] raise];
+      [self setResult:[r asyncResult]]; // turn into "real" result
+    }
+*/
+
+@class NSNotificationCenter, NSString, NSArray, NSException;
+@class SxComponentRegistry;
+@class SxComponentInvocation, SxComponentMethodSignature;
+
+extern NSString *SxAsyncResultReadyNotificationName;
+
+@protocol SxComponent
+
+/* accessors */
+
+- (SxComponentRegistry *)componentRegistry;
+- (NSString *)componentName;
+- (NSString *)namespace;
+
+/* reflection */
+
+- (NSArray *)signaturesForMethodNamed:(NSString *)_method;
+
+- (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method
+  methodSignature:(SxComponentMethodSignature *)_signature;
+- (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method;
+- (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method
+  arguments:(NSArray *)_args;
+
+/* introspection */
+
+- (NSArray *)listMethods;
+- (NSArray *)methodSignature:(NSString *)_methodName;
+- (NSString *)methodHelp:(NSString *)_methodName;
+
+/* operations */
+
+- (id)call:(NSString *)_methodName,...;
+- (id)call:(NSString *)_methodName arguments:(NSArray *)_args;
+- (NSException *)lastException;
+
+/* async calls */
+
+- (NSNotificationCenter *)notificationCenter;
+- (id)asyncCall:(NSString *)_methodName,...;
+- (id)asyncCall:(NSString *)_methodName arguments:(NSArray *)_args;
+
+/* subcomponents */
+
+- (NSArray *)componentNames;
+- (id<NSObject,SxComponent>)componentWithName:(NSString *)_name;
+
+@end
+
+@interface SxComponent : NSObject < SxComponent, NSCoding >
+{
+@protected
+  SxComponentRegistry *registry;
+  NSString            *componentName;
+  NSString            *namespace;
+@private
+  NSException         *lastException;
+}
+
+- (id)initWithName:(NSString *)_name
+  namespace:(NSString *)_namespace
+  registry:(SxComponentRegistry *)_registry;
+
+- (id)initWithName:(NSString *)_name
+  registry:(SxComponentRegistry *)_registry;
+
+- (void)flush;
+
+- (void)setLastException:(NSException *)_exception;
+- (void)resetLastException;
+- (BOOL)lastCallFailed;
+
+@end
+
+/*
+  Managing results of asynchronous invocations. The methods are
+  overridden by special proxy objects created by components. All
+  "usual" objects return:
+  - isAsyncResultPending => NO
+  - asyncResult          => self
+  - asyncCallFailed      => NO
+*/
+
+@interface NSObject(AsyncCallResult)
+
+- (BOOL)isAsyncResultPending;
+- (id)asyncResult;
+- (BOOL)asyncCallFailed;
+
+@end
+
+#endif /* __SxComponent_H__ */
diff --git a/skyrix-sope/SxComponents/SxComponent.m b/skyrix-sope/SxComponents/SxComponent.m
new file mode 100644 (file)
index 0000000..eca1ce3
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SxComponent.h"
+#include "SxComponentRegistry.h"
+#include "SxComponentInvocation.h"
+#include "SxComponentMethodSignature.h"
+#include "common.h"
+
+@interface SxComponentRegistry(Dealloc)
+- (void)_componentWillDealloc:(SxComponent *)_c;
+@end
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (void)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+NSString *SxAsyncResultReadyNotificationName =
+  @"SxAsyncResultReadyNotificationName";
+
+@implementation SxComponent
+
++ (int)version {
+  return 1;
+}
+
+- (id)initWithName:(NSString *)_name
+  namespace:(NSString *)_namespace
+  registry:(SxComponentRegistry *)_registry
+{
+  if ([_name length] == 0) {
+    NSLog(@"%s: missing component name ...", __PRETTY_FUNCTION__);
+    RELEASE(self);
+    return nil;
+  }
+  if (_registry == nil) {
+    NSLog(@"%s: missing registry of component %@ ...", __PRETTY_FUNCTION__,
+          _name);
+    RELEASE(self);
+    return nil;
+  }
+  
+  if ((self = [super init])) {
+    self->componentName = [_name copy];
+    self->namespace = [_namespace copy];
+    self->registry = RETAIN(_registry);
+  }
+  return self;
+}
+
+- (id)initWithName:(NSString *)_name
+  registry:(SxComponentRegistry *)_registry
+{
+  return [self initWithName:_name
+               namespace:[[_name componentsSeparatedByString:@"."] lastObject]
+               registry:_registry];
+}
+  
+- (id)init {
+  return [self initWithName:nil namespace:nil registry:nil];
+}
+
+- (void)dealloc {
+  [self->registry _componentWillDealloc:self];
+  self->registry = nil;
+  RELEASE(self->lastException);
+  RELEASE(self->componentName);
+  RELEASE(self->namespace);
+  [super dealloc];
+}
+
+/* accessors */
+
+- (SxComponentRegistry *)componentRegistry {
+  return self->registry;
+}
+- (NSString *)componentName {
+  return self->componentName;
+}
+
+- (NSString *)namespace {
+  return self->namespace;
+}
+
+/* reflection */
+
+- (Class)invocationClass {
+  static Class CompInv = Nil;
+  if (CompInv == Nil) CompInv = [SxComponentInvocation class];
+  return CompInv;
+}
+
+- (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method
+  methodSignature:(SxComponentMethodSignature *)_signature
+{
+  SxComponentInvocation *invocation = nil;
+  
+  invocation =
+    [[[self invocationClass] alloc]
+            initWithComponent:self
+            methodName:_method
+            signature:_signature];
+  return AUTORELEASE(invocation);
+}
+
+- (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method {
+  SxComponentMethodSignature *sig;
+  NSArray *sigs;
+
+  sig = nil;
+  sigs = [self signaturesForMethodNamed:_method];
+  if ([sigs count] > 0)
+    sig = [sigs objectAtIndex:0];
+  
+  return [self invocationForMethodNamed:_method
+               methodSignature:sig];
+}
+
+- (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method
+  arguments:(NSArray *)_args
+{
+  /*
+    naive approach, search for a signature matching the arg count,
+    should be overidden by subclass ..
+  */
+  SxComponentMethodSignature *sig;
+  SxComponentInvocation *inv;
+  NSArray  *sigs;
+  unsigned i, count, argCount;
+
+  argCount = [_args count];
+  sigs = [self signaturesForMethodNamed:_method];
+  if ((count = [sigs count]) == 0) {
+    inv = [self invocationForMethodNamed:_method
+                methodSignature:nil];
+    [inv setArguments:_args];
+    return inv;
+  }
+  else {
+    for (i = 0, sig = nil; i < count; i++) {
+      if ([sig numberOfArguments] == argCount)
+        break;
+    }
+  }
+  inv = [self invocationForMethodNamed:_method
+              methodSignature:sig];
+  [inv setArguments:_args];
+  return inv;
+}
+
+- (NSArray *)signaturesForMethodNamed:(NSString *)_method {
+  return nil;
+}
+
+/* introspection */
+
+- (NSArray *)listMethods {
+  NSArray *names;
+  
+  names = [[self componentRegistry] listMethods:[self componentName]];
+  if (names == nil) return nil;
+  
+  if ([names isKindOfClass:[NSException class]]) {
+    [self setLastException:(id)names];
+    return nil;
+  }
+  
+  if (![names isKindOfClass:[NSArray class]]) {
+    NSException  *exc;
+    NSDictionary *ui;
+
+    if ([names isKindOfClass:[NSException class]])
+      exc = (id)names;
+    else {
+      ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         names, @"resultObject",
+                         NSStringFromClass([names class]), @"resultClassName",
+                         [self componentName], @"componentName",
+                         nil];
+      
+      exc = [NSException exceptionWithName:@"SxComponentIntrospectionError"
+                         reason:@"listMethods failed ..."
+                         userInfo:ui];
+    }
+    [self setLastException:exc];
+    names = nil;
+  }
+  
+  return names;
+}
+
+- (NSArray *)methodSignature:(NSString *)_methodName {
+  NSArray *sig;
+  
+  sig = [[self componentRegistry]
+               methodSignature:[self componentName]
+               method:_methodName];
+  if (sig == nil) return nil;
+
+  if ([sig isKindOfClass:[NSException class]]) {
+    [self setLastException:(id)sig];
+    return nil;
+  }
+  
+  if (![sig isKindOfClass:[NSArray class]]) {
+    NSException  *exc;
+    NSDictionary *ui;
+    
+    if ([sig isKindOfClass:[NSException class]])
+      exc = (id)sig;
+    else {
+      [self logWithFormat:@"WARNING(%s): got invalid result type !",
+              __PRETTY_FUNCTION__];
+      
+      ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                           sig,                            @"resultObject",
+                           NSStringFromClass([sig class]), @"resultClassName",
+                           [self componentName],           @"componentName",
+                           nil];
+      
+      exc = [NSException exceptionWithName:@"SxComponentIntrospectionError"
+                         reason:@"methodSignature failed ..."
+                         userInfo:ui];
+    }
+    [self setLastException:exc];
+    sig = nil;
+  }
+  
+  return sig;
+}
+
+- (NSString *)methodHelp:(NSString *)_methodName {
+  return [[self componentRegistry]
+                methodHelp:[self componentName] method:_methodName];
+}
+
+/* operations */
+
+- (id)call:(NSString *)_methodName arguments:(NSArray *)_args {
+  [self subclassResponsibility:_cmd];
+  return nil;
+}
+
+- (BOOL)lastCallFailed {
+  return [self lastException] != nil ? YES : NO;
+}
+
+- (void)setLastException:(NSException *)_exception {
+  ASSIGN(self->lastException, _exception);
+}
+- (NSException *)lastException {
+  return self->lastException;
+}
+- (void)resetLastException {
+  ASSIGN(self->lastException, (id)nil);
+}
+
+- (id)call:(NSString *)_methodName,... {
+  id array, obj, *objects;
+  va_list list;
+  unsigned int count;
+  
+  va_start(list, _methodName);
+  for (count = 0, obj = va_arg(list, id); obj; obj = va_arg(list,id))
+    count++;
+  va_end(list);
+  
+  objects = calloc(count, sizeof(id));
+  {
+    va_start(list, _methodName);
+    for (count = 0, obj = va_arg(list, id); obj; obj = va_arg(list,id))
+      objects[count++] = obj;
+    va_end(list);
+    
+    array = [NSArray arrayWithObjects:objects count:count];
+  }
+  free(objects);
+  return [self call:_methodName arguments:array];
+}
+
+/* async calls */
+
+- (NSNotificationCenter *)notificationCenter {
+  return [NSNotificationCenter defaultCenter];
+}
+
+- (id)asyncCall:(NSString *)_methodName,... {
+  id array, obj, *objects;
+  va_list list;
+  unsigned int count;
+  
+  va_start(list, _methodName);
+  for (count = 0, obj = va_arg(list, id); obj; obj = va_arg(list,id))
+    count++;
+  va_end(list);
+  
+  objects = calloc(count, sizeof(id));
+  {
+    va_start(list, _methodName);
+    for (count = 0, obj = va_arg(list, id); obj; obj = va_arg(list,id))
+      objects[count++] = obj;
+    va_end(list);
+    
+    array = [NSArray arrayWithObjects:objects count:count];
+  }
+  free(objects);
+  return [self asyncCall:_methodName arguments:array];
+}
+
+- (id)asyncCall:(NSString *)_methodName arguments:(NSArray *)_args {
+  /* default: do everything in a synchronous way ... */
+  return [self call:_methodName arguments:_args];
+}
+
+/* subcomponents */
+
+- (NSArray *)componentNames {
+  NSArray  *array;
+  NSString *cp;
+  
+  cp    = [[self componentName] stringByAppendingString:@"."];
+  array = [[self componentRegistry] listComponents:cp];
+  
+  array = [array mappedArrayUsingSelector:@selector(stringWithoutPrefix:)
+                 withObject:[self componentName]];
+  
+  return array;
+}
+- (id<NSObject,SxComponent>)componentWithName:(NSString *)_name {
+  NSString *qn;
+  
+  qn = [[[self componentName]
+               stringByAppendingString:@"."]
+               stringByAppendingString:_name];
+  return [[self componentRegistry] getComponent:qn];
+}
+
+/* caching */
+
+- (void)flush {
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->componentName];
+  [_coder encodeConditionalObject:self->registry];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  self->componentName = [[_coder decodeObject] copy];
+  
+  if ((self->registry = [[_coder decodeObject] retain]) == nil)
+    self->registry = [[SxComponentRegistry defaultComponentRegistry] retain];
+  
+  return self;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]: name=%@",
+        self, NSStringFromClass([self class]),
+        [self componentName]];
+  [ms appendString:@">"];
+  
+  return ms;
+}
+
+@end /* SxComponent */
+
+@implementation NSObject(AsyncCallResult)
+
+- (BOOL)isAsyncResultPending {
+  return NO;
+}
+- (id)asyncResult {
+  return self;
+}
+- (BOOL)asyncCallFailed {
+  return NO;
+}
+
+@end /* NSObject(AsyncCall) */
diff --git a/skyrix-sope/SxComponents/SxComponentException.h b/skyrix-sope/SxComponents/SxComponentException.h
new file mode 100644 (file)
index 0000000..771adbe
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SxComponent_Exception_H__
+#define __SxComponent_Exception_H__
+
+#import <Foundation/NSException.h>
+
+@class SxComponentInvocation;
+
+@interface NSException(SxComponentExceptionTyping)
+- (BOOL)isCredentialsRequiredException;
+@end
+
+@interface SxComponentException : NSException
+@end
+
+@interface SxAuthException : SxComponentException
+{
+  id credentials;
+  SxComponentInvocation *invocation;
+}
+
+/* accessors */
+
+- (void)setCredentials:(id)_credentials;
+- (id)credentials;
+
+- (void)setInvocation:(SxComponentInvocation *)_invocation;
+- (SxComponentInvocation *)invocation;
+
+@end
+
+@interface SxMissingCredentialsException : SxAuthException
+@end
+
+@interface SxInvalidCredentialsException : SxAuthException
+@end
+
+#endif /* __SxComponent_Exception_H__ */
diff --git a/skyrix-sope/SxComponents/SxComponentException.m b/skyrix-sope/SxComponents/SxComponentException.m
new file mode 100644 (file)
index 0000000..500524b
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SxComponentException.h"
+#include "SxBasicAuthCredentials.h"
+#include "SxComponentInvocation.h"
+#include "common.h"
+
+@implementation NSException(SxComponentExceptionTyping)
+
+- (BOOL)isCredentialsRequiredException {
+  return NO;
+}
+
+@end /* NSException(SxComponentExceptionTyping) */
+
+@implementation SxComponentException
+@end /* SxComponentException */
+
+@implementation SxAuthException
+
+- (id)init {
+  return [self initWithName:NSStringFromClass([self class])
+               reason:nil
+               userInfo:nil];
+}
+
+- (void)dealloc {
+  RELEASE(self->invocation);
+  RELEASE(self->credentials);
+  [super dealloc];
+}
+
+/* accessors */
+
+- (BOOL)isCredentialsRequiredException {
+  return YES;
+}
+
+- (void)setCredentials:(id)_credentials {
+  ASSIGN(self->credentials, _credentials);
+}
+- (id)credentials {
+  return self->credentials;
+}
+
+- (void)setInvocation:(SxComponentInvocation *)_invocation {
+  ASSIGN(self->invocation, _invocation);
+}
+- (SxComponentInvocation *)invocation {
+  return self->invocation;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  id t;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]: name=%@",
+        self, NSStringFromClass([self class]),
+        [self name]];
+  
+  if ([self isCredentialsRequiredException])
+    [ms appendString:@" cred-required"];
+
+  if ((t = [self credentials]))
+    [ms appendFormat:@" creds=%@", t];
+  
+  if ((t = [self invocation]))
+    [ms appendFormat:@" inv=%@", t];
+  
+  [ms appendString:@">"];
+  
+  return ms;
+}
+
+@end /* SxAuthException */
+
+@implementation SxMissingCredentialsException
+@end /* SxMissingCredentialsException */
+
+@implementation SxInvalidCredentialsException
+@end /* SxInvalidCredentialsException */
diff --git a/skyrix-sope/SxComponents/SxComponentInvocation.h b/skyrix-sope/SxComponents/SxComponentInvocation.h
new file mode 100644 (file)
index 0000000..52b0e0c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SxComponentInvocation_H__
+#define __SxComponentInvocation_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSMutableArray, NSException, NSArray;
+@class SxComponent;
+@class SxComponentMethodSignature;
+
+/*
+  Note: a component method can have *multiple* signatures. Sigh. This
+  is because XML-RPC introspection is designed that way.
+  An invocation is always associated with either a single or no
+  signature (no signature for generic calls).
+*/
+
+@interface SxComponentInvocation : NSObject < NSCoding >
+{
+  SxComponent                *target;
+  NSString                   *methodName;
+  SxComponentMethodSignature *signature;
+  NSMutableArray             *arguments;
+  id                         result;
+  NSException                *lastException;
+  id                         credentials;
+}
+
+- (id)initWithComponent:(SxComponent *)_component
+  methodName:(NSString *)_method
+  signature:(SxComponentMethodSignature *)_signature;
+
+/* arguments */
+
+- (SxComponentMethodSignature *)methodSignature;
+
+- (void)setMethodName:(NSString *)_name;
+- (NSString *)methodName;
+
+- (void)setArgument:(id)_argument atIndex:(int)index;
+- (id)argumentAtIndex:(int)index;
+- (void)setArguments:(NSArray *)_args;
+- (NSArray *)arguments;
+
+- (void)setReturnValue:(id)_result;
+- (id)returnValue;
+
+- (void)setLastException:(NSException *)_exception;
+- (NSException *)lastException;
+- (void)resetLastException;
+
+- (BOOL)argumentsRetained;
+
+/* credentials */
+
+- (void)setCredentials:(id)_credentials;
+- (id)credentials;
+
+/* Dispatching an Invocation */
+
+- (BOOL)invokeWithTarget:(SxComponent *)_target;
+- (BOOL)invoke;
+- (BOOL)lastCallFailed; // if this is true, the result is nil !
+
+- (BOOL)asyncInvoke;
+- (BOOL)isAsyncResultPending;
+
+/* KVC */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key;
+- (id)valueForKey:(NSString *)_key;
+
+@end
+
+#endif /* __SxComponentInvocation_H__ */
diff --git a/skyrix-sope/SxComponents/SxComponentInvocation.m b/skyrix-sope/SxComponents/SxComponentInvocation.m
new file mode 100644 (file)
index 0000000..a561b7c
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SxComponentInvocation.h"
+#include "SxComponentMethodSignature.h"
+#include "SxComponent.h"
+#include <NGExtensions/NSString+Ext.h>
+#include "common.h"
+
+@implementation SxComponentInvocation
+
+static NSNull *null = nil;
+
++ (int)version {
+  return 1;
+}
+
+- (void)_ensureArgs {
+  unsigned i, count;
+
+  if (self->arguments) return;
+  if (self->signature == nil) return;
+  if (null == nil) null = [[NSNull null] retain];
+
+  count = [self->signature numberOfArguments];
+  
+  self->arguments = [[NSMutableArray alloc] initWithCapacity:count];
+  for (i = 0; i < count; i++)
+    [self->arguments addObject:null];
+}
+
+- (id)initWithMethodSignature:(id)_sig {
+  if (_sig == nil) {
+    [self release];
+    return nil;
+  }
+
+  self->signature = [_sig retain];
+  [self _ensureArgs];
+  
+  return self;
+}
+- (id)init {
+  return [self initWithMethodSignature:nil];
+}
+- (id)initWithComponent:(SxComponent *)_component
+  methodName:(NSString *)_method
+  signature:(SxComponentMethodSignature *)_signature
+{
+  if ((self = [self initWithMethodSignature:_signature])) {
+    self->methodName = [_method    copy];
+    self->target     = [_component retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->credentials   release];
+  [self->lastException release];
+  [self->arguments     release];
+  [self->result        release];
+  [self->target        release];
+  [self->methodName    release];
+  [self->signature     release];
+  [super dealloc];
+}
+
+/* arguments */
+
+- (SxComponentMethodSignature *)methodSignature {
+  return self->signature;
+}
+
+- (void)setArgument:(id)_argument atIndex:(int)_idx {
+  if (_argument == nil) _argument = null;
+  [self->arguments replaceObjectAtIndex:_idx withObject:_argument];
+}
+- (id)argumentAtIndex:(int)_idx {
+  id res;
+  
+  res = [self->arguments objectAtIndex:_idx];
+  if (res == null) res = nil;
+  return res;
+}
+- (void)setArguments:(NSArray *)_args {
+  NSAssert2(([self->signature numberOfArguments] == [_args count]),
+            @"arg count mismatch (%i expected, got %i)",
+            [self->signature numberOfArguments],
+            [_args count]);
+  
+  [self->arguments removeAllObjects];
+  [self->arguments addObjectsFromArray:_args];
+}
+- (NSArray *)arguments {
+  return [[self->arguments copy] autorelease];
+}
+
+- (BOOL)argumentsRetained {
+  return YES;
+}
+
+- (void)setTarget:(SxComponent *)_target {
+  ASSIGN(self->target, _target);
+}
+- (SxComponent *)target {
+  return self->target;
+}
+
+- (void)setMethodName:(NSString *)_name {
+  ASSIGNCOPY(self->methodName, _name);
+}
+- (NSString *)methodName {
+  return self->methodName;
+}
+
+- (void)setReturnValue:(id)_result {
+  ASSIGN(self->result, _result);
+}
+- (id)returnValue {
+  return self->result;
+}
+
+- (void)setLastException:(NSException *)_exception {
+  ASSIGN(self->lastException, _exception);
+}
+
+- (NSException *)lastException {
+  return self->lastException;
+}
+- (BOOL)lastCallFailed {
+  return self->lastException != nil ? YES : NO;
+}
+- (void)resetLastException {
+  ASSIGN(self->lastException, (id)nil);
+}
+
+/* credentials */
+
+- (void)setCredentials:(id)_credentials {
+  ASSIGN(self->credentials, _credentials);
+}
+- (id)credentials {
+  return self->credentials;
+}
+
+/* Dispatching an Invocation */
+
+- (NSArray *)argumentsForCall {
+  return self->arguments;
+}
+
+- (id)_call:(NSString *)_methodName
+  onTarget:(SxComponent *)_target
+  arguments:(NSArray *)_params
+{
+  return [_target call:_methodName arguments:_params];
+}
+- (BOOL)_asyncCall:(NSString *)_methodName
+  onTarget:(SxComponent *)_target
+  arguments:(NSArray *)_params
+{
+  return [_target asyncCall:_methodName arguments:_params] ? YES : NO;
+}
+
+- (BOOL)invokeWithTarget:(SxComponent *)_target {
+  NSAutoreleasePool *pool;
+  BOOL ok;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    NSArray *args;
+    id res;
+
+    /* reset state */
+    [self->lastException release]; self->lastException = nil;
+    [self->result        release]; self->result = nil;
+    
+    /* get arguments */
+    args = [self argumentsForCall];
+    
+    /* invoke remote method */
+    res = [self _call:[self methodName] onTarget:_target arguments:args];
+    
+    /* check for errors */
+    
+    if (self->lastException) {
+      ok = NO;
+      [self setReturnValue:nil];
+    }
+    else {
+      /* store return value */
+      [self setReturnValue:res];
+      ok = YES;
+    }
+  }
+  [pool release];
+
+  return ok;
+}
+- (BOOL)invoke {
+  return [self invokeWithTarget:[self target]];
+}
+
+/* asynchronous */
+
+- (void)asyncResultReady:(NSNotification *)_notification {
+  id proxy;
+  
+  if (self->result != [_notification object]) {
+    NSLog(@"%s: WARNING, got an invalid aync result notification: %@",
+          __PRETTY_FUNCTION__, _notification);
+    return;
+  }
+
+  proxy = [self->result retain];
+  [self->result release]; self->result = nil;
+  
+  if ([proxy asyncCallFailed]) {
+    self->lastException = [[proxy asyncResult] retain];
+    [self setReturnValue:nil];
+  }
+  else
+    [self setReturnValue:[proxy asyncResult]];
+  
+  [proxy release]; proxy = nil;
+  
+  [[self->target notificationCenter]
+                 postNotificationName:SxAsyncResultReadyNotificationName
+                 object:self];
+}
+
+- (BOOL)asyncInvoke {
+  NSAutoreleasePool *pool;
+  BOOL ok;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    NSArray *args;
+    id res;
+
+    /* reset state */
+    [self->lastException release]; self->lastException = nil;
+    [self->result        release]; self->result = nil;
+    
+    /* get arguments */
+    args = [self argumentsForCall];
+    
+    /* invoke remote method */
+    
+    res = [self->target asyncCall:[self methodName] arguments:args];
+    
+    if (![res isAsyncResultPending]) {
+      /* result is ready :-) */
+      
+      /* check for errors */
+      if ([self->target lastCallFailed]) {
+        self->lastException = [res retain];
+        [self setReturnValue:nil];
+        ok = NO;
+      }
+      else {
+        /* store return value */
+        [self setReturnValue:res];
+        ok = YES;
+      }
+    }
+    else {
+      /* result isn't ready yet, register for notification */
+      ok = YES;
+      self->result = [res retain];
+      
+      [[self->target notificationCenter]
+                     addObserver:self selector:@selector(asyncResultReady:)
+                     name:SxAsyncResultReadyNotificationName
+                     object:self->result];
+    }
+  }
+  [pool release];
+  
+  return ok;
+}
+
+- (BOOL)isAsyncResultPending {
+  return [self->result isAsyncResultPending];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->target];
+  [_coder encodeObject:self->methodName];
+  [_coder encodeObject:self->signature];
+  [_coder encodeObject:self->arguments];
+  [_coder encodeObject:self->result];
+  [_coder encodeObject:self->lastException];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  if (null == nil) null = [[NSNull null] retain];
+  
+  self->target        = [[_coder decodeObject] retain];
+  self->methodName    = [[_coder decodeObject] copy];
+  self->signature     = [[_coder decodeObject] retain];
+  self->arguments     = [[_coder decodeObject] retain];
+  self->result        = [[_coder decodeObject] retain];
+  self->lastException = [[_coder decodeObject] retain];
+  
+  if (self->signature == nil) {
+    NSLog(@"%s: missing signature (required during decoding)",
+          __PRETTY_FUNCTION__);
+    [self release];
+    return nil;
+  }
+  [self _ensureArgs];
+  
+  return self;
+}
+
+/* KVC */
+
+/* access the arguments with key "arg<element position>"
+   e.g. 'arg0' for the first element
+*/
+
+- (int)_indexForKey:(NSString *)_key {
+  NSString *prefix;
+
+  prefix = @"arg";
+  
+  if(![_key hasPrefix:prefix])
+    return -1;
+  
+  return [[_key substringFromIndex:[prefix length]] intValue];
+}
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  int index;
+
+  if ((index = [self _indexForKey:_key]) != -1)
+    [self setArgument:_value atIndex:index];
+}
+
+- (id)valueForKey:(NSString *)_key {
+  int index;
+
+  if ((index = [self _indexForKey:_key]) != -1)
+    return [self argumentAtIndex:index];
+
+  return nil;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  [ms appendFormat:@" %@", self->methodName];
+  if (self->arguments)
+    [ms appendFormat:@" #args=%i", [self->arguments count]];
+  else
+    [ms appendString:@" no-args"];
+  if (self->lastException)
+    [ms appendString:@" exception-is-set"];
+  if (self->result)
+    [ms appendString:@" result-is-set"];
+  if (self->signature == nil)
+    [ms appendString:@" no-signature"];
+  else {
+    [ms appendFormat:@" signature=%@",
+          [[self->signature xmlRpcTypes]
+                            componentsJoinedByString:@","]];
+    if ([self->signature isOneway])
+      [ms appendString:@" oneway"];
+  }
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SxComponentInvocation */
diff --git a/skyrix-sope/SxComponents/SxComponentMethodSignature.h b/skyrix-sope/SxComponents/SxComponentMethodSignature.h
new file mode 100644 (file)
index 0000000..278072a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SxComponentMethodSignature_H__
+#define __SxComponentMethodSignature_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+  XML-RPC types:
+    string
+    i4
+    base64
+    datetime
+*/
+
+@class NSArray;
+
+@interface SxComponentMethodSignature : NSObject
+{
+  NSArray *signature;
+}
+
++ (id)signatureWithXmlRpcTypes:(NSArray *)_args;
+- (id)initWithXmlRpcTypes:(NSArray *)_arg;
+
+/* accessors */
+
+- (unsigned)numberOfArguments;
+- (NSString *)argumentTypeAtIndex:(unsigned int)_idx;
+- (NSString *)methodReturnType;
+- (BOOL)isOneway;
+
+- (NSArray *)xmlRpcTypes;
+
+@end
+
+#endif /* __SxComponentMethodSignature_H__ */
diff --git a/skyrix-sope/SxComponents/SxComponentMethodSignature.m b/skyrix-sope/SxComponents/SxComponentMethodSignature.m
new file mode 100644 (file)
index 0000000..f271b5c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$ //
+
+#include "SxComponentMethodSignature.h"
+#include "common.h"
+
+@implementation SxComponentMethodSignature
+
++ (id)signatureWithXmlRpcTypes:(NSArray *)_args {
+  return [[[self alloc] initWithXmlRpcTypes:_args] autorelease];
+}
+- (id)initWithXmlRpcTypes:(NSArray *)_arg {
+  if ([_arg count] < 1) {
+    RELEASE(self);
+    return nil;
+  }
+  self->signature = [_arg copy];
+  return self;
+}
+- (id)init {
+  return [self initWithXmlRpcTypes:nil];
+}
+
+- (unsigned)numberOfArguments {
+  return ([self->signature count] - 1);
+}
+
+- (NSString *)argumentTypeAtIndex:(unsigned int)_idx {
+  return [self->signature objectAtIndex:(_idx + 1)];
+}
+
+- (NSString *)methodReturnType {
+  return [self->signature objectAtIndex:0];
+}
+
+- (BOOL)isOneway {
+  return NO;
+}
+
+- (NSArray *)xmlRpcTypes {
+  return self->signature;
+}
+
+@end /* SxComponentMethodSignature */
diff --git a/skyrix-sope/SxComponents/SxComponentRegistry.h b/skyrix-sope/SxComponents/SxComponentRegistry.h
new file mode 100644 (file)
index 0000000..0df040b
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SxComponentRegistry_H__
+#define __SxComponentRegistry_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSMapTable.h>
+#include <SxComponents/SxComponent.h>
+
+/*
+  This object is the client of the SandStorm/SKYRiX registry service.
+
+  Query any component you like by using
+    - (SxComponent *)getComponent:(NSString *)_namespace;
+  
+  eg:
+    SxComponent *c;
+    c = [[SxComponentRegistry defaultComponentRegistry]
+                              getComponent:@"com.skyrix.accounts"];
+    NSLog(@"Methods: ", [c call:@"system.listMethods", nil]);
+
+  A registry can have multiple registry backends, probably most
+  important/useful is the XML-RPC one implementing the SandStorm
+  registry interface.
+*/
+
+@class NSArray, NSMutableArray, NSMutableDictionary;
+
+@interface SxComponentRegistry : NSObject < NSCoding >
+{
+  NSArray             *backends;
+  NSMapTable          *lookupCache;
+  NSMutableArray      *credentials;
+  NSMutableDictionary *listMethodsCache;
+  NSMutableDictionary *methodSignatureCache;
+}
+
++ (id)defaultComponentRegistry;
+
+/* getting components */
+
+- (id<NSObject,SxComponent>)getComponent:(NSString *)_namespace;
+
+/* returns the names of the available components */
+
+- (NSArray *)listComponents:(NSString *)_prefix;
+- (NSArray *)listComponents;
+
+/* component registration */
+
+- (BOOL)registerComponent:(SxComponent *)_component;
+- (BOOL)unregisterComponent:(SxComponent *)_component;
+
+/* introspection methods */
+- (NSArray *)listMethods:(NSString *)_component;
+- (NSArray *)methodSignature:(NSString *)_component method:(NSString *)_name;
+- (NSString *)methodHelp:(NSString *)_component method:(NSString *)_name;
+
+/* component retries on error (failover) */
+
+- (int)componentRetryCountOnError;
+- (int)componentRetryTime;
+
+/* caching */
+
+- (SxComponent *)getCachedComponent:(NSString *)_namespace;
+- (void)flush;
+
+/* credentials */
+
+- (NSArray *)credentials;
+- (void)addCredentials:(id)_creds;
+
+@end
+
+@protocol SxComponentRegistryBackend
+
+- (BOOL)registry:(id)_registry canHandleNamespace:(NSString *)_prefix;
+- (NSArray *)registry:(id)_registry listComponents:(NSString *)_prefix;
+- (SxComponent *)registry:(id)_registry getComponent:(NSString *)_cname;
+
+- (NSArray *)registry:(id)_registry listMethods:(NSString *)_cname;
+- (NSArray *)registry:(id)_registry methodSignature:(NSString *)_component
+               method:(NSString *)_name;
+- (NSString *)registry:(id)_registry methodHelp:(NSString *)_component
+               method:(NSString *)_name;
+
+- (BOOL)canHandleComponent:(SxComponent *)_component;
+- (BOOL)registerComponent:(SxComponent *)_component;
+- (BOOL)unregisterComponent:(SxComponent *)_component;
+
+@end
+
+#endif /* __SxComponentRegistry_H__ */
diff --git a/skyrix-sope/SxComponents/SxComponentRegistry.m b/skyrix-sope/SxComponents/SxComponentRegistry.m
new file mode 100644 (file)
index 0000000..88f208b
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SxComponentRegistry.h"
+#include "SxComponent.h"
+#include "common.h"
+
+@implementation SxComponentRegistry
+
+static SxComponentRegistry *defreg = nil;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (!didInit) {
+    NSDictionary *defs;
+    didInit = YES;
+
+    defs = [NSDictionary dictionaryWithObjectsAndKeys:
+                         [NSArray arrayWithObject:@"SxXmlRpcRegBackend"],
+                         @"SxComponentRegistryBackends",
+                         [NSNumber numberWithInt:3],
+                         @"SxComponentRetriesOnError",
+                         [NSNumber numberWithInt:5],
+                         @"SxComponentRetryTime",
+                         nil];
+    [[NSUserDefaults standardUserDefaults] registerDefaults:defs];
+  }
+}
++ (NSArray *)defaultRegistryBackends {
+  return [[NSUserDefaults standardUserDefaults]
+                          arrayForKey:@"SxComponentRegistryBackends"];
+}
+
++ (id)defaultComponentRegistry {
+  if (defreg == nil) {
+    // THREAD
+    defreg = [[SxComponentRegistry alloc] init];
+  }
+  return defreg;
+}
+
+- (id)initWithBackends:(NSArray *)_backends { /* designated initializer */
+  self->credentials = [[NSMutableArray alloc] initWithCapacity:4];
+  self->backends    = [_backends shallowCopy];
+  self->listMethodsCache = [[NSMutableDictionary alloc] initWithCapacity:64];
+  self->methodSignatureCache =
+    [[NSMutableDictionary alloc] initWithCapacity:256];
+  return self;
+}
+
+- (id)initWithBackendClassNames:(NSArray *)_beClasses {
+  NSEnumerator   *e;
+  NSString       *beClassName;
+  NSMutableArray *bes;
+  
+  /* load backends */
+
+  bes = [NSMutableArray arrayWithCapacity:[_beClasses count]];
+  e   = [_beClasses objectEnumerator];
+  while ((beClassName = [e nextObject])) {
+    Class beClass;
+    id be;
+    
+    if ((beClass = NSClassFromString(beClassName)) == Nil) {
+      [self logWithFormat:@"did not find backend class '%@'", beClassName];
+      continue;
+    }
+    
+    if ((be = [[beClass alloc] init])) {
+      [bes addObject:be];
+      RELEASE(be);
+    }
+    else {
+      [self logWithFormat:@"backend of class %@ wasn't initialized ...",
+              NSStringFromClass(beClass)];
+    }
+  }
+  
+  return [self initWithBackends:bes];
+}
+- (id)init {
+  return [self initWithBackendClassNames:
+                 [[self class] defaultRegistryBackends]];
+}
+
+- (void)dealloc {
+  RELEASE(self->methodSignatureCache);
+  RELEASE(self->listMethodsCache);
+  RELEASE(self->backends);
+  RELEASE(self->credentials);
+  
+  if (self->lookupCache) {
+    NSFreeMapTable(self->lookupCache);
+    self->lookupCache = NULL;
+  }
+  [super dealloc];
+}
+
+/* callbacks */
+
+- (void)_componentWillDealloc:(SxComponent *)_c {
+  if (self->lookupCache)
+    NSMapRemove(self->lookupCache, [_c componentName]);
+}
+
+- (void)_removeComponentFromLookupCache:(NSString *)_cname {
+  if (self->lookupCache)
+    NSMapRemove(self->lookupCache, _cname);
+}
+
+/* getting components */
+
+- (id<NSObject,SxComponent>)getComponent:(NSString *)_namespace {
+  NSAutoreleasePool *pool;
+  SxComponent *c;
+  NSEnumerator *e;
+  id           backend;
+  
+  if (self->lookupCache == NULL) {
+    self->lookupCache = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                         NSNonRetainedObjectMapValueCallBacks,
+                                         64);
+  }
+  
+  if ((c = NSMapGet(self->lookupCache, _namespace))) {
+    return c;
+  }
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  e = [self->backends objectEnumerator];
+
+  while((backend = [e nextObject])) {
+    if ([backend registry:self canHandleNamespace:_namespace]) {
+      c = [backend registry:self getComponent:_namespace];
+      break;
+    }
+  }
+
+  if (c) NSMapInsert(self->lookupCache, [c componentName], c);
+  
+  RETAIN(c);
+  RELEASE(pool);
+
+  return AUTORELEASE(c);
+}
+
+/* returns the names of the available components */
+
+- (NSArray *)listComponents:(NSString *)_path {
+  NSMutableArray *results;
+  NSEnumerator *e;
+  id backend;
+  
+  results = nil;
+  e = [self->backends objectEnumerator];
+  while ((backend = [e nextObject])) {
+    NSArray *r;
+    
+    if ((r = [backend registry:self listComponents:_path])) {
+      if (results == nil)
+        results = [NSMutableArray arrayWithCapacity:128];
+      [results addObjectsFromArray:r];
+    }
+  }
+  return results;
+}
+- (NSArray *)listComponents {
+  return [self listComponents:nil];
+}
+
+- (NSArray *)listMethods:(NSString *)_component {
+  NSEnumerator *e;
+  id           backend;
+  NSArray      *result;
+
+  if ([_component length] == 0)
+    return nil;
+
+  /* check cache */
+  if ((result = [self->listMethodsCache objectForKey:_component]))
+    return AUTORELEASE(RETAIN(result));
+
+  /* let backends make reflection */
+  e = [self->backends objectEnumerator];
+  while((backend = [e nextObject])) {
+    if ([backend registry:self canHandleNamespace:_component]) {
+      result = [backend registry:self listMethods:_component];
+      break;
+    }
+  }
+
+  /* store in cache */
+  if (result)
+    [self->listMethodsCache setObject:result forKey:_component];
+  
+  return result;
+}
+
+- (NSArray *)methodSignature:(NSString *)_component method:(NSString *)_name {
+  NSEnumerator *e;
+  id           backend;
+  NSString     *key;
+  NSArray      *result;
+
+  /* check cache */
+  key = [NSString stringWithFormat:@"%@\n%@", _name, _component];
+  if ((result = [self->methodSignatureCache objectForKey:key]))
+    return AUTORELEASE(RETAIN(result));
+
+  /* perform operation */
+  e = [self->backends objectEnumerator];
+  while((backend = [e nextObject])) {
+    if ([backend registry:self canHandleNamespace:_component]) {
+      result = [backend registry:self methodSignature:_component method:_name];
+      break;
+    }
+  }
+
+  /* store in cache */
+  if (result)
+    [self->methodSignatureCache setObject:result forKey:key];
+  
+  return result;
+}
+
+- (NSString *)methodHelp:(NSString *)_component method:(NSString *)_name {
+  NSEnumerator *e;
+  id           backend;
+
+  e = [self->backends objectEnumerator];
+  
+  while((backend = [e nextObject])) {
+    if ([backend registry:self canHandleNamespace:_component]) {
+      return [backend registry:self methodHelp:_component method:_name];
+    }
+  }
+  return nil;
+}
+
+/* component registration */
+
+- (BOOL)registerComponent:(SxComponent *)_component {
+  if (_component == nil) return YES;
+  return NO;
+}
+- (BOOL)unregisterComponent:(SxComponent *)_component {
+  if (_component == nil) return YES;
+  return NO;
+}
+
+/* caching */
+
+- (SxComponent *)getCachedComponent:(NSString *)_namespace {
+  if (self->lookupCache == NULL) return nil;
+  return NSMapGet(self->lookupCache, _namespace);
+}
+- (void)flush {
+  if (self->lookupCache)
+    NSResetMapTable(self->lookupCache);
+  
+  [self->listMethodsCache     removeAllObjects];
+  [self->methodSignatureCache removeAllObjects];
+}
+
+/* component retries on error (failover) */
+
+- (NSUserDefaults *)userDefaults {
+  return [NSUserDefaults standardUserDefaults];
+}
+
+- (int)componentRetryCountOnError {
+  return [[[self userDefaults]
+                 valueForKey:@"SxComponentRetriesOnError"]
+                 intValue];
+}
+
+- (int)componentRetryTime {
+  return [[[self userDefaults]
+                 valueForKey:@"SxComponentRetryTime"]
+                 intValue];
+}
+
+/* credentials */
+
+- (NSArray *)credentials {
+  return self->credentials;
+}
+
+- (void)addCredentials:(id)_creds {
+  if (_creds == nil) {
+    [self logWithFormat:@"warning: passed <nil> to -addCredentials: ..."];
+    return;
+  }
+
+  [self->credentials addObject:_creds];
+}
+- (void)removeCredentials:(id)_creds {
+  [self->credentials removeObject:_creds];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [_coder encodeObject:self->backends];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  self->credentials = [[NSMutableArray alloc] initWithCapacity:4];
+  self->backends = [[_coder decodeObject] retain];
+  return self;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<0x%08X[%@]: backends=%@>",
+                     self, NSStringFromClass([self class]),
+                     self->backends];
+}
+
+@end /* SxComponentRegistry */
diff --git a/skyrix-sope/SxComponents/SxComponents.h b/skyrix-sope/SxComponents/SxComponents.h
new file mode 100644 (file)
index 0000000..98d4abb
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SxComponents_H__
+#define __SxComponents_H__
+
+#include <SxComponents/SxComponentRegistry.h>
+#include <SxComponents/SxComponent.h>
+#include <SxComponents/SxComponentInvocation.h>
+#include <SxComponents/SxComponentMethodSignature.h>
+#include <SxComponents/SxComponentException.h>
+
+#include <SxComponents/SxBasicAuthCredentials.h>
+
+#endif /* __SxComponents_H__ */
diff --git a/skyrix-sope/SxComponents/SxXmlRpcComponent.h b/skyrix-sope/SxComponents/SxXmlRpcComponent.h
new file mode 100644 (file)
index 0000000..f1922ad
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SxXmlRpcComponent_H__
+#define __SxXmlRpcComponent_H__
+
+#include <SxComponents/SxComponent.h>
+
+/*
+  A proxy object for a remote component accessible via
+  XML-RPC :-)
+*/
+
+@class NSURL, NSDictionary, NSMutableDictionary;
+@class NGXmlRpcClient;
+@class WOHTTPConnection;
+
+@interface SxXmlRpcComponent : SxComponent
+{
+  WOHTTPConnection    *httpConnection;
+  NSURL               *url;
+  NSMutableDictionary *signatureCache;
+  id                  lastCredentials;
+
+  int                 retryCnt;
+}
+
+/* initialization */
+
+- (id)initWithName:(NSString *)_name
+  registry:(SxComponentRegistry *)_registry
+  url:(NSURL *)_url;
+
+- (id)initWithName:(NSString *)_name
+  namespace:(NSString *)_namespace
+  registry:(SxComponentRegistry *)_registry
+  url:(NSURL *)_url;
+
+/* accessors */
+
+- (WOHTTPConnection *)httpConnection;
+- (NSURL *)url;
+
+- (void)addSuccessfulCredentials:(id)_creds;
+
+/* actions */
+
+- (id)call:(NSString *)_methodName arguments:(NSArray *)_params;
+
+@end
+
+#endif /* __SxXmlRpcComponent_H__ */
diff --git a/skyrix-sope/SxComponents/SxXmlRpcComponent.m b/skyrix-sope/SxComponents/SxXmlRpcComponent.m
new file mode 100644 (file)
index 0000000..f4e3f76
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SxXmlRpcComponent.h"
+#include "SxComponentRegistry.h"
+#include "SxComponentMethodSignature.h"
+#include "SxXmlRpcInvocation.h"
+#include "SxComponentException.h"
+#include <XmlRpc/NSObject+XmlRpc.h>
+#include <NGXmlRpc/NGXmlRpcClient.h>
+#include <NGObjWeb/WOHTTPConnection.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGStreams/NGSocketExceptions.h>
+#include "common.h"
+
+#include <unistd.h>
+
+@interface SxComponentRegistry(RemoveComponentFromCache)
+- (void)_removeComponentFromLookupCache:(NSString *)_cname;
+@end /* SxComponentRegistry(RemoveComponentFromCache) */
+
+@interface SxXmlRpcComponent(Privates)
+
+/* this method doesn't prepend component name ... */
+- (id)_call:(NSString *)_methodName arguments:(NSArray *)_params;
+
+@end
+
+@implementation SxXmlRpcComponent
+
++ (int)version {
+  return [super version] + 0 /* v1 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 1,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  registry:(SxComponentRegistry *)_registry
+  url:(NSURL *)_url
+{
+  return [self initWithName:_name
+               namespace:[[_name componentsSeparatedByString:@"."] lastObject]
+               registry:_registry
+               url:_url];
+}
+
+- (id)initWithName:(NSString *)_name
+  namespace:(NSString *)_namespace
+  registry:(SxComponentRegistry *)_registry
+  url:(NSURL *)_url
+{
+  if ((self = [self initWithName:_name namespace:_namespace
+                    registry:_registry])) {
+    self->url = [_url copy];
+    self->httpConnection =
+      [[WOHTTPConnection alloc] initWithHost:[_url host]
+                                onPort:[[_url port] intValue]];
+
+    self->retryCnt = 0;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->lastCredentials release];
+  [self->signatureCache  release];
+  [self->httpConnection  release];
+  [self->url             release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)uri {
+  return [self->url path];
+}
+
+- (WOHTTPConnection *)httpConnection {
+  return self->httpConnection;
+}
+
+- (NSURL *)url {
+  return self->url;
+}
+
+- (void)addSuccessfulCredentials:(id)_creds {
+  ASSIGN(self->lastCredentials, _creds);
+}
+
+- (NSString *)fqMethodNameForMethod:(NSString *)_method {
+  NSString *ns;
+
+  if (![_method hasPrefix:@"system."]) {
+    if ((ns = [self namespace]) != nil) {
+      return [[ns stringByAppendingString:@"."]
+                  stringByAppendingString:_method];
+    }
+  }
+  return _method;
+}
+
+/* operations */
+
+- (Class)invocationClass {
+  static Class CompInv = Nil;
+  if (CompInv == Nil) CompInv = [SxXmlRpcInvocation class];
+  return CompInv;
+}
+
+- (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method
+  methodSignature:(SxComponentMethodSignature *)_signature
+{
+  /*
+    Overridden to add the last successful credentials to newly created
+    invocation objects.
+  */
+  SxComponentInvocation *inv;
+  
+  inv = [super invocationForMethodNamed:_method
+               methodSignature:_signature];
+  [inv setCredentials:self->lastCredentials];
+  return inv;
+}
+
+- (NSArray *)signaturesForMethodNamed:(NSString *)_method {
+  NSMutableArray *result;
+  NSArray        *signatures;
+  NSString       *fqMethodName;
+  int i;
+  
+  [self resetLastException];
+  
+  if ([_method length] == 0)
+    return nil;
+  
+  if ((signatures = [self->signatureCache objectForKey:_method]))
+    return [signatures isNotNull] ? signatures : nil;
+
+  fqMethodName = [self fqMethodNameForMethod:_method];
+
+  signatures = [self _call:@"system.methodSignature"
+                     arguments:[NSArray arrayWithObject:fqMethodName]];
+  
+  if ([self lastCallFailed]) {
+    NSException *e;
+    
+    e = [self lastException];
+    [self logWithFormat:@"%s: couldn't get method signature:\n"
+            @"  method: %@\n"
+            @"  name:   %@ (class=%@)\n"
+            @"  reason: %@",
+            __PRETTY_FUNCTION__, _method,
+            NSStringFromClass([e class]), [e name], [e reason]];
+    return nil;
+  }
+  
+  if (![signatures isKindOfClass:[NSArray class]]) {
+    NSException *e;
+    
+    e = [NSException exceptionWithName:@"InvalidXmlRpcResult"
+                     reason:@"system.methodSignature did not return an array"
+                     userInfo:nil];
+    
+    [self logWithFormat:
+            @"system.methodSignature didn't return an array: '%@'<%@>",
+            signatures, NSStringFromClass([signatures class])];
+    
+    if (e) [self setLastException:e];
+    signatures = nil;
+    return nil;
+  }
+  
+  result = [NSMutableArray arrayWithCapacity:[signatures count]];
+  
+  for (i = 0; i < [signatures count]; i++) {
+    SxComponentMethodSignature *signature;
+    NSArray *bsig;
+    
+    bsig = [signatures objectAtIndex:i];
+    signature = [SxComponentMethodSignature signatureWithXmlRpcTypes:bsig];
+    [result addObject:signature];
+  }
+  
+  if (self->signatureCache == nil)
+    self->signatureCache = [[NSMutableDictionary alloc] initWithCapacity:32];
+  
+  [self->signatureCache
+       setObject:result?result:(id)[NSNull null]
+       forKey:_method];
+  
+  return result;
+}
+
+- (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method
+  arguments:(NSArray *)_args
+{
+  static NSArray *retType = nil;
+  SxComponentMethodSignature *sig;
+  SxXmlRpcInvocation *inv;
+  NSArray *xsig;
+  
+  if (retType == nil)
+    retType = [[NSArray alloc] initWithObjects:@"string", nil];
+  
+  xsig = [retType arrayByAddingObjectsFromArray:
+                    [_args xmlRpcElementSignature]];
+  sig = [[SxComponentMethodSignature alloc] initWithXmlRpcTypes:xsig];
+  
+  inv = (id)[self invocationForMethodNamed:_method
+                  methodSignature:sig];
+  [inv setArguments:_args];
+  
+  RELEASE(sig);
+  
+  return inv;
+}
+
+- (id)_call:(NSString *)_methodName arguments:(NSArray *)_params {
+  SxComponentInvocation *inv;
+  NSAutoreleasePool *pool;
+  NSException *e;
+  id result;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  [self resetLastException];
+
+  inv = [self invocationForMethodNamed:_methodName
+              arguments:_params];
+  
+  /* TODO: hh: invoke does not work yet fully, returns true on fail ... */
+  [inv invoke];
+  
+  if ((e = [inv lastException])) {
+    int retries;
+
+    retries = [[self componentRegistry] componentRetryCountOnError];
+
+    if (self->retryCnt < retries) {
+      if ([e isKindOfClass:[NGCouldNotConnectException class]]) {
+        SxXmlRpcComponent *tmpComp;
+        id compRegistry;
+
+        compRegistry = [self componentRegistry];
+        
+        [compRegistry _removeComponentFromLookupCache:[self componentName]];
+        tmpComp = (SxXmlRpcComponent *)
+          [compRegistry getComponent:[self componentName]];
+        
+        if (tmpComp) {
+          NSURL *tmpUrl;
+        
+          tmpUrl = [tmpComp url];
+        
+          [self->url            release]; self->url            = nil;
+          [self->httpConnection release]; self->httpConnection = nil;
+
+          self->url = RETAIN(tmpUrl);
+
+          self->httpConnection =
+            [[WOHTTPConnection alloc] initWithHost:[tmpUrl host]
+                                      onPort:[[tmpUrl port] intValue]];
+
+          NSLog(@"%s: trying once again (%d)....", __PRETTY_FUNCTION__,
+                self->retryCnt);
+
+          sleep(self->retryCnt*[[self componentRegistry] componentRetryTime]);
+          self->retryCnt++;
+          [self _call:_methodName arguments:_params];
+        }
+      }
+    }
+    else {
+      NSLog(@"%s: giving up....", __PRETTY_FUNCTION__);
+    }
+    
+    [self setLastException:e];
+    [inv resetLastException]; /* do this to avoid retain cycles ! */
+    
+    if ([e respondsToSelector:@selector(setInvocation:)])
+      [(id)e setInvocation:inv];
+  }
+
+  result = [inv returnValue];
+  self->retryCnt = 0;
+  
+  result = [result retain];
+  [pool release];
+  
+  return [result autorelease];
+}
+
+- (id)call:(NSString *)_methodName arguments:(NSArray *)_params {
+  return [self _call:_methodName arguments:_params];
+}
+
+- (id)asyncCall:(NSString *)_methodName arguments:(NSArray *)_args {
+  NSLog(@"%s: asyncCall(%@)", __PRETTY_FUNCTION__, _methodName);
+  return [self call:_methodName arguments:_args];
+}
+
+/* caching */
+
+- (void)flush {
+  [self->signatureCache removeAllObjects];
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [super encodeWithCoder:_coder];
+  [_coder encodeObject:self->httpConnection];
+  [_coder encodeObject:self->url];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  if ((self = [super initWithCoder:_coder])) {
+    self->httpConnection = [[_coder decodeObject] retain];
+    self->url            = [[_coder decodeObject] retain];
+  }
+  return self;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]: name=%@",
+        self, NSStringFromClass([self class]),
+        [self componentName]];
+  [ms appendFormat:@" url=%@", [self->url absoluteString]];
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* SxXmlRpcComponent */
diff --git a/skyrix-sope/SxComponents/SxXmlRpcInvocation.h b/skyrix-sope/SxComponents/SxXmlRpcInvocation.h
new file mode 100644 (file)
index 0000000..67b867e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SxXmlRpcInvocation_H__
+#define __SxXmlRpcInvocation_H__
+
+#include <SxComponents/SxComponentInvocation.h>
+
+/*
+  This class first converts the arguments to the proper
+  XML-RPC type as specified in the signature ...
+*/
+
+@class NSMutableArray;
+@class XmlRpcMethodCall;
+@class WORequest;
+@class SxXmlRpcComponent, SxXmlRpcTransaction;
+
+@interface SxXmlRpcInvocation : SxComponentInvocation
+{
+  /* transaction state */
+  SxXmlRpcTransaction *transaction;
+}
+
+@end
+
+#endif /* __SxXmlRpcInvocation_H__ */
diff --git a/skyrix-sope/SxComponents/SxXmlRpcInvocation.m b/skyrix-sope/SxComponents/SxXmlRpcInvocation.m
new file mode 100644 (file)
index 0000000..226584a
--- /dev/null
@@ -0,0 +1,766 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SxXmlRpcInvocation.h"
+#include "SxXmlRpcComponent.h"
+#include "SxComponentException.h"
+#include "SxBasicAuthCredentials.h"
+#include <NGXmlRpc/XmlRpcMethodCall+WO.h>
+#include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
+#include <SxComponents/SxComponentMethodSignature.h>
+#include <SxComponents/SxComponentRegistry.h>
+#include <NGObjWeb/NGObjWeb.h>
+#include <NGHttp/NGHttpHeaderFieldParser.h>
+#include "common.h"
+
+@interface NSObject(SxXmlRpcValue)
+- (NSArray *)asXmlRpcValueOfType:(NSString *)_type;
+@end
+
+@interface NSObject(HttpCredentials)
+
+- (BOOL)usableWithHttpResponse:(WOResponse *)_response;
+- (void)applyOnRequest:(WORequest *)_request;
+
+@end
+
+@interface SxXmlRpcInvocation(ErrorHandling)
+
+- (void)_setException:(NSString *)_name
+  reason:(NSString *)_reason
+  methodCall:(XmlRpcMethodCall *)_call;
+
+- (id)sendFailedForMethodCall:(XmlRpcMethodCall *)_call
+  exception:(NSException *)_exception;
+- (id)receiveFailedForMethodCall:(XmlRpcMethodCall *)_call;
+- (id)call:(XmlRpcMethodCall *)_call
+  failedWithResponse:(WOResponse *)_response;
+- (id)callFailedNoCredentials:(WOResponse *)_response;
+- (id)callFailedNoUsableCredentials:(WOResponse *)_response;
+- (id)handleCallExceptionResult:(NSException *)_exception;
+
+- (id)call:(XmlRpcMethodCall *)_call
+  invalidResultContentType:(WOResponse *)_response;
+  
+@end
+
+@interface SxXmlRpcInvocation(AsyncResult)
+
+- (void)resultReady:(id)_result;
+
+@end
+
+@interface SxXmlRpcInvocation(Creds)
+
+- (NSMutableArray *)_makeUsableCredentialsArrayForTarget:(id)_target
+  response:(WOResponse *)_response;
+- (void)_processSuccessfulCredentials:(id)_creds
+  forTarget:(SxXmlRpcComponent *)_target;
+
+@end
+
+@interface SxXmlRpcTransaction : NSObject
+{
+@public
+  SxXmlRpcInvocation *invocation;   /* non-retained */
+  id                 currentCreds;
+  XmlRpcMethodCall   *methodCall;
+  WORequest          *request;
+  SxXmlRpcComponent  *currentTarget;
+  NSMutableArray     *usableCreds;
+  unsigned           credIdx;
+  WOHTTPConnection   *httpConnection;
+}
+
+- (id)initWithMethod:(NSString *)_methodName
+  target:(SxXmlRpcComponent *)_target
+  arguments:(NSArray *)_params
+  forInvocation:(SxXmlRpcInvocation *)_inv;
+- (void)finish;
+
+- (BOOL)isAsyncResultPending;
+
+- (BOOL)sendFirstAsyncRequest;
+- (BOOL)sendNextRequest;
+- (WOResponse *)readResponse;
+
+- (void)processResponse:(WOResponse *)_response;
+
+@end
+
+@interface WOResponse(XmlRpcResponseType)
+
+- (BOOL)isXmlRpcResponse;
+
+@end
+
+@implementation WOResponse(XmlRpcResponseType)
+
+- (BOOL)isXmlRpcResponse {
+  NSString *ctype;
+  
+  ctype = [self headerForKey:@"content-type"];
+  
+  if ([ctype hasPrefix:@"text/xml"])
+    /* this is the expected/valid XML-RPC response content type ... */
+    return YES;
+
+  if ([ctype hasPrefix:@"text/"] || [ctype length] == 0) {
+    /* if the client send a text entity or no content-type, check the content */
+    NSData *data;
+    
+    data = [self content];
+    if ([data length] > 32) {
+      const unsigned char *bytes = [data bytes];
+      if (strncmp("<methodResponse>", bytes, 16) != 0)
+        return YES;
+    }
+  }
+  
+  return NO;
+}
+
+@end /* WOResponse(XmlRpcResponseType) */
+
+@implementation SxXmlRpcInvocation
+
+static NSNull *null = nil;
+
++ (int)version {
+  return [super version] + 0 /* v1 */;
+}
+
+- (void)dealloc {
+  RELEASE(self->transaction);
+  [super dealloc];
+}
+
+- (BOOL)isDebuggingEnabled {
+  static int debugOn = -1;
+  if (debugOn == -1) {
+    debugOn = [[[NSUserDefaults standardUserDefaults]
+                                objectForKey:@"SxXmlRpcInvocationDebug"]
+                                boolValue];
+  }
+  return debugOn ? YES : NO;
+}
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:
+                     @"XML-RPC Invocation[%@]", self->methodName];
+}
+
+- (NSArray *)argumentsForCall {
+  SxComponentMethodSignature *sig;
+  NSArray  *args;
+  unsigned count;
+  
+  if (null == nil) null = [[NSNull null] retain];
+  
+  sig = [self methodSignature];
+    
+  /* collect arguments, coerce types ... */
+  if ((count = [self->arguments count]) == 0) {
+    args = self->arguments;
+  }
+  else if (sig) {
+    unsigned i;
+    id *aa;
+      
+    aa = calloc(count, sizeof(id));
+    for (i = 0; i < count; i++) {
+      NSString *xrtype;
+      id value;
+      
+      xrtype = [sig argumentTypeAtIndex:i];
+        
+      value = [self->arguments objectAtIndex:i];
+      value = [value asXmlRpcValueOfType:xrtype];
+      aa[i] = value ? value : null;
+    }
+    args = [NSArray arrayWithObjects:aa count:count];
+    if (aa) free(aa);
+  }
+  else
+    args = self->arguments;
+  
+  return args;
+}
+
+- (NSArray *)credentialsUsableForComponent:(SxXmlRpcComponent *)_target {
+  /* select all credentials which respond to usableWithHttpResponse: ... */
+  NSMutableArray *ma;
+  NSArray        *creds;
+  NSEnumerator   *e;
+  id cred;
+  
+  creds = [[_target componentRegistry] credentials];
+  if ([creds count] == 0) {
+#if DEBUG
+    [self debugWithFormat:@"no credentials in registry %@ ...",
+            [_target componentRegistry]];
+#endif
+    return nil;
+  }
+  
+  ma = [NSMutableArray arrayWithCapacity:[creds count]];
+  e = [creds objectEnumerator];
+  while ((cred = [e nextObject])) {
+    if (![cred respondsToSelector:@selector(usableWithHttpResponse:)])
+      continue;
+    
+    [ma addObject:cred];
+  }
+#if DEBUG
+  [self debugWithFormat:@"found usable credentials in registry: %@ ...", ma];
+#endif
+  
+  return ma;
+}
+
+- (NSMutableArray *)_makeUsableCredentialsArrayForTarget:(id)_target
+  response:(WOResponse *)_response
+{
+  /*
+    fill 'usable' credentials array (you can store multiple login/pwds
+    for a single domain as a credential in the registry, and we will
+    test each credential for success ...)
+  */
+  NSMutableArray *lUsableCreds;
+  NSEnumerator   *e;
+  id             cred;
+  
+  lUsableCreds = [NSMutableArray arrayWithCapacity:8];
+  
+#if 1
+  /* check invocation credentials */
+  if (self->credentials) {
+    if ([self->credentials usableWithHttpResponse:_response])
+      [lUsableCreds addObject:self->credentials];
+    else
+      [self debugWithFormat:@"inv creds are not usable with response !"];
+  }
+#endif
+  
+  /* check registry credentials */
+  e = [[self credentialsUsableForComponent:_target] objectEnumerator];
+  while ((cred = [e nextObject])) {
+    if ([cred usableWithHttpResponse:_response])
+      [lUsableCreds addObject:cred];
+  }
+  
+  return lUsableCreds;
+}
+
+- (void)_processSuccessfulCredentials:(id)_creds
+  forTarget:(SxXmlRpcComponent *)_target
+{
+  /* the invocation credentials were used for authentication */
+  NSArray *regCreds;
+  
+  if (_creds == nil) return;
+  
+  [_target addSuccessfulCredentials:_creds];
+  
+  if (_creds == self->credentials) {
+    regCreds = [self credentialsUsableForComponent:_target];
+    
+    if (![regCreds containsObject:_creds] || regCreds == nil) {
+      /*
+        invocation credentials are not part of the registry creds,
+        automatically add them (should be configurable ?).
+      */
+      
+#if DEBUG
+      [self debugWithFormat:@"adding invocation credentials to registry .."];
+#endif
+      
+      [[_target componentRegistry] addCredentials:_creds];
+    }
+#if DEBUG
+    else {
+      [self debugWithFormat:
+              @"component credentials are already "
+              @"contained in the registry ..."];
+    }
+#endif
+  }
+}
+
+- (BOOL)beginTransactionForMethod:(NSString *)_methodName
+  onTarget:(SxXmlRpcComponent *)_target
+  arguments:(NSArray *)_params
+{
+  NSString *namespace;
+
+  if (self->transaction) {
+    NSLog(@"%s: transaction in progress ...", __PRETTY_FUNCTION__);
+    return NO;
+  }
+  
+  [self resetLastException];
+
+  if (![_methodName hasPrefix:@"system."]) {
+    if ((namespace = [_target namespace]) != nil) {
+      _methodName = [[namespace stringByAppendingString:@"."]
+                                stringByAppendingString:_methodName];
+    }
+  }
+  
+  self->transaction = [[SxXmlRpcTransaction alloc] initWithMethod:_methodName
+                                                  target:_target
+                                                  arguments:_params
+                                                  forInvocation:self];
+  return self->transaction ? YES : NO;
+}
+- (void)endTransaction {
+  [self->transaction finish];
+  ASSIGN(self->transaction, (id)nil);
+}
+
+- (id)_call:(NSString *)_methodName
+  onTarget:(SxXmlRpcComponent *)_target
+  arguments:(NSArray *)_params
+{
+#if DEBUG
+  [self debugWithFormat:@"invoking ..."];
+#endif
+
+  [self beginTransactionForMethod:_methodName
+       onTarget:_target
+       arguments:_params];
+  
+  do {
+    if ([self->transaction sendNextRequest]) {
+      WOResponse *response;
+  
+      response = [self->transaction readResponse];
+      [self->transaction processResponse:response];
+    }
+  }
+  while (self->transaction);
+  
+  [self endTransaction];
+  
+  return [self returnValue];
+}
+
+- (BOOL)invokeWithTarget:(SxComponent *)_target {
+  if ([self isAsyncResultPending]) {
+    NSLog(@"ERROR(%s): tried to invoke while tx is in progress !",
+         __PRETTY_FUNCTION__);
+    return NO;
+  }
+  
+  return [super invokeWithTarget:_target];
+}
+
+/* async result proxy implementation (invocation is passed back as result) */
+
+- (BOOL)isAsyncResultPending {
+  if (self->transaction == nil)
+    return NO;
+  return [self->transaction isAsyncResultPending];
+}
+- (id)asyncResult {
+  if ([self isAsyncResultPending])
+    return nil;
+  return [self returnValue];
+}
+- (BOOL)asyncCallFailed {
+  if ([self isAsyncResultPending])
+    return NO;
+  return self->lastException ? YES : NO;
+}
+
+/* async invoke */
+
+- (void)resultReady:(id)_result {
+  if ([_result isKindOfClass:[NSException class]]) {
+    [self setReturnValue:nil];
+    [self setLastException:_result];
+  }
+  else
+    [self setReturnValue:_result];
+  
+  [self endTransaction];
+  
+  [[self->target notificationCenter]
+    postNotificationName:SxAsyncResultReadyNotificationName
+    object:self];
+}
+
+- (BOOL)asyncInvoke {
+  if ([self isAsyncResultPending]) {
+    NSLog(@"ERROR(%s): tried to invoke while tx is in progress !",
+         __PRETTY_FUNCTION__);
+    return NO;
+  }
+  
+  [self beginTransactionForMethod:[self methodName]
+       onTarget:(id)self->target
+       arguments:[self argumentsForCall]];
+  
+  if ([self->transaction sendFirstAsyncRequest])
+    return YES;
+  
+  [self endTransaction];
+  return NO;
+}
+
+@end /* SxXmlRpcInvocation */
+
+@implementation SxXmlRpcInvocation(ErrorHandling)
+
+- (void)_setException:(NSString *)_name
+  reason:(NSString *)_reason
+  methodCall:(XmlRpcMethodCall *)_call
+{
+  NSException  *e;
+  NSDictionary *ui;
+  
+  ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                       _call, @"methodCall",
+                       nil];
+  e = [NSException exceptionWithName:_name
+                   reason:_reason
+                   userInfo:ui];
+  
+  [self debugWithFormat:@"EXCEPTION: %@", e];
+  [self setLastException:e];
+}
+
+- (id)sendFailedForMethodCall:(XmlRpcMethodCall *)_call
+  exception:(NSException *)_exception
+{
+  NSLog(@"%s: couldn't send XML-RPC call %@ via HTTP: %@",
+        __PRETTY_FUNCTION__, _call, _exception);
+  if (_exception)
+    [self setLastException:_exception];
+  else {
+    [self _setException:@"XmlRpcSendException"
+          reason:@"couldn't send XML-RPC request via HTTP"
+          methodCall:_call];
+  }
+  return nil;
+}
+- (id)receiveFailedForMethodCall:(XmlRpcMethodCall *)_call {
+  [self _setException:@"XmlRpcReceiveException"
+        reason:@"couldn't receive XML-RPC response via HTTP"
+        methodCall:_call];
+  return nil;
+}
+- (id)call:(XmlRpcMethodCall *)_call
+  failedWithResponse:(WOResponse *)_response
+{
+  NSLog(@"%s: XML-RPC response status: %i", __PRETTY_FUNCTION__,
+        [_response status]);
+  
+  if ([_response status] == 401) {
+    SxAuthException *exception;
+    
+    exception = [[SxAuthException alloc] init];
+    [self setLastException:exception];
+    RELEASE(exception);
+  }
+  else {
+    [self _setException:@"XmlRpcException"
+          reason:[_response contentAsString]
+          methodCall:_call];
+  }
+  return nil;
+}
+
+- (id)makeCredentialsTemplateUsableWithResponse:(WOResponse *)_response {
+  SxBasicAuthCredentials  *creds;
+  //NGMimeHeaderFieldParser *parser;
+  id authHeader;
+  
+  if ((authHeader = [_response headerForKey:@"www-authenticate"]) == nil) {
+    [self logWithFormat:@"missing www-authenticate header in 401 response !"];
+    return nil;
+  }
+  
+#warning detect realm ...
+  creds = [[SxBasicAuthCredentials alloc] init];
+  
+  return [creds autorelease];
+}
+- (id)callFailedNoCredentials:(WOResponse *)_response {
+  SxMissingCredentialsException *exception;
+  id creds;
+  
+  creds = [self makeCredentialsTemplateUsableWithResponse:_response];
+  
+  exception = [[SxMissingCredentialsException alloc] init];
+  [exception setCredentials:creds];
+  [self setLastException:exception];
+  [exception release];
+  return nil;
+}
+- (id)callFailedNoUsableCredentials:(WOResponse *)_response {
+  SxMissingCredentialsException *exception;
+  id creds;
+  
+  creds = [self makeCredentialsTemplateUsableWithResponse:_response];
+  
+  exception = [[SxInvalidCredentialsException alloc] init];
+  [exception setCredentials:creds];
+  [self setLastException:exception];
+  [exception release];
+  return nil;
+}
+
+- (id)handleCallExceptionResult:(NSException *)_exception {
+  [self setLastException:_exception];
+  return nil;
+}
+
+- (id)call:(XmlRpcMethodCall *)_call
+  invalidResultContentType:(WOResponse *)_response
+{
+  NSString *reason;
+  NSString *ctype;
+
+  ctype  = [_response headerForKey:@"content-type"];
+  reason = [NSString stringWithFormat:
+                       @"invalid content-type of XML-RPC response: "
+                       @"'%@' (XML-RPC requires text/xml !)", ctype];
+  [self _setException:@"XmlRpcException" reason:reason methodCall:_call];
+  return nil;
+}
+
+@end /* SxXmlRpcInvocation(ErrorHandling) */
+
+@implementation SxXmlRpcTransaction
+
+- (id)initWithMethod:(NSString *)_methodName
+  target:(SxXmlRpcComponent *)_target
+  arguments:(NSArray *)_params
+  forInvocation:(SxXmlRpcInvocation *)_inv
+{
+  self->invocation = _inv;
+  
+  self->currentTarget = RETAIN(_target);
+  self->methodCall = [[XmlRpcMethodCall alloc] 
+                      initWithMethodName:_methodName
+                      parameters:_params];
+  self->request = 
+    [[self->methodCall generateRequestWithUri:[[_target url] path]] retain];
+  
+  if ((self->httpConnection = [[_target httpConnection] retain]) == nil) {
+    RELEASE(self);
+    return nil;
+  }
+  
+  /* check first without credentials */
+  self->usableCreds  = nil;
+  self->currentCreds = [[self->invocation credentials] retain];
+  
+  return self;
+}
+
+- (void)finish {
+  self->invocation = nil;
+  ASSIGN(self->currentCreds,   (id)nil);
+  ASSIGN(self->methodCall,     (id)nil);
+  ASSIGN(self->request,        (id)nil);
+  ASSIGN(self->currentTarget,  (id)nil);
+  ASSIGN(self->httpConnection, (id)nil);
+  ASSIGN(self->usableCreds,    (id)nil);
+}
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [self finish];
+  [super dealloc];
+}
+
+- (BOOL)isDebuggingEnabled {
+  return [self->invocation isDebuggingEnabled];
+}
+
+- (BOOL)isAsyncResultPending {
+  return self->methodCall ? YES : NO;
+}
+
+- (void)resultReady:(id)_result {
+  /* if async, post notification ... */
+  ASSIGN(self->methodCall, (id)nil); // currently the marker ...
+  
+  [self->invocation resultReady:_result];
+}
+
+- (void)processOkResponse:(WOResponse *)_response {
+  XmlRpcMethodResponse *methodResponse;
+  id res;
+  
+  /* do post processing on successful credentials .. */
+  [self->invocation
+       _processSuccessfulCredentials:self->currentCreds 
+       forTarget:self->currentTarget];
+  
+  /* check whether returned body is XML-RPC ... */
+  if (![_response isXmlRpcResponse]) {
+    res = [self->invocation call:self->methodCall
+               invalidResultContentType:_response];
+    goto done;
+  }
+  
+  methodResponse = [[XmlRpcMethodResponse alloc] initWithResponse:_response];
+  res            = [methodResponse result];
+  
+  /* process faults */
+  if ([res isKindOfClass:[NSException class]])
+    res = [self->invocation handleCallExceptionResult:res];
+  
+  res = RETAIN(res);
+  RELEASE(methodResponse);
+  res = AUTORELEASE(res);
+  
+ done:
+  [self resultReady:res];
+}
+
+- (void)processAuthResponse:(WOResponse *)_response {
+  if (self->usableCreds == nil) {
+    self->credIdx = 0;
+    [self->usableCreds autorelease];
+    self->usableCreds =
+      [[self->invocation
+           _makeUsableCredentialsArrayForTarget:self->currentTarget
+           response:_response] retain];
+#if DEBUG
+    [self debugWithFormat:@"  usable credentials %@ ...", self->usableCreds];
+#endif
+    if ([self->usableCreds count] == 0) {
+      /* no credentials were found ... */
+      [self resultReady:[self->invocation callFailedNoCredentials:_response]];
+      return;
+    }
+  }
+      
+  /* go to next credentials */
+  if (self->credIdx >= [self->usableCreds count]) {
+    [self resultReady:[self->invocation callFailedNoUsableCredentials:_response]];
+    return;
+  }
+  
+  ASSIGN(self->currentCreds, [self->usableCreds objectAtIndex:self->credIdx]);
+  self->credIdx++;
+}
+
+- (void)processFailResponse:(WOResponse *)_response {
+  [self resultReady:[self->invocation call:self->methodCall
+                        failedWithResponse:_response]];
+}
+
+- (void)processResponse:(WOResponse *)_response {
+  if (_response == nil) {
+    [self resultReady:
+           [self->invocation receiveFailedForMethodCall:self->methodCall]];
+    return;
+  }
+
+#if DEBUG
+  [self debugWithFormat:@"  response status %i ...", [_response status]];
+#endif
+  
+  switch ([_response status]) {
+  case 200:
+    [self processOkResponse:_response];
+    break;
+  case 401:
+    [self processAuthResponse:_response];
+    break;
+  default:
+    [self processFailResponse:_response];
+    break;
+  }
+}
+
+- (void)_registerForNotification {
+  [[NSNotificationCenter defaultCenter] 
+    addObserver:self selector:@selector(responseAvailable:)
+    name:WOHTTPConnectionCanReadResponse object:self->httpConnection];
+}
+
+- (BOOL)sendNextRequest {
+  [self->currentCreds applyOnRequest:self->request];
+    
+  if (![self->httpConnection sendRequest:self->request]) {
+    [self resultReady:
+           [self->invocation sendFailedForMethodCall:self->methodCall
+                             exception:[self->httpConnection lastException]]];
+    return NO;
+  }
+  
+  return YES;
+}
+
+- (BOOL)sendFirstAsyncRequest {
+  [self _registerForNotification];
+  return [self sendNextRequest];
+}
+
+- (WOResponse *)readResponse {
+  return [self->httpConnection readResponse];
+}
+
+- (void)responseAvailable:(NSNotification *)_notification {
+  WOResponse *response;
+  
+#if DEBUG
+  [self debugWithFormat:@"  response available ..."];
+#endif
+
+  response = [self->httpConnection readResponse];
+
+#if DEBUG
+  [self debugWithFormat:@"  read response ..."];
+#endif
+  
+  AUTORELEASE(RETAIN(self));
+  [self processResponse:response];
+  
+  if ([self isAsyncResultPending]) {
+    /* send next request ... */
+#if DEBUG
+    [self debugWithFormat:@"  send next request ..."];
+#endif
+    [self sendNextRequest];
+  }
+  else {
+#if DEBUG
+    [self debugWithFormat:@"  result available ! ..."];
+#endif
+    //[self->invocation endTransaction];
+  }
+}
+
+/* description */
+
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:
+                     @"XML-RPC Tx[%@] 0x%08X", 
+                    [self->invocation methodName], self];
+}
+
+@end /* SxXmlRpcTransaction */
diff --git a/skyrix-sope/SxComponents/SxXmlRpcRegBackend.m b/skyrix-sope/SxComponents/SxXmlRpcRegBackend.m
new file mode 100644 (file)
index 0000000..6ee7d56
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <SxComponents/SxComponentRegistry.h>
+#include <SxComponents/SxComponentMethodSignature.h>
+#include "common.h"
+
+@class NGXmlRpcClient;
+
+@interface SxXmlRpcRegBackend : NSObject < SxComponentRegistryBackend >
+{
+  NGXmlRpcClient *registryServer;
+}
+
+@end
+
+#include "SxXmlRpcComponent.h"
+#import <NGXmlRpc/NGXmlRpcClient.h>
+
+@interface NSObject(AsUrl)
+- (NSURL *)asNSURL;
+@end
+
+@implementation SxXmlRpcRegBackend
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  NSDictionary   *defs;
+  
+  if (didInit) return;
+  didInit = YES;
+    
+  defs = [NSDictionary dictionaryWithObjectsAndKeys:
+                        @"http://127.0.0.1:14042/RPC2", 
+                        @"SxComponentRegistryURL",
+                      nil];
+  [ud registerDefaults:defs];
+}
+
++ (NSURL *)defaultRegistryURL {
+  NSString *s;
+  
+  s = [[NSUserDefaults standardUserDefaults]
+                       stringForKey:@"SxComponentRegistryURL"];
+  if ([s length] == 0)
+    return nil;
+  return [NSURL URLWithString:s];
+}
+
+- (id)initWithURL:(NSURL *)_url {
+  _url = [_url asNSURL];
+  if (_url == nil) {
+    [self release];
+    return nil;
+  }
+  self->registryServer = [[NGXmlRpcClient alloc] initWithURL:_url];
+  if (self->registryServer == nil) {
+    [self release];
+    return nil;
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithURL:[[self class] defaultRegistryURL]];
+}
+
+- (void)dealloc {
+  [self->registryServer release];
+  [super dealloc];
+}
+
+/* operations */
+
+- (BOOL)registry:(id)_registry canHandleNamespace:(NSString *)_prefix {
+  NSArray *supportedComponents = nil;
+  
+  supportedComponents = [self registry:_registry listComponents:@""];
+#if 0
+  [self logWithFormat:@"supported components : %@", supportedComponents];
+#endif
+  return [supportedComponents containsObject:_prefix];
+}
+
+- (BOOL)canHandleComponent:(SxComponent *)_component {
+  if (_component == nil) return NO;
+  if (![_component isKindOfClass:[SxXmlRpcComponent class]]) return NO;
+  return YES;
+}
+
+- (NSArray *)registry:(id)_registry listComponents:(NSString *)_prefix {
+  NSArray *result;
+  
+  result = [self->registryServer
+                invokeMethodNamed:@"active.registry.getComponents"];
+  if (result == nil)
+    return nil;
+  if ([result isKindOfClass:[NSException class]]) {
+    /* call failed */
+    [self logWithFormat:@"%s: component list failed: %@",
+            __PRETTY_FUNCTION__, result];
+    return nil;
+  }
+  else if ([result isKindOfClass:[NSDictionary class]]) {
+    /* call failed */
+    [self logWithFormat:@"%s: component list failed (got a dict?): %@",
+            __PRETTY_FUNCTION__, result];
+    return nil;
+  }
+  if (![result respondsToSelector:@selector(objectEnumerator)]) {
+    [self logWithFormat:@"%s: got invalid result: %@", __PRETTY_FUNCTION__,
+            result];
+    return nil;
+  }
+  
+  if ([_prefix length] == 0)
+    return result;
+  
+  /* limit search ... */
+  {
+    NSEnumerator *e;
+    NSString *k;
+    NSMutableArray *ma;
+
+    ma = nil;
+    e = [result objectEnumerator];
+    while ((k = [e nextObject])) {
+      if ([k hasPrefix:_prefix]) {
+        if (ma == nil)
+          ma = [NSMutableArray arrayWithCapacity:32];
+        [ma addObject:k];
+      }
+    }
+    result = ma;
+  }
+  
+  return result;
+}
+
+- (id)processInvalidResultType:(id)_result method:(NSString *)_name {
+  NSException  *exc;
+  NSDictionary *ui;
+  
+  ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                       _result,                            @"resultObject",
+                       NSStringFromClass([_result class]), @"resultClassName",
+                       nil];
+  
+  exc = [NSException exceptionWithName:@"SxRegistryIntrospectionError"
+                     reason:[_name stringByAppendingString:@" failed ..."]
+                     userInfo:ui];
+  
+  [self logWithFormat:@"WARNING(%@): got invalid result type !", _name];
+  return exc;
+}
+
+- (BOOL)isXmlRpcFault:(id)_object {
+  if ([_object isKindOfClass:[NSException class]])
+    return YES;
+  return NO;
+}
+
+- (NSArray *)registry:(id)_registry listMethods:(NSString *)_cname {
+  NSArray *res;
+  
+  res = [self->registryServer
+             invokeMethodNamed:@"active.registry.listComponentMethods"
+             parameters:[NSArray arrayWithObject:_cname]];
+  
+  if (res == nil) return nil;
+
+  if ([self isXmlRpcFault:res])
+    return res;
+  else if (![res isKindOfClass:[NSArray class]])
+    res = [self processInvalidResultType:res method:@"listMethods"];
+  
+  return res;
+}
+
+- (NSArray *)registry:(id)_registry methodSignature:(NSString *)_cname
+  method:(NSString *)_methods
+{
+  NSArray *sigs;
+  NSMutableArray *result;
+  NSEnumerator *sigEnum;
+  NSArray      *sigElem;
+
+  sigs =  [self->registryServer
+               invokeMethodNamed:@"active.registry.componentMethodSignatures"
+               parameters:[NSArray arrayWithObjects:_cname,_methods,nil]];
+  
+  if ([sigs isKindOfClass:[NSException class]])
+    return sigs;
+  else if (![sigs isKindOfClass:[NSArray class]])
+    return [self processInvalidResultType:sigs method:
+                 @"componentMethodSignatures"];
+  
+  sigEnum = [sigs objectEnumerator];
+  result = [NSMutableArray arrayWithCapacity:[sigs count]];
+  
+  while((sigElem = [sigEnum nextObject])) {
+    SxComponentMethodSignature *sig;
+
+    sig = [SxComponentMethodSignature signatureWithXmlRpcTypes:sigElem];
+    [result addObject:sig];
+  }
+  return result;
+}
+
+- (NSString *)registry:(id)_registry
+  methodHelp:(NSString *)_cname
+  method:(NSString *)_methods
+{
+  return [self->registryServer
+              invokeMethodNamed:@"active.registry.componentMethodHelp"
+              parameters:[NSArray arrayWithObjects:_cname,_methods,nil]];
+}
+
+- (SxComponent *)registry:(id)_registry getComponent:(NSString *)_cname {
+  NSDictionary      *res;
+  SxXmlRpcComponent *xc;
+  NSURL    *url;
+  NSString *s;
+  
+  res = [self->registryServer
+             invokeMethodNamed:@"active.registry.getComponentAndNamespace"
+             parameters:[NSArray arrayWithObject:_cname]];
+  
+  if (res == nil) return nil;
+  
+  if ([self isXmlRpcFault:res]) {
+    /* call failed */
+    NSLog(@"%s: component lookup failed: %@", __PRETTY_FUNCTION__, res);
+    return nil;
+  }
+  
+  if (![res isKindOfClass:[NSDictionary class]]) {
+    NSLog(@"%s: got invalid result: %@", __PRETTY_FUNCTION__, res);
+    return nil;
+  }
+
+  s = [NSString stringWithFormat:@"http://%@:%d%@",
+                  [res  objectForKey:@"host"],
+                  [[res objectForKey:@"port"] intValue],
+                  [res  objectForKey:@"uri"]];
+
+  if ((url = [NSURL URLWithString:s]) == nil) {
+    [self logWithFormat:@"didn't get a valid URL: '%@'", s];
+    return nil;
+  }
+  
+  xc =
+    [[SxXmlRpcComponent alloc] initWithName:_cname
+                               namespace:[res objectForKey:@"namespace"]
+                               registry:_registry
+                               url:url];
+  return AUTORELEASE(xc);
+}
+
+
+
+- (BOOL)removeComponent:(NSString *)_component {
+  id res;
+  
+  res = [self->registryServer
+             call:@"active.registry.removeComponent", _component, nil];
+  return [res boolValue];
+}
+
+- (BOOL)addComponent:(NSString *)_component url:(id)_url {
+  NSURL *url;
+
+  url = [_url asNSURL];
+  
+  return [[self->registryServer
+               call:@"active.registry.setComponent",
+                 _component, [url path], [url host], [url port], nil]
+               boolValue];
+}
+
+- (BOOL)registerComponent:(SxComponent *)_component {
+  SxXmlRpcComponent *xc;
+  
+  NSAssert([_component isKindOfClass:[SxXmlRpcComponent class]],
+           @"passed invalid component ...");
+  xc = (SxXmlRpcComponent *)_component;
+
+  return NO;
+}
+
+- (BOOL)unregisterComponent:(SxComponent *)_component {
+  SxXmlRpcComponent *xc;
+  
+  NSAssert([_component isKindOfClass:[SxXmlRpcComponent class]],
+           @"passed invalid component ...");
+  xc = (SxXmlRpcComponent *)_component;
+
+  return NO;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<0x%08X[%@]: server=%@>",
+                     self, NSStringFromClass([self class]),
+                     self->registryServer];
+}
+
+@end /* SxXmlRpcRegBackend */
+
+@implementation NSURL(AsUrl)
+
+- (NSURL *)asNSURL {
+  return self;
+}
+
+@end /* NSURL(AsUrl) */
+
+@implementation NSObject(AsUrl)
+
+- (NSURL *)asNSURL {
+  NSString *s;
+  s = [self stringValue];
+  if ([s length] == 0) return nil;
+  return [NSURL URLWithString:s];
+}
+
+@end /* NSURL(AsUrl) */
diff --git a/skyrix-sope/SxComponents/Version b/skyrix-sope/SxComponents/Version
new file mode 100644 (file)
index 0000000..9461bed
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=27
diff --git a/skyrix-sope/SxComponents/common.h b/skyrix-sope/SxComponents/common.h
new file mode 100644 (file)
index 0000000..272da07
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+
+#if !LIB_FOUNDATION_LIBRARY && !GNUSTEP_BASE_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#  include <NGExtensions/NGPropertyListParser.h>
+#  include <NGExtensions/NSString+Ext.h>
+#endif
+
+#include <EOControl/EOControl.h>
+#include <NGExtensions/NGExtensions.h>
diff --git a/skyrix-sope/SxComponents/sxc_call.m b/skyrix-sope/SxComponents/sxc_call.m
new file mode 100644 (file)
index 0000000..d49a6a4
--- /dev/null
@@ -0,0 +1,753 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "common.h"
+#include <SxComponents/SxComponentRegistry.h>
+#include <SxComponents/SxComponentMethodSignature.h>
+#include <SxComponents/SxComponentException.h>
+#include <SxComponents/SxComponentInvocation.h>
+#include <SxComponents/SxBasicAuthCredentials.h>
+#include <unistd.h>
+
+@interface App : NSObject
+{
+  int  nesting;
+  BOOL terminate;
+  BOOL errNewLine;
+}
+
+- (void)exit:(int)_code;
+- (void)printElement:(id)_element;
+
+- (void)printDictionary:(NSDictionary *)_dict;
+- (void)printArray:(NSArray *)_array;
+
+@end
+
+typedef enum {
+  EXIT_OK                = 0,
+  EXIT_MISSING_COMPONENT = 1,
+  EXIT_ARGCOUNT          = 2,
+  EXIT_EXCEPTION         = 3,
+  EXIT_COULD_NOT_LIST    = 4,
+  EXIT_NOSIGS_FOR_METHOD = 5,
+  EXIT_COULD_NOT_COERCE  = 6
+} AppExitCodes;
+
+@implementation NSObject(Printing)
+
+- (void)printWithTool:(App *)_tool {
+  printf("%s", [[self description] cString]);
+}
+
+@end
+
+@implementation NSData(Printing)
+
+- (void)printWithTool:(App *)_tool {
+  fwrite([self bytes], [self length], 1, stdout);
+}
+
+@end
+
+@implementation NSDictionary(Printing)
+
+- (void)printWithTool:(App *)_tool {
+  [_tool printDictionary:self];
+}
+
+@end
+
+@implementation NSArray(Printing)
+
+- (void)printWithTool:(App *)_tool {
+  [_tool printArray:self];
+}
+
+@end
+
+@implementation App
+
+- (void)help:(NSString *)pn {
+  fprintf(stderr,
+          "usage:    %s <component-name> [<method-name>] [<arg1>,...]\n"
+          "  sample: %s marvin.oracle.system bc 1 2\n"
+         " use special key <nil> or nil for creating NULL values\n"
+          ,[[pn lastPathComponent] cString], [[pn lastPathComponent] cString]);
+}
+
+- (void)logFail:(NSException *)e {
+  NSDictionary *ui;
+  NSString *reason;
+  id fault;
+  
+  if ([[e name] isEqualToString:@"SxInvalidCredentialsException"]) {
+    fprintf(stderr, "provided credentials are invalid.\n");
+    return;
+  }
+  
+  reason = [e reason];
+  ui     = [e userInfo];
+  
+  if ((fault = [ui valueForKey:@"faultCode"])) {
+    /* it's an XML-RPC fault (name is irrelevant ?) ... */
+    if ([reason length] > 0) {
+      fprintf(stderr, "fault[%i]: %s\n",
+             [fault intValue],
+             [reason cString]);
+    }
+    else {
+      fprintf(stderr, "fault[%i]\n", [fault intValue]);
+    }
+    return;
+  }
+  
+  NSLog(@"Call failed:\n"
+        @"  name:   %@", [e name]);
+  if ([reason length] > 0)
+    fprintf(stderr, "  reason: %s\n", [reason cString]);
+  if ([ui count] > 0)
+    fprintf(stderr, "  info:   %s\n", [[ui description] cString]);
+}
+
+/* printing objects */
+
+- (void)printDictionary:(NSDictionary *)_dict {
+  NSEnumerator *dictEnum;
+  id dictKey;
+  
+  dictEnum = [_dict keyEnumerator];
+  
+  while((dictKey = [dictEnum nextObject])) {
+    printf("%s=", [dictKey cString]);    
+    [self printElement:[_dict objectForKey:dictKey]];
+    printf("\n");
+  }
+}
+
+- (void)printArray:(NSArray *)_array {
+  NSEnumerator *arrayEnum;
+  id arrayElem;
+  
+  arrayEnum = [_array objectEnumerator];
+  while((arrayElem = [arrayEnum nextObject])) {
+    [self printElement:arrayElem];
+    printf("\n");
+  }
+}
+
+- (void)printElement:(id)element {
+  nesting++;
+  [element printWithTool:self];
+  nesting--;
+}
+
+- (void)printResult:(id)result {
+  [self printElement:result];
+}
+
+/* components */
+
+- (void)showComponent:(SxComponent *)_component {
+  NSEnumerator *mt;
+  NSString *m;
+
+  mt = [[[_component listMethods]
+                     sortedArrayUsingSelector:@selector(compare:)]
+                     objectEnumerator];
+  if (mt == nil) {
+    NSLog(@"couldn't list methods of component '%@'",
+          [_component componentName]);
+    [self exit:EXIT_COULD_NOT_LIST];
+  }
+  
+  printf("%s\n", [[_component componentName] cString]);
+  while ((m = [mt nextObject])) {
+    printf("  method %s\n", [m cString]);
+  }
+}
+
+- (void)exit:(int)_code {
+  exit(_code);
+}
+
+- (id)coerceBase64Argument:(id)_arg {
+  if([_arg isEqualToString:@"-"]) {
+    NSFileHandle *handle;
+    
+    handle = [NSFileHandle fileHandleWithStandardInput];
+    return [handle readDataToEndOfFile];
+  }
+  else {
+    if ([[NSFileManager defaultManager] fileExistsAtPath:_arg]) {
+      return [NSData dataWithContentsOfFile:_arg];
+    }
+    else {
+      [self logWithFormat:@"invalid input file %@", _arg];
+      return nil;
+    }
+  }
+}
+
+- (NSDictionary *)coerceStructArgument:(id)_arg {
+  NSEnumerator        *pairs;
+  NSMutableDictionary *md;
+  NSString *s;
+  NSDictionary *d;
+  
+  if ([_arg isKindOfClass:[NSDictionary class]])
+    return _arg;
+  
+  _arg = [_arg stringValue];
+  
+  /* try to process as property list first (most flexible) ... */
+  if ((d = [_arg propertyList])) {
+    if ([d isKindOfClass:[NSDictionary class]])
+      return d;
+  }
+  
+  /* process this syntax: "a=2,b=3,c=9" */
+
+  if ([_arg rangeOfString:@"="].length == 0)
+    /* not that syntax ... */
+    return _arg;
+  
+  pairs = [[_arg componentsSeparatedByString:@","] objectEnumerator];
+  md = [NSMutableDictionary dictionaryWithCapacity:16];
+    
+  while ((s = [pairs nextObject])) {
+    NSRange r;
+    NSString *key, *value;
+      
+    r = [s rangeOfString:@"="];
+    if (r.length == 0) {
+      md = nil;
+      break;
+    }
+    
+    key   = [s substringToIndex:r.location];
+    value = [s substringFromIndex:(r.location + r.length)];
+      
+    [md setObject:value forKey:key];
+  }
+  return md;
+}
+
+- (NSArray *)coerceArrayArgument:(id)_arg {
+  NSArray *a;
+  
+  if ([_arg isKindOfClass:[NSArray class]])
+    return _arg;
+
+  _arg = [_arg stringValue];
+
+  /* try to process as property list first (most flexible) ... */
+  if ((a = [_arg propertyList])) {
+    if ([a isKindOfClass:[NSArray class]])
+      return a;
+  }
+
+  /* process arg as comma separate list .. */
+  a = [_arg componentsSeparatedByString:@","];
+  
+  return _arg;
+}
+
+- (NSDate *)coerceDateArgument:(id)_arg {
+  NSCalendarDate *date;
+  static NSString *fmts[] = {
+    @"%Y%m%d%H%M%S%Z",
+    @"%Y%m%d%H%M%S",
+    @"%Y-%m-%d %H:%M:%S %Z",
+    @"%Y-%m-%d %H:%M:%S",
+    @"%Y%m%d",
+    @"%Y-%m-%d",
+    nil
+  };
+  int i;
+  
+  if ([_arg isKindOfClass:[NSDate class]])
+    return _arg;
+  
+  _arg = [_arg stringValue];
+  
+  if ([_arg isEqualToString:@"now"])
+    return [NSCalendarDate calendarDate];
+  if ([_arg isEqualToString:@"nil"])
+    return (id)[NSNull null];
+  
+  if ((date = [NSCalendarDate dateWithString:_arg]))
+    return date;
+  
+  for (i = 0; fmts[i]; i++) {
+    if ((date = [NSCalendarDate dateWithString:_arg calendarFormat:fmts[i]]))
+      return date;
+  }
+  
+  return date;
+}
+
+- (NSNumber *)coerceIntArgument:(id)_arg {
+  int i;
+  
+  if ((i = [_arg intValue]) == 0) {
+    if ([[_arg stringValue] isEqualToString:@"nil"])
+      return (id)[NSNull null];
+  }
+  return [NSNumber numberWithInt:i];
+}
+- (NSNumber *)coerceBoolArgument:(id)_arg {
+  return [NSNumber numberWithBool:[_arg boolValue]];
+}
+
+- (id)coerceArgument:(id)_arg forType:(NSString *)_type {
+  if ([_type isEqualToString:@"string"]) {
+    if ([_arg isKindOfClass:[NSString class]]) {
+      if ([_arg isEqualToString:@"<nil>"])
+       _arg = [NSNull null];
+    }
+    else
+      _arg = [_arg stringValue];
+  }
+  else if ([_type isEqualToString:@"base64"])
+    _arg = [self coerceBase64Argument:_arg];
+  else if ([_type isEqualToString:@"date"])
+    _arg = [self coerceDateArgument:_arg];
+  else if ([_type isEqualToString:@"int"] || [_type isEqualToString:@"i4"])
+    _arg = [self coerceIntArgument:_arg];
+  else if ([_type hasPrefix:@"bool"])
+    _arg = [self coerceBoolArgument:_arg];
+  else if ([_type hasPrefix:@"struct"])
+    _arg = [self coerceStructArgument:_arg];
+  else if ([_type hasPrefix:@"array"])
+    _arg = [self coerceArrayArgument:_arg];
+  else {
+    [self logWithFormat:@"WARNING: "
+           @"passing through argument '%@' for type %@",
+           _arg, _type];
+  }
+#if 0
+  NSLog(@"coerced %@ to %@ <%@>", 
+       _type, _arg, NSStringFromClass([_arg class]));
+#endif
+  return _arg;
+}
+
+- (NSArray *)coerceArguments:(NSArray *)_args
+  withSignatures:(NSArray *)_sigs
+{
+  NSEnumerator               *sigEnum;
+  SxComponentMethodSignature *signature;
+  NSMutableArray             *result;
+  int                        numberOfArguments;
+  int                        i;
+  
+  numberOfArguments = [_args count];
+  result = [NSMutableArray arrayWithCapacity:[_args count]];
+  
+  sigEnum = [_sigs objectEnumerator];
+  while((signature = [sigEnum nextObject])) {
+    if ([signature numberOfArguments] == numberOfArguments) {
+      break;
+    }
+  }
+
+  for (i = 0; i < [signature numberOfArguments]; i++) {
+    id object;
+
+    object = [self coerceArgument:[_args objectAtIndex:i]
+                   forType:[signature argumentTypeAtIndex:i]];
+    
+    if (object == nil) object = [NSNull null];
+    [result addObject:object];
+  }
+  
+  return result;
+}
+
+- (NSString *)prompt:(NSString *)_prompt {
+  NSString *login;
+  char clogin[256];
+  
+  printf("%s", [_prompt cString]);
+  fflush(stdout);
+  fgets(clogin, 200, stdin);
+  clogin[strlen(clogin) - 1] = '\0';
+  login = [NSString stringWithCString:clogin];
+  return login;
+}
+- (NSString *)promptPassword:(NSString *)_prompt {
+  NSString *pwd;
+  char     *cpwd;
+
+  cpwd = getpass("password: ");
+  pwd = [NSString stringWithCString:cpwd];
+  return pwd;
+}
+
+- (SxComponentRegistry *)registry {
+  return [SxComponentRegistry defaultComponentRegistry];
+}
+
+- (BOOL)_fillCredentials:(id)_creds {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  NSString *pwd, *login;
+  
+  login = [ud stringForKey:@"login"];
+  if ([login length] == 0)
+    login = [self prompt:@"login:    "];
+  if ([login length] == 0) return NO;
+  
+  pwd = [ud stringForKey:@"password"];
+  if (pwd == nil)
+    pwd = [self promptPassword:@"password: "];
+  
+  [_creds setCredentials:login password:pwd];
+  
+  return YES;
+}
+
+- (BOOL)runAsync {
+  static int async = -1;
+  if (async == -1)
+    async = [[NSUserDefaults standardUserDefaults] boolForKey:@"async"]? 1 : 0;
+  return async;
+}
+
+- (id)_waitForResult:(id)result {
+  if (![result isAsyncResultPending])
+    return result;
+  
+  while ([result isAsyncResultPending]) {
+    printf("#");
+    fflush(stdout);
+    sleep(1);
+  }
+  printf("\n");
+  NSLog(@"async result ready: %@", result);
+  return result;
+}
+
+- (void)resultReady:(NSNotification *)_notification {
+  /* called for async results ... */
+  SxComponentInvocation *inv;
+  NSException *e;
+  id result;
+  
+  //[self logWithFormat:@"result ready ..."];
+  
+  inv = [_notification object];
+  result = [inv returnValue];
+  
+  if ((e = [inv lastException]) == nil) {
+    result = [inv returnValue];
+    if (result == nil) {
+      [self logWithFormat:@"result is nil ..."];
+      self->terminate = YES;
+    }
+  }
+  else if ([e isCredentialsRequiredException]) {
+    /* authorization failed */
+    SxBasicAuthCredentials *creds;
+      
+    if ((creds = [(SxAuthException *)e credentials]) == nil) {
+      [self logWithFormat:@"no credentials to fill ..."];
+      self->terminate = YES;
+    }
+    else {
+      if (![self _fillCredentials:creds]) {
+       self->terminate = YES;
+      }
+      else {
+       [inv setCredentials:creds];
+#if 0
+       e = nil;
+       return;
+#else
+       if (![inv asyncInvoke]) {
+         NSLog(@"cred asyncInvoke failed ...");
+         self->terminate = YES;
+       }
+       else {
+         e = nil;
+         return;
+       }
+#endif
+      }
+    }
+  }
+  
+  if (self->errNewLine) {
+    fprintf(stderr, "\n");
+    fflush(stderr);
+    self->errNewLine = NO;
+  }
+  
+  if (result == nil && e == nil)
+    [self logWithFormat:@"both, exception and result are nil ??"];
+  
+  if (e) {
+    [self logFail:e];
+    [self exit:EXIT_EXCEPTION];
+  }
+  else {
+    [self printResult:result];
+    self->terminate = YES;
+  }
+}
+
+- (void)printProgress:(NSTimer *)_timer {
+  fprintf(stderr, "#");
+  fflush(stderr);
+  self->errNewLine = YES;
+}
+
+- (void)runAsyncMethod:(NSString *)_method
+  onComponent:(SxComponent *)component
+  withArguments:(NSArray *)_args
+{
+  SxComponentInvocation *inv;
+  NSException *e;
+  id          result;
+  NSTimer     *timer;
+  
+  terminate = NO;
+  
+  inv = [component invocationForMethodNamed:_method
+                   arguments:_args];
+
+  timer = [NSTimer scheduledTimerWithTimeInterval:1.0
+                  target:self selector:@selector(printProgress:)
+                  userInfo:nil repeats:YES];
+  
+  [[NSNotificationCenter defaultCenter]
+    addObserver:self selector:@selector(resultReady:)
+    name:SxAsyncResultReadyNotificationName object:inv];
+  
+  if (![inv asyncInvoke]) {
+    /* should check result ... */
+    [self logWithFormat:@"async invoke failed ..."];
+  }
+  else {
+    NSRunLoop *loop;
+    NSAutoreleasePool *pool;
+    
+    pool = [[NSAutoreleasePool alloc] init];
+    result = nil;
+    e      = nil;
+      
+    loop = [NSRunLoop currentRunLoop];
+    
+    do {
+      NSAutoreleasePool *pool2;
+      
+      pool2 = [[NSAutoreleasePool alloc] init];
+      {
+       NSDate *limitDate = nil;
+       
+       limitDate = [loop limitDateForMode:NSDefaultRunLoopMode];
+       [loop runMode:NSDefaultRunLoopMode beforeDate:limitDate];
+      }
+      RELEASE(pool2);
+    }
+    while (!self->terminate);
+    
+    RELEASE(pool);
+  }
+  
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)runMethod:(NSString *)_method
+  onComponent:(SxComponent *)component
+  withArguments:(NSArray *)_args
+{
+  SxComponentInvocation *inv;
+  NSException *e;
+  id result;
+
+  if ([self runAsync]) {
+    [self runAsyncMethod:_method onComponent:component withArguments:_args];
+    return;
+  }
+  
+#if 0
+  /* call method */
+  result = [component call:_method arguments:_args];
+  
+  e = result ? nil : [component lastException];
+  
+  /* check for missing auth */
+  while ([e isCredentialsRequiredException]) {
+    id creds;
+    
+    if ((inv = [(SxAuthException *)e invocation]) == nil) {
+      //[self logWithFormat:@"missing invocation !"];
+      break;
+    }
+    if ((creds = [(SxAuthException *)e credentials]) == nil) {
+      [self logWithFormat:@"missing credentials template !"];
+      break;
+    }
+    
+    if (![self _fillCredentials:creds])
+      break;
+    
+    [inv setCredentials:creds];
+    NSAssert([inv credentials] == creds, @"credentials lost ???");
+    
+    if (![inv invoke]) {
+      /* should check result ... */
+      //[self logWithFormat:@"invoke failed ..."];
+      e = [inv lastException];
+    }
+    else
+      e = nil;
+    result = [inv returnValue];
+  }
+  
+#else
+  /* now invoke ... */
+  
+  inv = [component invocationForMethodNamed:_method
+                   arguments:_args];
+  
+  do {
+    NSAutoreleasePool *pool;
+
+    pool = [[NSAutoreleasePool alloc] init];
+    result = nil;
+    e      = nil;
+    
+    if (![inv invoke]) {
+      /* should check result ... */
+      //[self logWithFormat:@"invoke failed ..."];
+    }
+    
+    if ((e = [inv lastException]) == nil) {
+      result = [inv returnValue];
+      if (result == nil) {
+        [self logWithFormat:@"result is nil ..."];
+        break;
+      }
+    }
+    else if ([e isCredentialsRequiredException]) {
+      /* authorization failed */
+      SxBasicAuthCredentials *creds;
+      
+      if ((creds = [(SxAuthException *)e credentials]) == nil) {
+        [self logWithFormat:@"no credentials to fill ..."];
+      }
+      else {
+        if (![self _fillCredentials:creds])
+          break;
+        [inv setCredentials:creds];
+        e = nil;
+      }
+    }
+    
+    RELEASE(pool);
+  }
+  while ((e == nil) && (result == nil));
+  
+#endif
+
+  if (result == nil && e == nil)
+    [self logWithFormat:@"both, exception and result are nil ??"];
+  
+  if (e) {
+    [self logFail:e];
+    [self exit:EXIT_EXCEPTION];
+  }
+  else {
+    [self printResult:result];
+  }
+}
+
+- (void)runWithArguments:(NSArray *)args {
+  SxComponentRegistry *reg;
+  SxComponent         *component;
+  NSArray  *rpcargs, *sigs;
+  NSString *mn;
+  
+  reg = [self registry];
+  
+  if ([args count] < 2) {
+    [self help:[args objectAtIndex:0]];
+    [self exit:EXIT_ARGCOUNT];
+  }
+  
+  /* lookup component */
+
+  if ((component = (SxComponent *)[reg getComponent:[args objectAtIndex:1]]) == nil) {
+    NSLog(@"did not find component named '%@'.",
+          [args objectAtIndex:1]);
+    [self exit:EXIT_MISSING_COMPONENT];
+  }
+  
+  if ([args count] == 2) {
+    /* do reflection */
+    [self showComponent:component];
+    [self exit:EXIT_OK];
+  }
+
+  /* make a call */
+  
+  mn = [args objectAtIndex:2];
+  sigs = [component signaturesForMethodNamed:mn];
+  if ([sigs count] == 0) {
+    [self logWithFormat:@"got no signatures for method: %@", mn];
+    [self exit:EXIT_NOSIGS_FOR_METHOD];
+    return;
+  }
+  
+  rpcargs = [args subarrayWithRange:NSMakeRange(3,[args count] - 3)];
+  rpcargs = [self coerceArguments:rpcargs withSignatures:sigs];
+  if (rpcargs == nil) {
+    [self logWithFormat:@"couldn't coerce arguments: %@", rpcargs];
+    [self exit:EXIT_COULD_NOT_COERCE];
+    return;
+  }
+  
+  [self runMethod:mn onComponent:component withArguments:rpcargs];
+}
+
+@end /* App */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  id app;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  app = [[App alloc] init];
+  [app runWithArguments:
+         [[NSProcessInfo processInfo] argumentsWithoutDefaults]];
+  [app release];
+  
+  RELEASE(pool);
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-sope/SxComponents/sxc_ls.m b/skyrix-sope/SxComponents/sxc_ls.m
new file mode 100644 (file)
index 0000000..e45ec97
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+#include <SxComponents/SxComponentRegistry.h>
+
+@interface SxcLsTool : NSObject
+- (int) runWithArguments: (NSArray*) _args;
+@end
+
+@implementation SxcLsTool
+
+- (void)list:(NSArray *)result indent:(int)indent {
+  NSEnumerator *e;
+  NSString *c;
+  
+  if (result == nil) {
+    fprintf(stderr, "got no result from registry !\n");
+    exit(2);
+    return;
+  }
+
+  if ([result isKindOfClass:[NSException class]]) {
+    NSLog(@"got excetpion: %@", result);
+    return;
+  }
+  else if ([result isKindOfClass:[NSDictionary class]]) {
+    NSLog(@"got dictionary: %@", result);
+    return;
+  }
+  
+  result = [result sortedArrayUsingSelector:@selector(compare:)];
+  
+  e = [result objectEnumerator];
+  while ((c = [e nextObject])) {
+    int i;
+    for (i = 0; i < indent; i++)
+      printf("  ");
+      
+    printf("%s\n", [c cString]);
+  }
+}
+
+- (int)runWithArguments:(NSArray *)_args {
+  SxComponentRegistry *reg;
+
+  reg = [SxComponentRegistry defaultComponentRegistry];
+  
+  if ([_args count] == 1) {
+    [self list:[reg listComponents] indent:0];
+  }
+  else {
+    NSEnumerator *e;
+    NSString *prefix;
+    
+    e = [_args objectEnumerator];
+    [e nextObject]; // cmd name
+    while ((prefix = [e nextObject])) {
+      printf("[%s]\n", [prefix cString]);
+      [self list:[reg listComponents:prefix] indent:1];
+    }
+  }
+  return 0;
+}
+
+@end
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  NSArray           *args;
+  int       exitCode;
+  SxcLsTool *tool;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  args = [[NSProcessInfo processInfo] argumentsWithoutDefaults];
+
+  tool = [[SxcLsTool alloc] init];
+  exitCode = [tool runWithArguments:args];
+  RELEASE(tool);
+  
+  RELEASE(pool);
+  exit(exitCode);
+  return exitCode;
+}
diff --git a/skyrix-sope/Version b/skyrix-sope/Version
new file mode 100644 (file)
index 0000000..8393deb
--- /dev/null
@@ -0,0 +1,7 @@
+# $Id$
+#
+# This file is included by library makefiles to set the version information 
+# of the executable.
+
+MAJOR_VERSION=4
+MINOR_VERSION=2
diff --git a/skyrix-sope/WEExtensions/.cvsignore b/skyrix-sope/WEExtensions/.cvsignore
new file mode 100644 (file)
index 0000000..bc9b159
--- /dev/null
@@ -0,0 +1,3 @@
+English.lproj
+WEExtensions.bundle
+shared_debug_obj
diff --git a/skyrix-sope/WEExtensions/COPYING b/skyrix-sope/WEExtensions/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/WEExtensions/COPYRIGHT b/skyrix-sope/WEExtensions/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-sope/WEExtensions/ChangeLog b/skyrix-sope/WEExtensions/ChangeLog
new file mode 100644 (file)
index 0000000..ab758a4
--- /dev/null
@@ -0,0 +1,763 @@
+2004-08-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * WECalendarField.m, WETimeField.m: minor code cleanups (v4.2.53)
+
+2004-08-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEWeekColumnView.m: added 'hideWeekend' association to disable
+         display of the Saturday/Sunday columns (v4.2.52)
+
+       * WEWeekOverview.m: added 'hideWeekend' association to disable display
+         of the Saturday/Sunday column, major code cleanups (v4.2.51)
+
+2004-07-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * common.h: fixed a gcc 3.4 warning (4.2.50)
+
+2004-07-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEDragContainer.m: minor code cleanups (v4.2.49)
+
+2004-07-02  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WETabView.m: avoid (auto)-creation of session (was used to check for
+         a JavaScript-available marker in the session) (v4.2.48)
+
+2004-06-24  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WETableCalcMatrix.m: fixed a bug in -dealloc which comes up in some
+         edge condition on MacOSX (v4.2.47)
+
+2004-06-24  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * WEMonthOverview.m: weekOfYear was always incremented by one,
+         regardless of year spillovers. (v4.2.46)
+
+2004-06-23  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * WEMonthOverview.m: added support for stylesheets (v4.2.45)
+
+2004-06-23  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WEMonthOverview.m: various code cleanups (v4.2.44)
+
+2004-06-23  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * WEMonthOverview.m: fixed OGo bug #326 (month printview showed 
+         incorrect week numbers)
+       
+2004-06-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.43
+
+       * GNUmakefile.preamble: added prebinding, fixed static dependencies for
+         OSX
+
+       * WETableCalcMatrix.m: code cleanups
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * JSMenu.h, JSMenuItem.h: added proper header protection (Note: those
+         elements are not compiled in gstep-make but in Xcode?) (v4.2.42)
+
+       * v4.2.41
+
+       * WETableCalcMatrix.m: minor code cleanups
+
+       * GNUmakefile.preamble: fixed relative search pathes
+
+2004-06-02  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile.preamble: more support for building with
+         GNUSTEP_BUILD_DIR environment variable set (v4.2.40)
+
+2004-05-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.39
+
+       * WEWeekOverview.m: fixed broken "</td" close tag (added missing '>')
+
+       * WEMonthOverview.m: fixed broken "</td" close tag (added missing '>'),
+         minor optimizations to -takeValuesFromRequest:
+
+2004-05-11  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WETableCalcMatrix.m: catch inits with 0/0 dimensions (was an assert,
+         now just prints a log) (v4.2.38)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.37)
+
+2004-05-05  Helge Hess  <helge.hess@skyrix.com>
+
+       * WETableView/WETableView.m: minor code cleanups (v4.2.36)
+
+       * v4.2.35
+
+       * WETableView/WETreeData.m: minor cleanups
+
+       * WETableView/WETableCell.m, WETableView/WETableView.m: improved XHTML
+         compatibility, some minor cleanups
+
+2004-04-26  Helge Hess  <helge.hess@skyrix.com>
+
+       * WETableView/WETableView+Grouping.m: fixed OGo bug #732 (release
+         error introduced in one of the last versions) (v4.2.34)
+
+2004-04-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.33
+       
+       * WExExtElemBuilder.m: generate WEPageLink for <var:pagelink> tag
+       
+       * added WEPageLink element for easier generation of component page 
+         links with parameters
+
+       * WECalendarField.m, JSShiftClick.m: minor code cleanups
+
+2004-04-07  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WEEpozEditor.m: fixed a compile warning on OSX (v4.2.32)
+
+2004-04-06  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WETableView/GNUmakefile (ADDITIONAL_INCLUDE_DIRS): fixed makefile for
+         "inline" compilation (thanks Luca for pointing that out) (v4.2.31)
+
+2004-04-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved WETableView to a subproject, moved WETableView classes to
+         separate files (v4.2.30)
+
+       * v4.2.29
+
+       * GNUmakefile: cleaned up makefile, created postamble makefile
+
+       * WEPageView.m: fixed a static variable init bug, improved XHTML
+         compatibility, major code cleanups
+
+       * WETableView.m: major code cleanups, changed behaviour with disabled
+         navigation buttons in tableviews, those are now hidden per default to
+         avoid screen clutter in small tableviews. Disabled buttons can still
+         be activated using the WETableView_showBlindNavigation default in
+         case you consider that better UI
+
+2004-03-31  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.28
+
+       * WExExtElemBuilder.m: create a WERedirect element for <var:redirect/>
+
+       * copied in old WORedirect dynamic element as "WERedirect" in case
+         someone actually uses that. The WORedirect will be a subclass of
+         WOComponent
+
+2004-03-24  Helge Hess  <helge.hess@skyrix.com>
+       
+       * v4.2.27
+
+       * WExExtElemBuilder.m: create WEQualifierConditional for "if-qualifier"
+         tag
+       
+       * added new WEQualifierConditional dynamic element
+       
+       * WESwitch.m: some code cleanups
+       
+2004-02-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WETableMatrix.m, WETableMatrixContent.m: fixed minor compilation
+         warnings on MacOSX (v4.2.26)
+
+2004-01-07  Helge Hess  <helge@groove.local>
+
+       * JSClipboard.m, JSMenu.m, WERichString.m: minor tweaks for MacOSX 
+         compilation (v4.2.25)
+
+2004-01-03  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.24
+
+       * WETableView.h: subminor cleanup
+
+       * WETabItem.m: minor cleanups
+
+2003-12-12  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WETreeView.m: fixed a memory leak, moved WETreeHeader, WETreeData and
+         WETreeMatrixElement classes to separate files, major cleanups
+         (v4.2.23)
+
+2003-11-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile: include makefiles from GNUSTEP_MAKEFILES (as suggested
+         by chunsj@embian.com (v4.2.22)
+
+2003-11-25  Helge Hess  <helge.hess@opengroupware.org>
+
+       * WEWeekOverview.m: added associations for attaching a CSS style class
+         to the view (v4.2.21)
+
+Tue Nov 11 16:27:30 2003  Martin Hoerning  <mh@skyrix.com>
+
+       * WEMonthOverview.m: fixed timeZone bug. timeZone details weren't 
+         forwarded to the date infos in the month-matrix.
+         (solves ogobug 110) (v4.2.20)
+
+2003-10-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * WECollapsibleComponentContent.m: small code cleanups, fixed some
+         XHTML issues (v4.2.19)
+
+2003-10-30  Thomas Schild  <ts@skyrix.com>
+
+       * WECollapsibleComponentContent.m: added client capabilities for
+         mozilla and netscape to generate javascript which adds the
+         hash part in requested url (v4.2.18)
+
+Tue Oct 28 14:51:21 2003  Jan Reichmann  <jr@skyrix.com>
+
+       * WEEpozEditor.m: add license text (v4.2.17) 
+
+2003-10-22  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEEpozEditor.m: Epoz style and charset are configurable now
+         (v4.2.16)
+
+       * added WEEpozEditor, a dynamic element for triggering the Epoz DHTML
+         editor if it is installed in the system. The element behaves almost
+         exactly like WOText.
+         Note: of course you must have installed Epoz! In OGo Epoz is located
+         in ThirdParty/epoz and must be copied to your WebServerResources
+         (v4.2.15)
+
+2003-10-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.14
+       
+       * GNUmakefile.preamble: added explicit library dependencies required
+         for OSX
+
+       * WETableMatrixContent.m: renamed superclass of WETableMatrixContent
+         to keep MacOSX gcc happy
+         
+       * common.h: removed dependency on FoundationExt
+
+2003-09-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * checked in the Linux generated .jsm files for easier compilation on
+         platforms which do not support "echo -n" in the default shell
+         (v4.2.13)
+
+2003-09-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.12
+
+       * general: improved XHTML compatibility
+       
+       * general: major cleanups and performance improvements (less 
+         autoreleased objects, better int=>str mapping, ...)
+
+2003-07-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * applied rangeOfString patches provided by Filip Van Raemdonck for 
+         improved compilation with gstep-base (v4.2.11)
+       
+       * applied GNUstep patches provided by Filip Van Raemdonck for improved
+         compilation with gstep-base (v4.2.10)
+
+2003-06-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * generate lowercase tags, cleanups, fixed some gcc 3.3 warnings
+         (v4.2.9)
+
+       * moved to skyrix-sope-42 (v4.2.8)
+
+Fri May  9 15:03:48 2003  Martin Hoerning  <mh@skyrix.com>
+
+       * v4.1.7
+       
+       * WEWeekOverview.m, WEWeekColumView.m: added support for 
+         allday-appointments (info items) (bug 1580)
+
+Mon Mar  3 16:29:28 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * WETreeView.m: fixed warnings(v4.1.6)
+
+Fri Feb 28 18:26:23 2003  Jan Reichmann  <jan@skyrix.com>
+
+       * WETreeView.m: replace Assertion with Warning (MAX_TREE_DEPTH)(v4.1.5)
+
+Mon Feb 24 14:47:18 2003  Martin Hoerning  <mh@skyrix.com>
+
+       * WETableMatrix.m(invokeActionForRequest): added WARNING (v4.1.4) 
+                        (bug 1029)
+
+Tue Feb  4 15:48:32 2003  Martin Hoerning  <mh@skyrix.com>
+
+       * v4.1.3
+       
+       * WETabView.m, WECollapsibleComponentContent.m, WETableCell.m,
+         WETableView.m: fixed tooltips (added 'title' to img and 
+         input type='image' tags) (bug 844)
+
+Tue Dec 17 17:58:51 2002  Martin Hoerning  <mh@skyrix.com>
+
+       * WETableView.m: added WETableView_hideBlindNavigation default, 
+         default value is NO, (bug 791) (v.4.1.2)
+
+2002-12-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: fixed linking
+
+2002-12-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: fixed SOVERSION (major/minor)
+
+2002-12-02  Helge Hess  <helge.hess@skyrix.com>
+       
+       * moved to Skyrix41e/WebUI/WEExtensions (v4.1.1)
+       
+Fri Nov 29 18:09:05 2002  Martin Hoerning  <mh@skyrix.com>
+
+       * WETableView.m: added </td> tag in form mode in footer row (bug 731)
+
+Thu Jul 18 16:27:13 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * WETableData.m: fixed font tags in simple-table-cells (bug 498)
+
+Wed May 15 15:00:06 2002  Martin Hoerning  <mh@skyrix.com>
+
+       * JSClipboard.m: added to exit on -isMacBrowser
+
+Sun May  5 14:42:22 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved to NGObjWeb
+
+Mon Jan  7 18:19:23 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WExExtElemBuilder.m: added mappings for tabs
+
+Mon Jan  7 17:01:34 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added WEExtensions bundle
+
+Mon Dec 17 16:59:57 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved WEClientCapabilities to NGObjWeb
+
+Wed Dec  5 13:09:54 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEDropContainer.m: now processes extra attributes on it's own ...
+
+Tue Dec  4 12:17:26 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WEClientCapabilities.m -doesSupportDHTMLDragAndDrop 
+         (only for MS Windows systems)
+
+Thu Nov 22 16:58:32 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView.m: show navigation in footer
+
+Tue Nov 20 17:24:58 2001  Martin Hoerning  <mh@skyrix.com>
+
+       * WEWeekOverview.m: added headerRows/footerRows
+
+Tue Nov 13 10:06:42 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: added user-agent string of 
+         MacOSX 10.1.1 DAV filesystem
+
+Thu Nov  8 16:38:19 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETabView.m: support of td background onclicks
+
+Wed Oct 24 15:00:04 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: recognize Dillo web browser
+
+Wed Oct 17 11:02:32 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEMonthOverview.m: fixed bug, currentday set too late
+
+Fri Oct  5 11:05:38 2001  Martin Hoerning  <mh@skyrix.com>
+
+       * WERichString.m: fixed insertBR
+
+Thu Oct  4 17:50:41 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WERichString.m: added insertBR association
+
+Mon Oct  1 19:53:07 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WESwitch: fixed -takeValuesFromRequest:...
+
+Wed Sep  5 12:05:47 2001  Sascha Schimke  <sascha@skyrix.com>
+
+       * WEWeekColumView.m, WEWeekOverview.m: fixed appointment filtering
+
+Tue Aug 28 17:35:31 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETabView.m: disable javascript
+
+Fri Aug 17 14:13:13 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WETabView.m: fixed bug, added color as font-size ...
+
+Tue Aug 14 14:35:26 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETabView.m set fontstyle of active label to bold
+
+Mon Aug  6 14:08:23 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WECalendarField.m: support of name association(used by DirectActions)
+
+Fri Aug  3 12:52:06 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WECalendarField.m: support of NSCalendarDate association ('date') 
+
+Thu Aug  2 22:27:39 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: added some new DAV client user-agents
+
+Tue Jul 24 20:55:51 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEClientCapabilities.m: added -isDAVClient, DAVFS recognized as 
+         client
+
+Tue Jul 24 19:37:59 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView.[h|m]: added showGroupTitle instance variable
+
+Wed Jun 20 16:23:45 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETabView.m: added font associations
+
+Thu Jun  7 12:23:55 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEDropContainer.m: fixed bug: drop tag was not properly closed !!
+
+Wed Jun  6 14:28:37 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WEDropContainer.m: fixed bug: element was generated on any browser
+
+Thu May 31 17:47:29 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WETabView.m: used double-quotes for href attributes
+
+Tue May 29 16:21:37 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableData.m: valign is set to 'TOP' by default
+
+Tue May 22 15:39:48 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView.m,WETableData.m: WETableView_DataMode wasn't set correct
+                                      in takeValuesFromRequest:inContext:
+
+Tue May 15 16:10:07 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETabView.m: isJavaScriptEnabled didn't work (fixed)
+       
+Sun May  6 16:45:44 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WEWeekOverview.m: dayIndex of sat and sun was wrong (only title)
+
+       * WETableView.m: currentBatch was wrong (takeValuesFromRequest:...)
+
+Tue May  1 19:02:12 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView.m: format of assert was wrong
+
+Mon Apr 30 20:56:12 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WEWeekOverview: added 'border', 'width', 'cellpadding' and
+                         'cellspacing' associations
+
+Mon Apr 23 12:30:13 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WETabItem.m: break up huge -appendToResponse:inContext:
+
+Sat Apr 21 21:29:38 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * WETabView.m: body-active-keys handled by view instead of item
+
+       * WETabView.m: break up huge -appendToResponse:inContext:
+
+Sat Apr 21 19:58:34 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * split up WETabView.m file
+
+Mon Apr  9 18:08:34 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView: don't throw exception if no table-content is set
+
+Wed Apr  4 15:28:33 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WEWeekOverview.m: fixed bug in -_calcMatrixInContext:
+
+       * WEWeekOverview.m: fixed bug in -_calcMatrixInContext:
+
+Thu Mar 29 14:55:39 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView.m added 'cellspacing', 'cellpadding', 'border'
+
+       * WETableData.m use font attributes for 'string'
+
+Wed Mar 28 16:18:24 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableData.m: added 'action' and fixed formatter bug
+
+Thu Mar  1 10:38:33 2001  Joerg Grimm  <joerg@trex2>
+
+       * WECollapsibleComponentContent.m: set anchor only in IE
+
+Wed Feb 28 14:30:45 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * WEClientCapabilities.m ([JSClientCapabilityDetector -initWithName:associations:template:]):
+         fixed bug (segfault if no user-agent was set in the request)
+
+Tue Feb 27 18:15:25 2001  Joerg Grimm  <joerg@trex2>
+
+       * WEWeekColumnView.m: fixed wrong idx2 in _calcMatrixInContext
+
+Mon Feb 12 20:36:37 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView+Grouping.m: added grouping behaviour
+
+Tue Feb  6 16:17:09 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WEWeekOverview.m: contentColor wasn't correct
+
+Fri Feb  2 16:17:59 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WEWeekOverview.m: fixed some problems with takeValuesFromRequest
+
+Wed Jan 31 17:31:31 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView.m: added resizeButtons for autoScollHeight
+
+Tue Jan 30 10:44:37 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * WEClientCapabilities.m: added support for Links browser
+
+Fri Jan 26 19:55:25 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * WETableView.m: changed semantics of autoscroll binding
+
+Thu Jan 25 18:20:45 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETreeView.m: added assert (MAX_TREE_DEPTH -> 10)
+
+       * WETableView: added resizeBatchButtons
+
+       * WETreeView.m: bug fixed (no header was rendered if list.count ==0)
+
+Wed Jan 24 18:10:07 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WEDragContainer.m allow DnD in forms
+
+       * WETableView.m takeValuesFromRequest: fixed bug
+
+       * WERichString.m added template and 'condition' binding
+
+       * WEWeekColumnView.m: fixed filtering of appointments with several days
+
+Tue Jan 23 17:28:28 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WEDropContainer.m: can attach behaviour to parent element
+
+Thu Jan 18 17:14:21 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WERichString.m: added
+
+       * WETabView.m: fixed javaScript
+
+       * WECalendarField.m: added
+
+       * WETimeField.m, WEDateField.m: merged into WECalendarField
+
+       * WEWeekOverview.m: default of self->weekStart was wrong
+
+       * WEWeekOverview.m: dito
+
+Wed Jan 17 15:18:02 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETabView.m: improved background img tabs
+
+       * clean up: removed some warnings
+
+Tue Jan 16 13:01:27 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETreeView.m: -invokeAction...: headers couldn't call actions
+
+Mon Jan 15 18:19:34 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETabView: added asBackground mode
+
+Tue Jan  9 19:00:58 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WECollapsibleComponentContent.m: 
+         submitAction can jump to the fragment Identifier
+
+Mon Jan  8 13:04:18 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * fixed compilation
+
+Fri Jan  5 16:57:53 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WEWeekOverview.m: renders own title only if necessary
+
+       * WEContextKey.m fixed retain bug
+
+Thu Jan  4 20:40:25 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WEContextConditional.m: added 'didMatch' binding
+
+       * WEWeekColumnView.m: renders an own title if necessary
+
+Tue Jan  2 14:52:23 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView.m
+         (_applyIdentifier):  - replaced 'self->list' by 'self->allObjects'
+         (_appendNavigation): - show navigation buttons only if neccessary
+
+Tue Jan  2 12:13:15 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * WETableView.m: check whether 'list' is settable before applying a
+         value
+
+Wed Dec 20 19:48:54 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView.m: added binding 'selection'
+
+Tue Dec 19 21:19:25 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WECollapsibleComponentContent.m: is collapsible on clientSide now
+
+       * WETreeView.m repaired 'showItem' bug
+
+       * WETreeView.m added binding 'showItem'
+
+       * WETreeView.m currentPath wasn't updated properly
+
+Tue Dec 19 02:16:49 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * WETableData.m: added cluster & formatting
+
+       * WETableView.m: fixed bug with YesNumber, NoNumber (was completly
+         broken [static's were not initializaed, NoNumber was not retained)
+
+       * WETableView.m: moved WETableData, WETableCell to separate files
+
+       * WETableView.m: added 'string' binding to WETableCell, made tags
+         lowercase (xhtml compatibility)
+
+Fri Dec 15 18:35:46 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WETreeView.m: reorganized matrix (created _WETreeMatrixElement)
+                       render no table if slow table browser
+
+       * WETimeField.m, WEDateField.m: added
+
+       * WETableView.m: browser check -> few tables if required
+
+Tue Dec 12 22:09:11 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WETreeView.m: added association 'currentPath'
+
+Fri Dec  8 11:56:56 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * WEClientCapabilities.m: added detection of Konqueror
+
+Thu Dec  7 11:46:14 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * cleanups, added WEWeekColumnView
+
+Mon Nov 27 19:18:14 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WESwitch.m: added 'keys' attribute to WECase
+                     added WEDefaultCase
+
+       * WESwitch.m: repaired default mode bug
+
+       * WETreeView.m: added 'isItemLeaf' binding
+
+Thu Nov 23 14:00:58 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WEMonthOverview.m: changed matrix into a list of NSMutableArray's 
+
+       * WEWeekOverview.m: changed matrix into a list of NSMutableArray's
+
+Wed Nov 22 16:39:00 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableMatrix*[h.m]: added
+
+Mon Nov 20 12:22:18 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * WETableView.m: check 'autoScroll' association
+
+Sat Nov 18 20:03:29 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * added WEClientCapabilities class
+
+Wed Nov 15 15:37:35 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WEComponentValue.m: added
+
+Thu Nov  9 18:57:13 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView: added 'identifier' association
+
+Wed Nov  1 18:46:58 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WEPageView.m: added
+
+       * WEContextKey.m: added
+
+Mon Oct 30 15:54:02 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WECollapsibleComponentContent.m: added 'action'
+                                          added 'fragmentIdentifier'
+
+Fri Oct 27 12:49:43 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WECollapsibleComponentContent.m: added association 'condition'
+
+Fri Oct 20 18:31:59 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WESwitch.m: added 'default' association in WECase
+
+       * WETableView.m: fixed sorting bug
+
+Wed Oct 18 15:42:53 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WETabView.m: added
+
+Tue Oct 17 09:54:52 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WESwitch.m: added
+
+Mon Oct 16 15:18:50 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView.m: changed association lastItem  into previousItem
+                        changed association lastIndex into previousIndex
+
+       * WETableView.m: only the sorted column can be grouped
+
+Thu Oct 12 17:30:50 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WETableView.m: fixed isGroup bug
+
+Mon Oct  9 18:45:48 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WETreeView.m: added association 'string' and 'extraAttributes'
+
+       * WETableView.m: changed visibility of navigation icons
+
+       * WETreeView.m, WEBrowser.m: added
+
+Thu Sep 28 13:24:37 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * created WEExtensions
diff --git a/skyrix-sope/WEExtensions/GNUmakefile b/skyrix-sope/WEExtensions/GNUmakefile
new file mode 100644 (file)
index 0000000..4f8e177
--- /dev/null
@@ -0,0 +1,63 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+include ../Version
+include ./Version
+
+LIBRARY_NAME = libWEExtensions
+BUNDLE_NAME  = WEExtensions
+
+libWEExtensions_HEADER_FILES_DIR         = .
+libWEExtensions_HEADER_FILES_INSTALL_DIR = /WEExtensions
+
+libWEExtensions_HEADER_FILES = \
+       WEClientCapabilities.h          \
+       WEContextConditional.h          \
+
+libWEExtensions_OBJC_FILES =   \
+       JSClipboard.m                   \
+       JSShiftClick.m                  \
+       WEBrowser.m                     \
+       WECalendarField.m               \
+       WECollapsibleComponentContent.m \
+       WEComponentValue.m              \
+       WEContextConditional.m          \
+       WEContextKey.m                  \
+       WEDateField.m                   \
+       WEDragContainer.m               \
+       WEDropContainer.m               \
+       WEMonthOverview.m               \
+       WEPageView.m                    \
+       WEPageLink.m                    \
+       WERichString.m                  \
+       WESwitch.m                      \
+       WETabItem.m                     \
+       WETabView.m                     \
+       WETableCalcMatrix.m             \
+       WETableMatrix.m                 \
+       WETableMatrixContent.m          \
+       WETableMatrixLabel.m            \
+       WETimeField.m                   \
+       WETreeView.m                    \
+       WETreeHeader.m                  \
+       WETreeData.m                    \
+       WETreeMatrixElement.m           \
+       WEWeekColumnView.m              \
+       WEWeekOverview.m                \
+       WExExtElemBuilder.m             \
+       WExCalElemBuilder.m             \
+       WExDnDElemBuilder.m             \
+       WEEpozEditor.m                  \
+       WEQualifierConditional.m        \
+       WERedirect.m                    \
+
+libWEExtensions_SUBPROJECTS += \
+       WETableView
+
+WEExtensions_OBJC_FILES      = WEExtensionsBundle.m
+WEExtensions_PRINCIPAL_CLASS = WEExtensionsBundle
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/WEExtensions/GNUmakefile.postamble b/skyrix-sope/WEExtensions/GNUmakefile.postamble
new file mode 100644 (file)
index 0000000..fb5c01e
--- /dev/null
@@ -0,0 +1,15 @@
+# $Id$
+
+
+WEDropScript.jsm : WEDropScript.js
+       sh js2m.sh $< $@
+       touch WEDropContainer.m
+
+calendar.jsm : calendar.js
+       sh js2m.sh $< $@
+       touch calendar.m
+
+WEDropContainer.m : WEDropScript.jsm
+
+before-all :: WEDropScript.jsm calendar.jsm
+
diff --git a/skyrix-sope/WEExtensions/GNUmakefile.preamble b/skyrix-sope/WEExtensions/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..ffcb865
--- /dev/null
@@ -0,0 +1,64 @@
+# $Id$
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-WEExtensions-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-WEExtensions-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
+
+libWEExtensions_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libWEExtensions_LIBRARIES_DEPEND_UPON += \
+       -lNGObjWeb -lNGJavaScript -lNGScripting \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC \
+       -ljs
+
+ADDITIONAL_CPPFLAGS += -Wall
+ADDITIONAL_INCLUDE_DIRS += -I.. -I../.. -I../NGObjWeb
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_JS=$(GNUSTEP_BUILD_DIR)/../../../ThirdParty/js-1.5
+RELBUILD_DIR_SOPE=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/../../skyrix-core
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                                            \
+        -L$(RELBUILD_DIR_SOPE)/NGObjWeb/$(GNUSTEP_OBJ_DIR_NAME)                \
+        -L$(RELBUILD_DIR_SOPE)/NGJavaScript/$(GNUSTEP_OBJ_DIR_NAME)    \
+        -L$(RELBUILD_DIR_SOPE)/NGScripting/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGMime/$(GNUSTEP_OBJ_DIR_NAME)        \
+        -L$(RELBUILD_DIR_SxCore)/NGStreams/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+        -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)             \
+        -L$(RELBUILD_DIR_SxXml)/XmlRpc/$(GNUSTEP_OBJ_DIR_NAME)         \
+        -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)            \
+        -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)                \
+       -L$(RELBUILD_DIR_JS)/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += \
+       -L./$(GNUSTEP_OBJ_DIR)                  \
+        -L../NGObjWeb/$(GNUSTEP_OBJ_DIR)        \
+        -L../NGJavaScript/$(GNUSTEP_OBJ_DIR)    \
+        -L../NGScripting/$(GNUSTEP_OBJ_DIR)
+endif
+
+WEExtensions_BUNDLE_LIBS   += -lWEExtensions
+WEExtensions_WOBUNDLE_LIBS += $(WEExtensions_BUNDLE_LIBS)
+ifneq ($(GNUSTEP_BUILD_DIR),)
+WEExtensions_LIB_DIRS      += -L$(GNUSTEP_OBJ_DIR)
+else
+WEExtensions_LIB_DIRS      += -L./$(GNUSTEP_OBJ_DIR)
+endif
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libWEExtensions_PREBIND_ADDR="0xC4000000"
+libWEExtensions_LDFLAGS += -seg1addr $(libWEExtensions_PREBIND_ADDR)
+endif
diff --git a/skyrix-sope/WEExtensions/JSClipboard.m b/skyrix-sope/WEExtensions/JSClipboard.m
new file mode 100644 (file)
index 0000000..b9e6a41
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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:
+
+#include <NGObjWeb/NGObjWeb.h>
+#include <NGObjWeb/WEClientCapabilities.h>
+#include "common.h"
+
+@interface JSClipboard : WODynamicElement
+{
+  WOAssociation *filename;
+  WOAssociation *imgURL;
+  WOAssociation *string;
+  WOAssociation *toolTip;
+  WOAssociation *value;
+}
+@end
+
+@implementation JSClipboard
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->filename = OWGetProperty(_config,@"filename");
+    self->imgURL   = OWGetProperty(_config,@"imgURL");
+    self->string   = OWGetProperty(_config,@"string");
+    self->toolTip  = OWGetProperty(_config,@"toolTip");
+    self->value    = OWGetProperty(_config,@"value");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->imgURL  release];
+  [self->string  release];
+  [self->toolTip release];
+  [self->value   release];
+  [super dealloc];
+}
+
+/* operations */
+
+- (NSString *)imageByFilename:(NSString *)_name
+  inContext:(WOContext *)_ctx
+  framework:(NSString *)_framework
+{
+  WOResourceManager *rm;
+  NSString          *tmp;
+  NSArray           *languages;
+
+  rm = [[_ctx application] resourceManager];
+    
+  languages = [_ctx hasSession]
+    ? [[_ctx session] languages]
+    : [[_ctx request] browserLanguages];
+    
+  tmp = [rm urlForResourceNamed:_name
+            inFramework:_framework
+            languages:languages
+            request:[_ctx request]];
+  return tmp;
+}
+
+- (void)appendToResponse:(WOResponse *)_response
+               inContext:(WOContext *)_ctx
+{
+  WOComponent          *comp;
+  NSString             *tmp;
+  NSString             *tt;    // toolTip
+  WEClientCapabilities *ccaps;
+
+  comp    = [_ctx component];
+  ccaps   = [[_ctx request] clientCapabilities];
+  tt      = [self->toolTip stringValueInComponent:comp];
+  tt      = tt ? tt : @"";
+
+  if (![ccaps isInternetExplorer]) return;
+  if ([ccaps isMacBrowser]) return;
+
+  tmp = [[NSString alloc] initWithFormat:
+                  @"<a href=\"#\" onclick=\"javascript:clipboardData."
+                  @"setData('text', '%@');return false;\" title=\"%@\">",
+                  [self->value stringValueInComponent:comp], tt];
+  [_response appendContentString:tmp];
+  [tmp release]; tmp = nil;
+  
+  NSAssert(self->imgURL != nil || self->string != nil || self->filename != nil,
+           @"ERROR: no imageURL or string defined...");
+
+  if (self->filename) {
+    NSString *imageFilename;
+
+    imageFilename =
+      [self imageByFilename:[self->filename stringValueInComponent:comp]
+            inContext:_ctx
+            framework:[comp frameworkName]];
+
+    tmp = [[NSString alloc] initWithFormat:
+                    @"<img border=\"0\"src=\"%@\" /></a>",
+                    imageFilename];
+  }
+  else if (self->imgURL) {
+    tmp = [[NSString alloc] initWithFormat:
+                    @"<img border=\"0\"src=\"%@\" /></a>",
+                    [self->imgURL stringValueInComponent:comp]];
+  }
+  else {
+    tmp = [[NSString alloc] initWithFormat:
+                    @"%@</a>",
+                    [self->string stringValueInComponent:comp]];
+  }
+  [_response appendContentString:tmp];
+  [tmp release];
+}
+
+@end /* JSClipboard */
diff --git a/skyrix-sope/WEExtensions/JSMenu.h b/skyrix-sope/WEExtensions/JSMenu.h
new file mode 100644 (file)
index 0000000..d9b807d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WEExtensions_JSMenu_H__
+#define __WEExtensions_JSMenu_H__
+
+#include <NGObjWeb/NGObjWeb.h>
+#ifdef __APPLE__
+#  include <NGObjWeb/WEClientCapabilities.h>
+#else
+#  include <WEExtensions/WEClientCapabilities.h>
+#endif
+#include "JSMenuItem.h"
+
+@class WOAssociation, WOElement;
+
+@interface JSMenu : WODynamicElement
+{
+  WOAssociation *fgColor;
+  WOAssociation *bgColor;
+  WOAssociation *fgColorHigh;
+  WOAssociation *bgColorHigh;
+  WOAssociation *borderColor;
+  WOAssociation *borderWidth;
+  WOAssociation *fontSize;
+  WOAssociation *width;
+  WOAssociation *leftPadding;
+  WOAssociation *string;
+  WOAssociation *bindAtId;
+  WOAssociation *tag;
+  WOAssociation *align;
+
+  WOElement     *template;
+}
+@end
+
+#endif /* __WEExtensions_JSMenu_H__ */
diff --git a/skyrix-sope/WEExtensions/JSMenu.m b/skyrix-sope/WEExtensions/JSMenu.m
new file mode 100644 (file)
index 0000000..3f76917
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "JSMenu.h"
+#include "JSMenuItem.h"
+#include <NGObjWeb/NGObjWeb.h>
+#include <NGObjWeb/WEClientCapabilities.h>
+#include "common.h"
+
+@implementation JSMenu
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->fgColor     = OWGetProperty(_config,@"fgColor");
+    self->bgColor     = OWGetProperty(_config,@"bgColor");
+    self->fgColorHigh = OWGetProperty(_config,@"fgColorHigh");
+    self->bgColorHigh = OWGetProperty(_config,@"bgColorHigh");
+    self->borderColor = OWGetProperty(_config,@"borderColor");
+    self->borderWidth = OWGetProperty(_config,@"borderWidth");
+    self->fontSize    = OWGetProperty(_config,@"fontSize");
+    self->width       = OWGetProperty(_config,@"width");
+    self->leftPadding = OWGetProperty(_config,@"leftPadding");
+    self->string      = OWGetProperty(_config,@"string");
+    self->bindAtId    = OWGetProperty(_config,@"bindAtId");
+    self->align       = OWGetProperty(_config,@"align");
+    self->tag         = OWGetProperty(_config,@"tag");
+
+    self->template = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->fgColor     release];
+  [self->bgColor     release];
+  [self->fgColorHigh release];
+  [self->bgColorHigh release];
+  [self->borderWidth release];
+  [self->fontSize    release];
+  [self->width       release];
+  [self->leftPadding release];
+  [self->string      release];
+  [self->bindAtId    release];
+  [self->align       release];
+  [self->tag         release];
+  [self->template    release];
+  [super dealloc];
+}
+
+/* handling requests */
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_req inContext:_ctx];
+}
+
+/* generate response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent          *comp;
+  NSString             *tmp;
+  NSString             *eid; // [_ctx elementID]
+  WEClientCapabilities *ccaps;
+  BOOL                 ie, ns;
+
+  eid   = [[[_ctx elementID] componentsSeparatedByString:@"."]
+                  componentsJoinedByString:@"_"];
+  comp  = [_ctx component];
+  ccaps = [[_ctx request] clientCapabilities];
+  ie    = [ccaps isJavaScriptBrowser] && [ccaps isInternetExplorer];
+  ns    = [ccaps isJavaScriptBrowser] && [ccaps isNetscape];
+
+  [_ctx setObject:eid forKey:@"eid"];
+
+  if (!ie) {
+    return;
+
+    [_response appendContentString:@"<font size=\"-1\">["];
+    [self->template appendToResponse:_response inContext:_ctx];
+    [_response appendContentString:@"]</font>"];
+    return;
+  }
+
+  if (ie) {
+    if ([_ctx objectForKey:@"jsmenu_included"] == nil) {
+      [_ctx setObject:@"done" forKey:@"jsmenu_included"];
+      tmp = [[NSString alloc] initWithFormat:
+                      @"<style>\n"
+                      @".menuItem {\n"
+                      @"  font:%@pt sans-serif;\n"
+                      @"  width:%@;\n"
+                      @"  padding-left:%@;\n"
+                      @"  background-Color:%@;\n"
+                      @"  color:%@;\n"
+                      @"  text-align:%@\n"
+                      @"}\n"
+                      @".highlightItem {\n"
+                      @"  font:%@pt sans-serif;\n"
+                      @"  width:%@;\n"
+                      @"  padding-left:%@;\n"
+                      @"  background-Color:%@;\n"
+                      @"  color:%@\n"
+                      @"  text-align:%@\n"
+                      @"}\n"
+                      @"</style>\n",
+                      [self->fontSize stringValueInComponent:comp],
+                      [self->width stringValueInComponent:comp],
+                      [self->leftPadding stringValueInComponent:comp],
+                      [self->bgColor stringValueInComponent:comp],
+                      [self->fgColor stringValueInComponent:comp],
+                      [self->align stringValueInComponent:comp],
+                      [self->fontSize stringValueInComponent:comp],
+                      [self->width stringValueInComponent:comp],
+                      [self->leftPadding stringValueInComponent:comp],
+                      [self->bgColorHigh stringValueInComponent:comp],
+                      [self->fgColorHigh stringValueInComponent:comp],
+                      [self->align stringValueInComponent:comp]];
+      [_response appendContentString:tmp];
+      [tmp release];
+
+      tmp = [[NSString alloc] initWithFormat:
+                      @"<script language=\"javascript\">\n"
+                      @"var menuOpened;\n"
+                      @"function displayMenu(m) {\n"
+                      @"  closeMenu();\n"
+                      @"  if(m.parentNode != event.srcElement)\n"
+                      @"    return false;\n"
+                      @"  menuOpened=m;\n"
+                      @"  m.style.posLeft=event.clientX+document.body.scrollLeft;\n"
+                      @"  m.style.posTop=event.clientY+document.body.scrollTop;\n"
+                      @"  if(document.body.clientWidth<event.clientX+%@+5)\n"
+                      @"    m.style.posLeft-=%@;\n"
+                      @"  m.style.display=\"\";\n"
+                      @"  m.setCapture();\n"
+                      @"  return false;\n"
+                      @"}\n"
+                      @"function switchMenu() {\n"
+                      @"  el=event.srcElement;\n"
+                      @"  if(el.className==\"menuItem\")\n"
+                      @"    el.className=\"highlightItem\";\n"
+                      @"  else if(el.className==\"highlightItem\")\n"
+                      @"    el.className=\"menuItem\";\n"
+                      @"}\n"
+                      @"function clickMenu(m) {\n"
+                      @"  m.releaseCapture();\n"
+                      @"  m.style.display=\"none\";\n"
+                      @"  el=event.srcElement;\n"
+                      @"  if(m==el.parentNode)window.location=el.url;\n"
+                      @"  return false;\n"
+                      @"}\n"
+                      @"function closeMenu() {\n"
+                      @"  if(menuOpened==null)"
+                      @"    return;\n"
+                      @"  menuOpened.releaseCapture();\n"
+                      @"  menuOpened.style.display=\"none\";\n"
+                      @"  menuOpened=null;\n"
+                      @"}\n"
+                      @"</script>\n",
+                      [self->width stringValueInComponent:comp],
+                      [self->width stringValueInComponent:comp]];
+      [_response appendContentString:tmp];
+      [tmp release];
+    }
+    tmp = [[NSString alloc] initWithFormat:
+                    @"<div id=\"m%@\" onclick=\"return clickMenu(m%@);\" "
+                    @"onmouseover=\"switchMenu();\" "
+                    @"onmouseout=\"switchMenu();\" "
+                    @"style=\"position:absolute;display:none;width:%@;"
+                    @"background-Color:%@;border:outset %@px %@;"
+                    @"text-decoration:none\">",
+                    eid, eid,
+                    [self->width       stringValueInComponent:comp],
+                    [self->bgColor     stringValueInComponent:comp],
+                    [self->borderWidth stringValueInComponent:comp],
+                    [self->borderColor stringValueInComponent:comp]];
+    [_response appendContentString:tmp];
+    [tmp release];
+
+    [self->template appendToResponse:_response inContext:_ctx];
+
+    [_response appendContentString:@"</div>"];
+#if 0
+    if ([self->tag stringValueInComponent:comp] != nil)
+      tmp = [[NSString alloc] initWithFormat:
+                      @"<script id=\"s%@\" language=\"javascript\">"
+                      @"function c%@(){return displayMenu(m%@);}"
+                      @"tmp=document.getElementById(\"s%@\");"
+                      @"i=5;"
+                      @"while((tmp.tagName!=\"%@\")&&i--)"
+                      @"tmp=tmp.parentNode;"
+                      @"tmp.oncontextmenu=c%@;"
+                      @"</script>",
+                      eid, eid, eid, eid,
+                      [self->tag stringValueInComponent:comp], eid];
+    else
+#endif
+      tmp = [[NSString alloc] initWithFormat:
+                      @"<script id=\"s%@\" language=\"javascript\">"
+                      @"function c%@() { return displayMenu(m%@); }"
+                      @"s%@.parentNode.oncontextmenu=c%@;"
+                      @"</script>",
+                      eid, eid, eid, eid, eid];
+    [_response appendContentString:tmp];
+    [tmp release];
+  }
+#if 0
+  if (ns) {
+    if ([_ctx objectForKey:@"jsmenu_included"] == nil) {
+      tmp = [[NSString alloc] initWithFormat:
+                      @"<script language=\"javascript1.2\" "
+                      @"src=\"http://inster:9000/sascha/menu07.js\">"
+                      @"</script>\n"
+                      @"<script language=\"javascript1.2\">"
+                      @"function onLoad(){m%@.writeMenus();}</script>\n",
+                      eid];
+      [_response appendContentString:tmp];
+      [tmp release];
+    }
+
+    tmp = [[NSString alloc] initWithFormat:
+                    @"<script language=\"javascript1.2\">\n"
+                    @"m%@=new Menu();",eid];
+    [_response appendContentString:tmp];
+    [tmp release];
+
+    [self->template appendToResponse:_response inContext:_ctx];
+
+    tmp = [[NSString alloc] initWithFormat:
+                    @"</script>\n"
+                    @"<a href=\"#\" onclick=\"showMenu(m%@);return false;\">"
+                    @"M</a>", eid];
+    [_response appendContentString:tmp];
+    [tmp release];
+
+    [_ctx setObject:@"done" forKey:@"jsmenu_included"];
+  }
+#endif
+}
+
+@end /* JSMenu */
diff --git a/skyrix-sope/WEExtensions/JSMenuItem.h b/skyrix-sope/WEExtensions/JSMenuItem.h
new file mode 100644 (file)
index 0000000..0a99b2c
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WEExtensions_JSMenuItem_H__
+#define __WEExtensions_JSMenuItem_H__
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@class WOAssociation, WOElement;
+
+@interface JSMenuItem : WODynamicElement
+{
+  WOAssociation *action;
+  WOAssociation *href;
+  WOAssociation *string;
+
+  WOElement     *template;
+}
+@end
+
+#endif /* __WEExtensions_JSMenuItem_H__ */
diff --git a/skyrix-sope/WEExtensions/JSMenuItem.m b/skyrix-sope/WEExtensions/JSMenuItem.m
new file mode 100644 (file)
index 0000000..fdb8648
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <NGObjWeb/NGObjWeb.h>
+#import <Foundation/Foundation.h>
+#ifdef __APPLE__
+#  import <NGObjWeb/WEClientCapabilities.h>
+#else
+#  import <WEExtensions/WEClientCapabilities.h>
+#endif
+#import "JSMenuItem.h"
+
+@implementation JSMenuItem
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs]))
+  {
+    self->action = OWGetProperty(_config,@"action");
+    self->href   = OWGetProperty(_config,@"href");
+    self->string = OWGetProperty(_config,@"string");
+
+    self->template = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->action   release];
+  [self->href     release];
+  [self->string   release];
+  [self->template release];
+  [super dealloc];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  if (![[_ctx elementID] isEqualToString:[_ctx senderID]]) {
+    NSLog(@"ERROR: elementID %@ and senderID %@ do not match.",
+          [_ctx elementID], [_ctx senderID]);
+    return nil;
+  }
+  return [self->action valueInComponent:[_ctx component]];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent          *comp;
+  NSString             *tmp;
+  NSString             *url = nil;
+  WEClientCapabilities *ccaps;
+  BOOL                 ie, ns;
+  NSString             *eid;
+  
+  comp  = [_ctx component];
+  ccaps = [[_ctx request] clientCapabilities];
+  ie    = [ccaps isJavaScriptBrowser] && [ccaps isInternetExplorer];
+  ns    = [ccaps isJavaScriptBrowser] && [ccaps isNetscape];
+  eid   = [_ctx objectForKey:@"eid"];
+
+  NSAssert(self->action != nil || self->href != nil,
+           @"ERROR: no action or href defined...");
+  if (self->action != nil)
+    url = [_ctx componentActionURL];
+  else if (self->href != nil)
+    url = [self->href stringValueInComponent:comp];
+  
+  if (ie) {
+    tmp  = [[NSString alloc] initWithFormat:
+                     @"<div align=\"left\" class=\"menuItem\" url=\"%@\">"
+                     @"%@</div>",
+                     url, [self->string stringValueInComponent:comp]];
+  }
+#if 0
+  else if (ns)
+    tmp = [[NSString alloc] initWithFormat:
+                    @"m%@.addMenuItem(\"%@\",\"top.window.location='%@'\");",
+                    //@"m%@.addMenuItem(\"%@\",\"alert('%@')\");",
+                    eid, [self->string stringValueInComponent:comp], url];
+#endif
+  else {
+    return;
+#if 0
+    tmp = [[NSString alloc] initWithFormat:
+                    @"<a href=\"%@\">%@</a>", url,
+                    [self->string stringValueInComponent:[_ctx component]]];
+#endif
+  }
+  
+  [_response appendContentString:tmp];
+  [tmp release];
+}
+
+@end /* JSMenuItem */
diff --git a/skyrix-sope/WEExtensions/JSShiftClick.m b/skyrix-sope/WEExtensions/JSShiftClick.m
new file mode 100644 (file)
index 0000000..fb843b3
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/NGObjWeb.h>
+#include "WEClientCapabilities.h"
+
+/*
+
+  < scriptName   (obligatory !!!)
+  > identifier
+  > prefix
+
+  Generates an ShiftClick JavaScript for CheckBoxes.
+
+  Example:
+
+  // wod:
+  ShiftClickScript: JSShiftClick {
+    scriptName = scriptName;
+  }
+
+  Repetition: WORepetition {
+    list = (1, 2, 3, 4, 5, 6, 7, 8, 9);
+    item = index;
+  }
+  CheckBox: WOCheckBox {
+    checked = checked;
+    value   = index;      // = index"              this must be done !!!
+    onClick = scriptCall; // = "scriptName(index)" this must be done !!!
+  }
+
+  // html:
+
+  <FORM....>
+  
+    <#ShiftClickScript />
+    <#Repetition>
+      <#CheckBox />
+    </#Repetition>
+
+  </FORM>
+  
+*/
+
+@interface JSShiftClick : WODynamicElement
+{
+  WOAssociation *identifier;
+  WOAssociation *prefix;
+  WOAssociation *scriptName;
+}
+@end
+
+static NSString *JSShiftClick_Script =
+      @"<script language=\"JavaScript\">\n"
+      @"<!--\n"
+      @"var ns = (document.layers) ? true : false;\n"
+      @"var ie = (document.all) ? true : false;\n"
+      @"var last = -1;\n"
+      @"function shiftClick%@SearchElement(el) { \n"
+      @"  for (i = 0; i < document.forms.length; i++) { \n"
+      @"    for (j = 0; j < document.forms[i].elements.length; j++) { \n"
+      @"      if (document.forms[i].elements[j].value == el) { \n"
+      @"        return document.forms[i].elements[j]; \n"
+      @"      } \n"
+      @"    } \n"
+      @"  } \n"
+      @"  return false; \n"
+      @"} \n\n"
+      @"function shiftClick%@(z) {\n"
+      @"  if (ie) {\n"
+      @"    var plusShift = window.event.shiftKey;\n"
+      @"    if (plusShift && last >= 0) {\n"
+      @"      var actEl    = shiftClick%@SearchElement('%@'+last); \n"
+      @"      if (actEl) { \n "
+      @"        var actState = actEl.checked;\n"
+      @"        if (z<last) { var e1 = z; var e2 = last; }\n"
+      @"        else { var e1 = last; var e2 = z; }\n"
+      @"        for (idx = e1; idx<= e2; idx++) {\n"
+      @"          actEl = shiftClick%@SearchElement('%@' + idx); \n"
+      @"          actEl.checked = actState;\n"
+      @"        }\n"
+      @"      } \n"
+      @"    }\n"
+      @"    last = z;\n"
+      @"  }\n"
+      @"}\n"
+      @"//-->\n"
+      @"</script>";
+
+#include "common.h"
+
+@implementation JSShiftClick
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmp
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmp])) {
+    self->identifier = WOExtGetProperty(_config, @"identifier");
+    self->prefix     = WOExtGetProperty(_config, @"prefix");
+    self->scriptName = WOExtGetProperty(_config, @"scriptName");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->identifier release];
+  [self->prefix     release];
+  [self->scriptName release];
+  [super dealloc];
+}
+
+/* response generation */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WEClientCapabilities *ccaps = nil;
+  NSString *eid  = nil;
+  NSString *prfx = nil;
+
+  ccaps = [[_ctx request] clientCapabilities];
+
+  eid = [self->identifier stringValueInComponent:[_ctx component]];
+  eid = (eid) ? eid : [_ctx elementID];
+  eid = [[eid componentsSeparatedByString:@"."]
+              componentsJoinedByString:@"_"];
+  
+  prfx = [self->prefix stringValueInComponent:[_ctx component]];
+  prfx = (prfx) ? prfx : @"";
+
+  if ([ccaps isJavaScriptBrowser]) {
+    NSString *s;
+    
+    s = [[NSString alloc] initWithFormat:JSShiftClick_Script,
+                          eid, eid, eid, prfx, eid, prfx];
+    [_response appendContentString:s];
+    [s release];
+  }
+  if ([self->scriptName isValueSettable]) {
+    NSString *sName = nil;
+
+    sName = [@"shiftClick" stringByAppendingString:eid];
+    [self->scriptName setValue:sName inComponent:[_ctx component]];
+  }
+#if DEBUG
+  else {
+    NSLog(@"Warning: JSShiftClick: 'scriptName' is not settable!!!");
+  }
+#endif
+}
+
+@end /* JSShiftClick */
diff --git a/skyrix-sope/WEExtensions/README b/skyrix-sope/WEExtensions/README
new file mode 100644 (file)
index 0000000..fa93f36
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+WEExtensions
+============
+
+This framework contains various dynamic elements for use with NGObjWeb.
+
+Defaults
+========
+
+WETableView_showBlindNavigation - BOOL - NO
diff --git a/skyrix-sope/WEExtensions/TODO b/skyrix-sope/WEExtensions/TODO
new file mode 100644 (file)
index 0000000..d814c8d
--- /dev/null
@@ -0,0 +1,8 @@
+# $Id: TODO,v 1.2 2004/04/02 15:45:39 helge Exp $
+
+TODO for WEExtensions
+=====================
+
+WETableView
+- document, document
+- much more support for CSS!
diff --git a/skyrix-sope/WEExtensions/Version b/skyrix-sope/WEExtensions/Version
new file mode 100644 (file)
index 0000000..fefabe0
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=53
diff --git a/skyrix-sope/WEExtensions/WEBrowser.m b/skyrix-sope/WEExtensions/WEBrowser.m
new file mode 100644 (file)
index 0000000..0b9c88e
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/NGObjWeb.h>
+#include "WEClientCapabilities.h"
+#include "common.h"
+
+/*
+  API:
+
+    - extra attributes are attributes of the <table> tag
+
+*/
+
+static NSString *WEBrowser_Plus    = @"WEBrowser_Plus";
+static NSString *WEBrowser_Minus   = @"WEBrowser_Minus";
+
+@interface WEBrowser : WODynamicElement
+{
+@protected
+  WOAssociation *list;
+  WOAssociation *item;
+  WOAssociation *sublist;
+  WOAssociation *currentPath;
+  
+  // config
+  WOAssociation *bgColor;
+  WOAssociation *height;
+  WOAssociation *columnWidth;
+  
+  WOElement     *template;
+}
+@end
+
+#include "common.h"
+
+@implementation WEBrowser
+
+#if 0
+static NSString *retStrForInt(int i) {
+  return [[NSString alloc] initWithFormat:@"%i", i];
+}
+#endif
+
+static inline void
+_applyPath(WEBrowser *self, NSArray *path, WOComponent *cmp) {
+  [self->currentPath setValue:path              inComponent:cmp];
+  [self->item        setValue:[path lastObject] inComponent:cmp];
+}
+
+static inline void
+_applyPathAppenedByItem(WEBrowser *self, NSArray *path, id obj, id cmp) {
+  [self->currentPath setValue:[path arrayByAddingObject:obj] inComponent:cmp];
+  [self->item        setValue:obj                            inComponent:cmp];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_root
+{
+  if ((self=[super initWithName:_name associations:_config template:_root])) {
+    self->list        = WOExtGetProperty(_config, @"list");
+    self->item        = WOExtGetProperty(_config, @"item");
+    self->sublist     = WOExtGetProperty(_config, @"sublist");
+    self->currentPath = WOExtGetProperty(_config, @"currentPath");
+
+    // config
+    self->bgColor     = WOExtGetProperty(_config, @"bgColor");
+    self->height      = WOExtGetProperty(_config, @"height");
+    self->columnWidth = WOExtGetProperty(_config, @"columnWidth");
+
+    self->template  = [_root retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->list        release];
+  [self->item        release];
+  [self->sublist     release];
+  [self->currentPath release];
+
+  [self->columnWidth release];
+  [self->bgColor     release];
+  [self->height      release];
+  
+  [self->template release];
+  [super dealloc];
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+#if 0
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+#endif
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent    *cmp;
+  NSMutableArray *stack;
+  NSArray        *selects;
+  NSArray        *subarray;
+  NSString       *cid;
+  id             result;
+  id             obj = nil;
+  int            col, row;
+  BOOL           isScroll = NO;
+
+  cmp     = [_ctx component];
+  selects = [self->currentPath valueInComponent:cmp];
+
+  cid = [_ctx currentElementID];
+  
+  if ([cid isEqualToString:@"scroll"]) {
+    isScroll = YES;
+
+    [_ctx appendElementIDComponent:cid];   // append scroll
+    cid = [_ctx consumeElementID];         // get currentPath index (=column)
+    col = [cid intValue];                  //
+    [_ctx appendElementIDComponent:cid];   // append column
+    cid = [_ctx consumeElementID];         // get row
+    row = [cid intValue];
+    [_ctx appendElementIDComponent:cid];   // append row
+    cid = [_ctx consumeElementID];         // get plus or minus action or else
+  }
+  else {
+    cid = [_ctx currentElementID];         // get row
+    row = [cid  intValue];
+    [_ctx appendElementIDComponent:cid];   // append row
+    cid = [_ctx consumeElementID];         // get currentPath index (=column)
+    col = [cid intValue];
+    [_ctx appendElementIDComponent:cid];   // append index
+    cid = [_ctx consumeElementID];         // get plus or minus action or else
+  }
+
+  stack = [NSMutableArray arrayWithArray:
+                          [selects subarrayWithRange:NSMakeRange(0, col)]];
+
+  if ([cid isEqual:WEBrowser_Minus]) {
+    // last object of current path is the clicked one
+    if (col < (int)[selects count]) {
+      [self->currentPath setValue:stack              inComponent:cmp];
+      [self->item        setValue:[stack lastObject] inComponent:cmp];
+    }
+    result = nil;
+  }
+  else {
+
+    // prepare for getting the clicked object
+    if (col == 0)
+      subarray = [self->list valueInComponent:cmp];
+    else {
+      obj = [selects objectAtIndex:col-1];
+      [self->item        setValue:obj   inComponent:cmp];
+      [self->currentPath setValue:stack inComponent:cmp];
+      
+      subarray = [self->sublist valueInComponent:cmp];
+    }
+    // get clicked object and update currentPath (=stack)
+    if (row < (int)[subarray count]) {
+      obj = [subarray objectAtIndex:row];
+      [stack addObject:obj];
+    }
+    
+    [self->currentPath setValue:stack inComponent:cmp];
+    [self->item        setValue:obj   inComponent:cmp];
+  
+    if ([cid isEqual:WEBrowser_Plus])
+      result = nil;
+    else
+      result = [self->template invokeActionForRequest:_req inContext:_ctx];
+  }
+  [_ctx deleteLastElementIDComponent];   // delete row
+  [_ctx deleteLastElementIDComponent];   // delete index
+
+  return result;
+}
+
+- (BOOL)_useScrollingInContext:(WOContext *)_ctx {
+  return [[[_ctx request] clientCapabilities] doesSupportCSSOverflow];
+}
+
+- (void)appendWithScrolling:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  WOComponent *cmp     = nil;
+  NSArray     *selects = nil;
+  NSArray     *path    = nil;
+  int         columns, cnt, i, j;
+  BOOL        useScrolling;
+
+  useScrolling = [self _useScrollingInContext:_ctx];
+  
+  cmp = [_ctx component];
+  
+  if ((selects = [[self->currentPath valueInComponent:cmp] copy]) == nil) {
+    selects = [[NSArray alloc] init];
+    [self->currentPath setValue:selects inComponent:cmp];
+  }
+  
+  columns   = [selects count] + 1;
+
+  [_resp appendContentString:@"<table"];
+  [self appendExtraAttributesToResponse:_resp inContext:_ctx];
+  [_resp appendContentString:@">"];
+  
+  [_resp appendContentString:@"<tr>"];
+  
+  [_ctx appendElementIDComponent:@"scroll"]; // scroll - mode
+  
+  [_ctx appendZeroElementIDComponent];
+  for (i=0; i < columns; i++) {
+    NSArray *array;
+    
+    path = [selects subarrayWithRange:NSMakeRange(0, i)];
+    _applyPath(self, path, cmp);
+    
+    array = (i == 0)
+      ? [self->list valueInComponent:cmp]
+      : [self->sublist valueInComponent:cmp];
+    cnt = [array count];
+      
+    if (cnt) {
+      [_resp appendContentString:@"<td valign=\"top\""];
+      if (self->columnWidth) {
+        [_resp appendContentString:@" width=\""];
+        [_resp appendContentHTMLAttributeValue:
+                 [self->columnWidth stringValueInComponent:cmp]];
+        [_resp appendContentString:@"\""];
+      }
+      [_resp appendContentCharacter:'>'];
+      if (self->height && useScrolling) {
+        [_resp appendContentString:@"<p style=\"width:100%; height="];
+        [_resp appendContentString:[self->height stringValueInComponent:cmp]];
+        [_resp appendContentString:@"; overflow-y: auto;\">"];
+      }
+      [_resp appendContentString:
+               @"<table width=\"100%\" border=\"0\" "
+               @"cellspacing=\"0\" cellpadding=\"2\">"];
+    
+      [_ctx appendZeroElementIDComponent];
+      for (j = 0; j < cnt; j++) {
+        NSString *bg = nil;
+        id       obj = nil;
+
+        obj = [array objectAtIndex:j];
+        _applyPathAppenedByItem(self, path, obj, cmp);
+        bg = [self->bgColor stringValueInComponent:cmp];
+        
+        [_resp appendContentString:@"<tr><td valign=\"center\""];
+        if (bgColor) {
+          [_resp appendContentString:@" bgcolor=\""];
+          [_resp appendContentHTMLAttributeValue:bg];
+          [_resp appendContentCharacter:'"'];
+        }
+        [_resp appendContentString:@">"];
+        
+#if 0
+        // named ankers for 'jump-to' functionality
+        [_resp appendContentString:@"<a name=\""];
+        s = retStrForInt(j);
+        [_resp appendContentString:s];
+        [s release];
+        [_resp appendContentString:@"\">"];
+        s = retStrForInt(j);
+        [_resp appendContentString:s];
+        [s release];
+        [_resp appendContentString:@"</a>"];
+#endif
+        
+        [self->template appendToResponse:_resp inContext:_ctx];
+
+        [_resp appendContentString:@"</td></tr>"];
+        [_ctx incrementLastElementIDComponent];
+      }
+      [_ctx deleteLastElementIDComponent];
+
+      [_resp appendContentString:@"</table>"];
+      if (self->height && useScrolling)
+        [_resp appendContentString:@"</p>"];
+      [_resp appendContentString:@"</td>"];
+    }
+    [_ctx incrementLastElementIDComponent];
+  }
+  [_ctx deleteLastElementIDComponent];
+  [_resp appendContentString:@"</tr></table>"];
+
+  [_ctx deleteLastElementIDComponent]; // delete scroll-mode
+  
+  [self->currentPath setValue:selects inComponent:cmp];
+  
+  [selects release]; selects = nil;
+}
+
+- (void)appendWithoutScrolling:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  WOComponent    *cmp     = nil;
+  NSArray        *selects = nil;
+  NSArray        *array   = nil;
+  NSMutableArray *path    = nil;
+  NSString       *bg      = nil;
+  int            selectCnt, cnt, i, j;
+  
+  NSAssert(self->currentPath,
+           @"WEBrowser: missing 'currentPath' association!");
+  
+  cmp       = [_ctx component];
+  array     = [self->list valueInComponent:cmp];
+  selects   = [[self->currentPath valueInComponent:cmp] copy];
+
+  cnt       = [array count];
+  selectCnt = [selects count] + 1;
+  path      = [NSMutableArray arrayWithCapacity:selectCnt];
+  
+  [_resp appendContentString:@"<table"];
+  [self appendExtraAttributesToResponse:_resp inContext:_ctx];
+  [_resp appendContentString:@">"];
+  
+  [_ctx appendZeroElementIDComponent];
+  for (i = 0; i < cnt; i++) {
+    [_resp appendContentString:@"<tr>"];
+    
+    [_ctx appendZeroElementIDComponent];
+    
+    for (j = 0; j < selectCnt; j++) {
+      NSArray *subarray;
+      int     subCount;
+
+      [path removeAllObjects];
+      [path addObjectsFromArray:
+            [selects subarrayWithRange:NSMakeRange(0, j)]];
+
+      // get subarray
+      if (j == 0) {
+        subarray = array;
+      }
+      else {
+        id obj;
+        obj = [selects objectAtIndex:j-1];
+        [self->item        setValue:obj  inComponent:cmp];
+        [self->currentPath setValue:path inComponent:cmp];
+        subarray = [self->sublist valueInComponent:cmp];
+      }
+      // update cnt
+      subCount = [subarray count];
+      cnt      = (subCount > cnt) ? subCount : cnt;
+
+      // append template
+      if (subCount > i) {
+        NSString *k;
+        id       obj;
+
+        obj = [subarray objectAtIndex:i];
+        [self->item        setValue:obj  inComponent:cmp];
+        // [self->currentPath setValue:path inComponent:cmp];
+
+        // is current object in currentPath?
+        
+        if ((j < (int)[selects count]) && 
+            [[selects objectAtIndex:j] isEqual:obj]) {
+          k = (j < selectCnt-1)
+            ? WEBrowser_Minus
+            : WEBrowser_Plus;
+        }
+        else
+          k = WEBrowser_Plus;
+        
+        bg = [self->bgColor stringValueInComponent:cmp];
+
+        WEAppendTD(_resp, nil, nil, bg);
+        [path addObject:obj];
+        [self->currentPath setValue:path inComponent:cmp];
+        [self->template appendToResponse:_resp inContext:_ctx];
+        [_resp appendContentString:@"</td>"];
+      }
+      else {
+        [_resp appendContentString:@"<td colspan=\"2\""];
+        [self->currentPath setValue:nil inComponent:cmp];
+        [self->item        setValue:nil inComponent:cmp];
+        bg = [self->bgColor stringValueInComponent:cmp];
+        if (bg) {
+          [_resp appendContentString:@" bgcolor=\""];
+          [_resp appendContentString:bg];
+        }
+        [_resp appendContentString:@"\">&nbsp;</td>"];
+      }
+      [_ctx incrementLastElementIDComponent];
+    }
+    [_ctx deleteLastElementIDComponent];
+    [_resp appendContentString:@"</tr>"];
+    [_ctx incrementLastElementIDComponent];
+  }
+  [_ctx deleteLastElementIDComponent];
+  [_resp appendContentString:@"</table>"];
+
+  [self->currentPath setValue:selects inComponent:cmp];
+  [selects release];
+}
+
+- (void)appendToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+#if 1
+  [self appendWithScrolling:_resp inContext:_ctx];
+#else
+  if ([self _useScrollingInContext:_ctx])
+    [self appendWithScrolling:_resp inContext:_ctx];
+  else
+    [self appendWithoutScrolling:_resp inContext:_ctx];
+#endif
+}
+
+@end /* WEBrowser */
diff --git a/skyrix-sope/WEExtensions/WECalendarField.h b/skyrix-sope/WEExtensions/WECalendarField.h
new file mode 100644 (file)
index 0000000..870681e
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WEExtensions_WECalendarField_H__
+#define __WEExtensions_WECalendarField_H__
+
+/*
+  required resources:
+
+  // time field:
+  downstairs.gif
+
+  // date field:
+  icon_popupcalendar.gif
+  first.gif
+  previous.gif
+  non_sorted.gif
+  next.gif
+  last.gif
+  icon_unread.gif
+*/
+
+#define HEAD_BACKGROUND_COLOR @"#FFDAAA"
+#define HEAD_COLOR            @"#000000"
+#define HEAD_NAVIGATION_COLOR @"#6F1537"
+
+#include <NGObjWeb/NGObjWeb.h>
+
+@interface WECalendarField : WODynamicElement
+{
+  WOAssociation *date;
+  WOAssociation *name;
+  
+  // dateField elements
+  WOAssociation *year;
+  WOAssociation *month;
+  WOAssociation *day;
+  WOAssociation *format;
+
+  // timeField elements
+  WOAssociation *hour;
+  WOAssociation *minute;
+  WOAssociation *second;
+  WOAssociation *useTextField;
+  WOAssociation *hourInterval;
+  WOAssociation *minuteInterval;
+  WOAssociation *secondInterval;
+
+  WOElement     *template;
+}
+@end
+
+@interface WEDateFieldScript : WODynamicElement
+{
+  WOAssociation *headBackground;
+  WOAssociation *headColor;
+  WOAssociation *headNavColor;
+  WOAssociation *labels;
+  WOAssociation *useImages;
+}
+
++ (void)appendWEDateFieldScriptToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  headBackground: (NSString *) _hBack
+  headColor:      (NSString *) _hCol
+  headNavColor:   (NSString *) _hNav
+  labels:         (id)_labels
+  useImages:      (BOOL)_useImg;
+
+@end
+
+@interface WECalendarField(WETimeFieldImplementation)
+
+- (void)_takeValuesFromTimeFieldRequest:(WORequest *)_rq
+  inContext:(WOContext *)_ctx;
+- (id)_invokeActionForTimeFieldRequest:(WORequest *)_rq
+  inContext:(WOContext *)_ctx;
+- (void)_appendTimeFieldToResponse:(WOResponse *)_r inContext:(WOContext *)_cx;
+
+@end /* WECalendarField(WETimeFieldImplementation) */
+
+@interface WECalendarField(WEDateFieldImplementation)
+
+- (void)_takeValuesFromDateFieldRequest:(WORequest *)_rq
+  inContext:(WOContext *)_ctx;
+- (id)_invokeActionForDateFieldRequest:(WORequest *)_rq 
+  inContext:(WOContext *)_ctx;
+- (void)_appendDateFieldToResponse:(WOResponse *)_r inContext:(WOContext *)_cx;
+
+@end /* WECalendarField(WEDateFieldImplementation) */
+
+@interface WECalendarField(Accessors)
+
+- (NSString *)elementIdWithSuffix:(NSString *)_suffix ctx:(WOContext *)_ctx;
+
+- (void)setSecond:(int)_second inComponent:(WOComponent *)_comp;
+- (int)secondInComponent:(WOComponent *)_comp;
+
+- (void)setMinute:(int)_minute inComponent:(WOComponent *)_comp;
+- (int)minuteInComponent:(WOComponent *)_comp;
+
+- (void)setHour:(int)_hour inComponent:(WOComponent *)_comp;
+- (int)hourInComponent:(WOComponent *)_comp;
+
+- (void)setDay:(int)_day inComponent:(WOComponent *)_comp;
+- (int)dayInComponent:(WOComponent *)_comp;
+
+- (void)setMonth:(int)_month inComponent:(WOComponent *)_comp;
+- (int)monthInComponent:(WOComponent *)_comp;
+
+- (void)setYear:(int)_year inComponent:(WOComponent *)_comp;
+- (int)yearInComponent:(WOComponent *)_comp;
+
+- (BOOL)isSecondSettable;
+- (BOOL)isMinuteSettable;
+- (BOOL)isHourSettable;
+- (BOOL)isDaySettable;
+- (BOOL)isMonthSettable;
+- (BOOL)isYearSettable;
+
+- (BOOL)hasSecondInComponent:(WOComponent *)_comp;
+- (BOOL)hasMinuteInComponent:(WOComponent *)_comp;
+- (BOOL)hasHourInComponent:(WOComponent *)_comp;
+- (BOOL)hasDayInComponent:(WOComponent *)_comp;
+- (BOOL)hasMonthInComponent:(WOComponent *)_comp;
+- (BOOL)hasYearInComponent:(WOComponent *)_comp;
+
+@end
+
+#endif /* __WEExtensions_WECalendarField_H__ */
diff --git a/skyrix-sope/WEExtensions/WECalendarField.m b/skyrix-sope/WEExtensions/WECalendarField.m
new file mode 100644 (file)
index 0000000..a5778d9
--- /dev/null
@@ -0,0 +1,1131 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WECalendarField.h"
+#include <NGObjWeb/NGObjWeb.h>
+#include <NGExtensions/NGExtensions.h>
+#include "WEClientCapabilities.h"
+#include "common.h"
+
+static Class StrClass = Nil;
+
+@implementation WECalendarField
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
+
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  StrClass = [NSString class];
+}
+
+static NSString *retStrForInt(int i) {
+  // TODO: find out good statics
+  return [[StrClass alloc] initWithFormat:@"%i", i];
+}
+static NSString *retStr02ForInt(int i) {
+  switch (i) { // TODO: find out a good count ...
+  case 0:  return @"00";
+  case 1:  return @"01";
+  case 2:  return @"02";
+  case 3:  return @"03";
+  case 4:  return @"04";
+  case 5:  return @"05";
+  case 6:  return @"06";
+  case 7:  return @"07";
+  case 8:  return @"08";
+  case 9:  return @"09";
+  default: 
+    // TODO: add log ...
+    return [[StrClass alloc] initWithFormat:@"%02i", i];
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations: _config template:_subs])) {
+    self->name           = OWGetProperty(_config, @"name");
+    self->date           = OWGetProperty(_config, @"date");
+    
+    // time field associations
+    self->hour           = OWGetProperty(_config, @"hour");
+    self->minute         = OWGetProperty(_config, @"minute");
+    self->second         = OWGetProperty(_config, @"second");
+    self->useTextField   = OWGetProperty(_config, @"useTextField");
+    self->hourInterval   = OWGetProperty(_config, @"hourInterval");
+    self->minuteInterval = OWGetProperty(_config, @"minuteInterval");
+    self->secondInterval = OWGetProperty(_config, @"secondInterval");
+
+    // date field associations
+    self->year           = OWGetProperty(_config, @"year");
+    self->month          = OWGetProperty(_config, @"month");
+    self->day            = OWGetProperty(_config, @"day");
+    self->format         = OWGetProperty(_config, @"format");
+
+    self->template = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->name release];
+  [self->date release];
+  
+  /* time field associations */
+  [self->hour           release];
+  [self->minute         release];
+  [self->second         release];
+  [self->useTextField   release];
+  [self->hourInterval   release];
+  [self->minuteInterval release];
+  [self->secondInterval release];
+
+  /* date field associations */
+  [self->year   release];
+  [self->month  release];
+  [self->day    release];
+  [self->format release];
+  
+  [self->template release];
+  [super dealloc];
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  [self _takeValuesFromTimeFieldRequest:_rq inContext:_ctx];
+  [self _takeValuesFromDateFieldRequest:_rq inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  id result = nil;
+
+  result = [self _invokeActionForTimeFieldRequest:_rq inContext:_ctx];
+  if (result == nil)
+    result = [self _invokeActionForDateFieldRequest:_rq inContext:_ctx];
+  
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [_response appendContentString:
+             @"<table border='0' cellpadding='0' cellspacing='0'>"
+             @"<tr>"
+             @"<td align='left' valign='bottom'>"];
+  [self _appendTimeFieldToResponse:_response inContext:_ctx];
+  
+  [_response appendContentString:
+             @"</td>"
+             @"<td align='left' valign='bottom'>"];
+  
+  [self _appendDateFieldToResponse:_response inContext:_ctx];
+
+  [_response appendContentString:
+             @"</td>"
+             @"</tr>"
+             @"</table>"];
+}
+
+@end /* WECalendarField */
+
+@implementation WECalendarField(WETimeFieldImplementation)
+
+/* Private Methodes */
+
+- (NSString *)_divIDAndScriptInContext:(WOContext *)_ctx
+  response:(WOResponse *)_response
+{
+  int divCount;
+  
+  divCount = [[_ctx valueForKey: @"WETimeFieldScript"] intValue];
+  if (divCount == 0) {
+    [_response appendContentString:
+      @"<style type=\"text/css\">\n"
+      @"<!--\n"
+      @"A.DDLlink { width: 23px; font: normal 10pt Arial; color: "
+      @"#6F1537; text-decoration: none; } \n"
+      @"A.DDLlink:hover { color: red; background: #FAE8B8; } \n"
+      @"//-->\n"
+      @"</style>"];
+    [_response appendContentString:
+      @"<script language=\"JavaScript\">\n"
+      @"<!--\n"
+      @"var DDLlayerCount = 1000;\n"
+      @"function DDLopen(layerObj,el) {\n"
+      @"  if (layerObj.style.visibility == 'hidden') {\n"
+      @"    layerObj.style.visibility = 'visible';\n"
+      @"    layerObj.style.zIndex     = DDLlayerCount;\n"
+      @"    formObj = DDLformField(el);\n"
+      @"    formObj.contentEditable = false;\n"
+      @"    DDLlayerCount++;\n"
+      @"    "
+      @"  } else { layerObj.style.visibility = 'hidden'; }\n"
+      @"}\n\n"
+      @"function DDLreturn(layerObj,el,value) {\n"
+      @"  formObj = DDLformField(el);\n"
+      @"  formObj.value = value;\n"
+      @"  formObj.contentEditable = true;\n"
+      @"  layerObj.style.visibility = 'hidden';\n"
+      @"}\n"
+      @"function DDLformField(el) {\n"
+      @"  for (i = 0; i < document.forms.length; i++)\n"
+      @"    for (j = 0; j < document.forms[i].elements.length; j++)\n"
+      @"      if (document.forms[i].elements[j].name == el)\n"
+      @"        return document.forms[i].elements[j];\n"
+      @"}\n"
+      @"//-->\n"
+      @"</script>"];
+  }
+  [_ctx takeValue:[NSNumber numberWithInt:(divCount+1)]
+        forKey:@"WETimeFieldScript"];
+  
+  return [StrClass stringWithFormat:@"dropDownDiv%i", divCount];
+}
+
+- (void)_appendSelectToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  elementIDComponent:(NSString *)_elementIDComponent
+  count:(int)_count
+  selectedIndex:(int)_idx
+  interval:(int)_interval
+{
+  WEClientCapabilities *ccaps;
+  NSString *tmp;
+  int      i;
+  NSString *userAgent;
+  BOOL     isMSIE;
+  NSString *divID;
+  NSString *img;
+  NSString *elementId;
+
+  ccaps     = [[_ctx request] clientCapabilities];
+  userAgent = [[_ctx request] headerForKey: @"user-agent"];
+  isMSIE    = [ccaps isInternetExplorer];
+  elementId = [self elementIdWithSuffix:_elementIDComponent ctx:_ctx];
+  
+  divID = [self _divIDAndScriptInContext:_ctx response:_response];
+  
+  img = WEUriOfResource(@"downstairs.gif", _ctx);
+
+  if (isMSIE && img) {
+    NSString *s;
+    
+    [_response appendContentString:@"<input readonly=\"readonly\" name=\""];
+    [_response appendContentString:elementId];
+    [_response appendContentString:@"\" value=\""];
+
+    s = retStr02ForInt(_idx);
+    [_response appendContentHTMLAttributeValue:s];
+    [s release];
+    
+    [_response appendContentString:
+                 @"\" type=\"text\" size=\"2\" maxlength=\"2\""];
+#if 0
+    [_response appendContentString:@" style=\"background-color: #FFDAAA;\""];
+#endif
+    [_response appendContentString:@" /><img border=\"0\" src=\""];
+    [_response appendContentString:img];
+    [_response appendContentString:@"\" onClick=\""];
+    [_response appendContentString:@"javascript:DDLopen("];
+    [_response appendContentString:divID];
+    [_response appendContentString:@",'"];
+    [_response appendContentString:elementId];
+    [_response appendContentString:@"')\" /><br />"];
+    [_response appendContentString:@"<div id=\""];
+    [_response appendContentString:divID];
+    [_response appendContentString:
+      @"\" style=\"position: absolute; overflow: auto; height: 150; width: 47;"
+      @" background: #FFDAAA; border: 1 solid; "
+      @"visibility: hidden; padding: 0 0 0 2;\">"];
+  }
+  else {
+    [_response appendContentString:@"<select name=\""];
+    [_response appendContentString:elementId];
+    [_response appendContentString:@"\">"];
+  }
+  
+  for (i = 0; i <= _count; i += _interval) {
+    tmp = retStr02ForInt(i);
+    if (isMSIE && img) {
+      NSString *s;
+
+      s = [[StrClass alloc] initWithFormat:
+         @"<a class=\"DDLlink\" href=\"javascript:DDLreturn(%@,'%@','%@')\">%@"
+         @"</a><br />",
+                    divID, elementId, tmp, tmp];
+      [_response appendContentString:s];
+      [s release];
+    }
+    else {
+      [_response appendContentString:@"<option value=\""];
+      [_response appendContentString:tmp];
+      [_response appendContentString:@"\""];
+      [_response appendContentString:
+                   (i == _idx) ? @" selected=\"selected\"" : @""];
+      [_response appendContentString:@">"];
+      [_response appendContentString:tmp];
+      [_response appendContentString:@"</option>"];
+    }
+    [tmp release]; tmp = nil;
+  }
+
+  if (isMSIE && img)
+    [_response appendContentString:@"</div>"];
+  else
+    [_response appendContentString:@"</select>"];
+}
+
+/* handle request */
+
+- (void)_takeValuesFromTimeFieldRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *comp;
+  id          formValue;
+  BOOL        tuseTField;
+  NSString    *elementId;
+  NSArray     *ta;
+  int         idx;
+  
+  comp = [_ctx component];
+  tuseTField = self->useTextField
+    ? [[self->useTextField valueInComponent: comp] boolValue]
+    : NO;
+  
+  if (tuseTField) {
+    // TextField value
+    elementId = [self elementIdWithSuffix:@"" ctx:_ctx];
+    if ((formValue = [_request formValueForKey:elementId])) {
+      int intValue, cnt;
+      
+      ta = [formValue componentsSeparatedByString:@":"];
+      cnt = [ta count];
+      
+      idx = 0;
+      if ([self isHourSettable]) {
+        intValue = (idx < cnt) ? [[ta objectAtIndex:idx] intValue] : 0;
+        [self setHour:intValue inComponent:comp];
+        idx++;
+      }
+      if ([self isMinuteSettable]) {
+        intValue = (idx < cnt) ? [[ta objectAtIndex:idx] intValue] : 0;
+        [self setMinute:intValue inComponent:comp];
+        idx++;
+      }
+      if ([self isSecondSettable]) {
+        intValue = (idx < cnt) ? [[ta objectAtIndex:idx] intValue] : 0;        
+        [self setSecond:intValue inComponent:comp];
+      }
+    }
+  }
+  else {
+    elementId = [self elementIdWithSuffix:@"hour" ctx:_ctx];
+    if ((formValue = [_request formValueForKey:elementId])) {
+      if ([self isHourSettable])
+        [self setHour:[formValue intValue] inComponent:comp];
+    }
+
+    elementId = [self elementIdWithSuffix:@"minute" ctx:_ctx];
+    if ((formValue = [_request formValueForKey:elementId])) {
+      if ([self isMinuteSettable])
+        [self setMinute:[formValue intValue] inComponent:comp];
+    }
+
+    elementId = [self elementIdWithSuffix:@"second" ctx:_ctx];
+    if ((formValue = [_request formValueForKey:elementId])) {
+      if ([self isSecondSettable])
+        [self setSecond:[formValue intValue] inComponent:comp];
+    }
+  }
+  
+  /* template */
+  [_ctx appendElementIDComponent:@"timeField"];
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)_invokeActionForTimeFieldRequest:(WORequest *)_rq
+  inContext:(WOContext *)_ctx
+{
+  return [self->template invokeActionForRequest:_rq inContext:_ctx];
+}
+
+/* generate response */
+
+- (void)_appendTimeFieldToResponse:(WOResponse *)_r inContext:(WOContext *)_cx{
+  NSCalendarDate *tdate;
+  WOComponent    *comp;
+  BOOL           tuseTField;
+  int            hourInt;        // hourInterval
+  int            minuteInt;      // minuteInterval
+  int            secondInt;      // secondInterval
+  NSMutableArray *ta;
+
+  comp  = [_cx component];
+  tdate = [NSCalendarDate calendarDate];
+
+  hourInt = self->hourInterval
+    ? [self->hourInterval intValueInComponent:comp] : 1;
+
+  minuteInt = self->minuteInterval
+    ? [self->minuteInterval intValueInComponent:comp] : 1;
+
+  secondInt = self->secondInterval
+    ? [self->secondInterval intValueInComponent:comp] : 1;
+
+  tuseTField = self->useTextField
+    ? [self->useTextField boolValueInComponent:comp]
+    : NO;
+  
+  // template
+  [_cx appendElementIDComponent:@"timeField"];
+  [self->template appendToResponse:_r inContext:_cx];
+  [_cx deleteLastElementIDComponent];
+  
+  // all values in one textField
+  if (tuseTField) {
+    int h, m, s;
+    NSString *tmp, *fmt;
+    // build string of values and @":"
+
+    h = [self   hourInComponent:comp];
+    m = [self minuteInComponent:comp];
+    s = [self secondInComponent:comp];
+    
+    ta = [[NSMutableArray alloc] initWithCapacity: 3];
+    fmt = @"%02i";
+    
+    if ([self hasHourInComponent:comp]) {
+      tmp = retStr02ForInt(h);
+      [ta addObject:tmp];
+      [tmp release];
+    }
+    if ([self hasMinuteInComponent:comp]) {
+      tmp = [[StrClass alloc] initWithFormat:fmt, m];
+      [ta addObject:tmp];
+      [tmp release];
+    }
+    if ([self hasSecondInComponent:comp]) {
+      tmp = [[StrClass alloc] initWithFormat:fmt, s];
+      [ta addObject:tmp];
+      [tmp release];
+    }
+    
+    tmp = [ta componentsJoinedByString:@":"];
+    [ta release]; ta = nil;
+
+    /* append to response */
+    if ([tmp length] > 0) {
+      [_r appendContentString:@"<input type=\"text\" name=\""];
+      [_r appendContentString:[self elementIdWithSuffix:@"" ctx:_cx]];
+      [_r appendContentString:@"\" value=\""];
+      [_r appendContentString:tmp];
+      [_r appendContentString:@"\""];
+      
+      tmp = retStrForInt([tmp length]);
+      [_r appendContentString:@" size=\""];
+      [_r appendContentString:tmp];
+      [_r appendContentString:@"\" maxlength=\""];
+      [_r appendContentString:tmp];
+      [_r appendContentString:@"\""];
+      [tmp release];
+      
+      [_r appendContentString:@" />"];
+    }
+  }
+  else {
+    // hour select field
+    [_r appendContentString:
+         @"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>"];
+
+    if ([self hasHourInComponent:comp]) {
+      [_r appendContentString:@"<td valign=\"bottom\">"];
+      [self _appendSelectToResponse:_r inContext:_cx
+           elementIDComponent:@"hour"
+            count:23 selectedIndex:[self hourInComponent:comp]
+            interval:hourInt];
+      [_r appendContentString:@"</td>"];
+    }
+     
+    // minute select field
+    if ([self hasMinuteInComponent:comp]) {
+      [_r appendContentString:@"<td valign=\"bottom\">"];
+      [self _appendSelectToResponse:_r inContext:_cx 
+           elementIDComponent:@"minute"
+            count:59 selectedIndex:[self minuteInComponent:comp]
+            interval:minuteInt];
+      [_r appendContentString:@"</td>"];
+    }
+    
+    // second select field
+    if ([self hasSecondInComponent:comp]) {
+      [_r appendContentString:@"<td valign=\"bottom\">"];
+      [self _appendSelectToResponse:_r inContext:_cx
+            elementIDComponent:@"second"
+            count:59 selectedIndex:[self secondInComponent:comp]
+            interval:secondInt];
+      [_r appendContentString:@"</td>"];
+    }
+    [_r appendContentString:@"</tr></table>"];
+
+  } /* end of (!tuseTField) */
+}
+
+@end /* WECalendarField(WETimeFieldImplementation */
+
+@implementation WECalendarField(WEDateFieldImplementation)
+
+- (void)_takeValuesFromDateFieldRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString       *tformat;
+  NSCalendarDate *tdate;
+  int            tyear;
+  int            tmonth;
+  int            tday;
+  WOComponent    *comp;
+  NSString       *elementId;
+  
+  comp = [_ctx component];
+
+  tformat = [self->format stringValueInComponent: comp];
+  if (tformat == nil) tformat = @"%Y-%m-%d";
+  elementId = [self elementIdWithSuffix:@"" ctx:_ctx];
+
+  if ([self isKindOfClass:[WECalendarField class]]) {
+    id t = tformat;
+    
+    t = [[t componentsSeparatedByString:@"%H"] componentsJoinedByString:@""];
+    t = [[t componentsSeparatedByString:@"%M"] componentsJoinedByString:@""];
+    t = [[t componentsSeparatedByString:@"%S"] componentsJoinedByString:@""];
+
+    tformat = t;
+  }
+  
+  tdate = [NSCalendarDate dateWithString:
+                          [_request formValueForKey:elementId]
+                          calendarFormat: tformat];
+  if (tdate == nil) {
+    NSLog(@"WARNING: WEDateField: field value and format do not match!");
+  }
+  else {
+    tyear  = [tdate yearOfCommonEra];
+    tmonth = [tdate monthOfYear];
+    tday   = [tdate dayOfMonth];
+
+
+    if ([self isYearSettable])  [self  setYear:tyear  inComponent:comp];
+    if ([self isMonthSettable]) [self setMonth:tmonth inComponent:comp];
+    if ([self isDaySettable])   [self   setDay:tday   inComponent:comp];
+  }
+
+  [_ctx appendElementIDComponent:@"dateField"];
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)_invokeActionForDateFieldRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  return [self->template invokeActionForRequest:_request inContext:_ctx];
+}
+
+- (void)_appendDateFieldToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WEClientCapabilities *ccaps;
+  int            tyear;
+  int            tmonth;
+  int            tday;
+  NSString       *tformat;
+  NSString       *tmp;
+  WOComponent    *comp;
+  NSCalendarDate *tdate;
+  NSString       *calendarDivID;
+  int            calendarID;
+  BOOL           isMSIE;
+  NSString       *value;
+
+  ccaps  = [[_ctx request] clientCapabilities];
+  comp   = [_ctx component];
+  tdate  = [NSCalendarDate calendarDate];
+  isMSIE = [ccaps isInternetExplorer];
+
+  if (![_ctx valueForKey:@"WEDateFieldScriptDone"])
+    [WEDateFieldScript appendWEDateFieldScriptToResponse: _response
+      inContext: _ctx
+      headBackground: HEAD_BACKGROUND_COLOR
+      headColor:      HEAD_COLOR
+      headNavColor:   HEAD_NAVIGATION_COLOR
+      labels:         nil
+      useImages:      NO];
+
+  // associations
+  tyear = ([self hasYearInComponent:comp])
+    ? [self yearInComponent:comp]
+    : [tdate yearOfCommonEra];
+  tmonth = ([self hasMonthInComponent:comp])
+    ? [self monthInComponent:comp]
+    : [tdate monthOfYear];
+  tday = ([self hasDayInComponent:comp])
+    ? [self dayInComponent:comp]
+    : [tdate dayOfMonth];
+  tformat    = self->format
+    ? [self->format stringValueInComponent: comp]
+    : @"%Y-%m-%d";
+
+  if ([self isKindOfClass:[WECalendarField class]]) {
+    id t = tformat;
+
+    t = [[t componentsSeparatedByString:@"%H"] componentsJoinedByString:@""];
+    t = [[t componentsSeparatedByString:@"%M"] componentsJoinedByString:@""];
+    t = [[t componentsSeparatedByString:@"%S"] componentsJoinedByString:@""];
+
+    tformat = t;
+  }
+
+  // input field value
+  tdate = [NSCalendarDate dateWithYear: tyear
+                          month:        tmonth
+                          day:          tday
+                          hour: 0 minute: 0 second: 0
+                          timeZone: [tdate timeZone]];
+
+  value = [tdate descriptionWithCalendarFormat: tformat];
+
+  // div id for javascript calendar
+  calendarID = ([_ctx valueForKey: @"WEDateField_DivID"])
+     ? [[_ctx valueForKey: @"WEDateField_DivID"] intValue]
+     : 0;
+  calendarDivID = [StrClass stringWithFormat:@"calendarDiv%d", calendarID];
+  calendarID++;
+  [_ctx takeValue:[NSNumber numberWithInt: calendarID]
+        forKey:@"WEDateField_DivID"];
+
+  // template
+  [_ctx appendElementIDComponent:@"dateField"];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+
+  [_response appendContentString:
+             @"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">"];
+  [_response appendContentString:
+             @"<td valign=\"top\" align=\"left\">"];
+
+  // input field
+  [_response appendContentString:@"<input type=\"text\" name=\""];
+  [_response appendContentString:[self elementIdWithSuffix:@"" ctx:_ctx]];
+  [_response appendContentString:@"\" value=\""];
+  [_response appendContentString:value];
+  [_response appendContentString:@"\" size=\""];
+  [_response appendContentString:
+             [[NSNumber numberWithInt: [value length]] stringValue]];
+  [_response appendContentString:@"\" maxlength=\""];
+  [_response appendContentString:
+             [[NSNumber numberWithInt: [value length]] stringValue]];
+  [_response appendContentString:@"\" />"];
+    
+  /* link to calendar panel */
+  [_response appendContentString:  @" <a href=\"javascript:doNothing()\" "];
+  [_response appendContentString: @"onClick=\""];
+  tmp = @"javascript:%@toggleCalendar('%@',%@%@,'%@')";
+  tmp = [[StrClass alloc] initWithFormat: tmp,
+              (isMSIE) ? @"" : @"actPos;",                  // layer position
+              [self elementIdWithSuffix:@"" ctx:_ctx],      // form element
+              (isMSIE) ? @"" : @"document.", calendarDivID, // calendar DIV
+              tformat];                                     // dateFormat
+  [_response appendContentString: tmp];
+  [tmp release];
+  [_response appendContentString: @"\">"];
+  
+  // calendar image
+  tmp = WEUriOfResource(@"icon_popupcalendar.gif", _ctx);
+
+  if (tmp) {
+    tmp = [[StrClass alloc] initWithFormat:
+                              @"<img border=\"0\" src=\"%@\" />", tmp];
+  }
+  else
+    tmp = @"x";
+  
+  [_response appendContentString:tmp];
+  [tmp release];
+
+  [_response appendContentString: @"</a><br />"];
+    
+  /* calendar panel */
+  [_response appendContentString: @"<div id=\""];
+  [_response appendContentString: calendarDivID];
+  [_response appendContentString: @"\" style=\"position: absolute; "];
+  [_response appendContentString: @"visibility: "];
+  [_response appendContentString: (isMSIE) ? @"hidden" : @"hide"];
+  [_response appendContentString: @";\"></div>"];
+
+  [_response appendContentString: @"</td></tr></table>"];
+}
+
+@end /* WECalendarField(WEDateFieldImplementation) */
+
+@implementation WEDateFieldScript
+
+- (id)initWithName:(NSString *)_name
+   associations:(NSDictionary *)_config
+   template:    (WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations: _config template:_subs]))
+  {
+    self->headBackground = OWGetProperty(_config, @"headBackground");
+    self->headColor      = OWGetProperty(_config, @"headColor");
+    self->headNavColor   = OWGetProperty(_config, @"headNavColor");
+    self->labels         = OWGetProperty(_config, @"labels");
+    self->useImages      = OWGetProperty(_config, @"useImages");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->useImages      release];
+  [self->headBackground release];
+  [self->headColor      release];
+  [self->headNavColor   release];
+  [self->labels         release];
+  [super dealloc];
+}
+
+
++ (void)appendWEDateFieldScriptToResponse: (WOResponse *)_response
+  inContext:      (WOContext *)_ctx
+  headBackground: (NSString *)_hBack
+  headColor:      (NSString *)_hCol
+  headNavColor:   (NSString *)_hNav
+  labels:         (id)_labels
+  useImages:      (BOOL)_useImg
+{
+  NSString *tmp;
+  NSString *tmon;
+  NSString *tweek;
+  NSString *timg;
+
+  // images...
+  NSString *firstI;
+  NSString *prevI;
+  NSString *todayI;
+  NSString *nextI;
+  NSString *lastI;
+  NSString *closeI;
+  
+  // colors
+  if (_hBack == nil) _hBack = HEAD_BACKGROUND_COLOR;
+  if (_hCol  == nil) _hCol  = HEAD_COLOR;
+  if (_hNav  == nil) _hNav  = HEAD_NAVIGATION_COLOR;
+
+  // months and weekdays
+  if (_labels   == nil) {
+    NSLog(@"WARNING: WEDateFieldScript: undefined variable 'labels'");
+    tmon  = @"var externMonths = false; \n";
+    tweek = @"var externWeekdays = false; \n";
+  }
+  else {
+    tmon = @"var externMonths = new Array("
+           @"\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\","
+           @"\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\"); \n";
+    tmon = [[StrClass alloc] initWithFormat: tmon,
+                     [_labels valueForKey: @"January"],
+                     [_labels valueForKey: @"February"],
+                     [_labels valueForKey: @"March"],
+                     [_labels valueForKey: @"April"],
+                     [_labels valueForKey: @"May"],
+                     [_labels valueForKey: @"June"],
+                     [_labels valueForKey: @"July"],
+                     [_labels valueForKey: @"August"],
+                     [_labels valueForKey: @"September"],
+                     [_labels valueForKey: @"October"],
+                     [_labels valueForKey: @"November"],
+                     [_labels valueForKey: @"December"]
+                     ];
+    tweek = @"var externWeekdays = new Array("
+            @"\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\"); \n";
+    tweek = [[StrClass alloc] initWithFormat: tweek,
+                      [_labels valueForKey: @"SundayAbbrev"],
+                      [_labels valueForKey: @"MondayAbbrev"],
+                      [_labels valueForKey: @"TuesdayAbbrev"],
+                      [_labels valueForKey: @"WednesdayAbbrev"],
+                      [_labels valueForKey: @"ThursdayAbbrev"],
+                      [_labels valueForKey: @"FridayAbbrev"],
+                      [_labels valueForKey: @"SaturdayAbbrev"]
+                      ];
+  }
+  
+  if (![_ctx valueForKey: @"WEDateFieldScriptDone"]) {
+    tmp = @"<style type='text/css'>\n"
+          @"<!--\n"
+          @"TD.heading { text-decoration: none; color: black; "
+            @"font: bold 8pt arial, helvetica; } \n "
+          @"A.focusDay { color: blue; text-decoration: none; "
+            @"font: 8pt arial, helvetica; } \n"
+          @"A.focusDay:hover { color:darkred; text-decoration: none; "
+            @"font: 8pt arial, helvetica; } \n"
+          @"A.weekday { color: blue; text-decoration: none; "
+            @"font: 8pt arial, helvetica; } \n"
+          @"A.weekday:hover { color: darkred; font: 8pt arial, helvetica; } \n"
+          @"A.navMonYear "
+            @"{ color: %@; text-decoration: none; font: 8pt Arial; }\n"
+          @"TD.topCal "
+            @"{ font: 10pt Arial; color: %@; background-color: %@; } \n"
+          @"-->\n"
+          @"</style>\n";
+    tmp = [StrClass stringWithFormat: tmp, _hNav, _hCol, _hBack];
+    [_response appendContentString: tmp];
+
+    [_response appendContentString:
+               @"<script language=\"JavaScript\">\n<!--\n"];
+    [_response appendContentString: @"var dateFormat = \"%Y-%m-%d\"; \n"];
+    [_response appendContentString: tmon];
+    [_response appendContentString: tweek];
+
+    // navigation images
+    // doppelt haelt wirklich besser
+    firstI = WEUriOfResource(@"first.gif", _ctx);
+    prevI  = WEUriOfResource(@"previous.gif", _ctx);
+    todayI = WEUriOfResource(@"non_sorted.gif", _ctx);
+    nextI  = WEUriOfResource(@"next.gif", _ctx);
+    lastI  = WEUriOfResource(@"last.gif", _ctx);
+    closeI = WEUriOfResource(@"icon_unread.gif", _ctx);
+
+    if (_useImg) {
+      NSString *s;
+      
+      timg = @"var %@=new Image(); %@.src='%@';\n"
+             @"var %@=\"<img border='0' name='%@' src='%@' />\";\n";
+      s = [[StrClass alloc] initWithFormat: timg,
+                  @"dateFieldFirst", @"dateFieldFirst", firstI,
+                  @"dateFieldFirstSRC", @"dateFieldFirstImg", firstI];
+      [_response appendContentString:s];
+      [s release];
+      s = [[StrClass alloc] initWithFormat: timg,
+                  @"dateFieldPrevious", @"dateFieldPrevious", prevI,
+                  @"dateFieldPreviousSRC", @"dateFieldPreviousImg", prevI];
+      [_response appendContentString:s];
+      [s release];
+      s = [[StrClass alloc] initWithFormat: timg,
+                  @"dateFieldToday", @"dateFieldToday", todayI,
+                  @"dateFieldTodaySRC", @"dateFieldTodayImg", todayI];
+      [_response appendContentString:s];
+      [s release];
+      s = [[StrClass alloc] initWithFormat: timg,
+                  @"dateFieldNext", @"dateFieldNext", nextI,
+                  @"dateFieldNextSRC", @"dateFieldNextImg", nextI];
+      [_response appendContentString:s];
+      [s release];
+      s = [[StrClass alloc] initWithFormat: timg,
+                  @"dateFieldLast", @"dateFieldLast", lastI,
+                  @"dateFieldLastSRC", @"dateFieldLastImg", lastI];
+      [_response appendContentString:s];
+      [s release];
+      s = [[StrClass alloc] initWithFormat: timg,
+                  @"dateFieldClose", @"dateFieldClose", closeI,
+                  @"dateFieldCloseSRC", @"dateFieldCloseImg", closeI];
+      [_response appendContentString:s];
+      [s release];
+      [_response appendContentString:@"var usesNavImages = true;\n"];
+    }
+    else {
+      [_response appendContentString:@"var dateFieldCloseSRC=\"X\";\n"];
+      [_response appendContentString:@"var dateFieldFirstSRC=\"&lt;&lt;\";\n"];
+      [_response appendContentString:@"var dateFieldPreviousSRC=\"&lt;\";\n"];
+      [_response appendContentString:@"var dateFieldTodaySRC=\"O\";\n"];
+      [_response appendContentString:@"var dateFieldNextSRC=\"&gt;\";\n"];
+      [_response appendContentString:@"var dateFieldLastSRC=\"&gt;&gt;\";\n"];
+      [_response appendContentString:@"var usesNavImages = false;\n"];
+    }
+    
+    tmp =
+#include "calendar.jsm"
+      ;
+    [_response appendContentString: tmp];
+    [_response appendContentString: @"\n//-->\n</script>"];
+    
+    [_ctx takeValue: [NSNumber numberWithBool: YES]
+          forKey: @"WEDateFieldScriptDone"];
+  }
+
+  [tmon  release];
+  [tweek release];
+}
+
+- (void)appendToResponse: (WOResponse *)_response
+  inContext: (WOContext *)_ctx
+{
+  WOComponent *comp;
+  comp = [_ctx component];
+  
+  [[self class] appendWEDateFieldScriptToResponse: _response inContext:_ctx
+    headBackground: [self->headBackground stringValueInComponent:comp]
+    headColor:      [self->headColor      stringValueInComponent:comp]
+    headNavColor:   [self->headNavColor   stringValueInComponent:comp]
+    labels:         [self->labels               valueInComponent:comp]
+    useImages:      [[self->useImages valueInComponent: comp] boolValue]];
+}
+
+@end /* WEDateFieldScript */
+
+@implementation WECalendarField(Accessors)
+
+- (NSString *)elementIdWithSuffix:(NSString *)_suffix ctx:(WOContext *)_ctx {
+  NSString *prefix = nil;
+  
+  if ((prefix = [self->name stringValueInComponent:[_ctx component]]) == nil)
+    prefix = [_ctx elementID];
+  
+  if ([_suffix length])
+    prefix = [prefix stringByAppendingString:@"_"];
+  
+  return [prefix stringByAppendingString:_suffix];
+}
+
+- (void)setSecond:(int)_second inComponent:(WOComponent *)_comp {
+  if (self->date) {
+    NSCalendarDate *d = [self->date valueInComponent:_comp];
+
+    
+    d = [NSCalendarDate dateWithYear:[d yearOfCommonEra]
+                        month:[d monthOfYear]
+                        day:[d dayOfMonth]
+                        hour:[d hourOfDay]
+                        minute:[d minuteOfHour]
+                        second:_second
+                        timeZone:[d timeZone]];
+    
+    [self->date setValue:d inComponent:_comp];
+  }
+  else {
+    [self->second setIntValue:_second inComponent:_comp];
+  }
+}
+- (int)secondInComponent:(WOComponent *)_comp {
+  return (self->date != nil)
+    ? [[self->date valueInComponent:_comp] secondOfMinute]
+    : [self->second intValueInComponent:_comp];
+}
+
+- (void)setMinute:(int)_minute inComponent:(WOComponent *)_comp {
+  if (self->date) {
+    NSCalendarDate *d;
+    
+    d = [self->date valueInComponent:_comp];
+    d = [NSCalendarDate dateWithYear:[d yearOfCommonEra]
+                        month:[d monthOfYear]
+                        day:[d dayOfMonth]
+                        hour:[d hourOfDay]
+                        minute:_minute
+                        second:[d secondOfMinute]
+                        timeZone:[d timeZone]];
+    
+    [self->date setValue:d inComponent:_comp];
+  }
+  else {
+    [self->minute setIntValue:_minute inComponent:_comp];
+  }
+}
+- (int)minuteInComponent:(WOComponent *)_comp {
+  return (self->date != nil)
+    ? [[self->date valueInComponent:_comp] minuteOfHour]
+    : [self->minute intValueInComponent:_comp];
+}
+
+- (void)setHour:(int)_hour inComponent:(WOComponent *)_comp {
+  if (self->date) {
+    NSCalendarDate *d = [self->date valueInComponent:_comp];
+
+    
+    d = [NSCalendarDate dateWithYear:[d yearOfCommonEra]
+                        month:[d monthOfYear]
+                        day:[d dayOfMonth]
+                        hour:_hour
+                        minute:[d minuteOfHour]
+                        second:[d secondOfMinute]
+                        timeZone:[d timeZone]];
+    
+    [self->date setValue:d inComponent:_comp];
+  }
+  else {
+    [self->hour setIntValue:_hour inComponent:_comp];
+  }
+}
+- (int)hourInComponent:(WOComponent *)_comp {
+  return (self->date != nil)
+    ? [[self->date valueInComponent:_comp] hourOfDay]
+    : [self->hour intValueInComponent:_comp];
+}
+
+- (void)setDay:(int)_day inComponent:(WOComponent *)_comp {
+  if (self->date) {
+    NSCalendarDate *d = [self->date valueInComponent:_comp];
+    
+    d = [NSCalendarDate dateWithYear:[d yearOfCommonEra]
+                        month:[d monthOfYear]
+                        day:_day
+                        hour:[d hourOfDay]
+                        minute:[d minuteOfHour]
+                        second:[d secondOfMinute]
+                        timeZone:[d timeZone]];
+    
+    [self->date setValue:d inComponent:_comp];
+  }
+  else {
+    [self->day setIntValue:_day inComponent:_comp];
+  }
+}
+- (int)dayInComponent:(WOComponent *)_comp {
+  return (self->date != nil)
+    ? [[self->date valueInComponent:_comp] dayOfMonth]
+    : [self->day intValueInComponent:_comp];
+}
+
+- (void)setMonth:(int)_month inComponent:(WOComponent *)_comp {
+  if (self->date) {
+    NSCalendarDate *d = [self->date valueInComponent:_comp];
+    
+    d = [NSCalendarDate dateWithYear:[d yearOfCommonEra]
+                        month:_month
+                        day:[d dayOfMonth]
+                        hour:[d hourOfDay]
+                        minute:[d minuteOfHour]
+                        second:[d secondOfMinute]
+                        timeZone:[d timeZone]];
+    
+    [self->date setValue:d inComponent:_comp];    
+  }
+  else {
+    [self->month setIntValue:_month inComponent:_comp];
+  }
+}
+- (int)monthInComponent:(WOComponent *)_comp {
+   return (self->date != nil)
+    ? [[self->date valueInComponent:_comp] monthOfYear]
+    : [self->month intValueInComponent:_comp];
+}
+
+- (void)setYear:(int)_year inComponent:(WOComponent *)_comp {
+  if (self->date) {
+    NSCalendarDate *d = [self->date valueInComponent:_comp];
+    
+    d = [NSCalendarDate dateWithYear:_year
+                        month:[d monthOfYear]
+                        day:[d dayOfMonth]
+                        hour:[d hourOfDay]
+                        minute:[d minuteOfHour]
+                        second:[d secondOfMinute]
+                        timeZone:[d timeZone]];
+    
+    [self->date setValue:d inComponent:_comp];        
+  }
+  else {
+    [self->year setIntValue:_year inComponent:_comp];
+  }
+}
+- (int)yearInComponent:(WOComponent *)_comp {
+  return (self->date != nil)
+    ? [[self->date valueInComponent:_comp] yearOfCommonEra]
+    : [self->year intValueInComponent:_comp];
+}
+
+- (BOOL)isSecondSettable {
+  return (self->date != nil)
+    ? [self->date isValueSettable] : [self->second isValueSettable];
+}
+
+- (BOOL)isMinuteSettable {
+  return (self->date != nil)
+    ? [self->date isValueSettable] : [self->minute isValueSettable];
+}
+
+- (BOOL)isHourSettable {
+  return (self->date != nil)
+    ? [self->date isValueSettable] : [self->hour isValueSettable];
+}
+
+- (BOOL)isDaySettable {
+  return (self->date != nil)
+    ? [self->date isValueSettable] : [self->day isValueSettable];
+}
+
+- (BOOL)isMonthSettable {
+  return (self->date != nil)
+    ? [self->date isValueSettable] : [self->month isValueSettable];
+}
+
+- (BOOL)isYearSettable {
+  return (self->date != nil)
+    ? [self->date isValueSettable] : [self->year isValueSettable];
+}
+
+- (BOOL)_chkDateFormatKey:(NSString *)_s inComponent:(WOComponent *)_comp {
+  NSString *fmt;
+  
+  if (self->format == nil)
+    return YES;
+  
+  fmt = [self->format stringValueInComponent:_comp];
+  return ([fmt rangeOfString:_s].length > 0) ? YES : NO;
+}
+
+- (BOOL)hasSecondInComponent:(WOComponent *)_comp {
+  return (self->date)
+    ? [self _chkDateFormatKey:@"S" inComponent:_comp]
+    : (self->second != nil ? YES : NO);
+}
+
+- (BOOL)hasMinuteInComponent:(WOComponent *)_comp {
+  return (self->date)
+    ? [self _chkDateFormatKey:@"M" inComponent:_comp]
+    : (self->minute != nil ? YES : NO);
+}
+
+- (BOOL)hasHourInComponent:(WOComponent *)_comp {
+  return (self->date)
+    ? [self _chkDateFormatKey:@"H" inComponent:_comp]
+    : (self->hour != nil ? YES : NO);
+}
+
+- (BOOL)hasDayInComponent:(WOComponent *)_comp {
+  return (self->date)
+    ? [self _chkDateFormatKey:@"d" inComponent:_comp]
+    : (self->day != nil ? YES : NO);
+}
+
+- (BOOL)hasMonthInComponent:(WOComponent *)_comp {
+  return (self->date)
+    ? [self _chkDateFormatKey:@"m" inComponent:_comp]
+    : (self->month != nil ? YES : NO);
+}
+
+- (BOOL)hasYearInComponent:(WOComponent *)_comp {
+  return (self->date)
+    ? [self _chkDateFormatKey:@"Y" inComponent:_comp]
+    : (self->year != nil ? YES : NO);
+}
+
+@end /* WECalendarField */
diff --git a/skyrix-sope/WEExtensions/WEClientCapabilities.h b/skyrix-sope/WEExtensions/WEClientCapabilities.h
new file mode 100644 (file)
index 0000000..8e64618
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WEClientCapabilities.h>
diff --git a/skyrix-sope/WEExtensions/WECollapsibleComponentContent.m b/skyrix-sope/WEExtensions/WECollapsibleComponentContent.m
new file mode 100644 (file)
index 0000000..ccc9ba2
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@class WOAssociation;
+
+@interface WECollapsibleComponentContent : WODynamicElement
+{
+@protected
+  WOAssociation *condition;
+  WOAssociation *visibility;
+  
+  WOAssociation *allowScript; /* perform clicks on browser (use javaScript) */
+  
+  WOElement     *template;
+}
+@end
+
+@interface WECollapsibleAction : WODynamicElement
+{
+@protected
+  WOAssociation *openedImageFileName;
+  WOAssociation *closedImageFileName;
+  WOAssociation *framework;
+  WOAssociation *openedLabel;
+  WOAssociation *closedLabel;
+  WOAssociation *submitActionName;
+  WOAssociation *action; // if submit button, use submitActionName instead
+  WOAssociation *fragmentIdentifier;
+  WOAssociation *isClicked;
+
+  WOElement *template;
+}
+@end
+
+#include <NGObjWeb/NGObjWeb.h>
+#include "WEContextConditional.h"
+#include "WEClientCapabilities.h"
+#include "common.h"
+
+static NSString *WECollapsible_TitleMode   = @"WECollapsible_TitleMode";
+static NSString *WECollapsible_ContentMode = @"WECollapsible_ContentMode";
+static NSString *WECollapsible_IsCollapsed = @"WECollapsible_IsCollapsed";
+static NSString *WECollapsible_ScriptId    = @"WECollapsible_ScriptId";
+static NSString *WECollapsible_HasScript   = @"WECollapsible_HasScript";
+static NSString *Yes                       = @"YES";
+static NSString *No                        = @"NO";
+
+@implementation WECollapsibleComponentContent
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmp
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmp])) {
+    self->condition   = WOExtGetProperty(_config, @"condition");
+    self->visibility  = WOExtGetProperty(_config, @"visibility");
+    self->allowScript = WOExtGetProperty(_config, @"allowScript");
+
+    if (self->visibility == nil)
+      NSLog(@"WARNING: WECollapsibleComponent 'visibility' not set");
+
+    if (self->visibility && ![self->visibility isValueSettable])
+      NSLog(@"WARNING: WECollapsibleComponent 'visibility' is not settable");
+    
+    self->template = [_tmp retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->condition   release];
+  [self->visibility  release];
+  [self->allowScript release];
+  [self->template    release];
+  [super dealloc];
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  BOOL isCollapsed;
+
+  isCollapsed = ![self->visibility boolValueInComponent:[_ctx component]];
+
+  // content
+  if (!isCollapsed) {
+    [_ctx setObject:Yes forKey:WECollapsible_ContentMode];
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+    [_ctx removeObjectForKey:WECollapsible_ContentMode];
+  }
+
+  // title
+  [_ctx setObject:Yes forKey:WECollapsible_TitleMode];
+
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+
+  [_ctx removeObjectForKey:WECollapsible_TitleMode];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  id   result = nil;
+  BOOL isCollapsed;
+
+  isCollapsed = ![self->visibility boolValueInComponent:[_ctx component]];
+  
+  // title
+  [_ctx setObject:Yes forKey:WECollapsible_TitleMode];
+  [_ctx setObject:Yes forKey:WECollapsible_ContentMode];
+  [_ctx setObject:(isCollapsed) ? Yes : No forKey:WECollapsible_IsCollapsed];
+
+  result = [self->template invokeActionForRequest:_request inContext:_ctx];
+  isCollapsed = [[_ctx objectForKey:WECollapsible_IsCollapsed] boolValue];
+
+  if ([self->visibility isValueSettable])
+    [self->visibility setBoolValue:!isCollapsed inComponent:[_ctx component]];
+
+  [_ctx removeObjectForKey:WECollapsible_IsCollapsed];
+  [_ctx removeObjectForKey:WECollapsible_ContentMode];
+  [_ctx removeObjectForKey:WECollapsible_TitleMode];
+  
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  WOComponent *comp;
+  BOOL        isCollapsed;
+  BOOL        doScript;
+  NSString    *scriptId;
+
+  comp     = [_ctx component];
+  doScript = [self->allowScript boolValueInComponent:comp];
+  scriptId = [[[_ctx elementID] componentsSeparatedByString:@"."]
+                     componentsJoinedByString:@"_"];
+
+  if (doScript) {
+    WEClientCapabilities *ccaps;
+    
+    ccaps    = [[_ctx request] clientCapabilities];
+    doScript = [ccaps isInternetExplorer];
+  }
+
+  if (doScript)
+    [_ctx setObject:scriptId forKey:WECollapsible_ScriptId];
+  
+  if ([self->visibility valueInComponent:comp] == nil) {
+    isCollapsed = ![self->condition boolValueInComponent:comp];
+    if ([self->visibility isValueSettable])
+      [self->visibility setBoolValue:!isCollapsed inComponent:comp];
+  }
+  else
+    isCollapsed = ![self->visibility boolValueInComponent:comp];
+
+  // append title
+  [_ctx setObject:Yes forKey:WECollapsible_TitleMode];
+  [_ctx setObject:(isCollapsed) ? Yes : No forKey:WECollapsible_IsCollapsed];
+
+  [self->template appendToResponse:_resp inContext:_ctx];
+  
+  [_ctx removeObjectForKey:WECollapsible_IsCollapsed];
+  [_ctx removeObjectForKey:WECollapsible_TitleMode];
+  
+  // append content
+  if (!isCollapsed || doScript) {
+    [_ctx setObject:Yes forKey:WECollapsible_ContentMode];
+    if (doScript) {
+      [_resp appendContentString:@"<div class=\"collapsible\" "];
+      [_resp appendContentString:@"id=\"collapsible"];
+      [_resp appendContentString:scriptId];
+      [_resp appendContentString:@"\" style=\"display:"];
+      [_resp appendContentString:(isCollapsed) ? @"none" : @"block"];
+      [_resp appendContentString:@";\">"];
+    }
+    
+    [self->template appendToResponse:_resp inContext:_ctx];
+    
+    if (doScript)
+      [_resp appendContentString:@"</div>"];
+    [_ctx removeObjectForKey:WECollapsible_ContentMode];
+  }
+  [_ctx removeObjectForKey:WECollapsible_ScriptId];
+}
+@end /* WECollapsibleComponentContent */
+
+@implementation WECollapsibleAction
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_temp
+{
+  if ((self = [super initWithName:_name associations:_config template:_temp])) {
+    self->openedImageFileName = WOExtGetProperty(_config, @"openedImageFileName");
+    self->closedImageFileName = WOExtGetProperty(_config, @"closedImageFileName");
+    self->framework           = WOExtGetProperty(_config, @"framework");
+    self->openedLabel         = WOExtGetProperty(_config, @"openedLabel");
+    self->closedLabel         = WOExtGetProperty(_config, @"closedLabel");
+    self->submitActionName    = WOExtGetProperty(_config, @"submitActionName");
+    self->action              = WOExtGetProperty(_config, @"action");
+    self->fragmentIdentifier  = WOExtGetProperty(_config, @"fragmentIdentifier");
+    self->isClicked           = WOExtGetProperty(_config, @"isClicked");
+
+    self->template = [_temp retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->openedImageFileName release];
+  [self->closedImageFileName release];
+  [self->framework           release];
+  [self->openedLabel         release];
+  [self->closedLabel         release];
+  [self->submitActionName    release];
+  [self->action              release];
+  [self->fragmentIdentifier  release];
+  [self->isClicked           release];
+  [self->template            release];
+  [super dealloc];
+}
+
+/* requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *eid;
+
+  eid = [_ctx elementID];
+
+  if ([_request formValueForKey:[eid stringByAppendingString:@".c.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:[[_ctx senderID] stringByAppendingString:@".c"]];
+  }
+  else if ([_request formValueForKey:[eid stringByAppendingString:@".e.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:[[_ctx senderID] stringByAppendingString:@".e"]];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  NSString    *state;
+  BOOL        doForm;
+  
+  state = [[_ctx currentElementID] stringValue];
+  
+  doForm = ([_ctx isInForm] && self->submitActionName &&
+            ([self->submitActionName valueInComponent:[_ctx component]]));
+  
+  [_ctx consumeElementID]; // consume state-id
+    
+  if ([state isEqualToString:@"e"]) {
+    [_ctx setObject:[NSNumber numberWithBool:YES]
+          forKey:WECollapsible_IsCollapsed];
+    
+    if (doForm)
+      [self->submitActionName valueInComponent:[_ctx component]];
+    else if ([self->action valueInComponent:[_ctx component]] != nil)
+      [self->action valueInComponent:[_ctx component]];
+  }
+  else if ([state isEqualToString:@"c"]) {
+    [_ctx setObject:[NSNumber numberWithBool:NO]
+          forKey:WECollapsible_IsCollapsed];
+    
+    if (doForm)
+      [self->submitActionName valueInComponent:[_ctx component]];
+    else if ([self->action valueInComponent:[_ctx component]] != nil)
+      [self->action valueInComponent:[_ctx component]];
+  }
+  if ([self->isClicked isValueSettable])
+    [self->isClicked setBoolValue:YES inComponent:[_ctx component]];
+    
+  return nil; 
+}
+
+- (void)_appendScriptWithID:(NSString *)scriptId 
+  label:(NSString *)label imageURL:(NSString *)img
+  toResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx 
+{
+  WOComponent *comp;
+    NSString *openedImg  = nil;
+    NSString *closedImg  = nil;
+    NSString *openLabel  = nil;
+    NSString *closeLabel = nil;
+
+    comp       = [_ctx component];
+    closedImg  = [self->closedImageFileName stringValueInComponent:comp];
+    openedImg  = [self->openedImageFileName stringValueInComponent:comp];
+    openLabel  = [self->openedLabel         stringValueInComponent:comp];
+    closeLabel = [self->closedLabel         stringValueInComponent:comp];
+
+    closedImg = WEUriOfResource(closedImg, _ctx);
+    openedImg = WEUriOfResource(openedImg, _ctx);
+
+    if (![_ctx objectForKey:WECollapsible_HasScript]) {
+      [_resp appendContentString:
+           @"\n<script language=\"JavaScript\">\n"
+           @"<!--\n"
+           @"function toggleColl(el, img1, img2, alt1, alt2)\n"
+           @"{\n"
+           @"  whichEl = eval(\"collapsible\" + el);\n"
+           @"  whichIm = event.srcElement;\n"
+           @"  if (whichEl.style.display == \"none\") {\n"
+           @"          whichEl.style.display = \"block\";\n"
+           @"          whichIm.src = img1;\n"
+           @"       whichIm.alt = alt1;\n"
+           @"  }\n"
+           @"  else {\n"
+           @"          whichEl.style.display = \"none\";\n"
+           @"      whichIm.src = img2;\n"
+           @"       whichIm.alt = alt2;\n"
+           @"   }\n"
+           @"}\n"
+           @"//-->\n"
+           @"</script>\n"];
+      [_ctx setObject:Yes forKey:WECollapsible_HasScript];
+    }
+    
+    [_resp appendContentString:@"<a href=\"#\" onclick=\"toggleColl('"];
+    [_resp appendContentString:scriptId];
+    [_resp appendContentString:@"','"];
+    [_resp appendContentHTMLString:openedImg];
+    [_resp appendContentString:@"','"];
+    [_resp appendContentHTMLString:closedImg];
+    [_resp appendContentString:@"','"];
+    [_resp appendContentHTMLString:openLabel];
+    [_resp appendContentString:@"','"];
+    [_resp appendContentHTMLString:closeLabel];
+    [_resp appendContentString:@"'); return false\"><img "];
+    if (label) {
+      [_resp appendContentString:@"alt=\""];
+      [_resp appendContentString:label];
+      [_resp appendContentString:@"\" title=\""];
+      [_resp appendContentString:label];
+      [_resp appendContentString:@"\" "];
+    }
+    [_resp appendContentString:@"border=\"0\" name=\"imEx\" src=\""];
+    [_resp appendContentString:img];
+    [_resp appendContentString:@"\" /></a>"];
+}
+
+- (void)_appendLinkWithFragmentID:(NSString *)fragId
+  label:(NSString *)label imageURL:(NSString *)img
+  isCollapsed:(BOOL)isCollapsed
+  toResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx 
+{
+  [_resp appendContentString:@"<a href=\""];
+  [_resp appendContentString:[_ctx componentActionURL]];
+  if ([fragId length] > 0) {
+    [_resp appendContentString:@"#"];
+    [_resp appendContentString:fragId];
+  }
+  [_resp appendContentString:@"\">"];
+  
+  if (img) {
+    [_resp appendContentString:@"<img border=\"0\" src=\""];
+    [_resp appendContentString:img];
+    [_resp appendContentString:@"\""];
+    if (label) {
+      [_resp appendContentString:@" alt=\""];
+      [_resp appendContentString:label];
+      [_resp appendContentString:@"\" title=\""];
+      [_resp appendContentString:label];
+      [_resp appendContentString:@"\""];
+    }
+    [_resp appendContentString:@" />"];
+  }
+  else
+    [_resp appendContentString:(isCollapsed) ? @"[+]" : @"[-]"];
+    
+  [_resp appendContentString:@"</a>"];
+}
+
+- (void)appendToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  /* TODO: split up this huge method */
+  BOOL        isCollapsed;
+  BOOL        doForm;
+  BOOL        doScript;
+  WOComponent *comp;
+  NSString    *img      = nil;
+  NSString    *label    = nil;
+  NSString    *fragId   = nil;
+  NSString    *scriptId = nil;
+  
+  comp   = [_ctx component];
+  fragId = [self->fragmentIdentifier stringValueInComponent:comp];
+
+  isCollapsed = [[_ctx objectForKey:WECollapsible_IsCollapsed] boolValue];
+  scriptId    = [_ctx objectForKey:WECollapsible_ScriptId];
+  doScript    = [scriptId length] > 0 ? YES : NO;
+  
+  img = (isCollapsed)
+    ? [self->closedImageFileName stringValueInComponent:comp]
+    : [self->openedImageFileName stringValueInComponent:comp];
+
+  label = (isCollapsed)
+    ? [self->closedLabel stringValueInComponent:comp]
+    : [self->openedLabel stringValueInComponent:comp];
+
+  img = WEUriOfResource(img, _ctx);
+
+  /*
+  if (isCollapsed)
+    [_resp appendContentString:@"&nbsp;"];
+  */
+
+  doForm = ([_ctx isInForm] && self->submitActionName && img);
+
+  [_ctx appendElementIDComponent:(isCollapsed) ? @"c" : @"e"];
+  if (doScript) {
+    [self _appendScriptWithID:scriptId label:label imageURL:img
+          toResponse:_resp inContext:_ctx];
+  }
+  else if (doForm) {
+    [_resp appendContentString:@"<input type=\"image\" border=\"0\" name=\""];
+    [_resp appendContentString:[_ctx elementID]];
+    [_resp appendContentString:@"\" src=\""];
+    [_resp appendContentString:img];
+    [_resp appendContentString:@"\" />"];
+  }
+  else {
+    [self _appendLinkWithFragmentID:fragId label:label imageURL:img
+          isCollapsed:isCollapsed
+          toResponse:_resp inContext:_ctx];
+  }
+  
+  if (fragId) {
+    WEClientCapabilities *ccaps;
+    
+    ccaps    = [[_ctx request] clientCapabilities];
+    
+    [_resp appendContentString:@"<a name=\""];
+    [_resp appendContentString:fragId];
+    [_resp appendContentString:@"\">&nbsp;</a>"];
+    if ([self->isClicked boolValueInComponent:comp] &&
+        ([ccaps isInternetExplorer] || [ccaps isMozilla] || [ccaps isNetscape6])) {
+      if ([self->isClicked isValueSettable])
+        [self->isClicked setBoolValue:NO inComponent:comp];
+      
+      [_resp appendContentString:
+             [NSString stringWithFormat:
+             @"\n<script language=\"JavaScript\">\n"
+             @"<!--\n"
+             @"  window.location.hash=\"#%@\";\n"
+             @"//-->\n"
+             @"</script>\n",
+             fragId]];
+    }
+  }
+  else
+    [_resp appendContentString:@"&nbsp;"];
+  
+  if (label && !doScript) {
+    if (!doForm) {
+      [_resp appendContentString:@"<a href=\""];
+      [_resp appendContentString:[_ctx componentActionURL]];
+      if (fragId) {
+        [_resp appendContentString:@"#"];
+        [_resp appendContentString:fragId];
+      }
+      [_resp appendContentString:@"\">"];
+    }
+    
+    [_resp appendContentString:label];
+
+    if (!doForm)
+      [_resp appendContentString:@"</a>"];
+  }
+  [_ctx deleteLastElementIDComponent];
+}
+
+@end /* WECollapsibleAction */
+
+@interface WECollapsibleTitleMode: WEContextConditional
+@end
+
+@implementation WECollapsibleTitleMode
+
+- (NSString *)_contextKey {
+  return WECollapsible_TitleMode;
+}
+
+@end /* WECollapsibleTitleMode */
+
+@interface WECollapsibleContentMode: WEContextConditional
+@end
+
+@implementation WECollapsibleContentMode
+
+- (NSString *)_contextKey {
+  return WECollapsible_ContentMode;
+}
+
+@end /* WECollapsibleContentMode */
diff --git a/skyrix-sope/WEExtensions/WEComponentValue.m b/skyrix-sope/WEExtensions/WEComponentValue.m
new file mode 100644 (file)
index 0000000..f736871
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WEComponentValue : WODynamicElement
+{
+  WOAssociation *value;
+  WOAssociation *boolValue;
+  WOAssociation *stringValue;
+  WOAssociation *intValue;
+  WOAssociation *unsignedIntValue;
+  WOAssociation *key;
+}
+@end
+
+#include "common.h"
+
+@implementation WEComponentValue
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmp
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmp])) {
+    int cnt = 0;
+    
+    self->value            = WOExtGetProperty(_config, @"value");
+    self->boolValue        = WOExtGetProperty(_config, @"boolValue");
+    self->stringValue      = WOExtGetProperty(_config, @"stringValue");
+    self->intValue         = WOExtGetProperty(_config, @"intValue");
+    self->unsignedIntValue = WOExtGetProperty(_config, @"unsignedIntValue");
+    self->key              = WOExtGetProperty(_config, @"key");
+
+    if (self->value)            cnt++;
+    if (self->boolValue)        cnt++;
+    if (self->stringValue)      cnt++;
+    if (self->intValue)         cnt++;
+    if (self->unsignedIntValue) cnt++;
+
+    if (cnt == 0)
+      NSLog(@"Warning: WEComponentValue neither 'value', 'boolValue',"
+            @"  'stringValue', 'intValue' nor 'unsignedIntValue' is set");
+    if (cnt > 0)
+      NSLog(@"Warning: WEComponentValue more than one '*Value' is set");
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->value);
+  RELEASE(self->boolValue);
+  RELEASE(self->stringValue);
+  RELEASE(self->intValue);
+  RELEASE(self->unsignedIntValue);
+  RELEASE(self->key);
+  [super dealloc];
+}
+#endif
+  
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *comp;
+  NSString    *k;
+  id          v;
+  SEL         sel;
+
+  comp = [_ctx component];
+  k    = [self->key stringValueInComponent:comp];
+
+  if (k == nil) return;
+
+  sel = NSSelectorFromString([k stringByAppendingString:@":"]);
+  sel = ([comp respondsToSelector:sel]) ? sel : NULL;
+
+#define _assign(_v_, _k_)                                            \
+                   {                                                 \
+                     if (sel != NULL)                                \
+                       [comp performSelector:sel withObject:_v_];    \
+                     else                                            \
+                       [comp takeValue:_v_ forKey:_k_];              \
+                   }                                                 \
+
+  if ((v = [self->value valueInComponent:comp])) {
+    _assign(v, k);
+  }
+  else if (self->boolValue) {
+    v = [NSNumber numberWithBool:[self->boolValue boolValueInComponent:comp]];
+    _assign(v, k);
+  }
+  else if ((v = [self->stringValue stringValueInComponent:comp])) {
+    _assign(v, k);
+  }
+  else if (self->intValue) {
+    v = [NSNumber numberWithInt:[self->intValue intValueInComponent:comp]];
+    _assign(v, k);
+  }
+  else if (self->unsignedIntValue) {
+    v = [NSNumber numberWithUnsignedInt:
+                  [self->unsignedIntValue unsignedIntValueInComponent:comp]];
+    _assign(v, k);
+  }
+    
+#undef _assignValue
+}
+
+@end /* WEComponentValue */
diff --git a/skyrix-sope/WEExtensions/WEContextConditional.h b/skyrix-sope/WEExtensions/WEContextConditional.h
new file mode 100644 (file)
index 0000000..806e6d5
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __WEExtensions_WEContextConditional_H__
+#define __WEExtensions_WEContextConditional_H__
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@class WOAssociation, WOElement;
+
+@interface WEContextConditional : WODynamicElement
+{
+@protected
+  WOAssociation *negate;
+  WOAssociation *contextKey;    // context key == condition
+  WOAssociation *didMatch;      // BOOL
+  
+  WOElement     *template;
+}
+
+@end /* WEContextConditional */
+
+#endif /* __WEExtensions_WEContextConditional_H__ */
diff --git a/skyrix-sope/WEExtensions/WEContextConditional.m b/skyrix-sope/WEExtensions/WEContextConditional.m
new file mode 100644 (file)
index 0000000..b77f9a6
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "common.h"
+#import "WEContextConditional.h"
+
+@implementation WEContextConditional
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->negate     = WOExtGetProperty(_config, @"negate");
+    self->contextKey = WOExtGetProperty(_config, @"contextKey");
+    self->didMatch   = WOExtGetProperty(_config, @"didMatch");
+
+    self->template  = RETAIN(_c);
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->template);
+  RELEASE(self->negate);
+  RELEASE(self->contextKey);
+  RELEASE(self->didMatch);
+  [super dealloc];
+}
+#endif
+
+// accessors
+
+- (WOElement *)template {
+  return self->template;
+}
+
+- (NSString *)_contextKey {
+  return nil;
+}
+
+- (NSString *)_didMatchKey {
+  return nil;
+}
+
+// state
+
+static inline BOOL _doShow(WEContextConditional *self, WOContext *_ctx) {
+  BOOL doShow   = NO;
+  BOOL doNegate = [self->negate boolValueInComponent:[_ctx component]];
+
+  if ([self _contextKey])
+    doShow = ([_ctx objectForKey:[self _contextKey]] != nil);
+  else if (self->contextKey) {
+    id cKey = [self->contextKey valueInComponent:[_ctx component]];
+
+    doShow = ([_ctx objectForKey:cKey] != nil);
+  }
+  doShow = doNegate ? !doShow : doShow;
+  
+  if (doShow && [self->didMatch isValueSettable])
+    [self->didMatch setBoolValue:YES inComponent:[_ctx component]];
+  
+  if (doShow && [self _didMatchKey] != nil)
+    [_ctx setObject:@"YES" forKey:[self _didMatchKey]];
+  
+  return doShow;
+}
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if (_doShow(self, _ctx)) {
+    [_ctx appendElementIDComponent:@"1"];
+    [self->template takeValuesFromRequest:_request inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  NSString *state;
+
+  state = [[_ctx currentElementID] stringValue];
+  
+  if (state) {
+    [_ctx consumeElementID]; // consume state-id (on or off)
+
+    if ([state isEqualToString:@"1"]) {
+      id result;
+      
+      [_ctx appendElementIDComponent:state];
+      result = [self->template invokeActionForRequest:_request inContext:_ctx];
+      [_ctx deleteLastElementIDComponent];
+
+      return result;
+    }
+  }
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (_doShow(self, _ctx)) {
+    [_ctx appendElementIDComponent:@"1"];
+    [self->template appendToResponse:_response inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+}
+
+@end /* WEContextConditional */
diff --git a/skyrix-sope/WEExtensions/WEContextKey.m b/skyrix-sope/WEExtensions/WEContextKey.m
new file mode 100644 (file)
index 0000000..cd2df1f
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WEContextKey : WODynamicElement
+{
+  WOAssociation *key;
+  WOAssociation *value;
+  WOElement     *template;
+}
+@end
+
+#include "common.h"
+
+@implementation WEContextKey
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmp
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmp])) {
+    self->key   = WOExtGetProperty(_config, @"key");
+    self->value = WOExtGetProperty(_config, @"value");
+
+    if (self->key == nil)
+      NSLog(@"Warning! WEContextKey no key set");
+    
+    if (self->value == nil) {
+      self->value = [WOAssociation associationWithValue:@"YES"];
+      RETAIN(self->value);
+    }
+    
+    ASSIGN(self->template, _tmp);
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->key);
+  RELEASE(self->value);
+  RELEASE(self->template);
+  
+  [super dealloc];
+}
+#endif
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSString *k  = nil;
+  id       v   = nil;
+  id       tmp = nil;
+
+  k = [self->key   stringValueInComponent:[_ctx component]];
+  v = [self->value valueInComponent:[_ctx component]];
+
+  if (k && v) {
+    tmp = [_ctx objectForKey:k]; // save old context value
+    [_ctx setObject:v forKey:k];
+  }
+  
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+
+  if (k && v)   [_ctx removeObjectForKey:k];
+  if (tmp && k) [_ctx setObject:tmp forKey:k]; // restore old context value
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSString *k     = nil;
+  id       v      = nil;
+  id       tmp    = nil;
+  id       result = nil;
+
+  k = [self->key   stringValueInComponent:[_ctx component]];
+  v = [self->value valueInComponent:[_ctx component]];
+
+  if (k && v) {
+    tmp = [_ctx objectForKey:k]; // save old context value
+    [_ctx setObject:v forKey:k];
+  }
+  
+  result = [self->template invokeActionForRequest:_req inContext:_ctx];
+  
+  if (k && v)   [_ctx removeObjectForKey:k];
+  if (tmp && k) [_ctx setObject:tmp forKey:k]; // restore old context value
+  
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *k  = nil;
+  id       v   = nil;
+  id       tmp = nil;
+  
+  k = [self->key   stringValueInComponent:[_ctx component]];
+  v = [self->value valueInComponent:[_ctx component]];
+
+  if (k && v) {
+    tmp = [_ctx objectForKey:k]; // save old context value
+    [_ctx setObject:v forKey:k];
+  }
+
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  if (k && v)   [_ctx removeObjectForKey:k];
+  if (tmp && k) [_ctx setObject:tmp forKey:k]; // restore old context value
+}
+
+@end /* WEContextKey */
diff --git a/skyrix-sope/WEExtensions/WEDateField.m b/skyrix-sope/WEExtensions/WEDateField.m
new file mode 100644 (file)
index 0000000..d69276c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WECalendarField.h"
+
+/*
+  required resources:
+
+  icon_popupcalendar.gif
+  first.gif
+  previous.gif
+  non_sorted.gif
+  next.gif
+  last.gif
+  icon_unread.gif
+  
+*/
+
+@interface WEDateField : WECalendarField
+{
+}
+@end
+
+@implementation WEDateField
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+                    inContext:(WOContext *)_ctx
+{
+  [self _takeValuesFromDateFieldRequest:_request inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+                   inContext:(WOContext *)_ctx
+{
+  return [self _invokeActionForDateFieldRequest:_request inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [self _appendDateFieldToResponse:_response inContext:_ctx];
+}
+
+@end
diff --git a/skyrix-sope/WEExtensions/WEDragContainer.m b/skyrix-sope/WEExtensions/WEDragContainer.m
new file mode 100644 (file)
index 0000000..dc7d385
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+/*
+  renders this:
+
+  <...small script...>
+  <SPAN onDragStart="fnSetInfo($tag,$effectsAllowed)">
+  $content
+  </SPAN>
+
+*/
+
+@interface WEDragContainer : WODynamicElement
+{
+  WOElement     *template;
+  WOAssociation *tag;
+  WOAssociation *effectsAllowed;
+  WOAssociation *elementName;
+  WOAssociation *isDraggable;
+  
+  WOAssociation *object;
+  WOAssociation *droppedObject;
+}
+@end
+
+@interface WEDragScript : WODynamicElement
++ (void)appendDragScriptToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+@end
+
+#include "WEClientCapabilities.h"
+#include <NGObjWeb/NGObjWeb.h>
+#include <NGExtensions/NGExtensions.h>
+#include "common.h"
+
+//#define DEBUG_TAKEVALUES 1
+
+@implementation WEDragContainer
+
+static BOOL debugTakeValues = NO;
+
++ (int)version {
+  return 0 + [super version];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->tag            = WOExtGetProperty(_config, @"tag");
+    self->effectsAllowed = WOExtGetProperty(_config, @"effectsAllowed");
+    self->elementName    = WOExtGetProperty(_config, @"elementName");
+    self->isDraggable    = WOExtGetProperty(_config, @"isDraggable");
+    
+    self->object         = WOExtGetProperty(_config, @"object");
+    self->droppedObject  = WOExtGetProperty(_config, @"droppedObject");
+    
+    self->template = [_t retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->isDraggable    release];
+  [self->object         release];
+  [self->droppedObject  release];
+  [self->tag            release];
+  [self->elementName    release];
+  [self->effectsAllowed release];
+  [self->template       release];
+  [super dealloc];
+}
+
+/* processing request values */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  id formValue;
+  
+  if ((formValue = [_rq formValueForKey:[_ctx elementID]]) != nil) {
+    id obj;
+
+    if (debugTakeValues) {
+      [[_ctx component]
+            debugWithFormat:@"WEDragContainer: got value '%@' for id '%@'",
+               formValue, [_ctx elementID]];
+    }
+
+    obj = [self->object valueInComponent:[_ctx component]];
+    
+    if (debugTakeValues)
+      NSLog(@"DRAG MATCH => ok, obj is %@",obj);
+    
+    if ([self->droppedObject isValueSettable])
+      [self->droppedObject setValue:obj inComponent:[_ctx component]];
+    
+    if (obj) {
+      [_ctx takeValue:obj forKey:@"WEDragContainer_DropObject"];
+    }
+  }
+  else if (debugTakeValues) {
+    [[_ctx component]
+           debugWithFormat:@"WEDragContainer: got no value for id '%@'",
+             [_ctx elementID]];
+  }
+  
+  [self->template takeValuesFromRequest:_rq inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_rq inContext:_ctx];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *tmp = nil;
+  NSString *ttag;
+  BOOL     doDnD;
+  
+  doDnD = [[[_ctx request] clientCapabilities] doesSupportDHTMLDragAndDrop];
+    
+  if (doDnD) {
+    if (self->isDraggable)
+      doDnD = [self->isDraggable boolValueInComponent:[_ctx component]];
+  }
+  
+  [WEDragScript appendDragScriptToResponse:_response inContext:_ctx];
+  
+  ttag = [self->tag stringValueInComponent:[_ctx component]];
+
+  if (doDnD) {
+    NSString *teffect, *tdragContent;
+
+    teffect = self->effectsAllowed
+      ? [self->effectsAllowed stringValueInComponent:[_ctx component]]
+      : @"all";
+    
+    tdragContent = @"this.innerHTML";
+    
+    tmp = @"fnSetInfo('%@?%@','%@', %@)";
+    tmp = [NSString stringWithFormat:tmp,
+                      [_ctx elementID], ttag,
+                      teffect,
+                      tdragContent];
+  }
+
+  if (self->elementName || doDnD) {
+    /* Note: not using lowercase names since this might break JS? */
+    [_response appendContentString:@"<SPAN "];
+    [_response appendContentString:@"ID=\"span_"];
+    [_response appendContentString:[_ctx elementID]];
+    [_response appendContentString:@"\" "];
+  }
+  
+  if (doDnD) {
+    [_response appendContentString:@" onDragStart=\""];
+    [_response appendContentString:tmp];
+    [_response appendContentString: @"\""];
+    [_response appendContentString:@" onDrag=\"fnDrag()\""];
+    [_response appendContentString:@" onDragEnd=\"fnDragEnd()\""];
+  }
+  
+  if (self->elementName || doDnD) {
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    [_response appendContentString:@">"];
+  }
+  
+  /* add template */
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  /* close container */
+  if (self->elementName || doDnD)
+    [_response appendContentString:@"</SPAN>"];
+}
+
+/* accessors */
+
+- (WOElement *)template {
+  return self->template;
+}
+
+@end /* WEDragContainer */
+
+@implementation WEDragScript
+
++ (void)appendDragScriptToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *dragScript;
+  BOOL     doDnD;
+  
+  doDnD = [[[_ctx request] clientCapabilities] doesSupportDHTMLDragAndDrop];
+  
+  if (![[_ctx valueForKey: @"WEDragContainerScriptDone"] boolValue] && doDnD) {
+    dragScript =
+      @"<DIV ID=\"DragDIV\" STYLE=\"position: absolute; visibility: hidden; width: 150;\"></DIV>"
+      @"<SCRIPT LANGUAGE=\"JScript\">\n"
+      @"<!--\n"
+      @"function fnSetInfo(objData, effects, dragContent) {\n"
+      @"  event.dataTransfer.clearData(\"Text\");\n"
+      @"  event.dataTransfer.setData(\"Text\", objData);\n"
+      @"  event.dataTransfer.effectAllowed = effects;\n "
+      @"  DragDIV.innerHTML = dragContent;\n"
+      @"  DragDIV.style.visibility = \"visible\";\n "
+      @"  DragDIV.style.top  =window.event.clientY+document.body.scrollTop;\n"
+      @"  DragDIV.style.left =window.event.clientX+document.body.scrollLeft;\n"
+      @"  DragDIV.style.zIndex += 20; \n"
+      @"}\n"
+      @"function fnDrag() {\n"
+      @"  DragDIV.style.top  =window.event.clientY+document.body.scrollTop;\n"
+      @"  DragDIV.style.left =window.event.clientX+document.body.scrollLeft;\n"
+      @"}\n"
+      @"function fnDragEnd() {\n"
+      @"  DragDIV.innerHTML = \"\";\n"
+      @"  DragDIV.style.visibility = \"hidden\";\n"
+      @"}\n"
+      @"// -->\n"
+      @"</SCRIPT>";
+
+    [_response appendContentString: dragScript];
+    
+    [_ctx takeValue: [NSNumber numberWithBool: YES] forKey:
+          @"WEDragContainerScriptDone"];
+  }
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [[self class] appendDragScriptToResponse:_response inContext:_ctx];
+}
+
+@end /* WEDragScript */
diff --git a/skyrix-sope/WEExtensions/WEDropContainer.m b/skyrix-sope/WEExtensions/WEDropContainer.m
new file mode 100644 (file)
index 0000000..dea0506
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/WODynamicElement.h>
+
+/*
+  usage:
+
+     DropContainer: WEDropContainer {
+       elementName   = "tr";
+       isAttached    = YES;
+       tags          = ( * );
+       action        = dropAction;
+       droppedObject = droppedObject;
+       
+       swapColor     = YES;
+       activeColor   = "lightblue";
+       bgColor       = bgColor;
+     }
+     
+  renders this:
+
+    <$area BGCOLOR=white 
+        onDragEnter="fnCancelDefault()"
+        onDragOver="fnCancelDefault()"
+        onDrop="fnGetInfo()">
+       $content
+    </$area>
+*/
+
+@interface WEDropContainer : WODynamicElement
+{
+  NSDictionary  *dExtraAttrs;
+  WOAssociation *tags;
+  WOAssociation *elementName;
+  WOAssociation *isAttached;  /* bool */
+  WOAssociation *effect;
+  WOAssociation *swapColor; /* swap bgcolor if drag object is over container */
+  WOAssociation *action;
+  WOAssociation *droppedObject;
+  
+  WOElement     *template;
+}
+@end
+
+@interface WEDropScript : WODynamicElement
++ (void)appendDropScriptToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx;
+@end
+
+#include "WEClientCapabilities.h"
+#import <NGObjWeb/NGObjWeb.h>
+#import <NGExtensions/NGExtensions.h>
+#include "common.h"
+
+@implementation WEDropContainer
+
++ (int)version {
+  return 0 + [super version];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->tags            = WOExtGetProperty(_config, @"tags");
+    self->elementName     = WOExtGetProperty(_config, @"elementName");
+    self->effect          = WOExtGetProperty(_config, @"effect");
+    self->action          = WOExtGetProperty(_config, @"action");
+    self->droppedObject   = WOExtGetProperty(_config, @"droppedObject");
+    self->swapColor       = WOExtGetProperty(_config, @"swapColor");
+    self->isAttached      = WOExtGetProperty(_config, @"isAttached");
+    
+    self->template = RETAIN(_subs);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->dExtraAttrs);
+  
+  RELEASE(self->swapColor);
+  RELEASE(self->droppedObject);
+  RELEASE(self->action);
+  RELEASE(self->template);
+  RELEASE(self->effect);
+  RELEASE(self->tags);
+  RELEASE(self->elementName);
+  RELEASE(self->isAttached);
+  
+  [super dealloc];
+}
+
+- (void)setExtraAttributes:(NSDictionary *)_extras {
+  ASSIGNCOPY(self->dExtraAttrs, _extras);
+}
+
+- (void)appendExtraAttributesToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if (self->dExtraAttrs) {
+    WOComponent  *sComponent;
+    NSEnumerator *keys;
+    NSString     *key;
+    
+    sComponent = [_ctx component];
+
+    keys = [self->dExtraAttrs keyEnumerator];
+    
+    while ((key = [keys nextObject])) {
+      id value;
+      
+      value = [self->dExtraAttrs objectForKey:key];
+      
+      if (value == nil)
+        continue;
+      
+      //key   = [key lowercaseString];
+      value = [value stringValueInComponent:sComponent];
+
+      [_response appendContentCharacter:' '];
+      [_response appendContentString:key];
+      [_response appendContentString:@"=\""];
+      [_response appendContentHTMLAttributeValue:value];
+      [_response appendContentCharacter:'"'];
+    }
+  }
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  [_ctx appendElementIDComponent:@"p"];
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *op;
+  id result;
+  
+  op = [[_ctx currentElementID] stringValue];
+#if 0
+    NSLog(@"check DROP ACTION %@ ..", op);
+#endif
+  
+  if ([op isEqualToString:@"p"]) {
+    /* an action inside of the component */
+    [_ctx consumeElementID]; // consume id
+    [_ctx appendElementIDComponent:@"p"];
+    result = [self->template invokeActionForRequest:_request inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+  else if ([op isEqualToString:@"drop"]) {
+    /* an action of *this* component */
+    [_ctx consumeElementID]; // consume id
+    [_ctx appendElementIDComponent:@"drop"];
+
+#if 0
+    NSLog(@"WILL RUN DROP ACTION ..");
+#endif
+    
+    if ([self->droppedObject isValueSettable]) {
+      [self->droppedObject setValue:
+                             [_ctx valueForKey:@"WEDragContainer_DropObject"]
+                           inComponent:[_ctx component]];
+    }
+    
+    result = [self->action valueInComponent:[_ctx component]];
+    
+    [_ctx deleteLastElementIDComponent];
+  }
+  else {
+    NSLog(@"invalid element-id: did not expect '%@' id", op);
+    result = nil;
+  }
+  return result;
+}
+
+- (void)appendExtraAttributesAsJavaScriptToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  if (self->dExtraAttrs) {
+    WOComponent     *sComponent = [_ctx component];
+    NSEnumerator    *keyEnum;
+    NSString        *key;
+
+    [_response appendContentString:
+               @"\n"
+               @"<script language=\"JavaScript\">\n"
+               @"<!--\n"];
+
+    keyEnum = [self->dExtraAttrs keyEnumerator];
+    while ((key = [keyEnum nextObject])) {
+      id value;
+      
+      value = [self->dExtraAttrs objectForKey:key];
+      
+      if (value == nil)
+        continue;
+
+      if ([[key lowercaseString] isEqualToString:@"width"])
+        key = @"width";
+      else if ([[key lowercaseString] isEqualToString:@"height"])
+        key = @"height";
+      else if ([[key lowercaseString] isEqualToString:@"bgcolor"])
+        key = @"bgColor";
+      else if ([[key lowercaseString] isEqualToString:@"activecolor"])
+        key = @"activeColor";
+      else if ([[key lowercaseString] isEqualToString:@"align"])
+        key = @"align";
+      else if ([[key lowercaseString] isEqualToString:@"valign"])
+        key = @"vAlign";
+      else if ([[key lowercaseString] isEqualToString:@"colspan"])
+        key = @"colSpan";
+      else if ([[key lowercaseString] isEqualToString:@"rowspan"])
+        key = @"rowSpan";
+      else if ([[key lowercaseString] isEqualToString:@"nowrap"])
+        key = @"noWrap";
+      
+      value = [value stringValueInComponent:sComponent];
+      [_response appendContentString:
+                 [NSString stringWithFormat:@"tmp.%@ = \"%@\";\n", key, value]];
+    }
+    [_response appendContentString:
+               @"// -->\n"
+               @"</script>\n"];
+  }
+}
+
+- (void)appendToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *htmlEl;
+  NSString *ttag;
+  NSString *teffect;
+  NSString *containerID = nil;
+  BOOL     doDnD, doSwap, doAttach;
+  
+  doDnD = [[[_ctx request] clientCapabilities] doesSupportDHTMLDragAndDrop];
+
+  //doDnD = YES;
+  
+  ttag = [[self->tags valueInComponent:[_ctx component]]
+                      componentsJoinedByString:@","];
+  
+  teffect = [self->effect stringValueInComponent:[_ctx component]];
+  if (teffect == nil) teffect = @"move";
+  
+  [WEDropScript appendDropScriptToResponse:_response inContext:_ctx];
+  
+  [_ctx appendElementIDComponent:@"drop"];
+  
+  htmlEl   = [self->elementName stringValueInComponent:[_ctx component]];
+  doAttach = ([self->isAttached boolValueInComponent:[_ctx component]] &&
+             (self->elementName != nil));
+  
+  if (htmlEl == nil || doAttach) htmlEl = @"span";
+  
+  if ((self->elementName != nil) || doDnD) {
+    int containerIDc;
+    
+    [_response appendContentString: @"<"];
+    [_response appendContentString:htmlEl];
+
+    if (doDnD) {
+      /* gen unique container id */
+      
+      if ((containerID = [_ctx valueForKey:@"WEDropContainerSequence"])) {
+        containerID = AUTORELEASE([containerID copy]);
+        containerIDc = [containerID intValue];
+      }
+      else {
+        containerID  = @"0";
+        containerIDc = 0;
+      }
+      
+      [_response appendContentString:@" id=\"skydrop"];
+      if (doAttach) [_response appendContentString:@"dummy"];
+      [_response appendContentString:containerID];
+      [_response appendContentString:@"\""];
+      
+      containerIDc++;
+    
+      [_ctx takeValue:[NSString stringWithFormat:@"%i", containerIDc]
+            forKey:@"WEDropContainerSequence"];
+    }
+  }
+  
+  if (doDnD) {
+    NSString *swapOnAction  = @"";
+    NSString *swapOffAction = @"";
+    NSString *cancelAction;
+    NSString *infoAction;
+      
+
+    doSwap = self->swapColor
+      ? [self->swapColor boolValueInComponent:[_ctx component]]
+      : YES;
+
+    cancelAction = [NSString stringWithFormat:@"fnCancelDefault('%@','%@');",
+                             ttag, teffect];
+    if (doSwap) {
+      swapOnAction  = [NSString stringWithFormat:
+                                @"dropFieldSwapColor(skydrop%@,true);",
+                                containerID];
+      swapOffAction = [NSString stringWithFormat:
+                                @"dropFieldSwapColor(skydrop%@,false);",
+                                containerID];
+    }
+    
+    infoAction = [NSString stringWithFormat:@"fnGetInfo(this, '%@');",
+                           [_ctx componentActionURL]];
+
+    if (doAttach) {
+      NSString *tagName = nil;
+
+      // doAttach==YES -> self->elementName != nil
+      tagName = [self->elementName stringValueInComponent:[_ctx component]];
+      tagName = [tagName uppercaseString];
+      
+      [_response appendContentCharacter:'>'];
+      
+      [_response appendContentString:[NSString stringWithFormat:
+           @"\n"
+           @"<script language=\"JavaScript\">\n"
+           @"<!--\n"
+           @"  function onDragEnterFunc%@() {\n    %@\n     %@\n}\n"
+           @"  function onDragOverFunc%@()  {\n    %@\n     %@\n}\n"
+           @"  function onDragLeaveFunc%@() {\n %@\n     }\n"
+           @"  function onDropFunc%@()      {\n %@\n     }\n"
+           @"\n"
+           @"  tmp = document.getElementById(\"%@\");\n"
+           @"  i = 5;\n"
+           @"  while ((tmp.tagName != \"%@\") && (i >= 0)) {\n"
+           @"    tmp = tmp.parentNode;\n"
+           @"    i--;\n"
+           @"  }\n"
+           @"  tmp.ondragover    = onDragOverFunc%@;\n"
+           @"  tmp.ondragleave   = onDragLeaveFunc%@;\n"
+           @"  tmp.ondrop        = onDropFunc%@;\n"
+           @"  tmp.ondragenter   = onDragEnterFunc%@;\n"
+           @"  tmp.id            = \"%@\";\n"
+           @"// -->\n"
+           @"</script>\n",
+           containerID, cancelAction, swapOnAction,
+           containerID, cancelAction, swapOnAction,
+           containerID, swapOffAction,
+           containerID, infoAction,
+           [@"skydropdummy" stringByAppendingString:containerID],
+           tagName,
+           containerID,
+           containerID,
+           containerID,
+           containerID,
+           [@"skydrop" stringByAppendingString:containerID]]];
+
+      // remove bgColors of TR's sub TD:
+      if ([tagName isEqualToString:@"TR"]) {
+        [_response appendContentString:
+           @"\n"
+           @"<script language=\"JavaScript\">\n"
+           @"<!--\n"
+           @"list = tmp.getElementsByTagName(\"TD\");\n"
+           @"cnt  = list.length;\n"
+           @"for (i=0; i<cnt; i++) {\n"
+           @"  list[i].removeAttribute(\"bgColor\");\n"
+           @"}\n"
+           @"// -->\n"
+           @"</script>\n"];
+      }
+
+      /* append extra attributes by script */
+      [self appendExtraAttributesAsJavaScriptToResponse:_response
+                                              inContext:_ctx];
+    }
+    else {
+      [_response appendContentString:@" onDragEnter=\""];
+      [_response appendContentString:cancelAction];
+      [_response appendContentString:swapOnAction];
+
+      [_response appendContentString:@"\" onDragOver=\""];
+      [_response appendContentString:cancelAction];
+      [_response appendContentString:swapOnAction];
+
+      [_response appendContentString:@"\" onDragLeave=\""];
+      [_response appendContentString:swapOffAction];
+     
+      [_response appendContentString:@"\" onDrop=\""];
+      [_response appendContentString:infoAction];
+      [_response appendContentCharacter:'"'];
+      
+      [self appendExtraAttributesToResponse:_response inContext:_ctx];
+      [_response appendContentCharacter:'>'];
+    }
+  }
+  else if (self->elementName != nil) {
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    [_response appendContentCharacter:'>'];
+  }
+  
+  [_ctx deleteLastElementIDComponent];
+  
+  /* add template */
+  [_ctx appendElementIDComponent:@"p"];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  
+  /* close container */
+  if ((self->elementName != nil) || doDnD) {
+    [_response appendContentString:@"</"];
+    [_response appendContentString:htmlEl];
+    [_response appendContentCharacter:'>'];
+  }
+}
+
+// --- accessors ---
+
+- (WOElement *)template {
+  return self->template;
+}
+
+@end /* WEDropContainer */
+
+@implementation WEDropScript
+
++ (void)appendDropScriptToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  BOOL doDnD;
+  
+  doDnD = [[[_ctx request] clientCapabilities] doesSupportDHTMLDragAndDrop];
+  
+  if (![[_ctx valueForKey:@"WEDropContainerScriptDone"] boolValue] && doDnD) {
+    NSString *dropScript;
+    
+    dropScript =
+#include "WEDropScript.jsm"
+      ;
+    
+    [_response appendContentString:dropScript];
+    
+    [_ctx takeValue:[NSNumber numberWithBool:YES]
+          forKey:@"WEDropContainerScriptDone"];
+  }
+}
+
+- (void)appendToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  [[self class] appendDropScriptToResponse:_response inContext:_ctx];
+}
+
+@end /* WEDropScript */
diff --git a/skyrix-sope/WEExtensions/WEDropScript.h b/skyrix-sope/WEExtensions/WEDropScript.h
new file mode 100644 (file)
index 0000000..f416ee0
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+/* automatically generated from WEDropScript.js, do not edit ! */
+@"<SCRIPT LANGUAGE=\"JScript\">\n"
+@"<!--\n"
+@"function fnGetInfo(dropElem, myurl) {\n"
+@"  event.returnValue = false;\n"
+@"  event.dataTransfer.dropEffect = \"none\";\n"
+@"  myData = event.dataTransfer.getData(\"Text\");\n"
+@"  myData = myData.split('?');\n"
+@"  myType = myData[1];\n"
+@"  myID   = myData[0];\n"
+@"  event.dataTransfer.clearData(\"Text\");\n"
+@"  this.location=''+myurl+'?'+myID+'='+myType;\n"
+@"  this.status='url:'+myurl+' data'+myData;\n"
+@"}\n"
+@"function fnCancelDefault(validObj, effect) {\n"
+@"  myData = event.dataTransfer.getData(\"Text\");\n"
+@"  myData = myData.split('?');\n"
+@"  myType = myData[1];\n"
+@"  myID   = myData[0];\n"
+@"  if ((validObj.indexOf(myType) != -1) || (validObj == '*')) {\n"
+@"    event.returnValue = false;\n"
+@"    event.dataTransfer.dropEffect = effect;\n"
+@"  }\n"
+@"  else {\n"
+@"    event.returnValue = false;\n"
+@"    event.dataTransfer.dropEffect = \"none\";\n"
+@"  }\n"
+@"}\n"
+@"var WODropContainerBgColor = new Array(); \n"
+@"function dropFieldSwapColor(obj,color) {\n"
+@"  if (color && event.dataTransfer.dropEffect == 'none') return false;\n"
+@"  if (color) {\n"
+@"    if (!WODropContainerBgColor[obj.id]) {\n"
+@"      WODropContainerBgColor[obj.id] = obj.bgColor;\n"
+@"    }\n"
+@"    color = WODropContainerBgColor[obj.id];\n"
+@"    color = lighterColor(color);\n"
+@"  } else {\n"
+@"    color = WODropContainerBgColor[obj.id];\n"
+@"  }\n"
+@"  obj.bgColor = color;\n"
+@"}\n"
+@"      \n"
+@"var lightAddition = 20;\n"
+@"var hex = '0123456789ABCDEF';\n"
+@"function convertHexToDec(h) {\n"
+@"  h1 = hex.indexOf(h.substr(0,1).toUpperCase());\n"
+@"  h2 = hex.indexOf(h.substr(1,1).toUpperCase());\n"
+@"  return (h1 * 16 + h2);\n"
+@"}\n"
+@"function convertDecToHex(d) {\n"
+@"  if (d >= 255) return 'FF';\n"
+@"  if (d <= 0)   return '00';\n"
+@"  d2 = d % 16; d1 = parseInt((d-d2) / 16);\n"
+@"  return hex.substr(d1,1)+hex.substr(d2,1);\n"
+@"}\n"
+@"function lighterColor(c) {\n"
+@"  if (!c) return c;\n"
+@"  if ((c.length != 7) || (c.substr(0,1) != '#')) return c;\n"
+@"  r = convertDecToHex(convertHexToDec(c.substr(1,2)) + lightAddition);\n"
+@"  g = convertDecToHex(convertHexToDec(c.substr(3,2)) + lightAddition);\n"
+@"  b = convertDecToHex(convertHexToDec(c.substr(5,2)) + lightAddition);\n"
+@"  return '#'+r+g+b;\n"
+@"}\n"
+@"// -->\n"
+@"</SCRIPT>\n"
diff --git a/skyrix-sope/WEExtensions/WEDropScript.js b/skyrix-sope/WEExtensions/WEDropScript.js
new file mode 100644 (file)
index 0000000..0ea1abb
--- /dev/null
@@ -0,0 +1,74 @@
+<SCRIPT LANGUAGE="JScript">
+<!--
+function fnGetInfo(dropElem, myurl) {
+  event.returnValue = false;
+  event.dataTransfer.dropEffect = "none";
+  myData = event.dataTransfer.getData("Text");
+  myData = myData.split('?');
+  myType = myData[1];
+  myID   = myData[0];
+  event.dataTransfer.clearData("Text");
+  this.location=''+myurl+'?'+myID+'='+myType;
+  this.status='url:'+myurl+' data'+myData;
+}
+function fnCancelDefault(validObj, effect) {
+  myData = event.dataTransfer.getData("Text");
+  myData = myData.split('?');
+  myType = myData[1];
+  myID   = myData[0];
+  if ((validObj.indexOf(myType) != -1) || (validObj == '*')) {
+    event.returnValue = false;
+    event.dataTransfer.dropEffect = effect;
+  }
+  else {
+    event.returnValue = false;
+    event.dataTransfer.dropEffect = "none";
+  }
+}
+function dropFieldSwapColor(obj,doLight) {
+  if (!obj.bgColor && !obj.activeColor && !obj.inactiveColor) return false;
+  if (doLight && event.dataTransfer.dropEffect == 'none') return false;
+
+  if (!obj.isColorsSet) {
+     obj.inactiveColor = obj.bgColor;
+     obj.isColorsSet   = true;
+  }
+
+  if (doLight) {
+    if (obj.activeColor)
+      obj.bgColor = obj.activeColor;
+    else if (obj.inactiveColor)
+      obj.bgColor = lighterColor(obj.inactiveColor);
+  }
+  else {
+    if (obj.inactiveColor)
+      obj.bgColor = obj.inactiveColor;
+    else
+      obj.removeAttribute("bgColor");
+  }
+}
+      
+var lightAddition = 20;
+var hex = '0123456789ABCDEF';
+function convertHexToDec(h) {
+  h1 = hex.indexOf(h.substr(0,1).toUpperCase());
+  h2 = hex.indexOf(h.substr(1,1).toUpperCase());
+  return (h1 * 16 + h2);
+}
+function convertDecToHex(d) {
+  if (d >= 255) return 'FF';
+  if (d <= 0)   return '00';
+  d2 = d % 16; d1 = parseInt((d-d2) / 16);
+  return hex.substr(d1,1)+hex.substr(d2,1);
+}
+function lighterColor(c) {
+  if (!c) return c;
+  if ((c.length != 7) || (c.substr(0,1) != '#')) return c;
+  r = convertDecToHex(convertHexToDec(c.substr(1,2)) + lightAddition);
+  g = convertDecToHex(convertHexToDec(c.substr(3,2)) + lightAddition);
+  b = convertDecToHex(convertHexToDec(c.substr(5,2)) + lightAddition);
+
+  return '#'+r+g+b;
+}
+// -->
+</SCRIPT>
diff --git a/skyrix-sope/WEExtensions/WEDropScript.jsm b/skyrix-sope/WEExtensions/WEDropScript.jsm
new file mode 100644 (file)
index 0000000..6ddc412
--- /dev/null
@@ -0,0 +1,72 @@
+/* automatically generated from WEDropScript.js, do not edit ! */
+@"<SCRIPT LANGUAGE=\"JScript\">\n"
+@"<!--\n"
+@"function fnGetInfo(dropElem, myurl) {\n"
+@"  event.returnValue = false;\n"
+@"  event.dataTransfer.dropEffect = \"none\";\n"
+@"  myData = event.dataTransfer.getData(\"Text\");\n"
+@"  myData = myData.split('?');\n"
+@"  myType = myData[1];\n"
+@"  myID   = myData[0];\n"
+@"  event.dataTransfer.clearData(\"Text\");\n"
+@"  this.location=''+myurl+'?'+myID+'='+myType;\n"
+@"  this.status='url:'+myurl+' data'+myData;\n"
+@"}\n"
+@"function fnCancelDefault(validObj, effect) {\n"
+@"  myData = event.dataTransfer.getData(\"Text\");\n"
+@"  myData = myData.split('?');\n"
+@"  myType = myData[1];\n"
+@"  myID   = myData[0];\n"
+@"  if ((validObj.indexOf(myType) != -1) || (validObj == '*')) {\n"
+@"    event.returnValue = false;\n"
+@"    event.dataTransfer.dropEffect = effect;\n"
+@"  }\n"
+@"  else {\n"
+@"    event.returnValue = false;\n"
+@"    event.dataTransfer.dropEffect = \"none\";\n"
+@"  }\n"
+@"}\n"
+@"function dropFieldSwapColor(obj,doLight) {\n"
+@"  if (!obj.bgColor && !obj.activeColor && !obj.inactiveColor) return false;\n"
+@"  if (doLight && event.dataTransfer.dropEffect == 'none') return false;\n"
+@"  if (!obj.isColorsSet) {\n"
+@"     obj.inactiveColor = obj.bgColor;\n"
+@"     obj.isColorsSet   = true;\n"
+@"  }\n"
+@"  if (doLight) {\n"
+@"    if (obj.activeColor)\n"
+@"      obj.bgColor = obj.activeColor;\n"
+@"    else if (obj.inactiveColor)\n"
+@"      obj.bgColor = lighterColor(obj.inactiveColor);\n"
+@"  }\n"
+@"  else {\n"
+@"    if (obj.inactiveColor)\n"
+@"      obj.bgColor = obj.inactiveColor;\n"
+@"    else\n"
+@"      obj.removeAttribute(\"bgColor\");\n"
+@"  }\n"
+@"}\n"
+@"      \n"
+@"var lightAddition = 20;\n"
+@"var hex = '0123456789ABCDEF';\n"
+@"function convertHexToDec(h) {\n"
+@"  h1 = hex.indexOf(h.substr(0,1).toUpperCase());\n"
+@"  h2 = hex.indexOf(h.substr(1,1).toUpperCase());\n"
+@"  return (h1 * 16 + h2);\n"
+@"}\n"
+@"function convertDecToHex(d) {\n"
+@"  if (d >= 255) return 'FF';\n"
+@"  if (d <= 0)   return '00';\n"
+@"  d2 = d % 16; d1 = parseInt((d-d2) / 16);\n"
+@"  return hex.substr(d1,1)+hex.substr(d2,1);\n"
+@"}\n"
+@"function lighterColor(c) {\n"
+@"  if (!c) return c;\n"
+@"  if ((c.length != 7) || (c.substr(0,1) != '#')) return c;\n"
+@"  r = convertDecToHex(convertHexToDec(c.substr(1,2)) + lightAddition);\n"
+@"  g = convertDecToHex(convertHexToDec(c.substr(3,2)) + lightAddition);\n"
+@"  b = convertDecToHex(convertHexToDec(c.substr(5,2)) + lightAddition);\n"
+@"  return '#'+r+g+b;\n"
+@"}\n"
+@"// -->\n"
+@"</SCRIPT>\n"
diff --git a/skyrix-sope/WEExtensions/WEEpozEditor.m b/skyrix-sope/WEExtensions/WEEpozEditor.m
new file mode 100644 (file)
index 0000000..29f8f96
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+  Copyright (C) 2003-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$
+
+/*
+  Note: Its very important that the URLs generated properly match the
+        appname! Otherwise you will get security exceptions in JavaScript
+        on the client side (probably depends on the browser).
+        This also implies, that WOResourcePrefix cannot be used in conjunction
+        with Epoz.
+*/
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WEEpozEditor : WODynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *name;
+  WOAssociation *value;
+  WOAssociation *disabled;
+  WOAssociation *rows;
+  WOAssociation *cols;
+  WOAssociation *epozCharset; /* def: iso-8859-1 */
+  WOAssociation *epozButtonStyle;
+  WOAssociation *epozStyle;
+}
+
+@end
+
+#include <NGObjWeb/WEClientCapabilities.h>
+#include <NGExtensions/NSString+Ext.h>
+#include "common.h"
+
+@implementation WEEpozEditor
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_root {
+
+  if ((self = [super initWithName:_name associations:_config template:_root])) {
+    self->containsForm = YES;
+    self->name     = OWGetProperty(_config, @"name");
+    self->value    = OWGetProperty(_config, @"value");
+    self->disabled = OWGetProperty(_config, @"disabled");
+    self->rows     = OWGetProperty(_config, @"rows");
+    self->cols     = OWGetProperty(_config, @"cols");
+    
+    self->epozCharset     = OWGetProperty(_config, @"charset");
+    self->epozStyle       = OWGetProperty(_config, @"style");
+    self->epozButtonStyle = OWGetProperty(_config, @"buttonstyle");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->epozCharset     release];
+  [self->epozButtonStyle release];
+  [self->epozStyle       release];
+  [self->rows     release];
+  [self->cols     release];
+  [self->name     release];
+  [self->value    release];
+  [self->disabled release];
+  [super dealloc];
+}
+
+/* form support */
+
+static NSString *OWFormElementName(WEEpozEditor *self, WOContext *_ctx) {
+  NSString *name;
+  
+  if (self->name == nil) 
+    return [_ctx elementID];
+  
+  if ((name = [self->name stringValueInComponent:[_ctx component]]))
+    return name;
+
+  [[_ctx component]
+             logWithFormat:
+               @"WARNING: in element %@, 'name' attribute configured (%@),"
+               @"but no name assigned (using elementID as name) !",
+               self, self->name];
+  return [_ctx elementID];
+}
+
+// ******************** responder ********************
+
+- (id)parseFormValue:(id)_value inContext:(WOContext *)_ctx {
+  return _value;
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSString *formName;
+  id formValue = nil;
+  
+  if ([self->disabled boolValueInComponent:[_ctx component]])
+    return;
+  
+  formName = OWFormElementName(self, _ctx);
+  
+  if ((formValue = [_req formValueForKey:formName])) {
+#if DEBUG && 0
+    NSLog(@"%s(%@): form=%@ ctx=%@ value=%@ ..", __PRETTY_FUNCTION__,
+         [_ctx elementID], formName, [_ctx contextID], formValue);
+#endif
+    
+    if ([self->value isValueSettable]) {
+      formValue = [self parseFormValue:formValue inContext:_ctx];
+      [self->value setStringValue:formValue inComponent:[_ctx component]];
+    }
+#if DEBUG
+    else {
+      NSLog(@"%s: form value is not settable: %@", __PRETTY_FUNCTION__,
+            self->value);
+    }
+#endif
+  }
+}
+
+- (BOOL)isDebuggingEnabled {
+  return NO;
+}
+
+- (BOOL)isEpozBrowserInContext:(WOContext *)_ctx {
+  WEClientCapabilities *cc;
+  
+  if ((cc = [[_ctx request] clientCapabilities]) == nil) {
+    [self debugWithFormat:@"WARNING: missing client capabilities object!"];
+    return YES;
+  }
+  
+  if ([cc isInternetExplorer]) {
+    if ([cc majorVersion] <= 4) {
+      [self debugWithFormat:@"disable Epoz with IE <5"];
+      return NO;
+    }
+    if ([cc majorVersion] == 5 && [cc minorVersion] <= 5) {
+      [self debugWithFormat:@"disable Epoz with IE <5.5"];
+      return NO;
+    }
+    [self debugWithFormat:@"enable Epoz with IE >=5.5"];
+    return YES;
+  }
+  
+  if ([cc isMozilla] || [cc isNetscape]) {
+    [self debugWithFormat:@"enable Epoz with Mozilla: %@", cc];
+    return YES;
+  }
+  
+  [self debugWithFormat:@"does not use Epoz with this browser: %@", cc];
+  return NO;
+}
+
+- (NSString *)stringValueInContext:(WOContext *)_ctx {
+  BOOL     removeCR = NO;
+  NSString *ua;
+  NSString *v;
+  
+  v = [[self->value valueInComponent:[_ctx component]] stringValue];
+  if ([v length] == 0)
+    return v;
+    
+  ua = [[_ctx request] headerForKey:@"user-agent"];
+  if ([ua rangeOfString:@"Opera"].length > 0)
+    removeCR = YES;
+    
+  if (removeCR)
+    v = [v stringByReplacingString:@"\r" withString:@""];
+  
+  return v;
+}
+
+- (void)appendTextAreaToResponse:(WOResponse *)_response 
+  inContext:(WOContext *)_ctx 
+{
+  WOComponent *sComponent;
+  NSString *v;
+  NSString *r, *c;
+  
+  sComponent = [_ctx component];
+  v = [self stringValueInContext:_ctx];
+  r = [self->rows  stringValueInComponent:sComponent];
+  c = [self->cols  stringValueInComponent:sComponent];
+  
+  [_response appendContentString:@"<textarea name=\""];
+  [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
+  [_response appendContentString:@"\""];
+  if (r > 0) {
+    [_response appendContentString:@" rows=\""];
+    [_response appendContentString:r];
+    [_response appendContentString:@"\""];
+  }
+  if (c > 0) {
+    [_response appendContentString:@" cols=\""];
+    [_response appendContentString:c];
+    [_response appendContentString:@"\""];
+  }
+  
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString) {
+    NSString *str;
+    
+    str = [self->otherTagString stringValueInComponent:sComponent];
+    [_response appendContentString:str];
+  }
+  [_response appendContentString:@">"];
+  
+  if ([v length] > 0)
+    [_response appendContentHTMLString:v];
+  
+  [_response appendContentString:@"</textarea>"];
+}
+
+- (WOResourceManager *)resourceManagerInContext:(WOContext *)_ctx {
+  WOResourceManager *rm;
+  
+  if ((rm = [[_ctx component] resourceManager]) == nil)
+    rm = [[_ctx application] resourceManager];
+  return rm;
+}
+- (NSString *)urlForEpozResourceNamed:(NSString *)_name 
+  inContext:(WOContext *)_ctx
+{
+  WOResourceManager *rm;
+  NSArray  *languages;
+  
+  rm = [self resourceManagerInContext:_ctx];
+  languages = [_ctx hasSession] ? [[_ctx session] languages] : nil;
+  
+  return [rm urlForResourceNamed:_name inFramework:nil
+             languages:languages request:[_ctx request]];
+}
+
+- (void)appendEpozScript:(NSString *)_scriptName
+  toResponse:(WOResponse *)_response 
+  inContext:(WOContext *)_ctx 
+{
+  NSString *src;
+  
+  src = [self urlForEpozResourceNamed:_scriptName inContext:_ctx];
+  [_response appendContentString:@"<script language=\"JavaScript\""];
+  [_response appendContentString:@" type=\"text/javascript\""];
+  [_response appendContentString:@" src=\""];
+  [_response appendContentHTMLAttributeValue:src];
+  [_response appendContentString:@"\"></script>\n"];
+}
+
+- (NSString *)epozImageURLInContext:(WOContext *)_ctx {
+  /*
+    Note: Epoz takes the directory where the resources are located, not
+          individual pointers. This also means that you need to have all
+          Epoz resources in the directory which contains the 
+          "epoz_button_bold.gif" (which is used as the "reference" point
+          to the active buttons).
+   */
+  NSString *src;
+  NSRange  r;
+  
+  src = [self urlForEpozResourceNamed:@"epoz_button_bold.gif" inContext:_ctx];
+  r = [src rangeOfString:@"/" options:(NSBackwardsSearch | NSLiteralSearch)];
+  if (r.length > 0)
+    src = [src substringToIndex:(r.location + r.length)];
+  
+  return src;
+}
+- (NSString *)epozToolboxURLInContext:(WOContext *)_ctx {
+  /* TODO: replace */
+  // return @"/epoz/WebServerResources/toolbox";
+  return [self urlForEpozResourceNamed:@"epoz_toolbox.html" inContext:_ctx];
+}
+- (NSString *)epozCSSURLInContext:(WOContext *)_ctx {
+  return [self urlForEpozResourceNamed:@"epoz.css" inContext:_ctx];
+}
+
+- (void)appendEpozToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSString *v, *tmp;
+  
+  sComponent = [_ctx component];
+  v = [self stringValueInContext:_ctx];
+  
+  /* first, the background iframe */
+  [_r appendContentString:@"<iframe id=\"EpozIFrame\""];
+  [_r appendContentString:@" style=\""];
+  [_r appendContentString:@"position: absolute;"];
+  [_r appendContentString:@" visibility: hidden;"];
+  [_r appendContentString:@" width: 0px; height: 0px;"];
+  [_r appendContentString:@"\"></iframe>\n"];
+  
+  /* the language mappings */
+  [self appendEpozScript:@"epoz_lang_en.js" 
+        toResponse:_r inContext:_ctx];
+  
+  /* the processing JavaScripts */
+  [self appendEpozScript:@"epoz_script_widget.js"
+        toResponse:_r inContext:_ctx];
+  [self appendEpozScript:@"epoz_script_detect.js" 
+        toResponse:_r inContext:_ctx];
+  [self appendEpozScript:@"epoz_script_main.js" 
+        toResponse:_r inContext:_ctx];
+  
+  /* 
+     Start Epoz
+    """ Create an Epoz-Wysiwyg-Editor.
+    
+        name : the name of the form-element which submits the data
+        data : the data to edit
+        toolbox : a link to a HTML-Page which delivers additional tools
+        lang: a code for the language-file (en,de,...)
+        path : path to Epoz-Javascript. Needed mainly for Plone (portal_url).
+        widget: You can specify a path to an alternative JavaScript for
+                epoz_script_widget.js
+        style : style-definition for the editor-area
+        button : style-definiton for buttons
+        
+        If Epoz can't create a Rich-Text-Editor, a simple textarea is created.
+    """
+  */
+  
+  [_r appendContentString:
+        @"<script language=\"JavaScript\" type=\"text/javascript\"><!--\n"];
+  [_r appendContentString:@"InitEpoz("];
+
+  /* name */
+  [_r appendContentString:@"'"];
+  [_r appendContentString:OWFormElementName(self, _ctx)];
+  [_r appendContentString:@"',"];
+  
+  /* value */
+  [_r appendContentString:@"'"];
+  {
+    /* TODO: escape value, is that enough? */
+    NSString *jsv;
+    
+    jsv = v;
+    jsv = [jsv stringByReplacingString:@"'"  withString:@"\\'"];
+    jsv = [jsv stringByReplacingString:@"\n" withString:@"\\n"];
+    jsv = [jsv stringByReplacingString:@"\r" withString:@""];
+    [_r appendContentString:jsv];
+  }
+  [_r appendContentString:@"',"];
+  
+  /* image path */
+  [_r appendContentString:@"'"];
+  [_r appendContentString:[self epozImageURLInContext:_ctx]];
+  [_r appendContentString:@"',"];
+  
+  /* toolbox path */
+  [_r appendContentString:@"'"];
+  [_r appendContentString:[self epozToolboxURLInContext:_ctx]];
+  [_r appendContentString:@"',"];
+
+  if ((tmp = [self->epozStyle stringValueInComponent:sComponent]) == nil)
+    tmp = @"width: 590px; height: 250px; border: 1px solid #000000;";
+  [_r appendContentString:@"'"];
+  [_r appendContentString:tmp];
+  [_r appendContentString:@"',"];
+
+  if ((tmp=[self->epozButtonStyle stringValueInComponent:sComponent])==nil) {
+    tmp = 
+      @"background-color: #EFEFEF; border: 1px solid #A0A0A0; "
+      @"cursor: pointer; margin-right: 1px; margin-bottom: 1px;";
+  }
+  [_r appendContentString:@"'"];
+  [_r appendContentString:tmp];
+  [_r appendContentString:@"',"];
+  
+  /* CSS path */
+  [_r appendContentString:@"'"];
+  [_r appendContentString:[self epozCSSURLInContext:_ctx]];
+  [_r appendContentString:@"',"];
+  
+  /* charset */
+  if ((tmp = [self->epozCharset stringValueInComponent:sComponent]) == nil)
+    tmp = @"iso-8859-1";
+  [_r appendContentString:@"'"];
+  [_r appendContentString:tmp];
+  [_r appendContentString:@"'"];
+  
+  [_r appendContentString:@");\n"];
+  [_r appendContentString:@"//-->\n</script>"];
+  
+  /* fallback if scripting is disabled */
+  [_r appendContentString:@"<noscript>"];
+  [self appendTextAreaToResponse:_r inContext:_ctx];
+  [_r appendContentString:@"</noscript>"];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if ([self isEpozBrowserInContext:_ctx])
+    [self appendEpozToResponse:_response inContext:_ctx];
+  else
+    [self appendTextAreaToResponse:_response inContext:_ctx];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = nil;
+  
+  str = [NSMutableString stringWithCapacity:64];
+  
+  if (self->value)    [str appendFormat:@" value=%@",    self->value];
+  if (self->name)     [str appendFormat:@" name=%@",     self->name];
+  if (self->disabled) [str appendFormat:@" disabled=%@", self->disabled];
+  
+  if (self->rows) [str appendFormat:@" rows=%@", self->rows];
+  if (self->cols) [str appendFormat:@" cols=%@", self->cols];
+  
+  return str;
+}
+
+@end /* WEEpozEditor */
diff --git a/skyrix-sope/WEExtensions/WEExtensions-Info.plist b/skyrix-sope/WEExtensions/WEExtensions-Info.plist
new file mode 100644 (file)
index 0000000..35f53a6
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>WEExtensions</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.WEExtensions</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/WEExtensions/WEExtensionsBundle.m b/skyrix-sope/WEExtensions/WEExtensionsBundle.m
new file mode 100644 (file)
index 0000000..d489caa
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/NSObject.h>
+
+@interface WEExtensionsBundle : NSObject
+@end
+
+@implementation WEExtensionsBundle
+@end /* WEExtensionsBundle */
diff --git a/skyrix-sope/WEExtensions/WEMonthOverview.m b/skyrix-sope/WEExtensions/WEMonthOverview.m
new file mode 100644 (file)
index 0000000..03f10e6
--- /dev/null
@@ -0,0 +1,1271 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@class NSMutableArray, NSCalendarDate;
+
+#define MatrixSize 42
+
+@interface WEMonthOverview : WODynamicElement
+{
+  WOAssociation *list;       // list of appointments
+  WOAssociation *item;       // current item in list
+  WOAssociation *index;      // index of current element
+  WOAssociation *identifier; // unique identifier for current item
+
+  WOAssociation *currentDay;  // current day, e.g. 31.Aug, 1.Sep, 2.Sep, ...
+  
+  WOAssociation *year;        // year
+  WOAssociation *month;       // month
+  WOAssociation *timeZone;    // timeZone
+  
+  WOAssociation *firstDay;    // 0 - Sunday .. 6 - Saturday (default:1)
+  WOAssociation *tableTags;   // make table tags
+
+  WOAssociation *startDateKey;
+  WOAssociation *endDateKey;
+
+  WOAssociation *labelStyle;  // style sheet classes
+  WOAssociation *contentStyle;
+
+  WOAssociation *labelColor;
+  WOAssociation *contentColor;
+
+@private
+  NSMutableArray *matrix[MatrixSize];
+  
+  struct {
+    int firstDisplayedDay; // first day to be displayed Sun 0 .. Sat 6
+    int weeks;             // number of weeks to display
+    NSCalendarDate *start; // reference date in matrix
+  } matrixInfo;
+  
+  WOElement     *template;
+  // extra attributes forwarded to table data
+}
+
+@end /* WEMonthOverview */
+
+@interface WEMonthLabel : WODynamicElement
+{
+  WOAssociation *orientation;
+  // left/top | top | right/top | right | right/bottom | bottom | left/bottom
+  // left | header
+  WOAssociation *dayOfWeek;
+  // set if orientation is top or bottom
+  WOAssociation *weekOfYear;
+  // set if orientation is left or right
+  WOAssociation *colspan;
+  // set if orientation is header
+  WOElement     *template;
+}
+@end /* WEMonthLabel */
+
+@interface WEMonthTitle : WODynamicElement
+{
+  WOElement *template;
+}
+@end /* WEMonthTitle */
+
+
+#include "WEContextConditional.h"
+#include <math.h> /* needed for floor() */
+#include "common.h"
+
+static NSString *WEMonthOverview_InfoMode    = @"WEMonthOverview_InfoMode";
+static NSString *WEMonthOverview_ContentMode = @"WEMonthOverview_ContentMode";
+
+#define SecondsPerDay (24 * 60 * 60)
+
+@interface WOContext(WEMonthOverview)
+
+- (void)setupMonthOverviewContextWithValue:(id)_value forKey:(NSString *)_key;
+- (void)setupMonthOverviewContextForQueryMode;
+- (void)setupMonthOverviewContextWithOrientation:(NSString *)_orient;
+
+- (void)tearDownMonthOverviewContext;
+- (NSDictionary *)monthOverviewContext;
+- (NSMutableArray *)monthOverviewQueryObjects;
+
+- (void)enableMonthOverviewInfoMode;
+- (void)disableMonthOverviewInfoMode;
+- (void)enableMonthOverviewContentMode;
+- (void)disableMonthOverviewContentMode;
+
+@end
+
+@implementation WOContext(WEMonthOverview)
+
+- (void)setupMonthOverviewContextWithValue:(id)_value forKey:(NSString *)_key {
+  NSDictionary *d;
+  
+  d = [[NSDictionary alloc] initWithObjects:&_value forKeys:&_key count:1];
+  [self setObject:d forKey:@"WEMonthOverview"];
+  [d release];
+}
+- (void)setupMonthOverviewContextForQueryMode {
+  NSDictionary *d;
+
+  d = [[NSDictionary alloc] initWithObjectsAndKeys:
+                             [NSMutableArray arrayWithCapacity:4],
+                             @"query",nil];
+  [self setObject:d forKey:@"WEMonthOverview"];
+  [d release];
+}
+- (void)setupMonthOverviewContextWithOrientation:(NSString *)_orient {
+  NSDictionary *d;
+  
+  d = [[NSDictionary alloc] initWithObjectsAndKeys:@"--", _orient, nil];
+  [self setObject:d forKey:@"WEMonthOverview"];
+  [d release];
+}
+
+- (void)tearDownMonthOverviewContext {
+  [self removeObjectForKey:@"WEMonthOverview"];
+}
+
+- (NSDictionary *)monthOverviewContext {
+  return [self objectForKey:@"WEMonthOverview"];
+}
+- (NSArray *)monthOverviewQueryObjects {
+  return [[self monthOverviewContext] valueForKey:@"query"];
+}
+
+- (void)enableMonthOverviewInfoMode {
+  [self setObject:@"YES" forKey:WEMonthOverview_InfoMode];
+}
+- (void)disableMonthOverviewInfoMode {
+  [self removeObjectForKey:WEMonthOverview_InfoMode];
+}
+
+- (void)enableMonthOverviewContentMode {
+  [self setObject:@"YES" forKey:WEMonthOverview_ContentMode];
+}
+- (void)disableMonthOverviewContentMode {
+  [self removeObjectForKey:WEMonthOverview_ContentMode];
+}
+
+@end /* WOContext(WEMonthOverview) */
+
+@implementation WEMonthOverview
+
+static Class StrClass = nil;
+
++ (void)initialize {
+  if (StrClass == Nil) StrClass = [NSString class];
+}
+
+static NSString *retStrForInt(int i) {
+  switch(i) {
+  case 0:  return @"0";
+  case 1:  return @"1";
+  case 2:  return @"2";
+  case 3:  return @"3";
+  case 4:  return @"4";
+  case 5:  return @"5";
+  case 6:  return @"6";
+  case 7:  return @"7";
+  case 8:  return @"8";
+  case 9:  return @"9";
+  case 10: return @"10";
+    // TODO: find useful count!
+  default: {
+    unsigned char buf[32];
+    sprintf(buf, "%i", i);
+    return [[StrClass alloc] initWithCString:buf];
+  }
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary*)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->list         = WOExtGetProperty(_config, @"list");
+    self->item         = WOExtGetProperty(_config, @"item");
+    self->index        = WOExtGetProperty(_config, @"index");
+    self->identifier   = WOExtGetProperty(_config, @"identifier");
+
+    self->currentDay   = WOExtGetProperty(_config, @"currentDay");
+    
+    self->year         = WOExtGetProperty(_config, @"year");
+    self->month        = WOExtGetProperty(_config, @"month");
+    self->timeZone     = WOExtGetProperty(_config, @"timeZone");
+    self->firstDay     = WOExtGetProperty(_config, @"firstDay");
+    self->tableTags    = WOExtGetProperty(_config, @"tableTags");
+    
+    self->startDateKey = WOExtGetProperty(_config, @"startDateKey");
+    self->endDateKey   = WOExtGetProperty(_config, @"endDateKey");
+
+    self->labelStyle   = WOExtGetProperty(_config, @"labelStyle");
+    self->contentStyle = WOExtGetProperty(_config, @"contentStyle");
+
+    self->labelColor   = WOExtGetProperty(_config, @"labelColor");
+    self->contentColor = WOExtGetProperty(_config, @"contentColor");
+
+    if (self->startDateKey == nil) {
+      self->startDateKey = 
+        [[WOAssociation associationWithValue:@"startDate"] retain];
+    }
+    if (self->endDateKey == nil) {
+      self->endDateKey = 
+        [[WOAssociation associationWithValue:@"endDate"] retain];
+    }     
+    self->template = [_t retain];
+  }
+  return self;
+}
+
+- (void)resetMatrix {
+  int i;
+  
+  for (i=0; i < MatrixSize; i++) {
+    [self->matrix[i] release];
+    self->matrix[i] = nil;
+  }
+  [self->matrixInfo.start release]; self->matrixInfo.start = nil;
+}
+
+- (void)dealloc {
+  [self->list       release];
+  [self->item       release];
+  [self->index      release];
+  [self->identifier release];
+  [self->currentDay release];
+  [self->year       release];
+  [self->month      release];
+  [self->timeZone   release];
+  [self->firstDay   release];
+  [self->tableTags  release];
+  
+  [self->startDateKey release];
+  [self->endDateKey   release];
+  [self->labelStyle   release];
+  [self->contentStyle release];
+  [self->labelColor   release];
+  [self->contentColor release];
+
+  [self resetMatrix];
+  
+  [self->template release];
+
+  [super dealloc];
+}
+
+/* OWResponder */
+
+static inline void
+_applyIdentifier(WEMonthOverview *self, WOComponent *comp, NSString *_idx)
+{
+  NSArray  *array;
+  unsigned count;
+  unsigned cnt;
+  
+  array = [self->list valueInComponent:comp];
+  count = [array count];
+
+  if (count <= 0)
+    return;
+    
+  /* find subelement for unique id */
+    
+  for (cnt = 0; cnt < count; cnt++) {
+    NSString *ident;
+      
+    if (self->index)
+      [self->index setUnsignedIntValue:cnt inComponent:comp];
+
+    if (self->item)
+      [self->item setValue:[array objectAtIndex:cnt] inComponent:comp];
+    
+    ident = [self->identifier stringValueInComponent:comp];
+    
+    if ([ident isEqualToString:_idx]) {
+      /* found subelement with unique id */
+      return;
+    }
+  }
+    
+  [comp logWithFormat:
+          @"WEMonthOverview: array did change, "
+          @"unique-id isn't contained."];
+  [self->item  setValue:nil          inComponent:comp];
+  [self->index setUnsignedIntValue:0 inComponent:comp];
+}
+
+static inline void
+_applyIndex(WEMonthOverview *self, WOComponent *comp, unsigned _idx)
+{
+  NSArray *array;
+  unsigned count;
+
+  array = [self->list valueInComponent:comp];
+  
+  if (self->index)
+    [self->index setUnsignedIntValue:_idx inComponent:comp];
+
+  if (self->item == nil)
+    return;
+  
+  count = [array count];
+    
+  if (_idx < count) {
+    [self->item setValue:[array objectAtIndex:_idx] inComponent:comp];
+    return;
+  }
+
+  [comp logWithFormat:
+          @"WEMonthOverview: array did change, index is invalid."];
+  [self->item  setValue:nil          inComponent:comp];
+  [self->index setUnsignedIntValue:0 inComponent:comp];
+}
+
+
+static inline void
+_generateCell(WEMonthOverview *self, WOResponse *response,
+              WOContext *ctx, NSString *key, id value,
+              NSCalendarDate *dateId)
+{
+  [ctx setupMonthOverviewContextWithValue:value forKey:key];
+  
+  [ctx appendElementIDComponent:key];
+
+  if (dateId) {
+    NSString *s;
+    
+    s = retStrForInt([dateId timeIntervalSince1970]);
+    [ctx appendElementIDComponent:s];
+    [s release];
+  }
+  
+  [self->template appendToResponse:response inContext:ctx];
+  
+  if (dateId) [ctx deleteLastElementIDComponent];
+  [ctx deleteLastElementIDComponent];
+  [ctx tearDownMonthOverviewContext];
+}
+
+static inline void
+_takeValuesInCell(WEMonthOverview *self, WORequest *request,
+                  WOContext *ctx, NSString *key, id value)
+{
+  [ctx setupMonthOverviewContextWithValue:value forKey:key];
+  
+  [ctx appendElementIDComponent:key];
+  [self->template takeValuesFromRequest:request inContext:ctx];
+  [ctx deleteLastElementIDComponent];
+  // TODO: no teardown of context?
+}
+
+- (void)_calcMatrixInContext:(WOContext *)_ctx {
+  WOComponent    *comp;
+  NSArray        *array;
+  NSString       *startKey;
+  NSString       *endKey;
+  int            m, y; // month, year
+  int            i, cnt;
+
+  [self resetMatrix];
+  
+  comp       = [_ctx component];
+  array      = [self->list valueInComponent:comp];
+  startKey   = [self->startDateKey stringValueInComponent:comp];
+  endKey     = [self->endDateKey   stringValueInComponent:comp];
+
+  y = (self->year == nil)
+    ? [[NSCalendarDate calendarDate] yearOfCommonEra]
+    : [self->year intValueInComponent:comp];
+  
+  m = (self->month == nil)
+    ? [[NSCalendarDate calendarDate] monthOfYear]
+    : [self->month intValueInComponent:comp];
+  
+
+  {
+    NSCalendarDate *monthStart = nil;
+    NSCalendarDate *d  = nil;
+    NSTimeZone     *tz = nil;
+    int            firstDisplayedDay, firstIdx;
+    int            i  = 27;
+
+    tz = [self->timeZone valueInComponent:comp];
+    
+    monthStart = [NSCalendarDate dateWithYear:y month:m day:1 hour:0 minute:0
+                                       second:0 timeZone:tz];
+    
+    d = [monthStart dateByAddingYears:0 months:0 days:i];
+
+    while ([d monthOfYear] == m) {
+      i++;
+      d = [monthStart dateByAddingYears:0 months:0 days:i];
+    }
+    
+    firstDisplayedDay = (self->firstDay) 
+      ? ([self->firstDay intValueInComponent:comp] % 7)
+      : 1; // Monday
+    
+    firstIdx = (([monthStart dayOfWeek]-firstDisplayedDay)+7) % 7;
+    
+    self->matrixInfo.weeks = ceil((float)(firstIdx + i) / 7);
+    self->matrixInfo.firstDisplayedDay = firstDisplayedDay;
+
+    // keep the timezone in the date
+    self->matrixInfo.start =
+      [[monthStart dateByAddingYears:0 months:0 days:-firstIdx] retain];
+  }
+  
+  for (i = 0, cnt = [array count]; i < cnt; i++) {
+    id             app;
+    NSCalendarDate *sd, *ed;
+    NSTimeInterval diff;
+    int            idx, idx2;
+
+    app = [array objectAtIndex:i];
+    sd  = [app valueForKey:startKey]; // startDate
+    ed  = [app valueForKey:endKey];   // endDate
+
+    if (sd == nil && ed == nil) continue;
+
+    diff = [sd timeIntervalSinceDate:self->matrixInfo.start];
+    
+    idx = floor(diff / SecondsPerDay);
+
+    if (0 <= idx  && idx < MatrixSize) {
+      if (self->matrix[idx] == nil)
+        self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
+
+      [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
+    }
+    idx = (idx < 0) ? 0 : idx + 1;
+
+    diff = [ed timeIntervalSinceDate:self->matrixInfo.start];
+    idx2 = floor(diff / SecondsPerDay);
+    idx2 = (idx2 > MatrixSize) ? MatrixSize : idx2;
+    
+    while (idx < idx2) {
+      if (self->matrix[idx] == nil)
+        self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
+
+      [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
+      idx++;
+    }
+  }
+  
+  for (i = 0; i < MatrixSize; i++) {
+    if (self->matrix[i] == nil)
+      self->matrix[i] = [[NSArray alloc] init];
+  }
+}
+
+- (void)appendContentToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  index:(int)_idx
+{
+  WOComponent  *comp;
+  NSArray      *array;
+  id           app;
+  int          i, cnt, idx, count;
+
+  comp  = [_ctx component];
+  array = [self->list valueInComponent:comp];
+  count = [array count];
+
+  // *** append day info
+  [_ctx enableMonthOverviewInfoMode];
+  [_ctx appendElementIDComponent:@"i"];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  [_ctx disableMonthOverviewInfoMode];
+  
+  // *** append day content
+  [_ctx enableMonthOverviewContentMode];
+  [_ctx appendElementIDComponent:@"c"]; // append content mode
+  for (i = 0, cnt = [self->matrix[_idx] count]; i < cnt; i++) {
+    NSString *s;
+    
+    idx = [[self->matrix[_idx] objectAtIndex:i] intValue];
+
+    if (idx >= count) {
+      NSLog(@"Warning! WEMonthOverview: index out of range");
+      continue;
+    }
+    app = [array objectAtIndex:idx];
+    
+    if ([self->item isValueSettable])
+      [self->item  setValue:app inComponent:comp];
+    if ([self->index isValueSettable])
+      [self->index setIntValue:idx inComponent:comp];
+
+    if (self->identifier == nil) {
+      s = retStrForInt(idx);
+      [_ctx appendElementIDComponent:s];
+      [s release];
+    }
+    else {
+      s = [self->identifier stringValueInComponent:comp];
+      [_ctx appendElementIDComponent:s];
+    }
+    
+    [self->template appendToResponse:_response inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+  [_ctx deleteLastElementIDComponent]; // delete content mode
+  [_ctx disableMonthOverviewContentMode];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent    *comp;
+  NSString       *style;
+  NSString       *bgcolor;
+  BOOL           useTableTags;
+
+  BOOL           renderDefaults = NO;
+  BOOL           hasTitle       = NO;
+  BOOL           hasHeader      = NO;
+  BOOL           hasLeftTop     = NO;
+  BOOL           hasLeft        = NO;
+  BOOL           hasTop         = NO;
+  BOOL           hasRightTop    = NO;
+  BOOL           hasRight       = NO;
+  BOOL           hasLeftBottom  = NO;
+  BOOL           hasBottom      = NO;
+  BOOL           hasRightBottom = NO;
+  BOOL           hasCell        = NO;
+
+  [self _calcMatrixInContext:_ctx];
+      
+  comp = [_ctx component];
+
+  useTableTags = (self->tableTags) 
+    ? [self->tableTags boolValueInComponent:comp]
+    : YES;
+
+  { // query mode ... testing orientations
+    NSEnumerator *queryE;
+    NSString     *orient;
+    
+    // only query mode .. no value setting
+    [_ctx setupMonthOverviewContextForQueryMode];
+    
+    /* this walks over all subelements and collects 'query' info */
+    
+    [self->template appendToResponse:_response inContext:_ctx];
+    
+    /* now process the results */
+    
+    queryE = [[_ctx monthOverviewQueryObjects] objectEnumerator];
+    
+    while ((orient = [queryE nextObject])) {
+      if ((!hasHeader) && ([orient isEqualToString:@"header"]))
+        hasHeader = YES;
+      if ((!hasCell) && ([orient isEqualToString:@"cell"]))
+        hasCell = YES;
+      if ((!hasTitle) && ([orient isEqualToString:@"title"]))
+        hasTitle = YES;
+      if ((!hasLeftTop) && ([orient isEqualToString:@"left/top"]))
+        hasLeftTop = YES;
+      if ((!hasLeftBottom) && ([orient isEqualToString:@"left/bottom"]))
+        hasLeftBottom = YES;
+      if ((!hasLeft) && ([orient isEqualToString:@"left"]))
+        hasLeft = YES;
+      if ((!hasTop) && ([orient isEqualToString:@"top"]))
+        hasTop = YES;
+      if ((!hasRightTop) && ([orient isEqualToString:@"right/top"]))
+        hasRightTop = YES;
+      if ((!hasRight) && ([orient isEqualToString:@"right"]))
+        hasRight = YES;
+      if ((!hasRightBottom) && ([orient isEqualToString:@"right/bottom"]))
+        hasRightBottom = YES;
+      if ((!hasBottom) && ([orient isEqualToString:@"bottom"]))
+        hasBottom = YES;
+    }
+
+    if (!(hasLeft || hasRight || hasTop || hasBottom))
+      renderDefaults = YES;
+
+    [_ctx tearDownMonthOverviewContext];
+  }
+  
+  /* open table */
+  if (useTableTags) {
+    [_response appendContentString:@"<table"];
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    [_response appendContentString:@">"];
+  }
+
+  /* generating head */
+  if (hasHeader) {
+    NSString *s;
+    int width = 7;
+    
+    if ((hasLeft) || (hasLeftTop) || (hasLeftBottom))
+      width++;
+    if ((hasRight) || (hasRightTop) || (hasRightBottom))
+      width++;
+
+    [_response appendContentString:@"<tr>"];
+    
+    s = retStrForInt(width);
+    _generateCell(self, _response, _ctx, @"header", s, nil);
+    [s release];
+
+    [_response appendContentString:@"</tr>"];
+  }
+
+  // generating top
+  if ((hasTop) || (hasLeftTop) || (hasRightTop) || (renderDefaults)) {
+    [_response appendContentString:@"<tr>"];
+
+    if (hasLeftTop)
+      _generateCell(self, _response, _ctx, @"left/top", @"--", nil);
+    else if (hasLeft || hasLeftBottom || renderDefaults)
+      [_response appendContentString:@"<td>&nbsp;</td>"];
+
+    if (hasTop) {
+      int i, dow = 0;
+
+      dow = self->matrixInfo.firstDisplayedDay;
+      for (i = 0; i < 7; i++) {
+        _generateCell(self, _response, _ctx, @"top",
+                      [[NSNumber numberWithInt:dow] stringValue], nil);
+        dow = (dow == 6) ? 0 : dow+1;
+      }
+    }
+    else if (renderDefaults) {
+      NSCalendarDate *day;
+      int i;
+      
+      day = self->matrixInfo.start;
+      for (i = 0; i < 7; i++) {
+        NSString *s;
+        
+        [_response appendContentString:@"<td align=\"center\""];
+        if ((style = [self->labelStyle stringValueInComponent:comp])) {
+            [_response appendContentString:@" class=\""];
+            [_response appendContentHTMLAttributeValue:style];
+            [_response appendContentCharacter:'"'];
+        }
+        if ((bgcolor = [self->labelColor stringValueInComponent:comp])) {
+          [_response appendContentString:@" bgcolor=\""];
+          [_response appendContentString:bgcolor];
+          [_response appendContentCharacter:'"'];
+        }
+        [_response appendContentString:@"><b>"];
+        /* TODO: replace with manual string */
+        s = [day descriptionWithCalendarFormat:@"%A"];
+        [_response appendContentString:s];
+        [_response appendContentString:@"</b></td>"];
+        day = [day tomorrow];
+      }
+    }
+    else if (hasRightTop || hasLeftTop) {
+      [_response appendContentString:
+                 @"<td></td><td></td><td></td><td></td>"
+                 @"<td></td><td></td><td></td>"];
+    }
+    
+    if (hasRightTop)
+      _generateCell(self, _response, _ctx, @"right/top", @"--", nil);
+    else if (hasRightBottom || hasRight)
+      [_response appendContentString:@"<td>&nbsp;</td>"];
+
+    [_response appendContentString:@"</tr>"];
+  }
+
+  /* generating content */
+  {
+    NSCalendarDate *day;
+    NSString       *week;
+    int            i, j, maxNumberOfWeeks;
+
+    day = self->matrixInfo.start;
+    maxNumberOfWeeks = [day numberOfWeeksInYear];
+    week = 
+      retStrForInt([[day dateByAddingYears:0 months:0 days:3] weekOfYear]);
+    for (i = 0; i < self->matrixInfo.weeks; i++) {
+      [_response appendContentString:@"<tr>"];
+
+      if (hasLeft) {
+        _generateCell(self, _response, _ctx, @"left", week, nil);
+      }
+      else if (renderDefaults) {
+        [_response appendContentString:@"<td width=\"2%\" align=\"center\""];
+          if ((style = [self->labelStyle stringValueInComponent:comp])) {
+              [_response appendContentString:@" class=\""];
+              [_response appendContentHTMLAttributeValue:style];
+              [_response appendContentCharacter:'"'];
+          }
+          if ((bgcolor = [self->labelColor stringValueInComponent:comp])) {
+          [_response appendContentString:@" bgcolor=\""];
+          [_response appendContentString:bgcolor];
+          [_response appendContentCharacter:'"'];
+        }
+        [_response appendContentCharacter:'>'];
+        [_response appendContentString:week];
+        [_response appendContentString:@"</td>"];
+      }
+      else if (hasLeftTop || hasLeftBottom)
+        [_response appendContentString:@"<td>&nbsp;</td>"];
+
+      /* append days of week */
+      for (j = 0; j < 7; j++) {
+        NSString *s;
+        
+        if ([self->currentDay isValueSettable])
+          [self->currentDay setValue:day inComponent:comp];
+        
+        [_response appendContentString:@"<td"];
+        if ((style = [self->contentStyle stringValueInComponent:comp])) {
+            [_response appendContentString:@" class=\""];
+            [_response appendContentHTMLAttributeValue:style];
+            [_response appendContentCharacter:'"'];
+        }
+        if ((bgcolor = [self->contentColor stringValueInComponent:comp])) {
+          [_response appendContentString:@" bgcolor=\""];
+          [_response appendContentString:bgcolor];
+          [_response appendContentCharacter:'"'];
+        }
+        [_response appendContentCharacter:'>'];
+
+        
+        [_response appendContentString:
+                   @"<table border='0' height='100%' cellspacing='0'"
+                   @" cellpadding='2' width='100%'><tr>"];
+        
+        if (hasTitle)
+          _generateCell(self, _response, _ctx, @"title", @"--", day);
+        else {
+          [_response appendContentString:
+                       @"<td valign=\"top\">"
+                       @"<font size=\"4\" color=\"black\">"
+                       @"<u>"];
+          s = retStrForInt([day dayOfMonth]);
+          [_response appendContentString:s];
+          [s release];
+          [_response appendContentString:@"</u></font></td>"];
+        }
+
+
+        /*** appending content ***/
+        [_ctx appendElementIDComponent:@"cell"];
+        s = retStrForInt([day timeIntervalSince1970]);
+        [_ctx appendElementIDComponent:s];
+        [s release];
+        [_response appendContentString:@"<td valign=\"top\">"];
+        [self appendContentToResponse:_response inContext:_ctx index:(i*7+j)];
+        [_response appendContentString:@"</td>"];
+        [_ctx deleteLastElementIDComponent]; // delete date
+        [_ctx deleteLastElementIDComponent]; // delete "cell"
+
+        [_response appendContentString:@"</tr></table></td>"];
+        day  = [day tomorrow];
+      }
+
+      if (hasRight)
+        _generateCell(self, _response, _ctx, @"right", week, nil);
+      else if (hasRightTop || hasRightBottom)
+        [_response appendContentString:@"<td>&nbsp;</td>"];
+      
+      [_response appendContentString:@"</tr>"];
+      
+      {
+         int nextWeek;
+         nextWeek = ([week intValue] % maxNumberOfWeeks) + 1;
+         [week release]; week = nil;
+         week = retStrForInt(nextWeek);
+      }
+    }
+    [week release]; week = nil;
+  }
+  
+  /* generating footer */
+  if ((hasBottom) || (hasLeftBottom) || (hasRightBottom)) {
+
+    [_response appendContentString:@"<tr>"];
+
+    if (hasLeftBottom)
+      _generateCell(self, _response, _ctx, @"left/bottom", @"--", nil);
+    else if (hasLeft || hasLeftTop)
+      [_response appendContentString:@"<td>&nbsp;</td>"];
+
+    if (hasBottom) {
+      int i, dow = 0; // dayOfWeek
+
+      dow = self->matrixInfo.firstDisplayedDay;
+      
+      for (i = 0; i < 7; i++) {
+        NSString *s;
+
+        s = retStrForInt(dow);
+        _generateCell(self, _response, _ctx, @"bottom", s, nil);
+        [s release];
+        dow = (dow == 6) ? 0 : dow + 1;
+      }
+    }
+    else {
+      [_response appendContentString:
+                 @"<td></td><td></td><td></td><td></td>"
+                 @"<td></td><td></td><td></td>"];
+    }
+
+    if (hasRightBottom)
+      _generateCell(self, _response, _ctx, @"right/bottom", @"--", nil);
+    else if (hasRightTop || hasRight)
+      [_response appendContentString:@"<td>&nbsp;</td>"]; 
+
+    [_response appendContentString:@"</tr>"];
+  }
+
+  // close table
+  if (useTableTags)
+    [_response appendContentString:@"</table>"];
+
+  [self resetMatrix];
+}
+
+
+- (void)takeContentValues:(WORequest *)_req
+                inContext:(WOContext *)_ctx
+                    index:(int)_idx
+{
+  WOComponent *comp;
+  NSString    *s;
+  NSArray     *array;
+  int         i, idx, cnt, count;
+
+  comp  = [_ctx component];
+  array = [self->list valueInComponent:comp];
+  count = [array count];
+  
+  [_ctx appendElementIDComponent:@"c"]; // append content mode
+
+  cnt = [self->matrix[_idx] count];
+  for (i=0; i<cnt; i++) {
+    idx = [[self->matrix[_idx] objectAtIndex:i] intValue];
+
+    if (self->index)
+      [self->index setUnsignedIntValue:idx inComponent:comp];
+    if (self->item)
+      [self->item setValue:[array objectAtIndex:idx] inComponent:comp];
+    
+    s = (self->identifier)
+      ? [[self->identifier stringValueInComponent:comp] retain]
+      : retStrForInt(idx);
+    
+    [_ctx appendElementIDComponent:s]; // append index-id
+    [s release];
+      
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+    [_ctx deleteLastElementIDComponent]; // delte index-id
+  }
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent    *sComponent;
+  NSCalendarDate *day;
+  NSString       *week;
+  int            i, j;
+  unsigned int   weekOfYear;
+  unsigned char  buf[32];
+  
+  [self _calcMatrixInContext:_ctx];
+  
+  sComponent = [_ctx component];
+  
+  day = self->matrixInfo.start;
+  
+  weekOfYear = [[day dateByAddingYears:0 months:0 days:3] weekOfYear];
+  sprintf(buf, "%d", weekOfYear);
+  week = [StrClass stringWithCString:buf];
+  
+  // TODO: weird use of NSString for week?
+  for (i = 0; i < self->matrixInfo.weeks; i++) {
+    for (j = 0; j < 7; j++) {
+      NSString *eid;
+      
+      if ([self->currentDay isValueSettable])
+        [self->currentDay setValue:day inComponent:sComponent];
+      
+      sprintf(buf, "%d", (unsigned)[day timeIntervalSince1970]);
+      eid = [[StrClass alloc] initWithCString:buf];
+      [_ctx appendElementIDComponent:eid];
+      [eid release];
+      
+      _takeValuesInCell(self, _req, _ctx, @"title", @"--");
+      [self takeContentValues:_req inContext:_ctx index:(i * 7 + j)];
+      [_ctx deleteLastElementIDComponent];
+      
+      day  = [day tomorrow];
+    }
+    sprintf(buf, "%d", ([week intValue] + 1));
+    week = [StrClass stringWithCString:buf];
+  }
+
+  [self resetMatrix];
+}
+
+- (id)invokeContentAction:(WORequest *)_request inContext:(WOContext *)_ctx{
+  id       result = nil;
+  NSString *idxId = nil;
+
+  if ((idxId = [_ctx currentElementID]) == 0) // no content nor info mode
+    return nil;
+    
+  [_ctx consumeElementID];                // consume mode
+  [_ctx appendElementIDComponent:idxId];  // append mode ("c" or "i")
+
+  if ([idxId isEqualToString:@"i"])
+    // info mode
+    result = [self->template invokeActionForRequest:_request inContext:_ctx];
+  else if ((idxId = [_ctx currentElementID])) {
+    // content mode
+    [_ctx consumeElementID];               // consume index-id
+    [_ctx appendElementIDComponent:idxId];
+
+    if (self->identifier)
+      _applyIdentifier(self, [_ctx component], idxId);
+    else
+      _applyIndex(self, [_ctx component], [idxId intValue]);
+
+    result = [self->template invokeActionForRequest:_request inContext:_ctx];
+
+    [_ctx deleteLastElementIDComponent]; // delete index-id
+  }
+  [_ctx deleteLastElementIDComponent]; // delete mode
+    
+  return result;
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent     *sComponent;
+  id              result = nil;
+  NSString        *ident;
+  NSString        *orient;
+
+  sComponent = [_ctx component];
+  
+  if ((orient = [_ctx currentElementID]) == nil) {
+    [[_ctx session]
+           logWithFormat:@"%@: MISSING ORIENTATION ID in URL !", self];
+    return nil;
+  }
+
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:orient];
+  
+  [_ctx setupMonthOverviewContextWithOrientation:orient];
+  
+  if ([orient isEqualToString:@"cell"] || [orient isEqualToString:@"title"]){
+    /* content or 'title' */
+    if ((ident = [_ctx currentElementID]) != nil) {
+        NSCalendarDate *day;
+        int ti;
+    
+        [_ctx consumeElementID]; // consume date-id
+        [_ctx appendElementIDComponent:ident];
+
+        ti = [ident intValue];
+      
+        day = [NSCalendarDate dateWithTimeIntervalSince1970:ti];
+        [day setTimeZone:[self->timeZone valueInComponent:sComponent]];
+
+        if ([self->currentDay isValueSettable])
+          [self->currentDay setValue:day inComponent:sComponent];
+
+        if ([orient isEqualToString:@"title"])
+          result = [self->template invokeActionForRequest:_req inContext:_ctx];
+        else
+          result = [self invokeContentAction:_req inContext:_ctx];
+        
+        [_ctx deleteLastElementIDComponent]; // delete 'cell' or 'title'
+    }
+    else
+      [[_ctx session]
+             logWithFormat:@"%@: MISSING DATE ID in '%@' URL !", self, orient];
+  }
+  else {
+    /* neither 'cell' nor 'title' (some label) */
+    result = [self->template invokeActionForRequest:_req inContext:_ctx];
+  }
+  [_ctx deleteLastElementIDComponent]; /* delete orient */
+
+  // TODO: no teardown of month-overview context?
+    
+  return result;
+}
+
+@end /* WEMonthOverview */
+
+@implementation WEMonthLabel
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary*)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->orientation  = WOExtGetProperty(_config, @"orientation");
+    self->dayOfWeek    = WOExtGetProperty(_config, @"dayOfWeek");
+    self->weekOfYear   = WOExtGetProperty(_config, @"weekOfYear");
+    self->colspan      = WOExtGetProperty(_config, @"colspan");
+
+    self->template = [_t retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->orientation release];
+  [self->dayOfWeek   release];
+  [self->weekOfYear  release];
+  [self->colspan     release];
+  
+  [self->template release];
+  [super dealloc];
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSDictionary *monthViewContextDict;
+  NSString     *orient;
+  BOOL         isEdge;
+  id tmp;
+  
+  orient = [self->orientation valueInComponent:[_ctx component]];
+  isEdge = ([orient rangeOfString:@"/"].length > 0);
+  
+  monthViewContextDict  = [_ctx monthOverviewContext];
+  if ((tmp = [monthViewContextDict objectForKey:orient]) != nil) {
+    if (!isEdge) {
+      [_ctx appendElementIDComponent:orient];
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+      [_ctx deleteLastElementIDComponent];
+    }
+    else {
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+    }
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSDictionary *monthViewContextDict;
+  NSString     *orient;
+  BOOL         isEdge;
+  id           result;
+  id tmp;
+  
+  orient = [self->orientation valueInComponent:[_ctx component]];
+  isEdge = ([orient rangeOfString:@"/"].length > 0);
+  
+  monthViewContextDict  = [_ctx monthOverviewContext];
+  if ((tmp = [monthViewContextDict objectForKey:orient]) == nil)
+    return nil;
+
+  if (isEdge)
+    return [self->template invokeActionForRequest:_req inContext:_ctx];
+
+  tmp = [_ctx currentElementID];
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:tmp];
+      
+  if ([orient isEqualToString:@"top"] ||
+      [orient isEqualToString:@"bottom"]) {
+    [self->dayOfWeek setIntValue:[tmp intValue]
+                         inComponent:[_ctx component]];
+  }
+  else if ([orient isEqualToString:@"left"] ||
+           [orient isEqualToString:@"right"]) {
+    [self->weekOfYear setIntValue:[tmp intValue]
+                          inComponent:[_ctx component]];
+  }
+  else if ([orient isEqualToString:@"header"]) {
+    [self->colspan setIntValue:[tmp intValue]
+                       inComponent:[_ctx component]];
+  }
+      
+  result = [self->template invokeActionForRequest:_req inContext:_ctx];
+
+  [_ctx deleteLastElementIDComponent];
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSDictionary   *monthViewContextDict;
+  NSMutableArray *queryContext;
+  id       tmp;
+  NSString *orient;
+  BOOL     isEdge;
+  int      cols;
+
+  orient = [self->orientation stringValueInComponent:[_ctx component]];
+  isEdge = ([orient rangeOfString:@"/"].length > 0);
+  
+  if (orient == nil) return;
+  
+  if ((queryContext = [_ctx monthOverviewQueryObjects]) != nil) {
+    [queryContext addObject:orient];
+    return;
+  }
+  
+  monthViewContextDict = [_ctx monthOverviewContext];
+  if ((tmp = [monthViewContextDict objectForKey:orient]) == nil)
+    return;
+  
+  cols = -1;
+  if (!isEdge) {
+    int orientIntValue;
+    
+    orientIntValue = [tmp intValue];
+    if ([orient isEqualToString:@"top"] ||
+       [orient isEqualToString:@"bottom"]) {
+        [self->dayOfWeek setIntValue:orientIntValue 
+                        inComponent:[_ctx component]];
+      }
+      else if ([orient isEqualToString:@"left"] ||
+               [orient isEqualToString:@"right"]) {
+        [self->weekOfYear setIntValue:orientIntValue
+                         inComponent:[_ctx component]];
+      } 
+      else if ([orient isEqualToString:@"header"]) {
+        [self->colspan setIntValue:orientIntValue
+                       inComponent:[_ctx component]];
+        cols = [tmp intValue];
+      }
+  }
+    
+  [_response appendContentString:@"<td"];
+
+  if (cols != -1) {
+    NSString *colStr;
+    
+    colStr = retStrForInt(cols);
+    [_response appendContentString:@" colspan=\""];
+    [_response appendContentString:colStr];
+    [_response appendContentString:@"\""];
+    [colStr release];
+  }
+    
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  [_response appendContentString:@">"];
+      
+  if (!isEdge)
+    [_ctx appendElementIDComponent:[tmp stringValue]];
+    
+  [self->template appendToResponse:_response inContext:_ctx];
+    
+  if (!isEdge)
+    [_ctx deleteLastElementIDComponent];
+
+  // close table data tag
+  [_response appendContentString:@"</td>"];
+}
+
+@end /* WEMonthLabel */
+
+@implementation WEMonthTitle
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary*)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->template = [_t retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template release];
+  [super dealloc];
+}
+
+/* handling requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSDictionary *monthViewContextDict;
+  id tmp;
+  
+  monthViewContextDict  = [_ctx monthOverviewContext];
+  if ((tmp = [monthViewContextDict objectForKey:@"title"]) != nil)
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSDictionary *monthViewContextDict;
+  id tmp;
+  
+  monthViewContextDict  = [_ctx monthOverviewContext];
+  if ((tmp = [monthViewContextDict objectForKey:@"title"]) != nil)
+    return [self->template invokeActionForRequest:_req inContext:_ctx];
+  
+  return nil;
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSDictionary *monthViewContextDict;
+  id tmp;
+  
+  if ((tmp = [_ctx monthOverviewQueryObjects]) != nil) {
+    [(NSMutableArray *)tmp addObject:@"title"];
+    return;
+  }
+  
+  monthViewContextDict = [_ctx monthOverviewContext];
+  if ((tmp = [monthViewContextDict objectForKey:@"title"]) != nil) {
+    // append table date, forwarding extra attributes
+    [_response appendContentString:@"<td"];
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    [_response appendContentString:@">"];
+    // append child
+    [self->template appendToResponse:_response inContext:_ctx];
+    // close table data tag
+    [_response appendContentString:@"</td>"];
+  }
+}
+
+@end /* WEMonthTitle */
+
+@interface WEMonthOverviewInfoMode : WEContextConditional
+@end
+
+@implementation WEMonthOverviewInfoMode
+
+- (NSString *)_contextKey {
+  return WEMonthOverview_InfoMode;
+}
+
+@end /* WEMonthOverviewInfoMode */
+
+@interface WEMonthOverviewContentMode : WEContextConditional
+@end
+
+@implementation WEMonthOverviewContentMode
+
+- (NSString *)_contextKey {
+  return WEMonthOverview_ContentMode;
+}
+
+@end /* WEMonthOverviewContentMode */
diff --git a/skyrix-sope/WEExtensions/WEPageLink.m b/skyrix-sope/WEExtensions/WEPageLink.m
new file mode 100644 (file)
index 0000000..4d8fc40
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+/*
+  WEPageLink
+  
+  This element is pretty similiar to WOHyperlink with the "pageName" binding,
+  but in addition allows for parameters being passed to the page.
+
+  WEPageLink associations:
+    
+    pageName
+    sync     (either array of names or a string with names seperated by ',')
+*/
+
+@class WOAssociation, WOElement;
+@class NSDictionary;
+
+@interface WEPageLink : WODynamicElement
+{
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *pageName;
+  WOAssociation *syncBindings;
+  WOElement     *template;
+  unsigned      keyCount;
+  NSArray       *keys;
+  NSArray       *assocs;
+}
+
+@end
+
+#include "common.h"
+
+@implementation WEPageLink
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    NSMutableArray *mkeys, *massocs;
+    NSEnumerator *e;
+    NSString *k;
+    
+    self->pageName     = WOExtGetProperty(_config, @"pageName");
+    self->syncBindings = WOExtGetProperty(_config, @"sync");
+    self->template = [_t retain];
+    
+    self->keyCount = [_config count];
+    mkeys   = [[NSMutableArray alloc] initWithCapacity:self->keyCount];
+    massocs = [[NSMutableArray alloc] initWithCapacity:self->keyCount];
+    
+    e = [_config keyEnumerator];
+    while ((k = [e nextObject])) {
+      [mkeys addObject:k];
+      [massocs addObject:[_config objectForKey:k]];
+    }
+    self->keys   = [mkeys   copy]; [mkeys   release];
+    self->assocs = [massocs copy]; [massocs release];
+    
+    [(NSMutableDictionary *)_config removeAllObjects];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->syncBindings release];
+  [self->template release];
+  [self->pageName release];
+  [self->keys     release];
+  [self->assocs   release];
+  [super dealloc];
+}
+
+/* handling requests */
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  WOComponent *page, *sComponent;
+  NSString    *name;
+  unsigned    i;
+  id sync;
+  
+  if (![[_ctx elementID] isEqualToString:[_ctx senderID]])
+    /* link is not the active element */
+    return [self->template invokeActionForRequest:_rq inContext:_ctx];
+
+  /* link is the active element */
+  
+  sComponent = [_ctx component];
+  name = [self->pageName stringValueInComponent:sComponent];
+  page = [[_ctx application] pageWithName:name inContext:_ctx];
+  
+  if (page == nil) {
+    [self logWithFormat:@"did not find page with name '%@'.", name];
+    return nil;
+  }
+  
+  /* apply sync bindings */
+  
+  if ((sync = [self->syncBindings valueInComponent:sComponent])) {
+    unsigned count;
+    
+    if (![sync isKindOfClass:[NSArray class]])
+      sync = [[sync stringValue] componentsSeparatedByString:@","];
+    
+    // Note: we cannot use keypathes in a useful way here because we reuse
+    //       the key for assignment
+    for (i = 0, count = [sync count]; i < count; i++) {
+      NSString *key;
+      id value;
+      
+      key   = [sync objectAtIndex:i];
+      value = [sComponent valueForKey:key];
+      [page takeValue:value forKey:key];
+    }
+  }
+  
+  /* apply bindings */
+  
+  for (i = 0; i < self->keyCount; i++) {
+    id value;
+    
+    value = [[self->assocs objectAtIndex:i] valueInComponent:sComponent];
+    [page takeValue:value forKey:[self->keys objectAtIndex:i]];
+  }
+  
+  return page;
+}
+
+/* response generation */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *href;
+  
+  href = [_ctx componentActionURL];
+  [_response appendContentCString:"<a href=\""];
+  [_response appendContentString:href];
+  [_response appendContentCharacter:'"'];
+  
+  if (self->otherTagString) {
+    NSString *s;
+    
+    s = [self->otherTagString stringValueInComponent:[_ctx component]];
+    [_response appendContentString:s];
+  }
+  [_response appendContentCharacter:'>'];
+  
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_response appendContentCString:"</a>"];
+}
+
+@end /* WEPageLink */
diff --git a/skyrix-sope/WEExtensions/WEPageView.m b/skyrix-sope/WEExtensions/WEPageView.m
new file mode 100644 (file)
index 0000000..157ae80
--- /dev/null
@@ -0,0 +1,823 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+#include <NGObjWeb/WOContext.h>
+
+/*
+  WEPageView
+  
+  TODO: describe what it does
+*/
+
+@interface WEPageView : WODynamicElement
+{
+  WOAssociation *selection;
+
+  /* config: */
+  WOAssociation *titleColor;
+  WOAssociation *contentColor;
+
+  WOAssociation *fontColor;
+  WOAssociation *fontFace;
+  WOAssociation *fontSize;
+  
+  WOAssociation *firstIcon;
+  WOAssociation *firstBlind;    // firstBlindIcon
+  WOAssociation *previousIcon;
+  WOAssociation *previousBlind; // previousBlindIcon
+  WOAssociation *nextIcon;
+  WOAssociation *nextBlind;     // nextBlindIcon
+  WOAssociation *lastIcon;
+  WOAssociation *lastBlind;     // lastBlindIcon
+
+  WOAssociation *firstLabel;
+  WOAssociation *previousLabel;
+  WOAssociation *nextLabel;
+  WOAssociation *lastLabel;
+  
+  id            template;
+}
+
+@end
+
+@interface WEPageItem : WODynamicElement
+{
+  WOAssociation *key;
+  WOAssociation *title;
+  WOAssociation *action;
+  
+  id            template;
+}
+
+@end
+
+@interface WEPageItemInfo : NSObject
+{
+@public
+  NSString *title;
+  NSString *key;
+  NSString *uri;
+}
+@end
+
+#include "common.h"
+#include "WEClientCapabilities.h"
+#import <NGObjWeb/NGObjWeb.h>
+#import <NGExtensions/NGExtensions.h>
+#import <EOControl/EOControl.h>
+
+// #define DEBUG_TAKEVALUES 1
+
+/* context keys */
+static NSString *WEPageView_HEAD      = @"WEPageView_head";
+static NSString *WEPageView_BODY      = @"WEPageView_body";
+static NSString *WEPageView_KEYS      = @"WEPageView_keys";
+static NSString *WEPageView_ACTIVEKEY = @"WEPageView_activekey";
+static NSString *WEPageView_COLLECT   = @"~tv~";
+
+// navigation icons
+static NSString *WEPageView_first          = @"WEPageView_first";
+static NSString *WEPageView_first_blind    = @"WEPageView_first_blind";
+static NSString *WEPageView_previous       = @"WEPageView_previous";
+static NSString *WEPageView_previous_blind = @"WEPageView_previous_blind";
+static NSString *WEPageView_next           = @"WEPageView_next";
+static NSString *WEPageView_next_blind     = @"WEPageView_next_blind";
+static NSString *WEPageView_last           = @"WEPageView_last";
+static NSString *WEPageView_last_blind     = @"WEPageView_last_blind";
+
+// labels
+static NSString *WEPageView_firstLabel     = @"WEPageView_firstLabel";
+static NSString *WEPageView_previousLabel  = @"WEPageView_previousLabel";
+static NSString *WEPageView_nextLabel      = @"WEPageView_nextLabel";
+static NSString *WEPageView_lastLabel      = @"WEPageView_lastLabel";
+
+static NSString *WEPageView_               = @"WEPageView_";
+
+@implementation WEPageView
+
+static NSNumber *YesNumber = nil;
+
++ (void)initialize {
+  if (YesNumber == nil) YesNumber = [[NSNumber numberWithBool:YES] retain];
+}
+
++ (int)version {
+  return [super version] + 0;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->selection      = WOExtGetProperty(_config, @"selection");
+
+    self->contentColor   = WOExtGetProperty(_config, @"contentColor");
+    self->titleColor     = WOExtGetProperty(_config, @"titleColor");
+    
+    self->firstIcon      = WOExtGetProperty(_config, @"firstIcon");
+    self->firstBlind     = WOExtGetProperty(_config, @"firstBlindIcon");
+    self->previousIcon   = WOExtGetProperty(_config, @"previousIcon");
+    self->previousBlind  = WOExtGetProperty(_config, @"previousBlindIcon");
+    self->nextIcon       = WOExtGetProperty(_config, @"nextIcon");
+    self->nextBlind      = WOExtGetProperty(_config, @"nextBlindIcon");
+    self->lastIcon       = WOExtGetProperty(_config, @"lastIcon");
+    self->lastBlind      = WOExtGetProperty(_config, @"lastBlindIcon");
+
+    self->firstLabel     = WOExtGetProperty(_config, @"firstLabel");
+    self->previousLabel  = WOExtGetProperty(_config, @"previousLabel");
+    self->nextLabel      = WOExtGetProperty(_config, @"nextLabel");
+    self->lastLabel      = WOExtGetProperty(_config, @"lastLabel");
+
+    self->fontColor      = WOExtGetProperty(_config, @"fontColor");
+    self->fontFace       = WOExtGetProperty(_config, @"fontFace");
+    self->fontSize       = WOExtGetProperty(_config, @"fontSize");
+
+#define SetAssociationValue(_a_, _value_) \
+    if (_a_ == nil) \
+      _a_ = [[WOAssociation associationWithValue:_value_] retain];
+    
+    SetAssociationValue(self->firstLabel,    @"<<");
+    SetAssociationValue(self->previousLabel, @"<");
+    SetAssociationValue(self->nextLabel,     @">");
+    SetAssociationValue(self->lastLabel,     @">>");
+           
+#undef SetAssociationValue
+    
+    self->template = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->selection);
+  
+  RELEASE(self->contentColor);
+  RELEASE(self->titleColor);
+
+  RELEASE(self->firstIcon);
+  RELEASE(self->firstBlind);
+  RELEASE(self->previousIcon);
+  RELEASE(self->previousBlind);
+  RELEASE(self->nextIcon);
+  RELEASE(self->nextBlind);
+  RELEASE(self->lastIcon);
+  RELEASE(self->lastBlind);
+
+  RELEASE(self->firstLabel);
+  RELEASE(self->previousLabel);
+  RELEASE(self->nextLabel);
+  RELEASE(self->lastLabel);
+
+  RELEASE(self->fontColor);
+  RELEASE(self->fontFace);
+  RELEASE(self->fontSize);
+  
+  RELEASE(self->template);
+  [super dealloc];
+}
+
+
+- (void)updateConfigInContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSString    *tmp;
+
+  cmp = [_ctx component];
+
+#define SetConfigInContext(_a_, _key_)                                  \
+      if (_a_ && (tmp = [_a_ valueInComponent:cmp]))                    \
+        [_ctx setObject:tmp forKey:_key_];                              \
+    
+  SetConfigInContext(self->firstIcon,     WEPageView_first);
+  SetConfigInContext(self->firstBlind,    WEPageView_first_blind);
+  SetConfigInContext(self->previousIcon,  WEPageView_previous);
+  SetConfigInContext(self->previousBlind, WEPageView_previous_blind);
+  SetConfigInContext(self->nextIcon,      WEPageView_next);
+  SetConfigInContext(self->nextBlind,     WEPageView_next_blind);
+  SetConfigInContext(self->lastIcon,      WEPageView_last);
+  SetConfigInContext(self->lastBlind,     WEPageView_last_blind);
+
+  SetConfigInContext(self->firstLabel,    WEPageView_firstLabel);
+  SetConfigInContext(self->previousLabel, WEPageView_previousLabel);
+  SetConfigInContext(self->nextLabel,     WEPageView_nextLabel);
+  SetConfigInContext(self->lastLabel,     WEPageView_lastLabel);
+
+#undef SetConfigInContext
+}
+
+- (void)removeConfigInContext:(WOContext *)_ctx {
+  [_ctx removeObjectForKey:WEPageView_first];
+  [_ctx removeObjectForKey:WEPageView_first_blind];
+  [_ctx removeObjectForKey:WEPageView_previous];
+  [_ctx removeObjectForKey:WEPageView_previous_blind];
+  [_ctx removeObjectForKey:WEPageView_next];
+  [_ctx removeObjectForKey:WEPageView_next_blind];
+  [_ctx removeObjectForKey:WEPageView_last];
+  [_ctx removeObjectForKey:WEPageView_last_blind];
+
+  [_ctx removeObjectForKey:WEPageView_firstLabel];
+  [_ctx removeObjectForKey:WEPageView_previousLabel];
+  [_ctx removeObjectForKey:WEPageView_nextLabel];
+  [_ctx removeObjectForKey:WEPageView_lastLabel];
+}
+
+static inline NSString *WEPageLabelForKey(NSString *_key, WOContext *_ctx) {
+  NSString *key;
+
+  key = [NSString stringWithFormat:@"WEPageView_%@Label", _key];
+  return [_ctx objectForKey:key];
+}
+
+/* nesting */
+
+- (id)saveNestedStateInContext:(WOContext *)_ctx {
+  return nil;
+}
+- (void)restoreNestedState:(id)_state inContext:(WOContext *)_ctx {
+  if (_state == nil) return;
+}
+
+- (NSArray *)collectKeysInContext:(WOContext *)_ctx {
+  /* collect mode, collects all keys */
+  [_ctx setObject:WEPageView_COLLECT forKey:WEPageView_HEAD];
+
+  [self->template appendToResponse:nil inContext:_ctx];
+  
+  [_ctx removeObjectForKey:WEPageView_HEAD];
+  return [_ctx objectForKey:WEPageView_KEYS];
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  id nestedState;
+  
+  nestedState = [self saveNestedStateInContext:_ctx];
+
+  [_ctx appendElementIDComponent:@"h"];
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  
+  [_ctx appendElementIDComponent:@"b"];
+  [_ctx setObject:self->selection forKey:WEPageView_BODY];
+
+#if DEBUG_TAKEVALUES
+  [[_ctx component] debugWithFormat:@"WEPageView: body takes values, eid='%@'",
+                    [_ctx elementID]];
+#endif
+  
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+  
+  [_ctx removeObjectForKey:WEPageView_BODY];
+  [_ctx deleteLastElementIDComponent]; /* 'b' */
+  [self restoreNestedState:nestedState inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  NSString *key;
+  id result;
+
+  result = nil;
+  if ((key = [_ctx currentElementID])) {
+    id nestedState;
+    
+    nestedState = [self saveNestedStateInContext:_ctx];
+    
+    if ([key isEqualToString:@"h"]) {
+      /* header action */
+      
+      [_ctx consumeElementID];
+      [_ctx appendElementIDComponent:key];
+      
+      [_ctx setObject:self->selection forKey:WEPageView_HEAD];
+      result = [self->template invokeActionForRequest:_request inContext:_ctx];
+      [_ctx removeObjectForKey:WEPageView_HEAD];
+      
+      [_ctx deleteLastElementIDComponent];
+    }
+    else if ([key isEqualToString:@"b"]) {
+      /* body action */
+      
+      [_ctx consumeElementID];
+      [_ctx appendElementIDComponent:key];
+
+      [_ctx setObject:self->selection forKey:WEPageView_BODY];
+      
+      result = [self->template invokeActionForRequest:_request inContext:_ctx];
+      
+      [_ctx removeObjectForKey:WEPageView_BODY];
+      
+      [_ctx deleteLastElementIDComponent];
+    }
+    else {
+      [[_ctx application]
+             debugWithFormat:@"unknown page container key '%@'", key];
+    }
+    
+    [self restoreNestedState:nestedState inContext:_ctx];
+  }
+  return result;
+}
+
+
+
+- (void)_appendNav:(NSString *)_nav isBlind:(BOOL)_isBlind
+  toResponse:(WOResponse *)_response inContext:(WOContext *)_ctx
+  info:(WEPageItemInfo *)_info
+{
+  NSString *img;
+  NSString *label;
+  BOOL     doForm;
+  
+  doForm = [_ctx isInForm];
+  img = [WEPageView_ stringByAppendingString:_nav];
+  img = [img stringByAppendingString:(_isBlind) ? @"_blind" : @""];
+  img = [_ctx objectForKey:img];
+  img = WEUriOfResource(img,_ctx);
+  
+  label  = WEPageLabelForKey(_nav, _ctx);
+
+  // append as submit button
+  if (doForm && !_isBlind && img && _info) {
+    NSString *uri;
+
+    uri = [[_info->uri componentsSeparatedByString:@"/"] lastObject];
+    
+    [_ctx appendElementIDComponent:_nav];
+    [_response appendContentString:@"<input type=\"image\" border=\"0\""];
+    [_response appendContentString:@" name=\""];
+    [_response appendContentString:uri];
+    [_response appendContentString:@"\" src=\""];
+    [_response appendContentString:img];
+    [_response appendContentString:@"\" alt=\""];
+    [_response appendContentString:label];
+    [_response appendContentString:@"\" />"];
+    [_ctx deleteLastElementIDComponent];
+    return;
+  }
+
+  /* open anker */
+  if (!_isBlind && _info) {
+    [_ctx appendElementIDComponent:_nav];
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:_info->uri];
+    [_response appendContentString:@"\">"];
+  }
+  if (!img) {
+    [_response appendContentCharacter:'['];
+    [_response appendContentString:label];
+    [_response appendContentCharacter:']'];
+  }
+  else {
+    [_response appendContentString:@"<img border=\"0\" src=\""];
+    [_response appendContentString:img];
+    [_response appendContentString:@"\" alt=\""];
+    [_response appendContentString:label];
+    [_response appendContentString:@"\" />"];
+  }
+  /* close anker */
+  if (!_isBlind && _info) {
+    [_response appendContentString:@"</a>"];
+    [_ctx deleteLastElementIDComponent];
+  }
+}
+
+- (void)appendNavToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  isLeft:(BOOL)_isLeft
+  activeKey:(WEPageItemInfo *)_activeKey
+  keys:(NSArray *)_keys
+{
+  WEPageItemInfo *info;
+  int idx, cnt;
+
+  idx = [_keys indexOfObject:_activeKey];
+  cnt = [_keys count];
+
+  if (idx > cnt) {
+    NSLog(@"Warning! WEPageView: idx is out of range!");
+    return;
+  }
+
+  if (_isLeft) {
+    info = (cnt > 0) ? [_keys objectAtIndex:0] : nil;
+    [self _appendNav:@"first"     isBlind:(idx < 1) ? YES : NO
+          toResponse:_response  inContext:_ctx info:info];
+
+    info = (cnt > 0 && idx > 0) ? [_keys objectAtIndex:idx-1] : nil;
+    [self _appendNav:@"previous"   isBlind:(idx < 1) ? YES : NO
+          toResponse:_response  inContext:_ctx info:info];
+  }
+  else {
+    info = (cnt > idx+1) ? [_keys objectAtIndex:idx+1] : nil;
+    [self _appendNav:@"next"     isBlind:(cnt <= idx+1) ? YES : NO
+          toResponse:_response inContext:_ctx info:info];
+
+    info = (cnt > 0) ? [_keys objectAtIndex:cnt-1] : nil;
+    [self _appendNav:@"last"     isBlind:(cnt <= idx+1) ? YES : NO
+          toResponse:_response inContext:_ctx info:info];
+  }
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent    *cmp;
+  BOOL           indentContent;
+  BOOL           doForm;
+  NSString       *bgcolor;
+  id             nestedState;
+  NSString       *activeKey;
+  WEPageItemInfo *activeInfo = nil;
+  NSArray        *keys;
+  unsigned       i, count;
+  
+  [self updateConfigInContext:_ctx];
+  
+  doForm        = NO;  /* generate form controls ? */
+  indentContent = YES; /* put additional padding table into content */
+  cmp           = [_ctx component];
+  
+  /* check for browser */
+
+  {
+    WEClientCapabilities *ccaps;
+
+    ccaps = [[_ctx request] clientCapabilities];
+    if ([ccaps isFastTableBrowser] && ![ccaps isTextModeBrowser])
+      indentContent = YES;
+  }
+  
+  /* save state */
+  
+  nestedState = [self saveNestedStateInContext:_ctx];
+    
+  /* collect & process keys (= available tabs) */
+
+  [_ctx appendElementIDComponent:@"h"];
+
+  activeKey = [self->selection stringValueInComponent:cmp];
+  keys      = [self collectKeysInContext:_ctx];
+  
+  if (![[keys valueForKey:@"key"] containsObject:activeKey])
+    /* selection is not available in keys */
+    activeKey = nil;
+  
+  if ((activeKey == nil) && ([keys count] > 0)) {
+    /* no or invalid selection, use first key */
+    activeKey = [[keys objectAtIndex:0] key];
+    if ([self->selection isValueSettable])
+      [self->selection setValue:activeKey inComponent:[_ctx component]];
+  }
+  
+  for (i = 0, count = [keys count]; i < count; i++) {
+    WEPageItemInfo *info;
+
+    info     = [keys objectAtIndex:i];
+
+    if ([info->key isEqualToString:activeKey]) {
+      activeInfo = info;
+      break;
+    }
+  }
+
+  /* start appending */
+
+  [_response appendContentString:
+               @"<table border=\"0\" width=\"100%\""
+               @" cellpadding=\"0\" cellspacing=\"0\">"];
+
+  /* generate header row */
+
+  bgcolor = [self->titleColor stringValueInComponent:cmp];
+
+  [_response appendContentString:@"<tr>"];
+
+  /* left navigation */
+  WEAppendTD(_response, @"left", nil, bgcolor);
+  [self appendNavToResponse:_response
+        inContext:_ctx
+        isLeft:YES
+        activeKey:activeInfo
+        keys:keys];
+  [_response appendContentString:@"</td>"];
+
+
+  /* title */
+  WEAppendTD(_response, @"center", nil, bgcolor);
+  {
+    unsigned char buf[256];
+    NSString *tC, *tF, *tS; // text font attrtibutes
+    BOOL     hasFont;
+    
+    cmp = [_ctx component];
+  
+    tC  = [self->fontColor stringValueInComponent:cmp];
+    tF  = [self->fontFace  stringValueInComponent:cmp];
+    tS  = [self->fontSize  stringValueInComponent:cmp];
+
+    hasFont = (tC || tF || tS) ? YES : NO;
+
+    if (hasFont)
+      WEAppendFont(_response, tC, tF, tS);
+  
+    for (i = 0, count = [keys count]; i < count; i++) {
+      WEPageItemInfo *info;
+
+      info     = [keys objectAtIndex:i];
+
+      if ([info->key isEqualToString:activeKey]) {
+        [_response appendContentString:@"<b>"];
+        [_response appendContentString:info->title];
+        [_response appendContentString:@"</b>"];
+        break;
+      }
+    }
+    sprintf(buf, " <small>(%d/%d)</small>", (i + 1), count);
+    [_response appendContentCString:buf];
+    
+    if (hasFont)
+      [_response appendContentString:@"</font>"];
+  }
+  [_response appendContentString:@"</td>"];
+
+  /* right navigation */
+
+  WEAppendTD(_response, @"right", nil, bgcolor);
+  [self appendNavToResponse:_response
+        inContext:_ctx
+        isLeft:NO
+        activeKey:activeInfo
+        keys:keys];
+  [_response appendContentString:@"</td>"];
+  
+  [_response appendContentString:@"</tr>"];
+  [_ctx deleteLastElementIDComponent]; // delete "h"
+  [_ctx removeObjectForKey:WEPageView_HEAD];
+  
+  /* body row */
+
+  bgcolor = [self->contentColor stringValueInComponent:cmp];
+  
+  {
+    [_response appendContentString:@"<tr><td colspan=\"3\""];
+    if (bgcolor) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentHTMLAttributeValue:bgcolor];
+      [_response appendContentString:@"\""];
+    }
+    [_response appendContentString:@">"];
+    
+    if (indentContent) {
+      /* start padding table */
+      [_response appendContentString:
+                   @"<table border=\"0\" width=\"100%\""
+                   @" cellpadding=\"10\" cellspacing=\"0\">"];
+      [_response appendContentString:@"<tr><td>"];
+    }
+    
+    [_ctx appendElementIDComponent:@"b"];
+
+    /* generate currently active page */
+    
+    {
+      [_ctx setObject:activeKey forKey:WEPageView_BODY];
+      [self->template appendToResponse:_response inContext:_ctx];
+      [_ctx removeObjectForKey:WEPageView_BODY];
+    }
+    
+    [_ctx deleteLastElementIDComponent];
+    
+    if (indentContent)
+      /* close padding table */
+      [_response appendContentString:@"</td></tr></table>"];
+    
+    [_response appendContentString:@"</td></tr>"];
+  }  
+  [_response appendContentString:@"</table>"];
+  
+  [_ctx removeObjectForKey:WEPageView_ACTIVEKEY];
+  [_ctx removeObjectForKey:WEPageView_KEYS];
+  [self restoreNestedState:nestedState inContext:_ctx];
+
+  [self removeConfigInContext:_ctx];
+}
+
+@end /* WEPageView */
+
+@implementation WEPageItem
+
++ (int)version {
+  return [super version] + 0;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->key      = WOExtGetProperty(_config, @"key");
+    self->title    = WOExtGetProperty(_config, @"title");
+    self->action   = WOExtGetProperty(_config, @"action");
+
+    self->template = RETAIN(_subs);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->action   release];
+  [self->title    release];
+  [self->key      release];
+  [self->template release];
+  [super dealloc];
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  WOAssociation *tmp;
+  
+  if ((tmp = [_ctx objectForKey:WEPageView_BODY])) {
+    NSString *activeTabKey;
+    NSString *myTabKey;
+    
+    activeTabKey = [tmp stringValueInComponent:[_ctx component]];
+    myTabKey     = [self->key stringValueInComponent:[_ctx component]];
+
+    if ([activeTabKey isEqualToString:myTabKey]) {
+      [_ctx appendElementIDComponent:activeTabKey];
+
+#if DEBUG_TAKEVALUES
+      [[_ctx component] debugWithFormat:
+                          @"WEPageItem: body takes values, eid='%@'",
+                          [_ctx elementID]];
+#endif
+      
+      [self->template takeValuesFromRequest:_request inContext:_ctx];
+      [_ctx deleteLastElementIDComponent];
+    }
+#if DEBUG_TAKEVALUES
+    else {
+      [[_ctx component] debugWithFormat:
+                          @"WEPageItem: body takes no values, eid='%@'",
+                          [_ctx elementID]];
+    }
+#endif
+  }
+  else {
+    NSString *k;
+    NSString *eid;
+
+    k = [self->key stringValueInComponent:[_ctx component]];
+    
+    eid = [[_ctx elementID] stringByAppendingString:@"."];
+    eid = [eid stringByAppendingString:k];
+    
+    if (k && [_request formValueForKey:[eid stringByAppendingString:@".x"]]) {
+      [_ctx addActiveFormElement:self];
+      [_ctx setRequestSenderID:eid];
+    }
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  NSString      *tabkey;
+  id            result;
+  WOAssociation *tmp;
+
+  tabkey = [_ctx currentElementID];
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:tabkey];
+  
+  if ((tmp = [_ctx objectForKey:WEPageView_HEAD])) {
+    /* click on tab icon */
+    if ([tmp isValueSettable])
+      [tmp setValue:tabkey inComponent:[_ctx component]];
+    
+    result = [self->action valueInComponent:[_ctx component]];
+  }
+  else if ((tmp = [_ctx objectForKey:WEPageView_BODY])) {
+    /* clicked somewhere in the body */
+    if ([tmp isValueSettable])
+      [tmp setValue:tabkey inComponent:[_ctx component]];
+    
+    result = [self->template invokeActionForRequest:_rq inContext:_ctx];
+  }
+  else {
+    [[_ctx component] debugWithFormat:@"WEPageItem: invalid invoke state"];
+    result = [self->template invokeActionForRequest:_rq inContext:_ctx];
+  }
+  
+  [_ctx deleteLastElementIDComponent];
+  return result;
+}
+
+- (void)appendHead:(NSString *)tmp 
+  toResponse:(WOResponse *)_response inContext:(WOContext *)_ctx 
+{
+  NSMutableArray *keys;
+  WEPageItemInfo *info;
+  WOComponent    *cmp;
+  NSString *k;
+  
+  if (![tmp isEqual:WEPageView_COLLECT])
+    return;
+  
+  /* collect keys */
+
+  cmp  = [_ctx component];
+  keys = [_ctx objectForKey:WEPageView_KEYS];
+  if (keys == nil) {
+    keys = [NSMutableArray arrayWithCapacity:8];
+    [_ctx setObject:keys forKey:WEPageView_KEYS];
+  }
+  
+  if ((k = [self->key stringValueInComponent:[_ctx component]]) == nil) {
+    /* auto-assign a key */
+    unsigned char kb[16];
+    sprintf(kb, "%d", [keys count]);
+    k = [NSString stringWithCString:kb];
+  }
+  [_ctx appendElementIDComponent:k];
+      
+  info = [[WEPageItemInfo alloc] init];
+  info->key      = [k copy];
+  info->title    = [[self->title stringValueInComponent:cmp] copy];
+  info->uri      = [[_ctx componentActionURL] copy];
+      
+  [keys addObject:info];
+  [info release];
+  
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (void)appendBody:(NSString *)tmp 
+  toResponse:(WOResponse *)_response inContext:(WOContext *)_ctx 
+{
+  NSString *k;
+  
+  k = [self->key stringValueInComponent:[_ctx component]];
+  if (![tmp isEqualToString:k])
+    return;
+  
+  /* content is active or used as layer*/
+  [_ctx appendElementIDComponent:k];
+#if DEBUG
+  [self debugWithFormat:@"PAGE: %@", k];
+#endif
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *tmp;
+  
+  if ((tmp = [_ctx objectForKey:WEPageView_HEAD]))
+    [self appendHead:tmp toResponse:_response inContext:_ctx];
+  else if ((tmp = [_ctx objectForKey:WEPageView_BODY]))
+    [self appendBody:tmp toResponse:_response inContext:_ctx];
+  else
+    [_response appendContentString:@"[invalid pageview state]"];
+}
+
+@end /* WEPageItem */
+
+@implementation WEPageItemInfo
+
+- (void)dealloc {
+  [self->uri   release];
+  [self->title release];
+  [self->key   release];
+  [super dealloc];
+}
+
+- (NSString *)key {
+  return self->key;
+}
+- (NSString *)title {
+  return self->title;
+}
+- (NSString *)uri {
+  return self->uri;
+}
+
+@end /* WEPageItemInfo */
diff --git a/skyrix-sope/WEExtensions/WEQualifierConditional.m b/skyrix-sope/WEExtensions/WEQualifierConditional.m
new file mode 100644 (file)
index 0000000..1009184
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+  Copyright (C) 2000-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$
+
+/*
+  WEQualifierConditional
+
+    IfPerson: WEQualifierConditional {
+      condition = "isPerson=YES AND isCategory like '*customer*'";
+      object    = currentPerson;
+      negate    = NO;
+      bindings  = nil; // optional qualifier bindings
+      requiresAllVariables = YES; // whether all bindings must be resolved
+    }
+  
+  If no object is given, the qualifier is evaluated against the component.
+*/
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@class WOAssociation;
+
+@interface WEQualifierConditional : WODynamicElement
+{
+@protected
+  WOAssociation *condition;
+  WOAssociation *object;
+  WOAssociation *negate;
+  WOElement     *template;
+  WOAssociation *bindings;
+  WOAssociation *requiresAllVariables;
+}
+@end
+
+#include "common.h"
+
+// TODO: add support for qualifier arguments?
+
+@implementation WEQualifierConditional
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->condition = WOExtGetProperty(_config, @"condition");
+    self->object    = WOExtGetProperty(_config, @"object");
+    self->negate    = WOExtGetProperty(_config, @"negate");
+    self->bindings  = WOExtGetProperty(_config, @"bindings");
+    self->requiresAllVariables = 
+      WOExtGetProperty(_config, @"requiresAllVariables");
+    self->template  = [_t retain];
+    
+    if (self->condition == nil) {
+      [self logWithFormat:
+              @"WARNING: missing 'condition' association in element: '%@'",
+              _name];
+    }
+    else if ([self->condition isValueConstant]) {
+      /* optimization, replace constant associations with a parsed qualifier */
+      NSString *value;
+      
+      if ((value = [self->condition stringValueInComponent:nil])) {
+        EOQualifier   *q;
+        
+        q = [EOQualifier qualifierWithQualifierFormat:value];
+        if (q) {
+          WOAssociation *tmp;
+          
+          tmp = [[WOAssociation associationWithValue:q] retain];
+          [self->condition release];
+          self->condition = tmp;
+        }
+      }
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template  release];
+  [self->condition release];
+  [self->object    release];
+  [self->negate    release];
+  [self->bindings  release];
+  [self->requiresAllVariables release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOElement *)template {
+  return self->template;
+}
+
+/* state */
+
+- (BOOL)_doShowInContext:(WOContext *)_ctx {
+  WOComponent  *cmp;
+  NSDictionary *vars;
+  NSArray      *args;
+  id   qualifier, context;
+  BOOL doShow, doNegate, needAllVars;
+  
+  cmp         = [_ctx component];
+  doNegate    = self->negate ? [self->negate boolValueInComponent:cmp] : NO;
+  doShow      = NO;
+  vars        = [self->bindings valueInComponent:cmp];
+  args        = nil;
+  needAllVars = self->requiresAllVariables 
+    ? [self->requiresAllVariables boolValueInComponent:cmp]
+    : NO;
+  
+  /* determine qualifier */
+  
+  if ((qualifier = [self->condition valueInComponent:cmp])) {
+    if ([qualifier isKindOfClass:[NSString class]]) {
+      qualifier = [EOQualifier qualifierWithQualifierFormat:qualifier
+                               arguments:args];
+    }
+  }
+  
+  /* apply qualifier bindings */
+  
+  if (vars != nil && qualifier != nil) {
+    qualifier = [qualifier qualifierWithBindings:vars 
+                           requiresAllVariables:needAllVars];
+  }
+  
+  /* find context object */
+  
+  context = self->object
+    ? [self->object valueInComponent:cmp]
+    : cmp;
+  
+  /* evaluate */
+  
+  if (![qualifier respondsToSelector:@selector(evaluateWithObject:)]) {
+    [self logWithFormat:
+            @"ERROR: got a qualifier which does not respond to "
+            @"evaluateWithObject: %@", qualifier];
+    doShow = NO;
+  }
+  else
+    doShow = [qualifier evaluateWithObject:context];
+  
+  return doNegate ? !doShow : doShow;
+}
+
+/* processing requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  if (![self _doShowInContext:_ctx])
+    return;
+
+  [_ctx appendElementIDComponent:@"1"];
+  [self->template takeValuesFromRequest:_rq inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  NSString *state;
+  id result;
+
+  state = [[_ctx currentElementID] stringValue];
+  
+  if (!state) 
+    return nil;
+  [_ctx consumeElementID]; // consume state-id (on or off)
+  
+  if (![state isEqualToString:@"1"])
+    return nil;
+  
+  [_ctx appendElementIDComponent:state];
+  result = [self->template invokeActionForRequest:_rq inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  return result;
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![self _doShowInContext:_ctx])
+    return;
+
+  [_ctx appendElementIDComponent:@"1"];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:64];
+  if (self->condition) [str appendFormat:@" condition=%@", self->condition];
+  if (self->object)    [str appendFormat:@" object=%@",    self->object];
+  if (self->negate)    [str appendFormat:@" negate=%@",    self->negate];
+  if (self->template)  [str appendFormat:@" template=%@",  self->template];
+  return str;
+}
+
+@end /* WEQualifierConditional */
diff --git a/skyrix-sope/WEExtensions/WERedirect.m b/skyrix-sope/WEExtensions/WERedirect.m
new file mode 100644 (file)
index 0000000..cb608aa
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+/* 
+   Q: Whats the difference to WORedirect?
+   A: It is a dynamic element while WORedirect is a component.
+
+   Note: you can also use the WOComponent -redirectToLocation: method.
+*/
+
+@interface WERedirect : WODynamicElement
+{
+  WOAssociation *setURL;
+}
+@end
+
+#include "common.h"
+
+@implementation WERedirect
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->setURL = WOExtGetProperty(_config, @"setURL");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->setURL release];
+  [super dealloc];
+}
+
+/* generating the response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [_response setStatus:302];
+  [_response setHeader:[self->setURL stringValueInComponent:[_ctx component]]
+             forKey:@"location"];
+}
+
+@end /* WERedirect */
diff --git a/skyrix-sope/WEExtensions/WERichString.m b/skyrix-sope/WEExtensions/WERichString.m
new file mode 100644 (file)
index 0000000..e151a0a
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WERichString : WODynamicElement
+{
+  WOAssociation *isBold;
+  WOAssociation *isItalic;
+  WOAssociation *isUnderlined;
+  WOAssociation *isSmall;
+  WOAssociation *color;
+  WOAssociation *face;
+  WOAssociation *size;
+  WOAssociation *insertBR;
+
+  WOAssociation *condition;
+  WOAssociation *negate;
+
+  WOAssociation *formatter;
+  
+  WOAssociation *value;
+  
+  WOElement     *template;
+}
+
+@end
+
+#include <NGObjWeb/NGObjWeb.h>
+#include "common.h"
+
+@implementation WERichString
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->value        = OWGetProperty(_config, @"value");
+    
+    self->isBold       = OWGetProperty(_config, @"isBold");
+    self->isItalic     = OWGetProperty(_config, @"isItalic");
+    self->isUnderlined = OWGetProperty(_config, @"isUnderlined");
+    self->isSmall      = OWGetProperty(_config, @"isSmall");
+    self->color        = OWGetProperty(_config, @"color");
+    self->face         = OWGetProperty(_config, @"face");
+    self->size         = OWGetProperty(_config, @"size");
+    self->insertBR     = OWGetProperty(_config, @"insertBR");
+
+    self->condition    = OWGetProperty(_config, @"condition");
+    self->negate       = OWGetProperty(_config, @"negate");
+
+    self->formatter    = OWGetProperty(_config, @"formatter");
+
+    ASSIGN(self->template, _t);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->value);
+  RELEASE(self->isBold);
+  RELEASE(self->isItalic);
+  RELEASE(self->isUnderlined);
+  RELEASE(self->isSmall);
+  RELEASE(self->color);
+  RELEASE(self->face);
+  RELEASE(self->size);
+  RELEASE(self->insertBR);
+  RELEASE(self->formatter);
+
+  RELEASE(self->condition);
+  RELEASE(self->negate);
+
+  RELEASE(self->template);
+  
+  [super dealloc];
+}
+
+static inline BOOL _doShow(WERichString *self, WOContext *_ctx) {
+  BOOL doShow   = YES;
+  BOOL doNegate = NO;
+
+  if (self->condition != nil) {
+    doShow   = [self->condition boolValueInComponent:[_ctx component]];
+    doNegate = [self->negate boolValueInComponent:[_ctx component]];
+  }
+  
+  return (doNegate) ? !doShow : doShow;
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if (_doShow(self, _ctx)) {
+    [_ctx appendElementIDComponent:@"1"];
+    [self->template takeValuesFromRequest:_request inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  NSString *state;
+
+  state = [[_ctx currentElementID] stringValue];
+  
+  if (state) {
+    [_ctx consumeElementID]; // consume state-id (on or off)
+
+    if ([state isEqualToString:@"1"]) {
+      id result;
+      
+      [_ctx appendElementIDComponent:state];
+      result = [self->template invokeActionForRequest:_request inContext:_ctx];
+      [_ctx deleteLastElementIDComponent];
+
+      return result;
+    }
+  }
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *comp      = nil;
+  BOOL     doBold        = NO;
+  BOOL     doItalic      = NO;
+  BOOL     doUnderlined  = NO;
+  BOOL     doSmall       = NO;
+  NSString *color_       = nil;
+  NSString *face_        = nil;
+  NSString *size_        = nil;
+  NSFormatter *fmt       = nil;
+  id       v             = nil;
+
+
+  if (!_doShow(self, _ctx)) return;
+  
+  comp = [_ctx component];
+  
+  doBold       = [self->isBold       boolValueInComponent:comp];
+  doItalic     = [self->isItalic     boolValueInComponent:comp];
+  doUnderlined = [self->isUnderlined boolValueInComponent:comp];
+  doSmall      = [self->isSmall      boolValueInComponent:comp];
+  face_        = [self->face       stringValueInComponent:comp];
+  color_       = [self->color      stringValueInComponent:comp];
+  size_        = [self->size       stringValueInComponent:comp];
+  v            = [self->value            valueInComponent:comp];
+  fmt          = [self->formatter        valueInComponent:comp];
+
+  if (doSmall)
+    [_response appendContentString:@"<small>"];
+  if (doBold)
+    [_response appendContentString:@"<b>"];
+  if (doItalic)
+    [_response appendContentString:@"<i>"];
+  if (doUnderlined)
+    [_response appendContentString:@"<u>"];
+
+  [_response appendContentString:@"<font"];
+  if (color_ != nil) {
+    [_response appendContentString:@" color='"];
+    [_response appendContentHTMLString:color_];
+    [_response appendContentCharacter:'\''];
+  }
+  if (face_ != nil) {
+    [_response appendContentString:@" face='"];
+    [_response appendContentHTMLString:face_];
+    [_response appendContentCharacter:'\''];
+  }
+  if (size_ != nil) {
+    [_response appendContentString:@" size='"];
+    [_response appendContentHTMLString:size_];
+    [_response appendContentCharacter:'\''];
+  }
+  [_response appendContentCharacter:'>'];
+
+  [_ctx appendElementIDComponent:@"1"];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+
+  v = (fmt)
+    ? [fmt stringForObjectValue:v]
+    : [v stringValue];
+
+  if (v && [self->insertBR boolValueInComponent:comp]) {
+    NSArray *lines;
+    unsigned i, count;
+      
+    lines = [v componentsSeparatedByString:@"\n"];
+    count = [lines count];
+    for (i = 0; i < count; i++) {
+      NSString *line = [lines objectAtIndex:i];
+
+      if (i != 0) [_response appendContentString:@"<br />"];
+
+      [_response appendContentHTMLString:line];
+    }
+  }
+  else
+    [_response appendContentHTMLString:v];
+
+  [_response appendContentString:@"</font>"];
+  if (doUnderlined)
+    [_response appendContentString:@"</u>"];
+  if (doItalic)
+    [_response appendContentString:@"</i>"];
+  if (doBold)
+    [_response appendContentString:@"</b>"];
+  if (doSmall)
+    [_response appendContentString:@"</small>"];
+
+}
+@end
diff --git a/skyrix-sope/WEExtensions/WESwitch.m b/skyrix-sope/WEExtensions/WESwitch.m
new file mode 100644 (file)
index 0000000..10f573d
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+  Copyright (C) 2000-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$
+
+/*
+  WESwitch      { selection | selections };
+  WECase        { key | keys };
+  WEDefaultCase {};
+  
+  Warning: The DefaultCase must appear at the last position!!!
+*/
+
+/*  
+  example:
+  
+  // wod:
+  Switch:      WESwitch { selection = selection;           };
+  FirstCase:   WECase   { key       = "first";             };
+  SecondCase:  WECase   { keys      = ("second", "third"); };
+  DefaultCase: WEDefaultCase {};
+
+  // html:
+  <#Switch>
+    <#FirstCase>content of first case</#FirstCase>
+    <#SecondCase>content of second case</#SecondCase>
+    <#DefaultCase>content of default case</#SecondCase>
+  </#Switch>
+  
+*/
+#include <NGObjWeb/WODynamicElement.h>
+
+@class WOAssociation;
+
+@interface WESwitch : WODynamicElement
+{
+@protected
+  WOAssociation *selection;     // string -> single switch
+  WOAssociation *selections;    // array  -> multi  switch
+  WOElement     *template;
+}
+@end
+
+@interface WECase : WODynamicElement
+{
+  WOAssociation *key;          // string -> unique identifier
+  WOAssociation *keys;         // array of unique identifiers
+
+  WOAssociation *defaultCase;  // emulates a WEDefaultCase DEPRECATED!!!
+  
+  WOElement     *template;
+}
+@end
+
+@interface WEDefaultCase : WODynamicElement
+{
+  WOElement *template;
+}
+@end
+
+#include "common.h"
+
+#if DEBUG
+static NSString *WESwitch_DefaultCaseFound = @"WESwitch_DefaultCaseFound";
+#endif
+static NSString *WESwitch_CaseDidMatch     = @"WESwitch_CaseDidMatch";
+static NSString *WESwitchSelection         = @"WESwitchSelection";
+static NSString *WESwitchSelections        = @"WESwitchSelections";
+static NSString *WESwitchDict              = @"WESwitchDict";
+
+@implementation WESwitch
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->selection  = WOExtGetProperty(_config, @"selection");
+    self->selections = WOExtGetProperty(_config, @"selections");
+    
+    self->template   = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template   release];
+  [self->selection  release];
+  [self->selections release];
+  [super dealloc];
+}
+
+/* processing requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *cmp   = nil;
+  NSArray     *array = nil;
+  NSString    *k     = nil;
+  unsigned    i, cnt;
+  BOOL        doLazy = YES;
+
+  
+  cmp   = [_ctx component];
+  array = [self->selections valueInComponent:cmp];
+  k     = [self->selection  valueInComponent:cmp];
+  cnt   = [array count];
+
+  if (_req == nil) {
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+  }
+  else if (k) {
+    [_ctx setObject:k forKey:WESwitchSelection];
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+    [_ctx removeObjectForKey:WESwitchSelection];
+  }
+  else if (doLazy) {
+    for (i = 0; i < cnt; i++) {
+      [_ctx setObject:[array objectAtIndex:i] forKey:WESwitchSelection];
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+    }
+    if (cnt == 0) {
+      [_ctx setObject:array forKey:WESwitchSelections];
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+      [_ctx removeObjectForKey:WESwitchSelections];
+    }
+    [_ctx removeObjectForKey:WESwitchSelection];
+  }
+  else if (cnt > 0) {
+    NSLog(@"Warning(%s):This case is not implemented!!!", __PRETTY_FUNCTION__);
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+  }
+  
+#if DEBUG
+  else {
+    [cmp logWithFormat:
+         @"Warning! WESwitch: Neither 'selection' nor 'selections' set!!!"];
+  }
+#endif
+
+  [_ctx removeObjectForKey:WESwitch_CaseDidMatch];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_request inContext:_ctx];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *cmp   = nil;
+  NSArray     *array = nil;
+  NSString    *k     = nil;
+  unsigned    i, cnt;
+  BOOL        doLazy = YES;
+
+  
+  cmp   = [_ctx component];
+  array = [self->selections valueInComponent:cmp];
+  k     = [self->selection  valueInComponent:cmp];
+  cnt   = [array count];
+
+  if (_response == nil) {
+    [self->template appendToResponse:_response inContext:_ctx];
+  }
+  else if (k) {
+    [_ctx setObject:k forKey:WESwitchSelection];
+    [self->template appendToResponse:_response inContext:_ctx];
+    [_ctx removeObjectForKey:WESwitchSelection];
+  }
+  else if (doLazy) {
+    for (i=0; i<cnt; i++) {
+      [_ctx setObject:[array objectAtIndex:i] forKey:WESwitchSelection];
+      [self->template appendToResponse:_response inContext:_ctx];
+    }
+    if (cnt == 0) {
+      [_ctx setObject:array forKey:WESwitchSelections];
+      [self->template appendToResponse:_response inContext:_ctx];
+      [_ctx removeObjectForKey:WESwitchSelections];
+    } 
+    [_ctx removeObjectForKey:WESwitchSelection];
+  }
+  else if (cnt > 0) {
+    NSMutableDictionary *dict = nil;
+    
+    // get subcontent of WECases
+    [_ctx setObject:array forKey:WESwitchSelections];
+    [self->template appendToResponse:_response inContext:_ctx];
+    
+    dict = [_ctx objectForKey:WESwitchDict];
+
+    // append subcontent
+    if (dict) {
+      for (i=0; i<cnt; i++) {
+        NSString *k = [array objectAtIndex:i];
+        NSData   *c = [dict objectForKey:k];   // subcontent of WECase
+
+        if (c)
+          [_response appendContentData:c];
+      }
+    }
+    
+    [_ctx removeObjectForKey:WESwitchDict];
+    [_ctx removeObjectForKey:WESwitchSelections];
+  }
+  
+#if DEBUG
+  else {
+    [cmp logWithFormat:
+         @"Warning! WESwitch: Neither 'selection' nor 'selections' set!!!"];
+  }
+#endif
+
+  [_ctx removeObjectForKey:WESwitch_CaseDidMatch];
+}
+
+@end /* WESwitch */
+
+@implementation WECase
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->key  = WOExtGetProperty(_config, @"key");
+    self->keys = WOExtGetProperty(_config, @"keys");
+
+    // DEPRECATED!!!
+    self->defaultCase  = WOExtGetProperty(_config, @"default");
+    
+    self->template = [_t retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template    release];
+  [self->key         release];
+  [self->keys        release];
+  [self->defaultCase release];
+  [super dealloc];
+}
+
+/* processing requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSArray     *selections = nil;
+  NSString    *selection  = nil;
+  NSString    *k          = nil;
+  NSArray     *ks         = nil;
+  
+  k   = [self->key  stringValueInComponent:[_ctx component]];
+  ks  = [self->keys valueInComponent:[_ctx component]];
+  
+  selections = [_ctx objectForKey:WESwitchSelections];
+  selection  = [_ctx objectForKey:WESwitchSelection];
+
+  if ([self->defaultCase boolValueInComponent:[_ctx component]]) {
+    if ([_ctx objectForKey:WESwitch_CaseDidMatch] == nil)
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+    return;
+  }
+
+  if ((k == nil) && (ks == nil)) {
+#if DEBUG
+    [[_ctx component] logWithFormat:
+                      @"Warning! WECase: Neither 'key' nor 'keys' set!!!"];
+#endif
+    return;
+  }
+  if ((k != nil) && (ks != nil)) {
+#if DEBUG
+    [[_ctx component] logWithFormat:
+                      @"Warning! WECase: Both, 'key' and 'keys' are set!!!"];
+#endif
+    return;
+  }
+  
+  if (_req == nil) {
+    [self->template takeValuesFromRequest:nil inContext:_ctx];
+  }
+  if (selection) {
+    if (k && [k isEqualToString:selection]) {
+       [self->template takeValuesFromRequest:_req inContext:_ctx];
+       [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch];
+    }
+    else if (ks && [ks containsObject:selection]) {
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+      [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch];
+    }
+  }
+  else if (selections && [selections count] > 0) {
+    NSLog(@"Warning(%s): This case is not implemented!", __PRETTY_FUNCTION__);
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_req inContext:_ctx];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSArray     *selections = nil;
+  NSString    *selection  = nil;
+  NSString    *k          = nil;
+  NSArray     *ks         = nil;
+
+
+  k   = [self->key  stringValueInComponent:[_ctx component]];
+  ks  = [self->keys valueInComponent:[_ctx component]];
+
+  selections = [_ctx objectForKey:WESwitchSelections];
+  selection  = [_ctx objectForKey:WESwitchSelection];
+
+  if ([self->defaultCase boolValueInComponent:[_ctx component]]) {
+    if ([_ctx objectForKey:WESwitch_CaseDidMatch] == nil)
+      [self->template appendToResponse:_response inContext:_ctx];
+    return;
+  }
+
+  if ((k == nil) && (ks == nil)) {
+#if DEBUG
+    [[_ctx component] logWithFormat:
+                      @"Warning! WECase: Neither 'key' nor 'keys' set!!!"];
+#endif
+    return;
+  }
+  if ((k != nil) && (ks != nil)) {
+#if DEBUG
+    [[_ctx component] logWithFormat:
+                      @"Warning! WECase: Both, 'key' and 'keys' are set!!!"];
+#endif
+    return;
+  }
+  
+  if (_response == nil) {
+    [self->template appendToResponse:nil inContext:_ctx];
+  }
+  if (selection) {
+    if (k && [k isEqualToString:selection]) {
+       [self->template appendToResponse:_response inContext:_ctx];
+       [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch];
+    }
+    else if (ks && [ks containsObject:selection]) {
+      [self->template appendToResponse:_response inContext:_ctx];
+      [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch];
+    }
+  }
+  else if (selections && [selections count] > 0) {
+    if ([selections containsObject:k]) {
+      static NSData *emptyData = nil;
+      NSMutableDictionary *dict       = nil;
+      NSData              *oldContent = nil;
+
+      if (emptyData == nil)
+        emptyData = [[NSData alloc] init];
+
+      // get subcontent dictionary
+      dict = [_ctx objectForKey:WESwitchDict];
+      if (dict == nil)
+        dict = [NSMutableDictionary dictionaryWithCapacity:[selections count]];
+
+      // set new content
+      oldContent = [_response content];
+      RETAIN(oldContent);
+      [_response setContent:emptyData];
+      
+      // append template to new content
+      [self->template appendToResponse:_response inContext:_ctx];
+
+      // save new content in dict
+      if ([_response content])
+        [dict setObject:[_response content] forKey:k];
+      [_ctx setObject:dict forKey:WESwitchDict];
+
+      // restore old content
+      [_response setContent:oldContent];
+      [oldContent release]; oldContent = nil;
+
+      // TODO: use NSNumber here?
+      [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch];
+    }
+  }
+}
+
+@end /* WECase */
+
+@implementation WEDefaultCase
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->template = [_t retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template release];
+  [super dealloc];
+}
+
+/* processing requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  if (([_ctx objectForKey:WESwitch_CaseDidMatch] == nil))
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_req inContext:_ctx];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (([_ctx objectForKey:WESwitch_CaseDidMatch] == nil))
+    [self->template appendToResponse:_response inContext:_ctx];
+  
+#if DEBUG
+  [_ctx setObject:@"Yes" forKey:WESwitch_DefaultCaseFound];
+#endif
+}
+
+@end /* WEDefaultCase */
diff --git a/skyrix-sope/WEExtensions/WETabItem.m b/skyrix-sope/WEExtensions/WETabItem.m
new file mode 100644 (file)
index 0000000..06a899d
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WETabView.h"
+#include "common.h"
+
+#if DEBUG
+#  define DEBUG_JS 1
+#endif
+
+/* context keys */
+extern NSString *WETabView_HEAD;
+extern NSString *WETabView_BODY;
+extern NSString *WETabView_KEYS;
+extern NSString *WETabView_SCRIPT;
+extern NSString *WETabView_ACTIVEKEY;
+extern NSString *WETabView_COLLECT;
+
+@implementation WETabItem
+
+static Class StrClass = Nil;
+
++ (int)version {
+  return [super version] + 0;
+}
++ (void)initialize {
+  StrClass = [NSString class];
+}
+
+static NSString *retStrForInt(int i) {
+  switch(i) {
+  case 0:  return @"0";
+  case 1:  return @"1";
+  case 2:  return @"2";
+  case 3:  return @"3";
+  case 4:  return @"4";
+  case 5:  return @"5";
+  case 6:  return @"6";
+  case 7:  return @"7";
+  case 8:  return @"8";
+  case 9:  return @"9";
+  case 10: return @"10";
+    // TODO: find useful count!
+  default:
+    return [[StrClass alloc] initWithFormat:@"%i", i];
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->key      = WOExtGetProperty(_config, @"key");
+    self->icon     = WOExtGetProperty(_config, @"icon");
+    self->label    = WOExtGetProperty(_config, @"label");
+    self->action   = WOExtGetProperty(_config, @"action");
+    self->isScript = WOExtGetProperty(_config, @"isScript");
+
+    self->tabIcon         = WOExtGetProperty(_config, @"tabIcon");
+    self->leftTabIcon     = WOExtGetProperty(_config, @"leftTabIcon");
+    self->selectedTabIcon = WOExtGetProperty(_config, @"selectedTabIcon");
+    
+    self->asBackground    = WOExtGetProperty(_config, @"asBackground");
+    self->width           = WOExtGetProperty(_config, @"width");
+    self->height          = WOExtGetProperty(_config, @"height");
+    self->activeBgColor   = WOExtGetProperty(_config, @"activeBgColor");
+    self->inactiveBgColor = WOExtGetProperty(_config, @"inactiveBgColor");
+    
+    self->template = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->action   release];
+  [self->label    release];
+  [self->icon     release];
+  [self->key      release];
+  [self->isScript release];
+  [self->template release];
+
+  [self->leftTabIcon     release];
+  [self->selectedTabIcon release];
+  [self->tabIcon         release];
+
+  [self->asBackground release];
+  [self->width        release];
+  [self->height       release];
+
+  [self->activeBgColor   release];
+  [self->inactiveBgColor release];
+  
+  [super dealloc];
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  NSString *activeTabKey;
+  NSString *myTabKey;
+  BOOL     doCheck;
+  
+  if ([_ctx objectForKey:WETabView_HEAD]) {
+    /* head clicks */
+    [[_ctx component] debugWithFormat:
+                        @"WETabItem: head takes (no) values, eid='%@'",
+                        [_ctx elementID]];
+    return;
+  }
+
+  if ((activeTabKey = [_ctx objectForKey:WETabView_BODY]) == nil) {
+    [[_ctx component] debugWithFormat:@"WETabItem: invalid state"];
+    [self->template takeValuesFromRequest:_rq inContext:_ctx];
+    return;
+  }
+  
+  myTabKey = [self->key      stringValueInComponent:[_ctx component]];
+  doCheck  = [self->isScript boolValueInComponent:[_ctx component]];
+    
+  if ([activeTabKey isEqualToString:myTabKey] || doCheck) {
+#if ADD_OWN_ELEMENTIDS
+    [_ctx appendElementIDComponent:activeTabKey];
+#endif
+      
+#if DEBUG_TAKEVALUES
+    [[_ctx component] debugWithFormat:
+                          @"WETabItem: body takes values, eid='%@'",
+                          [_ctx elementID]];
+#endif
+      
+    [self->template takeValuesFromRequest:_rq inContext:_ctx];
+#if ADD_OWN_ELEMENTIDS
+    [_ctx deleteLastElementIDComponent];
+#endif
+  }
+#if DEBUG_TAKEVALUES
+  else {
+      [[_ctx component] debugWithFormat:
+                          @"WETabItem: body takes no values, eid='%@'",
+                          [_ctx elementID]];
+  }
+#endif
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  id            result;
+  WOAssociation *tmp;
+  NSString      *activeTabKey;
+  
+  if ((tmp = [_ctx objectForKey:WETabView_HEAD])) {
+    /* click on tab icon */
+    NSString      *tabkey;
+    
+    tabkey = [_ctx currentElementID];
+    [_ctx consumeElementID];
+    [_ctx appendElementIDComponent:tabkey];
+    
+    if ([tmp isValueSettable])
+      [tmp setValue:tabkey inComponent:[_ctx component]];
+    
+    result = [self->action valueInComponent:[_ctx component]];
+
+    [_ctx deleteLastElementIDComponent];
+  }
+  else if ((activeTabKey = [_ctx objectForKey:WETabView_BODY])) {
+    /* clicked somewhere in the (active) body */
+    result = [self->template invokeActionForRequest:_req inContext:_ctx];
+  }
+  else {
+    [[_ctx component] logWithFormat:@"WETabItem: invalid invoke state"];
+    result = [self->template invokeActionForRequest:_req inContext:_ctx];
+  }
+  
+  return result;
+}
+
+/* info collection */
+
+- (void)_collectInContext:(WOContext *)_ctx key:(NSString *)k {
+  BOOL  isLeft = NO;
+  NSMutableArray *keys;
+  WETabItemInfo  *info;
+  WOComponent    *cmp;
+      
+  cmp  = [_ctx component];
+  keys = [_ctx objectForKey:WETabView_KEYS];
+  if (keys == nil) {
+    keys = [[[NSMutableArray alloc] init] autorelease];
+    [_ctx setObject:keys forKey:WETabView_KEYS];
+    isLeft = YES;
+  }
+      
+  if (k == nil) {
+    /* auto-assign a key */
+    k = retStrForInt([keys count]);
+  }
+  else
+    k = [k retain];
+  [_ctx appendElementIDComponent:k];
+  
+  info = [[WETabItemInfo alloc] init];
+  info->key      = [k copy];
+  info->label    = [[self->label stringValueInComponent:cmp] copy];
+  info->icon     = [[self->icon  stringValueInComponent:cmp] copy];
+  info->uri      = [[_ctx componentActionURL] copy];
+  info->isScript = [self->isScript boolValueInComponent:cmp];
+  info->tabIcon  = [[self->tabIcon stringValueInComponent:cmp] copy];
+  info->leftIcon = [[self->leftTabIcon stringValueInComponent:cmp] copy];
+  info->selIcon  = [[self->selectedTabIcon stringValueInComponent:cmp]
+                                           copy];
+  if (self->asBackground == nil)
+    info->asBackground = 0;
+  else {
+    info->asBackground
+      = ([self->asBackground boolValueInComponent:cmp]) ? 1 : -1;
+  }
+  info->width        = [[self->width  stringValueInComponent:cmp] copy];
+  info->height       = [[self->height stringValueInComponent:cmp] copy];
+  info->activeBg     = [[self->activeBgColor stringValueInComponent:cmp]
+                                             copy];
+  info->inactiveBg   = [[self->inactiveBgColor stringValueInComponent:cmp]
+                                               copy];
+      
+  if (info->leftIcon == nil) info->leftIcon = [info->tabIcon copy];
+      
+  [keys addObject:info];
+  [info release];
+  [k release];
+      
+  [_ctx deleteLastElementIDComponent];
+}
+
+/* header generation */
+
+- (void)_appendHeadToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  activeKey:(NSString *)activeKey
+  key:(NSString *)k
+{
+  /* head is currently generated in WETabView */
+#if 0
+  // note: some associations can be inherited by WETabView !
+  BOOL        doImages;
+  WOComponent *comp;
+  BOOL        doBgIcon;
+  NSString    *label;
+  NSString    *w, *h;
+  
+  doImages = ![[[_ctx request] clientCapabilities] isTextModeBrowser];
+  comp     = [_ctx component];
+  
+  doBgIcon = self->asBackground && doImages
+    ? [self->asBackground boolValueInComponent:comp] ? YES : NO
+    : NO;
+  
+  if ((label = [self->label stringValueInComponent:comp]) == nil)
+    label = k;
+
+  if (doImages) {
+    /* lookup image */
+    NSString *imgName = nil;
+    // ...
+    
+    imgUri = WEUriOfResource(imgName, _ctx);
+    if ([imgUri length] < 1)
+      doImages = NO;
+  }
+  
+  // .... _isActive
+#endif
+}
+
+/* body generation */
+
+- (void)_appendBodyToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  activeKey:(NSString *)tmp
+  key:(NSString *)k
+{
+  BOOL doScript;
+  BOOL isScript_;
+  BOOL isActive;
+
+  doScript  = [[_ctx objectForKey:WETabView_SCRIPT] boolValue];
+  isScript_ = [self->isScript boolValueInComponent:[_ctx component]];
+  isActive  = [tmp isEqualToString:k];
+    
+  if (doScript && (isActive || isScript_)) {
+    [_response appendContentString:@"<div id=\""];
+    [_response appendContentString:k];
+    [_response appendContentString:@"TabLayer\" style=\"display: none;\">\n"];
+  }
+  
+  if (isActive || (doScript && isScript_)) {
+    /* content is active or used as layer*/
+#if ADD_OWN_ELEMENTIDS
+    [_ctx appendElementIDComponent:k];
+#endif
+#if DEBUG && 0
+    NSLog(@"TAB: %@", k);
+#endif
+    
+    [self->template appendToResponse:_response inContext:_ctx];
+    
+#if ADD_OWN_ELEMENTIDS
+    [_ctx deleteLastElementIDComponent];
+#endif
+  }
+    
+  if (doScript && (isActive || isScript_)) {
+    NSString *jsout;
+    [_response appendContentString:@"</div>"];
+
+    jsout = [NSString alloc];
+    jsout = [jsout initWithFormat:
+                   @"<script language=\"JavaScript\">\n<!--\n"
+                   @"%@Tab[\"Div\"] = %@TabLayer;\n",
+                   k, k];
+    
+    [_response appendContentString:jsout];
+    [jsout release];
+    
+#if DEBUG_JS
+    jsout = [NSString alloc];
+    jsout = [jsout initWithFormat:
+                     @"if (%@Tab[\"Div\"].style==null) {"
+                     @"alert('missing style in div for tab %@');}",
+                     k, k];
+    
+    [_response appendContentString:jsout];
+    [jsout release];
+#endif
+    
+    if (isActive) {
+      [_response appendContentString:@"showTab("];
+      [_response appendContentString:k];
+      [_response appendContentString:@"Tab);\n"];
+    }
+    [_response appendContentString:@"//-->\n</script>"];
+  }
+}
+
+/* master generation method */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *k;
+  BOOL     doForm;
+  id       tmp;
+  
+  doForm = [_ctx isInForm];
+  k = [self->key stringValueInComponent:[_ctx component]];
+  
+  if ((tmp = [_ctx objectForKey:WETabView_HEAD])) {
+    if ([tmp isEqual:WETabView_COLLECT]) {
+      [self _collectInContext:_ctx key:k];
+    }
+    else {
+      [self _appendHeadToResponse:_response inContext:_ctx
+            activeKey:tmp key:k];
+    }
+  }
+  else if ((tmp = [_ctx objectForKey:WETabView_BODY])) {
+    [self _appendBodyToResponse:_response inContext:_ctx
+          activeKey:tmp key:k];
+  }
+  else {
+    NSLog(@"WARNING(%s): invalid WETabItem state !!!", __PRETTY_FUNCTION__);
+    [_response appendContentString:@"[invalid state]"];
+  }
+}
+
+@end /* WETabItem */
+
+@implementation WETabItemInfo
+
+- (void)dealloc {
+  [self->uri        release];
+  [self->icon       release];
+  [self->label      release];
+  [self->key        release];
+  [self->tabIcon    release];
+  [self->selIcon    release];
+  [self->leftIcon   release];
+  [self->width      release];
+  [self->height     release];
+  [self->activeBg   release];
+  [self->inactiveBg release];
+  
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)key {
+  return self->key;
+}
+- (NSString *)label {
+  return self->label;
+}
+- (NSString *)icon {
+  return self->icon;
+}
+- (NSString *)uri {
+  return self->uri;
+}
+- (BOOL)isScript {
+  return self->isScript;
+}
+
+- (int)asBackground {
+  return self->asBackground;
+}
+
+- (NSString *)width {
+  return self->width;
+}
+
+- (NSString *)height {
+  return self->height;
+}
+
+- (NSString *)activeBg {
+  return self->activeBg;
+}
+
+- (NSString *)inactiveBg {
+  return self->inactiveBg;
+}
+
+@end /* WETabItemInfo */
diff --git a/skyrix-sope/WEExtensions/WETabView.h b/skyrix-sope/WEExtensions/WETabView.h
new file mode 100644 (file)
index 0000000..9eff985
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WETabView_H__
+#define __WETabView_H__
+
+/*
+  This is a library private header !
+*/
+
+#include <NGObjWeb/WODynamicElement.h>
+
+/*
+  Does not support tab-head-creation from nested components !!!
+
+  hh: Why not ??? -> Because selection is manipulated in sub-elements
+
+  WETabView creates element-IDs like
+
+    .h.*.$key.  for the tab-items   (head-mode)
+    .b.$key...  for the tab-content (content-mode) (new, hh)
+
+  !!! WETabView JavaScript can't handle duplicate tab-keys !!!
+*/
+
+@interface WETabView : WODynamicElement
+{
+  WOAssociation *selection;
+
+  /* config: */
+  WOAssociation *bgColor;
+  WOAssociation *nonSelectedBgColor;
+  WOAssociation *leftCornerIcon;
+  WOAssociation *rightCornerIcon;
+  
+  WOAssociation *tabIcon;
+  WOAssociation *leftTabIcon;
+  WOAssociation *selectedTabIcon;
+  
+  WOAssociation *asBackground;
+  WOAssociation *width;
+  WOAssociation *height;
+  WOAssociation *activeBgColor;
+  WOAssociation *inactiveBgColor;
+
+  WOAssociation *fontColor;
+  WOAssociation *fontSize;
+  WOAssociation *fontFace;
+
+  id            template;
+}
+
+@end
+
+@interface WETabItem : WODynamicElement
+{
+  WOAssociation *key;
+  WOAssociation *icon;
+  WOAssociation *label;
+  WOAssociation *action;
+  WOAssociation *isScript;
+
+  /* config: */
+  WOAssociation *tabIcon;
+  WOAssociation *leftTabIcon;
+  WOAssociation *selectedTabIcon;
+
+  WOAssociation *asBackground;
+  WOAssociation *width;
+  WOAssociation *height;
+  WOAssociation *activeBgColor;
+  WOAssociation *inactiveBgColor;
+  
+  id            template;
+}
+
+@end
+
+@interface WETabItemInfo : NSObject
+{
+@public
+  NSString *label;
+  NSString *icon;
+  NSString *key;
+  NSString *uri;
+  NSString *tabIcon;
+  NSString *leftIcon;
+  NSString *selIcon;
+
+  int      asBackground; // 0 -> not set, 1 -> YES, else -> NO
+  NSString *width;
+  NSString *height;
+  NSString *activeBg;
+  NSString *inactiveBg;
+
+  BOOL     isScript;
+}
+@end
+
+#endif /* __WETabView_H__ */
diff --git a/skyrix-sope/WEExtensions/WETabView.m b/skyrix-sope/WEExtensions/WETabView.m
new file mode 100644 (file)
index 0000000..d1e7a48
--- /dev/null
@@ -0,0 +1,884 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WETabView.h"
+#include "common.h"
+#include "WEClientCapabilities.h"
+#import <NGObjWeb/NGObjWeb.h>
+#import <NGExtensions/NGExtensions.h>
+#import <EOControl/EOControl.h>
+
+#if DEBUG
+// #  define DEBUG_TAKEVALUES 1
+#  define DEBUG_JS 1
+#endif
+
+/* context keys */
+NSString *WETabView_HEAD      = @"WETabView_head";
+NSString *WETabView_BODY      = @"WETabView_body";
+NSString *WETabView_KEYS      = @"WETabView_keys";
+NSString *WETabView_SCRIPT    = @"WETabView_script";
+NSString *WETabView_ACTIVEKEY = @"WETabView_activekey";
+NSString *WETabView_COLLECT   = @"~tv~";
+
+@implementation WETabView
+
+static NSNumber *YesNumber;
+
++ (void)initialize {
+  if (YesNumber == nil)
+    YesNumber = [[NSNumber numberWithBool:YES] retain];
+}
+
++ (int)version {
+  return [super version] + 0;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->selection          = WOExtGetProperty(_config, @"selection");
+    
+    self->bgColor            = WOExtGetProperty(_config, @"bgColor");
+    self->nonSelectedBgColor = WOExtGetProperty(_config, @"nonSelectedBgColor");
+    self->leftCornerIcon     = WOExtGetProperty(_config, @"leftCornerIcon");
+    self->rightCornerIcon    = WOExtGetProperty(_config, @"rightCornerIcon");
+
+    self->tabIcon            = WOExtGetProperty(_config, @"tabIcon");
+    self->leftTabIcon        = WOExtGetProperty(_config, @"leftTabIcon");
+    self->selectedTabIcon    = WOExtGetProperty(_config, @"selectedTabIcon");
+
+    self->asBackground       = WOExtGetProperty(_config, @"asBackground");
+    self->width              = WOExtGetProperty(_config, @"width");
+    self->height             = WOExtGetProperty(_config, @"height");
+    self->activeBgColor      = WOExtGetProperty(_config, @"activeBgColor");
+    self->inactiveBgColor    = WOExtGetProperty(_config, @"inactiveBgColor");
+
+    self->fontColor          = WOExtGetProperty(_config, @"fontColor");
+    self->fontSize           = WOExtGetProperty(_config, @"fontSize");
+    self->fontFace           = WOExtGetProperty(_config, @"fontFace");
+
+    self->template = [_t retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->selection);
+  
+  RELEASE(self->bgColor);
+  RELEASE(self->nonSelectedBgColor);
+  RELEASE(self->leftCornerIcon);
+  RELEASE(self->rightCornerIcon);
+
+  RELEASE(self->leftTabIcon);
+  RELEASE(self->selectedTabIcon);
+  RELEASE(self->tabIcon);
+
+  RELEASE(self->width);
+  RELEASE(self->height);
+
+  RELEASE(self->activeBgColor);
+  RELEASE(self->inactiveBgColor);
+
+  RELEASE(self->fontColor);
+  RELEASE(self->fontSize);
+  RELEASE(self->fontFace);
+  
+  RELEASE(self->template);
+  [super dealloc];
+}
+
+/* nesting */
+
+- (id)saveNestedStateInContext:(WOContext *)_ctx {
+  return nil;
+}
+- (void)restoreNestedState:(id)_state inContext:(WOContext *)_ctx {
+  if (_state == nil) return;
+}
+
+- (NSArray *)collectKeysInContext:(WOContext *)_ctx {
+  /* collect mode, collects all keys */
+  [_ctx setObject:WETabView_COLLECT forKey:WETabView_HEAD];
+  
+  [self->template appendToResponse:nil inContext:_ctx];
+  
+  [_ctx removeObjectForKey:WETabView_HEAD];
+  return [_ctx objectForKey:WETabView_KEYS];
+}
+
+/* responder */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  id       nestedState;
+  NSString *activeTabKey;
+  
+  activeTabKey = [self->selection stringValueInComponent:[_ctx component]];
+  
+  nestedState = [self saveNestedStateInContext:_ctx];
+  [_ctx appendElementIDComponent:@"b"];
+  [_ctx appendElementIDComponent:activeTabKey];
+  
+  [_ctx setObject:activeTabKey forKey:WETabView_BODY];
+  
+#if DEBUG_TAKEVALUES
+  [[_ctx component] debugWithFormat:@"WETabView: body takes values, eid='%@'",
+                    [_ctx elementID]];
+#endif
+  
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+  
+  [_ctx removeObjectForKey:WETabView_BODY];
+  [_ctx deleteLastElementIDComponent]; // activeKey
+  [_ctx deleteLastElementIDComponent]; /* 'b' */
+  [self restoreNestedState:nestedState inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSString *key;
+  id       result;
+  id       nestedState;
+  
+  if ((key = [_ctx currentElementID]) == nil)
+    return nil;
+  
+  result      = nil;
+  nestedState = [self saveNestedStateInContext:_ctx];
+    
+  if ([key isEqualToString:@"h"]) {
+    /* header action */
+    //NSString *urlKey;
+    
+    [_ctx consumeElementID];
+    [_ctx appendElementIDComponent:@"h"];
+#if 0
+    if ((urlKey = [_ctx currentElementID]) == nil) {
+      [[_ctx application]
+             debugWithFormat:@"missing active head tab key !"];
+    }
+    else {
+      //NSLog(@"clicked: %@", urlKey);
+      [_ctx consumeElementID];
+      [_ctx appendElementIDComponent:urlKey];
+    }
+#endif
+    
+    [_ctx setObject:self->selection forKey:WETabView_HEAD];
+    result = [self->template invokeActionForRequest:_req inContext:_ctx];
+    [_ctx removeObjectForKey:WETabView_HEAD];
+
+#if 0
+    if (urlKey)
+      [_ctx deleteLastElementIDComponent]; // active key
+#endif
+    [_ctx deleteLastElementIDComponent]; // 'h'
+  }
+  else if ([key isEqualToString:@"b"]) {
+    /* body action */
+    NSString *activeTabKey, *urlKey;
+    
+    [_ctx consumeElementID];
+    [_ctx appendElementIDComponent:@"b"];
+      
+    if ((urlKey = [_ctx currentElementID]) == nil) {
+      [[_ctx application]
+             debugWithFormat:@"missing active body tab key !"];
+    }
+    else {
+      //NSLog(@"clicked: %@", urlKey);
+      [_ctx consumeElementID];
+      [_ctx appendElementIDComponent:urlKey];
+    }
+    
+    activeTabKey = [self->selection stringValueInComponent:[_ctx component]];
+    [_ctx setObject:activeTabKey forKey:WETabView_BODY];
+    
+    result = [self->template invokeActionForRequest:_req inContext:_ctx];
+      
+    [_ctx removeObjectForKey:WETabView_BODY];
+
+    if (urlKey)
+      [_ctx deleteLastElementIDComponent]; // active key
+    [_ctx deleteLastElementIDComponent]; // 'b'
+  }
+  else {
+    [[_ctx application]
+           debugWithFormat:@"unknown tab container key '%@'", key];
+  }
+    
+  [self restoreNestedState:nestedState inContext:_ctx];
+  return result;
+}
+
+- (NSString *)_tabViewCountInContext:(WOContext *)_ctx {
+  int count;
+  count = [[_ctx valueForKey:@"WETabViewScriptDone"] intValue];
+  return [NSString stringWithFormat:@"%d",count];
+}
+
+- (NSString *)scriptHref:(WETabItemInfo *)_info
+  inContext:(WOContext *)_ctx
+  isLeft:(BOOL)_isLeft
+  keys:(NSArray *)_keys
+{
+  NSMutableString *result = [NSMutableString string];
+  WETabItemInfo *tmp;
+  NSString       *activeKey;
+  int            i, cnt;
+  NSString       *elID;
+  NSString       *tstring;
+  
+  activeKey = [self->selection stringValueInComponent:[_ctx component]];
+  [result appendString:@"JavaScript:showTab("];
+  [result appendString:_info->key];
+  [result appendString:@"Tab);"];
+  
+  [result appendString:@"swapCorners("];
+  tstring = (!_isLeft)
+    ? @"tabCorner%@,tabCornerLeft%@);"
+    : @"tabCornerLeft%@,tabCorner%@);";
+  elID = [self _tabViewCountInContext:_ctx];
+  [result appendString:[NSString stringWithFormat:tstring,elID,elID]];
+  
+  for (i=0, cnt = [_keys count]; i < cnt; i++) {
+    tmp = [_keys objectAtIndex:i];
+
+    if ((tmp->isScript || [tmp->key isEqualToString:activeKey])
+        && ![tmp->key isEqualToString:_info->key]) {
+      [result appendString:@"hideTab("];
+      [result appendString:tmp->key];
+      [result appendString:@"Tab);"];
+    }
+  }
+  return result;
+}
+
+- (void)appendLink:(WETabItemInfo *)_info
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  isActive:(BOOL)_isActive isLeft:(BOOL)_isLeft
+  doScript:(BOOL)_doScript keys:(NSArray *)_keys
+{
+  BOOL        doBgIcon;
+  BOOL        doImages;
+  NSString    *headUri    = nil;
+  NSString    *imgUri     = nil;
+  NSString    *label      = nil;
+  NSString    *bgcolor    = nil;
+  NSString    *w          = nil;
+  NSString    *h          = nil;
+  NSString    *scriptHref = nil;
+  WOComponent *comp;
+
+  doImages = ![[[_ctx request] clientCapabilities] isTextModeBrowser];
+
+  comp = [_ctx component];
+  headUri = _info->uri;
+
+  if (_info->asBackground == 0)
+    doBgIcon = [self->asBackground boolValueInComponent:comp];
+  else
+    doBgIcon = (_info->asBackground == 1) ? YES : NO;
+  
+  if ((label = _info->label) == nil)
+    label = _info->key;
+  
+  if (doImages) {
+    /* lookup image */
+    NSString *imgName = nil;
+    
+    if (_isActive) {
+      imgName = _info->selIcon;  // selectedTabIcon
+      if (imgName == nil)
+        imgName = [self->selectedTabIcon stringValueInComponent:comp];
+    }
+    else if (_isLeft) {
+      imgName = _info->leftIcon; // leftTabIcon
+      if (imgName == nil)
+        imgName = [self->leftTabIcon stringValueInComponent:comp];
+    }
+    else {
+      imgName = _info->tabIcon;  // tabIcon
+      if (imgName == nil)
+        imgName = [self->tabIcon stringValueInComponent:comp];
+    }
+
+    if (imgName == nil) {
+      imgName = _info->icon;
+    }
+
+    imgUri = WEUriOfResource(imgName, _ctx);
+    
+    if ([imgUri length] < 1)
+      doImages = NO;
+  }
+
+  if (_isActive) {
+    bgcolor = (_info->activeBg)
+      ? _info->activeBg
+      : [self->activeBgColor stringValueInComponent:comp];
+  }
+  else {
+    bgcolor = (_info->inactiveBg)
+      ? _info->inactiveBg
+      : [self->inactiveBgColor stringValueInComponent:comp];
+  }
+  
+  w  = (_info->width)
+    ? _info->width
+    : [self->width stringValueInComponent:comp];
+  h  = (_info->height)
+    ? _info->height
+    : [self->height stringValueInComponent:comp];
+  
+  [_response appendContentString:@"<td align='center' valign='middle'"];
+  
+  if (w) {
+    [_response appendContentString:@" width='"];
+    [_response appendContentHTMLAttributeValue:w];
+    [_response appendContentCharacter:'\''];
+  }
+  if (h) {
+    [_response appendContentString:@" height='"];
+    [_response appendContentHTMLAttributeValue:h];
+    [_response appendContentCharacter:'\''];
+  }
+  if (bgcolor) {
+    [_response appendContentString:@" bgcolor='"];
+    [_response appendContentHTMLAttributeValue:bgcolor];
+    [_response appendContentCharacter:'\''];
+  }
+  if (doBgIcon && doImages) {
+    WEClientCapabilities *ccaps;
+  
+    ccaps = [[_ctx request] clientCapabilities];
+    
+    [_response appendContentString:@" background='"];
+    [_response appendContentHTMLAttributeValue:imgUri];
+    [_response appendContentCharacter:'\''];
+
+    // click on td background
+    if ([ccaps isInternetExplorer] && [ccaps isJavaScriptBrowser]) {
+      [_response appendContentString:@" onclick=\"window.location.href='"];
+       [_response appendContentHTMLAttributeValue:headUri];
+      [_response appendContentString:@"'\""];
+    }
+  }
+  
+  [_response appendContentCharacter:'>'];
+  
+  if (!doImages) [_response appendContentString:@"["];
+  
+  [_response appendContentString:@"<a style=\"text-decoration:none;\" href=\""];
+
+  if (_doScript && doImages && (_info->isScript || _isActive)) {
+    scriptHref =
+      [self scriptHref:_info inContext:_ctx isLeft:_isLeft keys:_keys];
+    [_response appendContentHTMLAttributeValue:scriptHref];
+  }
+  else {
+    [_response appendContentHTMLAttributeValue:headUri];
+  }
+  
+  [_response appendContentString:@"\" "];
+  [_response appendContentString:
+               [NSString stringWithFormat:@"name='%@TabLink'", _info->key]];
+  [_response appendContentString:@">"];
+  
+  if (!doImages && _isActive)
+    [_response appendContentString:@"<b>"];
+  
+  if (doImages && !doBgIcon) {
+    [_response appendContentString:@"<img border='0' src='"];
+    [_response appendContentString:imgUri];
+    [_response appendContentString:@"' name='"];
+    [_response appendContentString:_info->key];
+    [_response appendContentString:@"TabImg' alt='"];
+    [_response appendContentHTMLAttributeValue:label];
+    [_response appendContentString:@"' title='"];
+    [_response appendContentHTMLAttributeValue:label];
+    [_response appendContentString:@"'"];
+    [_response appendContentString:@" />"];
+  }
+  else {
+    NSString *fc     = [self->fontColor stringValueInComponent:comp];
+    NSString *fs     = [self->fontSize  stringValueInComponent:comp];
+    NSString *ff     = [self->fontFace  stringValueInComponent:comp];
+    BOOL     hasFont;
+    
+    hasFont = (fc || fs || ff) ? YES : NO;
+    
+    if ([label length] < 1)
+      label = _info->key;
+    [_response appendContentString:@"<nobr>"];
+    if (hasFont) WEAppendFont(_response, fc, ff, fs);           // <font>
+    
+    if (_isActive) [_response appendContentString:@"<b>"];
+    [_response appendContentHTMLString:label];
+    if (_isActive) [_response appendContentString:@"</b>"];
+    
+    if (hasFont) [_response appendContentString:@"</font>"];    // </font>
+    [_response appendContentString:@"</nobr>"];
+  }
+  
+  if (!doImages && _isActive)
+    [_response appendContentString:@"</b>"];
+  
+  [_response appendContentString:@"</a>"];
+  if (!doImages) [_response appendContentString:@"]"];
+
+
+  [_response appendContentString:@"</td>"];
+  
+  if (_doScript && doImages && (_info->isScript || _isActive)) {
+    NSString *k; // key 
+    NSString *s; // selected   tab icon
+    NSString *u; // unselected tab icon
+    //NSString *out;
+
+    k = _info->key;
+    s = _info->selIcon; // selectedTabIcon
+    u = (_isLeft) ? _info->leftIcon : _info->tabIcon;
+    
+    s = WEUriOfResource(s, _ctx);
+    u = WEUriOfResource(u, _ctx);
+
+    s = ([s length] < 1) ? imgUri : s;
+    u = ([u length] < 1) ? imgUri : u;
+    
+#if 0
+    out = [NSString alloc];
+    out = [out initWithFormat:
+                    @"<script language=\"JavaScript\">\n"
+                    @"<!--\n"
+                    @"var %@Tab = new Array();\n"
+                    @"%@Tab[\"link\"] = %@TabLink;\n"
+                    @"%@Tab[\"href1\"] = \"%@\";\n"
+                    @"%@Tab[\"href2\"] = \"%@\";\n"
+                    @"%@Tab[\"Img\"] = window.document.%@TabImg;\n"
+                    @"%@Tab[\"Ar\"]  = new Array();\n"
+                    @"%@Tab[\"Ar\"][0] = new Image();\n"
+                    @"%@Tab[\"Ar\"][0].src = \"%@\";\n"
+                    @"%@Tab[\"Ar\"][1] = new Image();\n"
+                    @"%@Tab[\"Ar\"][1].src = \"%@\";\n"
+                    @"//-->\n</script>",
+                    k, k, k, k, scriptHref, k, headUri,
+                    k, k, k, k,
+                    k, u, k, k, s
+                    ];
+    [_response appendContentString:out];
+    RELEASE(out);
+#else
+#  define _appendStr_(_str_) [_response appendContentString:_str_]
+    _appendStr_(@"<script language=\"JavaScript\">\n<!--\nvar ");
+    _appendStr_(k); _appendStr_(@"Tab = new Array();\n");
+
+    _appendStr_(k); _appendStr_(@"Tab[\"link\"] = ");
+    _appendStr_(k); _appendStr_(@"TabLink;\n");   // linkName
+      
+    _appendStr_(k); _appendStr_(@"Tab[\"href1\"] = \"");
+    _appendStr_(scriptHref); _appendStr_(@"\";\n"); // scriptHref
+
+    _appendStr_(k); _appendStr_(@"Tab[\"href2\"] = \"");
+    _appendStr_(_info->uri); _appendStr_(@"\";\n"); // actionHref
+      
+    _appendStr_(k); _appendStr_(@"Tab[\"Img\"] = window.document.");
+    _appendStr_(k); _appendStr_(@"TabImg;\n");
+    _appendStr_(k); _appendStr_(@"Tab[\"Ar\"]  = new Array();\n");
+    _appendStr_(k); _appendStr_(@"Tab[\"Ar\"][0] = new Image();\n");
+    _appendStr_(k); _appendStr_(@"Tab[\"Ar\"][0].src = \"");
+    _appendStr_(u); _appendStr_(@"\";\n");  // unselected img
+    _appendStr_(k); _appendStr_(@"Tab[\"Ar\"][1] = new Image();\n");
+    _appendStr_(k); _appendStr_(@"Tab[\"Ar\"][1].src = \"");
+    _appendStr_(s); _appendStr_(@"\";\n");  // selected img
+    _appendStr_(@"//-->\n</script>");
+#undef _appendStr_
+#endif
+  }
+}
+
+- (void)appendSubmitButton:(WETabItemInfo *)_info
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  isActive:(BOOL)_isActive isLeft:(BOOL)_left
+  doScript:(BOOL)_doScript   keys:(NSArray *)_keys
+{
+  [self appendLink:_info
+        toResponse:_response
+        inContext:_ctx
+        isActive:_isActive isLeft:_left
+        doScript:_doScript   keys:_keys];
+}
+
+- (void)_appendTabViewJSScriptToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  [_response appendContentString:
+               @"<script language=\"JavaScript\">\n<!--\n\n"
+               @"function showTab(obj) {\n"
+#if DEBUG_JS
+               @"  if (obj==null) { alert('missing tab obj ..'); return; }\n"
+               @"  if (obj['Div']==null) {"
+               @"    alert('missing div key in ' + obj); return; }\n"
+               @"  if (obj['Div'].style==null) {"
+               @"    alert('missing style key in div ' + obj['Div']);return; }\n"
+#endif
+               @"  obj['Div'].style.display = \"\";\n"
+               @"  obj['Img'].src = obj[\"Ar\"][1].src;\n"
+               @"  obj['link'].href = obj[\"href2\"];\n"
+               @"}\n"
+               @"function hideTab(obj) {\n"
+#if DEBUG_JS
+               @"  if (obj==null) { alert('missing tab obj ..'); return; }\n"
+               @"  if (obj['Div']==null) {"
+               @"    alert('missing div key in ' + obj); return; }\n"
+               @"  if (obj['Div'].style==null) {"
+               @"    alert('missing style key in div ' + obj['Div']);return; }\n"
+#endif
+               @" obj['Div'].style.display = \"none\";\n"
+               @" obj['Img'].src = obj[\"Ar\"][0].src;\n"
+               @" obj['link'].href = obj[\"href1\"];\n"
+               @"}\n"
+               @"function swapCorners(obj1,obj2) {\n"
+               @"   if (obj1==null) { alert('missing corner 1'); return; }\n"
+               @"   if (obj2==null) { alert('missing corner 2'); return; }\n"
+               @"   obj1.style.display = \"none\";\n"
+               @"   obj2.style.display = \"\";\n"
+               @"}\n"
+               @"//-->\n</script>"];
+}
+
+- (void)_appendHeaderRowToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  keys:(NSArray *)keys activeKey:(NSString *)activeKey
+  doScript:(BOOL)doScript
+{
+  unsigned i, count;
+  BOOL doForm;
+  
+  doForm = NO;  /* generate form controls ? */
+  
+  [_response appendContentString:@"<tr><td colspan='2'>"];
+  [_response appendContentString:
+               @"<table border='0' cellpadding='0' cellspacing='0'><tr>"];
+  
+  for (i = 0, count = [keys count]; i < count; i++) {
+    WETabItemInfo *info;
+    NSString       *key;
+    BOOL           isActive;
+    
+    info     = [keys objectAtIndex:i];
+    key      = info->key;
+    isActive = [key isEqualToString:activeKey];
+    
+    [_ctx appendElementIDComponent:key];
+    
+    if (doForm) {
+      /* tab is inside of a FORM, so produce submit buttons */
+      [self appendSubmitButton:info
+            toResponse:_response
+            inContext:_ctx
+            isActive:isActive
+            isLeft:(i == 0) ? YES : NO
+            doScript:doScript
+            keys:keys];
+    }
+    else {
+      /* tab is not in a FORM, generate hyperlinks for tab */
+      [self appendLink:info
+            toResponse:_response
+            inContext:_ctx
+            isActive:isActive
+            isLeft:(i == 0) ? YES : NO
+            doScript:doScript
+            keys:keys];
+    }
+    
+    [_ctx deleteLastElementIDComponent];
+  }
+  //  [_response appendContentString:@"<td></td>"];
+  [_response appendContentString:@"</tr></table>"];
+  [_response appendContentString:@"</td></tr>"];
+}
+
+- (void)_appendHeaderFootRowToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  bgcolor:(NSString *)bgcolor
+  doScript:(BOOL)doScript
+  isLeftActive:(BOOL)isLeftActive
+{
+  [_response appendContentString:@"  <tr"];
+  if (bgcolor) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentHTMLAttributeValue:bgcolor];
+    [_response appendContentString:@"\""];
+  }
+  [_response appendContentString:@">\n"];
+    
+  /* left corner */
+  [_response appendContentString:@"    <td align=\"left\" width=\"10\">"];
+  
+  if (doScript) {
+    [_response appendContentString:@"<div id=\"tabCorner"];
+    [_response appendContentString:[self _tabViewCountInContext:_ctx]];
+    [_response appendContentString:@"\" "];
+    [_response appendContentString:@"style=\"display: "];
+    [_response appendContentString:(isLeftActive) ? @"" : @"none"];
+    [_response appendContentString:@";\">"];
+    [_response appendContentString:@"&nbsp;"];
+    [_response appendContentString:@"</div>"];
+  }
+  else if (isLeftActive)
+    [_response appendContentString:@"&nbsp;"];
+  
+  if (doScript) {
+    [_response appendContentString:@"<div id=\"tabCornerLeft"];
+    [_response appendContentString:[self _tabViewCountInContext:_ctx]];
+    [_response appendContentString:@"\" "];
+    [_response appendContentString:@"style=\"display: "];
+    [_response appendContentString:(!isLeftActive) ? @"visible" : @"none"];
+    [_response appendContentString:@";\">"];
+  }
+  
+  if (!isLeftActive || doScript) {
+    NSString *uri;
+    
+    uri = [self->leftCornerIcon stringValueInComponent:[_ctx component]];
+    if ((uri = WEUriOfResource(uri, _ctx))) {
+      [_response appendContentString:@"<img border=\"0\" alt=\"\" src=\""];
+      [_response appendContentString:uri];
+      [_response appendContentString:@"\">"];
+    }
+    else
+      [_response appendContentString:@"&nbsp;"];
+  }
+  if (doScript)
+    [_response appendContentString:@"</div>"];
+
+  [_response appendContentString:@"</td>\n"];
+
+  /* right corner */
+  [_response appendContentString:@"    <td align=\"right\">"];
+  {
+    NSString *uri;
+      
+    uri = [self->rightCornerIcon stringValueInComponent:[_ctx component]];
+    if ((uri = WEUriOfResource(uri, _ctx))) {
+      [_response appendContentString:@"<img border=\"0\" alt=\"\" src=\""];
+      [_response appendContentString:uri];
+      [_response appendContentString:@"\" />"];
+    }
+    else
+      [_response appendContentString:@"&nbsp;"];
+  }
+  [_response appendContentString:@"</td>\n"];
+    
+  [_response appendContentString:@"  </tr>\n"];
+}
+
+- (void)_appendBodyRowToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  bgcolor:(NSString *)bgcolor
+  activeKey:(NSString *)activeKey
+{
+  WEClientCapabilities *ccaps;
+  BOOL indentContent;
+  
+  ccaps = [[_ctx request] clientCapabilities];
+  
+  /* put additional padding table into content ??? */
+  indentContent = [ccaps isFastTableBrowser] && ![ccaps isTextModeBrowser];
+  
+  [_response appendContentString:@"<tr><td colspan='2'"];
+  
+  if (bgcolor) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentHTMLAttributeValue:bgcolor];
+    [_response appendContentString:@"\""];
+  }
+  [_response appendContentString:@">"];
+    
+  if (indentContent) {
+    /* start padding table */
+    [_response appendContentString:
+               @"<table border='0' width='100%'"
+               @" cellpadding='10' cellspacing='0'>"];
+    [_response appendContentString:@"<tr><td>"];
+  }
+    
+  [_ctx appendElementIDComponent:@"b"];
+  [_ctx appendElementIDComponent:activeKey];
+  
+  /* generate currently active body */
+  {
+    [_ctx setObject:activeKey forKey:WETabView_BODY];
+    [self->template appendToResponse:_response inContext:_ctx];
+    [_ctx removeObjectForKey:WETabView_BODY];
+  }
+  
+  [_ctx deleteLastElementIDComponent]; // activeKey
+  [_ctx deleteLastElementIDComponent]; // 'b'
+    
+  if (indentContent)
+    /* close padding table */
+    [_response appendContentString:@"</td></tr></table>"];
+    
+  [_response appendContentString:@"</td></tr>"];
+}
+
+- (BOOL)isLeftActiveInKeys:(NSArray *)keys activeKey:(NSString *)activeKey{
+  unsigned i, count;
+  BOOL isLeftActive;
+  
+  isLeftActive = NO;
+  
+  for (i = 0, count = [keys count]; i < count; i++) {
+    WETabItemInfo *info;
+    
+    info = [keys objectAtIndex:i];
+    
+    if ((i == 0) && [info->key isEqualToString:activeKey])
+      isLeftActive = YES;
+  }
+  
+  return isLeftActive;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent  *cmp;
+  NSString     *bgcolor;
+  BOOL         isLeftActive;
+  BOOL         doScript;
+  id           nestedState;
+  NSString     *activeKey;
+  NSArray      *keys;
+  int          tabViewCount; /* used for image id's and writing script once */
+  
+  doScript      = NO;  /* perform tab-clicks on browser (use javascript) */
+  tabViewCount  = [[_ctx valueForKey:@"WETabViewScriptDone"] intValue];
+  cmp           = [_ctx component];
+  
+  /* check for browser */
+  {
+    WEClientCapabilities *ccaps;
+    //BOOL isJavaScriptBrowser;
+    
+    ccaps    = [[_ctx request] clientCapabilities];
+    doScript = [ccaps isInternetExplorer] && [ccaps isJavaScriptBrowser]; 
+    if ([_ctx hasSession]) {
+      WOSession *sn;
+      
+      sn = [cmp session];
+      doScript = (doScript &&
+                 [[sn valueForKey:@"isJavaScriptEnabled"] boolValue]);
+    }
+  }
+
+  /* disable javascript */
+  doScript = NO;
+  
+  /* save state */
+  
+  nestedState = [self saveNestedStateInContext:_ctx];
+  
+  /* configure */
+  
+  activeKey = [self->selection stringValueInComponent:cmp];
+  
+  bgcolor = [self->bgColor stringValueInComponent:cmp];
+  bgcolor = [bgcolor stringValue];
+  
+  [_ctx appendElementIDComponent:@"h"];
+  
+  /* collect & process keys (= available tabs) */
+  
+  keys = [self collectKeysInContext:_ctx];
+  
+  if (![[keys valueForKey:@"key"] containsObject:activeKey])
+    /* selection is not available in keys */
+    activeKey = nil;
+  
+  if ((activeKey == nil) && ([keys count] > 0)) {
+    /* no or invalid selection, use first key */
+    activeKey = [[keys objectAtIndex:0] key];
+    if ([self->selection isValueSettable])
+      [self->selection setValue:activeKey inComponent:[_ctx component]];
+  }
+
+  if (doScript) {
+    doScript = [[keys valueForKey:@"isScript"] containsObject:YesNumber];
+    [_ctx setObject:[NSNumber numberWithBool:doScript]
+          forKey:WETabView_SCRIPT];
+  }
+
+  /* start appending */
+  
+  if ((doScript) && (tabViewCount == 0))
+    [self _appendTabViewJSScriptToResponse:_response inContext:_ctx];
+  
+  /* count up for unique tabCorner/tabCornerLeft images */
+  [_ctx takeValue:[NSNumber numberWithInt:(tabViewCount + 1)]
+        forKey:@"WETabViewScriptDone"];
+  
+  [_response appendContentString:
+               @"<table border='0' width='100%'"
+               @" cellpadding='0' cellspacing='0'>"];
+  
+  /* find out whether left is active */
+  
+  isLeftActive = [self isLeftActiveInKeys:keys activeKey:activeKey];
+  
+  /* generate header row */
+  
+  [self _appendHeaderRowToResponse:_response inContext:_ctx
+        keys:keys activeKey:activeKey
+        doScript:doScript];
+  
+  [_ctx deleteLastElementIDComponent]; // 'h' for head
+  [_ctx removeObjectForKey:WETabView_HEAD];
+  
+  /* header foot row */
+  
+  [self _appendHeaderFootRowToResponse:_response inContext:_ctx
+        bgcolor:bgcolor
+        doScript:doScript
+        isLeftActive:isLeftActive];
+  
+  /* body row */
+  
+  [self _appendBodyRowToResponse:_response inContext:_ctx
+        bgcolor:bgcolor
+        activeKey:activeKey];
+  
+  /* close table */
+  
+  [_response appendContentString:@"</table>"];
+  [_ctx removeObjectForKey:WETabView_ACTIVEKEY];
+  [_ctx removeObjectForKey:WETabView_KEYS];
+  [self restoreNestedState:nestedState inContext:_ctx];
+}
+
+@end /* WETabView */
diff --git a/skyrix-sope/WEExtensions/WETableCalcMatrix.h b/skyrix-sope/WEExtensions/WETableCalcMatrix.h
new file mode 100644 (file)
index 0000000..280e50c
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WETableCalcMatrix_H__
+#define __WETableCalcMatrix_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSMapTable.h>
+#import <Foundation/NSRange.h>
+
+@class NSArray;
+
+/*
+  Object to calculate HTML Table based charts, eg the
+  Appointment week-overview.
+*/
+
+@interface WETableCalcMatrixSpan : NSObject
+{
+  id      object;
+  NSRange range;
+}
+
++ (id)spanWithObject:(id)_obj range:(NSRange *)_range;
+- (id)initWithObject:(id)_obj range:(NSRange *)_range;
+
+/* accessors */
+
+- (id)object;
+- (NSRange)range;
+
+/* calculates accessors */
+
+- (BOOL)startsAtIndex:(unsigned)_idx;
+- (BOOL)occupiesIndex:(unsigned)_idx;
+- (unsigned)size;
+
+@end
+
+@interface WETableCalcMatrix : NSObject
+{
+  void           *matrix;
+  unsigned short width;
+  unsigned short height;
+  NSMapTable     *objToPos;
+  id             delegate;  /* non-retained */
+  BOOL           columnCheck;
+  BOOL           rowCheck;
+}
+
+- (id)initWithSize:(unsigned)_width:(unsigned)_height;
+
+/* static accessors */
+
+- (unsigned)width;
+- (unsigned)height;
+
+- (void)setDelegate:(id)_delegate;
+- (id)delegate;
+
+/* clearing the structure */
+
+- (void)removeAllObjects;
+
+/* adding objects */
+
+- (void)placeObjects:(NSArray *)_objects;
+- (void)placeObject:(id)_object;
+
+/* calculating */
+
+- (NSArray *)objectsInColumn:(unsigned)_x;
+- (NSArray *)objectsInRow:(unsigned)_y;
+- (NSArray *)spansOfColumn:(unsigned)_x;
+- (NSArray *)spansOfRow:(unsigned)_y;
+- (NSArray *)columnSpans;
+- (NSArray *)rowSpans;
+
+@end
+
+@interface NSObject(WETableCalcMatrixDelegate)
+
+/* method for optimizing matrix scan (not required) */
+
+- (BOOL)tableCalcMatrix:(WETableCalcMatrix *)_matrix
+  shouldProcessColumn:(unsigned)_x
+  forObject:(id)_object;
+- (BOOL)tableCalcMatrix:(WETableCalcMatrix *)_matrix
+  shouldProcessRow:(unsigned)_y
+  forObject:(id)_object;
+
+/* shall the object be placed at the specified coordinate ? */
+
+- (BOOL)tableCalcMatrix:(WETableCalcMatrix *)_matrix
+  shouldPlaceObject:(id)_object
+  atPosition:(unsigned)_x:(unsigned)_y;
+
+/* define if you want to create own span objects */
+
+- (id)tableCalcMatrix:(WETableCalcMatrix *)_matrix
+  spanForObject:(id)_object
+  range:(NSRange)_range;
+
+@end
+
+#endif /* __WETableCalcMatrix_H__ */
diff --git a/skyrix-sope/WEExtensions/WETableCalcMatrix.m b/skyrix-sope/WEExtensions/WETableCalcMatrix.m
new file mode 100644 (file)
index 0000000..50454da
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WETableCalcMatrix.h"
+#include "common.h"
+
+typedef struct {
+  NSMutableArray *items;
+} MatrixEntry;
+
+typedef struct {
+  unsigned x;
+  unsigned y;
+} MatrixCoord;
+
+typedef struct {
+  id *objects;
+} MatrixThread;
+
+typedef enum { WERow, WEColumn } WEOrientation;
+
+static NSNull *null = nil;
+
+@implementation WETableCalcMatrixSpan
+
++ (id)spanWithObject:(id)_obj range:(NSRange *)_range {
+  id span;
+  span = [[WETableCalcMatrixSpan alloc] initWithObject:_obj range:_range];
+  return [span autorelease];
+}
+- (id)initWithObject:(id)_obj range:(NSRange *)_range {
+  self->object = [_obj retain];
+  self->range  = *_range;
+  return self;
+}
+- (void)dealloc {
+  [self->object release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id)object {
+  return self->object;
+}
+- (NSRange)range {
+  return self->range;
+}
+
+/* calculations */
+
+- (BOOL)startsAtIndex:(unsigned)_idx {
+  return (_idx == self->range.location) ? YES : NO;
+}
+- (BOOL)occupiesIndex:(unsigned)_idx {
+  if (_idx < self->range.location)
+    return NO;
+  if (_idx >= (self->range.location + self->range.length))
+    return NO;
+  return YES;
+}
+- (unsigned)size {
+  return self->range.length;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<0x%08X[%@]: object=0x%08X start=%d len=%d>",
+                     self, NSStringFromClass([self class]),
+                     [self object],
+                     self->range.location,
+                     self->range.length];
+}
+
+@end /* WETableCalcMatrixSpan */
+
+@interface WETableCalcMatrixStripe : NSObject
+{
+@private
+  unsigned           size;
+  MatrixThread       *threads;
+  short              threadCount;
+  WETableCalcMatrix *matrix;     /* non-retained */
+  id                 delegate;    /* non-retained */
+}
+
+- (unsigned)threadCount;
+- (NSArray *)threads;
+- (NSArray *)threadSpans;
+
+/* modification */
+
+- (void)addObject:(id)_obj atPositions:(unsigned *)_pos count:(unsigned)_c;
+
+@end
+
+@implementation WETableCalcMatrixStripe
+
++ (void)initialize {
+  if (null == nil) null = [[NSNull null] retain];
+}
+
+- (id)initWithSize:(unsigned)_h
+  matrix:(WETableCalcMatrix *)_matrix
+  delegate:(id)_delegate
+{
+  self->size   = _h;
+  self->matrix = _matrix;
+
+  if ([_delegate respondsToSelector:
+                   @selector(tableCalcMatrix:spanForObject:range:)])
+    self->delegate = _delegate;
+  
+  return self;
+}
+- (void)dealloc {
+  if (self->threads) {
+    unsigned i;
+    
+    for (i = 0; i < (unsigned)self->threadCount; i++) {
+      if (self->threads[i].objects) {
+        unsigned j;
+
+        for (j = 0; j < self->size; j++)
+          [self->threads[i].objects[j] release];
+        free(self->threads[i].objects);
+      }
+    }
+    free(self->threads);
+  }
+  [super dealloc];
+}
+
+/* accessors */
+
+- (unsigned)threadCount {
+  return self->threadCount;
+}
+
+- (NSArray *)threadAtIndex:(unsigned)_idx {
+  id       *objs;
+  unsigned i;
+  NSArray  *result;
+  
+  objs = calloc(self->size, sizeof(id));
+  NSAssert(objs, @"could not allocate memory ..");
+  NSAssert(self->size > 0, @"invalid size ..");
+  
+  for (i = 0; i < self->size; i++) {
+    objs[i] = self->threads[_idx].objects[i];
+    
+    if (objs[i] == nil)
+      objs[i] = null;
+  }
+  result = [NSArray arrayWithObjects:objs count:self->size];
+  free(objs);
+  return result;
+}
+- (NSArray *)spansAtIndex:(unsigned)_idx {
+  id       *spans;
+  unsigned i, spanCount;
+  NSArray  *result;
+  
+  spans = calloc(self->size, sizeof(id));
+  
+  for (i = 0, spanCount = 0; i < self->size; ) {
+    WETableCalcMatrixSpan *span;
+    id      obj;
+    NSRange r;
+    
+    span = nil;
+    obj  = self->threads[_idx].objects[i];
+
+    if ((i + 1) == self->size) {
+      /* last entry */
+      r.location = i;
+      r.length   = 1;
+      i++;
+    }
+    else {
+      /* look ahead for similiar entries */
+      unsigned j;
+      
+      r.location = i;
+      r.length   = 0;
+
+      for (j = i + 1; j < self->size; j++) {
+        id nextObj;
+        
+        nextObj = self->threads[_idx].objects[j];
+        if (nextObj != obj)
+          break;
+      }
+      r.length = (j - i);
+
+      /* continue at end of this object */
+      i = j;
+    }
+
+    span = nil;
+    if (self->delegate) {
+      span = [self->delegate tableCalcMatrix:self->matrix
+                             spanForObject:obj
+                             range:r];
+    }
+    if (span == nil) {
+      span = [[WETableCalcMatrixSpan alloc] initWithObject:obj range:&r];
+      AUTORELEASE(span);
+    }
+
+    spans[spanCount] = span;
+    spanCount++;
+  }
+  result = [NSArray arrayWithObjects:spans count:spanCount];
+  free(spans);
+  return result;
+}
+
+- (NSArray *)threads {
+  if (self->threadCount == 0)
+    return nil;
+  if (self->threadCount == 1)
+    return [NSArray arrayWithObject:[self threadAtIndex:0]];
+  
+  {
+    id       threadArrays[self->threadCount];
+    unsigned i;
+
+    for (i = 0; i < (unsigned)self->threadCount; i++)
+      threadArrays[i] = [self threadAtIndex:i];
+    
+    return [NSArray arrayWithObjects:threadArrays count:self->threadCount];
+  }
+}
+- (NSArray *)threadSpans {
+  if (self->threadCount == 0)
+    return nil;
+  else if (self->threadCount == 1)
+    return [NSArray arrayWithObject:[self spansAtIndex:0]];
+  else {
+    NSArray  *threadArrays[self->threadCount];
+    unsigned i;
+    
+    for (i = 0; i < (unsigned)self->threadCount; i++) {
+      threadArrays[i] = [self spansAtIndex:i];
+    }
+    
+    return [NSArray arrayWithObjects:threadArrays count:self->threadCount];
+  }
+}
+
+/* addition */
+
+- (unsigned)threadForPositions:(unsigned *)_pos count:(unsigned)_c {
+  unsigned i;
+  void *tmp;
+  
+  if (self->threadCount == 0) {
+    self->threads  = calloc(1, sizeof(MatrixThread));
+    self->threads[0].objects = calloc(self->size, sizeof(id));
+    self->threadCount = 1;
+    return 0;
+  }
+  
+  /* check each column */
+  for (i = 0; i < (unsigned)self->threadCount; i++) {
+    unsigned       j;
+    MatrixThread *column;
+    BOOL           ok;
+    
+    column = &(self->threads[i]);
+    
+    /* check each required position in column */
+    for (j = 0, ok = YES; j < _c; j++) {
+      unsigned requiredPos;
+      
+      requiredPos = _pos[j];
+      NSAssert(requiredPos < self->size, @"index to high ..");
+      
+      if (column->objects[requiredPos] != nil) {
+        /* position already assigned */
+        ok = NO;
+        break;
+      }
+    }
+    if (ok) {
+      /* all required position available, return column */
+      return i;
+    }
+    /* check next column */
+  }
+
+  /* all available threads are full, make new one .. */
+  tmp = self->threads;
+  self->threads = calloc(self->threadCount + 1, sizeof(MatrixThread));
+  memcpy(self->threads, tmp, self->threadCount * sizeof(MatrixThread));
+  self->threads[self->threadCount].objects = calloc(self->size, sizeof(id));
+  self->threadCount++;
+  return (self->threadCount - 1);
+}
+
+- (void)addObject:(id)_obj atPositions:(unsigned *)_pos count:(unsigned)_c {
+  unsigned thread;
+  unsigned i;
+
+  if (_c == 0) return;
+  
+  /* find row */
+  thread = [self threadForPositions:_pos count:_c];
+  NSAssert(thread < (unsigned)self->threadCount, @"invalid idx");
+  
+  /* place object */
+  for (i = 0; i < _c; i++) {
+    unsigned requiredIdx;
+    
+    requiredIdx = _pos[i];
+    
+#if DEBUG
+    NSAssert(requiredIdx < self->size, @"index to high ..");
+    NSAssert3(self->threads[thread].objects[requiredIdx] == nil,
+              @"index %i is already marked (by=0x%08X, my=0x%08X) !",
+              requiredIdx, self->threads[thread].objects[requiredIdx], _obj);
+#endif
+    
+    self->threads[thread].objects[requiredIdx] = RETAIN(_obj);
+  }
+}
+
+@end
+
+@interface WETableCalcMatrixPositionArray : NSObject
+{ /* mutable array of matrix coordinates */
+@private
+  unsigned    count;
+  MatrixCoord *positions;
+}
+
+- (void)addPosition:(unsigned)_x:(unsigned)_y;
+- (void)checkForDuplicates;
+
+/* narrow set to row or column */
+- (unsigned *)indicesInColumn:(unsigned)_x count:(unsigned *)_count;
+- (unsigned *)indicesInRow:(unsigned)_y    count:(unsigned *)_count;
+
+@end
+
+@implementation WETableCalcMatrixPositionArray
+
+- (void)dealloc {
+  if (self->positions) free(self->positions);
+  [super dealloc];
+}
+
+- (void)checkForDuplicates {
+  unsigned j;
+  
+  for (j = 0; j < self->count; j++) {
+    unsigned i;
+
+    for (i = 0; i < j; i++) {
+      NSAssert4(!((self->positions[j].x) == self->positions[i].x &&
+                 (self->positions[j].y) == self->positions[i].y),
+                @"duplicate coordinate at %d and %d: %d/%d !",
+                j, i, self->positions[j].x, self->positions[j].y);
+    }
+  }
+}
+
+- (void)addPosition:(unsigned)_x:(unsigned)_y {
+  if (self->positions == NULL) {
+    self->positions = calloc(1, sizeof(MatrixCoord));
+    self->positions[0].x = _x;
+    self->positions[0].y = _y;
+    self->count = 1;
+  }
+  else {
+    unsigned oldCount = self->count;
+    void *tmp;
+    
+    tmp = self->positions;
+    self->positions = calloc(oldCount + 1, sizeof(MatrixCoord));
+    memcpy(self->positions, tmp, (oldCount * sizeof(MatrixCoord)));
+    
+    self->positions[oldCount].x = _x;
+    self->positions[oldCount].y = _y;
+    self->count++;
+  }
+}
+
+- (unsigned *)indicesIn:(WEOrientation)o index:(unsigned)_idx
+  count:(unsigned *)_count
+{
+  unsigned i, rowCount;
+  unsigned *pos, *p;
+  
+  /* first count */
+  for (i = 0, rowCount = 0; i < self->count; i++) {
+    unsigned j;
+    
+    j = (o == WEColumn) ? self->positions[i].x : self->positions[i].y;
+    if (j == _idx)
+      rowCount++;
+  }
+  if (rowCount == 0)
+    return NULL;
+  
+  /* then copy */
+  pos = calloc(rowCount, sizeof(unsigned));
+  *_count = rowCount;
+  
+  for (i = 0, p = pos; i < self->count; i++) {
+    unsigned j;
+    
+    j = (o == WEColumn) ? self->positions[i].x : self->positions[i].y;
+    
+    if (j == _idx) {
+      *p = (o == WEColumn)
+        ? self->positions[i].y
+        : self->positions[i].x;
+      p++;
+    }
+  }
+  return pos;
+}
+
+- (unsigned *)indicesInRow:(unsigned)_y count:(unsigned *)_count {
+  return [self indicesIn:WERow index:_y count:_count];
+}
+- (unsigned *)indicesInColumn:(unsigned)_x count:(unsigned *)_count {
+  return [self indicesIn:WEColumn index:_x count:_count];
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%08X[%@]: count=%d>",
+                     self, NSStringFromClass([self class]),
+                     self->count];
+}
+
+@end /* WETableCalcMatrixPositionArray */
+
+@implementation WETableCalcMatrix
+
++ (int)version {
+  return 0;
+}
+
+static inline MatrixEntry *entryAt(WETableCalcMatrix *self, unsigned x, 
+                                  unsigned y) {
+  return self->matrix +
+         (x * self->height * sizeof(MatrixEntry)) +
+         (y * sizeof(MatrixEntry));
+}
+
+- (id)initWithSize:(unsigned)_width:(unsigned)_height {
+  if (_width == 0 || _height == 0) {
+    [self logWithFormat:@"ERROR: specified invalid matrix dimensions: %ix%i",
+            _width, _height];
+    [self release];
+    return nil;
+  }
+  
+  NSAssert(_width > 0 && _height > 0, @"invalid args ..");
+  self->width  = _width;
+  self->height = _height;
+  self->matrix = (void *)calloc(_width * _height, sizeof(MatrixEntry));
+  memset(self->matrix, 0, _width * _height * sizeof(MatrixEntry));
+
+  self->objToPos = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
+                                    NSObjectMapValueCallBacks,
+                                    64);
+  
+  return self;
+}
+- (void)dealloc {
+  [self removeAllObjects];
+
+  if (self->objToPos)
+    NSFreeMapTable(self->objToPos);
+  
+  if (self->matrix)
+    free(self->matrix);
+  
+  [super dealloc];
+}
+
+/* accessors */
+
+- (unsigned)width {
+  return self->width;
+}
+- (unsigned)height {
+  return self->height;
+}
+
+- (void)setDelegate:(id)_delegate {
+  self->delegate = _delegate;
+  
+  self->columnCheck =
+    [_delegate respondsToSelector:
+                 @selector(tableCalcMatrix:shouldProcessColumn:forObject:)];
+  self->rowCheck =
+    [_delegate respondsToSelector:
+                 @selector(tableCalcMatrix:shouldProcessRow:forObject:)];
+}
+- (id)delegate {
+  return self->delegate;
+}
+
+/* clearing the structure */
+
+- (void)removeAllObjects {
+  unsigned y, x;
+  
+  if (self->objToPos) {
+    NSResetMapTable(self->objToPos);
+    self->objToPos = NULL;
+  }
+  
+  if (self->matrix == NULL)
+    return;
+  
+  for (y = 0; y < self->height; y++) {
+    for (x = 0; x < self->width; x++) {
+      MatrixEntry *e;
+      
+      e = entryAt(self, x, y);
+      
+      if (e->items == nil) 
+       continue;
+      
+      [e->items release]; e->items = nil;
+    }
+  }
+}
+
+/* queries */
+
+- (BOOL)object:(id)_obj possibleInRow:(unsigned)_y {
+  /* optimization method, can always return 'YES' */
+  if (self->rowCheck) {
+    return [self->delegate tableCalcMatrix:self
+                           shouldProcessRow:_y
+                           forObject:_obj];
+  }
+  return YES;
+}
+
+- (BOOL)object:(id)_obj possibleInColumn:(unsigned)_x {
+  /* optimization method, can always return 'YES' */
+  if (self->columnCheck) {
+    return [self->delegate tableCalcMatrix:self
+                           shouldProcessColumn:_x
+                           forObject:_obj];
+  }
+  return YES;
+}
+
+- (BOOL)object:(id)_obj matchesCellAt:(unsigned)_x:(unsigned)_y {
+  return [self->delegate tableCalcMatrix:self
+                         shouldPlaceObject:_obj
+                         atPosition:_x:_y];
+}
+
+/* adding object to structure */
+
+- (void)addObject:(id)_obj toCellAt:(unsigned)_x:(unsigned)_y {
+  WETableCalcMatrixPositionArray *positions;
+  MatrixEntry *e;
+  
+  if ((positions = NSMapGet(self->objToPos, _obj)) == nil) {
+    positions = [[WETableCalcMatrixPositionArray alloc] init];
+    NSMapInsert(self->objToPos, _obj, positions);
+    RELEASE(positions);
+  }
+  
+  [positions checkForDuplicates];
+  
+  e = entryAt(self, _x, _y);
+  
+  if (e->items == nil)
+    e->items = [[NSMutableArray alloc] init];
+  
+  [e->items addObject:_obj];
+
+  [positions checkForDuplicates];
+  [positions addPosition:_x:_y];
+  [positions checkForDuplicates];
+}
+
+/* placing objects */
+
+- (void)placeObject:(id)_object {
+  unsigned y, x;
+
+  if (NSMapGet(self->objToPos, _object)) {
+    //NSLog(@"already placed object %@ !", _object);
+    return;
+  }
+  
+  if (self->rowCheck) {
+    for (y = 0; y < self->height; y++) {
+      if (![self object:_object possibleInRow:y])
+        continue;
+
+      for (x = 0; x < self->width; x++) {
+        if ([self object:_object matchesCellAt:x:y]) {
+          /* add to cell x:y */
+          [self addObject:_object toCellAt:x:y];
+        }
+      }
+    }
+  }
+  else {
+    for (x = 0; x < self->width; x++) {
+      if (![self object:_object possibleInColumn:x])
+        continue;
+    
+      for (y = 0; y < self->height; y++) {
+        if ([self object:_object matchesCellAt:x:y]) {
+          /* add to cell x:y */
+          [self addObject:_object toCellAt:x:y];
+        }
+      }
+    }
+  }
+}
+
+- (void)placeObjects:(NSArray *)_objects {
+  unsigned oc, i;
+  
+  if ((oc = [_objects count]) == 0)
+    return;
+  
+  for (i = 0; i < oc; i++)
+    [self placeObject:[_objects objectAtIndex:i]];
+}
+
+/* formatting */
+
+- (NSArray *)objectsInColumn:(unsigned)_x {
+  unsigned     y;
+  NSMutableSet *set;
+  NSArray      *result;
+
+  set = [[NSMutableSet alloc] init];
+  
+  for (y = 0; y < self->height; y++) {
+    MatrixEntry *e;
+    
+    e = entryAt(self, _x, y);
+    if (e->items)
+      [set addObjectsFromArray:e->items];
+  }
+  result = [set allObjects];
+  RELEASE(set);
+  return result;
+}
+- (NSArray *)objectsInRow:(unsigned)_y {
+  unsigned     x;
+  NSMutableSet *set;
+  NSArray      *result;
+
+  set = [[NSMutableSet alloc] init];
+  
+  for (x = 0; x < self->width; x++) {
+    MatrixEntry *e;
+    
+    e = entryAt(self, x, _y);
+    if (e->items)
+      [set addObjectsFromArray:e->items];
+  }
+  result = [set allObjects];
+  RELEASE(set);
+  return result;
+}
+
+- (NSArray *)spansOfColumn:(unsigned)_x {
+  WETableCalcMatrixStripe *stripe;
+  NSEnumerator  *objects;
+  id            object;
+  
+  stripe = [[WETableCalcMatrixStripe alloc]
+                                      initWithSize:self->height
+                                      matrix:self
+                                      delegate:self->delegate];
+  
+  objects = [[self objectsInColumn:_x] objectEnumerator];
+  while ((object = [objects nextObject])) {
+    WETableCalcMatrixPositionArray *pos;
+    unsigned *indices;
+    unsigned idxCount;
+    
+    pos = NSMapGet(self->objToPos, object);
+    [pos checkForDuplicates];
+    
+    indices = [pos indicesInColumn:_x count:&idxCount];
+    NSAssert(indices, @"available in column, but no indices ?");
+
+    [stripe addObject:object atPositions:indices count:idxCount];
+  }
+  
+  AUTORELEASE(stripe);
+  return [stripe threadSpans];
+}
+- (id)spansOfRow:(unsigned)_y {
+  WETableCalcMatrixStripe *stripe;
+  NSEnumerator  *objects;
+  id            object;
+  
+  stripe = [[WETableCalcMatrixStripe alloc]
+                                      initWithSize:self->width
+                                      matrix:self
+                                      delegate:self->delegate];
+  
+  objects = [[self objectsInRow:_y] objectEnumerator];
+  while ((object = [objects nextObject])) {
+    WETableCalcMatrixPositionArray *pos;
+    unsigned *indices;
+    unsigned idxCount;
+    
+    pos = NSMapGet(self->objToPos, object);
+    [pos checkForDuplicates];
+    
+    indices = [pos indicesInRow:_y count:&idxCount];
+    NSAssert(indices, @"available in column, but no indices ?");
+    
+    [stripe addObject:object atPositions:indices count:idxCount];
+  }
+  
+  AUTORELEASE(stripe);
+  return [stripe threadSpans];
+}
+
+- (NSArray *)columnSpans {
+  id       objs[self->width];
+  unsigned i;
+  
+  for (i = 0; i < self->width; i++) {
+    objs[i] = [self spansOfColumn:i];
+    if (objs[i] == nil) objs[i] = [NSArray array];
+  }
+  return [NSArray arrayWithObjects:objs count:self->width];
+}
+- (NSArray *)rowSpans {
+  id       objs[self->height];
+  unsigned i;
+  
+  for (i = 0; i < self->height; i++) {
+    objs[i] = [self spansOfRow:i];
+    if (objs[i] == nil) objs[i] = [NSArray array];
+  }
+  return [NSArray arrayWithObjects:objs count:self->height];
+}
+
+/* counting */
+
+- (unsigned)widthOfColumn:(unsigned)_x {
+  unsigned y;
+  unsigned count;
+  
+  for (y = 0, count = 0; y < self->height; y++) {
+    MatrixEntry *e;
+
+    e = entryAt(self, _x, y);
+    if ([e->items count] > count)
+      count = [e->items count];
+  }
+  return count;
+}
+
+- (unsigned)countOfColumn:(unsigned)_x {
+  return [[self objectsInColumn:_x] count];
+}
+
+@end /* WETableCalcMatrix */
diff --git a/skyrix-sope/WEExtensions/WETableMatrix.m b/skyrix-sope/WEExtensions/WETableMatrix.m
new file mode 100644 (file)
index 0000000..25e5598
--- /dev/null
@@ -0,0 +1,831 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+#include <NGObjWeb/WOAssociation.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOResponse.h>
+#include "WETableCalcMatrix.h"
+#include "common.h"
+
+/*
+  for examples of this element, look at SkySchedulerViews chart-views.
+*/
+
+/* context keys */
+static NSString *WETableMatrix_Query   = @"WETableMatrix_Query";
+static NSString *WETableMatrix_Mode    = @"WETableMatrix_Mode";
+static NSString *WETableMatrix_Index   = @"WETableMatrix_Index";
+static NSString *WETableMatrix_Count   = @"WETableMatrix_Count";
+static NSString *WETableMatrix_ColSpan = @"WETableMatrix_ColSpan";
+static NSString *WETableMatrix_RowSpan = @"WETableMatrix_RowSpan";
+
+@interface WETableMatrix : WODynamicElement
+{
+  WOAssociation *list;    /* array of objects */
+  WOAssociation *item;    /* current object   */
+  
+  WOAssociation *rows;    /* array of row objects    (eg days)         */
+  WOAssociation *columns; /* array of column objects (eg times of day) */
+  WOAssociation *row;     /* current row object    */
+  WOAssociation *column;  /* current column object */
+  
+  WOAssociation *itemActive; /* query whether item is active in row/column */
+  WOAssociation *isRowActive;
+  WOAssociation *isColumnActive;
+
+  WOElement     *template;
+
+  /* transient, not reentrant (need to lock) */
+  WOComponent   *component;
+  NSArray       *_rows;
+  NSArray       *_cols;
+  NSArray       *objs;
+  NSSet         *subElems;
+}
+
+@end
+
+@interface WEHSpanTableMatrix : WETableMatrix
+@end
+
+@interface WEVSpanTableMatrix : WETableMatrix
+{
+  WOAssociation *rowHeight;          /* height of TR tag */
+  WOAssociation *noSpanInEmptyCells; /* do empty cells span rows ? */
+} 
+@end
+
+static BOOL genComments = NO;
+
+@implementation WETableMatrix
+
+// premature: don't know a "good" count
+static NSNumber *smap[10] = { nil,nil,nil,nil,nil,nil,nil,nil,nil,nil };
+static Class StrClass = Nil;
+static Class NumClass = Nil;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  int i;
+  if (didInit) return;
+  didInit = YES;
+  
+  StrClass = [NSString class];
+  NumClass = [NSNumber class];
+  for (i = 0; i < 10; i++)
+    smap[i] = [[NumClass numberWithUnsignedInt:i] retain];
+}
+
+static NSNumber *numForUInt(unsigned int i) {
+  // TODO: prof
+  if (i < 10) return smap[i];
+  return [NumClass numberWithUnsignedInt:i];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->list           = WOExtGetProperty(_config, @"list");
+    self->item           = WOExtGetProperty(_config, @"item");
+    self->rows           = WOExtGetProperty(_config, @"rows");
+    self->columns        = WOExtGetProperty(_config, @"columns");
+    self->row            = WOExtGetProperty(_config, @"row");
+    self->column         = WOExtGetProperty(_config, @"column");
+    self->itemActive     = WOExtGetProperty(_config, @"itemActive");
+    self->isRowActive    = WOExtGetProperty(_config, @"isRowActive");
+    self->isColumnActive = WOExtGetProperty(_config, @"isColumnActive");
+    
+    self->template = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->isRowActive    release];
+  [self->isColumnActive release];
+  [self->itemActive release];
+  [self->row        release];
+  [self->column   release];
+  [self->rows     release];
+  [self->columns  release];
+  [self->list     release];
+  [self->item     release];
+  [self->template release];
+  [super dealloc];
+}
+
+/* matrix delegate */
+
+- (BOOL)tableCalcMatrix:(WETableCalcMatrix *)_matrix
+  shouldPlaceObject:(id)_object
+  atPosition:(unsigned)_x:(unsigned)_y
+{
+  id   _row, _col;
+  BOOL doPlace;
+  
+  _col = [self->_cols objectAtIndex:_x];
+  _row = [self->_rows objectAtIndex:_y];
+  
+  /* setup context in component */
+  [self->row    setValue:_row    inComponent:self->component];
+  [self->column setValue:_col    inComponent:self->component];
+  [self->item   setValue:_object inComponent:self->component];
+  
+#if 0
+  NSLog(@"%i/%i: col %@ row %@", _x,_y, _col, _row);
+#endif
+  
+  /* check */
+  doPlace = [self->itemActive boolValueInComponent:self->component];
+#if 0
+  NSLog(@"  %@ placed: %s", self->itemActive, doPlace ? "yes" : "no");
+#endif
+  
+  return doPlace;
+}
+
+- (BOOL)tableCalcMatrix:(WETableCalcMatrix *)_matrix
+  shouldProcessColumn:(unsigned)_x
+  forObject:(id)_object
+{
+  if (!self->isColumnActive)
+    return YES;
+  
+  [self->column setValue:[self->_cols objectAtIndex:_x]
+                inComponent:self->component];
+  [self->item setValue:_object inComponent:self->component];
+    
+  return [self->isColumnActive boolValueInComponent:self->component];
+}
+- (BOOL)tableCalcMatrix:(WETableCalcMatrix *)_matrix
+  shouldProcessRow:(unsigned)_y
+  forObject:(id)_object
+{
+  if (!self->isRowActive)
+    return YES;
+  
+  [self->row setValue:[self->_rows objectAtIndex:_y]
+             inComponent:self->component];
+  [self->item setValue:_object inComponent:self->component];
+
+  return [self->isRowActive boolValueInComponent:self->component];
+}
+
+/* HTML generation */
+
+- (NSArray *)spansFromMatrix:(WETableCalcMatrix *)_matrix {
+  [self logWithFormat:@"ERROR: subclasses should override %@!",
+          NSStringFromSelector(_cmd)];
+  return nil;
+}
+- (void)appendSpans:(NSArray *)_spans
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  [self logWithFormat:@"ERROR: subclasses should override %@!",
+          NSStringFromSelector(_cmd)];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSLog(@"WARNING(WETableMatrix): unsupported invokeActionForRequest called!");
+  return [super invokeActionForRequest:_req inContext:_ctx];
+}
+
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSAutoreleasePool  *pool;
+  WETableCalcMatrix *matrix;
+  NSArray            *allSpans;
+  unsigned           rowCount, colCount, count;
+  
+  self->component = [_ctx component];
+  self->objs      = 
+    [[[self->list    valueInComponent:self->component] copy] autorelease];
+  self->_rows     = 
+    [[[self->rows    valueInComponent:self->component] copy] autorelease];
+  self->_cols     = 
+    [[[self->columns valueInComponent:self->component] copy] autorelease];
+  
+  count    = [self->objs count];
+  rowCount = [self->_rows count];
+  colCount = [self->_cols count];
+  
+  /* query subelements */
+  {
+    NSMutableSet *qs;
+
+    qs = [[NSMutableSet alloc] init];
+    [_ctx setObject:qs forKey:WETableMatrix_Query];
+    [self->template appendToResponse:_response inContext:_ctx];
+    [_ctx removeObjectForKey:WETableMatrix_Query];
+    self->subElems = [[qs copy] autorelease];
+    [qs release];
+  }
+  
+  if ([self->subElems count] == 0) {
+    /* no content */
+    NSLog(@"WARNING: no sub-elements !");
+    return;
+  }
+
+#if 0
+  NSLog(@"subelems: %@", [self->subElems allObjects]);
+#endif
+  
+  /* fill matrix and calculate spans */
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    matrix = [[WETableCalcMatrix alloc] initWithSize:colCount:rowCount];
+    [matrix setDelegate:self];
+    [matrix placeObjects:objs];
+    allSpans = [[self spansFromMatrix:matrix] copy];
+    [matrix release]; matrix = nil;
+  }
+  [pool release]; pool = nil;
+  [allSpans autorelease];
+
+  /* generate vertical table */
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  [_response appendContentString:@"<table"];
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  [_response appendContentString:@">"];
+  
+  [self appendSpans:allSpans
+        toResponse:_response
+        inContext:_ctx];
+
+  [_response appendContentString:@"</table>"];
+
+  /* remove context keys */
+  [_ctx removeObjectForKey:WETableMatrix_Mode];
+  [_ctx removeObjectForKey:WETableMatrix_Index];
+  [_ctx removeObjectForKey:WETableMatrix_Count];
+  [_ctx removeObjectForKey:WETableMatrix_ColSpan];
+  [_ctx removeObjectForKey:WETableMatrix_RowSpan];
+  
+  /* reset transients */
+  self->subElems  = nil;
+  self->_rows     = nil;
+  self->_cols     = nil;
+  self->objs      = nil;
+  self->component = nil;
+  [pool release];
+}
+
+@end /* WETableMatrix */
+
+@implementation WEVSpanTableMatrix
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->rowHeight          = WOExtGetProperty(_config, @"rowHeight");
+    self->noSpanInEmptyCells = WOExtGetProperty(_config, @"noSpanInEmptyCells");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->noSpanInEmptyCells release];
+  [self->rowHeight release];
+  [super dealloc];
+}
+
+- (NSArray *)spansFromMatrix:(WETableCalcMatrix *)_matrix {
+  return [_matrix columnSpans];
+}
+
+- (void)_genEmptyCellWithRowSpan:(int)_span
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString *s;
+  
+  if (_span > 1) {
+    char buf[16];
+    sprintf(buf, "%i", _span);
+    s = [[StrClass alloc] initWithCString:buf];
+  }
+  else
+    s = @"1";
+  
+  if ([self->subElems containsObject:@"empty"]) {
+    if (_span > 0)
+      [_ctx setObject:s forKey:WETableMatrix_RowSpan];
+    
+    [_ctx setObject:@"empty" forKey:WETableMatrix_Mode];
+    
+    [self->template appendToResponse:_response inContext:_ctx];
+    
+    if (_span > 0)
+      [_ctx removeObjectForKey:WETableMatrix_RowSpan];
+  }
+  else {
+    [_response appendContentString:@"<td"];
+    if (_span > 1) {
+      [_response appendContentString:@" rowspan=\""];
+      [_response appendContentString:s];
+      [_response appendContentString:@"\""];
+    }
+    [_response appendContentString:@">"];
+
+    [_response appendContentString:@"&nbsp;"];
+    [_response appendContentString:@"</td>\n"];
+  }
+  
+  [s release];
+}
+
+- (void)appendSpans:(NSArray *)_spans
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent;
+#if 0 // hh: unused
+  NSString *horizWidth;
+#endif
+  unsigned columnCount, rowCount;
+  BOOL noEmptySpan; // empty cells do not have ROWSPAN (more cells are written)
+  
+  sComponent  = [_ctx component];
+  columnCount = [self->_cols count];
+  rowCount    = [self->_rows count];
+#if 0 // hh: unused
+  horizWidth  =
+    [StrClass stringWithFormat:@"%d%%", (unsigned)(100.0/columnCount)];
+#endif
+
+  noEmptySpan = [self->noSpanInEmptyCells boolValueInComponent:sComponent];
+  
+  [_ctx setObject:numForUInt(columnCount) forKey:WETableMatrix_Count];
+
+  /* head row */
+  if ([self->subElems containsObject:@"top"]) {
+    unsigned x;
+    int numOfLeftLabels;
+
+    numOfLeftLabels = 0;
+    if ([self->subElems containsObject:@"left"])
+      numOfLeftLabels++;
+    
+    [_response appendContentString:@"<tr>\n"];
+
+    /* left/top edge */
+    if (numOfLeftLabels > 0) {
+      char buf[8];
+      NSString *s;
+      
+      sprintf(buf, "%i", numOfLeftLabels);
+      s = [[StrClass alloc] initWithCString:buf];
+      
+      if ([self->subElems containsObject:@"topleft"]) {
+        [_ctx setObject:s          forKey:WETableMatrix_ColSpan];
+        [_ctx setObject:@"topleft" forKey:WETableMatrix_Mode];
+        
+        [self->template appendToResponse:_response inContext:_ctx];
+        
+        [_ctx removeObjectForKey:WETableMatrix_ColSpan];
+      }
+      else {
+        [_response appendContentString:@"  <td"];
+        if (numOfLeftLabels > 1) {
+          [_response appendContentString:@" colspan=\""];
+          [_response appendContentString:s];
+          [_response appendContentString:@"\""];
+        }
+        [_response appendContentString:@">&nbsp;</td>\n"];
+      }
+      [s release];
+    }
+    
+    /* header */
+    [_ctx setObject:@"top" forKey:WETableMatrix_Mode];
+    
+    for (x = 0; x < columnCount; x++) {
+      NSArray  *spans;
+      char     buf[64];
+      NSString *s;
+      
+      spans = [_spans objectAtIndex:x];
+      
+      sprintf(buf, "%d", [spans count]);
+      s = [[StrClass alloc] initWithCString:buf];
+      [_ctx setObject:s forKey:WETableMatrix_ColSpan];
+      
+      [self->column setValue:[self->_cols objectAtIndex:x]
+                    inComponent:sComponent];
+      [_ctx setObject:numForUInt(x) forKey:WETableMatrix_Index];
+      
+      [self->template appendToResponse:_response inContext:_ctx];
+      
+      [s release]; s = nil;
+    }
+    
+    [_response appendContentString:@"</tr>"];
+  }
+
+  [_ctx removeObjectForKey:WETableMatrix_ColSpan];
+  [_ctx removeObjectForKey:WETableMatrix_RowSpan];
+  [_ctx removeObjectForKey:WETableMatrix_Index];
+  
+  /* body rows */
+  {
+    unsigned y;
+    
+    /* foreach row */
+    for (y = 0; y < rowCount; y++) {
+      unsigned x;
+
+      [self->row setValue:[self->_rows objectAtIndex:y]
+                 inComponent:[_ctx component]];
+
+      if (self->rowHeight) {
+        [_response appendContentString:@"<tr height=\""];
+        [_response appendContentString:
+                     [self->rowHeight stringValueInComponent:sComponent]];
+        [_response appendContentString:@"\">"];
+      }
+      else {
+        [_response appendContentString:@"<tr>"];
+      }
+      if (genComments) {
+        NSString *s;
+        s = [[StrClass alloc] initWithFormat:@"<!-- row %i -->\n", y];
+        [_response appendContentString:s];
+        [s release];
+      }
+      
+      /* left edge */
+      {
+        char     buf[64];
+        NSString *s;
+        
+        [_ctx setObject:@"left" forKey:WETableMatrix_Mode];
+
+        sprintf(buf, "%i", y);
+        s = [[StrClass alloc] initWithCString:buf];
+        
+        [_ctx setObject:numForUInt(y) forKey:WETableMatrix_Index];
+        
+        [self->template appendToResponse:_response inContext:_ctx];
+        [s release];
+      }
+      
+      /* foreach column */
+      for (x = 0; x < columnCount; x++) {
+        NSArray  *spans;
+        unsigned i;
+
+        spans = [_spans objectAtIndex:x];
+        
+        if ([spans count] == 0) { /* no content cells */
+          if ((y == 0) || noEmptySpan) {
+            /* max rowspan, only encode in first row */
+            
+            [self _genEmptyCellWithRowSpan:(noEmptySpan ? 1 : rowCount)
+                  toResponse:_response
+                  inContext:_ctx];
+          }
+          continue;
+        }
+        
+        /* foreach sub-columns (title-COLSPAN=subcell-count) */
+
+        for (i = 0; i < [spans count]; i++) {
+          NSArray *thread; /* sub-column top-down */
+          unsigned j;
+            
+          thread = [spans objectAtIndex:i];
+          NSCAssert([thread count] > 0, @"no contents in thread");
+            
+          for (j = 0; j < [thread count]; j++) {
+            id span;
+              
+            span = [thread objectAtIndex:j];
+            if (![span occupiesIndex:y])
+              continue;
+            
+            if ([span startsAtIndex:y]) {
+              char buf[64];
+              NSString *s;
+              
+              sprintf(buf, "%i", [span size]);
+              s = [[StrClass alloc] initWithCString:buf];
+              [_ctx setObject:s forKey:WETableMatrix_RowSpan];
+              
+              [self->column setValue:[self->_cols objectAtIndex:x]
+                            inComponent:self->component];
+              
+              if ([span object]) {
+                /* setup context */
+                [self->item setValue:[span object] inComponent:self->component];
+                
+                /* generate body */
+                [_ctx setObject:@"content" forKey:WETableMatrix_Mode];
+              
+                [self->template appendToResponse:_response inContext:_ctx];
+              }
+              else {
+                [self _genEmptyCellWithRowSpan:(noEmptySpan ? 1 : [span size])
+                      toResponse:_response
+                      inContext:_ctx];
+              }
+
+              [_ctx removeObjectForKey:WETableMatrix_RowSpan];
+              [s release]; s = nil;
+            }
+            else if (noEmptySpan) {
+              if ([span object] == nil) {
+                [self _genEmptyCellWithRowSpan:1
+                      toResponse:_response
+                      inContext:_ctx];
+              }
+            }
+          }
+        } /* end of 'foreach sub-columns (title-COLSPAN=subcell-count)' */
+      } /* end of 'foreach column' */
+      [_response appendContentString:@"</tr>"];
+    }
+  }
+  
+  /* footer row */
+  
+  if ([self->subElems containsObject:@"bottom"]) {
+  }
+}
+
+@end /* WEVSpanTableMatrix */
+
+@implementation WEHSpanTableMatrix
+
+- (NSArray *)spansFromMatrix:(WETableCalcMatrix *)_matrix {
+  return [_matrix rowSpans];
+}
+
+- (void)appendVerticalSpan:(NSArray *)_threads
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  unsigned x, width;
+  
+  width = [self->_cols count];
+
+  for (x = 0; x < width; x++) { /* foreach table column */
+    unsigned j, tc;
+          
+    for (j = 0, tc = [_threads count]; j < tc; j++) {
+      id span;
+            
+      span = [_threads objectAtIndex:j];
+      if (![span occupiesIndex:x])
+        continue;
+
+      if ([span startsAtIndex:x]) {
+        NSString *s;
+        char buf[64];
+
+        sprintf(buf, "%d", [span size]);
+        s = [[StrClass alloc] initWithCString:buf];
+        [_ctx setObject:s forKey:WETableMatrix_ColSpan];
+        
+        if ([span object]) {
+          /* setup context */
+          [self->column setValue:[self->_cols objectAtIndex:x]
+                        inComponent:self->component];
+          [self->item setValue:[span object] inComponent:self->component];
+
+          /* generate body */
+          [_ctx setObject:@"content" forKey:WETableMatrix_Mode];
+          [self->template appendToResponse:_response inContext:_ctx];
+        }
+        else {
+          /* generate empty body */
+          if ([self->subElems containsObject:@"empty"]) {
+            [_ctx setObject:@"empty" forKey:WETableMatrix_Mode];
+            [self->template appendToResponse:_response inContext:_ctx];
+          }
+          else {
+            [_response appendContentString:@"<td colspan=\""];
+            [_response appendContentString:s];
+            [_response appendContentString:@"\">"];
+            [_response appendContentString:@"&nbsp;"];
+            [_response appendContentString:@"</td>\n"];
+          }
+        }
+        [s release]; s = nil;
+      }
+    }
+  }
+}
+
+- (void)appendSpans:(NSArray *)_spans
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *sComponent;
+#if 0 // hh: unused
+  NSString *horizWidth;
+#endif
+  unsigned columnCount;
+
+  sComponent  = [_ctx component];
+  columnCount = [self->_cols count];
+#if 0 // hh: unused
+  horizWidth  =
+    [StrClass stringWithFormat:@"%d%%", (unsigned)(100.0/columnCount)];
+#endif
+  
+  [_ctx setObject:numForUInt(columnCount) forKey:WETableMatrix_Count];
+  
+  /* head row */
+
+  if ([self->subElems containsObject:@"top"]) {
+    unsigned i, count;
+    
+    [_response appendContentString:@"<tr>"];
+
+    /* edge */
+    if ([self->subElems containsObject:@"left"])
+      [_response appendContentString:@"<td>&nbsp;</td>"];
+    
+    /* header */
+    [_ctx setObject:@"top" forKey:WETableMatrix_Mode];
+    count = [self->_cols count];
+    
+    for (i = 0; i < count; i++) {
+      [_ctx setObject:numForUInt(i) forKey:WETableMatrix_Index];
+      
+      [self->column setValue:[self->_cols objectAtIndex:i]
+                    inComponent:sComponent];
+      
+      [self->template appendToResponse:_response inContext:_ctx];
+    }
+    [_response appendContentString:@"</tr>"];
+  }
+  
+  /* body rows */
+  {
+    unsigned y, width, height;
+
+    width  = [self->_cols count];
+    height = [self->_rows count];
+    
+    for (y = 0; y < height; y++) { /* foreach row */
+      NSArray  *rowSpans;
+      unsigned i, count;
+      
+      /* apply context */
+      [self->row setValue:[self->_rows objectAtIndex:y]
+                 inComponent:self->component];
+
+      /* get span */
+      rowSpans = [_spans objectAtIndex:y];
+      count    = [rowSpans count];
+
+      /* begin first row */
+      [_response appendContentString:@"<tr>"];
+
+      /* left edge */
+      {
+        char     buf[64];
+        NSString *s;
+      
+        sprintf(buf, "%d", count);
+        s = [[StrClass alloc] initWithCString:buf];
+        [_ctx setObject:s forKey:WETableMatrix_RowSpan];
+        
+        [_ctx setObject:@"left" forKey:WETableMatrix_Mode];
+        
+        [_ctx setObject:numForUInt(y) forKey:WETableMatrix_Index];        
+        [self->template appendToResponse:_response inContext:_ctx];
+        [s release]; s = nil;
+        [_ctx removeObjectForKey:WETableMatrix_RowSpan];
+      }
+#if 0 /* hh: why is this commented out ? */
+      /* left label ? */
+      [_response appendContentString:@"<td"];
+      if (count > 1) {
+        NSString *s;
+
+        [_response appendContentString:@" rowspan=\""];
+        s = [[StrClass alloc] initWithFormat:@"%d", count];
+        [_response appendContentString:s];
+        [s release];
+        [_response appendContentString:@"\""];
+      }
+      [_response appendContentString:@">"];
+      [genLabel];
+      [_response appendContentString:@"</td>"];
+#endif
+      
+      /* check for empty span */
+      if (count == 0) {
+        NSString *s;
+
+        s = [[StrClass alloc] initWithFormat:@"%d", width];
+        
+        /* max rowspan, only encode in first row */
+        [_ctx setObject:@"empty" forKey:WETableMatrix_Mode];
+        [_ctx setObject:s forKey:WETableMatrix_ColSpan];
+        [self->template appendToResponse:_response inContext:_ctx];
+        [_ctx removeObjectForKey:WETableMatrix_ColSpan];
+#if 0 /* hh: why is this commented out ? */
+        
+        [_response appendContentString:@"<td colspan=\""];
+        [_response appendContentString:s];
+        [_response appendContentString:@"\">&nbsp;</td>"];
+        
+        /* close completly filled row */
+        [_response appendContentString:@"</tr>"];
+#endif
+        [s release];
+        continue;
+      }
+      
+      /* first span (same row like vertical label) */
+      if (count > 0) {
+        NSArray *thread;
+        
+        thread = [rowSpans objectAtIndex:0];
+
+        [self appendVerticalSpan:thread
+              toResponse:_response
+              inContext:_ctx];
+      }
+      /* close first row */
+      [_response appendContentString:@"</tr>"];
+
+      for (i = 1; i < count; i++) { /* foreach additional span */
+        NSArray *thread;
+        
+        thread = [rowSpans objectAtIndex:i];
+
+        [_response appendContentString:@"<tr>"];
+        
+        [self appendVerticalSpan:thread
+              toResponse:_response
+              inContext:_ctx];
+        
+        [_response appendContentString:@"</tr>"];
+      }
+      [_ctx removeObjectForKey:WETableMatrix_ColSpan];
+    }
+  }
+  
+  /* footer row */
+  
+  if ([self->subElems containsObject:@"bottom"]) {
+    unsigned i, count;
+    
+    [_response appendContentString:@"<tr>"];
+    
+    /* edge */
+    if ([self->subElems containsObject:@"left"])
+      [_response appendContentString:@"<td>&nbsp;</td>"];
+    
+    /* footer */
+    
+    [_ctx setObject:@"bottom" forKey:WETableMatrix_Mode];
+    
+    count = [self->_cols count];
+    
+    for (i = 0; i < count; i++) {
+      [_ctx setObject:numForUInt(i) forKey:WETableMatrix_Index];
+      
+      [self->column setValue:[self->_cols objectAtIndex:i]
+                    inComponent:sComponent];
+      
+      [self->template appendToResponse:_response inContext:_ctx];
+    }
+    [_response appendContentString:@"</tr>"];
+  }
+}
+
+@end /* WEVSpanTableMatrix */
diff --git a/skyrix-sope/WEExtensions/WETableMatrixContent.m b/skyrix-sope/WEExtensions/WETableMatrixContent.m
new file mode 100644 (file)
index 0000000..3eddb77
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WETableMatrixContentImp : WODynamicElement
+{
+  WOAssociation *elementName;
+  WOAssociation *rowspan;     /* a write variable */
+  WOAssociation *colspan;     /* a write variable */
+  
+  WOElement     *template;
+}
+@end
+
+@interface WETableMatrixContent : WETableMatrixContentImp
+@end
+
+@interface WETableMatrixNoContent : WETableMatrixContentImp
+@end
+
+#include <NGObjWeb/NGObjWeb.h>
+#include "common.h"
+
+@implementation WETableMatrixContentImp
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->elementName = WOExtGetProperty(_config, @"elementName");
+    self->rowspan     = WOExtGetProperty(_config, @"rowspan");
+    self->colspan     = WOExtGetProperty(_config, @"colspan");
+    
+    self->template = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->rowspan);
+  RELEASE(self->colspan);
+  RELEASE(self->elementName);
+  RELEASE(self->template);
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)modeKey {
+  [self logWithFormat:@"ERROR: subclasses should override -modeKey!"];
+  return nil;
+}
+
+/* response generation */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  id       tmp;
+  NSString *tag;
+  int      cspan, rspan;
+  
+  if ((tmp = [_ctx valueForKey:@"WETableMatrix_Query"])) {
+    [tmp addObject:[self modeKey]];
+    return;
+  }
+  
+  if ((tmp = [_ctx valueForKey:@"WETableMatrix_Mode"]) == nil)
+    return;
+
+  if (![tmp isEqualToString:[self modeKey]])
+    return;
+
+  cspan = [[_ctx objectForKey:@"WETableMatrix_ColSpan"] intValue];
+  if (cspan < 1) cspan = 1;
+  rspan = [[_ctx objectForKey:@"WETableMatrix_RowSpan"] intValue];
+  if (rspan < 1) rspan = 1;
+  
+  if ([self->colspan isValueSettable]) {
+    [self->colspan setValue:[NSNumber numberWithInt:cspan]
+                   inComponent:[_ctx component]];
+  }
+  if ([self->rowspan isValueSettable]) {
+    [self->rowspan setValue:[NSNumber numberWithInt:rspan]
+                   inComponent:[_ctx component]];
+  }
+  
+  tag = [self->elementName stringValueInComponent:[_ctx component]];
+
+  if (tag) {
+    NSString *s;
+    char buf[64];
+    
+    [_response appendContentString:@"<"];
+    [_response appendContentString:tag];
+
+    if (cspan > 1) {
+      sprintf(buf, "%i", cspan);
+      s = [[NSString alloc] initWithCString:buf];
+      [_response appendContentString:@" colspan=\""];
+      [_response appendContentString:s];
+      [_response appendContentString:@"\""];
+      [s release];
+    }
+    if (rspan > 1) {
+      sprintf(buf, "%i", rspan);
+      s = [[NSString alloc] initWithCString:buf];
+      [_response appendContentString:@" rowspan=\""];
+      [_response appendContentString:s];
+      [_response appendContentString:@"\""];
+      [s release];
+    }
+
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    
+    [_response appendContentString:@">"];
+  }
+  
+  [self->template appendToResponse:_response inContext:_ctx];
+
+  if (tag) {
+    [_response appendContentString:@"</"];
+    [_response appendContentString:tag];
+    [_response appendContentString:@">"];
+  }
+}
+
+@end /* WETableMatrixContentImp */
+
+@implementation WETableMatrixContent
+
+- (NSString *)modeKey {
+  return @"content";
+}
+
+@end /* WETableMatrixContent */
+
+@implementation WETableMatrixNoContent
+
+- (NSString *)modeKey {
+  return @"empty";
+}
+
+@end /* WETableMatrixNoContent */
diff --git a/skyrix-sope/WEExtensions/WETableMatrixLabel.m b/skyrix-sope/WEExtensions/WETableMatrixLabel.m
new file mode 100644 (file)
index 0000000..ff8581c
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WETableMatrixLabel : WODynamicElement
+{
+  WOAssociation *position;    /* top, bottom, left, right, topleft */
+  WOAssociation *elementName;
+  WOAssociation *span;
+  WOAssociation *string;
+  
+  WOElement     *template;
+}
+@end
+
+#include <NGObjWeb/NGObjWeb.h>
+#include "common.h"
+
+@implementation WETableMatrixLabel
+
+static Class    StrClass  = Nil;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  if (didInit) return;
+  didInit = YES;
+  
+  StrClass = [NSString class];
+}
+
+static NSString *retStrForInt(int i) {
+  switch(i) {
+  case 0:  return @"0";
+  case 1:  return @"1";
+  case 2:  return @"2";
+  case 3:  return @"3";
+  case 4:  return @"4";
+  case 5:  return @"5";
+  case 6:  return @"6";
+  case 7:  return @"7";
+  case 8:  return @"8";
+  case 9:  return @"9";
+  case 10: return @"10";
+    // TODO: find useful count!
+  default:
+    return [[StrClass alloc] initWithFormat:@"%i", i];
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])) {
+    self->position = WOExtGetProperty(_config, @"position");
+    if (self->position == nil)
+      self->position = [[WOAssociation associationWithValue:@"top"] retain];
+
+    self->elementName = WOExtGetProperty(_config, @"elementName");
+    self->span        = WOExtGetProperty(_config, @"span");
+    self->string      = WOExtGetProperty(_config, @"string");
+    
+    self->template = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->string      release];
+  [self->span        release];
+  [self->elementName release];
+  [self->position    release];
+  [self->template    release];
+  [super dealloc];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *pos;
+  id       tmp;
+  NSString *tag;
+  int      ispan;
+  
+  pos = [self->position stringValueInComponent:[_ctx component]];
+  
+  if ((tmp = [_ctx valueForKey:@"WETableMatrix_Query"])) {
+    [tmp addObject:pos];
+    return;
+  }
+
+  if ((tmp = [_ctx valueForKey:@"WETableMatrix_Mode"]) == nil)
+    return;
+
+  if (![tmp isEqualToString:pos])
+    return;
+
+  /* check span (some kind of condition) */
+  
+  ispan = [self->span intValueInComponent:[_ctx component]];
+  if (ispan < 1) ispan = 1;
+  
+  if (ispan > 1) {
+    int idx;
+
+    idx = [[_ctx objectForKey:@"WETableMatrix_Index"] intValue];
+    if (idx % ispan != 0)
+      /* the label is not active in that column/row */
+      return;
+  }
+  else if (ispan < 1)
+    ispan = 1;
+  
+  tag = [self->elementName stringValueInComponent:[_ctx component]];
+  
+  if (tag) {
+    NSString *s;
+    int rspan, cspan;
+    
+    [_response appendContentString:@"<"];
+    [_response appendContentString:tag];
+    
+    rspan = [[_ctx objectForKey:@"WETableMatrix_RowSpan"] intValue];
+    cspan = [[_ctx objectForKey:@"WETableMatrix_ColSpan"] intValue];
+    
+    if (rspan > 1) {
+      [_response appendContentString:@" rowspan=\""];
+      s = retStrForInt(rspan);
+      [_response appendContentString:s];
+      [s release];
+      [_response appendContentString:@"\""];
+    }
+    if (cspan > 1) {
+      [_response appendContentString:@" colspan=\""];
+      s = retStrForInt(cspan);
+      [_response appendContentString:s];
+      [s release];
+      [_response appendContentString:@"\""];
+    }
+    
+    if (ispan > 1) {
+      if ([tmp isEqualToString:@"bottom"] || [tmp isEqualToString:@"top"]) {
+        [_response appendContentString:@" colspan=\""];
+        NSAssert(cspan <= 1, @"double row-span !!");
+      }
+      else {
+        [_response appendContentString:@" rowspan=\""];
+        NSAssert(rspan <= 1, @"double row-span !!");
+      }
+      s = retStrForInt(ispan);
+      [_response appendContentString:s];
+      [s release];
+      [_response appendContentString:@"\""];
+    }
+
+    if ([tmp isEqualToString:@"top"]) {
+      int    count;
+      double width;
+      char   buf[64];
+      NSString *s;
+
+      count = [[_ctx objectForKey:@"WETableMatrix_Count"] intValue];
+      width = 100.0 / ((double)count / (double)ispan);
+      
+      sprintf(buf, "%.0f", width);
+      s = [[StrClass alloc] initWithCString:buf];
+      
+      [_response appendContentString:@" width=\""];
+      [_response appendContentString:s];
+      [_response appendContentString:@"%\""];
+      
+      [s release];
+    }
+    
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    [_response appendContentString:@">"];
+  }
+  
+  if (self->string) {
+    NSString *s;
+    s = [self->string stringValueInComponent:[_ctx component]];
+    [_response appendContentHTMLString:s];
+  }
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  if (tag) {
+    [_response appendContentString:@"</"];
+    [_response appendContentString:tag];
+    [_response appendContentString:@">"];
+  }
+}
+
+@end /* WETableMatrixLabel */
diff --git a/skyrix-sope/WEExtensions/WETableView/.cvsignore b/skyrix-sope/WEExtensions/WETableView/.cvsignore
new file mode 100644 (file)
index 0000000..52c916d
--- /dev/null
@@ -0,0 +1 @@
+Resources
diff --git a/skyrix-sope/WEExtensions/WETableView/GNUmakefile b/skyrix-sope/WEExtensions/WETableView/GNUmakefile
new file mode 100644 (file)
index 0000000..c6dfbbc
--- /dev/null
@@ -0,0 +1,29 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = WETableView
+
+WETableView_OBJC_FILES = \
+       WETableCell.m           \
+       WETableData.m           \
+       WETableHeader.m         \
+       WETableView.m           \
+       WETableView+Grouping.m  \
+       \
+       WETableViewState.m              \
+       WETableViewConfigObject.m       \
+       WETableViewColorConfig.m        \
+       WETableViewIconConfig.m         \
+       WETableViewLabelConfig.m        \
+       \
+       WETableViewButtonMode.m \
+       WETableViewFooterMode.m \
+       WETableViewGroupMode.m  \
+       WETableViewTitleMode.m  \
+
+ADDITIONAL_INCLUDE_DIRS += -I. -I.. -I../.. -I../../NGObjWeb
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/WEExtensions/WETableView/README b/skyrix-sope/WEExtensions/WETableView/README
new file mode 100644 (file)
index 0000000..03b314a
--- /dev/null
@@ -0,0 +1,28 @@
+# $Id$
+
+WETableView
+===========
+
+TODO: write some documentation how it works, what it supports, etc ...
+
+Capabilities
+============
+
+- grouping! That is, you can join rows in row-groups which can be 
+  expanded/collapsed
+- checkbox handling
+
+FAQ
+===
+
+Q: How do I enable checkboxes?
+A: Place the tableview inside a WOForm, then set the "selection" binding to
+   an NSArray ivar in your component.
+   Everything else should work out of the box.
+
+Q: Whats is the difference between WETableView and SkyTableView as used in OGo?
+A: The SkyTableView is a component wrapping WETableView. Besides utomatically
+   binding the icons and colors of the WETableView, it also provides some
+   advanced functionality like shift-select checkboxes as well as datasource
+   support.
+   Note: 'selection' is called 'selections' in the SkyTableView ...
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableCell.h b/skyrix-sope/WEExtensions/WETableView/WETableCell.h
new file mode 100644 (file)
index 0000000..83624df
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __WETableCell_H__
+#define __WETableCell_H__
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WETableCell : WODynamicElement
+{
+@protected
+  WOAssociation *sortKey;  
+  WOAssociation *negateSortDir;    // if YES, default sort dir is NSDescending
+
+  WOAssociation *bgColor;          // background color
+  WOAssociation *upwardSortIcon;
+  WOAssociation *downwardSortIcon;
+  WOAssociation *nonSortIcon;  
+  WOAssociation *sortLabel;
+
+  WOElement     *template;
+}
+- (void)appendSortIcon:(WOResponse *)_response inContext:(WOContext *)_ctx;
+@end
+
+#endif /* __WETableCell_H__ */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableCell.m b/skyrix-sope/WEExtensions/WETableView/WETableCell.m
new file mode 100644 (file)
index 0000000..3796fda
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WETableCell.h"
+#include "WETableView.h"
+#include "common.h"
+#include <NGObjWeb/NGObjWeb.h>
+
+@implementation WETableCell
+
+static NSNumber *YesNumber = nil;
+static NSNumber *NoNumber  = nil;
+
++ (void)initialize {
+  if (YesNumber == nil) YesNumber = [[NSNumber numberWithBool:YES] retain];
+  if (NoNumber  == nil) NoNumber  = [[NSNumber numberWithBool:NO]  retain];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->sortKey          = WOExtGetProperty(_config, @"sortKey");
+    self->negateSortDir    = WOExtGetProperty(_config, @"negateSortDir");
+    
+    self->bgColor          = WOExtGetProperty(_config, @"bgColor");
+    self->upwardSortIcon   = WOExtGetProperty(_config, @"upwardSortIcon");
+    self->downwardSortIcon = WOExtGetProperty(_config, @"downwardSortIcon");
+    self->nonSortIcon      = WOExtGetProperty(_config, @"nonSortIcon");
+    self->sortLabel        = WOExtGetProperty(_config, @"sortLabel");
+    
+    self->template = [_c retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->sortKey);
+  RELEASE(self->negateSortDir);
+  RELEASE(self->bgColor);
+  RELEASE(self->upwardSortIcon);
+  RELEASE(self->downwardSortIcon);
+  RELEASE(self->nonSortIcon);
+  RELEASE(self->sortLabel);
+  RELEASE(self->template);
+  [super dealloc];
+}
+
+/* generating response */
+
+- (void)appendSortIcon:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSString    *icon = nil;
+  NSString    *nav  = nil;
+  BOOL        doForm;
+  NSString    *sortedKey;
+  NSString    *label;
+  NSString    *sk;
+  int         sortDir;
+  
+  doForm    = [_ctx isInForm];
+  cmp       = [_ctx component];
+  sortedKey = [_ctx objectForKey:WETableView_SORTEDKEY];
+  sk        = [self->sortKey stringValueInComponent:cmp];
+  
+  label     = [self->sortLabel stringValueInComponent:cmp];
+  label     = (label) ? label : WETableLabelForKey(@"sort", _ctx);
+
+  if (sk == nil)
+    return;
+
+  if (![sk isEqualToString:sortedKey])
+    sortDir = 0;
+  else if ( [_ctx objectForKey:WETableView_ISDESCENDING] == nil ||
+           [[_ctx objectForKey:WETableView_ISDESCENDING] boolValue])
+    sortDir = -1;
+  else
+    sortDir = 1;
+  
+  switch (sortDir) {
+    case  1: nav = @"down"; break;
+    case  0: nav = @"non";  break;
+    case -1: nav = @"up";   break;
+  }
+  switch (sortDir) {
+    case  1: icon = [self->downwardSortIcon stringValueInComponent:cmp]; break;
+    case  0: icon = [self->nonSortIcon      stringValueInComponent:cmp]; break;
+    case -1: icon = [self->upwardSortIcon   stringValueInComponent:cmp]; break;
+  }
+  if (!WEUriOfResource(icon,_ctx)) {
+    switch (sortDir) {
+      case  1: icon = [_ctx objectForKey:WETableView_downwardIcon]; break;
+      case  0: icon = [_ctx objectForKey:WETableView_nonSortIcon];  break;
+      case -1: icon = [_ctx objectForKey:WETableView_upwardIcon];   break;
+    }
+  }
+
+  icon   = WEUriOfResource(icon, _ctx);
+  doForm = doForm && (icon);
+
+#if 0
+  if (icon == nil)
+    return;
+#endif
+
+  // append something like that: sort.name.down
+  [_ctx appendElementIDComponent:@"sort"];
+  [_ctx appendElementIDComponent:sk];     // remember sortKey
+  [_ctx appendElementIDComponent:nav];    // remember sortDirection
+
+  // append as submit button
+  if (doForm) {
+    [_response appendContentString:@"<input type=\"image\" border=\"0\""];
+    [_response appendContentString:@" align=\"top\" name=\""];
+    [_response appendContentString:[_ctx elementID]];
+    [_response appendContentString:@"\" src=\""];
+    [_response appendContentString:icon];
+    [_response appendContentString:@"\" alt=\""];
+    [_response appendContentString:label];
+    [_response appendContentString:@"\" title=\""];
+    [_response appendContentString:label];
+    [_response appendContentString:@"\" />"];
+  }
+  /* append as hyperlink */
+  else {
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentString:@"\">"];
+
+    if (icon) {
+      [_response appendContentString:@"<img border=\"0\" src=\""];
+      [_response appendContentString:icon];
+      [_response appendContentString:@"\" alt=\""];
+      [_response appendContentString:label];
+      [_response appendContentString:@"\" title=\""];
+      [_response appendContentString:label];
+      [_response appendContentString:@"\" align=\"top\" />"];
+    }
+    else {
+      switch (sortDir) {
+        case  1: [_response appendContentString:@"&uarr;"]; break;
+        case  0: [_response appendContentString:@"-"]; break;
+        case -1: [_response appendContentString:@"&darr;"]; break;
+      }
+    }
+    [_response appendContentString:@"</a>"];
+  }
+  [_ctx deleteLastElementIDComponent];
+  [_ctx deleteLastElementIDComponent];
+  [_ctx deleteLastElementIDComponent];
+
+  return;
+}
+
+/* processing request */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSString *k;
+
+  k = [self->sortKey stringValueInComponent:[_ctx component]];
+
+  if (k && [[_ctx objectForKey:WETableView_HeaderMode] boolValue]) {
+    NSString *tmp;
+    
+    tmp = [[_ctx elementID] stringByAppendingFormat:@".sort.%@.", k];
+
+    if ([_req formValueForKey:[tmp stringByAppendingString:@"down.x"]]) {
+      [_ctx addActiveFormElement:self];
+      [_ctx setRequestSenderID:[tmp stringByAppendingString:@"down"]];
+    }
+    else if ([_req formValueForKey:[tmp stringByAppendingString:@"up.x"]]) {
+      [_ctx addActiveFormElement:self];
+      [_ctx setRequestSenderID:[tmp stringByAppendingString:@"up"]];
+    }
+    else if ([_req formValueForKey:[tmp stringByAppendingString:@"non.x"]]) {
+      [_ctx addActiveFormElement:self];
+      [_ctx setRequestSenderID:[tmp stringByAppendingString:@"non"]];
+    }
+    else
+      [self ->template takeValuesFromRequest:_req inContext:_ctx];
+  }
+  else if (![[_ctx objectForKey:WETableView_HeaderMode] boolValue])
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  WOComponent *cmp   = nil;
+  NSString    *k, *tmp;
+  BOOL        doNegate;
+  
+  cmp = [_ctx component];
+  k   = [self->sortKey stringValueInComponent:cmp];
+  if (!([[_ctx currentElementID] isEqual:@"sort"] && k != nil))
+    return [self->template invokeActionForRequest:_request inContext:_ctx];
+    
+  [_ctx consumeElementID];                 // consume "sort"
+  [_ctx appendElementIDComponent:@"sort"]; // append  "sort"
+  
+  tmp = [_ctx currentElementID];
+  if (!(tmp != nil && [tmp isEqualToString:k])) {
+    [_ctx deleteLastElementIDComponent]; // 'sort'
+    return nil;
+  }
+  
+  doNegate = [[self->negateSortDir valueInComponent:cmp] boolValue];
+
+  [_ctx consumeElementID];               // consume sortKey
+  [_ctx appendElementIDComponent:k];     // append  sortKey
+  [_ctx setObject:k forKey:WETableView_SORTEDKEY];
+
+  tmp = [_ctx currentElementID];
+
+  if ([tmp isEqualToString:@"down"])
+    [_ctx setObject:YesNumber forKey:WETableView_ISDESCENDING];
+  else if ([tmp isEqualToString:@"up"])
+    [_ctx setObject:NoNumber forKey:WETableView_ISDESCENDING];
+  else if ([tmp isEqualToString:@"non"])
+    [_ctx setObject:[NSNumber numberWithBool:doNegate]
+             forKey:WETableView_ISDESCENDING];
+  else {
+    [_ctx removeObjectForKey:WETableView_ISDESCENDING];
+    [_ctx removeObjectForKey:WETableView_SORTEDKEY];
+  }
+  [_ctx deleteLastElementIDComponent]; // sortKey
+  [_ctx deleteLastElementIDComponent]; // 'sort'
+  
+  return nil;
+}
+
+@end /* WETableCell */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableData.m b/skyrix-sope/WEExtensions/WETableView/WETableData.m
new file mode 100644 (file)
index 0000000..95f435c
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WETableCell.h"
+
+@interface WETableData : WETableCell
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *title;   // title
+  WOAssociation *align;   // align
+  WOAssociation *valign;  // valign
+  WOAssociation *isGroup; // show data content?
+}
+
+- (id)_initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c;
+
+@end /* WETableData */
+
+@interface _WEComplexTableData : WETableData
+{
+  WOAssociation *string;       // string content
+  WOAssociation *value;        // object content (can be formatted)
+  WOAssociation *numberformat; // string
+  WOAssociation *dateformat;   // string
+  WOAssociation *formatter;    // WO4: NSFormatter object
+  WOAssociation *action;       // 
+}
+
+@end
+
+#include "WETableView.h"
+#import "common.h"
+#import <Foundation/NSNumberFormatter.h>
+#import <Foundation/NSDateFormatter.h>
+
+@implementation WETableData
+
++ (int)version {
+  return [super version] + 1 /* v3 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)_initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->isGroup = WOExtGetProperty(_config, @"isGroup");
+    self->title   = WOExtGetProperty(_config, @"title");
+    self->align   = WOExtGetProperty(_config, @"align");
+    self->valign  = WOExtGetProperty(_config, @"valign");
+    if (self->valign == nil) {
+      self->valign = [WOAssociation associationWithValue:@"TOP"];
+      RETAIN(self->valign);
+    }
+  }
+  return self;
+}
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  /* cluster */
+  if (([_config objectForKey:@"string"] != nil) ||
+      ([_config objectForKey:@"value"] != nil)) {
+    RELEASE(self);
+    return [[_WEComplexTableData alloc] _initWithName:_name
+                                        associations:_config
+                                        template:_c];
+  }
+  else
+    return [self _initWithName:_name associations:_config template:_c];
+}
+
+- (void)dealloc {
+  RELEASE(self->title);
+  RELEASE(self->isGroup);
+  RELEASE(self->align);
+  RELEASE(self->valign);
+  [super dealloc];
+}
+
+- (void)_collectDataInContext:(WOContext *)_ctx {
+  WOComponent      *cmp;
+  NSMutableArray   *infos;
+  WETableViewInfo  *info;
+  NSString         *key;
+  NSString         *sortedKey;
+
+  cmp       = [_ctx component];
+  infos     = [_ctx objectForKey:WETableView_INFOS];
+  key       = [self->sortKey valueInComponent:cmp];
+  sortedKey = [_ctx objectForKey:WETableView_SORTEDKEY];
+
+
+  if (infos == nil) {
+    infos = [NSMutableArray array];
+    [_ctx setObject:infos forKey:WETableView_INFOS];
+  }
+  info = [[WETableViewInfo allocWithZone:[self zone]] init];
+  info->rowSpan  = 1;
+  info->isGroup  = [self->isGroup boolValueInComponent:cmp];
+  info->isSorted = (key != nil && sortedKey != nil && [key isEqual:sortedKey]);
+
+  [infos addObject:info];
+  AUTORELEASE(info);
+}
+
+- (void)_appendHeader:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSString    *bg; // bgcolor
+  NSString    *t;  // title
+  NSString    *tC, *tF, *tS; // text font attrtibutes
+  NSString    *a;  // align
+  BOOL        hasFont;
+
+  cmp = [_ctx component];
+  
+  tC  = [_ctx objectForKey:WETableView_fontColor];
+  tF  = [_ctx objectForKey:WETableView_fontFace];
+  tS  = [_ctx objectForKey:WETableView_fontSize];
+  a   = [self->align stringValueInComponent:cmp];
+
+  hasFont = (tC || tF || tS) ? YES : NO;
+
+  bg = [_ctx objectForKey:WETableView_headerColor];
+  t  = [self->title stringValueInComponent:cmp];
+
+  WEAppendTD(_response, a, nil, bg);                     // <td...>
+  [_response appendContentString:@"<nobr />"];
+  
+  [self appendSortIcon:_response inContext:_ctx];
+
+  if (t) {
+    if (hasFont)
+      WEAppendFont(_response, tC, tF, tS);               //   <font...>
+   
+    [_response appendContentString:@" <b>"];
+    [_response appendContentString:t];
+    [_response appendContentString:@"</b>"];
+
+    if (hasFont)
+      [_response appendContentString:@"</font>"];        //   </font>
+  }
+  [_response appendContentString:@"</nobr>"];
+  [_response appendContentString:@"</td>"];              // </td>
+}
+
+- (void)_appendStringContentToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+}
+
+- (void)_appendData:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  info:(WETableViewInfo *)_info
+{
+  if (!_info->isGroup) {
+    WOComponent *cmp = [_ctx component];
+    NSString    *bg  = [self->bgColor stringValueInComponent:cmp];
+    NSString    *a   = [self->align   stringValueInComponent:cmp];
+    NSString    *va  = [self->valign  stringValueInComponent:cmp];
+    NSString    *tC, *tF, *tS; // text font attrtibutes
+    BOOL        hasFont;
+    
+    tC  = [_ctx objectForKey:WETableView_fontColor];
+    tF  = [_ctx objectForKey:WETableView_fontFace];
+    tS  = [_ctx objectForKey:WETableView_fontSize];
+    hasFont = (tC || tF || tS) ? YES : NO;
+    
+    if (bg == nil) {
+      bg = (_info->isEven)
+        ? [_ctx objectForKey:WETableView_evenColor]
+        : [_ctx objectForKey:WETableView_oddColor];
+    }
+    
+    [_response appendContentString:@"<td "];          // <td...>
+    if (bg) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:bg];
+      [_response appendContentCharacter:'"'];
+    }
+    if (_info->rowSpan > 1) {
+      switch (_info->rowSpan) {
+      case 0:
+        [_response appendContentString:@" rowspan=\"0\""];
+        break;
+      case 1:
+        [_response appendContentString:@" rowspan=\"1\""];
+        break;
+      case 2:
+        [_response appendContentString:@" rowspan=\"2\""];
+        break;
+      default: {
+        NSString *s;
+        s = [[NSString alloc] initWithFormat:@"%i", _info->rowSpan];
+        [_response appendContentString:@" rowspan=\""];
+        [_response appendContentString:s];
+        [_response appendContentCharacter:'"'];
+        [s release];
+        break; }
+      }
+    }
+    if (a) {
+      [_response appendContentString:@" align=\""];
+      [_response appendContentString:a];
+      [_response appendContentCharacter:'"'];
+    }
+    if (va) {
+      [_response appendContentString:@" valign=\""];
+      [_response appendContentString:va];
+      [_response appendContentCharacter:'"'];
+    }
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    [_response appendContentCharacter:'>'];
+    
+    if (hasFont)
+      WEAppendFont(_response, tC, tF, tS);                      //   <font...>
+    [self->template appendToResponse:_response inContext:_ctx];
+
+    [self _appendStringContentToResponse:_response inContext:_ctx];
+    if (hasFont)
+      [_response appendContentString:@"</font>"];                 // </font>
+
+    [_response appendContentString:@"</td>"];                  // </td>
+  }
+}
+
+/* responder */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if ([_ctx objectForKey:WETableView_CollectMode]) {
+    [self _collectDataInContext:_ctx];
+    return;
+  }
+  
+  if ([_ctx objectForKey:WETableView_HeaderMode] && self->title) {
+    [self _appendHeader:_response inContext:_ctx];
+  }
+  else if ([[_ctx objectForKey:WETableView_DataMode] boolValue]) {
+    NSMutableArray *infos = nil;
+
+    infos  = [_ctx objectForKey:WETableView_INFOS];
+
+    if (infos != nil && [infos count] > 0) {
+      [self _appendData:_response inContext:_ctx info:[infos objectAtIndex:0]];
+      [infos removeObjectAtIndex:0];
+    }
+  }
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+                    inContext:(WOContext *)_ctx
+{
+  if ([[_ctx objectForKey:WETableView_DataMode] boolValue] ||
+      [[_ctx objectForKey:WETableView_HeaderMode] boolValue]) {
+    [super takeValuesFromRequest:_request inContext:_ctx];
+  }
+}
+
+@end /* WETableData */
+
+@implementation _WEComplexTableData
+
+- (id)_initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super _initWithName:_name associations:_config template:_c])) {
+    self->string       = WOExtGetProperty(_config, @"string");
+    self->value        = WOExtGetProperty(_config, @"value");
+    self->formatter    = WOExtGetProperty(_config, @"formatter");
+    self->numberformat = WOExtGetProperty(_config, @"numberformat");
+    self->dateformat   = WOExtGetProperty(_config, @"dateformat");
+    self->action       = WOExtGetProperty(_config, @"action");
+    
+    /* check formats */
+    {
+      int num = 0;
+      if (self->formatter)    num++;
+      if (self->numberformat) num++;
+      if (self->dateformat)   num++;
+      if (num > 1)
+        NSLog(@"WARNING: more than one formats specified in element %@", self);
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->formatter);
+  RELEASE(self->numberformat);
+  RELEASE(self->dateformat);
+  RELEASE(self->string);
+  RELEASE(self->value);
+  RELEASE(self->action);
+  [super dealloc];
+}
+
+- (void)_appendStringContentToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *cmp;
+  NSString    *s;
+  NSString    *tC, *tF, *tS; // text font attrtibutes
+  BOOL        hasFont;
+  
+  cmp = [_ctx component];
+
+  tC  = [_ctx objectForKey:WETableView_fontColor];
+  tF  = [_ctx objectForKey:WETableView_fontFace];
+  tS  = [_ctx objectForKey:WETableView_fontSize];
+  hasFont = (tC || tF || tS) ? YES : NO;
+  
+  if (self->action != nil) {
+    [_ctx appendElementIDComponent:@"act"];
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentString:@"\">"];
+  }
+  if (hasFont)
+    WEAppendFont(_response, tC, tF, tS);                      //   <FONT...>
+  
+  /* add value */
+  
+  if (self->value) {
+    NSFormatter *fmt = nil;
+    id          obj;
+    
+    obj = [self->value valueInComponent:cmp];
+
+    if (self->numberformat) {
+      fmt = AUTORELEASE([[NSNumberFormatter alloc] init]);
+      [(NSNumberFormatter *)fmt setFormat:
+                            [self->numberformat valueInComponent:cmp]];
+    }
+    else if (self->dateformat) {
+      fmt = [[NSDateFormatter alloc]
+                              initWithDateFormat:
+                              [self->dateformat valueInComponent:
+                                   cmp]
+                              allowNaturalLanguage:NO];
+      fmt = AUTORELEASE(fmt);
+    }
+    else if (self->formatter) {
+      fmt = [self->formatter valueInComponent:cmp];
+#ifdef DEBUG
+      if (fmt && ![fmt respondsToSelector:@selector(stringForObjectValue:)]) {
+        [cmp logWithFormat:
+                    @"invalid formatter determined by keypath %@: %@",
+                    self->formatter,
+                    fmt];
+      }
+#endif
+    }
+    
+    if (fmt)
+      obj = [fmt stringForObjectValue:obj];
+    
+    s = [obj stringValue];
+    
+    if (s) [_response appendContentHTMLString:s];
+  }
+  
+  /* add string */
+  
+  if (self->string) {
+    s = [self->string stringValueInComponent:cmp];
+    [_response appendContentHTMLString:s];
+  }
+  if (hasFont)
+    [_response appendContentString:@"</font>"];                 // </font>
+  
+  if (self->action) {
+    [_ctx deleteLastElementIDComponent]; // delete 'act'
+    [_response appendContentString:@"</a>"];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx
+{
+  NSString *eid;
+
+  eid = [_ctx currentElementID];
+
+  return ([eid isEqualToString:@"act"])
+    ? [self->action valueInComponent:[_ctx component]]
+    : [super invokeActionForRequest:_request inContext:_ctx];
+}
+
+@end /* _WEComplexTableData */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableHeader.m b/skyrix-sope/WEExtensions/WETableView/WETableHeader.m
new file mode 100644 (file)
index 0000000..325fc6d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WETableCell.h"
+
+@interface WETableHeader : WETableCell
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+}
+
+@end /* WETableHeader */
+
+#include "WETableView.h"
+#include "common.h"
+
+@implementation WETableHeader
+
+/* responder */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if ([[_ctx objectForKey:WETableView_HeaderMode] boolValue]) {
+    WOComponent *cmp = nil;
+    NSString    *bg  = nil;
+
+    cmp = [_ctx component];
+    bg  = [self->bgColor stringValueInComponent:cmp];
+
+    if (!bg)
+      bg = [_ctx objectForKey:WETableView_headerColor];
+  
+    [_response appendContentString:@"<td"];
+    if (bg) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:bg];
+      [_response appendContentCharacter:'"'];
+    }
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    if (self->otherTagString) {
+      [_response appendContentString:
+            [self->otherTagString stringValueInComponent:[_ctx component]]];
+    }
+    [_response appendContentString:@"><nobr>"];
+    [self appendSortIcon:_response inContext:_ctx];
+    [self->template appendToResponse:_response inContext:_ctx];
+  
+    [_response appendContentString:@"</nobr>"];
+    [_response appendContentString:@"</td>\n"];
+  }
+}
+
+@end /* WETableHeader */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableView+Grouping.h b/skyrix-sope/WEExtensions/WETableView/WETableView+Grouping.h
new file mode 100644 (file)
index 0000000..6f8eabe
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-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.
+*/
+#ifndef __WETableView_Grouping_H__
+#define __WETableView_Grouping_H__
+
+#include "WETableView.h"
+
+@class WORequest, WOContext, WOResponse;
+@class NSString, NSMutableArray;
+
+@interface WETableView(Grouping)
+
+- (id)invokeGrouping:(WORequest *)_request inContext:(WOContext *)_ctx;
+- (void)_appendGroupTitle:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  infos:(NSMutableArray *)_infos
+  actionUrl:(NSString *)_actionUrl
+  rowSpan:(unsigned)_rowSpan
+  groupId:(NSString *)_groupId;
+
+@end
+
+#endif /*__WETableView_Grouping_H__*/
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableView+Grouping.m b/skyrix-sope/WEExtensions/WETableView/WETableView+Grouping.m
new file mode 100644 (file)
index 0000000..fbc0e50
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WETableView+Grouping.h"
+#include "WETableView.h"
+#include "common.h"
+
+@implementation WETableView(Grouping)
+
+- (id)invokeGrouping:(WORequest *)_request inContext:(WOContext *)_ctx {
+  NSString *stateId;
+
+  if ((stateId = [[_ctx currentElementID] stringValue]) == nil)
+    return nil;
+  
+  if ([stateId isEqualToString:@"e"]) {
+    if ([self->showGroup isValueSettable])
+      [self->showGroup setBoolValue:NO inComponent:[_ctx component]];
+    return nil;
+  }
+  else if ([stateId isEqualToString:@"c"]) {
+    if ([self->showGroup isValueSettable])
+      [self->showGroup setBoolValue:YES inComponent:[_ctx component]];
+    return nil;
+  }
+  
+  return [self->template invokeActionForRequest:_request inContext:_ctx];
+}
+
+- (void)_appendGroupTitle:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  infos:(NSMutableArray *)_infos
+  actionUrl:(NSString *)_actionUrl
+  rowSpan:(unsigned)_rowSpan
+  groupId:(NSString *)_groupId
+{
+  NSString    *bgcolor;
+  BOOL        isCollapsed;
+  WOComponent *comp;
+  NSString    *img;
+  int         colspan;
+  unsigned char buf[16];
+  
+  comp = [_ctx component];
+
+  [_ctx removeObjectForKey:WETableView_INFOS];
+  colspan  = [_infos count] - 2;
+  colspan += (self->state->doCheckBoxes) ? 1 : 0;
+
+  isCollapsed = ![self->showGroup boolValueInComponent:comp];
+  
+  [_response appendContentString:@"<tr><td colspan=\""];
+  sprintf(buf, "%d", colspan);
+  [_response appendContentCString:buf];
+  [_response appendContentCharacter:'"'];
+  
+  if ((bgcolor = [self->groupColor stringValueInComponent:comp])) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentString:bgcolor];
+    [_response appendContentCharacter:'"'];
+  }
+  [_response appendContentString:@"width=\"1%\">"];
+      
+  [_ctx setObject:@"Yes" forKey:WETableView_GroupMode];
+  
+  img = (!isCollapsed)
+    ? [self->groupOpenedIcon stringValueInComponent:comp]
+    : [self->groupClosedIcon stringValueInComponent:comp];
+
+  img = WEUriOfResource(img, _ctx);
+  
+  [_ctx appendElementIDComponent:(isCollapsed) ? @"c" : @"e"];
+
+  if (!self->state->doScriptCollapsing) {
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentString:@"\">"];
+  }
+
+  if (img) {
+    [_response appendContentString:@"<img border=\"0\" src=\""];
+    [_response appendContentString:img];
+    [_response appendContentCharacter:'"'];
+    if (self->state->doScriptCollapsing) {
+      NSString *openImg;
+      NSString *closeImg;
+
+      openImg  = [self->groupOpenedIcon stringValueInComponent:comp];
+      closeImg = [self->groupClosedIcon stringValueInComponent:comp];
+
+      openImg  = WEUriOfResource(openImg, _ctx);
+      closeImg = WEUriOfResource(closeImg, _ctx);
+
+      openImg  = (openImg) ? openImg : closeImg;
+      closeImg = (closeImg) ? closeImg : openImg;
+      
+      [_response appendContentString:@" onClick=\"toggleTableGroup();\""];
+      [_response appendContentString:@" group=\""];
+      [_response appendContentString:_groupId];
+      [_response appendContentString:@"\" openImg=\""];
+      [_response appendContentString:openImg];
+      [_response appendContentString:@"\" closeImg=\""];
+      [_response appendContentString:closeImg];
+      [_response appendContentCharacter:'"'];
+      if (isCollapsed)
+        [_response appendContentString:@" isGroupVisible=\"none\""];
+      else
+        [_response appendContentString:@" isGroupVisible=\"\""];
+    }
+    [_response appendContentString:@">"];
+  }
+  else
+    [_response appendContentString:(isCollapsed) ? @"[+]" : @"[-]"];
+  if (!self->state->doScriptCollapsing)
+    [_response appendContentString:@"</a>&nbsp;"];
+
+  [_ctx deleteLastElementIDComponent];
+
+  if ([self->groups isValueSettable]) {
+    NSAssert(([_infos count] > 1), @"info count must be at least 2");
+    [self->groups setValue:[_infos objectAtIndex:[_infos count]-1]
+               inComponent:comp];
+  }
+  
+  [_ctx setObject:@"YES" forKey:WETableView_GroupMode];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx removeObjectForKey:WETableView_GroupMode];
+
+  [_response appendContentString:@"</td>"];
+
+  if (_rowSpan) {
+    [self _appendBatchResizeButtons:_response
+                            rowSpan:_rowSpan
+                          actionUrl:_actionUrl
+                          inContext:_ctx];
+  }
+  [_response appendContentString:@"</tr>"];
+  [_infos removeLastObject]; // groups
+  [_infos removeLastObject]; // WETableView_GroupMode
+}
+
+@end /* WOComponentContent */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableView.h b/skyrix-sope/WEExtensions/WETableView/WETableView.h
new file mode 100644 (file)
index 0000000..8d715c2
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WETableView_H__
+#define __WETableView_H__
+
+#include <NGObjWeb/WODynamicElement.h>
+
+/*
+  
+  WETableView attributes:
+    
+    list          - list to iterate through                          (NSArray)
+    batchSize     - size of a page                                   (unsigned)
+    currentBatch  - current page                                     (unsigned)
+    
+    item          - current item                                     (id)
+    index         - current item index                               (unsigned)
+    identifier    - unique id for element                            (id)
+    previousItem  - previous item       // used to calculate groupBy (id)
+    previousIndex - previous item index // used to calculate groupBy (unsigned)
+    
+    indexOfFirst  - index of first item of current page              (unsigned)
+    indexOfLast   - index of last  item of current page              (unsigend)
+    
+    sortedKey     -                                                  (NSString)
+    isDescending  - sort descending                                  (BOOL)
+    groups        -                                                  (id)
+    showGroup     -                                                  (BOOL)
+
+    collapseOnClient       - use JavaScript for collapsing (only IE) (BOOL)
+    scrollOnClient         - use JavaScript for scrolling  (only IE) (BOOL)
+    autoScroll             - use overflow-scrolling        (only IE) (int)
+    showBatchResizeButtons - default = YES                           (BOOL)
+
+  WETableHeader attributes:
+   
+    sortKey       - unique key; if set, a sorticon will be displayed (NSString) 
+    negateSortDir - if YES, default sort dir is NSDescending         (BOOL)
+    bgColor       - background color                                 (NSString)
+    
+
+  WETableData attributes:
+  
+    sortKey       - unique key; if set, a sorticon will be displayed (NSString)
+    negateSortDir - if YES, default sort dir is NSDescending         (BOOL)
+    bgColor       - background color                                 (NSString)
+    title         - title of header -> no header cell is needed      (NSString)
+    isGroup       -
+  
+  WETableView config attributes:
+
+    titleColor
+    headerColor
+    footerColor
+    evenColor
+    oddColor
+    fontColor
+    fontFace
+    fontSize
+
+    nonSortIcon
+    downwardSortIcon
+    upwardSortIcon
+  
+    firstIcon
+    firstBlindIcon
+    previousIcon
+    previousBlindIcon
+    nextIcon
+    nextBlindIcon
+    lastIcon
+    lastBlindIcon
+
+    plusResizeIcon
+    minusResizeIcon
+
+    groupOpenedIcon
+    groupClosedIcon
+    ofLabel
+    toLabel
+    firstLabel
+    previousLabel
+    nextLabel
+    lastLabel
+    pageLabel
+    sortLabel
+
+    border
+    cellpadding
+    cellspacing
+   
+  WETableHeader, WETableData config attributes:
+  
+    upwardSortIcon;
+    downwardSortIcon;
+    nonSortIcon;
+    sortLabel;
+*/
+
+@class WETableViewLabelConfig, WETableViewIconConfig;
+@class WETableViewColorConfig, WETableViewIconConfig;
+@class WETableViewState;
+
+@interface WETableView : WODynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation  *list;           // list of objects
+  WOAssociation  *batchSize;      // batch size
+  WOAssociation  *currentBatch;   // index of the displayed batch
+  
+  WOAssociation  *item;           // current item in the array
+  WOAssociation  *index;          // current index
+  WOAssociation  *identifier;     // unique id for element
+  WOAssociation  *previousItem;   // predecessor of item  (used by isGroup)
+  WOAssociation  *previousIndex;  // predecessor of index (used by isGroup)
+
+  WOAssociation  *indexOfFirst;   // index of first displayed object
+  WOAssociation  *indexOfLast;    // index of last  displayed object
+  
+  WOAssociation  *sortedKey;      // 
+  WOAssociation  *isDescending;   //
+  WOAssociation  *groups;         //
+  WOAssociation  *showGroup;      //
+
+  WOAssociation  *selection;      // 
+
+  WOAssociation  *collapseOnClient; // use JS for collapsing default = NO
+  WOAssociation  *scrollOnClient;   // use JS for scrolling  default = NO
+  WOAssociation  *autoScroll;       // use overflow-scrolling (only IE)
+  WOAssociation  *showBatchResizeButtons; // 
+  
+  WOAssociation  *sortAction;     // called if sort     button is clicked
+  WOAssociation  *firstAction;    // called if first    button is clicked
+  WOAssociation  *previousAction; // called if previous button is clicked
+  WOAssociation  *nextAction;     // called if next     button is clicked
+  WOAssociation  *lastAction;     // called if last     button is clicked
+
+  // config stuff:
+  WETableViewColorConfig *colors;
+  WOAssociation  *groupColor;
+  WOAssociation  *fontColor;
+  WOAssociation  *fontFace;
+  WOAssociation  *fontSize;
+
+  WETableViewIconConfig *icons;
+  WOAssociation  *groupOpenedIcon;
+  WOAssociation  *groupClosedIcon;
+
+  WETableViewLabelConfig *labels;
+  
+  WOAssociation  *border;
+  WOAssociation  *cellspacing;
+  WOAssociation  *cellpadding;
+
+  WOAssociation  *showGroupTitle;
+  
+  // private stuff:
+  NSArray          *allObjects;
+  BOOL             doScript;       // generate JavaScript
+  NSString         *scriptID;      // to unify the JavaScript
+  WETableViewState *state;
+  WOElement        *template;
+}
+
+- (void)_appendHeader:(WOResponse *)_response inContext:(WOContext *)_ctx;
+- (void)_appendData:(WOResponse *)_response inContext:(WOContext *)_ctx;
+- (void)_appendFooter:(WOResponse *)_response inContext:(WOContext *)_ctx;
+
+- (void)updateStateInContext:(WOContext *)_ctx; // returns isAutoScroll
+
+@end /* WETableView */
+
+#include "WETableViewDefines.h"
+#include "WETableViewState.h"
+#include "WETableViewInfo.h"
+
+static inline NSString *WETableLabelForKey(NSString *_key, WOContext *_ctx)
+     __attribute__((unused));
+
+#include <NGObjWeb/WOContext.h>
+#import <Foundation/NSString.h>
+
+static NSString *WETableLabelForKey(NSString *_key, WOContext *_ctx) {
+  NSString *key;
+  id tmp;
+  
+  key = [[NSString alloc] initWithFormat:@"WETableView_%@Label", _key];
+  tmp = [_ctx objectForKey:key];
+  [key release];
+  return tmp;
+}
+
+@interface WETableView(Private)
+- (void)_appendBatchResizeButtons:(WOResponse *)_response
+  rowSpan:(unsigned int)_rowSpan
+  actionUrl:(NSString *)_actionUrl
+  inContext:(WOContext *)_ctx;
+@end /* WETableView(Private) */
+
+#endif /* __WETableView_H__ */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableView.m b/skyrix-sope/WEExtensions/WETableView/WETableView.m
new file mode 100644 (file)
index 0000000..caa01a2
--- /dev/null
@@ -0,0 +1,2018 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WETableView.h"
+#include "WETableView+Grouping.h"
+#include "WETableViewState.h"
+#include "WETableViewColorConfig.h"
+#include "WETableViewIconConfig.h"
+#include "WETableViewLabelConfig.h"
+
+#include "common.h"
+#include <NGObjWeb/NGObjWeb.h>
+#include <EOControl/EOSortOrdering.h>
+#include "WEContextConditional.h"
+
+@interface WETableView(JavaScriptAdditions)
+
+- (void)_appendGroupCollapseScript:(WOResponse *)_resp
+                         inContext:(WOContext *)_ctx;
+- (void)jsButton:(WOResponse *)_resp ctx:(WOContext *)_ctx
+  name:(NSString *)_name button:(NSString *)_button;
+
+- (void)appendJavaScript:(WOResponse *)_resp inContext:(WOContext *)_ctx;
+- (void)_appendTableContentAsScript:(WOResponse *)_resp
+  inContext:(WOContext *)_ctx;
+
+- (void)_appendScriptLink:(WOResponse *)_response name:(NSString *)_name;
+- (void)_appendScriptImgName:(WOResponse *)_response name:(NSString *)_name;
+
+@end
+
+#include "WEClientCapabilities.h"
+
+@implementation WETableView
+
+static NSNumber *YesNumber = nil;
+static NSNumber *NoNumber  = nil;
+static Class    StrClass   = Nil;
+static BOOL ShowNavigationAlways   = YES;
+static BOOL ShowNavigationInFooter = YES;
+
++ (int)version {
+  return [super version] + 1 /* v3 */;
+}
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+  
+  StrClass = [NSString class];
+  if (YesNumber == nil) YesNumber = [[NSNumber numberWithBool:YES] retain];
+  if (NoNumber  == nil) NoNumber  = [[NSNumber numberWithBool:NO]  retain];
+  
+  ShowNavigationAlways = [ud boolForKey:@"WETableView_showBlindNavigation"];
+}
+
+static NSString *retStrForInt(int i) {
+  switch(i) {
+  case 0:  return @"0";
+  case 1:  return @"1";
+  case 2:  return @"2";
+  case 3:  return @"3";
+  case 4:  return @"4";
+  case 5:  return @"5";
+  case 6:  return @"6";
+  case 7:  return @"7";
+  case 8:  return @"8";
+  case 9:  return @"9";
+  case 10: return @"10";
+    // TODO: find useful count!
+  default:
+    return [[StrClass alloc] initWithFormat:@"%i", i];
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->state = [[WETableViewState alloc] init];
+
+    self->list           = WOExtGetProperty(_config, @"list");
+    self->currentBatch   = WOExtGetProperty(_config, @"currentBatch");
+    self->batchSize      = WOExtGetProperty(_config, @"batchSize");
+    
+    self->item           = WOExtGetProperty(_config, @"item");
+    self->index          = WOExtGetProperty(_config, @"index");
+    self->identifier     = WOExtGetProperty(_config, @"identifier");
+    self->previousItem   = WOExtGetProperty(_config, @"previousItem");
+    self->previousIndex  = WOExtGetProperty(_config, @"previousIndex");
+    self->sortedKey      = WOExtGetProperty(_config, @"sortedKey");
+    self->isDescending   = WOExtGetProperty(_config, @"isDescending");
+    self->selection      = WOExtGetProperty(_config, @"selection");
+    self->groups         = WOExtGetProperty(_config, @"groups");
+    self->showGroup      = WOExtGetProperty(_config, @"showGroup");
+
+    // display state
+    self->indexOfFirst =
+      WOExtGetProperty(_config, @"indexOfFirstDisplayedObject");
+    self->indexOfLast  =
+      WOExtGetProperty(_config, @"indexOfLastDisplayedObject");
+
+    self->collapseOnClient = WOExtGetProperty(_config, @"collapseOnClient");
+    self->scrollOnClient   = WOExtGetProperty(_config, @"scrollOnClient");
+    self->autoScroll       = WOExtGetProperty(_config, @"autoScroll");
+    self->showBatchResizeButtons =
+      WOExtGetProperty(_config, @"showBatchResizeButtons");
+
+    // actions
+    self->sortAction     = WOExtGetProperty(_config, @"sortAction");
+    self->firstAction    = WOExtGetProperty(_config, @"firstAction");
+    self->previousAction = WOExtGetProperty(_config, @"previousAction");
+    self->nextAction     = WOExtGetProperty(_config, @"nextAction");
+    self->lastAction     = WOExtGetProperty(_config, @"lastAction");
+    
+    // config stuff:
+    self->colors = 
+      [[WETableViewColorConfig alloc] initWithAssociations:_config];
+    self->groupColor     = WOExtGetProperty(_config, @"groupColor");
+    self->fontColor      = WOExtGetProperty(_config, @"fontColor");
+    self->fontFace       = WOExtGetProperty(_config, @"fontFace");
+    self->fontSize       = WOExtGetProperty(_config, @"fontSize");
+
+    // icons:
+    self->icons = [[WETableViewIconConfig alloc] initWithAssociations:_config];
+    self->groupOpenedIcon = WOExtGetProperty(_config, @"groupOpenedIcon");
+    self->groupClosedIcon = WOExtGetProperty(_config, @"groupClosedIcon");
+    
+    // labels:
+    self->labels = 
+      [[WETableViewLabelConfig alloc] initWithAssociations:_config];
+
+    self->cellspacing    = WOExtGetProperty(_config, @"cellspacing");
+    self->cellpadding    = WOExtGetProperty(_config, @"cellpadding");
+    self->border         = WOExtGetProperty(_config, @"border");
+
+    self->showGroupTitle = WOExtGetProperty(_config, @"showGroupTitle");
+
+#define SetAssociationValue(_a_, _value_) \
+         if (_a_ == nil)                  \
+           _a_ = [[WOAssociation associationWithValue:_value_] retain];
+    
+    SetAssociationValue(self->cellspacing,   @"0");
+    SetAssociationValue(self->cellpadding,   @"1");
+    SetAssociationValue(self->border,        @"0");
+           
+#undef SetAssociationValue
+
+    if (self->list == nil) {
+      [self logWithFormat:@"ERROR: no 'list' binding is set!"];
+      [self release];
+      return nil;
+    }
+
+    self->state->doScriptScrolling = NO;
+    self->template = [_c retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->state  release];
+  [self->colors release];
+  [self->labels release];
+  [self->icons  release];
+
+  [self->list          release];
+  [self->currentBatch  release];
+  [self->batchSize     release];
+  
+  [self->item          release];
+  [self->index         release];
+  [self->identifier    release];
+  [self->previousItem  release];
+  [self->previousIndex release];
+  [self->sortedKey     release];
+  [self->isDescending  release];
+  [self->selection     release];
+  [self->groups        release];
+  [self->showGroup     release];
+
+  [self->indexOfFirst  release];
+  [self->indexOfLast   release];
+
+  [self->collapseOnClient release];
+  [self->scrollOnClient   release];
+  [self->autoScroll       release];
+  [self->showBatchResizeButtons release];
+  
+  [self->sortAction     release];
+  [self->firstAction    release];
+  [self->previousAction release];
+  [self->nextAction     release];
+  [self->lastAction     release];
+
+  [self->fontColor   release];
+  [self->fontFace    release];
+  [self->fontSize    release];
+
+  [self->groupColor      release];
+  [self->groupOpenedIcon release];
+  [self->groupClosedIcon release];
+  
+  [self->allObjects release];
+  [self->scriptID   release];
+  [self->template   release];
+
+  [self->cellpadding release];
+  [self->cellspacing release];
+  [self->border release];
+
+  [self->showGroupTitle release];
+
+  [super dealloc];
+}
+
+static inline void
+_applyIdentifier(WETableView *self, WOComponent *comp, NSString *_idx)
+{
+  unsigned count;
+  count = [self->allObjects count];
+
+  if (count > 0) {
+    unsigned i;
+
+    /* find subelement for unique id */
+    
+    for (i = 0; i < count; i++) {
+      NSString *ident;
+      
+      if (self->index)
+        [self->index setUnsignedIntValue:i inComponent:comp];
+
+      if (self->item) {
+        [self->item setValue:[self->allObjects objectAtIndex:i]
+                    inComponent:comp];
+      }
+      if ([self->previousItem isValueSettable]) {
+        [self->previousItem setValue:(i > self->state->firstIndex)
+             ? [self->allObjects objectAtIndex:i-1] : nil
+             inComponent:comp];
+      }
+      if ([self->previousIndex isValueSettable])
+        [self->previousIndex setUnsignedIntValue:(i-1) inComponent:comp];
+
+      ident = [self->identifier stringValueInComponent:comp];
+
+      if ([ident isEqualToString:_idx]) {
+        /* found subelement with unique id */
+        return;
+      }
+    }
+    
+    [comp logWithFormat:
+          @"WETableView: array did change, "
+          @"unique-id isn't contained."];
+    [self->item  setValue:nil          inComponent:comp];
+    [self->index setUnsignedIntValue:0 inComponent:comp];
+  }
+}
+
+static inline void _applyItems_(WETableView *self, WOComponent *cmp, int i) {
+  if ([self->index isValueSettable])
+    [self->index setUnsignedIntValue:i inComponent:cmp];
+  if ([self->item isValueSettable])
+    [self->item setValue:[self->allObjects objectAtIndex:i] inComponent:cmp];
+  if ([self->previousItem isValueSettable]) {
+    id value;
+
+    value = (i > (int)self->state->firstIndex) 
+      ? [self->allObjects objectAtIndex:(i - 1)] 
+      : nil;
+    [self->previousItem setValue:value inComponent:cmp];
+  }
+  if ([self->previousIndex isValueSettable])
+    [self->previousIndex setUnsignedIntValue:(i-1) inComponent:cmp];
+}
+
+static inline void _applyState_(WETableView *self, WOComponent *cmp) {
+  if ([self->currentBatch isValueSettable])
+    [self->currentBatch setUnsignedIntValue:self->state->currentBatch
+                                inComponent:cmp];
+}
+
+- (void)updateStateInContext:(WOContext *)_ctx {
+  WEClientCapabilities *ccaps;
+  BOOL        isAutoScroll;
+  WOComponent *cmp;
+  NSArray     *array;
+  unsigned    batchIdx, size, cnt;
+
+  cmp            = [_ctx component];
+  ccaps          = [[_ctx request] clientCapabilities];
+  isAutoScroll   = [ccaps doesSupportCSSOverflow];
+  self->state->doScriptScrolling  = [ccaps isInternetExplorer];
+  self->state->doScriptCollapsing = [ccaps isInternetExplorer];
+  if (self->state->doScriptCollapsing) {
+    self->state->doScriptCollapsing =
+      [self->collapseOnClient boolValueInComponent:cmp];
+  }
+
+  if ([[self->autoScroll valueInComponent:cmp] intValue] < 10)
+    isAutoScroll   = NO;
+  else if (isAutoScroll)
+    self->state->doScriptScrolling = NO;
+  
+  /* use JavaScript on InternetExplorer only */
+  self->state->doScriptScrolling = (self->state->doScriptScrolling)
+    ? (self->state->batchCount > 1)
+    : NO;
+  
+  self->state->doScriptScrolling = (self->state->doScriptScrolling)
+    ? [self->scrollOnClient boolValueInComponent:cmp]
+    : NO;
+  
+  array    = [self->list         valueInComponent:cmp];
+  batchIdx = [self->currentBatch unsignedIntValueInComponent:cmp];
+  size     = [self->batchSize    unsignedIntValueInComponent:cmp];
+  cnt      = [array count];
+  size     = (isAutoScroll) ? cnt : size;
+  batchIdx = (batchIdx) ? batchIdx : 1;
+  batchIdx = ((batchIdx * size) < (cnt+size)) ? batchIdx : 1;
+
+  ASSIGN(self->allObjects, array);
+
+  self->state->currentBatch = batchIdx;
+  self->state->batchSize    = size;
+  
+  self->state->batchCount = (!size) ? 1 :(cnt / size) + ((cnt % size) ? 1 : 0);
+  self->state->firstIndex = (batchIdx - 1) * size;
+  self->state->lastIndex  = 
+    (size == 0 || !((self->state->firstIndex+size) < cnt))
+    ? cnt-1
+    : self->state->firstIndex + size - 1;
+
+  if ([self->indexOfFirst isValueSettable]) {
+    [self->indexOfFirst setUnsignedIntValue:self->state->firstIndex
+                        inComponent:cmp];
+  }
+  
+  if ([self->indexOfLast isValueSettable]) {
+    [self->indexOfLast setUnsignedIntValue:self->state->lastIndex
+                       inComponent:cmp];
+  }
+  
+  self->state->doCheckBoxes = 
+    ([_ctx isInForm] && [self->selection isValueSettable]) ? YES : NO;
+  self->state->doOverflow = isAutoScroll;
+}
+
+- (void)updateScriptIdInContext:(WOContext *)_ctx {
+  NSArray  *tmp;
+  NSString *str;
+
+  tmp = [[_ctx elementID] componentsSeparatedByString:@"."];
+  str = [tmp componentsJoinedByString:@""];
+  
+  ASSIGN(self->scriptID, str);
+}
+
+- (void)updateConfigInContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSString    *tmp;
+
+  cmp = [_ctx component];
+  
+  [self->colors updateConfigInContext:_ctx];
+  [self->icons  updateConfigInContext:_ctx];
+  [self->labels updateConfigInContext:_ctx];
+  
+#define SetConfigInContext(_a_, _key_)                                  \
+      if (_a_ && (tmp = [_a_ valueInComponent:cmp]))                    \
+        [_ctx setObject:tmp forKey:_key_];                              \
+
+  SetConfigInContext(self->fontColor,       WETableView_fontColor);
+  SetConfigInContext(self->fontFace,        WETableView_fontFace);
+  SetConfigInContext(self->fontSize,        WETableView_fontSize);
+#undef SetConfigInContext
+}
+
+- (void)removeConfigInContext:(WOContext *)_ctx {
+  [_ctx removeObjectForKey:WETableView_titleColor];
+  [_ctx removeObjectForKey:WETableView_headerColor];
+  [_ctx removeObjectForKey:WETableView_footerColor];
+  [_ctx removeObjectForKey:WETableView_evenColor];
+  [_ctx removeObjectForKey:WETableView_oddColor];
+  [_ctx removeObjectForKey:WETableView_fontColor];
+  [_ctx removeObjectForKey:WETableView_fontFace];
+  [_ctx removeObjectForKey:WETableView_fontSize];
+  
+  [_ctx removeObjectForKey:WETableView_downwardIcon];
+  [_ctx removeObjectForKey:WETableView_upwardIcon];
+  [_ctx removeObjectForKey:WETableView_nonSortIcon];
+
+  [_ctx removeObjectForKey:WETableView_first];
+  [_ctx removeObjectForKey:WETableView_first_blind];
+  [_ctx removeObjectForKey:WETableView_previous];
+  [_ctx removeObjectForKey:WETableView_previous_blind];
+  [_ctx removeObjectForKey:WETableView_next];
+  [_ctx removeObjectForKey:WETableView_next_blind];
+  [_ctx removeObjectForKey:WETableView_last];
+  [_ctx removeObjectForKey:WETableView_last_blind];
+  [_ctx removeObjectForKey:WETableView_select_all];
+  [_ctx removeObjectForKey:WETableView_deselect_all];
+
+  [_ctx removeObjectForKey:WETableView_ofLabel];
+  [_ctx removeObjectForKey:WETableView_toLabel];
+  [_ctx removeObjectForKey:WETableView_firstLabel];
+  [_ctx removeObjectForKey:WETableView_previousLabel];
+  [_ctx removeObjectForKey:WETableView_nextLabel];
+  [_ctx removeObjectForKey:WETableView_lastLabel];
+  [_ctx removeObjectForKey:WETableView_pageLabel];
+  [_ctx removeObjectForKey:WETableView_sortLabel];
+}
+
+- (NSArray *)_collectDataInContext:(WOContext *)_ctx
+{
+  NSAutoreleasePool *pool;
+  NSMutableArray    *matrix    = nil;
+  NSMutableArray    *headInfos = nil;
+  NSString          *k         = nil;
+  WOComponent       *cmp       = nil;
+  id                oldGroup   = nil;
+  int               i, first, last;
+  int               sortedHeadIndex = -2;
+  
+  pool   = [[NSAutoreleasePool alloc] init];
+  cmp    = [_ctx component];
+  k      = [self->sortedKey stringValueInComponent:cmp];
+
+  first  = self->state->firstIndex;
+  last   = self->state->lastIndex;
+  matrix = [NSMutableArray arrayWithCapacity:last-first+1];
+
+  [_ctx setObject:YesNumber forKey:WETableView_CollectMode];
+  [_ctx setObject:k         forKey:WETableView_SORTEDKEY];
+
+  self->state->groupCount = 0;
+
+  for (i=first; i<=last; i++) {
+    NSMutableArray *infos = nil;
+    NSString       *tmp   = nil;
+
+    _applyItems_(self, cmp, i);
+    
+    [_ctx removeObjectForKey:WETableView_INFOS];
+    [self->template appendToResponse:nil inContext:_ctx];
+    infos = [_ctx objectForKey:WETableView_INFOS];
+
+    if (infos == nil)
+      infos = [NSArray array];
+
+    NSAssert(infos != nil, @"Infos is nil.");
+
+    if (headInfos == nil) {
+      unsigned j, cnt;
+      headInfos = [[NSMutableArray alloc] initWithArray:infos];
+
+      for (j=0, cnt=[headInfos count]; j<cnt; j++) {
+        WETableViewInfo *headInfo = [headInfos objectAtIndex:j];
+        
+        headInfo->isEven = (((i-first) % 2) == 0) ? YES : NO;
+      }
+    }
+    else {
+      unsigned j, cnt;
+      BOOL     isEven = NO;
+
+      cnt = [infos count];
+      
+      if (sortedHeadIndex == -2) { // first time
+        for (j=0; j < cnt; j++) {
+          WETableViewInfo *info;
+
+          info = [infos objectAtIndex:j];
+          if (info->isSorted) {
+            sortedHeadIndex = j;
+            break;
+          }
+        }
+        sortedHeadIndex = (sortedHeadIndex < 0) ? -1 : sortedHeadIndex;
+      }
+
+      if (cnt) {
+        WETableViewInfo *headInfo;
+        WETableViewInfo *info;
+
+        if (sortedHeadIndex >= 0) {
+          NSAssert(sortedHeadIndex < (int)cnt, 
+                   @"SortedHeadIndex out of range!!!");
+          headInfo = [headInfos objectAtIndex:sortedHeadIndex];
+          info     = [infos     objectAtIndex:sortedHeadIndex];
+          isEven = (!info->isGroup) ? !headInfo->isEven : headInfo->isEven;
+        }
+        else { // sortedHeadIndex == -1 --> no column is sorted
+          headInfo = [headInfos lastObject];
+          isEven = !headInfo->isEven;
+        }
+      }
+
+      for (j = 0; j < cnt; j++) {
+        WETableViewInfo *info     = [infos     objectAtIndex:j];
+        WETableViewInfo *headInfo = [headInfos objectAtIndex:j];
+
+        if (!info->isGroup || ((int)j != sortedHeadIndex)) {
+          info->isEven  = isEven;
+          info->isGroup = NO;
+          [headInfos replaceObjectAtIndex:j withObject:info];
+        }
+        else
+          headInfo->rowSpan++;
+      }
+    }
+    {
+      BOOL doGroupTitle = [self->showGroupTitle boolValueInComponent:cmp];
+
+      // insert groupMode (to render the group title)
+      tmp = [self->groups valueInComponent:cmp];
+      if ((tmp != nil) && ![oldGroup isEqual:tmp] && doGroupTitle) {
+        oldGroup = [self->groups valueInComponent:cmp];
+        self->state->groupCount++;
+        [infos addObject:tmp];
+        [infos addObject:WETableView_GroupMode];
+      }
+    }
+
+    [matrix addObject:infos];
+  }
+  [_ctx removeObjectForKey:WETableView_INFOS];
+  [_ctx removeObjectForKey:WETableView_CollectMode];
+  [_ctx removeObjectForKey:WETableView_SORTEDKEY];
+
+  matrix = [matrix retain];
+  [headInfos release];
+  [pool      release];
+
+  return [matrix autorelease];
+}
+
+- (void)_appendNav:(NSString *)_nav isBlind:(BOOL)_isBlind
+  toResponse:(WOResponse *)_response inContext:(WOContext *)_ctx
+{
+  NSString *imgUri;
+  NSString *label;
+  BOOL     doForm   = [_ctx isInForm];
+
+  imgUri = [WETableView_ stringByAppendingString:_nav];
+  imgUri = [imgUri stringByAppendingString:(_isBlind) ? @"_blind" : @""];
+  imgUri = [_ctx objectForKey:imgUri];
+  imgUri = WEUriOfResource(imgUri,_ctx);
+  
+  label  = WETableLabelForKey(_nav, _ctx);
+
+  [_response appendContentString:@"<td valign='middle' width='5'>"];
+  // append as submit button
+  if (doForm && !_isBlind && !self->state->doScriptScrolling && imgUri) {
+    [_ctx appendElementIDComponent:_nav];
+    [_response appendContentString:@"<input type=\"image\" border=\"0\""];
+    [_response appendContentString:@" name=\""];
+    [_response appendContentString:[_ctx elementID]];
+    [_response appendContentString:@"\" src=\""];
+    [_response appendContentString:imgUri];
+    [_response appendContentString:@"\" alt=\""];
+    [_response appendContentString:label];
+    [_response appendContentString:@"\" title=\""];
+    [_response appendContentString:label];
+    [_response appendContentString:@"\" />"];
+    [_ctx deleteLastElementIDComponent];
+    [_response appendContentString:@"</td>"];
+    return;
+  }
+
+  /* open anker */
+  if (!_isBlind || self->state->doScriptScrolling) {
+    [_ctx appendElementIDComponent:_nav];
+    [_response appendContentString:@"<a href=\""];
+    if (self->state->doScriptScrolling)
+      [self _appendScriptLink:_response name:_nav];
+    else
+      [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentString:@"\">"];
+  }
+  if (imgUri == nil) {
+    [_response appendContentCharacter:'['];
+    [_response appendContentString:label];
+    [_response appendContentCharacter:']'];
+  }
+  else {
+    [_response appendContentString:@"<img border=\"0\" src=\""];
+    [_response appendContentString:imgUri];
+    if (self->state->doScriptScrolling) {
+      [_response appendContentString:@"\" name=\""];
+      [self _appendScriptImgName:_response name:_nav];
+    }
+    [_response appendContentString:@"\" alt=\""];
+    [_response appendContentString:label];
+    [_response appendContentString:@"\" title=\""];
+    [_response appendContentString:label];
+    [_response appendContentString:@"\" />"];
+  }
+  /* close anker */
+  if (!_isBlind || self->state->doScriptScrolling) {
+    [_response appendContentString:@"</a>"];
+    [_ctx deleteLastElementIDComponent];
+  }
+  [_response appendContentString:@"</td>"];
+}
+
+- (void)_appendPreviousNav:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  int  batch, batchCount;
+  BOOL isFirstBlind, isPreviousBlind, isNextBlind, isLastBlind;
+  
+  batch      = self->state->currentBatch;
+  batchCount = self->state->batchCount;
+
+  isFirstBlind    = (batch < 2);
+  isPreviousBlind = (batch < 2);
+  isNextBlind     = ((batchCount-1) < batch);
+  isLastBlind     = ((batchCount-1) < batch);
+
+  if ((ShowNavigationAlways) ||
+      (!(isFirstBlind && isPreviousBlind && isNextBlind && isLastBlind))) {
+    [self _appendNav:@"first"    isBlind:isFirstBlind
+          toResponse:_resp     inContext:_ctx];
+    [self _appendNav:@"previous"   isBlind:isPreviousBlind
+          toResponse:_resp       inContext:_ctx];
+  }
+}
+
+- (void)_appendNextNav:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  int  batch, batchCount;
+  BOOL isFirstBlind, isPreviousBlind, isNextBlind, isLastBlind;
+  
+  batch      = self->state->currentBatch;
+  batchCount = self->state->batchCount;
+
+  isFirstBlind    = (batch < 2);
+  isPreviousBlind = (batch < 2);
+  isNextBlind     = ((batchCount-1) < batch);
+  isLastBlind     = ((batchCount-1) < batch);
+
+  if ((ShowNavigationAlways) ||
+      (!(isFirstBlind && isPreviousBlind && isNextBlind && isLastBlind))) {
+    [self _appendNav:@"next"     isBlind:isNextBlind
+          toResponse:_resp     inContext:_ctx];
+    [self _appendNav:@"last"     isBlind:isLastBlind
+          toResponse:_resp     inContext:_ctx];
+  }
+}
+
+- (void)_appendNavigation:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  [_resp appendContentString:
+         @"<table border='0' cellspacing='0' cellpadding='0'><tr>"];
+
+  [self _appendPreviousNav:_resp inContext:_ctx];
+  
+  /* append extra buttons */
+  [_resp appendContentString:@"<td valign='middle'>"];
+  [_ctx setObject:YesNumber forKey:WETableView_ButtonMode];
+  [_ctx appendElementIDComponent:@"button"];
+  [self->template appendToResponse:_resp     inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  [_ctx removeObjectForKey:WETableView_ButtonMode];
+  [_resp appendContentString:@"</td>"];
+
+  [self _appendNextNav:_resp inContext:_ctx];
+  
+  [_resp appendContentString:@"</tr></table>"];
+}
+
+- (void)_appendTitle:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *bg;
+
+  bg = [_ctx objectForKey:WETableView_titleColor];
+  
+  /* open title bar*/
+  [_response appendContentString:
+             @"<table border='0' width='100%' cellpadding='0' cellspacing='0'>"
+             @"<tr>"];
+
+  /* append title */
+  [_ctx setObject:YesNumber forKey:WETableView_TitleMode];
+  [_ctx appendElementIDComponent:@"title"];
+  WEAppendTD(_response, @"left", @"middle", bg);                   // <td..>
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_response appendContentString:@"</td>"];                        // </td>
+  [_ctx deleteLastElementIDComponent]; // delete "title"
+  [_ctx removeObjectForKey:WETableView_TitleMode];
+
+  /* append navigation + extra buttons */
+  WEAppendTD(_response, @"right", @"middle", bg);                  // <td..>
+  [self _appendNavigation:_response inContext:_ctx];
+  [_response appendContentString:@"</td>"];                        // </td>
+  
+  /* close title bar*/
+  [_response appendContentString:@"</tr></table>"];
+}
+
+- (void)_appendHeader:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (self->sortedKey)
+    [_ctx setObject:[self->sortedKey stringValueInComponent:[_ctx component]]
+             forKey:WETableView_SORTEDKEY];
+  if (self->isDescending)
+    [_ctx setObject:[self->isDescending valueInComponent:[_ctx component]]
+             forKey:WETableView_ISDESCENDING];
+  [_ctx setObject:YesNumber forKey:WETableView_HeaderMode];
+  [_response appendContentString:@"<tr>"];
+
+  [_ctx appendElementIDComponent:@"header"];
+  {
+    NSString *bn;
+    bn = retStrForInt(self->state->currentBatch);
+    [_ctx appendElementIDComponent:bn]; // append batchNumber
+    [bn release];
+  }
+  if (self->state->doCheckBoxes) {
+    NSString *img;
+    NSArray  *selArray;
+    BOOL     doSelectAll;
+
+    selArray    = [self->selection valueInComponent:[_ctx component]];
+    doSelectAll = ([selArray count] < ([self->allObjects count] / 2));
+
+    img = [_ctx objectForKey:(doSelectAll)
+                ? WETableView_select_all
+                : WETableView_deselect_all];
+
+    img = WEUriOfResource(img, _ctx);
+
+    [_response appendContentString:
+               @"<td  align=\"center\" bgcolor=\""];
+    [_response appendContentString:
+               [_ctx objectForKey:WETableView_headerColor]];
+    [_response appendContentString:@"\">"];
+      
+    if (doSelectAll)
+      [_ctx appendElementIDComponent:@"_sa"]; // select all
+    else
+      [_ctx appendElementIDComponent:@"_dsa"]; // deselect all
+    
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentString:@"\">"];
+
+    if (img) {
+      [_response appendContentString:@"<img border=\"0\" src=\""];
+      [_response appendContentString:img];
+      [_response appendContentString:@"\" alt=\""];
+      [_response appendContentString:(doSelectAll)
+                 ? @"selectall"
+                 : @"deselect all"];
+      [_response appendContentString:@"\" title=\""];
+      [_response appendContentString:(doSelectAll)
+                 ? @"selectall"
+                 : @"deselect all"];
+      [_response appendContentString:@"\" />"];
+    }
+    else
+      [_response appendContentString:(doSelectAll) ? @"[+]" : @"[-]"];
+
+    [_response appendContentString:@"</a>"];
+    [_ctx deleteLastElementIDComponent];    // (de)select all
+    [_response appendContentString:@"</td>"];
+  }
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  [_ctx deleteLastElementIDComponent]; // delete batchNumber
+  [_ctx deleteLastElementIDComponent]; // delete "header"
+
+  if (self->state->showBatchResizeButtons) {
+    int cnt;
+
+    cnt = (self->state->lastIndex - self->state->firstIndex + 1);
+
+    if (cnt == (int)self->state->batchSize && !self->state->doOverflow) {
+      [_response appendContentString:@"<td width=\"1%\""];
+      if ([_ctx objectForKey:WETableView_headerColor]) {
+        [_response appendContentString:@" bgcolor=\""];
+        [_response appendContentString:
+                   [_ctx objectForKey:WETableView_headerColor]];
+        [_response appendContentString:@"\""];
+      }
+      [_response appendContentString:@"></td>"];
+    }
+  }
+  
+  [_response appendContentString:@"</tr>"];
+  [_ctx removeObjectForKey:WETableView_HeaderMode];
+  [_ctx removeObjectForKey:WETableView_SORTEDKEY];
+  [_ctx removeObjectForKey:WETableView_ISDESCENDING];
+}
+
+- (void)_appendResizeButtons:(WOResponse *)_response
+  actionUrl:(NSString *)_actionUrl
+  inContext:(WOContext *)_ctx
+{
+  NSString *img;
+  NSString *uri;
+
+  // append batchSize--Button  
+  img = [self->icons->minusResizeIcon stringValueInComponent:[_ctx component]];
+  img = WEUriOfResource(img, _ctx);
+  uri = [_actionUrl stringByAppendingString:@".mm"];
+  
+  if (img && [_ctx isInForm]) {
+    uri = [[uri componentsSeparatedByString:@"/"] lastObject];
+    [_response appendContentString:@"<input type=\"image\" border=\"0\""];
+    [_response appendContentString:@" name=\""];
+    [_response appendContentString:uri];
+    [_response appendContentString:@"\" src=\""];
+    [_response appendContentString:img];
+    [_response appendContentString:@"\" alt=\"minus\" title=\"minus\" />"];
+  }
+  else {
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:uri];
+    [_response appendContentString:@"\">"];
+  }
+  
+  if (img && ![_ctx isInForm]) {
+    [_response appendContentString:@"<img border=\"0\" src=\""];
+    [_response appendContentString:img];
+    [_response appendContentString:@"\" alt=\"minus\" title=\"minus\" />"];
+  }
+  else if (!img)
+    [_response appendContentString:@"-"];
+
+  if (!(img && [_ctx isInForm]))
+    [_response appendContentString:@"</a>"];
+
+  // append batchSize--Button
+  img = [self->icons->plusResizeIcon stringValueInComponent:[_ctx component]];
+  img = WEUriOfResource(img, _ctx);
+  uri = [_actionUrl stringByAppendingString:@".pp"] ;
+  
+  if (img && [_ctx isInForm]) {
+    uri = [[uri componentsSeparatedByString:@"/"] lastObject];
+    [_response appendContentString:@"<input type=\"image\" border=\"0\""];
+    [_response appendContentString:@" name=\""];
+    [_response appendContentString:uri];
+    [_response appendContentString:@"\" src=\""];
+    [_response appendContentString:img];
+    [_response appendContentString:@"\" alt=\"plus\" title=\"plus\" />"];
+  }
+  else {
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:uri];
+    [_response appendContentString:@"\">"];
+  }
+  
+  if (img && ![_ctx isInForm]) {
+    [_response appendContentString:@"<img border=\"0\" src=\""];
+    [_response appendContentString:img];
+    [_response appendContentString:@"\" alt=\"plus\" title=\"plus\" />"];
+  }
+  else if (!img)
+    [_response appendContentString:@"+"];
+
+  if (!(img && [_ctx isInForm]))
+    [_response appendContentString:@"</a>"];
+
+}
+
+- (void)_appendBatchResizeButtons:(WOResponse *)_response
+  rowSpan:(unsigned int)_rowSpan
+  actionUrl:(NSString *)_actionUrl
+  inContext:(WOContext *)_ctx
+{
+  NSString *s;
+  
+  // open "td"
+  s = [[StrClass alloc] initWithFormat:
+                  @"<td align='center' valign='bottom' width='5' rowspan='%d'", _rowSpan];
+  [_response appendContentString:s];
+  [s release];
+  
+  if ([_ctx objectForKey:WETableView_footerColor]) {
+    [_response appendContentString:@" bgcolor='"];
+    [_response appendContentString:
+               [_ctx objectForKey:WETableView_footerColor]];
+    [_response appendContentCharacter:'\''];
+  }
+  [_response appendContentCharacter:'>'];
+
+      // apppend resize buttons
+  [self _appendResizeButtons:_response
+        actionUrl:_actionUrl
+        inContext:_ctx];
+  // close "td"
+  [_response appendContentString:@"</td>"];
+}
+
+- (void)_appendData:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *comp;
+  NSArray     *matrix;
+  NSString    *batchSizeUrl = nil;
+  NSArray     *selArray     = nil;
+  NSString    *groupId      = nil;
+  BOOL        hideObject    = NO;
+  unsigned    i, cnt, first;
+
+  comp     = [_ctx component];
+  matrix   = [self _collectDataInContext:_ctx];
+  first    = self->state->firstIndex;
+  cnt      = [matrix count];
+
+  if (matrix == nil || cnt == 0)
+    return;
+
+  if (self->state->doCheckBoxes)
+    selArray = [self->selection valueInComponent:comp];
+
+  if (self->state->doScriptCollapsing)
+    [self _appendGroupCollapseScript:_response inContext:_ctx];
+
+  [_ctx appendElementIDComponent:@"data"];
+  {
+    NSString *bn;
+    bn = retStrForInt(self->state->currentBatch);
+    [_ctx appendElementIDComponent:bn]; // append batchNumber
+    [bn release];
+  }
+
+  batchSizeUrl = [_ctx componentActionURL];
+
+  if (self->identifier == nil) {
+    NSString *s;
+    
+    s = retStrForInt(first);
+    [_ctx appendElementIDComponent:s];
+    [s release];
+  }
+  
+  for (i = 0; i < cnt; i++) {
+    NSMutableArray *infos = nil;
+
+    _applyItems_(self, comp, first+i);
+    if (self->identifier) {
+      NSString *ident;
+
+      ident = [self->identifier stringValueInComponent:comp];
+      [_ctx appendElementIDComponent:ident];
+    }
+    
+    infos = [matrix objectAtIndex:i];
+
+    if ([[infos lastObject] isEqual:WETableView_GroupMode]) {
+      unsigned rowSpan;
+      
+      groupId = [StrClass stringWithFormat:@"group%d", i];
+
+      rowSpan = ((i==0) && self->state->showBatchResizeButtons)
+        ? cnt+self->state->groupCount
+        : 0;
+      [self _appendGroupTitle:_response
+            inContext:_ctx
+            infos:infos
+            actionUrl:batchSizeUrl
+            rowSpan:rowSpan
+            groupId:groupId];
+      
+      if ((self->state->groupCount > 0) && !self->state->doScriptCollapsing &&
+          (self->showGroup) && ![self->showGroup boolValueInComponent:comp])
+        hideObject = YES;
+      else
+        hideObject = NO;
+    }
+        
+    [_ctx setObject:infos forKey:WETableView_INFOS];
+
+    if (hideObject) {
+      if (self->identifier == nil)
+        [_ctx incrementLastElementIDComponent];
+      else
+        [_ctx deleteLastElementIDComponent]; // delete identifier
+      continue;
+    }
+    
+    [_response appendContentString:@"<tr"];
+    if (groupId) {
+      [_response appendContentString:@" groupName=\""];
+      [_response appendContentString:groupId];
+      [_response appendContentCharacter:'"'];
+      if (self->state->doScriptCollapsing &&
+          self->showGroup && ![self->showGroup boolValueInComponent:comp])
+        [_response appendContentString:@" style=\"display:none;\""];
+    }
+    [_response appendContentCharacter:'>'];
+
+    [_ctx setObject:YesNumber forKey:WETableView_DataMode];
+
+    if (self->state->doCheckBoxes) {
+      WETableViewInfo *info = nil;
+      NSString        *bg   = nil;
+      NSString *s;
+
+      info = ([infos count]) ? [infos objectAtIndex:0] : nil;
+
+      bg = (info && info->isEven)
+        ? [_ctx objectForKey:WETableView_evenColor]
+        : [_ctx objectForKey:WETableView_oddColor];
+
+      [_ctx appendElementIDComponent:@"cb"];
+      [_response appendContentString:@"<td width=\"15\" align=\"left\""];
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:bg];
+      [_response appendContentString:@"\"><input type=\"checkbox\" name=\""];
+      [_response appendContentHTMLAttributeValue:[_ctx elementID]];
+      [_response appendContentString:@"\" value=\""];
+      s = retStrForInt(first + i);
+      [_response appendContentString:s];
+      [s release];
+      [_response appendContentCharacter:'"'];
+
+      if ([selArray containsObject:[self->allObjects objectAtIndex:first+i]])
+        [_response appendContentString:@" checked=\"checked\""];
+        
+      [_response appendContentString:@" />"];
+      [_response appendContentString:@"</td>"];
+      
+      [_ctx deleteLastElementIDComponent]; // delete "cb"
+    }
+
+    [self->template appendToResponse:_response inContext:_ctx];
+
+    if (!i && self->state->showBatchResizeButtons &&!self->state->groupCount) {
+      [self _appendBatchResizeButtons:_response
+                              rowSpan:cnt+self->state->groupCount
+                            actionUrl:batchSizeUrl
+                            inContext:_ctx];
+    }
+    
+    [_response appendContentString:@"</tr>"];
+
+    if (self->identifier == nil)
+      [_ctx incrementLastElementIDComponent];
+    else
+      [_ctx deleteLastElementIDComponent]; // delete identifier
+  }
+  if (self->identifier == nil)
+    [_ctx deleteLastElementIDComponent]; // delete index
+  [_ctx deleteLastElementIDComponent];   // delete batchNumber
+  [_ctx deleteLastElementIDComponent];   // delete "data"
+  [_ctx removeObjectForKey:WETableView_DataMode];
+}
+
+- (void)_appendFooter:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *bg      = nil;
+  unsigned first    = self->state->firstIndex + 1;
+  unsigned last     = self->state->lastIndex  + 1;
+  unsigned count    = [self->allObjects count];
+  unsigned batch    = self->state->currentBatch;
+  unsigned batchCnt = self->state->batchCount;
+  NSString *s;
+
+  first    = (count)    ? first    : 0;
+  batchCnt = (batchCnt) ? batchCnt : 1;
+  bg       = [_ctx objectForKey:WETableView_footerColor];
+  
+  [_response appendContentString:
+             @"<table border='0' width='100%' cellpadding='0' cellspacing='0'>"];
+  [_response appendContentString:@"<tr>"];                        // <TR>
+
+  WEAppendTD(_response, @"left", nil, bg);                        //   <TD...>
+
+  [_ctx setObject:YesNumber forKey:WETableView_FooterMode];
+  [_ctx appendElementIDComponent:@"footer"];  
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  [_ctx removeObjectForKey:WETableView_FooterMode];
+
+  [_response appendContentString:@"<small>"];
+  if (!self->state->doOverflow) {
+    s = [[StrClass alloc] initWithFormat:@"%d ", first];
+    [_response appendContentString:s];
+    [s release];
+    [_response appendContentString:WETableLabelForKey(@"to", _ctx)];
+    s = [[StrClass alloc] initWithFormat:@" %d ", last];
+    [_response appendContentString:s];
+    [s release];
+    [_response appendContentString:WETableLabelForKey(@"of", _ctx)];
+  }
+  s = [[StrClass alloc] initWithFormat:@" %d", count];
+  [_response appendContentString:s];
+  [s release];
+  [_response appendContentString:@"</small>"];
+  
+  [_response appendContentString:@"</td>"];                       // </td>
+
+  WEAppendTD(_response, @"right", nil, bg);                     // <td...> 
+  if (!self->state->doOverflow) {
+    if (ShowNavigationInFooter) {
+      [_response appendContentString:
+                 @"<table border='0' cellpadding='0' cellspacing='0'><tr>"];
+      [self _appendPreviousNav:_response inContext:_ctx];
+      WEAppendTD(_response, nil, nil, bg);                        // <td...>
+    }
+    [_response appendContentString:@"<small>"];
+    [_response appendContentString:@"&nbsp;"];
+    [_response appendContentString:WETableLabelForKey(@"page", _ctx)];
+    s = [[StrClass alloc] initWithFormat:@": %d ", batch];
+    [_response appendContentString:s];
+    [s release];
+    [_response appendContentString:WETableLabelForKey(@"of", _ctx)];
+    s = [[StrClass alloc] initWithFormat:@" %d", batchCnt];
+    [_response appendContentString:s];
+    [s release];
+    [_response appendContentString:@"&nbsp;"];
+    [_response appendContentString:@"</small>"];
+    if (ShowNavigationInFooter) {
+      [_response appendContentString:@"</td>"];
+      [self _appendNextNav:_response inContext:_ctx];
+      [_response appendContentString:@"</tr></table>"];
+    }
+  }
+  else {
+    [self _appendResizeButtons:_response
+          actionUrl:[_ctx componentActionURL]
+          inContext:_ctx];
+  }
+
+  [_response appendContentString:@"</td></tr>"];                // </td></tr>
+  [_response appendContentString:@"</table>"];                  // </table>
+}
+
+// --- action handler -----------------------------------------------------
+
+- (void)_handleSortActionInContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSString    *key;
+  NSString    *oldKey;
+  BOOL        isDesc;
+  BOOL        oldIsDesc;
+
+  if (self->sortedKey == nil || self->isDescending == nil)
+    return; // nothing to do
+
+  if ([_ctx objectForKey:WETableView_SORTEDKEY] == nil ||
+      [_ctx objectForKey:WETableView_ISDESCENDING] == nil)
+    return; // nothing to do
+
+  cmp    = [_ctx component];
+  key    = [_ctx  objectForKey:WETableView_SORTEDKEY];
+  isDesc = [[_ctx objectForKey:WETableView_ISDESCENDING] boolValue];
+
+  oldIsDesc = [self->isDescending boolValueInComponent:cmp];
+  oldKey    = [self->sortedKey  stringValueInComponent:cmp];
+
+  if ([oldKey isEqual:key] && oldIsDesc == isDesc)
+    return; // nothing to do
+
+  if ([self->isDescending isValueSettable])
+    [self->isDescending setBoolValue:isDesc inComponent:cmp];
+  if ([self->sortedKey isValueSettable])
+    [self->sortedKey setStringValue:key inComponent:cmp];
+
+  if (self->sortAction == nil && key != nil) {
+    EOSortOrdering *so;
+    NSArray        *soArray;
+    SEL            sel;
+    NSArray        *tmp;
+    
+    sel = (isDesc) ? EOCompareDescending : EOCompareAscending;
+    so  = [EOSortOrdering sortOrderingWithKey:key selector:sel];
+    
+    soArray = [[NSArray alloc] initWithObjects:&so count:1];
+    tmp = [self->allObjects sortedArrayUsingKeyOrderArray:soArray];
+    [soArray release];
+    
+    if ([self->list isValueSettable])
+      [self->list setValue:tmp inComponent:[_ctx component]];
+    else {
+      [[_ctx component] debugWithFormat:
+                          @"couldn't set sorted list on 'list' binding"];
+    }
+  }
+  else if (self->sortAction)
+    [self->sortAction valueInComponent:cmp];
+}
+
+- (void)_handleFirstButtonInContext:(WOContext *)_ctx {
+  if (self->firstAction)
+    [self->firstAction valueInComponent:[_ctx component]];
+  else if (self->state->currentBatch != 1) {
+    self->state->currentBatch = 1;
+    _applyState_(self, [_ctx component]);
+  }
+}
+
+- (void)_handlePreviousButtonInContext:(WOContext *)_ctx {
+  if (self->previousAction)
+    [self->previousAction valueInComponent:[_ctx component]];
+  else {
+    unsigned batch = self->state->currentBatch;
+    
+    self->state->currentBatch = ((batch -1) > 0) ? batch - 1 : 1;
+    _applyState_(self, [_ctx component]);
+  }
+}
+
+- (void)_handleNextButtonInContext:(WOContext *)_ctx {
+  if (self->nextAction)
+    [self->nextAction valueInComponent:[_ctx component]];
+  else {
+    unsigned batch = self->state->currentBatch;
+    unsigned cnt   = self->state->batchCount;
+
+    self->state->currentBatch = ((batch +1) < cnt) ? batch + 1 : cnt;
+    _applyState_(self, [_ctx component]);
+  }
+}
+
+- (void)_handleLastButtonInContext:(WOContext *)_ctx {
+  if (self->lastAction)
+    [self->lastAction valueInComponent:[_ctx component]];
+  else {
+    self->state->currentBatch = self->state->batchCount;
+    _applyState_(self, [_ctx component]);
+  }
+}
+
+// --- main methodes -------------------------------------------------------
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  forBatch:(int)_batch
+  selections:(NSMutableArray *)_selArray
+  inContext:(WOContext *)_ctx
+{
+  NSString *eid, *s;
+  int      i, first, last;
+  
+  first = self->state->firstIndex;
+  last  = self->state->lastIndex;
+  
+  {
+    NSString *bn;
+    bn = retStrForInt(self->state->currentBatch);
+    [_ctx appendElementIDComponent:bn]; // append batchNumber
+    [bn release];
+  }
+
+  eid = [_ctx elementID];
+
+  if ([_request formValueForKey:[eid stringByAppendingString:@".pp.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".pp"]];
+  }
+  else if ([_request formValueForKey:[eid stringByAppendingString:@".mm.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".mm"]];
+  }
+  
+  if (self->identifier == nil) { // append index
+    s = retStrForInt(first);
+    [_ctx appendElementIDComponent:s];
+    [s release];
+  }
+
+  for (i = first; i <= last; i++) {
+    _applyItems_(self, [_ctx component], i);
+    if (self->identifier) {
+      NSString *s;
+      
+      s = [self->identifier stringValueInComponent:[_ctx component]];
+      [_ctx appendElementIDComponent:s];
+    }
+    
+    if (_selArray) {
+      NSString *cbID; // checkBoxID
+      id       formValue;
+      id       obj;
+      
+      cbID = [[_ctx elementID] stringByAppendingString:@".cb"];
+      obj  = [self->item valueInComponent:[_ctx component]];
+
+      if (obj) {
+        if ((formValue = [_request formValueForKey:cbID])) {
+          if (![_selArray containsObject:obj])
+            [_selArray addObject:obj];
+        }
+        else if ([_selArray containsObject:obj])
+          [_selArray removeObject:obj];
+      }
+    }
+    [self->template takeValuesFromRequest:_request inContext:_ctx];
+    
+    if (self->identifier == nil)
+      [_ctx incrementLastElementIDComponent];
+    else
+      [_ctx deleteLastElementIDComponent]; // delete identifier
+  }
+  if (self->identifier == nil)
+    [_ctx deleteLastElementIDComponent]; // delete index
+
+  [_ctx deleteLastElementIDComponent]; // delete batchNumber
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  int            i, firstBatch, lastBatch, savedCurrentBatch;
+  NSString       *eid;
+  NSMutableArray *selArray = nil;
+
+  [self updateStateInContext:_ctx];
+
+  eid      = [_ctx elementID];
+
+  /* handle "data" section */
+
+  if (self->state->doCheckBoxes) {
+    selArray = [self->selection valueInComponent:[_ctx component]];
+    selArray = [selArray mutableCopyWithZone:[self zone]];
+  }
+
+  firstBatch = (self->state->doScriptScrolling) ? 1 : self->state->currentBatch;
+  
+  lastBatch  = (self->state->doScriptScrolling)
+    ? self->state->batchCount
+    : self->state->currentBatch;
+
+
+  [_ctx appendElementIDComponent:@"data"];
+  [_ctx setObject:YesNumber forKey:WETableView_DataMode];
+
+  savedCurrentBatch = self->state->currentBatch;
+  for (i = firstBatch; i <= lastBatch; i++) {    
+    self->state->currentBatch = i;
+    _applyState_(self, [_ctx component]);
+    [self updateStateInContext:_ctx];
+
+    [self takeValuesFromRequest:_request
+          forBatch:i
+          selections:selArray
+          inContext:_ctx];
+  }
+  [_ctx removeObjectForKey:WETableView_DataMode];
+  
+  if (self->state->currentBatch != (unsigned)savedCurrentBatch) {
+    self->state->currentBatch = savedCurrentBatch;
+    _applyState_(self, [_ctx component]);
+  }
+
+  [_ctx deleteLastElementIDComponent]; // delete "data"
+
+  if (self->state->doCheckBoxes) {
+    [self->selection setValue:selArray inComponent:[_ctx component]];
+    [selArray release];
+  }
+  
+  // handle header (sort buttons, ...)
+  [_ctx setObject:YesNumber forKey:WETableView_HeaderMode];
+  [_ctx appendElementIDComponent:@"header"];
+  
+  for (i = 1; i <= (int)self->state->batchCount; i++) {
+    NSString *s;
+    
+    // TODO: improve
+    s = retStrForInt(i);
+    [_ctx appendElementIDComponent:s];
+    [s release];
+    
+    [self->template takeValuesFromRequest:_request inContext:_ctx];
+    [_ctx deleteLastElementIDComponent]; // delete batchNumber
+  }
+
+  [_ctx deleteLastElementIDComponent]; // delete "header"
+  [_ctx removeObjectForKey:WETableView_HeaderMode];
+
+  // handle title
+  [_ctx setObject:YesNumber forKey:WETableView_TitleMode];
+  [_ctx appendElementIDComponent:@"title"];
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent]; // delete "title"
+  [_ctx removeObjectForKey:WETableView_TitleMode];
+
+  // handle buttons
+  [_ctx setObject:YesNumber forKey:WETableView_ButtonMode];
+  [_ctx appendElementIDComponent:@"button"];
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent]; // delete "button"
+  [_ctx removeObjectForKey:WETableView_ButtonMode];
+
+  // handle footer
+  [_ctx setObject:YesNumber forKey:WETableView_FooterMode];
+  [_ctx appendElementIDComponent:@"footer"];
+
+  // reset autoScrollHeight
+  if ([_request formValueForKey:
+                [eid stringByAppendingString:@".footer.pp.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".pp"]];
+  }
+  else if ([_request formValueForKey:
+                     [eid stringByAppendingString:@".footer.mm.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".mm"]];
+  }
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent]; // delete "footer"
+  [_ctx removeObjectForKey:WETableView_FooterMode];
+
+  if ([_request formValueForKey:[eid stringByAppendingString:@".first.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".first"]];
+  }
+  if ([_request formValueForKey:[eid stringByAppendingString:@".next.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".next"]];
+  }
+  if ([_request formValueForKey:[eid stringByAppendingString:@".last.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".last"]];
+  }
+  if ([_request formValueForKey:[eid stringByAppendingString:@".previous.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:
+          [[_ctx senderID] stringByAppendingString:@".previous"]];
+  }
+}
+
+- (id)increaseAutoScrollHeightInContext:(WOContext *)_ctx {
+  if ([self->autoScroll isValueSettable]) {
+    int sh; // scrollHeight
+
+    sh = [self->autoScroll intValueInComponent:[_ctx component]] + 20;
+    [self->autoScroll setIntValue:sh inComponent:[_ctx component]];
+  }
+  return nil;
+}
+
+- (id)decreaseAutoScrollHeightInContext:(WOContext *)_ctx {
+  if ([self->autoScroll isValueSettable]) {
+    int sh; // scrollHeight
+
+    sh = [self->autoScroll intValueInComponent:[_ctx component]] - 20;
+    if (sh > 50)
+      [self->autoScroll setIntValue:sh inComponent:[_ctx component]];
+  }
+  return nil;
+}
+
+
+- (id)increaseBatchSizeInContext:(WOContext *)_ctx {
+  if ([self->batchSize isValueSettable]) {
+    int bs;
+
+    bs = [self->batchSize intValueInComponent:[_ctx component]] + 1;
+    [self->batchSize setIntValue:bs inComponent:[_ctx component]];
+  }
+  return nil;
+}
+
+- (id)decreaseBatchSizeInContext:(WOContext *)_ctx {
+  if ([self->batchSize isValueSettable]) {
+    int bs;
+
+    bs = [self->batchSize intValueInComponent:[_ctx component]] - 1;
+    if (bs > 1)
+      [self->batchSize setIntValue:bs inComponent:[_ctx component]];
+  }
+  return nil;
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  WOComponent    *cmp;
+  NSString       *eid;
+  id             result = nil;
+
+  [self updateStateInContext:_ctx];
+
+  eid = [_ctx currentElementID];
+  cmp = [_ctx component];
+
+  if ([eid isEqual:@"first"])
+    [self _handleFirstButtonInContext:_ctx];
+  else if ([eid isEqual:@"previous"])
+    [self _handlePreviousButtonInContext:_ctx];
+  else if ([eid isEqual:@"next"])
+    [self _handleNextButtonInContext:_ctx];
+  else if ([eid isEqual:@"last"])
+    [self _handleLastButtonInContext:_ctx];
+  else if ([eid isEqual:@"data"]) {
+    NSString *idxId;
+
+    [_ctx consumeElementID];             // consume "data"
+    [_ctx appendElementIDComponent:eid]; // append  "data"
+
+    {
+      NSString *bn;
+
+      bn = [_ctx currentElementID];
+      if ([self->currentBatch isValueSettable])
+        [self->currentBatch setIntValue:[bn intValue] inComponent:cmp];
+      
+      [_ctx consumeElementID];            // consume batchNumber
+      [_ctx appendElementIDComponent:bn]; // append batch
+    }
+
+    if ((idxId = [_ctx currentElementID])) {
+      [_ctx consumeElementID];               // consume index-id
+      [_ctx appendElementIDComponent:idxId]; // append index-id
+
+      // reset batchSize
+      if ([idxId isEqualToString:@"pp"])
+        result = [self increaseBatchSizeInContext:_ctx];
+      else if ([idxId isEqualToString:@"mm"])
+        result = [self decreaseBatchSizeInContext:_ctx];
+      else {
+        if (self->identifier == nil) {
+          unsigned idx;
+      
+          idx   = [idxId unsignedIntValue];
+          if (idx < [self->allObjects count] && idx >= 0) {
+            _applyItems_(self, cmp, idx);
+          }
+          else
+            NSLog(@"WETableView: index is out of range!");
+        }
+        else
+          _applyIdentifier(self, cmp, idxId);
+
+        result = [self invokeGrouping:_request inContext:_ctx];
+      }
+      [_ctx deleteLastElementIDComponent]; // delete index-id
+    }
+    [_ctx deleteLastElementIDComponent]; // delete batchNumber
+    [_ctx deleteLastElementIDComponent]; // delete "data"
+  }
+  else if ([eid isEqual:@"header"]) {
+    [_ctx consumeElementID];             // consume "header"
+    [_ctx appendElementIDComponent:eid]; // append  "header"
+
+    if ([self->currentBatch isValueSettable]) {
+      int bn = [[_ctx currentElementID] intValue];
+      [self->currentBatch setIntValue:bn inComponent:cmp];
+    }
+    [_ctx appendElementIDComponent:[_ctx currentElementID]]; // batchNumber
+    [_ctx consumeElementID];                         // consume batchNumber
+
+    // handle selectAllCheckBoxes:
+    if ([[_ctx currentElementID] isEqualToString:@"_sa"]) {
+      NSMutableArray *selArray;
+        
+      selArray = [self->allObjects mutableCopyWithZone:[self zone]];
+      [self->selection setValue:selArray inComponent:cmp];
+      [selArray release];
+    }
+    // handle deselectAllCheckBoxes:
+    else if ([[_ctx currentElementID] isEqualToString:@"_dsa"]) {
+      [self->selection setValue:[NSMutableArray array] inComponent:cmp];
+    }
+    else
+      result = [self->template invokeActionForRequest:_request inContext:_ctx];
+    
+    [_ctx deleteLastElementIDComponent]; // delete batchNumber
+    [_ctx deleteLastElementIDComponent]; // delete "header"
+
+    [self _handleSortActionInContext:_ctx];
+    
+    [_ctx removeObjectForKey:WETableView_SORTEDKEY];
+    [_ctx removeObjectForKey:WETableView_ISDESCENDING];
+  }
+  else if ([eid isEqual:@"title"] || [eid isEqual:@"button"] ||
+           [eid isEqual:@"footer"]) {
+    [_ctx consumeElementID];
+    [_ctx appendElementIDComponent:eid];
+
+    eid = [_ctx currentElementID];
+
+    // reset autoScrollHeight
+    if ([eid isEqualToString:@"pp"])
+      result = [self increaseAutoScrollHeightInContext:_ctx];
+    else if ([eid isEqualToString:@"mm"])
+      result = [self decreaseAutoScrollHeightInContext:_ctx];
+    else
+      result = [self->template invokeActionForRequest:_request inContext:_ctx];
+    
+    [_ctx deleteLastElementIDComponent];
+  }
+  else
+    result = [self->template invokeActionForRequest:_request inContext:_ctx];
+  
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  
+  [self updateStateInContext:_ctx];
+  [self updateScriptIdInContext:_ctx];
+  [self updateConfigInContext:_ctx];
+  
+  cmp = [_ctx component];
+
+  /* open tableView */
+  [_response appendContentString:
+             @"<table border='0' width='100%' cellpadding='0' cellspacing='0'>"];
+
+  /* append tableTitle + navigation */
+  [_response appendContentString:@"<tr><td>"];
+  [self _appendTitle:_response inContext:_ctx];
+  [_response appendContentString:@"</td></tr>"];
+
+  [_response appendContentString:@"<tr><td></td></tr>"];
+  
+  if (self->state->doScriptScrolling) {
+    [self _appendTableContentAsScript:_response inContext:_ctx]; //close tables
+  }
+  else {
+    /* open header + data area */
+    [_response appendContentString:@"<tr><td>"];
+    
+    if (self->state->doOverflow) {
+      [_response appendContentString:
+                 @"<p style=\"width:100%; height: "];
+      [_response appendContentString:
+                   [self->autoScroll stringValueInComponent:cmp]];
+      [_response appendContentString:@"; overflow-y: auto\">"];
+    }
+    
+    [_response appendContentString:@"<table width='100%' border='"];
+    [_response appendContentString:[self->border stringValueInComponent:cmp]];
+    [_response appendContentString:@"' cellpadding='"];
+    [_response appendContentString:
+               [self->cellpadding stringValueInComponent:cmp]];
+    [_response appendContentString:@"' cellspacing='"];
+    [_response appendContentString:
+               [self->cellspacing stringValueInComponent:cmp]];
+    [_response appendContentString:@"'>"];
+
+
+    self->state->showBatchResizeButtons =
+      ([self->showBatchResizeButtons boolValueInComponent:cmp] &&
+       (self->state->currentBatch < self->state->batchCount) &&
+       !self->state->doOverflow);
+    
+    [self _appendHeader:_response inContext:_ctx];
+    [self _appendData:_response   inContext:_ctx];
+  
+    [_response appendContentString:@"</table>"];
+    if (self->state->doOverflow)
+      [_response appendContentString:@"</p>"];
+    
+    /* close header + data area */
+    [_response appendContentString:@"</td></tr>"];
+    
+    [_response appendContentString:@"</table>"];                  // </TABLE>
+
+    /* append footer */
+    [self _appendFooter:_response inContext:_ctx];
+  }
+  
+  // close tableView
+
+
+  if (self->state->doScriptScrolling)
+    [self appendJavaScript:_response inContext:_ctx];
+  
+  [self removeConfigInContext:_ctx];
+}
+
+@end /* WETableView */
+
+@implementation WETableViewInfo
+@end
+
+// --- JavaScript additions -------------------------------------------------
+
+@implementation WETableView(JavaScriptAdditions)
+
+- (void)_appendGroupCollapseScript:(WOResponse *)_resp
+  inContext:(WOContext *)_ctx
+{
+  if ([_ctx objectForKey:WETableView_HasCollapseScript])
+    return;
+
+  [_resp appendContentString:
+           @"\n<script language=\"JavaScript\">\n"
+           @"<!--\n"
+           @"function toggleTableGroup()\n"
+           @"{\n"
+           @"   img = event.srcElement;\n"
+           @"   visibility = img.isGroupVisible;\n"
+           @"   visibility = (visibility != \"none\") ? \"none\" : \"\";\n"
+           @"   img.isGroupVisible = visibility;\n"
+           @"   img.src = (visibility == \"\") ? img.openImg : img.closeImg;\n"
+           @"   groupName  = img.group;\n"
+           @"   table  = img.parentNode.parentNode.parentNode;\n"
+           @"   trList = table.getElementsByTagName(\"TR\");\n"
+           @"   cnt    = trList.length;\n"
+           @"   for (i=0; i<cnt; i++) {\n"
+           @"     tr = trList[i];\n"
+           @"     if (tr.groupName == groupName)\n"
+           @"       tr.style.display = visibility;\n"
+           @"   }\n"
+           @"}\n"
+           @"//-->\n"
+           @"</script>\n"];
+  [_ctx setObject:YesNumber forKey:WETableView_HasCollapseScript];
+}
+
+- (void)jsButton:(WOResponse *)_resp ctx:(WOContext *)_ctx
+  name:(NSString *)_name button:(NSString *)_button 
+{
+  NSString *imgUri;
+  NSString *n;
+  
+  _button = [_button stringByAppendingString:@".gif"];
+  imgUri  = WEUriOfResource(_button, _ctx);
+  n       = [_name stringByAppendingString:self->scriptID];
+  
+  n = [[StrClass alloc] initWithFormat:
+          @"var %@ = new Image(); %@.src = \"%@\";\n", n, n, imgUri];
+  [_resp appendContentString:n];
+  [n release];
+}
+                                    
+- (void)appendJavaScript:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  NSString *n;
+  
+  [_resp appendContentString:@"<script language=\"JavaScript\">\n<!--\n"];
+  
+  [self jsButton:_resp ctx:_ctx name:@"First"     button:@"first"];
+  [self jsButton:_resp ctx:_ctx name:@"First2"    button:@"first_blind"];
+  [self jsButton:_resp ctx:_ctx name:@"Previous"  button:@"previous"];
+  [self jsButton:_resp ctx:_ctx name:@"Previous2" button:@"previous_blind"];
+  [self jsButton:_resp ctx:_ctx name:@"Next"      button:@"next"];
+  [self jsButton:_resp ctx:_ctx name:@"Next2"     button:@"next_blind"];
+  [self jsButton:_resp ctx:_ctx name:@"Last"      button:@"last"];
+  [self jsButton:_resp ctx:_ctx name:@"Last2"     button:@"last_blind"];
+
+  n = [[StrClass alloc] initWithFormat:
+    @"function showPage%@() {\n"
+    @"  for (var i=1; i< page%@.length; i++) {\n"
+       @"    if (i == actualPage%@) {\n"
+    @"      page%@[i][\"Div\"].style.display = \"\";\n"
+    @"      footer%@[i][\"Div\"].style.display = \"\";\n"
+    @"    }\n"
+       @"    else {\n"
+    @"      page%@[i][\"Div\"].style.display = \"none\";\n"
+    @"      footer%@[i][\"Div\"].style.display = \"none\";\n"
+    @"    }\n"
+       @"      }\n"
+       @"      flushImages%@();\n"
+       @"}\n",
+    self->scriptID, // showPage
+    self->scriptID, // page.length
+    self->scriptID, // actualPage
+    self->scriptID, // page
+    self->scriptID, // footer
+    self->scriptID, // page
+    self->scriptID, // footer
+    self->scriptID  // flushImages
+  ];
+  [_resp appendContentString:n];
+  [n release];
+
+  n = [[StrClass alloc] initWithFormat:
+    @"function firstPage%@() {\n"
+    @"  actualPage%@ = 1;\n"
+    @"  showPage%@();\n"
+    @"}\n",
+    self->scriptID, // firstPage
+    self->scriptID, // actualPage
+    self->scriptID  // showPage
+  ];
+  [_resp appendContentString:n];
+  [n release];
+
+  n = [[StrClass alloc] initWithFormat:
+    @"function previousPage%@() {\n"
+    @" if (actualPage%@ > 1) {\n"
+    @"    actualPage%@--;\n"
+    @"    showPage%@();\n"
+    @"  }\n"
+       @"}\n",
+    self->scriptID, // previousPage
+    self->scriptID, // actualPage
+    self->scriptID, // actualPage
+    self->scriptID  // showPage
+  ];
+  [_resp appendContentString:n];
+  [n release];
+  
+  n = [[StrClass alloc] initWithFormat:
+    @"function nextPage%@() {\n"
+    @"  if (actualPage%@ < page%@.length - 1) {\n"
+    @"    actualPage%@++;\n"
+    @"    showPage%@();\n"
+    @" }\n"
+       @"}\n",
+    self->scriptID, // nextPage
+    self->scriptID, // actualPage
+    self->scriptID, // page
+    self->scriptID, // actualPage
+    self->scriptID  // showPage
+  ];
+  [_resp appendContentString:n];
+  [n release];
+
+  n = [[StrClass alloc] initWithFormat:
+    @"function lastPage%@() {\n"
+    @"  actualPage%@ = page%@.length - 1;\n"
+    @"  showPage%@();\n"
+    @"}\n",
+    self->scriptID, // lastPage
+    self->scriptID, // actualPage
+    self->scriptID, // page
+    self->scriptID  // showPage
+  ];
+  [_resp appendContentString:n];
+  [n release];
+
+  n = [[StrClass alloc] initWithFormat:
+    @"function flushImages%@() {\n"
+    @"  document.images[\"firstPageImg%@\"].src    = First%@.src;\n"
+    @"  document.images[\"previousPageImg%@\"].src = Previous%@.src;\n"
+    @"  document.images[\"nextPageImg%@\"].src     = Next%@.src;\n"
+    @"  document.images[\"lastPageImg%@\"].src     = Last%@.src;\n"
+    @"  if (actualPage%@ == 1) {\n"
+    @"    document.images[\"firstPageImg%@\"].src    = First2%@.src;\n"
+    @"    document.images[\"previousPageImg%@\"].src = Previous2%@.src;\n"
+    @"  }\n"
+                             
+#if 0          
+        @"  if (actualPage%@ == 2) {\n"
+        @"    document.images[\"firstPageImg%@\"].src = First2%@.src;\n"
+        @"  }\n"
+        @"  if (actualPage%@ == page%@.length -2) {\n"
+        @"    document.images[\"lastPageImg%@\"].src = Last2%@.src;\n"
+        @"  }\n"
+#endif
+                                       
+    @"  if (actualPage%@ == page%@.length - 1) {\n"
+    @"    document.images[\"nextPageImg%@\"].src = Next2%@.src;\n"
+    @"    document.images[\"lastPageImg%@\"].src = Last2%@.src;\n"
+    @"  }\n"
+    @"}\n",
+    self->scriptID, // flushImages
+    self->scriptID, // firstPageImg
+    self->scriptID, // First
+    self->scriptID, // previousPageImg
+    self->scriptID, // Previous
+    self->scriptID, // nextPageImg
+    self->scriptID, // Next
+    self->scriptID, // lastPageImg
+    self->scriptID, // Last
+    self->scriptID, // actualPage
+    self->scriptID, // firstPageImg
+    self->scriptID, // First2
+    self->scriptID, // previousPageImg
+    self->scriptID, // Previous2
+                                       
+#if 0
+    self->scriptID, // actualPage
+    self->scriptID, // firstPageImg
+    self->scriptID, // First2
+                                       
+    self->scriptID, // actualPage
+    self->scriptID, // page
+    self->scriptID, // lastPageImg
+    self->scriptID, // Last2
+#endif
+                                       
+    self->scriptID, // actualPage
+    self->scriptID, // page
+    self->scriptID, // nextPageImg,
+    self->scriptID, // Next2
+    self->scriptID, // lastPageImg
+    self->scriptID  // Last2
+  ];
+  [_resp appendContentString:n];
+  [n release];
+  
+  n = [[StrClass alloc] initWithFormat:
+    @"var page%@   = new Array();\n"
+    @"var footer%@ = new Array();\n"
+    @"var actualPage%@ = %d;",
+    self->scriptID, // page
+    self->scriptID, // footer
+    self->scriptID, //actualPage
+    self->state->currentBatch
+  ];
+  [_resp appendContentString:n];
+  [n release];
+
+  {
+    unsigned i;
+
+    for (i = 1; i <= self->state->batchCount; i++) {
+      n = [[StrClass alloc] initWithFormat:
+        @"page%@[%d] = new Array();\n"
+        @"page%@[%d][\"Div\"] = page%dDiv%@;\n\n"
+        @"footer%@[%d] = new Array();\n"
+        @"footer%@[%d][\"Div\"] = footer%dDiv%@;\n\n",
+        self->scriptID, // page
+        i,              // page[i]
+        self->scriptID, // page
+        i,              // page[i]
+        i,              // pageiDiv
+        self->scriptID, // pageDiv
+        self->scriptID, // footer
+        i,              // footer[i]
+        self->scriptID, // footer
+        i,              // footer[i]
+        i,              // footeriDiv
+        self->scriptID  // footerDiv
+      ];
+      [_resp appendContentString:n];
+      [n release];
+    }
+  }
+  n = [[StrClass alloc] initWithFormat:@"showPage%@();", self->scriptID];
+  [_resp appendContentString:n];
+  [n release];
+
+  [_resp appendContentString:@"//-->\n</script>\n"];
+}
+
+- (void)_appendTableContentAsScript:(WOResponse *)_resp 
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *cmp;
+  unsigned i, savedBatchIndex;
+
+  cmp = [_ctx component];
+  
+  savedBatchIndex = self->state->currentBatch;
+  /* open header + data area */
+  [_resp appendContentString:@"<tr><td>"];
+
+  for (i = 1; i <= self->state->batchCount; i++) {
+    NSString *s;
+    
+    self->state->currentBatch = i;
+    _applyState_(self, cmp);
+    [self updateStateInContext:_ctx];
+    
+    s = [[StrClass alloc] initWithFormat:         // <DIV...>
+      @"<div id=\"page%dDiv%@\" style=\"display: ; \">", i, self->scriptID];
+    [_resp appendContentString:s];
+    [s release];
+
+    [_resp appendContentString:
+           @"<table border='0' width='100%' cellpadding='1' cellspacing='0'>"];
+    
+    [self _appendHeader:_resp inContext:_ctx];
+    [self _appendData:_resp inContext:_ctx];
+    
+    [_resp appendContentString:@"</table>"];
+    [_resp appendContentString:@"</div>"];                        // </DIV>
+    
+
+    /* append footer */
+    s = [[StrClass alloc] initWithFormat:        // <DIV...>
+      @"<div id=\"footer%dDiv%@\" style=\"display: ; \">", i, self->scriptID];
+    [_resp appendContentString:s];
+    [s release];
+
+    [self _appendFooter:_resp inContext:_ctx];
+    
+    [_resp appendContentString:@"</div>"];                        // </DIV>
+  }
+  
+  /* close header + data area */
+  [_resp appendContentString:@"</td></tr>"];
+  if (self->state->currentBatch != savedBatchIndex) {
+    self->state->currentBatch = savedBatchIndex;
+    _applyState_(self, cmp);
+  }
+  [self updateStateInContext:_ctx];
+}
+
+- (void)_appendScriptLink:(WOResponse *)_response name:(NSString *)_name {
+  NSString *s;
+  
+  [_response appendContentString:@"JavaScript:"];
+  [_response appendContentString:_name];
+  s = [[StrClass alloc] initWithFormat:@"Page%@();", self->scriptID];
+  [_response appendContentString:s];
+  [s release];
+}
+
+- (void)_appendScriptImgName:(WOResponse *)_response name:(NSString *)_name {
+  [_response appendContentString:_name];
+  [_response appendContentString:@"PageImg"];
+  [_response appendContentString:self->scriptID];
+}
+
+@end /* WETableView(JavaScriptAdditions) */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewButtonMode.m b/skyrix-sope/WEExtensions/WETableView/WETableViewButtonMode.m
new file mode 100644 (file)
index 0000000..16a5abb
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WEContextConditional.h"
+#include "WETableViewDefines.h"
+#include "common.h"
+
+@interface WETableViewButtonMode: WEContextConditional
+@end
+
+@implementation WETableViewButtonMode
+
+- (NSString *)_contextKey {
+  return WETableView_ButtonMode;
+}
+
+@end /* WETableViewButtonMode */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewColorConfig.h b/skyrix-sope/WEExtensions/WETableView/WETableViewColorConfig.h
new file mode 100644 (file)
index 0000000..8215c54
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WEExtensions_WETableViewColorConfig_H__
+#define __WEExtensions_WETableViewColorConfig_H__
+
+#include "WETableViewConfigObject.h"
+
+@interface WETableViewColorConfig : WETableViewConfigObject
+{
+  WOAssociation  *titleColor;
+  WOAssociation  *headerColor;
+  WOAssociation  *footerColor;
+  WOAssociation  *evenColor;
+  WOAssociation  *oddColor;
+}
+
+@end
+
+#endif /* __WEExtensions_WETableViewColorConfig_H__ */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewColorConfig.m b/skyrix-sope/WEExtensions/WETableView/WETableViewColorConfig.m
new file mode 100644 (file)
index 0000000..3ff5ca2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WETableViewColorConfig.h"
+#include "WETableViewDefines.h"
+#include "common.h"
+
+@implementation WETableViewColorConfig
+
+- (id)initWithAssociations:(NSDictionary *)_config {
+  if ((self = [super initWithAssociations:_config])) {
+    self->titleColor  = WOExtGetProperty(_config, @"titleColor");
+    self->headerColor = WOExtGetProperty(_config, @"headerColor");
+    self->footerColor = WOExtGetProperty(_config, @"footerColor");
+    self->evenColor   = WOExtGetProperty(_config, @"evenColor");
+    self->oddColor    = WOExtGetProperty(_config, @"oddColor");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->titleColor  release];
+  [self->headerColor release];
+  [self->footerColor release];
+  [self->evenColor   release];
+  [self->oddColor    release];
+  [super dealloc];
+}
+
+- (void)updateConfigInContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSString    *tmp;
+
+  cmp = [_ctx component];
+  
+#define SetConfigInContext(_a_, _key_)           \
+  if (_a_ && (tmp = [_a_ valueInComponent:cmp])) \
+    [_ctx setObject:tmp forKey:_key_];
+  
+  SetConfigInContext(self->titleColor,      WETableView_titleColor);
+  SetConfigInContext(self->headerColor,     WETableView_headerColor);
+  SetConfigInContext(self->footerColor,     WETableView_footerColor);
+  SetConfigInContext(self->evenColor,       WETableView_evenColor);
+  SetConfigInContext(self->oddColor,        WETableView_oddColor);
+#undef SetConfigInContext
+}
+
+@end /* WETableViewColorConfig */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewConfigObject.h b/skyrix-sope/WEExtensions/WETableView/WETableViewConfigObject.h
new file mode 100644 (file)
index 0000000..4b877d2
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WEExtensions_WETableViewConfigObject_H__
+#define __WEExtensions_WETableViewConfigObject_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSDictionary;
+@class WOAssociation, WOContext;
+
+@interface WETableViewConfigObject : NSObject
+{
+}
+
+- (id)initWithAssociations:(NSDictionary *)_config;
+- (void)updateConfigInContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __WEExtensions_WETableViewConfigObject_H__ */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewConfigObject.m b/skyrix-sope/WEExtensions/WETableView/WETableViewConfigObject.m
new file mode 100644 (file)
index 0000000..55be0ff
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WETableViewConfigObject.h"
+#include "common.h"
+
+@implementation WETableViewConfigObject
+
+- (id)initWithAssociations:(NSDictionary *)_config {
+  return [super init];
+}
+- (id)init {
+  return [self initWithAssociations:nil];
+}
+
+- (void)updateConfigInContext:(WOContext *)_ctx {
+}
+
+@end /* WETableViewConfigObject */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewDefines.h b/skyrix-sope/WEExtensions/WETableView/WETableViewDefines.h
new file mode 100644 (file)
index 0000000..58648c7
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WETableViewDefines_H__
+#define __WETableViewDefines_H__
+
+#define WETableView_              @"WETableView_"
+#define WETableView_TitleMode     @"WETableView_TitleMode"
+#define WETableView_ButtonMode    @"WETableView_ButtonMode"
+#define WETableView_CollectMode   @"WETableView_CollectMode"
+#define WETableView_HeaderMode    @"WETableView_HeaderMode"
+#define WETableView_DataMode      @"WETableView_DataMode"
+#define WETableView_FooterMode    @"WETableView_FooterMode"
+#define WETableView_GroupMode     @"WETableView_GroupMode"
+
+#define WETableView_INFOS         @"WETableView_INFOS"
+#define WETableView_SORTEDKEY     @"WETableView_SORTEDKEY"
+#define WETableView_ISDESCENDING  @"WETableView_ISDESCENDING"
+
+#define WETableView_HasCollapseScript @"WETableView_HasCollapseScript"
+
+// config stuff:
+#define WETableView_titleColor    @"WETableView_titleColor"
+#define WETableView_headerColor   @"WETableView_headerColor"
+#define WETableView_footerColor   @"WETableView_footerColor"
+#define WETableView_evenColor     @"WETableView_evenColor"
+#define WETableView_oddColor      @"WETableView_oddColor"
+#define WETableView_fontColor     @"WETableView_fontColor"
+#define WETableView_fontFace      @"WETableView_fontFace"
+#define WETableView_fontSize      @"WETableView_fontSize"
+
+// sort icons:
+#define WETableView_upwardIcon    @"WETableView_upwardIcon"
+#define WETableView_downwardIcon  @"WETableView_downwardIcon"
+#define WETableView_nonSortIcon   @"WETableView_nonSortIcon"
+
+// navigation icons
+#define WETableView_first           @"WETableView_first"
+#define WETableView_first_blind     @"WETableView_first_blind"
+#define WETableView_previous        @"WETableView_previous"
+#define WETableView_previous_blind  @"WETableView_previous_blind"
+#define WETableView_next            @"WETableView_next"
+#define WETableView_next_blind      @"WETableView_next_blind"
+#define WETableView_last            @"WETableView_last"
+#define WETableView_last_blind      @"WETableView_last_blind"
+#define WETableView_select_all      @"WETableView_select_all"
+#define WETableView_deselect_all    @"WETableView_deselect_all"
+
+// labels
+#define WETableView_ofLabel         @"WETableView_ofLabel"
+#define WETableView_toLabel         @"WETableView_toLabel"
+#define WETableView_firstLabel      @"WETableView_firstLabel"
+#define WETableView_previousLabel   @"WETableView_previousLabel"
+#define WETableView_nextLabel       @"WETableView_nextLabel"
+#define WETableView_lastLabel       @"WETableView_lastLabel"
+#define WETableView_pageLabel       @"WETableView_pageLabel"
+#define WETableView_sortLabel       @"WETableView_sortLabel"
+
+#endif /* __WETableViewDefines_H__ */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewFooterMode.m b/skyrix-sope/WEExtensions/WETableView/WETableViewFooterMode.m
new file mode 100644 (file)
index 0000000..45fc7ac
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WEContextConditional.h"
+
+@interface WETableViewFooterMode: WEContextConditional
+@end
+
+#include "WETableViewDefines.h"
+#include "common.h"
+
+@implementation WETableViewFooterMode
+
+- (NSString *)_contextKey {
+  return WETableView_FooterMode;
+}
+
+@end /* WETableViewFooterMode */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewGroupMode.m b/skyrix-sope/WEExtensions/WETableView/WETableViewGroupMode.m
new file mode 100644 (file)
index 0000000..a81d622
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WEContextConditional.h"
+
+@interface WETableViewGroupMode: WEContextConditional
+@end
+
+#include "WETableViewDefines.h"
+#include "common.h"
+
+@implementation WETableViewGroupMode
+
+- (NSString *)_contextKey {
+  return WETableView_GroupMode;
+}
+
+@end /* WETableViewGroupMode */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewIconConfig.h b/skyrix-sope/WEExtensions/WETableView/WETableViewIconConfig.h
new file mode 100644 (file)
index 0000000..c1e7b07
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WEExtensions_WETableViewIconConfig_H__
+#define __WEExtensions_WETableViewIconConfig_H__
+
+#include "WETableViewConfigObject.h"
+
+@interface WETableViewIconConfig : WETableViewConfigObject
+{
+@public
+  WOAssociation  *plusResizeIcon;
+  WOAssociation  *minusResizeIcon;
+@private
+  WOAssociation  *downwardIcon;  // downwardSortIcon
+  WOAssociation  *upwardIcon;    // upwardSortIcon
+  WOAssociation  *nonSortIcon;   // nonSortIcon
+  WOAssociation  *firstIcon;
+  WOAssociation  *firstBlind;    // firstBlindIcon
+  WOAssociation  *previousIcon;
+  WOAssociation  *previousBlind; // previousBlindIcon
+  WOAssociation  *nextIcon;
+  WOAssociation  *nextBlind;     // nextBlindIcon
+  WOAssociation  *lastIcon;
+  WOAssociation  *lastBlind;     // lastBlindIcon
+  WOAssociation  *selectAllIcon;
+  WOAssociation  *deselectAllIcon;
+}
+
+@end
+
+#endif /* __WEExtensions_WETableViewIconConfig_H__ */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewIconConfig.m b/skyrix-sope/WEExtensions/WETableView/WETableViewIconConfig.m
new file mode 100644 (file)
index 0000000..3607b7c
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WETableViewIconConfig.h"
+#include "WETableViewDefines.h"
+#include "common.h"
+
+@implementation WETableViewIconConfig
+
+- (id)initWithAssociations:(NSDictionary *)_config {
+  if ((self = [super initWithAssociations:_config])) {
+    self->downwardIcon    = WOExtGetProperty(_config, @"downwardSortIcon");
+    self->upwardIcon      = WOExtGetProperty(_config, @"upwardSortIcon");
+    self->nonSortIcon     = WOExtGetProperty(_config, @"nonSortIcon");
+
+    self->firstIcon       = WOExtGetProperty(_config, @"firstIcon");
+    self->firstBlind      = WOExtGetProperty(_config, @"firstBlindIcon");
+    self->previousIcon    = WOExtGetProperty(_config, @"previousIcon");
+    self->previousBlind   = WOExtGetProperty(_config, @"previousBlindIcon");
+    self->nextIcon        = WOExtGetProperty(_config, @"nextIcon");
+    self->nextBlind       = WOExtGetProperty(_config, @"nextBlindIcon");
+    self->lastIcon        = WOExtGetProperty(_config, @"lastIcon");
+    self->lastBlind       = WOExtGetProperty(_config, @"lastBlindIcon");
+    self->selectAllIcon   = WOExtGetProperty(_config, @"selectAllIcon");
+    self->deselectAllIcon = WOExtGetProperty(_config, @"deselectAllIcon");
+    self->plusResizeIcon  = WOExtGetProperty(_config, @"plusResizeIcon");
+    self->minusResizeIcon = WOExtGetProperty(_config, @"minusResizeIcon");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->downwardIcon  release];
+  [self->upwardIcon    release];
+  [self->nonSortIcon   release];
+  [self->firstIcon     release];
+  [self->firstBlind    release];
+  [self->previousIcon  release];
+  [self->previousBlind release];
+  [self->nextIcon      release];
+  [self->nextBlind     release];
+  [self->lastIcon      release];
+  [self->lastBlind     release];
+  [self->selectAllIcon   release];
+  [self->deselectAllIcon release];
+  [self->plusResizeIcon  release];
+  [self->minusResizeIcon release];
+  [super dealloc];
+}
+
+- (void)updateConfigInContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSString    *tmp;
+
+  cmp = [_ctx component];
+  
+#define SetConfigInContext(_a_, _key_)                                  \
+      if (_a_ && (tmp = [_a_ valueInComponent:cmp]))                    \
+        [_ctx setObject:tmp forKey:_key_];                              \
+
+  SetConfigInContext(self->downwardIcon,    WETableView_downwardIcon);
+  SetConfigInContext(self->upwardIcon,      WETableView_upwardIcon);
+  SetConfigInContext(self->nonSortIcon,     WETableView_nonSortIcon);
+  
+  SetConfigInContext(self->firstIcon,       WETableView_first);
+  SetConfigInContext(self->firstBlind,      WETableView_first_blind);
+  SetConfigInContext(self->previousIcon,    WETableView_previous);
+  SetConfigInContext(self->previousBlind,   WETableView_previous_blind);
+  SetConfigInContext(self->nextIcon,        WETableView_next);
+  SetConfigInContext(self->nextBlind,       WETableView_next_blind);
+  SetConfigInContext(self->lastIcon,        WETableView_last);
+  SetConfigInContext(self->lastBlind,       WETableView_last_blind);
+  SetConfigInContext(self->selectAllIcon,   WETableView_select_all);
+  SetConfigInContext(self->deselectAllIcon, WETableView_deselect_all);
+#undef SetConfigInContext
+}
+
+@end /* WETableViewIconConfig */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewInfo.h b/skyrix-sope/WEExtensions/WETableView/WETableViewInfo.h
new file mode 100644 (file)
index 0000000..d7a6e21
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WETableViewInfo_H__
+#define __WETableViewInfo_H__
+
+#import <Foundation/NSObject.h>
+
+@interface WETableViewInfo: NSObject
+{
+@public
+  unsigned rowSpan;
+  BOOL     isGroup;
+  BOOL     isEven;
+  BOOL     isSorted;
+}
+@end
+
+#endif /* __WETableViewInfo_H__ */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewLabelConfig.h b/skyrix-sope/WEExtensions/WETableView/WETableViewLabelConfig.h
new file mode 100644 (file)
index 0000000..bf4a3c6
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WEExtensions_WETableViewLabelConfig_H__
+#define __WEExtensions_WETableViewLabelConfig_H__
+
+#include "WETableViewConfigObject.h"
+
+@interface WETableViewLabelConfig : WETableViewConfigObject
+{
+  WOAssociation  *ofLabel;
+  WOAssociation  *toLabel;
+  WOAssociation  *firstLabel;
+  WOAssociation  *previousLabel;
+  WOAssociation  *nextLabel;
+  WOAssociation  *lastLabel;
+  WOAssociation  *pageLabel;
+  WOAssociation  *sortLabel;
+}
+
+@end
+
+#endif /* __WEExtensions_WETableViewLabelConfig_H__ */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewLabelConfig.m b/skyrix-sope/WEExtensions/WETableView/WETableViewLabelConfig.m
new file mode 100644 (file)
index 0000000..d17ceac
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WETableViewLabelConfig.h"
+#include "WETableViewDefines.h"
+#include "common.h"
+
+@implementation WETableViewLabelConfig
+
+- (id)initWithAssociations:(NSDictionary *)_config {
+  if ((self = [super initWithAssociations:_config])) {
+    self->ofLabel        = WOExtGetProperty(_config, @"ofLabel");
+    self->toLabel        = WOExtGetProperty(_config, @"toLabel");
+    self->firstLabel     = WOExtGetProperty(_config, @"firstLabel");
+    self->previousLabel  = WOExtGetProperty(_config, @"previousLabel");
+    self->nextLabel      = WOExtGetProperty(_config, @"nextLabel");
+    self->lastLabel      = WOExtGetProperty(_config, @"lastLabel");
+    self->pageLabel      = WOExtGetProperty(_config, @"pageLabel");
+    self->sortLabel      = WOExtGetProperty(_config, @"sortLabel");
+
+    /* defaults */
+#define SetAssociationValue(_a_, _value_) \
+         if (_a_ == nil)                  \
+           _a_ = [[WOAssociation associationWithValue:_value_] retain];
+    
+    SetAssociationValue(self->ofLabel,       @"/");
+    SetAssociationValue(self->toLabel,       @"-");
+    SetAssociationValue(self->firstLabel,    @"<<");
+    SetAssociationValue(self->previousLabel, @"<");
+    SetAssociationValue(self->nextLabel,     @">");
+    SetAssociationValue(self->lastLabel,     @">>");
+    SetAssociationValue(self->pageLabel,     @"Page");
+    SetAssociationValue(self->sortLabel,     @"sort column");
+#undef SetAssociationValue
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->ofLabel       release];
+  [self->toLabel       release];
+  [self->firstLabel    release];
+  [self->previousLabel release];
+  [self->nextLabel release];
+  [self->lastLabel release];
+  [self->pageLabel release];
+  [self->sortLabel release];
+  [super dealloc];
+}
+
+- (void)updateConfigInContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSString    *tmp;
+
+  cmp = [_ctx component];
+  
+#define SetConfigInContext(_a_, _key_)                                  \
+      if (_a_ && (tmp = [_a_ valueInComponent:cmp]))                    \
+        [_ctx setObject:tmp forKey:_key_];
+  SetConfigInContext(self->ofLabel,         WETableView_ofLabel);
+  SetConfigInContext(self->toLabel,         WETableView_toLabel);
+  SetConfigInContext(self->firstLabel,      WETableView_firstLabel);
+  SetConfigInContext(self->previousLabel,   WETableView_previousLabel);
+  SetConfigInContext(self->nextLabel,       WETableView_nextLabel);
+  SetConfigInContext(self->lastLabel,       WETableView_lastLabel);
+  SetConfigInContext(self->pageLabel,       WETableView_pageLabel);
+  SetConfigInContext(self->sortLabel,       WETableView_sortLabel);
+#undef SetConfigInContext
+}
+
+@end /* WETableViewLabelConfig */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewState.h b/skyrix-sope/WEExtensions/WETableView/WETableViewState.h
new file mode 100644 (file)
index 0000000..590596d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WEExtensions_WETableViewState_H__
+#define __WEExtensions_WETableViewState_H__
+
+#import <Foundation/NSObject.h>
+
+@interface WETableViewState : NSObject
+{
+@public
+  unsigned currentBatch;
+  unsigned batchSize;
+  unsigned firstIndex;
+  unsigned lastIndex;
+  unsigned batchCount;
+  unsigned groupCount;
+  BOOL     doCheckBoxes;
+  BOOL     doOverflow;         // generate overflow-scrolling
+  BOOL     doScriptScrolling;  // scroll pages per JavaScript
+  BOOL     doScriptCollapsing; // collapse groups per JavaScript
+  BOOL     showBatchResizeButtons;
+}
+
+@end
+
+#endif /* __WEExtensions_WETableViewState_H__ */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewState.m b/skyrix-sope/WEExtensions/WETableView/WETableViewState.m
new file mode 100644 (file)
index 0000000..dc53c26
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WETableViewState.h"
+#include "common.h"
+
+@implementation WETableViewState
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+@end /* WETableViewState */
diff --git a/skyrix-sope/WEExtensions/WETableView/WETableViewTitleMode.m b/skyrix-sope/WEExtensions/WETableView/WETableViewTitleMode.m
new file mode 100644 (file)
index 0000000..4916946
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WEContextConditional.h"
+
+@interface WETableViewTitleMode: WEContextConditional
+@end
+
+#include "WETableViewDefines.h"
+#include "common.h"
+
+@implementation WETableViewTitleMode
+
+- (NSString *)_contextKey {
+  return WETableView_TitleMode;
+}
+
+@end /* WETableViewTitleMode */
diff --git a/skyrix-sope/WEExtensions/WETimeField.m b/skyrix-sope/WEExtensions/WETimeField.m
new file mode 100644 (file)
index 0000000..8dbcd56
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WECalendarField.h"
+
+/*
+  WETimeField
+
+  A subclass of WECalendarField which just renders the time.
+*/
+
+@interface WETimeField : WECalendarField
+@end
+
+@implementation WETimeField
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  [self _takeValuesFromTimeFieldRequest:_rq inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  return [self _invokeActionForTimeFieldRequest:_rq inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [self _appendTimeFieldToResponse:_response inContext:_ctx];
+}
+
+@end /* WETimeField */
diff --git a/skyrix-sope/WEExtensions/WETreeContextKeys.h b/skyrix-sope/WEExtensions/WETreeContextKeys.h
new file mode 100644 (file)
index 0000000..522a5f7
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __WEExtensions_WETreeContextKeys_H__
+#define __WEExtensions_WETreeContextKeys_H__
+
+#import <Foundation/NSString.h>
+
+extern NSString *WETreeView_HEADER_MODE;
+extern NSString *WETreeView_ZOOM_ACTION_ID;
+
+extern NSString *WETreeView_TreeElement;
+extern NSString *WETreeView_RenderNoTable;
+
+extern NSString *WETreeView_IconWidth;
+extern NSString *WETreeView_Plus;
+extern NSString *WETreeView_Minus;
+extern NSString *WETreeView_Leaf;
+extern NSString *WETreeView_Line;
+extern NSString *WETreeView_Junction;
+extern NSString *WETreeView_Corner;
+extern NSString *WETreeView_CornerPlus;
+extern NSString *WETreeView_CornerMinus;
+extern NSString *WETreeView_CornerLeaf;
+extern NSString *WETreeView_Space;
+
+#endif /* __WEExtensions_WETreeContextKeys_H__ */
diff --git a/skyrix-sope/WEExtensions/WETreeData.m b/skyrix-sope/WEExtensions/WETreeData.m
new file mode 100644 (file)
index 0000000..2ae9121
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+  Copyright (C) 2000-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$
+
+/*
+  WETreeDate
+
+  Take a look at WETreeView for more information.
+
+  WETreeData associations:
+    isTreeElement
+    icon
+    cornerIcon
+    title
+    string
+
+  Example:
+      TreeDataCell: WETreeData {
+        isTreeElement = YES; // this is a tree cell (that means, it has plus
+                             // and minus icons and all that stuff)
+      }
+      DataCell: WETreeData {
+        isTreeElement = NO;  // this is NOT a  tree cell, i.e. it does NOT
+                             // have any plus or minus icons. (This is just a
+                             // ordinary <td></td>!!!)
+      }
+*/
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WETreeData : WODynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *isTreeElement;
+  WOAssociation *title;
+  WOAssociation *string;
+  WOAssociation *icon;
+  WOAssociation *cornerIcon;
+  
+  BOOL          doTable;
+  WOElement     *template;
+}
+
+@end
+
+#include "WETreeContextKeys.h"
+#include "WETreeMatrixElement.h"
+#include "common.h"
+
+@implementation WETreeData
+
+static Class StrClass = Nil;
+
++ (void)initialize {
+  StrClass = [NSString class];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_root
+{
+  if ((self = [super initWithName:_name associations:_config template:_root])){
+    self->isTreeElement = WOExtGetProperty(_config, @"isTreeElement");
+    self->icon          = WOExtGetProperty(_config, @"icon");
+    self->cornerIcon    = WOExtGetProperty(_config, @"cornerIcon");
+    self->title         = WOExtGetProperty(_config, @"title");
+    self->string        = WOExtGetProperty(_config, @"string");
+
+    self->template = [_root retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->isTreeElement release];
+  [self->icon          release];
+  [self->cornerIcon    release];
+  [self->title         release];
+  [self->string        release];
+  [self->template      release];
+  [super dealloc];
+}
+
+/* HTML generation */
+
+- (void)_appendIcon:(NSString *)_icon alt:(NSString *)_alt
+  toResponse:(WOResponse *)_response inContext:(WOContext *)_ctx
+{
+  NSString *iconWidth;
+  
+  iconWidth = [_ctx objectForKey:WETreeView_IconWidth];
+  
+  [_response appendContentString:@"<img border=\"0\" src=\""];
+  [_response appendContentHTMLAttributeValue:_icon];
+  [_response appendContentString:@"\""];
+  
+  if ([iconWidth length] > 0) {
+    [_response appendContentString:@" width=\""];
+    [_response appendContentString:iconWidth];
+    [_response appendContentString:@"\""];
+  }
+  if ([_alt length] > 0) {
+    [_response appendContentString:@" alt=\""];
+    [_response appendContentHTMLAttributeValue:_alt];
+    [_response appendContentString:@"\""];
+  }
+  
+  [_response appendContentString:@" />"];
+}
+
+- (void)_appendLink:(NSString *)_icon resp:(WOResponse *)_response
+  ctx:(WOContext *)_ctx
+{
+  BOOL doForm = [_ctx isInForm];
+
+  doForm = NO;
+  
+  if (doForm) {
+    [_response appendContentString:@"<input type=\"image\" border=\"0\""];
+    [_response appendContentString:@" align=\"top\" name=\""];
+    [_response appendContentString:[_ctx elementID]];
+    [_response appendContentString:@"\" src=\""];
+    [_response appendContentString:_icon];
+    [_response appendContentString:@"\" />"];
+  }
+  else {
+    [_ctx appendElementIDComponent:WETreeView_ZOOM_ACTION_ID];
+    [_response appendContentString:@"<a href=\""];
+    [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentString:@"\">"];
+    [self _appendIcon:_icon alt:@"z" toResponse:_response inContext:_ctx];
+    [_response appendContentString:@"</a>"];
+    [_ctx deleteLastElementIDComponent];
+  }
+}
+
+- (void)_appendTreeElement:(NSString *)_key
+  toResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  BOOL     doLink;
+  NSString *img;
+  
+  doLink = (_key == WETreeView_Plus   || _key == WETreeView_CornerPlus ||
+            _key == WETreeView_Minus  || _key == WETreeView_CornerMinus);
+  
+  img    = [_ctx objectForKey:_key];
+  img    = WEUriOfResource(img, _ctx);
+
+  if (_key == WETreeView_Leaf) {
+    NSString *tmp = [self->icon stringValueInComponent:[_ctx component]];
+    
+    tmp = WEUriOfResource(tmp, _ctx);
+    img = (tmp) ? tmp : img;    
+  }
+  else if (_key == WETreeView_CornerLeaf) {
+    NSString *tmp = [self->cornerIcon stringValueInComponent:[_ctx component]];
+    tmp = WEUriOfResource(tmp, _ctx);
+    img = (tmp) ? tmp : img;
+  }
+  
+  if (img == nil) {
+    if (doLink) {
+      [_ctx appendElementIDComponent:WETreeView_ZOOM_ACTION_ID];
+      [_response appendContentString:@"<a href=\""];
+      [_response appendContentString:[_ctx componentActionURL]];
+      [_response appendContentString:@"\">"];
+
+      if (_key == WETreeView_Plus || _key == WETreeView_CornerPlus)
+        [_response appendContentString:@"<tt>[+]</tt>"];
+      else if (_key == WETreeView_Minus || _key == WETreeView_CornerMinus)
+        [_response appendContentString:@"<tt>[-]</tt>"];
+    
+      [_response appendContentString:@"</a>"];
+      [_ctx deleteLastElementIDComponent];
+    }
+    else if (_key == WETreeView_Leaf)
+      [_response appendContentString:@"<tt>--&nbsp;</tt>"];
+    else if (_key == WETreeView_CornerLeaf)
+      [_response appendContentString:@"<tt>-|&nbsp;</tt>"];
+    else if (_key == WETreeView_Line)
+      [_response appendContentString:@"<tt>&nbsp;|&nbsp;</tt>"];
+    else if (_key == WETreeView_CornerLeaf)
+      [_response appendContentString:@"<tt>&nbsp;--</tt>"];
+    else if (_key == WETreeView_Junction || _key == WETreeView_Corner)
+      [_response appendContentString:@"<tt>&nbsp;|-</tt>"];
+    else if (_key == WETreeView_Space)
+      [_response appendContentString:@"<tt>&nbsp;&nbsp;&nbsp;</tt>"];
+  }
+  else {
+    if (doLink)
+      [self _appendLink:img resp:_response ctx:_ctx];
+    else
+      [self _appendIcon:img alt:@"z" toResponse:_response inContext:_ctx];
+  }
+}
+
+- (void)appendHeader:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *cmp   = [_ctx component];
+  NSString    *tmp   = [self->title stringValueInComponent:cmp];
+  BOOL        isTree = [self->isTreeElement boolValueInComponent:cmp];;
+
+  if (tmp == nil)
+    return;
+  
+  if (self->doTable) {
+    [_response appendContentString:@"<td"];
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    if (self->otherTagString) {
+        [_response appendContentString:
+                   [self->otherTagString stringValueInComponent:
+                        [_ctx component]]];
+    }
+    if (isTree) {
+        [_response appendContentString:@" colspan=\""];
+        [_response appendContentString:
+                   [[_ctx objectForKey:WETreeView_HEADER_MODE] stringValue]];
+        [_response appendContentString:@"\"><nobr>"];
+    }
+    else
+      [_response appendContentString:@"><nobr>"];
+  }
+  
+  [_response appendContentString:@"<b>"];
+  [_response appendContentHTMLString:tmp];
+  [_response appendContentString:@"</b>"];
+  
+  if (doTable)
+    [_response appendContentString:@"</nobr></td>"];
+}
+
+- (void)appendData:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  /* TODO: split up this method */
+  _WETreeMatrixElement *treeElement;
+  WOComponent *cmp       = nil;
+  BOOL        isTree     = NO;
+  NSString    *content   = nil;
+  int         i;
+
+  cmp         = [_ctx component];
+  isTree      = [self->isTreeElement boolValueInComponent:cmp];
+  content     = [self->string stringValueInComponent:cmp];
+  treeElement = [_ctx objectForKey:WETreeView_TreeElement];
+
+  if (isTree) {
+    for (i = 0; i < [treeElement depth]+1; i++) {
+      NSString *iconWidth;
+      NSString *treeElm;
+
+      iconWidth = [_ctx objectForKey:WETreeView_IconWidth];
+      
+      treeElm = (i < [treeElement depth])
+        ? [treeElement elementAtIndex:i]
+        : [treeElement leaf];
+
+      if (self->doTable) {
+        [_response appendContentString:@"<td"];
+        [self appendExtraAttributesToResponse:_response inContext:_ctx];
+        [_response appendContentString:@" valign=\"middle\" align=\"center\""];
+        
+        if (iconWidth) {
+          NSString *s;
+          s = [[StrClass alloc] initWithFormat:@" width=\"%@\"", iconWidth];
+          [_response appendContentString:s];
+          [s release];
+        }
+        
+        if (treeElm == WETreeView_Plus     || treeElm == WETreeView_Minus ||
+            treeElm == WETreeView_Junction || treeElm == WETreeView_Line) {
+          NSString *img;
+          
+          img = [_ctx objectForKey:WETreeView_Line];
+          img = WEUriOfResource(img, _ctx);
+          if (img) {
+            [_response appendContentString:@" background=\""];
+            [_response appendContentString:img];
+            [_response appendContentCharacter:'"'];
+          }
+        }
+        [_response appendContentString:@"><nobr>"];
+      }
+        
+      [self _appendTreeElement:treeElm toResponse:_response inContext:_ctx];
+      if (self->doTable)
+        [_response appendContentString:@"</nobr></td>"];
+    }
+
+    if (self->doTable) {
+      [_response appendContentString:@"<td"];
+      [self appendExtraAttributesToResponse:_response inContext:_ctx];
+      [_response appendContentString:@" width='97%'"];
+      [_response appendContentString:@" valign='middle' align='left'"];
+      [_response appendContentString:@" colspan=\""];
+      [_response appendContentString:[treeElement colspanAsString]];
+      [_response appendContentString:@"\">"];
+    }
+    
+    /* add cell content */
+    [self->template appendToResponse:_response inContext:_ctx];
+    if (content)
+      [_response appendContentHTMLString:content];
+    
+    if (self->doTable)
+      [_response appendContentString:@"</td>"];
+  }
+  else { // ! isTree
+    if (self->doTable) {
+      [_response appendContentString:@"<td"];
+      [self appendExtraAttributesToResponse:_response inContext:_ctx];
+      if (self->otherTagString) {
+        [_response appendContentString:
+                   [self->otherTagString stringValueInComponent:
+                        [_ctx component]]];
+      }
+      [_response appendContentCharacter:'>'];
+    }
+    
+    /* add cell content */
+    [self->template appendToResponse:_response inContext:_ctx];
+    if (content) [_response appendContentHTMLString:content];
+
+    if (self->doTable)
+      [_response appendContentString:@"</td>"];
+  }
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  [self->template takeValuesFromRequest:_rq inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_rq inContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  self->doTable = ([_ctx objectForKey:WETreeView_RenderNoTable] == nil);
+  
+  if ([_ctx objectForKey:WETreeView_HEADER_MODE])
+    [self appendHeader:_response inContext:_ctx];
+  else
+    [self appendData:_response inContext:_ctx];
+}
+
+@end /* WETreeData */
diff --git a/skyrix-sope/WEExtensions/WETreeHeader.m b/skyrix-sope/WEExtensions/WETreeHeader.m
new file mode 100644 (file)
index 0000000..65a2be6
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  WETreeHeader
+
+  Take a look at WETreeView for more information.
+
+  WETreeHeader associations:
+    isTreeElement
+    icon
+    cornerIcon
+    title
+    string
+
+  Example:
+      TreeHeaderCell: WETreeHeader {
+        isTreeElement = YES;
+      }
+      HeaderCell: WETreeHeader {
+        isTreeElement = NO;
+      }
+*/
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WETreeHeader : WODynamicElement
+{
+@protected
+  WOAssociation  *isTreeElement;
+  WOElement      *template;
+  WOAssociation  *string;
+}
+@end
+
+#include "WETreeContextKeys.h"
+#include "common.h"
+
+@implementation WETreeHeader
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self=[super initWithName:_name associations:_config template:_subs])) {
+    self->isTreeElement = WOExtGetProperty(_config, @"isTreeElement");
+    self->string        = WOExtGetProperty(_config, @"string");
+    
+    self->template      = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->string        release];
+  [self->isTreeElement release];
+  [self->template      release];
+  [super dealloc];
+}
+
+/* request processing */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  [self->template takeValuesFromRequest:_rq inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_rq inContext:_ctx];
+}
+
+/* response generation */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *content;
+  BOOL isTree;
+  BOOL doTable;
+
+  if (![_ctx objectForKey:WETreeView_HEADER_MODE])
+    return;
+    
+  isTree  = [self->isTreeElement boolValueInComponent:[_ctx component]];
+  doTable = ([_ctx objectForKey:WETreeView_RenderNoTable] == nil);
+  content = [self->string        stringValueInComponent:[_ctx component]];
+    
+  if (doTable) {
+    [_response appendContentString:@"<td"];
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    if (self->otherTagString) {
+      [_response appendContentString:
+                 [self->otherTagString stringValueInComponent:
+                      [_ctx component]]];
+    }
+    if (isTree) {
+      [_response appendContentString:@" colspan=\""];
+      [_response appendContentString:
+                 [[_ctx objectForKey:WETreeView_HEADER_MODE] stringValue]];
+      [_response appendContentString:@"\"><nobr>"];
+    }
+    else
+      [_response appendContentString:@"><nobr>"];
+  }
+    
+  /* add cell content */
+  [self->template appendToResponse:_response inContext:_ctx];
+  if (content)
+    [_response appendContentHTMLString:content];
+
+  if (doTable)
+    [_response appendContentString:@"</nobr></td>"];
+}
+
+@end /* WETreeHeader */
diff --git a/skyrix-sope/WEExtensions/WETreeMatrixElement.h b/skyrix-sope/WEExtensions/WETreeMatrixElement.h
new file mode 100644 (file)
index 0000000..54a2ec0
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __WEExtensions_WETreeMatrixElement_H__
+#define __WEExtensions_WETreeMatrixElement_H__
+
+#import <Foundation/NSString.h>
+
+#define MAX_TREE_DEPTH 11  /* max recursion depth is 10 */
+
+@interface _WETreeMatrixElement : NSObject
+{
+@protected
+  int      depth;
+  NSString *leaf;
+  NSString *elements[MAX_TREE_DEPTH];
+  id       itemPath[MAX_TREE_DEPTH];      // --> currentPath
+  int      indexPath[MAX_TREE_DEPTH];
+  int      colspan;
+}
+
+- (id)initWithElement:(_WETreeMatrixElement *)_element;
+- (void)setLeaf:(NSString *)_leaf;
+- (void)setElement:(NSString *)_element;
+- (void)setItem:(id)_item;
+- (void)setIndex:(int)_index;
+
+- (NSString *)leaf;
+- (int)index;
+- (id)item;
+- (NSArray *)currentPath;
+
+- (NSString *)elementAtIndex:(int)_index;
+- (int)depth;
+- (void)setColspan:(int)_colspan;
+- (NSString *)colspanAsString;
+- (NSString *)elementID;
+
+@end
+
+#endif /* __WEExtensions_WETreeMatrixElement_H__ */
diff --git a/skyrix-sope/WEExtensions/WETreeMatrixElement.m b/skyrix-sope/WEExtensions/WETreeMatrixElement.m
new file mode 100644 (file)
index 0000000..7dd046c
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "WETreeMatrixElement.h"
+#include "common.h"
+
+@implementation _WETreeMatrixElement
+
+static Class StrClass = Nil;
+
++ (void)initialize {
+  StrClass = [NSString class];
+}
+
+- (id)initWithElement:(_WETreeMatrixElement *)_element {
+  if ((self = [super init])) {
+    int j;
+    
+    for (j = 0; j < MAX_TREE_DEPTH; j++)
+      self->elements[j] = 0;
+    
+    if (_element) {
+      int i;
+      
+      self->depth = _element->depth + 1;
+      for (i = 0; i < self->depth; i++) {
+        self->leaf         = _element->leaf;
+        self->elements[i]  = [_element->elements[i] retain];
+        self->indexPath[i] = _element->indexPath[i];
+        self->itemPath[i]  = [_element->itemPath[i] retain];
+      }
+    }
+    else
+      self->depth = 0;
+  }
+  return self;  
+}
+
+- (id)init {
+  return [self initWithElement:nil];
+}
+
+- (void)dealloc {
+  int i;
+
+  for (i = 0; i < self->depth; i++) {
+    [self->itemPath[i] release];
+    [self->elements[i] release];
+  }
+  [super dealloc];
+}
+
+/* accessors */
+  
+- (void)setElement:(NSString *)_element {
+  ASSIGN(self->elements[self->depth], _element);
+}
+- (NSString *)elementAtIndex:(int)_index {
+  return self->elements[_index];
+}
+
+- (void)setItem:(id)_item {
+  ASSIGN(self->itemPath[self->depth], _item);
+}
+- (id)item {
+  return self->itemPath[self->depth-1];
+}
+
+- (void)setIndex:(int)_index {
+  self->indexPath[self->depth] = _index;
+}
+- (int)index {
+  return self->indexPath[self->depth-1];
+}
+
+- (void)setLeaf:(NSString *)_leaf {
+  ASSIGN(self->leaf, _leaf);
+}
+- (NSString *)leaf {
+  return self->leaf;
+}
+
+- (void)setColspan:(int)_colspan {
+  self->colspan = _colspan;
+}
+
+- (NSString *)colspanAsString {
+  unsigned char buf[8];
+  sprintf(buf, "%d", self->colspan);
+  return [NSString stringWithCString:buf];
+}
+
+- (int)depth {
+  return self->depth;
+}
+
+- (NSArray *)currentPath {
+  NSMutableArray *result;
+  int            i;
+
+  result = [NSMutableArray arrayWithCapacity:self->depth];
+  for (i = 0; i < self->depth+1; i++) {
+    if (self->itemPath[i] == nil)
+      break;
+    [result addObject:self->itemPath[i]];
+  }
+  return (NSArray *)result;
+}
+
+- (NSString *)elementID {
+  // TODO: improve performance
+  NSMutableArray *tmp;
+  NSString *s;
+  int            i;
+  
+  tmp = [[NSMutableArray alloc] initWithCapacity:self->depth];
+  
+  for (i = 0; i < self->depth; i++) {
+    s = [[StrClass alloc] initWithFormat:@"%d", self->indexPath[i]];
+    [tmp addObject:s];
+    [s release];
+  }
+  s = [tmp componentsJoinedByString:@"."];
+  [tmp release];
+  return s;
+}
+
+@end /* _WETreeMatrixElement */
diff --git a/skyrix-sope/WEExtensions/WETreeView.m b/skyrix-sope/WEExtensions/WETreeView.m
new file mode 100644 (file)
index 0000000..8f6d3a1
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  WETreeView
+  
+  A WETreeView is very similiar to a WETableView (eg it can have arbitary
+  columns), but can also show/manage a tree of objects.
+  
+  TODO: we should support a cookie to store the tree hiearchy for stateless 
+        servers like the Zope tree. This probably needs to be implemented in
+        takeValues (cookie decoding) and appendToResponse (cookie encoding).
+        Zooming (invokeAction) needs to ignore? the component-id in case the
+        cookie is set and somehow work based on cookie data.
+  
+  WETreeView associations:
+    list & sublist & (item | index | currentPath)
+    itemIsLeaf
+    showItem
+    zoom
+    string
+
+    noTable
+
+    // config:
+    iconWidth
+    plusIcon 
+    minusIcon
+    leafIcon
+    junctionIcon
+    cornerIcon
+    cornerPlusIcon
+    cornerMinusIcon
+    leafCornerIcon
+    lineIcon
+
+  WETreeHeader associations:
+    isTreeElement
+    icon
+    cornerIcon
+    title
+    string
+
+  WETreeData associations:
+    isTreeElement
+    icon
+    cornerIcon
+    title
+    string
+  
+  Example:
+
+    TestTree.wod:
+      --- snip ---
+      TestTree: WETreeView {
+        list    = rootList;
+        item    = item;
+        index   = index;
+        sublist = item.sublist;
+        zoom    = treeState.isExpanded; // take a look at LSWTreeState !!!
+        // if you leave out *zoom*, the tree is rendered full expanded
+        // and without plus and minus icons
+
+        // if no icons are specified, the tree replaces these icons with
+        // ascii characters (that style is supposed to be ugly :-)
+
+        // icon config
+        iconWidth       = "13"; // every icon's width should be equal to "13"
+        plusIcon        = "plus.gif";
+        minusIcon       = "minus.gif";
+        leafIcon        = "leaf.gif";
+        junctionIcon    = "junction.gif";
+        cornerIcon      = "corner.gif";
+        cornerPlusIcon  = "corner_plus.gif";
+        cornerMinusIcon = "corner_miunus.gif";
+        leafCornerIcon  = "leaf_corner.gif";
+        lineIcon        = "line.gif";
+      }
+      TreeDataCell: WETreeData {
+        isTreeElement = YES; // this is a tree cell (that means, it has plus
+                             // and minus icons and all that stuff)
+      }
+      DataCell: WETreeData {
+        isTreeElement = NO;  // this is NOT a  tree cell, i.e. it does NOT
+                             // have any plus or minus icons. (This is just a
+                             // ordinary <td></td>!!!)
+      }
+
+      TreeHeaderCell: WETreeHeader {
+        isTreeElement = YES;
+      }
+      HeaderCell: WETreeHeader {
+        isTreeElement = NO;
+      }
+
+      --- snap ---
+
+    TestTree.html:
+      --- snip ---
+      <#TestTree>
+        <!--- tree header --->
+          <#TreeHeaderCell>some title</#TreeHeaderCell>
+          <#HeaderCell">some title</#HeaderCell>
+          <#HeaderCell">some title</#HeaderCell>
+
+        <!-- tree content -->
+
+          <#TreeDataCell">some content</#TreeDataCell>
+          <#DataCell">some content</#DataCell>
+          <#DataCell">some content</#DataCell>
+      </#TestTree>
+      --- snap ---
+*/
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@class NSMutableArray;
+
+@interface WETreeView : WODynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation  *list;        // array of objects to iterate through
+  WOAssociation  *item;        // current item in the array
+  WOAssociation  *sublist;     // sub list of item
+  WOAssociation  *itemIsLeaf;  // hh-optimization
+  WOAssociation  *index;       // current index
+  WOAssociation  *zoom;        // show sub list of item (BOOL)
+  WOAssociation  *currentPath; //
+  WOAssociation  *showItem;    // show current item
+
+  WOAssociation  *noTable;     // render no TABLE (BOOL)
+  
+  // config:
+  WOAssociation  *plusIcon;
+  WOAssociation  *minusIcon;
+  WOAssociation  *leafIcon;
+  WOAssociation  *junctionIcon;
+  WOAssociation  *cornerIcon;
+  WOAssociation  *cornerPlusIcon;
+  WOAssociation  *cornerMinusIcon;
+  WOAssociation  *leafCornerIcon;
+  WOAssociation  *lineIcon;
+  WOAssociation  *spaceIcon;
+  WOAssociation  *iconWidth;
+
+  // private:
+  NSMutableArray *matrix;
+  
+  WOElement      *template;
+}
+
+@end /* WETreeView */
+
+#include "WETreeContextKeys.h"
+#include "WETreeMatrixElement.h"
+#include "common.h"
+#include <NGObjWeb/NGObjWeb.h>
+#include <NGObjWeb/WEClientCapabilities.h>
+
+NSString *WETreeView_HEADER_MODE    = @"WETreeView_HEADER_MODE";
+NSString *WETreeView_ZOOM_ACTION_ID = @"_";
+
+NSString *WETreeView_TreeElement    = @"WETreeView_TreeElement";
+NSString *WETreeView_RenderNoTable  = @"WETreeView_RenderNoTable";
+
+NSString *WETreeView_IconWidth      = @"WETreeView_IconWidth";
+NSString *WETreeView_Plus           = @"WETreeView_Plus";
+NSString *WETreeView_Minus          = @"WETreeView_Minus";
+NSString *WETreeView_Leaf           = @"WETreeView_Leaf";
+NSString *WETreeView_Line           = @"WETreeView_Line";
+NSString *WETreeView_Junction       = @"WETreeView_Junction";
+NSString *WETreeView_Corner         = @"WETreeView_Corner";
+NSString *WETreeView_CornerPlus     = @"WETreeView_CornerPlus";
+NSString *WETreeView_CornerMinus    = @"WETreeView_CornerMinus";
+NSString *WETreeView_CornerLeaf     = @"WETreeView_CornerLeaf";
+NSString *WETreeView_Space          = @"WETreeView_Space";
+
+@implementation WETreeView
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_t
+{
+  if ((self = [super initWithName:_name associations:_config template:_t])) {
+    self->list        = WOExtGetProperty(_config, @"list");
+    self->item        = WOExtGetProperty(_config, @"item");
+    self->index       = WOExtGetProperty(_config, @"index");
+    self->sublist     = WOExtGetProperty(_config, @"sublist");
+    self->itemIsLeaf  = WOExtGetProperty(_config, @"itemIsLeaf");
+    self->zoom        = WOExtGetProperty(_config, @"zoom");
+    self->currentPath = WOExtGetProperty(_config, @"currentPath");
+    self->showItem    = WOExtGetProperty(_config, @"showItem");
+
+    self->noTable     = WOExtGetProperty(_config, @"noTable");
+    
+    // config
+    self->plusIcon        = WOExtGetProperty(_config, @"plusIcon");
+    self->minusIcon       = WOExtGetProperty(_config, @"minusIcon");
+    self->leafIcon        = WOExtGetProperty(_config, @"leafIcon");
+    self->junctionIcon    = WOExtGetProperty(_config, @"junctionIcon");
+    self->cornerIcon      = WOExtGetProperty(_config, @"cornerIcon");
+    self->cornerPlusIcon  = WOExtGetProperty(_config, @"cornerPlusIcon");
+    self->cornerMinusIcon = WOExtGetProperty(_config, @"cornerMinusIcon");
+    self->leafCornerIcon  = WOExtGetProperty(_config, @"leafCornerIcon");
+    self->lineIcon        = WOExtGetProperty(_config, @"lineIcon");
+    self->spaceIcon       = WOExtGetProperty(_config, @"spaceIcon");
+    self->iconWidth       = WOExtGetProperty(_config, @"iconWidth");
+    
+    self->template = [_t retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->itemIsLeaf  release];
+  [self->sublist     release];
+  [self->list        release];
+  [self->item        release];
+  [self->index       release];
+  [self->zoom        release];
+  [self->currentPath release];
+  [self->showItem    release];
+
+  [self->noTable     release];
+
+  [self->plusIcon        release];
+  [self->minusIcon       release];
+  [self->leafIcon        release];
+  [self->junctionIcon    release];
+  [self->cornerIcon      release];
+  [self->cornerPlusIcon  release];
+  [self->cornerMinusIcon release];
+  [self->leafCornerIcon  release];
+  [self->lineIcon        release];
+  [self->spaceIcon       release];
+  [self->iconWidth       release];
+
+  [self->template release];
+  [self->matrix   release];
+  
+  [super dealloc];
+}
+
+- (void)updateConfigInContext:(WOContext *)_ctx {
+  NSString       *tmp;
+  WOComponent    *cmp;
+
+  cmp = [_ctx component];
+
+  // TODO: replace the macro with methods?
+#define SetConfigInContext(_a_, _key_)                                  \
+      if (_a_ && (tmp = [_a_ valueInComponent:cmp]))                    \
+        [_ctx setObject:tmp forKey:_key_];                              \
+
+  SetConfigInContext(self->plusIcon,        WETreeView_Plus);
+  SetConfigInContext(self->minusIcon,       WETreeView_Minus);
+  SetConfigInContext(self->leafIcon,        WETreeView_Leaf);
+  SetConfigInContext(self->junctionIcon,    WETreeView_Junction);
+  SetConfigInContext(self->cornerIcon,      WETreeView_Corner);
+  SetConfigInContext(self->cornerPlusIcon,  WETreeView_CornerPlus);
+  SetConfigInContext(self->cornerMinusIcon, WETreeView_CornerMinus);
+  SetConfigInContext(self->leafCornerIcon,  WETreeView_CornerLeaf);
+  SetConfigInContext(self->lineIcon,        WETreeView_Line);
+  SetConfigInContext(self->spaceIcon,       WETreeView_Space);
+  SetConfigInContext(self->iconWidth,       WETreeView_IconWidth);
+  
+#undef SetConfigInContext
+}
+
+- (void)removeConfigInContext:(WOContext *)_ctx {
+  [_ctx removeObjectForKey:WETreeView_Plus];
+  [_ctx removeObjectForKey:WETreeView_Minus];
+  [_ctx removeObjectForKey:WETreeView_Leaf];
+  [_ctx removeObjectForKey:WETreeView_Junction];
+  [_ctx removeObjectForKey:WETreeView_Corner];
+  [_ctx removeObjectForKey:WETreeView_CornerPlus];
+  [_ctx removeObjectForKey:WETreeView_CornerMinus];
+  [_ctx removeObjectForKey:WETreeView_CornerLeaf];
+  [_ctx removeObjectForKey:WETreeView_Line];
+  [_ctx removeObjectForKey:WETreeView_Space];
+  [_ctx removeObjectForKey:WETreeView_IconWidth];
+}
+
+- (id)_toggleZoomInContext:(WOContext *)_ctx {
+  WOComponent *component = [_ctx component];
+
+  if ([self->zoom isValueSettable]) {
+    BOOL isZoom;
+    
+    isZoom = [self->zoom boolValueInComponent:component];
+    [self->zoom setBoolValue:!isZoom inComponent:component];
+  }
+  return nil;
+}
+
+/* OWResponder */
+
+- (NSArray *)_sublistInContext:(WOContext *)_ctx {
+  NSArray *a;
+  
+  if (self->sublist == nil)
+    return nil;
+  if (self->itemIsLeaf) {
+    if ([self->itemIsLeaf boolValueInComponent:[_ctx component]])
+      return nil;
+  }
+  
+  if ((a = [self->sublist valueInComponent:[_ctx component]]) == nil)
+    return nil;
+  
+  return ([a count] > 0) ? a : nil;
+}
+
+- (void)_takeValuesFromRequest:(WORequest *)_req
+  inContext:(WOContext *)_ctx
+  withArray:(NSArray *)array
+      depth:(int)_depth
+{
+  WOComponent *cmp;
+  int i, cnt;
+
+#if DEBUG
+#if 1
+  if (!(_depth <= MAX_TREE_DEPTH-1)) {
+    NSLog(@"ERROR[%s]: WETreeView takeValuesFromRequest: max."
+          @"recursion depth is %d",
+          __PRETTY_FUNCTION__, MAX_TREE_DEPTH-1);
+    return;
+  }
+#else  
+  NSAssert1((_depth <= MAX_TREE_DEPTH-1),
+            @"WETreeView takeValuesFromRequest: max. recursion depth is %d",
+            MAX_TREE_DEPTH-1);
+#endif  
+#endif
+  
+  cmp = [_ctx component];
+  cnt = [array count];
+  
+  [_ctx appendZeroElementIDComponent]; // append index
+  for (i = 0; i < cnt; i++) {
+    NSArray *subArray;
+    
+    if ([self->index isValueSettable])
+      [self->index setUnsignedIntValue:i inComponent:cmp];
+    if ([self->item isValueSettable])
+      [self->item setValue:[array objectAtIndex:i] inComponent:cmp];
+
+    if (self->showItem && ![self->showItem boolValueInComponent:cmp])
+      continue;
+
+    if (self->zoom == nil || [self->zoom boolValueInComponent:cmp])
+      subArray = [self _sublistInContext:_ctx];
+    else
+      subArray = nil;
+    
+    if (subArray)
+      [self _takeValuesFromRequest:_req
+                         inContext:_ctx
+                         withArray:subArray
+                             depth:_depth+1];
+    else
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+    
+    [_ctx incrementLastElementIDComponent];
+  }
+  [_ctx deleteLastElementIDComponent]; // delete index
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  NSArray *array;
+
+  array = [self->list valueInComponent:[_ctx component]];
+  [self _takeValuesFromRequest:_req inContext:_ctx withArray:array depth:0];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  id       result  = nil;
+  id       idxId   = nil;
+  id       object  = nil;
+  NSMutableArray *stack = nil;
+  NSArray  *array;
+  unsigned idCount = 0;
+
+  sComponent = [_ctx component];
+  array      = [self->list valueInComponent:sComponent];
+  if ([array count] < 1) return nil;
+
+  stack = [NSMutableArray array];
+  
+  idxId = [_ctx currentElementID]; // top level index
+  idCount = 0;
+  
+  if ([idxId isEqualToString:@"h"]) {
+    [_ctx setObject:@"YES" forKey:WETreeView_HEADER_MODE];
+    [_ctx appendElementIDComponent:@"h"];
+    [_ctx consumeElementID];
+    result = [self->template invokeActionForRequest:_rq inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+    [_ctx removeObjectForKey:WETreeView_HEADER_MODE];
+    return result;
+  }
+  
+  while ((![idxId isEqualToString:@"end"]) && (idxId != nil) &&
+         (array != nil)) {
+    unsigned idx = [idxId unsignedIntValue];
+
+    object = [array objectAtIndex:idx];
+    [stack addObject:object];
+    
+    if ([self->index isValueSettable])
+      [self->index setUnsignedIntValue:idx inComponent:sComponent];
+    if ([self->item isValueSettable])
+      [self->item setValue:object inComponent:sComponent];
+    if ([self->currentPath isValueSettable])
+      [self->currentPath setValue:stack inComponent:sComponent];
+
+    array = [self->sublist valueInComponent:sComponent];
+    
+    [_ctx appendElementIDComponent:idxId]; idCount++;
+    idxId = [_ctx consumeElementID]; // sub level index
+  }
+  if ([idxId isEqualToString:@"end"]) {
+    [_ctx appendElementIDComponent:idxId]; idCount++;
+    idxId = [_ctx consumeElementID];
+  }
+  
+  result = ([[_ctx senderID] hasSuffix:WETreeView_ZOOM_ACTION_ID])
+    ? [self _toggleZoomInContext:_ctx]
+    : [self->template invokeActionForRequest:_rq inContext:_ctx];
+  
+  /* remove element-ids */
+  for (; idCount > 0; idCount--)
+    [_ctx deleteLastElementIDComponent];
+  
+  return result;
+}
+
+- (void)appendList:(NSArray *)_list
+  treeElement:(_WETreeMatrixElement *)_element
+  inContext:(WOContext *)_ctx
+{
+  /* TODO: split up this method! */
+  WOComponent    *comp;
+  unsigned       i, cnt;
+
+  comp = [_ctx component];
+  cnt  = [_list count];
+
+#if DEBUG
+#if 1  
+  if (!([_element depth] <= MAX_TREE_DEPTH-1)) {
+    NSLog(@"ERROR[%s]: WETreeView takeValuesFromRequest: max."
+          @"recursion depth is %d",
+          __PRETTY_FUNCTION__, MAX_TREE_DEPTH-1);
+    return;
+  }
+#else  
+  NSAssert1(([_element depth] <= MAX_TREE_DEPTH-1),
+            @"WETreeView appendToResponse: max. recursion depth is %d",
+            MAX_TREE_DEPTH-1);
+#endif  
+#endif
+    
+  for (i = 0; i < cnt; i++) {
+    id object = [_list objectAtIndex:i];
+
+    [_element setIndex:i];
+    [_element setItem:object];
+    
+    if ([self->index isValueSettable])
+      [self->index setUnsignedIntValue:i inComponent:comp];
+    if ([self->item isValueSettable])
+      [self->item setValue:object inComponent:comp];
+    if ([self->currentPath isValueSettable])
+      [self->currentPath setValue:[_element currentPath] inComponent:comp];
+
+    if (self->showItem && ![self->showItem boolValueInComponent:comp])
+      continue;
+
+    {
+      BOOL    isLast;
+      BOOL    isLeaf;
+      BOOL    isZoom = YES;
+      NSArray *sl;
+
+      if (self->itemIsLeaf) {
+        isLeaf = [self->itemIsLeaf boolValueInComponent:comp];
+        isZoom = (self->zoom)
+          ? [self->zoom boolValueInComponent:comp]
+          : YES;
+        
+        sl = (!isLeaf && isZoom)
+          ? [self _sublistInContext:_ctx]
+          : nil;
+      }
+      else {
+        sl = [self _sublistInContext:_ctx];
+        isLeaf = !([sl count] > 0);
+      }
+
+      if (self->showItem) {
+        if (i == (cnt-1))
+          isLast = YES;
+        else {
+          id       obj;
+          unsigned k;
+
+          isLast = YES;
+          for (k = (i + 1); k < cnt; k++) {
+            obj = [_list objectAtIndex:k];
+            
+            [_element setIndex:k];
+            [_element setItem:obj];
+            if ([self->index isValueSettable])
+              [self->index setUnsignedIntValue:k inComponent:comp];
+            if ([self->item isValueSettable])
+              [self->item setValue:obj inComponent:comp];
+            if ([self->currentPath isValueSettable])
+              [self->currentPath setValue:[_element currentPath]
+                   inComponent:comp];
+            
+            if ([self->showItem boolValueInComponent:comp]) {
+              isLast = NO;
+              break;
+            }
+          }
+          [_element setIndex:i];
+          [_element setItem:object];
+
+          if ([self->index isValueSettable])
+            [self->index setUnsignedIntValue:i inComponent:comp];
+          if ([self->item isValueSettable])
+            [self->item setValue:object inComponent:comp];
+          if ([self->currentPath isValueSettable])
+            [self->currentPath setValue:[_element currentPath]
+                   inComponent:comp];
+        }
+      }
+      else
+        isLast = (i == (cnt-1));
+        
+      if (!isLeaf) { // not a leaf
+        _WETreeMatrixElement *newElement;
+        
+        if (self->zoom == nil) {
+          [_element setElement:(isLast)
+                    ? WETreeView_Corner
+                    : WETreeView_Junction];
+        }
+        else {
+          isZoom = [self->zoom boolValueInComponent:comp];
+          if (isZoom) {
+            [_element setElement:(isLast)
+                 ? ([sl count]) ? WETreeView_CornerMinus : WETreeView_Corner
+                 : ([sl count]) ? WETreeView_Minus : WETreeView_Junction];
+          }
+          else
+            [_element setElement:(isLast)
+                      ? WETreeView_CornerPlus
+                      : WETreeView_Plus];
+        }
+        [_element setLeaf:(isZoom && [sl count])
+                  ? WETreeView_CornerLeaf
+                  : WETreeView_Leaf];
+
+        newElement = [[_WETreeMatrixElement alloc] initWithElement:_element];
+
+        [self->matrix addObject:newElement];
+        [newElement release]; newElement = nil;
+        
+        if (isZoom) {
+          [_element setElement:(isLast)
+                      ? WETreeView_Space
+                      : WETreeView_Line];
+          
+          newElement = [[_WETreeMatrixElement alloc] initWithElement:_element];
+
+          [self appendList:sl treeElement:newElement inContext:_ctx];
+          [newElement release]; newElement = nil;
+        }
+      }
+      else {
+        _WETreeMatrixElement *newElement;
+
+        [_element setElement: (isLast)
+                  ? WETreeView_Corner
+                  : WETreeView_Junction];
+
+        newElement = [[_WETreeMatrixElement alloc] initWithElement:_element];
+
+        [newElement setLeaf:WETreeView_Leaf];
+
+        [self->matrix addObject:newElement];
+        [newElement release]; newElement = nil;
+      }
+    }
+  }
+}
+
+- (void)_calcMatrixInContext:(WOContext *)_ctx depth:(int *)_depth {
+  _WETreeMatrixElement *treeElm = nil;
+  NSArray              *top     = nil;
+  int i, cnt, d, maxDepth = 0;
+
+  top = [self->list valueInComponent:[_ctx component]];
+  
+  [self->matrix release]; self->matrix = nil;
+  self->matrix = [[NSMutableArray allocWithZone:[self zone]]
+                                 initWithCapacity:64];
+
+  treeElm = [[_WETreeMatrixElement alloc] init];
+  
+  [self appendList:top treeElement:treeElm inContext:_ctx];
+  
+  [treeElm release]; treeElm = nil;
+
+  cnt = [self->matrix count];
+
+  /* calc max depth */
+  for (i = 0; i < cnt; i++) {
+    d = [[self->matrix objectAtIndex:i] depth];
+    maxDepth = (maxDepth < d) ? d : maxDepth;
+  }
+
+  /* update depth */
+  for (i = 0; i < cnt; i++) {
+    _WETreeMatrixElement *element;
+
+    element = [self->matrix objectAtIndex:i];
+    [element setColspan:maxDepth-[element depth]+1];
+  }
+  *_depth = maxDepth + 2;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *comp;
+  BOOL        doTable;
+  int         i, cnt, depth;
+
+  [self updateConfigInContext:_ctx];
+
+  comp = [_ctx component];
+
+  /* check for browser */
+  if (self->noTable == nil) {
+    WEClientCapabilities *ccaps;
+    
+    ccaps = [[_ctx request] clientCapabilities];
+    doTable = [ccaps isFastTableBrowser];
+  }
+  else
+    doTable = ![self->noTable boolValueInComponent:comp];
+
+  if (!doTable)
+    [_ctx setObject:@"1" forKey:WETreeView_RenderNoTable];
+
+  if (doTable) {
+    [_response appendContentString:
+               @"<table border='0' cellspacing='0' cellpadding='0'"];
+
+    [self appendExtraAttributesToResponse:_response inContext:_ctx];
+    if (self->otherTagString) {
+      [_response appendContentString:
+                 [self->otherTagString stringValueInComponent:
+                      [_ctx component]]];
+    }
+    [_response appendContentCharacter:'>'];
+  }
+
+  [self _calcMatrixInContext:_ctx depth:&depth];
+
+    /* append table title */
+  if (doTable)
+    [_response appendContentString:@"<tr>"];
+
+  [_ctx setObject:[NSNumber numberWithInt:depth]
+        forKey:WETreeView_HEADER_MODE];
+  [_ctx appendElementIDComponent:@"h"];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  [_ctx removeObjectForKey:WETreeView_HEADER_MODE];
+  if (doTable)
+    [_response appendContentString:@"</tr>"];
+  else
+    [_response appendContentString:@"<br />"];
+
+  cnt = [self->matrix count];
+
+  for (i = 0; i < cnt; i++) {
+    _WETreeMatrixElement *element;
+
+    element = [self->matrix objectAtIndex:i];
+      
+    if ([self->index isValueSettable])
+      [self->index setUnsignedIntValue:[element index]
+           inComponent:comp];
+
+    if ([self->item isValueSettable])
+      [self->item setValue:[element item]
+           inComponent:comp];
+
+    if ([self->currentPath isValueSettable])
+      [self->currentPath setValue:[element currentPath]
+           inComponent:comp];
+
+    [_ctx setObject:element forKey:WETreeView_TreeElement];
+
+    [_ctx appendElementIDComponent:[element elementID]];
+      
+    [_ctx appendElementIDComponent:@"end"];
+    if (doTable)
+      [_response appendContentString:@"<tr>"];
+    [self->template appendToResponse:_response inContext:_ctx];
+    if (doTable)
+      [_response appendContentString:@"</tr>"];
+    else
+      [_response appendContentString:@"<br />"];
+      
+    [_ctx deleteLastElementIDComponent]; // delete "end"
+      
+    [_ctx deleteLastElementIDComponent]; // delete eids
+  }
+  [_ctx removeObjectForKey:WETreeView_TreeElement];
+
+  if (doTable)
+    [_response appendContentString:@"</table>"];
+
+  [self removeConfigInContext:_ctx];
+  [_ctx removeObjectForKey:WETreeView_RenderNoTable];
+  [self->matrix release]; self->matrix = nil;
+}
+
+@end /* WETreeView */
diff --git a/skyrix-sope/WEExtensions/WEWeekColumnView.m b/skyrix-sope/WEExtensions/WEWeekColumnView.m
new file mode 100644 (file)
index 0000000..fcb2a4c
--- /dev/null
@@ -0,0 +1,828 @@
+/*
+  Copyright (C) 2000-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: #
+
+#include "WEContextConditional.h"
+#include <NGObjWeb/WODynamicElement.h>
+
+/*
+    draws this:
+    
+      |---------------|---------------|
+      |Mo  <content>  | Do  <content> |             
+      |               |               |
+      |               |               |
+      |---------------|---------------|
+      |Di  <content>  | Fr  <content> |             
+      |               |               |
+      |               |               |
+      |---------------|---------------|
+      |Mi  <content>  | Sa  <content> |             
+      |               |---------------|
+      |               | So  <content> |
+      |---------------|---------------|
+*/
+
+#define SecondsPerWeek (7 * 24 * 60 * 60)
+#define SecondsPerDay      (24 * 60 * 60)
+#define MatrixSections  7
+
+@class NSMutableArray;
+
+
+#define WEWeekColumnView_TitleMode         @"WEWeekColumnView_TitleMode"
+#define WEWeekColumnView_TitleModeDidMatch @"WEWeekColumnView_TitleModeMatched"
+#define WEWeekColumnView_InfoMode          @"WEWeekColumnView_InfoMode"
+#define WEWeekColumnView_ContentMode       @"WEWeekColumnView_ContentMode"
+
+@interface WEWeekColumnView : WODynamicElement
+{
+@protected
+  WOAssociation  *list;
+  WOAssociation  *item;
+  WOAssociation  *index;
+  WOAssociation  *identifier;
+  
+  WOAssociation  *dayIndex;
+  WOAssociation  *weekStart;
+  
+  WOAssociation  *startDateKey;
+  WOAssociation  *endDateKey;
+
+  WOAssociation  *titleColor;
+  WOAssociation  *contentColor;
+  
+  WOAssociation  *isInfoItem; // is current item info entry
+  WOAssociation  *infoItems;  // current info entries
+  
+  WOAssociation  *hideWeekend; /* should Sa/So be rendered? */
+  
+@private
+  NSMutableArray *matrix[MatrixSections];
+  NSMutableArray *infos[MatrixSections];
+  BOOL           hasOwnTitle;
+  
+  WOElement      *template;
+}
+@end
+
+#include <math.h> /* Needed for floor() */
+#include "common.h"
+
+@implementation WEWeekColumnView
+
+static Class StrClass = Nil;
+
++ (void)initialize {
+  StrClass = [NSString class];
+}
+
+static NSString *retStrForInt(int i) {
+  switch(i) {
+  case 0:  return @"0";
+  case 1:  return @"1";
+  case 2:  return @"2";
+  case 3:  return @"3";
+  case 4:  return @"4";
+  case 5:  return @"5";
+  case 6:  return @"6";
+  case 7:  return @"7";
+  case 8:  return @"8";
+  case 9:  return @"9";
+  case 10: return @"10";
+    // TODO: find useful count!
+  default:
+    return [[StrClass alloc] initWithFormat:@"%i", i];
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmp
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmp])) {
+    self->list         = WOExtGetProperty(_config, @"list");
+    self->item         = WOExtGetProperty(_config, @"item");
+    self->index        = WOExtGetProperty(_config, @"index");
+    self->identifier   = WOExtGetProperty(_config, @"identifier");
+    self->dayIndex     = WOExtGetProperty(_config, @"dayIndex");
+    self->weekStart    = WOExtGetProperty(_config, @"weekStart");
+    self->startDateKey = WOExtGetProperty(_config, @"startDateKey");
+    self->endDateKey   = WOExtGetProperty(_config, @"endDateKey");
+    
+    self->titleColor   = WOExtGetProperty(_config, @"titleColor");
+    self->contentColor = WOExtGetProperty(_config, @"contentColor");
+    
+    self->hideWeekend  = WOExtGetProperty(_config, @"hideWeekend");
+
+    if (self->startDateKey == nil) {
+      self->startDateKey =
+        [[WOAssociation associationWithValue:@"startDate"] retain];
+    }
+    if (self->endDateKey == nil) {
+      self->endDateKey = 
+        [[WOAssociation associationWithValue:@"endDate"] retain];
+    }
+
+    self->isInfoItem = WOExtGetProperty(_config, @"isInfoItem");
+    self->infoItems  = WOExtGetProperty(_config, @"infoItems");
+    
+    ASSIGN(self->template, _tmp);    
+  }
+  return self;
+}
+
+- (void)resetMatrix {
+  int i;
+  
+  for (i=0; i<MatrixSections; i++) {
+    [self->matrix[i] release]; self->matrix[i] = nil;
+    [self->infos[i]  release]; self->infos[i]  = nil;
+  }
+}
+
+- (void)dealloc {
+  [self->hideWeekend  release];
+  [self->list         release];
+  [self->item         release];
+  [self->index        release];
+  [self->identifier   release];
+  [self->dayIndex     release];
+  [self->weekStart    release];
+  [self->startDateKey release];
+  [self->endDateKey   release];
+  [self->titleColor   release];
+  [self->contentColor release];
+  [self->infoItems    release];
+  [self->isInfoItem   release];
+
+  [self resetMatrix];
+  [self->template release];
+  [super dealloc];
+}
+
+static inline void
+_applyIdentifier(WEWeekColumnView *self, WOComponent *comp, NSString *_idx)
+{
+  NSArray *array;
+  unsigned count, cnt;
+
+  array = [self->list valueInComponent:comp];
+  count = [array count];
+
+  if (count == 0)
+    return;
+    
+  /* find subelement for unique id */
+    
+  for (cnt = 0; cnt < count; cnt++) {
+      NSString *ident;
+      
+      if (self->index)
+        [self->index setUnsignedIntValue:cnt inComponent:comp];
+
+      if (self->item)
+        [self->item setValue:[array objectAtIndex:cnt] inComponent:comp];
+      
+      ident = [self->identifier stringValueInComponent:comp];
+
+      if ([ident isEqualToString:_idx]) {
+        /* found subelement with unique id */
+        return;
+      }
+    }
+    
+  [comp logWithFormat:
+                  @"WEWeekColumnView: array did change, "
+                  @"unique-id isn't contained."];
+  [self->item  setValue:nil          inComponent:comp];
+  [self->index setUnsignedIntValue:0 inComponent:comp];
+}
+
+static inline void
+_applyIndex(WEWeekColumnView *self, WOComponent *comp, unsigned _idx)
+{
+  NSArray *array;
+  unsigned count;
+  
+  array = [self->list valueInComponent:comp];
+  
+  if (self->index)
+    [self->index setUnsignedIntValue:_idx inComponent:comp];
+
+  if (self->item == nil)
+    return;
+
+  count = [array count];
+  if (_idx < count) {
+    [self->item setValue:[array objectAtIndex:_idx] inComponent:comp];
+    return;
+  }
+
+  [comp logWithFormat:
+            @"WEWeekColumnView: array did change, index is invalid."];
+  [self->item  setValue:nil          inComponent:comp];
+  [self->index setUnsignedIntValue:0 inComponent:comp];
+}
+
+- (void)_calcMatrixInContext:(WOContext *)_ctx {
+  WOComponent    *comp;
+  NSCalendarDate *startWeek;
+  NSArray        *array;
+  NSString       *startKey;
+  NSString       *endKey;
+  int            i, idx, idx2, cnt;
+  
+  [self resetMatrix];
+
+  [_ctx removeObjectForKey:WEWeekColumnView_TitleModeDidMatch];
+  [_ctx setObject:@"YES" forKey:WEWeekColumnView_TitleMode];
+  [self->template appendToResponse:nil inContext:_ctx];
+  [_ctx removeObjectForKey:WEWeekColumnView_TitleMode];
+  
+  if ([_ctx objectForKey:WEWeekColumnView_TitleModeDidMatch] != nil)
+    self->hasOwnTitle = YES;
+  else
+    self->hasOwnTitle = NO;
+  
+  comp      = [_ctx component];
+  array     = [self->list valueInComponent:comp];
+  startKey  = [self->startDateKey stringValueInComponent:comp];
+  endKey    = [self->endDateKey   stringValueInComponent:comp];
+  startWeek = (self->weekStart)
+    ? [self->weekStart    valueInComponent:comp]
+    : [NSCalendarDate calendarDate];
+  
+  for (i = 0, cnt = [array count]; i < cnt; i++) {
+    id             app;
+    NSCalendarDate *sd, *ed;
+    NSTimeInterval diff;
+    BOOL           isInfo;
+    
+    app = [array objectAtIndex:i];
+    sd  = [app valueForKey:startKey]; // startDate
+    ed  = [app valueForKey:endKey];   // endDate
+
+    if ((sd == nil) && (ed == nil)) continue;
+
+    if ((sd != nil) && (ed != nil) && [ed isEqual:[sd earlierDate:ed]]) {
+      NSCalendarDate *tmp;
+
+      tmp = sd;
+      sd  = ed;
+      ed  = tmp;
+    }
+    
+    diff  = [(sd ? sd : ed) timeIntervalSinceDate:startWeek];
+    
+    idx = floor((diff / SecondsPerWeek) * MatrixSections);
+
+    if ((self->item) && (self->isInfoItem)) {
+      [self->item setValue:app inComponent:comp];
+      isInfo = [[self->isInfoItem valueInComponent:comp] boolValue];
+    }
+    else isInfo = NO;
+
+    if ((0 <= idx) && (idx < MatrixSections)) {
+      if (isInfo) {
+        if (self->infos[idx] == nil)
+          self->infos[idx] = [[NSMutableArray alloc] initWithCapacity:2];      
+        [self->infos[idx] addObject:[NSNumber numberWithInt:i]];
+      }
+      else {
+        if (self->matrix[idx] == nil)
+          self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
+        [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
+      }
+    }
+    idx = (idx >= 0) ? idx+1 : idx;
+    diff = [ed timeIntervalSinceDate:startWeek];
+    
+    idx2 = floor((diff / SecondsPerWeek) * MatrixSections);
+    idx2 = (idx2 >= MatrixSections) ? (MatrixSections - 1) : idx2;
+
+    if (idx2 < 0) continue;
+    
+    while (idx <= idx2) {
+      idx = (idx < 0) ? 0 : idx;
+      if (isInfo) {
+        if (self->infos[idx] == nil)
+          self->infos[idx] = [[NSMutableArray alloc] initWithCapacity:2];      
+        [self->infos[idx] addObject:[NSNumber numberWithInt:i]];
+      }
+      else {
+        if (self->matrix[idx] == nil)
+          self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
+        [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
+      }
+      idx++;
+    }
+  }
+}
+
+- (void)appendDateTitleToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  day:(int)_day
+{
+  WOComponent *comp;
+  NSString    *bgcolor;
+
+  comp = [_ctx component];
+  
+  bgcolor = [self->titleColor stringValueInComponent:comp];
+  
+  if ([self->dayIndex isValueSettable])
+    [self->dayIndex setIntValue:_day inComponent:comp];
+
+  [_response appendContentString:@"<td valign='top' align='left' width='50%'"];
+  if (bgcolor) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentString:bgcolor];
+    [_response appendContentCharacter:'"'];
+  }
+  [_response appendContentCharacter:'>'];
+
+  if (self->hasOwnTitle) {
+    NSString *s;
+    
+    [_ctx setObject:@"YES" forKey:WEWeekColumnView_TitleMode];
+    
+    [_ctx appendElementIDComponent:@"t"];
+    s = retStrForInt(_day);
+    [_ctx appendElementIDComponent:s];
+    [s release];
+    
+    [self->template appendToResponse:_response inContext:_ctx];
+
+    [_ctx deleteLastElementIDComponent]; // delete day index
+    [_ctx deleteLastElementIDComponent]; // delete "t"
+
+    [_ctx removeObjectForKey:WEWeekColumnView_TitleMode];
+  }
+  else {
+    NSCalendarDate *date;
+    
+    date = (self->weekStart)
+      ? [self->weekStart valueInComponent:comp]
+      : [NSCalendarDate calendarDate];
+    date = [date addTimeInterval:_day * SecondsPerDay];
+
+    [_response appendContentString:
+               @"<table cellpadding=0 width=100% border=0 cellspacing=0>"
+               @"<tr>"
+               @"<td align=left valign=top>"
+               @"<font color=\"black\" size=\"+2\"><b>"];
+    [_response appendContentString:[date descriptionWithCalendarFormat:@"%d"]];
+
+    [_response appendContentString:
+               @"</b></font></td>"
+               @"<td align=\"center\" valign=\"top\">"
+               @"<font color=\"black\">"];
+
+    [_response appendContentString:[date descriptionWithCalendarFormat:@"%A"]];
+    [_response appendContentString:
+               @"</font>"
+               @"</td>"
+               @"</tr>"
+               @"</table>"];
+  }
+  [_response appendContentString:@"</td>"];
+}
+
+- (void)appendContentToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  day:(int)_day
+{
+  WOComponent *comp;
+  NSArray     *array;
+  id          app;
+  NSString    *s;
+  int         i, cnt, idx, count;
+
+  comp  = [_ctx component];
+  array = [self->list valueInComponent:comp];
+  count = [array count];
+
+  if ([self->infoItems isValueSettable]) {
+    if ((cnt = [self->infos[_day] count])) {
+      NSMutableArray *infoArr;
+      
+      infoArr = [NSMutableArray arrayWithCapacity:cnt];
+      for (i = 0; i < cnt; i++) {
+        idx = [[self->infos[_day] objectAtIndex:i] intValue];
+        
+        if (idx >= count) {
+          [self logWithFormat:
+                 @"WARNING: WEWeekOverview: info index out of range"];
+          continue;
+        }
+        [infoArr addObject:[array objectAtIndex:idx]];
+      }
+      [self->infoItems setValue:infoArr inComponent:comp];
+    }
+    else {
+      [self->infoItems setValue:[NSArray array] inComponent:comp];
+    }
+  }
+  
+  // *** append day info
+  [_ctx setObject:@"YES" forKey:WEWeekColumnView_InfoMode];
+  [_ctx appendElementIDComponent:@"i"];
+  s = retStrForInt(_day);
+  [_ctx appendElementIDComponent:s];
+  [s release];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent]; // delete day
+  [_ctx deleteLastElementIDComponent]; // delete "i"
+  [_ctx removeObjectForKey:WEWeekColumnView_InfoMode];
+
+  // *** append day content
+  [_ctx appendElementIDComponent:@"c"];
+  s = retStrForInt(_day);
+  [_ctx appendElementIDComponent:s];
+  [s release];
+  
+  [_ctx setObject:@"YES" forKey:WEWeekColumnView_ContentMode];
+
+  for (i = 0, cnt = [self->matrix[_day] count]; i < cnt; i++) {
+    idx = [[self->matrix[_day] objectAtIndex:i] intValue];
+
+    if (idx >= count) {
+      NSLog(@"Warning! WEWeekColumnView: index out of range");
+      continue;
+    }
+    app = [array objectAtIndex:idx];
+
+    if ([self->item isValueSettable])
+      [self->item  setValue:app inComponent:comp];
+    if ([self->index isValueSettable])
+      [self->index setIntValue:idx inComponent:comp];
+
+    if (self->identifier == nil) {
+      s = retStrForInt(idx);
+      [_ctx appendElementIDComponent:s];
+      [s release];
+    }
+    else {
+      NSString *s;
+
+      s = [self->identifier stringValueInComponent:comp];
+      [_ctx appendElementIDComponent:s];
+    }
+    [self->template appendToResponse:_response inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+  if (cnt == 0)
+    [_response appendContentString:@"&nbsp;"];
+  [_ctx removeObjectForKey:WEWeekColumnView_ContentMode];
+
+  [_ctx deleteLastElementIDComponent]; // delete day index
+  [_ctx deleteLastElementIDComponent]; // delete "c"
+}
+
+/* handling requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *comp;
+  NSArray     *array;
+  int         i, count;
+  
+  comp  = [_ctx component];
+  array = [self->list valueInComponent:comp];
+  count = [array count];
+
+  /* titles */
+  [_ctx setObject:@"YES" forKey:WEWeekColumnView_TitleMode];
+  [_ctx appendElementIDComponent:@"t"]; // append title mode
+  [_ctx appendZeroElementIDComponent];  // append first day (monday)
+  for (i = 0; i < 7; i++) {
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:i inComponent:comp];
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+    [_ctx incrementLastElementIDComponent]; // increment day
+  }
+  [_ctx deleteLastElementIDComponent];  // delete day
+  [_ctx deleteLastElementIDComponent];  // delete title mode
+  [_ctx removeObjectForKey:WEWeekColumnView_TitleMode];
+  
+  /* infos */
+  [_ctx setObject:@"YES" forKey:WEWeekColumnView_InfoMode];
+  [_ctx appendElementIDComponent:@"i"]; // append info mode
+  [_ctx appendZeroElementIDComponent];  // append day
+  for (i=0; i< 7; i++) {
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:i inComponent:comp];
+    
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+    
+    [_ctx incrementLastElementIDComponent]; // increment day
+    [_ctx incrementLastElementIDComponent]; // in steps of 2
+  }
+  [_ctx deleteLastElementIDComponent];  // delete day
+  [_ctx deleteLastElementIDComponent];  // delete info mode
+  [_ctx removeObjectForKey:WEWeekColumnView_InfoMode];
+
+  // content
+  [self _calcMatrixInContext:_ctx];
+
+  [_ctx setObject:@"YES" forKey:WEWeekColumnView_ContentMode];
+  [_ctx appendElementIDComponent:@"c"]; // append content mode
+  [_ctx appendZeroElementIDComponent];  // append day-id
+  for (i = 0; i < 7; i++) {
+    int     j, cnt, idx;
+    
+    cnt   = [self->matrix[i] count];
+    
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:i inComponent:comp];
+    
+    for (j = 0; j < cnt; j++) {
+      idx = [[self->matrix[i] objectAtIndex:j] intValue];
+      
+      if (idx >= count) {
+        NSLog(@"Warning! WEWeekColumnView: Index is out of range");
+        continue;
+      }
+      
+      _applyIndex(self, comp, idx);
+      
+      if (self->identifier) {
+        NSString *s;
+       
+        s = [self->identifier stringValueInComponent:comp];
+        [_ctx appendElementIDComponent:s];
+      }
+      else {
+        NSString *s;
+        
+        s = retStrForInt(idx);
+        [_ctx appendElementIDComponent:s];
+        [s release];
+      }
+
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+      
+      [_ctx deleteLastElementIDComponent];   // delete index-id
+    }
+    [_ctx incrementLastElementIDComponent]; // increase day-id
+  }
+  [_ctx deleteLastElementIDComponent];  // delete day-id
+  [_ctx deleteLastElementIDComponent];  // delete content mode
+  [_ctx removeObjectForKey:WEWeekColumnView_ContentMode];
+  
+  [self resetMatrix];  
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *comp;
+  id          result = nil;
+  NSString    *cid;
+  NSString    *dayId;
+
+  cid = [_ctx currentElementID];           // get mode ("t" or "i" or "c")
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:cid];
+  dayId = [_ctx currentElementID];         // get day
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:dayId];
+
+  comp = [_ctx component];
+  
+  if ([cid isEqualToString:@"t"]) {
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:[dayId intValue] inComponent:comp];
+    result = [self->template invokeActionForRequest:_req inContext:_ctx];
+  }
+  else if ([cid isEqualToString:@"i"]) {
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:[dayId intValue] inComponent:comp];
+    result = [self->template invokeActionForRequest:_req inContext:_ctx];
+  }
+  else if ([cid isEqualToString:@"c"]) {
+    NSString *idxId;
+
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:[dayId intValue] inComponent:comp];
+
+    if ((idxId = [_ctx currentElementID])) {
+      [_ctx consumeElementID];               // consume index-id
+      [_ctx appendElementIDComponent:idxId];
+
+      if (self->identifier)
+        _applyIdentifier(self, comp, idxId);
+      else
+        _applyIndex(self, comp, [idxId intValue]);
+
+      result = [self->template invokeActionForRequest:_req inContext:_ctx];
+
+      [_ctx deleteLastElementIDComponent]; // delete index-id
+    }
+  }
+  else
+    [self logWithFormat:@"WARNING! WEWeekColumnView: wrong section"];
+  
+  [_ctx deleteLastElementIDComponent]; // delete section id
+  [_ctx deleteLastElementIDComponent]; // delete mode
+  
+  return result;
+}
+
+/* generating response */
+
+- (void)appendBgColor:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  day:(unsigned)_day 
+{
+  NSString *bg;
+  
+  if ([self->dayIndex isValueSettable])
+    [self->dayIndex setIntValue:_day inComponent:[_ctx component]];
+  
+  if ((bg = [self->contentColor stringValueInComponent:[_ctx component]])) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentString:bg];
+    [_response appendContentCharacter:'"'];
+  }
+}
+
+- (void)appendFirstRowToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx 
+{
+  /* first row (Mo,Do) */
+    [_response appendContentString:@"<tr>"];
+    [self appendDateTitleToResponse:_response inContext:_ctx day:0];
+    [self appendDateTitleToResponse:_response inContext:_ctx day:3];
+    [_response appendContentString:@"</tr>"];
+
+    [_response appendContentString:@"<tr>"];
+    
+    [_response appendContentString:@"<td valign=\"top\""];
+    [self appendBgColor:_response inContext:_ctx day:0];
+    [_response appendContentCharacter:'>'];
+    
+    [self appendContentToResponse:_response inContext:_ctx day:0];
+    [_response appendContentString:@"</td>"];
+    
+    [_response appendContentString:@"<td valign=\"top\""];
+    [self appendBgColor:_response inContext:_ctx day:3];
+    [_response appendContentCharacter:'>'];
+    
+    [self appendContentToResponse:_response inContext:_ctx day:3];
+    [_response appendContentString:@"</td>"];
+    [_response appendContentString:@"</tr>"];
+}
+
+- (void)appendSecondRowToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx 
+{
+  /* second row (Di,Fr) */
+    [_response appendContentString:@"<tr>"];
+    [self appendDateTitleToResponse:_response inContext:_ctx day:1];
+    [self appendDateTitleToResponse:_response inContext:_ctx day:4];
+    [_response appendContentString:@"</tr>"];
+
+    [_response appendContentString:@"<tr>"];
+
+    [_response appendContentString:@"<td valign=\"top\""];
+    [self appendBgColor:_response inContext:_ctx day:1];
+    [_response appendContentCharacter:'>'];
+
+    [self appendContentToResponse:_response inContext:_ctx day:1];
+    [_response appendContentString:@"</td>"];
+    [_response appendContentString:@"<td valign=\"top\""];
+    [self appendBgColor:_response inContext:_ctx day:4];
+    [_response appendContentCharacter:'>'];
+    
+    [self appendContentToResponse:_response inContext:_ctx day:4];
+    [_response appendContentString:@"</td>"];
+    [_response appendContentString:@"</tr>"];
+}
+
+- (void)appendThirdRowToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx 
+{
+  /* third row (Mi, Sa, So ) */
+  BOOL showWeekend;
+
+  showWeekend = (self->hideWeekend != nil)
+    ? [self->hideWeekend boolValueInComponent:[_ctx component]] ? NO : YES
+    : YES;
+  
+  [_response appendContentString:@"<tr>"];
+  [self appendDateTitleToResponse:_response inContext:_ctx day:2]; /* Wed */
+  if (showWeekend)
+    [self appendDateTitleToResponse:_response inContext:_ctx day:5]; /* Sat */
+  [_response appendContentString:@"</tr>"];
+
+  [_response appendContentString:@"<tr>"];
+    
+  [_response appendContentString:
+              showWeekend 
+            ? @"<td rowspan=\"3\" valign=\"top\"" : @"<td valign=\"top\""];
+  [self appendBgColor:_response inContext:_ctx day:2]; /* Wed */
+  [_response appendContentCharacter:'>'];
+  
+  [self appendContentToResponse:_response inContext:_ctx day:2]; /* Wed */
+  [_response appendContentString:@"</td>"];
+  
+  if (showWeekend) {
+    [_response appendContentString:@"<td valign=\"top\""];
+    [self appendBgColor:_response inContext:_ctx day:5];
+    [_response appendContentCharacter:'>'];
+    
+    [self appendContentToResponse:_response inContext:_ctx day:5];
+    [_response appendContentString:@"</td>"];
+    [_response appendContentString:@"</tr>"];
+
+    [_response appendContentString:@"<tr>"];
+    [self appendDateTitleToResponse:_response inContext:_ctx day:6];
+    [_response appendContentString:@"</tr>"];
+
+    [_response appendContentString:@"<tr>"];
+    
+    [_response appendContentString:@"<td valign=\"top\""];
+    [self appendBgColor:_response inContext:_ctx day:6];
+    [_response appendContentCharacter:'>'];
+  
+    [self appendContentToResponse:_response inContext:_ctx day:6];
+    [_response appendContentString:@"</td>"];
+  }
+  
+  [_response appendContentString:@"</tr>"];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [self _calcMatrixInContext:_ctx];
+  
+  [_response appendContentString:@"<table "];
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  [_response appendContentString:@">"];  
+  
+  /* first row (Mo,Do) */
+  [self appendFirstRowToResponse:_response inContext:_ctx];
+  
+  /* second row (Di,Fr) */
+  [self appendSecondRowToResponse:_response inContext:_ctx];
+  
+  /* third row (Mi, Sa, So ) */
+  [self appendThirdRowToResponse:_response inContext:_ctx];
+  
+  [_response appendContentString:@"</table>"];
+
+  [self resetMatrix];
+}
+
+@end /* WeekOverview */
+
+@interface WEWeekColumnViewTitleMode : WEContextConditional
+@end
+
+@implementation WEWeekColumnViewTitleMode
+- (NSString *)_contextKey {
+  return WEWeekColumnView_TitleMode;
+}
+- (NSString *)_didMatchKey {
+  return WEWeekColumnView_TitleModeDidMatch;
+}
+@end
+
+// --
+
+@interface WEWeekColumnViewInfoMode : WEContextConditional
+@end
+
+@implementation WEWeekColumnViewInfoMode
+- (NSString *)_contextKey {
+  return WEWeekColumnView_InfoMode;
+}
+@end
+
+// --
+
+@interface WEWeekColumnViewContentMode : WEContextConditional
+@end
+
+@implementation WEWeekColumnViewContentMode
+- (NSString *)_contextKey {
+  return WEWeekColumnView_ContentMode;
+}
+@end
diff --git a/skyrix-sope/WEExtensions/WEWeekOverview.m b/skyrix-sope/WEExtensions/WEWeekOverview.m
new file mode 100644 (file)
index 0000000..9c6e507
--- /dev/null
@@ -0,0 +1,1379 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WEContextConditional.h"
+#include <NGObjWeb/WODynamicElement.h>
+
+/*
+
+  renders this:
+  _______________________________
+  | MO | TU | WE | TH | FR | SA |
+  |-----------------------------|
+  |    |    |    |    |    | 10 |
+  |  0 |  2 |  4 |  6 |  8 | 11 |
+  |____|____|____|____|____|____|
+  |    |    |    |    |    | SU |
+  |    |    |    |    |    |----|
+  |    |    |    |    |    | 12 |
+  |  1 |  3 |  5 |  7 |  9 | 13 |
+  |____|____|____|____|____|____|
+
+  Would be a nice addition:
+  |a   |b   |c   |d   |e   |f   |
+  -------------------------------
+  |a   |b   |c   |d   |e   |f   |
+  -------------------------------
+  footerRow = 0 / footerRowList = ( 0, 1, 2, 3, 4 );
+  headerRow = 0 / headerRowList = ( 0, 1, 2, 3, 4 );
+  startDate/endDate
+  
+  the numbers corresponde to the indxes in the matrix (self->matrix[])
+
+  Note: it does support additional header and footer rows which can be used
+        to generate content above and below the view itself.
+
+  Usage:
+    WeekOverview: WEWeekOverview {
+      list       = list;
+      item       = item;
+      weekStart  = weekStart;
+      
+      titleStyle   = "weekview_title";
+      contentStyle = "weekview_content";
+    }
+    
+    TitleMode:   WEWeekOverviewTitleMode   {};
+    InfoMode:    WEWeekOverviewInfoMode    {};
+    ContentMode: WEWeekOverviewContentMode {};
+*/
+
+// TODO: allow stylesheet classes!
+
+#define SecondsPerWeek (7 * 24 * 60 * 60)
+#define SecondsPerDay      (24 * 60 * 60)
+
+@class NSMutableArray;
+
+#define WEWeekOverview_TitleMode         @"WEWeekOverview_TitleMode"
+#define WEWeekOverview_TitleModeDidMatch @"WEWeekOverview_TitleModeDidMatch"
+#define WEWeekOverview_InfoMode          @"WEWeekOverview_InfoMode"
+#define WEWeekOverview_PMInfoMode        @"WEWeekOverview_PMInfoMode"
+#define WEWeekOverview_ContentMode       @"WEWeekOverview_ContentMode"
+
+#define WEWeekOverview_FooterRowMode     @"WEWeekOverview_FooterRowMode"
+#define WEWeekOverview_HeaderRowMode     @"WEWeekOverview_HeaderRowMode"
+
+@interface WEWeekOverview : WODynamicElement
+{
+@protected
+  WOAssociation  *list;
+  WOAssociation  *item;
+  WOAssociation  *index;
+  WOAssociation  *identifier;
+  
+  WOAssociation  *dayIndex; // 0=firstDay, 1=secondDay, ..., 6=seventh day
+  WOAssociation  *weekStart;
+  
+  WOAssociation  *startDateKey;
+  WOAssociation  *endDateKey;
+  
+  WOAssociation  *titleStyle;
+  WOAssociation  *contentStyle;
+  WOAssociation  *titleColor;   // DEPRECATED
+  WOAssociation  *contentColor; // DEPRECATED
+  
+  WOAssociation  *width;
+  WOAssociation  *border;
+  WOAssociation  *cellpadding;
+  WOAssociation  *cellspacing;
+
+  WOAssociation  *footerRows; // list of elements for footer rows
+  WOAssociation  *footerRow;  // current element in footer row
+  WOAssociation  *headerRows; // list of elements for header rows
+  WOAssociation  *headerRow;  // current element in header row
+  WOAssociation  *colIndex;   // for header/footer row
+  
+  WOAssociation  *isInfoItem; // is current item info entry
+  WOAssociation  *infoItems;  // current info entries
+  
+  WOAssociation  *hideWeekend; /* should Sa/So be rendered? */
+
+@private
+  NSMutableArray *matrix[14];
+  NSMutableArray *infos[14];
+  BOOL           hasOwnTitle;
+  
+  WOElement      *template;
+}
+@end
+
+#include <math.h> /* Needed for floor() */
+#include "common.h"
+
+@interface WOContext(WEWeekOverview)
+
+- (void)appendWEIntElementID:(int)_intID;
+
+- (void)enterWEWOMode:(NSString *)_mode elementID:(NSString *)_eid;
+- (void)leaveWEWOMode:(NSString *)_mode;
+
+@end
+
+static NSString *retStrForInt(int i);
+static NSString *WEInfoElementID = @"i";
+
+@implementation WOContext(WEWeekOverview)
+
+- (void)appendWEIntElementID:(int)_intID {
+  NSString *s;
+  // TODO: could make the number switch in here?
+  
+  s = retStrForInt(_intID);
+  [self appendElementIDComponent:s];
+  [s release];
+}
+
+- (void)enterWEWOMode:(NSString *)_mode elementID:(NSString *)_eid {
+  [self setObject:@"YES" forKey:_mode];
+  [self appendElementIDComponent:_eid];
+}
+- (void)leaveWEWOMode:(NSString *)_mode {
+  [self deleteLastElementIDComponent]; // delete eid
+  [self removeObjectForKey:_mode];
+}
+
+@end /* WOContext(WEWeekOverview) */
+
+@implementation WEWeekOverview
+
+// premature: don't know a "good" count
+static NSNumber *smap[10] = { nil,nil,nil,nil,nil,nil,nil,nil,nil,nil };
+static Class    NumClass  = Nil;
+static Class    StrClass  = Nil;
+static NSArray  *emptyArray = nil;
+
++ (void)initialize {
+  static BOOL didInit = NO;
+  int i;
+  if (didInit) return;
+  didInit = YES;
+  
+  StrClass = [NSString class];
+  NumClass = [NSNumber class];
+  for (i = 0; i < 10; i++)
+    smap[i] = [[NumClass numberWithInt:i] retain];
+  
+  if (emptyArray == nil) emptyArray = [[NSArray alloc] init];
+}
+
+static NSNumber *numForInt(int i) {
+  if (i >= 0 && i < 10)
+    return smap[i];
+  return [NumClass numberWithInt:i];
+}
+static NSString *retStrForInt(int i) {
+  switch(i) {
+  case 0:  return @"0";
+  case 1:  return @"1";
+  case 2:  return @"2";
+  case 3:  return @"3";
+  case 4:  return @"4";
+  case 5:  return @"5";
+  case 6:  return @"6";
+  case 7:  return @"7";
+  case 8:  return @"8";
+  case 9:  return @"9";
+  case 10: return @"10";
+    // TODO: find useful count!
+  default: {
+    char buf[16];
+    sprintf(buf, "%i", i);
+    return [[StrClass alloc] initWithCString:buf];
+  }
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmp
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmp])) {
+    self->list         = WOExtGetProperty(_config, @"list");
+    self->item         = WOExtGetProperty(_config, @"item");
+    self->index        = WOExtGetProperty(_config, @"index");
+    self->identifier   = WOExtGetProperty(_config, @"identifier");
+    self->dayIndex     = WOExtGetProperty(_config, @"dayIndex");
+    self->weekStart    = WOExtGetProperty(_config, @"weekStart");
+    self->startDateKey = WOExtGetProperty(_config, @"startDateKey");
+    self->endDateKey   = WOExtGetProperty(_config, @"endDateKey");
+    self->hideWeekend  = WOExtGetProperty(_config, @"hideWeekend");
+
+    self->titleColor   = WOExtGetProperty(_config, @"titleColor");
+    self->titleStyle   = WOExtGetProperty(_config, @"titleStyle");
+    self->contentColor = WOExtGetProperty(_config, @"contentColor");
+    self->contentStyle = WOExtGetProperty(_config, @"contentStyle");
+    
+    self->width        = WOExtGetProperty(_config, @"width");
+    self->border       = WOExtGetProperty(_config, @"border");
+    self->cellspacing  = WOExtGetProperty(_config, @"cellspacing");
+    self->cellpadding  = WOExtGetProperty(_config, @"cellpadding");
+
+    self->headerRows   = WOExtGetProperty(_config, @"headerRows");
+    self->headerRow    = WOExtGetProperty(_config, @"headerRow");
+    self->footerRows   = WOExtGetProperty(_config, @"footerRows");
+    self->footerRow    = WOExtGetProperty(_config, @"footerRow");
+    self->colIndex     = WOExtGetProperty(_config, @"columnIndex");
+
+    
+    if (self->startDateKey == nil) {
+      self->startDateKey = 
+        [[WOAssociation associationWithValue:@"startDate"] retain];
+    }
+
+    if (self->endDateKey == nil) {
+      self->endDateKey = 
+        [[WOAssociation associationWithValue:@"endDate"] retain];
+    }
+    
+    if (self->width == nil)
+      self->width = [[WOAssociation associationWithValue:@"100%"] retain];
+    if (self->border == nil)
+      self->border = [[WOAssociation associationWithValue:@"0"] retain];
+    if (self->cellspacing == nil)
+      self->cellspacing = [[WOAssociation associationWithValue:@"2"] retain];
+    if (self->cellpadding == nil)
+      self->cellpadding = [[WOAssociation associationWithValue:@"5"] retain];
+    
+    self->isInfoItem = WOExtGetProperty(_config, @"isInfoItem");
+    self->infoItems  = WOExtGetProperty(_config, @"infoItems");
+
+    self->template = [_tmp retain];    
+  }
+  return self;
+}
+
+- (void)resetMatrix {
+  int i;
+  
+  for (i = 0; i < 14; i++) {
+    [self->matrix[i] release]; self->matrix[i] = nil;
+    [self->infos[i]  release]; self->infos[i]  = nil;
+  }
+}
+
+- (void)dealloc {
+  [self->hideWeekend  release];
+  [self->list         release];
+  [self->item         release];
+  [self->index        release];
+  [self->identifier   release];
+  [self->dayIndex     release];
+  [self->weekStart    release];
+  [self->startDateKey release];
+  [self->endDateKey   release];
+  [self->titleColor   release];
+  [self->titleStyle   release];
+  [self->contentColor release];
+  [self->contentStyle release];
+  [self->width        release];
+  [self->border       release];
+  [self->cellpadding  release];
+  [self->cellspacing  release];
+  [self->headerRows   release];
+  [self->headerRow    release];
+  [self->footerRows   release];
+  [self->footerRow    release];
+  [self->colIndex     release];
+  [self->infoItems    release];
+  [self->isInfoItem   release];
+
+  [self resetMatrix];
+
+  [self->template release];
+  
+  [super dealloc];
+}
+
+static inline void
+_applyIdentifier(WEWeekOverview *self, WOComponent *comp, NSString *_idx)
+{
+  NSArray *array;
+  unsigned count, cnt;
+
+  array = [self->list valueInComponent:comp];
+  count = [array count];
+
+  if (count == 0)
+    return;
+    
+  /* find subelement for unique id */
+    
+  for (cnt = 0; cnt < count; cnt++) {
+    NSString *ident;
+      
+    if (self->index)
+      [self->index setUnsignedIntValue:cnt inComponent:comp];
+
+    if (self->item)
+      [self->item setValue:[array objectAtIndex:cnt] inComponent:comp];
+
+    ident = [self->identifier stringValueInComponent:comp];
+
+    if ([ident isEqualToString:_idx]) {
+      /* found subelement with unique id */
+      return;
+    }
+  }
+    
+  [comp logWithFormat:
+         @"WEWeekOverview: array did change, "
+         @"unique-id isn't contained."];
+  [self->item  setValue:nil          inComponent:comp];
+  [self->index setUnsignedIntValue:0 inComponent:comp];
+}
+
+static inline void
+_applyIndex(WEWeekOverview *self, WOComponent *comp, unsigned _idx)
+{
+  NSArray  *array;
+  unsigned count;
+  
+  array = [self->list valueInComponent:comp];
+  
+  if (self->index)
+    [self->index setUnsignedIntValue:_idx inComponent:comp];
+
+  if (self->item == nil)
+    return;
+  
+  count = [array count];
+  if (_idx < count) {
+    [self->item setValue:[array objectAtIndex:_idx] inComponent:comp];
+    return;
+  }
+
+  [comp logWithFormat:
+            @"WEWeekOverview: array did change, index is invalid."];
+  [self->item  setValue:nil          inComponent:comp];
+  [self->index setUnsignedIntValue:0 inComponent:comp];
+}
+
+- (void)_calcMatrixInContext:(WOContext *)_ctx {
+  WOComponent    *comp;
+  NSCalendarDate *startWeek;
+  NSCalendarDate *endWeek;
+  NSArray        *array;
+  NSString       *startKey;
+  NSString       *endKey;
+  int            i, idx, idx2, cnt;
+  
+  [self resetMatrix];
+
+  [_ctx removeObjectForKey:WEWeekOverview_TitleModeDidMatch];
+  [_ctx setObject:@"YES" forKey:WEWeekOverview_TitleMode];
+  [self->template appendToResponse:nil inContext:_ctx];
+  [_ctx removeObjectForKey:WEWeekOverview_TitleMode];
+  
+  if ([_ctx objectForKey:WEWeekOverview_TitleModeDidMatch] != nil)
+    self->hasOwnTitle = YES;
+  else
+    self->hasOwnTitle = NO;
+  
+  comp      = [_ctx component];
+  array     = [self->list valueInComponent:comp];
+  startKey  = [self->startDateKey stringValueInComponent:comp];
+  endKey    = [self->endDateKey   stringValueInComponent:comp];
+  startWeek = (self->weekStart)
+    ? [self->weekStart valueInComponent:comp]
+    : [NSCalendarDate calendarDate];
+  endWeek   = [startWeek addTimeInterval:SecondsPerWeek];
+  
+  for (i = 0, cnt = [array count]; i < cnt; i++) {
+    id             app;
+    NSCalendarDate *sd, *ed;
+    NSTimeInterval diff;
+    BOOL           isInfo;
+    
+    app = [array objectAtIndex:i];
+#if 0 // hh: so muesste es eigentlich sein: !!!
+    [self->item setValue:app inComponent:comp];
+    
+    sd = [self->startDate valueInComponent:comp]; // item.startDate;
+    ed = [self->endDate   valueInComponent:comp]; // item.startDate;
+#endif
+    
+    sd  = [app valueForKey:startKey]; // startDate
+    ed  = [app valueForKey:endKey];   // endDate
+
+    if ((sd == nil) && (ed == nil)) continue;
+    
+    diff  = [(sd ? sd : ed) timeIntervalSinceDate:startWeek];
+
+    idx = floor((diff / SecondsPerWeek) * 14);
+
+    if ((self->item) && (self->isInfoItem)) {
+      [self->item setValue:app inComponent:comp];
+      isInfo = [[self->isInfoItem valueInComponent:comp] boolValue];
+    }
+    else isInfo = NO;
+    
+    if ((0 <= idx) && (idx < 14)) {      
+      if (isInfo) {
+        if (self->infos[idx] == nil)
+          self->infos[idx] = [[NSMutableArray alloc] initWithCapacity:2];      
+        [self->infos[idx] addObject:numForInt(i)];
+      }
+      else {
+        if (self->matrix[idx] == nil)
+          self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
+        [self->matrix[idx] addObject:numForInt(i)];       
+      }
+    }
+    if (idx >= 0)
+      idx = (idx % 2) ? idx + 1: idx +2;
+    
+    diff = [ed timeIntervalSinceDate:startWeek];
+    
+    idx2 = floor((diff / SecondsPerWeek) * 14);
+    idx2 = (idx2 > 13) ? 13 : idx2;
+
+    if (idx2 < 0) continue;
+    
+    while (idx <= idx2) {
+      idx = (idx < 0) ? 0 : idx;
+      if (isInfo) {
+        if (self->infos[idx] == nil)
+          self->infos[idx] = [[NSMutableArray alloc] initWithCapacity:2];      
+        // TODO: optimize
+        [self->infos[idx] addObject:numForInt(i)];
+      }
+      else {
+        if (self->matrix[idx] == nil)
+          self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
+        // TODO: optimize
+        [self->matrix[idx] addObject:numForInt(i)];       
+      }
+      idx = idx + 2;
+    }
+  }
+}
+
+/* common template operations */
+
+- (void)appendTemplateToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx
+  mode:(NSString *)_mode elementID:(NSString *)_modeId
+  index:(int)_idx
+{
+  [_ctx enterWEWOMode:_mode elementID:_modeId];
+  [_ctx appendWEIntElementID:_idx];
+  [self->template appendToResponse:_r inContext:_ctx];
+  [_ctx deleteLastElementIDComponent]; // delete idx
+  [_ctx leaveWEWOMode:_mode];
+}
+
+/* header rows */
+
+- (void)appendHeaderRowToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  column:(int)_col
+{
+  WOComponent *comp;
+  NSString    *bgcolor, *style;
+  
+  comp = [_ctx component];
+
+  if ([self->colIndex isValueSettable])
+    [self->colIndex setIntValue:_col inComponent:comp];
+
+  bgcolor = [self->contentColor stringValueInComponent:comp];
+  style   = [self->contentStyle stringValueInComponent:comp];
+  
+  [_response appendContentString:
+             @"<td valign=\"top\" align=\"left\" width=\"17%\""];
+  if (bgcolor) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentString:bgcolor];
+    [_response appendContentCharacter:'"'];
+  }
+  if ([style length] > 0) {
+    [_response appendContentString:@" class=\""];
+    [_response appendContentString:style];
+    [_response appendContentCharacter:'"'];
+  }
+  [_response appendContentCharacter:'>'];
+
+  [self appendTemplateToResponse:_response inContext:_ctx
+       mode:WEWeekOverview_HeaderRowMode elementID:@"h"
+       index:_col];
+  
+  [_response appendContentString:@"</td>"];
+}
+- (void)appendHeaderRowToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  row:(id)_rowItem
+{
+  int i, cnt;
+  
+  if ([self->headerRow isValueSettable])
+    [self->headerRow setValue:_rowItem inComponent:[_ctx component]];
+  
+  /* Saturday/Sunday is the 6th column */
+  cnt = (self->hideWeekend != nil)
+    ? [self->hideWeekend boolValueInComponent:[_ctx component]] ? 5 : 6
+    : 6;
+  
+  for (i = 0; i < cnt; i++)
+    [self appendHeaderRowToResponse:_response inContext:_ctx column:i];
+}
+- (void)appendHeaderRowsToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  /* add n <tr> rows */
+  WOComponent *comp;
+  NSArray     *headers;
+  int         cnt, i;
+  
+  comp = [_ctx component];
+  if ((headers = [self->headerRows valueInComponent:comp]) == nil)
+    return;
+  
+  for (i = 0, cnt = [headers count]; i < cnt; i++) {
+    id one;
+    
+    one = [headers objectAtIndex:i];
+      
+    [_response appendContentString:@"<tr>"];
+    [_ctx appendElementIDComponent:@"hr"]; // header row
+    [_ctx appendWEIntElementID:i];
+    
+    [self appendHeaderRowToResponse:_response inContext:_ctx row:one];
+      
+    [_ctx deleteLastElementIDComponent]; // remove idx (i)
+    [_ctx deleteLastElementIDComponent]; // remove 'hr'
+    [_response appendContentString:@"</tr>"];
+  }
+}
+
+/* footer rows */
+
+- (void)appendFooterRowToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  column:(int)_col
+{
+  WOComponent *comp;
+  NSString    *bgcolor;
+  
+  comp = [_ctx component];
+  
+  if ([self->colIndex isValueSettable])
+    [self->colIndex setIntValue:_col inComponent:comp];
+  
+  bgcolor = [self->contentColor stringValueInComponent:comp];
+  
+  [_response appendContentString:
+             @"<td valign=\"top\" align=\"left\" width=\"17%\""];
+  if (bgcolor) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentString:bgcolor];
+    [_response appendContentCharacter:'"'];
+  }
+  [_response appendContentCharacter:'>'];
+
+  [self appendTemplateToResponse:_response inContext:_ctx
+       mode:WEWeekOverview_FooterRowMode elementID:@"f"
+       index:_col];
+  
+  [_response appendContentString:@"</td>"];
+}
+
+- (void)appendFooterRowToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  row:(id)_rowItem
+{
+  // TODO: this method is a DUP to appendHeaderRowToResponse... => refactor
+  int i, cnt;
+  
+  if ([self->footerRow isValueSettable])
+    [self->footerRow setValue:_rowItem inComponent:[_ctx component]];
+  
+  /* Saturday/Sunday is the 6th column */
+  cnt = (self->hideWeekend != nil)
+    ? [self->hideWeekend boolValueInComponent:[_ctx component]] ? 5 : 6
+    : 6;
+  
+  for (i = 0; i < cnt; i++) 
+    [self appendFooterRowToResponse:_response inContext:_ctx column:i];
+}
+
+- (void)appendFooterRowsToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  // TODO: this is a copy of the head-row method!
+  WOComponent *comp;
+  NSArray     *footers;
+  int i, cnt;
+
+  comp = [_ctx component];
+
+  if ((footers = [self->footerRows valueInComponent:comp]) == nil)
+    return;
+
+  for (i = 0, cnt = [footers count]; i < cnt; i++) {
+    NSString *s;
+    id one;
+
+    one = [footers objectAtIndex:i];
+      
+    [_response appendContentString:@"<tr>"];
+    [_ctx appendElementIDComponent:@"fr"];
+
+    s = retStrForInt(i);
+    [_ctx appendElementIDComponent:s];
+    [s release];
+      
+    [self appendFooterRowToResponse:_response inContext:_ctx row:one];
+      
+    [_ctx deleteLastElementIDComponent]; // remove idx (i)
+    [_ctx deleteLastElementIDComponent]; // remove 'fr'
+    [_response appendContentString:@"</tr>"];
+  }
+}
+
+- (void)appendDateTitleToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  day:(int)_day
+{
+  WOComponent *comp;
+  NSString    *bgcolor, *style;
+
+  comp = [_ctx component];
+  
+  if ([self->dayIndex isValueSettable])
+    [self->dayIndex setIntValue:_day inComponent:comp];
+
+  bgcolor = [self->titleColor stringValueInComponent:comp];
+  style   = [self->titleStyle stringValueInComponent:comp];
+  
+  // TODO: use CSS for alignment, width and color
+  [_response appendContentString:
+             @"<td valign=\"top\" align=\"left\" width=\"17%\""];
+  if ([bgcolor length] > 0) {
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentString:bgcolor];
+    [_response appendContentCharacter:'"'];
+  }
+  if ([style length] > 0) {
+    [_response appendContentString:@" class=\""];
+    [_response appendContentString:style];
+    [_response appendContentCharacter:'"'];
+  }
+  [_response appendContentCharacter:'>'];
+  
+  if (self->hasOwnTitle) {
+    [self appendTemplateToResponse:_response inContext:_ctx
+         mode:WEWeekOverview_TitleMode elementID:@"t"
+         index:_day];
+  }
+  else {
+    NSCalendarDate *date;
+    NSString *s;
+    
+    date = (self->weekStart)
+      ? [self->weekStart valueInComponent:comp]
+      : [NSCalendarDate calendarDate];
+    date = [date addTimeInterval:_day * SecondsPerDay];
+    
+    [_response appendContentString:
+               @"<table cellpadding=\"0\" width=\"100%\" border=\"0\" "
+              @"cellspacing=\"0\">"
+               @"<tr>"
+               @"<td align=\"left\" valign=\"top\">"
+              // TODO: use style for that
+               @"<font color=\"black\" size=\"+2\"><b>"];
+    
+    s = [date descriptionWithCalendarFormat:@"%d"]; // TODO: no cal-desc!
+    [_response appendContentString:s];
+    
+    [_response appendContentString:
+               @"</b></font></td>"
+               @"<td align=\"center\" valign=\"top\">"
+              // TODO: use style for that
+               @"<font color=\"black\">"];
+    s = [date descriptionWithCalendarFormat:@"%A"]; // TODO: no cal-desc
+    [_response appendContentString:s]; // TODO: do not use cal-desc
+    [_response appendContentString:
+               @"</font>"
+               @"</td></tr></table>"];
+  }
+  [_response appendContentString:@"</td>"];
+}
+
+- (void)appendContentToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+  index:(int)_index
+{
+  WOComponent *comp;
+  NSArray     *array;
+  id          app;
+  int         i, cnt, idx, count;
+  
+  comp  = [_ctx component];
+  array = [self->list valueInComponent:comp];
+  count = [array count];
+
+  /* idx is the dayIndex 0=1stDay ... 6=7thDay (e.g. 0=Mon ... 6=Sun) */
+  idx = (int)(_index / 2);
+  
+  if ([self->dayIndex isValueSettable])
+    [self->dayIndex setIntValue:idx inComponent:comp];
+
+  if ([self->infoItems isValueSettable]) {
+    cnt = [self->infos[_index] count];
+    if (cnt) {
+      NSMutableArray *infoArr;
+      
+      infoArr = [[NSMutableArray alloc] initWithCapacity:cnt];
+      for (i = 0; i < cnt; i++) {
+        idx = [[self->infos[_index] objectAtIndex:i] intValue];
+        
+        if (idx >= count) {
+          [self logWithFormat:
+                 @"WARNING: WEWeekOverview: info index out of range"];
+          continue;
+        }
+        [infoArr addObject:[array objectAtIndex:idx]];
+      }
+      [self->infoItems setValue:infoArr inComponent:comp];
+      [infoArr release]; infoArr = nil;
+    }
+    else
+      [self->infoItems setValue:emptyArray inComponent:comp];
+  }
+
+  // *** append day info
+  if ((_index % 2) == 0) {
+    // if AM-section...
+    
+    [self appendTemplateToResponse:_response inContext:_ctx
+         mode:WEWeekOverview_InfoMode elementID:WEInfoElementID
+         index:idx];
+  }
+  else if (_index < 10) {
+    /*  P.M. slot of Monday .. Friday */
+    [self appendTemplateToResponse:_response inContext:_ctx
+         mode:WEWeekOverview_PMInfoMode elementID:@"p"
+         index:idx];
+  }
+  
+  // *** append day content
+  [_ctx enterWEWOMode:WEWeekOverview_ContentMode elementID:@"c"];
+  
+  // append section id (0 = Mon AM, 1 = Mon PM, 2 = Tue AM, ...)
+  [_ctx appendWEIntElementID:_index];
+  
+  for (i = 0, cnt = [self->matrix[_index] count]; i < cnt; i++) {
+    idx = [[self->matrix[_index] objectAtIndex:i] intValue];
+
+    if (idx >= count) {
+      NSLog(@"Warning! WEWeekOverview: index out of range");
+      continue;
+    }
+    
+    app = [array objectAtIndex:idx];
+
+    if ([self->item isValueSettable])
+      [self->item  setValue:app inComponent:comp];
+    if ([self->index isValueSettable])
+      [self->index setIntValue:idx inComponent:comp];
+
+    if (self->identifier == nil) {
+      NSString *s;
+      
+      s = retStrForInt(idx);
+      [_ctx appendElementIDComponent:s];
+      [s release];
+    }
+    else {
+      NSString *s;
+
+      s = [self->identifier stringValueInComponent:comp];
+      [_ctx appendElementIDComponent:s];
+    }
+    [self->template appendToResponse:_response inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+  if (cnt == 0)
+    [_response appendContentString:@"&nbsp;"];
+  
+  [_ctx deleteLastElementIDComponent]; // delete section id
+  [_ctx leaveWEWOMode:WEWeekOverview_ContentMode];
+}
+
+/* processing requests */
+
+- (void)takeValuesForHeaderRows:(WORequest *)_req
+  ctx:(WOContext *)_ctx
+{
+  WOComponent *comp;
+  NSArray     *headers;
+  int i, cnt;
+
+  comp    = [_ctx component];
+  if ((headers = [self->headerRows valueInComponent:comp]) == nil)
+    return;
+
+  [_ctx setObject:@"YES" forKey:WEWeekOverview_HeaderRowMode];
+  [_ctx appendElementIDComponent:@"hr"]; // append 'hr'
+  [_ctx appendZeroElementIDComponent];   // append i
+
+  for (i = 0, cnt = [headers count]; i < cnt; i++) {
+    int c;
+
+    [_ctx appendElementIDComponent:@"h"]; // append 'h'
+    [_ctx appendZeroElementIDComponent];  // append c
+      
+    if ([self->headerRow isValueSettable])
+      [self->headerRow setValue:[headers objectAtIndex:i] inComponent:comp];
+      
+    // TODO: do not go over Saturday (6) with hideWeekend=YES
+    for (c = 0; c < 6; c++) { // go throw columns
+      if ([self->colIndex isValueSettable])
+       [self->colIndex setIntValue:c inComponent:comp];
+        
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+      [_ctx incrementLastElementIDComponent]; // increment c
+    }
+      
+    [_ctx deleteLastElementIDComponent];    // delete c
+    [_ctx deleteLastElementIDComponent];    // delete 'h'
+    [_ctx incrementLastElementIDComponent]; // increment i
+  }
+  
+  [_ctx deleteLastElementIDComponent]; // remove i
+  [_ctx deleteLastElementIDComponent]; // remove 'hr'
+  [_ctx removeObjectForKey:WEWeekOverview_HeaderRowMode];
+}
+- (void)takeValuesForFooterRows:(WORequest *)_req
+  ctx:(WOContext *)_ctx
+{
+  // TODO: this is a DUP of the header row
+  //       we might implement that code as an internal WODynamicElement?
+  WOComponent *comp;
+  NSArray     *footers;
+  int i, cnt;
+
+  comp    = [_ctx component];
+  if ((footers = [self->footerRows valueInComponent:comp]) == nil)
+    return;
+
+  [_ctx setObject:@"YES" forKey:WEWeekOverview_FooterRowMode];
+  [_ctx appendElementIDComponent:@"hr"]; // append 'fr'
+  [_ctx appendZeroElementIDComponent];   // append i
+  
+  for (i = 0, cnt = [footers count]; i < cnt; i++) {
+      int c;
+      [_ctx appendElementIDComponent:@"f"]; // append 'f'
+      [_ctx appendZeroElementIDComponent];  // append c
+      
+      if ([self->footerRow isValueSettable])
+        [self->footerRow setValue:[footers objectAtIndex:i] inComponent:comp];
+      
+      // TODO: do not go over Saturday (6) with hideWeekend=YES
+      for (c = 0; c < 6; c++) { // go throw columns
+        if ([self->colIndex isValueSettable])
+          [self->colIndex setIntValue:c inComponent:comp];
+        [self->template takeValuesFromRequest:_req inContext:_ctx];
+        [_ctx incrementLastElementIDComponent]; // increment c
+      }
+      
+      [_ctx deleteLastElementIDComponent];    // delete c
+      [_ctx deleteLastElementIDComponent];    // delete 'f'
+      [_ctx incrementLastElementIDComponent]; // increment i
+  }
+
+  [_ctx deleteLastElementIDComponent]; // remove i
+  [_ctx deleteLastElementIDComponent]; // remove 'fr'
+  [_ctx removeObjectForKey:WEWeekOverview_FooterRowMode];
+}
+
+- (void)takeValues:(WORequest *)_req
+  mode:(NSString *)_mode modeId:(NSString *)_id
+  ctx:(WOContext *)_ctx
+{
+  int i;
+  
+  [_ctx setObject:@"YES" forKey:_mode];
+  [_ctx appendElementIDComponent:_id];   // append mode id
+  [_ctx appendZeroElementIDComponent];   // append first day (monday)
+  
+  // TODO: do not go over Saturday (5), Sunday(6) with hideWeekend=YES
+  for (i = 0; i < 7; i++) {
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:i inComponent:[_ctx component]];
+    
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+    [_ctx incrementLastElementIDComponent]; // increment day
+  }
+  [_ctx deleteLastElementIDComponent];  // delete day
+  [_ctx deleteLastElementIDComponent];  // delete title mode
+  [_ctx removeObjectForKey:_mode];
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *comp;
+  NSArray     *array;
+  int         i, count;
+  
+  comp  = [_ctx component];
+  array = [self->list valueInComponent:comp];
+  count = [array count];
+
+  /* titles */
+  [self takeValues:_req mode:WEWeekOverview_TitleMode modeId:@"t" ctx:_ctx];
+
+  /* headers */
+  [self takeValuesForHeaderRows:_req ctx:_ctx];
+  
+  /* infos */
+  [self takeValues:_req mode:WEWeekOverview_InfoMode modeId:WEInfoElementID 
+       ctx:_ctx];
+
+  /* P.M.Infos */
+  [self takeValues:_req mode:WEWeekOverview_PMInfoMode modeId:@"p" ctx:_ctx];
+
+  [self _calcMatrixInContext:_ctx];
+
+  [_ctx setObject:@"YES" forKey:WEWeekOverview_ContentMode];
+  [_ctx appendElementIDComponent:@"c"]; // append content mode
+  [_ctx appendZeroElementIDComponent];  // append section-id
+  for (i = 0; i < 14; i++) {
+    int     j, cnt, idx;
+    
+    cnt   = [self->matrix[i] count];
+    
+    if ((i % 2) == 0 && [self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:(int)(i / 2) inComponent:comp];
+    
+    for (j = 0; j < cnt; j++) {
+      NSString *s;
+      
+      idx = [[self->matrix[i] objectAtIndex:j] intValue];
+      
+      if (idx >= count) {
+        NSLog(@"Warning! WEWeekRepetition: Index is out of range");
+        continue;
+      }
+      
+      _applyIndex(self, comp, idx);
+      
+      if (self->identifier) {
+        s = [self->identifier stringValueInComponent:comp];
+        [_ctx appendElementIDComponent:s];
+      }
+      else {
+        s = retStrForInt(idx);
+        [_ctx appendElementIDComponent:s];
+        [s release];
+      }
+
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+      
+      [_ctx deleteLastElementIDComponent];   // delete index-id
+    }
+    [_ctx incrementLastElementIDComponent]; // increase section-id
+  }
+  [_ctx deleteLastElementIDComponent];  // delete section-id
+  [_ctx deleteLastElementIDComponent];  // delete content mode
+  [_ctx removeObjectForKey:WEWeekOverview_ContentMode];
+  
+  /* footers */
+  [self takeValuesForFooterRows:_req ctx:_ctx];
+
+  [self resetMatrix];  
+}
+
+- (id)invokeActionForHeader:(WORequest *)_req inContext:(WOContext *)_ctx
+  row:(id)_row
+{
+  WOComponent *comp;
+  NSString *section;   // must be 'h'
+  NSString *colIdx;    // must be between 0 and 6
+
+  id result;
+
+  comp = [_ctx component];
+
+  section = [_ctx currentElementID];
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:section];
+  colIdx  = [_ctx currentElementID];
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:colIdx];
+
+  if ([self->headerRow isValueSettable])
+    [self->headerRow setValue:_row inComponent:comp];
+  if ([self->dayIndex isValueSettable])
+    [self->colIndex setIntValue:[colIdx intValue] inComponent:comp];
+
+  result = [self->template invokeActionForRequest:_req inContext:_ctx];
+
+  [_ctx deleteLastElementIDComponent]; // column idx
+  [_ctx deleteLastElementIDComponent]; // section ('h')
+
+  return result;
+}
+- (id)invokeActionForFooter:(WORequest *)_req inContext:(WOContext *)_ctx
+  row:(id)_row
+{
+  WOComponent *comp;
+  NSString *section;   // must be 'f'
+  NSString *colIdx;    // must be between 0 and 6
+
+  id result;
+
+  comp = [_ctx component];
+
+  section = [_ctx currentElementID];
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:section];
+  colIdx  = [_ctx currentElementID];
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:colIdx];
+
+  if ([self->footerRow isValueSettable])
+    [self->footerRow setValue:_row inComponent:comp];
+  if ([self->dayIndex isValueSettable])
+    [self->colIndex setIntValue:[colIdx intValue] inComponent:comp];
+
+  result = [self->template invokeActionForRequest:_req inContext:_ctx];
+
+  [_ctx deleteLastElementIDComponent]; // column idx
+  [_ctx deleteLastElementIDComponent]; // section ('f')
+
+  return result;
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *comp;
+  id          result = nil;
+  NSString    *cid;
+  NSString    *sectionId;
+
+  cid = [_ctx currentElementID];       // get mode ("t" or "i" or "c")
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:cid];
+  sectionId = [_ctx currentElementID];       // get section id
+  [_ctx consumeElementID];
+  [_ctx appendElementIDComponent:sectionId];
+
+  comp = [_ctx component];
+
+  if ([cid isEqualToString:@"t"] ||
+      [cid isEqualToString:WEInfoElementID] || [cid isEqualToString:@"p"]) {
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:[sectionId intValue] inComponent:comp];
+    result = [self->template invokeActionForRequest:_req inContext:_ctx];
+  }
+  else if ([cid isEqualToString:@"c"]) {
+    NSString *idxId;
+
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:([sectionId intValue] / 2) inComponent:comp];
+
+    if ((idxId = [_ctx currentElementID])) {
+      [_ctx consumeElementID];               // consume index-id
+      [_ctx appendElementIDComponent:idxId];
+
+      if (self->identifier)
+        _applyIdentifier(self, comp, idxId);
+      else
+        _applyIndex(self, comp, [idxId intValue]);
+
+      result = [self->template invokeActionForRequest:_req inContext:_ctx];
+
+      [_ctx deleteLastElementIDComponent]; // delete index-id
+    }
+  }
+  else if ([cid isEqualToString:@"hr"]) {
+    NSArray  *headers;
+    int      idx;
+
+    headers = [self->headerRows valueInComponent:comp];
+    idx     = [sectionId intValue];
+    if (idx >= (int)[headers count]) {
+      NSLog(@"WARNING! WEWeekOverview: wrong headerrow index");
+    }
+    else {
+      result = [self invokeActionForHeader:_req
+                     inContext:_ctx
+                     row:[headers objectAtIndex:idx]];
+    }
+  }
+  else if ([cid isEqualToString:@"fr"]) {
+    NSArray  *footers;
+    int      idx;
+
+    footers = [self->footerRows valueInComponent:comp];
+    idx     = [sectionId intValue];
+    if (idx >= (int)[footers count]) {
+      NSLog(@"WARNING! WEWeekOverview: wrong footerrow index");
+    }
+    else {
+      result = [self invokeActionForFooter:_req
+                     inContext:_ctx
+                     row:[footers objectAtIndex:idx]];
+    }
+  }
+  else
+    NSLog(@"WARNING! WEWeekOverview: wrong section");
+
+  [_ctx deleteLastElementIDComponent]; // delete section id
+  [_ctx deleteLastElementIDComponent]; // delete mode
+  
+  return result;
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *comp;
+  NSString    *bgcolor, *style;
+  NSString    *w;  // width
+  NSString    *b;  // border
+  NSString    *cp; // cellpadding
+  NSString    *cs; // cellspacing
+  int         i;
+  BOOL        showWeekend;
+  
+  [self _calcMatrixInContext:_ctx];
+  
+  comp = [_ctx component];
+  w    = [self->width       stringValueInComponent:comp];
+  b    = [self->border      stringValueInComponent:comp];
+  cs   = [self->cellspacing stringValueInComponent:comp];
+  cp   = [self->cellpadding stringValueInComponent:comp];
+  
+  showWeekend = (self->hideWeekend != nil)
+    ? [self->hideWeekend boolValueInComponent:comp] ? NO : YES
+    : YES;
+  
+  [_response appendContentString:
+             @"<table border=\""];
+  [_response appendContentString:b];  // border
+  [_response appendContentString:@"\" cellpadding=\""];
+  [_response appendContentString:cp]; // cellspacing
+  [_response appendContentString:@"\" width=\""];
+  [_response appendContentString:w];  // width
+  [_response appendContentString:@"\" cellspacing=\""];
+  [_response appendContentString:cs]; // cellspaing
+  [_response appendContentString:@"\">"];
+  
+  /*** append title row (monday - saturday) ***/
+  [_response appendContentString:@"<tr>"];
+  for (i = 0; i < (showWeekend ? 6 : 5 ); i++)
+    [self appendDateTitleToResponse:_response inContext:_ctx day:i];
+  [_response appendContentString:@"</tr>"];
+  
+  /**** header rows ****/
+  [self appendHeaderRowsToResponse:_response inContext:_ctx];
+
+  /*** append AM content row + saturday ***/
+  [_response appendContentString:@"<tr>"];
+
+  /* AM weekdays content (this is count=10 because we slot 0=AM/1=PM, etc) */
+  for (i = 0; i < 10; i = i + 2) {
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:(i / 2) inComponent:comp];
+
+    [_response appendContentString:@"<td valign=\"top\""];
+    if ((bgcolor = [self->contentColor stringValueInComponent:comp])) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:bgcolor];
+      [_response appendContentCharacter:'"'];
+    }
+    if ((style = [self->contentStyle stringValueInComponent:comp])) {
+      [_response appendContentString:@" class=\""];
+      [_response appendContentString:style];
+      [_response appendContentCharacter:'"'];
+    }
+    [_response appendContentCharacter:'>'];
+    [self appendContentToResponse:_response inContext:_ctx index:i];
+    [_response appendContentString:@"</td>"];
+  }
+  /* saturday content */
+  if (showWeekend) {
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:5 inComponent:comp];
+
+    [_response appendContentString:@"<td valign=\"top\""];
+  
+    if ((bgcolor = [self->contentColor stringValueInComponent:comp])) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:bgcolor];
+      [_response appendContentCharacter:'"'];
+    }
+    if ((style = [self->contentStyle stringValueInComponent:comp])) {
+      [_response appendContentString:@" class=\""];
+      [_response appendContentString:style];
+      [_response appendContentCharacter:'"'];
+    }
+    [_response appendContentCharacter:'>'];
+    
+    /* 10 is Saturday AM, 11 is Saturday PM, week overview shows them in one */
+    [self appendContentToResponse:_response inContext:_ctx index:10];
+    [self appendContentToResponse:_response inContext:_ctx index:11];
+    [_response appendContentString:@"</td>"];
+  }
+  
+  [_response appendContentString:@"</tr>"]; /* close AM row */
+
+  /*** append PM content row + sunday ***/
+  [_response appendContentString:@"<tr>"];
+
+  /* PM weekdays content */
+  for (i = 1; i < 11; i = i + 2) {
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:(i/2) inComponent:comp];
+      
+    [_response appendContentString:@"<td valign=\"top\""];
+    
+    if (showWeekend) /* for Sunday we need an additional <tr> */
+      [_response appendContentString:@" rowspan=\"2\""]; 
+    
+    if ((bgcolor = [self->contentColor stringValueInComponent:comp])) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:bgcolor];
+      [_response appendContentCharacter:'"'];
+    }
+    if ((style = [self->contentStyle stringValueInComponent:comp])) {
+      [_response appendContentString:@" class=\""];
+      [_response appendContentString:style];
+      [_response appendContentCharacter:'"'];
+    }
+    [_response appendContentCharacter:'>'];
+
+      
+    [self appendContentToResponse:_response inContext:_ctx index:i];
+    [_response appendContentString:@"</td>"];
+  }
+
+  if (showWeekend) {
+    /* sunday title */
+    [self appendDateTitleToResponse:_response inContext:_ctx day:6];
+    [_response appendContentString:@"</tr>"];
+
+    /*  sunday row */
+    [_response appendContentString:@"<tr>"];
+
+    if ([self->dayIndex isValueSettable])
+      [self->dayIndex setIntValue:6 inComponent:comp];
+  
+    [_response appendContentString:@"<td valign=\"top\""];
+    if ((bgcolor = [self->contentColor stringValueInComponent:comp])) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:bgcolor];
+      [_response appendContentCharacter:'"'];
+    }
+    [_response appendContentCharacter:'>'];
+    
+    /* 12 is Sunday/AM, 13 is Sunday/PM */
+    [self appendContentToResponse:_response inContext:_ctx index:12];
+    [self appendContentToResponse:_response inContext:_ctx index:13];
+    [_response appendContentString:@"</td>"];
+  }
+  
+  [_response appendContentString:@"</tr>"]; /* close PM row */
+
+  /***** footer rows *****/
+  [self appendFooterRowsToResponse:_response inContext:_ctx];
+
+  [_response appendContentString:@"</table>"];
+
+  [self resetMatrix];
+}
+
+@end /* WeekOverview */
+
+@interface WEWeekOverviewTitleMode : WEContextConditional
+@end
+
+@implementation WEWeekOverviewTitleMode
+- (NSString *)_contextKey {
+  return WEWeekOverview_TitleMode;
+}
+
+- (NSString *)_didMatchKey {
+  return WEWeekOverview_TitleModeDidMatch;
+}
+@end /* WEWeekOverviewTitleMode */
+
+// --
+
+@interface WEWeekOverviewInfoMode : WEContextConditional
+@end
+
+@implementation WEWeekOverviewInfoMode
+- (NSString *)_contextKey {
+  return WEWeekOverview_InfoMode;
+}
+@end /* WEWeekOverviewInfoMode */
+
+// --
+
+@interface WEWeekOverviewContentMode : WEContextConditional
+@end
+
+@implementation WEWeekOverviewContentMode
+- (NSString *)_contextKey {
+  return WEWeekOverview_ContentMode;
+}
+@end /* WEWeekOverview_ContentMode */
+
+// --
+
+@interface WEWeekOverviewPMInfoMode : WEContextConditional
+@end
+
+@implementation WEWeekOverviewPMInfoMode
+- (NSString *)_contextKey {
+  return WEWeekOverview_PMInfoMode;
+}
+@end /* WEWeekOverviewPMInfoMode */
+
+@interface WEWeekOverviewHeaderMode : WEContextConditional
+@end
+
+@implementation WEWeekOverviewHeaderMode
+- (NSString *)_contextKey {
+  return WEWeekOverview_HeaderRowMode;
+}
+@end /* WEWeekOverviewHeaderMode */
+
+@interface WEWeekOverviewFooterMode : WEContextConditional
+@end
+
+@implementation WEWeekOverviewFooterMode
+- (NSString *)_contextKey {
+  return WEWeekOverview_FooterRowMode;
+}
+@end /* WEWeekOverviewFooterMode */
diff --git a/skyrix-sope/WEExtensions/WExCalElemBuilder.m b/skyrix-sope/WEExtensions/WExCalElemBuilder.m
new file mode 100644 (file)
index 0000000..626c3a6
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOxElemBuilder.h>
+
+/*
+  This builder builds various calendaring elements from the WEExtensions
+  library.
+
+  All tags are mapped into the <var:> namespace (XMLNS_OD_BIND).
+
+  Supported tags:
+    <var:month-overview .../> to WEMonthOverview
+    <var:month-label    .../> to WEMonthLabel
+    <var:month-title    .../> to WEMonthTitle
+    <var:month-info     .../> to WEMonthOverviewInfoMode
+    <var:month          .../> to WEMonthOverviewContentMode
+
+    <var:week-overview  .../> to WEWeekOverview
+    <var:week-title     .../> to WEWeekOverviewTitleMode
+    <var:week-info      .../> to WEWeekOverviewInfoMode
+    <var:week-pminfo    .../> to WEWeekOverviewPMInfoMode
+    <var:week           .../> to WEWeekOverviewContentMode
+    <var:week-header    .../> to WEWeekOverviewHeaderMode
+    <var:week-footer    .../> to WEWeekOverviewFooterMode
+
+    <var:weekcol-view   .../> to WEWeekColumnView
+    <var:weekcol-title  .../> to WEWeekColumnViewTitleMode
+    <var:weekcol-info   .../> to WEWeekColumnViewInfoMode
+    <var:weekcol        .../> to WEWeekColumnViewContentMode
+*/
+
+@interface WExCalElemBuilder : WOxTagClassElemBuilder
+{
+}
+
+@end
+
+#include <SaxObjC/XMLNamespaces.h>
+#include "common.h"
+
+@implementation WExCalElemBuilder
+
+- (Class)classForElement:(id<DOMElement>)_element {
+  NSString *tagName;
+  unsigned tl;
+  unichar  c1;
+  
+  if (![[_element namespaceURI] isEqualToString:XMLNS_OD_BIND])
+    return Nil;
+  
+  tagName = [_element tagName];
+  if ((tl = [tagName length]) < 4)
+    return Nil;
+
+  c1 = [tagName characterAtIndex:0];
+
+  if (c1 == 'm') {
+    /* month stuff */
+
+    if (![tagName hasPrefix:@"month"])
+      return Nil;
+    
+    switch (tl) {
+      case 5:
+        return NSClassFromString(@"WEMonthOverviewContentMode");
+
+      case 10:
+        if ([tagName isEqualToString:@"month-info"])
+          return NSClassFromString(@"WEMonthOverviewInfoMode");
+        break;
+        
+      case 11:
+        if ([tagName isEqualToString:@"month-label"])
+          return NSClassFromString(@"WEMonthLabel");
+        if ([tagName isEqualToString:@"month-title"])
+          return NSClassFromString(@"WEMonthTitle");
+        break;
+        
+      case 14:
+        if ([tagName isEqualToString:@"month-overview"])
+          return NSClassFromString(@"WEMonthOverview");
+        break;
+    }
+  }
+  else if (c1 == 'w') {
+    /* week stuff */
+    
+    if (![tagName hasPrefix:@"week"])
+      return Nil;
+    
+    switch (tl) {
+      case 4:
+        return NSClassFromString(@"WEWeekOverviewContentMode");
+        
+      case 7:
+        if ([tagName isEqualToString:@"weekcol"])
+          return NSClassFromString(@"WEWeekColumnViewContentMode");
+        break;
+
+      case 9:
+        if ([tagName isEqualToString:@"week-info"])
+          return NSClassFromString(@"WEWeekOverviewInfoMode");
+        break;
+        
+      case 10:
+        if ([tagName isEqualToString:@"week-title"])
+          return NSClassFromString(@"WEWeekOverviewTitleMode");
+        break;
+        
+      case 11:
+        if ([tagName isEqualToString:@"week-header"])
+          return NSClassFromString(@"WEWeekOverviewHeaderMode");
+        if ([tagName isEqualToString:@"week-footer"])
+          return NSClassFromString(@"WEWeekOverviewFooterMode");
+        if ([tagName isEqualToString:@"week-pminfo"])
+          return NSClassFromString(@"WEWeekOverviewPMInfoMode");
+        break;
+
+      case 12:
+        if ([tagName isEqualToString:@"weekcol-view"])
+          return NSClassFromString(@"WEWeekColumnView");
+        if ([tagName isEqualToString:@"weekcol-info"])
+          return NSClassFromString(@"WEWeekColumnViewInfoMode");
+        break;
+
+      case 13:
+        if ([tagName isEqualToString:@"weekcol-title"])
+          return NSClassFromString(@"WEWeekColumnViewTitleMode");
+        if ([tagName isEqualToString:@"week-overview"])
+          return NSClassFromString(@"WEWeekOverview");
+        break;
+    }
+  }
+  
+  return Nil;
+}
+
+@end /* WExCalElemBuilder */
diff --git a/skyrix-sope/WEExtensions/WExDnDElemBuilder.m b/skyrix-sope/WEExtensions/WExDnDElemBuilder.m
new file mode 100644 (file)
index 0000000..709a09e
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOxElemBuilder.h>
+
+/*
+  This builder builds drag&drop elements from the WEExtensions library.
+  Note that there are other builders for WEExtensions elements as well !!
+
+  All tags are mapped into the <var:> namespace (XMLNS_OD_BIND).
+
+  Supported tags:
+    <var:js-drag .../>      maps to WEDragContainer
+    <var:js-drop .../>      maps to WEDropContainer
+    <var:script-drag/>      maps to WEDragScript
+    <var:script-drop/>      maps to WEDropScript
+*/
+
+@interface WExDnDElemBuilder : WOxTagClassElemBuilder
+{
+}
+
+@end
+
+#include <SaxObjC/XMLNamespaces.h>
+#include "common.h"
+
+@implementation WExDnDElemBuilder
+
+- (Class)classForElement:(id<DOMElement>)_element {
+  NSString *tagName;
+  unsigned tl;
+  unichar c1;
+  
+  if (![[_element namespaceURI] isEqualToString:XMLNS_OD_BIND])
+    return Nil;
+  
+  tagName = [_element tagName];
+  if ((tl = [tagName length]) < 7)
+    return Nil;
+  
+  c1 = [tagName characterAtIndex:0];
+
+  switch (c1) {
+    case 'j': /* starting with 'j' */
+      if (tl == 7) {
+        if ([tagName hasPrefix:@"js-dr"]) {
+          if ([tagName isEqualToString:@"js-drag"])
+            return NSClassFromString(@"WEDragContainer");
+          if ([tagName isEqualToString:@"js-drop"])
+            return NSClassFromString(@"WEDropContainer");
+        }
+      }
+      break;
+      
+    case 's': /* starting with 's' */
+      if (tl == 11) {
+        if ([tagName hasPrefix:@"script-"]) {
+          if ([tagName isEqualToString:@"script-drag"])
+            return NSClassFromString(@"WEDragScript");
+          if ([tagName isEqualToString:@"script-drop"])
+            return NSClassFromString(@"WEDropScript");
+        }
+      }
+      break;
+  }
+  return Nil;
+}
+
+@end /* WExDnDElemBuilder */
diff --git a/skyrix-sope/WEExtensions/WExExtElemBuilder.m b/skyrix-sope/WEExtensions/WExExtElemBuilder.m
new file mode 100644 (file)
index 0000000..cd29f00
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOxElemBuilder.h>
+
+/*
+  This builder builds various elements from the WEExtensions library.
+  Note that there are other builders for WEExtensions elements as well !!
+
+  All tags are mapped into the <var:> namespace (XMLNS_OD_BIND).
+
+  Supported tags:
+    <var:js-clipboard .../> maps to JSClipboard
+    <var:js-menu .../>      maps to JSMenu
+    <var:js-menu-item .../> maps to JSMenuItem
+    <var:js-shiftclick ../> maps to JSShiftClick
+
+    <var:rich-string .../>  maps to WERichString
+    <var:we-browser .../>   maps to WEBrowser
+    <var:cal-field .../>    maps to WECalendarField
+    <var:date-field .../>   maps to WEDateField
+    <var:time-field .../>   maps to WETimeField
+    
+    <var:script-datefield/> maps to WEDateFieldScript
+    
+    <var:tableview .../>    maps to WETableView
+    <var:tbutton   .../>    maps to WETableViewButtonMode
+    <var:ttitle    .../>    maps to WETableViewTitleMode
+    <var:tfooter   .../>    maps to WETableViewFooterMode
+    <var:tgroup    .../>    maps to WETableViewGroupMode
+    <var:td        .../>    maps to WETableData
+    <var:th        .../>    maps to WETableHeader
+    
+    <var:tabview   .../>    maps to WETabView
+    <var:tab       .../>    maps to WETabItem
+
+    <var:pageview  .../>    maps to WEPageView
+    <var:page      .../>    maps to WEPageItem
+    <var:pagelink  .../>    maps to WEPageLink
+    
+    <var:we-collapsible .../>  maps to WECollapsibleComponentContent
+    <var:we-collapsible-action .../> maps to WECollapsibleAction
+    <var:we-collapsible-title  .../> maps to WECollapsibleTitleMode
+    <var:we-collapsible-content  .../> maps to WECollapsibleContentMode
+
+    <var:switch    .../>    maps to WESwitch
+    <var:case      .../>    maps to WECase
+    <var:default   .../>    maps to WEDefaultCase
+
+    <var:treeview  .../>    maps to WETreeView
+    <var:tree-header .../>  maps to WETreeHeader
+    <var:tree-data   .../>  maps to WETreeData
+
+    <var:hspan-matrix .../> maps to WEHSpanTableMatrix
+    <var:vspan-matrix .../> maps to WEVSpanTableMatrix
+    <var:matrix-cell  .../> maps to WETableMatrixContent
+    <var:matrix-empty .../> maps to WETableMatrixNoContent
+    <var:matrix-label .../> maps to WETableMatrixLabel
+
+    <var:if-ctx-key   .../> maps to WEContextConditional
+    <var:ctx-key      .../> maps to WEContextKey
+    <var:if-qualifier .../> maps to WEQualifierConditional
+
+    <var:redirect    .../>  maps to WERedirect
+    
+    WEComponentValue : WODynamicElement
+*/
+
+@interface WExExtElemBuilder : WOxTagClassElemBuilder
+{
+}
+
+@end
+
+#include <SaxObjC/XMLNamespaces.h>
+#include "common.h"
+
+@implementation WExExtElemBuilder
+
+- (Class)classForElement:(id<DOMElement>)_element {
+  NSString *tagName;
+  unsigned tl;
+  unichar c1;
+  
+  if (![[_element namespaceURI] isEqualToString:XMLNS_OD_BIND])
+    return Nil;
+  
+  tagName = [_element tagName];
+  if ((tl = [tagName length]) < 2)
+    return Nil;
+
+  c1 = [tagName characterAtIndex:0];
+
+  switch (c1) {
+    case 'c': /* starting with 'c' */
+      if (tl > 8) {
+        if ([tagName isEqualToString:@"cal-field"])
+          return NSClassFromString(@"WECalendarField");
+      }
+      else if (tl > 3) {
+        if ([tagName isEqualToString:@"case"])
+          return NSClassFromString(@"WECase");
+        if ([tagName isEqualToString:@"ctx-key"])
+          return NSClassFromString(@"WEContextKey");
+      }
+      break;
+
+    case 'd':
+      if (tl > 8) {
+        if ([tagName isEqualToString:@"date-field"])
+          return NSClassFromString(@"WEDateField");
+      }
+      else if (tl > 6) {
+        if ([tagName isEqualToString:@"default"])
+          return NSClassFromString(@"WEDefaultCase");
+      }
+      break;
+
+    case 'h':
+      if (tl == 12) {
+        if ([tagName isEqualToString:@"hspan-matrix"])
+          return NSClassFromString(@"WEHSpanTableMatrix");
+      }
+      break;
+
+    case 'i':
+      if (tl == 10) {
+        if ([tagName isEqualToString:@"if-ctx-key"])
+          return NSClassFromString(@"WEContextConditional");
+      }
+      if (tl == 12) {
+        if ([tagName isEqualToString:@"if-qualifier"])
+          return NSClassFromString(@"WEQualifierConditional");
+      }
+      break;
+      
+    case 'j': /* starting with 'j' */
+      if ([tagName hasPrefix:@"js-"]) {
+        if (tl < 6) return Nil;
+        
+        if ([tagName isEqualToString:@"js-clipboard"])
+          return NSClassFromString(@"JSClipboard");
+        if ([tagName isEqualToString:@"js-menu"])
+          return NSClassFromString(@"JSMenu");
+        if ([tagName isEqualToString:@"js-menu-item"])
+          return NSClassFromString(@"JSMenuItem");
+        
+        if ([tagName isEqualToString:@"js-shiftclick"])
+          return NSClassFromString(@"JSShiftClick");
+      }
+      break;
+
+    case 'm':
+      if (tl == 11) {
+        if ([tagName isEqualToString:@"matrix-cell"])
+          return NSClassFromString(@"WETableMatrixContent");
+      }
+      else if (tl == 12) {
+        if ([tagName isEqualToString:@"matrix-empty"])
+          return NSClassFromString(@"WETableMatrixNoContent");
+        if ([tagName isEqualToString:@"matrix-label"])
+          return NSClassFromString(@"WETableMatrixLabel");
+      }
+      break;
+      
+    case 'p':
+      if (tl > 3) {
+        if (tl == 8 && [tagName isEqualToString:@"pagelink"])
+          return NSClassFromString(@"WEPageLink");
+        if (tl == 4 && [tagName isEqualToString:@"page"])
+          return NSClassFromString(@"WEPageItem");
+        if (tl == 8 && [tagName isEqualToString:@"pageview"])
+          return NSClassFromString(@"WEPageView");
+      }
+      break;
+
+    case 'r': /* starting with 'r' */
+      if (tl > 8) {
+        if ([tagName isEqualToString:@"rich-string"])
+          return NSClassFromString(@"WERichString");
+      }
+      if (tl == 8) {
+        if ([tagName isEqualToString:@"redirect"])
+          return NSClassFromString(@"WERedirect");
+      }
+      break;
+      
+    case 's': /* starting with 's' */
+      if (tl > 10) {
+        if ([tagName isEqualToString:@"script-datefield"])
+          return NSClassFromString(@"WEDateFieldScript");
+      }
+      else if (tl > 5) {
+        if ([tagName isEqualToString:@"switch"])
+          return NSClassFromString(@"WESwitch");
+      }
+      break;
+
+    case 't': { /* starting with 't' */
+      unichar c2;
+      
+      c2 = [tagName characterAtIndex:1];
+      
+      if (tl == 2) {
+        if (c2 == 'd') return NSClassFromString(@"WETableData");
+        if (c2 == 'h') return NSClassFromString(@"WETableHeader");
+      }
+      if (tl == 3 && c2 == 'a') {
+        if ([tagName characterAtIndex:2] == 'b')
+          return NSClassFromString(@"WETabItem");
+      }
+
+      if (tl > 5) {
+        if (c2 == 'a') {
+          if ([tagName isEqualToString:@"tableview"])
+            return NSClassFromString(@"WETableView");
+        
+          if ([tagName isEqualToString:@"tabview"])
+            return NSClassFromString(@"WETabView");
+        }
+        if (c2 == 'r' && tl > 7) {
+          if ([tagName isEqualToString:@"tree-data"])
+            return NSClassFromString(@"WETreeData");
+          if ([tagName isEqualToString:@"treeview"])
+            return NSClassFromString(@"WETreeView");
+          if ([tagName isEqualToString:@"tree-header"])
+            return NSClassFromString(@"WETreeHeader");
+        }
+        
+        if ([tagName isEqualToString:@"tbutton"])
+          return NSClassFromString(@"WETableViewButtonMode");
+        if ([tagName isEqualToString:@"ttitle"])
+          return NSClassFromString(@"WETableViewTitleMode");
+        if ([tagName isEqualToString:@"tfooter"])
+          return NSClassFromString(@"WETableViewFooterMode");
+        if ([tagName isEqualToString:@"tgroup"])
+          return NSClassFromString(@"WETableViewGroupMode");
+
+        if ([tagName isEqualToString:@"time-field"])
+          return NSClassFromString(@"WETimeField");
+      }
+      break;
+    }
+
+    case 'v':
+      if (tl == 12) {
+        if ([tagName isEqualToString:@"vspan-matrix"])
+          return NSClassFromString(@"WEVSpanTableMatrix");
+      }
+      break;
+
+    case 'w':
+      if (tl > 8) {
+        if ([tagName isEqualToString:@"we-browser"])
+          return NSClassFromString(@"WEBrowser");
+        
+        if ([tagName hasPrefix:@"we-collapsible"]) {
+          if (tl == 14)
+            return NSClassFromString(@"WECollapsibleComponentContent");
+          
+          if ([tagName isEqualToString:@"we-collapsible-action"])
+            return NSClassFromString(@"WECollapsibleAction");
+          if ([tagName isEqualToString:@"we-collapsible-title"])
+            return NSClassFromString(@"WECollapsibleTitleMode");
+          if ([tagName isEqualToString:@"we-collapsible-content"])
+            return NSClassFromString(@"WECollapsibleContentMode");
+        }
+      }
+      break;
+  }
+  
+  return Nil;
+}
+
+@end /* WExExtElemBuilder */
diff --git a/skyrix-sope/WEExtensions/bundle-info.plist b/skyrix-sope/WEExtensions/bundle-info.plist
new file mode 100644 (file)
index 0000000..db775a6
--- /dev/null
@@ -0,0 +1,34 @@
+{
+  CVSID = "$Id: bundle-info.plist,v 1.3 2004/03/31 12:07:37 helge Exp $";
+
+  requires = {
+    bundleManagerVersion = 1;
+    
+    classes = (
+      { name = NSObject; }
+    );
+  };
+
+  provides = {
+    WOxElemBuilder = (
+      { name = "WExExtElemBuilder"; },
+      { name = "WExCalElemBuilder"; },
+      { name = "WExDnDElemBuilder"; },
+    );
+    
+    WODynamicElements = (
+      { name = "JSClipboard";          },
+      { name = "WEQualifierCondition"; },
+      { name = "WERedirect";           },
+    );
+    
+    classes = (
+      { name = "WExExtElemBuilder";    },
+      { name = "WExCalElemBuilder";    },
+      { name = "WExDnDElemBuilder";    },
+      { name = "JSClipboard";          },
+      { name = "WEQualifierCondition"; },
+      { name = "WERedirect";           },
+    );
+  };
+}
diff --git a/skyrix-sope/WEExtensions/calendar.js b/skyrix-sope/WEExtensions/calendar.js
new file mode 100644 (file)
index 0000000..4d81177
--- /dev/null
@@ -0,0 +1,609 @@
+var monthArray = getMonthSelect();
+var calDateField;
+var calDate;
+
+
+// innerHTML IS ONLY SUPPORTED BY MSIE...
+function rewriteLayerWithData(obj,data) {
+  if (isNav) {
+    obj.document.clear();
+    obj.document.write(data);
+    obj.document.close();
+  }
+  if (isIE) {
+    obj.innerHTML = data;
+  }
+  if (usesNavImages) {
+    document.images['dateFieldFirstImg'].src = dateFieldFirst.src;
+    document.images['dateFieldPreviousImg'].src = dateFieldPrevious.src;
+    document.images['dateFieldTodayImg'].src = dateFieldToday.src;
+    document.images['dateFieldNextImg'].src = dateFieldNext.src;
+    document.images['dateFieldLastImg'].src = dateFieldLast.src;
+    document.images['dateFieldCloseImg'].src = dateFieldClose.src;
+  }
+}
+
+// DETERMINE BROWSER BRAND
+var isNav = false;
+var isIE  = false;
+
+if (navigator.appName == "Netscape") {
+    isNav = true;
+}
+else {
+    isIE = true;
+}
+
+// PRE-BUILD PORTIONS OF THE CALENDAR WHEN THIS JS LIBRARY LOADS INTO THE BROWSER
+buildCalParts();
+
+
+// CALENDAR FUNCTIONS BEGIN HERE ---------------------------------------------------
+
+
+
+// SET THE INITIAL VALUE OF THE GLOBAL DATE FIELD
+function setDateField(dateField) {
+
+    // ASSIGN THE INCOMING FIELD OBJECT TO A GLOBAL VARIABLE
+    calDateField = dateField;    
+
+    // GET THE VALUE OF THE INCOMING FIELD
+    inDate = dateField.value;
+
+    // SET calDate TO THE DATE IN THE INCOMING FIELD OR DEFAULT TO TODAY'S DATE
+    setInitialDate();
+
+}
+
+
+// SET THE INITIAL CALENDAR DATE TO TODAY OR TO THE EXISTING VALUE IN dateField
+function setInitialDate() {
+   
+    // CREATE A NEW DATE OBJECT (WILL GENERALLY PARSE CORRECT DATE EXCEPT WHEN "." IS USED AS A DELIMITER)
+    // (THIS ROUTINE DOES *NOT* CATCH ALL DATE FORMATS, IF YOU NEED TO PARSE A CUSTOM DATE FORMAT, DO IT HERE)
+    // ADD CUSTOM DATE PARSING HERE
+
+    ypos = dateFormat.indexOf('%Y');
+    inYear = parseInt(inDate.substr(ypos,4));
+
+    mpos = dateFormat.indexOf('%m');
+    if (ypos < mpos) mpos+=2;  // because %Y stands for yyyy, add 2
+    inMonth = inDate.substr(mpos,2);
+    if (inMonth.charAt(0) == "0") 
+      inMonth = inMonth.substr(1,inMonth.length-1);
+    inMonth = parseInt(inMonth);
+    
+    dpos = dateFormat.indexOf('%d');
+    if (ypos < dpos) dpos+=2;  // same as mpos
+    inDay = inDate.substr(dpos,2);
+    if (inDay.charAt(0) == "0") 
+      inDay = inDay.substr(1,inDay.length-1);
+    inDay = parseInt(inDay);
+
+    if ((inYear) && (inMonth) && (inDay)) {
+
+        calDate = new Date(inYear,inMonth-1,inDay);
+    }
+    else {
+
+       calDate = new Date();
+    }
+
+    // KEEP TRACK OF THE CURRENT DAY VALUE
+    calDay  = calDate.getDate();
+
+    // SET DAY VALUE TO 1... TO AVOID JAVASCRIPT DATE CALCULATION ANOMALIES
+    // (IF THE MONTH CHANGES TO FEB AND THE DAY IS 30, THE MONTH WOULD CHANGE TO MARCH
+    //  AND THE DAY WOULD CHANGE TO 2.  SETTING THE DAY TO 1 WILL PREVENT THAT)
+    calDate.setDate(1);
+}
+
+
+// ENABLE MULTIPLE CALENDAR-USING OBJECTS BY USING VARIABLE calendarDiv;
+var calendarDiv = false;
+
+function toggleCalendar(dateFieldEl,calObj,calFormat) {
+  if ((calendarDiv) &&  (calendarDiv.id != calObj.id)) {
+    hideCalendar();
+  }
+  calendarDiv = calObj;
+  
+  if (isNav) condition = (calendarDiv.visibility == 'show');
+  if (isIE)  condition = (calendarDiv.style.visibility    == 'visible');
+  if (condition) {
+    hideCalendar();
+  }
+  else {
+    var i,j;
+    var dateField;
+
+    for (i = 0; i < document.forms.length; i++) {
+      for (j = 0; j < document.forms[i].elements.length; j++) {
+        if (document.forms[i].elements[j].name == dateFieldEl) {
+          dateField = document.forms[i].elements[j];
+        }
+      }
+    }
+    dateFormat = calFormat;
+    showCalendar(dateField);
+  }
+}
+
+// CAPTURE onMouseMove EVENT IF NETSCAPE FOR POSITIONING calendarDiv
+
+if (isNav) {
+  document.captureEvents( Event.MOUSEMOVE );
+  document.onmousemove = actPos;
+}
+
+var curScreenPosX;
+var curScreenPosY;
+
+function actPos(e) {
+  
+  curScreenPosX = e.pageX + 10;
+  curScreenPosY = e.pageY;
+  return true;
+}
+
+
+function showCalendar(dateField) {
+
+    // SET INITIAL VALUE OF THE DATE FIELD AND CREATE TOP AND BOTTOM FRAMES
+    setDateField(dateField);
+
+    writeCalendar();
+    if (isNav) {
+      calendarDiv.visibility   = 'show';
+      calendarDiv.left = curScreenPosX;
+      calendarDiv.top  = curScreenPosY;
+    }
+    if (isIE) {
+      calendarDiv.style.visibility      = 'visible';
+    }
+
+    return true;
+}
+
+function hideCalendar() {
+    if (isNav) {
+      calendarDiv.visibility = 'hide';
+    }
+    if (isIE) {
+      calendarDiv.style.visibility = 'hidden';
+    }
+    calendarDiv = false;
+}
+
+// NEW: NO FRAMES ANYMORE, ONE <DIV> INSTEAD
+function writeCalendar() {
+
+  data = buildTopCalFrame() + buildBottomCalFrame();
+  if (isNav) rewriteLayerWithData(calendarDiv, data);
+  if (isIE)  rewriteLayerWithData(calendarDiv, data);
+}
+
+
+// CREATE month/year DISPLAY
+function buildCalControlMonthYear() {
+  month = calDate.getMonth();
+  year  = calDate.getFullYear();
+  return String(monthArray[month])+" "+String(year);
+}
+
+
+
+var obj=false;
+var X,Y;
+
+function MD() {
+  if (isIE) {
+    ob = true;
+    X=event.offsetX;
+    Y=event.offsetY;
+    document.onmousemove = MM;
+    document.onmouseup   = MU;
+  }
+}
+
+function MM() {
+  if (ob) {
+    calendarDiv.style.pixelLeft = event.clientX-X + document.body.scrollLeft;
+    calendarDiv.style.pixelTop = event.clientY-Y + document.body.scrollTop;
+    return false;
+  }
+}
+
+function MU() {
+  ob = false;
+//  document.onmousemove = null;
+//  document.onmouseup   = null;
+}
+
+// CREATE THE TOP CALENDAR PART
+function buildTopCalFrame() {
+
+     var calDoc =
+       "<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0><TR><TD BGCOLOR=black>" +
+       "<TABLE CELLPADDING=0 CELLSPACING=1 BORDER=0>" +
+       "<TR><TD COLSPAN=6 ALIGN=left CLASS=topCal onMouseDown='MD()'>" +
+       buildCalControlMonthYear() +
+       "</TD>" +
+       "<TD ALIGN=right CLASS=topCal>"+
+       "<A CLASS=navMonYear HREF='javascript:hideCalendar()'>" +
+       dateFieldCloseSRC+"</A>&nbsp;</TD></TR>" +
+       "<TR>" +
+       "<TD COLSPAN=7 CLASS=topCal ALIGN=center><FONT SIZE=1 FACE='Arial'>"+
+       "<A CLASS=navMonYear HREF='javascript:setPreviousYear()'>"+
+       dateFieldFirstSRC+"</A>" +
+       " <A CLASS=navMonYear HREF='javascript:setPreviousMonth()'>"+
+       dateFieldPreviousSRC+"</A>" +
+       " <A CLASS=navMonYear HREF='javascript:setToday()'>"+
+       dateFieldTodaySRC+"</A>" +
+       " <A CLASS=navMonYear HREF='javascript:setNextMonth()'>"+
+       dateFieldNextSRC+"</A>"+
+       " <A CLASS=navMonYear HREF='javascript:setNextYear()'>"+
+       dateFieldLastSRC+"</A>" +
+       "</FONT></TD>" +
+       "</TR>";
+   return calDoc;
+}
+
+
+// CREATE THE BOTTOM CALENDAR PART
+function buildBottomCalFrame() {       
+
+    // START CALENDAR DOCUMENT
+    var calDoc = calendarBegin;
+
+    // GET MONTH, AND YEAR FROM GLOBAL CALENDAR DATE
+    month   = calDate.getMonth();
+    year    = calDate.getFullYear();
+
+
+    // GET GLOBALLY-TRACKED DAY VALUE (PREVENTS JAVASCRIPT DATE ANOMALIES)
+    day     = calDay;
+
+    var i   = 0;
+
+    // DETERMINE THE NUMBER OF DAYS IN THE CURRENT MONTH
+    var days = getDaysInMonth();
+
+    // IF GLOBAL DAY VALUE IS > THAN DAYS IN MONTH, HIGHLIGHT LAST DAY IN MONTH
+    if (day > days) {
+        day = days;
+    }
+
+    // DETERMINE WHAT DAY OF THE WEEK THE CALENDAR STARTS ON
+    var firstOfMonth = new Date (year, month, 1);
+
+    // GET THE DAY OF THE WEEK THE FIRST DAY OF THE MONTH FALLS ON
+    var startingPos  = firstOfMonth.getDay();
+    days += startingPos;
+
+    // KEEP TRACK OF THE COLUMNS, START A NEW ROW AFTER EVERY 7 COLUMNS
+    var columnCount = 0;
+
+    // MAKE BEGINNING NON-DATE CELLS BLANK
+    for (i = 0; i < startingPos; i++) {
+
+        calDoc += blankCell;
+       columnCount++;
+    }
+
+    // SET VALUES FOR DAYS OF THE MONTH
+    var currentDay = 0;
+    var dayType    = "weekday";
+
+    // DATE CELLS CONTAIN A NUMBER
+    for (i = startingPos; i < days; i++) {
+
+       var paddingChar = "&nbsp;";
+
+        // ADJUST SPACING SO THAT ALL LINKS HAVE RELATIVELY EQUAL WIDTHS
+        if (i-startingPos+1 < 10) {
+            padding = "&nbsp;&nbsp;";
+        }
+        else {
+            padding = "&nbsp;";
+        }
+
+        // GET THE DAY CURRENTLY BEING WRITTEN
+        currentDay = i-startingPos+1;
+
+        // SET THE TYPE OF DAY, THE focusDay GENERALLY APPEARS AS A DIFFERENT COLOR
+        if (currentDay == day) {
+            dayType = "focusDay";
+        }
+        else {
+            dayType = "weekDay";
+        }
+
+        // ADD THE DAY TO THE CALENDAR STRING
+        calDoc += "<TD align=center bgcolor='lightgrey'>" +
+                  "<a class='" + dayType + "' href='javascript:returnDate(" + 
+                  currentDay + ")'>" + padding + currentDay + paddingChar + "</a></TD>";
+
+        columnCount++;
+
+        // START A NEW ROW WHEN NECESSARY
+        if (columnCount % 7 == 0) {
+            calDoc += "</TR><TR>";
+        }
+    }
+
+    // MAKE REMAINING NON-DATE CELLS BLANK
+    for (i=days; i<42; i++)  {
+
+        calDoc += blankCell;
+       columnCount++;
+
+        // START A NEW ROW WHEN NECESSARY
+        if (columnCount % 7 == 0) {
+            calDoc += "</TR>";
+            if (i<41) {
+                calDoc += "<TR>";
+            }
+        }
+    }
+
+    // FINISH THE NEW CALENDAR PAGE
+    calDoc += calendarEnd;
+
+    // RETURN THE COMPLETED CALENDAR PAGE
+    return calDoc;
+}
+
+
+// SET THE CALENDAR TO TODAY'S DATE AND DISPLAY THE NEW CALENDAR
+function setToday() {
+
+    // SET GLOBAL DATE TO TODAY'S DATE
+    calDate = new Date();
+
+    // DISPLAY THE NEW CALENDAR
+    writeCalendar();
+}
+
+
+// SET THE GLOBAL DATE TO THE PREVIOUS YEAR AND REDRAW THE CALENDAR
+function setPreviousYear() {
+
+    var year  = calDate.getFullYear();
+
+    if (year > 1000) {
+        year--;
+        calDate.setFullYear(year);
+        writeCalendar();
+    }
+}
+
+
+// SET THE GLOBAL DATE TO THE PREVIOUS MONTH AND REDRAW THE CALENDAR
+function setPreviousMonth() {
+
+    var year  = calDate.getFullYear();
+    var month = calDate.getMonth();
+   
+    // IF MONTH IS JANUARY, SET MONTH TO DECEMBER AND DECREMENT THE YEAR
+    if (month == 0) {
+        month = 11;
+        if (year > 1000) {
+            year--;
+            calDate.setFullYear(year);
+        }
+    }
+    else {
+        month--;
+    }
+    calDate.setMonth(month);
+    writeCalendar();
+}
+
+
+// SET THE GLOBAL DATE TO THE NEXT MONTH AND REDRAW THE CALENDAR
+function setNextMonth() {
+
+    var year = calDate.getFullYear();
+
+        var month = calDate.getMonth();
+
+        // IF MONTH IS DECEMBER, SET MONTH TO JANUARY AND INCREMENT THE YEAR
+        if (month == 11) {
+            month = 0;
+            year++;
+            calDate.setFullYear(year);
+        }
+        else {
+            month++;
+        }
+        calDate.setMonth(month);
+        writeCalendar();
+}
+
+
+// SET THE GLOBAL DATE TO THE NEXT YEAR AND REDRAW THE CALENDAR
+function setNextYear() {
+
+    var year  = calDate.getFullYear();
+        year++;
+        calDate.setFullYear(year);
+        writeCalendar();
+}
+
+
+// GET NUMBER OF DAYS IN MONTH
+function getDaysInMonth()  {
+
+    var days;
+    var month = calDate.getMonth()+1;
+    var year  = calDate.getFullYear();
+
+    // RETURN 31 DAYS
+    if (month==1 || month==3 || month==5 || month==7 || month==8 ||
+        month==10 || month==12)  {
+        days=31;
+    }
+    // RETURN 30 DAYS
+    else if (month==4 || month==6 || month==9 || month==11) {
+        days=30;
+    }
+    // RETURN 29 DAYS
+    else if (month==2)  {
+        if (isLeapYear(year)) {
+            days=29;
+        }
+        // RETURN 28 DAYS
+        else {
+            days=28;
+        }
+    }
+    return (days);
+}
+
+
+// CHECK TO SEE IF YEAR IS A LEAP YEAR
+function isLeapYear (Year) {
+
+    if (((Year % 4)==0) && ((Year % 100)!=0) || ((Year % 400)==0)) {
+        return (true);
+    }
+    else {
+        return (false);
+    }
+}
+
+
+// BUILD THE MONTH SELECT LIST
+function getMonthSelect() {
+
+    // IF SET BY A PARAMETER (WRITTEN AT THE BEGINNING BY WOCalendar)
+    if (externMonths) {
+      monthArray = externMonths;
+    }
+    else {
+        monthArray = new Array('January', 'February', 'March', 'April', 
+           'May', 'June', 'July', 'August', 
+           'September', 'October', 'November', 'December');
+    }
+    return monthArray;
+}
+
+
+// SET DAYS OF THE WEEK DEPENDING ON LANGUAGE
+function createWeekdayList() {
+
+    // IF SET BY A PARAMETER (WRITTEN AT THE BEGINNING BY WODateFieldScript)
+    if (externWeekdays) {
+      weekdayArray = externWeekdays;
+    }
+    else {
+        weekdayArray = new Array('Su','Mo','Tu','We','Th','Fr','Sa');
+    }
+
+    var weekdays = "<TR BGCOLOR='white'>";
+    for (i in weekdayArray) {
+        weekdays += "<TD class='heading' align=center>"
+                 + weekdayArray[i] + "</TD>";
+    }
+    weekdays += "</TR>";
+
+    return weekdays;
+}
+
+
+// PRE-BUILD PORTIONS OF THE CALENDAR (FOR PERFORMANCE REASONS)
+function buildCalParts() {
+
+    // BUILD THE BLANK CELL ROWS
+    blankCell = "<TD align=center bgcolor='lightGrey'>&nbsp;&nbsp;&nbsp;</TD>";
+
+    // BUILD THE TOP PORTION OF THE CALENDAR PAGE USING CSS TO CONTROL SOME DISPLAY ELEMENTS
+    calendarBegin = createWeekdayList() + "<TR>";
+
+    // BUILD THE BOTTOM PORTION OF THE CALENDAR PAGE
+    calendarEnd = "";
+
+        // END THE TABLE AND HTML DOCUMENT
+        calendarEnd +=
+            "</TABLE></TD></TR></TABLE>";
+}
+
+
+// REPLACE ALL INSTANCES OF find WITH replace
+// inString: the string you want to convert
+// find:     the value to search for
+// replace:  the value to substitute
+//
+// usage:    jsReplace(inString, find, replace);
+// example:  jsReplace("To be or not to be", "be", "ski");
+//           result: "To ski or not to ski"
+//
+function jsReplace(inString, find, replace) {
+
+    var outString = "";
+
+    if (!inString) {
+        return "";
+    }
+
+    // REPLACE ALL INSTANCES OF find WITH replace
+    if (inString.indexOf(find) != -1) {
+        // SEPARATE THE STRING INTO AN ARRAY OF STRINGS USING THE VALUE IN find
+        t = inString.split(find);
+
+        // JOIN ALL ELEMENTS OF THE ARRAY, SEPARATED BY THE VALUE IN replace
+        return (t.join(replace));
+    }
+    else {
+        return inString;
+    }
+}
+
+
+// JAVASCRIPT FUNCTION -- DOES NOTHING (USED FOR THE HREF IN THE CALENDAR CALL)
+function doNothing() {
+}
+
+
+// ENSURE THAT VALUE IS TWO DIGITS IN LENGTH
+function makeTwoDigit(inValue) {
+
+    var numVal = parseInt(inValue, 10);
+
+    // VALUE IS LESS THAN TWO DIGITS IN LENGTH
+    if (numVal < 10) {
+
+        // ADD A LEADING ZERO TO THE VALUE AND RETURN IT
+        return("0" + numVal);
+    }
+    else {
+        return numVal;
+    }
+}
+
+
+// SET FIELD VALUE TO THE DATE SELECTED AND CLOSE THE CALENDAR WINDOW
+function returnDate(inDay)
+{
+
+    // inDay = THE DAY THE USER CLICKED ON
+    calDate.setDate(inDay);
+
+    // SET THE DATE RETURNED TO THE USER
+    var day           = calDate.getDate();
+    var month         = calDate.getMonth()+1;
+    var year          = calDate.getFullYear();
+
+    outDate = dateFormat;
+    outDate = jsReplace(outDate,'%Y',String(year));
+    outDate = jsReplace(outDate,'%m',makeTwoDigit(month));
+    outDate = jsReplace(outDate,'%d',makeTwoDigit(day));
+
+    // SET THE VALUE OF THE FIELD THAT WAS PASSED TO THE CALENDAR
+    calDateField.value = outDate;
+
+    // CLOSE THE CALENDAR WINDOW
+    hideCalendar();
+}
diff --git a/skyrix-sope/WEExtensions/calendar.jsm b/skyrix-sope/WEExtensions/calendar.jsm
new file mode 100644 (file)
index 0000000..1995c18
--- /dev/null
@@ -0,0 +1,473 @@
+/* automatically generated from calendar.js, do not edit ! */
+@"var monthArray = getMonthSelect();\n"
+@"var calDateField;\n"
+@"var calDate;\n"
+@"// innerHTML IS ONLY SUPPORTED BY MSIE...\n"
+@"function rewriteLayerWithData(obj,data) {\n"
+@"  if (isNav) {\n"
+@"    obj.document.clear();\n"
+@"    obj.document.write(data);\n"
+@"    obj.document.close();\n"
+@"  }\n"
+@"  if (isIE) {\n"
+@"    obj.innerHTML = data;\n"
+@"  }\n"
+@"  if (usesNavImages) {\n"
+@"    document.images['dateFieldFirstImg'].src = dateFieldFirst.src;\n"
+@"    document.images['dateFieldPreviousImg'].src = dateFieldPrevious.src;\n"
+@"    document.images['dateFieldTodayImg'].src = dateFieldToday.src;\n"
+@"    document.images['dateFieldNextImg'].src = dateFieldNext.src;\n"
+@"    document.images['dateFieldLastImg'].src = dateFieldLast.src;\n"
+@"    document.images['dateFieldCloseImg'].src = dateFieldClose.src;\n"
+@"  }\n"
+@"}\n"
+@"// DETERMINE BROWSER BRAND\n"
+@"var isNav = false;\n"
+@"var isIE  = false;\n"
+@"if (navigator.appName == \"Netscape\") {\n"
+@"    isNav = true;\n"
+@"}\n"
+@"else {\n"
+@"    isIE = true;\n"
+@"}\n"
+@"// PRE-BUILD PORTIONS OF THE CALENDAR WHEN THIS JS LIBRARY LOADS INTO THE BROWSER\n"
+@"buildCalParts();\n"
+@"// CALENDAR FUNCTIONS BEGIN HERE ---------------------------------------------------\n"
+@"// SET THE INITIAL VALUE OF THE GLOBAL DATE FIELD\n"
+@"function setDateField(dateField) {\n"
+@"    // ASSIGN THE INCOMING FIELD OBJECT TO A GLOBAL VARIABLE\n"
+@"    calDateField = dateField;    \n"
+@"    // GET THE VALUE OF THE INCOMING FIELD\n"
+@"    inDate = dateField.value;\n"
+@"    // SET calDate TO THE DATE IN THE INCOMING FIELD OR DEFAULT TO TODAY'S DATE\n"
+@"    setInitialDate();\n"
+@"}\n"
+@"// SET THE INITIAL CALENDAR DATE TO TODAY OR TO THE EXISTING VALUE IN dateField\n"
+@"function setInitialDate() {\n"
+@"   \n"
+@"    // CREATE A NEW DATE OBJECT (WILL GENERALLY PARSE CORRECT DATE EXCEPT WHEN \".\" IS USED AS A DELIMITER)\n"
+@"    // (THIS ROUTINE DOES *NOT* CATCH ALL DATE FORMATS, IF YOU NEED TO PARSE A CUSTOM DATE FORMAT, DO IT HERE)\n"
+@"    // ADD CUSTOM DATE PARSING HERE\n"
+@"    ypos = dateFormat.indexOf('%Y');\n"
+@"    inYear = parseInt(inDate.substr(ypos,4));\n"
+@"    mpos = dateFormat.indexOf('%m');\n"
+@"    if (ypos < mpos) mpos+=2;  // because %Y stands for yyyy, add 2\n"
+@"    inMonth = inDate.substr(mpos,2);\n"
+@"    if (inMonth.charAt(0) == \"0\") \n"
+@"      inMonth = inMonth.substr(1,inMonth.length-1);\n"
+@"    inMonth = parseInt(inMonth);\n"
+@"    \n"
+@"    dpos = dateFormat.indexOf('%d');\n"
+@"    if (ypos < dpos) dpos+=2;  // same as mpos\n"
+@"    inDay = inDate.substr(dpos,2);\n"
+@"    if (inDay.charAt(0) == \"0\") \n"
+@"      inDay = inDay.substr(1,inDay.length-1);\n"
+@"    inDay = parseInt(inDay);\n"
+@"    if ((inYear) && (inMonth) && (inDay)) {\n"
+@"        calDate = new Date(inYear,inMonth-1,inDay);\n"
+@"    }\n"
+@"    else {\n"
+@"     calDate = new Date();\n"
+@"    }\n"
+@"    // KEEP TRACK OF THE CURRENT DAY VALUE\n"
+@"    calDay  = calDate.getDate();\n"
+@"    // SET DAY VALUE TO 1... TO AVOID JAVASCRIPT DATE CALCULATION ANOMALIES\n"
+@"    // (IF THE MONTH CHANGES TO FEB AND THE DAY IS 30, THE MONTH WOULD CHANGE TO MARCH\n"
+@"    //  AND THE DAY WOULD CHANGE TO 2.  SETTING THE DAY TO 1 WILL PREVENT THAT)\n"
+@"    calDate.setDate(1);\n"
+@"}\n"
+@"// ENABLE MULTIPLE CALENDAR-USING OBJECTS BY USING VARIABLE calendarDiv;\n"
+@"var calendarDiv = false;\n"
+@"function toggleCalendar(dateFieldEl,calObj,calFormat) {\n"
+@"  if ((calendarDiv) &&  (calendarDiv.id != calObj.id)) {\n"
+@"    hideCalendar();\n"
+@"  }\n"
+@"  calendarDiv = calObj;\n"
+@"  \n"
+@"  if (isNav) condition = (calendarDiv.visibility == 'show');\n"
+@"  if (isIE)  condition = (calendarDiv.style.visibility    == 'visible');\n"
+@"  if (condition) {\n"
+@"    hideCalendar();\n"
+@"  }\n"
+@"  else {\n"
+@"    var i,j;\n"
+@"    var dateField;\n"
+@"    for (i = 0; i < document.forms.length; i++) {\n"
+@"      for (j = 0; j < document.forms[i].elements.length; j++) {\n"
+@"        if (document.forms[i].elements[j].name == dateFieldEl) {\n"
+@"          dateField = document.forms[i].elements[j];\n"
+@"        }\n"
+@"      }\n"
+@"    }\n"
+@"    dateFormat = calFormat;\n"
+@"    showCalendar(dateField);\n"
+@"  }\n"
+@"}\n"
+@"// CAPTURE onMouseMove EVENT IF NETSCAPE FOR POSITIONING calendarDiv\n"
+@"if (isNav) {\n"
+@"  document.captureEvents( Event.MOUSEMOVE );\n"
+@"  document.onmousemove = actPos;\n"
+@"}\n"
+@"var curScreenPosX;\n"
+@"var curScreenPosY;\n"
+@"function actPos(e) {\n"
+@"  \n"
+@"  curScreenPosX = e.pageX + 10;\n"
+@"  curScreenPosY = e.pageY;\n"
+@"  return true;\n"
+@"}\n"
+@"function showCalendar(dateField) {\n"
+@"    // SET INITIAL VALUE OF THE DATE FIELD AND CREATE TOP AND BOTTOM FRAMES\n"
+@"    setDateField(dateField);\n"
+@"    writeCalendar();\n"
+@"    if (isNav) {\n"
+@"      calendarDiv.visibility   = 'show';\n"
+@"      calendarDiv.left = curScreenPosX;\n"
+@"      calendarDiv.top  = curScreenPosY;\n"
+@"    }\n"
+@"    if (isIE) {\n"
+@"      calendarDiv.style.visibility      = 'visible';\n"
+@"    }\n"
+@"    return true;\n"
+@"}\n"
+@"function hideCalendar() {\n"
+@"    if (isNav) {\n"
+@"      calendarDiv.visibility = 'hide';\n"
+@"    }\n"
+@"    if (isIE) {\n"
+@"      calendarDiv.style.visibility = 'hidden';\n"
+@"    }\n"
+@"    calendarDiv = false;\n"
+@"}\n"
+@"// NEW: NO FRAMES ANYMORE, ONE <DIV> INSTEAD\n"
+@"function writeCalendar() {\n"
+@"  data = buildTopCalFrame() + buildBottomCalFrame();\n"
+@"  if (isNav) rewriteLayerWithData(calendarDiv, data);\n"
+@"  if (isIE)  rewriteLayerWithData(calendarDiv, data);\n"
+@"}\n"
+@"// CREATE month/year DISPLAY\n"
+@"function buildCalControlMonthYear() {\n"
+@"  month = calDate.getMonth();\n"
+@"  year  = calDate.getFullYear();\n"
+@"  return String(monthArray[month])+\" \"+String(year);\n"
+@"}\n"
+@"var obj=false;\n"
+@"var X,Y;\n"
+@"function MD() {\n"
+@"  if (isIE) {\n"
+@"    ob = true;\n"
+@"    X=event.offsetX;\n"
+@"    Y=event.offsetY;\n"
+@"    document.onmousemove = MM;\n"
+@"    document.onmouseup   = MU;\n"
+@"  }\n"
+@"}\n"
+@"function MM() {\n"
+@"  if (ob) {\n"
+@"    calendarDiv.style.pixelLeft = event.clientX-X + document.body.scrollLeft;\n"
+@"    calendarDiv.style.pixelTop = event.clientY-Y + document.body.scrollTop;\n"
+@"    return false;\n"
+@"  }\n"
+@"}\n"
+@"function MU() {\n"
+@"  ob = false;\n"
+@"//  document.onmousemove = null;\n"
+@"//  document.onmouseup   = null;\n"
+@"}\n"
+@"// CREATE THE TOP CALENDAR PART\n"
+@"function buildTopCalFrame() {\n"
+@"     var calDoc =\n"
+@"       \"<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0><TR><TD BGCOLOR=black>\" +\n"
+@"       \"<TABLE CELLPADDING=0 CELLSPACING=1 BORDER=0>\" +\n"
+@"       \"<TR><TD COLSPAN=6 ALIGN=left CLASS=topCal onMouseDown='MD()'>\" +\n"
+@"       buildCalControlMonthYear() +\n"
+@"       \"</TD>\" +\n"
+@"       \"<TD ALIGN=right CLASS=topCal>\"+\n"
+@"       \"<A CLASS=navMonYear HREF='javascript:hideCalendar()'>\" +\n"
+@"       dateFieldCloseSRC+\"</A>&nbsp;</TD></TR>\" +\n"
+@"       \"<TR>\" +\n"
+@"       \"<TD COLSPAN=7 CLASS=topCal ALIGN=center><FONT SIZE=1 FACE='Arial'>\"+\n"
+@"       \"<A CLASS=navMonYear HREF='javascript:setPreviousYear()'>\"+\n"
+@"       dateFieldFirstSRC+\"</A>\" +\n"
+@"       \" <A CLASS=navMonYear HREF='javascript:setPreviousMonth()'>\"+\n"
+@"       dateFieldPreviousSRC+\"</A>\" +\n"
+@"       \" <A CLASS=navMonYear HREF='javascript:setToday()'>\"+\n"
+@"       dateFieldTodaySRC+\"</A>\" +\n"
+@"       \" <A CLASS=navMonYear HREF='javascript:setNextMonth()'>\"+\n"
+@"       dateFieldNextSRC+\"</A>\"+\n"
+@"       \" <A CLASS=navMonYear HREF='javascript:setNextYear()'>\"+\n"
+@"       dateFieldLastSRC+\"</A>\" +\n"
+@"       \"</FONT></TD>\" +\n"
+@"       \"</TR>\";\n"
+@"   return calDoc;\n"
+@"}\n"
+@"// CREATE THE BOTTOM CALENDAR PART\n"
+@"function buildBottomCalFrame() {       \n"
+@"    // START CALENDAR DOCUMENT\n"
+@"    var calDoc = calendarBegin;\n"
+@"    // GET MONTH, AND YEAR FROM GLOBAL CALENDAR DATE\n"
+@"    month   = calDate.getMonth();\n"
+@"    year    = calDate.getFullYear();\n"
+@"    // GET GLOBALLY-TRACKED DAY VALUE (PREVENTS JAVASCRIPT DATE ANOMALIES)\n"
+@"    day     = calDay;\n"
+@"    var i   = 0;\n"
+@"    // DETERMINE THE NUMBER OF DAYS IN THE CURRENT MONTH\n"
+@"    var days = getDaysInMonth();\n"
+@"    // IF GLOBAL DAY VALUE IS > THAN DAYS IN MONTH, HIGHLIGHT LAST DAY IN MONTH\n"
+@"    if (day > days) {\n"
+@"        day = days;\n"
+@"    }\n"
+@"    // DETERMINE WHAT DAY OF THE WEEK THE CALENDAR STARTS ON\n"
+@"    var firstOfMonth = new Date (year, month, 1);\n"
+@"    // GET THE DAY OF THE WEEK THE FIRST DAY OF THE MONTH FALLS ON\n"
+@"    var startingPos  = firstOfMonth.getDay();\n"
+@"    days += startingPos;\n"
+@"    // KEEP TRACK OF THE COLUMNS, START A NEW ROW AFTER EVERY 7 COLUMNS\n"
+@"    var columnCount = 0;\n"
+@"    // MAKE BEGINNING NON-DATE CELLS BLANK\n"
+@"    for (i = 0; i < startingPos; i++) {\n"
+@"        calDoc += blankCell;\n"
+@"     columnCount++;\n"
+@"    }\n"
+@"    // SET VALUES FOR DAYS OF THE MONTH\n"
+@"    var currentDay = 0;\n"
+@"    var dayType    = \"weekday\";\n"
+@"    // DATE CELLS CONTAIN A NUMBER\n"
+@"    for (i = startingPos; i < days; i++) {\n"
+@"     var paddingChar = \"&nbsp;\";\n"
+@"        // ADJUST SPACING SO THAT ALL LINKS HAVE RELATIVELY EQUAL WIDTHS\n"
+@"        if (i-startingPos+1 < 10) {\n"
+@"            padding = \"&nbsp;&nbsp;\";\n"
+@"        }\n"
+@"        else {\n"
+@"            padding = \"&nbsp;\";\n"
+@"        }\n"
+@"        // GET THE DAY CURRENTLY BEING WRITTEN\n"
+@"        currentDay = i-startingPos+1;\n"
+@"        // SET THE TYPE OF DAY, THE focusDay GENERALLY APPEARS AS A DIFFERENT COLOR\n"
+@"        if (currentDay == day) {\n"
+@"            dayType = \"focusDay\";\n"
+@"        }\n"
+@"        else {\n"
+@"            dayType = \"weekDay\";\n"
+@"        }\n"
+@"        // ADD THE DAY TO THE CALENDAR STRING\n"
+@"        calDoc += \"<TD align=center bgcolor='lightgrey'>\" +\n"
+@"                  \"<a class='\" + dayType + \"' href='javascript:returnDate(\" + \n"
+@"                  currentDay + \")'>\" + padding + currentDay + paddingChar + \"</a></TD>\";\n"
+@"        columnCount++;\n"
+@"        // START A NEW ROW WHEN NECESSARY\n"
+@"        if (columnCount % 7 == 0) {\n"
+@"            calDoc += \"</TR><TR>\";\n"
+@"        }\n"
+@"    }\n"
+@"    // MAKE REMAINING NON-DATE CELLS BLANK\n"
+@"    for (i=days; i<42; i++)  {\n"
+@"        calDoc += blankCell;\n"
+@"     columnCount++;\n"
+@"        // START A NEW ROW WHEN NECESSARY\n"
+@"        if (columnCount % 7 == 0) {\n"
+@"            calDoc += \"</TR>\";\n"
+@"            if (i<41) {\n"
+@"                calDoc += \"<TR>\";\n"
+@"            }\n"
+@"        }\n"
+@"    }\n"
+@"    // FINISH THE NEW CALENDAR PAGE\n"
+@"    calDoc += calendarEnd;\n"
+@"    // RETURN THE COMPLETED CALENDAR PAGE\n"
+@"    return calDoc;\n"
+@"}\n"
+@"// SET THE CALENDAR TO TODAY'S DATE AND DISPLAY THE NEW CALENDAR\n"
+@"function setToday() {\n"
+@"    // SET GLOBAL DATE TO TODAY'S DATE\n"
+@"    calDate = new Date();\n"
+@"    // DISPLAY THE NEW CALENDAR\n"
+@"    writeCalendar();\n"
+@"}\n"
+@"// SET THE GLOBAL DATE TO THE PREVIOUS YEAR AND REDRAW THE CALENDAR\n"
+@"function setPreviousYear() {\n"
+@"    var year  = calDate.getFullYear();\n"
+@"    if (year > 1000) {\n"
+@"        year--;\n"
+@"        calDate.setFullYear(year);\n"
+@"        writeCalendar();\n"
+@"    }\n"
+@"}\n"
+@"// SET THE GLOBAL DATE TO THE PREVIOUS MONTH AND REDRAW THE CALENDAR\n"
+@"function setPreviousMonth() {\n"
+@"    var year  = calDate.getFullYear();\n"
+@"    var month = calDate.getMonth();\n"
+@"   \n"
+@"    // IF MONTH IS JANUARY, SET MONTH TO DECEMBER AND DECREMENT THE YEAR\n"
+@"    if (month == 0) {\n"
+@"        month = 11;\n"
+@"        if (year > 1000) {\n"
+@"            year--;\n"
+@"            calDate.setFullYear(year);\n"
+@"        }\n"
+@"    }\n"
+@"    else {\n"
+@"        month--;\n"
+@"    }\n"
+@"    calDate.setMonth(month);\n"
+@"    writeCalendar();\n"
+@"}\n"
+@"// SET THE GLOBAL DATE TO THE NEXT MONTH AND REDRAW THE CALENDAR\n"
+@"function setNextMonth() {\n"
+@"    var year = calDate.getFullYear();\n"
+@"        var month = calDate.getMonth();\n"
+@"        // IF MONTH IS DECEMBER, SET MONTH TO JANUARY AND INCREMENT THE YEAR\n"
+@"        if (month == 11) {\n"
+@"            month = 0;\n"
+@"            year++;\n"
+@"            calDate.setFullYear(year);\n"
+@"        }\n"
+@"        else {\n"
+@"            month++;\n"
+@"        }\n"
+@"        calDate.setMonth(month);\n"
+@"        writeCalendar();\n"
+@"}\n"
+@"// SET THE GLOBAL DATE TO THE NEXT YEAR AND REDRAW THE CALENDAR\n"
+@"function setNextYear() {\n"
+@"    var year  = calDate.getFullYear();\n"
+@"        year++;\n"
+@"        calDate.setFullYear(year);\n"
+@"        writeCalendar();\n"
+@"}\n"
+@"// GET NUMBER OF DAYS IN MONTH\n"
+@"function getDaysInMonth()  {\n"
+@"    var days;\n"
+@"    var month = calDate.getMonth()+1;\n"
+@"    var year  = calDate.getFullYear();\n"
+@"    // RETURN 31 DAYS\n"
+@"    if (month==1 || month==3 || month==5 || month==7 || month==8 ||\n"
+@"        month==10 || month==12)  {\n"
+@"        days=31;\n"
+@"    }\n"
+@"    // RETURN 30 DAYS\n"
+@"    else if (month==4 || month==6 || month==9 || month==11) {\n"
+@"        days=30;\n"
+@"    }\n"
+@"    // RETURN 29 DAYS\n"
+@"    else if (month==2)  {\n"
+@"        if (isLeapYear(year)) {\n"
+@"            days=29;\n"
+@"        }\n"
+@"        // RETURN 28 DAYS\n"
+@"        else {\n"
+@"            days=28;\n"
+@"        }\n"
+@"    }\n"
+@"    return (days);\n"
+@"}\n"
+@"// CHECK TO SEE IF YEAR IS A LEAP YEAR\n"
+@"function isLeapYear (Year) {\n"
+@"    if (((Year % 4)==0) && ((Year % 100)!=0) || ((Year % 400)==0)) {\n"
+@"        return (true);\n"
+@"    }\n"
+@"    else {\n"
+@"        return (false);\n"
+@"    }\n"
+@"}\n"
+@"// BUILD THE MONTH SELECT LIST\n"
+@"function getMonthSelect() {\n"
+@"    // IF SET BY A PARAMETER (WRITTEN AT THE BEGINNING BY WOCalendar)\n"
+@"    if (externMonths) {\n"
+@"      monthArray = externMonths;\n"
+@"    }\n"
+@"    else {\n"
+@"        monthArray = new Array('January', 'February', 'March', 'April', \n"
+@"           'May', 'June', 'July', 'August', \n"
+@"           'September', 'October', 'November', 'December');\n"
+@"    }\n"
+@"    return monthArray;\n"
+@"}\n"
+@"// SET DAYS OF THE WEEK DEPENDING ON LANGUAGE\n"
+@"function createWeekdayList() {\n"
+@"    // IF SET BY A PARAMETER (WRITTEN AT THE BEGINNING BY WODateFieldScript)\n"
+@"    if (externWeekdays) {\n"
+@"      weekdayArray = externWeekdays;\n"
+@"    }\n"
+@"    else {\n"
+@"        weekdayArray = new Array('Su','Mo','Tu','We','Th','Fr','Sa');\n"
+@"    }\n"
+@"    var weekdays = \"<TR BGCOLOR='white'>\";\n"
+@"    for (i in weekdayArray) {\n"
+@"        weekdays += \"<TD class='heading' align=center>\"\n"
+@"                 + weekdayArray[i] + \"</TD>\";\n"
+@"    }\n"
+@"    weekdays += \"</TR>\";\n"
+@"    return weekdays;\n"
+@"}\n"
+@"// PRE-BUILD PORTIONS OF THE CALENDAR (FOR PERFORMANCE REASONS)\n"
+@"function buildCalParts() {\n"
+@"    // BUILD THE BLANK CELL ROWS\n"
+@"    blankCell = \"<TD align=center bgcolor='lightGrey'>&nbsp;&nbsp;&nbsp;</TD>\";\n"
+@"    // BUILD THE TOP PORTION OF THE CALENDAR PAGE USING CSS TO CONTROL SOME DISPLAY ELEMENTS\n"
+@"    calendarBegin = createWeekdayList() + \"<TR>\";\n"
+@"    // BUILD THE BOTTOM PORTION OF THE CALENDAR PAGE\n"
+@"    calendarEnd = \"\";\n"
+@"        // END THE TABLE AND HTML DOCUMENT\n"
+@"        calendarEnd +=\n"
+@"            \"</TABLE></TD></TR></TABLE>\";\n"
+@"}\n"
+@"// REPLACE ALL INSTANCES OF find WITH replace\n"
+@"// inString: the string you want to convert\n"
+@"// find:     the value to search for\n"
+@"// replace:  the value to substitute\n"
+@"//\n"
+@"// usage:    jsReplace(inString, find, replace);\n"
+@"// example:  jsReplace(\"To be or not to be\", \"be\", \"ski\");\n"
+@"//           result: \"To ski or not to ski\"\n"
+@"//\n"
+@"function jsReplace(inString, find, replace) {\n"
+@"    var outString = \"\";\n"
+@"    if (!inString) {\n"
+@"        return \"\";\n"
+@"    }\n"
+@"    // REPLACE ALL INSTANCES OF find WITH replace\n"
+@"    if (inString.indexOf(find) != -1) {\n"
+@"        // SEPARATE THE STRING INTO AN ARRAY OF STRINGS USING THE VALUE IN find\n"
+@"        t = inString.split(find);\n"
+@"        // JOIN ALL ELEMENTS OF THE ARRAY, SEPARATED BY THE VALUE IN replace\n"
+@"        return (t.join(replace));\n"
+@"    }\n"
+@"    else {\n"
+@"        return inString;\n"
+@"    }\n"
+@"}\n"
+@"// JAVASCRIPT FUNCTION -- DOES NOTHING (USED FOR THE HREF IN THE CALENDAR CALL)\n"
+@"function doNothing() {\n"
+@"}\n"
+@"// ENSURE THAT VALUE IS TWO DIGITS IN LENGTH\n"
+@"function makeTwoDigit(inValue) {\n"
+@"    var numVal = parseInt(inValue, 10);\n"
+@"    // VALUE IS LESS THAN TWO DIGITS IN LENGTH\n"
+@"    if (numVal < 10) {\n"
+@"        // ADD A LEADING ZERO TO THE VALUE AND RETURN IT\n"
+@"        return(\"0\" + numVal);\n"
+@"    }\n"
+@"    else {\n"
+@"        return numVal;\n"
+@"    }\n"
+@"}\n"
+@"// SET FIELD VALUE TO THE DATE SELECTED AND CLOSE THE CALENDAR WINDOW\n"
+@"function returnDate(inDay)\n"
+@"{\n"
+@"    // inDay = THE DAY THE USER CLICKED ON\n"
+@"    calDate.setDate(inDay);\n"
+@"    // SET THE DATE RETURNED TO THE USER\n"
+@"    var day           = calDate.getDate();\n"
+@"    var month         = calDate.getMonth()+1;\n"
+@"    var year          = calDate.getFullYear();\n"
+@"    outDate = dateFormat;\n"
+@"    outDate = jsReplace(outDate,'%Y',String(year));\n"
+@"    outDate = jsReplace(outDate,'%m',makeTwoDigit(month));\n"
+@"    outDate = jsReplace(outDate,'%d',makeTwoDigit(day));\n"
+@"    // SET THE VALUE OF THE FIELD THAT WAS PASSED TO THE CALENDAR\n"
+@"    calDateField.value = outDate;\n"
+@"    // CLOSE THE CALENDAR WINDOW\n"
+@"    hideCalendar();\n"
+@"}\n"
diff --git a/skyrix-sope/WEExtensions/calendar.m b/skyrix-sope/WEExtensions/calendar.m
new file mode 100644 (file)
index 0000000..e585eae
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
diff --git a/skyrix-sope/WEExtensions/common.h b/skyrix-sope/WEExtensions/common.h
new file mode 100644 (file)
index 0000000..1e05e89
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WEExtensions_common_H__
+#define __WEExtensions_common_H__
+
+#import <Foundation/Foundation.h>
+#include <NGObjWeb/NGObjWeb.h>
+#include <NGExtensions/NGExtensions.h>
+
+#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#endif
+
+@interface WOContext(WOExtensionsPrivate)
+- (void)addActiveFormElement:(WOElement *)_element;
+@end
+
+static inline id WOExtGetProperty(NSDictionary *_set, NSString *_name) {
+  id propValue = [_set objectForKey:_name];
+
+  if (propValue) {
+    propValue = [propValue retain];
+    [(NSMutableDictionary *)_set removeObjectForKey:_name];
+  }
+  return propValue;
+}
+
+static inline NSString *WEUriOfResource(NSString *_name, WOContext *_ctx) {
+  NSArray           *languages;
+  WOResourceManager *resourceManager;
+  NSString          *uri;
+
+  if (_name == nil)
+    return nil;
+
+  languages = [_ctx hasSession]
+    ? [[_ctx session] languages]
+    : [[_ctx request] browserLanguages];
+  
+  resourceManager = [[_ctx application] resourceManager];
+  
+  uri = [resourceManager urlForResourceNamed:_name
+                         inFramework:nil
+                         languages:languages
+                         request:[_ctx request]];
+  if ([uri rangeOfString:@"/missingresource?"].length > 0)
+    uri = nil;
+  
+  return uri;
+}
+
+static inline void WEAppendFont(WOResponse *_resp,
+                                NSString   *_color,
+                                NSString   *_face,
+                                NSString   *_size)
+{
+  [_resp appendContentString:@"<font"];
+  if (_color) {
+    [_resp appendContentString:@" color=\""];
+    [_resp appendContentHTMLAttributeValue:_color];
+    [_resp appendContentCharacter:'"'];
+  }
+  if (_face) {
+    [_resp appendContentString:@" face=\""];
+    [_resp appendContentHTMLAttributeValue:_face];
+    [_resp appendContentCharacter:'"'];
+  }
+  if (_size) {
+    [_resp appendContentString:@" size=\""];
+    [_resp appendContentHTMLAttributeValue:_size];
+    [_resp appendContentCharacter:'"'];
+  }
+  [_resp appendContentCharacter:'>'];
+}
+
+static inline void WEAppendTD(WOResponse *_resp,
+                              NSString   *_align,
+                              NSString   *_valign,
+                              NSString   *_bgColor)
+{
+  [_resp appendContentString:@"<td"];
+  if (_bgColor) {
+    [_resp appendContentString:@" bgcolor=\""];
+    [_resp appendContentHTMLAttributeValue:_bgColor];
+    [_resp appendContentCharacter:'"'];
+  }
+  if (_align) {
+    [_resp appendContentString:@" align=\""];
+    [_resp appendContentHTMLAttributeValue:_align];
+    [_resp appendContentCharacter:'"'];
+  }
+  if (_valign) {
+    [_resp appendContentString:@" valign=\""];
+    [_resp appendContentHTMLAttributeValue:_valign];
+    [_resp appendContentCharacter:'"'];
+  }
+  [_resp appendContentCharacter:'>'];
+}
+
+static inline WOElement *WECreateElement(NSString *_className,
+                                         NSString *_name,
+                                         NSDictionary *_config,
+                                         WOElement *_template)
+{
+  Class               c;
+  WOElement           *result = nil;
+  NSMutableDictionary *config = nil;
+  
+  if ((c = NSClassFromString(_className)) == Nil) {
+    NSLog(@"%s: missing '%@' class", __PRETTY_FUNCTION__, _className);
+    return nil;
+  }
+  config = [NSMutableDictionary dictionaryWithCapacity:4];
+  {
+    NSEnumerator *keyEnum;
+    id           key;
+
+    keyEnum = [_config keyEnumerator];
+
+    while ((key = [keyEnum nextObject])) {
+      WOAssociation *a;
+
+      a = [WOAssociation associationWithValue:[_config objectForKey:key]];
+      [config setObject:a forKey:key];
+    }
+  }
+  result = [[c alloc] initWithName:_name
+                      associations:config
+                      template:_template];
+  return [result autorelease];
+}
+
+#define OWGetProperty WOExtGetProperty
+
+#endif /* __WEExtensions_common_H__ */
diff --git a/skyrix-sope/WEExtensions/dummy.m b/skyrix-sope/WEExtensions/dummy.m
new file mode 100644 (file)
index 0000000..ccff33f
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  dummy file to produce an executable for the bundle ...
+*/
diff --git a/skyrix-sope/WEExtensions/js2m.sh b/skyrix-sope/WEExtensions/js2m.sh
new file mode 100755 (executable)
index 0000000..c1b7737
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+jsfile=$1
+mfile=$2
+
+if [ "x${jsfile}" = "x" ]; then
+  echo "usage: $0 <jsfile> <mfile>"
+  exit 1;
+fi
+if [ "x${mfile}" = "x" ]; then
+  echo "usage: $0 <jsfile> <mfile>"
+  exit 1;
+fi
+
+if [ ! -f $jsfile ]; then
+  echo "$0: file '${jsfile}' can't be found !"
+  exit 2;
+fi
+
+echo "transforming ${jsfile} to ${mfile} .."
+
+IFS="
+"
+replaceto='\\"'
+
+SEDCMD=sed
+ECHOCMD=echo
+
+$ECHOCMD >$mfile "/* automatically generated from ${jsfile}, do not edit ! */"
+for i in `${SEDCMD} "s|\\"|$replaceto|g" <${jsfile}`; do
+  $ECHOCMD -n >>$mfile "@\""
+  $ECHOCMD -n >>$mfile "${i}"
+  $ECHOCMD >>$mfile "\\n\""
+done
diff --git a/skyrix-sope/WOExtensions/.cvsignore b/skyrix-sope/WOExtensions/.cvsignore
new file mode 100644 (file)
index 0000000..5a7e3b5
--- /dev/null
@@ -0,0 +1,4 @@
+English.lproj
+WOExtensions.bundle
+WOExtensions_Prefix.h
+shared_debug_obj
diff --git a/skyrix-sope/WOExtensions/COPYING b/skyrix-sope/WOExtensions/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/WOExtensions/COPYRIGHT b/skyrix-sope/WOExtensions/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-sope/WOExtensions/ChangeLog b/skyrix-sope/WOExtensions/ChangeLog
new file mode 100644 (file)
index 0000000..eaf23a5
--- /dev/null
@@ -0,0 +1,191 @@
+2004-06-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.14
+
+       * GNUmakefile.preamble: added prebinding
+
+       * JSModalWindow.m: improved XHTML compatibility
+
+       * JSTextFlyover.m, JSValidatedField.m, WOCheckBoxMatrix.m: minor 
+         cleanups
+
+2004-06-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * common.h: added typecast to avoid gcc 3.4 warning (v4.2.13)
+
+       * v4.2.12
+
+       * JSAlertPanel.m: minor code cleanups, improved XHTML compatibility
+
+       * GNUmakefile.preamble: fixed relative search pathes
+
+2004-06-02  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * GNUmakefile: more support for building with GNUSTEP_BUILD_DIR
+         env variable set (v4.2.11)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.10)
+
+2004-03-31  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.9
+
+       * WOxExtElemBuilder.m: do not process <var:redirect/> (now handled
+         by WExExtElemBuilder)
+
+       * added new WORedirect implementation as a subclass of WOComponent,
+         added WORedirect header file
+
+       * added WOExtensions.h header file
+
+       * moved WORedirect dynamic element to WEExtensions as WERedirect
+
+2003-12-12  Helge Hess  <helge.hess@skyrix.com>
+
+       * JSConfirmPanel.m: sourcecode cleanups, fixed with regards to
+         XHTML generation (v4.2.8)
+
+2003-11-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile: include makefiles from GNUSTEP_MAKEFILES (as suggested
+         by chunsj@embian.com (v4.2.7)
+
+2003-10-15  Helge Hess  <helge@mac.in.skyrix.com.0.168.192.in-addr.arpa>
+
+       * v4.2.6
+
+       * GNUmakefile.preamble: added explicit library dependencies as
+         required by MacOSX
+
+       * common.h: made independend from FoundationExt
+
+2003-09-09  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed js2m.sh, not required in WOExtensions
+
+2003-09-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * various: smaller cleanups and performance improvements (v4.2.5)
+
+2003-07-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * applied rangeOfString patches provided by Filip Van Raemdonck for 
+         improved compilation with gstep-base (v4.2.4)
+
+2003-06-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * some cleanups, generate lowercase HTML tags, fixed some 
+         signed/unsigned gcc warnings (v4.2.3)
+
+       * moved to skyrix-sope-42 (v4.2.2)
+
+2002-12-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: fixed linking
+
+2002-12-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: fixed SOVERSION (major/minor)
+
+2002-12-02  Helge Hess  <helge.hess@skyrix.com>
+       
+       * moved to Skyrix41e/WebUI/WOExtensions (v4.1.1)
+       
+2002-06-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOTabPanel.m: use -isEqual: to find the selected tab instead of
+         object identity since tabkeys which where passed thru a bridge
+         (eg JavaScript engine) usually don't preserve identity of base
+         types
+
+Wed Feb 27 13:39:08 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODictionaryRepetition.m: remove warning for immutable dicts
+
+Wed Jan  9 17:07:10 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WOxExtElemBuilder.m: all WOExtensions tags supported now
+
+Mon Jan  7 17:37:39 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added WOExtensions bundle
+
+Fri Jun 15 14:42:12 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * JSConfirmPanel.m: added 'showPanel' association
+
+Tue Apr 17 13:37:56 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WOTable.m: upper limit of 'maxColumns' is count of 'list'
+
+Tue Apr 10 16:03:10 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WOTable.m: added WOTableHeader and WOTableContent
+
+Fri Apr  6 20:23:06 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * WOTable.m: added hasOwnTDs association
+
+       * JSValidatedField.m: escape inputText
+
+Mon Jan  8 13:38:27 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * fixed compilation
+
+Thu Dec  7 14:16:53 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WOThresholdColoredNumber.m: renamed 'treshold' assoc. to 'thres...'
+
+       * GNUmakefile: renamed Treshold.m into Threshold.m
+
+Thu Dec  7 12:15:39 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * cleanups, renamed WETresholdColoredNumber to WOThre...
+
+Thu Nov 23 14:42:11 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WOTable.m: generate TD WIDTH depending on maxColumns 
+
+Fri Oct 27 19:13:30 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WOCheckBoxMatrix.m: added
+
+       * WORadioButtonMatrix.m: added
+
+       * WOCollapsibleComponentContent.m: added association 'condition'
+
+Tue Oct 17 11:25:44 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * WOTabPanel.m: 'selectedTab' wasn't updated correctly
+
+       * WOResponse+HtmlAdditions.[h|m]: removed
+
+       * WODynamicElement+WOExtensions.[h|m]: removed
+
+       * WOContextConditional.*: moved to WEExtensions/WEContextConditional.*
+
+       * WOTableView.m: moved to WEExtensions/WETableView.m
+
+       * WOTreeView.m: moved to WEExtensions/WETreeView.m
+
+       * WOSwitch.m: moved to WEExtensions/WESwitch.m
+
+Fri Oct  6 15:25:28 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * JSImageFlyover.m: added direct-action bindings
+
+Tue Sep 19 14:03:10 2000  Martin Spindler  <spindler@mdlink.de>
+
+       * added WOSwitch, WOTable, WOContextConditional, WOTableView
+
+Fri Aug  4 18:26:22 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * added JS* components done by semkat
+
+Thu Jul 20 13:54:03 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * created WOExtensions directory
diff --git a/skyrix-sope/WOExtensions/GNUmakefile b/skyrix-sope/WOExtensions/GNUmakefile
new file mode 100644 (file)
index 0000000..51fa16d
--- /dev/null
@@ -0,0 +1,52 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+include ../Version
+include ./Version
+
+LIBRARY_NAME = libWOExtensions
+BUNDLE_NAME  = WOExtensions
+
+libWOExtensions_HEADER_FILES_DIR        = .
+libWOExtensions_HEADER_FILES_INSTALL_DIR = /WOExtensions
+
+libWOExtensions_HEADER_FILES = \
+       WOExtensions.h                  \
+       WORedirect.h                    \
+
+libWOExtensions_OBJC_FILES = \
+       WOxExtElemBuilder.m             \
+       compat.m                        \
+       WOKeyValueConditional.m         \
+       WORedirect.m                    \
+       WOTabPanel.m                    \
+       WOTable.m                       \
+       JSAlertPanel.m                  \
+       JSConfirmPanel.m                \
+       JSImageFlyover.m                \
+       JSTextFlyover.m                 \
+       JSValidatedField.m              \
+       JSModalWindow.m                 \
+       WOCollapsibleComponentContent.m \
+       WODictionaryRepetition.m        \
+       WOThresholdColoredNumber.m      \
+       WORadioButtonMatrix.m           \
+       WOCheckBoxMatrix.m              \
+
+WOExtensions_OBJC_FILES += dummy.m
+WOExtensions_PRINCIPAL_CLASS = WOxExtElemBuilder
+
+ifneq ($(GNUSTEP_BUILD_DIR),) 
+after-WOExtensions-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION)) 
+else
+after-WOExtensions-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/WOExtensions/GNUmakefile.preamble b/skyrix-sope/WOExtensions/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..19f741b
--- /dev/null
@@ -0,0 +1,52 @@
+# $Id$
+
+libWOExtensions_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libWOExtensions_LIBRARIES_DEPEND_UPON += \
+       -lWEExtensions                                  \
+       -lNGObjWeb -lNGJavaScript -lNGScripting         \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC        \
+       -ljs
+
+ADDITIONAL_CPPFLAGS += -Wall
+ADDITIONAL_INCLUDE_DIRS += -I.. -I../.. -I../NGObjWeb
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_JS=$(GNUSTEP_BUILD_DIR)/../../../ThirdParty/js-1.5
+RELBUILD_DIR_SOPE=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/../../skyrix-core
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../skyrix-xml
+
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                                            \
+        -L$(RELBUILD_DIR_SOPE)/WEExtensions/$(GNUSTEP_OBJ_DIR_NAME)    \
+        -L$(RELBUILD_DIR_SOPE)/NGObjWeb/$(GNUSTEP_OBJ_DIR_NAME)                \
+        -L$(RELBUILD_DIR_SOPE)/NGJavaScript/$(GNUSTEP_OBJ_DIR_NAME)    \
+        -L$(RELBUILD_DIR_SOPE)/NGScripting/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGMime/$(GNUSTEP_OBJ_DIR_NAME)        \
+        -L$(RELBUILD_DIR_SxCore)/NGStreams/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+        -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)             \
+        -L$(RELBUILD_DIR_SxXml)/XmlRpc/$(GNUSTEP_OBJ_DIR_NAME)         \
+        -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)            \
+        -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)                \
+       -L$(RELBUILD_DIR_JS)/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += \
+       -L./$(GNUSTEP_OBJ_DIR)                  \
+        -L../NGObjWeb/$(GNUSTEP_OBJ_DIR)        \
+        -L../NGJavaScript/$(GNUSTEP_OBJ_DIR)    \
+        -L../NGScripting/$(GNUSTEP_OBJ_DIR)     \
+        -L../WEExtensions/$(GNUSTEP_OBJ_DIR)
+endif
+
+WOExtensions_BUNDLE_LIBS += -lWOExtensions -lWEExtensions
+WOExtensions_WOBUNDLE_LIBS += $(WOExtensions_BUNDLE_LIBS)
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libWOExtensions_PREBIND_ADDR="0xC4300000"
+libWOExtensions_LDFLAGS += -seg1addr $(libWOExtensions_PREBIND_ADDR)
+endif
diff --git a/skyrix-sope/WOExtensions/JSAlertPanel.m b/skyrix-sope/WOExtensions/JSAlertPanel.m
new file mode 100644 (file)
index 0000000..961ce67
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <NGObjWeb/WODynamicElement.h>
+
+@interface JSAlertPanel : WODynamicElement
+{
+  WOAssociation *action;
+  WOAssociation *javaScriptFunction;
+  WOAssociation *pageName;
+  WOAssociation *alertMessage;
+  WOAssociation *altTag;
+  WOAssociation *filename;
+  WOAssociation *targetWindow;
+  WOAssociation *string;
+  
+  WOElement     *template;
+}
+
+@end
+
+#include "common.h"
+
+@implementation JSAlertPanel
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs]))
+  {
+    int funcCount;
+
+    self->action             = WOExtGetProperty(_config,@"action");
+    self->javaScriptFunction = WOExtGetProperty(_config,@"javaScriptFunction");
+    self->pageName           = WOExtGetProperty(_config,@"pageName");
+    self->alertMessage       = WOExtGetProperty(_config,@"alertMessage");
+    self->altTag             = WOExtGetProperty(_config,@"altTag");
+    self->filename           = WOExtGetProperty(_config,@"filename");
+    self->targetWindow       = WOExtGetProperty(_config,@"targetWindow");
+    self->string             = WOExtGetProperty(_config,@"string");
+    
+    funcCount = 0;
+    if (self->action) funcCount++;
+    if (self->pageName) funcCount++;
+    if (self->javaScriptFunction) funcCount++;
+
+    if (funcCount > 1) {
+      NSLog(@"WARNING: JSAlertPanel: choose only one of "
+            @"action | pageName | javaScriptFunction");
+    }
+    if (funcCount < 1) {
+      NSLog(@"WARNING: JSAlertPanel: no function declared - choose one of"
+            @"action | pageName | javaScriptFunction");
+    }
+    if (!self->alertMessage) {
+      NSLog(@"WARNING: JSAlertPanel: no value for 'alertMessage'"
+            @" - using default");
+    }
+    
+    self->template = RETAIN(_subs);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->action);
+  RELEASE(self->javaScriptFunction);
+  RELEASE(self->pageName);
+  RELEASE(self->alertMessage);
+  RELEASE(self->altTag);
+  RELEASE(self->filename);
+  RELEASE(self->targetWindow);
+  RELEASE(self->string);
+  RELEASE(self->template);
+  [super dealloc];
+}
+
+/* processing requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  [self->template takeValuesFromRequest:_rq inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  if (self->pageName) {
+    NSString *name;
+    
+    name = [self->pageName stringValueInComponent: [_ctx component]];
+    return [[_ctx application] pageWithName:name inContext:_ctx];
+  }
+  if (self->action)
+    return [self->action valueInComponent:[_ctx component]];
+  
+  return [self->template invokeActionForRequest:_rq inContext:_ctx];
+}
+
+
+- (void)appendToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent     *comp;
+  NSString        *tmp;
+  NSArray         *languages;
+  
+  comp = [_ctx component];
+  
+  // link
+  [_response appendContentString:@"<a onClick=\"javascript:alert('"];
+  tmp = (self->alertMessage)
+    ? [self->alertMessage stringValueInComponent: comp]
+    : @"Press OK.";
+  [_response appendContentHTMLString:tmp];
+  [_response appendContentString:@"');\""];
+  [_response appendContentString:@" href=\""];
+  
+  if (self->javaScriptFunction) {
+    [_response appendContentString:@"javascript:"];
+    [_response appendContentHTMLAttributeValue:
+                 [self->javaScriptFunction stringValueInComponent:comp]];
+  }
+  else {
+    [_response appendContentString:[_ctx componentActionURL]];
+  }
+  [_response appendContentString:@"\" "];
+  if (self->targetWindow) {
+    [_response appendContentString:@" target=\""];
+    [_response appendContentHTMLAttributeValue:
+                 [self->targetWindow stringValueInComponent: comp]];
+    [_response appendContentString:@"\" "];
+  }
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  [_response appendContentString:@" >"];
+
+  // link content  
+  if (self->filename) {
+    WOResourceManager *rm;
+
+    rm = [[_ctx application] resourceManager];
+    
+    languages = [_ctx hasSession]
+      ? [[_ctx session] languages]
+      : [[_ctx request] browserLanguages];
+    
+    tmp = [rm urlForResourceNamed:[self->filename stringValueInComponent:comp]
+              inFramework:[comp frameworkName]
+              languages:languages
+              request:[_ctx request]];
+    
+    [_response appendContentString:@"<img border=\"0\" src=\""];
+    [_response appendContentString:tmp];
+    [_response appendContentString:@"\""];
+    
+    if (self->altTag) {
+      [_response appendContentString:@" alt=\""];
+      [_response appendContentString:
+        [self->altTag stringValueInComponent:comp]];
+      [_response appendContentString:@"\" "];
+    }
+    [_response appendContentString:@" />"];
+  }
+  [self->template appendToResponse:_response inContext:_ctx];
+  if (self->string) 
+    [_response appendContentString:[self->string stringValueInComponent:comp]];
+
+  /* close link */
+  [_response appendContentString:@"</a>"];
+}
+
+@end /* JSAlertPanel */
diff --git a/skyrix-sope/WOExtensions/JSConfirmPanel.m b/skyrix-sope/WOExtensions/JSConfirmPanel.m
new file mode 100644 (file)
index 0000000..4b52e03
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/WODynamicElement.h>
+
+@interface JSConfirmPanel : WODynamicElement
+{
+  WOAssociation *action;
+  WOAssociation *javaScriptFunction;
+  WOAssociation *pageName;
+  WOAssociation *confirmMessage;
+  WOAssociation *altTag;
+  WOAssociation *filename;
+  WOAssociation *targetWindow;
+  WOAssociation *string;
+
+  /* non WO */
+  WOAssociation *showPanel;
+  WOElement     *template;
+}
+
+@end
+
+#include "common.h"
+
+@implementation JSConfirmPanel
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs]))
+  {
+    int funcCount;
+
+    self->action             = WOExtGetProperty(_config,@"action");
+    self->javaScriptFunction = WOExtGetProperty(_config,@"javaScriptFunction");
+    self->pageName           = WOExtGetProperty(_config,@"pageName");
+    self->confirmMessage     = WOExtGetProperty(_config,@"confirmMessage");
+    self->altTag             = WOExtGetProperty(_config,@"altTag");
+    self->filename           = WOExtGetProperty(_config,@"filename");
+    self->targetWindow       = WOExtGetProperty(_config,@"targetWindow");
+    self->string             = WOExtGetProperty(_config,@"string");
+    self->showPanel          = WOExtGetProperty(_config,@"showPanel");
+
+    funcCount = 0;
+    if (self->action) funcCount++;
+    if (self->pageName) funcCount++;
+    if (self->javaScriptFunction) funcCount++;
+
+    if (funcCount > 1) {
+      NSLog(@"WARNING: JSConfirmPanel: choose only one of "
+            @"action | pageName | javaScriptFunction");
+    }
+    if (funcCount < 1) {
+      NSLog(@"WARNING: JSConfirmPanel: no function declared - choose one of"
+            @"action | pageName | javaScriptFunction");
+    }
+    if (!self->confirmMessage) {
+      NSLog(@"WARNING: JSConfirmPanel: no value for 'confirmMessage'"
+            @" - using default");
+    }
+    
+    self->template = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->action             release];
+  [self->javaScriptFunction release];
+  [self->pageName           release];
+  [self->confirmMessage     release];
+  [self->altTag             release];
+  [self->filename           release];
+  [self->targetWindow       release];
+  [self->string             release];
+  [self->template           release];
+  [self->showPanel          release];
+  [super dealloc];
+}
+
+/* request processing */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  [self->template takeValuesFromRequest:_rq inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx{
+  id       result;
+  NSString *name;
+
+  if (self->showPanel &&
+      ![self->showPanel boolValueInComponent:[_ctx component]]) {
+    return nil;
+  }
+  
+  if (self->pageName) {
+    name = [self->pageName stringValueInComponent: [_ctx component]];
+    result = [[_ctx application] pageWithName:name inContext:_ctx];
+  }
+  else if (self->action) {
+    result = [self->action valueInComponent:[_ctx component]];
+  }
+  else {
+    result = [self->template invokeActionForRequest:_request inContext:_ctx];
+  }
+  return result;
+}
+
+/* response generation */
+
+- (void)_appendPanelToResponse:(WOResponse *)_response 
+  message:(NSString *)_msg
+  inContext:(WOContext *)_ctx 
+{
+  if (![self->showPanel boolValueInComponent:[_ctx component]])
+    return;
+  
+  [_response appendContentString:
+               @"<script language=\"javascript\">\nvar res = confirm(\""];
+  [_response appendContentHTMLString:_msg];
+  [_response appendContentString:@"\");\n if (res) {\n"];
+
+  if (self->javaScriptFunction) {
+    NSString *js;
+    
+    js = [self->javaScriptFunction stringValueInComponent:[_ctx component]];
+    [_response appendContentString:js];
+  }
+  else if (self->action || self->pageName) {
+    [_response appendContentString:@"document.location.href=\""];
+    [_response appendContentString:[_ctx componentActionURL]];
+    [_response appendContentString:@"\";"];
+  }
+    
+  [_response appendContentString:@"}"];
+  [_response appendContentString:@"</script>"];
+}
+
+- (void)_appendLinkToResponse:(WOResponse *)_response 
+  message:(NSString *)_msg
+  inContext:(WOContext *)_ctx 
+{
+  WOComponent *comp;
+  NSString    *tmp;
+  NSArray     *languages;
+  
+  comp = [_ctx component];
+  
+  [_response appendContentString:@"<a onclick=\"javascript:return confirm('"];
+  [_response appendContentHTMLString:_msg];
+  [_response appendContentString:@"');\""];
+  [_response appendContentString:@" href=\""];
+  
+  if (self->javaScriptFunction) {
+      [_response appendContentString:@"javascript:"];
+      [_response appendContentHTMLAttributeValue:
+                 [self->javaScriptFunction stringValueInComponent:comp]];
+  }
+  else {
+      [_response appendContentString:[_ctx componentActionURL]];
+  }
+  [_response appendContentString:@"\" "];
+  if (self->targetWindow) {
+      [_response appendContentString:@" target=\""];
+      [_response appendContentHTMLAttributeValue:
+                 [self->targetWindow stringValueInComponent: comp]];
+      [_response appendContentString:@"\" "];
+  }
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  [_response appendContentString:@" >"];
+
+  /* link content */
+  if (self->filename) { /* image */
+      WOResourceManager *rm;
+
+      rm = [[_ctx application] resourceManager];
+    
+      languages = [_ctx hasSession]
+        ? [[_ctx session] languages]
+        : [[_ctx request] browserLanguages];
+    
+      tmp = [rm urlForResourceNamed:[self->filename stringValueInComponent:comp]
+                inFramework:[comp frameworkName]
+                languages:languages
+                request:[_ctx request]];
+    
+      [_response appendContentString:@"<img border=\"0\" src=\""];
+      [_response appendContentString:tmp];
+      [_response appendContentString:@"\" "];
+    
+      if (self->altTag) {
+        [_response appendContentString:@"alt=\""];
+        [_response appendContentString:
+                   [self->altTag stringValueInComponent:comp]];
+        [_response appendContentString:@"\" "];
+      }
+      [_response appendContentString:@" />"];
+  }
+  
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  if (self->string) {
+    [_response appendContentString:
+                 [self->string stringValueInComponent:comp]];
+  }
+  
+  /* close link */
+  [_response appendContentString:@"</a>"];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *msg;
+  
+  msg  = (self->confirmMessage)
+    ? [self->confirmMessage stringValueInComponent:[_ctx component]]
+    : @"Really?";
+  
+  if (self->showPanel)
+    [self _appendPanelToResponse:_response message:msg inContext:_ctx];
+  else 
+    [self _appendLinkToResponse:_response message:msg inContext:_ctx];
+}
+
+@end /* JSConfirmPanel */
diff --git a/skyrix-sope/WOExtensions/JSImageFlyover.m b/skyrix-sope/WOExtensions/JSImageFlyover.m
new file mode 100644 (file)
index 0000000..5ce49e4
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/WODynamicElement.h>
+
+@interface JSImageFlyover : WODynamicElement
+{
+  WOAssociation *action;
+  WOAssociation *javaScriptFunction;
+  WOAssociation *pageName;
+  WOAssociation *selectedImage;
+  WOAssociation *unselectedImage;
+  WOAssociation *framework;
+  WOAssociation *targetWindow;
+
+  // Skyrix add-ons
+  WOAssociation *directActionName;
+  WOAssociation *actionClass;
+  BOOL          sidInUrl;
+  WOAssociation *queryDictionary;
+  NSDictionary  *queryParameters;
+  
+  WOElement     *template;
+}
+
+@end
+
+#import <NGObjWeb/NGObjWeb.h>
+#include "common.h"
+
+@implementation JSImageFlyover
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+           @"invalid superclass (%@) version %i !",
+           NSStringFromClass([self superclass]), [super version]);
+}
+
+- (NSDictionary *)extractQueryParameters: (NSDictionary *)_set {
+  NSMutableDictionary *paras = nil;
+  NSMutableArray      *paraKeys = nil;
+  NSEnumerator        *keys;
+  NSString            *key;
+
+  // locate query parameters
+  keys = [_set keyEnumerator];
+  while ((key = [keys nextObject])) {
+    if ([key hasPrefix:@"?"]) {
+      WOAssociation *value;
+
+      if ([key isEqualToString:@"?wosid"])
+        continue;
+
+      value = [_set objectForKey:key];
+          
+      if (paraKeys == nil)
+        paraKeys = [NSMutableArray arrayWithCapacity:8];
+      if (paras == nil)
+        paras = [NSMutableDictionary dictionaryWithCapacity:8];
+          
+      [paraKeys addObject:key];
+      [paras setObject:value forKey:[key substringFromIndex:1]];
+    }
+  }
+
+  // remove query parameters
+  if (paraKeys) {
+    unsigned cnt, count;
+    for (cnt = 0, count = [paraKeys count]; cnt < count; cnt++) {
+      [(NSMutableDictionary *)_set removeObjectForKey:
+                                     [paraKeys objectAtIndex:cnt]];
+    }
+  }
+
+  // assign parameters
+  return [paras copy];
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs]))
+  {
+    int           funcCount;
+    WOAssociation *sidInUrlAssoc;
+
+    
+    self->action             = WOExtGetProperty(_config, @"action");
+    self->javaScriptFunction = WOExtGetProperty(_config, @"javaScriptFunction");
+    self->pageName           = WOExtGetProperty(_config, @"pageName");
+    self->selectedImage      = WOExtGetProperty(_config, @"selectedImage");
+    self->unselectedImage    = WOExtGetProperty(_config, @"unselectedImage");
+    self->framework          = WOExtGetProperty(_config, @"framework");
+    self->targetWindow       = WOExtGetProperty(_config, @"targetWindow");
+
+    self->directActionName   = WOExtGetProperty(_config, @"directActionName");
+    self->actionClass        = WOExtGetProperty(_config, @"actionClass");
+    self->queryDictionary    = WOExtGetProperty(_config, @"queryDictionary");
+    self->queryParameters    = [self extractQueryParameters:_config];
+    
+    funcCount = 0;
+    if (self->action) funcCount++;
+    if (self->pageName) funcCount++;
+    if (self->javaScriptFunction) funcCount++;
+    if (self->directActionName) funcCount++;
+
+    if (funcCount > 1)
+      NSLog(@"WARNING: JSImageFlyover: choose only one of "
+            @"action | pageName | javaScriptFunction | directActionName");
+    if (funcCount < 1)
+      NSLog(@"WARNING: JSImageFlyover: no function declared - choose one of"
+            @"action | pageName | javaScriptFunction | directActionName");
+    if (!self->selectedImage)
+      NSLog(@"WARNING: JSImageFlyover: no value for 'selectedImage'");
+    if (!self->unselectedImage)
+      NSLog(@"WARNING: JSImageFlyover: no value for 'unselectedImage'");
+
+    /* for directActionName */
+    sidInUrlAssoc = WOExtGetProperty(_config, @"?wosid");
+    self->sidInUrl = (sidInUrlAssoc)
+      ? [sidInUrlAssoc boolValueInComponent:nil]
+      : YES;
+    
+
+    self->template = RETAIN(_subs);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->action);
+  RELEASE(self->javaScriptFunction);
+  RELEASE(self->pageName);
+  RELEASE(self->selectedImage);
+  RELEASE(self->unselectedImage);
+  RELEASE(self->framework);
+  RELEASE(self->targetWindow);
+  RELEASE(self->template);
+
+  RELEASE(self->directActionName);
+  RELEASE(self->actionClass);
+  RELEASE(self->queryDictionary);
+  RELEASE(self->queryParameters);
+  
+  [super dealloc];
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  id          result;
+  NSString    *name;
+
+  if (self->pageName) {
+    name = [self->pageName stringValueInComponent: [_ctx component]];
+    result = [[_ctx application] pageWithName:name inContext:_ctx];
+  }
+  else if (self->action) {
+    result = [self->action valueInComponent:[_ctx component]];
+  }
+  else {
+    result = [self->template invokeActionForRequest:_request inContext:_ctx];
+  }
+  return result;
+}
+
+
+- (NSString *)imageByFilename:(NSString *)_name
+  inContext:(WOContext *)_ctx
+  framework:(NSString *)_framework
+{
+  WOResourceManager *rm;
+  NSString          *tmp;
+  NSArray           *languages;
+
+  rm = [[_ctx application] resourceManager];
+    
+  languages = [_ctx hasSession]
+    ? [[_ctx session] languages]
+    : [[_ctx request] browserLanguages];
+    
+  tmp = [rm urlForResourceNamed:_name
+            inFramework:_framework
+            languages:languages
+            request:[_ctx request]];
+  return tmp;
+}
+    
+
+- (void)appendDirectActionURLToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *comp;
+  NSString            *daName;
+  NSString            *daClass;
+  NSMutableDictionary *qd;
+  WOSession           *sn;
+  NSDictionary        *tdict;
+  NSString *s;
+  
+  comp    = [_ctx component];
+  daName  = [self->directActionName stringValueInComponent:comp];
+  daClass = [self->actionClass stringValueInComponent:comp];
+      
+  if (daClass) {
+    if (daName) {
+      if (![daClass isEqualToString:@"DirectAction"])
+        daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
+    }
+    else
+      daName = daClass;
+  }
+      
+  qd = [NSMutableDictionary dictionaryWithCapacity:16];
+
+  if (self->queryDictionary) {
+    if ((tdict = [self->queryDictionary valueInComponent:comp]))
+      [qd addEntriesFromDictionary:tdict];
+  }
+
+  if (self->queryParameters) {
+    NSEnumerator *keys;
+    NSString     *key;
+
+    keys = [self->queryParameters keyEnumerator];
+    while ((key = [keys nextObject])) {
+      id assoc, value;
+      assoc = [self->queryParameters objectForKey:key];
+      value = [assoc stringValueInComponent:comp];
+      [qd setObject:(value ? value : @"") forKey:key];
+    }
+  }
+      
+  if ((self->sidInUrl) && ([_ctx hasSession])) {
+    sn = [_ctx session];
+    [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
+    if (![sn isDistributionEnabled]) {
+      [qd setObject:[[WOApplication application] number]
+          forKey:WORequestValueInstance];
+    }
+  }
+      
+  s = [_ctx directActionURLForActionNamed:daName queryDictionary:qd];
+  [_response appendContentString:s];
+}
+
+- (void)appendToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *comp;
+  NSString    *tmp;
+  NSString    *tunselected, *tselected, *tframework;
+  NSString    *elID;
+  NSArray     *ta;
+  NSString    *s;
+  
+  comp = [_ctx component];
+  tunselected = [self->unselectedImage stringValueInComponent:comp];
+  tselected   = [self->selectedImage   stringValueInComponent:comp];
+  tframework  = (self->framework)
+    ? [self->framework stringValueInComponent:comp]
+    : [comp frameworkName];
+
+  tunselected = [self imageByFilename: tunselected inContext:_ctx
+                      framework: tframework];
+  tselected   = [self imageByFilename: tselected inContext:_ctx
+                      framework: tframework];
+  
+  elID = [_ctx elementID];
+  /* javascript didn't work with #.#.#.# -> replacing to #x#x#x# */
+  ta = [[NSArray alloc] initWithArray:[elID componentsSeparatedByString:@"."]];
+  elID = [ta componentsJoinedByString:@"x"];
+  [ta release];
+  
+  /* template */
+  [self->template appendToResponse:_response inContext:_ctx];
+
+  /* script */
+  [_response appendContentString:@"<script language=\"JavaScript\">\n<!--\n"];
+
+  if (![_ctx valueForKey:@"JSImageFlyoverScriptDone"]) {
+    tmp = @"var JSImageFlyoverImages = new Array();\n"
+          @"function JSImageFlyover(imgName,imgKind) {\n"
+          @"  document.images[imgName].src = "
+          @"JSImageFlyoverImages[imgName][imgKind].src;\n"
+          @"}\n";
+    [_response appendContentString:tmp];
+    [_ctx takeValue:[NSNumber numberWithBool:YES]
+          forKey:@"JSImageFlyoverScriptDone"];
+  }
+
+  tmp = @"JSImageFlyoverImages['%@'] = new Array; \n"
+        @"JSImageFlyoverImages['%@'][0] = new Image; "
+        @"JSImageFlyoverImages['%@'][0].src = '%@'; \n"
+        @"JSImageFlyoverImages['%@'][1] = new Image; "
+        @"JSImageFlyoverImages['%@'][1].src = '%@'; \n";
+  
+  s = [[NSString alloc] initWithFormat:tmp,
+                          elID, elID, elID, tunselected,
+                          elID, elID, tselected];
+  [_response appendContentString:s];
+  [s release];
+  
+  [_response appendContentString:@"\n//-->\n</script>"];
+  
+  /* link containing onMouseOver, onMouseOut and HREF */
+  [_response appendContentString:@"<a onmouseover=\"JSImageFlyover('"];
+  [_response appendContentString:elID];
+  [_response appendContentString:@"',1)\""];
+  [_response appendContentString:@" onmouseout=\"JSImageFlyover('"];
+  [_response appendContentString:elID];
+  [_response appendContentString:@"',0)\""];
+  [_response appendContentString:@" href=\""];
+  
+  if (self->javaScriptFunction) {
+    [_response appendContentString:@"javascript:"];
+    [_response appendContentHTMLAttributeValue:
+                 [self->javaScriptFunction stringValueInComponent:comp]];
+  }
+  else if (self->directActionName)
+    [self appendDirectActionURLToResponse:_response inContext:_ctx];
+  else /* component action */
+    [_response appendContentString:[_ctx componentActionURL]];
+  
+  [_response appendContentString:@"\" "];
+
+  if (self->targetWindow) {
+    [_response appendContentString:@" target=\""];
+    [_response appendContentHTMLAttributeValue:
+                 [self->targetWindow stringValueInComponent: comp]];
+    [_response appendContentString:@"\" "];
+  }
+  [_response appendContentString:@" >"];
+
+  /* image itself */
+  [_response appendContentString:@"<img border='0' src=\""];
+  [_response appendContentString:tunselected];
+  [_response appendContentString:@"\" name=\""];
+  [_response appendContentString:elID];
+  [_response appendContentString:@"\" "];
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  [_response appendContentString:@" />"];
+
+  /* close link */
+  [_response appendContentString:@"</a>"];
+}
+
+@end /* JSImageFlyover */
diff --git a/skyrix-sope/WOExtensions/JSKeyHandler.m b/skyrix-sope/WOExtensions/JSKeyHandler.m
new file mode 100644 (file)
index 0000000..555c325
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+  Copyright (C) 2000-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$
+
+/*
+  to be done ...
+
+  Usage:
+
+    KeyHandler: KSKeyHandler {
+      handleKeys = (
+        "<ctrl>@left",
+        "<ctrl><right>",
+        "<ctrl><shift>s"
+      );
+      
+      modifiers = clickedModifiers;
+      key       = clickedKey;
+      action    = doKeyAction;
+    }
+*/
+
+#import <NGObjWeb/WODynamicElement.h>
+
+@interface JSKeyHandler : WODynamicElement
+@end
+
+@implementation JSKeyHandler
+@end /* JSKeyHandler */
+
+/*
+<html>
+  <head><title>doof</title></head>
+  
+  <body>
+    Blah<br />
+
+    <form>
+       <input type="text" size="20" />
+    </form>
+
+    <script>
+      function keyDown() {
+       if (event.keyCode == 17) {
+         // ctrl
+       }
+       else if (event.keyCode == 18) {
+         // alt
+       }
+       else if (event.keyCode == 16) {
+         // shift
+       }
+       else {
+         if (event.shiftKey)
+           window.status += "_";
+         if (event.ctrlKey)
+           window.status += "^";
+         if (event.altKey)
+           window.status += "@";
+         if (event.keyCode == 37) {
+           window.status += "left,";
+           return false;
+         }
+         else if (event.keyCode == 39) {
+           window.status += "right,";
+           return false;
+         }
+         return true;
+
+         //window.status += "key:" + event.keyCode + "," + event.shiftKey;
+
+       alert("Modifiers: " + event.modifiers +
+             "\nALT:     " + event.altKey +
+             "\nCTRL:    " + event.ctrlKey +
+             "\nSHIFT:   " + event.shiftKey +
+             "\ntype:    " + event.type +
+             "\nkeyCode: " + event.keyCode +
+             "\nctrl-on: " + isCtrlOn +
+             "\nalt-on:  " + isAltOn
+       );
+
+       }
+      }
+      function keyUp() {
+       if (event.keyCode == 17) {
+         // ctrl
+       }
+       else if (event.keyCode == 18) {
+         // alt
+       }
+       else if (event.keyCode == 16) {
+         // shift
+       }
+       else {
+         // window.status += "-" + event.keyCode + ",";
+       }
+      }
+
+      function keyClicked() {
+       alert("Modifiers: " + event.modifiers +
+             "\nALT:     " + event.altKey +
+             "\nCTRL:    " + event.ctrlKey +
+             "\nSHIFT:   " + event.shiftKey +
+             "\ntype:    " + event.type +
+             "\nkeyCode: " + event.keyCode
+       );
+      }
+      var i = 0;
+      function ooverride() {
+         window.status = "" + i + "ooverride " + oldHandler.funcname;
+         i += 1;
+       return true;
+      }
+
+      function setHandler(name, func) {
+        oldHandler = document["on" + name];
+       if (oldHandler == func) {
+         window.status += "reset handler" + name;
+         return;
+        }
+       
+       document["on" + name] = func;
+       
+       if (oldHandler) {
+         func.oldHandler = oldHandler;
+         //window.status += "set old handler " + oldHandler;
+       }
+      }
+      
+      setHandler("keydown", keyDown);
+      setHandler("keyup",   keyUp);
+
+      setHandler("keydown", ooverride);
+      setHandler("keyup",   ooverride);
+      
+      //document.onkeypress=keyClicked;
+    </script>
+  </body>
+</html>
+*/
diff --git a/skyrix-sope/WOExtensions/JSModalWindow.m b/skyrix-sope/WOExtensions/JSModalWindow.m
new file mode 100644 (file)
index 0000000..3a0b632
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface JSModalWindow : WODynamicElement
+{
+  WOAssociation *action;
+  WOAssociation *pageName;
+  WOAssociation *href;      /* non - WO API */
+  
+  WOAssociation *height;
+  WOAssociation *width;
+  WOAssociation *windowName;
+  WOAssociation *isResizable;
+  WOAssociation *showLocation;
+  WOAssociation *showMenuBar;
+  WOAssociation *showScrollbars;
+  WOAssociation *showStatus;
+  WOAssociation *showToolbar;
+
+  /* non - WO API */
+  WOAssociation *top;
+  WOAssociation *left;
+  WOAssociation *isCenter;
+  WOAssociation *filename;
+  WOAssociation *string;
+  
+  WOElement     *template;
+}
+
+@end
+
+#include "common.h"
+
+@implementation JSModalWindow
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])){
+    int funcCount;
+
+    self->action             = WOExtGetProperty(_config, @"action");
+    self->pageName           = WOExtGetProperty(_config, @"pageName");
+    self->href               = WOExtGetProperty(_config, @"href");
+    
+    self->height             = WOExtGetProperty(_config, @"height");
+    self->width              = WOExtGetProperty(_config, @"width");
+    self->windowName         = WOExtGetProperty(_config, @"windowName");
+    self->isResizable        = WOExtGetProperty(_config, @"isResizable");
+    self->showLocation       = WOExtGetProperty(_config, @"showLocation");
+    self->showMenuBar        = WOExtGetProperty(_config, @"showMenuBar");
+    self->showScrollbars     = WOExtGetProperty(_config, @"showScrollbars");
+    self->showStatus         = WOExtGetProperty(_config, @"showStatus");
+    self->showToolbar        = WOExtGetProperty(_config, @"showToolbar");
+
+    self->top                = WOExtGetProperty(_config, @"top");
+    self->left               = WOExtGetProperty(_config, @"left");
+    self->isCenter           = WOExtGetProperty(_config, @"isCenter");
+    self->filename           = WOExtGetProperty(_config, @"filename");
+    self->string             = WOExtGetProperty(_config, @"string");
+
+    funcCount = 0;
+    if (self->action)   funcCount++;
+    if (self->pageName) funcCount++;
+    if (self->href)     funcCount++;
+
+    if (funcCount > 1)
+      NSLog(@"WARNING: JSModalWindow: choose only one of "
+            @"action | pageName | href");
+    if (funcCount < 1)
+      NSLog(@"WARNING: JSModalWindow: no function declared - choose one of"
+            @"action | pageName | href");
+
+#define SetAssociationValue(_assoc_, _value_)                               \
+             if (_assoc_ == nil) {                                          \
+               _assoc_ = [WOAssociation associationWithValue:_value_];      \
+               [_assoc_ retain];                                            \
+             }                                                              \
+
+    SetAssociationValue(self->height,         @"300");
+    SetAssociationValue(self->width,          @"300");
+    SetAssociationValue(self->isResizable,    @"Yes");
+    SetAssociationValue(self->showLocation,   @"Yes");
+    SetAssociationValue(self->showMenuBar,    @"Yes");
+    SetAssociationValue(self->showScrollbars, @"Yes");
+    SetAssociationValue(self->showStatus,     @"Yes");
+    SetAssociationValue(self->showToolbar,    @"Yes");
+    SetAssociationValue(self->top,            @"500");
+    SetAssociationValue(self->left,           @"500");
+
+#undef SetAssociationValue
+
+    self->template = RETAIN(_subs);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->action);
+  RELEASE(self->pageName);
+  RELEASE(self->href);
+  
+  RELEASE(self->height);
+  RELEASE(self->width);
+  RELEASE(self->windowName);
+  RELEASE(self->isResizable);
+  RELEASE(self->showLocation);
+  RELEASE(self->showMenuBar);
+  RELEASE(self->showScrollbars);
+  RELEASE(self->showStatus);
+  RELEASE(self->showToolbar);
+
+  RELEASE(self->top);
+  RELEASE(self->left);
+  RELEASE(self->isCenter);
+  RELEASE(self->filename);
+  RELEASE(self->string);
+  
+  RELEASE(self->template);
+  [super dealloc];
+}
+
+/* handling requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  [self->template takeValuesFromRequest:_rq inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if (self->pageName) {
+    NSString *name;
+    
+    name = [self->pageName stringValueInComponent: [_ctx component]];
+    return [[_ctx application] pageWithName:name inContext:_ctx];
+  }
+  
+  if (self->action)
+    return [self->action valueInComponent:[_ctx component]];
+
+  return [self->template invokeActionForRequest:_request inContext:_ctx];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_resp
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *comp;
+  NSString    *tmp;
+  NSArray     *languages;
+  
+  comp = [_ctx component];
+  
+  // link
+  [_resp appendContentString:
+             @"<a onclick=\"window.showModalDialog('"];
+  if (self->href)
+    [_resp appendContentString:[self->href stringValueInComponent:comp]];
+  else
+    [_resp appendContentString:@"http://www.ccc.de"];
+  
+  [_resp appendContentString:@"', 'a short text', '"];
+
+  /* configure modal panel */
+  if (self->height) {
+    [_resp appendContentString:@" dialogHeight: "];
+    [_resp appendContentString:[self->height stringValueInComponent:comp]];
+    [_resp appendContentString:@"px;"];
+  }
+  if (self->width) {
+    [_resp appendContentString:@" dialogWidth: "];
+    [_resp appendContentString:[self->width stringValueInComponent:comp]];
+    [_resp appendContentString:@"px;"];
+  }
+  if (self->top) {
+    [_resp appendContentString:@" dialogTop: "];
+    [_resp appendContentString:[self->top stringValueInComponent:comp]];
+    [_resp appendContentString:@"px;"];
+  }
+  if (self->left) {
+    [_resp appendContentString:@" dialogLeft: "];
+    [_resp appendContentString:[self->left stringValueInComponent:comp]];
+    [_resp appendContentString:@"px;"];
+  }
+  if (self->isResizable) {
+    [_resp appendContentString:@" resizable: "];
+    [_resp appendContentString:[self->isResizable stringValueInComponent:comp]];
+    [_resp appendContentCharacter:';'];
+  }
+  if (self->showStatus) {
+    [_resp appendContentString:@" status: "];
+    [_resp appendContentString:[self->showStatus stringValueInComponent:comp]];
+    [_resp appendContentCharacter:';'];
+  }
+  if (self->isCenter) {
+    [_resp appendContentString:@" center: "];
+    [_resp appendContentString:[self->isCenter stringValueInComponent:comp]];
+    [_resp appendContentCharacter:';'];
+  }
+
+  [_resp appendContentString:@"')\""];
+  
+  [_resp appendContentString:@" href=\""];
+  [_resp appendContentString:[_ctx componentActionURL]];
+  [_resp appendContentString:@"\" "];
+  
+  [self appendExtraAttributesToResponse:_resp inContext:_ctx];
+  [_resp appendContentString:@" >"];
+
+  // link content
+  if (self->filename) {
+    WOResourceManager *rm;
+
+    rm = [[_ctx application] resourceManager];
+    
+    languages = [_ctx hasSession]
+      ? [[_ctx session] languages]
+      : [[_ctx request] browserLanguages];
+    
+    tmp = [rm urlForResourceNamed:[self->filename stringValueInComponent:comp]
+              inFramework:[comp frameworkName]
+              languages:languages
+              request:[_ctx request]];
+    
+    [_resp appendContentString:@"<img border=\"0\" src=\""];
+    [_resp appendContentString:tmp];
+    [_resp appendContentString:@"\" "];
+    
+    [_resp appendContentString:@" />"];
+  }
+  [self->template appendToResponse:_resp inContext:_ctx];
+  if (self->string) 
+    [_resp appendContentString:[self->string stringValueInComponent:comp]];
+
+  /* close link */
+  [_resp appendContentString:@"</a>"];
+}
+
+@end /* JSModalWindow */
diff --git a/skyrix-sope/WOExtensions/JSTextFlyover.m b/skyrix-sope/WOExtensions/JSTextFlyover.m
new file mode 100644 (file)
index 0000000..b4b18b7
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface JSTextFlyover : WODynamicElement
+{
+  WOAssociation *action;
+  WOAssociation *pageName;
+  WOAssociation *selectedColor;
+  WOAssociation *unselectedColor;
+  WOAssociation *targetWindow;
+  /* additional, not in api */
+  WOAssociation *string;
+  
+  WOElement     *template;
+}
+
+@end
+
+#include "common.h"
+
+@implementation JSTextFlyover
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs])){
+    self->action             = WOExtGetProperty(_config,@"action");
+    self->pageName           = WOExtGetProperty(_config,@"pageName");
+    self->selectedColor      = WOExtGetProperty(_config,@"selectedColor");
+    self->unselectedColor    = WOExtGetProperty(_config,@"unselectedColor");
+    self->targetWindow       = WOExtGetProperty(_config,@"targetWindow");
+    self->string             = WOExtGetProperty(_config,@"string");
+    
+    if ((self->action) && (self->pageName)) 
+      NSLog(@"WARNING: JSTextFlyover: choose only one of "
+            @"action | pageName ");
+    if (!((self->action) || (self->pageName)))
+      NSLog(@"WARNING: JSTextFlyover: no function declared - choose one of"
+            @"action | pageName | javaScriptFunction");
+    if (!self->selectedColor)
+      NSLog(@"WARNING: JSTextFlyover: no value for 'selectedColor'");
+    if (!self->unselectedColor)
+      NSLog(@"WARNING: JSTextFlyover: no value for 'unselectedColor'");
+
+    self->template = [_subs retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->action          release];
+  [self->pageName        release];
+  [self->selectedColor   release];
+  [self->unselectedColor release];
+  [self->targetWindow    release];
+  [self->string          release];
+  [self->template        release];
+  [super dealloc];
+}
+
+/* processing requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  [self->template takeValuesFromRequest:_rq inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if (self->pageName) {
+    NSString *name;
+    
+    name = [self->pageName stringValueInComponent: [_ctx component]];
+    return [[_ctx application] pageWithName:name inContext:_ctx];
+  }
+  if (self->action)
+    return [self->action valueInComponent:[_ctx component]];
+
+  return [self->template invokeActionForRequest:_request inContext:_ctx];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  WOComponent *comp;
+  NSString    *tmp;
+  NSString    *userAgent;
+  NSString    *normalColor;
+  NSString    *rollColor;
+  NSString    *obj;
+  NSRange     r;
+  
+  comp        = [_ctx component];
+  userAgent   = [[_ctx request] headerForKey:@"user-agent"];
+  normalColor = [self->unselectedColor stringValueInComponent:comp];
+  rollColor   = [self->selectedColor   stringValueInComponent:comp];
+  
+  /* link containing onMouseOver, onMouseOut, STYLE and HREF */
+  r = [userAgent rangeOfString: @"MSIE"];
+  obj = (r.length == 0)
+    ? @"this.textcolor"
+    : @"this.style.color";
+  [_response appendContentString:@"<a onmouseover=\""];
+  tmp = [[NSString alloc] initWithFormat:@"%@='%@'",obj,rollColor];
+  [_response appendContentString:tmp];
+  [tmp release];
+  [_response appendContentString:@"\" onmouseout=\""];
+  tmp = [[NSString alloc] initWithFormat:@"%@='%@'",obj,normalColor];
+  [_response appendContentString:tmp];
+  [tmp release];
+
+  [_response appendContentString:@"\" style=\"color: "];
+  [_response appendContentString:normalColor];
+  [_response appendContentString:@"\" "];
+
+  [_response appendContentString:@" href=\""];
+  [_response appendContentString:[_ctx componentActionURL]];
+  [_response appendContentString:@"\" "];
+
+  if (self->targetWindow) {
+    [_response appendContentString:@" target=\""];
+    [_response appendContentHTMLAttributeValue:
+                 [self->targetWindow stringValueInComponent: comp]];
+    [_response appendContentString:@"\" "];
+  }
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  [_response appendContentString:@" >"];
+
+  /* text itself */
+  [self->template appendToResponse:_response inContext:_ctx];
+  if (self->string)
+    [_response appendContentString:[self->string stringValueInComponent:comp]];
+
+  /* close link */
+  [_response appendContentString:@"</a>"];
+}
+
+@end /* JSTextFlyover */
diff --git a/skyrix-sope/WOExtensions/JSValidatedField.m b/skyrix-sope/WOExtensions/JSValidatedField.m
new file mode 100644 (file)
index 0000000..fcc616e
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface JSValidatedField : WODynamicElement
+{
+  WOAssociation *inputText;
+  WOAssociation *errorMessage;
+  WOAssociation *formName;
+  WOAssociation *fieldSize;
+  WOAssociation *inputIsRequired;
+  WOAssociation *requiredText;
+
+  WOElement     *template;
+}
+@end
+
+#include "common.h"
+
+@implementation JSValidatedField
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_subs
+{
+  if ((self = [super initWithName:_name associations:_config template:_subs]))
+  {
+    self->inputText       = WOExtGetProperty(_config,@"inputText");
+    self->errorMessage    = WOExtGetProperty(_config,@"errorMessage");
+    self->formName        = WOExtGetProperty(_config,@"formName");
+    self->fieldSize       = WOExtGetProperty(_config,@"fieldSize");
+    self->inputIsRequired = WOExtGetProperty(_config,@"inputIsRequired");
+    self->requiredText    = WOExtGetProperty(_config,@"requiredText");
+
+    if (!self->inputText)
+      NSLog(@"WARNING: JSValidatedField: 'inputText' not bound.");
+    if (!self->errorMessage)
+      NSLog(@"WARNING: JSValidatedField: 'errorMessage' not bound, "
+            @"using default.");
+    if (!self->formName)
+      NSLog(@"ERROR: JSValidatedField: 'formName' not bound.");
+
+    self->template = RETAIN(_subs);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->inputText);
+  RELEASE(self->errorMessage);
+  RELEASE(self->fieldSize);
+  RELEASE(self->inputIsRequired);
+  RELEASE(self->requiredText);
+  RELEASE(self->template);
+  [super dealloc];
+}
+
+/* operations */
+
+- (NSString *)buildJSSaveID:(NSString *)_id {
+  NSArray *ta;
+
+  ta = [[NSArray alloc] initWithArray: [_id componentsSeparatedByString:@"."]];
+  _id = [ta componentsJoinedByString:@"x"];
+  [ta release];
+  return _id;
+}
+
+/* processing requests */
+
+- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  id       formValue;
+  NSString *elID;
+
+  elID = [self buildJSSaveID:[_ctx elementID]];
+  
+  if ((formValue = [_rq formValueForKey:elID])) {
+    if ([self->inputText isValueSettable])
+      [self->inputText setValue: formValue inComponent:[_ctx component]];
+  }
+
+  [self->template takeValuesFromRequest:_rq inContext:_ctx];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
+  return [self->template invokeActionForRequest:_rq inContext:_ctx];
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  NSString    *elID;
+  WOComponent *comp;
+  NSString    *tmp;
+  int         objectsCount;
+  NSString    *terrMesg, *tformName, *tinput, *ttext;
+  NSString    *s;
+
+  comp = [_ctx component];
+  elID = [self buildJSSaveID:[_ctx elementID]];
+
+  terrMesg = (self->errorMessage)
+    ? [self->errorMessage stringValueInComponent:comp]
+    : @"Invalid values.";
+  tformName = [self->formName stringValueInComponent:comp];
+  tinput = ([self->inputIsRequired boolValueInComponent:comp])
+    ? @"true"
+    : @"false";
+  ttext = (self->requiredText)
+    ? [NSString stringWithFormat:@"\"%@\"",
+                  [self->requiredText stringValueInComponent:comp]]
+    : @"false";
+
+  
+  /* script */
+  [_response appendContentString:@"<script language=\"JavaScript\">\n<!--\n"];
+
+  if (!((objectsCount =
+         [[_ctx valueForKey:@"JSValidatedFieldCounter"] intValue]))) {
+    objectsCount = 0;
+
+    tmp = @"var JSVFtestedObjects = new Array();\n"
+          @"function JSValidatedFieldCheckValues() {\n"
+          @"  for (var i = 0; i < JSVFtestedObjects.length; i++) {\n"
+          @"    tform  = JSVFtestedObjects[i][\"form\"];\n"
+          @"    tname  = JSVFtestedObjects[i][\"name\"];\n"
+          @"    tinput = JSVFtestedObjects[i][\"inputIsRequired\"];\n"
+          @"    ttext  = JSVFtestedObjects[i][\"requiredText\"];\n"
+          @"    tmesg  = JSVFtestedObjects[i][\"errorMessage\"];\n"
+          @"    obj = document.forms[tform].elements[tname];\n"
+          @"    if (((tinput) && (obj.value == \"\")) || \n"
+          @"        ((ttext)  && (obj.value.indexOf(ttext) == -1))) {\n"
+          @"      alert(tmesg);\n"
+          @"      obj.focus();\n"
+          @"      return false;\n"
+          @"    }\n"
+          @"  }\n"
+          @"  return true;\n"
+          @"}\n";
+
+    [_response appendContentString:tmp];
+  }
+  
+  tmp = @"JSVFtestedObjects[%i] = new Array();\n"
+        @"JSVFtestedObjects[%i][\"name\"]            = \"%@\";\n"
+        @"JSVFtestedObjects[%i][\"form\"]            = \"%@\";\n"
+        @"JSVFtestedObjects[%i][\"inputIsRequired\"] = %@;\n"
+        @"JSVFtestedObjects[%i][\"requiredText\"]    = %@;\n"
+        @"JSVFtestedObjects[%i][\"errorMessage\"]    = \"%@\";\n"
+        @"document.%@.onsubmit = JSValidatedFieldCheckValues;\n";
+  
+  s = [[NSString alloc] initWithFormat:tmp,
+                                              objectsCount,
+                                              objectsCount, elID,
+                                              objectsCount, tformName,
+                                              objectsCount, tinput,
+                                              objectsCount, ttext,
+                                              objectsCount, terrMesg,
+                tformName];
+  [_response appendContentString:s];
+  [s release];
+  
+  [_ctx takeValue:[NSNumber numberWithInt:(objectsCount + 1)]
+        forKey:@"JSValidatedFieldCounter"];
+  [_response appendContentString:@"\n//-->\n</script>"];
+
+  /* input element */
+  
+  [_response appendContentString:@"<input type=\"text\" name=\""];
+  [_response appendContentString:elID];
+  [_response appendContentString:@"\" value=\""];
+  [_response appendContentHTMLAttributeValue:
+               [self->inputText stringValueInComponent:comp]];
+  [_response appendContentString:@"\""];
+  if (self->fieldSize) {
+    [_response appendContentString:@" size=\""];
+    [_response appendContentString:
+                 [self->fieldSize stringValueInComponent:comp]];
+    [_response appendContentString:@"\""];
+  }
+  [_response appendContentString:@" />"];
+}
+
+@end /* JSValidatedField */
diff --git a/skyrix-sope/WOExtensions/Version b/skyrix-sope/WOExtensions/Version
new file mode 100644 (file)
index 0000000..cc039ac
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=14
diff --git a/skyrix-sope/WOExtensions/WOCheckBoxMatrix.m b/skyrix-sope/WOExtensions/WOCheckBoxMatrix.m
new file mode 100644 (file)
index 0000000..634699d
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WOCheckBoxMatrix : WODynamicElement
+{
+  // WODynamicElement: extraAttributes (are appended at the main table)
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *list;       // array of objects to iterate through
+  WOAssociation *item;       // current item in the array
+  WOAssociation *selections; // selected objects
+  WOAssociation *maxColumns; // number of columns
+  
+  /* non WO attribute */
+  WOAssociation *index;      // current index
+  WOAssociation *col;        // current column (is updated with each iteration)
+  WOAssociation *row;        // current row    (is updated with each iteration)
+
+  WOAssociation *cellAlign;  // current cell align
+  WOAssociation *cellVAlign; // current cell valign
+  WOAssociation *rowBackgroundColor;  // current row background color;
+  WOAssociation *cellBackgroundColor; // current cell background color;
+  WOAssociation *horizontal;   // order items horizontal (default = NO)
+
+  WOElement     *template;
+}
+@end
+
+#include "common.h"
+
+@implementation WOCheckBoxMatrix
+
+static NSString *retStrForInt(int i) {
+  switch(i) {
+  case 0:  return @"0";
+  case 1:  return @"1";
+  case 2:  return @"2";
+  case 3:  return @"3";
+  case 4:  return @"4";
+  case 5:  return @"5";
+  case 6:  return @"6";
+  case 7:  return @"7";
+  case 8:  return @"8";
+  case 9:  return @"9";
+  case 10: return @"10";
+    // TODO: find useful count!
+  default:
+    return [[NSString alloc] initWithFormat:@"%i", i];
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->list       = WOExtGetProperty(_config, @"list");
+    self->item       = WOExtGetProperty(_config, @"item");
+    self->selections = WOExtGetProperty(_config, @"selections");
+    self->maxColumns = WOExtGetProperty(_config, @"maxColumns");
+    
+    self->index      = WOExtGetProperty(_config, @"index");
+    self->col        = WOExtGetProperty(_config, @"col");
+    self->row        = WOExtGetProperty(_config, @"row");
+    self->horizontal = WOExtGetProperty(_config, @"horizontal");
+
+    self->cellAlign  = WOExtGetProperty(_config, @"cellAlign");
+    self->cellVAlign = WOExtGetProperty(_config, @"cellVAlign");
+    self->rowBackgroundColor  = 
+      WOExtGetProperty(_config, @"rowBackgroundColor");
+    self->cellBackgroundColor = 
+      WOExtGetProperty(_config, @"cellBackgroundColor");
+
+    self->template = RETAIN(_c);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->template);
+  
+  RELEASE(self->list);
+  RELEASE(self->item);
+  RELEASE(self->maxColumns);
+  RELEASE(self->selections);
+  
+  RELEASE(self->index);
+  RELEASE(self->col);
+  RELEASE(self->row);
+  RELEASE(self->horizontal);
+
+  RELEASE(self->cellAlign);
+  RELEASE(self->cellVAlign);
+  RELEASE(self->rowBackgroundColor);
+  RELEASE(self->cellBackgroundColor);
+  [super dealloc];
+}
+
+/* request handling */
+
+static inline
+void _applyIndex(WOCheckBoxMatrix *self, WOComponent *cmp, unsigned _idx)
+{
+  NSArray  *array;
+  BOOL     isHor;
+  unsigned r, c, cnt, cols;
+
+  isHor = [self->horizontal boolValueInComponent:cmp];
+  cols  = [self->maxColumns unsignedIntValueInComponent:cmp];
+  array = [self->list valueInComponent:cmp];
+  cnt   = [array count];
+  cols  = (cols) ? cols : 1;
+  r     = (isHor) ? (_idx / cols) + 1 : _idx % ((cnt / cols)+1) + 1;
+  c     = (isHor) ? (_idx % cols) + 1 : _idx / ((cnt / cols)+1) + 1;
+    
+  if ([self->index isValueSettable])
+    [self->index setUnsignedIntValue:_idx inComponent:cmp];
+
+  if ([self->row isValueSettable])
+    [self->row setUnsignedIntValue:r inComponent:cmp];
+
+  if ([self->col isValueSettable])
+    [self->col setUnsignedIntValue:c inComponent:cmp];
+
+  if ([self->item isValueSettable]) {
+    if (_idx < cnt)
+      [self->item setValue:[array objectAtIndex:_idx] inComponent:cmp];
+    else {
+      [cmp logWithFormat:
+           @"WOCheckBoxMatrix: array did change, index is invalid."];
+      [self->item setValue:nil inComponent:cmp];
+    }
+  }
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSArray     *array;
+  NSArray     *selArray = nil;
+  unsigned    cnt, i;
+
+  cmp   = [_ctx component];
+  array = [self->list valueInComponent:cmp];
+  cnt   = [array count];
+
+  if (cnt) {
+    NSMutableArray *newSelection = nil;
+
+    if (self->selections)
+        newSelection = [[NSMutableArray alloc] initWithCapacity:cnt];
+  
+    [_ctx appendZeroElementIDComponent];
+    for (i = 0; i < cnt; i++) {
+      id formValue = nil;
+      id obj       = nil;
+      
+      _applyIndex(self, cmp, i);
+      [self->template takeValuesFromRequest:_req inContext:_ctx];
+
+      if ((formValue = [_req formValueForKey:[_ctx elementID]])) {
+        NSString *s;
+
+        s = retStrForInt(i);
+        if ([formValue isEqualToString:s]) {
+          if ((obj = [self->item valueInComponent:cmp]) && (newSelection))
+            [newSelection addObject:obj];
+        }
+        [s release];
+      }
+      [_ctx incrementLastElementIDComponent];
+    }
+    [_ctx deleteLastElementIDComponent];
+
+    if (self->selections) {
+      selArray = [newSelection copy];
+      [newSelection release];
+    }
+  }
+  else
+    selArray = [[NSArray alloc] init];
+
+  if ([self->selections isValueSettable])
+    [self->selections setValue:selArray inComponent:cmp];
+
+  [selArray release];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  id          result = nil;
+  unsigned    idx;
+  NSString    *s;
+
+  cmp = [_ctx component];
+  if ([self->list valueInComponent:cmp] == nil)
+    return nil;
+  
+  idx = [[_ctx currentElementID] intValue];
+  [_ctx consumeElementID]; // consume index
+  s = retStrForInt(idx);
+  [_ctx appendElementIDComponent:s];
+  [s release];
+  _applyIndex(self, cmp, idx);
+  result = [self->template invokeActionForRequest:_req inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  return result;
+}
+
+/* generating response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSArray     *array;
+  NSArray     *selArray;
+  BOOL        isHor;       // is horizontal
+  unsigned    c, colCount; // column index
+  unsigned    r, rowCount; // row    index
+  unsigned    cnt;
+
+  cmp      = [_ctx component];
+  colCount = [self->maxColumns unsignedIntValueInComponent:cmp];
+  array    = [self->list valueInComponent:cmp];
+  cnt      = [array count];
+  isHor    = [self->horizontal boolValueInComponent:cmp];
+  selArray = [self->selections valueInComponent:cmp];
+
+  colCount = (colCount) ? colCount : 1;
+  rowCount = ((cnt % colCount) > 0) ? (cnt / colCount) + 1 : (cnt / colCount);
+
+  [_response appendContentString:@"<table "];
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  [_response appendContentCharacter:'>'];
+
+  for (r = 0; r < rowCount; r++) {
+    NSString *rowColor;
+    
+    rowColor = [self->rowBackgroundColor stringValueInComponent:cmp];
+    [_response appendContentString:@"<tr"];
+    if (rowColor) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:rowColor];
+      [_response appendContentCharacter:'"'];
+    }
+    [_response appendContentCharacter:'>'];
+    
+    for (c = 0; c < colCount; c++) {
+      NSString *cColor, *align, *valign;
+      unsigned i;
+      
+      cColor = [self->cellBackgroundColor stringValueInComponent:cmp];
+      align  = [self->cellAlign  stringValueInComponent:cmp];
+      valign = [self->cellVAlign stringValueInComponent:cmp];
+      i = (isHor) ? (r * colCount + c) : (c * rowCount + r);
+      
+      [_response appendContentString:@"<td"];
+      if (cColor) {
+        [_response appendContentString:@" bgcolor=\""];
+        [_response appendContentString:cColor];
+        [_response appendContentCharacter:'"'];
+      }
+      if (align) {
+        [_response appendContentString:@" align=\""];
+        [_response appendContentString:align];
+        [_response appendContentCharacter:'"'];
+      }
+      if (valign) {
+        [_response appendContentString:@" valign=\""];
+        [_response appendContentString:valign];
+        [_response appendContentCharacter:'"'];
+      }
+      [_response appendContentCharacter:'>'];
+      
+      if (i < cnt) {
+        NSString *s;
+        id obj;
+        
+        s = retStrForInt(i);
+        [_ctx appendElementIDComponent:s];
+        [s release];
+        _applyIndex(self, cmp, i);
+        obj = [self->item valueInComponent:cmp];
+
+        // append check box
+        [_response appendContentString:@"<input type=\"checkbox\" name=\""];
+        [_response appendContentHTMLAttributeValue:[_ctx elementID]];
+        [_response appendContentString:@"\" value=\""];
+        s = retStrForInt(i);
+        [_response appendContentString:s];
+        [s release];
+        [_response appendContentCharacter:'"'];
+  
+        if ([selArray containsObject:obj])
+         [_response appendContentString:@" checked=\"checked\""];
+        
+        [_response appendContentString:@" />"];
+
+        /* append template */
+        [self->template appendToResponse:_response inContext:_ctx];
+        [_ctx deleteLastElementIDComponent];
+      }
+      else
+        [_response appendContentString:@"&nbsp;"];
+      [_response appendContentString:@"</td>"];
+    }
+    [_response appendContentString:@"</tr>"];
+  }
+  [_response appendContentString:@"</table>"];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:128];
+  if (self->list)       [str appendFormat:@" list=%@",       self->list];
+  if (self->item)       [str appendFormat:@" item=%@",       self->item];
+  if (self->maxColumns) [str appendFormat:@" maxColumns=%@", self->maxColumns];
+  if (self->selections) [str appendFormat:@" selections=%@", self->selections];
+  if (self->index)      [str appendFormat:@" index=%@",      self->index];
+  if (self->col)        [str appendFormat:@" col=%@",        self->col];
+  if (self->row)        [str appendFormat:@" row=%@",        self->row];
+  if (self->horizontal) [str appendFormat:@" horizontal=%@", self->horizontal];
+  if (self->template)   [str appendFormat:@" template=%@",   self->template];
+
+  return str;
+}
+
+@end /* WOCheckBoxMatrix */
diff --git a/skyrix-sope/WOExtensions/WOCollapsibleComponentContent.m b/skyrix-sope/WOExtensions/WOCollapsibleComponentContent.m
new file mode 100644 (file)
index 0000000..f317c8f
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/NGObjWeb.h>
+#include "common.h"
+
+@interface WOCollapsibleComponentContent : WODynamicElement
+{
+@protected
+  WOAssociation *condition;
+  WOAssociation *visibility;
+  WOAssociation *openedImageFileName;
+  WOAssociation *closedImageFileName;
+  WOAssociation *framework;
+  WOAssociation *openedLabel;
+  WOAssociation *closedLabel;
+  WOAssociation *submitActionName;
+
+  WOElement *template;
+}
+@end
+
+@interface WOContext(WOExtensionsPrivate)
+- (void)addActiveFormElement:(WOElement *)_element;
+@end
+
+@implementation WOCollapsibleComponentContent
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_temp
+{
+  if ((self = [super initWithName:_name associations:_config template:_temp])) {
+    self->condition           = WOExtGetProperty(_config, @"condition");
+    self->visibility          = WOExtGetProperty(_config, @"visibility");
+    self->openedImageFileName = 
+      WOExtGetProperty(_config, @"openedImageFileName");
+    self->closedImageFileName = 
+      WOExtGetProperty(_config, @"closedImageFileName");
+    self->framework           = WOExtGetProperty(_config, @"framework");
+    self->openedLabel         = WOExtGetProperty(_config, @"openedLabel");
+    self->closedLabel         = WOExtGetProperty(_config, @"closedLabel");
+    self->submitActionName    = WOExtGetProperty(_config, @"submitActionName");
+
+    if (WOExtGetProperty(_config, @"condition"))
+      NSLog(@"WARNING: WOCollapsibleComponent does not support 'condition'");
+
+    if (self->visibility == nil)
+      NSLog(@"WARNING: WOCollapsibleComponent 'visibility' not set");
+
+    if (self->visibility && ![self->visibility isValueSettable])
+      NSLog(@"WARNING: WOCollapsibleComponent 'visibility' is not settable");
+
+    ASSIGN(self->template, _temp);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->condition);
+  RELEASE(self->visibility);
+  RELEASE(self->openedImageFileName);
+  RELEASE(self->closedImageFileName);
+  RELEASE(self->framework);
+  RELEASE(self->openedLabel);
+  RELEASE(self->closedLabel);
+  RELEASE(self->submitActionName);
+
+  RELEASE(self->template);
+  
+  [super dealloc];
+}
+
+// responder
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  NSString *eid;
+
+  eid = [_ctx elementID];
+
+  if ([self->visibility boolValueInComponent:[_ctx component]]) {
+    [_ctx appendZeroElementIDComponent];
+    [self->template takeValuesFromRequest:_request inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+  
+  if ([_request formValueForKey:[eid stringByAppendingString:@".c.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:[[_ctx senderID] stringByAppendingString:@".c"]];
+  }
+  else if ([_request formValueForKey:[eid stringByAppendingString:@".e.x"]]) {
+    [_ctx addActiveFormElement:self];
+    [_ctx setRequestSenderID:[[_ctx senderID] stringByAppendingString:@".e"]];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  NSString *state;
+  NSString *eid;
+
+  state = [[_ctx currentElementID] stringValue];
+
+  eid = [_ctx elementID];
+
+  if (state) {
+    BOOL doForm;
+    
+    [_ctx consumeElementID]; // consume state-id (on or off)
+
+    doForm = ([_ctx isInForm] && self->submitActionName);
+    
+    if ([state isEqualToString:@"e"]) {
+      if ([self->visibility isValueSettable])
+        [self->visibility setBoolValue:NO inComponent:[_ctx component]];
+      if (doForm)
+        [self->submitActionName valueInComponent:[_ctx component]];
+    }
+    else if ([state isEqualToString:@"c"]) {
+      if ([self->visibility isValueSettable])
+        [self->visibility setBoolValue:YES inComponent:[_ctx component]];
+      if (doForm)
+        [self->submitActionName valueInComponent:[_ctx component]];
+    }
+    else {
+      id result;
+      
+      [_ctx appendElementIDComponent:state];
+      result = [self->template invokeActionForRequest:_request inContext:_ctx];
+      [_ctx deleteLastElementIDComponent];
+
+      return result;
+    }
+  }
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  BOOL        isCollapsed;
+  BOOL        doForm;
+  WOComponent *comp;
+  NSString    *img;
+  NSString    *label;
+  
+  comp = [_ctx component];
+
+  if ([self->visibility valueInComponent:comp] == nil) {
+    isCollapsed = ![self->condition boolValueInComponent:comp];
+    if ([self->visibility isValueSettable])
+      [self->visibility setBoolValue:!isCollapsed inComponent:comp];
+  }
+  else
+    isCollapsed = ![self->visibility boolValueInComponent:comp];
+
+  img = (isCollapsed)
+    ? [self->closedImageFileName stringValueInComponent:comp]
+    : [self->openedImageFileName stringValueInComponent:comp];
+
+  label = (isCollapsed)
+    ? [self->closedLabel stringValueInComponent:comp]
+    : [self->openedLabel stringValueInComponent:comp];
+
+  img = WOUriOfResource(img, _ctx);
+  
+  if (isCollapsed)
+    [_resp appendContentString:@"&nbsp;"];
+
+  doForm = ([_ctx isInForm] && self->submitActionName && img);
+
+  [_ctx appendElementIDComponent:(isCollapsed) ? @"c" : @"e"];
+  if (doForm) {
+    [_resp appendContentString:@"<INPUT TYPE=\"image\" BORDER=\"0\" NAME=\""];
+    [_resp appendContentString:[_ctx elementID]];
+    [_resp appendContentString:@"\" SRC=\""];
+    [_resp appendContentString:img];
+    [_resp appendContentString:@"\">"];
+  }
+  else {
+    [_resp appendContentString:@"<A HREF=\""];
+    [_resp appendContentString:[_ctx componentActionURL]];
+    [_resp appendContentString:@"\">"];
+
+    if (img) {
+      [_resp appendContentString:@"<IMG BORDER=0 SRC=\""];
+      [_resp appendContentString:img];
+      [_resp appendContentString:@"\""];
+      if (label) {
+        [_resp appendContentString:@" NAME=\""];
+        [_resp appendContentString:label];
+        [_resp appendContentString:@"\""];
+      }
+      [_resp appendContentString:@">"];
+    }
+    else
+      [_resp appendContentString:(isCollapsed) ? @"[+]" : @"[-]"];
+    [_resp appendContentString:@"</A>&nbsp;"];
+  }
+  
+  if (label) {
+    if (!doForm) {
+      [_resp appendContentString:@"<A HREF=\""];
+      [_resp appendContentString:[_ctx componentActionURL]];
+      [_resp appendContentString:@"\">"];
+    }
+    
+    [_resp appendContentString:label];
+
+    if (!doForm)
+      [_resp appendContentString:@"</A>"];
+  }
+  [_ctx deleteLastElementIDComponent];
+  
+  [_resp appendContentString:@"<BR>"];
+  
+  if (!isCollapsed) {
+    [_ctx appendZeroElementIDComponent];
+    [self->template appendToResponse:_resp inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+}
+
+@end /* WOComponentContent */
diff --git a/skyrix-sope/WOExtensions/WODictionaryRepetition.m b/skyrix-sope/WOExtensions/WODictionaryRepetition.m
new file mode 100644 (file)
index 0000000..1f8fd7f
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/NGObjWeb.h>
+
+@interface WODictionaryRepetition : WODynamicElement
+{
+@protected
+  WOAssociation *dictionary;
+  WOAssociation *key;
+  WOAssociation *item;
+
+  WOElement *template;
+}
+@end
+
+#include "common.h"
+
+/* TODO: the implementation does not work with keys that contain a dot! */
+
+@implementation WODictionaryRepetition
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_temp
+{
+  if ((self = [super initWithName:_name associations:_config template:_temp])) {
+    self->dictionary = WOExtGetProperty(_config, @"dictionary");
+    self->key        = WOExtGetProperty(_config, @"key");
+    self->item       = WOExtGetProperty(_config, @"item");
+
+    self->template = [_temp retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->dictionary release];
+  [self->key        release];
+  [self->item       release];
+  [self->template   release];
+  [super dealloc];
+}
+
+- (NSString *)unescapeKey:(NSString *)_key {
+  return _key;
+}
+- (NSString *)escapeKey:(NSString *)_key {
+  if ([_key rangeOfString:@"."].length == 0)
+    return _key;
+  
+  NSLog(@"WARNING(%s): key '%@' can't be processed by "
+        @"WODictionaryRepetition !!",
+        __PRETTY_FUNCTION__, _key);
+  return _key;
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent  *comp;
+  NSDictionary *dict;
+  NSEnumerator *keyEnum;
+  NSString     *k;
+  BOOL         isMutable;
+  id           obj;
+  
+  comp    = [_ctx component];
+  dict    = [self->dictionary valueInComponent:comp];
+  keyEnum = [dict keyEnumerator];
+
+  isMutable = [dict isKindOfClass:[NSMutableDictionary class]];
+
+#if 0
+  if (!isMutable) {
+    NSLog(@"WARNING: WODictionaryRepetition: 'dictionary' is immutable."
+          @" Cannot change values.");
+  }
+#endif
+  
+  while ((k = [keyEnum nextObject])) {
+    
+    if ([self->key isValueSettable])
+      [self->key setValue:k inComponent:comp];
+    
+    [_ctx appendElementIDComponent:[self escapeKey:k]];
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+
+    if (isMutable) {
+      obj = [self->item valueInComponent:comp];
+      if (obj) {
+        [(NSMutableDictionary *)dict setObject:obj forKey:k];
+      }
+      else
+        NSLog(@"WARNING: WODictionaryRepetition: nil object forKey: '%@'", k);
+    }
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent  *comp;
+  NSDictionary *dict;
+  NSString     *k;
+  id           obj;
+  id           result = nil;
+
+  comp = [_ctx component];
+  dict = [self->dictionary valueInComponent:comp];
+  k    = [self unescapeKey:[_ctx currentElementID]];
+  
+  if (k) {
+    if ((obj = [dict objectForKey:k])) {
+      if ([self->item isValueSettable])
+        [self->item setValue:obj inComponent:comp];
+      if ([self->key isValueSettable])
+        [self->key setStringValue:k inComponent:comp];
+
+      [_ctx consumeElementID]; // consume k
+
+      [_ctx appendElementIDComponent:k];
+      result = [self->template invokeActionForRequest:_req inContext:_ctx];
+      [_ctx deleteLastElementIDComponent];
+    }
+    else 
+      NSLog(@"WARNING: WODictionaryRepetition nil object for key:'%@'", k);
+  }
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  WOComponent  *comp;
+  NSDictionary *dict;
+  NSEnumerator *keyEnum;
+  NSString     *k;
+
+  comp = [_ctx component];
+  dict = [self->dictionary valueInComponent:comp];
+  
+  keyEnum = [dict keyEnumerator];
+  
+  while ((k = [keyEnum nextObject])) {
+    if ([self->item isValueSettable])
+      [self->item setValue:[dict objectForKey:k] inComponent:comp];
+    if ([self->key isValueSettable])
+      [self->key setStringValue:k inComponent:comp];
+    
+    [_ctx appendElementIDComponent:[self escapeKey:k]];
+    [self->template appendToResponse:_resp inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+}
+  
+@end /* WODictionaryRepetition */
diff --git a/skyrix-sope/WOExtensions/WOExtensions-Info.plist b/skyrix-sope/WOExtensions/WOExtensions-Info.plist
new file mode 100644 (file)
index 0000000..2c7b198
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>WOExtensions</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.WOExtensions</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/WOExtensions/WOExtensions.h b/skyrix-sope/WOExtensions/WOExtensions.h
new file mode 100644 (file)
index 0000000..a07d6de
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOExtensions_H__
+#define __WOExtensions_H__
+
+#include <WOExtensions/WORedirect.h>
+
+#endif /* __WOExtensions_H__ */
diff --git a/skyrix-sope/WOExtensions/WOKeyValueConditional.m b/skyrix-sope/WOExtensions/WOKeyValueConditional.m
new file mode 100644 (file)
index 0000000..86e7dcb
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WOKeyValueConditional : WODynamicElement
+{
+@protected
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+  
+  WOAssociation *key;
+  WOAssociation *value;
+  WOElement     *template;
+}
+
+@end /* WOKeyValueConditional */
+
+#include "common.h"
+
+@implementation WOKeyValueConditional
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->key   = WOExtGetProperty(_config, @"key");
+    self->value = WOExtGetProperty(_config, @"value");
+    
+    self->template = RETAIN(_c);
+  }
+  return self;
+}
+
+#if !LIB_FOUNDATION_BOEHM_GC
+- (void)dealloc {
+  RELEASE(self->template);
+  RELEASE(self->value);
+  RELEASE(self->key);
+  [super dealloc];
+}
+#endif
+
+// accessors
+
+- (WOElement *)template {
+  return self->template;
+}
+
+// state
+
+static inline BOOL _doShow(WOKeyValueConditional *self, WOContext *_ctx) {
+  WOComponent *c;
+  BOOL doShow   = NO;
+  BOOL doNegate = NO;
+  id   v, kv;
+  NSString *k;
+
+  c = [_ctx component];
+
+  k  = [self->key   stringValueInComponent:c];
+  v  = [self->value valueInComponent:c];
+  kv = [c valueForKey:k];
+  
+  doShow = [kv isEqual:v];
+  
+  return doNegate ? !doShow : doShow;
+}
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if (_doShow(self, _ctx)) {
+    [_ctx appendElementIDComponent:@"1"];
+    [self->template takeValuesFromRequest:_request inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+#if 0
+  else {
+    NSLog(@"didn't take value from request: %@\n  doShow=%@\n  doNegate=%@",
+          [self elementID],
+          self->condition, self->negate);
+  }
+#endif
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  NSString *state;
+
+  state = [[_ctx currentElementID] stringValue];
+  
+  if (state) {
+    [_ctx consumeElementID]; // consume state-id (on or off)
+
+    if ([state isEqualToString:@"1"]) {
+      id result;
+      
+      [_ctx appendElementIDComponent:state];
+      result = [self->template invokeActionForRequest:_request inContext:_ctx];
+      [_ctx deleteLastElementIDComponent];
+
+      return result;
+    }
+  }
+  return nil;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (_doShow(self, _ctx)) {
+    [_ctx appendElementIDComponent:@"1"];
+    [self->template appendToResponse:_response inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str = [[NSMutableString alloc] init];
+
+  if (self->key)      [str appendFormat:@" key=%@",      self->key];
+  if (self->value)    [str appendFormat:@" value=%@",    self->value];
+  if (self->template) [str appendFormat:@" template=%@", self->template];
+  
+  return AUTORELEASE(str);
+}
+
+@end /* WOKeyValueConditional */
diff --git a/skyrix-sope/WOExtensions/WORadioButtonMatrix.m b/skyrix-sope/WOExtensions/WORadioButtonMatrix.m
new file mode 100644 (file)
index 0000000..4d2e6db
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WORadioButtonMatrix : WODynamicElement
+{
+  // WODynamicElement: extraAttributes (are appended at the main table)
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *list;       // array of objects to iterate through
+  WOAssociation *item;       // current item in the array
+  WOAssociation *selection;  // selected object
+  WOAssociation *maxColumns; // number of columns
+  
+  /* non WO attribute */
+  WOAssociation *index;      // current index
+  WOAssociation *col;        // current column (is updated with each iteration)
+  WOAssociation *row;        // current row    (is updated with each iteration)
+
+  WOAssociation *cellAlign;  // current cell align
+  WOAssociation *cellVAlign; // current cell valign
+  WOAssociation *rowBackgroundColor;  // current row background color;
+  WOAssociation *cellBackgroundColor; // current cell background color;
+  WOAssociation *horizontal;   // order items horizontal (default = NO)
+
+  WOElement     *template;
+}
+@end
+
+#include "common.h"
+
+// TODO: this shares a lot of common code with WOCheckBoxMatrix!!
+
+@implementation WORadioButtonMatrix
+
+static NSString *retStrForInt(int i) {
+  switch(i) {
+  case 0:  return @"0";
+  case 1:  return @"1";
+  case 2:  return @"2";
+  case 3:  return @"3";
+  case 4:  return @"4";
+  case 5:  return @"5";
+  case 6:  return @"6";
+  case 7:  return @"7";
+  case 8:  return @"8";
+  case 9:  return @"9";
+  case 10: return @"10";
+    // TODO: find useful count!
+  default:
+    return [[NSString alloc] initWithFormat:@"%i", i];
+  }
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->list       = WOExtGetProperty(_config, @"list");
+    self->item       = WOExtGetProperty(_config, @"item");
+    self->selection  = WOExtGetProperty(_config, @"selection");
+    self->maxColumns = WOExtGetProperty(_config, @"maxColumns");
+    
+    self->index      = WOExtGetProperty(_config, @"index");
+    self->col        = WOExtGetProperty(_config, @"col");
+    self->row        = WOExtGetProperty(_config, @"row");
+    self->horizontal = WOExtGetProperty(_config, @"horizontal");
+
+    self->cellAlign  = WOExtGetProperty(_config, @"cellAlign");
+    self->cellVAlign = WOExtGetProperty(_config, @"cellVAlign");
+    
+    self->rowBackgroundColor  = 
+      WOExtGetProperty(_config, @"rowBackgroundColor");
+    self->cellBackgroundColor = 
+      WOExtGetProperty(_config, @"cellBackgroundColor");
+
+    self->template = RETAIN(_c);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template release];
+  
+  [self->list release];
+  [self->item release];
+  [self->maxColumns release];
+  [self->selection release];
+  
+  [self->index release];
+  [self->col release];
+  [self->row release];
+  [self->horizontal release];
+
+  [self->cellAlign release];
+  [self->cellVAlign release];
+  [self->rowBackgroundColor release];
+  [self->cellBackgroundColor release];
+  [super dealloc];
+}
+
+static inline
+void _applyIndex(WORadioButtonMatrix *self, WOComponent *cmp, unsigned _idx)
+{
+  NSArray  *array;
+  BOOL     isHor;
+  unsigned r, c, cnt, cols;
+
+  isHor = [self->horizontal boolValueInComponent:cmp];
+  cols  = [self->maxColumns unsignedIntValueInComponent:cmp];
+  array = [self->list valueInComponent:cmp];
+  cnt   = [array count];
+  cols  = (cols) ? cols : 1;
+  r     = (isHor) ? (_idx / cols) + 1 : _idx % ((cnt / cols)+1) + 1;
+  c     = (isHor) ? (_idx % cols) + 1 : _idx / ((cnt / cols)+1) + 1;
+    
+  if ([self->index isValueSettable])
+    [self->index setUnsignedIntValue:_idx inComponent:cmp];
+
+  if ([self->row isValueSettable])
+    [self->row setUnsignedIntValue:r inComponent:cmp];
+
+  if ([self->col isValueSettable])
+    [self->col setUnsignedIntValue:c inComponent:cmp];
+
+  if ([self->item isValueSettable]) {
+    if (_idx < cnt)
+      [self->item setValue:[array objectAtIndex:_idx] inComponent:cmp];
+    else {
+      [cmp logWithFormat:
+           @"WORadioButtonMatrix: array did change, index is invalid."];
+      [self->item setValue:nil inComponent:cmp];
+    }
+  }
+}
+
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSArray     *array;
+  id          formValue;
+  unsigned    cnt, i;
+
+  cmp   = [_ctx component];
+  array = [self->list valueInComponent:cmp];
+  cnt   = [array count];
+
+  [_ctx appendZeroElementIDComponent];
+  for (i=0; i<cnt; i++) {
+    _applyIndex(self, cmp, i);
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+    [_ctx incrementLastElementIDComponent];
+  }
+  [_ctx deleteLastElementIDComponent];
+
+  if ((formValue = [_req formValueForKey:[_ctx elementID]])) {
+    i = [formValue unsignedIntValue];
+    _applyIndex(self, cmp, i);
+    
+    if ([self->selection isValueSettable])
+      [self->selection setValue:[array objectAtIndex:i] inComponent:cmp];
+  }
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  id          result = nil;
+  unsigned    idx;
+  NSString    *s;
+
+  cmp = [_ctx component];
+  if ([self->list valueInComponent:cmp] == nil)
+    return nil;
+  
+  idx = [[_ctx currentElementID] intValue];
+  [_ctx consumeElementID]; // consume index
+  s = retStrForInt(idx);
+  [_ctx appendElementIDComponent:s];
+  [s release];
+  _applyIndex(self, cmp, idx);
+  result = [self->template invokeActionForRequest:_req inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *cmp   = nil;
+  NSArray     *array = nil;
+  NSString    *n     = nil;
+  id          sel    = nil;
+  BOOL        isHor  = NO; // is horizontal
+  unsigned    c, colCount; // column index
+  unsigned    r, rowCount; // row    index
+  unsigned    cnt;
+
+  cmp      = [_ctx component];
+  colCount = [self->maxColumns unsignedIntValueInComponent:cmp];
+  array    = [self->list valueInComponent:cmp];
+  cnt      = [array count];
+  isHor    = [self->horizontal boolValueInComponent:cmp];
+  sel      = [self->selection valueInComponent:cmp];
+
+  colCount = (colCount) ? colCount : 1;
+  rowCount = ((cnt % colCount) > 0) ? (cnt / colCount) + 1 : (cnt / colCount);
+
+  n = [_ctx elementID];
+
+  [_response appendContentString:@"<table "];
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  [_response appendContentCharacter:'>'];
+
+  for (r = 0; r < rowCount; r++) {
+    NSString *rowColor;
+    
+    rowColor = [self->rowBackgroundColor stringValueInComponent:cmp];
+    [_response appendContentString:@"<tr"];
+    if (rowColor) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:rowColor];
+      [_response appendContentCharacter:'"'];
+    }
+    [_response appendContentCharacter:'>'];
+    
+    for (c = 0; c < colCount; c++) {
+      NSString *cColor = [self->cellBackgroundColor stringValueInComponent:cmp];
+      NSString *align  = [self->cellAlign  stringValueInComponent:cmp];
+      NSString *valign = [self->cellVAlign stringValueInComponent:cmp];
+      unsigned i = (isHor) ? r*colCount+c : c*rowCount+r;
+
+      [_response appendContentString:@"<td"];
+      if (cColor) {
+        [_response appendContentString:@" bgcolor=\""];
+        [_response appendContentString:cColor];
+        [_response appendContentCharacter:'"'];
+      }
+      if (align) {
+        [_response appendContentString:@" align=\""];
+        [_response appendContentString:align];
+        [_response appendContentCharacter:'"'];
+      }
+      if (valign) {
+        [_response appendContentString:@" valign=\""];
+        [_response appendContentString:valign];
+        [_response appendContentCharacter:'"'];
+      }
+      [_response appendContentCharacter:'>'];
+      
+      if (i < cnt) {
+        NSString *s;
+        id obj;
+        
+        s = retStrForInt(i);
+        [_ctx appendElementIDComponent:s];
+        [s release];
+        _applyIndex(self, cmp, i);
+        obj = [self->item valueInComponent:cmp];
+
+        /* append radio button */
+        [_response appendContentString:@"<input type=\"radio\" name=\""];
+        [_response appendContentHTMLAttributeValue:n];
+        [_response appendContentString:@"\" value=\""];
+        s = retStrForInt(i);
+        [_response appendContentString:s];
+        [s release];
+        [_response appendContentCharacter:'"'];
+  
+        if ([sel isEqual:obj])
+         [_response appendContentString:@" checked=\"checked\""];
+        
+        [_response appendContentString:@" />"];
+
+        // append template
+        [self->template appendToResponse:_response inContext:_ctx];
+        [_ctx deleteLastElementIDComponent];
+      }
+      else
+        [_response appendContentString:@"&nbsp;"];
+      [_response appendContentString:@"</td>"];
+    }
+    [_response appendContentString:@"</tr>"];
+  }
+  [_response appendContentString:@"</table>"];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:128];
+  if (self->list)       [str appendFormat:@" list=%@",       self->list];
+  if (self->item)       [str appendFormat:@" item=%@",       self->item];
+  if (self->maxColumns) [str appendFormat:@" maxColumns=%@", self->maxColumns];
+  if (self->selection)  [str appendFormat:@" selection=%@",  self->selection];
+  if (self->index)      [str appendFormat:@" index=%@",      self->index];
+  if (self->col)        [str appendFormat:@" col=%@",        self->col];
+  if (self->row)        [str appendFormat:@" row=%@",        self->row];
+  if (self->horizontal) [str appendFormat:@" horizontal=%@", self->horizontal];
+  if (self->template)   [str appendFormat:@" template=%@",   self->template];
+
+  return str;
+}
+
+@end /* WORadioButtonMatrix */
diff --git a/skyrix-sope/WOExtensions/WORedirect.h b/skyrix-sope/WOExtensions/WORedirect.h
new file mode 100644 (file)
index 0000000..e7c44af
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOExtensions_WORedirect_H__
+#define __WOExtensions_WORedirect_H__
+
+#include <NGObjWeb/WOComponent.h>
+
+/*
+  WORedirect
+
+   Q: Whats the difference to WERedirect?
+   A: It is a component while WERedirect is a dynamic element.
+   
+   Note: you can also use the WOComponent -redirectToLocation: method (SOPE
+         specific extension).
+*/
+
+@interface WORedirect : WOComponent
+{
+  id url;
+}
+
+/* accessors */
+
+- (void)setURL:(id)_url;
+- (void)setUrl:(id)_url; // for KVC
+- (id)url;
+
+@end
+
+#endif /* __WOExtensions_WORedirect_H__ */
diff --git a/skyrix-sope/WOExtensions/WORedirect.m b/skyrix-sope/WOExtensions/WORedirect.m
new file mode 100644 (file)
index 0000000..efdbd7a
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WORedirect.h"
+#include "common.h"
+
+@implementation WORedirect
+
+- (void)dealloc {
+  [self->url release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setURL:(id)_url {
+  [self setUrl:_url];
+}
+
+- (void)setUrl:(id)_url {
+  ASSIGNCOPY(self->url, _url);
+}
+- (id)url {
+  return self->url;
+}
+
+/* handling requests (do nothing, avoid loading of template) */
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+}
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  [self logWithFormat:@"WARNING: called %s on WORedirect!", 
+          __PRETTY_FUNCTION__];
+  return nil;
+}
+
+/* generating the response */
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *loc;
+  
+  if (![self->url isNotNull]) {
+    [self logWithFormat:@"ERROR: missing URL for redirect!"];
+    return;
+  }
+  
+  if ([self->url isKindOfClass:[NSURL class]])
+    loc = [self->url absoluteString];
+  else
+    loc = [self->url stringValue];
+
+  if ([loc length] == 0) {
+    [self logWithFormat:@"ERROR: got invalid URL for redirect: '%@'(%@)", 
+            self->url, NSStringFromClass([self->url class])];
+    return;
+  }
+  
+  [_response setStatus:302 /* temporarily moved */];
+  [_response setHeader:loc forKey:@"location"];
+}
+
+@end /* WORedirect */
diff --git a/skyrix-sope/WOExtensions/WOTabPanel.m b/skyrix-sope/WOExtensions/WOTabPanel.m
new file mode 100644 (file)
index 0000000..949b2bb
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WOTabPanel : WODynamicElement
+{
+  WOAssociation *tabs;
+  WOAssociation *selectedTab;
+  WOAssociation *tabNameKey;
+  WOAssociation *nonSelectedBgColor;
+  WOAssociation *bgcolor;
+  WOAssociation *textColor;
+  WOAssociation *submitActionName;
+  
+  WOElement *template;
+}
+@end
+
+#include "common.h"
+
+@interface WOContext(NGPrivates)
+- (void)addActiveFormElement:(WOElement *)_element;
+@end
+
+@implementation WOTabPanel
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->tabs               = WOExtGetProperty(_config, @"tabs");
+    self->selectedTab        = WOExtGetProperty(_config, @"selectedTab");
+    self->tabNameKey         = WOExtGetProperty(_config, @"tabNameKey");
+    
+    self->nonSelectedBgColor = 
+      WOExtGetProperty(_config, @"nonSelectedBgColor");
+    self->bgcolor            = WOExtGetProperty(_config, @"bgcolor");
+    self->textColor          = WOExtGetProperty(_config, @"textColor");
+    
+    self->submitActionName   = WOExtGetProperty(_config, @"submitActionName");
+
+    self->template = [_c retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->submitActionName release];
+  [self->textColor   release];
+  [self->bgcolor     release];
+  [self->nonSelectedBgColor release];
+  [self->tabNameKey  release];
+  [self->selectedTab release];
+  [self->tabs        release];
+  [self->template    release];
+  [super dealloc];
+}
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  /* check whether a (form) tab was clicked */
+  [_ctx appendElementIDComponent:@"tab"];
+  {
+    WOComponent *sComponent;
+    NSArray *ttabs;
+    unsigned i;
+    
+    sComponent = [_ctx component];
+    ttabs = [self->tabs valueInComponent:sComponent];
+    
+    [_ctx appendZeroElementIDComponent];
+    
+    for (i = 0; i < [ttabs count]; i++) {
+      if ([_req formValueForKey:[_ctx elementID]]) {
+        /* found active tab */
+        [self->selectedTab setValue:[ttabs objectAtIndex:i]
+                           inComponent:sComponent];
+        [_ctx addActiveFormElement:self];
+        break;
+      }
+      [_ctx incrementLastElementIDComponent];
+    }
+    
+    [_ctx deleteLastElementIDComponent];
+  }
+  [_ctx deleteLastElementIDComponent];
+
+  /* let content take values */
+  [_ctx appendElementIDComponent:@"content"];
+  [self->template takeValuesFromRequest:_req inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  id result;
+  NSString *section;
+
+  section = [_ctx currentElementID];
+  if ([section isEqualToString:@"tab"]) {
+    WOComponent *sComponent;
+    NSArray *ttabs;
+    int idx;
+    
+    [_ctx consumeElementID]; // consume 'tab'
+    
+    sComponent = [_ctx component];
+    ttabs = [self->tabs valueInComponent:sComponent];
+
+    idx = [[_ctx currentElementID] intValue];
+    [_ctx consumeElementID]; // consume index
+
+    if (idx >= (int)[ttabs count]) {
+      /* index out of range */
+      idx = 0;
+    }
+    
+    [self->selectedTab setValue:[ttabs objectAtIndex:idx]
+                       inComponent:sComponent];
+    
+    result = [_ctx page];
+  }
+  else if ([section isEqualToString:@"content"]) { 
+    [_ctx consumeElementID]; // consume 'content'
+    
+    [_ctx appendElementIDComponent:@"content"];
+    result = [self->template invokeActionForRequest:_req inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+  else {
+    NSLog(@"%s: missing section id !", __PRETTY_FUNCTION__);
+    result = [_ctx page];
+  }
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *sComponent;
+  NSArray     *ttabs;
+  BOOL        isInForm;
+  unsigned    i, selIdx;
+  NSString    *selColor, *unselColor, *s;
+  
+  sComponent = [_ctx component];
+  ttabs = [self->tabs valueInComponent:sComponent];
+
+  selColor = self->bgcolor
+    ? [self->bgcolor stringValueInComponent:sComponent]
+    : @"#CCCCCC";
+  
+  unselColor = self->nonSelectedBgColor
+    ? [self->nonSelectedBgColor stringValueInComponent:sComponent]
+    : @"#AAAAAA";
+  
+  if ([ttabs count] < 1) {
+    /* no tabs configured .. */
+    [self->template appendToResponse:_response inContext:_ctx];
+    return;
+  }
+  
+  [_response appendContentString:@"<table border='0'>"];
+  [_response appendContentString:@"<tr>"];
+
+  isInForm = [_ctx isInForm];
+  
+  /* cannot use -indexOfObjectIdenticalTo:, since this doesn't work
+     with language bridges (base types crossing a bridge aren't
+     enforced to be identical ... */
+  selIdx = [ttabs indexOfObject:
+                   [self->selectedTab valueInComponent:sComponent]];
+  if (selIdx == NSNotFound)
+    selIdx = 0;
+  
+  [_ctx appendElementIDComponent:@"tab"];
+  [_ctx appendZeroElementIDComponent];
+  
+  for (i = 0; i < [ttabs count]; i++) {
+    id       tab;
+    BOOL     isCurrentSelected;
+    NSString *title;
+    
+    tab = [ttabs objectAtIndex:i];
+    isCurrentSelected = i == selIdx;
+    
+    [self->selectedTab setValue:tab inComponent:sComponent];
+
+    title = (self->tabNameKey)
+      ? [self->tabNameKey stringValueInComponent:sComponent]
+      : [tab stringValue];
+    
+    [_response appendContentString:@"<td"];
+    [_response appendContentString:@" bgcolor=\""];
+    [_response appendContentString:isCurrentSelected ? selColor : unselColor];
+    [_response appendContentString:@"\""];
+    [_response appendContentString:@">"];
+    
+    if (isInForm) {
+      /* gen submit button */
+      [_response appendContentString:@"<input type='submit' name=\""];
+      [_response appendContentHTMLAttributeValue:[_ctx elementID]];
+      [_response appendContentString:@"\" value=\""];
+      [_response appendContentString:title];
+      [_response appendContentString:@"\" />"];
+    }
+    else {
+      /* gen link */
+      [_response appendContentString:@"<a href=\""];
+      [_response appendContentHTMLAttributeValue:[_ctx componentActionURL]];
+      [_response appendContentString:@"\" title=\""];
+      [_response appendContentHTMLAttributeValue:title];
+      [_response appendContentString:@"\">"];
+      
+      if (self->textColor) {
+        [_response appendContentString:@"<font color=\""];
+        [_response appendContentHTMLAttributeValue:
+                     [self->textColor stringValueInComponent:sComponent]];
+        [_response appendContentString:@"\">"];
+      }
+      
+      [_response appendContentHTMLString:title];
+
+      if (self->textColor)
+        [_response appendContentString:@"</font>"];
+      [_response appendContentString:@"</a>"];
+    }
+    
+    [_response appendContentString:@"</td>"];
+    
+    [_ctx incrementLastElementIDComponent]; /* increment index */
+  }
+  [_ctx deleteLastElementIDComponent]; /* del index */
+  [_ctx deleteLastElementIDComponent]; /* del 'tab' */
+
+  [self->selectedTab setValue:[ttabs objectAtIndex:selIdx]
+                     inComponent:sComponent];
+  
+  [_response appendContentString:@"</tr><tr><td colspan=\""];
+  s = [[NSString alloc] initWithFormat:@"%d",[ttabs count]];
+  [_response appendContentString:s];
+  [s release];
+  [_response appendContentString:@"\" bgcolor=\""];
+  [_response appendContentString:selColor];
+  [_response appendContentString:@"\">"];
+  
+  [_ctx appendElementIDComponent:@"content"];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  
+  [_response appendContentString:@"</td></tr></table>"];
+}
+
+@end /* WOTabPanel */
diff --git a/skyrix-sope/WOExtensions/WOTable.m b/skyrix-sope/WOExtensions/WOTable.m
new file mode 100644 (file)
index 0000000..061310c
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface WOTable : WODynamicElement
+{
+  // WODynamicElement: extraAttributes
+  // WODynamicElement: otherTagString
+@protected
+  WOAssociation *list;        // array of objects to iterate through
+  WOAssociation *item;        // current item in the array
+  WOAssociation *maxColumns;  // number of columns
+  WOAssociation *index;       // current index
+  WOAssociation *col;         // current column (is updated with each iteration)
+  WOAssociation *row;         // current row    (is updated with each iteration)
+
+  WOAssociation *cellAlign;   // current cell align
+  WOAssociation *cellVAlign;  // current cell valign
+  WOAssociation *rowBackgroundColor;  // current row background color;
+  WOAssociation *cellBackgroundColor; // current cell background color;
+
+  /*
+    table attributes are implemented as extraAttributes:
+     
+         tableBackgroundColor, --> bgColor
+         border,               --> border
+         cellpadding,          --> cellpadding
+         cellspacing,          --> cellspacing
+  */
+  
+  /* non WO attribute */
+  WOAssociation *horizontal;   // order items horizontal (default = NO)
+  WOAssociation *hasOwnTDs;    // don't draw TDs
+
+  WOElement     *template;
+}
+@end
+
+#include "common.h"
+
+static NSString *_WOTableHeaderString_  = @"_WOTableHeaderString_";
+static NSString *_WOTableContentString_ = @"_WOTableContentString_";
+static NSString *_WOTableContextMode_   = @"_WOTableContextMode_";
+
+@implementation WOTable
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->list       = WOExtGetProperty(_config, @"list");
+    self->item       = WOExtGetProperty(_config, @"item");
+    self->maxColumns = WOExtGetProperty(_config, @"maxColumns");
+    self->index      = WOExtGetProperty(_config, @"index");
+    self->col        = WOExtGetProperty(_config, @"col");
+    self->row        = WOExtGetProperty(_config, @"row");
+    self->horizontal = WOExtGetProperty(_config, @"horizontal");
+    self->hasOwnTDs  = WOExtGetProperty(_config, @"hasOwnTDs");
+
+    self->cellAlign  = WOExtGetProperty(_config, @"cellAlign");
+    self->cellVAlign = WOExtGetProperty(_config, @"cellVAlign");
+    
+    self->rowBackgroundColor  = 
+      WOExtGetProperty(_config, @"rowBackgroundColor");
+    self->cellBackgroundColor = 
+      WOExtGetProperty(_config, @"cellBackgroundColor");
+
+    self->template = RETAIN(_c);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template release];
+  
+  [self->list       release];
+  [self->item       release];
+  [self->maxColumns release];
+  [self->index      release];
+  [self->col        release];
+  [self->row        release];
+  [self->horizontal release];
+  [self->hasOwnTDs  release];
+
+  [self->cellAlign           release];
+  [self->cellVAlign          release];
+  [self->rowBackgroundColor  release];
+  [self->cellBackgroundColor release];
+  [super dealloc];
+}
+
+static inline void _applyIndex(WOTable *self, WOComponent *cmp, unsigned _idx)
+{
+  NSArray  *array;
+  BOOL     isHor;
+  unsigned r, c, cnt, cols;
+
+  isHor = [self->horizontal boolValueInComponent:cmp];
+  cols  = [self->maxColumns unsignedIntValueInComponent:cmp];
+  array = [self->list valueInComponent:cmp];
+  cnt   = [array count];
+  cols  = (cols) ? cols : 1;
+  r     = (isHor) ? (_idx / cols) + 1 : _idx % ((cnt / cols)+1) + 1;
+  c     = (isHor) ? (_idx % cols) + 1 : _idx / ((cnt / cols)+1) + 1;
+    
+  if ([self->index isValueSettable])
+    [self->index setUnsignedIntValue:_idx inComponent:cmp];
+
+  if ([self->row isValueSettable])
+    [self->row setUnsignedIntValue:r inComponent:cmp];
+
+  if ([self->col isValueSettable])
+    [self->col setUnsignedIntValue:c inComponent:cmp];
+
+  if ([self->item isValueSettable]) {
+    if (_idx < cnt)
+      [self->item setValue:[array objectAtIndex:_idx] inComponent:cmp];
+    else {
+      [cmp logWithFormat:@"WOTable: array did change, index is invalid."];
+      [self->item setValue:nil inComponent:cmp];
+    }
+  }
+}
+
+
+- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  NSArray     *array;
+  unsigned    cnt, i;
+
+  cmp   = [_ctx component];
+  array = [self->list valueInComponent:cmp];
+  cnt   = [array count];
+
+  [_ctx appendZeroElementIDComponent];
+
+  [_ctx setObject:_WOTableContentString_ forKey:_WOTableContextMode_];
+
+  for (i=0; i<cnt; i++) {
+    _applyIndex(self, cmp, i);
+    [self->template takeValuesFromRequest:_req inContext:_ctx];
+    [_ctx incrementLastElementIDComponent];
+  }
+
+  [_ctx removeObjectForKey:_WOTableContextMode_];
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
+  WOComponent *cmp;
+  id          result = nil;
+
+  cmp = [_ctx component];
+  
+  if ([self->list valueInComponent:cmp] != nil) {
+    unsigned idx = [[_ctx currentElementID] intValue];
+    NSString *s;
+    
+    [_ctx consumeElementID]; // consume index
+    s = [[NSString alloc] initWithFormat:@"%i", idx];
+    [_ctx appendElementIDComponent:s];
+    [s release];
+    _applyIndex(self, cmp, idx);
+    result = [self->template invokeActionForRequest:_req inContext:_ctx];
+    [_ctx deleteLastElementIDComponent];
+  }
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  WOComponent *cmp   = nil;
+  NSArray     *array = nil;
+  BOOL        isHor  = NO; // is horizontal
+  BOOL        drawTD = YES;
+  unsigned    c, colCount; // column index
+  unsigned    r, rowCount; // row    index
+  unsigned    cnt;
+  unsigned    ownTDCount = 0;
+
+  cmp      = [_ctx component];
+  colCount = [self->maxColumns unsignedIntValueInComponent:cmp];
+  array    = [self->list valueInComponent:cmp];
+  cnt      = [array count];
+  isHor    = [self->horizontal boolValueInComponent:cmp];
+  drawTD   = ![self->hasOwnTDs boolValueInComponent:cmp];
+  if (!drawTD)
+    ownTDCount = [self->hasOwnTDs intValueInComponent:cmp];
+  
+  colCount = (colCount < cnt) ? colCount : cnt;
+  colCount = (colCount) ? colCount : 1;
+  rowCount = ((cnt % colCount) > 0) ? (cnt / colCount) + 1 : (cnt / colCount);
+
+  [_response appendContentString:@"<table "];
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  [_response appendContentCharacter:'>'];
+
+  if (!drawTD) {
+    NSString *rowColor = [self->rowBackgroundColor stringValueInComponent:cmp];
+    unsigned i;
+
+    [_ctx setObject:_WOTableHeaderString_ forKey:_WOTableContextMode_];
+    [_response appendContentString:@"<tr"];
+    if (rowColor) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:rowColor];
+      [_response appendContentCharacter:'"'];
+    }
+    [_response appendContentCharacter:'>'];
+    for (i = 0; i < colCount; i++) {
+      [self->template appendToResponse:_response inContext:_ctx];
+    }
+    [_response appendContentString:@"</tr>"];
+    [_ctx removeObjectForKey:_WOTableContextMode_];
+  }
+
+  if (!drawTD)
+    [_ctx setObject:_WOTableContentString_ forKey:_WOTableContextMode_];
+
+  for (r=0; r<rowCount; r++) {
+    NSString *rowColor = [self->rowBackgroundColor stringValueInComponent:cmp];
+    [_response appendContentString:@"<tr"];
+    if (rowColor) {
+      [_response appendContentString:@" bgcolor=\""];
+      [_response appendContentString:rowColor];
+      [_response appendContentCharacter:'"'];
+    }
+    [_response appendContentCharacter:'>'];
+    
+    for (c=0; c<colCount; c++) {
+      NSString *cColor = [self->cellBackgroundColor stringValueInComponent:cmp];
+      NSString *align  = [self->cellAlign  stringValueInComponent:cmp];
+      NSString *valign = [self->cellVAlign stringValueInComponent:cmp];
+      NSString *width  = nil;
+      unsigned i = (isHor) ? r*colCount+c : c*rowCount+r;
+      
+      if (drawTD) {
+        [_response appendContentString:@"<td"];
+        width = [[NSString alloc] initWithFormat:@"%d%%", (int)(100 / colCount)];
+        if (width) {
+          [_response appendContentString:@" width=\""];
+          [_response appendContentString:width];
+          [_response appendContentCharacter:'"'];
+          [width release];
+        }
+        if (cColor) {
+          [_response appendContentString:@" bgcolor=\""];
+          [_response appendContentString:cColor];
+          [_response appendContentCharacter:'"'];
+        }
+        if (align) {
+          [_response appendContentString:@" align=\""];
+          [_response appendContentString:align];
+          [_response appendContentCharacter:'"'];
+        }
+        if (valign) {
+          [_response appendContentString:@" valign=\""];
+          [_response appendContentString:valign];
+          [_response appendContentCharacter:'"'];
+        }
+        [_response appendContentCharacter:'>'];
+      }
+      if (i < cnt) {
+        NSString *s;
+
+        s = [[NSString alloc] initWithFormat:@"%i", i];
+        [_ctx appendElementIDComponent:s];
+        [s release];
+        _applyIndex(self, cmp, i);
+        [self->template appendToResponse:_response inContext:_ctx];
+        [_ctx deleteLastElementIDComponent];
+      }
+      else if (ownTDCount > 0) {
+        unsigned j;
+        
+        for (j = 0; j < ownTDCount; j++)
+          [_response appendContentString:@"<td>&nbsp;</td>"];
+      }
+      else
+        [_response appendContentString:@"&nbsp;"];
+
+      if (drawTD)
+        [_response appendContentString:@"</td>"];
+    }
+    [_response appendContentString:@"</tr>"];
+  }
+  if (!drawTD)
+    [_ctx removeObjectForKey:_WOTableContextMode_];
+
+  [_response appendContentString:@"</table>"];
+}
+
+/* description */
+
+- (NSString *)associationDescription {
+  NSMutableString *str;
+
+  str = [NSMutableString stringWithCapacity:128];
+  if (self->list)       [str appendFormat:@" list=%@",       self->list];
+  if (self->item)       [str appendFormat:@" item=%@",       self->item];
+  if (self->maxColumns) [str appendFormat:@" maxColumns=%@", self->maxColumns];
+  if (self->index)      [str appendFormat:@" index=%@",      self->index];
+  if (self->col)        [str appendFormat:@" col=%@",        self->col];
+  if (self->row)        [str appendFormat:@" row=%@",        self->row];
+  if (self->horizontal) [str appendFormat:@" horizontal=%@", self->horizontal];
+  if (self->hasOwnTDs)  [str appendFormat:@" hasOwnTDs=%@",  self->hasOwnTDs];
+  if (self->template)   [str appendFormat:@" template=%@",   self->template];
+  return str;
+}
+
+@end /* WOTable */
+
+@interface WOTableContextKey : WODynamicElement
+{
+  WOElement *template;
+}
+@end
+
+@implementation WOTableContextKey
+
+- (NSString *)_contextValue {
+  return nil;
+}
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_c
+{
+  if ((self = [super initWithName:_name associations:_config template:_c])) {
+    self->template  = [_c retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->template release];
+  [super dealloc];
+}
+
+- (BOOL)doShow:(WOContext *)_ctx {
+  NSString *key = [_ctx objectForKey:_WOTableContextMode_];
+
+  if (key == nil)
+    return NO;
+
+  return [key isEqualToString:[self _contextValue]];
+}
+
+// ******************** responder ********************
+
+- (void)takeValuesFromRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+{
+  if (![self doShow:_ctx])
+    return;
+
+  [_ctx appendElementIDComponent:@"1"];
+  [self->template takeValuesFromRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
+  NSString *state;
+  id result;
+
+  if ((state = [[_ctx currentElementID] stringValue]) == nil)
+    return nil;
+  
+  [_ctx consumeElementID]; // consume state-id (on or off)
+  
+  if (![state isEqualToString:@"1"])
+    return nil;
+  
+  [_ctx appendElementIDComponent:state];
+  result = [self->template invokeActionForRequest:_request inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+  return result;
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  if (![self doShow:_ctx]) 
+    return;
+
+  [_ctx appendElementIDComponent:@"1"];
+  [self->template appendToResponse:_response inContext:_ctx];
+  [_ctx deleteLastElementIDComponent];
+}
+
+@end /* WOTableContextKey */
+
+@interface WOTableHeader : WOTableContextKey
+@end /* WOTableHeader */
+
+@implementation WOTableHeader
+
+- (NSString *)_contextValue {
+  return _WOTableHeaderString_;
+}
+
+@end /* WOTableHeader */
+
+
+@interface WOTableContent : WOTableContextKey
+@end /* WOTableContent */
+
+@implementation WOTableContent
+
+- (NSString *)_contextValue {
+  return _WOTableContentString_;
+}
+
+@end /* WOTableContent */
diff --git a/skyrix-sope/WOExtensions/WOThresholdColoredNumber.m b/skyrix-sope/WOExtensions/WOThresholdColoredNumber.m
new file mode 100644 (file)
index 0000000..f72c869
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/NGObjWeb.h>
+
+@interface WOThresholdColoredNumber : WODynamicElement
+{
+  WOAssociation *lowColor;
+  WOAssociation *highColor;
+  WOAssociation *threshold;
+  WOAssociation *value;
+  WOAssociation *numberFormat;
+}
+@end
+
+#import <Foundation/NSNumberFormatter.h>
+#include "common.h"
+
+@implementation WOThresholdColoredNumber
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_temp
+{
+  if ((self = [super initWithName:_name associations:_config template:_temp])) {
+    self->lowColor     = WOExtGetProperty(_config, @"lowColor");
+    self->highColor    = WOExtGetProperty(_config, @"highColor");
+    self->threshold    = WOExtGetProperty(_config, @"threshold");
+    self->value        = WOExtGetProperty(_config, @"value");
+    self->numberFormat = WOExtGetProperty(_config, @"numberformat");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->lowColor);
+  RELEASE(self->highColor);
+  RELEASE(self->threshold);
+  RELEASE(self->value);
+  RELEASE(self->numberFormat);
+  
+  [super dealloc];
+}
+
+
+// *** responder ***
+
+- (void)appendToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
+  WOComponent *comp;
+  NSString    *low;     // lowColor     association
+  NSString    *high;    // highColor    association
+  NSNumber    *t;       // threshold    association
+  NSNumber    *v;       // value        association
+  NSString    *nFormat; // numberFormat association
+  NSString    *color;
+  NSString    *result = nil;
+
+  comp    = [_ctx component];
+  low     = [self->lowColor     stringValueInComponent:comp];
+  high    = [self->highColor    stringValueInComponent:comp];
+  t       = [self->threshold    valueInComponent:comp];
+  v       = [self->value        valueInComponent:comp];
+  nFormat = [self->numberFormat stringValueInComponent:comp];
+
+  if (![v isKindOfClass:[NSNumber class]]) {
+#if DEBUG
+    NSLog(@"WARNING! WOThresholdColoredNumber 'value' is not a NSNumber");
+    result = @"[WARNING! WOThresholdColoredNumber:'value' must be a NSNumber]";
+#else
+    result = @"";
+#endif
+  }
+  else if (nFormat) {
+    NSNumberFormatter *formatter;
+
+    formatter = AUTORELEASE([[NSNumberFormatter alloc] init]);
+    [formatter setFormat:nFormat];
+    result = [formatter stringForObjectValue:v];
+  }
+  else
+    result = [v stringValue];
+
+  color = ([v compare:t] == NSOrderedAscending) ? low : high;
+
+  if (color) {
+    [_resp appendContentString:@"<FONT COLOR=\""];
+    [_resp appendContentString:color];
+    [_resp appendContentString:@"\">"];
+  }
+  [_resp appendContentString:result];
+  if (color)
+    [_resp appendContentString:@"</FONT>"];
+}
+
+@end /* WOThresholdColoredNumber */
diff --git a/skyrix-sope/WOExtensions/WOxExtElemBuilder.m b/skyrix-sope/WOExtensions/WOxExtElemBuilder.m
new file mode 100644 (file)
index 0000000..f424d25
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOxElemBuilder.h>
+
+/*
+  This builder builds various elements from the WOExtensions library.
+
+  All tags are mapped into the <var:> namespace (XMLNS_OD_BIND).
+
+  Supported tags:
+    <var:js-alert-panel     .../> maps to JSAlertPanel
+    <var:js-confirm-panel   .../> maps to JSConfirmPanel
+    <var:js-img-flyover     .../> maps to JSImageFlyover
+    <var:js-text-flyover    .../> maps to JSTextFlyover
+    <var:js-modal-window    .../> maps to JSModalWindow
+    <var:js-validated-field .../> maps to JSValidatedField
+
+    <var:threshold-colored-number .../> maps to WOThresholdColoredNumber
+
+    <var:collapsible .../>  maps to WOCollapsibleComponentContent
+    <var:checkbox-matrix../>maps to WOCheckBoxMatrix
+    <var:radio-matrix .../> maps to WORadioButtonMatrix
+    
+    <var:foreach-key .../>  maps to WODictionaryRepetition
+    <var:if-key      .../>  maps to WOKeyValueConditional
+
+    <var:tab-panel   .../>  maps to WOTabPanel
+
+    <var:table        .../> maps to WOTable
+    <var:table-header  ../> maps to WOTableHeader
+    <var:table-content ../> maps to WOTableContent
+    <var:table-ctx-key ../> maps to WOTableContextKey
+    
+    //JSKeyHandler : WODynamicElement
+*/
+
+@interface WOxExtElemBuilder : WOxTagClassElemBuilder
+{
+}
+
+@end
+
+#include <SaxObjC/XMLNamespaces.h>
+#include "common.h"
+
+@implementation WOxExtElemBuilder
+
+- (Class)classForElement:(id<DOMElement>)_element {
+  NSString *tagName;
+  unsigned tl;
+  unichar  c1;
+  
+  if (![[_element namespaceURI] isEqualToString:XMLNS_OD_BIND])
+    return Nil;
+  
+  tagName = [_element tagName];
+  if ((tl = [tagName length]) < 3)
+    return Nil;
+
+  c1 = [tagName characterAtIndex:0];
+  switch (c1) {
+    case 'c':
+      if (tl > 10) {
+        if ([tagName isEqualToString:@"collapsible"])
+          return NSClassFromString(@"WOCollapsibleComponentContent");
+        if ([tagName isEqualToString:@"checkbox-matrix"])
+          return NSClassFromString(@"WOCheckBoxMatrix");
+      }
+      break;
+
+    case 'f':
+      if (tl > 10) {
+        if ([tagName isEqualToString:@"foreach-key"])
+          return NSClassFromString(@"WODictionaryRepetition");
+      }
+      break;
+
+    case 'i':
+      if (tl == 6) {
+        if ([tagName isEqualToString:@"if-key"])
+          return NSClassFromString(@"WOKeyValueConditional");
+      }
+      break;
+      
+    case 'j':
+      if (tl > 13 && [tagName hasPrefix:@"js-"]) {
+        if ([tagName isEqualToString:@"js-alert-panel"])
+          return NSClassFromString(@"JSAlertPanel");
+        if ([tagName isEqualToString:@"js-confirm-panel"])
+          return NSClassFromString(@"JSConfirmPanel");
+        if ([tagName isEqualToString:@"js-img-flyover"])
+          return NSClassFromString(@"JSImageFlyover");
+        if ([tagName isEqualToString:@"js-text-flyover"])
+          return NSClassFromString(@"JSTextFlyover");
+        if ([tagName isEqualToString:@"js-modal-window"])
+          return NSClassFromString(@"JSModalWindow");
+        if ([tagName isEqualToString:@"js-validated-field"])
+          return NSClassFromString(@"JSValidatedField");
+      }
+      break;
+
+    case 'r':
+      if (tl > 10) {
+        if ([tagName isEqualToString:@"radio-matrix"])
+          return NSClassFromString(@"WORadioButtonMatrix");
+      }
+      break;
+
+    case 't':
+      if (tl > 20) {
+        if ([tagName isEqualToString:@"threshold-colored-number"])
+          return NSClassFromString(@"WOThresholdColoredNumber");
+      }
+      if (tl > 8) {
+        if ([tagName isEqualToString:@"tab-panel"])
+          return NSClassFromString(@"WOTabPanel");
+      }
+      if (tl > 4) {
+        if ([tagName hasPrefix:@"table"]) {
+          if (tl == 5)
+            return NSClassFromString(@"WOTable");
+          
+          if (tl > 11) {
+            if ([tagName isEqualToString:@"table-content"])
+              return NSClassFromString(@"WOTableContent");
+            if ([tagName isEqualToString:@"table-header"])
+              return NSClassFromString(@"WOTableHeader");
+            if ([tagName isEqualToString:@"table-ctx-key"])
+              return NSClassFromString(@"WOTableContextKey");
+          }
+        }
+      }
+      break;
+  }
+  return Nil;
+}
+
+@end /* WOxExtElemBuilder */
diff --git a/skyrix-sope/WOExtensions/bundle-info.plist b/skyrix-sope/WOExtensions/bundle-info.plist
new file mode 100644 (file)
index 0000000..1a0c0e3
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  CVSID = "$Id: bundle-info.plist,v 1.2 2004/03/31 12:08:21 helge Exp $";
+
+  requires = {
+    bundleManagerVersion = 1;
+    
+    classes = (
+      { name = NSObject; }
+    );
+  };
+
+  provides = {
+    WOxElemBuilder = (
+      { name = "WOxExtElemBuilder"; },
+    );
+    
+    WODynamicElements = (
+      { name = "JSAlertPanel";          },
+      { name = "JSConfirmPanel";        },
+      { name = "JSImageFlyover";        },
+      { name = "JSModalWindow";         },
+      { name = "JSTextFlyover";         },
+      { name = "JSValidatedField";      },
+      { name = "WOCheckBoxMatrix";      },
+      { name = "WOCollapsibleComponentContent"; },
+      { name = "WODictionaryRepetition";   },
+      { name = "WOKeyValueConditional"; },
+      { name = "WORadioButtonMatrix";   },
+      { name = "WOTabPanel";            },
+      { name = "WOTable";               },
+      { name = "WOThresholdColoredNumber"; },
+    );
+
+    WOComponents = (
+      { name = "WORedirect";            },
+    );
+    
+    classes = (
+      { name = "WOxExtElemBuilder";     },
+
+      { name = "JSAlertPanel";          },
+      { name = "JSConfirmPanel";        },
+      { name = "JSImageFlyover";        },
+      { name = "JSModalWindow";         },
+      { name = "JSTextFlyover";         },
+      { name = "JSValidatedField";      },
+      { name = "WOCheckBoxMatrix";      },
+      { name = "WOCollapsibleComponentContent"; },
+      { name = "WODictionaryRepetition";   },
+      { name = "WOKeyValueConditional"; },
+      { name = "WORadioButtonMatrix";   },
+      { name = "WORedirect";            },
+      { name = "WOTabPanel";            },
+      { name = "WOTable";               },
+      { name = "WOThresholdColoredNumber"; },
+    );
+  };
+}
diff --git a/skyrix-sope/WOExtensions/common.h b/skyrix-sope/WOExtensions/common.h
new file mode 100644 (file)
index 0000000..3fc5626
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __common_H__
+#define __common_H__
+
+#import <Foundation/Foundation.h>
+#include <NGObjWeb/NGObjWeb.h>
+#include <NGExtensions/NGExtensions.h>
+
+#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#endif
+
+static inline id WOExtGetProperty(NSDictionary *_set, NSString *_name) {
+  id propValue;
+  
+  if ((propValue = [_set objectForKey:_name]) == nil)
+    return nil;
+  
+  propValue = [propValue retain];
+  [(NSMutableDictionary *)_set removeObjectForKey:_name];
+  return propValue;
+}
+
+static inline NSString *WOUriOfResource(NSString *_name, WOContext *_ctx) {
+  NSArray           *languages;
+  WOResourceManager *resourceManager;
+  NSString          *uri;
+
+  if (_name == nil)
+    return nil;
+
+  languages = [_ctx hasSession]
+    ? [[_ctx session] languages]
+    : [[_ctx request] browserLanguages];
+  
+  resourceManager = [[_ctx application] resourceManager];
+  
+  uri = [resourceManager urlForResourceNamed:_name
+                         inFramework:nil
+                         languages:languages
+                         request:[_ctx request]];
+  if ([uri rangeOfString:@"/missingresource?"].length > 0)
+    uri = nil;
+  
+  return uri;
+}
+
+
+#define OWGetProperty WOExtGetProperty
+
+#endif /* __common_H__ */
diff --git a/skyrix-sope/WOExtensions/compat.m b/skyrix-sope/WOExtensions/compat.m
new file mode 100644 (file)
index 0000000..b89cf7c
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "common.h"
+
+@interface WODragContainer : WODynamicElement
+@end
+
+@interface WODropContainer : WODynamicElement
+@end
+
+@interface WODragScript : WODynamicElement
+@end
+
+@interface WODropScript : WODynamicElement
+@end
+
+@implementation WODragContainer
+
++ (id)allocWithZone:(NSZone *)_zone {
+  static Class realClass = Nil;
+  if (realClass == Nil) {
+    NSLog(@"DEPRECATED: %@ !", self);
+    realClass = NSClassFromString(@"WEDragContainer");
+    NSAssert(realClass, @"missing WEDragContainer !");
+  }
+  return [realClass allocWithZone:_zone];
+}
+
+@end
+
+@implementation WODropContainer
+
++ (id)allocWithZone:(NSZone *)_zone {
+  static Class realClass = Nil;
+  if (realClass == Nil) {
+    NSLog(@"DEPRECATED: %@ !", self);
+    realClass = NSClassFromString(@"WEDropContainer");
+    NSAssert(realClass, @"missing WEDropContainer !");
+  }
+  return [realClass allocWithZone:_zone];
+}
+
+@end
+
+@implementation WODragScript
+
++ (id)allocWithZone:(NSZone *)_zone {
+  static Class realClass = Nil;
+  if (realClass == Nil) {
+    NSLog(@"DEPRECATED: %@ !", self);
+    realClass = NSClassFromString(@"WEDragScript");
+    NSAssert(realClass, @"missing WEDropScript !");
+  }
+  return [realClass allocWithZone:_zone];
+}
+
+@end
+
+@implementation WODropScript
+
++ (id)allocWithZone:(NSZone *)_zone {
+  static Class realClass = Nil;
+  if (realClass == Nil) {
+    NSLog(@"DEPRECATED: %@ !", self);
+    realClass = NSClassFromString(@"WEDropScript");
+    NSAssert(realClass, @"missing WEDragScript !");
+  }
+  return [realClass allocWithZone:_zone];
+}
+
+@end
diff --git a/skyrix-sope/WOExtensions/dummy.m b/skyrix-sope/WOExtensions/dummy.m
new file mode 100644 (file)
index 0000000..ccff33f
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  dummy file to produce an executable for the bundle ...
+*/
diff --git a/skyrix-sope/WOXML/COPYING b/skyrix-sope/WOXML/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/WOXML/COPYRIGHT b/skyrix-sope/WOXML/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-sope/WOXML/ChangeLog b/skyrix-sope/WOXML/ChangeLog
new file mode 100644 (file)
index 0000000..471524f
--- /dev/null
@@ -0,0 +1,30 @@
+2004-07-29  Frank Reppin  <frank@opengroupware.org>
+
+       * GNUmakefile.preamble: added libWOXML_SOVERSION (v4.2.5)
+
+2004-07-29  Frank Reppin  <frank@opengroupware.org>
+
+       * GNUmakefile: inherit Version from skyrix-sope (v4.2.4)
+
+2004-06-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile.prebinding: added prebinding (v4.2.3)
+
+2004-04-28  Marcus Mueller  <znek@mulle-kybernetik.com>
+       
+       * v4.2.2
+
+       * WOXML-Info.plist: new file for Xcode project
+
+       * common.h: include NGObjectMacros if NeXT_Foundation_LIBRARY is set.
+
+       * WOXMLDecoder.m: Workaround for missing subclassResponsibility: in
+         NeXT and Apple runtimes.
+
+       * WOXMLSaxModelHandler.m: include common.h (NGObjectMacros)
+
+2004-04-24  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * added WOXML to OGo/SOPE
+
+       * created ChangeLog
diff --git a/skyrix-sope/WOXML/GNUmakefile b/skyrix-sope/WOXML/GNUmakefile
new file mode 100644 (file)
index 0000000..c6a3c0e
--- /dev/null
@@ -0,0 +1,28 @@
+# $Id$
+
+include ../common.make
+include ../Version
+include ./Version
+
+LIBRARY_NAME = libWOXML
+
+libWOXML_HEADER_FILES += \
+       WOXML.h                 \
+       WOXMLDecoder.h          \
+       WOXMLMappingModel.h     \
+
+libWOXML_OBJC_FILES += \
+       WOXMLDecoder.m          \
+       \
+       WOXMLMapDecoder.m       \
+       WOXMLMappingEntity.m    \
+       WOXMLMappingModel.m     \
+       WOXMLMappingProperty.m  \
+       WOXMLSaxModelHandler.m  \
+
+libWOXML_HEADER_FILES_DIR         = .
+libWOXML_HEADER_FILES_INSTALL_DIR = /WOXML
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/WOXML/GNUmakefile.preamble b/skyrix-sope/WOXML/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..06370f4
--- /dev/null
@@ -0,0 +1,24 @@
+# $Id$
+
+libWOXML_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libWOXML_INCLUDE_DIRS += -I. -I..
+
+libWOXML_LIBRARIES_DEPEND_UPON += -lDOM -lSaxObjC
+
+ADDITIONAL_LIB_DIRS += \
+       -L../../skyrix-xml/DOM/$(GNUSTEP_OBJ_DIR)       \
+       -L../../skyrix-xml/SaxObjC/$(GNUSTEP_OBJ_DIR)   \
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libWOXML_PREBIND_ADDR="0xC5B00000"
+libWOXML_LDFLAGS += -seg1addr $(libWOXML_PREBIND_ADDR)
+endif
+
+# Windows
+
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+libWOXML_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
diff --git a/skyrix-sope/WOXML/README b/skyrix-sope/WOXML/README
new file mode 100644 (file)
index 0000000..718e1a9
--- /dev/null
@@ -0,0 +1,9 @@
+# $Id$
+
+WOXML
+=====
+
+This directory contains a reimplementation of the WOXML framework in
+Objective-C.
+It is discouraged to use this framework in OGo, its intended for legacy
+ObjC web applications. Please let us know whether it works for you.
diff --git a/skyrix-sope/WOXML/Version b/skyrix-sope/WOXML/Version
new file mode 100644 (file)
index 0000000..6b227f7
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=5
diff --git a/skyrix-sope/WOXML/WOXML-Info.plist b/skyrix-sope/WOXML/WOXML-Info.plist
new file mode 100644 (file)
index 0000000..75913ea
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>WOXML</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.SOPE.WOXML</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-sope/WOXML/WOXML.h b/skyrix-sope/WOXML/WOXML.h
new file mode 100644 (file)
index 0000000..a67e214
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOXML_H__
+#define __WOXML_H__
+
+#include <WOXML/WOXMLDecoder.h>
+#include <WOXML/WOXMLMappingEntity.h>
+#include <WOXML/WOXMLMappingModel.h>
+#include <WOXML/WOXMLMappingProperty.h>
+
+#endif /* __WOXML_H__ */
diff --git a/skyrix-sope/WOXML/WOXMLDecoder.h b/skyrix-sope/WOXML/WOXMLDecoder.h
new file mode 100644 (file)
index 0000000..7a85a06
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOXML_WOXMLDecoder_H__
+#define __WOXML_WOXMLDecoder_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSData, NSFileHandle;
+
+@interface WOXMLDecoder : NSObject
+
++ (id)xmlDecoderWithMapping:(NSString *)_mapURL;
+
+/* root object */
+
+- (id)decodeRootObjectFromData:(NSData *)_data;
+- (id)decodeRootObjectFromString:(NSString *)_str;
+- (id)decodeRootObjectFromFileHandle:(NSFileHandle *)_fh;
+
+@end
+
+#endif /* __WOXML_WOXMLDecoder_H__ */
diff --git a/skyrix-sope/WOXML/WOXMLDecoder.m b/skyrix-sope/WOXML/WOXMLDecoder.m
new file mode 100644 (file)
index 0000000..a4f8ecf
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <WOXML/WOXMLDecoder.h>
+#include "WOXMLMappingModel.h"
+#include "WOXMLMapDecoder.h"
+#include <DOM/DOMDocument.h>
+#include "common.h"
+
+#if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
+@interface NSObject(Miss)
+- (id)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+@implementation WOXMLDecoder
+
++ (id)xmlDecoderWithMapping:(NSString *)_mapURL {
+  WOXMLMappingModel *model;
+
+  if ((model = [WOXMLMappingModel mappingModelByParsingFromURL:_mapURL]) == nil)
+    return nil;
+
+  return AUTORELEASE([[WOXMLMapDecoder alloc] initWithModel:model]);
+}
+
+/* root object */
+
+- (id)decodeRootObjectFromString:(NSString *)_str {
+  return [self subclassResponsibility:_cmd];
+}
+- (id)decodeRootObjectFromData:(NSData *)_data {
+  return [self subclassResponsibility:_cmd];
+}
+
+- (id)decodeRootObjectFromFileHandle:(NSFileHandle *)_fh {
+  return [self decodeRootObjectFromData:[_fh readDataToEndOfFile]];
+}
+
+@end /* WOXMLDecoder */
diff --git a/skyrix-sope/WOXML/WOXMLMapDecoder.h b/skyrix-sope/WOXML/WOXMLMapDecoder.h
new file mode 100644 (file)
index 0000000..9a63e9f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOXML_WOXMLMapDecoder_H__
+#define __WOXML_WOXMLMapDecoder_H__
+
+#include <WOXML/WOXMLDecoder.h>
+
+@class WOXMLMappingModel;
+
+@interface WOXMLMapDecoder : WOXMLDecoder
+{
+  WOXMLMappingModel *model;
+}
+
+- (id)initWithModel:(WOXMLMappingModel *)_model;
+
+@end
+
+#endif /* __WOXML_WOXMLMapDecoder_H__ */
diff --git a/skyrix-sope/WOXML/WOXMLMapDecoder.m b/skyrix-sope/WOXML/WOXMLMapDecoder.m
new file mode 100644 (file)
index 0000000..7c75fdf
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOXMLMapDecoder.h"
+#include "WOXMLMappingModel.h"
+#include "WOXMLMappingEntity.h"
+#include "WOXMLMappingProperty.h"
+#include "common.h"
+
+#include <DOM/DOMElement.h>
+#include <DOM/DOMDocument.h>
+
+@implementation WOXMLMapDecoder
+
+- (id)initWithModel:(id)_model {
+  self->model = RETAIN(_model);
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->model);
+  [super dealloc];
+}
+
+- (WOXMLMappingEntity *)defaultEntity {
+  return nil;
+}
+
+- (id)_processDOMElementNode:(id)_node {
+  WOXMLMappingEntity *entity;
+  Class        entityClass;
+  id           object;
+  NSMutableSet *childTags;
+  
+  NSAssert1([_node nodeType] == DOM_ELEMENT_NODE,
+            @"passed invalid element node: %@", _node);
+  
+  if ((entity = [self->model entityForXmlTag:[_node tagName]]) == nil) {
+    /* missing entity */
+    entity = [self defaultEntity];
+  }
+  if (entity == nil)
+    return [_node textValue];
+  
+  entityClass = NSClassFromString([entity name]);
+  if (entityClass == Nil) entityClass = [NSMutableDictionary class];
+  
+  object = AUTORELEASE([[entityClass alloc] init]);
+
+  childTags = [NSMutableSet setWithCapacity:16];
+  
+  /* apply properties */
+  {
+    NSEnumerator *e;
+    WOXMLMappingProperty *prop;
+    
+    e = [[entity properties] objectEnumerator];
+    while ((prop = [e nextObject])) {
+      if (![prop isValid])
+        continue;
+      
+      if ([prop attribute]) {
+        /* an attribute property */
+        NSString *attrName;
+        NSString *value;
+        
+        attrName = [prop xmlTag];
+
+        if ((value = [_node attribute:attrName]) == nil)
+          value = [_node attribute:attrName namespaceURI:@"*"];
+        
+        if (value)
+          [object takeValue:value forKey:[prop name]];
+      }
+      else
+        [childTags addObject:[prop xmlTag]];
+    }
+  }
+  
+  /* walk children */
+  {
+    unsigned i, count;
+    id childNodes;
+    NSMutableDictionary *d;
+
+    d = [NSMutableDictionary dictionaryWithCapacity:16];
+    
+    childNodes = [_node childNodes];
+    for (i = 0, count = [childNodes count]; i < count; i++) {
+      id child;
+      
+      child = [childNodes objectAtIndex:i];
+
+      if ([child nodeType] == DOM_ELEMENT_NODE) {
+        if ([childTags containsObject:[child tagName]]) {
+          /* a property */
+          WOXMLMappingProperty *prop;
+          id o;
+          
+          prop = [entity propertyForXmlTag:[child tagName]];
+          
+          o = [self _processDOMElementNode:child];
+          if (o == nil)
+            o = [EONull null];
+
+          if ([prop forceList]) {
+            NSMutableArray *a;
+
+            a = [d objectForKey:[prop name]];
+            if (a == nil) {
+              a = [NSMutableArray arrayWithCapacity:1];
+              [d setObject:a forKey:[prop name]];
+            }
+            [a addObject:o];
+          }
+          else {
+            id old;
+            
+            if ((old = [d objectForKey:[prop name]])) {
+              if ([old isKindOfClass:[NSMutableArray class]])
+                [old addObject:o];
+              else {
+                NSMutableArray *a;
+
+                a = [NSMutableArray arrayWithCapacity:2];
+                [a addObject:old];
+                [a addObject:o];
+                [d setObject:a forKey:[prop name]];
+              }
+            }
+            else {
+              /* first element */
+              [d setObject:o forKey:[prop name]];
+            }
+          }
+        }
+        else {
+          /* plain content tag */
+        }
+      }
+      else {
+      }
+    }
+    [object takeValuesFromDictionary:d];
+  }
+  
+  return object;
+}
+
+- (id)_processDOMDocument:(id)_dom {
+  return [self _processDOMElementNode:[_dom documentElement]];
+}
+
+/* parsing DOM tree */
+
+- (id)decodeRootObjectFromString:(NSString *)_str {
+  id doc;
+  
+  doc = [DOMDocument documentFromString:_str];
+  
+  return [self _processDOMDocument:doc];
+}
+
+- (id)decodeRootObjectFromData:(NSData *)_data {
+  id doc;
+  
+  doc = [DOMDocument documentFromData:_data];
+  
+  return [self _processDOMDocument:doc];
+}
+- (id)decodeRootObjectFromFileHandle:(NSFileHandle *)_fh {
+  return [self decodeRootObjectFromData:[_fh readDataToEndOfFile]];
+}
+
+@end /* WOXMLMapDecoder */
diff --git a/skyrix-sope/WOXML/WOXMLMappingEntity.h b/skyrix-sope/WOXML/WOXMLMappingEntity.h
new file mode 100644 (file)
index 0000000..9ad6695
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOXMLMappingEntity_H__
+#define __WOXMLMappingEntity_H__
+
+#import <Foundation/NSObject.h>
+
+@class WOXMLMappingProperty;
+@class NSMutableArray, NSString, NSMutableDictionary, NSArray;
+
+@interface WOXMLMappingEntity : NSObject
+{
+  NSMutableArray      *properties;
+  NSMutableDictionary *tagToProperty;
+  
+  NSString *name;
+  NSString *xmlTag;
+  NSString *unmappedTagsKey;
+  BOOL     ignoreUnmappedTags;
+  NSString *contentsKey;
+}
+
+- (BOOL)isValid;
+
+/* attributes */
+
+- (void)setName:(NSString *)_name;
+- (NSString *)name;
+- (void)setXmlTag:(NSString *)_xmlTag;
+- (NSString *)xmlTag;
+- (void)setUnmappedTagsKey:(NSString *)_unmappedTagsKey;
+- (NSString *)unmappedTagsKey;
+- (void)setContentsKey:(NSString *)_contentsKey;
+- (NSString *)contentsKey;
+- (void)setIgnoreUnmappedTags:(BOOL)_flag;
+- (BOOL)ignoreUnmappedTags;
+
+/* properties */
+
+- (void)addProperty:(WOXMLMappingProperty *)_property;
+- (WOXMLMappingProperty *)propertyForXmlTag:(NSString *)_xmlTag;
+- (NSArray *)properties;
+
+@end
+
+#endif /* __WOXMLMappingEntity_H__ */
diff --git a/skyrix-sope/WOXML/WOXMLMappingEntity.m b/skyrix-sope/WOXML/WOXMLMappingEntity.m
new file mode 100644 (file)
index 0000000..fc5563c
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOXMLMappingEntity.h"
+#include "WOXMLMappingProperty.h"
+#include "common.h"
+
+@implementation WOXMLMappingEntity
+
+- (void)dealloc {
+  RELEASE(self->name);
+  RELEASE(self->xmlTag);
+  RELEASE(self->unmappedTagsKey);
+  RELEASE(self->contentsKey);
+  RELEASE(self->properties);
+  [super dealloc];
+}
+
+/* validity */
+
+- (BOOL)isValid {
+  if ([self->name length] == 0)
+    return NO;
+  if ([self->xmlTag length] == 0)
+    return NO;
+  return YES;
+}
+
+/* attributes */
+
+- (void)setName:(NSString *)_name {
+  ASSIGN(self->name, _name);
+}
+- (NSString *)name {
+  return self->name;
+}
+
+- (void)setXmlTag:(NSString *)_xmlTag {
+  ASSIGN(self->xmlTag, _xmlTag);
+}
+- (NSString *)xmlTag {
+  return self->xmlTag;
+}
+
+- (void)setUnmappedTagsKey:(NSString *)_unmappedTagsKey {
+  ASSIGN(self->unmappedTagsKey, _unmappedTagsKey);
+}
+- (NSString *)unmappedTagsKey {
+  return self->unmappedTagsKey;
+}
+
+- (void)setContentsKey:(NSString *)_contentsKey {
+  ASSIGN(self->contentsKey, _contentsKey);
+}
+- (NSString *)contentsKey {
+  return self->contentsKey;
+}
+
+- (void)setIgnoreUnmappedTags:(BOOL)_flag {
+  self->ignoreUnmappedTags = _flag;
+}
+- (BOOL)ignoreUnmappedTags {
+  return self->ignoreUnmappedTags;
+}
+
+/* properties */
+
+- (void)addProperty:(WOXMLMappingProperty *)_property {
+  NSAssert1([_property isValid], @"tried to add invalid property %@", _property);
+  
+  if (self->properties == nil)
+    self->properties = [[NSMutableArray alloc] init];
+  if (self->tagToProperty == nil)
+    self->tagToProperty = [[NSMutableDictionary alloc] init];
+  
+  if ([self->tagToProperty objectForKey:[_property xmlTag]]) {
+    NSLog(@"WARNING: already defined propery for tag %@", [_property xmlTag]);
+    return;
+  }
+
+  [self->properties    addObject:_property];
+  [self->tagToProperty setObject:_property forKey:[_property xmlTag]];
+}
+
+- (WOXMLMappingProperty *)propertyForXmlTag:(NSString *)_xmlTag {
+  return [self->tagToProperty objectForKey:_xmlTag];
+}
+
+- (NSArray *)properties {
+  return self->properties;
+}
+
+/* XML representation */
+
+- (NSString *)xmlStringValue {
+  NSMutableString *s;
+  NSEnumerator *e;
+  id prop;
+
+  s = [NSMutableString stringWithCapacity:4096];
+  [s appendString:@"<entity"];
+  [s appendString:@" name='"];
+  [s appendString:[self name]];
+  [s appendString:@"' xmlTag='"];
+  [s appendString:[self xmlTag]];
+  [s appendString:@"'"];
+  [s appendString:@">\n"];
+  
+  e = [[self properties] objectEnumerator];
+  while ((prop = [e nextObject]))
+    [s appendString:[prop xmlStringValue]];
+  
+  [s appendString:@"</entity>\n"];
+  return s;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+
+  s = [NSMutableString stringWithCapacity:100];
+  [s appendFormat:@"<%@ 0x%08X:", NSStringFromClass([self class]), self];
+
+  if ([self name])
+    [s appendFormat:@" name=%@", [self name]];
+  if ([self xmlTag])
+    [s appendFormat:@" tag=%@", [self xmlTag]];
+  if ([self unmappedTagsKey])
+    [s appendFormat:@" unmapped=%@", [self unmappedTagsKey]];
+  if ([self contentsKey])
+    [s appendFormat:@" content=%@", [self contentsKey]];
+  
+  if (self->ignoreUnmappedTags)
+    [s appendString:@" ignore-unmapped"];
+  
+  [s appendString:@">"];
+  return s;
+}
+
+@end /* WOXMLMappingEntity */
diff --git a/skyrix-sope/WOXML/WOXMLMappingModel.h b/skyrix-sope/WOXML/WOXMLMappingModel.h
new file mode 100644 (file)
index 0000000..ba1d374
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOXMLMappingModel_H__
+#define __WOXMLMappingModel_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSMutableArray, NSMutableDictionary, NSArray;
+@class WOXMLMappingEntity;
+
+@interface WOXMLMappingModel : NSObject
+{
+  NSMutableArray      *entities;
+  NSMutableDictionary *tagToEntity;
+  NSMutableDictionary *tagToAttribute;
+}
+
++ (id)mappingModelByParsingFromURL:(NSString *)_url;
+
+/* entities */
+
+- (void)addEntity:(WOXMLMappingEntity *)_entity;
+- (WOXMLMappingEntity *)entityForXmlTag:(NSString *)_xmlTag;
+- (NSArray *)entities;
+
+@end
+
+#endif /* __WOXMLMappingModel_H__ */
diff --git a/skyrix-sope/WOXML/WOXMLMappingModel.m b/skyrix-sope/WOXML/WOXMLMappingModel.m
new file mode 100644 (file)
index 0000000..5205362
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOXMLMappingModel.h"
+#include "WOXMLMappingEntity.h"
+#include "WOXMLSaxModelHandler.h"
+#include <SaxObjC/SaxXMLReader.h>
+#include <SaxObjC/SaxXMLReaderFactory.h>
+#include "common.h"
+
+@implementation WOXMLMappingModel
+
++ (id)mappingModelByParsingFromURL:(NSString *)_url {
+  id<NSObject,SaxXMLReader> parser;
+  WOXMLSaxModelHandler      *sax;
+  WOXMLMappingModel         *model;
+  
+  if ([_url length] == 0)
+    /* invalid URL */
+    return nil;
+  
+  parser = [[SaxXMLReaderFactory standardXMLReaderFactory] createXMLReader];
+  if (parser == nil)
+    /* couldn't create parser */
+    return nil;
+  
+  sax = [[WOXMLSaxModelHandler alloc] init];
+  [parser setContentHandler:sax];
+  [parser setErrorHandler:sax];
+  
+  [parser parseFromSystemId:_url];
+  
+  model = RETAIN([sax model]);
+  RELEASE(sax);
+  
+  return AUTORELEASE(model);
+}
+
+- (void)dealloc {
+  RELEASE(self->tagToEntity);
+  RELEASE(self->entities);
+  [super dealloc];
+}
+
+/* entities */
+
+- (void)addEntity:(WOXMLMappingEntity *)_entity {
+  NSAssert1([_entity isValid], @"tried to add invalid entity %@", _entity);
+  
+  if (self->entities == nil)
+    self->entities = [[NSMutableArray alloc] init];
+  if (self->tagToEntity == nil)
+    self->tagToEntity = [[NSMutableDictionary alloc] init];
+  
+  if ([self->tagToEntity objectForKey:[_entity xmlTag]]) {
+    NSLog(@"WARNING: already defined entity for tag %@", [_entity xmlTag]);
+    return;
+  }
+  
+  [self->entities    addObject:_entity];
+  [self->tagToEntity setObject:_entity forKey:[_entity xmlTag]];
+}
+
+- (WOXMLMappingEntity *)entityForXmlTag:(NSString *)_xmlTag {
+  return [self->tagToEntity objectForKey:_xmlTag];
+}
+
+- (NSArray *)entities {
+  return self->entities;
+}
+
+/* XML representation */
+
+- (NSString *)xmlStringValue {
+  NSMutableString *s;
+  NSEnumerator *e;
+  id entity;
+
+  s = [NSMutableString stringWithCapacity:4096];
+  [s appendString:@"<model>\n"];
+  
+  e = [[self entities] objectEnumerator];
+  while ((entity = [e nextObject]))
+    [s appendString:[entity xmlStringValue]];
+  
+  [s appendString:@"</model>\n"];
+  return s;
+}
+
+@end /* WOXMLMappingModel */
diff --git a/skyrix-sope/WOXML/WOXMLMappingProperty.h b/skyrix-sope/WOXML/WOXMLMappingProperty.h
new file mode 100644 (file)
index 0000000..d8a0f48
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOXMLMappingProperty_H__
+#define __WOXMLMappingProperty_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+@class WOXMLMappingEntity;
+
+@interface WOXMLMappingProperty : NSObject
+{
+  WOXMLMappingEntity *entity;
+  NSString *name;
+  NSString *xmlTag;
+  BOOL     attribute;         /* used during encoding */
+  BOOL     forceList;         /* decoding only        */
+  NSString *codeBasedOn;
+  BOOL     reportEmptyValues; /* decoding only        */
+  NSString *outputTags;       /* encoding only ?      */
+}
+
+- (id)initWithEntity:(WOXMLMappingEntity *)_entity;
+
+/* validity */
+
+- (BOOL)isValid;
+
+/* attributes */
+
+- (void)setName:(NSString *)_name;
+- (NSString *)name;
+- (void)setXmlTag:(NSString *)_xmlTag;
+- (NSString *)xmlTag;
+- (void)setCodeBasedOn:(NSString *)_codeBasedOn;
+- (NSString *)codeBasedOn;
+- (void)setOutputTags:(NSString *)_tags;
+- (NSString *)outputTags;
+- (void)setAttribute:(BOOL)_flag;
+- (BOOL)attribute;
+- (void)setForceList:(BOOL)_flag;
+- (BOOL)forceList;
+- (void)setReportEmptyValues:(BOOL)_flag;
+- (BOOL)reportEmptyValues;
+
+@end
+
+#endif /* __WOXMLMappingProperty_H__ */
diff --git a/skyrix-sope/WOXML/WOXMLMappingProperty.m b/skyrix-sope/WOXML/WOXMLMappingProperty.m
new file mode 100644 (file)
index 0000000..5327192
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOXMLMappingProperty.h"
+#include "common.h"
+
+@implementation WOXMLMappingProperty
+
+- (id)initWithEntity:(WOXMLMappingEntity *)_entity {
+  self->entity = _entity;
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->name);
+  RELEASE(self->xmlTag);
+  RELEASE(self->codeBasedOn);
+  RELEASE(self->outputTags);
+  [super dealloc];
+}
+
+/* validity */
+
+- (BOOL)isValid {
+  if ([self->name length] == 0)
+    return NO;
+  if ([self->xmlTag length] == 0)
+    return NO;
+  return YES;
+}
+
+- (WOXMLMappingEntity *)entity {
+  return self->entity;
+}
+
+/* attributes */
+
+- (void)setName:(NSString *)_name {
+  ASSIGN(self->name, _name);
+}
+- (NSString *)name {
+  return self->name;
+}
+
+- (void)setXmlTag:(NSString *)_xmlTag {
+  ASSIGN(self->xmlTag, _xmlTag);
+}
+- (NSString *)xmlTag {
+  return self->xmlTag;
+}
+
+- (void)setCodeBasedOn:(NSString *)_codeBasedOn {
+  ASSIGN(self->codeBasedOn, _codeBasedOn);
+}
+- (NSString *)codeBasedOn {
+  return self->codeBasedOn;
+}
+
+- (void)setOutputTags:(NSString *)_tags {
+  ASSIGN(self->outputTags, _tags);
+}
+- (NSString *)outputTags {
+  return self->outputTags;
+}
+
+- (void)setAttribute:(BOOL)_flag {
+  self->attribute = _flag;
+}
+- (BOOL)attribute {
+  return self->attribute;
+}
+
+- (void)setForceList:(BOOL)_flag {
+  self->forceList = _flag;
+}
+- (BOOL)forceList {
+  return self->forceList;
+}
+
+- (void)setReportEmptyValues:(BOOL)_flag {
+  self->reportEmptyValues = _flag;
+}
+- (BOOL)reportEmptyValues {
+  return self->reportEmptyValues;
+}
+
+/* XML representation */
+
+- (NSString *)xmlStringValue {
+  NSMutableString *s;
+  
+  s = [NSMutableString stringWithCapacity:100];
+  [s appendString:@"<property"];
+  [s appendString:@" name='"];
+  [s appendString:[self name]];
+  [s appendString:@"' xmlTag='"];
+  [s appendString:[self xmlTag]];
+  [s appendString:@"'"];
+  
+  if ([self reportEmptyValues])
+    [s appendString:@" reportEmptyValues='YES'"];
+  if ([self forceList])
+    [s appendString:@" forceList='YES'"];
+  if ([self attribute])
+    [s appendString:@" attribute='YES'"];
+  
+  [s appendString:@"/>\n"];
+  return s;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+
+  s = [NSMutableString stringWithCapacity:100];
+  [s appendFormat:@"<%@ 0x%08X:", NSStringFromClass([self class]), self];
+
+  if ([self name])
+    [s appendFormat:@" name=%@", [self name]];
+  if ([self xmlTag])
+    [s appendFormat:@" tag=%@", [self xmlTag]];
+  if ([self codeBasedOn])
+    [s appendFormat:@" codeBasedOn=%@", [self codeBasedOn]];
+  if ([self outputTags])
+    [s appendFormat:@" out-tags=%@", [self outputTags]];
+
+  if ([self attribute])
+    [s appendString:@" attribute"];
+  if ([self forceList])
+    [s appendString:@" forceList"];
+  if ([self reportEmptyValues])
+    [s appendString:@" reportEmptyValues"];
+  
+  [s appendString:@">"];
+  return s;
+}
+
+@end /* WOXMLMappingProperty */
diff --git a/skyrix-sope/WOXML/WOXMLSaxModelHandler.h b/skyrix-sope/WOXML/WOXMLSaxModelHandler.h
new file mode 100644 (file)
index 0000000..8d8f78c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOXMLSaxModelHandler_H__
+#define __WOXMLSaxModelHandler_H__
+
+#include <SaxObjC/SaxDefaultHandler.h>
+
+@class WOXMLMappingProperty, WOXMLMappingModel, WOXMLMappingEntity;
+
+@interface WOXMLSaxModelHandler : SaxDefaultHandler
+{
+  WOXMLMappingModel    *currentModel;
+  WOXMLMappingEntity   *currentEntity;
+  WOXMLMappingProperty *currentProperty;
+}
+
+- (WOXMLMappingModel *)model;
+
+@end
+
+#endif /* __WOXMLSaxModelHandler_H__ */
diff --git a/skyrix-sope/WOXML/WOXMLSaxModelHandler.m b/skyrix-sope/WOXML/WOXMLSaxModelHandler.m
new file mode 100644 (file)
index 0000000..689077c
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "WOXMLSaxModelHandler.h"
+#include "WOXMLMappingEntity.h"
+#include "WOXMLMappingModel.h"
+#include "WOXMLMappingProperty.h"
+#include "common.h"
+
+@implementation WOXMLSaxModelHandler
+
+- (void)dealloc {
+  RELEASE(self->currentModel);
+  RELEASE(self->currentProperty);
+  RELEASE(self->currentEntity);
+  [super dealloc];
+}
+
+- (WOXMLMappingModel *)model {
+  return AUTORELEASE(RETAIN(self->currentModel));
+}
+
+/* tag handler */
+
+- (void)startModel:(id<SaxAttributes>)_attrs {
+  if ((self->currentProperty != nil) || (self->currentEntity != nil)) {
+    NSLog(@"cannot nest 'model' tags inside property or entity tags !");
+    return;
+  }
+
+  RELEASE(self->currentModel); self->currentModel = nil;
+  self->currentModel = [[WOXMLMappingModel alloc] init];
+}
+- (void)endModel {
+  if ((self->currentProperty != nil) || (self->currentEntity != nil))
+    return;
+}
+
+- (void)startEntity:(id<SaxAttributes>)_attrs {
+  NSString *s;
+  
+  if (self->currentProperty) {
+    NSLog(@"cannot nest 'entity' tags inside property tags !");
+    return;
+  }
+  if (self->currentEntity) {
+    NSLog(@"cannot nest 'entity' tags inside entity tags !");
+    return;
+  }
+  if (self->currentModel == nil) {
+    NSLog(@"missing 'model' parent element for 'entity' tag !");
+    return;
+  }
+  
+  self->currentEntity = [[WOXMLMappingEntity alloc] init];
+  
+  if ((s = [_attrs valueForRawName:@"name"]))
+    [self->currentEntity setName:s];
+  if ((s = [_attrs valueForRawName:@"xmlTag"]))
+    [self->currentEntity setXmlTag:s];
+  if ((s = [_attrs valueForRawName:@"unmappedTagsKey"]))
+    [self->currentEntity setUnmappedTagsKey:s];
+  if ((s = [_attrs valueForRawName:@"contentsKey"]))
+    [self->currentEntity setContentsKey:s];
+  
+  if ((s = [_attrs valueForRawName:@"ignoreUnmappedTags"])) {
+    [self->currentEntity setIgnoreUnmappedTags:
+         [[s uppercaseString] isEqualToString:@"YES"]];
+  }
+}
+- (void)endEntity {
+  if ((self->currentProperty != nil) || (self->currentModel == nil))
+    return;
+  
+  if (self->currentEntity) {
+    if ([self->currentEntity isValid])
+      [self->currentModel addEntity:self->currentEntity];
+    RELEASE(self->currentEntity); self->currentEntity = nil;
+  }
+}
+
+- (void)startProperty:(id<SaxAttributes>)_attrs {
+  NSString *s;
+  
+  if (self->currentProperty) {
+    NSLog(@"cannot nest 'property' tags inside property tags !");
+    return;
+  }
+  if ((self->currentEntity == nil) || (self->currentModel == nil)) {
+    NSLog(@"missing 'entity' parent element for 'property' tag !");
+    return;
+  }
+
+  self->currentProperty = [[WOXMLMappingProperty alloc] init];
+
+  if ((s = [_attrs valueForRawName:@"name"]))
+    [self->currentProperty setName:s];
+  if ((s = [_attrs valueForRawName:@"xmlTag"]))
+    [self->currentProperty setXmlTag:s];
+  if ((s = [_attrs valueForRawName:@"codeBasedOn"]))
+    [self->currentProperty setCodeBasedOn:s];
+  if ((s = [_attrs valueForRawName:@"outputTags"]))
+    [self->currentProperty setOutputTags:s];
+  
+  if ((s = [_attrs valueForRawName:@"attribute"])) {
+    [self->currentProperty setAttribute:
+         [[s uppercaseString] isEqualToString:@"YES"]];
+  }
+  if ((s = [_attrs valueForRawName:@"forceList"])) {
+    [self->currentProperty setForceList:
+         [[s uppercaseString] isEqualToString:@"YES"]];
+  }
+  if ((s = [_attrs valueForRawName:@"reportEmptyValues"])) {
+    [self->currentProperty setReportEmptyValues:
+         [[s uppercaseString] isEqualToString:@"YES"]];
+  }
+}
+- (void)endProperty {
+  if ((self->currentEntity == nil) || (self->currentModel == nil))
+    return;
+
+  if (self->currentProperty) {
+    if ([self->currentProperty isValid])
+      [self->currentEntity addProperty:self->currentProperty];
+
+    RELEASE(self->currentProperty); self->currentProperty = nil;
+  }
+}
+
+/* SAX */
+
+- (void)startDocument {
+  RELEASE(self->currentModel);    self->currentModel    = nil;
+  RELEASE(self->currentEntity);   self->currentEntity   = nil;
+  RELEASE(self->currentProperty); self->currentProperty = nil;
+}
+- (void)endDocument {
+}
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attrs
+{
+  if ([_rawName isEqualToString:@"model"])
+    [self startModel:_attrs];
+  else if ([_rawName isEqualToString:@"entity"])
+    [self startEntity:_attrs];
+  else if ([_rawName isEqualToString:@"property"])
+    [self startProperty:_attrs];
+}
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  if ([_rawName isEqualToString:@"model"])
+    [self endModel];
+  else if ([_rawName isEqualToString:@"entity"])
+    [self endEntity];
+  else if ([_rawName isEqualToString:@"property"])
+    [self endProperty];
+}
+
+@end /* WOXMLSaxModelHandler */
diff --git a/skyrix-sope/WOXML/common.h b/skyrix-sope/WOXML/common.h
new file mode 100644 (file)
index 0000000..47a9c0a
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __WOXML_common_H__
+#define __WOXML_common_H__
+
+#import <Foundation/Foundation.h>
+
+#if NeXT_Foundation_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#endif
+
+#include <EOControl/EONull.h>
+
+#endif /* __WOXML_common_H__ */
diff --git a/skyrix-sope/WOXML/samples/slashdot/GNUmakefile b/skyrix-sope/WOXML/samples/slashdot/GNUmakefile
new file mode 100644 (file)
index 0000000..928527d
--- /dev/null
@@ -0,0 +1,13 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+TOOL_NAME = woslash
+
+woslash_OBJC_FILES = \
+       woslash.m       \
+       SlashDotStory.m \
+
+woslash_TOOL_LIBS += -lNGObjWeb -lWOXML
+
+include $(GNUSTEP_MAKEFILES)/tool.make
diff --git a/skyrix-sope/WOXML/samples/slashdot/SlashDotStory.m b/skyrix-sope/WOXML/samples/slashdot/SlashDotStory.m
new file mode 100644 (file)
index 0000000..4b01de6
--- /dev/null
@@ -0,0 +1,111 @@
+// $Id$
+
+#include <Foundation/NSObject.h>
+
+@class NSString, NSCalendarDate;
+
+@interface SlashDotStory : NSObject
+{
+  NSString       *title;
+  NSString       *url;
+  NSCalendarDate *time;
+  NSString       *author;
+  NSString       *department;
+  NSString       *topic;
+  unsigned       numberOfComments;
+  NSString       *section;
+  NSString       *image;
+}
+@end
+
+#import <Foundation/Foundation.h>
+
+@implementation SlashDotStory
+
+- (void)setTitle:(NSString *)_value {
+  ASSIGN(self->title, _value);
+}
+- (NSString *)title {
+  return self->title;
+}
+
+- (void)setUrl:(NSString *)_value {
+  ASSIGN(self->url, _value);
+}
+- (NSString *)url {
+  return self->url;
+}
+
+- (void)setTime:(NSCalendarDate *)_value {
+  if (![_value isKindOfClass:[NSCalendarDate class]]) {
+    NSString *svalue;
+    
+    svalue = [[_value description] stringByAppendingString:@" GMT"];
+    _value = [NSCalendarDate dateWithString:svalue
+                             calendarFormat:@"%Y-%m-%d %H:%M:%S %Z"];
+  }
+  ASSIGN(self->time, _value);
+}
+- (NSCalendarDate *)time {
+  return self->time;
+}
+
+- (void)setAuthor:(NSString *)_value {
+  ASSIGN(self->author, _value);
+}
+- (NSString *)author {
+  return self->author;
+}
+
+- (void)setDepartment:(NSString *)_value {
+  ASSIGN(self->department, _value);
+}
+- (NSString *)department {
+  return self->department;
+}
+
+- (void)setTopic:(NSString *)_topic {
+  ASSIGN(self->topic, _topic);
+}
+- (NSString *)topic {
+  return self->topic;
+}
+
+- (void)setNumberOfComments:(unsigned)_count {
+  self->numberOfComments = _count;
+}
+- (unsigned)numberOfComments {
+  return self->numberOfComments;
+}
+
+- (void)setSection:(NSString *)_section {
+  ASSIGN(self->section, _section);
+}
+- (NSString *)section {
+  return self->section;
+}
+
+- (void)setImage:(NSString *)_image {
+  ASSIGN(self->image, _image);
+}
+- (NSString *)image {
+  return self->image;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+
+  s = [NSMutableString stringWithCapacity:200];
+
+  [s appendFormat:@"<%@[0x%08X]: author=%@ topic=%@ title='%@'>",
+       NSStringFromClass([self class]), self,
+       [self topic],
+       [self title],
+       [self author]];
+  
+  return s;
+}
+
+@end /* SlashDotStory */
diff --git a/skyrix-sope/WOXML/samples/slashdot/slashdot.xmlmodel b/skyrix-sope/WOXML/samples/slashdot/slashdot.xmlmodel
new file mode 100644 (file)
index 0000000..187565c
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+
+<model>
+
+  <entity xmlTag="backslash" name="NSMutableDictionary">
+    <property xmlTag="story" name="stories" forceList="YES"/>
+  </entity>
+  
+  <entity xmlTag="story" name="SlashDotStory">
+    <property xmlTag="title"      name="title"/>
+    <property xmlTag="url"        name="url"/>
+    <property xmlTag="time"       name="time"/>
+    <property xmlTag="author"     name="author"/>
+    <property xmlTag="department" name="department"/>
+    <property xmlTag="topic"      name="topic"/>
+    <property xmlTag="comments"   name="numberOfComments"/>
+    <property xmlTag="section"    name="section"/>
+    <property xmlTag="image"      name="image"/>
+  </entity>
+
+</model>
diff --git a/skyrix-sope/WOXML/samples/slashdot/woslash.m b/skyrix-sope/WOXML/samples/slashdot/woslash.m
new file mode 100644 (file)
index 0000000..f6ee63c
--- /dev/null
@@ -0,0 +1,77 @@
+// $Id$
+
+#import <Foundation/Foundation.h>
+#import <NGObjWeb/NGObjWeb.h>
+#import <WOXML/WOXMLDecoder.h>
+#import <DOM/DOMSaxBuilder.h>
+#import <DOM/DOMXMLOutputter.h>
+
+static void test(void) {
+  WOHTTPConnection *http;
+  WORequest  *request;
+  WOResponse *response;
+  NSData     *content;
+
+  http = [[WOHTTPConnection alloc] initWithHost:@"slashdot.org" onPort:80];
+  AUTORELEASE(http);
+
+  request = [[WORequest alloc] initWithMethod:@"GET"
+                               uri:@"/slashdot.xml"
+                               httpVersion:@"HTTP/1.0"
+                               headers:nil
+                               content:nil
+                               userInfo:nil];
+  AUTORELEASE(request);
+
+  if (![http sendRequest:request]) {
+    NSLog(@"couldn't send HTTP request");
+    return;
+  }
+
+  if ((response = [http readResponse]) == nil) {
+    NSLog(@"couldn't read HTTP response");
+    return;
+  }
+  
+  content = [response content];
+
+  /* WOXMLDecoder */
+  if ([content length] > 0) {
+    WOXMLDecoder *decoder;
+    id result;
+    
+    decoder = [WOXMLDecoder xmlDecoderWithMapping:@"file://slashdot.xmlmodel"];
+    result  = [decoder decodeRootObjectFromData:content];
+    
+    NSLog(@"./:\n %@", result);
+  }
+
+#if 0
+  /* DOM */
+  {
+    id doc;
+    id builder, outputter;
+    builder   = [[[DOMSaxBuilder   alloc] init] autorelease];
+    outputter = [[[DOMXMLOutputter alloc] init] autorelease];
+  
+    doc = [builder buildFromData:content];
+    NSLog(@"parsed: %@", doc);
+  
+    [outputter outputDocument:doc to:nil];
+  }
+#endif
+}
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  pool = [[NSAutoreleasePool alloc] init];
+  test();
+  RELEASE(pool);
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-sope/common.make b/skyrix-sope/common.make
new file mode 100644 (file)
index 0000000..f766594
--- /dev/null
@@ -0,0 +1,20 @@
+# $Id: common.make,v 1.3 2004/06/27 19:04:59 helge Exp $
+
+include $(GNUSTEP_MAKEFILES)/common.make
+include ../Version
+-include ./Version
+
+GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT)
+
+ADDITIONAL_CPPFLAGS += -pipe -Wall -Wno-protocol
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I..                    \
+       -I../../skyrix-core/    \
+       -I../../skyrix-core/NGExtensions
+
+ADDITIONAL_LIB_DIRS += -L./$(GNUSTEP_OBJ_DIR)
+
+ifeq ($(FOUNDATION_LIB),nx)
+ADDITIONAL_LDFLAGS += -framework Foundation
+endif
diff --git a/skyrix-sope/samples/.cvsignore b/skyrix-sope/samples/.cvsignore
new file mode 100644 (file)
index 0000000..9f1ee7c
--- /dev/null
@@ -0,0 +1,2 @@
+WOExtTest
+perftest
diff --git a/skyrix-sope/samples/COPYING b/skyrix-sope/samples/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-sope/samples/ChangeLog b/skyrix-sope/samples/ChangeLog
new file mode 100644 (file)
index 0000000..bf1ff0d
--- /dev/null
@@ -0,0 +1,13 @@
+2004-02-29  Helge Hess  <helge.hess@opengroupware.org>
+
+       * added the HelloWorld application example - the simplest application 
+         possible ;-)
+
+2003-10-15  Helge Hess  <helge.hess@skyrix.com>
+
+       * added "davpropget" example - useful for fetching DAV properties from
+         a DAV server and an example which demonstrates the usage of 
+         WOHTTPConnection
+       
+       * created ChangeLog
+
diff --git a/skyrix-sope/samples/GNUmakefile b/skyrix-sope/samples/GNUmakefile
new file mode 100644 (file)
index 0000000..59c11b7
--- /dev/null
@@ -0,0 +1,12 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECTS += \
+       davpropget      \
+       parsedav        \
+       WOxExtTest      \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/aggregate.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/samples/HelloWorld/ChangeLog b/skyrix-sope/samples/HelloWorld/ChangeLog
new file mode 100644 (file)
index 0000000..afee3e2
--- /dev/null
@@ -0,0 +1,8 @@
+2004-06-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * added GNUmakefile.preamble with static library dependencies for
+         Mach linker
+
+       * created ChangeLog
+
+
diff --git a/skyrix-sope/samples/HelloWorld/GNUmakefile b/skyrix-sope/samples/HelloWorld/GNUmakefile
new file mode 100644 (file)
index 0000000..7581d32
--- /dev/null
@@ -0,0 +1,12 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+WOAPP_NAME = HelloWorld
+
+HelloWorld_OBJC_FILES += HelloWorld.m Main.m
+HelloWorld_COMPONENTS += Main.wo
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/woapp.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/samples/HelloWorld/GNUmakefile.preamble b/skyrix-sope/samples/HelloWorld/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..9667a62
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id$
+
+# static references required for Mach linker
+
+ADDITIONAL_TOOL_LIBS += \
+       -lNGJavaScript -lNGScripting    \
+       -lEOControl                     \
+       -lDOM -lXmlRpc -lSaxObjC        \
+       -ljs
+
diff --git a/skyrix-sope/samples/HelloWorld/HelloWorld.m b/skyrix-sope/samples/HelloWorld/HelloWorld.m
new file mode 100644 (file)
index 0000000..f0fa342
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  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$
+
+#include <NGObjWeb/NGObjWeb.h>
+
+@interface HelloWorld : WOApplication
+{
+}
+
+@end
+
+#include "common.h"
+
+@implementation HelloWorld
+@end /* HelloWorld */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  WOApplicationMain(@"HelloWorld", argc, (void*)argv);
+
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-sope/samples/HelloWorld/Main.m b/skyrix-sope/samples/HelloWorld/Main.m
new file mode 100644 (file)
index 0000000..b4b296b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSArray;
+
+@interface Main : WOComponent
+{
+  NSArray *items;
+  id      item;
+}
+
+@end
+
+#include "common.h"
+
+@implementation Main
+
+- (id)initWithContext:(id)_ctx {
+  if ((self = [super initWithContext:_ctx])) {
+    NSMutableArray *ma;
+    int i;
+
+    ma = [[NSMutableArray alloc] init];
+    for (i = 0; i < 1000; i++) {
+      char buf[16];
+      NSString *s;
+      sprintf(buf, "%i", i);
+      s = [[NSString alloc] initWithCString:buf];
+      [ma addObject:s];
+      [s release];
+    }
+    self->items = ma;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->items release];
+  [self->item  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setItem:(id)_item {
+  ASSIGN(self->item, _item);
+}
+- (id)item {
+  return self->item;
+}
+
+- (NSArray *)list {
+  return self->items;
+}
+
+/* response generation */
+
+- (void)appendToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  NSDate *s;
+
+  s = [NSDate date];
+  [super appendToResponse:_r inContext:_ctx];
+  printf("duration: %.3f\n", [[NSDate date] timeIntervalSinceDate:s]);
+}
+
+@end /* Main */
diff --git a/skyrix-sope/samples/HelloWorld/Main.wo/Main.html b/skyrix-sope/samples/HelloWorld/Main.wo/Main.html
new file mode 100644 (file)
index 0000000..bbca2e3
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+  <HEAD>
+    <META NAME="generator" CONTENT="SOPE 4.2">
+    <TITLE>Hello World</TITLE>
+  </HEAD>
+  <BODY BGCOLOR="#FFFFFF">
+    <h2>Hello World</h2>
+
+    Application Name: 
+    <#AppName/> (Hash),
+    <WEBOBJECT NAME="AppName"></WEBOBJECT> (WO)
+  </BODY>
+</HTML>
diff --git a/skyrix-sope/samples/HelloWorld/Main.wo/Main.wod b/skyrix-sope/samples/HelloWorld/Main.wo/Main.wod
new file mode 100644 (file)
index 0000000..23343ce
--- /dev/null
@@ -0,0 +1,5 @@
+// $Id: Main.wod,v 1.2 2004/02/29 18:43:44 helge Exp $
+
+AppName: WOString {
+  value = application.name;
+}
\ No newline at end of file
diff --git a/skyrix-sope/samples/HelloWorld/common.h b/skyrix-sope/samples/HelloWorld/common.h
new file mode 100644 (file)
index 0000000..d196da1
--- /dev/null
@@ -0,0 +1,4 @@
+// $Id$
+
+#import <Foundation/Foundation.h>
+#include <NGObjWeb/NGObjWeb.h>
diff --git a/skyrix-sope/samples/TestPages/ChangeLog b/skyrix-sope/samples/TestPages/ChangeLog
new file mode 100644 (file)
index 0000000..646283a
--- /dev/null
@@ -0,0 +1,3 @@
+2004-06-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * created app from HelloWorld as a container for testing pages
\ No newline at end of file
diff --git a/skyrix-sope/samples/TestPages/GNUmakefile b/skyrix-sope/samples/TestPages/GNUmakefile
new file mode 100644 (file)
index 0000000..b591be8
--- /dev/null
@@ -0,0 +1,21 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+WOAPP_NAME = TestPages
+
+TestPages_OBJC_FILES += \
+       TestPages.m     \
+       Main.m          \
+       TwoForms.m
+
+TestPages_COMPONENTS += \
+       Main.wo         \
+       TwoForms.wo     \
+
+# for testing resources
+TestPages_RESOURCE_FILES  += $(TestPages_OBJC_FILES)
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/woapp.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/samples/TestPages/GNUmakefile.preamble b/skyrix-sope/samples/TestPages/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..9667a62
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id$
+
+# static references required for Mach linker
+
+ADDITIONAL_TOOL_LIBS += \
+       -lNGJavaScript -lNGScripting    \
+       -lEOControl                     \
+       -lDOM -lXmlRpc -lSaxObjC        \
+       -ljs
+
diff --git a/skyrix-sope/samples/TestPages/Main.m b/skyrix-sope/samples/TestPages/Main.m
new file mode 100644 (file)
index 0000000..f974aa7
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSArray;
+
+@interface Main : WOComponent
+{
+  NSArray *items;
+  id      item;
+}
+
+@end
+
+#include "common.h"
+
+@implementation Main
+
+- (id)initWithContext:(id)_ctx {
+  if ((self = [super initWithContext:_ctx])) {
+    NSMutableArray *ma;
+    int i;
+
+    ma = [[NSMutableArray alloc] init];
+    for (i = 0; i < 1000; i++) {
+      char buf[16];
+      NSString *s;
+      sprintf(buf, "%i", i);
+      s = [[NSString alloc] initWithCString:buf];
+      [ma addObject:s];
+      [s release];
+    }
+    self->items = ma;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->items release];
+  [self->item  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setItem:(id)_item {
+  ASSIGN(self->item, _item);
+}
+- (id)item {
+  return self->item;
+}
+
+- (NSArray *)list {
+  return self->items;
+}
+
+/* response generation */
+
+- (void)appendToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  NSDate *s;
+
+  s = [NSDate date];
+  [super appendToResponse:_r inContext:_ctx];
+  printf("duration: %.3f\n", [[NSDate date] timeIntervalSinceDate:s]);
+}
+
+@end /* Main */
diff --git a/skyrix-sope/samples/TestPages/Main.wo/Main.html b/skyrix-sope/samples/TestPages/Main.wo/Main.html
new file mode 100644 (file)
index 0000000..18300e0
--- /dev/null
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+  <HEAD>
+    <META NAME="generator" CONTENT="SOPE 4.2">
+    <TITLE>Hello World</TITLE>
+  </HEAD>
+  <BODY BGCOLOR="#FFFFFF">
+    <h2>Hello World</h2>
+
+    Application Name: 
+    <#AppName/> (Hash),
+    <WEBOBJECT NAME="AppName"></WEBOBJECT> (WO)
+
+    <hr />
+
+    <ul>
+      <li><#TwoFormsLink/></li>
+    </ul>
+  </BODY>
+</HTML>
diff --git a/skyrix-sope/samples/TestPages/Main.wo/Main.wod b/skyrix-sope/samples/TestPages/Main.wo/Main.wod
new file mode 100644 (file)
index 0000000..2f0986c
--- /dev/null
@@ -0,0 +1,10 @@
+// $Id: Main.wod,v 1.2 2004/06/15 10:35:11 helge Exp $
+
+AppName: WOString {
+  value = application.name;
+}
+
+TwoFormsLink: WOHyperlink {
+  pageName = "TwoForms";
+  string   = "two forms on one page";
+}
diff --git a/skyrix-sope/samples/TestPages/TestPages.m b/skyrix-sope/samples/TestPages/TestPages.m
new file mode 100644 (file)
index 0000000..59b0fa2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  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$
+
+#include <NGObjWeb/NGObjWeb.h>
+
+@interface TestPages : WOApplication
+{
+}
+
+@end
+
+#include "common.h"
+
+@implementation TestPages
+@end /* TestPages */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  WOApplicationMain(@"TestPages", argc, (void*)argv);
+
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-sope/samples/TestPages/TwoForms.m b/skyrix-sope/samples/TestPages/TwoForms.m
new file mode 100644 (file)
index 0000000..fd0b41c
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSArray;
+
+@interface TwoForms : WOComponent
+{
+  id selection1;
+  id selection2;
+  id item;
+}
+
+@end
+
+#include "common.h"
+
+@implementation TwoForms
+
+- (id)initWithContext:(WOContext *)_ctx {
+  if ((self = [super initWithContext:_ctx])) {
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->selection1 release];
+  [self->selection2 release];
+  [self->item       release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setItem:(id)_item {
+  ASSIGN(self->item, _item);
+}
+- (id)item {
+  return self->item;
+}
+
+- (void)setSelection1:(id)_value {
+  [self logWithFormat:@"set form 1 selection to: %@", _value];
+  ASSIGN(self->selection1, _value);
+}
+- (id)selection1 {
+  return self->selection1;
+}
+
+- (void)setSelection2:(id)_value {
+  [self logWithFormat:@"set form 2 selection to: %@", _value];
+  ASSIGN(self->selection2, _value);
+}
+- (id)selection2 {
+  return self->selection2;
+}
+
+/* actions */
+
+- (id)ok1 {
+  [self logWithFormat:@"OK: Form 1"];
+  return nil;
+}
+- (id)ok2 {
+  [self logWithFormat:@"OK: Form 2"];
+  return nil;
+}
+
+@end /* TwoForms */
diff --git a/skyrix-sope/samples/TestPages/TwoForms.wo/TwoForms.html b/skyrix-sope/samples/TestPages/TwoForms.wo/TwoForms.html
new file mode 100644 (file)
index 0000000..e601081
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <!-- $Id: TwoForms.html,v 1.2 2004/06/16 12:06:56 helge Exp $ -->
+  <head>
+    <title>Two Forms</title>
+  </head>
+
+  <body>
+    <h1>Two Forms on a single page</h1>
+    <i><#MainLink>Main</#MainLink></i>
+    <hr />
+
+    <#Form1>
+      Form1: <#PopUp1/><#Submit1/>
+    </#Form1>
+
+    <#Form2>
+      Form2: <#PopUp2/><#Submit2/>
+    </#Form2>
+
+    <hr />
+    Note: you need to set "WOFormAlwaysPassDown" to make that work properly!
+
+    <hr />
+    <address><a href="mailto:helge.hess@opengroupware.org">Helge Hess</a></address>
+<!-- Created: Tue Jun 15 12:15:36 CEST 2004 -->
+<!-- hhmts start -->
+Last modified: Tue Jun 15 12:40:49 CEST 2004
+<!-- hhmts end -->
+  </body>
+</html>
diff --git a/skyrix-sope/samples/TestPages/TwoForms.wo/TwoForms.wod b/skyrix-sope/samples/TestPages/TwoForms.wo/TwoForms.wod
new file mode 100644 (file)
index 0000000..d22b2a5
--- /dev/null
@@ -0,0 +1,32 @@
+// $Id: TwoForms.wod,v 1.1 2004/06/15 10:35:11 helge Exp $
+
+Form1: WOForm {
+}
+Form2: WOForm {
+}
+
+PopUp1: WOPopUpButton {
+  list            = ( a1, b1, c1, d1, e1 );
+  item            = item;
+  selection       = selection1;
+  singleSelection = YES;
+}
+PopUp2: WOPopUpButton {
+  list            = ( a2, b2, c2, d2, e2 );
+  item            = item;
+  selection       = selection2;
+  singleSelection = YES;
+}
+
+Submit1: WOSubmitButton {
+  value  = "ok1";
+  action = ok1;
+}
+Submit2: WOSubmitButton {
+  value = "ok2";
+  action = ok2;
+}
+
+MainLink: WOHyperlink {
+  pageName = "Main";
+}
diff --git a/skyrix-sope/samples/TestPages/common.h b/skyrix-sope/samples/TestPages/common.h
new file mode 100644 (file)
index 0000000..d196da1
--- /dev/null
@@ -0,0 +1,4 @@
+// $Id$
+
+#import <Foundation/Foundation.h>
+#include <NGObjWeb/NGObjWeb.h>
diff --git a/skyrix-sope/samples/TestSite/.sope.plist b/skyrix-sope/samples/TestSite/.sope.plist
new file mode 100644 (file)
index 0000000..7753c59
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  // site local defaults
+  WODebugEnabled = YES;
+}
diff --git a/skyrix-sope/samples/TestSite/ChangeLog b/skyrix-sope/samples/TestSite/ChangeLog
new file mode 100644 (file)
index 0000000..ace57e4
--- /dev/null
@@ -0,0 +1,8 @@
+2003-05-26  Helge Hess  <helge.hess@skyrix.com>
+
+       * added 'htpasswd', use -clientObject
+
+2003-05-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * created ChangeLog
+
diff --git a/skyrix-sope/samples/TestSite/Debug.xtmpl b/skyrix-sope/samples/TestSite/Debug.xtmpl
new file mode 100644 (file)
index 0000000..2288b76
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding">
+  <body bgcolor="#AAAACC">
+    <table border="0" cellpadding="4" cellspacing="0" bgcolor="#EEEEEE">
+      <tr>
+        <th colspan="2">Template: <var:string value="name"/></th>
+      </tr>
+      <tr bgcolor="#CCCCCC">
+        <td valign="top" align="right">clientObject:</td>
+        <td valign="top" align="left">
+          <var:string value="clientObject"/>
+        </td>
+      </tr>
+      <tr bgcolor="#CCCCCC">
+        <td valign="top" align="right">soClass:</td>
+        <td valign="top" align="left">
+          <var:string value="clientObject.soClass"/>
+        </td>
+      </tr>
+      <tr bgcolor="#CCCCCC">
+        <td valign="top" align="right">pageName:</td>
+        <td valign="top" align="left"><var:string value="context.page.name"/></td>
+      </tr>
+      <tr bgcolor="#CCCCCC">
+        <td valign="top" align="right">page:</td>
+        <td valign="top" align="left"><var:string value="context.page"/></td>
+      </tr>
+      
+      <tr><td height="4"></td></tr>
+      <tr>
+        <td bgcolor="white" colspan="2">
+          <var:component value="context.page"/>
+        </td>
+      </tr>
+      <tr><td height="4"></td></tr>
+
+      <tr>
+        <td colspan="2">
+          <a href="test.wox"   >test.wox</a>,
+          <a href="index.html" >index.html</a>,
+          <a href="/index.html">/index.html</a>,
+          <a href="embed.wox"  >embed.wox</a>,
+          <a href="accept.gif" >accept.gif</a>,
+          <a href="subdir"     >subdir</a>,
+          <a href="/subdir"    >/subdir</a>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="2">
+          traversal-stack:
+          <var:foreach list="context.objectTraversalStack" item="stackItem">
+            <li><var:string value="stackItem.nameInContainer" /></li>
+          </var:foreach>
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>
diff --git a/skyrix-sope/samples/TestSite/Main.xtmpl b/skyrix-sope/samples/TestSite/Main.xtmpl
new file mode 100644 (file)
index 0000000..eb4c94a
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding">
+  <head>
+    <title><var:string value="context.page.title"/></title>
+    
+    <meta name="lastChanged" var:content="clientObject.davLastModified"/>
+    <meta name="author"      content="SKYRIX Software AG"/>
+    <meta name="generator"   content="SKYRiX Object Publishing Environment"/>
+    <meta name="robots"      content="index, follow, all" />
+    
+    <link rel="shortcut icon" href="/favicon.ico" />
+    <link rel="stylesheet"    href="stylesheet.css" type="text/css" />
+    <link rev="made"          href="mailto:info@developer.skyrix.com" /> 
+  </head>
+  
+  <body bgcolor="white">
+    <table width="100%" cellpadding="0" cellspacing="0" border="0">
+      <tr>
+        <td width="462"><a target="_top" href="/index.html"
+         ><img border="0" src="images/banner_left.gif"/></a></td>
+        <td width="100%" 
+            background="images/banner_back.gif"><entity name="nbsp"/></td>
+        <td align="right" width="14"
+         ><img border="0" src="images/banner_right.gif"/></td>
+      </tr>
+    </table>
+    
+    <var:component value="context.page"/>
+    
+    <hr />
+    <var:foreach list="clientObject.container.toOneRelationshipKeys"
+                 item="sibling">
+      <var:string value="sibling" />
+    </var:foreach>
+  </body>
+</html>
diff --git a/skyrix-sope/samples/TestSite/Projects/Main.xtmpl b/skyrix-sope/samples/TestSite/Projects/Main.xtmpl
new file mode 100644 (file)
index 0000000..6af8cd9
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding"
+>
+  <head>
+    <title><var:string value="context.page.title"/></title>
+    
+    <meta name="lastChanged" var:content="clientObject.davLastModified"/>
+    <meta name="author"      content="SKYRIX Software AG"/>
+    <meta name="generator"   content="SKYRiX Object Publishing Environment"/>
+    <meta name="robots"      content="index, follow, all" />
+    
+    <link rel="shortcut icon" href="/favicon.ico" />
+
+    <!-- link rel="stylesheet"    href="stylesheet.css" type="text/css" / -->
+    <link rel="stylesheet"    href="blogstyle.css"  type="text/css" />
+
+    <link rev="made"          href="mailto:hh@skyrix.com" /> 
+  </head>
+  
+  <var:component value="context.page"/>
+</html>
diff --git a/skyrix-sope/samples/TestSite/Projects/OGoLogo.gif b/skyrix-sope/samples/TestSite/Projects/OGoLogo.gif
new file mode 100644 (file)
index 0000000..ea1b5f5
Binary files /dev/null and b/skyrix-sope/samples/TestSite/Projects/OGoLogo.gif differ
diff --git a/skyrix-sope/samples/TestSite/Projects/blogstyle.css b/skyrix-sope/samples/TestSite/Projects/blogstyle.css
new file mode 100644 (file)
index 0000000..68bff15
--- /dev/null
@@ -0,0 +1,88 @@
+/* movable type stuff */
+
+a        { color: #003366; text-decoration: underline; }
+a:link   { color: #003366; text-decoration: underline; }
+a:visited { color: #003366; text-decoration: underline; }
+a:active  { color: #999999;  }
+a:hover          { color: #999999;  }
+
+h1, h2, h3 {
+  margin:  0px;
+  padding: 0px;
+}
+
+div#banner {
+  font-family:   palatino,  georgia, verdana, arial, sans-serif;
+  color:         #333333;
+  font-size:     12pt;
+  font-weight:   normal;       
+  margin:        5px;
+  border-bottom: 1px solid #08348B;
+}
+
+div#banner a, div#banner a:link, div#banner a:visited, 
+div#banner a:active, div#banner h1 {
+  font-family:     palatino,  georgia, verdana, arial, sans-serif;
+  font-size:       12pt;
+  color:           #333333;
+  text-decoration: none;
+}
+div#banner a:hover {
+  font-family:     palatino,  georgia, verdana, arial, sans-serif;
+  font-size:       xx-large;
+  color:           #333333;
+  text-decoration: underline;
+}
+
+span.description {
+  font-family:    palatino,  georgia, times new roman, serif;
+  color:          #333333;
+  font-size:      small;
+  text-transform: none;        
+}
+
+div#content {
+  background: #FFFFFF;
+  border:     1px solid #FFFFFF;
+}
+
+div.blog {
+  padding:    15px;
+  background: #FFFFFF;
+}
+
+div.blogbody {
+  font-family: palatino, georgia, verdana, arial, sans-serif;
+  color:       #333333;
+  font-size:   small;
+  font-weight: normal;
+  background:  #FFFFFF;
+  line-height: 150%;
+}
+
+div.blogbody a,        div.blogbody a:link, div.blogbody a:visited,
+div.blogbody a:active, div.blogbody a:hover {
+  font-weight:     normal;
+  text-decoration: underline;
+}
+
+h3.title {
+  font-family: palatino, georgia, times new roman, serif;
+  font-size:   8pt;
+  color:       #666666;
+}                      
+h2.projecttitle { 
+  font-family:   palatino, georgia, times new roman, serif; 
+  font-size:     11pt; 
+  color:         #333333; 
+  border-bottom: 1px solid #08348B;
+  margin-bottom: 10px;
+  font-weight:   bold;
+}                      
+               
+div.projectowner { 
+  font-family:   verdana, arial, sans-serif; 
+  font-size:     x-small; 
+  color:         #000000; 
+  margin-bottom: 25px;
+}
diff --git a/skyrix-sope/samples/TestSite/Projects/index.wox b/skyrix-sope/samples/TestSite/Projects/index.wox
new file mode 100644 (file)
index 0000000..e808c59
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<body xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding"
+>
+
+<div id="banner">
+  <table border="0" width="100%">
+    <tr>
+      <td>
+  <h1><a href="accounts/helge/">Helge's</a> Projects</h1>
+  <span class="description"></span>
+      </td>
+      <td align="right">
+        <img src="OGoLogo.gif" alt="Logo" />
+      </td>
+    </tr>
+  </table>
+</div>
+
+<div id="content">
+  <div class="blog">
+
+    <!-- loop begin -->
+      <var:component className="projectcard" 
+       const:title="Sales - Internal"
+        const:subtitle="Blah Fasel"
+        const:leadurl="accounts/muenst/"
+        const:lead="Jens Muenster"
+        const:startdate="2003-09-10"
+      >
+        The Sales Internal Project collects information regarding the Sales 
+        process. Pricing information etc.
+      </var:component>
+
+      <var:component className="projectcard" 
+       const:title="Development"
+        const:subtitle="Junk Junn"
+        const:leadurl="accounts/helge/"
+        const:lead="Helge Hess"
+        const:startdate="2000-10-23"
+      >
+        OGo Development Information. asdhf jkasd skadfh j asdf
+        asd  jsdkfh asjdfh j asdhfjkasdh fjhsadf jshad fjash dfkj
+        asdfkj asdk aksd klasdjf k asdjf k asdfasdfj.
+      </var:component>
+
+    <!-- loop end -->
+
+  </div>
+</div>
+
+</body>
diff --git a/skyrix-sope/samples/TestSite/Projects/projectcard.wox b/skyrix-sope/samples/TestSite/Projects/projectcard.wox
new file mode 100644 (file)
index 0000000..4e9cc4e
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<span xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding"
+      class="projectcard"
+>
+      <h2 class="projecttitle"><var:string value="title" /></h2>
+      <div class="blogbody">
+        <h3 class="title"><var:string value="subtitle" /></h3>
+        <p><var:component-content/></p>
+        
+        <div class="projectowner">
+          Projectlead is <a var:href="leadurl"><var:string value="lead"/></a>, 
+          started at 2003-09-10.
+        </div>
+      </div>
+</span>
diff --git a/skyrix-sope/samples/TestSite/Projects/stylesheet.css b/skyrix-sope/samples/TestSite/Projects/stylesheet.css
new file mode 100644 (file)
index 0000000..2211ce0
--- /dev/null
@@ -0,0 +1,36 @@
+/* common stuff */
+
+body {
+  font-size: 12px;
+}
+
+/* header */
+
+div#header {
+  margin-left:  5px;
+  margin-right: 5px;
+  padding:      0;
+  border-bottom: 1px solid #000000;
+}
+div#header img.headerlogo {
+  float:  right; 
+  width:  182px; 
+  height: 30px;
+}
+
+div#header div#headerhistory {
+  font-size:   11px;
+  color:       #000000;
+  margin:      0px;
+  padding-top: 18px;
+  height:      12px;
+}
+div#header a, div#header span {
+  margin:      0px;
+}
+div#header span#navtitle {
+  font-weight: bold;
+}
+div#header a:hover {
+  text-decoration: none;
+}
diff --git a/skyrix-sope/samples/TestSite/README b/skyrix-sope/samples/TestSite/README
new file mode 100644 (file)
index 0000000..5cb5f9a
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+A small SOPE test site ...
diff --git a/skyrix-sope/samples/TestSite/accept.gif b/skyrix-sope/samples/TestSite/accept.gif
new file mode 100644 (file)
index 0000000..7afd377
Binary files /dev/null and b/skyrix-sope/samples/TestSite/accept.gif differ
diff --git a/skyrix-sope/samples/TestSite/embed.wox b/skyrix-sope/samples/TestSite/embed.wox
new file mode 100644 (file)
index 0000000..164ee00
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>\r
+<span xmlns="http://www.w3.org/1999/xhtml"\r
+      xmlns:var="http://www.skyrix.com/od/binding">\r
+  <small>I'm Embedded Component: <var:string value="self"/><br/>\r
+  On Client: <var:string value="clientObject"/></small>\r
+</span>\r
diff --git a/skyrix-sope/samples/TestSite/favicon.ico b/skyrix-sope/samples/TestSite/favicon.ico
new file mode 100644 (file)
index 0000000..d1065d3
Binary files /dev/null and b/skyrix-sope/samples/TestSite/favicon.ico differ
diff --git a/skyrix-sope/samples/TestSite/htpasswd b/skyrix-sope/samples/TestSite/htpasswd
new file mode 100644 (file)
index 0000000..f49f8e1
--- /dev/null
@@ -0,0 +1,2 @@
+root:sn0aIIKddfHxQ
+guest:WzkWlwFIGv6i.
diff --git a/skyrix-sope/samples/TestSite/images/banner-new.gif b/skyrix-sope/samples/TestSite/images/banner-new.gif
new file mode 100644 (file)
index 0000000..70d3592
Binary files /dev/null and b/skyrix-sope/samples/TestSite/images/banner-new.gif differ
diff --git a/skyrix-sope/samples/TestSite/images/banner.gif b/skyrix-sope/samples/TestSite/images/banner.gif
new file mode 100644 (file)
index 0000000..04c73fe
Binary files /dev/null and b/skyrix-sope/samples/TestSite/images/banner.gif differ
diff --git a/skyrix-sope/samples/TestSite/images/banner_back.gif b/skyrix-sope/samples/TestSite/images/banner_back.gif
new file mode 100644 (file)
index 0000000..af134d0
Binary files /dev/null and b/skyrix-sope/samples/TestSite/images/banner_back.gif differ
diff --git a/skyrix-sope/samples/TestSite/images/banner_left.gif b/skyrix-sope/samples/TestSite/images/banner_left.gif
new file mode 100644 (file)
index 0000000..cd6a53a
Binary files /dev/null and b/skyrix-sope/samples/TestSite/images/banner_left.gif differ
diff --git a/skyrix-sope/samples/TestSite/images/banner_right.gif b/skyrix-sope/samples/TestSite/images/banner_right.gif
new file mode 100644 (file)
index 0000000..d4812f8
Binary files /dev/null and b/skyrix-sope/samples/TestSite/images/banner_right.gif differ
diff --git a/skyrix-sope/samples/TestSite/index.html b/skyrix-sope/samples/TestSite/index.html
new file mode 100644 (file)
index 0000000..984633f
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>Welcome to SOPE - The SKYRiX Object Publishing Environment</title>
+  </head>
+
+  <body>
+    <h4>Welcome to SOPE - The SKYRiX Object Publishing Environment</h4>
+    <p>
+      This is a small demo site created using the SOPE server. It tries to
+      demonstrate various aspects of the system.
+    </p>
+    
+    <li><a href="index.html">index.html</a> (this page)
+    <li><a href="test.wox"  >test.wox</a>
+    <li><a href="embed.wox" >embed.wox</a>
+    <li><a href="accept.gif">accept.gif</a>
+    <li><a href="webfolders.xhtml">webfolders.xhtml</a>
+    
+    <hr />
+    <address><a href="mailto:helge.hess@skyrix.com">Helge Hess</a></address>
+<!-- Created: Tue Apr 15 22:07:22 CEST 2003 -->
+<!-- hhmts start -->
+Last modified: Fri May 30 16:28:17 CEST 2003
+<!-- hhmts end -->
+  </body>
+</html>
diff --git a/skyrix-sope/samples/TestSite/plisttest/Main.xtmpl b/skyrix-sope/samples/TestSite/plisttest/Main.xtmpl
new file mode 100644 (file)
index 0000000..3170ba4
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding">
+  <head>
+    <title><var:string value="context.page.title"/></title>
+    
+    <meta name="lastChanged" var:content="clientObject.davLastModified"/>
+    <meta name="author"      content="SKYRIX Software AG"/>
+    <meta name="generator"   content="SKYRiX Object Publishing Environment"/>
+    <meta name="robots"      content="index, follow, all" />
+    
+    <link rel="shortcut icon" href="/favicon.ico" />
+    <link rel="stylesheet"    href="stylesheet.css" type="text/css" />
+    <link rev="made"          href="mailto:info@developer.skyrix.com" /> 
+  </head>
+  
+  <body bgcolor="white">
+    <table width="100%" cellpadding="0" cellspacing="0" border="0">
+      <tr>
+        <td width="462"><a target="_top" href="/index.html"
+         ><img border="0" src="images/banner_left.gif"/></a></td>
+        <td width="100%" 
+            background="images/banner_back.gif"><entity name="nbsp"/></td>
+        <td align="right" width="14"
+         ><img border="0" src="images/banner_right.gif"/></td>
+      </tr>
+    </table>
+
+    <!-- process news (property list) item -->
+   <var:if condition="clientObject.soClassName" 
+           const:value="OFSPropertyListObject">
+    <br />
+    <br />
+    <table cellpadding="3" cellspacing="0">
+      <tr bgcolor="#ACACAC">
+        <th>Access as "context.page"</th>
+        <th>Access as "clientObject"</th>
+      </tr>
+      <tr>
+        <td>
+          <h4><var:string value="context.page.subject"/></h4>
+          Date:  <var:string value="context.page.date"/><br />
+          Color: <var:string value="context.page.color"/><br />
+          Object: <var:string value="context.page"/>
+        </td>
+        <td>
+          <h4><var:string value="clientObject.subject"/></h4>
+          Date:  <var:string value="clientObject.date"/><br />
+          Color: <var:string value="clientObject.color"/><br />
+          Object: <var:string value="clientObject"/>
+        </td>
+      </tr>
+    </table>
+   </var:if>
+    
+    <!-- process templates -->
+    <var:if condition="clientObject.soClassName" 
+            const:value="OFSPropertyListObject"
+            const:negate="YES">
+      <var:component value="context.page" />
+    </var:if>
+  </body>
+</html>
diff --git a/skyrix-sope/samples/TestSite/plisttest/MyNews1.plist b/skyrix-sope/samples/TestSite/plisttest/MyNews1.plist
new file mode 100644 (file)
index 0000000..5be08c5
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  date = 20031009;
+  subject = "SOPE as a CMS?";
+  color = "red";
+}
diff --git a/skyrix-sope/samples/TestSite/plisttest/MyNews2.plist b/skyrix-sope/samples/TestSite/plisttest/MyNews2.plist
new file mode 100644 (file)
index 0000000..f2c4b51
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  date = 20031010;
+  subject = "SOPE rocks as a CMS?";
+  color = "green";
+}
diff --git a/skyrix-sope/samples/TestSite/plisttest/index.wox b/skyrix-sope/samples/TestSite/plisttest/index.wox
new file mode 100644 (file)
index 0000000..4dc2e70
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<span xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding">
+  <h3>I'm the index page ...</h3>
+  
+  Client: <var:string value="clientObject"/>
+  <br />
+  PathInfo: <var:string value="context.PATHINFO"/>
+  <br />
+  <br />
+
+  <table border="0" cellpadding="3" cellspacing="0" width="100%">
+    <tr bgcolor="#AAAAAA">
+      <th align="left">Subject</th>
+      <th align="left">Date</th>
+      <th align="left">Color</th>
+    </tr>
+
+    <!-- var:foreach datasource="clientObject.contentDataSource"
+                 qualifier="category='news'"
+                 sortedby="date,-color" -->
+
+    <var:foreach list="clientObject.allValues">
+      <tr bgcolor="#DDDDDD">
+        <td><a var:href="nameInContainer"><var:string value="subject"/></a></td>
+        <td><var:string value="date"/></td>
+        <td><var:string value="color"/></td>
+      </tr>
+    </var:foreach>
+  </table>
+</span>
diff --git a/skyrix-sope/samples/TestSite/plone/Main.xtmpl b/skyrix-sope/samples/TestSite/plone/Main.xtmpl
new file mode 100644 (file)
index 0000000..353e84f
--- /dev/null
@@ -0,0 +1,416 @@
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding"
+      xml:lang="en" lang="en"
+>
+  <head>
+    <!-- CONFLICTS: meta http-equiv="Content-Type" content="text/html; charset=utf-8" / -->
+    <title>OGo Docs - BlahBlah</title>
+    
+    <!-- Basic crude style for Netscape4.x - This can be removed
+         if you don't want the special NS4 look - it will still work,
+        just be plain text instead. -->
+    <link rel="Stylesheet" type="text/css"
+          href="ploneNS4.css" />
+
+    <!-- Main style sheets for CSS2 capable browsers -->
+    <style type="text/css" media="all"> @import url(plone.css);</style>
+
+    <!-- Custom style sheet if available -->
+    <style type="text/css" media="all">@import url(ploneCustom.css);</style>
+
+    <!-- Style sheet used for printing -->
+    <link rel="stylesheet" type="text/css" media="print"
+          href="plonePrint.css" />
+
+    <!-- Style sheet used for presentations (Opera is the only browser supporting this at the moment) -->
+    <link rel="stylesheet" type="text/css"
+          media="projection"
+          href="plonePresentation.css" />
+
+    <link rel="shortcut icon"
+          href="../favicon.ico"
+          type="image/x-icon" />
+
+    <link rel="home" href="http://docs.opengroupware.org"
+          title="Front Page" />
+    <link rel="search"
+          href="http://docs.opengroupware.org/search_form"
+          title="Search this site" />
+    
+    <!-- Disable IE6 image toolbar -->
+    <!-- CONFLICTS: meta http-equiv="imagetoolbar" content="no" / -->
+    
+    <!-- Common Plone ECMAScripts -->
+    <script type="text/javascript" src="plone_javascripts.js" />
+    <script type="text/javascript" src="plone_formtooltip.js" />
+  </head>
+
+  <body>
+    <div>
+      <div class="top">
+         <div class="searchBox">
+            <form name="searchform"
+                  href="http://docs.opengroupware.org/search">
+
+                    <input id="searchGadget"
+                           name="SearchableText" type="text"
+                           size="20" tabindex="30001" />
+
+                    <input class="context searchButton"
+                           type="submit" value="Search"
+                           tabindex="30002" />
+                </form>
+            </div>
+
+            <a href="http://docs.opengroupware.org">
+                <img src="http://docs.opengroupware.org/logo.jpg?skin="
+                     class="logo" border="0" alt=""
+                     height="56" width="356" />
+            </a>
+        </div>
+
+        <hr size="" class="netscape4" />
+
+        <div class="tabs">
+            <a href="http://docs.opengroupware.org"
+               class="plain">
+                Welcome
+            </a>
+            <a href="http://docs.opengroupware.org/news"
+               class="plain">
+                News
+            </a>
+            <a href="http://docs.opengroupware.org/search_form"
+               class="plain">
+                Search
+            </a>
+            <a href="http://docs.opengroupware.org/docs"
+               class="plain">
+                User Docs
+            </a>
+            <a href="http://docs.opengroupware.org/develdocs"
+               class="plain">
+                Dev Docs
+            </a>
+            <a href="http://docs.opengroupware.org/support"
+               class="plain">
+                Support
+            </a>
+        </div>
+
+        <div class="personalBar"><entity name="nbsp" />
+            <span>You are not logged in</span>
+            
+            <a href="http://docs.opengroupware.org/login_form">
+                <img src="http://docs.opengroupware.org/linkOpaque.gif" alt="" title="" height="11" width="6" border="0" />
+
+                Log in
+            </a>
+            
+            
+            <a href="http://docs.opengroupware.org/portal_form/join_form">
+                <img src="http://docs.opengroupware.org/linkOpaque.gif" alt="" title="" height="11" width="6" border="0" />
+
+                Join
+            </a>
+            
+        </div>
+
+        <div class="pathBar">
+           You are here:
+                <a href="http://docs.opengroupware.org">Home</a>
+                <strong><entity name="raquo"/></strong>
+            <span>
+                <a href="http://docs.opengroupware.org/Members/view">Members</a>
+                <strong> <entity name="raquo"/> </strong>
+            </span>
+            <span>
+                <span>helge's Home</span>
+            </span>
+        </div>
+        <hr size="" class="netscape4" />
+    </div>
+
+<table class="columns">
+    <tbody>
+        <tr>
+            <td class="left">
+    <div class="box">
+        <h5>Navigation</h5>
+        <div class="body">
+            <div class="content odd">
+                <div style="white-space: nowrap;">
+                    <span>
+                        <a href="http://docs.opengroupware.org/"
+                           title="">
+                            <img src="http://docs.opengroupware.org/site_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" />OGo Docs
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        <entity name="nbsp" />
+                        <a href="http://docs.opengroupware.org/Members/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" />Members
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                           <span class="currentNavItem">
+                        </span>
+                        <a href="http://docs.opengroupware.org/Members/helge/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" /><span
+    class="currentNavItem">helge's Home</span>
+                        </a>
+                        
+                        
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <a href="http://docs.opengroupware.org/Members/helge/DocumentAPI/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" />DocumentAPI
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <a href="http://docs.opengroupware.org/Members/helge/Forms/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" />Forms
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <a href="http://docs.opengroupware.org/Members/helge/Logic/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" />Logic
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <a href="http://docs.opengroupware.org/Members/helge/Tools/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" />OGo Tools
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <a href="http://docs.opengroupware.org/Members/helge/Pictures/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" />Pictures
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                               
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <a href="http://docs.opengroupware.org/Members/helge/SOPE/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" />SOPE
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <a href="http://docs.opengroupware.org/Members/helge/xmlrpc/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" />XML-RPC
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <entity name="nbsp" />
+                        <a href="http://docs.opengroupware.org/Members/helge/ZideStore/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" /><entity name="nbsp" />ZideStore
+                        </a>
+                    </span>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <div class="box">
+        <h5>Log in</h5>
+        <div class="body">
+            <div class="content odd">
+                <form href="http://docs.opengroupware.org/logged_in"
+                      method="post">
+                    <strong>Name</strong> <br />
+                    <input type="text" name="__ac_name"
+                           size="12" tabindex="10001"
+                           value="" />
+                    <br />
+    
+                    <strong>Password</strong>  <br />
+                    <input type="password"
+                           name="__ac_password" size="12"
+                           tabindex="10002" />
+    
+                    <br />
+                    <entity name="nbsp" />
+                    <br />
+    
+                    <input class="context searchButton"
+                           type="submit" name="submit"
+                           value="Log in" tabindex="10003" />
+                </form>
+            </div>
+    
+            <div class="content even"> 
+                <a href="http://docs.opengroupware.org/mail_password_form">
+                   <img src="http://docs.opengroupware.org/linkTransparent.gif" alt="" title="" height="11" width="6" border="0" />
+                   Forgot your password?
+                </a>
+            </div>
+
+            <div class="content odd">
+          
+                <a href="http://docs.opengroupware.org/portal_form/join_form">
+                    <img src="http://docs.opengroupware.org/linkTransparent.gif" alt="" title="" height="11" width="6" border="0" />
+                    New user?
+                </a>
+            </div>
+        </div>
+    </div>
+
+    <div class="box">
+        <h5>About</h5>
+        <div class="body">
+            <div class="content odd">
+                <strong>Created by</strong> <br />
+                <img src="http://docs.opengroupware.org/user.gif" alt="" title="" height="12" width="8" border="0" />            
+                
+                <a href="http://docs.opengroupware.org/Members/chris">chris</a>
+            </div>
+        
+            <div class="content even">
+                <img src="http://docs.opengroupware.org/document_icon.gif"
+                     alt="Document" /><entity name="nbsp" />Document
+            </div>
+            
+            <div class="content odd">
+                <strong>Last modified</strong> <br />
+                2003-12-04
+            </div>
+        
+            <div class="content even">
+                <strong>State</strong> <br />
+                <span class="visible">visible</span>
+            </div>
+        </div>
+    </div>
+            </td>
+            <td class="main">
+                <div class="document">
+                    <div id="content">
+                        <div class="documentActions">
+                            <a href="javascript:this.print();">
+                                <img alt="Print"
+    src="http://docs.opengroupware.org/print_icon.gif"
+    title="Print this page" />
+                            </a>
+                        </div>
+
+  <!-- the content page -->
+  <var:component value="context.page"/>
+
+                        <div>
+</div>
+                    </div>
+                </div>
+            </td>
+        </tr>
+    </tbody>
+</table>
+
+<hr size="" class="netscape4" />
+
+<div class="footer">
+
+<a href="http://plone.org">
+<img src="http://docs.opengroupware.org/plone_powered.gif"
+     height="30" width="96" border="0"
+     alt="Powered by Plone"
+     title="This site was built using the Plone Content Management System. Click for more information." />
+</a>
+
+<!-- 
+     
+     Please keep the Plone Powered button (or a textual link to us) if you use 
+     Plone on your site. It's a nice token of gratitude, and we appreciate your
+     help in promoting the Plone name. 
+     
+     Plone is powered by the combined forces of Zope and CMF, two absolutely
+     great systems made by Zope Corporation (http://zope.com) and they in turn
+     are based on the best programming language in the world - Python
+     (http://www.python.org). We owe these guys a lot, thanks for making Plone
+     possible!
+     
+ -->
+
+<br />
+
+
+Plone is Copyright <entity name="copy"/> 2000-<span>2003</span>
+by
+<a href="http://limi.net">Alexander Limi</a>,
+<a href="http://www.runyaga.com">Alan Runyan</a>,
+<a href="http://blacktar.com">Vidar Andersen</a>.
+
+
+<hr size="" class="netscape4" />
+
+<strong class="netscape4">
+If you can read this text, it means you are not experiencing the Plone design at its best.
+Plone makes heavy use of CSS, which means it is accessible to any internet browser, 
+but the design needs a 
+<a href="http://www.webstandards.org/upgrade/">standards-compliant browser to look like we intended it</a>. 
+Just so you know ;)
+</strong>
+</div>
+  </body>
+</html>
diff --git a/skyrix-sope/samples/TestSite/plone/NOTES.txt b/skyrix-sope/samples/TestSite/plone/NOTES.txt
new file mode 100644 (file)
index 0000000..d5f836f
--- /dev/null
@@ -0,0 +1,17 @@
+view | edit | properties | state
+/Members/helge/index_html/document_view
+/Members/helge/index_html/portal_form/document_edit_form
+/Members/helge/index_html/portal_form/metadata_edit_form
+/Members/helge/index_html/portal_form/content_status_history
+
+Contents View | Item View
+http://docs.opengroupware.org/Members/helge/folder_contents
+http://docs.opengroupware.org/Members/helge/
+
+Edit POST action
+/Members/helge/index_html/portal_form/document_edit_form
+
+Prefs | Plone Setup
+/portal_form/personalize_form
+/portal_form/reconfig_form
+
diff --git a/skyrix-sope/samples/TestSite/plone/index.wox b/skyrix-sope/samples/TestSite/plone/index.wox
new file mode 100644 (file)
index 0000000..50bc265
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<div xmlns="http://www.w3.org/1999/xhtml"
+     xmlns:var="http://www.skyrix.com/od/binding"
+>
+  <h1>Blah Blah</h1>
+  
+  <div class="description">
+    My Blahblah Frontpage. Collecting all kinds of unorganized documentation 
+    in the directories below ...
+    <br />
+    NOTE: This is not Plone, its just a testpage for OGo SOPE.
+  </div>
+    
+  <p>
+    <em><a href="folder_contents">Switch Plone to contents view</a> to see the actual folder contents and skip this personal junk!</em>
+  </p>
+
+  <p>
+    Well, seems like I'm the project lead of OpenGroupware.org until I can 
+    pass over the job to someone more qualified and concentrate on development 
+    tasks ;-)
+  </p>
+  <p>
+    Please send me mail at 
+    <a href="mailto:hh@opengroupware.org">hh@opengroupware.org</a>.
+  </p>
+
+  <h4><a href="http://faculty.washington.edu/hhess/">My brothers website</a></h4>
+  <p>Recently got forwarded a mail by my precious brother ...</p>
+  <pre>
+    "I'd like to look at your work on your website but I can't because I use 
+    Linux.  I'm curious why you have such a strong 'only people with 
+    Microsoft software can see my site' approach.  It is one of the most 
+    aggressively anti open source sites I've come across."
+  </pre>
+  <p>... now if people only would understand that it is really hard to live 
+    in Seattle?!
+  </p>
+
+  <h4>OGo related articles ...</h4>
+  <li><a href="DocumentAPI/DocStorage/">OGo Project Document Stores</a></li>
+  <li><a href="SOPE/">What is SOPE?</a></li>
+
+  <h4>OGo Snippets</h4>
+  <li><a href="bundles/">Regarding OGo Bundles</a></li>
+  <li><a href="Profiling/">Profiling OGo</a></li>
+  <li><a href="WebUI/activation/">Component Activation</a></li>
+  <li><a href="ZideStore/ZideStore-URLs/">ZideStore Folders/URLs</a></li>
+
+  <h4>Cyrus Links</h4>
+  <p>
+    <a href="http://sourceforge.net/project/showfiles.php?group_id=33489&amp;release_id=91587">Cyrus Tools</a>
+  </p>
+</div>
diff --git a/skyrix-sope/samples/TestSite/plone/linkOpaque.gif b/skyrix-sope/samples/TestSite/plone/linkOpaque.gif
new file mode 100644 (file)
index 0000000..24010ec
Binary files /dev/null and b/skyrix-sope/samples/TestSite/plone/linkOpaque.gif differ
diff --git a/skyrix-sope/samples/TestSite/plone/linkTransparent.gif b/skyrix-sope/samples/TestSite/plone/linkTransparent.gif
new file mode 100644 (file)
index 0000000..c2dd10f
Binary files /dev/null and b/skyrix-sope/samples/TestSite/plone/linkTransparent.gif differ
diff --git a/skyrix-sope/samples/TestSite/plone/loggedin.html b/skyrix-sope/samples/TestSite/plone/loggedin.html
new file mode 100644 (file)
index 0000000..d131ee9
--- /dev/null
@@ -0,0 +1,490 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+      lang="en">
+  <head>
+    <meta http-equiv="Content-Type"
+          content="text/html;charset=utf-8" />
+    <title>OGo Docs - Helge Heß</title>
+       
+    <!-- Basic crude style for Netscape4.x - This can be removed
+         if you don't want the special NS4 look - it will still work,
+        just be plain text instead. -->
+    <link rel="Stylesheet" type="text/css"
+          href="ploneNS4.css" />
+
+    <!-- Main style sheets for CSS2 capable browsers -->
+    <style type="text/css" media="all"> @import url(plone.css);</style>
+
+    <!-- Custom style sheet if available -->
+    <style type="text/css" media="all">@import url(ploneCustom.css);</style>
+
+    <!-- Style sheet used for printing -->
+    <link rel="stylesheet" type="text/css" media="print"
+          href="plonePrint.css" />
+
+    <!-- Style sheet used for presentations (Opera is the only browser supporting this at the moment) -->
+    <link rel="stylesheet" type="text/css"
+          media="projection"
+          href="plonePresentation.css" />
+
+    <link rel="shortcut icon"
+          href="http://docs.opengroupware.org/favicon.ico"
+          type="image/x-icon" />
+
+    <link rel="home" href="http://docs.opengroupware.org"
+          title="Front Page" />
+    <link rel="search"
+          href="http://docs.opengroupware.org/search_form"
+          title="Search this site" />
+
+    <!-- Disable IE6 image toolbar -->
+    <meta http-equiv="imagetoolbar" content="no" />
+
+    <!-- Common Plone ECMAScripts -->
+    <script type="text/javascript" src="plone_javascripts.js"></script>
+    <script type="text/javascript" src="plone_formtooltip.js"></script>
+  </head>
+
+  <body>
+    <div>
+        <div class="top">
+            <div class="searchBox">
+                <form name="searchform"
+                      action="http://docs.opengroupware.org/search">
+                    <input id="searchGadget"
+                           name="SearchableText" type="text"
+                           size="20" tabindex="30001" />
+                    <input class="context searchButton"
+                           type="submit" value="Search"
+                           tabindex="30002" />
+                </form>
+            </div>
+
+            <a href="http://docs.opengroupware.org">
+                <img src="http://docs.opengroupware.org/logo.jpg?skin="
+                     class="logo" border="0" alt=""
+                     height="56" width="356" />
+            </a>
+        </div>
+
+        <hr size="" class="netscape4" />
+
+        <div class="tabs">
+            <a href="http://docs.opengroupware.org"
+               class="plain">Welcome</a>
+            <a href="http://docs.opengroupware.org/news"
+               class="plain">News</a>
+            <a href="http://docs.opengroupware.org/search_form"
+               class="plain">Search</a>
+            <a href="http://docs.opengroupware.org/docs"
+               class="plain">User Docs</a>
+            <a href="http://docs.opengroupware.org/develdocs"
+               class="plain">Dev Docs</a>
+            <a href="http://docs.opengroupware.org/support"
+               class="plain">Support</a>
+        </div>
+
+        <div class="personalBar">&nbsp;
+            <a href="http://docs.opengroupware.org/Members/helge">
+                <img src="http://docs.opengroupware.org/user.gif" alt="" title="" height="12" width="8" border="0" />
+                helge
+            </a>
+            <a href="http://docs.opengroupware.org/Members/helge/folder_contents">
+                <img src="http://docs.opengroupware.org/linkOpaque.gif" alt="" title="" height="11" width="6" border="0" />
+                My Folder
+            </a>
+            <a href="http://docs.opengroupware.org/portal_form/personalize_form">
+                <img src="http://docs.opengroupware.org/linkOpaque.gif" alt="" title="" height="11" width="6" border="0" />
+                My Preferences
+            </a>
+            <a href=" http://docs.opengroupware.org/undo_form">
+                <img src="http://docs.opengroupware.org/linkOpaque.gif" alt="" title="" height="11" width="6" border="0" />
+                Undo
+            </a>
+            <a href="http://docs.opengroupware.org/portal_form/reconfig_form">
+                <img src="http://docs.opengroupware.org/linkOpaque.gif" alt="" title="" height="11" width="6" border="0" />
+                Plone Setup
+            </a>
+            <a href="http://docs.opengroupware.org/logout">
+                <img src="http://docs.opengroupware.org/linkOpaque.gif" alt="" title="" height="11" width="6" border="0" />
+                Log out
+            </a>
+        </div>
+
+        <div class="pathBar">
+            <a href="http://docs.opengroupware.org/Members/helge/index_html/addtoFavorites">
+                <img src="http://docs.opengroupware.org/addFavorite.gif" alt="" title="Add this location to My Favorites" height="14" width="16" border="0" class="addFavorite" />
+            </a>
+           You are here:
+                <a href="http://docs.opengroupware.org">Home</a>
+                <strong>&raquo;</strong>
+            <span>
+                <a href="http://docs.opengroupware.org/Members/view">Members</a>
+                <strong> &raquo; </strong>
+            </span>
+            <span>
+                <span>helge's Home</span>
+            </span>
+        </div>
+
+        <hr size="" class="netscape4" />
+    </div>
+    <table class="columns">
+      <tbody>
+        <tr>
+            <td class="left">
+    <div class="box">
+        <h5>Navigation</h5>
+        <div class="body">
+                <div class="content even">
+                    <div>
+                        <a href="http://docs.opengroupware.org/Members/helge/folder_contents">
+                            <img src="http://docs.opengroupware.org/linkTransparent.gif" alt="" title="" height="11" width="6" border="0" />&nbsp;<span>Switch to Contents view</span>
+                        </a>
+                    </div>
+                </div>
+            <div class="content odd">
+                <div style="white-space: nowrap;">
+                    <span>
+                        <a href="http://docs.opengroupware.org/"
+                           title="">
+                            <img src="http://docs.opengroupware.org/site_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;OGo Docs
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/develdocs/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;Developer Docs
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;Members
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                           <span class="currentNavItem">
+                        </span>
+                        <a href="http://docs.opengroupware.org/Members/helge/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;<span
+    class="currentNavItem">helge's Home</span>
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/Configurations/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;Configurations
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/DocumentAPI/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;DocumentAPI
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/Forms/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;Forms
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/Logic/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;Logic
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/Tools/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;OGo Tools
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/.personal/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;Personal Items
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/Pictures/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;Pictures
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/SOPE/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;SOPE
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/WebUI/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;WebUI
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/xmlrpc/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;XML-RPC
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        &nbsp;
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/Members/helge/ZideStore/"
+                           class="plain" title="">
+                
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;ZideStore
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/support/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;Support
+                        </a>
+                    </span>
+                </div>
+                <div style="white-space: nowrap;">
+                    <span>
+                        &nbsp;
+                        <a href="http://docs.opengroupware.org/docs/"
+                           class="plain" title="">
+                            <img src="http://docs.opengroupware.org/folder_icon.gif" alt="" title="" height="16" width="16" border="0" />&nbsp;User Docs
+                        </a>
+                    </span>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <div class="box">
+        <h5>About</h5>
+        <div class="body">
+            <div class="content odd">
+                <strong>Created by</strong> <br />
+                <img src="http://docs.opengroupware.org/user.gif" alt="" title="" height="12" width="8" border="0" />            
+                <a href="http://docs.opengroupware.org/Members/chris">chris</a>
+            </div>
+            <div class="content even">
+                <img src="http://docs.opengroupware.org/document_icon.gif"
+                     alt="Document" />&nbsp;Document
+            </div>
+            <div class="content odd">
+                <strong>Last modified</strong> <br />
+                2003-12-04
+            </div>
+            <div class="content even">
+                <strong>State</strong> <br />
+                <span class="visible">visible</span>
+            </div>
+        </div>
+    </div>
+            </td>
+            <td class="main">
+                <div id="contentTabs">
+                        <a class="selected"
+                           href="http://docs.opengroupware.org/Members/helge/index_html/document_view">
+                            View
+                        </a>
+                        <a class="plain"
+                           href="http://docs.opengroupware.org/Members/helge/index_html/portal_form/document_edit_form">
+                            Edit
+                        </a>
+                        <a class="plain"
+                           href="http://docs.opengroupware.org/Members/helge/index_html/portal_form/metadata_edit_form">
+                            Properties
+                        </a>
+                        <a class="plain"
+                           href="http://docs.opengroupware.org/Members/helge/index_html/portal_form/content_status_history">
+                            State
+                        </a>
+                </div>
+                <div id="contentBar">
+                &nbsp;
+                </div>
+                <div class="editableDocument">
+                    <div id="content">
+                        <div class="documentActions">
+                            <a href="javascript:this.print();">
+                                <img alt="Print"
+    src="http://docs.opengroupware.org/print_icon.gif"
+    title="Print this page" />
+                            </a>
+                        </div>
+                        <div>
+    <h1>Helge Heß</h1>
+    <div class="description">Helge's OGo Plone Frontpage. Collecting all kinds of unorganized documentation in the directories below ...</div>
+        <p>\r
+<em><a href="folder_contents">Switch Plone to contents view</a> to see the actual folder contents and skip this personal junk!</em>\r
+</p>\r
+\r
+<p>\r
+  <a href="Pictures/"><img src="dresscode" alt="helge" align="right" border="2"/></a>\r
+  Well, seems like I'm the project lead of OpenGroupware.org until I can pass over\r
+  the job to someone more qualified and concentrate on development tasks ;-)\r
+</p>\r
+<p>\r
+  Besides that, I'm also the CTO (hear, hear) of\r
+  <a href="http://www.skyrix.com/" target="extlink">SKYRIX Software AG</a>,\r
+  a company I founded together with Jens E. and Jens M. in 2000. Before that (since\r
+  about 1994) I used to develop SKYRiX 3, various CMS and shopping tools at\r
+  <a href="http://www.mdlink.de/" target="extlink">MDlink</a>, a local ISP,\r
+  which attracted my interest by having a full set of NeXT machines. The ones\r
+  the Web was created on - and the ones which lead to the creation of OGo ;-)\r
+</p>\r
+<p>\r
+  Please send me mail at \r
+  <a href="mailto:hh@opengroupware.org">hh@opengroupware.org</a>.\r
+</p>\r
+<p>\r
+  <i>PS: yes, Helge is actually a firstname for boys in Germany ;-) While some people reported cases\r
+  where Helge is also used as a girls name, the usual "girl variant" of Helge is Helga (with a trailing "a").\r
+  I guess the origin is Swedish: <a href="http://www.fos.su.se/physical/aatto/helge/">Hälge</a>.\r
+  </i>\r
+</p>\r
+\r
+<h4>My Google Timeline - the E-Life?</h4>\r
+<p>\r
+  How retro ...: <a href="google_timeline">what I have done so far ...</a>\r
+</p>\r
+\r
+<h4><a href="http://faculty.washington.edu/hhess/">My brothers website</a></h4>\r
+<p>Recently got forwarded a mail by my precious brother ...</p>\r
+<pre>\r
+"I'd like to look at your work on your website but I can't because I use \r
+Linux.  I'm curious why you have such a strong 'only people with \r
+Microsoft software can see my site' approach.  It is one of the most \r
+aggressively anti open source sites I've come across."\r
+</pre>\r
+<p>... now if people only would understand that it is really hard to live in Seattle?!</p>\r
+\r
+<h4>OGo related articles ...</h4>\r
+<li><a href="DocumentAPI/DocStorage/">OGo Project Document Stores</a></li>\r
+<li><a href="SOPE/">What is SOPE?</a></li>\r
+\r
+<h4>OGo Snippets</h4>\r
+<li><a href="bundles/">Regarding OGo Bundles</a></li>\r
+<li><a href="Profiling/">Profiling OGo</a></li>\r
+<li><a href="WebUI/activation/">Component Activation</a></li>\r
+<li><a href="ZideStore/ZideStore-URLs/">ZideStore Folders/URLs</a></li>\r
+\r
+<h4>Cyrus Links</h4>\r
+<p>\r
+  <a href="http://sourceforge.net/project/showfiles.php?group_id=33489&release_id=91587">Cyrus Tools</a>\r
+</p>
+</div>
+                        <div>
+</div>
+                        
+                    </div>
+                </div>
+            </td>
+        </tr>
+    </tbody>
+</table>
+
+<hr size="" class="netscape4" />
+
+<div class="footer">
+
+<a href="http://plone.org">
+<img src="http://docs.opengroupware.org/plone_powered.gif"
+     height="30" width="96" border="0"
+     alt="Powered by Plone"
+     title="This site was built using the Plone Content Management System. Click for more information." />
+</a>
+
+<br />
+Plone is Copyright &copy; 2000-<span>2003</span>
+by
+<a href="http://limi.net">Alexander Limi</a>,
+<a href="http://www.runyaga.com">Alan Runyan</a>,
+<a href="http://blacktar.com">Vidar Andersen</a>.
+
+<hr size="" class="netscape4" />
+
+<strong class="netscape4">
+If you can read this text, it means you are not experiencing the Plone design at its best.
+Plone makes heavy use of CSS, which means it is accessible to any internet browser, 
+but the design needs a 
+<a href="http://www.webstandards.org/upgrade/">standards-compliant browser to look like we intended it</a>. 
+Just so you know ;)
+</strong>
+</div>
+</body>
+</html>
diff --git a/skyrix-sope/samples/TestSite/plone/plone.css b/skyrix-sope/samples/TestSite/plone/plone.css
new file mode 100644 (file)
index 0000000..4a1cbf8
--- /dev/null
@@ -0,0 +1,893 @@
+/* 
+** Plone style sheet for CSS2-capable browsers.
+** Copyright Alexander Limi, 2002 - http://limi.net
+**
+** Thanks to Geir Bækholt, Stian Søiland for input and guidance.
+**
+** Style sheet documentation can be found at http://plone.org/documentation
+**
+** You should preferrably use ploneCustom.css to add your own CSS classes and to
+** customize your portal, as these are the base fundaments of Plone, and will 
+** change and be refined in newer versions. Keeping your changes in
+** ploneCustom.css will make it easier to upgrade. 
+**
+** Feel free to use whole or parts of this for your own designs, but give credit
+** where credit is due.
+**
+*/
+
+
+/*
+**  DTML instructions to set caching headers. Inside comments area to play nicer with CSS editors.
+**
+** **   
+**   
+**   
+**   
+** */
+/*  */
+
+
+body {
+    font:       65% Verdana, Helvetica, Arial, sans-serif;
+    background: White;
+    color:      Black;
+    margin:     0;
+    padding:    0;
+/* These work in IE only, changes the look of the scrollbar + textareas */
+    scrollbar-base-color:       #DEE7EC;
+    scrollbar-highlight-color:  #DEE7EC;
+    scrollbar-track-color:      #F7F9FA;
+    scrollbar-darkshadow-color: #F7F9FA;
+    scrollbar-3dlight-color:    #8CACBB;
+    scrollbar-shadow-color:     #8CACBB;
+    scrollbar-arrow-color:      #436976;
+}
+
+table {
+    font-size: 100%;
+}
+
+a {
+    text-decoration:  none;
+    color:            #436976;
+    background-color: transparent;
+}
+
+table {
+
+}
+
+
+img {
+    border:         none;
+    vertical-align: middle;
+}
+
+p {
+    margin:      0.5em 0em 1em 0em;
+    text-align:  justify;
+    line-height: 1.5em;
+}
+
+p a {
+    text-decoration: underline;
+}
+
+p a:visited {
+       color: Purple;
+    background-color: transparent;
+}
+
+p a:active {
+       color: Red;
+    background-color: transparent;
+}
+
+p img {
+    border: 0;
+    margin: 0;
+}
+
+
+hr {
+    clear:  both;
+    height: 1px;
+    color:  #8CACBB;
+    background-color: transparent;
+}
+
+
+h1, h2, h3, h4, h5, h6 {
+    color:         Black;
+    clear:         left;
+    font:          100% Verdana, Helvetica, Arial, sans-serif;
+    margin:        0;
+    padding-top:   0.5em;
+    border-bottom: 1px solid #8CACBB;
+}
+
+h1 { font-size: 160%; }
+h2 { font-size: 150%; }
+h3 { font-size: 140%; }
+h4 { font-size: 120%; }
+h5 { font-size: 100%; }
+h6 { font-size: 80%;  }
+
+ul { 
+    line-height:     1.5em;
+    list-style-type: square;
+    margin:          0.5em 0 0 2em;
+    padding:         0;
+}
+
+ol {
+    line-height: 1.5em;
+    margin:      0.5em 0 0 2em;
+    padding:     0;
+}
+
+ul a, ol a {
+    text-decoration: underline;
+}
+
+li {
+    margin-bottom: 1em;
+}
+
+dl {
+}
+dt {
+    font-weight: bold;    
+}
+
+dt a {
+    text-decoration: underline;
+}
+
+
+dd {
+    line-height: 1.5em;
+    margin-bottom: 1em;
+}
+
+d a {
+    text-decoration: underline;
+}
+
+
+fieldset {
+    border: 1px solid #8cacbb;
+    margin: 2em 0em 1em 0em;
+    padding: 1em 0em;
+}
+
+legend {
+    background: White;
+    padding:    0.5em;
+}
+
+
+form {
+    border: none;
+    margin: 0;
+}
+
+textarea {
+    border:  1px solid #8cacbb;  
+    color:   Black;
+    background-color: white;
+    width:   88%;
+    padding: 0.1em;
+}
+
+input {
+    font:             100% Verdana, Helvetica, Arial, sans-serif;
+    border:           1px solid #8cacbb;  
+    color:            Black;
+    background-color: white;
+    vertical-align:   middle;
+    margin-bottom:    1px; /* IE bug fix */
+    padding:          0.1em;
+}
+
+select {
+    font:   100% Verdana, Helvetica, Arial, sans-serif;
+    border: 1px solid #8cacbb;  
+    vertical-align: top;
+}
+
+abbr, acronym, .explain {
+    border-bottom:    1px dotted Black;
+    color:            Black;
+    background-color: transparent;
+    cursor:           help;
+}
+
+q {
+    font-family: Times, "Times New Roman", serif;
+    font-style:  italic;
+    font-size:   120%;
+}
+
+blockquote {
+    font-family: Times, "Times New Roman", serif; 
+    font-style:  italic;
+    font-size:   120%;
+}
+
+code {
+    font-size:        120%;
+    color:            Black;
+    background-color: #dee7ec;
+}
+
+pre {
+    font-size: 120%;
+    padding:   1em;
+    border:    1px solid #8cacbb;
+    color:     Black;
+    background-color: #dee7ec;
+}
+
+.netscape4 {
+    display: none;
+}
+
+/*
+** Structural Elements
+*/
+
+div.top {
+    /* Top section */
+    background: transparent;
+    margin:     0;
+    padding:    0;
+}
+
+.logo {
+    /* Logo properties */
+    margin:  1em 0em 1em 2em;
+    padding: 0;
+}
+
+div.searchBox {
+    /*searchbox style and positioning */
+    background-color: transparent;
+    color:          Black;
+    float:          right;
+    margin:         3em 0em 0em 0em;
+    padding:        0em 2em 0em 0em;
+    text-align:     right;
+    text-transform: lowercase;
+    width:          30%;
+}
+
+input.searchButton {
+    font-size:     100% ! important;
+    margin-bottom: 1px ! important;
+}
+
+div.tabs {
+    /* Navigational Plone Tabs(tm), implemented by customizing the a tag - they are surprisingly elegant. The power of CSS runs strong in these :) */
+    background:          transparent;
+    border-collapse:     collapse;
+    border-bottom-color: #8CACBB;
+    border-bottom-style: solid;
+    border-bottom-width: 1px;
+    padding:             0.5em 0em 0em 2em;
+    white-space:         nowrap;
+}
+
+div.tabs a {
+    /* The normal, unselected tabs. They are all links */
+    background:     transparent;
+    border-color:   #8CACBB;
+    border-width:   1px; 
+    border-style:   solid solid none solid;
+    color:          #436976;
+    font-weight:    normal;
+    height:         1.2em;
+    margin-right:   0.5em;
+    padding:        0em 2em;
+    text-transform: lowercase;
+}
+
+div.tabs a.selected {
+    /* The selected tab. There's only one of this */
+    background:    #DEE7EC;
+    border:        1px solid #8CACBB;
+    border-bottom: #DEE7EC 1px solid;
+    color:         #436976;
+    font-weight:   normal;
+}
+
+div.tabs a:hover {
+    background:   #DEE7EC;
+    border-color: #8CACBB;
+    border-bottom-color: #DEE7EC;
+    color:        #436976;
+}
+
+div.personalBar {
+    /* Bar with personalized menu (user preferences, favorites etc) */
+    background:          #DEE7EC;
+    border-bottom-color: #8CACBB;
+    border-bottom-style: solid;
+    border-bottom-width: 1px;
+    color:          Black;
+    padding-right:  3em;
+    text-align:     right;
+    text-transform: lowercase;
+}
+
+div.personalBar a {
+    background-color: transparent;
+    color:       #436976;
+    font-weight: normal;
+    margin-left: 1em;
+}
+
+div.personalBar img {
+    vertical-align: top;
+}
+.caseSensitive {
+    text-transform: none;
+}
+
+div.pathBar {
+    /* The path bar, including breadcrumbs and add to favorites */
+    border-bottom-color: #8CACBB;
+    border-bottom-style: solid;
+    border-bottom-width: 1px;
+    padding-left:        2em;
+    padding-right:       2em;
+    text-transform:      lowercase;
+}
+
+.breadcrumbs {
+    float:          left;
+    text-transform: lowercase;
+}
+
+.addFavorite {
+    vertical-align: bottom;
+}
+
+table.columns {
+       width: 100%;
+}
+
+table.columns td.left {
+    vertical-align: top;
+    width:          15%;
+    padding:        2em 0em 1em 2em;
+}
+
+table.columns td.main {
+    vertical-align: top;
+    padding:        0em 2em 1em 2em;
+    margin:         0;
+}
+
+table.columns td.right {
+    vertical-align: top;
+    width:          15%;
+    padding:        2em 2em 1em 0em;
+}
+
+#contentTabs {
+    background:      transparent;
+    border-collapse: collapse;
+    border-bottom:   1px solid #74AE0B;
+    padding-left:    1em;
+    margin-top:      2em;
+    white-space:     nowrap;
+}
+
+#contentTabs a {
+    background:     transparent;
+    border:         1px solid #74AE0B;
+    border-style:   solid solid none solid;
+    color:          #578308;
+    font-weight:    normal;
+    height:         1.2em;
+    margin-right:   0.5em;
+    padding:        0em 2em;
+    text-transform: lowercase;
+}
+
+#contentTabs a.selected {
+    background:    #CDE2A7;
+    border-bottom: #CDE2A7 1px solid;
+    color:         #578308;
+    font-weight:   normal;
+}
+
+#contentTabs a:hover {
+    background-color: #CDE2A7;
+    color: #578308;
+}
+
+#contentBar {
+    background:     #CDE2A7;
+    border-left:    1px solid #74AE0B;
+    border-right:   1px solid #74AE0B;
+    color:          #578308;
+    text-align:     right;
+    text-transform: lowercase;
+}
+
+div.document {
+    background: White;
+    font:       120% Verdana, Helvetica, Arial, sans-serif;
+    padding:    0;
+    margin:     0em 0em 2em 0em;
+}
+
+div.editableDocument {
+    background: White;
+    border:     1px solid #74AE0B;
+    font:       120% Verdana, Helvetica, Arial, sans-serif;
+    margin:     0em 0em 2em 0em;
+    padding:    0em 1em 2em 1em;
+}
+
+div.documentActions {
+    float:      right; 
+    margin-top: 1.5em;
+}
+
+div.message {
+    background: #FFCE7B;
+    border:     1px solid #FFA500;
+    color:      Black;
+    font:       bold 80% Verdana, Helvetica, Arial, sans-serif;
+    margin:     2em 0em 1em 0em;
+    padding:    0.5em 1em;
+    vertical-align: middle;
+}
+
+div.message a {
+    color: Black;
+    text-decoration: underline;
+}
+
+
+div.title {
+    margin-top: 1em;
+}
+
+.description {
+    /* The summary text describing the document */
+    font:        bold 100% Verdana, Helvetica, Arial, sans-serif;
+    display:     block;
+    margin:      1em 0em;
+    line-height: 1.5em;
+}
+
+.footer {
+    background:    #DEE7EC;
+    border-top:    1px solid #8CACBB;
+    border-bottom: 1px solid #8CACBB;
+    color:         Black;
+    clear:         both;
+    float:         none;
+    margin:        2em 0em;
+    padding:       0.5em 0em 1em 0em;
+    text-align:    center;
+}
+
+
+/*
+** Widgets
+*/
+
+input.standalone {
+    background: #DEE7EC url(linkOpaque.gif) 9px 1px no-repeat;
+    color: Black;
+    cursor: pointer;
+    font-size: 80%;
+    font-weight: normal;
+    margin-bottom: 1em;
+    padding: 1px 1px 1px 15px;
+    text-transform: lowercase;
+}
+
+input.context {
+    background: White url(linkTransparent.gif) 9px 1px no-repeat;
+    color: Black;
+    cursor: pointer;
+    font-size: 80%;
+    font-weight: normal;
+    margin-bottom: 1em;
+    padding: 1px 1px 1px 15px;
+    text-transform: lowercase;
+}
+
+input.destructive {
+    background: #FFCE7B url(linkTransparent.gif) 9px 1px no-repeat;
+    border: 1px solid #FFA500;  
+    color: Black;
+    cursor: pointer;
+    font-size: 80%;
+    font-weight: normal;
+    margin-bottom: 1em;
+    padding: 1px 1px 1px 15px;
+    text-transform: lowercase;
+}
+
+input.noborder {
+    border: none;
+    margin: 0;
+    background-color: transparent;
+}
+
+div.row {
+    clear: both;
+    min-height: 4em;
+    margin: 0em 0em 1em 0em;
+    position: relative;
+}
+
+.group {
+    border: 1px solid #8cacbb;
+    margin: 1em 0em 1em 0em;
+    padding: 0em 1em;
+}
+span.legend {
+    background: White;
+    font-size: 80%;
+    padding: 0.5em;
+    position : relative;
+    top: -0.8em;
+    left: 0em;
+}
+
+div.label {
+    font-weight: bold;
+    display: inline;
+    padding-right: 0.5em;
+}
+
+div.field {
+    margin-top: 0.2em;
+}
+
+div.help {
+    background-color: #FFFFE1; 
+    border: 1px solid black; 
+    font-size: 80%;
+    font-weight: normal;
+    line-height: normal;
+    text-align: left;
+    position: absolute;
+    left: -18em;
+    top: 1.5em;
+    width: 16em;
+    padding: 0.5em;
+}
+
+.error {
+    /* Class for error indication in forms */
+    background: #FFCE7B;
+    border: 1px solid #FFA500;
+    padding: 1em;
+    margin: 0;
+    width: 68% !important;
+}
+
+.required {
+    /* Used in addition to class "label" on required elements */
+    background: url(required.gif) right no-repeat;
+}
+
+span.card {
+    background: #DEE7EC;
+    border-color: #8CACBB;
+    border-width: 1px;
+    border-style: solid;
+    float: left;
+    margin: 1em;
+    padding: 1em;
+    text-align: center;
+    width: 15%;
+}
+
+table.listing,
+div.stx table {
+    /* The default table for document listings. Contains name, document types, modification times etc in a file-browser-like fashion */
+    border-collapse: collapse;
+    border-left: 1px solid #8CACBB;
+    border-bottom: 1px solid #8CACBB;
+    font-size: 80%;
+    margin: 1em 0em 1em 0em;
+    clear: both;
+}
+
+table.listing th,
+div.stx table th {
+    background: #DEE7EC;
+    border-top: 1px solid #8CACBB;
+    border-bottom: 1px solid #8CACBB;
+    border-right: 1px solid #8CACBB;
+    color: Black;
+    font-weight: normal;
+    padding: 0em 1em 0em 1em;
+    text-transform: lowercase;
+    white-space: nowrap;
+}
+
+table.listing td.top {
+    border-left: 1px solid White;
+    border-top: 1px solid White ! important;
+    border-right: 1px solid White ! important;
+    text-align: right ! important;
+    padding: 0em 0em 1em 0em;
+    /* insane IE row bug workaround */
+    position: relative;
+    left: -1px;
+    top: -1px;
+}
+
+table.listing tr.odd {
+    /*every second line should be shaded */
+    background: transparent;
+}
+
+table.listing tr.even {
+    background: #F7F9FA;
+}
+
+table.listing td,
+div.stx table td {
+    border-right: 1px solid #8CACBB;
+    padding: 0em 1em;
+    text-align: left;
+}
+
+table.listing a:hover {
+    text-decoration: underline;
+}
+
+table.listing img {
+       vertical-align: middle;
+}
+
+/* Additional STX workaround classes */
+
+div.stx table p /* stupid STX table workaround */
+{
+    margin: 0;
+    padding: 0;
+}
+
+div.stx table  /* stupid STX table workaround */
+{
+    border: 1px solid #8CACBB ! important;
+}
+div.stx table td {
+    border-bottom: 1px solid #8CACBB;
+}
+
+
+div.box {
+    border: none;
+    margin: 0em 0em 2em 0em;
+    padding: 0;
+}
+
+div.box h4 {
+    font-size: 1em;
+}
+
+div.box h5 { 
+    background: #DEE7EC;
+    border: 1px solid #8CACBB;
+    border-style: solid solid none solid;
+    color: Black;
+    padding: 0em 1em 0em 1em;
+    text-transform: lowercase;
+    display: inline;
+    font-size: 1em;
+    height: 1em;
+}
+
+div.box h6 { 
+    background: #DEE7EC;
+    border: 1px solid #8CACBB;
+    border-style: solid solid none solid;
+    color: Black;
+    padding: 0em 1em 0em 1em;
+    text-transform: lowercase;
+    display: block;
+    font-size: 1em;
+    height: 1.2em;
+}
+
+
+div.box div.body {
+    background: transparent;
+    border-collapse: collapse;
+    border: 1px solid #8CACBB;
+}
+
+.boxDetails {
+    text-align: right;
+}
+
+div.box .content {
+    padding: 1em;
+}
+
+div.box a.close {
+    float: right;
+    text-transform: none;
+    border-left: 1px solid #8CACBB;
+    padding: 0em 0.2em;
+}
+
+div.box h1, 
+div.box h2, 
+div.box h3, 
+div.box h4 {
+    margin: 0;
+    padding: 0;
+}
+
+div.box .even {
+    background-color: #F7F9FA;
+}
+
+div.box .odd {
+    background-color: transparent;
+}
+
+div.box input {
+    font-size: 100%;
+}
+
+div.spacer {
+       margin: 1em;
+}
+
+.currentNavItem {
+    color: Black;
+    font-weight: bold;
+}
+
+.private {
+    color: Black;
+}
+
+.published {
+    color: #74AE0B;
+}
+
+.pending {
+    color: #FFA500;
+}
+
+.syndicated {
+    color: #008000;
+}
+
+.expired {
+    color: Red;
+}
+
+.even {
+    background-color: #F7F9FA;
+}
+
+.odd {
+    background-color: transparent;
+}
+
+.highlight {
+    background-color: #F7F9FA;
+}
+
+div.listingBar {
+    background: #DEE7EC;
+    border-color: #8CACBB;
+    border-style: solid;
+    border-width: 1px;
+    padding: 0em 1em;
+    text-align: center;
+    text-transform: lowercase;
+    clear: both;
+    vertical-align: top;
+    margin: 1em 0em;
+}
+
+div.listingBar span.previous {
+    text-align: left;
+    float: left;
+}
+
+div.listingBar span.next {
+    text-align: right;
+    float: right;
+}
+
+div listingBar img {
+       vertical-align: middle;
+}
+
+/*
+** Calendar elements - used in the calendar rendering 
+*/
+
+div.day {
+    background-color: #FFFFBB;
+    border: 1px solid Black;
+    padding: 0.2em;
+    position: absolute;
+    visibility: hidden;
+    width: 12em;
+    z-index: 2;
+}
+
+div.date {
+    font-weight: bold;
+}
+
+  
+table.calendar {
+    border: 1px solid #8CACBB;
+    margin: 0em 1em 2em 0em;
+    text-align: right;
+}
+
+table.calendar a {
+    text-decoration: none;
+    color: #436976;
+}
+
+table.calendar a:hover {
+    text-decoration: none;
+}
+
+table.calendar th {
+    background-color: #DEE7EC;
+    color: Black;
+    font-weight: bold;
+    text-align: center;
+}
+
+table.calendar td {
+    background-color: transparent;
+    width: 1.5em;
+    padding: 2px;
+}
+
+table.calendar td.weekdays {
+    background-color: #DEE7EC;
+    border: 1px solid #8CACBB;
+    border-style: solid none;
+    text-align: center;
+}
+
+table.calendar td.event {
+    background-color: #DEE7EC;
+    font-weight: bold;
+}
+
+table.calendar td.noevent {
+    background-color: transparent;
+}
+
+table.calendar td.todayevent {
+    background-color: #DEE7EC;
+    border: 2px solid #FFA500;
+    font-weight: bold;
+}
+
+table.calendar td.todaynoevent {
+    border-collapse: collapse;
+    border: 2px solid #FFA500;
+}
+
+/*  */
diff --git a/skyrix-sope/samples/TestSite/plone/ploneCustom.css b/skyrix-sope/samples/TestSite/plone/ploneCustom.css
new file mode 100644 (file)
index 0000000..0ea6c31
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *  This is the file where you put your CSS changes. You should preferrably use this and
+ *  override the relevant properties you want to change here instead of customizing plone.css.
+ */
+
+/*
+**  DTML instructions to set caching headers. Inside comments area to play nicer with CSS editors.
+**
+** **   
+**   
+**   
+**   
+** */
+/*  */
+
+
+/* DELETE THIS LINE AND PUT YOUR CUSTOM STUFF HERE */
+
+
+
+
+
+
+/*  */
+
+
+
+
diff --git a/skyrix-sope/samples/TestSite/plone/ploneNS4.css b/skyrix-sope/samples/TestSite/plone/ploneNS4.css
new file mode 100644 (file)
index 0000000..21e3118
--- /dev/null
@@ -0,0 +1,158 @@
+/* 
+** Plone style sheet for Netscape 4 and other non-CSS2-compatible browsers.
+** Alexander Limi, 2002 - http://limi.net
+**
+** Tip: don't use margins or floats in NS4 - it freaks out.
+*/
+
+/* DTML instructions to set caching headers.
+*/
+
+/*
+*/
+
+/* Basic Elements */
+body, td, th, div, span, table { font-family: Verdana, Helvetica, sans-serif; }
+body  { background: White; color: Black; padding: 0; }
+a     { text-decoration: none; color: #436976; }
+p     { font-family: Verdana, Helvetica, sans-serif; }
+p a   { text-decoration: underline; }
+p img { border: 0; }
+hr    { margin:0; padding: 0; }
+h1, h2, h3, h4, h5, h6 { color: Black; }
+form  { border: none; }
+textarea {  }
+input  {  }
+select {  }
+abbr, acronym, .explain { border-bottom: 1px dotted #436976; cursor: help; }
+code   { }
+pre    { padding: 1em; border: 1px solid #8cacbb; background-color: #dee7ec; }
+
+/* Structural elements */
+div.top { background: transparent; width: 100%; }
+div.searchBox { float: right; text-align: right; }
+div.tabs { padding: 0 0 0 1em; margin: 0; }
+div.tabs a { background: transparent; color: #436976; font-weight: normal; }
+div.tabs a.selected { background: #DEE7EC; color: #436976; font-weight: normal; }
+div.personalBar { text-align: right; margin: 0; }
+div.personalBar a{ font-weight: normal; }
+div.pathBar { padding: 0 0 0 1em; margin: 0;}
+table.columns { width: 100%; }
+table.columns td.left { vertical-align: top; padding-top: 2em; width: 15%; }
+table.columns td.main { vertical-align: top; padding-top: 2em; width: 70%; }
+table.columns td.right { vertical-align: top; padding-top: 2em; width: 15%; }
+div.contentTabs { padding: 0;}
+div.contentTabs a { background: transparent; color: #578308; font-weight: normal; }
+div.contentTabs a.selected { background: #CDE2A7; color: #578308; font-weight: normal; }
+div.contentTabs a:hover { background-color: #CDE2A7; }
+div.contentBar {  }
+div.document { background: White; }
+div.editableDocument { border: 1px solid #74AE0B; padding: 0em 1em 0em 1em; }
+div.message { background: #FFCE7B; font: bold 80% Verdana, Helvetica, Arial, sans-serif; padding: 0.5em 1em; vertical-align: middle; }
+.description { font-family: Verdana, Helvetica, Arial, sans-serif; display: block; }
+.footer { clear: both; float: none; padding: 0em 0em 0em 0em; text-align: center; }
+
+/* Widgets */
+div.row     { clear: both; }
+div.rowEven { clear: both; }
+div.rowOdd  { clear: both; }
+
+.group  { border: 1px solid #8cacbb; padding: 1em; }
+.legend { font-weight: bold; }
+
+input.standalone { cursor: pointer; font-weight: normal; }
+input.context    { cursor: pointer; font-weight: normal; }
+
+.error    { background: #FFCE7B; border: 1px solid #FFA500; }
+.required { background: url(required.gif) right no-repeat; }
+.label    { font-weight: bold; padding: 0em 0em; }
+.field    { padding: 0em 0em 0em 0em; text-align: left; }
+.info     { padding: 0em 0em 0.2em 0em; text-align: left; }
+div.help  { font-weight: normal; }
+span.card { 
+  background:   #DEE7EC; 
+  border-color: #8CACBB; 
+  border-width: 1px; 
+  border-style: solid; 
+  text-align:   center;
+}
+
+span.left  { 
+  float:      left; 
+  text-align: left; 
+  width:      40%; 
+}
+span.right { 
+  float:      right; 
+  text-align: right; 
+  width:      40%; 
+}
+
+table.listing { }
+table.listing th { 
+  background:  #DEE7EC; 
+  color:       Black; 
+  font-weight: normal; 
+  padding:     0em 1em 0em 1em; 
+}
+table.listing tr.odd  { background: transparent; }
+table.listing tr.even { background: #F7F9FA; }
+table.listing td      { padding: 0em 1em;}
+table.listing a:hover { text-decoration: underline; }
+div.boxDetails        { text-align: right; }
+
+div.box {
+    border: 1px solid #8CACBB;
+    margin-bottom: 1em;
+}
+
+.boxTitle {
+    background: #DEE7EC;
+}
+
+
+table.box a.comment { 
+  background-image: url(http://docs.opengroupware.org/discussionitem_icon.gif); 
+  background-position: 0px 0px; 
+  padding: 0em 0em 0.5em 2em; 
+}
+table.box a.plain { padding: 0; }
+span.folderName { 
+  font-size: 150%; 
+  font-weight: bold; 
+}
+div.spacer  { }
+.private    { color: Black;  }
+.published  { color: #74AE0B; }
+.pending    { color: #FFA500; }
+.syndicated { color: #008000; }
+.expired    { color: Red;     }
+
+/* Calendar elements */
+div.day { background-color: #FFFFBB; }
+div.date { font-weight: bold; }
+table.calendar { border: 1px solid #8CACBB; text-align: right; }
+table.calendar a { text-decoration: none; color: #436976; }
+table.calendar a:hover { text-decoration: none; }
+table.calendar th { 
+  background-color: #DEE7EC; 
+  color:            Black; 
+  font-weight:      bold; 
+  text-align:       center; 
+}
+table.calendar td { width: 1.5em; padding: 2px; }
+table.calendar td.weekdays { 
+  background-color: #DEE7EC; 
+  border:           1px solid #8CACBB; 
+  border-style:     solid none; 
+  text-align:       center; 
+}
+table.calendar td.event { background-color: #DEE7EC; font-weight: bold; }
+table.calendar td.noevent { }
+table.calendar td.othermonth { background-color: #FFFFFF; border: 1px solid #8CACBB; vertical-align: bottom; }
+table.calendar td.holiday { background-color: #CF6060; border: 1px solid #8CACBB; }
+table.calendar td.todayevent { background-color: #DEE7EC; border: 2px solid #FFA500; font-weight: bold; }
+table.calendar td.todaynoevent { border-collapse: collapse; border: 2px solid #FFA500; }
+
+/*
+*/
diff --git a/skyrix-sope/samples/TestSite/plone/plonePresentation.css b/skyrix-sope/samples/TestSite/plone/plonePresentation.css
new file mode 100644 (file)
index 0000000..29f5263
--- /dev/null
@@ -0,0 +1,102 @@
+
+
+
+
+body {
+    background: White url(logo.jpg) no-repeat fixed 95% 95%;
+    font-family: Verdana Helvetica Arial sans-serif;
+    font-size: 40px;
+    color: Black;
+    margin: 5%;
+    
+}
+
+h1 {
+       font-size: 40px;
+    background: #DEE7EC;
+    border-color: #8CACBB;
+    border-style: solid;
+    border-width: 1px;
+    padding-top: 0em;
+    padding-left: 0.5em;
+    padding-right: 0.5em;
+    margin-top: 1em;
+    page-break-before : always;
+}
+
+h2 {
+    font-size: 30px;   
+}
+
+p, dl, ol, ul {
+    font-size: 30px;
+    text-align: left;
+}
+
+.description {
+    font-size: 30px;
+    font-weight: normal;
+}
+
+div.top,
+.netscape4,
+.tabs,
+.personalBar,
+.pathBar,
+td.left,
+td.right,
+.footer,
+.help,
+.legend,
+div.message,
+div.documentActions,
+input
+{
+    display: none;
+}
+
+#contentTabs,
+#contentBar
+{
+    display: none;
+}
+
+ul { 
+    list-style-type: square;
+}
+
+pre { 
+    font-size: 20px;
+    padding: 1em;
+}
+
+div.editableDocument,
+div.document,
+.group {
+    background: transparent;
+    border: none;
+    padding: 0;
+    margin: 0;
+}
+
+table.listing,
+table.listing td
+ {
+       border: 1pt solid black;
+    border-collapse: collapse;
+}
+
+a:link, a:visited {
+       color: #520;
+       background: transparent;
+       font-weight: bold;
+       text-decoration: underline;
+       }
+
+div.document a:link:after, 
+div.document a:visited:after {
+   content: " (" attr(href) ") ";
+   font-size: 90%;
+   }
+
+
diff --git a/skyrix-sope/samples/TestSite/plone/plonePrint.css b/skyrix-sope/samples/TestSite/plone/plonePrint.css
new file mode 100644 (file)
index 0000000..debeb09
--- /dev/null
@@ -0,0 +1,74 @@
+
+
+
+
+/* Thanks to alistapart.com for useful extras */
+
+body {
+    background: White;
+    font-family: Georgia, Garamond, Times, serif;
+    font-size: 10pt;
+    color: Black;
+    margin: 0;
+    padding: 0;
+}
+
+div.top,
+.netscape4,
+.tabs,
+.personalBar,
+.pathBar,
+td.left,
+td.right,
+#contentTabs,
+#contentBar,
+div.documentActions,
+.footer,
+.help,
+.legend,
+div.message,
+input
+{
+    display: none;
+}
+
+ul { 
+    list-style-type: square;
+}
+
+.editableDocument,
+.document,
+div.description,
+.group {
+    background: transparent;
+    border: none ! important;
+    font-family: Georgia, Garamond, Times, serif;
+    font-size: 10pt;
+    padding: 0;
+    margin: 0;
+}
+
+table.listing,
+table.listing td
+ {
+       border: 1pt solid black;
+    border-collapse: collapse;
+}
+
+a:link, a:visited {
+       color: #520;
+       background: transparent;
+       font-weight: bold;
+       text-decoration: underline;
+       }
+
+pre {
+  white-space: normal;
+}
+
+div.document a:link:after, 
+div.document a:visited:after {
+   content: " (" attr(href) ") ";
+   font-size: 90%;
+   }
+
diff --git a/skyrix-sope/samples/TestSite/plone/plone_formtooltip.js b/skyrix-sope/samples/TestSite/plone/plone_formtooltip.js
new file mode 100644 (file)
index 0000000..95f15ba
--- /dev/null
@@ -0,0 +1,21 @@
+
+
+
+
+// Tooltip-like help pop-ups used in forms
+
+  function formtooltip(el,flag){
+    elem = document.getElementById(el);
+    if (flag) { 
+      elem.parentNode.parentNode.style.zIndex=1000;
+      elem.parentNode.parentNode.style.borderRight='0px solid #000';
+      // ugly , yes .. but neccesary to avoid a small but very annoying bug in IE6
+      elem.style.visibility='visible';
+    }
+    else {
+      elem.parentNode.parentNode.style.zIndex=1;
+      elem.parentNode.parentNode.style.border='none';
+      elem.style.visibility='hidden' };
+  }
+
+
diff --git a/skyrix-sope/samples/TestSite/plone/plone_javascripts.js b/skyrix-sope/samples/TestSite/plone/plone_javascripts.js
new file mode 100644 (file)
index 0000000..07902ee
--- /dev/null
@@ -0,0 +1,300 @@
+
+
+
+
+// Fix for bug in IE6.0 float handling (don't ask, don't tell ;)
+
+if (document.all && window.attachEvent) window.attachEvent("onload", fixWinIE);
+function fixWinIE() {
+    try {
+        document.getElementById('content').style.display = 'block';
+    } catch(er) {}
+}
+
+
+// The calendar popup show/hide:
+
+    function showDay(date) {
+        document.getElementById('day' + date).style.visibility = 'visible';
+        return true;
+    }
+    
+    function hideDay(date) {
+        document.getElementById('day' + date).style.visibility = 'hidden';
+        return true;
+    }
+
+// Focus on error or tabindex=1
+if (window.addEventListener) window.addEventListener("load",setFocus,false);
+else if (window.attachEvent) window.attachEvent("onload",setFocus);
+function setFocus() {
+    var xre = new RegExp(/\berror\b/);
+    // Search only forms to avoid spending time on regular text
+    for (var f = 0; (formnode = document.getElementsByTagName('form').item(f)); f++) {
+        // Search for errors first, focus on first error if found
+        for (var i = 0; (node = formnode.getElementsByTagName('div').item(i)); i++) {
+            if (xre.exec(node.className)) {
+                for (var j = 0; (inputnode = node.getElementsByTagName('input').item(j)); j++) {
+                    inputnode.focus();
+                    return;   
+                }
+            }
+        }
+        // If no error, focus on input element with tabindex 1
+        for (var i = 0; (node = formnode.getElementsByTagName('input').item(i)); i++) {
+            if (node.getAttribute('tabindex') == 1) {
+                 node.focus();
+                 return;   
+            }
+        }
+    }
+}
+
+/********* Table sorter script *************/
+// Table sorter script, thanks to Geir Bækholt for this.
+// DOM table sorter originally made by Paul Sowden 
+
+function compare(a,b)
+{
+    au = new String(a);
+    bu = new String(b);
+
+    if (au.charAt(4) != '-' && au.charAt(7) != '-')
+    {
+    var an = parseFloat(au)
+    var bn = parseFloat(bu)
+    }
+    if (isNaN(an) || isNaN(bn))
+        {as = au.toLowerCase()
+         bs = bu.toLowerCase()
+        if (as > bs)
+            {return 1;}
+        else
+            {return -1;}
+        }
+    else {
+    return an - bn;
+    }
+}
+
+
+
+function getConcatenedTextContent(node) {
+    var _result = "";
+         if (node == null) {
+                   return _result;
+         }
+    var childrens = node.childNodes;
+    var i = 0;
+    while (i < childrens.length) {
+        var child = childrens.item(i);
+        switch (child.nodeType) {
+            case 1: // ELEMENT_NODE
+            case 5: // ENTITY_REFERENCE_NODE
+                _result += getConcatenedTextContent(child);
+                break;
+            case 3: // TEXT_NODE
+            case 2: // ATTRIBUTE_NODE
+            case 4: // CDATA_SECTION_NODE
+                _result += child.nodeValue;
+                break;
+            case 6: // ENTITY_NODE
+            case 7: // PROCESSING_INSTRUCTION_NODE
+            case 8: // COMMENT_NODE
+            case 9: // DOCUMENT_NODE
+            case 10: // DOCUMENT_TYPE_NODE
+            case 11: // DOCUMENT_FRAGMENT_NODE
+            case 12: // NOTATION_NODE
+                // skip
+                break;
+        }
+        i ++;
+    }
+       return _result;
+}
+
+
+
+function sort(e) {
+    var el = window.event ? window.event.srcElement : e.currentTarget;
+
+    // a pretty ugly sort function, but it works nonetheless
+    var a = new Array();
+    // check if the image or the th is clicked. Proceed to parent id it is the image
+    // NOTE THAT nodeName IS UPPERCASE
+    if (el.nodeName == 'IMG') el = el.parentNode;
+    //var name = el.firstChild.nodeValue;
+    // This is not very robust, it assumes there is an image as first node then text
+    var name = el.childNodes.item(1).nodeValue;
+    var dad = el.parentNode;
+    var node;
+    
+    // kill all arrows
+    for (var im = 0; (node = dad.getElementsByTagName("th").item(im)); im++) {
+        // NOTE THAT nodeName IS IN UPPERCASE
+        if (node.lastChild.nodeName == 'IMG')
+        {
+            lastindex = node.getElementsByTagName('img').length - 1;
+            node.getElementsByTagName('img').item(lastindex).setAttribute('src','http://docs.opengroupware.org/arrowBlank.gif');
+        }
+    }
+    
+    for (var i = 0; (node = dad.getElementsByTagName("th").item(i)); i++) {
+        var xre = new RegExp(/\bnosort\b/);
+        // Make sure we are not messing with nosortable columns, then check second node.
+        if (!xre.exec(node.className) && node.childNodes.item(1).nodeValue == name) 
+        {
+            //window.alert(node.childNodes.item(1).nodeValue;
+            lastindex = node.getElementsByTagName('img').length -1;
+            node.getElementsByTagName('img').item(lastindex).setAttribute('src','http://docs.opengroupware.org/arrowUp.gif');
+            break;
+        }
+    }
+
+    var tbody = dad.parentNode.parentNode.getElementsByTagName("tbody").item(0);
+    for (var j = 0; (node = tbody.getElementsByTagName("tr").item(j)); j++) {
+
+        // crude way to sort by surname and name after first choice
+        a[j] = new Array();
+        a[j][0] = getConcatenedTextContent(node.getElementsByTagName("td").item(i));
+        a[j][1] = getConcatenedTextContent(node.getElementsByTagName("td").item(1));
+        a[j][2] = getConcatenedTextContent(node.getElementsByTagName("td").item(0));           
+        a[j][3] = node;
+    }
+
+    if (a.length > 1) {
+       
+        a.sort(compare);
+
+        // not a perfect way to check, but hell, it suits me fine
+        if (a[0][0] == getConcatenedTextContent(tbody.getElementsByTagName("tr").item(0).getElementsByTagName("td").item(i))
+              && a[1][0] == getConcatenedTextContent(tbody.getElementsByTagName("tr").item(1).getElementsByTagName("td").item(i))) 
+        {
+            a.reverse();
+            lastindex = el.getElementsByTagName('img').length - 1;
+            el.getElementsByTagName('img').item(lastindex).setAttribute('src','http://docs.opengroupware.org/arrowDown.gif');
+        }
+
+    }
+       
+    for (var j = 0; j < a.length; j++) {
+        tbody.appendChild(a[j][3]);
+    }
+}
+    
+function init(e) {
+    var tbls = document.getElementsByTagName('table');
+    for (var t = 0; t < tbls.length; t++)
+        {
+        // elements of class="listing" can be sorted
+        var re = new RegExp(/\blisting\b/)
+        // elements of class="nosort" should not be sorted
+        var xre = new RegExp(/\bnosort\b/)
+        if (re.exec(tbls[t].className) && !xre.exec(tbls[t].className))
+        {
+            try {
+                var tablename = tbls[t].getAttribute('id');
+                var thead = document.getElementById(tablename).getElementsByTagName("thead").item(0);
+                var node;
+                // set up blank spaceholder gifs
+                blankarrow = document.createElement('img');
+                blankarrow.setAttribute('src','http://docs.opengroupware.org/arrowBlank.gif');
+                blankarrow.setAttribute('height',6);
+                blankarrow.setAttribute('width',9);
+                // the first sortable column should get an arrow initially.
+                initialsort = false;
+                for (var i = 0; (node = thead.getElementsByTagName("th").item(i)); i++) {
+                    // check that the columns does not have class="nosort"
+                    if (!xre.exec(node.className)) {
+                        node.insertBefore(blankarrow.cloneNode(1), node.firstChild);
+                        if (!initialsort) {
+                            initialsort = true;
+                            uparrow = document.createElement('img');
+                            uparrow.setAttribute('src','http://docs.opengroupware.org/arrowUp.gif');
+                            uparrow.setAttribute('height',6);
+                            uparrow.setAttribute('width',9);
+                            node.appendChild(uparrow);
+                        } else {
+                            node.appendChild(blankarrow.cloneNode(1));
+                        }
+    
+                        if (node.addEventListener) node.addEventListener("click",sort,false);
+                        else if (node.attachEvent) node.attachEvent("onclick",sort);
+                    }
+                }
+            } catch(er) {}
+        }
+    }
+}
+
+// initialize the sorter functions 
+// add stuff to secure it from broken DOM-implanetations or missing objects.
+   
+    
+       
+//    p.appendChild(document.createTextNode("Change sorting by clicking on each individual heading."));
+//    document.getElementById(tablename).parentNode.insertBefore(p,document.getElementById(tablename));
+    
+
+if (window.addEventListener) window.addEventListener("load",init,false);
+else if (window.attachEvent) window.attachEvent("onload",init);
+
+       
+// **** End table sort script ***
+
+
+
+// Actions used in the folder_contents view
+
+function submitFolderAction(folderAction) {
+    document.folderContentsForm.action = document.folderContentsForm.action+'/'+folderAction;
+    document.folderContentsForm.submit();
+}
+
+function submitFilterAction() {
+    document.folderContentsForm.action = document.folderContentsForm.action+'/folder_contents';
+    filter_selection=document.getElementById('filter_selection');
+    for (var i =0; i < filter_selection.length; i++){
+        if (filter_selection.options[i].selected) {
+            if (filter_selection.options[i].value=='#') {
+                document.folderContentsForm.filter_state.value='clear_view_filter';
+            }
+            else {
+                document.folderContentsForm.filter_state.value='set_view_filter'
+            }
+        }                                              
+    }
+    document.folderContentsForm.submit();
+}
+    
+
+// Functions for selecting all checkboxes in folder_contents view
+
+isSelected = false;
+
+function selectAll() {
+  checkboxes = document.getElementsByName('ids:list');
+  for (i = 0; i < checkboxes.length; i++)
+    checkboxes[i].checked = true ;
+  isSelected = true;
+  return isSelected;
+}
+
+function deselectAll() {
+  checkboxes = document.getElementsByName('ids:list');
+  for (i = 0; i < checkboxes.length; i++)
+    checkboxes[i].checked = false ;
+  isSelected = false;
+  return isSelected;
+}
+
+function toggleSelect(selectbutton) {
+  if (isSelected == false) {
+    selectbutton.setAttribute('src','http://docs.opengroupware.org/select_none_icon.gif');
+    return selectAll();
+  }
+  else {
+    selectbutton.setAttribute('src','http://docs.opengroupware.org/select_all_icon.gif');
+    return deselectAll();
+  }
+}
diff --git a/skyrix-sope/samples/TestSite/plone/required.gif b/skyrix-sope/samples/TestSite/plone/required.gif
new file mode 100644 (file)
index 0000000..bd71976
Binary files /dev/null and b/skyrix-sope/samples/TestSite/plone/required.gif differ
diff --git a/skyrix-sope/samples/TestSite/plone/searchbox.wox b/skyrix-sope/samples/TestSite/plone/searchbox.wox
new file mode 100644 (file)
index 0000000..4e8cd21
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<div xmlns="http://www.w3.org/1999/xhtml"
+     xmlns:var="http://www.skyrix.com/od/binding"
+     class="searchBox"
+>
+  <form name="searchform"
+        href="http://docs.opengroupware.org/search">
+
+                    <input id="searchGadget"
+                           name="SearchableText" type="text"
+                           size="20" tabindex="30001" />
+
+                    <input class="context searchButton"
+                           type="submit" value="Search"
+                           tabindex="30002" />
+  </form>
+</div>
diff --git a/skyrix-sope/samples/TestSite/stylesheet.css b/skyrix-sope/samples/TestSite/stylesheet.css
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/skyrix-sope/samples/TestSite/subdir/index.wox b/skyrix-sope/samples/TestSite/subdir/index.wox
new file mode 100644 (file)
index 0000000..72563e4
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding">
+  <body>
+    <h3>SubDir Index</h3>
+    
+    <small>I'm Component: <var:string value="self"/><br/>
+    On Client: <var:string value="clientObject"/><br/></small>
+    
+    <table border="1" bgcolor="#EFEFEF">
+      <tr><th>Embed</th></tr>
+      <tr><td><var:component className="embed.wox"/></td></tr>
+    </table>
+    
+    <h4>Querying Images</h4>
+    <p>
+      accept.gif via filename: <img filename="accept.gif"/> 
+      <br/>
+      accept.gif via src: <img src="accept.gif"/>
+    </p>
+
+    <hr />
+    <a href="test.wox"  >test.wox</a>,
+    <a href="/test.wox" >/test.wox</a>,
+    <a href="index.html">index.html</a>,
+    <a href="embed.wox" >embed.wox</a>,
+    <a href="accept.gif">accept.gif</a>
+  </body>
+</html>
diff --git a/skyrix-sope/samples/TestSite/test.wox b/skyrix-sope/samples/TestSite/test.wox
new file mode 100644 (file)
index 0000000..20f929c
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding">
+  <body>
+    <h3>Hello World</h3>
+    
+    <small>
+      I'm Component: <var:string value="self"/><br/>
+      On Client: <var:string value="clientObject"/><br/>
+      PathInfo: <var:string value="context.pathInfo"/>
+    </small>
+    
+    <h4>Embedding Components</h4>
+    <p>
+      You can embed components using the usual WOX "&lt;var:component&gt;"
+      tag. As usual subcomponents are looked up using the master components
+      WOResourceManager which in turn will usually perform a SOPE lookup
+      to find the component.
+    </p>
+    
+    <table border="1" bgcolor="#EFEFEF">
+      <tr><th>Embed</th></tr>
+      <tr><td><var:component className="embed.wox"/></td></tr>
+    </table>
+    
+    <h4>Querying Images</h4>
+    <p>
+      You should access images using the "src" attribute, but you can
+      query them using "filename". So what is the difference ? 
+      <br/>
+      Images selected using "filename" delay the resolution of the
+      query to the runtime. They construct a URI like "component/image.gif",
+      so the component will be asked during the actual image query. The
+      component then will locate the image using it's WOResourceManager.
+      <br />
+      In contrast, images selected using "src" defer the selection to the
+      browser, that is, the browser will calculate the image path based on
+      it's query URL. Of course the URL calculated by the client can still
+      be dynamic !
+    </p>
+    <p>
+      accept.gif via filename: <img filename="accept.gif"/> 
+      <br/>
+      accept.gif via src: <img src="accept.gif"/>
+    </p>
+
+    <hr />
+    <a href="test.wox"  >test.wox</a>,
+    <a href="index.html">index.html</a>,
+    <a href="embed.wox" >embed.wox</a>,
+    <a href="accept.gif">accept.gif</a>,
+    <a href="subdir/"   >subdir/</a>
+  </body>
+</html>
diff --git a/skyrix-sope/samples/TestSite/webfolders.xhtml b/skyrix-sope/samples/TestSite/webfolders.xhtml
new file mode 100644 (file)
index 0000000..906a123
--- /dev/null
@@ -0,0 +1,23 @@
+<span xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding">
+  <br />
+
+  M$ Webfolder Behavior is described on:
+  <a href="http://msdn.microsoft.com/workshop/author/behaviors/overview/webfolder.asp">MSDN</a>.
+  <br />
+  Some interesting mail:
+  <a href="http://lists.w3.org/Archives/Public/w3c-dist-auth/2000JanMar/0247.html">Mail on WebFolders</a>
+  
+  <br />
+  <br />
+  
+  <style>
+  A { behavior: url(#default#AnchorClick);}
+  </style>
+  
+  <a var:href="baseURL" var:folder="baseURL" 
+     target="_top">Open in WebFolder View (target is _top)</a>
+  <br />
+  <a var:href="baseURL" var:folder="baseURL" 
+     target="newwin">Open in WebFolder View (target is newwin)</a>
+</span>
diff --git a/skyrix-sope/samples/WOxExtTest/AlertPanel.m b/skyrix-sope/samples/WOxExtTest/AlertPanel.m
new file mode 100644 (file)
index 0000000..caf9f9a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface AlertPanel : WOComponent
+@end
+
+#include "common.h"
+
+@implementation AlertPanel
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:[NSNumber numberWithInt:0] forKey:@"clicks"];
+  }
+  return self;
+}
+- (id)countClicks {
+  int clicks;
+
+  [self logWithFormat:@"+++ invoke 'countClicks' action +++"];
+  
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  [self takeValue:[NSNumber numberWithInt:++clicks] forKey:@"clicks"];
+
+  return nil;
+}
+
+@end /* AlertPanel */
diff --git a/skyrix-sope/samples/WOxExtTest/AlertPanel.wox b/skyrix-sope/samples/WOxExtTest/AlertPanel.wox
new file mode 100644 (file)
index 0000000..a336aca
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+  <var:js-alert-panel 
+        const:pageName="PanelContent"
+        const:alertMessage="Show a page in a new target window ..."
+        const:targetWindow="panel"
+        const:string="'new page' - alert panel"/>
+  <br/>
+  
+  <var:js-alert-panel
+        action="countClicks"
+        const:alertMessage="Increment the clicks ..."
+        const:string="'invoke action' - alert panel"/>
+  
+  clicks: <b><var:string value="clicks"/></b> <br/>
+  
+  <var:js-alert-panel
+        javaScriptFunction="javaScriptFunction"
+        const:alertMessage="Invoke a javaScript function ..."
+        const:string="'invoke javescript' - alert panel"/>
+  <br/>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/Browser.m b/skyrix-sope/samples/WOxExtTest/Browser.m
new file mode 100644 (file)
index 0000000..56f09c9
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/WOComponent.h>
+
+@class NSFileManager, NSArray, NSString;
+
+@interface Browser : WOComponent < NSCoding >
+{
+  NSFileManager *fm;
+
+  NSArray  *currentPath;
+  NSString *currentPathString;
+}
+@end
+
+#include "common.h"
+
+@implementation Browser
+
+- (id)init {
+  if ((self = [super init])) {
+    self->fm = [[NSFileManager defaultManager] retain];
+
+    //    [self setCurrentPath:nil];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->currentPathString);
+  RELEASE(self->currentPath);
+  RELEASE(self->fm);
+  [super dealloc];
+}
+
+- (void)setCurrentPath:(NSArray *)_p {
+  if (_p == nil)
+    _p = [NSArray array];
+  
+  ASSIGN(self->currentPath, _p);
+  
+  RELEASE(self->currentPathString); self->currentPathString = nil;
+  self->currentPathString = [[_p componentsJoinedByString:@"/"] copy];
+}
+- (NSArray *)currentPath {
+  return self->currentPath;
+}
+- (NSString *)currentPathString {
+  return self->currentPathString;
+}
+
+- (NSFileManager *)fileManager {
+  return self->fm;
+}
+
+- (NSArray *)rootFolder {
+  return [[self fileManager] directoryContentsAtPath:@"."];
+}
+
+- (NSString *)bgColor {
+  NSString *cf;
+
+  cf = [self valueForKey:@"currentFolder"];
+  if ([cf isEqualToString:[self currentPathString]])
+    return @"AAAAAA";
+  if ([cf hasPrefix:[self currentPathString]])
+    return @"#FAE8B8";
+
+  return @"white"; // default bg
+}
+
+- (BOOL)currentIsDirectory {
+  BOOL isDir;
+
+  if (![self->fm fileExistsAtPath:[self currentPathString] isDirectory:&isDir])
+    return NO;
+  
+  return isDir;
+}
+
+- (NSString *)currentImage {
+  if ([self currentIsDirectory]) {
+    /* directory */
+    NSString *cf;
+    
+    cf = [self valueForKey:@"currentFolder"];
+
+    if ([cf hasPrefix:[self currentPathString]])
+      return @"folder_opened.gif";
+    else
+      return @"folder_closed.gif";
+  }
+  return nil;
+}
+
+- (NSArray *)dirContents {
+  if (![self currentIsDirectory])
+    return nil;
+  
+  return [[self fileManager] directoryContentsAtPath:[self currentPathString]];
+}
+
+- (id)clicked {
+  NSLog(@"clicked: path is %@", [self currentPathString]);
+  NSLog(@"clicked: item is %@", [self valueForKey:@"item"]);
+  [self takeValue:[self currentPathString] forKey:@"currentFolder"];
+  return self;
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [super encodeWithCoder:_coder];
+
+  [_coder encodeObject:self->currentPath];
+  [_coder encodeObject:self->currentPathString];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  if ((self = [super initWithCoder:_coder])) {
+    self->fm   = [[NSFileManager defaultManager] retain];
+
+    self->currentPath       = [[_coder decodeObject] retain];
+    self->currentPathString = [[_coder decodeObject] retain];
+  }
+  return self;
+}
+
+@end /* TableView */
diff --git a/skyrix-sope/samples/WOxExtTest/Browser.wox b/skyrix-sope/samples/WOxExtTest/Browser.wox
new file mode 100644 (file)
index 0000000..e7ab8f2
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <var:we-browser list="rootFolder" item="item" sublist="dirContents"
+                  currentPath="currentPath"
+                  const:border="1" bgColor="bgColor" 
+                  const:columnWidth="200" const:height="100">
+     <a var:action="clicked"><var:if condition="currentIsDirectory"><img var:filename="currentImage" border="0" var:alt="item"/></var:if><var:string value="item"/></a>
+  </var:we-browser>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/CalendarField.m b/skyrix-sope/samples/WOxExtTest/CalendarField.m
new file mode 100644 (file)
index 0000000..972e733
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/NGObjWeb.h>
+
+@interface CalendarField : WOComponent
+@end
+
+@implementation CalendarField
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"12"   forKey:@"hour"];
+    [self takeValue:@"30"   forKey:@"minute"];
+    [self takeValue:@"50"   forKey:@"second"];
+
+    [self takeValue:@"2001" forKey:@"year"];
+    [self takeValue:@"5"    forKey:@"month"];
+    [self takeValue:@"23"   forKey:@"day"];
+
+    [self takeValue:[NSCalendarDate date] forKey:@"date"];
+  }
+  return self;
+}
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/CalendarField.wox b/skyrix-sope/samples/WOxExtTest/CalendarField.wox
new file mode 100644 (file)
index 0000000..0214940
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+  xmlns="http://www.w3.org/1999/xhtml"
+  xmlns:var="http://www.skyrix.com/od/binding"
+  xmlns:const="http://www.skyrix.com/od/constant"
+>
+  <form var:action="self">
+    <var:cal-field hour="hour" minute="minute" second="second"
+                   year="year" month="month" day="day"/>
+    <br/>
+    <var:cal-field date="date"/>
+    <br/>
+    <input type="submit" value="Apply"/>
+  </form>  
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/ChangeLog b/skyrix-sope/samples/WOxExtTest/ChangeLog
new file mode 100644 (file)
index 0000000..f8bf09a
--- /dev/null
@@ -0,0 +1,34 @@
+2004-06-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * KeyValueConditional.m: added ivars
+
+2004-03-24  Helge Hess  <helge.hess@skyrix.com>
+
+       * added a test page for WEQualifierConditional
+
+2004-01-23  Helge Hess  <helge.hess@opengroupware.org>
+
+       * use common.h instead of Foundation to improve compilation on OSX
+
+2003-12-12  Helge Hess  <helge.hess@opengroupware.org>
+
+       * general visual cleanups
+
+       * TreeView.m: added some component variables
+
+2002-10-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * TabView.wox: added demo for background-image tabs
+
+2002-08-05  Helge Hess  <helge.hess@skyrix.com>
+
+       * added example for <var:string />
+
+Wed Jan 23 15:59:31 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NSCoding, to support WOFileSessionStore
+
+Wed Jan 23 15:59:24 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * created ChangeLog
+
diff --git a/skyrix-sope/samples/WOxExtTest/CheckBoxMatrix.m b/skyrix-sope/samples/WOxExtTest/CheckBoxMatrix.m
new file mode 100644 (file)
index 0000000..148b64d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface CheckBoxMatrix : WOComponent
+@end
+
+#include "common.h"
+
+@implementation CheckBoxMatrix
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"3" forKey:@"maxColumns"];
+  }
+  return self;
+}
+
+- (id)increaseClicks {
+  int clicks;
+
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  [self takeValue:[NSNumber numberWithInt:++clicks] forKey:@"clicks"];
+  
+  return nil;
+}
+
+- (NSArray *)list {
+  return [NSArray arrayWithObjects:@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11", @"12", @"13", nil];
+}
+
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/CheckBoxMatrix.wox b/skyrix-sope/samples/WOxExtTest/CheckBoxMatrix.wox
new file mode 100644 (file)
index 0000000..ad1ba4e
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <form var:action="self">
+    <var:checkbox-matrix list="list" item="item" 
+                         maxColumns="maxColumns"
+                         selections="selections"
+                         horizontal="horizontal">
+       <var:string value="item"/>
+       <a var:action="increaseClicks">increase clicks</a>
+    </var:checkbox-matrix>
+    <br/>
+
+    clicks: <var:string value="clicks"/>
+    <br/>
+
+    <var:string value="selections"/>
+
+    <table border="0">
+       <tr><td></td><td></td></tr>
+       <tr>
+         <td>MaxColumns:</td>
+         <td><input type="text" var:value="maxColumns" size="4"/></td>
+       </tr>
+       <tr>
+         <td>Horizontal:</td>
+         <td><input type="checkbox" var:checked="horizontal"/></td>
+       </tr>
+     </table>
+    <input type="submit" var:action="self" value="apply"/>
+  </form>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/CollapsibleContent.m b/skyrix-sope/samples/WOxExtTest/CollapsibleContent.m
new file mode 100644 (file)
index 0000000..8a6bbd1
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface CollapsibleContent : WOComponent
+@end
+
+#include "common.h"
+
+@implementation CollapsibleContent
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:[NSNumber numberWithInt:0]    forKey:@"clicks"];
+  }
+  return self;
+}
+
+- (id)increaseClicks {
+  int clicks;
+
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  [self takeValue:[NSNumber numberWithInt:++clicks] forKey:@"clicks"];
+  
+  return nil;
+}
+
+- (id)clearClicks {
+  [self takeValue:[NSNumber numberWithInt:0] forKey:@"clicks"];
+  
+  return nil;
+}
+
+@end /* CollapsibleContent */
diff --git a/skyrix-sope/samples/WOxExtTest/CollapsibleContent.wox b/skyrix-sope/samples/WOxExtTest/CollapsibleContent.wox
new file mode 100644 (file)
index 0000000..3070e41
--- /dev/null
@@ -0,0 +1,77 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <form var:action="self">
+    <var:collapsible
+       const:condition  ="NO"
+       visibility       = "firstVisibility"
+       submitActionName ="clearClicks"
+       const:openedLabel = "first opened"
+       const:closedLabel = "first closed"
+       const:openedImageFileName = "expanded.gif"
+       const:closedImageFileName = "collapsed.gif">
+
+       <table border="0" bgcolor="#FAE8B8">
+         <tr>
+           <td>
+             content of the <b>first</b> component
+             <input type="checkbox" var:checked="isFirstChecked"/>
+           </td>
+         </tr>
+         <tr>
+           <td align="center"><a var:action="increaseClicks">click</a></td>
+         </tr>
+       </table>
+    </var:collapsible>
+  
+    <var:collapsible 
+       const:condition  = "YES"
+       visibility       = "secondVisibility"
+       submitActionName = "clearClicks"
+       const:openedLabel = "second opened"
+       const:closedLabel = "second closed"
+       const:openedImageFileName = "expanded.gif"
+       const:closedImageFileName = "collapsed.gif">
+       
+       <table border="0" bgcolor="#FAE8B8">
+         <tr>
+           <td>
+             content of the <b>second</b> component
+             <input type="checkbox" var:checked="isSecondChecked"/>
+           </td>
+         </tr>
+         <tr>
+           <td align="center"><a var:action="increaseClicks">click</a></td>
+         </tr>
+       </table>
+    </var:collapsible>
+    
+    <var:collapsible
+       const:condition="NO"
+       visibility="thirdVisibility"
+       submitActionName="clearClicks"
+       const:openedLabel = "third open"
+       const:closedLabel = "third closed"
+       const:openedImageFileName = "expanded.gif"
+       const:closedImageFileName = "collapsed.gif">
+
+       <table border="0" bgcolor="#FAE8B8">
+         <tr>
+           <td>
+             content of the <b>third</b> component
+             <input type="checkbox" var:checked="isThirdChecked"/>
+           </td>
+         </tr>
+         <tr>
+           <td align="center"><a var:action="increaseClicks">click</a></td>
+         </tr>
+       </table>
+    </var:collapsible>
+  </form>
+  
+  <br/>
+  clicks: <var:string value="clicks"/>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/CollapsibleContentExt.m b/skyrix-sope/samples/WOxExtTest/CollapsibleContentExt.m
new file mode 100644 (file)
index 0000000..bc3f84d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface CollapsibleContentExt : WOComponent
+@end
+
+#include "common.h"
+
+@implementation CollapsibleContentExt
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:[NSNumber numberWithInt:0]    forKey:@"clicks"];
+  }
+  return self;
+}
+
+- (id)increaseClicks {
+  int clicks;
+
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  [self takeValue:[NSNumber numberWithInt:++clicks] forKey:@"clicks"];
+  
+  return nil;
+}
+
+- (id)clearClicks {
+  [self takeValue:[NSNumber numberWithInt:0] forKey:@"clicks"];
+  
+  return nil;
+}
+
+@end /* CollapsibleContentExt */
diff --git a/skyrix-sope/samples/WOxExtTest/CollapsibleContentExt.wox b/skyrix-sope/samples/WOxExtTest/CollapsibleContentExt.wox
new file mode 100644 (file)
index 0000000..4dde9b1
--- /dev/null
@@ -0,0 +1,132 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame"
+           title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+  some text <br />
+
+  <form var:action="self">
+    <br/>
+
+    <var:we-collapsible const:condition="NO" 
+                        visibility="firstVisibility"
+                        const:allowScript="YES">
+
+        <var:we-collapsible-title NAME="TitleMode">
+          <var:we-collapsible-action
+             const:openedLabel         = "first opened"
+             const:closedLabel         = "first closed"
+             const:openedImageFileName = "expanded.gif"
+             const:closedImageFileName = "collapsed.gif"
+             submitActionName    = "clearClicks"/>
+
+          first collapsible (javaScript: only IE)<br/>
+        </var:we-collapsible-title>
+        
+        <var:we-collapsible-content NAME="ContentMode">
+           content of the <b>first</b> collapsible
+           some text, some text, some text <br/>
+           some text, some text, some text <br/>
+           some text, some text, some text <br/>
+           some text, some text, some text <br/>
+           some text, some text, some text <br/>
+           <input type="checkbox" var:checked="isFirstChecked"/>
+           <a var:action="increaseClicks">increase clicks</a>
+        </var:we-collapsible-content>
+    </var:we-collapsible>
+
+    <br/>
+
+    <var:we-collapsible NAME="SecondCollapsibleContent">
+
+        <var:we-collapsible-title NAME="TitleMode">
+          <var:we-collapsible-action
+             const:openedLabel         = "second opened"
+             const:closedLabel         = "second closed"
+             const:openedImageFileName = "expanded.gif"
+             const:closedImageFileName = "collapsed.gif"
+             submitActionName    = "clearClicks"
+             isLastClicked       = "isSecondLastClicked"
+             const:fragmentIdentifier  = "second"/>
+
+           second collapsible (javaScript: only IE)<br/>
+        </var:we-collapsible-title>
+
+        <var:we-collapsible-content NAME="ContentMode">
+           content of the <b>second</b> collapsible
+           some text, some text, some text <br/>
+           some text, some text, some text <br/>
+           some text, some text, some text <br/>
+           some text, some text, some text <br/>
+           some text, some text, some text <br/>
+           <input type="checkbox" var:checked="isSecondChecked"/>
+           <a var:action="increaseClicks">increase clicks</a>
+        </var:we-collapsible-content>
+
+    </var:we-collapsible>
+
+    <br/>
+    
+    <var:we-collapsible NAME="ThirdCollapsibleContent">
+
+        <var:we-collapsible-title NAME="TitleMode">
+          <var:we-collapsible-action
+             const:openedLabel         = "third opened"
+             const:closedLabel         = "third closed"
+             const:openedImageFileName = "expanded.gif"
+             const:closedImageFileName = "collapsed.gif"
+             submitActionName    = "clearClicks"
+             isLastClicked       = "isThirdLastClicked"
+             const:fragmentIdentifier  = "third"/>
+          <br/>
+        </var:we-collapsible-title>
+
+        <var:we-collapsible-content NAME="ContentMode">
+           content of the <b>third</b> collapsible
+           <input type="checkbox" var:checked="isThirdChecked"/>
+           <a var:action="increaseClicks">increase clicks</a>
+        </var:we-collapsible-content>
+
+    </var:we-collapsible>
+
+  </form> <!--Form-->
+
+  <br/>
+  clicks: <var:string value="clicks"/>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/ConfirmPanel.m b/skyrix-sope/samples/WOxExtTest/ConfirmPanel.m
new file mode 100644 (file)
index 0000000..efe6469
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface ConfirmPanel : WOComponent
+@end
+
+#include "common.h"
+
+@implementation ConfirmPanel
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:[NSNumber numberWithInt:0] forKey:@"clicks"];
+  }
+  return self;
+}
+- (id)countClicks {
+  int clicks;
+
+  [self logWithFormat:@"+++ invoke 'countClicks' action +++"];
+  
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  [self takeValue:[NSNumber numberWithInt:++clicks] forKey:@"clicks"];
+
+  return nil;
+}
+
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/ConfirmPanel.wox b/skyrix-sope/samples/WOxExtTest/ConfirmPanel.wox
new file mode 100644 (file)
index 0000000..0bebef9
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className="Frame" title="name" 
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <var:js-confirm-panel
+        const:pageName="PanelContent"
+        const:confirmMessage="Do you want to open a new target window ?"
+        const:targetWindow="panel"
+        const:string="'new page' - confirm panel"/>
+  <br/>
+  
+  <var:js-confirm-panel
+        action="countClicks"
+        const:confirmMessage="Do you want to increase the clicks?"
+        const:string="'invoke action' - confirm panel"/>
+  clicks: <b><var:string value="clicks"/></b>
+  <br/>
+
+  <var:js-confirm-panel
+        javaScriptFunction="javaScriptFunction"
+        const:confirmMessage="Do you want to invoke a javaScript function?"
+        const:string="'invoke javescript' - confirm panel"/>
+  <br/>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/DateField.m b/skyrix-sope/samples/WOxExtTest/DateField.m
new file mode 100644 (file)
index 0000000..018052f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/NGObjWeb.h>
+
+@interface DateField : WOComponent
+{
+}
+@end
+
+@implementation DateField
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"2000" forKey:@"year"];
+    [self takeValue:@"10"   forKey:@"month"];
+    [self takeValue:@"20"   forKey:@"day"];
+    [self takeValue:[NSCalendarDate date] forKey:@"date"];
+  }                           
+  return self;
+}
+
+@end /* DateField */
diff --git a/skyrix-sope/samples/WOxExtTest/DateField.wox b/skyrix-sope/samples/WOxExtTest/DateField.wox
new file mode 100644 (file)
index 0000000..1a675d3
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className="Frame" title="name" 
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+  <form var:action="self">
+    <var:date-field year="year" month="month" day="day" const:format="%Y-%m-%d"/>
+    <var:date-field date="date" const:format="%Y-%m-%d"/>
+    <input type="submit" value="apply"/>
+  </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/DictionaryRepetition.m b/skyrix-sope/samples/WOxExtTest/DictionaryRepetition.m
new file mode 100644 (file)
index 0000000..52bdb88
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface DictionaryRepetition : WOComponent
+{
+}
+@end
+
+#include "common.h"
+
+@implementation DictionaryRepetition
+
+- (id)init {
+  if ((self = [super init])) {
+    WOResourceManager *rm;
+    NSString          *file;
+
+    rm   = [[self application] resourceManager];
+
+    file = [rm pathForResourceNamed:@"Dictionary.plist"
+               inFramework:nil
+               languages:nil];
+                              
+    [self takeValue:[NSMutableDictionary dictionaryWithContentsOfFile:file]
+             forKey:@"dictionary"];
+    
+    [self takeValue:[NSNumber numberWithInt:0] forKey:@"clicks"];
+  }
+  return self;
+}
+
+- (id)increaseClicks {
+  int clicks;
+
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  [self takeValue:[NSNumber numberWithInt:++clicks] forKey:@"clicks"];
+  
+  return nil;
+}
+
+- (id)clearClicks {
+  [self takeValue:[NSNumber numberWithInt:0] forKey:@"clicks"];
+  return nil;
+}
+
+@end /* DictionaryRepetition */
diff --git a/skyrix-sope/samples/WOxExtTest/DictionaryRepetition.wox b/skyrix-sope/samples/WOxExtTest/DictionaryRepetition.wox
new file mode 100644 (file)
index 0000000..4364672
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <form var:action="self">
+    <table border="0">
+
+      <var:foreach-key dictionary="dictionary" key="key" item="item">
+         <tr>
+           <td align="right"><var:string value="key"/></td>
+           <td><input type="text" var:value="item" const:size="30"/></td>
+           <td><a var:action="increaseClicks">increase clicks</a></td>
+         </tr>
+      </var:foreach-key>
+      
+      <tr><td colspan="2">
+        <input type="submit" var:action="clearClicks" value="apply"/>
+      </td></tr>
+    </table>
+    
+    <br/>
+    clicks: <var:string value="clicks"/>
+
+  </form>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/DirectAction.m b/skyrix-sope/samples/WOxExtTest/DirectAction.m
new file mode 100644 (file)
index 0000000..2299ebb
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/NGObjWeb.h>
+
+@interface DirectAction: WODirectAction
+
+@end
+
+@implementation DirectAction
+
+
+- (id)flytoAction {
+  id page;
+  
+  page = [self pageWithName:@"ImageFlyover"];
+  [page takeValue:[[self request] formValueForKey:@"test"] forKey:@"flyover"]; 
+  return page;
+}
+
+
+@end /* DirectAction */
diff --git a/skyrix-sope/samples/WOxExtTest/DnD.m b/skyrix-sope/samples/WOxExtTest/DnD.m
new file mode 100644 (file)
index 0000000..8b4c3bf
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/WOComponent.h>
+
+@interface DnD : WOComponent
+@end
+
+#include "common.h"
+
+@implementation DnD
+
+- (void)awake {
+  [super awake];
+  [self setObject:nil forKey:@"lastDropOn"];
+}
+
+- (NSArray *)oneList {
+  return [NSArray arrayWithObject:@"one"];
+}
+- (NSArray *)twoList {
+  return [NSArray arrayWithObject:@"two"];
+}
+- (NSArray *)listOneTwo {
+  return [NSArray arrayWithObjects:@"one", @"two", nil];
+}
+
+- (BOOL)droppedOnOne {
+  return [[self objectForKey:@"lastDropOn"] isEqualToString:@"one"];
+}
+- (BOOL)droppedOnTwo {
+  return [[self objectForKey:@"lastDropOn"] isEqualToString:@"two"];
+}
+- (BOOL)droppedOnOneTwo {
+  return [[self objectForKey:@"lastDropOn"] isEqualToString:@"oneTwo"];
+}
+
+- (id)one {
+  NSLog(@"one: dropped %@", [self objectForKey:@"droppedObject"]);
+  [self setObject:@"one" forKey:@"lastDropOn"];
+  return nil;
+}
+- (id)two {
+  NSLog(@"two: dropped %@", [self objectForKey:@"droppedObject"]);
+  [self setObject:@"two" forKey:@"lastDropOn"];
+  return nil;
+}
+- (id)oneTwo {
+  NSLog(@"oneTwo: dropped %@", [self objectForKey:@"droppedObject"]);
+  [self setObject:@"oneTwo" forKey:@"lastDropOn"];
+  return nil;
+}
+
+@end /* DnD */
diff --git a/skyrix-sope/samples/WOxExtTest/DnD.wox b/skyrix-sope/samples/WOxExtTest/DnD.wox
new file mode 100644 (file)
index 0000000..3957d63
--- /dev/null
@@ -0,0 +1,99 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+   Drag'n'Drop - only works on IE !<br/>
+
+   Used elements:
+   <ul>
+     <li>WEDragContainer</li>
+     <li>WEDropContainer</li>
+     <li>WEDragScript</li>
+     <li>WEDropScript</li>
+   </ul>
+   
+   <var:script-drag/>
+   <var:script-drop/>
+   
+   <table border="0">
+     <tr>
+       <td valign="top">
+         <table border="1">
+           <tr>
+             <td colspan="3">DropZone</td>
+           </tr>
+           <tr>
+             <td>one</td>
+             <td>two</td>
+             <td>one/two</td>
+           </tr>
+           
+           <tr>
+             <td>
+               <var:js-drop const:elementName   = "td"
+                            const:isAttached    = "YES"
+                            tags                = "oneList"
+                            droppedObject       = "droppedObject"
+                            action              = "one"
+                            const:swapColor     = "YES"
+                            const:bgcolor       = "gray"
+                            const:activeColor   = "blue"
+                            const:inactiveColor = "green"
+                            const:width         = "80"
+                            const:height        = "80">
+                 <var:if condition="droppedOnOne">
+                   <var:string value="droppedObject"/></var:if>
+                 <entity name="nbsp"/>
+               </var:js-drop>
+             </td>
+             
+             <var:js-drop const:elementName   = "td"
+                          const:isAttached    = "YES"
+                          tags                = "twoList"
+                          droppedObject       = "droppedObject"
+                          action              = "two"
+                          const:swapColor     = "YES"
+                          const:bgcolor       = "gray"
+                          const:width         = "80"
+                          const:height        = "80">
+               <var:if condition="droppedOnTwo">
+                 <var:string value="droppedObject"/></var:if>
+               <entity name="nbsp"/>
+             </var:js-drop>
+
+             <var:js-drop const:elementName   = "td"
+                          const:isAttached    = "YES"
+                          tags                = "listOneTwo"
+                          droppedObject       = "droppedObject"
+                          action              = "two"
+                          const:swapColor     = "YES"
+                          const:bgcolor       = "gray"
+                          const:width         = "80"
+                          const:height        = "80">
+               <var:if condition="droppedOnOneTwo">
+                 <var:string value="droppedObject"/></var:if>
+               <entity name="nbsp"/>
+             </var:js-drop>
+           </tr>
+         </table>
+       </td>
+       
+       <td valign="top" align="left">
+         Outside form:<br/><br/>
+      
+         <var:js-drag const:tag="one" const:object="one-toBeDropped">
+           <a href="#">DragMe</a></var:js-drag>
+         
+         <hr/>
+         
+         Inside form:
+         <form var:action="self">
+           <var:js-drag const:tag="one" const:object="one-toBeDropped">
+             <a href="#">DragMe</a></var:js-drag>
+         </form>
+       </td>
+     </tr>
+   </table>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/Frame.m b/skyrix-sope/samples/WOxExtTest/Frame.m
new file mode 100644 (file)
index 0000000..f91041e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSString;
+
+@interface Frame : WOComponent
+{
+  NSString *title;
+}
+@end
+
+#include "common.h"
+
+@implementation Frame
+
+- (void)dealloc {
+  [self->title release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setTitle:(NSString *)_t {
+  ASSIGNCOPY(self->title, _t);
+}
+- (NSString *)title {
+  return self->title;
+}
+
+- (NSString *)xmlContent {
+  WOResourceManager *rm;
+  NSString          *path;
+  NSString          *str;
+  
+  str  = [[self valueForKey:@"title"] stringByAppendingPathExtension:@"wox"];
+  rm   = [[self application] resourceManager];
+  
+  path = [rm pathForResourceNamed:str
+             inFramework:nil
+             languages:nil];
+  
+  str = [NSString stringWithContentsOfFile:path];
+
+  return str;
+}
+
+@end /* Frame */
diff --git a/skyrix-sope/samples/WOxExtTest/Frame.wox b/skyrix-sope/samples/WOxExtTest/Frame.wox
new file mode 100644 (file)
index 0000000..2a0dedf
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version='1.0' standalone='yes'?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding"
+      xmlns:const="OGo:value"
+      xmlns:rsrc="OGo:url"
+>
+  <head>
+    <title><var:string value="title"/></title>
+
+    <meta name="author" content="SKYRIX Software AG" />
+    <meta name="robots" content="stop" />
+
+    <link type="text/css" rel="stylesheet" rsrc:href="site.css"    />
+    <link href="mailto:helge.hess@opengroupware.org" rev="made" />
+    <link rel="shortcut icon" rsrc:href="favicon.ico" />
+  </head>
+
+  <body>
+    <div id="header">
+      <img filename="OGoLogo.gif" class="headerlogo" alt="Logo" />
+      <div id="headerhistory">
+        <span id="navtitle">WOxExtTest - Dynamic Element Demonstration</span>
+      </div>
+    </div>
+    <br />
+    
+    <h3><var:string value="title"/></h3>
+
+    <!-- this embeds the content of the page -->
+    <var:component-content/>
+
+    <!-- here we keep a link back to the Main page -->
+    <hr/>
+    [<a pageName="Main">main</a>]
+    <hr/>
+    
+    <!-- and we print out the template source of the page -->
+    <pre id="tmplsrc"><var:string value="xmlContent"/></pre>
+  </body>
+</html>
diff --git a/skyrix-sope/samples/WOxExtTest/GNUmakefile b/skyrix-sope/samples/WOxExtTest/GNUmakefile
new file mode 100644 (file)
index 0000000..a50739e
--- /dev/null
@@ -0,0 +1,94 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+WOAPP_NAME = WOxExtTest
+
+WOxExtTest_OBJC_FILES += \
+       WOxExtTest.m               \
+       Main.m                     \
+       Frame.m                    \
+       PanelContent.m  \
+       \
+       ValidatedField.m           \
+       Switch.m                   \
+       Table.m                    \
+       TableView.m                \
+       DnD.m                      \
+       TreeView.m                 \
+       Browser.m                  \
+       ImageFlyover.m             \
+       DirectAction.m             \
+       TabPanel.m                 \
+       KeyValueConditional.m      \
+       TabView.m                  \
+       AlertPanel.m               \
+       ConfirmPanel.m             \
+       TextFlyover.m              \
+       ModalWindow.m              \
+       CollapsibleContent.m       \
+       DictionaryRepetition.m     \
+       ThresholdColoredNumber.m   \
+       CollapsibleContentExt.m    \
+       RadioButtonMatrix.m        \
+       CheckBoxMatrix.m           \
+       PageView.m                 \
+       WeekOverview.m             \
+       WeekColumnView.m           \
+       MonthOverview.m            \
+       TableMatrix.m              \
+       ShiftClick.m               \
+       TimeField.m                \
+       DateField.m                \
+       CalendarField.m            \
+       RichString.m               \
+       QualifierConditional.m     \
+
+WOxExtTest_RESOURCE_FILES += \
+       Resources/TableView.plist       \
+       Resources/TreeView.plist        \
+       Resources/Dictionary.plist      \
+       Resources/appointments.plist    \
+       \
+       Main.wox                        \
+       Frame.wox                       \
+       ValidatedField.wox              \
+       Switch.wox                      \
+       Table.wox                       \
+       DnD.wox                         \
+       TableView.wox                   \
+       TreeView.wox                    \
+       Browser.wox                     \
+       ImageFlyover.wox                \
+       TabPanel.wox                    \
+       KeyValueConditional.wox         \
+       TabView.wox                     \
+       AlertPanel.wox                  \
+       ConfirmPanel.wox                \
+       TextFlyover.wox                 \
+       CollapsibleContent.wox          \
+       DictionaryRepetition.wox        \
+       ThresholdColoredNumber.wox      \
+       CollapsibleContentExt.wox       \
+       RadioButtonMatrix.wox           \
+       CheckBoxMatrix.wox              \
+       PageView.wox                    \
+       WeekOverview.wox                \
+       WeekColumnView.wox              \
+       MonthOverview.wox               \
+       ShiftClick.wox                  \
+       TimeField.wox                   \
+       DateField.wox                   \
+       CalendarField.wox               \
+       RichString.wox                  \
+       VarString.wox                   \
+       QualifierConditional.wox        \
+
+WOxExtTest_WEBSERVER_RESOURCE_FILES = \
+       favicon.ico                   \
+       site.css                      \
+       WebServerResources/*.gif      \
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/woapp.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/samples/WOxExtTest/GNUmakefile.preamble b/skyrix-sope/samples/WOxExtTest/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..247bc2c
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+WOxExtTest_TOOL_LIBS += \
+       -lWEExtensions -lWOExtensions   \
+       -lNGObjWeb -lNGScripting        \
+       -lEOControl                     \
+       -lXmlRpc -lDOM -lSaxObjC
+
+WOxExtTest_LIB_DIRS  += -L../$(GNUSTEP_OBJ_DIR)
+
+ADDITIONAL_CPPFLAGS += -Wall
diff --git a/skyrix-sope/samples/WOxExtTest/ImageFlyover.m b/skyrix-sope/samples/WOxExtTest/ImageFlyover.m
new file mode 100644 (file)
index 0000000..9fe075f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface ImageFlyover : WOComponent
+@end
+
+#include "common.h"
+
+@implementation ImageFlyover
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:[NSNumber numberWithInt:0] forKey:@"clicks"];
+  }
+  return self;
+}
+- (id)countClicks {
+  int clicks;
+
+  [self logWithFormat:@"+++ invoke 'countClicks' action +++"];
+  
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  [self takeValue:[NSNumber numberWithInt:++clicks] forKey:@"clicks"];
+
+  return nil;
+}
+
+@end /* ImageFlyover */
diff --git a/skyrix-sope/samples/WOxExtTest/ImageFlyover.wox b/skyrix-sope/samples/WOxExtTest/ImageFlyover.wox
new file mode 100644 (file)
index 0000000..6c5242e
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className="Frame" title="name" 
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <b>JSImageFlyover example:</b><br/><br/>
+  
+  <var:js-img-flyover
+      const:pageName        = "PanelContent"
+      const:targetWindow    = "panel"
+      const:selectedImage   = "menu_email.gif"
+      const:unselectedImage = "menu_email_inactive.gif"
+      const:ALT             = "'new page' - image flyover"/>
+  <br/><br/>
+  
+  <var:js-img-flyover
+      var:action            = "countClicks"
+      const:selectedImage   = "menu_email.gif"
+      const:unselectedImage = "menu_email_inactive.gif"
+      const:alt             = "'invoke action' - image flyover"
+      const:align           = "middle"/>
+  clicks: <b><var:string value="clicks"/></b>
+  <br/><br/>
+  
+  <var:js-img-flyover
+      javaScriptFunction    = "javaScriptFunction"
+      const:selectedImage   = "menu_email.gif"
+      const:unselectedImage = "menu_email_inactive.gif"
+      const:alt             = "'invoke javescript' - image flyover"/>
+  <br/><br/>
+
+  <var:js-img-flyover
+      const:directActionName = "flyto"
+      const:selectedImage    = "menu_email.gif"
+      const:unselectedImage  = "menu_email_inactive.gif"
+      const:_test            = "direct action invoked" 
+      const:align            = "middle"
+      const:alt              = "'direct action' - image flyover"/>
+  (Note: _ is used for query parameters instead of ?)
+  
+  <var:string value="flyover"/>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/KeyValueConditional.m b/skyrix-sope/samples/WOxExtTest/KeyValueConditional.m
new file mode 100644 (file)
index 0000000..ef39b46
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <NGObjWeb/WOComponent.h>
+
+@interface KeyValueConditional : WOComponent
+{
+  id selection;
+  id item;
+}
+@end
+
+#include "common.h"
+
+@implementation KeyValueConditional
+
+- (id)init {
+  if ((self = [super init])) {
+    self->selection = @"second";
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->selection release];
+  [self->item      release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setItem:(id)_item {
+  ASSIGN(self->item, _item);
+}
+- (id)item {
+  return self->item;
+}
+
+- (void)setSelection:(id)_selection {
+  ASSIGN(self->selection, _selection);
+}
+- (id)selection {
+  return self->selection;
+}
+
+- (NSArray *)list {
+  static NSArray *list = nil;
+  if (list == nil) {
+    list = [[NSArray alloc] initWithObjects:
+                    @"first", @"second", @"third", @"fourth", nil];
+  }
+  return list;
+}
+
+@end /* KeyValueConditional */
diff --git a/skyrix-sope/samples/WOxExtTest/KeyValueConditional.wox b/skyrix-sope/samples/WOxExtTest/KeyValueConditional.wox
new file mode 100644 (file)
index 0000000..86e5575
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <var:if-key const:key="selection" const:value="first">
+    *** content of <b>first</b> KeyValueCondition ***
+  </var:if-key>
+
+  <var:if-key const:key="selection" const:value="second">
+    +++ content of <b>second</b> KeyValueCondition +++
+  </var:if-key>
+
+  <var:if-key const:key="selection" const:value="third">
+    --- content of <b>third</b> KeyValueCondition ---
+  </var:if-key>
+
+  <var:if-key const:key="selection" const:value="fourth">
+    ### content of <b>fourth</b> KeyValueCondition ###
+  </var:if-key>
+   
+  <form var:action="self">
+    <var:popup list="list" item="item" selection="selection" string="item"
+               const:singleSelection="YES"/>
+    
+    <input type="submit" var:action="self" value="apply"/>
+  </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/Lori.icns b/skyrix-sope/samples/WOxExtTest/Lori.icns
new file mode 100644 (file)
index 0000000..4d10244
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/Lori.icns differ
diff --git a/skyrix-sope/samples/WOxExtTest/Main.m b/skyrix-sope/samples/WOxExtTest/Main.m
new file mode 100644 (file)
index 0000000..c7739df
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface Main : WOComponent
+{
+}
+
+@end
+
+#include "common.h"
+
+@implementation Main
+
+@end /* Main */
diff --git a/skyrix-sope/samples/WOxExtTest/Main.wox b/skyrix-sope/samples/WOxExtTest/Main.wox
new file mode 100644 (file)
index 0000000..622075c
--- /dev/null
@@ -0,0 +1,94 @@
+<?xml version='1.0' standalone='yes'?>
+
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding"
+      xmlns:const="OGo:value"
+      xmlns:rsrc="OGo:url"
+>
+  <head>
+    <title>WOExtensions / WEExtensions</title>
+
+    <meta name="author" content="SKYRIX Software AG" />
+    <meta name="robots" content="stop" />
+
+    <link type="text/css" rel="stylesheet" rsrc:href="site.css"    />
+    <link href="mailto:helge.hess@opengroupware.org" rev="made" />
+    <link rel="shortcut icon" rsrc:href="favicon.ico" />
+  </head>
+
+  <body>
+    <div id="header">
+      <img filename="OGoLogo.gif" class="headerlogo" alt="Logo" />
+      <div id="headerhistory">
+        <span id="navtitle">WOxExtTest - Dynamic Element Demonstration</span>
+      </div>
+    </div>
+    <br />
+    
+    <h2>WOExtensions/WEExtensions Test (Oeffner)</h2>
+
+    <table width="100%" border="0" cellspacing="3">
+      <tr>
+       <td valign="top">
+          <h4>JavaScript Elements</h4>
+            <li><a pageName="ValidatedField">var:js-validated-field</a></li>
+            <li><a pageName="AlertPanel"    >var:js-alert-panel</a></li>
+            <li><a pageName="ConfirmPanel"  >var:js-confirm-panel</a></li>
+            <li><a pageName="ModalWindow"   >var:js-modal-window</a></li>
+            <li><a pageName="ImageFlyover"  >var:js-img-flyover</a></li>
+            <li><a pageName="TextFlyover"   >var:js-text-flyover</a></li>
+            <li><a pageName="DnD"           >Drag'n'Drop</a></li>
+            <li><a pageName="ShiftClick"    >var:js-shiftclick</a></li>
+        </td>
+        <td valign="top">
+          <h4>Misc Control Elements</h4>
+            <li><a pageName="KeyValueConditional"   >var:if-key</a></li>
+            <li><a pageName="QualifierConditional"  >var:if-qualifier</a></li>
+            <li><a pageName="Switch"                >var:switch</a></li>
+            <li><a pageName="DictionaryRepetition"  >var:foreach-key</a></li>
+
+          <h4>Misc Elements</h4>
+            <li>WORedirect</li>
+            <li><a pageName="TabPanel"              >var:tab-panel</a></li>
+            <li><a pageName="Table"                 >var:table</a></li>
+            <li><a pageName="CollapsibleContent"    >var:collapsible</a></li>
+            <li><a pageName="ThresholdColoredNumber">var:threshold-colored-number</a></li>
+            <li><a pageName="RichString">var:rich-string</a></li>
+          <h4>Misc Form Elements</h4>
+            <li><a pageName="RadioButtonMatrix">var:radio-button-matrix</a></li>
+            <li><a pageName="CheckBoxMatrix">var:checkbox-matrix</a></li>
+         <br />
+       </td>
+      </tr>
+
+      <tr>
+       <td valign="top">
+          <h4>Complex Elements (WEExtensions)</h4>
+            <li><a pageName="TableView">var:tableview</a></li>
+            <li><a pageName="TreeView" >var:treeview</a></li>
+            <li><a pageName="TabView"  >var:tabview</a></li>
+            <li><a pageName="Browser"  >var:we-browser</a></li>
+            <li><a pageName="CollapsibleContentExt">var:we-collapsible</a></li>
+            <li><a pageName="PageView"   >var:pageview</a></li>
+            <li><a pageName="TableMatrix">var:table-matrix</a></li>
+        </td>
+        <td valign="top">
+          <h4>Scheduling Elements (WEExtensions)</h4>
+            <li><a pageName="WeekOverview"  >var:week-overview</a></li>
+            <li><a pageName="WeekColumnView">var:weekcol-view</a></li>
+            <li><a pageName="MonthOverview" >var:month-overview</a></li>
+            <li><a pageName="TimeField"     >var:time-field</a></li>
+            <li><a pageName="DateField"     >var:date-field</a></li>
+            <li><a pageName="CalendarField" >var:cal-field</a></li>
+       </td>
+      </tr>
+
+      <tr>
+       <td valign="top">
+          <h4>Standard Elements (NGObjWeb)</h4>
+         <li><a pageName="VarString">var:string</a></li>
+       </td>
+      </tr>
+    </table>
+  </body>
+</html>
diff --git a/skyrix-sope/samples/WOxExtTest/ModalWindow.m b/skyrix-sope/samples/WOxExtTest/ModalWindow.m
new file mode 100644 (file)
index 0000000..7aab5c3
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/NGObjWeb.h>
+
+@interface ModalWindow : WOComponent
+@end
+
+@implementation ModalWindow
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/ModalWindow.wox b/skyrix-sope/samples/WOxExtTest/ModalWindow.wox
new file mode 100644 (file)
index 0000000..1fb1195
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <var:js-modal-window 
+        const:href="http://www.heise.de"
+        const:pageName="PanelContent"
+        const:string="modaltest"/>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/MonthOverview.m b/skyrix-sope/samples/WOxExtTest/MonthOverview.m
new file mode 100644 (file)
index 0000000..ae2a5ac
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSArray;
+
+@interface MonthOverview: WOComponent
+{
+  NSArray *list;
+}
+@end
+
+#include "common.h"
+
+@implementation MonthOverview
+
+static inline void setDateWithKey(id obj, NSString *key) {
+  NSString *str;
+
+  str = [obj objectForKey:key];
+
+  if (str) {
+    NSCalendarDate *date;
+
+    date = [NSCalendarDate dateWithString:str
+                           calendarFormat:@"%Y-%m-%d %H:%M:%S %Z"];
+    [obj setObject:date forKey:key];
+  }
+}
+
+- (id)init {
+  if ((self = [super init])) {
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->list);
+  [super dealloc];
+}
+
+- (NSCalendarDate *)weekStart {
+  return [NSCalendarDate dateWithString:@"2000-11-06 00:00:00 +0100"
+                         calendarFormat:@"%Y-%m-%d %H:%M:%S %Z"];
+}
+
+- (NSArray *)list {
+  if (self->list == nil) {
+    WOResourceManager *rm;
+    NSString          *path;
+
+    rm = [[self application] resourceManager];
+    path = [rm pathForResourceNamed:@"appointments.plist"
+               inFramework:nil
+               languages:nil];
+
+    self->list = [[NSArray alloc] initWithContentsOfFile:path];
+
+    {
+      int i, cnt;
+      
+      for (i = 0, cnt = [self->list count]; i < cnt; i++) {
+        setDateWithKey([self->list objectAtIndex:i], @"startDate");
+        setDateWithKey([self->list objectAtIndex:i], @"endDate");
+      }
+    }
+  }
+  return self->list;
+}
+
+- (NSString *)contentColor {
+  NSCalendarDate *day = nil;
+
+  day = [self valueForKey:@"currentDay"];
+  return ([day monthOfYear] == 11) ? @"#CCCCCC" : @"EEEEEE";
+}
+
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/MonthOverview.wox b/skyrix-sope/samples/WOxExtTest/MonthOverview.wox
new file mode 100644 (file)
index 0000000..8ba932e
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <var:month-overview list="list" item="item" index="index" 
+                      currentDay="currentDay"
+                      const:year="2000" const:month="11"
+                      const:labelColor="#DDAAAA" contentColor="contentColor">
+
+    <var:month-info>
+      <small><b><i>infos of day</i></b></small><br/><br/>
+    </var:month-info>
+    
+    <var:month>
+      <b><var:string value="item.title"/></b>
+      <br/>
+      <small><var:string value="item.startDate"/></small>
+      <br/><br/>
+    </var:month>
+
+  </var:month-overview>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/PageView.m b/skyrix-sope/samples/WOxExtTest/PageView.m
new file mode 100644 (file)
index 0000000..028929d
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/WOComponent.h>
+
+@interface PageView : WOComponent
+@end
+
+#include "common.h"
+
+@implementation PageView
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"#FFDAAA" forKey:@"contentColor"];
+    [self takeValue:@"#FAE8B8" forKey:@"titleColor"];
+  }
+  return self;
+}
+
+- (NSArray *)pages {
+  return [NSArray arrayWithObjects:@"one", @"two", @"three", nil];
+}
+
+@end /* PageView */
diff --git a/skyrix-sope/samples/WOxExtTest/PageView.wox b/skyrix-sope/samples/WOxExtTest/PageView.wox
new file mode 100644 (file)
index 0000000..7d975e3
--- /dev/null
@@ -0,0 +1,178 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  Selection: <var:string value="selection"/>
+  <br/>
+
+  <hr/>
+  Without form:<br/>
+  <var:pageview selection="selection"
+                titleColor="titleColor"
+                contentColor="contentColor"
+                const:firstIcon         = "first.gif"
+                const:firstBlindIcon    = "first_blind.gif"
+                const:previousIcon      = "previous.gif"
+                const:previousBlindIcon = "previous_blind.gif"
+                const:nextIcon          = "next.gif"
+                const:nextBlindIcon     = "next_blind.gif"
+                const:lastIcon          = "last.gif"
+                const:lastBlindIcon     = "last_blind.gif"
+    >
+    <var:page const:key="first" const:title="first page">
+       first page content
+    </var:page>
+
+    <var:page const:key="second" const:title="second page">
+       second page content
+    </var:page>
+      
+    <var:page const:key="third" const:title="third page">
+       third page content
+    </var:page>
+
+    <var:page const:key="fourth" const:title="fourth page">
+       fourth page content
+    </var:page>
+
+    <var:page const:key="fifth" const:title="fifth page">
+       fifth page content
+    </var:page>
+  </var:pageview>
+
+  <hr/>
+  Dynamically generated pages (using a var:foreach ...):<br/>
+  DO NOT WORK !
+<!--
+  <var:pageview selection="selection"
+                titleColor="titleColor"
+                contentColor="contentColor"
+                const:firstIcon         = "first.gif"
+                const:firstBlindIcon    = "first_blind.gif"
+                const:previousIcon      = "previous.gif"
+                const:previousBlindIcon = "previous_blind.gif"
+                const:nextIcon          = "next.gif"
+                const:nextBlindIcon     = "next_blind.gif"
+                const:lastIcon          = "last.gif"
+                const:lastBlindIcon     = "last_blind.gif"
+    >
+    <var:foreach list="pages" item="page">
+      <var:page key="page" title="page">
+        Content of <var:string value="page"/>
+      </var:page>
+    </var:foreach>
+  </var:pageview>
+-->
+  
+  <hr/>
+  With form inside :<br/>
+  <var:pageview selection="selection"
+                titleColor="titleColor"
+                contentColor="contentColor"
+                const:firstIcon         = "first.gif"
+                const:firstBlindIcon    = "first_blind.gif"
+                const:previousIcon      = "previous.gif"
+                const:previousBlindIcon = "previous_blind.gif"
+                const:nextIcon          = "next.gif"
+                const:nextBlindIcon     = "next_blind.gif"
+                const:lastIcon          = "last.gif"
+                const:lastBlindIcon     = "last_blind.gif"
+    >
+    <var:page const:key="first" const:title="first page">
+      <form var:action="self">
+         first page content
+         
+      </form>
+    </var:page>
+
+    <var:page const:key="second" const:title="second page">
+       second page content
+       <form var:action="self">
+         <table border="0">
+            <tr>
+              <td align="right">title color:</td>
+              <td><input type="text" var:value="titleColor"/></td>
+            </tr>
+            <tr>
+              <td align="right">content color:</td>
+              <td><input type="text" var:value="contentColor"/></td>
+            </tr>
+            <tr>
+              <td colspan="2">
+                <input type="submit" var:action="self" value="apply"/>
+              </td>
+            </tr>
+        </table>  
+      </form>
+    </var:page>
+      
+      <var:page const:key="third" const:title="third page">
+         third page content
+      </var:page>
+
+      <var:page const:key="fourth" const:title="fourth page">
+         fourth page content
+      </var:page>
+
+      <var:page const:key="fifth" const:title="fifth page">
+         fifth page content
+      </var:page>
+  </var:pageview>
+
+  <hr/>
+  With form (doesn't work ...):<br/>
+  <form var:action="self">
+    <var:pageview selection="selection"
+                  titleColor="titleColor"
+                  contentColor="contentColor"
+                  const:firstIcon         = "first.gif"
+                  const:firstBlindIcon    = "first_blind.gif"
+                  const:previousIcon      = "previous.gif"
+                  const:previousBlindIcon = "previous_blind.gif"
+                  const:nextIcon          = "next.gif"
+                  const:nextBlindIcon     = "next_blind.gif"
+                  const:lastIcon          = "last.gif"
+                  const:lastBlindIcon     = "last_blind.gif"
+      >
+      <var:page const:key="first" const:title="first page">
+         first page content
+      </var:page>
+
+      <var:page const:key="second" const:title="second page">
+         second page content
+      </var:page>
+      
+      <var:page const:key="third" const:title="third page">
+         third page content
+      </var:page>
+
+      <var:page const:key="fourth" const:title="fourth page">
+         fourth page content
+      </var:page>
+
+      <var:page const:key="fifth" const:title="fifth page">
+         fifth page content
+      </var:page>
+    </var:pageview>
+  </form>
+
+  <form var:action="self">
+    <table border="0">
+       <tr>
+         <td align="right">title color:</td>
+         <td><input type="text" var:value="titleColor"/></td>
+       </tr>
+       <tr>
+         <td align="right">content color:</td>
+         <td><input type="text" var:value="contentColor"/></td>
+       </tr>
+       <tr>
+         <td colspan="2">
+           <input type="submit" var:action="self" value="apply"/>
+         </td>
+       </tr>
+     </table>  
+  </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/PanelContent.m b/skyrix-sope/samples/WOxExtTest/PanelContent.m
new file mode 100644 (file)
index 0000000..a40ceda
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/NGObjWeb.h>
+
+@interface PanelContent : WOComponent
+@end
+
+@implementation PanelContent
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/PanelContent.wox b/skyrix-sope/samples/WOxExtTest/PanelContent.wox
new file mode 100644 (file)
index 0000000..da1369c
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' standalone='yes'?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding"
+      xmlns:const="http://www.skyrix.com/od/constant">
+  <head><title>Panel Content</title></head>
+
+  <body bgcolor="#FFDAAA">
+    <center><img filename="menu_email.gif" alt="nice image" border="0"/></center>
+    <center><b>some panel content</b></center>
+  </body>
+
+</html>
diff --git a/skyrix-sope/samples/WOxExtTest/QualifierConditional.m b/skyrix-sope/samples/WOxExtTest/QualifierConditional.m
new file mode 100644 (file)
index 0000000..56729d8
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <NGObjWeb/WOComponent.h>
+
+@interface QualifierConditional : WOComponent
+{
+  id qualifier;
+}
+@end
+
+#include "common.h"
+
+@implementation QualifierConditional
+
+- (id)init {
+  if ((self = [super init])) {
+    self->qualifier = 
+      @"context.request.clientCapabilities.userAgent like '*Mozilla*'";
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->qualifier release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setQualifier:(id)_q {
+  ASSIGN(self->qualifier, _q);
+}
+- (id)qualifier {
+  return self->qualifier;
+}
+
+@end /* QualifierConditional */
diff --git a/skyrix-sope/samples/WOxExtTest/QualifierConditional.wox b/skyrix-sope/samples/WOxExtTest/QualifierConditional.wox
new file mode 100644 (file)
index 0000000..d9ab63a
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <var:if-qualifier const:condition="name like '*Quali*'">
+    Qualifier matches: <tt>name like '*Quali*'</tt>
+  </var:if-qualifier>
+
+  <br />
+
+  <var:if-qualifier condition="qualifier">
+    Qualifier matches: <tt><var:string value="qualifier" /></tt>
+  </var:if-qualifier>
+  <var:if-qualifier condition="qualifier" const:negate="YES">
+    Qualifier does not match: <tt><var:string value="qualifier" /></tt>
+  </var:if-qualifier>
+
+  <hr />
+  
+  <form var:action="self">
+    Qualifier: 
+    <input type="text" name="qual" var:value="qualifier" size="60" />
+    <br />
+    
+    <input name="doit" type="submit" var:action="self" value="apply" />
+  </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/RadioButtonMatrix.m b/skyrix-sope/samples/WOxExtTest/RadioButtonMatrix.m
new file mode 100644 (file)
index 0000000..dcc592f
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface RadioButtonMatrix : WOComponent
+@end
+
+#include "common.h"
+
+@implementation RadioButtonMatrix
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"3" forKey:@"maxColumns"];
+  }
+  return self;
+}
+
+- (id)increaseClicks {
+  int clicks;
+
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  [self takeValue:[NSNumber numberWithInt:++clicks] forKey:@"clicks"];
+  
+  return nil;
+}
+
+- (NSArray *)list {
+  return [NSArray arrayWithObjects:
+                    @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8",
+                    @"9", @"10", @"11", @"12", @"13", nil];
+}
+
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/RadioButtonMatrix.wox b/skyrix-sope/samples/WOxExtTest/RadioButtonMatrix.wox
new file mode 100644 (file)
index 0000000..2aa79af
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <form var:action="self">
+    
+    <var:radio-button-matrix list="list" item="item"
+        maxColumns="maxColumns" selection="selection" 
+        horizontal="horizontal">
+      <var:string value="item"/>
+      <a var:action="increaseClicks">increase clicks</a>
+    </var:radio-button-matrix>
+    <br/>
+
+    clicks: <var:string value="clicks"/>
+    <br/>
+
+    <table border="0">
+      <tr><td></td><td></td></tr>
+      <tr>
+        <td>MaxColumns:</td>
+        <td><input type="text" var:value="maxColumns" size="4"/></td>
+      </tr>
+      <tr>
+        <td>Horizontal:</td>
+        <td><input type="checkbox" var:checked="horizontal"/></td>
+      </tr>
+    </table>
+     
+    <input type="submit" var:action="self" value="apply"/>
+  </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/Resources/Dictionary.plist b/skyrix-sope/samples/WOxExtTest/Resources/Dictionary.plist
new file mode 100644 (file)
index 0000000..d98e790
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  name      = "Brown";
+  title     = "Doc.";
+  firstName = "James";
+  age       = "42";
+  street    = "Mainst. 1";
+  city      = "New York";
+  zip       = "01234";
+}
diff --git a/skyrix-sope/samples/WOxExtTest/Resources/TableView.plist b/skyrix-sope/samples/WOxExtTest/Resources/TableView.plist
new file mode 100644 (file)
index 0000000..ebfb55f
--- /dev/null
@@ -0,0 +1,83 @@
+(
+   {
+     firstName  = "Donald";
+     name       = "Duck";
+     street     = "Mainst. 1";
+     city       = "Hamburg";
+     zip        = "01234";
+     identifier = "object1";
+   },
+   {
+     firstName  = "Heinz";
+     name       = "Mueller";
+     street     = "Hauptstrasse 34";
+     city       = "Hannover";
+     zip        = "54222";
+     identifier = "object2";
+   },
+   {
+     firstName  = "Johanna";
+     name       = "Buttelmann";
+     street     = "Dorfstrasse 3";
+     city       = "Magdeburg";
+     zip        = "39120";
+     identifier = "object3";
+   },
+   {
+     firstName  = "Steffen";
+     name       = "Kohlau";
+     street     = "Buchenweg 28";
+     city       = "Hannover";
+     zip        = "54222";
+     identifier = "object4";
+   },
+   {
+     firstName  = "Klaus";
+     name       = "Burger";
+     street     = "Alleestrasse 6";
+     city       = "Hamburg";
+     zip        = "01234";
+     identifier = "object5";
+   },
+   {
+     firstName  = "Dieter";
+     name       = "Hundertgross";
+     street     = "Hummelweg 5";
+     city       = "Magdeburg";
+     zip        = "39120";
+     identifier = "object6";
+   },
+  {
+     firstName  = "Heidrun";
+     name       = "Kleinmann";
+     street     = "Buttergasse 23";
+     city       = "Magdeburg";
+     zip        = "39122";
+     identifier = "object7";
+   },
+   {
+     firstName  = "Joerg";
+     name       = "Zunder";
+     street     = "Breitstrasse 4a";
+     city       = "Hannover";
+     zip        = "54222";
+     identifier = "object8";
+   },
+  {
+     firstName  = "Paul";
+     name       = "Mann";
+     street     = "Einsteinstrasse 7";
+     city       = "Hamburg";
+     zip        = "01231";
+     identifier = "object9";
+   },
+   {
+     firstName  = "Paula";
+     name       = "Frau";
+     street     = "Gareisstrasse 11";
+     city       = "Hannover";
+     zip        = "54112";
+     identifier = "object10";
+   },
+
+)
diff --git a/skyrix-sope/samples/WOxExtTest/Resources/TreeView.plist b/skyrix-sope/samples/WOxExtTest/Resources/TreeView.plist
new file mode 100644 (file)
index 0000000..5dede7b
--- /dev/null
@@ -0,0 +1,158 @@
+(
+ {
+   firstName = "Jochen";
+   name      = "Gutmann";
+   key       = one;
+   sublist   = (
+     {
+       firstName = "Ulli";
+       name      = "Bauer";
+       key       = one.one;
+       sublist   = ();
+     },
+     {
+       firstName = "Herbert";
+       name      = "Ganghover";
+       key       = one.two;
+       sublist   = (
+         {
+           firstName = "Traudel";
+           name      = "Busemann";
+           key       = one.two.one;
+           sublist   = (
+             {
+               firstName = "Flip";
+               name      = "Flop";
+               key       = one.two.one.one;
+               sublist   = (
+                 {
+                   firstName = "Tura";
+                   name      = "Nabelbauch";
+                   key       = one.two.one.one.one;
+                   sublist   = ();
+                 },
+                 {
+                   firstName = "Gollum";
+                   name      = "Hobbit";
+                   key       = one.two.one.one.two;
+                   sublist   = ();
+                 }
+               )
+             }
+           );
+         },
+         {
+           firstName = "Hubi";
+           name      = "Gubert";
+           key       = one.two.two;
+           sublist   = ();
+         },
+         {
+           firstName = "Klaus";
+           name      = "Fallenstein";
+           key       = one.two.three;
+           sublist   = ();
+         },
+         {
+           firstName = "Judith";
+           name      = "Beckstein";
+           key       = one.two.four;
+           sublist   = ();
+         }
+       );
+     },
+     {
+        firstName = "Johanna";
+        name      = "Strauss";
+        key       = one.three;
+        sublist   = ();
+     },
+     {
+        firstName = "Falco";
+        name      = "Jufert";
+        key       = one.four;
+        sublist   = ();
+     },
+     {
+       firstName = "Anja";
+       name      = "Jungblume";
+        key      = one.five;
+        sublist  = (
+          {
+            firstName = "Jan";
+            name      = "Pfitzmann";
+            key       = one.five.one;
+            sublist   = ();
+          },
+          {
+            firstName = "Oliver";
+            name      = "Stein";
+            key       = one.five.two;
+            sublist   = ();
+          },
+          {
+            firstName = "Gustav";
+            name      = "Schaffenbach";
+            key       = one.five.three;
+            sublist   = ();
+          }
+        );
+     }
+   );
+ },
+ {
+   name      = "Meier";
+   firstName = "Hannes";
+   key       = two;
+   sublist   = ();
+ },
+ {
+   firstName = "Liesel";
+   name      = "Rautenstein";
+   key       = three;
+   sublist   = (
+     {
+       firstName = "Lotte";
+       name      = "Buchholz";
+       key     = three.one;
+       sublist = ();
+     },
+     {
+       firstName = "Ingmar";
+       name      = "Rosenherz";
+       key       = three.two;
+       sublist   = ();
+     },
+     {
+       firstName = "Helge";
+       name      = "Schulz";
+       key       = three.three;
+       sublist   = ();
+     }
+   )
+ },
+ {
+   firstName = "Dieter";
+   name      = "Hosenfranz";
+   key       = four;
+   sublist   = ();
+ },
+ {
+   firstName = "Inge";
+   name      = "Meisel";
+   key       = five;
+   sublist   = ();
+ },
+ {
+   firstName = "Andre";
+   name      = "Zerter";
+   key       = six;
+   sublist   = ();
+ },
+ {
+   firstName = "Joseph";
+   name      = "Hedermeier";
+   key       = seven;
+   sublist   = ();
+ }
+)
diff --git a/skyrix-sope/samples/WOxExtTest/Resources/appointments.plist b/skyrix-sope/samples/WOxExtTest/Resources/appointments.plist
new file mode 100644 (file)
index 0000000..04a8ac1
--- /dev/null
@@ -0,0 +1,100 @@
+(
+        {
+            dateId = 126646;
+            endDate = "2000-11-02 12:00:00 +0100";
+            location = magdeburg;
+            startDate = "2000-11-02 11:00:00 +0100";
+            title = "collapsible cyclic";
+        },
+        {
+            dateId = 127000;
+            endDate = "2000-11-04 12:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-04 11:00:00 +0100";
+            title = test;
+        },
+        {
+            dateId = 127046;
+            endDate = "2000-11-06 12:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-06 11:00:00 +0100";
+            title = "monday test";
+        },
+        {
+            dateId = 127073;
+            endDate = "2000-11-06 14:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-06 13:00:00 +0100";
+            title = "test termin 2";
+        },
+        {
+            dateId = 127065;
+            endDate = "2000-11-06 17:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-06 15:00:00 +0100";
+            title = dfgdfgdfg;
+        },
+        {
+            dateId = 127080;
+            endDate = "2000-11-07 10:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-07 09:00:00 +0100";
+            title = asdasdasd;
+        },
+        {
+            dateId = 127061;
+            endDate = "2000-11-07 12:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-07 11:00:00 +0100";
+            title = sdfsdfsdf;
+        },
+        {
+            dateId = 127090;
+            endDate = "2000-11-08 18:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-08 17:00:00 +0100";
+            title = dsfdsfdsf;
+        },
+        {
+            dateId = 127041;
+            endDate = "2000-11-09 12:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-09 11:00:00 +0100";
+            title = test;
+        },
+        {
+            dateId = 127154;
+            endDate = "2000-11-11 12:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-09 11:00:00 +0100";
+            title = "di-do";
+        },
+        {
+            dateId = 127103;
+            endDate = "2000-11-11 12:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-11 11:00:00 +0100";
+            title = "saturday am";
+        },
+        {
+            dateId = 127107;
+            endDate = "2000-11-11 23:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-11 22:00:00 +0100";
+            title = "saturday pm";
+        },
+        {
+            dateId = 127098;
+            endDate = "2000-11-12 12:00:00 +0100";
+            location = " ";
+            startDate = "2000-11-12 11:00:00 +0100";
+            title = "sunday am test";
+        },
+        {
+            dateId   = 127111;
+            endDate  = "2000-11-12 23:59:00 +0100";
+            location = " ";
+            startDate = "2000-11-12 23:00:00 +0100";
+            title = "sunday pm";
+        }
+)
diff --git a/skyrix-sope/samples/WOxExtTest/RichString.m b/skyrix-sope/samples/WOxExtTest/RichString.m
new file mode 100644 (file)
index 0000000..2536423
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/NGObjWeb.h>
+
+@interface RichString : WOComponent
+{
+}
+@end
+
+@implementation RichString
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"richString richString richString" forKey:@"value"];
+  }
+  return self;
+}
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/RichString.wox b/skyrix-sope/samples/WOxExtTest/RichString.wox
new file mode 100644 (file)
index 0000000..77ed9a0
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className="Frame" title="name" 
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <var:rich-string value="value"
+    isBold="isBold" isItalic="isItalic" isUnderlined="isUnderlined" isSmall="isSmall"
+    size="size" color="color"/>
+  
+  <form var:action="self">
+     <table border="0">
+       <tr>
+         <td align="right">value:</td>
+         <td><input type="text" var:value="value" size="50"/></td>
+       </tr>
+       <tr>
+         <td align="right">isBold:</td>
+         <td><input type="checkbox" var:checked="isBold"/></td>
+       </tr>
+       <tr>
+         <td align="right">isItalic:</td>
+         <td><input type="checkbox" var:checked="isItalic"/></td>
+       </tr>
+       <tr>
+         <td align="right">isUnderlined:</td>
+         <td><input type="checkbox" var:checked="isUnderlined"/></td>
+       </tr>
+       <tr>
+         <td align="right">isSmall:</td>
+         <td><input type="checkbox" var:checked="isSmall"/></td>
+       </tr>
+
+       <tr>
+         <td align="right">color:</td>
+         <td><input type="text" var:value="color" size="8"/></td>
+       </tr>
+
+       <tr>
+         <td align="right">size:</td>
+         <td><input type="text" var:value="size" size="8"/></td>
+       </tr>
+
+       <tr>
+         <td colspan="2"><input type="submit" value="Apply"/></td>
+       </tr>
+     </table>
+  </form>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/ShiftClick.m b/skyrix-sope/samples/WOxExtTest/ShiftClick.m
new file mode 100644 (file)
index 0000000..d21e112
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface ShiftClick : WOComponent
+@end
+
+#include "common.h"
+
+@implementation ShiftClick
+
+- (NSArray *)items {
+  static NSArray *items = nil;
+  if (items == nil)
+    items = [[NSArray alloc] initWithObjects:
+              @"one", @"two", @"three", @"four", 
+              @"five", @"six", @"seven", @"eight", nil];
+  return items;
+}
+
+- (BOOL)isChecked {
+  return [[self valueForKey:[self valueForKey:@"item"]] boolValue];
+}
+- (void)setIsChecked:(BOOL)_flag {
+  [self takeValue:[NSNumber numberWithBool:_flag]
+        forKey:[self valueForKey:@"item"]];
+}
+- (NSString *)scriptCall {
+  return [NSString stringWithFormat:@"%@(%d)",
+                   [self valueForKey:@"scriptName"],
+                   [[self valueForKey:@"index"] intValue]];
+}
+@end /* ShiftClick */
diff --git a/skyrix-sope/samples/WOxExtTest/ShiftClick.wox b/skyrix-sope/samples/WOxExtTest/ShiftClick.wox
new file mode 100644 (file)
index 0000000..fb3dc33
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className="Frame" title="name" 
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+  
+  <var:js-shiftclick scriptName="scriptName"/>
+  
+  <form var:action="self">
+    <var:for-each list="items" item="item" index="index">
+      <input type="checkbox" 
+             var:checked="isChecked" 
+             var:value="index" 
+             var:onClick="scriptCall"/>
+      <var:string value="item"/>
+      <br/>
+    </var:for-each>
+    
+    <input type="submit" const:value="apply"/>
+  </form>
+  
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/Switch.m b/skyrix-sope/samples/WOxExtTest/Switch.m
new file mode 100644 (file)
index 0000000..639ab13
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface Switch : WOComponent
+@end
+
+#include "common.h"
+
+@implementation Switch
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"three" forKey:@"selection"];
+    
+    [self takeValue:
+            [NSArray arrayWithObjects:@"one", @"three", @"four",  nil]
+          forKey:@"selections"];
+
+  }
+  return self;
+}
+
+- (NSArray *)list {
+  return [NSArray arrayWithObjects:
+                    @"one", @"two", @"three", @"four",
+                    @"five", @"six", @"seven",nil];
+}
+
+- (NSArray *)keys {
+  return [NSArray arrayWithObjects:@"five", @"six", nil];
+}
+
+@end /* Switch */
diff --git a/skyrix-sope/samples/WOxExtTest/Switch.wox b/skyrix-sope/samples/WOxExtTest/Switch.wox
new file mode 100644 (file)
index 0000000..8370398
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+  
+  <b>MultiSwitch:</b><br/><br/>
+
+  <var:switch selections="selections">
+    <var:case const:key="one">     content of <b>one</b>       <br/></var:case>
+    <var:case const:key="two">     content of <b>two</b>       <br/></var:case>
+    <var:case const:key="three">   content of <b>three</b>     <br/></var:case>
+    <var:case const:key="four">    content of <b>four</b>      <br/></var:case>
+    <var:case keys="keys">   content of <b>fifth/six</b> <br/></var:case>
+    <var:default> content of <b>default</b> <br/></var:default>
+  </var:switch>
+  
+  <br/>
+
+  <b>SingleSwitch:</b>
+  <br/><br/>
+
+  <var:switch selection="selection">
+    <var:case const:key="one">   1. content of one    <br/></var:case>
+    <var:case const:key="two">   2. content of two    <br/></var:case>
+    <var:case const:key="three"> 3. content of three  <br/></var:case>
+    <var:case const:key="four">  4. content of four   <br/></var:case>
+    <var:case keys="keys">  content of fifth/six <br/></var:case>
+    <var:default> content of <b>default</b> <br/></var:default>
+  </var:switch> <!--SingleSwitch-->
+
+  <hr/>
+
+  <form var:action="self">
+    <table border="0">
+      <tr>
+        <td align="right">multi selection:</td>
+        <td>
+          <var:checkbox-list list="list" item="item"
+                             selections="selections"
+                             suffix="item"/>
+        </td>
+      </tr>
+      <tr>
+        <td align="right">single selection:</td>
+        <td><var:popup list="list" item="item" 
+                       selection="selection"
+                       const:singleSelection="YES"/></td>
+      </tr>
+      <tr>
+        <td colspan="2">
+          <input type="submit" var:action="self" value="apply"/></td>
+      </tr>
+    </table>
+    
+    content--
+      <var:component-content/>
+    --content
+  </form>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/TabPanel.m b/skyrix-sope/samples/WOxExtTest/TabPanel.m
new file mode 100644 (file)
index 0000000..86d3657
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/WOComponent.h>
+
+@interface TabPanel : WOComponent
+{
+}
+@end
+
+#include "common.h"
+
+@implementation TabPanel
+
+- (id) init {
+  if ((self = [super init])) {
+    [self takeValue:@"#777777" forKey:@"nonSelectedBgColor"];
+    [self takeValue:@"#BBBBBB" forKey:@"bgcolor"];
+    [self takeValue:@"#000077" forKey:@"textColor"];
+  }
+  return self;
+}
+
+- (NSArray *)tabKeys {
+  return [NSArray arrayWithObjects:@"first", @"second", @"third", nil];
+}
+
+@end /* TabPanel */
diff --git a/skyrix-sope/samples/WOxExtTest/TabPanel.wox b/skyrix-sope/samples/WOxExtTest/TabPanel.wox
new file mode 100644 (file)
index 0000000..b3ea3bc
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+  
+  <var:tab-panel tabs="tabKeys" selectedTab="selection"
+                 nonSelectedBgColor="nonSelectedBgColor"
+                 bgcolor="bgcolor" textColor="textColor">
+    
+    <var:if-key const:key="selection" const:value="first">
+        ------------------ <br/>
+        This is the content<br/>for the <b>first</b> tab.<br/>
+        ------------------ <br/>
+    </var:if-key>
+    
+    <var:if-key const:key="selection" const:value="second">
+        ****************** <br/>
+        This is the content<br/>for the <b>second</b> tab.<br/>
+        ****************** <br/>
+    </var:if-key>
+
+    <var:if-key const:key="selection" const:value="third">
+        ++++++++++++++++++ <br/>
+        This is the content<br/>for the <b>third</b> tab.<br/>
+        ++++++++++++++++++ <br/>
+    </var:if-key>
+
+  </var:tab-panel>
+
+  <form var:action="self">
+    <table border='0'>
+      <tr>
+        <td align='right'>non selected bg color:</td>
+        <td><input type="text" var:value="nonSelectedBgColor" size="8"/></td>
+      </tr>
+      <tr>
+        <td align='right'>selected bg color:</td>
+        <td><input type="text" var:value="bgcolor" size="8"/></td>
+      </tr>
+      <tr>
+        <td align='right'>textColor:</td>
+        <td><input type="text" var:value="textColor" size="8"/></td>
+      </tr>
+      <tr>
+        <td colspan='2'><input type="submit" var:action="self" value="apply"/></td>
+      </tr>
+    </table>
+  </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/TabView.m b/skyrix-sope/samples/WOxExtTest/TabView.m
new file mode 100644 (file)
index 0000000..5746c75
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/WOComponent.h>
+
+@interface TabView : WOComponent
+{
+  id bgColor;
+  id leftCornerIcon;
+  id rightCornerIcon;
+  id selection;
+}
+@end
+
+#include "common.h"
+
+@implementation TabView
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"persons" forKey:@"selection"];
+    [self takeValue:@"#FCF8DF" forKey:@"bgColor"];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->bgColor         release];
+  [self->rightCornerIcon release];
+  [self->leftCornerIcon  release];
+  [self->selection       release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setBgColor:(id)_col {
+  ASSIGN(self->bgColor, _col);
+}
+- (id)bgColor {
+  return self->bgColor;
+}
+
+- (void)setRightCornerIcon:(id)_icon {
+  ASSIGN(self->rightCornerIcon, _icon);
+}
+- (id)rightCornerIcon {
+  return self->rightCornerIcon;
+}
+
+- (void)setLeftCornerIcon:(id)_icon {
+  ASSIGN(self->leftCornerIcon, _icon);
+}
+- (id)leftCornerIcon {
+  return self->leftCornerIcon;
+}
+
+- (void)setSelection:(id)_col {
+  ASSIGN(self->selection, _col);
+}
+- (id)selection {
+  return self->selection;
+}
+
+/* actions */
+
+- (id)increaseClicks {
+  int clicks;
+
+  //[self debugWithFormat:@"increasing clicks .."];
+  
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  clicks++;
+  
+  [self takeValue:[NSNumber numberWithInt:clicks] forKey:@"clicks"];
+  
+  return nil;
+}
+
+@end /* TabView */
diff --git a/skyrix-sope/samples/WOxExtTest/TabView.wox b/skyrix-sope/samples/WOxExtTest/TabView.wox
new file mode 100644 (file)
index 0000000..5f49d45
--- /dev/null
@@ -0,0 +1,99 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+  
+  Clicks: <var:string value="clicks"/><br />
+
+  <var:tabview selection="selection" bgColor="bgColor"
+               const:leftCornerIcon  = "corner_left.gif"
+               const:rightCornerIcon = "corner_right.gif">
+     
+     <var:tab const:key="news" const:label="news tab"
+              isScript="useJavaScriptTabs"
+              const:tabIcon         = "tab_news.gif"
+              const:selectedTabIcon = "tab_news_selected.gif"
+              const:leftTabIcon     = "tab_news_left.gif">
+       content of <b>news</b> tab
+       <a var:action="increaseClicks">click</a>
+     </var:tab>
+
+     <var:tab const:key="persons" const:label="persons tab"
+              isScript="useJavaScriptTabs"
+              const:tabIcon         = "tab_persons.gif"
+              const:selectedTabIcon = "tab_persons_selected.gif"
+              const:leftTabIcon     = "tab_persons_left.gif">
+       content of <b>persons</b> tab
+       <a var:action="increaseClicks">click</a>
+     </var:tab>
+
+     <var:tab const:key="projects" const:label="projects tab"
+              isScript="useJavaScriptTabs"
+              const:tabIcon         = "tab_projects.gif"
+              const:selectedTabIcon = "tab_projects_selected.gif"
+              const:leftTabIcon     = "tab_projects_left.gif">
+       content of <b>projects</b> tab
+     </var:tab>
+
+  </var:tabview>
+
+  <hr />
+
+  <var:tabview selection="selection" bgColor="bgColor"
+              const:fontSize="3" const:fontColor="#000000"
+               const:leftCornerIcon  = "corner_left.gif"
+               const:rightCornerIcon = "corner_right.gif">
+     
+     <var:tab const:key="news" const:label="news"
+              isScript="useJavaScriptTabs" const:asBackground="1"
+             const:width="100" const:height="22"
+              const:tabIcon         = "tab_.gif"
+              const:selectedTabIcon = "tab_selected.gif"
+              const:leftTabIcon     = "tab_left.gif">
+       content of <b>news</b> tab
+       <a var:action="increaseClicks">click</a>
+     </var:tab>
+     
+     <var:tab const:key="persons" const:label="persons"
+              isScript="useJavaScriptTabs" const:asBackground="1"
+             const:width="100" const:height="22"
+              const:tabIcon         = "tab_.gif"
+              const:selectedTabIcon = "tab_selected.gif"
+              const:leftTabIcon     = "tab_left.gif">
+       content of <b>persons</b> tab
+       <a var:action="increaseClicks">click</a>
+     </var:tab>
+
+     <var:tab const:key="projects" const:label="projects"
+              isScript="useJavaScriptTabs" const:asBackground="1"
+             const:width="100" const:height="22"
+              const:tabIcon         = "tab_.gif"
+              const:selectedTabIcon = "tab_selected.gif"
+              const:leftTabIcon     = "tab_left.gif">
+       content of <b>projects</b> tab
+     </var:tab>
+
+  </var:tabview>
+  
+  <form var:action="self">
+    <hr />
+    
+    <table border="0">
+      <tr>
+        <td align="right">bg color:</td>
+        <td><input type="text" var:value="bgColor" const:size="8"/></td>
+      </tr>
+      <tr>
+        <td align="right">JS tabs:</td>
+        <td><input type="checkbox" var:checked="useJavaScriptTabs"/></td>
+      </tr>
+      <tr>
+        <td align="right"></td><td></td>
+      </tr>
+      <tr>
+        <td colspan="2"><input type="submit" var:action="self" value="Apply"/></td>
+      </tr>
+    </table>
+  </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/Table.m b/skyrix-sope/samples/WOxExtTest/Table.m
new file mode 100644 (file)
index 0000000..72cb8cc
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/NGObjWeb.h>
+
+@interface Table : WOComponent
+@end
+
+@implementation Table
+
+- (id)init {
+  if ((self = [super init])) {
+    [self setObject:@"3"   forKey:@"maxColumns"];
+    [self setObject:@"YES" forKey:@"horizontal"];
+    [self setObject:@"1"   forKey:@"border"];
+    
+    [self setObject:@"one,two,three,four,five,six,seven,eight,nine,ten"
+          forKey:@"list"];
+  }
+  return self;
+}
+
+- (NSArray *)listAsArray {
+  return [[self objectForKey:@"list"] componentsSeparatedByString:@","];
+}
+
+@end /* Table */
diff --git a/skyrix-sope/samples/WOxExtTest/Table.wox b/skyrix-sope/samples/WOxExtTest/Table.wox
new file mode 100644 (file)
index 0000000..c6e2f2e
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+   
+   <var:table maxColumns="maxColumns" col="col" row="row" 
+              index="index" item="item"
+              list="listAsArray" horizontal="horizontal"
+              border="border">
+      (<var:string value="row"/>/<var:string value="col"/>)
+      = <var:string value="index"/>
+      <b><var:string value="item"/></b>
+   </var:table>
+   
+   <var:table maxColumns="maxColumns" col="col" row="row" 
+              index="index" item="item"
+              list="listAsArray" horizontal="horizontal"
+              border="border"
+              const:hasOwnTDs="4" width="100%">
+      <td><var:string value="row"/></td>
+      <td><var:string value="col"/></td>
+      <td><var:string value="index"/></td>
+      <td><b><var:string value="item"/></b></td>
+   </var:table>
+
+   <form var:action="self">
+     <hr/>
+     <table border="0">
+       <tr><td><i>Config Bindings</i></td></tr>
+       <tr>
+         <td>MaxColumns:</td>
+         <td><input type="text" var:value="maxColumns" size="4"/></td>
+       </tr>
+       <tr>
+         <td>Horizontal:</td>
+         <td><input type="checkbox" var:checked="horizontal"/></td>
+       </tr>
+     </table>
+     <input type="submit" var:action="self" value="apply"/>
+   </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/TableMatrix.m b/skyrix-sope/samples/WOxExtTest/TableMatrix.m
new file mode 100644 (file)
index 0000000..38c9bc1
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/NGObjWeb.h>
+
+@interface TableMatrix : WOComponent
+@end
+
+@implementation TableMatrix
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/TableMatrix.wox b/skyrix-sope/samples/WOxExtTest/TableMatrix.wox
new file mode 100644 (file)
index 0000000..d10a3c2
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version='1.0' standalone='yes'?>
+<var:Frame title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <h3>this demo doesn't work ...</h3>
+
+  <var:hspan-matrix NAME="ChartMatrix">
+    <var:matrix-title NAME="ChartTitle">
+      <var:string NAME="WeekdayTitle"/>
+    </var:matrix-title>
+    
+    <var:matrix-title NAME="ChartRowTitle">
+      <font size="-4"><var:string NAME="RowInfo"/></font>
+    </var:matrix-title>
+    
+    <var:matrix-empty><entity name="nbsp"/></var:matrix-empty>
+    
+    <var:matrix-cell NAME="ChartCell">
+      <font size="-4">
+        <var:if NAME="IsViewAccessAllowed">
+          <a NAME="AptLink"><img NAME="AptInfoIcon"/><font NAME="TitleFont"><var:string NAME="AptInfo"/></font></a>
+        </var:if>
+  
+        <var:if NAME="IsViewAccessNotAllowed">
+          <img NAME="AptInfoIcon"/><font NAME="TitleFont"><var:string NAME="AptInfo"/></font>
+        </var:if>
+      </font>
+    </var:matrix-cell>
+  </var:hspan-matrix>
+</var:Frame>
diff --git a/skyrix-sope/samples/WOxExtTest/TableView.m b/skyrix-sope/samples/WOxExtTest/TableView.m
new file mode 100644 (file)
index 0000000..313772d
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSArray;
+
+@interface TableView : WOComponent < NSCoding >
+{
+  NSArray *list;
+  int clicks;
+}
+@end
+
+#include "common.h"
+
+@implementation TableView
+
+- (id)init {
+  if ((self = [super init])) {
+    WOResourceManager *rm;
+    NSString          *file;
+
+    rm   = [[self application] resourceManager];
+
+    file = [rm pathForResourceNamed:@"TableView.plist"
+               inFramework:nil
+               languages:nil];
+                              
+    self->list = [[NSArray alloc] initWithContentsOfFile:file];
+    
+    [self takeValue:@"4"       forKey:@"batchSize"];
+    [self takeValue:@"#FCF8DF" forKey:@"evenColor"];
+    [self takeValue:@"#FFFFF0" forKey:@"oddColor"];
+    [self takeValue:@"#FFDAAA" forKey:@"headerColor"];
+    [self takeValue:@"#FFDAAA" forKey:@"footerColor"];
+    [self takeValue:@"#FAE8B8" forKey:@"titleColor"];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->list release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSArray *)list {
+  return self->list;
+}
+- (void)setList:(NSArray *)_list {
+  ASSIGN(self->list, _list);
+}
+
+- (BOOL)isGroupCity {
+  id obj1;
+  id obj2;
+
+  obj1 = [self valueForKey:@"item"];
+  obj2 = [self valueForKey:@"previousItem"];
+
+  return [[obj1 objectForKey:@"city"] isEqualToString:
+                                      [obj2 objectForKey:@"city"]];
+}
+
+- (BOOL)isGroupZip {
+  id obj1;
+  id obj2;
+
+  obj1 = [self valueForKey:@"item"];
+  obj2 = [self valueForKey:@"previousItem"];
+  
+  return [[obj1 objectForKey:@"zip"] isEqualToString:
+                                     [obj2 objectForKey:@"zip"]];
+}
+
+- (void)setClicks:(int)_clicks {
+  self->clicks = _clicks;
+}
+- (int)clicks {
+  return self->clicks;
+}
+
+/* actions */
+
+- (id)increaseClicks {
+  self->clicks++;
+  [self takeValue:[self valueForKey:@"item"] forKey:@"clickedItem"];
+  return nil;
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [super encodeWithCoder:_coder];
+  [_coder encodeObject:self->list];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  if ((self = [super initWithCoder:_coder])) {
+    self->list = [[_coder decodeObject] retain];
+  }
+  return self;
+}
+
+@end /* TableView */
diff --git a/skyrix-sope/samples/WOxExtTest/TableView.wox b/skyrix-sope/samples/WOxExtTest/TableView.wox
new file mode 100644 (file)
index 0000000..3c2c036
--- /dev/null
@@ -0,0 +1,120 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component
+           className="Frame" 
+           title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <form var:action="self">
+
+    <!-- in this case we need some 'subtags' for configuration ... -->
+    
+    <var:tableview list="list" item="item" identifier="item.identifier"
+        batchSize="batchSize" currentBatch="currentBatch"
+        previousItem="previousItem"
+        sortedKey      = "sortedKey"
+        isDescending   = "isDescending"
+        scrollOnClient = "javaSciptScrolling"
+        autoScroll     = "overflowScrolling"
+        titleColor     = "titleColor"
+        headerColor    = "headerColor"
+        footerColor    = "footerColor"
+        evenColor      = "evenColor"
+        oddColor       = "oddColor"
+        
+        const:nonSortIcon       = "non_sorted.gif"
+        const:upwardSortIcon    = "upward_sorted.gif"
+        const:downwardSortIcon  = "downward_sorted.gif"
+        const:firstIcon         = "first.gif"
+        const:firstBlindIcon    = "first_blind.gif"
+        const:previousIcon      = "previous.gif"
+        const:previousBlindIcon = "previous_blind.gif"
+        const:nextIcon          = "next.gif"
+        const:nextBlindIcon     = "next_blind.gif"
+        const:lastIcon          = "last.gif"
+        const:lastBlindIcon     = "last_blind.gif"
+      >
+      
+      <var:ttitle><b>Folder</b></var:ttitle>
+      <var:tbutton>Buttons of TableView</var:tbutton>
+      
+      <var:td const:sortKey="city" const:title="city" const:valign="top"
+              isGroup="isGroupCity">
+        <var:string value="item.identifier"/>
+      </var:td>
+
+      <var:td const:sortKey="zip" const:title="zip" const:valign="top"
+              isGroup="isGroupZip">
+        <var:string value="item.zip"/>
+      </var:td>
+
+      <var:td const:sortkey="firstName" const:title="first name">
+        <var:string value="item.firstName"/>
+      </var:td>
+      
+      <var:td const:sortkey="name" const:title="name">
+        <var:string value="item.name"/>
+        <a var:action="increaseClicks">increaseClicks</a>
+      </var:td>
+      
+      <var:td const:sortkey="street" const:title="street">
+        <var:string value="item.street"/>
+      </var:td>
+      
+      <var:tfooter><small>Footer of TableView:</small></var:tfooter>
+   </var:tableview>
+   
+   <br/>
+    <b>clickedItem = <var:string value="clickedItem"/></b>
+   <br/>
+      
+      <table border="0">
+        <tr>
+          <td align="right">
+            javaScriptScrolling (only MSIE):
+          </td>
+          <td><input type="checkbox" var:checked="javaScriptScrolling"/></td>
+        </tr>
+        <var:if condition="javaScriptScrolling" const:negate="YES">
+          <tr>
+            <td align="right">
+              overflow scrolling (only MSIE):
+            </td>
+            <td><input type="checkbox" var:checked="overflowScrolling"/></td>
+          </tr>
+        </var:if>
+
+          <tr>
+            <td align="right">batch size:</td>
+            <td><input type="text" size="1" var:value="batchSize"/></td>
+          </tr>
+          <tr>
+            <td align="right">even color:</td>
+            <td><input type="text" var:value="evenColor"/></td>
+          </tr>
+          <tr>
+            <td align="right">odd color:</td>
+            <td><input type="text" var:value="oddColor"/></td>
+          </tr>
+          <tr>
+            <td align="right">title color:</td>
+            <td><input type="text" var:value="titleColor"/></td>
+          </tr>
+          <tr>
+            <td align="right">header color:</td>
+            <td><input type="text" var:value="headerColor"/></td>
+          </tr>
+          <tr>
+            <td align="right">footer color:</td>
+            <td><input type="text" var:value="footerColor"/></td>
+          </tr>
+
+        <tr>
+          <td colspan="2">
+            <input type="submit" value="apply"/>
+          </td>
+        </tr>
+      </table>  
+   </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/TextFlyover.m b/skyrix-sope/samples/WOxExtTest/TextFlyover.m
new file mode 100644 (file)
index 0000000..d924568
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface TextFlyover : WOComponent
+@end
+
+#include "common.h"
+
+@implementation TextFlyover
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"blue"                    forKey:@"unselectedColor"];
+    [self takeValue:@"red"                     forKey:@"selectedColor"];
+    [self takeValue:[NSNumber numberWithInt:0] forKey:@"clicks"];
+  }
+  return self;
+}
+- (id)countClicks {
+  int clicks;
+
+  [self logWithFormat:@"+++ invoke 'countClicks' action +++"];
+  
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  [self takeValue:[NSNumber numberWithInt:++clicks] forKey:@"clicks"];
+
+  return nil;
+}
+
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/TextFlyover.wox b/skyrix-sope/samples/WOxExtTest/TextFlyover.wox
new file mode 100644 (file)
index 0000000..a7829e9
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <var:js-text-flyover
+     const:pageName     = "PanelContent"
+     const:targetWindow = "panel"
+     selectedColor      = "selectedColor"
+     unselectedColor    = "unselectedColor"
+     const:string       = "'new page' - text flyover"/>
+  <br/>
+  
+  <var:js-text-flyover
+     action          = "countClicks"
+     selectedColor   = "selectedColor"
+     unselectedColor = "unselectedColor"
+     const:string    = "'invoke action' - text flyover"/>
+  
+  clicks: <b><var:string value="clicks"/></b>
+  <br/>
+
+  <var:js-text-flyover
+     javaScriptFunction = "javaScriptFunction"
+     selectedColor      = "selectedColor"
+     unselectedColor    = "unselectedColor"
+     const:string       = "'invoke javescript' - text flyover"/>
+  <br/>
+
+  <form var:action="self">
+    <table border="0">
+      <tr>
+        <td align="right">selected color:</td>
+        <td><input type="text" size="10" var:value="selectedColor"/></td>
+      </tr>
+      <tr>
+        <td align="right">unselected color:</td>
+        <td><input type="text" size="10" var:value="unselectedColor"/></td>
+      </tr>
+      <tr><td colspan="2">
+        <input type="submit" value="apply" var:action="self"/>
+      </td></tr>
+     </table>
+  </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/ThresholdColoredNumber.m b/skyrix-sope/samples/WOxExtTest/ThresholdColoredNumber.m
new file mode 100644 (file)
index 0000000..be1c184
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface ThresholdColoredNumber : WOComponent
+{
+}
+@end
+
+#include "common.h"
+
+@implementation ThresholdColoredNumber
+
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"blue"    forKey:@"lowColor"];
+    [self takeValue:@"red"     forKey:@"highColor"];
+    [self takeValue:@"0.00 DM" forKey:@"numberformat"];
+    [self takeValue:[NSNumber numberWithInt:1] forKey:@"threshold"];
+    [self takeValue:[NSNumber numberWithInt:2] forKey:@"value"];
+  }
+  return self;
+}
+
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/ThresholdColoredNumber.wox b/skyrix-sope/samples/WOxExtTest/ThresholdColoredNumber.wox
new file mode 100644 (file)
index 0000000..c08649d
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+  
+  threshold colored number: 
+  <var:threshold-colored-number
+        lowColor="lowColor" highColor="highColor"
+        threshold="threshold"
+        value="value"
+        numberformat="numberformat"/>
+  <br/>
+
+  <form var:action="self">
+    <table border="0">
+      <tr>
+         <td align="right">low color:</td>
+         <td><input type="text" var:value="lowColor" size="10"/></td>
+      </tr>
+      <tr>
+         <td align="right">high color:</td>
+         <td><input type="text" var:value="highColor" size="10"/></td>
+      </tr>
+      <tr>
+        <td align="right">threshold:</td>
+        <td>
+          <input type="text" var:value="threshold" size="10" 
+                 numberformat="0.00"/>
+        </td>
+      </tr>
+      <tr>
+         <td align="right">value:</td>
+         <td>
+           <input type="text" var:value="value" size="10" 
+                  numberformat="0.00"/>
+         </td>
+      </tr>
+      <tr>
+         <td align="right">NumberFormat:</td>
+         <td><input type="text" var:value="numberformat" size="10"/></td>
+      </tr>
+      <tr>
+         <td colspan="2"><input type="submit" value="apply"/></td>
+      </tr>
+    </table>
+  </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/TimeField.m b/skyrix-sope/samples/WOxExtTest/TimeField.m
new file mode 100644 (file)
index 0000000..a272857
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/NGObjWeb.h>
+
+@interface TimeField: WOComponent
+{
+}
+@end
+
+@implementation TimeField
+- (id)init {
+  if ((self = [super init])) {
+    [self takeValue:@"12" forKey:@"hour"];
+    [self takeValue:@"30" forKey:@"minute"];
+    [self takeValue:@"40" forKey:@"second"];
+    [self takeValue:[NSCalendarDate date] forKey:@"date"];
+  }
+  return self;
+}
+@end
diff --git a/skyrix-sope/samples/WOxExtTest/TimeField.wox b/skyrix-sope/samples/WOxExtTest/TimeField.wox
new file mode 100644 (file)
index 0000000..7f1371d
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <form var:action="self">
+
+    <var:time-field hour="hour" minute="minute" second="second"
+                    const:hourInterval="2"
+                    const:minuteInterval="10"
+                    const:secondInterval="30"
+                    useTextField="useTextField"/>
+    <br/><br/>
+
+    <var:time-field date="date"
+                    const:hourInterval="2"
+                    const:minuteInterval="10"
+                    const:secondInterval="30"
+                    useTextField="useTextField"/>
+    <br/><br/>
+
+    useTextField: <input type="checkbox" var:checked="useTextField"/>
+    <br/>
+
+    <input type="submit" value="apply"/>
+  </form>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/TreeView.m b/skyrix-sope/samples/WOxExtTest/TreeView.m
new file mode 100644 (file)
index 0000000..2040543
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSArray, NSMutableDictionary;
+
+@interface TreeView : WOComponent < NSCoding >
+{
+  NSArray             *root;
+  NSMutableDictionary *state;
+  id                  item;
+
+  int clicks;
+  id  currentPath;
+}
+@end
+
+#include "common.h"
+
+@implementation TreeView
+
+- (id)init {
+  if ((self = [super init])) {
+    WOResourceManager *rm;
+    NSString          *path;
+
+    rm   = [[self application] resourceManager];
+    
+    path = [rm pathForResourceNamed:@"TreeView.plist"
+               inFramework:nil
+               languages:nil];
+    
+    self->root      = [[NSArray alloc] initWithContentsOfFile:path];
+    self->state     = [[NSMutableDictionary alloc] init];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->currentPath release];
+  [self->root  release];
+  [self->item  release];
+  [self->state release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSArray *)root {
+  return self->root;
+}
+
+- (NSArray *)oneTags {
+  return [NSArray arrayWithObject:@"one"];
+}
+
+- (void)setItem:(id)_item {
+  ASSIGN(self->item, _item);
+}
+- (id)item {
+  return self->item;
+}
+
+- (void)setClicks:(int)_clicks {
+  self->clicks = _clicks;
+}
+- (int)clicks {
+  return self->clicks;
+}
+
+- (void)setCurrentPath:(NSString *)_value {
+  ASSIGN(self->currentPath, _value);
+}
+- (id)currentPath {
+  return self->currentPath;
+}
+
+- (NSString *)keyPath {
+  return [[[self valueForKey:@"currentPath"]
+                 valueForKey:@"key"] componentsJoinedByString:@"."];
+}
+
+- (void)setIsZoom:(BOOL)_flag {
+  NSString *key;
+
+  key = [self keyPath];
+
+  NSLog(@"setIsZoom is %@", key);
+  if (key)
+    [self->state setObject:[NSNumber numberWithBool:_flag] forKey:key];
+}
+- (BOOL)isZoom {
+  NSString *key;
+
+  key = [self keyPath];
+
+  NSLog(@"isZoom is %@", key);
+  
+  if (key == nil)
+    return NO;
+    
+  return [[self->state objectForKey:key] boolValue];
+}
+
+- (BOOL)showItem {
+  return ([[self keyPath] hasSuffix:@"two"] ||
+          [[self keyPath] hasSuffix:@"four"])
+    ? NO
+    : YES;
+}
+
+/* actions */
+
+- (id)countClicks {
+  self->clicks++;
+  return nil /* stay on page */;
+}
+
+- (id)dropAction {
+  NSLog(@"... droppedObject is %@", [self valueForKey:@"droppedObject"]);
+  return nil;
+}
+
+/* NSCoding */
+
+- (void)encodeWithCoder:(NSCoder *)_coder {
+  [super encodeWithCoder:_coder];
+  [_coder encodeObject:self->root];
+  [_coder encodeObject:self->state];
+  [_coder encodeObject:self->item];
+}
+- (id)initWithCoder:(NSCoder *)_coder {
+  if ((self = [super initWithCoder:_coder])) {
+    self->root  = [[_coder decodeObject] retain];
+    self->state = [[_coder decodeObject] retain];
+    self->item  = [[_coder decodeObject] retain];
+  }
+  return self;
+}
+
+@end /* TableView */
diff --git a/skyrix-sope/samples/WOxExtTest/TreeView.wox b/skyrix-sope/samples/WOxExtTest/TreeView.wox
new file mode 100644 (file)
index 0000000..429b571
--- /dev/null
@@ -0,0 +1,107 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant"
+>
+   <var:js-drag const:tag="one" const:object="one-toBeDropped">
+     <a href="#">DragMe</a></var:js-drag>
+   
+   <table border="0">
+     <tr>
+       <td valign="top" width="50%">
+         <form var:action="self">
+   
+           <var:treeview list="root" sublist="item.sublist" item="item"
+                         currentPath="currentPath" zoom="isZoom"
+                         showItem="showItem"
+                         const:iconWidth       = "13"
+                         const:plusIcon        = "treeview_plus.gif"
+                         const:minusIcon       = "treeview_minus.gif"
+                         const:lineIcon        = "treeview_line.gif"
+                         const:cornerIcon      = "treeview_corner.gif"
+                         const:junctionIcon    = "treeview_junction.gif"
+                         const:leafIcon        = "treeview_leaf.gif"
+                         const:leafCornerIcon  = "treeview_leaf_corner.gif"
+                         const:cornerPlusIcon  = "treeview_corner_plus.gif"
+                         const:cornerMinusIcon = "treeview_corner_minus.gif"
+                         const:spaceIcon       = "treeview_space.gif"
+             >
+             
+             <!-- Header Content -->
+             
+             <var:tree-header const:isTreeElement="YES" const:bgcolor="#FFDAAA">
+               <b>tree cell</b><entity name="nbsp"/><entity name="nbsp"/>
+             </var:tree-header>
+             <var:tree-header const:isTreeElement="NO" const:bgcolor="#FFDAAA">
+               <b>first name</b><entity name="nbsp"/><entity name="nbsp"/>
+             </var:tree-header>
+             <var:tree-header const:isTreeElement="NO" const:bgcolor="#FFDAAA">
+               <b>name</b><entity name="nbsp"/><entity name="nbsp"/>
+             </var:tree-header>
+             
+             <!-- Data Content -->
+             <var:tree-data const:isTreeElement="YES" const:bgcolor="#FCF8DF"><a var:action="countClicks"><var:string value="keyPath"/></a></var:tree-data>
+        
+             <var:tree-data const:isTreeElement="NO" const:bgcolor="#FCF8DF">
+               <var:js-drop action="dropAction" droppedObject="droppedObject"
+                  const:elementName   = "tr"
+                  const:isAttached    = "YES"
+                  tags                = "oneTags"
+                  const:swapColor     = "YES"
+                  const:bgcolor       = "green">
+                  <var:string value="item.firstName"/>
+                </var:js-drop>
+             </var:tree-data>
+
+             <var:tree-data const:isTreeElement="NO" const:bgcolor="#FCF8DF">
+               <var:string value="item.name"/>
+             </var:tree-data>
+             
+           </var:treeview>
+         </form>
+       </td>
+        
+       <td width="30"><entity name="nbsp"/></td>
+
+       <td valign="top">
+         <var:treeview list="root" sublist="item.sublist" item="item"
+                       currentPath="currentPath" zoom="isZoom"
+                       showItem="showItem">
+      
+           <!-- Header Content -->
+           <var:tree-header const:isTreeElement="YES" const:bgcolor="#FFDAAA">
+              <b>tree cell</b>
+              <a var:action="countClicks">count</a>
+              <entity name="nbsp"/><entity name="nbsp"/>
+           </var:tree-header>
+
+           <var:tree-header const:isTreeElement="NO" const:bgcolor="#FFDAAA">
+             <b>first name</b>
+             <a var:action="countClicks">count</a>
+             <entity name="nbsp"/><entity name="nbsp"/>
+           </var:tree-header>
+
+           <var:tree-header const:isTreeElement="NO" const:bgcolor="#FFDAAA">
+             <b>name</b><entity name="nbsp"/><entity name="nbsp"/>
+           </var:tree-header>
+           
+           <!-- Data Content -->
+           <var:tree-data const:isTreeElement="YES" const:bgcolor="#FCF8DF">
+             <a var:action="countClicks"><var:string value="keyPath"/></a>
+           </var:tree-data>
+      
+           <var:tree-data const:isTreeElement="NO" const:bgcolor="#FCF8DF">
+             <var:string value="item.firstName"/>
+           </var:tree-data>
+           <var:tree-data const:isTreeElement="NO" const:bgcolor="#FCF8DF">
+             <var:string value="item.name"/>
+           </var:tree-data>
+      
+         </var:treeview>
+       </td>
+     </tr>
+   </table>
+   
+   <var:string value="clicks"/>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/ValidatedField.m b/skyrix-sope/samples/WOxExtTest/ValidatedField.m
new file mode 100644 (file)
index 0000000..46bc499
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <NGObjWeb/NGObjWeb.h>
+
+@interface ValidatedField : WOComponent
+@end
+
+@implementation ValidatedField
+@end /* ValidateField */
diff --git a/skyrix-sope/samples/WOxExtTest/ValidatedField.wox b/skyrix-sope/samples/WOxExtTest/ValidatedField.wox
new file mode 100644 (file)
index 0000000..2ce5f8f
--- /dev/null
@@ -0,0 +1,41 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+  xmlns="http://www.w3.org/1999/xhtml"
+  xmlns:var="http://www.skyrix.com/od/binding"
+  xmlns:const="http://www.skyrix.com/od/constant"
+>
+  <form name="validateForm" var:action="self">
+    <table border="0">
+      <tr>
+        <td align="right">input is required:</td>
+        <td>
+          <var:js-validated-field
+                inputText="inputIsRequiredText"
+                const:fieldSize="50" const:inputIsRequired="YES"
+                const:formName="validateForm"
+                const:errorMessage=
+                  "Please fill out the 'input is required' - textfield"/>
+        </td>
+      </tr>
+      <tr>
+        <td align="right">text is required:</td>
+        <td>
+          <var:js-validated-field
+                inputText          = "textIsRequiredText"
+                const:fieldSize    = "50"
+                const:requiredText = "500$"
+                const:formName     = "validateForm"
+                const:errorMessage=
+                "The 'text is required' - textfield doesn't contain '500$'"/>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="2">
+          <input type="submit" var:action="self" value="apply"/>
+        </td>
+      </tr>
+    </table>
+
+  </form>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/VarString.wox b/skyrix-sope/samples/WOxExtTest/VarString.wox
new file mode 100644 (file)
index 0000000..8163a22
--- /dev/null
@@ -0,0 +1,76 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  Samples for the &lt;var:string&gt; tag ...
+
+  <pre>Bindings:
+value;        // object
+escapeHTML;   // BOOL
+numberformat; // string
+dateformat;   // string
+formatter;    // WO4: NSFormatter object
+</pre>
+
+  <table border="1" width="100%">
+    <tr>
+      <td width="40%">var:string on val</td>
+      <td><var:string value="val" escapeHTML="escapeHTML" 
+                     insertBR="insertBR" nilString="nilString"/></td>
+    </tr>
+    <tr>
+      <td width="40%">var:string on date (dateformatter)</td>
+      <td><var:string value="now" escapeHTML="escapeHTML"
+                     insertBR="insertBR" dateformat="dateformat"
+                     nilString="nilString"/></td>
+    </tr>
+    <tr>
+      <td width="40%">var:string on None (nilString)</td>
+      <td><var:string value="nil" escapeHTML="escapeHTML"
+                     insertBR="insertBR"
+                     nilString="nilString"/></td>
+    </tr>
+  </table>
+
+  <form var:action="self">
+    <hr />
+    <table border="0">
+      <tr>
+       <th>Binding</th>
+       <th>Value</th>
+      </tr>
+      <tr>
+        <td align="right">value:</td>
+        <td><textarea var:value="val" cols="40" rows="3"/></td>
+      </tr>
+      <tr>
+        <td align="right">escape HTML:</td>
+        <td><input type="checkbox" var:checked="escapeHTML"/></td>
+      </tr>
+      <tr>
+        <td align="right">insert &lt;BR&gt;:</td>
+        <td><input type="checkbox" var:checked="insertBR"/></td>
+      </tr>
+      <tr>
+        <td align="right">nilString:</td>
+        <td><input type="text" var:value="nilString" const:size="40"/></td>
+      </tr>
+      <tr>
+        <td align="right">dateformat:</td>
+        <td><input type="text" var:value="dateformat" const:size="40"/></td>
+      </tr>
+    </table>
+    <input type="submit" var:action="self" value="apply"/>
+  </form>
+  
+  <var:script><![CDATA[
+    var now        = SkyDate();
+    var val        = "a value";
+    var escapeHTML = true;
+    var insertBR   = true;
+    var nilString  = "no value set !";
+    var dateformat = "%Y-%m-%d !";
+  ]]></var:script>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/WOxExtTest.m b/skyrix-sope/samples/WOxExtTest/WOxExtTest.m
new file mode 100644 (file)
index 0000000..ea34045
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/NGObjWeb.h>
+#include <NGObjWeb/WORequestHandler.h>
+#include "common.h"
+
+@interface WOxExtTest : WOApplication
+@end
+
+@implementation WOxExtTest
+
+- (id)init {
+  if ((self = [super init])) {
+    WORequestHandler *rh;
+    
+    rh = [[NSClassFromString(@"OWViewRequestHandler") alloc] init];
+    [self setDefaultRequestHandler:rh];
+    [self registerRequestHandler:rh
+          forKey:[WOApplication componentRequestHandlerKey]];
+    [rh release]; rh = nil;
+  }
+  return self;
+}
+
+- (WOResponse *)handleException:(NSException *)_exc
+  inContext:(WOContext *)_ctx
+{
+  printf("%s\n", [[_exc description] cString]);
+  abort();
+}
+
+@end /* WOxExtTest */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  WOApplicationMain(@"WOxExtTest", argc, (void*)argv);
+
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-sope/samples/WOxExtTest/WOxExtTest.pbproj/project.pbxproj b/skyrix-sope/samples/WOxExtTest/WOxExtTest.pbproj/project.pbxproj
new file mode 100644 (file)
index 0000000..e274858
--- /dev/null
@@ -0,0 +1,1796 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 38;
+       objects = {
+               6904BAA001EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = CalendarField.wox;
+                       refType = 4;
+               };
+               6904BAA101EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = CheckBoxMatrix.wox;
+                       refType = 4;
+               };
+               6904BAA201EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = CollapsibleContent.wox;
+                       refType = 4;
+               };
+               6904BAA301EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = CollapsibleContentExt.wox;
+                       refType = 4;
+               };
+               6904BAA401EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = DictionaryRepetition.wox;
+                       refType = 4;
+               };
+               6904BAA501EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = DnD.wox;
+                       refType = 4;
+               };
+               6904BAA601EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = KeyValueConditional.wox;
+                       refType = 4;
+               };
+               6904BAA701EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = ModalWindow.wox;
+                       refType = 4;
+               };
+               6904BAA801EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = MonthOverview.wox;
+                       refType = 4;
+               };
+               6904BAA901EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = PageView.wox;
+                       refType = 4;
+               };
+               6904BAAA01EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = PanelContent.wox;
+                       refType = 4;
+               };
+               6904BAAB01EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = RadioButtonMatrix.wox;
+                       refType = 4;
+               };
+               6904BAAC01EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = Switch.wox;
+                       refType = 4;
+               };
+               6904BAAD01EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = Table.wox;
+                       refType = 4;
+               };
+               6904BAAE01EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = TableMatrix.wox;
+                       refType = 4;
+               };
+               6904BAAF01EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = TableView.wox;
+                       refType = 4;
+               };
+               6904BAB001EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = TabPanel.wox;
+                       refType = 4;
+               };
+               6904BAB101EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = TabView.wox;
+                       refType = 4;
+               };
+               6904BAB201EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = TextFlyover.wox;
+                       refType = 4;
+               };
+               6904BAB301EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = ThresholdColoredNumber.wox;
+                       refType = 4;
+               };
+               6904BAB401EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = TimeField.wox;
+                       refType = 4;
+               };
+               6904BAB501EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = TreeView.wox;
+                       refType = 4;
+               };
+               6904BAB601EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = ValidatedField.wox;
+                       refType = 4;
+               };
+               6904BAB701EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = WeekColumnView.wox;
+                       refType = 4;
+               };
+               6904BAB801EB9B4900A8007E = {
+                       isa = PBXFileReference;
+                       path = WeekOverview.wox;
+                       refType = 4;
+               };
+               6905B77501CE9CDB006474DE = {
+                       buildStyles = (
+                               6905B77701CE9CDB006474DE,
+                               6905B77801CE9CDB006474DE,
+                       );
+                       isa = PBXProject;
+                       mainGroup = 6905B77601CE9CDB006474DE;
+                       productRefGroup = 6941F0270242A10C00A8007E;
+                       projectDirPath = "";
+                       targets = (
+                               6918B0C201CE9E590053A783,
+                               6941F0290242A10C00A8007E,
+                       );
+               };
+               6905B77601CE9CDB006474DE = {
+                       children = (
+                               6918B09801CE9DFF0053A783,
+                               691DC05601F6197E00A8007E,
+                               69AC2E89031D8E3200A8CBE9,
+                               6918B09901CE9DFF0053A783,
+                               6918B09A01CE9DFF0053A783,
+                               6905B77901CE9D13006474DE,
+                               6941F0830242A2FE00A8007E,
+                               6941F0270242A10C00A8007E,
+                       );
+                       isa = PBXGroup;
+                       refType = 4;
+               };
+               6905B77701CE9CDB006474DE = {
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                       };
+                       isa = PBXBuildStyle;
+                       name = Development;
+               };
+               6905B77801CE9CDB006474DE = {
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                       };
+                       isa = PBXBuildStyle;
+                       name = Deployment;
+               };
+               6905B77901CE9D13006474DE = {
+                       children = (
+                               6918B09C01CE9DFF0053A783,
+                               6918B09D01CE9DFF0053A783,
+                               6918B09E01CE9DFF0053A783,
+                               691DC04401F4D3CB00A8007E,
+                               6918B09F01CE9DFF0053A783,
+                               6904BAA001EB9B4900A8007E,
+                               6918B0A001CE9DFF0053A783,
+                               6904BAA101EB9B4900A8007E,
+                               6918B0A101CE9DFF0053A783,
+                               6904BAA201EB9B4900A8007E,
+                               6918B0A201CE9DFF0053A783,
+                               6904BAA301EB9B4900A8007E,
+                               6918B0A301CE9DFF0053A783,
+                               6918B0F701CEA8DF0053A783,
+                               6918B0A401CE9DFF0053A783,
+                               6918B0F801CEAA3F0053A783,
+                               6918B0A501CE9DFF0053A783,
+                               6904BAA401EB9B4900A8007E,
+                               6918B0A601CE9DFF0053A783,
+                               6918B0A701CE9DFF0053A783,
+                               6904BAA501EB9B4900A8007E,
+                               6918B0A801CE9DFF0053A783,
+                               6918B0A901CE9DFF0053A783,
+                               6918B0AA01CE9DFF0053A783,
+                               6918B0F901CEAB5E0053A783,
+                               6918B0AB01CE9DFF0053A783,
+                               6904BAA601EB9B4900A8007E,
+                               6918B0AC01CE9DFF0053A783,
+                               6918B0AD01CE9DFF0053A783,
+                               6918B0AE01CE9DFF0053A783,
+                               6904BAA701EB9B4900A8007E,
+                               6918B0AF01CE9DFF0053A783,
+                               6904BAA801EB9B4900A8007E,
+                               6918B0B001CE9DFF0053A783,
+                               6904BAA901EB9B4900A8007E,
+                               6918B0B101CE9DFF0053A783,
+                               6904BAAA01EB9B4900A8007E,
+                               6918B0B201CE9DFF0053A783,
+                               6904BAAB01EB9B4900A8007E,
+                               6918B0B301CE9DFF0053A783,
+                               6918B0F301CEA4C20053A783,
+                               6918B0B401CE9DFF0053A783,
+                               6918B0F101CEA2F40053A783,
+                               6918B0B501CE9DFF0053A783,
+                               6904BAAC01EB9B4900A8007E,
+                               6918B0B601CE9DFF0053A783,
+                               6904BAAD01EB9B4900A8007E,
+                               6918B0B701CE9DFF0053A783,
+                               6904BAAE01EB9B4900A8007E,
+                               6918B0B801CE9DFF0053A783,
+                               6904BAAF01EB9B4900A8007E,
+                               6918B0B901CE9DFF0053A783,
+                               6904BAB001EB9B4900A8007E,
+                               6918B0BA01CE9DFF0053A783,
+                               6904BAB101EB9B4900A8007E,
+                               6918B0BB01CE9DFF0053A783,
+                               6904BAB201EB9B4900A8007E,
+                               6918B0BC01CE9DFF0053A783,
+                               6904BAB301EB9B4900A8007E,
+                               6918B0BD01CE9DFF0053A783,
+                               6904BAB401EB9B4900A8007E,
+                               6918B0BE01CE9DFF0053A783,
+                               6904BAB501EB9B4900A8007E,
+                               6918B0BF01CE9DFF0053A783,
+                               6904BAB601EB9B4900A8007E,
+                               6918B0C001CE9DFF0053A783,
+                               6904BAB701EB9B4900A8007E,
+                               6918B0C101CE9DFF0053A783,
+                               6904BAB801EB9B4900A8007E,
+                       );
+                       isa = PBXGroup;
+                       name = Components;
+                       refType = 4;
+               };
+               6918B09601CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = GNUmakefile;
+                       refType = 4;
+               };
+               6918B09701CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = GNUmakefile.preamble;
+                       refType = 4;
+               };
+               6918B09801CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = WOxExtTest.m;
+                       refType = 4;
+               };
+               6918B09901CE9DFF0053A783 = {
+                       children = (
+                               6918B0C301CE9EEE0053A783,
+                               6918B0C401CE9EEE0053A783,
+                               6918B0C501CE9EEE0053A783,
+                               6918B0C601CE9EEE0053A783,
+                       );
+                       isa = PBXGroup;
+                       name = Resources;
+                       refType = 4;
+               };
+               6918B09A01CE9DFF0053A783 = {
+                       children = (
+                               6918B09B01CE9DFF0053A783,
+                               6918B0C701CE9EEE0053A783,
+                               6918B0C801CE9EEE0053A783,
+                               6918B0C901CE9EEE0053A783,
+                               6918B0CA01CE9EEE0053A783,
+                               6918B0CB01CE9EEE0053A783,
+                               6918B0CC01CE9EEE0053A783,
+                               6918B0CD01CE9EEE0053A783,
+                               6918B0CE01CE9EEE0053A783,
+                               6918B0CF01CE9EEE0053A783,
+                               6918B0D001CE9EEE0053A783,
+                               6918B0D101CE9EEE0053A783,
+                               6918B0D201CE9EEE0053A783,
+                               6918B0D301CE9EEE0053A783,
+                               6918B0D401CE9EEE0053A783,
+                               6918B0D501CE9EEE0053A783,
+                               6918B0D601CE9EEE0053A783,
+                               6918B0D701CE9EEE0053A783,
+                               6918B0D801CE9EEE0053A783,
+                               6918B0D901CE9EEE0053A783,
+                               6918B0DA01CE9EEE0053A783,
+                               6918B0DB01CE9EEE0053A783,
+                               6918B0DC01CE9EEE0053A783,
+                               6918B0DD01CE9EEE0053A783,
+                               6918B0DE01CE9EEE0053A783,
+                               6918B0DF01CE9EEE0053A783,
+                               6918B0E001CE9EEE0053A783,
+                               6918B0E101CE9EEE0053A783,
+                               6918B0E201CE9EEE0053A783,
+                               6918B0E301CE9EEE0053A783,
+                               6918B0E401CE9EEE0053A783,
+                               6918B0E501CE9EEE0053A783,
+                               6918B0E601CE9EEE0053A783,
+                               6918B0E701CE9EEE0053A783,
+                               6918B0E801CE9EEE0053A783,
+                               6918B0E901CE9EEE0053A783,
+                               6918B0EA01CE9EEE0053A783,
+                               6918B0EB01CE9EEE0053A783,
+                               6918B0EC01CE9EEE0053A783,
+                       );
+                       isa = PBXGroup;
+                       name = WebServerResources;
+                       refType = 4;
+               };
+               6918B09B01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = favicon.ico;
+                       refType = 4;
+               };
+               6918B09C01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = AlertPanel.m;
+                       refType = 4;
+               };
+               6918B09D01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = AlertPanel.wox;
+                       refType = 4;
+               };
+               6918B09E01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = Browser.m;
+                       refType = 4;
+               };
+               6918B09F01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = CalendarField.m;
+                       refType = 4;
+               };
+               6918B0A001CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = CheckBoxMatrix.m;
+                       refType = 4;
+               };
+               6918B0A101CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = CollapsibleContent.m;
+                       refType = 4;
+               };
+               6918B0A201CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = CollapsibleContentExt.m;
+                       refType = 4;
+               };
+               6918B0A301CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = ConfirmPanel.m;
+                       refType = 4;
+               };
+               6918B0A401CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = DateField.m;
+                       refType = 4;
+               };
+               6918B0A501CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = DictionaryRepetition.m;
+                       refType = 4;
+               };
+               6918B0A601CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = DirectAction.m;
+                       refType = 4;
+               };
+               6918B0A701CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = DnD.m;
+                       refType = 4;
+               };
+               6918B0A801CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = Frame.m;
+                       refType = 4;
+               };
+               6918B0A901CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = Frame.wox;
+                       refType = 4;
+               };
+               6918B0AA01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = ImageFlyover.m;
+                       refType = 4;
+               };
+               6918B0AB01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = KeyValueConditional.m;
+                       refType = 4;
+               };
+               6918B0AC01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = Main.m;
+                       refType = 4;
+               };
+               6918B0AD01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = Main.wox;
+                       refType = 4;
+               };
+               6918B0AE01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = ModalWindow.m;
+                       refType = 4;
+               };
+               6918B0AF01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = MonthOverview.m;
+                       refType = 4;
+               };
+               6918B0B001CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = PageView.m;
+                       refType = 4;
+               };
+               6918B0B101CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = PanelContent.m;
+                       refType = 4;
+               };
+               6918B0B201CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = RadioButtonMatrix.m;
+                       refType = 4;
+               };
+               6918B0B301CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = RichString.m;
+                       refType = 4;
+               };
+               6918B0B401CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = ShiftClick.m;
+                       refType = 4;
+               };
+               6918B0B501CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = Switch.m;
+                       refType = 4;
+               };
+               6918B0B601CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = Table.m;
+                       refType = 4;
+               };
+               6918B0B701CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = TableMatrix.m;
+                       refType = 4;
+               };
+               6918B0B801CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = TableView.m;
+                       refType = 4;
+               };
+               6918B0B901CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = TabPanel.m;
+                       refType = 4;
+               };
+               6918B0BA01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = TabView.m;
+                       refType = 4;
+               };
+               6918B0BB01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = TextFlyover.m;
+                       refType = 4;
+               };
+               6918B0BC01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = ThresholdColoredNumber.m;
+                       refType = 4;
+               };
+               6918B0BD01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = TimeField.m;
+                       refType = 4;
+               };
+               6918B0BE01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = TreeView.m;
+                       refType = 4;
+               };
+               6918B0BF01CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = ValidatedField.m;
+                       refType = 4;
+               };
+               6918B0C001CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = WeekColumnView.m;
+                       refType = 4;
+               };
+               6918B0C101CE9DFF0053A783 = {
+                       isa = PBXFileReference;
+                       path = WeekOverview.m;
+                       refType = 4;
+               };
+               6918B0C201CE9E590053A783 = {
+                       buildArgumentsString = $ACTION;
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "gs-WOxExtTest";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                               debug = yes;
+                               shared = yes;
+                       };
+                       buildToolPath = /usr/bin/gnumake;
+                       dependencies = (
+                       );
+                       isa = PBXLegacyTarget;
+                       name = "gs-WOxExtTest";
+                       productName = "gs-WOxExtTest";
+                       settingsToExpand = 6;
+                       settingsToPassInEnvironment = 287;
+                       settingsToPassOnCommandLine = 280;
+                       shouldUseHeadermap = 0;
+               };
+               6918B0C301CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = appointments.plist;
+                       path = Resources/appointments.plist;
+                       refType = 4;
+               };
+               6918B0C401CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = Dictionary.plist;
+                       path = Resources/Dictionary.plist;
+                       refType = 4;
+               };
+               6918B0C501CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = TableView.plist;
+                       path = Resources/TableView.plist;
+                       refType = 4;
+               };
+               6918B0C601CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = TreeView.plist;
+                       path = Resources/TreeView.plist;
+                       refType = 4;
+               };
+               6918B0C701CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = collapsed.gif;
+                       path = WebServerResources/collapsed.gif;
+                       refType = 4;
+               };
+               6918B0C801CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = corner_left.gif;
+                       path = WebServerResources/corner_left.gif;
+                       refType = 4;
+               };
+               6918B0C901CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = corner_right.gif;
+                       path = WebServerResources/corner_right.gif;
+                       refType = 4;
+               };
+               6918B0CA01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = downward_sorted.gif;
+                       path = WebServerResources/downward_sorted.gif;
+                       refType = 4;
+               };
+               6918B0CB01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = expanded.gif;
+                       path = WebServerResources/expanded.gif;
+                       refType = 4;
+               };
+               6918B0CC01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = first_blind.gif;
+                       path = WebServerResources/first_blind.gif;
+                       refType = 4;
+               };
+               6918B0CD01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = first.gif;
+                       path = WebServerResources/first.gif;
+                       refType = 4;
+               };
+               6918B0CE01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = folder_closed.gif;
+                       path = WebServerResources/folder_closed.gif;
+                       refType = 4;
+               };
+               6918B0CF01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = folder_opened.gif;
+                       path = WebServerResources/folder_opened.gif;
+                       refType = 4;
+               };
+               6918B0D001CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = last_blind.gif;
+                       path = WebServerResources/last_blind.gif;
+                       refType = 4;
+               };
+               6918B0D101CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = last.gif;
+                       path = WebServerResources/last.gif;
+                       refType = 4;
+               };
+               6918B0D201CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = menu_email_inactive.gif;
+                       path = WebServerResources/menu_email_inactive.gif;
+                       refType = 4;
+               };
+               6918B0D301CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = menu_email.gif;
+                       path = WebServerResources/menu_email.gif;
+                       refType = 4;
+               };
+               6918B0D401CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = next_blind.gif;
+                       path = WebServerResources/next_blind.gif;
+                       refType = 4;
+               };
+               6918B0D501CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = next.gif;
+                       path = WebServerResources/next.gif;
+                       refType = 4;
+               };
+               6918B0D601CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = non_sorted.gif;
+                       path = WebServerResources/non_sorted.gif;
+                       refType = 4;
+               };
+               6918B0D701CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = previous_blind.gif;
+                       path = WebServerResources/previous_blind.gif;
+                       refType = 4;
+               };
+               6918B0D801CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = previous.gif;
+                       path = WebServerResources/previous.gif;
+                       refType = 4;
+               };
+               6918B0D901CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = tab_news_left.gif;
+                       path = WebServerResources/tab_news_left.gif;
+                       refType = 4;
+               };
+               6918B0DA01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = tab_news_selected.gif;
+                       path = WebServerResources/tab_news_selected.gif;
+                       refType = 4;
+               };
+               6918B0DB01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = tab_news.gif;
+                       path = WebServerResources/tab_news.gif;
+                       refType = 4;
+               };
+               6918B0DC01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = tab_persons_left.gif;
+                       path = WebServerResources/tab_persons_left.gif;
+                       refType = 4;
+               };
+               6918B0DD01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = tab_persons_selected.gif;
+                       path = WebServerResources/tab_persons_selected.gif;
+                       refType = 4;
+               };
+               6918B0DE01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = tab_persons.gif;
+                       path = WebServerResources/tab_persons.gif;
+                       refType = 4;
+               };
+               6918B0DF01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = tab_projects_left.gif;
+                       path = WebServerResources/tab_projects_left.gif;
+                       refType = 4;
+               };
+               6918B0E001CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = tab_projects_selected.gif;
+                       path = WebServerResources/tab_projects_selected.gif;
+                       refType = 4;
+               };
+               6918B0E101CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = tab_projects.gif;
+                       path = WebServerResources/tab_projects.gif;
+                       refType = 4;
+               };
+               6918B0E201CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = treeview_corner_minus.gif;
+                       path = WebServerResources/treeview_corner_minus.gif;
+                       refType = 4;
+               };
+               6918B0E301CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = treeview_corner_plus.gif;
+                       path = WebServerResources/treeview_corner_plus.gif;
+                       refType = 4;
+               };
+               6918B0E401CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = treeview_corner.gif;
+                       path = WebServerResources/treeview_corner.gif;
+                       refType = 4;
+               };
+               6918B0E501CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = treeview_junction.gif;
+                       path = WebServerResources/treeview_junction.gif;
+                       refType = 4;
+               };
+               6918B0E601CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = treeview_leaf_corner.gif;
+                       path = WebServerResources/treeview_leaf_corner.gif;
+                       refType = 4;
+               };
+               6918B0E701CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = treeview_leaf.gif;
+                       path = WebServerResources/treeview_leaf.gif;
+                       refType = 4;
+               };
+               6918B0E801CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = treeview_line.gif;
+                       path = WebServerResources/treeview_line.gif;
+                       refType = 4;
+               };
+               6918B0E901CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = treeview_minus.gif;
+                       path = WebServerResources/treeview_minus.gif;
+                       refType = 4;
+               };
+               6918B0EA01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = treeview_plus.gif;
+                       path = WebServerResources/treeview_plus.gif;
+                       refType = 4;
+               };
+               6918B0EB01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = treeview_space.gif;
+                       path = WebServerResources/treeview_space.gif;
+                       refType = 4;
+               };
+               6918B0EC01CE9EEE0053A783 = {
+                       isa = PBXFileReference;
+                       name = upward_sorted.gif;
+                       path = WebServerResources/upward_sorted.gif;
+                       refType = 4;
+               };
+               6918B0F101CEA2F40053A783 = {
+                       isa = PBXFileReference;
+                       path = ShiftClick.wox;
+                       refType = 4;
+               };
+               6918B0F301CEA4C20053A783 = {
+                       isa = PBXFileReference;
+                       path = RichString.wox;
+                       refType = 4;
+               };
+               6918B0F701CEA8DF0053A783 = {
+                       isa = PBXFileReference;
+                       path = ConfirmPanel.wox;
+                       refType = 4;
+               };
+               6918B0F801CEAA3F0053A783 = {
+                       isa = PBXFileReference;
+                       path = DateField.wox;
+                       refType = 4;
+               };
+               6918B0F901CEAB5E0053A783 = {
+                       isa = PBXFileReference;
+                       path = ImageFlyover.wox;
+                       refType = 4;
+               };
+               691DC04401F4D3CB00A8007E = {
+                       isa = PBXFileReference;
+                       path = Browser.wox;
+                       refType = 4;
+               };
+               691DC05601F6197E00A8007E = {
+                       isa = PBXFileReference;
+                       path = common.h;
+                       refType = 4;
+               };
+               6941F0270242A10C00A8007E = {
+                       children = (
+                               6941F0280242A10C00A8007E,
+                       );
+                       isa = PBXGroup;
+                       name = Products;
+                       refType = 4;
+               };
+               6941F0280242A10C00A8007E = {
+                       isa = PBXApplicationReference;
+                       path = WOxExtTest.woa;
+                       refType = 3;
+               };
+               6941F0290242A10C00A8007E = {
+                       buildPhases = (
+                               6941F02A0242A10C00A8007E,
+                               6941F02B0242A10C00A8007E,
+                               6941F04A0242A10C00A8007E,
+                               6941F06C0242A10C00A8007E,
+                               6941F06D0242A10C00A8007E,
+                       );
+                       buildSettings = {
+                               FRAMEWORK_SEARCH_PATHS = /Users/helge/build;
+                               OTHER_CFLAGS = "-DCOCOA_Foundation_LIBRARY=1 -DNeXT_Foundation_LIBRARY=1 -DNeXT_RUNTIME=1";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = WOxExtTest;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                               WRAPPER_EXTENSION = woa;
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXApplicationTarget;
+                       name = WOxExtTest;
+                       productInstallPath = "$(USER_APPS_DIR)";
+                       productName = WOxExtTest;
+                       productReference = 6941F0280242A10C00A8007E;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string></string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.WOxExtTest</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string></string>
+       <key>CFBundlePackageType</key>
+       <string>BDNL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
+";
+                       shouldUseHeadermap = 0;
+               };
+               6941F02A0242A10C00A8007E = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               6941F0760242A19200A8007E,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               6941F02B0242A10C00A8007E = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               6941F02C0242A10C00A8007E,
+                               6941F02D0242A10C00A8007E,
+                               6941F02E0242A10C00A8007E,
+                               6941F02F0242A10C00A8007E,
+                               6941F0300242A10C00A8007E,
+                               6941F0310242A10C00A8007E,
+                               6941F0320242A10C00A8007E,
+                               6941F0330242A10C00A8007E,
+                               6941F0340242A10C00A8007E,
+                               6941F0350242A10C00A8007E,
+                               6941F0360242A10C00A8007E,
+                               6941F0370242A10C00A8007E,
+                               6941F0380242A10C00A8007E,
+                               6941F0390242A10C00A8007E,
+                               6941F03A0242A10C00A8007E,
+                               6941F03B0242A10C00A8007E,
+                               6941F03C0242A10C00A8007E,
+                               6941F03D0242A10C00A8007E,
+                               6941F03E0242A10C00A8007E,
+                               6941F03F0242A10C00A8007E,
+                               6941F0400242A10C00A8007E,
+                               6941F0410242A10C00A8007E,
+                               6941F0420242A10C00A8007E,
+                               6941F0430242A10C00A8007E,
+                               6941F0440242A10C00A8007E,
+                               6941F0450242A10C00A8007E,
+                               6941F0460242A10C00A8007E,
+                               6941F0470242A10C00A8007E,
+                               6941F0480242A10C00A8007E,
+                               6941F0490242A10C00A8007E,
+                               6941F06F0242A18300A8007E,
+                               6941F0700242A18300A8007E,
+                               6941F0710242A18300A8007E,
+                               6941F0720242A18300A8007E,
+                               6941F0770242A19200A8007E,
+                               6941F0780242A19200A8007E,
+                               6941F0790242A19200A8007E,
+                               6941F07A0242A19200A8007E,
+                               69FC79A902983FB40083626D,
+                               69FC79AA02983FB50083626D,
+                               69FC79AB02983FB60083626D,
+                               69FC79AC02983FB60083626D,
+                               69FC79AD02983FB70083626D,
+                               69FC79AE02983FB70083626D,
+                               69FC79AF02983FB80083626D,
+                               69FC79B002983FB80083626D,
+                               69FC79B202983FBA0083626D,
+                               69FC79B302983FBA0083626D,
+                               69FC79B402983FBB0083626D,
+                               69FC79B502983FBC0083626D,
+                               69FC79B602983FBD0083626D,
+                               69FC79B702983FBD0083626D,
+                               69FC79B802983FBE0083626D,
+                               69FC79B902983FBE0083626D,
+                               69FC79BA02983FBF0083626D,
+                               69FC79BB02983FC00083626D,
+                               69FC79BC02983FC00083626D,
+                               69FC79BD02983FC10083626D,
+                               69FC79BE02983FC10083626D,
+                               69FC79BF02983FC40083626D,
+                               69FC79C002983FC40083626D,
+                               69FC79C102983FC50083626D,
+                               69FC79C202983FC50083626D,
+                               69FC79C302983FC60083626D,
+                               69FC79C402983FC60083626D,
+                               69FC79C502983FCC0083626D,
+                               69FC79C602983FCD0083626D,
+                               69FC79C702983FCD0083626D,
+                               69FC79C802983FCE0083626D,
+                               69FC79C902983FCE0083626D,
+                               69FC79CA02983FCF0083626D,
+                               69FC79CB02983FCF0083626D,
+                               69FC79CC02983FD00083626D,
+                               69FC79CD02983FD00083626D,
+                               69FC79CE02983FD40083626D,
+                               69FC79CF02983FD70083626D,
+                               69FC79D002983FD80083626D,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               6941F02C0242A10C00A8007E = {
+                       fileRef = 6918B09D01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F02D0242A10C00A8007E = {
+                       fileRef = 691DC04401F4D3CB00A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F02E0242A10C00A8007E = {
+                       fileRef = 6904BAA001EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F02F0242A10C00A8007E = {
+                       fileRef = 6904BAA101EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0300242A10C00A8007E = {
+                       fileRef = 6904BAA201EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0310242A10C00A8007E = {
+                       fileRef = 6904BAA301EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0320242A10C00A8007E = {
+                       fileRef = 6918B0F701CEA8DF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0330242A10C00A8007E = {
+                       fileRef = 6918B0F801CEAA3F0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0340242A10C00A8007E = {
+                       fileRef = 6904BAA401EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0350242A10C00A8007E = {
+                       fileRef = 6904BAA501EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0360242A10C00A8007E = {
+                       fileRef = 6918B0A901CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0370242A10C00A8007E = {
+                       fileRef = 6918B0F901CEAB5E0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0380242A10C00A8007E = {
+                       fileRef = 6904BAA601EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0390242A10C00A8007E = {
+                       fileRef = 6918B0AD01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F03A0242A10C00A8007E = {
+                       fileRef = 6904BAA701EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F03B0242A10C00A8007E = {
+                       fileRef = 6904BAA801EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F03C0242A10C00A8007E = {
+                       fileRef = 6904BAA901EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F03D0242A10C00A8007E = {
+                       fileRef = 6904BAAA01EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F03E0242A10C00A8007E = {
+                       fileRef = 6904BAAB01EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F03F0242A10C00A8007E = {
+                       fileRef = 6918B0F301CEA4C20053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0400242A10C00A8007E = {
+                       fileRef = 6918B0F101CEA2F40053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0410242A10C00A8007E = {
+                       fileRef = 6904BAAC01EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0420242A10C00A8007E = {
+                       fileRef = 6904BAAD01EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0430242A10C00A8007E = {
+                       fileRef = 6904BAAE01EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0440242A10C00A8007E = {
+                       fileRef = 6904BAAF01EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0450242A10C00A8007E = {
+                       fileRef = 6904BAB001EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0460242A10C00A8007E = {
+                       fileRef = 6904BAB101EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0470242A10C00A8007E = {
+                       fileRef = 6904BAB201EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0480242A10C00A8007E = {
+                       fileRef = 6904BAB301EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0490242A10C00A8007E = {
+                       fileRef = 6904BAB401EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F04A0242A10C00A8007E = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               6941F04B0242A10C00A8007E,
+                               6941F04C0242A10C00A8007E,
+                               6941F04D0242A10C00A8007E,
+                               6941F04E0242A10C00A8007E,
+                               6941F04F0242A10C00A8007E,
+                               6941F0500242A10C00A8007E,
+                               6941F0510242A10C00A8007E,
+                               6941F0520242A10C00A8007E,
+                               6941F0530242A10C00A8007E,
+                               6941F0540242A10C00A8007E,
+                               6941F0550242A10C00A8007E,
+                               6941F0560242A10C00A8007E,
+                               6941F0570242A10C00A8007E,
+                               6941F0580242A10C00A8007E,
+                               6941F0590242A10C00A8007E,
+                               6941F05A0242A10C00A8007E,
+                               6941F05B0242A10C00A8007E,
+                               6941F05C0242A10C00A8007E,
+                               6941F05D0242A10C00A8007E,
+                               6941F05E0242A10C00A8007E,
+                               6941F05F0242A10C00A8007E,
+                               6941F0600242A10C00A8007E,
+                               6941F0610242A10C00A8007E,
+                               6941F0620242A10C00A8007E,
+                               6941F0630242A10C00A8007E,
+                               6941F0640242A10C00A8007E,
+                               6941F0650242A10C00A8007E,
+                               6941F0660242A10C00A8007E,
+                               6941F0670242A10C00A8007E,
+                               6941F0680242A10C00A8007E,
+                               6941F0690242A10C00A8007E,
+                               6941F06A0242A10C00A8007E,
+                               6941F06B0242A10C00A8007E,
+                               6941F0730242A18300A8007E,
+                               6941F0740242A18300A8007E,
+                               6941F0750242A18300A8007E,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               6941F04B0242A10C00A8007E = {
+                       fileRef = 6918B09801CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F04C0242A10C00A8007E = {
+                       fileRef = 6918B09C01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F04D0242A10C00A8007E = {
+                       fileRef = 6918B09E01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F04E0242A10C00A8007E = {
+                       fileRef = 6918B09F01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F04F0242A10C00A8007E = {
+                       fileRef = 6918B0A001CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0500242A10C00A8007E = {
+                       fileRef = 6918B0A101CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0510242A10C00A8007E = {
+                       fileRef = 6918B0A201CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0520242A10C00A8007E = {
+                       fileRef = 6918B0A301CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0530242A10C00A8007E = {
+                       fileRef = 6918B0A401CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0540242A10C00A8007E = {
+                       fileRef = 6918B0A501CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0550242A10C00A8007E = {
+                       fileRef = 6918B0A601CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0560242A10C00A8007E = {
+                       fileRef = 6918B0A701CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0570242A10C00A8007E = {
+                       fileRef = 6918B0A801CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0580242A10C00A8007E = {
+                       fileRef = 6918B0AA01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0590242A10C00A8007E = {
+                       fileRef = 6918B0AB01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F05A0242A10C00A8007E = {
+                       fileRef = 6918B0AC01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F05B0242A10C00A8007E = {
+                       fileRef = 6918B0AE01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F05C0242A10C00A8007E = {
+                       fileRef = 6918B0AF01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F05D0242A10C00A8007E = {
+                       fileRef = 6918B0B001CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F05E0242A10C00A8007E = {
+                       fileRef = 6918B0B101CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F05F0242A10C00A8007E = {
+                       fileRef = 6918B0B201CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0600242A10C00A8007E = {
+                       fileRef = 6918B0B301CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0610242A10C00A8007E = {
+                       fileRef = 6918B0B401CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0620242A10C00A8007E = {
+                       fileRef = 6918B0B501CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0630242A10C00A8007E = {
+                       fileRef = 6918B0B601CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0640242A10C00A8007E = {
+                       fileRef = 6918B0B701CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0650242A10C00A8007E = {
+                       fileRef = 6918B0B801CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0660242A10C00A8007E = {
+                       fileRef = 6918B0B901CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0670242A10C00A8007E = {
+                       fileRef = 6918B0BA01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0680242A10C00A8007E = {
+                       fileRef = 6918B0BB01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0690242A10C00A8007E = {
+                       fileRef = 6918B0BC01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F06A0242A10C00A8007E = {
+                       fileRef = 6918B0BD01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F06B0242A10C00A8007E = {
+                       fileRef = 6918B0BE01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F06C0242A10C00A8007E = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               6941F07F0242A1F300A8007E,
+                               6941F0800242A1F300A8007E,
+                               6941F0850242A2FE00A8007E,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               6941F06D0242A10C00A8007E = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXRezBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               6941F06F0242A18300A8007E = {
+                       fileRef = 6904BAB501EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0700242A18300A8007E = {
+                       fileRef = 6904BAB601EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0710242A18300A8007E = {
+                       fileRef = 6904BAB701EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0720242A18300A8007E = {
+                       fileRef = 6904BAB801EB9B4900A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0730242A18300A8007E = {
+                       fileRef = 6918B0BF01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0740242A18300A8007E = {
+                       fileRef = 6918B0C001CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0750242A18300A8007E = {
+                       fileRef = 6918B0C101CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0760242A19200A8007E = {
+                       fileRef = 691DC05601F6197E00A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0770242A19200A8007E = {
+                       fileRef = 6918B0C301CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0780242A19200A8007E = {
+                       fileRef = 6918B0C401CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0790242A19200A8007E = {
+                       fileRef = 6918B0C501CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F07A0242A19200A8007E = {
+                       fileRef = 6918B0C601CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F07B0242A1F300A8007E = {
+                       isa = PBXFrameworkReference;
+                       name = FoundationExt.framework;
+                       path = /Users/helge/build/FoundationExt.framework;
+                       refType = 0;
+               };
+               6941F07C0242A1F300A8007E = {
+                       isa = PBXFrameworkReference;
+                       name = NGObjWeb.framework;
+                       path = /Users/helge/build/NGObjWeb.framework;
+                       refType = 0;
+               };
+               6941F07F0242A1F300A8007E = {
+                       fileRef = 6941F07B0242A1F300A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0800242A1F300A8007E = {
+                       fileRef = 6941F07C0242A1F300A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               6941F0830242A2FE00A8007E = {
+                       children = (
+                               6941F07C0242A1F300A8007E,
+                               6941F07B0242A1F300A8007E,
+                               6941F0840242A2FE00A8007E,
+                       );
+                       isa = PBXGroup;
+                       name = "Linked Frameworks";
+                       refType = 4;
+               };
+               6941F0840242A2FE00A8007E = {
+                       isa = PBXFrameworkReference;
+                       name = Foundation.framework;
+                       path = /System/Library/Frameworks/Foundation.framework;
+                       refType = 0;
+               };
+               6941F0850242A2FE00A8007E = {
+                       fileRef = 6941F0840242A2FE00A8007E;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69AC2E89031D8E3200A8CBE9 = {
+                       children = (
+                               6918B09601CE9DFF0053A783,
+                               6918B09701CE9DFF0053A783,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+               };
+               69FC79A902983FB40083626D = {
+                       fileRef = 6918B09B01CE9DFF0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79AA02983FB50083626D = {
+                       fileRef = 6918B0C701CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79AB02983FB60083626D = {
+                       fileRef = 6918B0C801CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79AC02983FB60083626D = {
+                       fileRef = 6918B0C901CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79AD02983FB70083626D = {
+                       fileRef = 6918B0CA01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79AE02983FB70083626D = {
+                       fileRef = 6918B0CB01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79AF02983FB80083626D = {
+                       fileRef = 6918B0CC01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79B002983FB80083626D = {
+                       fileRef = 6918B0CD01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79B202983FBA0083626D = {
+                       fileRef = 6918B0D001CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79B302983FBA0083626D = {
+                       fileRef = 6918B0CF01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79B402983FBB0083626D = {
+                       fileRef = 6918B0CE01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79B502983FBC0083626D = {
+                       fileRef = 6918B0D101CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79B602983FBD0083626D = {
+                       fileRef = 6918B0D201CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79B702983FBD0083626D = {
+                       fileRef = 6918B0D301CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79B802983FBE0083626D = {
+                       fileRef = 6918B0D401CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79B902983FBE0083626D = {
+                       fileRef = 6918B0D501CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79BA02983FBF0083626D = {
+                       fileRef = 6918B0D701CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79BB02983FC00083626D = {
+                       fileRef = 6918B0D601CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79BC02983FC00083626D = {
+                       fileRef = 6918B0D801CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79BD02983FC10083626D = {
+                       fileRef = 6918B0D901CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79BE02983FC10083626D = {
+                       fileRef = 6918B0DA01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79BF02983FC40083626D = {
+                       fileRef = 6918B0DB01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79C002983FC40083626D = {
+                       fileRef = 6918B0DC01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79C102983FC50083626D = {
+                       fileRef = 6918B0DD01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79C202983FC50083626D = {
+                       fileRef = 6918B0DE01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79C302983FC60083626D = {
+                       fileRef = 6918B0DF01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79C402983FC60083626D = {
+                       fileRef = 6918B0E001CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79C502983FCC0083626D = {
+                       fileRef = 6918B0E101CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79C602983FCD0083626D = {
+                       fileRef = 6918B0E201CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79C702983FCD0083626D = {
+                       fileRef = 6918B0E301CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79C802983FCE0083626D = {
+                       fileRef = 6918B0E401CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79C902983FCE0083626D = {
+                       fileRef = 6918B0E501CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79CA02983FCF0083626D = {
+                       fileRef = 6918B0E601CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79CB02983FCF0083626D = {
+                       fileRef = 6918B0E701CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79CC02983FD00083626D = {
+                       fileRef = 6918B0E801CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79CD02983FD00083626D = {
+                       fileRef = 6918B0E901CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79CE02983FD40083626D = {
+                       fileRef = 6918B0EA01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79CF02983FD70083626D = {
+                       fileRef = 6918B0EC01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               69FC79D002983FD80083626D = {
+                       fileRef = 6918B0EB01CE9EEE0053A783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+       };
+       rootObject = 6905B77501CE9CDB006474DE;
+}
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/OGoLogo.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/OGoLogo.gif
new file mode 100644 (file)
index 0000000..ea1b5f5
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/OGoLogo.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/collapsed.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/collapsed.gif
new file mode 100644 (file)
index 0000000..13e2be5
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/collapsed.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/corner_left.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/corner_left.gif
new file mode 100644 (file)
index 0000000..6ac16f1
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/corner_left.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/corner_right.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/corner_right.gif
new file mode 100644 (file)
index 0000000..1fc0317
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/corner_right.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/downward_sorted.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/downward_sorted.gif
new file mode 100644 (file)
index 0000000..bbaeab6
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/downward_sorted.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/expanded.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/expanded.gif
new file mode 100644 (file)
index 0000000..ba919e3
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/expanded.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/first.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/first.gif
new file mode 100644 (file)
index 0000000..66d4c6e
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/first.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/first_blind.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/first_blind.gif
new file mode 100644 (file)
index 0000000..3e40d4e
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/first_blind.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/folder_closed.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/folder_closed.gif
new file mode 100644 (file)
index 0000000..0e7ec76
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/folder_closed.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/folder_opened.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/folder_opened.gif
new file mode 100644 (file)
index 0000000..75348bd
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/folder_opened.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/last.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/last.gif
new file mode 100644 (file)
index 0000000..5412ed0
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/last.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/last_blind.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/last_blind.gif
new file mode 100644 (file)
index 0000000..c687147
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/last_blind.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/menu_email.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/menu_email.gif
new file mode 100644 (file)
index 0000000..8527707
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/menu_email.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/menu_email_inactive.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/menu_email_inactive.gif
new file mode 100644 (file)
index 0000000..7e2ecef
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/menu_email_inactive.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/next.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/next.gif
new file mode 100644 (file)
index 0000000..d827ea1
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/next.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/next_blind.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/next_blind.gif
new file mode 100644 (file)
index 0000000..cc26c04
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/next_blind.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/non_sorted.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/non_sorted.gif
new file mode 100644 (file)
index 0000000..d3da766
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/non_sorted.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/previous.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/previous.gif
new file mode 100644 (file)
index 0000000..4590633
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/previous.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/previous_blind.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/previous_blind.gif
new file mode 100644 (file)
index 0000000..cf6391e
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/previous_blind.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_.gif
new file mode 100644 (file)
index 0000000..ca1efd8
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_left.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_left.gif
new file mode 100644 (file)
index 0000000..5f76e6a
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_left.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news.gif
new file mode 100644 (file)
index 0000000..44fd324
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news_left.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news_left.gif
new file mode 100644 (file)
index 0000000..bad7b5f
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news_left.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news_selected.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news_selected.gif
new file mode 100644 (file)
index 0000000..e2f6f87
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_news_selected.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons.gif
new file mode 100644 (file)
index 0000000..259b838
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons_left.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons_left.gif
new file mode 100644 (file)
index 0000000..259b838
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons_left.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons_selected.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons_selected.gif
new file mode 100644 (file)
index 0000000..9c0dc0f
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_persons_selected.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects.gif
new file mode 100644 (file)
index 0000000..15a7ff9
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects_left.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects_left.gif
new file mode 100644 (file)
index 0000000..9052382
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects_left.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects_selected.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects_selected.gif
new file mode 100644 (file)
index 0000000..743c06c
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_projects_selected.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_selected.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_selected.gif
new file mode 100644 (file)
index 0000000..ffe1952
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/tab_selected.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner.gif
new file mode 100644 (file)
index 0000000..8010b6d
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner_minus.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner_minus.gif
new file mode 100644 (file)
index 0000000..52b9276
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner_minus.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner_plus.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner_plus.gif
new file mode 100644 (file)
index 0000000..f2f907e
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_corner_plus.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_junction.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_junction.gif
new file mode 100644 (file)
index 0000000..a617dc7
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_junction.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_leaf.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_leaf.gif
new file mode 100644 (file)
index 0000000..ca6b3ba
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_leaf.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_leaf_corner.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_leaf_corner.gif
new file mode 100644 (file)
index 0000000..43fb1ed
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_leaf_corner.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_line.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_line.gif
new file mode 100644 (file)
index 0000000..0afe949
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_line.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_minus.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_minus.gif
new file mode 100644 (file)
index 0000000..5a9ab78
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_minus.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_plus.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_plus.gif
new file mode 100644 (file)
index 0000000..056b90d
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_plus.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_space.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_space.gif
new file mode 100644 (file)
index 0000000..31b1849
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/treeview_space.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WebServerResources/upward_sorted.gif b/skyrix-sope/samples/WOxExtTest/WebServerResources/upward_sorted.gif
new file mode 100644 (file)
index 0000000..db69529
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/WebServerResources/upward_sorted.gif differ
diff --git a/skyrix-sope/samples/WOxExtTest/WeekColumnView.m b/skyrix-sope/samples/WOxExtTest/WeekColumnView.m
new file mode 100644 (file)
index 0000000..195770d
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSArray;
+
+@interface WeekColumnView : WOComponent
+{
+  NSArray *list;
+}
+@end
+
+#include "common.h"
+
+@implementation WeekColumnView
+
+static inline void setDateWithKey(id obj, NSString *key) {
+  NSString *str;
+
+  str = [obj objectForKey:key];
+
+  if (str) {
+    NSCalendarDate *date;
+
+    date = [NSCalendarDate dateWithString:str
+                           calendarFormat:@"%Y-%m-%d %H:%M:%S %Z"];
+    [obj setObject:date forKey:key];
+  }
+}
+
+- (id)init {
+  if ((self = [super init])) {
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->list);
+  [super dealloc];
+}
+
+- (NSCalendarDate *)weekStart {
+  return [NSCalendarDate dateWithString:@"2000-11-06 00:00:00 +0100"
+                         calendarFormat:@"%Y-%m-%d %H:%M:%S %Z"];
+}
+
+- (NSArray *)oneList {
+  return [NSArray arrayWithObject:@"one"];
+}
+
+- (NSArray *)list {
+  if (self->list == nil) {
+    WOResourceManager *rm;
+    NSString          *path;
+
+    rm = [[self application] resourceManager];
+    path = [rm pathForResourceNamed:@"appointments.plist"
+               inFramework:nil
+               languages:nil];
+
+    self->list = [[NSArray alloc] initWithContentsOfFile:path];
+
+    [self takeValue:@"0" forKey:@"clicks"];
+
+    {
+      int i, cnt;
+      
+      for (i = 0, cnt = [self->list count]; i < cnt; i++) {
+        setDateWithKey([self->list objectAtIndex:i], @"startDate");
+        setDateWithKey([self->list objectAtIndex:i], @"endDate");
+      }
+    }
+  }
+  return self->list;
+}
+
+- (NSString *)dayTitle {
+  switch([[self valueForKey:@"dayIndex"] intValue]) {
+    case 0: return @"Mo";
+    case 1: return @"Di";
+    case 2: return @"Mi";
+    case 3: return @"Do";
+    case 4: return @"Fr";
+    case 5: return @"Sa";
+    case 6: return @"So";
+    default: return @"??";
+  }
+}
+
+- (id)increaseClicks {
+  int clicks;
+  
+  clicks = [[self valueForKey:@"clicks"] intValue];
+  clicks++;
+  [self takeValue:[NSNumber numberWithInt:clicks] forKey:@"clicks"];
+  return nil;
+}
+
+- (id)dropAction {
+  NSLog(@".......dropped object is %@", [self valueForKey:@"droppedObject"]);
+  return nil;
+}
+
+@end /* WeekColumnView */
diff --git a/skyrix-sope/samples/WOxExtTest/WeekColumnView.wox b/skyrix-sope/samples/WOxExtTest/WeekColumnView.wox
new file mode 100644 (file)
index 0000000..5895264
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <form var:action="self">
+
+    <var:weekcol-view list="list" item="item" weekStart="weekStart"
+                      dayIndex="dayIndex"
+                      const:titleColor="#FFDAAA" const:contentColor="#FAE8B8"
+                      const:width="100%" const:border="0"
+                      const:cellspacing="2" const:cellpadding="4">
+  
+      <var:weekcol-title>
+        <font size="+2"><b><var:string value="dayTitle"/></b></font>
+      </var:weekcol-title>
+      
+      <var:weekcol-info>
+        <var:js-drop const:elementName="td" 
+                     const:isAttached="YES"
+                     tags="oneList" 
+                     action="dropAction" droppedObject="droppedObject"
+                     const:swapColor="YES"/>
+        
+        <small><b><i>
+            infos of day <var:string value="dayTitle"/>
+          <hr width="80%"/>
+        </i></b></small>
+      </var:weekcol-info>
+      
+      <var:weekcol>
+        <var:js-drag const:tag="one" const:object="one-toBeDropped">
+          <var:rich-string value="item.startDate" 
+                           const:isSmall="YES" const:color="red"/>
+          <var:rich-string value="item.endDate" 
+                           const:isSmall="YES" const:color="red"/>
+
+          <var:rich-string value="item.title" 
+                           const:isBold="YES" const:color="green"/>
+
+          <a var:action="increaseClicks">increase clicks</a>
+          <br/>
+        </var:js-drag>
+      </var:weekcol>
+    
+    </var:weekcol-view>
+  </form>
+
+  <var:string value="clicks"/>
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/WeekOverview.m b/skyrix-sope/samples/WOxExtTest/WeekOverview.m
new file mode 100644 (file)
index 0000000..3ace6af
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSArray;
+
+@interface WeekOverview : WOComponent
+{
+  NSArray *list;
+}
+@end
+
+#include "common.h"
+
+@implementation WeekOverview
+
+static inline void setDateWithKey(id obj, NSString *key) {
+  NSString *str;
+
+  str = [obj objectForKey:key];
+
+  if (str) {
+    NSCalendarDate *date;
+
+    date = [NSCalendarDate dateWithString:str
+                           calendarFormat:@"%Y-%m-%d %H:%M:%S %Z"];
+    [obj setObject:date forKey:key];
+  }
+}
+
+- (id)init {
+  if ((self = [super init])) {
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->list);
+  [super dealloc];
+}
+
+- (NSArray *)abList {
+  return [NSArray arrayWithObjects:@"a", @"b", nil];
+}
+- (NSArray *)cdList {
+  return [NSArray arrayWithObjects:@"c", @"d", nil];
+}
+
+- (NSCalendarDate *)weekStart {
+  NSCalendarDate *ws;
+  
+  ws = [NSCalendarDate dateWithString:@"2000-11-06 00:00:00 +0100"
+                       calendarFormat:@"%Y-%m-%d %H:%M:%S %z"];
+  if (ws == nil)
+    [self logWithFormat:@"couldn't create weekstart !"];
+  return ws;
+}
+
+- (NSArray *)list {
+  if (self->list == nil) {
+    WOResourceManager *rm;
+    NSString          *path;
+
+    rm = [[self application] resourceManager];
+    path = [rm pathForResourceNamed:@"appointments.plist"
+               inFramework:nil
+               languages:nil];
+    
+    self->list = [[NSArray alloc] initWithContentsOfFile:path];
+
+    {
+      int i, cnt;
+      
+      for (i = 0, cnt = [self->list count]; i < cnt; i++) {
+        setDateWithKey([self->list objectAtIndex:i], @"startDate");
+        setDateWithKey([self->list objectAtIndex:i], @"endDate");
+      }
+    }
+  }
+  return self->list;
+}
+
+@end /* WeekOverview */
diff --git a/skyrix-sope/samples/WOxExtTest/WeekOverview.wox b/skyrix-sope/samples/WOxExtTest/WeekOverview.wox
new file mode 100644 (file)
index 0000000..2df031f
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version='1.0' standalone='yes'?>
+<var:component className="Frame" title="name"
+           xmlns="http://www.w3.org/1999/xhtml"
+           xmlns:var="http://www.skyrix.com/od/binding"
+           xmlns:const="http://www.skyrix.com/od/constant">
+
+  <var:week-overview list="list" item="item" weekStart="weekStart"
+                     const:titleColor="#FFDAAA" const:contentColor="#FAE8B8"
+                     headerRows="abList" footerRows="cdList"
+                     headerRow="item"    footerRow="item"
+                     columnIndex="colIndex">
+
+    <var:week-info>
+      <small><b><i>infos of day</i></b></small><br/>
+      <hr width="80%"/><br/>
+    </var:week-info>
+    
+    <var:week>
+      <b><var:string value="item.title"/></b><br/>
+      <small><var:string value="item.startDate"/></small><br/><br/>
+    </var:week>
+
+    <var:week-header>
+      Row:<var:string value="item"/><br />
+      Column:<var:string value="colIndex"/>
+    </var:week-header>
+
+    <var:week-footer>
+      Row:<var:string value="item"/><br />
+      Column:<var:string value="colIndex"/>
+    </var:week-footer>
+  </var:week-overview>
+
+</var:component>
diff --git a/skyrix-sope/samples/WOxExtTest/common.h b/skyrix-sope/samples/WOxExtTest/common.h
new file mode 100644 (file)
index 0000000..cfa858f
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <Foundation/Foundation.h>
+
+#if LIB_FOUNDATION_LIBRARY
+#  import <Foundation/exceptions/GeneralExceptions.h>
+#elif NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+#  import <NGExtensions/NGObjectMacros.h>
+#  import <NGExtensions/NSString+Ext.h>
+#endif
+
+#include <NGExtensions/NGExtensions.h>
+#include <NGObjWeb/NGObjWeb.h>
diff --git a/skyrix-sope/samples/WOxExtTest/favicon.ico b/skyrix-sope/samples/WOxExtTest/favicon.ico
new file mode 100644 (file)
index 0000000..10d4951
Binary files /dev/null and b/skyrix-sope/samples/WOxExtTest/favicon.ico differ
diff --git a/skyrix-sope/samples/WOxExtTest/site.css b/skyrix-sope/samples/WOxExtTest/site.css
new file mode 100644 (file)
index 0000000..b4f215d
--- /dev/null
@@ -0,0 +1,39 @@
+/* $Id: site.css,v 1.1 2003/12/12 01:48:43 helge Exp $ */
+
+#tmplsrc {
+  font-size: 8pt;
+  padding:   1em;
+  border:    1px solid #FFDAAA; /* Plone: #8cacbb; */
+  color:     Black;
+  background-color: #FCF8DF;
+  /* Plone: background-color: #dee7ec; */
+}
+
+div#header {
+        margin-left:  5px;
+        margin-right: 5px;
+        padding:      0;
+        border-bottom: 1px solid #000000;
+}
+div#header img.headerlogo {
+        float:  right; 
+        width:  182px; 
+        height: 30px;
+}
+      
+div#header div#headerhistory {
+        font-size:   11px;
+        color:       #000000;
+        margin:      0px;
+        padding-top: 18px;
+        height:      12px;
+}
+div#header a, div#header span {
+        margin:      0px;
+}
+div#header span#navtitle {
+  font-weight: bold;
+}
+div#header a:hover {
+  text-decoration: none;
+}
diff --git a/skyrix-sope/samples/davpropget/GNUmakefile b/skyrix-sope/samples/davpropget/GNUmakefile
new file mode 100644 (file)
index 0000000..519fa24
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+TOOL_NAME = davpropget
+
+davpropget_OBJC_FILES = davpropget.m
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/tool.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/samples/davpropget/GNUmakefile.preamble b/skyrix-sope/samples/davpropget/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..92c4bcf
--- /dev/null
@@ -0,0 +1,6 @@
+# $Id$
+
+davpropget_TOOL_LIBS += \
+       -lNGObjWeb -lNGScripting \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lDOM -lXmlRpc -lSaxObjC
diff --git a/skyrix-sope/samples/davpropget/NOTES b/skyrix-sope/samples/davpropget/NOTES
new file mode 100644 (file)
index 0000000..e9842a2
--- /dev/null
@@ -0,0 +1,29 @@
+# $Id$
+
+Q: Apache 1.3 WebDAV not returning a content-length header?
+==
+
+Apparently Apache doesn't transmit a proper length header for PROPFIND
+responses, urks. Isn't that required for HTTP/1.1 responses (which it claims
+it is).
+
+---snip---
+PROPFIND /zs/H_chste_Ebene_der_Pers_nlichen_Ordner/My_Calendar/1B40B81E-6F11EE4B-9F81EFE5-6B2F7D7F HTTP/1.0
+Host: mac
+content-type: text/xml
+content-length: 101
+Depth: 0
+Brief: t
+
+<?xml version="1.0" encoding="utf-8" ?>
+<propfind xmlns="DAV:"  xmlns:V="DAV:"><allprop/></propfind>
+
+HTTP/1.1 207 Multi-Status
+Date: Thu, 16 Oct 2003 13:18:57 GMT
+Server: Apache/1.3.28 (Darwin) DAV/1.0.3
+Connection: close
+Content-Type: text/xml; charset="utf-8"
+
+<?xml version="1.0" encoding="utf-8"?>
+<D:multistatus xmlns:D="DAV:">
+---snap---
diff --git a/skyrix-sope/samples/davpropget/README b/skyrix-sope/samples/davpropget/README
new file mode 100644 (file)
index 0000000..7ccc851
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id$
+
+Note: you need to use the "simple" HTTP parser:
+  Defaults write davpropget WOHTTPConnectionUseSimpleParser YES
+
+davpropget
+==========
+
+Simple example to retrieve the properties of a WebDAV URL using
+WOHTTPConnection.
diff --git a/skyrix-sope/samples/davpropget/davpropget.m b/skyrix-sope/samples/davpropget/davpropget.m
new file mode 100644 (file)
index 0000000..4688889
--- /dev/null
@@ -0,0 +1,272 @@
+// $Id$
+
+#import <Foundation/Foundation.h>
+#include <NGExtensions/NGExtensions.h>
+#include <NGObjWeb/WOHTTPConnection.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <SaxObjC/SaxObjC.h>
+#include <SaxObjC/XMLNamespaces.h>
+#include <NGObjWeb/SaxDAVHandler.h>
+
+#define DEFAULT_NS @"DAV:"
+
+@interface DavPropGetTool : NSObject
+{
+  WOHTTPConnection *client;
+  NSURL    *url;
+  NSString *prop;
+  NSString *ns;
+  NSString *creds;
+
+  BOOL debugOn;
+  BOOL outputFlat;
+  BOOL outputPList;
+  BOOL didOutputOne;
+}
+
+@end
+
+@implementation DavPropGetTool
+
+static id<NSObject,SaxXMLReader> xmlParser = nil;
+static SaxDAVHandler             *davsax   = nil;
+
+- (void)usage {
+  fprintf(stderr, "usage: davpropget <url> [property] [ns]\n");
+  exit(1);
+}
+
+- (id)initWithArguments:(NSArray *)args {
+  if ((self = [super init])) {
+    NSString *tmp;
+    
+    if ([args count] < 2) {
+      [self usage];
+      [self release];
+      return nil;
+    }
+
+    url  = [[NSURL URLWithString:[args objectAtIndex:1]] copy];
+    prop = ([args count] > 2) ? [[args objectAtIndex:2] copy] : nil;
+    ns   = ([args count] > 3) ? [[args objectAtIndex:3] copy] : DEFAULT_NS;
+    
+    if ((tmp = [url user])) {
+      creds = [NSString stringWithFormat:@"%@:%@", tmp, [url password]];
+      creds = [creds stringByEncodingBase64];
+      creds = [[@"Basic " stringByAppendingString:creds] copy];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->creds  release];
+  [self->url    release];
+  [self->prop   release];
+  [self->ns     release];
+  [self->client release];
+  [super dealloc];
+}
+
+/* parser */
+
+- (void)lockParser:(id)_sax {
+  [_sax reset];
+  [xmlParser setContentHandler:_sax];
+  [xmlParser setErrorHandler:_sax];
+}
+- (void)unlockParser:(id)_sax {
+  [xmlParser setContentHandler:nil];
+  [xmlParser setErrorHandler:nil];
+  [_sax reset];
+}
+
+- (BOOL)setupXmlParser {
+  if (xmlParser == nil) {
+    xmlParser =
+      [[[SaxXMLReaderFactory standardXMLReaderFactory] 
+                             createXMLReaderForMimeType:@"text/xml"]
+                             retain];
+    if (xmlParser == nil)
+      return NO;
+  }
+  if (davsax == nil) {
+    if ((davsax = [[SaxDAVHandler alloc] init]) == nil)
+      return NO;
+  }
+  return YES;
+}
+
+/* connection */
+
+- (WOHTTPConnection *)client {
+  if (self->client) return self->client;
+  
+  self->client = [[WOHTTPConnection alloc] 
+                   initWithHost:[self->url host] 
+                   onPort:[[self->url port] intValue]];
+  if (debugOn) NSLog(@"  client: %@", client);
+  return self->client;
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return self->debugOn;
+}
+
+/* operations */
+
+- (void)davHandler:(SaxDAVHandler *)_handler
+  receivedProperties:(NSDictionary *)_record
+  forURI:(NSString *)_uri
+{
+  NSEnumerator *keys;
+  NSString *key;
+  
+  if (debugOn) {
+    [self debugWithFormat:@"URI: %@", _uri];
+    [self debugWithFormat:@"  properties: %@", _record];
+  }
+  
+  if (self->didOutputOne)
+    printf("\n");
+  
+  if (self->outputPList) {
+    printf("%s\n", [[_record description] cString]);
+    return;
+  }
+  
+  keys = [[[_record allKeys] sortedArrayUsingSelector:@selector(compare:)]
+                    objectEnumerator];
+  while ((key = [keys nextObject])) {
+    printf("%-40s: %s\n",
+           [key cString],
+           [[[_record objectForKey:key] stringValue] cString]);
+  }
+  
+  // [self logWithFormat:@"RECORD: %@", _record];
+  self->didOutputOne = YES;
+}
+
+- (void)logResponse:(WOResponse *)_response {
+  if (self->debugOn) {
+    [self debugWithFormat:@"received:\n----------\n%@----------", 
+            [_response contentAsString]];
+  }
+  
+  if (![self setupXmlParser]) {
+    [self logWithFormat:@"could not setup XML parser ..."];
+    return;
+  }
+  
+  [self lockParser:davsax];
+  {
+    [davsax setDelegate:self];
+    [xmlParser parseFromSource:[_response content]];
+  }
+  [self unlockParser:davsax];
+}
+
+- (void)sendRequestWithAuth:(WORequest *)rq {
+  WOHTTPConnection *httpClient;
+
+  httpClient = [self client];
+  
+  do {
+    WOResponse *r;
+    
+    if (![httpClient sendRequest:rq]) {
+      [self logWithFormat:@"ERROR: send failed: %@", 
+              [httpClient lastException]];
+      break;
+    }
+    if ((r = [httpClient readResponse]) == nil) {
+      [self logWithFormat:@"ERROR: receive failed: %@", 
+              [httpClient lastException]];
+      break;
+    }
+    
+    if ([r status] == 401) {
+      id auth;
+      
+      if ((auth = [rq headerForKey:@"authorization"])) {
+       [self logWithFormat:@"invalid credentials: %@", auth];
+       break;
+      }
+      
+      auth = [r headerForKey:@"www-authenticate"];
+      [self logWithFormat:@"authentication required: %@", auth];
+      
+      break;
+    }
+    
+    [self logResponse:r];
+    break;
+  }
+  while (YES);
+}
+
+- (void)appendBodyToRequest:(WORequest *)rq {
+  [rq appendContentString:
+       @"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
+        @"<propfind xmlns=\"DAV:\" "];
+  [rq appendContentString:@" xmlns:V=\""];
+  [rq appendContentString:ns];
+  [rq appendContentString:@"\""];
+  [rq appendContentString:@">"];
+  
+  if (self->prop) {
+    [rq appendContentString:@"<prop>"];
+    [rq appendContentString:@"<V:"];
+    [rq appendContentString:prop];
+    [rq appendContentString:@"/>"];
+    [rq appendContentString:@"</prop>"];
+  }
+  else
+    [rq appendContentString:@"<allprop/>"];
+  [rq appendContentString:@"</propfind>\n"];
+}
+
+- (void)run {
+  WORequest *rq;
+  
+  [self debugWithFormat:
+          @"Query:\n  url:  %@\n  prop: %@\n  ns:   %@", 
+          url, prop, ns];
+  
+  rq = [[[WORequest alloc] initWithMethod:@"PROPFIND"
+                          uri:[url path]
+                          httpVersion:@"HTTP/1.0"
+                          headers:nil
+                          content:nil
+                          userInfo:nil]
+                           autorelease];
+  [rq setHeader:@"t" forKey:@"Brief"];
+  [rq setHeader:@"0" forKey:@"Depth"];
+  [self appendBodyToRequest:rq];
+  
+  if (creds) [rq setHeader:creds forKey:@"authorization"];
+  [rq setHeader:@"text/xml" forKey:@"content-type"];
+  
+  [self sendRequestWithAuth:rq];
+}
+
+@end /* DavPropGetTool */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  NSArray *args;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  args = [[NSProcessInfo processInfo] argumentsWithoutDefaults];
+  [[[DavPropGetTool alloc] initWithArguments:args] run];
+  
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-sope/samples/iCalPortal/.cvsignore b/skyrix-sope/samples/iCalPortal/.cvsignore
new file mode 100644 (file)
index 0000000..1e243a1
--- /dev/null
@@ -0,0 +1,3 @@
+data
+.gdb_history
+ddd
diff --git a/skyrix-sope/samples/iCalPortal/COPYING b/skyrix-sope/samples/iCalPortal/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program 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 of the License, or
+    (at your option) any later version.
+
+    This program 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; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/skyrix-sope/samples/iCalPortal/COPYRIGHT b/skyrix-sope/samples/iCalPortal/COPYRIGHT
new file mode 100644 (file)
index 0000000..cdcf335
--- /dev/null
@@ -0,0 +1,3 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+Contact: info@skyrix.com
diff --git a/skyrix-sope/samples/iCalPortal/ChangeLog b/skyrix-sope/samples/iCalPortal/ChangeLog
new file mode 100644 (file)
index 0000000..550b7a1
--- /dev/null
@@ -0,0 +1,17 @@
+2004-01-23  Helge Hess  <helge.hess@opengroupware.org>
+
+       * iCalPortalDatabase.m, Pages/iCalPortalRegistrationPage.m: replaced 
+         -indexOfString: with -rangeOfString:
+
+       * iCalPortalUser.h: fixed header file for MacOSX
+
+       * imported as an NGObjWeb example into OpenGroupware.org
+       
+2002-10-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * accepts OL 2000 Web Assistent Publish requests
+
+2002-10-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * created ChangeLog
+
diff --git a/skyrix-sope/samples/iCalPortal/DirectAction.m b/skyrix-sope/samples/iCalPortal/DirectAction.m
new file mode 100644 (file)
index 0000000..d598225
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WODirectAction.h>
+
+@interface DirectAction : WODirectAction
+@end
+
+#include "iCalPortalUser.h"
+#include "iCalPortalDatabase.h"
+#include "iCalPortalPage.h"
+#include "common.h"
+
+@implementation WODirectAction(Ext)
+
+- (id<WOActionResults>)indexPage {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  WOSession *sn;
+  
+  if ((sn = [self existingSession])) {
+    [sn removeObjectForKey:@"user"];
+    [sn terminate];
+  }
+  
+  if ([ud boolForKey:@"DevMode"])
+    return [[self pageWithName:@"iCalPortalWelcomePage"] performPage];
+  
+  {
+    WOResponse *r;
+    NSString *loc;
+    
+    r = [WOResponse responseWithRequest:[self request]];
+    
+    loc = @"/en/index.xhtml"; // TODO: make configurable!
+    [self debugWithFormat:@"Deployment mode: redirecting to: %@", loc];
+    [r setStatus:302];
+    [r setHeader:loc forKey:@"location"];
+    
+    return r;
+  }
+}
+
+- (id)logoutAction {
+  return [self indexPage];
+}
+
+- (id)defaultAction {
+  return [self indexPage];
+}
+
+@end /* WODirectAction(Ext) */
+
+@implementation DirectAction
+
+- (id)showLicenseAction {
+  return [[self pageWithName:@"iCalPortalLicensePage"] performPage];
+}
+
+- (id)feedbackAction {
+  return [[self pageWithName:@"iCalPortalFeedbackPage"] performPage];
+}
+
+- (id)editProfileAction {
+  return [[self pageWithName:@"iCalPortalProfilePage"] performPage];
+}
+
+- (id)homeAction {
+  return [[self pageWithName:@"iCalPortalHomePage"] performPage];
+}
+
+/* calendars */
+
+- (id)weekOverviewAction {
+  return [[self pageWithName:@"iCalPortalWeekOverview"] performPage];
+}
+- (id)dayOverviewAction {
+  return [[self pageWithName:@"iCalPortalDayOverview"] performPage];
+}
+- (id)monthViewAction {
+  return [[self pageWithName:@"iCalPortalMonthView"] performPage];
+}
+- (id)todoViewAction {
+  return [[self pageWithName:@"iCalPortalToDoView"] performPage];
+}
+
+- (id)showCalendarAction {
+  return [self weekOverviewAction];
+}
+
+@end /* DirectAction */
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/back.gif b/skyrix-sope/samples/iCalPortal/English.lproj/back.gif
new file mode 100644 (file)
index 0000000..b11e5e9
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/back.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/back_menu.gif b/skyrix-sope/samples/iCalPortal/English.lproj/back_menu.gif
new file mode 100644 (file)
index 0000000..da29d0d
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/back_menu.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/back_menu2.gif b/skyrix-sope/samples/iCalPortal/English.lproj/back_menu2.gif
new file mode 100644 (file)
index 0000000..5dfbe09
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/back_menu2.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/back_seite.gif b/skyrix-sope/samples/iCalPortal/English.lproj/back_seite.gif
new file mode 100644 (file)
index 0000000..da29d0d
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/back_seite.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/banner_a.gif b/skyrix-sope/samples/iCalPortal/English.lproj/banner_a.gif
new file mode 100644 (file)
index 0000000..f0119ec
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/banner_a.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/banner_b.gif b/skyrix-sope/samples/iCalPortal/English.lproj/banner_b.gif
new file mode 100644 (file)
index 0000000..3bb3503
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/banner_b.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/banner_c.gif b/skyrix-sope/samples/iCalPortal/English.lproj/banner_c.gif
new file mode 100644 (file)
index 0000000..2b6716b
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/banner_c.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/banner_d.gif b/skyrix-sope/samples/iCalPortal/English.lproj/banner_d.gif
new file mode 100644 (file)
index 0000000..b1cfe3d
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/banner_d.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/banner_deutsch.gif b/skyrix-sope/samples/iCalPortal/English.lproj/banner_deutsch.gif
new file mode 100644 (file)
index 0000000..fc20ca5
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/banner_deutsch.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/banner_e.gif b/skyrix-sope/samples/iCalPortal/English.lproj/banner_e.gif
new file mode 100644 (file)
index 0000000..5a627a4
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/banner_e.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/favicon.ico b/skyrix-sope/samples/iCalPortal/English.lproj/favicon.ico
new file mode 100644 (file)
index 0000000..d1065d3
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/favicon.ico differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/feedback.gif b/skyrix-sope/samples/iCalPortal/English.lproj/feedback.gif
new file mode 100644 (file)
index 0000000..a918f53
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/feedback.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/free_hosting.gif b/skyrix-sope/samples/iCalPortal/English.lproj/free_hosting.gif
new file mode 100644 (file)
index 0000000..8656078
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/free_hosting.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/line.gif b/skyrix-sope/samples/iCalPortal/English.lproj/line.gif
new file mode 100644 (file)
index 0000000..e2be264
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/line.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/main.strings b/skyrix-sope/samples/iCalPortal/English.lproj/main.strings
new file mode 100644 (file)
index 0000000..38e3e9a
--- /dev/null
@@ -0,0 +1,58 @@
+login     = "Login"
+password  = "Password"
+password2 = "Repeat Password"
+firstName = "First Name"
+lastName  = "Last Name"
+email     = "Email"
+address   = "Address"
+city      = "City"
+state     = "State"
+zip       = "ZIP"
+country   = "Country"
+phone     = "Phone"
+
+OEAHomePage   = "SKYRiX Open eMail Server"
+FoldersTitle   = "Shared IMAP Folders"
+GroupsTitle    = "Create And Manage Groups"
+MailTitle      = "Configure your Mail System"
+ResourcesTitle = "Manage SKYRiXgreen Resources and Resource-Groups"
+SystemTitle    = "View and Edit System Configurations"
+UsersTitle     = "Create and Edit Users"
+VirtUsersTitle = "Create and Edit Virtual Users (Mail Aliases)"
+
+mailIndexAbstract   = "Configure and maintain your core mail system: postfix, cyrus and fetchmail."
+usersIndexAbstract  = "Create and edit users in the OpenLDAP server."
+vusersIndexAbstract = "Create and edit virtual users. Virtual users are email address aliases which can be mapped to one or many user accounts."
+groupsIndexAbstract = "Create and manage groups of user accounts."
+
+mail_fetchmail  = "Fetch Mail"
+mail_postfix    = "Postfix"
+mail_postfixex  = "Postfix Expert"
+mail_imapcfg    = "IMAP Configuration"
+mail_mailqueue  = "Mail Queue"
+
+users_new       = "New User"
+users_edit      = "Edit User"
+users_adminpwd  = "Admin Password"
+users_admindata = "Admin Profile"
+
+vusers_new      = "New Alias"
+vusers_edit     = "Edit Alias"
+vusers_domains  = "Domains"
+vusers_dnsnew   = "New Hostname"
+vusers_dnsdel   = "Delete Hostname"
+
+groups_new      = "New Group"
+groups_edit     = "Edit Group"
+
+folders_new     = "New Folder"
+folders_edit    = "Edit Folder"
+
+system_apache     = "Apache"
+system_ca         = "Certificates"
+system_browseldap = "Browse LDAP"
+system_mailtoall  = "Mail To All"
+
+resources_res       = "Resources"
+resources_newgroup  = "New Group"
+resources_editgroup = "Edit Group"
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/pixel.gif b/skyrix-sope/samples/iCalPortal/English.lproj/pixel.gif
new file mode 100644 (file)
index 0000000..75b945d
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/pixel.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/powered_by_publisher.gif b/skyrix-sope/samples/iCalPortal/English.lproj/powered_by_publisher.gif
new file mode 100644 (file)
index 0000000..76f175d
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/powered_by_publisher.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/search.gif b/skyrix-sope/samples/iCalPortal/English.lproj/search.gif
new file mode 100644 (file)
index 0000000..22cdde3
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/search.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/sidesmiley.gif b/skyrix-sope/samples/iCalPortal/English.lproj/sidesmiley.gif
new file mode 100644 (file)
index 0000000..2f29e3a
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/sidesmiley.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/site.css b/skyrix-sope/samples/iCalPortal/English.lproj/site.css
new file mode 100644 (file)
index 0000000..cd6e295
--- /dev/null
@@ -0,0 +1,120 @@
+body {
+  color:            #000000;
+  font-family:      Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  font-size:        10pt;
+  background-color: #FFFFFF;
+}
+
+font.header {
+  letter-spacing:   0pt;
+  color:            #034EA2;
+  font-family:      Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  font-size:        12pt;
+  font-weight:      bold;
+}
+tablink {
+  letter-spacing:   0pt;
+  font-color:       #000000;
+  color:            #000000;
+  font-family:      Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  font-size:        9pt;
+  font-weight:      bold;
+  text-decoration:  none;
+}
+
+a:link {
+  color:       #034EA2;
+  font-family: Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  letter-spacing:   0pt;
+}
+
+a:visited {
+  color:       #034EA2;
+  font-family: Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  letter-spacing:   0pt;
+}
+
+a:hover {
+  color:       #034EA2;
+  font-family: Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  letter-spacing:   0pt;
+}
+
+a:link.submenu {
+  color:       #034EA2;
+  font-family: Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  text-decoration: none;
+  font-size:        8pt;
+  letter-spacing:   0pt;
+}
+
+a:visited.submenu {
+  color:       #034EA2;
+  font-family: Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  font-size:        8pt;
+  text-decoration: none;
+  letter-spacing:   0pt;
+}
+
+a:hover.submenu {
+  color:           #000000;
+  font-family:     Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  text-decoration: underline;
+  font-size:        8pt;
+  letter-spacing:   0pt;
+}
+
+ul {
+  list-style-type:  disc;
+}
+
+pre {
+  letter-spacing:   0;
+  font-family:      monospace;
+  font-size:        7.5pt;
+  line-height:      10pt;
+  text-align:       left;
+  color:            #000000;
+}
+
+.default {
+  letter-spacing:   0.5pt;
+  font-family:      Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  font-size:        8pt;
+  line-height:      12pt;
+  color:            #000000;
+}
+
+.small {
+  font-family:      Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  font-size:        8pt;
+  color:            #000000;
+  text-decoration: none;
+}
+
+.menu {
+  letter-spacing:   0.5pt;
+  font-family:      Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  font-size:        10pt;
+  line-height:      12pt;
+  color:            #034EA2;
+  text-decoration:  none;
+  font-weight:      bold; 
+}
+
+.big {
+  letter-spacing:   0.5pt;
+  font-family:      Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  font-size:        10pt;
+  line-height:      12pt;
+  color:            #000000;
+}
+
+.news {
+  letter-spacing:   0pt;
+  font-family:      Arial, Helvetica, Verdana, Geneva, Tahoma, sans-serif;
+  font-size:        8pt;
+  line-height:      10pt;
+  text-align:       justify;
+  color:            #000000;
+}
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/small.gif b/skyrix-sope/samples/iCalPortal/English.lproj/small.gif
new file mode 100644 (file)
index 0000000..d5c614c
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/small.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/submit.gif b/skyrix-sope/samples/iCalPortal/English.lproj/submit.gif
new file mode 100644 (file)
index 0000000..d113b9d
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/submit.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/tab_.gif b/skyrix-sope/samples/iCalPortal/English.lproj/tab_.gif
new file mode 100644 (file)
index 0000000..ca1efd8
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/tab_.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/tab_left.gif b/skyrix-sope/samples/iCalPortal/English.lproj/tab_left.gif
new file mode 100644 (file)
index 0000000..5f76e6a
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/tab_left.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/tab_selected.gif b/skyrix-sope/samples/iCalPortal/English.lproj/tab_selected.gif
new file mode 100644 (file)
index 0000000..ffe1952
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/tab_selected.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/wp_config.gif b/skyrix-sope/samples/iCalPortal/English.lproj/wp_config.gif
new file mode 100644 (file)
index 0000000..0385023
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/wp_config.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/wp_create.gif b/skyrix-sope/samples/iCalPortal/English.lproj/wp_create.gif
new file mode 100644 (file)
index 0000000..a0ca6d6
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/wp_create.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/wp_faq.gif b/skyrix-sope/samples/iCalPortal/English.lproj/wp_faq.gif
new file mode 100644 (file)
index 0000000..62541c3
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/wp_faq.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/wp_feedback.gif b/skyrix-sope/samples/iCalPortal/English.lproj/wp_feedback.gif
new file mode 100644 (file)
index 0000000..5bc8b8d
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/wp_feedback.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/English.lproj/wp_info.gif b/skyrix-sope/samples/iCalPortal/English.lproj/wp_info.gif
new file mode 100644 (file)
index 0000000..05d6b2c
Binary files /dev/null and b/skyrix-sope/samples/iCalPortal/English.lproj/wp_info.gif differ
diff --git a/skyrix-sope/samples/iCalPortal/GNUmakefile b/skyrix-sope/samples/iCalPortal/GNUmakefile
new file mode 100644 (file)
index 0000000..20a065d
--- /dev/null
@@ -0,0 +1,33 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+WOAPP_NAME = iCalPortal
+
+iCalPortal_OBJC_FILES += \
+       iCalPortal.m                    \
+       iCalPortalDatabase.m            \
+       iCalPortalUser.m                \
+       iCalPortalCalendar.m            \
+       DirectAction.m                  \
+       \
+       iCalPortalPage.m                \
+       \
+       iCalView.m                      \
+       iCalDayView.m                   \
+       iCalWeekView.m                  \
+
+# this is a bit of a hack, because our gstep-make version cannot properly
+# copy resources of a subproject
+iCalPortal_RESOURCE_FILES += Pages/*.wox
+
+iCalPortal_SUBPROJECTS = WebDAV Pages
+
+iCalPortal_LANGUAGES = English German
+iCalPortal_LOCALIZED_RESOURCE_FILES = main.strings
+
+include icons.make
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/woapp.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/samples/iCalPortal/GNUmakefile.preamble b/skyrix-sope/samples/iCalPortal/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..fffd8a1
--- /dev/null
@@ -0,0 +1,14 @@
+# $Id$
+
+ADDITIONAL_INCLUDE_DIRS += -I. -I./WebDAV
+
+ADDITIONAL_TOOL_LIBS += -lNGiCal
+
+ifeq ($(FOUNDATION_LIB),apple)
+ADDITIONAL_TOOL_LIBS += \
+       -lNGScripting   \
+       -lEOControl     \
+       -lXmlRpc -lDOM -lSaxObjC
+else
+ADDITIONAL_TOOL_LIBS += -lcrypt
+endif
diff --git a/skyrix-sope/samples/iCalPortal/German.lproj/main.strings b/skyrix-sope/samples/iCalPortal/German.lproj/main.strings
new file mode 100644 (file)
index 0000000..d120646
--- /dev/null
@@ -0,0 +1,21 @@
+login     = "Nutzername"
+password  = "Passwort"
+password2 = "Passwort"
+firstName = "Vorname"
+lastName  = "Nachname"
+email     = "eMail"
+address   = "Adresse"
+city      = "Stadt"
+state     = "Bundesland"
+zip       = "Postleitzahl"
+country   = "Land"
+phone     = "Telefon"
+
+OEAHomePage           = "SKYRiX Open eMail Server"
+OEAFoldersIndexPage   = "Gemeinsame Postfaecher"
+OEAGroupsIndexPage    = "Erstellen und Verwalten von Gruppen"
+OEAMailIndexPage      = "Konfiguration des Mailsystems"
+OEAResourcesIndexPage = "Verwalten der SKYRiXgreen Ressourcen"
+OEASystemIndexPage    = "Anzeigen und Editieren von Systemkonfigurationen"
+OEAUsersIndexPage     = "Erstellen und Editieren von Nutzern"
+OEAVirtUsersIndexPage = "Erstellen und Editieren von virtuellen Nutzern"
diff --git a/skyrix-sope/samples/iCalPortal/Pages/.cvsignore b/skyrix-sope/samples/iCalPortal/Pages/.cvsignore
new file mode 100644 (file)
index 0000000..52c916d
--- /dev/null
@@ -0,0 +1 @@
+Resources
diff --git a/skyrix-sope/samples/iCalPortal/Pages/GNUmakefile b/skyrix-sope/samples/iCalPortal/Pages/GNUmakefile
new file mode 100644 (file)
index 0000000..61147bd
--- /dev/null
@@ -0,0 +1,29 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = Pages
+
+Pages_OBJC_FILES = \
+       iCalPortalBaseFrame.m           \
+       iCalPortalBox.m                 \
+       iCalPortalCalTabs.m             \
+       iCalPortalDayOverview.m         \
+       iCalPortalFeedbackPage.m        \
+       iCalPortalFrame.m               \
+       iCalPortalHomePage.m            \
+       iCalPortalLeftMenu.m            \
+       iCalPortalLicensePage.m         \
+       iCalPortalMonthView.m           \
+       iCalPortalProfilePage.m         \
+       iCalPortalRegistrationPage.m    \
+       iCalPortalRightMenu.m           \
+       iCalPortalToDoView.m            \
+       iCalPortalWeekOverview.m        \
+       iCalPortalWelcomePage.m         \
+
+ADDITIONAL_INCLUDE_DIRS += -I. -I..
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalBaseFrame.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalBaseFrame.m
new file mode 100644 (file)
index 0000000..b8b8c10
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WODirectAction.h>
+
+@interface iCalPortalBaseFrame : WOComponent
+{
+  NSString *title;
+  BOOL showHeader;
+}
+
+@end
+
+#include "common.h"
+
+@implementation iCalPortalBaseFrame
+
+- (void)dealloc {
+  [self->title release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setTitle:(NSString *)_title {
+  ASSIGN(self->title, _title);
+}
+- (NSString *)title {
+  return self->title;
+}
+
+- (void)setShowHeader:(BOOL)_flag {
+  self->showHeader = _flag;
+}
+- (BOOL)showHeader {
+  return self->showHeader;
+}
+
+@end /* iCalPortalBaseFrame */
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalBaseFrame.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalBaseFrame.wox
new file mode 100644 (file)
index 0000000..4bc6436
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version='1.0' standalone='yes'?>
+
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding"
+      xmlns:const="http://www.skyrix.com/od/constant">
+  <head>
+    <title><var:string value="title"/></title>
+    <meta name="description" content="SKYRiX iCalendar Portal" />
+    <meta name="author"      content="SKYRIX Software AG" />
+    <meta name="robots"      content="stop" />
+
+    <link rel="shortcut icon" href="http://calendar.skyrix.com/favicon.ico" />
+    <link type="text/css" 
+          rel="stylesheet" 
+          href="/iCalPortal.woa/WebServerResources/English.lproj/site.css" />
+    <link href="mailto:webmaster@skyrix.com" rev="made" />
+  </head>
+  
+  <body background="/iCalPortal.woa/WebServerResources/English.lproj/back.gif">
+
+    <var:if condition="showHeader">
+      <center>
+        <table border="0" cellpadding="0" cellspacing="0">
+          <tr>
+            <td align="center"><img 
+                border="0" filename="small.gif" width="1" height="30" /></td>
+            <td align="center"><img
+                border="0" filename="free_hosting.gif" width="622" height="30" /></td>
+            <td align="center"><img
+                border="0" filename="small.gif" width="1" height="30" /></td>
+          </tr>
+          <tr>
+            <td align="center"
+                background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+                border="0" filename="pixel.gif" width="1" height="1" /></td>
+    
+
+            <td align="center" bgcolor="white" height="200">
+              <var:component-content/>
+            </td>
+
+            <td align="center"
+                background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+                border="0" filename="pixel.gif" width="1" height="1" /></td>
+          </tr>
+        </table>
+      </center>
+    </var:if>
+    
+    <var:if const:negate="YES" condition="showHeader">
+      <var:component-content/>
+    </var:if>
+  </body>
+</html>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalBox.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalBox.m
new file mode 100644 (file)
index 0000000..90d26d0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WODirectAction.h>
+
+@interface iCalPortalBox : WOComponent
+{
+  NSString *title;
+}
+
+@end
+
+#include "common.h"
+
+@implementation iCalPortalBox
+
+- (void)dealloc {
+  [self->title release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setTitle:(NSString *)_title {
+  ASSIGN(self->title, _title);
+}
+- (NSString *)title {
+  return self->title;
+}
+
+/* actions */
+
+@end /* iCalPortalBox */
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalBox.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalBox.wox
new file mode 100644 (file)
index 0000000..f9562ed
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version='1.0' standalone='yes'?>
+
+<span xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding"
+      xmlns:const="http://www.skyrix.com/od/constant">
+  <table border="0" cellspacing="1" cellpadding="4" 
+        background="/iCalPortal.woa/WebServerResources/English.lproj/back_menu.gif">
+    <tr>
+      <td background="/iCalPortal.woa/WebServerResources/English.lproj/back.gif"><i><var:string value="title"/></i></td>
+    </tr>
+    <tr>
+      <td bgcolor="#FFFFFF"><var:component-content/></td>
+    </tr>
+  </table>
+</span>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalCalTabs.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalCalTabs.m
new file mode 100644 (file)
index 0000000..07a46be
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPortalPage.h"
+
+@interface iCalPortalCalTabs : iCalPortalPage
+{
+  NSString *selection;
+  NSString *calendarName;
+}
+
+@end
+
+#include "common.h"
+
+@implementation iCalPortalCalTabs
+
+- (void)dealloc {
+  [self->selection    release];
+  [self->calendarName release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setSelection:(NSString *)_sel {
+  ASSIGN(self->selection, _sel);
+}
+- (NSString *)selection {
+  return self->selection;
+}
+
+- (void)setCalendarName:(NSString *)_sel {
+  ASSIGN(self->calendarName, _sel);
+}
+- (NSString *)calendarName {
+  return self->calendarName;
+}
+
+/* tab state */
+
+- (BOOL)isDaySelected {
+  return [self->selection isEqualToString:@"day"] ? YES : NO;
+}
+- (BOOL)isWeekSelected {
+  return [self->selection isEqualToString:@"week"] ? YES : NO;
+}
+- (BOOL)isMonthSelected {
+  return [self->selection isEqualToString:@"month"] ? YES : NO;
+}
+- (BOOL)isToDoSelected {
+  return [self->selection isEqualToString:@"todo"] ? YES : NO;
+}
+
+- (NSString *)_url:(NSString *)_name {
+  return [NSString stringWithFormat:
+                    @"/iCalPortal.woa/WebServerResources/English.lproj/"
+                    @"tab_%@.gif", _name];
+}
+
+- (NSString *)dayTabURL {
+  return [self _url:[self isDaySelected] ? @"selected":@"left"];
+}
+- (NSString *)weekTabURL {
+  return [self _url:[self isWeekSelected] ? @"selected" : @""];
+}
+- (NSString *)monthTabURL {
+  return [self _url:[self isMonthSelected] ? @"selected" : @""];
+}
+- (NSString *)todoTabURL {
+  return [self _url:[self isToDoSelected] ? @"selected" : @""];
+}
+
+/* actions */
+
+@end /* iCalPortalCalTabs */
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalCalTabs.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalCalTabs.wox
new file mode 100644 (file)
index 0000000..2b274c0
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version='1.0' standalone='yes'?>
+
+<table border='0' width='100%' cellpadding='0' cellspacing='0'
+       xmlns='http://www.w3.org/1999/xhtml'
+       xmlns:var='http://www.skyrix.com/od/binding'
+       xmlns:const='http://www.skyrix.com/od/constant'>
+  <tr>
+    <td colspan='2'>
+      <table border='0' cellpadding='0' cellspacing='0'>
+        <tr>
+         <td align='center' valign='middle' width='100' height='22' 
+             var:background='dayTabURL'><a 
+           style="text-decoration: none;" directActionName="dayOverview" 
+           var:_calendarName="calendarName"><font
+           class="tablink"><var:string value="label.day_tab"/></font></a>
+         </td>
+         <td align='center' valign='middle' width='100' height='22' 
+             var:background='weekTabURL'><a 
+           style="text-decoration: none;" directActionName="weekOverview" 
+           var:_calendarName="calendarName"><font 
+           class="tablink"><var:string value="label.week_tab"/></font></a>
+         </td>
+         <td align='center' valign='middle' width='100' height='22' 
+             var:background='monthTabURL'><a 
+           style="text-decoration: none;" directActionName="monthView" 
+           var:_calendarName="calendarName"><font
+           class="tablink"><var:string value="label.month_tab"/></font></a>
+         </td>
+         <td align='center' valign='middle' width='100' height='22' 
+             var:background='todoTabURL'><a 
+           style="text-decoration: none;" directActionName="todoView" 
+           var:_calendarName="calendarName"><font
+           class="tablink"><var:string value="label.todo_tab"/></font></a>
+         </td>
+       </tr>
+      </table>
+    </td>
+  </tr>
+  <tr bgcolor="#FCF8DF">
+    <td align="left" width="10"><entity name="nbsp"/></td>
+    <td align="right"><entity name="nbsp"/></td>
+  </tr>
+  <tr>
+    <td colspan='2' bgcolor="#FCF8DF"><var:component-content/></td>
+  </tr>
+</table>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalDayOverview.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalDayOverview.m
new file mode 100644 (file)
index 0000000..1f84b5c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalDayView.h"
+#include <NGObjWeb/WODirectAction.h>
+
+@interface iCalPortalDayOverview : iCalDayView
+{
+}
+
+@end
+
+@interface iCalPortalDayOverviewAction : WODirectAction
+@end
+
+#include "common.h"
+
+@implementation iCalPortalDayOverview
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* accessors */
+
+/* actions */
+
+@end /* iCalPortalDayOverview */
+
+@implementation iCalPortalDayOverviewAction
+@end /* iCalPortalDayOverviewAction */
+
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalDayOverview.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalDayOverview.wox
new file mode 100644 (file)
index 0000000..eec1d28
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalFrame' title='localizedTitle'
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+  <var:component className="iCalPortalCalTabs" const:selection="day"
+                calendarName="calendarName">
+
+    days
+
+  </var:component>
+</var:component>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalFeedbackPage.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalFeedbackPage.m
new file mode 100644 (file)
index 0000000..b45e0c9
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPortalPage.h"
+
+@interface iCalPortalFeedbackPage : iCalPortalPage
+{
+}
+
+@end
+
+#include "common.h"
+
+@implementation iCalPortalFeedbackPage
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* accessors */
+
+/* actions */
+
+@end /* iCalPortalFeedbackPage */
+
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalFeedbackPage.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalFeedbackPage.wox
new file mode 100644 (file)
index 0000000..30dafb0
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalFrame' title='localizedTitle'
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+
+  Page: iCalPortalFeedbackPage
+
+</var:component>
+
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalFrame.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalFrame.m
new file mode 100644 (file)
index 0000000..f510e7f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+
+@interface iCalPortalFrame : WOComponent
+{
+  NSString *title;
+  BOOL     showRightMenu;
+}
+
+@end
+
+#include "common.h"
+
+@implementation iCalPortalFrame
+
+- (void)dealloc {
+  [self->title release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setTitle:(NSString *)_title {
+  ASSIGN(self->title, _title);
+}
+- (NSString *)title {
+  return self->title;
+}
+
+- (void)setShowRightMenu:(BOOL)_flag {
+  self->showRightMenu = _flag;
+}
+- (BOOL)showRightMenu {
+  return self->showRightMenu;
+}
+
+/* actions */
+
+@end /* iCalPortalFrame */
+
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalFrame.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalFrame.wox
new file mode 100644 (file)
index 0000000..b1eab20
--- /dev/null
@@ -0,0 +1,114 @@
+<?xml version='1.0' standalone='yes'?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding"
+      xmlns:const="http://www.skyrix.com/od/constant">
+  <head>
+    <title><var:string value="title"/></title>
+    <meta name="description" content="SKYRiX iCalendar Portal" />
+    <meta name="author"      content="SKYRIX Software AG" />
+    <meta name="robots"      content="stop" />
+    
+    <!-- link rel="shortcut icon" href="/favicon.ico" -->
+    <link type="text/css" 
+          rel="stylesheet" 
+          href="/iCalPortal.woa/WebServerResources/English.lproj/site.css" />
+    <link href="mailto:webmaster@skyrix.com" rev="made" />
+  </head>
+  
+  <body bgcolor="white">
+
+  <table border="0" cellpadding="0" cellspacing="0">
+    <tr>
+      <td><img filename="banner_a.gif" width="1" height="123"/></td>
+      <td><img filename="banner_b.gif" width="125" height="123"/></td>
+      <td><img filename="banner_c.gif" width="1" height="123"/></td>
+      <td colspan="2"><img filename="banner_d.gif" width="672" height="123"/></td>
+      <td><img filename="banner_e.gif" width="1" height="123"/></td>
+    </tr>
+    <tr>
+      <td background="/iCalPortal.woa/WebServerResources/English.lproj/line.gif"
+         ><img filename="pixel.gif"/></td>
+      <td valign="top"
+          background="/iCalPortal.woa/WebServerResources/English.lproj/back_menu.gif">
+        <var:component className="iCalPortalLeftMenu"/>
+      </td>
+      <td background="/iCalPortal.woa/WebServerResources/English.lproj/line.gif"
+         ><img filename="pixel.gif"/></td>
+      <td width="10"><img filename="pixel.gif"/></td>
+      <td valign="top">
+        <span>
+          <table border="0" width="662" cellspacing="0" cellpadding="0">
+            <tr>
+              <td><font class="default"></font></td>
+              <td align="right"><font class="default">
+                <a href="mailto:?body=http://www.xml-rpc.de/index.xhtml&amp;subject=XML-RPC HomePage">mail to...</a
+>
+                |
+                <a href="print/index.xhtml" target="printer">Druckansicht</a><entity name="nbsp"/></font>
+              </td>
+            </tr>
+            <tr>
+              <td colspan="2" height="1" background="/iCalPortal.woa/WebServerResources/English.lproj/line.gif"><img filename="pixel.gif"/></td>
+            </tr>
+            <tr>
+              <td colspan="2" height="3"><img filename="pixel.gif" height="3" /></td>
+            </tr>
+          </table>
+        </span>
+
+        <!-- the content title -->
+        <font class="header"><var:string value="title"/></font>
+
+        <table border="0" cellpadding="0" cellspacing="0" width="640">
+          <tr>
+            <td height="1" 
+               background="/iCalPortal.woa/WebServerResources/English.lproj/line.gif"
+              ><img filename="pixel.gif" /></td>
+            <td height="1" width="1"
+               background="/iCalPortal.woa/WebServerResources/English.lproj/line.gif"
+              ><img filename="pixel.gif" /></td>
+            <var:if condition="showRightMenu">
+              <td height="1"><img filename="pixel.gif" /></td>
+            </var:if>
+          </tr>
+          <tr>
+            <!-- the content area -->
+            <!-- td align="left" valign="top" width="464" -->
+            <td align="left" valign="top" bgcolor="#FCF8DF">
+              <table border="0" cellpadding="0" cellspacing="10" width="100%">
+                <tr>
+                  <td align="left" valign="top" width="100%">
+                    <font class="default"><var:component-content/></font>
+                  </td>
+                </tr>
+              </table>
+            </td>
+    
+            <var:if condition="showRightMenu">
+              <!-- horizontal line ! -->
+              <td width="1" 
+                 background="/iCalPortal.woa/WebServerResources/English.lproj/line.gif"
+                ><img filename="pixel.gif" /></td>
+              
+              <!-- right menu -->
+              <td align="left" valign="top" width="146">
+                <table width="100%" cellpadding="1" cellspacing="5" border="0">
+                  <tr>
+                    <td><var:component className="iCalPortalRightMenu"/></td>
+                  </tr>
+                </table>
+              </td>
+            </var:if>
+          </tr>
+        </table>
+      </td>
+
+      <td background="/iCalPortal.woa/WebServerResources/English.lproj/line.gif"><img filename="pixel.gif"/></td>
+    </tr>
+    <tr>
+      <td background="/iCalPortal.woa/WebServerResources/English.lproj/line.gif" colspan="6"><img filename="pixel.gif"/></td>
+    </tr>
+  </table>
+
+ </body>
+</html>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalHomePage.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalHomePage.m
new file mode 100644 (file)
index 0000000..bba6151
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPortalPage.h"
+
+@interface iCalPortalHomePage : iCalPortalPage
+{
+  /* transient */
+  id item;
+}
+
+@end
+
+#include "common.h"
+
+@implementation iCalPortalHomePage
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setItem:(id)_item {
+  ASSIGN(self->item, _item);
+}
+- (id)item {
+  return self->item;
+}
+
+/* notifications */
+
+- (void)sleep {
+  [super sleep];
+  [self setItem:nil];
+}
+
+/* actions */
+
+@end /* iCalPortalHomePage */
+
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalHomePage.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalHomePage.wox
new file mode 100644 (file)
index 0000000..465d9be
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalFrame' title='localizedTitle'
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+  
+  <h3>
+    Welcome 
+    <var:string value="user.firstName"/>
+    <var:string value="user.lastName"/>
+    !
+  </h3>
+  
+  <var:component className="iCalPortalBox" const:title="Info">
+
+    <a directActionName="editProfile">edit profile</a>
+  
+  </var:component>
+
+  <br />
+
+  <var:component className="iCalPortalBox" const:title="Published">
+    <ul>
+      <var:foreach list="session.user.calendarNames" item="item">
+        <li>
+          <a directActionName="showCalendar" var:_calendarName="item"
+            ><var:string value="item"/></a></li>
+      </var:foreach>
+    </ul>
+  </var:component>
+
+  <br />
+
+  <var:component className="iCalPortalBox" const:title="Directory">
+  
+  </var:component>
+  
+</var:component>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalLeftMenu.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalLeftMenu.m
new file mode 100644 (file)
index 0000000..1c733c1
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WODirectAction.h>
+
+@interface iCalPortalLeftMenu : WOComponent
+{
+  /* transient */
+  id item;
+}
+
+@end
+
+@interface iCalPortalLeftMenuAction : WODirectAction
+@end
+
+#include "iCalPortalUser.h"
+#include "common.h"
+
+@implementation iCalPortalLeftMenu
+
+- (void)dealloc {
+  [self->item release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (iCalPortalUser *)user {
+  if (![self hasSession]) return nil;
+  return [[self session] valueForKey:@"user"];
+}
+
+- (NSArray *)allCalendars {
+  return [[self user] calendarNames];
+}
+
+- (void)setItem:(id)_item {
+  ASSIGN(self->item, _item);
+}
+- (id)item {
+  return self->item;
+}
+
+/* notifications */
+
+- (void)sleep {
+  [super sleep];
+  [self setItem:nil];
+}
+
+/* actions */
+
+@end /* iCalPortalLeftMenu */
+
+@implementation iCalPortalLeftMenuAction
+@end /* iCalPortalLeftMenuAction */
+
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalLeftMenu.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalLeftMenu.wox
new file mode 100644 (file)
index 0000000..5302767
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version='1.0' standalone='yes'?>
+
+<nodig xmlns='http://www.w3.org/1999/xhtml'
+       xmlns:var='http://www.skyrix.com/od/binding'
+       xmlns:const='http://www.skyrix.com/od/constant'>
+
+  <table border="0" cellpadding="5" cellspacing="0" 
+                  height="200" width="125">
+    <tr>
+      <td valign="top" align="left" 
+                   background="/app/WebServerResources/English.lproj/back_menu.gif">
+        <table border="0" cellpadding="0" cellspacing="0" width="100%">
+          <tr>
+            <td valign="top" align="right">
+              <a directActionName="home" class="menu">Home</a>
+            </td>
+          </tr>
+          <tr>
+            <td valign="top" align="right">
+              <a directActionName="editProfile" class="menu">Profile</a>
+            </td>
+          </tr>
+          
+          <tr>
+            <td valign="top" align="right" class="menu">Calendars</td>
+          </tr>
+          <var:foreach list="allCalendars" item="item">
+            <tr>
+              <td valign="top" align="right" 
+                 background="/app/WebServerResources/English.lproj/back_menu.gif">
+                <table cellpadding="0" cellspacing="0" border="0" width="100%">
+                  <tr>
+                    <td valign="top" align="right" width="75%">
+                      <font class="small">
+                        <a directActionName="showCalendar" 
+                          var:_calendarName="item"
+                          class="submenu"><var:string value="item"/></a>
+                      </font>
+                    </td>
+                    <td width="25%"> </td>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </var:foreach>
+         
+          <tr>
+            <td valign="top" align="right"><a
+             href="about/index.xhtml" class="menu"><entity 
+             name="nbsp"/><var:entity const:name="Uuml"/>ber uns</a></td>
+          </tr>
+
+          <tr>
+            <td valign="top" align="right">
+              <a directActionName="logout" class="menu">Logout</a>
+            </td>
+          </tr>
+        </table>
+      </td>
+    </tr>
+  </table>
+</nodig>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalLicensePage.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalLicensePage.m
new file mode 100644 (file)
index 0000000..b0e46b2
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WODirectAction.h>
+
+@interface iCalPortalLicensePage : WOComponent
+{
+}
+
+@end
+
+@interface iCalPortalLicenseAction : WODirectAction
+@end
+
+#include "common.h"
+
+@implementation iCalPortalLicensePage
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* accessors */
+
+/* actions */
+
+- (id)run {
+  return self;
+}
+- (id)performPage {
+  return [self run];
+}
+
+/* label */
+
+- (NSString *)localizedTitle {
+  return @"Calendar.SKYRIX.COM Rules & Information";
+}
+
+@end /* iCalPortalLicensePage */
+
+#include "iCalPortalPage.h"
+
+@implementation iCalPortalLicenseAction
+
+- (id)acceptRulesAction {
+  return [[self pageWithName:@"iCalPortalRegistrationPage"] performPage];
+}
+
+- (id)declineRulesAction {
+  return [self indexPage];
+}
+
+@end /* iCalPortalLicenseAction */
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalLicensePage.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalLicensePage.wox
new file mode 100644 (file)
index 0000000..59d143a
--- /dev/null
@@ -0,0 +1,77 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalBaseFrame' title='name'
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+   <center>
+    <table border="0" cellpadding="0" cellspacing="0">
+      <tr>
+        <td align="center"><img 
+           border="0" filename="small.gif" width="1" height="30" /></td>
+        <td align="center"><img
+           border="0" filename="free_hosting.gif" width="622" height="30" /></td>
+        <td align="center"><img
+           border="0" filename="small.gif" width="1" height="30" /></td>
+      </tr>
+
+      <tr>
+        <td align="center"
+           background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+           border="0" filename="pixel.gif" width="1" height="1" /></td>
+
+        <td align="center" bgcolor="white" height="200">
+  <table border="0" width="550">
+    <tr>
+      <td colspan="2">
+       <p>
+         Registration to this service is free! We do insist that you abide
+         by the rules and policies detailed below. If you agree to the
+         terms, please press the Accept button at the end of the page.
+       </p>
+
+        <p>
+           blah blah blah blah blah blah blah blah blah blah <br />
+           blah blah blah blah blah blah blah blah blah blah <br />
+           blah blah blah blah blah blah blah blah blah blah <br />
+        </p>   
+        <p>
+           blah blah blah blah blah blah blah blah blah blah <br />
+           blah blah blah blah blah blah blah blah blah blah <br />
+           blah blah blah blah blah blah blah blah blah blah <br />
+        </p>   
+        <p>
+           blah blah blah blah blah blah blah blah blah blah <br />
+           blah blah blah blah blah blah blah blah blah blah <br />
+           blah blah blah blah blah blah blah blah blah blah <br />
+        </p>   
+        
+       <p>
+         <b>By accepting this agreement you hereby agree to all the listed
+         items above and take full responsibility for the actions and
+         information that you the member post.</b>
+       </p>
+     </td>
+    </tr>
+
+    <tr>
+      <td align="center" width="50%">
+        <a directActionName="acceptRules" 
+          actionClass="iCalPortalLicenseAction"
+          >Accept and continue</a>
+      </td>
+      <td align="center" width="50%">
+        <a directActionName="declineRules" 
+          actionClass="iCalPortalLicenseAction"
+         >Decline</a>
+      </td>
+    </tr>
+  </table>
+        </td>
+        <td align="center"
+           background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+           border="0" filename="pixel.gif" width="1" height="1" /></td>
+      </tr>
+    </table>
+   </center>
+</var:component>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalMonthView.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalMonthView.m
new file mode 100644 (file)
index 0000000..937f44c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalView.h"
+#include <NGObjWeb/WODirectAction.h>
+
+@interface iCalPortalMonthView : iCalView
+{
+  id currentDay;
+}
+
+@end
+
+@interface iCalPortalMonthViewAction : WODirectAction
+@end
+
+#include "common.h"
+
+@implementation iCalPortalMonthView
+
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (void)dealloc {
+  [self->currentDay release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setCurrentDay:(id)_day {
+  ASSIGN(self->currentDay, _day);
+}
+- (id)currentDay {
+  return self->currentDay;
+}
+
+/* datasource */
+
+- (NSString *)entityName {
+  return @"vevent";
+}
+
+/* actions */
+
+@end /* iCalPortalMonthView */
+
+@implementation iCalPortalMonthViewAction
+@end /* iCalPortalMonthViewAction */
+
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalMonthView.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalMonthView.wox
new file mode 100644 (file)
index 0000000..ecdc58c
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalFrame' title='localizedTitle'
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+  <var:component className="iCalPortalCalTabs" const:selection="month"
+                calendarName="calendarName">
+
+  <var:month-overview list="dataSource.fetchObjects" item="item"
+                      currentDay="currentDay"
+                      const:year="2002" const:month="10"
+                      const:labelColor="#FFDAAA" const:contentColor="#FAE8B8"
+  >
+    <!--var:month-info>
+      <small><b><i>infos of day</i></b></small><br/><br/>
+    </var:month-info-->
+    
+    <var:month>
+      <font class="default">
+        <b><var:string value="item.summary"/></b>
+        <br/>
+        <var:string value="item.startDate" const:dateformat="%H:%M"/>
+        <br/>
+      </font>
+    </var:month>
+
+  </var:month-overview>
+
+  </var:component>
+</var:component>
+
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalProfilePage.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalProfilePage.m
new file mode 100644 (file)
index 0000000..66a490a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPortalPage.h"
+
+@interface iCalPortalProfilePage : iCalPortalPage
+{
+}
+
+@end
+
+#include "common.h"
+
+@implementation iCalPortalProfilePage
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* accessors */
+
+/* actions */
+
+@end /* iCalPortalProfilePage */
+
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalProfilePage.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalProfilePage.wox
new file mode 100644 (file)
index 0000000..db606e5
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalFrame' title='localizedTitle'
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+  
+  <h3>Edit Profile of
+    <var:string value="user.firstName"/>
+    <var:string value="user.lastName"/>
+  </h3>
+
+  <form directActionName="saveProfile">
+    <table border="0">
+      <tr>
+       <td align="right">Login:</td>
+       <td><var:string value="user.login" size="40"/></td>
+      </tr>
+      
+      <tr>
+       <td align="right"><nobr><var:string value="label.firstName"/>:</nobr>
+:</td>
+       <td><input name="firstName" var:value="user.firstName" size="40"/></td>
+      </tr>
+      <tr>
+       <td align="right"><nobr><var:string value="label.lastName"/>:</nobr>
+:</td>
+       <td><input name="lastName" var:value="user.lastName" size="40"/></td>
+      </tr>
+      <tr>
+       <td align="right"><nobr><var:string value="label.email"/>:</nobr>
+:</td>
+       <td><input name="email" var:value="user.email" size="40"/></td>
+      </tr>
+      <tr>
+       <td align="right"><nobr><var:string value="label.address"/>:</nobr>
+:</td>
+       <td><input name="address" var:value="user.address" size="40"/></td>
+      </tr>
+      <tr>
+       <td align="right"><nobr><var:string value="label.city"/>:</nobr>
+:</td>
+       <td><input name="city" var:value="user.city" size="40"/></td>
+      </tr>
+      <tr>
+       <td align="right"><nobr><var:string value="label.zip"/>:</nobr>
+:</td>
+       <td><input name="zip" var:value="user.zip" size="40"/></td>
+      </tr>
+      <tr>
+       <td align="right"><nobr><var:string value="label.country"/>:</nobr>
+:</td>
+       <td><input name="country" var:value="user.country" size="40"/></td>
+      </tr>
+      <tr>
+       <td align="right"><nobr><var:string value="label.phone"/>:</nobr>
+:</td>
+       <td><input name="phone" var:value="user.phone" size="40"/></td>
+      </tr>
+
+      <tr>
+        <td></td>
+        <td><input type="submit" value="save" name="save"/></td>
+      </tr>
+    </table>
+  </form>
+  
+</var:component>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalRegistrationPage.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalRegistrationPage.m
new file mode 100644 (file)
index 0000000..6466d1d
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPortalPage.h"
+#include <NGObjWeb/WODirectAction.h>
+
+@interface iCalPortalRegistrationPage : iCalPortalPage
+{
+  NSString *login;
+  NSString *firstName;
+  NSString *lastName;
+  NSString *email;
+  NSString *address;
+  NSString *city;
+  NSString *state;
+  NSString *zip;
+  NSString *country;
+  NSString *phone;
+  NSString *wantIcalNews;
+  NSString *wantSkyrixNews;
+
+  BOOL loginOK;
+  BOOL loginAvailable;
+  BOOL pwdOK;
+  BOOL firstNameOK;
+  BOOL lastNameOK;
+  BOOL emailOK;
+}
+
+- (void)markLoginWrong;
+- (void)markLoginUsed;
+- (void)markPwdWrong;
+- (void)markFirstNameWrong;
+- (void)markLastNameWrong;
+- (void)markEmailWrong;
+
+@end
+
+@interface iCalPortalRegistrationAction : WODirectAction
+@end
+
+#include "common.h"
+
+@interface NSString(EmailAddress)
+- (BOOL)isValidEmailAddress;
+@end
+
+@implementation iCalPortalRegistrationPage
+
+- (id)init {
+  if ((self = [super init])) {
+    self->loginOK        = YES;
+    self->loginAvailable = YES;
+    self->pwdOK          = YES;
+    self->firstNameOK    = YES;
+    self->lastNameOK     = YES;
+    self->emailOK        = YES;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->login          release];
+  [self->firstName      release];
+  [self->lastName       release];
+  [self->email          release];
+  [self->address        release];
+  [self->city           release];
+  [self->state          release];
+  [self->zip            release];
+  [self->country        release];
+  [self->phone          release];
+  [self->wantIcalNews   release];
+  [self->wantSkyrixNews release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setLogin:(NSString *)_value {
+  ASSIGN(self->login, _value);
+}
+- (NSString *)login {
+  return self->login;
+}
+
+- (void)setFirstName:(NSString *)_value {
+  ASSIGN(self->firstName, _value);
+}
+- (NSString *)firstName {
+  return self->firstName;
+}
+
+- (void)setLastName:(NSString *)_value {
+  ASSIGN(self->lastName, _value);
+}
+- (NSString *)lastName {
+  return self->lastName;
+}
+
+- (void)setEmail:(NSString *)_value {
+  ASSIGN(self->email, _value);
+}
+- (NSString *)email {
+  return self->email;
+}
+
+- (void)setAddress:(NSString *)_value {
+  ASSIGN(self->address, _value);
+}
+- (NSString *)address {
+  return self->address;
+}
+
+- (void)setCity:(NSString *)_value {
+  ASSIGN(self->city, _value);
+}
+- (NSString *)city {
+  return self->city;
+}
+
+- (void)setState:(NSString *)_value {
+  ASSIGN(self->state, _value);
+}
+- (NSString *)state {
+  return self->state;
+}
+
+- (void)setZip:(NSString *)_value {
+  ASSIGN(self->zip, _value);
+}
+- (NSString *)zip {
+  return self->zip;
+}
+
+- (void)setCountry:(NSString *)_value {
+  ASSIGN(self->country, _value);
+}
+- (NSString *)country {
+  return self->country;
+}
+
+- (void)setPhone:(NSString *)_value {
+  ASSIGN(self->phone, _value);
+}
+- (NSString *)phone {
+  return self->phone;
+}
+
+- (void)setWantIcalNews:(NSString *)_value {
+  ASSIGN(self->wantIcalNews, _value);
+}
+- (NSString *)wantIcalNews {
+  return self->wantIcalNews;
+}
+
+- (void)setWantSkyrixNews:(NSString *)_value {
+  ASSIGN(self->wantSkyrixNews, _value);
+}
+- (NSString *)wantSkyrixNews {
+  return self->wantSkyrixNews;
+}
+
+- (void)markLoginWrong {
+  self->loginOK = NO;
+}
+- (BOOL)loginWrong {
+  return !self->loginOK;
+}
+- (void)markLoginUsed {
+  self->loginAvailable = NO;
+}
+- (BOOL)loginUsed {
+  return !self->loginAvailable;
+}
+- (void)markPwdWrong {
+  self->pwdOK = NO;
+}
+- (BOOL)pwdWrong {
+  return !self->pwdOK;
+}
+- (void)markFirstNameWrong {
+  self->firstNameOK = NO;
+}
+- (BOOL)firstNameWrong {
+  return !self->firstNameOK;
+}
+- (void)markLastNameWrong {
+  self->lastNameOK = NO;
+}
+- (BOOL)lastNameWrong {
+  return !self->lastNameOK;
+}
+- (void)markEmailWrong {
+  self->emailOK = NO;
+}
+- (BOOL)emailWrong {
+  return !self->emailOK;
+}
+
+/* actions */
+
+- (void)validate {
+  // login: 4 to 16
+  // pwd:   6 to 20
+}
+
+- (BOOL)isSessionProtectedPage {
+  return NO;
+}
+
+- (id)run {
+  return self;
+}
+
+@end /* iCalPortalRegistrationPage */
+
+#include "iCalPortalUser.h"
+#include "iCalPortalDatabase.h"
+
+@implementation iCalPortalRegistrationAction
+
+- (NSMutableDictionary *)collectFormValues {
+  static NSString *keys[] = {
+    /* do not add passwords here !! */
+    @"login",
+    @"firstName",
+    @"lastName",
+    @"email",
+    @"address",
+    @"city",
+    @"state",
+    @"zip",
+    @"country",
+    @"phone",
+    @"wantIcalNews",
+    @"wantSkyrixNews",
+    nil
+  };
+  NSMutableDictionary *md;
+  WORequest *rq;
+  NSString  *key;
+  unsigned  i;
+  
+  md = [NSMutableDictionary dictionaryWithCapacity:16];
+  rq = [self request];
+  
+  for (i = 0; (key = keys[i]) != nil; i++) {
+    NSString *val;
+    
+    val = [rq formValueForKey:key];
+    if ([val isNotNull])
+      [md setObject:val forKey:key];
+  }
+  
+  return md;
+}
+
+- (id)saveProfile {
+  iCalPortalRegistrationPage *page;
+  iCalPortalDatabase  *db;
+  NSMutableDictionary *values;
+  NSString            *tmp;
+  BOOL loginOK        = YES;
+  BOOL loginAvailable = YES;
+  BOOL pwdOK          = YES;
+  BOOL firstNameOK    = YES;
+  BOOL lastNameOK     = YES;
+  BOOL emailOK        = YES;
+  
+  if ((db = [(id)[WOApplication application] database]) == nil)
+    return nil;
+  
+  values = [self collectFormValues];
+  
+  /* validate login */
+  
+  tmp = [values objectForKey:@"login"];
+  if ((loginOK = [db isLoginNameValid:tmp]))
+    loginAvailable = [db isLoginNameUsed:tmp] ? NO : YES;
+  
+  /* validate password */
+  
+  tmp = [[self request] formValueForKey:@"pwd1"];
+  if ((pwdOK = [db isPasswordValid:tmp])) {
+    NSString *tmp2;
+    
+    if ((tmp2 = [[self request] formValueForKey:@"pwd2"])) {
+      if (![tmp2 isEqualToString:tmp])
+       pwdOK = NO;
+    }
+    else
+      pwdOK = NO;
+  }
+  
+  /* validate names */
+  
+  tmp = [values objectForKey:@"firstName"];
+  if ([tmp length] < 3) firstNameOK = NO;
+  tmp = [values objectForKey:@"lastName"];
+  if ([tmp length] < 3) lastNameOK = NO;
+
+  /* validate email */
+  
+  emailOK = [[values objectForKey:@"email"] isValidEmailAddress];
+  
+  /* process */
+  
+  if (loginOK&&loginAvailable&&pwdOK&&firstNameOK&&lastNameOK&&emailOK) {
+    iCalPortalUser *user = nil;
+    NSString *pwd = nil, *login = nil;
+    
+    pwd = [[self request] formValueForKey:@"pwd1"];
+    
+    login = [values objectForKey:@"login"];
+    
+    if ([db createUser:login info:values password:pwd]) {
+      [self logWithFormat:@"did create account: %@ ...", login];
+      
+      user = [db userWithName:[values objectForKey:@"login"] password:pwd];
+      if (user == nil) {
+       [self logWithFormat:@"login of created account failed ?! (user=%@)",
+               user];
+      }
+      else {
+       [[self session] setObject:user forKey:@"user"];
+       return [[self pageWithName:@"iCalPortalHomePage"] performPage];
+      }
+    }
+    else {
+      [self logWithFormat:@"failed to create account: %@ ...", user];
+    }
+  }
+  
+  page = [self pageWithName:@"iCalPortalRegistrationPage"];
+  
+  [page takeValuesFromDictionary:values];
+  
+  if (!loginOK)        [page markLoginWrong];
+  if (!loginAvailable) [page markLoginUsed];
+  if (!pwdOK)          [page markPwdWrong];
+  if (!firstNameOK)    [page markFirstNameWrong];
+  if (!lastNameOK)     [page markLastNameWrong];
+  if (!emailOK)        [page markEmailWrong];
+  
+  return [page performPage];
+}
+
+- (id)saveProfileAction {
+  if ([[[self request] formValueForKey:@"action"] isEqualToString:@"save"])
+    return [self saveProfile];
+  
+  return [self indexPage];
+}
+
+@end /* iCalPortalRegistrationAction */
+
+@implementation NSString(EmailAddress)
+
+- (BOOL)isValidEmailAddress {
+  BOOL emailOK;
+  
+  if ([self length] < 3) 
+    return NO;
+  
+  {
+    static NSString *forbiddenOnes[] = {
+      @"steve@apple.com",
+      @"jobs@apple.com",
+      @"steve.jobs@apple.com",
+      @"bill@microsoft",
+      @"gates@microsoft",
+      @"bill.gates@microsoft",
+      nil
+    };
+    NSString *tmp;
+    unsigned i;
+    NSRange  r;
+    
+    for (i = 0; (tmp = forbiddenOnes[i]) != nil; i++) {
+      if ([self rangeOfString:tmp].length > 0) {
+       [self logWithFormat:@"someone tried '%@' ...", tmp];
+       return NO;
+      }
+    }
+    
+    tmp = self;
+    
+    r = [tmp rangeOfString:@"@"];
+    if (r.length == 0)
+      emailOK = NO;
+    else if (r.location < 2) 
+      emailOK = NO;
+    else {
+      tmp = [tmp substringFromIndex:(r.location + r.length)];
+      r = [tmp rangeOfString:@"."];
+      if (r.length == 0)
+       emailOK = NO;
+      else if (r.location == 0)
+       emailOK = NO;
+      else {
+       tmp = [tmp substringFromIndex:(r.location + r.length)];
+       emailOK = [tmp length] > 1;
+      }
+    }
+  }
+  return emailOK;
+}
+
+@end /* NSString(EmailAddress) */
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalRegistrationPage.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalRegistrationPage.wox
new file mode 100644 (file)
index 0000000..4f35a65
--- /dev/null
@@ -0,0 +1,183 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalBaseFrame' 
+              title='name' 
+              const:showHeader="1"
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+  <br />
+  <form directActionName="saveProfile" 
+       actionClass="iCalPortalRegistrationAction">
+<center>
+   <var:component className="iCalPortalBox" const:title="Create Account">
+    <table border="0" width="500">
+      <tr>
+       <td align="right">
+         <var:if condition="loginWrong"><font color="red">FIX:</font></var:if>
+         
+         <var:string value="label.login"/>:
+       </td>
+       <td><input name="login" var:value="login" size="16"/>
+         <var:if condition="loginUsed"><font color="red">already used</font></var:if>
+       </td>
+       <td width="50%"><small>(4 to 16 characters)</small></td>
+      </tr>
+      
+      <tr>
+       <td align="right">
+         <var:if condition="pwdWrong"><font color="red">FIX:</font></var:if>
+         <var:string value="label.password"/>:
+       </td>
+       <td><input type="password" name="pwd1" var:value="password" size="16"/></td>
+       <td><small>(6 to 16 characters)</small></td>
+      </tr>
+      <tr>
+       <td align="right"><nobr><var:string value="label.password2"/>:</nobr></td>
+       <td><input type="password" name="pwd2" var:value="password" size="16"/></td>
+       <td><small>(enter the same as above)</small></td>
+      </tr>
+      
+      <tr><td colspan="3"><hr/></td></tr>
+      
+      <tr>
+       <td align="right"><nobr>
+         <var:if condition="firstNameWrong"><font color="red">FIX:</font></var:if>
+         <var:string value="label.firstName"/>:</nobr>
+       </td>
+       <td><input name="firstName" var:value="firstName" size="32"/></td>
+       <td><small>(required)</small></td>
+      </tr>
+      
+      <tr>
+       <td align="right"><nobr>
+         <var:if condition="lastNameWrong"><font color="red">FIX:</font></var:if>
+         <var:string value="label.lastName"/>:</nobr>
+       </td>
+       <td><input name="lastName" var:value="lastName" size="32"/></td>
+       <td><small>(required)</small></td>
+      </tr>
+      
+      <tr>
+       <td align="right">
+         <var:if condition="emailOK"><font color="red">FIX:</font></var:if>
+         <var:string value="label.email"/>:
+       </td>
+       <td><input name="email" var:value="email" size="32"/></td>
+       <td><small>(required)</small></td>
+      </tr>
+      
+      <tr>
+       <td align="right"><i><var:string value="label.address"/>:</i></td>
+       <td><input name="address" var:value="address" size="32"/></td>
+      </tr>
+      <tr>
+       <td align="right"><i><var:string value="label.city"/>:</i></td>
+       <td><input name="city" var:value="city" size="32"/></td>
+      </tr>
+      <tr>
+       <td align="right"><i><var:string value="label.state"/>:</i></td>
+       <td>
+          <select name="state">
+            <option value="other" selected="selected">-other-</option>
+            
+            <option value="Alabama"       >Alabama</option>
+            <option value="Alaska"        >Alaska</option>
+            <option value="Arizona"       >Arizona</option>
+            <option value="Arkansas"      >Arkansas</option>
+            <option value="California"    >California</option>
+            <option value="Colorado"      >Colorado</option>
+            <option value="Connecticut"   >Connecticut</option>
+            <option value="Delaware"      >Delaware</option>
+            <option value="Florida"       >Florida</option>
+            <option value="Georgia"       >Georgia</option>
+            <option value="Hawaii"        >Hawaii</option>
+            <option value="Idaho"         >Idaho</option>
+            <option value="Illinois"      >Illinois</option>
+            <option value="Indiana"       >Indiana</option>
+            <option value="Iowa"          >Iowa</option>
+            <option value="Kansas"        >Kansas</option>
+            <option value="Kentucky"      >Kentucky</option>
+            <option value="Louisiana"     >Louisiana</option>
+            <option value="Maine"         >Maine</option>
+            <option value="Maryland"      >Maryland</option>
+            <option value="Massachusetts" >Massachusetts</option>
+            <option value="Michigan"      >Michigan</option>
+            <option value="Minnesota"     >Minnesota</option>
+            <option value="Mississippi"   >Mississippi</option>
+            <option value="Missouri"      >Missouri</option>
+            <option value="Montana"       >Montana</option>
+            <option value="Nebraska"      >Nebraska</option>
+            <option value="Nevada"        >Nevada</option>
+            <option value="New Hampshire" >New Hampshire</option>
+            <option value="New Jersey"    >New Jersey</option>
+            <option value="New Mexico"    >New Mexico</option>
+            <option value="New York"      >New York</option>
+            <option value="North Carolina">North Carolina</option>
+            <option value="North Dakota"  >North Dakota</option>
+            <option value="Ohio"          >Ohio</option>
+            <option value="Oklahoma"      >Oklahoma</option>
+            <option value="Oregon"        >Oregon</option>
+            <option value="Pennsylvania"  >Pennsylvania</option>
+            <option value="Rhode Island"  >Rhode Island</option>
+            <option value="South Carolina">South Carolina</option>
+            <option value="South Dakota"  >South Dakota</option>
+            <option value="Tennessee"     >Tennessee</option>
+            <option value="Texas"         >Texas</option>
+            <option value="Utah"          >Utah</option>
+            <option value="Vermont"       >Vermont</option>
+            <option value="Virginia"      >Virginia</option>
+            <option value="Washington"    >Washington</option>
+            <option value="West Virginia" >West Virginia</option>
+            <option value="Wisconsin"     >Wisconsin</option>
+            <option value="Wyoming"       >Wyoming</option>
+          </select>
+        </td>
+      </tr>
+      <tr>
+       <td align="right"><i><var:string value="label.zip"/>:</i></td>
+       <td><input name="zip" var:value="zip" size="32"/></td>
+      </tr>
+      <tr>
+       <td align="right"><i><var:string value="label.country"/>:</i></td>
+       <td><input name="country" var:value="country" size="32"/></td>
+      </tr>
+      <tr>
+       <td align="right"><i><var:string value="label.phone"/>:</i></td>
+       <td><input name="phone" var:value="phone" size="32"/></td>
+      </tr>
+      
+      <tr><td colspan="3"><hr/></td></tr>
+
+      <tr>
+        <td></td>
+        <td colspan="2">
+         <input type="checkbox" name="wantIcalNews" value="1" 
+                checked="YES"/>
+         <small><var:string value="label.wantIcalNews"/></small>
+       </td>
+      </tr>
+      <tr>
+        <td></td>
+        <td colspan="2">
+         <input type="checkbox" name="wantSkyrixNews" value="1" 
+                checked="YES"/>
+         <small><var:string value="label.wantSkyrixNews"/></small>
+       </td>
+      </tr>
+      
+      <tr><td colspan="3"><hr/></td></tr>
+      
+      <tr>
+        <td></td>
+        <td>
+         <input type="submit" value="save"   name="action"/>
+         <input type="submit" value="cancel" name="action"/>
+       </td>
+      </tr>
+    </table>
+   </var:component>
+  </center>  
+  </form>
+  <br/>
+</var:component>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalRightMenu.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalRightMenu.m
new file mode 100644 (file)
index 0000000..f71a8ff
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WODirectAction.h>
+
+@interface iCalPortalRightMenu : WOComponent
+{
+}
+
+@end
+
+@interface iCalPortalRightMenuAction : WODirectAction
+@end
+
+#include "common.h"
+
+@implementation iCalPortalRightMenu
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* accessors */
+
+/* actions */
+
+@end /* iCalPortalRightMenu */
+
+@implementation iCalPortalRightMenuAction
+@end /* iCalPortalRightMenuAction */
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalRightMenu.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalRightMenu.wox
new file mode 100644 (file)
index 0000000..1095159
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version='1.0' standalone='yes'?>
+
+<span xmlns='http://www.w3.org/1999/xhtml'
+      xmlns:var='http://www.skyrix.com/od/binding'
+      xmlns:const='http://www.skyrix.com/od/constant'>
+
+  <font class="default">
+    right sidebar
+  </font>
+</span>
+
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalToDoView.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalToDoView.m
new file mode 100644 (file)
index 0000000..adf4b4e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalView.h"
+#include <NGObjWeb/WODirectAction.h>
+
+@interface iCalPortalToDoView : iCalView
+{
+}
+
+@end
+
+#include "common.h"
+
+@implementation iCalPortalToDoView
+
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* datasource */
+
+- (NSString *)entityName {
+  return @"vtodo";
+}
+
+/* accessors */
+
+/* actions */
+
+@end /* iCalPortalToDoView */
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalToDoView.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalToDoView.wox
new file mode 100644 (file)
index 0000000..874172c
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalFrame' title='localizedTitle'
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+
+  <var:component className="iCalPortalCalTabs" const:selection="todo"
+                calendarName="calendarName">
+
+    <table border="0" width="100%">
+      <tr bgcolor="#aaaaaa">
+        <th align="left">summary</th>
+        <th align="left">startdate</th>
+        <th align="left">duedate</th>
+        <th align="left">priority</th>
+      </tr>
+      
+      <var:foreach list="dataSource.fetchObjects" item="item">
+       <tr>
+         <td><a directActionName="showJob" var:_uid="uid"
+                var:_calendarName="calendarName"
+               ><var:string value="item.summary"/></a></td>
+         <td><var:string value="item.startDate"
+                         const:dateformat="%Y-%m-%d"/></td>
+         <td><var:string value="item.due" const:dateformat="%Y-%m-%d"/></td>
+         <td><var:string value="item.priority"/></td>
+       </tr>
+      </var:foreach>
+    </table>
+
+  </var:component>
+</var:component>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalWeekOverview.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalWeekOverview.m
new file mode 100644 (file)
index 0000000..068f261
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalWeekView.h"
+
+@interface iCalPortalWeekOverview : iCalWeekView
+{
+}
+
+@end
+
+#include "common.h"
+
+@implementation iCalPortalWeekOverview
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+@end /* iCalPortalWeekOverview */
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalWeekOverview.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalWeekOverview.wox
new file mode 100644 (file)
index 0000000..76540d6
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalFrame' 
+              title='localizedTitle'
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+
+ <var:component className="iCalPortalCalTabs" const:selection="week"
+                calendarName="calendarName">
+  <var:week-overview list="dataSource.fetchObjects" item="item" 
+                    weekStart="weekStart"
+                     const:titleColor="#FFDAAA" const:contentColor="#FAE8B8"
+                     headerRows="abList" footerRows="cdList"
+                     headerRow="item"    footerRow="item"
+                     columnIndex="colIndex" const:width="100%">
+    
+    <!-- var:week-info><font class="default">all day</font></var:week-info -->
+    
+    <var:week>
+      <font class="default">
+        <b><var:string value="item.summary"/></b><br/>
+        <var:string value="item.startDate" const:dateformat="%H:%M"/><br/>
+      </font>
+    </var:week>
+
+    <var:week-header>
+      Row:<var:string value="item"/><br />
+      Column:<var:string value="colIndex"/>
+    </var:week-header>
+
+    <var:week-footer>
+      Row:<var:string value="item"/><br />
+      Column:<var:string value="colIndex"/>
+    </var:week-footer>
+  </var:week-overview>
+ </var:component>
+</var:component>
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalWelcomePage.m b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalWelcomePage.m
new file mode 100644 (file)
index 0000000..cd02212
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WODirectAction.h>
+
+@interface iCalPortalWelcomePage : WOComponent
+{
+}
+
+@end
+
+@interface iCalPortalWelcomeAction : WODirectAction
+@end
+
+#include "iCalPortalUser.h"
+#include "iCalPortalDatabase.h"
+#include "common.h"
+
+@implementation iCalPortalWelcomePage
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* accessors */
+
+/* actions */
+
+- (BOOL)isSessionProtectedPage {
+  return NO;
+}
+
+- (id)run {
+  return self;
+}
+- (id)performPage {
+  return [self run];
+}
+
+@end /* iCalPortalWelcomePage */
+
+@implementation iCalPortalWelcomeAction
+
+- (BOOL)redirectOnLogin {
+  return NO;
+}
+
+- (id)loginAction {
+  NSString           *login, *pwd;
+  iCalPortalDatabase *db;
+  iCalPortalUser     *user;
+  
+  db = [(id)[WOApplication application] database];
+  
+  login = [[self request] formValueForKey:@"user"];
+  pwd   = [[self request] formValueForKey:@"pwd"];
+  
+  if (![db isLoginNameValid:login]) {
+    [self logWithFormat:@"tried an invalid login: '%@'", login];
+    return [self indexPage];
+  }
+  
+  if ((user = [db userWithName:login password:pwd]) == nil) {
+    [self logWithFormat:@"login failed: '%@'", login];
+    return [self indexPage];
+  }
+  
+  [self logWithFormat:@"user %@ is logged in.", login];
+  [[self session] setObject:user forKey:@"user"];
+  
+  /* check language */
+  {
+    NSString *lang;
+    
+    if ((lang = [[self request] formValueForKey:@"language"])) {
+      NSMutableArray *langs;
+
+      if ([lang isEqualToString:@"en"])
+       lang = @"English";
+      else if ([lang isEqualToString:@"de"])
+       lang = @"German";
+      
+      langs = [NSMutableArray arrayWithCapacity:16];
+      [langs addObject:lang];
+      [langs addObject:[[self session] languages]];
+      [[self session] setLanguages:langs];
+    }
+  }
+  
+  /* deliver login result */
+  
+  if ([self redirectOnLogin]) {
+    /* make a redirect on login (better for deployment) ... */
+    WOResponse   *r;
+    NSString     *homeURL;
+    NSDictionary *qd;
+
+    qd = [NSDictionary dictionaryWithObject:[[self session] sessionID]
+                      forKey:WORequestValueSessionID];
+    
+    homeURL = [[[WOApplication application] context] 
+                              directActionURLForActionNamed:@"home"
+                              queryDictionary:qd];
+    
+    r = [WOResponse responseWithRequest:[self request]];
+    [r setStatus:302];
+    [r setHeader:homeURL forKey:@"location"];
+    return r;
+  }
+  else {
+    /* better for development */
+    return [[self pageWithName:@"iCalPortalHomePage"] performPage];
+  }
+}
+
+@end /* iCalPortalWelcomeAction */
diff --git a/skyrix-sope/samples/iCalPortal/Pages/iCalPortalWelcomePage.wox b/skyrix-sope/samples/iCalPortal/Pages/iCalPortalWelcomePage.wox
new file mode 100644 (file)
index 0000000..2fcc806
--- /dev/null
@@ -0,0 +1,118 @@
+<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalBaseFrame' title='localizedTitle'
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+
+<div align="center">
+  <table border="0" cellpadding="0" cellspacing="0">
+    <tr>
+      <td align="center"><img 
+       border="0" filename="small.gif" width="1" height="30" /></td>
+      <td align="center"><img
+        border="0" filename="free_hosting.gif" width="622" height="30" /></td>
+      <td align="center"><img
+        border="0" filename="small.gif" width="1" height="30" /></td>
+    </tr>
+    <tr>
+      <td align="center"
+        background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img 
+       border="0" filename="pixel.gif" width="1" height="1" /></td>
+      <td align="center"><img 
+       border="0" filename="wp_info.gif" width="622" height="50" /></td>
+      <td align="center" 
+       background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+        border="0" filename="pixel.gif" width="1" height="1" /></td>
+    </tr>
+
+    <!-- create account -->
+    <tr>
+      <td align="center"
+        background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+        border="0" filename="pixel.gif" width="1" height="1" /></td>
+      <td align="center"><a directActionName="showLicense"><img
+        border="0" filename="wp_create.gif" width="622" height="50" /></a></td>
+      <td align="center" 
+       background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+        border="0" filename="pixel.gif" width="1" height="1" /></td>
+    </tr>
+
+    <!-- config -->
+    <tr>
+      <td align="center" 
+       background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img 
+       border="0" filename="pixel.gif" width="1" height="1" /></td>
+      <td align="center"><img
+        border="0" filename="wp_config.gif" width="622" height="50" /></td>
+      <td align="center" 
+       background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+        border="0" filename="pixel.gif" width="1" height="1" /></td>
+    </tr>
+
+    <!-- FAQ -->
+    <tr>
+      <td align="center"
+        background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+        border="0" filename="pixel.gif" width="1" height="1" /></td>
+      <td align="center"><img 
+       border="0" filename="wp_faq.gif" width="622" height="50" /></td>
+      <td align="center"
+        background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+        border="0" filename="pixel.gif" width="1" height="1" /></td>
+    </tr>
+
+    <!-- feedback -->
+    <tr>
+      <td align="center"
+        background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+        border="0" filename="pixel.gif" width="1" height="1" /></td>
+      <td align="center"><a directActionName="feedback"><img 
+       border="0" filename="wp_feedback.gif" width="622" height="66" /></a></td>
+      <td align="center"
+        background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img 
+       border="0" filename="pixel.gif" width="1" height="1" /></td>
+    </tr>
+
+    <!-- login -->
+    <tr>
+      <td align="center" 
+       background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img 
+       border="0" filename="pixel.gif" width="1" height="1" /></td>
+
+      <td align="right" bgcolor="white" height="200">
+
+        <form directActionName="login" actionClass="iCalPortalWelcomeAction">
+           <table width="200" border="0" cellspacing="0" cellpadding="3">
+             <tr> 
+               <td><font face="Arial,Helvetica,Verdana,Geneva,Tahoma"><strong>Username</strong></font></td>
+             </tr>
+             <tr> 
+               <td><input name="user" type="text" id="user" size="17" /></td>
+             </tr>
+             <tr> 
+               <td><font face="Arial,Helvetica,Verdana,Geneva,Tahoma"><strong>Password</strong></font></td>
+             </tr>
+             <tr> 
+               <td><input name="pwd" type="password" id="pwd" size="17" /></td>
+             </tr>
+             <tr> 
+               <td><input type="submit" name="login" value="login" /></td>
+             </tr>
+           </table>
+       
+         </form>
+
+      </td>
+      <td align="center"
+        background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img
+        border="0" filename="pixel.gif" width="1" height="1" /></td>
+    </tr>
+    <tr>
+      <td align="center" background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img border="0" filename="pixel.gif" width="1" height="1" /></td>
+      <td align="center" background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img border="0" filename="pixel.gif" width="622" height="1" /></td>
+      <td align="center" background="/iCalPortal.woa/WebServerResources/English.lproj/pixel.gif"><img border="0" filename="pixel.gif" width="1" height="1" /></td>
+    </tr>
+  </table>
+</div>
+</var:component>
diff --git a/skyrix-sope/samples/iCalPortal/README b/skyrix-sope/samples/iCalPortal/README
new file mode 100644 (file)
index 0000000..37e3e50
--- /dev/null
@@ -0,0 +1,41 @@
+# $Id$
+
+iCalPortal
+==========
+
+A small application for hosting iCalendar files.
+
+- this is far from complete! (but has nice graphics ;-)
+
+Installation
+============
+
+Please ensure that a SAX reader bundle for iCalendar files is installed
+(in Library/SaxDrivers/, eg iCalSaxDriver.sax).
+
+
+TODO
+====
+
+- rewrite DAV part to use SOPE WebDAV
+- rewrite iCalPublishAction not to use -httpRequest, use WOSimpleHTTPParser
+  for iCalPortal if possible
+- no navigation in scheduler views!
+
+
+Defaults
+========
+
+DevMode        - YES|NO        - Development mode, do not redirect to static homepages
+
+
+Apache Config
+=============
+
+<LocationMatch "^/iCalPortal/*">
+SetHandler ngobjweb-adaptor
+SetAppPort 29022
+</LocationMatch>
+
+Alias /iCalPortal.woa/WebServerResources/ \
+  /home/helge/dev/OGo/helge/iCalPortal/iCalPortal.woa/WebServerResources/
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/.cvsignore b/skyrix-sope/samples/iCalPortal/WebDAV/.cvsignore
new file mode 100644 (file)
index 0000000..52c916d
--- /dev/null
@@ -0,0 +1 @@
+Resources
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/GNUmakefile b/skyrix-sope/samples/iCalPortal/WebDAV/GNUmakefile
new file mode 100644 (file)
index 0000000..01572b7
--- /dev/null
@@ -0,0 +1,21 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = DAV
+
+DAV_OBJC_FILES = \
+       iCalRequestHandler.m            \
+       iCalAction.m                    \
+       \
+       iCalPublishAction.m             \
+       iCalGetAction.m                 \
+       iCalDeleteAction.m              \
+       iCalOptionsAction.m             \
+       iCalLockAction.m                \
+
+ADDITIONAL_INCLUDE_DIRS += -I. -I..
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalAction.h b/skyrix-sope/samples/iCalPortal/WebDAV/iCalAction.h
new file mode 100644 (file)
index 0000000..4703958
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalAction_H__
+#define __iCalPortal_iCalAction_H__
+
+#import <Foundation/NSObject.h>
+
+@class WOContext, WORequest, WOResponse;
+@class iCalPortalUser, iCalPortalDatabase;
+
+@interface iCalAction : NSObject
+{
+  WOContext *ctx;
+}
+
+- (id)initWithContext:(WOContext *)_ctx;
+
+/* accessors */
+
+- (WOContext *)context;
+- (WORequest *)request;
+- (id)application;
+
+- (NSString *)requestUser;
+- (NSString *)requestCalendarPath;
+
+/* operation */
+
+- (WOResponse *)run;
+
+/* auth */
+
+- (NSString *)credentials;
+- (iCalPortalDatabase *)database;
+- (iCalPortalUser *)user;
+
+- (WOResponse *)missingAuthResponse;
+- (WOResponse *)accessDeniedResponse;
+- (WOResponse *)notFoundResponse;
+
+@end
+
+@interface iCalFakeAction : iCalAction
+{
+  int code;
+}
+
+- (id)initWithContext:(WOContext *)_ctx code:(int)_status;
+
+@end
+
+#endif /* __iCalPortal_iCalAction_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalAction.m b/skyrix-sope/samples/iCalPortal/WebDAV/iCalAction.m
new file mode 100644 (file)
index 0000000..9ef08de
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalAction.h"
+#include "iCalPortalDatabase.h"
+#include "iCalPortalUser.h"
+#include "common.h"
+
+@implementation iCalAction
+
+- (id)initWithContext:(WOContext *)_ctx {
+  self->ctx = [_ctx retain];
+  return self;
+}
+- (void)dealloc {
+  [self->ctx release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (WOContext *)context {
+  return self->ctx;
+}
+- (WORequest *)request {
+  return [self->ctx request];
+}
+- (id)application {
+  return [WOApplication application];
+}
+
+- (NSString *)requestUser {
+  NSRange  r;
+  NSString *s;
+  
+  s = [[self request] requestHandlerPath];
+  r = [s rangeOfString:@"/"];
+  if (r.length == 0) return nil;
+  return [s substringToIndex:r.location];
+}
+- (NSString *)requestCalendarPath {
+  NSRange  r;
+  NSString *s;
+  
+  s = [[self request] requestHandlerPath];
+  r = [s rangeOfString:@"/"];
+  if (r.length == 0) return nil;
+  return [s substringFromIndex:(r.location + 1)];
+}
+
+/* operation */
+
+- (WOResponse *)run {
+  return nil;
+}
+
+- (NSString *)credentials {
+  WORequest *rq;
+  id        creds;
+  NSRange   r;
+  
+  if ((rq = [self->ctx request]) == nil)
+    return nil;
+  if ((creds = [rq headerForKey:@"authorization"]) == nil)
+    return nil;
+  
+  r = [creds rangeOfString:@" " options:NSBackwardsSearch];
+  if (r.length == 0) {
+    [self logWithFormat:@"invalid 'authorization' header: '%@'", creds];
+    return nil;
+  }
+  return [creds substringFromIndex:(r.location + r.length)];
+}
+
+- (NSString *)credentialsLogin {
+  id creds;
+
+  creds = [creds stringByDecodingBase64];
+  creds = [creds componentsSeparatedByString:@":"];
+  if ([creds count] < 2) {
+    [self logWithFormat:@"invalid credentials"];
+    return nil;
+  }
+  
+  return [creds objectAtIndex:0];
+}
+
+- (iCalPortalDatabase *)database {
+  return [(id)[WOApplication application] database];
+}
+
+- (iCalPortalUser *)user {
+  iCalPortalDatabase *db;
+  iCalPortalUser *user;
+  id       creds;
+  NSString *login, *pwd;
+  
+  if ((db = [self database]) == nil)
+    return nil;
+  
+  if ((creds = [self credentials]) == nil)
+    return nil;
+  
+  /* assuming basic authentication ... */
+  creds = [creds stringByDecodingBase64];
+  creds = [creds componentsSeparatedByString:@":"];
+  if ([creds count] < 2) {
+    [self logWithFormat:@"invalid credentials"];
+    return nil;
+  }
+  
+  login = [creds objectAtIndex:0];
+  pwd   = [creds objectAtIndex:1];
+  
+  user = [db userWithName:login password:pwd];
+  
+  return user;
+}
+
+- (NSString *)authRealm {
+  WOApplication *app = [self application];
+  return [app name];
+}
+
+- (WOResponse *)missingAuthResponse {
+  WOResponse *resp;
+  NSString *auth;
+
+  auth = [NSString stringWithFormat:@"Basic realm=\"%@\"",[self authRealm]];
+  
+  resp = [(WOResponse *)[WOResponse alloc] initWithRequest:[self request]];
+  [resp setStatus:401 /* unauthorized */];
+  [resp setHeader:auth forKey:@"www-authenticate"];
+  //[resp setHeader:@"close" forKey:@"connection"];
+  [resp setHeader:@"text/html; charset=iso-8859-1" forKey:@"content-type"];
+  [resp appendContentString:
+    @"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">"
+    @"<HTML><HEAD>"
+    @"<TITLE>401 Authorization Required</TITLE>"
+    @"</HEAD><BODY>"
+    @"<H1>Authorization Required</H1>"
+    @"<ADDRESS>Apache/1.3.26 Server at dogbert Port 9000</ADDRESS>"
+    @"</BODY></HTML>"
+   ];
+  
+  return AUTORELEASE(resp);
+}
+
+- (WOResponse *)accessDeniedResponse {
+  WOResponse *resp;
+  NSString *auth;
+  
+  auth = [NSString stringWithFormat:@"Basic realm=\"%@\"",[self authRealm]];
+  
+  [self logWithFormat:@"access was denied"];
+  
+  resp = [(WOResponse *)[WOResponse alloc] initWithRequest:[self request]];
+  [resp setStatus:403 /* forbidden */];
+  [resp setHeader:auth forKey:@"www-authenticate"];
+  return [resp autorelease];
+}
+
+- (WOResponse *)notFoundResponse {
+  WOResponse *resp;
+  
+  resp = [(WOResponse *)[WOResponse alloc] initWithRequest:[self request]];
+  [resp setStatus:404 /* not found */];
+  return [resp autorelease];
+}
+
+@end /* iCalAction */
+
+@implementation iCalFakeAction
+
+- (id)initWithContext:(WOContext *)_ctx code:(int)_status {
+  if ((self = [super initWithContext:_ctx])) {
+    self->code = _status;
+  }
+  return self;
+}
+
+- (id)initWithContext:(WOContext *)_ctx {
+  return [self initWithContext:_ctx code:200];
+}
+
+- (WOResponse *)run {
+  WOResponse *r;
+  
+  r = [WOResponse responseWithRequest:[self request]];
+  [r setStatus:self->code];
+  
+  [r setHeader:@"close" forKey:@"connection"];
+  [r setHeader:@"text/plain; charset=iso-8859-1" forKey:@"content-type"];
+  
+  [r appendContentString:@"operation executed\r\n"];
+  
+  return r;
+}
+
+@end /* iCalFakeAction */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalDeleteAction.h b/skyrix-sope/samples/iCalPortal/WebDAV/iCalDeleteAction.h
new file mode 100644 (file)
index 0000000..04b4bbd
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalDeleteAction_H__
+#define __iCalPortal_iCalDeleteAction_H__
+
+#include "iCalAction.h"
+
+@interface iCalDeleteAction : iCalAction
+{
+}
+
+@end
+
+#endif /* __iCalPortal_iCalDeleteAction_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalDeleteAction.m b/skyrix-sope/samples/iCalPortal/WebDAV/iCalDeleteAction.m
new file mode 100644 (file)
index 0000000..a9f2633
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalDeleteAction.h"
+#include "iCalPortalUser.h"
+#include "common.h"
+
+@implementation iCalDeleteAction
+
+- (WOResponse *)run {
+  iCalPortalUser *user;
+  WOResponse  *r;
+  NSException *e;
+  
+  if ((user = [self user]) == nil) {
+    return nil;
+  }
+  
+  [self logWithFormat:@"delete a calendar of user: %@", user];
+  [self logWithFormat:@"  url of:   %@", [self requestUser]];
+  [self logWithFormat:@"  calendar: %@", [self requestCalendarPath]];
+  
+  r = [WOResponse responseWithRequest:[self request]];
+  
+  if ((e = [user deleteCalendarWithPath:[self requestCalendarPath]])) {
+    /* failed */
+    [self logWithFormat:@"calendar deletion failed: %@", e];
+    
+    [r setStatus:500 /* server error */];
+    [r appendContentString:@"<h3>calendar deletion failed !</h3>"];
+    [r appendContentHTMLString:[e description]];
+  }
+  else {
+    [r setStatus:204 /* no content */];
+    [r appendContentString:@"the calendar has been deleted ..."];
+  }
+  
+  return r;
+}
+
+@end /* iCalDeleteAction */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalGetAction.h b/skyrix-sope/samples/iCalPortal/WebDAV/iCalGetAction.h
new file mode 100644 (file)
index 0000000..76ba988
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalGetAction_H__
+#define __iCalPortal_iCalGetAction_H__
+
+#include "iCalAction.h"
+
+@interface iCalGetAction : iCalAction
+{
+}
+
+@end
+
+#endif /* __iCalPortal_iCalGetAction_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalGetAction.m b/skyrix-sope/samples/iCalPortal/WebDAV/iCalGetAction.m
new file mode 100644 (file)
index 0000000..80ffd31
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalGetAction.h"
+#include "iCalPortalCalendar.h"
+#include "iCalPortalUser.h"
+#include "iCalPortalDatabase.h"
+#include "common.h"
+
+@implementation iCalGetAction
+
+- (WOResponse *)run {
+  iCalPortalDatabase *db;
+  iCalPortalUser     *user = nil;
+  iCalPortalUser     *calUser;
+  iCalPortalCalendar *cal;
+  WOResponse         *r;
+  
+  if ((db = [self database]) == nil)
+    return nil;
+  
+  if ((calUser = [db userWithName:[self requestUser]]) == nil) {
+    [self debugWithFormat:@"did not find request user: %@", 
+           [self requestUser]];
+    return [self notFoundResponse];
+  }
+  
+  if ((cal = [calUser calendarAtPath:[self requestCalendarPath]]) == nil) {
+    [self debugWithFormat:@"did not find request cal path: %@", 
+           [self requestUser]];
+    return [self notFoundResponse];
+  }
+  
+  if (![cal isPublic]) {
+    if ((user = [self user]) == nil)
+      return nil;
+
+    /* check access */
+  }
+  
+  r = [WOResponse responseWithRequest:[self request]];
+  
+  [self logWithFormat:@"access calendar as user: %@", user];
+  [self logWithFormat:@"  cal owner: %@", calUser];
+  [self logWithFormat:@"  calendar : %@", cal];
+  
+  [r setStatus:200 /* OK */];
+  [r setHeader:@"text/calendar" forKey:@"content-type"];
+  [r setContent:[cal rawContent]];
+  return r;
+}
+
+@end /* iCalGetAction */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalLockAction.h b/skyrix-sope/samples/iCalPortal/WebDAV/iCalLockAction.h
new file mode 100644 (file)
index 0000000..f8feb80
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalLockAction_H__
+#define __iCalPortal_iCalLockAction_H__
+
+#include "iCalAction.h"
+
+@interface iCalLockAction : iCalAction
+{
+}
+
+@end
+
+#endif /* __iCalPortal_iCalLockAction_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalLockAction.m b/skyrix-sope/samples/iCalPortal/WebDAV/iCalLockAction.m
new file mode 100644 (file)
index 0000000..5c56608
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalLockAction.h"
+#include "common.h"
+
+@implementation iCalLockAction
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+- (WOResponse *)run {
+  WOResponse *r;
+  
+  r = [WOResponse responseWithRequest:[self request]];
+  
+  /*
+    fake a successful locking operationf or M$ publisher (eg OL2002)
+  */
+  {
+    NSString *content = nil;
+    
+    content = @"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+      @"<D:prop xmlns:D=\"DAV:\">\n"
+      @"<D:lockdiscovery>\n"
+      @"<D:activelock>\n"
+      @"<D:locktype><D:write/></D:locktype>\n"
+      @"</D:activelock>\n"
+      @"</D:lockdiscovery>\n"
+      @"</D:prop>\n";
+    [r setContent:[content dataUsingEncoding:NSUTF8StringEncoding]];
+    [r setHeader:@"text/xml; charset=\"utf-8\"" forKey:@"content-type"];
+    [r setHeader:[NSString stringWithFormat:@"%i",[content length]]
+       forKey:@"content-length"];
+    
+    [r setStatus:200];
+  }
+  
+  return r;
+}
+
+@end /* iCalLockAction */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalOptionsAction.h b/skyrix-sope/samples/iCalPortal/WebDAV/iCalOptionsAction.h
new file mode 100644 (file)
index 0000000..dfb63d2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalOptionsAction_H__
+#define __iCalPortal_iCalOptionsAction_H__
+
+#include "iCalAction.h"
+
+@interface iCalOptionsAction : iCalAction
+{
+}
+
+@end
+
+#endif /* __iCalPortal_iCalOptionsAction_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalOptionsAction.m b/skyrix-sope/samples/iCalPortal/WebDAV/iCalOptionsAction.m
new file mode 100644 (file)
index 0000000..8b61744
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalOptionsAction.h"
+#include <NGObjWeb/WEClientCapabilities.h>
+#include "common.h"
+
+@implementation iCalOptionsAction
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+- (WOResponse *)run {
+  WEClientCapabilities *cc;
+  WORequest  *rq;
+  WOResponse *r;
+  NSString   *allow;
+  
+  rq = [self request];
+  cc = [rq clientCapabilities];
+  r  = [WOResponse responseWithRequest:rq];
+  [r setStatus:200];
+  [r setHeader:@"text/plain" forKey:@"content-type"];
+
+  if ([cc isWebFolder])
+    [r setHeader:@"DAV" forKey:@"MS-Author-Via"];
+  
+  /* this is send by Apache */
+  [r setHeader:@"1,2,<http://apache.org/dav/propset/fs/1>" 
+     forKey:@"DAV"];
+  
+  /* now the methods */
+#if FULL_DAV
+  allow =
+    @"OPTIONS, GET, HEAD, POST, DELETE, TRACE, "
+    @"PROPFIND, PROPPATCH, COPY, MOVE, LOCK, UNLOCK, PUT";
+#else
+  allow = @"GET, HEAD, POST, DELETE, PUT";
+#endif
+  
+  [r setHeader:allow forKey:@"allow"];
+  
+  return r;
+}  
+
+@end /* iCalOptionsAction */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalPublishAction.h b/skyrix-sope/samples/iCalPortal/WebDAV/iCalPublishAction.h
new file mode 100644 (file)
index 0000000..7643edb
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalPublishAction_H__
+#define __iCalPortal_iCalPublishAction_H__
+
+#include "iCalAction.h"
+
+@interface iCalPublishAction : iCalAction
+{
+}
+
+@end
+
+#endif /* __iCalPortal_iCalPublishAction_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalPublishAction.m b/skyrix-sope/samples/iCalPortal/WebDAV/iCalPublishAction.m
new file mode 100644 (file)
index 0000000..c6b5125
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPublishAction.h"
+#include "iCalPortalUser.h"
+#include <NGObjWeb/WEClientCapabilities.h>
+#include <NGMime/NGMime.h>
+#include "common.h"
+
+/*
+  Publish Sequence in Outlook 2000 is:
+  a) post an empty request without creds => 401
+  b) post an empty request with creds => 200
+  c) post the full request with (validated) creds
+*/
+
+@implementation iCalPublishAction
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+- (int)maxCalSizeForUser:(iCalPortalUser *)_user {
+  return 200 * 1024; /* 200K for now */
+}
+
+- (WOResponse *)run {
+  WORequest      *rq;
+  iCalPortalUser *user;
+  WOResponse  *r;
+  NSData      *data;
+  NSException *e;
+  int okStatus = 201 /* created */;
+  
+  if ((user = [self user]) == nil) {
+    return nil;
+  }
+
+  rq = [self request];
+  
+  r = [WOResponse responseWithRequest:[self request]];
+  
+  /* check for OL 2000 (which does a "POST" to publish requests) */
+  
+  if ([[rq method] isEqualToString:@"POST"]) {
+    /* could extract file name from content-disposition ... */
+    NGMimeMultipartBody *body;
+    BOOL isEmpty = NO;
+    
+    okStatus = 200; /* override for OL 2K */
+    
+    [self debugWithFormat:@"got a post from: %@",
+           [rq headerForKey:@"user-agent"]];
+    
+    if ((body = [[rq httpRequest] body]) == nil)
+      isEmpty = YES;
+    else if (![body isKindOfClass:[NGMimeMultipartBody class]])
+      /* probably a bit strict ... */
+      isEmpty = YES;
+    else {
+      NSArray *parts;
+
+      if ((parts = [body parts]) == nil)
+       isEmpty = YES;
+      else if ([parts count] == 0)
+       isEmpty = YES;
+      else {
+       NGMimeBodyPart *part;
+       
+       part = [parts objectAtIndex:0];
+       data = [part body];
+      }
+    }
+    
+    if (isEmpty) {
+      [self debugWithFormat:@"but the content was empty, returning 200 !!!"];
+      [r setStatus:200];
+      return r;
+    }
+  }
+  else
+    data = [[self request] content];
+  
+  /* process a "usual" PUT */
+  
+  [self debugWithFormat:@"write calendar of user: %@", user];
+  [self debugWithFormat:@"  url of: %@", [self requestUser]];
+  [self debugWithFormat:@"  cal:    %@", [self requestCalendarPath]];
+  
+  if (data == nil) data = [[[NSData alloc] init] autorelease];
+  
+  if ([data length] > [self maxCalSizeForUser:user]) {
+    [self logWithFormat:@"calendar to be published exceeds maximum size !"];
+    [r setStatus:500];
+  }
+  else if ((e = [user writeICalendarData:data
+                     toCalendar:[self requestCalendarPath]])) {
+    /* failed */
+    [self logWithFormat:@"calendar upload failed: %@", e];
+    
+    [r setStatus:500 /* server error */];
+    [r appendContentString:@"<h3>calendar upload failed !</h3>"];
+    [r appendContentHTMLString:[e description]];
+  }
+  else {
+    WEClientCapabilities *cc;
+    
+    cc = [[self request] clientCapabilities];
+    
+    if ([cc isWebFolder]) {
+      [r setStatus:200 /* OK */];
+    }
+    else {
+      /* 201 is generated by mod_dav, when iCal.app does a PUT */
+      [r setStatus:okStatus];
+      [r appendContentString:@"the calendar has been created ..."];
+    }
+  }
+  
+  return r;
+}
+
+@end /* iCalPublishAction */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalRequestHandler.h b/skyrix-sope/samples/iCalPortal/WebDAV/iCalRequestHandler.h
new file mode 100644 (file)
index 0000000..7932a7e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalRequestHandler_H__
+#define __iCalRequestHandler_H__
+
+#include <NGObjWeb/WORequestHandler.h>
+
+@interface iCalRequestHandler : WORequestHandler
+@end
+
+#endif /* __iCalRequestHandler_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/WebDAV/iCalRequestHandler.m b/skyrix-sope/samples/iCalPortal/WebDAV/iCalRequestHandler.m
new file mode 100644 (file)
index 0000000..4ed7ff9
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalRequestHandler.h"
+#include "iCalPortalUser.h"
+#include "iCalPortalDatabase.h"
+
+#include "iCalAction.h"
+#include "iCalPublishAction.h"
+#include "iCalDeleteAction.h"
+#include "iCalGetAction.h"
+#include "iCalLockAction.h"
+#include "iCalOptionsAction.h"
+
+#include "common.h"
+
+@implementation iCalRequestHandler
+
++ (int)version {
+  return [super version] + 0 /* 2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+
+/*
+  The request handler part of an ical action URI looks like this:
+
+    user-login/calendar-name
+*/
+
+- (BOOL)restoreSessionUsingIDs {
+  return NO;
+}
+- (BOOL)autocreateSessionForRequest:(WORequest *)_request {
+  return NO;
+}
+- (BOOL)requiresSessionForRequest:(WORequest *)_request {
+  return NO;
+}
+
+- (WOResponse *)handleRequest:(WORequest *)_request
+  inContext:(WOContext *)_ctx
+  session:(WOSession *)session
+  application:(WOApplication *)app
+{
+  iCalAction *action;
+  NSString   *userAgent;
+  NSString   *m;
+  id         creds;
+  
+  userAgent = [_request headerForKey:@"user-agent"];
+  m = [[_request method] uppercaseString];
+
+  if ([m isEqualToString:@"GET"])
+    action = [[iCalGetAction alloc] initWithContext:_ctx];
+  else if ([m isEqualToString:@"PUT"])
+    action = [[iCalPublishAction alloc] initWithContext:_ctx];
+  else if ([m isEqualToString:@"POST"])
+    action = [[iCalPublishAction alloc] initWithContext:_ctx];
+  else if ([m isEqualToString:@"DELETE"])
+    action = [[iCalDeleteAction alloc] initWithContext:_ctx];
+  else if ([m isEqualToString:@"LOCK"])
+    action = [[iCalLockAction alloc] initWithContext:_ctx];
+  else if ([m isEqualToString:@"OPTIONS"])
+    action = [[iCalOptionsAction alloc] initWithContext:_ctx];
+  
+  else if ([m isEqualToString:@"MKCOL"]) {
+    action = [[iCalFakeAction alloc] initWithContext:_ctx 
+                                    code:405 /* method not allowed */];
+  }
+  else if ([m isEqualToString:@"PROPFIND"]) {
+    [self debugWithFormat:@"PROPFIND:\n%@\n--------",
+           [_request contentAsString]];
+    action = [[iCalFakeAction alloc] initWithContext:_ctx 
+                                    code:200 /* method not allowed */];
+  }
+  
+  else {
+    [self logWithFormat:@"cannot handle HTTP method: '%@'", m];
+    return nil;
+  }
+  
+  action = [action autorelease];
+  if ((creds = [_request headerForKey:@"authorization"]) == nil)
+    return [action missingAuthResponse];
+  
+  return [action run];
+}
+
+/* logging */
+
+- (NSString *)loggingPrefix {
+  return @"[ical-handler]";
+}
+
+- (BOOL)isDebuggingEnabled {
+  return YES;
+}
+
+@end /* iCalRequestHandler */
diff --git a/skyrix-sope/samples/iCalPortal/common.h b/skyrix-sope/samples/iCalPortal/common.h
new file mode 100644 (file)
index 0000000..19e5262
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+  Copyright (C) 2000-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$
+
+#import <Foundation/Foundation.h>
+
+#include <NGExtensions/NGExtensions.h>
+#include <NGObjWeb/NGObjWeb.h>
diff --git a/skyrix-sope/samples/iCalPortal/db/account.tmpl b/skyrix-sope/samples/iCalPortal/db/account.tmpl
new file mode 100644 (file)
index 0000000..758ae25
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  password  = "blah";
+  firstName = "Donald";
+  lastName  = "Duck";
+  street    = "Am Geldspeicher 2";
+  city      = "Entenhausen";
+  email     = "donald.duck@geldspeicher.com";
+}
diff --git a/skyrix-sope/samples/iCalPortal/db/donald/.account.plist b/skyrix-sope/samples/iCalPortal/db/donald/.account.plist
new file mode 100644 (file)
index 0000000..74d8a36
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    address = "Am Geldspeicher 1";
+    city = "Entenhausen";
+    country = "USA";
+    cryptedPassword = "hukHKVmjiZevg";
+    email = "donald.duck@entenhausen.com";
+    firstName = Donald;
+    lastName = Duck;
+    login = donald;
+    phone = "+49-391-6623-0";
+    state = SA;
+    wantIcalNews = 1;
+    wantSkyrixNews = 1;
+    zip = "39104";
+}
\ No newline at end of file
diff --git a/skyrix-sope/samples/iCalPortal/db/donald/korg.ics b/skyrix-sope/samples/iCalPortal/db/donald/korg.ics
new file mode 100644 (file)
index 0000000..503bab2
--- /dev/null
@@ -0,0 +1,224 @@
+BEGIN:VCALENDAR
+PRODID
+ :-//K Desktop Environment//NONSGML KOrganizer 3.0.3//EN
+VERSION
+ :2.0
+BEGIN:VTODO
+CREATED
+ :20021014T170416Z
+UID
+ :KOrganizer-728719860.448
+SEQUENCE
+ :0
+LAST-MODIFIED
+ :20021014T170416Z
+DTSTAMP
+ :20021016T112857Z
+ORGANIZER
+ :MAILTO:helge.hess@skyrix.com
+SUMMARY
+ :Test ToDo 1
+CLASS
+ :PUBLIC
+PRIORITY
+ :3
+X-PILOTID
+ :0
+X-PILOTSTAT
+ :1
+DUE
+ ;VALUE=DATE
+ :20021029
+PERCENT-COMPLETE
+ :0
+END:VTODO
+BEGIN:VTODO
+CREATED
+ :20021014T170435Z
+UID
+ :KOrganizer-1717415543.998
+SEQUENCE
+ :0
+LAST-MODIFIED
+ :20021014T170435Z
+DTSTAMP
+ :20021016T112857Z
+ORGANIZER
+ :MAILTO:helge.hess@skyrix.com
+SUMMARY
+ :Test ToDo 2
+CLASS
+ :PRIVATE
+PRIORITY
+ :3
+X-PILOTID
+ :0
+X-PILOTSTAT
+ :1
+COMPLETED
+ :20021014T170437Z
+PERCENT-COMPLETE
+ :100
+END:VTODO
+BEGIN:VEVENT
+CREATED
+ :20021010T152156Z
+UID
+ :KOrganizer-253733106.322
+SEQUENCE
+ :3
+LAST-MODIFIED
+ :20021010T152420Z
+DTSTAMP
+ :20021016T112857Z
+ORGANIZER
+ :MAILTO:helge.hess@skyrix.com
+ATTENDEE
+ ;CN=Donald Duck
+ ;RSVP=FALSE
+ ;PARTSTAT=ACCEPTED
+ ;ROLE=REQ-PARTICIPANT
+ ;X-UID=x22sAAHGf
+ :mailto:donald.duck@entenhausen.de
+SUMMARY
+ :meeting
+CLASS
+ :PUBLIC
+PRIORITY
+ :3
+X-PILOTID
+ :0
+X-PILOTSTAT
+ :1
+DURATION
+ :PTS0
+DTSTART
+ :20021011T160000Z
+DTEND
+ :20021011T180000Z
+END:VEVENT
+BEGIN:VEVENT
+CREATED
+ :20021014T170350Z
+UID
+ :KOrganizer-1621241184.888
+SEQUENCE
+ :0
+LAST-MODIFIED
+ :20021014T170350Z
+DTSTAMP
+ :20021016T112857Z
+ORGANIZER
+ :MAILTO:helge.hess@skyrix.com
+DESCRIPTION
+ :autsch ..
+SUMMARY
+ :Zahnarzt !
+CLASS
+ :PUBLIC
+PRIORITY
+ :3
+X-PILOTID
+ :0
+X-PILOTSTAT
+ :1
+DURATION
+ :PTS0
+DTSTART
+ :20021015T080000Z
+DTEND
+ :20021015T100000Z
+END:VEVENT
+BEGIN:VEVENT
+CREATED
+ :20021014T170402Z
+UID
+ :KOrganizer-1848896883.532
+SEQUENCE
+ :1
+LAST-MODIFIED
+ :20021016T112843Z
+DTSTAMP
+ :20021016T112857Z
+ORGANIZER
+ :MAILTO:helge.hess@skyrix.com
+DESCRIPTION
+ :ddd
+SUMMARY
+ :korg test 1
+CLASS
+ :PUBLIC
+PRIORITY
+ :3
+X-PILOTID
+ :0
+X-PILOTSTAT
+ :1
+DURATION
+ :PTS0
+DTSTART
+ :20021017T140000Z
+DTEND
+ :20021017T160000Z
+END:VEVENT
+BEGIN:VEVENT
+CREATED
+ :20021016T112855Z
+UID
+ :KOrganizer-1489180552.929
+SEQUENCE
+ :0
+LAST-MODIFIED
+ :20021016T112855Z
+DTSTAMP
+ :20021016T112857Z
+ORGANIZER
+ :MAILTO:helge.hess@skyrix.com
+SUMMARY
+ :schon wieder Zahnarzt
+CLASS
+ :PUBLIC
+PRIORITY
+ :3
+X-PILOTID
+ :0
+X-PILOTSTAT
+ :1
+DURATION
+ :PTS0
+DTSTART
+ :20021018T103000Z
+DTEND
+ :20021018T123000Z
+END:VEVENT
+BEGIN:VEVENT
+CREATED
+ :20020807T104550Z
+UID
+ :KOrganizer-2065038380.433
+SEQUENCE
+ :5
+LAST-MODIFIED
+ :20020807T104938Z
+DTSTAMP
+ :20021016T112857Z
+ORGANIZER
+ :MAILTO:helge.hess@skyrix.com
+SUMMARY
+ :test
+CLASS
+ :PUBLIC
+PRIORITY
+ :3
+X-PILOTID
+ :0
+X-PILOTSTAT
+ :1
+DURATION
+ :PTS0
+DTSTART
+ :20020806T073000Z
+DTEND
+ :20020806T083000Z
+END:VEVENT
+END:VCALENDAR
diff --git a/skyrix-sope/samples/iCalPortal/db/donald/mozcal-clean.ics b/skyrix-sope/samples/iCalPortal/db/donald/mozcal-clean.ics
new file mode 100644 (file)
index 0000000..4c174d2
--- /dev/null
@@ -0,0 +1,56 @@
+BEGIN:VCALENDAR
+VERSION
+ :2.0
+PRODID
+ :-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN
+METHOD
+ :PUBLISH
+BEGIN:VEVENT
+UID
+ :916143937
+SUMMARY
+ :test
+LOCATION
+ :dort
+CLASS
+ :PRIVATE
+DTSTART
+ :20020926T150500Z
+DTEND
+ :20020926T160500Z
+DTSTAMP
+ :20020926T150321Z
+END:VEVENT
+BEGIN:VEVENT
+UID
+ :953073077
+SUMMARY
+ :test 2
+LOCATION
+ :dort
+CLASS
+ :PRIVATE
+DTSTART
+ :20021010T010000Z
+DTEND
+ :20021010T020000Z
+DTSTAMP
+ :20021009T111606Z
+END:VEVENT
+BEGIN:VEVENT
+UID
+ :943370923
+SUMMARY
+ :test
+LOCATION
+ :dort
+CLASS
+ :PRIVATE
+DTSTART
+ :20021010T111500Z
+DTEND
+ :20021010T121500Z
+DTSTAMP
+ :20021009T111530Z
+END:VEVENT
+END:VCALENDAR
diff --git a/skyrix-sope/samples/iCalPortal/db/donald/mozcal.ics b/skyrix-sope/samples/iCalPortal/db/donald/mozcal.ics
new file mode 100644 (file)
index 0000000..33e5b7a
--- /dev/null
@@ -0,0 +1,72 @@
+BEGIN:VCALENDAR
+VERSION
+ :2.0
+PRODID
+ :-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN
+METHOD
+ :PUBLISH
+BEGIN:VEVENT
+UID
+ :916143937
+SUMMARY
+ :test
+LOCATION
+ :dort
+CLASS
+ :PRIVATE
+DTSTART
+ :20020926T150500Z
+DTEND
+ :20020926T160500Z
+DTSTAMP
+ :20020926T150321Z
+END:VEVENT
+END:VCALENDAR
+BEGIN:VCALENDAR
+VERSION
+ :2.0
+PRODID
+ :-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN
+METHOD
+ :PUBLISH
+BEGIN:VEVENT
+UID
+ :953073077
+SUMMARY
+ :test 2
+LOCATION
+ :dort
+CLASS
+ :PRIVATE
+DTSTART
+ :20021010T010000Z
+DTEND
+ :20021010T020000Z
+DTSTAMP
+ :20021009T111606Z
+END:VEVENT
+END:VCALENDAR
+BEGIN:VCALENDAR
+VERSION
+ :2.0
+PRODID
+ :-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN
+METHOD
+ :PUBLISH
+BEGIN:VEVENT
+UID
+ :943370923
+SUMMARY
+ :test
+LOCATION
+ :dort
+CLASS
+ :PRIVATE
+DTSTART
+ :20021010T111500Z
+DTEND
+ :20021010T121500Z
+DTSTAMP
+ :20021009T111530Z
+END:VEVENT
+END:VCALENDAR
diff --git a/skyrix-sope/samples/iCalPortal/db/donald/shire-cal1.ics b/skyrix-sope/samples/iCalPortal/db/donald/shire-cal1.ics
new file mode 100644 (file)
index 0000000..c1d3211
--- /dev/null
@@ -0,0 +1,74 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+X-WR-TIMEZONE;VALUE=TEXT:Europe/Berlin
+PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
+X-WR-CALNAME;VALUE=TEXT:shire-cal1
+X-WR-RELCALID;VALUE=TEXT:377A1CA8-DC62-11D6-94DA-00039340AF4A
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20021008T155243Z
+SUMMARY:work
+DTSTART;TZID=Europe/Berlin:20021009T120000
+UID:3779F2E4-DC62-11D6-94DA-00039340AF4A
+DURATION:PT3H45M
+END:VEVENT
+BEGIN:VEVENT
+ATTENDEE;CN=Donald Duck:mailto:donald.duck@entenhausen.de
+ATTENDEE;CN=Dagobert Duck:mailto:chef@entenhausen.de
+DTSTAMP:20021009T211917Z
+SUMMARY:trink
+DTSTART;TZID=Europe/Berlin:20021010T190000
+ORGANIZER;CN=Helge Heß:mailto:helge.hess@skyrix.com
+DESCRIPTION:Meine Notiz\n\nvom iBook\n
+UID:3779F944-DC62-11D6-94DA-00039340AF4A
+DURATION:PT45M
+BEGIN:VALARM
+TRIGGER;VALUE=DURATION:-PT15M
+ACTION:DISPLAY
+DESCRIPTION:Event reminder
+END:VALARM
+BEGIN:VALARM
+TRIGGER;VALUE=DURATION:-PT15M
+ATTACH;VALUE=URI:Ping
+ACTION:AUDIO
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20021008T155256Z
+SUMMARY:Zahnarzt
+DTEND;TZID=Europe/Berlin:20021009T110000
+DTSTART;TZID=Europe/Berlin:20021009T094500
+UID:3779FD6C-DC62-11D6-94DA-00039340AF4A
+END:VEVENT
+BEGIN:VTODO
+DTSTAMP:20021009T154221Z
+SUMMARY:testjob
+DTSTART;TZID=Europe/Berlin:20021008T175228
+DUE;TZID=Europe/Berlin:20021011T175228
+PRIORITY:5
+UID:377A019E-DC62-11D6-94DA-00039340AF4A
+END:VTODO
+BEGIN:VTODO
+DTSTART;TZID=Europe/Berlin:20021010T000000
+SUMMARY:testjob2
+DTSTAMP:20021009T154205Z
+UID:377A057C-DC62-11D6-94DA-00039340AF4A
+END:VTODO
+BEGIN:VEVENT
+DTSTAMP:20021010T120837Z
+SUMMARY:nochmal Zahnarzt
+UID:377A097E-DC62-11D6-94DA-00039340AF4A
+DTSTART;TZID=Europe/Berlin:20021016T094500
+DURATION:PT2H45M
+BEGIN:VALARM
+TRIGGER;VALUE=DURATION:-PT15M
+ACTION:DISPLAY
+DESCRIPTION:Event reminder
+END:VALARM
+BEGIN:VALARM
+ATTACH;VALUE=URI:Ping
+TRIGGER;VALUE=DURATION:-PT15M
+ACTION:AUDIO
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff --git a/skyrix-sope/samples/iCalPortal/db/donald/skytest1.ics b/skyrix-sope/samples/iCalPortal/db/donald/skytest1.ics
new file mode 100644 (file)
index 0000000..e73dffa
--- /dev/null
@@ -0,0 +1,29 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
+X-WR-CALNAME;VALUE=TEXT:skytest1
+X-WR-TIMEZONE;VALUE=TEXT:Europe/Berlin
+X-WR-RELCALID;VALUE=TEXT:C52C8550-DADD-11D6-A381-00039340AF4A
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20021008T155243Z
+SUMMARY:work
+UID:C52C744A-DADD-11D6-A381-00039340AF4A
+DTSTART;TZID=Europe/Berlin:20021009T120000
+DURATION:PT3H45M
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20021008T154300Z
+SUMMARY:trink
+UID:C52C7BEA-DADD-11D6-A381-00039340AF4A
+DTSTART;TZID=Europe/Berlin:20021008T190000
+DURATION:PT45M
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20021008T155256Z
+SUMMARY:Zahnarzt
+DTEND;TZID=Europe/Berlin:20021009T110000
+UID:C52C7FE0-DADD-11D6-A381-00039340AF4A
+DTSTART;TZID=Europe/Berlin:20021009T094500
+END:VEVENT
+END:VCALENDAR
diff --git a/skyrix-sope/samples/iCalPortal/db/donald/skytest2.ics b/skyrix-sope/samples/iCalPortal/db/donald/skytest2.ics
new file mode 100644 (file)
index 0000000..a66f2d9
--- /dev/null
@@ -0,0 +1,29 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+X-WR-TIMEZONE;VALUE=TEXT:Europe/Berlin
+PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
+X-WR-CALNAME;VALUE=TEXT:skytest2
+X-WR-RELCALID;VALUE=TEXT:D962E6CC-DB9D-11D6-9FC6-000393C29C2A
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20021009T154302Z
+SUMMARY:sadf
+DTEND;TZID=Europe/Berlin:20021010T130000
+DTSTART;TZID=Europe/Berlin:20021010T101500
+UID:D962D8C0-DB9D-11D6-9FC6-000393C29C2A
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20021009T153253Z
+SUMMARY:trink
+DTEND;TZID=Europe/Berlin:20021010T190000
+DTSTART;TZID=Europe/Berlin:20021010T180000
+UID:D962DE5E-DB9D-11D6-9FC6-000393C29C2A
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20021009T154308Z
+SUMMARY:New Event
+UID:D962E1E7-DB9D-11D6-9FC6-000393C29C2A
+DTSTART;TZID=Europe/Berlin:20021011T101500
+DURATION:PT1H30M
+END:VEVENT
+END:VCALENDAR
diff --git a/skyrix-sope/samples/iCalPortal/iCalDayView.h b/skyrix-sope/samples/iCalPortal/iCalDayView.h
new file mode 100644 (file)
index 0000000..aeb7355
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalDayView_H__
+#define __iCalPortal_iCalDayView_H__
+
+#include "iCalView.h"
+
+@interface iCalDayView : iCalView
+{
+}
+
+@end
+
+#endif /* __iCalPortal_iCalDayView_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/iCalDayView.m b/skyrix-sope/samples/iCalPortal/iCalDayView.m
new file mode 100644 (file)
index 0000000..cc911ed
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalDayView.h"
+#include "common.h"
+
+@implementation iCalDayView
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* datasource */
+
+- (NSString *)entityName {
+  return @"vevent";
+}
+
+@end /* iCalDayView */
diff --git a/skyrix-sope/samples/iCalPortal/iCalPortal.h b/skyrix-sope/samples/iCalPortal/iCalPortal.h
new file mode 100644 (file)
index 0000000..694324f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalPortal_H__
+#define __iCalPortal_iCalPortal_H__
+
+#include <NGObjWeb/WOApplication.h>
+
+@class iCalPortalDatabase;
+
+@interface iCalPortal : WOApplication
+{
+  iCalPortalDatabase *db;
+}
+
+- (iCalPortalDatabase *)database;
+
+@end
+
+#endif /* __iCalPortal_iCalPortal_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/iCalPortal.m b/skyrix-sope/samples/iCalPortal/iCalPortal.m
new file mode 100644 (file)
index 0000000..f3af0d1
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPortal.h"
+#include "iCalPortalDatabase.h"
+#include "iCalRequestHandler.h"
+#include <NGObjWeb/WORequestHandler.h>
+#include "common.h"
+
+@implementation iCalPortal
+
+- (id)init {
+  if ((self = [super init])) {
+    WORequestHandler *rh;
+    NSString *dbpath;
+
+    /* setup database */
+    
+    dbpath = [[NSUserDefaults standardUserDefaults] stringForKey:@"DBPath"];
+    if ([dbpath length] == 0) {
+      [self logWithFormat:@"configured no DBPath, using ./db ..."];
+      dbpath = [[NSFileManager defaultManager] currentDirectoryPath];
+      dbpath = [dbpath stringByAppendingPathComponent:@"db"];
+    }
+    
+    self->db = [[iCalPortalDatabase alloc] initWithPath:dbpath];
+    
+    if (self->db == nil) {
+      [self logWithFormat:@"couldn't setup database at path: %@", dbpath];
+      [self release];
+      exit(1);
+      return nil;
+    }
+    
+    /* setup request handlers */
+    
+    rh = [[NSClassFromString(@"OWViewRequestHandler") alloc] init];
+    [self registerRequestHandler:rh
+          forKey:[WOApplication componentRequestHandlerKey]];
+    [rh release];
+    
+    rh = [self requestHandlerForKey:
+                [WOApplication directActionRequestHandlerKey]];
+    [self setDefaultRequestHandler:rh];
+
+    rh = [[iCalRequestHandler alloc] init];
+    [self registerRequestHandler:rh forKey:@"ical"];
+    [rh release];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->db release];
+  [super dealloc];
+}
+
+/* exception handling */
+
+- (WOResponse *)handleException:(NSException *)_exc
+  inContext:(WOContext *)_ctx
+{
+  printf("EXCEPTION: %s\n", [[_exc description] cString]);
+  abort();
+}
+
+/* accessors */
+
+- (iCalPortalDatabase *)database {
+  return self->db;
+}
+
+@end /* iCalPortal */
+
+@implementation NSObject(A)
+- (int)indexOfString:(NSString *)_s {
+  printf("NOPE!:\n");
+  printf("%s\n%s\n", [self cString], [_s cString]);
+  abort();
+}
+@end
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  WOWatchDogApplicationMain(@"iCalPortal", argc, (void*)argv);
+
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-sope/samples/iCalPortal/iCalPortalCalendar.h b/skyrix-sope/samples/iCalPortal/iCalPortalCalendar.h
new file mode 100644 (file)
index 0000000..dc39d3a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalPortalCalendar_H__
+#define __iCalPortal_iCalPortalCalendar_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSData;
+@class EODataSource;
+@class iCalPortalUser;
+
+@interface iCalPortalCalendar : NSObject
+{
+  iCalPortalUser *user;
+  NSString       *path;
+  NSData         *content;
+}
+
+- (id)initWithUser:(iCalPortalUser *)_user path:(NSString *)_path;
+
+/* access */
+
+- (BOOL)isPublic;
+
+/* content */
+
+- (NSData *)rawContent;
+- (EODataSource *)dataSource;
+
+@end
+
+#endif /* __iCalPortal_iCalPortalCalendar_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/iCalPortalCalendar.m b/skyrix-sope/samples/iCalPortal/iCalPortalCalendar.m
new file mode 100644 (file)
index 0000000..e587764
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPortalCalendar.h"
+#include "iCalPortalUser.h"
+#include "common.h"
+#include <NGiCal/iCalDataSource.h>
+
+@implementation iCalPortalCalendar
+
+- (id)initWithUser:(iCalPortalUser *)_user path:(NSString *)_path {
+  if ((self->user = [_user retain]) == nil) {
+    [self release];
+    return nil;
+  }
+  if ((self->path = [_path copy]) == nil) {
+    [self release];
+    return nil;
+  }
+  
+  return self;
+}
+
+- (void)dealloc {
+  [self->content release];
+  [self->path    release];
+  [self->user    release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (iCalPortalUser *)user {
+  return self->user;
+}
+
+/* access */
+
+- (BOOL)isPublic {
+  return YES;
+}
+
+- (NSData *)rawContent {
+  if (self->content == nil)
+    self->content = [[NSData alloc] initWithContentsOfMappedFile:self->path];
+  
+  return self->content;
+}
+
+- (EODataSource *)dataSource {
+  iCalDataSource *ds;
+  
+  if ([self->path length] == 0)
+    return nil;
+  if ((ds = [[iCalDataSource alloc] initWithPath:self->path]) == nil)
+    return nil;
+  
+  return [ds autorelease];
+}
+
+/* logging */
+
+- (BOOL)isDebuggingEnabled {
+  return YES;
+}
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@"[cal:%@]", 
+                    self->path ? self->path : @"<new>"];
+}
+
+- (NSString *)description {
+  NSMutableString *s;
+  
+  s = [NSMutableString stringWithCapacity:128];
+  [s appendFormat:@"<0x%08X[%@]: ", self, NSStringFromClass([self class])];
+  [s appendFormat:@" path=%@", self->path];
+  
+  if ([self isPublic])
+    [s appendString:@" public"];
+  
+  [s appendString:@">"];
+  
+  return s;
+}
+
+@end /* iCalPortalCalendar */
diff --git a/skyrix-sope/samples/iCalPortal/iCalPortalDatabase.h b/skyrix-sope/samples/iCalPortal/iCalPortalDatabase.h
new file mode 100644 (file)
index 0000000..a49a9ef
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalPortalDatabase_H__
+#define __iCalPortal_iCalPortalDatabase_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSFileManager, NSString, NSDictionary;
+@class iCalPortalUser;
+
+@interface iCalPortalDatabase : NSObject
+{
+  NSFileManager *fileManager;
+  NSString      *rootPath;
+}
+
+- (id)initWithPath:(NSString *)_path;
+
+/* operations */
+
+- (iCalPortalUser *)userWithName:(NSString *)_name password:(NSString *)_pwd;
+- (iCalPortalUser *)userWithName:(NSString *)_name;
+
+- (BOOL)createUser:(NSString *)_login
+  info:(NSDictionary *)_userInfo
+  password:(NSString *)_pwd;
+
+- (BOOL)isLoginNameValid:(NSString *)_name;
+- (BOOL)isPasswordValid:(NSString *)_name;
+- (BOOL)isLoginNameUsed:(NSString *)_name;
+
+/* accessors */
+
+- (NSFileManager *)fileManager;
+
+@end
+
+#endif /* __iCalPortal_iCalPortalDatabase_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/iCalPortalDatabase.m b/skyrix-sope/samples/iCalPortal/iCalPortalDatabase.m
new file mode 100644 (file)
index 0000000..5e89330
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPortalDatabase.h"
+#include "iCalPortalUser.h"
+#include "common.h"
+
+@interface NSString(Crypt)
+- (NSString *)cryptString;
+- (BOOL)compareWithCryptedString:(NSString *)_crypt;
+@end
+
+@implementation iCalPortalDatabase
+
+- (id)initWithPath:(NSString *)_path {
+  if ((self = [super init])) {
+    BOOL isDir;
+    
+    self->fileManager = [[NSFileManager defaultManager] retain];
+    self->rootPath    = [_path copy];
+    
+    if (![self->fileManager fileExistsAtPath:_path isDirectory:&isDir]) {
+      [self logWithFormat:@"database path %@ does not exist ...", _path];
+      [self release];
+      return nil;
+    }
+    if (!isDir) {
+      [self logWithFormat:@"database path %@ is not a directory ...", _path];
+      [self release];
+      return nil;
+    }
+  }
+  return self;
+}
+- (id)init {
+  return [self initWithPath:@"."];
+}
+
+- (void)dealloc {
+  [self->fileManager release];
+  [self->rootPath release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSFileManager *)fileManager {
+  return self->fileManager;
+}
+
+/* name->path */
+
+- (NSString *)pathForLogin:(NSString *)_login {
+  static NSString *escapeChars[] = {
+    @"/", @"_s_",
+    @".", @"_p_",
+    @"~", @"_t_",
+    @"$", @"_d_",
+    nil, nil
+  };
+  NSRange  r;
+  NSString *p;
+  int i;
+
+  if ([self->rootPath length] < 4)
+    return nil;
+  if ([_login length] < 3)
+    return nil;
+  if ([_login rangeOfString:@" "].length > 0)
+    return nil;
+  if ([_login rangeOfString:@"\t"].length > 0)
+    return nil;
+  
+  if ([_login length] > 63)
+    _login = [_login substringToIndex:63];
+  
+  p = [[_login copy] autorelease];
+  
+  /* first quote quoting chars ;-) */
+  r = [p rangeOfString:@"_"];
+  if (r.length == 0) p = [p stringByReplacingString:@"_" withString:@"__"];
+  
+  /* now quote special chars */
+  for (i = 0; escapeChars[i] != nil; i+=2) {
+    r = [p rangeOfString:escapeChars[i]];
+    if (r.length > 0) {
+      p = [p stringByReplacingString:escapeChars[i] 
+            withString:escapeChars[i + 1]];
+    }
+  }
+  
+  return [self->rootPath stringByAppendingPathComponent:p];
+}
+
+/* operations */
+
+- (iCalPortalUser *)userWithName:(NSString *)_name password:(NSString *)_pwd {
+  /* return an authenicated user object */
+  iCalPortalUser *user;
+  
+  if ([_pwd length] < 4) {
+    [self logWithFormat:@"password smaller than minimum length ..."];
+    return nil;
+  }
+  
+  if ((user = [self userWithName:_name]) == nil)
+    return nil;
+  
+  if (![user authenticate:_pwd]) {
+    [self logWithFormat:@"got wrong password for user '%@' ...", _name];
+    return nil;
+  }
+  
+  return user;
+}
+
+- (iCalPortalUser *)userWithName:(NSString *)_name {
+  /* return a user object */
+  NSString       *p;
+  iCalPortalUser *user;
+  
+  if ((p = [self pathForLogin:_name]) == nil) {
+    [self logWithFormat:@"couldn't transform name '%@' into path ...", _name];
+    return nil;
+  }
+  
+  if (![self->fileManager fileExistsAtPath:p]) {
+    [self logWithFormat:@"user '%@' does not exist (path=%@) !", _name, p];
+    return nil;
+  }
+
+  user = [[iCalPortalUser alloc] initWithPath:p login:_name database:self];
+  
+  if (user == nil) {
+    [self logWithFormat:@"couldn't allocate object for user '%@' ...", _name];
+    return nil;
+  }
+  
+  return [user autorelease];
+}
+
+- (BOOL)createUser:(NSString *)_login
+  info:(NSDictionary *)_userInfo
+  password:(NSString *)_pwd
+{
+  NSString *p;
+  NSMutableDictionary *ui;
+  
+  if ([_userInfo count] < 3) {
+    [self debugWithFormat:@"invalid userinfo: %@", _userInfo];
+    return NO;
+  }
+  if ([_pwd length] < 6) {
+    [self debugWithFormat:@"got invalid passwrd ..."];
+    return NO;
+  }
+  
+  ui = [_userInfo mutableCopy];
+
+  if ((p = [self pathForLogin:_login]) == nil) {
+    [self logWithFormat:@"couldn't transform name '%@' into path ...", _login];
+    return NO;
+  }
+
+  [ui setObject:[_pwd cryptString] forKey:@"cryptedPassword"];
+  
+  if (![self->fileManager createDirectoryAtPath:p attributes:nil]) {
+    [self logWithFormat:@"couldn't create user directory: '%@'.", p];
+    return NO;
+  }
+  
+  [ui writeToFile:[p stringByAppendingPathComponent:@".account.plist"]
+      atomically:NO];
+  [ui release];
+  
+  return YES;
+}
+
+- (BOOL)isLoginNameValid:(NSString *)_name {
+  return [self pathForLogin:_name] == nil ? NO : YES;
+}
+
+- (BOOL)isLoginNameUsed:(NSString *)_name {
+  NSString *p;
+  
+  if ((p = [self pathForLogin:_name]) == nil)
+    return YES;
+  
+  if ([self->fileManager fileExistsAtPath:p])
+    return YES;
+  
+  return NO;
+}
+
+- (BOOL)isPasswordValid:(NSString *)_pwd {
+  if ([_pwd length] < 6)  return NO;
+  if ([_pwd length] > 16) return NO;
+  return YES;
+}
+
+@end /* iCalPortalDatabase */
+
+#include <unistd.h>
+#if !defined(__APPLE__)
+#include <crypt.h>
+#endif
+
+@implementation NSString(Crypt)
+
+static void _makeSalt(unsigned char *s) {
+  int           i, timeInt;
+  unsigned char c;    
+  
+  timeInt = (int)time(0);
+  srand(timeInt);
+  
+  for (i = 0; i < 2; i++) {
+    do {
+      c = 46 + (rand() % 76);
+    }
+    while (((c > 57) && (c < 65)) || ((c > 90) && (c < 97)));
+    
+    s[i] = c;
+  }
+}
+
+- (NSString *)cryptString {
+  unsigned char *s;
+  unsigned char salt[4] = { 0,0,0,0 };
+  
+  _makeSalt(salt);
+  s = (void*)[self cString];
+  s = crypt(s, salt);
+  return [[[NSString alloc] initWithCString:s] autorelease];
+}
+
+- (BOOL)compareWithCryptedString:(NSString *)_crypt {
+  unsigned char *s, *cs;
+  
+  if ([_crypt length] < 2) 
+    /* not a valid crypt string ... */
+    return NO;
+  if ((cs = (unsigned char *)[_crypt cString]) == NULL)
+    return NO;
+  if (strlen(cs) < 2)
+    return NO;
+  
+  s = (unsigned char *)[self cString];
+  s = crypt(s, cs);
+  return strcmp(s, cs) == 0 ? YES : NO;
+}
+
+@end /* NSString(Crypt) */
diff --git a/skyrix-sope/samples/iCalPortal/iCalPortalPage.h b/skyrix-sope/samples/iCalPortal/iCalPortalPage.h
new file mode 100644 (file)
index 0000000..ff22b9e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalPortalPage_H__
+#define __iCalPortal_iCalPortalPage_H__
+
+#include <NGObjWeb/WOComponent.h>
+
+@class iCalPortalUser, iCalPortalDatabase;
+
+@interface iCalPortalPage : WOComponent
+{
+}
+
+/* accessors */
+
+- (iCalPortalDatabase *)database;
+- (iCalPortalUser *)user;
+
+/* actions */
+
+- (id)performPage;
+- (id)run;
+
+/* labels */
+
+- (NSString *)localizedTitle;
+- (NSString *)stringForKey:(NSString *)_key;
+
+@end
+
+#endif /* __iCalPortal_iCalPortalPage_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/iCalPortalPage.m b/skyrix-sope/samples/iCalPortal/iCalPortalPage.m
new file mode 100644 (file)
index 0000000..6446c72
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPortalPage.h"
+#include "common.h"
+
+@interface iCalLabelDispatcher : NSObject
+{
+  iCalPortalPage *component;
+}
+
+- (id)initWithComponent:(iCalPortalPage *)_comp;
+
+@end
+
+@implementation iCalPortalPage
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* accessors */
+
+- (iCalPortalDatabase *)database {
+  return [(id)[self application] database];
+}
+
+- (iCalPortalUser *)user {
+  if (![self hasSession])
+    return nil;
+  
+  return [[self session] objectForKey:@"user"];
+}
+
+/* actions */
+
+- (BOOL)isSessionProtectedPage {
+  return YES;
+}
+
+- (id<WOActionResults>)indexPage {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  WOSession *sn;
+  
+  if ((sn = [self existingSession])) {
+    [sn removeObjectForKey:@"user"];
+    [sn terminate];
+  }
+  
+  if ([[ud objectForKey:@"DevMode"] boolValue]) {
+    return [[self pageWithName:@"iCalPortalWelcomePage"] performPage];
+  }
+  else {
+    WOResponse *r;
+    
+    r = [WOResponse responseWithRequest:[[self context] request]];
+    
+    [r setStatus:302];
+    [r setHeader:@"/en/index.xhtml" forKey:@"location"];
+    
+    return r;
+  }
+}
+
+- (id)performPage {
+  id result;
+  
+  if ([self isSessionProtectedPage]) {
+    if (![self hasSession]) {
+      [self logWithFormat:
+             @"tried to access login protected page without session !"];
+      return [self indexPage];
+    }
+  }
+  
+  result = [self run];
+  
+  return result;
+}
+
+- (id)run {
+  return self;
+}
+
+/* labels */
+
+- (id)label {
+  return [[[iCalLabelDispatcher alloc] initWithComponent:self] autorelease];
+}
+
+- (NSString *)stringForKey:(NSString *)_key {
+  NSString *s;
+  NSArray  *langs;
+
+  langs = [self hasSession]
+    ? [[self session] languages]
+    : [[[self context] request] browserLanguages];
+  
+  s = [[self resourceManager] 
+             stringForKey:_key inTableNamed:@"main" withDefaultValue:_key
+            languages:langs];
+  return s;
+}
+
+- (NSString *)localizedTitle {
+  return [self stringForKey:[self name]];
+}
+
+@end /* iCalPortalPage */
+
+@implementation iCalLabelDispatcher
+
+- (id)initWithComponent:(iCalPortalPage *)_comp {
+  self->component = _comp;
+  return self;
+}
+
+- (id)valueForKey:(NSString *)_key {
+  if ([_key length] == 0)
+    return _key;
+  
+  return [self->component stringForKey:_key];
+}
+
+@end /* iCalLabelDispatcher */
diff --git a/skyrix-sope/samples/iCalPortal/iCalPortalUser.h b/skyrix-sope/samples/iCalPortal/iCalPortalUser.h
new file mode 100644 (file)
index 0000000..72dcc6f
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalPortalUser_H__
+#define __iCalPortal_iCalPortalUser_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSFileManager, NSString, NSException, NSData, NSDictionary, NSArray;
+@class EODataSource;
+@class iCalPortalDatabase, iCalPortalCalendar;
+
+@interface iCalPortalUser : NSObject
+{
+  iCalPortalDatabase *database;
+  NSFileManager      *fileManager;
+  NSString           *path;
+  NSString           *login;
+
+  NSString *firstName;
+  NSString *lastName;
+  NSString *street;
+  NSString *city;
+  NSString *email;
+  NSString *address;
+  NSString *country;
+  NSString *phone;
+  NSString *state;
+  NSString *zip;
+  NSString *wantIcalNews;
+  NSString *wantSkyrixNews;
+}
+
+- (id)initWithPath:(NSString *)_path
+  login:(NSString *)_login
+  database:(iCalPortalDatabase *)_db;
+
+/* accessors */
+
+- (iCalPortalDatabase *)database;
+
+/* password checking */
+
+- (BOOL)authenticate:(NSString *)_pwd;
+
+/* read/store */
+
+- (BOOL)read;
+
+/* calendars */
+
+- (NSDictionary *)calendars;
+- (NSArray *)calendarNames;
+
+- (iCalPortalCalendar *)calendarAtPath:(NSString *)_path;
+- (EODataSource *)dataSourceAtPath:(NSString *)_path;
+
+- (NSException *)deleteCalendarWithPath:(NSString *)_path;
+- (NSException *)writeICalendarData:(NSData *)_data toCalendar:(NSString *)_path;
+
+@end
+
+#endif /* __iCalPortal_iCalPortalUser_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/iCalPortalUser.m b/skyrix-sope/samples/iCalPortal/iCalPortalUser.m
new file mode 100644 (file)
index 0000000..40b6627
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalPortalUser.h"
+#include "iCalPortalDatabase.h"
+#include "iCalPortalCalendar.h"
+#include "common.h"
+
+@implementation iCalPortalUser
+
+- (id)initWithDatabase:(iCalPortalDatabase *)_db {
+  if (_db == nil) {
+    [self release];
+    return nil;
+  }
+  if ((self = [super init])) {
+    self->database = [_db retain];
+
+    if ((self->fileManager = [[_db fileManager] retain]) == nil) {
+      [self release];
+      return nil;
+    }
+  }
+  return self;
+}
+
+- (id)initWithPath:(NSString *)_path
+  login:(NSString *)_login
+  database:(iCalPortalDatabase *)_db;
+{
+  if ((self = [self initWithDatabase:_db])) {
+    self->path  = [_path copy];
+    self->login = [_login copy];
+
+    if (self->path) {
+      if (![self read]) {
+       [self release];
+       return nil;
+      }
+    }
+  }
+  return self;
+}
+
+- (id)init {
+  return [self initWithDatabase:nil];
+}
+
+- (void)dealloc {
+  [self->firstName    release];
+  [self->lastName     release];
+  [self->street       release];
+  [self->city         release];
+  [self->email        release];
+  [self->address      release];
+  [self->country      release];
+  [self->phone        release];
+  [self->state        release];
+  [self->zip          release];
+  [self->wantIcalNews   release];
+  [self->wantSkyrixNews release];
+  
+  [self->login       release];
+  [self->fileManager release];
+  [self->database    release];
+  [self->path        release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (iCalPortalDatabase *)database {
+  return self->database;
+}
+
+- (void)setFirstName:(NSString *)_value {
+  ASSIGN(self->firstName, _value);
+}
+- (NSString *)firstName {
+  return self->firstName;
+}
+
+- (void)setLastName:(NSString *)_value {
+  ASSIGN(self->lastName, _value);
+}
+- (NSString *)lastName {
+  return self->lastName;
+}
+
+- (void)setStreet:(NSString *)_value {
+  ASSIGN(self->street, _value);
+}
+- (NSString *)street {
+  return self->street;
+}
+
+- (void)setCity:(NSString *)_value {
+  ASSIGN(self->city, _value);
+}
+- (NSString *)city {
+  return self->city;
+}
+
+- (void)setEmail:(NSString *)_value {
+  ASSIGN(self->email, _value);
+}
+- (NSString *)email {
+  return self->email;
+}
+
+- (void)setLogin:(NSString *)_login {
+  /* do not allow login change via KVC ! ... */
+}
+- (NSString *)login {
+  return self->login;
+}
+
+- (void)setAddress:(NSString *)_value {
+  ASSIGN(self->address, _value);
+}
+- (NSString *)address {
+  return self->address;
+}
+- (void)setCountry:(NSString *)_value {
+  ASSIGN(self->country, _value);
+}
+- (NSString *)country {
+  return self->country;
+}
+- (void)setPhone:(NSString *)_value {
+  ASSIGN(self->phone, _value);
+}
+- (NSString *)phone {
+  return self->phone;
+}
+- (void)setState:(NSString *)_value {
+  ASSIGN(self->state, _value);
+}
+- (NSString *)state {
+  return self->state;
+}
+- (void)setZip:(NSString *)_value {
+  ASSIGN(self->zip, _value);
+}
+- (NSString *)zip {
+  return self->zip;
+}
+
+- (void)setWantIcalNews:(NSString *)_value {
+  ASSIGN(self->wantIcalNews, _value);
+}
+- (NSString *)wantIcalNews {
+  return self->wantIcalNews;
+}
+- (void)setWantSkyrixNews:(NSString *)_value {
+  ASSIGN(self->wantSkyrixNews, _value);
+}
+- (NSString *)wantSkyrixNews {
+  return self->wantSkyrixNews;
+}
+
+/* do not store password in process ! ... */
+
+- (void)setPassword:(NSString *)_value {
+}
+- (NSString *)password {
+  return nil;
+}
+- (void)setCryptedPassword:(NSString *)_value {
+}
+- (NSString *)cryptedPassword {
+  return nil;
+}
+
+/* load/store */
+
+- (NSDictionary *)accountDictionary {
+  NSDictionary *d;
+  NSString     *p;
+  
+  if ([self->path length] < 4) {
+    [self logWithFormat:@"tried to read an account which has no path ..."];
+    return nil;
+  }
+  
+  p = [self->path stringByAppendingPathComponent:@".account.plist"];
+  
+  if ((d = [NSDictionary dictionaryWithContentsOfFile:p]) == nil) {
+    [self logWithFormat:@"couldn't load dictionary of account (%@) ...", p];
+    return nil;
+  }
+  
+  return d;
+}
+
+- (BOOL)read {
+  NSDictionary *d;
+  
+  if ((d = [self accountDictionary]) == nil)
+    return NO;
+  
+  [self takeValuesFromDictionary:d];
+  return YES;
+}
+
+- (BOOL)write {
+  return NO;
+}
+
+/* password checking */
+
+- (BOOL)authenticate:(NSString *)_pwd {
+  NSDictionary *d;
+  NSString *tmp;
+  
+  if ([_pwd length] < 4) 
+    return NO;
+  
+  if ((d = [self accountDictionary]) == nil)
+    return NO;
+  
+  if ((tmp = [d objectForKey:@"cryptedPassword"]))
+    return [_pwd compareWithCryptedString:tmp];
+  
+  if ((tmp = [d objectForKey:@"password"])) {
+    if ([tmp isEqualToString:_pwd]) {
+      [self logWithFormat:@"authenticated account."];
+      return YES;
+    }
+    [self logWithFormat:@"got invalid password for account"];
+    return NO;
+  }
+  
+  return NO;
+}
+
+/* calendars */
+
+- (BOOL)containsUnsafeChars:(NSString *)_path {
+  /* check for dangerous stuff ... */
+  NSRange r;
+
+  if ([_path hasPrefix:@"."]) return YES;
+  
+  r = [_path rangeOfString:@".."];
+  if (r.length > 0) return YES;
+  r = [_path rangeOfString:@"/"];
+  if (r.length > 0) return YES;
+  r = [_path rangeOfString:@"~"];
+  if (r.length > 0) return YES;
+  r = [_path rangeOfString:@"\\"];
+  if (r.length > 0) return YES;
+
+  return NO;
+}
+
+- (NSString *)cleanupCalendarPath:(NSString *)_path {
+  static NSArray *validExts = nil;
+  NSString *calName;
+  NSString *ext;
+  
+  if (validExts == nil) {
+    validExts = [[NSArray alloc] initWithObjects:
+                                  @"ics", @"vfb", @"ifb",
+                                  @"ical", @"cal", nil];
+  }
+  
+  if ((calName = [_path lastPathComponent]) == nil)
+    return nil;
+  
+  ext = [calName pathExtension]; 
+  
+  if ([ext length] == 0) {
+    calName = [calName stringByAppendingPathComponent:@"ics"];
+  }
+  else if (![validExts containsObject:ext]) {
+    [self logWithFormat:@"invalid calendar extension '%@': %@", ext, _path];
+    return nil;
+  }
+  
+  if ([self containsUnsafeChars:calName])
+    return nil;
+  
+  return [self->path stringByAppendingPathComponent:calName];
+}
+
+- (NSException *)invalidPathException:(NSString *)_path {
+  return [NSException exceptionWithName:@"InvalidCalendarPath"
+                     reason:@"got an invalid calendar path ..."
+                     userInfo:nil];
+}
+
+- (iCalPortalCalendar *)calendarAtPath:(NSString *)_path {
+  NSString *calpath;
+  BOOL     isDir;
+  iCalPortalCalendar *cal;
+  
+  if ((calpath = [self cleanupCalendarPath:_path]) == nil)
+    return nil;
+  
+  if (![self->fileManager fileExistsAtPath:calpath isDirectory:&isDir]) {
+    [self debugWithFormat:@"  cal '%@' does not exist ...", _path];
+    return nil;
+  }
+  if (isDir) {
+    [self logWithFormat:@"  calpath is a directory: %@ !", calpath];
+    return nil;
+  }
+  
+  cal = [[iCalPortalCalendar alloc] initWithUser:self path:calpath];
+  if (cal == nil) return nil;
+  
+  return [cal autorelease];
+}
+- (EODataSource *)dataSourceAtPath:(NSString *)_path {
+  iCalPortalCalendar *cal;
+  
+  if ((cal = [self calendarAtPath:_path]) == nil)
+    return nil;
+  return [cal dataSource];
+}
+
+- (NSException *)deleteCalendarWithPath:(NSString *)_path {
+  NSString *calpath;
+  BOOL isDir;
+  
+  if ((calpath = [self cleanupCalendarPath:_path]) == nil)
+    return [self invalidPathException:_path];
+  
+  [self debugWithFormat:@"delete calendar: %@", calpath];
+  
+  if (![self->fileManager fileExistsAtPath:calpath isDirectory:&isDir]) {
+    [self debugWithFormat:@"  cal does not exist ..."];
+    return nil;
+  }
+  if (isDir) {
+    [self logWithFormat:@"  calpath to be deleted is a directory: %@ !",
+           calpath];
+    return nil;
+  }
+  
+  /* go on, delete ... */
+  if (![self->fileManager removeFileAtPath:calpath handler:nil]) {
+    [self logWithFormat:@"  failed to delete calendar %@", path];
+    return [NSException exceptionWithName:@"DeleteError"
+                       reason:@"reason unknown"
+                       userInfo:nil];
+  }
+  
+  return nil;
+}
+
+- (NSException *)writeICalendarData:(NSData *)_data toCalendar:(NSString *)_path{
+  NSString *calpath;
+  
+  if ((calpath = [self cleanupCalendarPath:_path]) == nil)
+    return [self invalidPathException:_path];
+  
+  [self debugWithFormat:@"upload calendar data: %@, size %i", 
+         calpath, [_data length]];
+
+  if (![_data writeToFile:calpath atomically:YES]) {
+    [self logWithFormat:@"  failed to write calendar of size %i to path %@",
+           [_data length], calpath];
+    return [NSException exceptionWithName:@"WriteError"
+                       reason:@"reason unknown"
+                       userInfo:nil];
+  }
+  
+  return nil;
+}
+
+- (NSArray *)calendarNames {
+  NSAutoreleasePool *pool;
+  NSEnumerator      *e;
+  NSString          *filename;
+  NSMutableArray    *md = nil;
+  
+  e = [[self->fileManager directoryContentsAtPath:self->path]
+       objectEnumerator];
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  while ((filename = [e nextObject])) {
+    iCalPortalCalendar *cal;
+    
+    if ([self containsUnsafeChars:filename]) continue;
+    
+    if ((cal = [self calendarAtPath:filename]) == nil)
+      continue;
+    
+    if (md == nil)
+      md = [[NSMutableArray alloc] initWithCapacity:16];
+    
+    [md addObject:filename];
+  }
+  
+  [md sortUsingSelector:@selector(compare:)];
+  [pool release];
+  
+  return [md autorelease];
+}
+- (NSDictionary *)calendars {
+  NSEnumerator        *e;
+  NSString            *filename;
+  NSMutableDictionary *md = nil;
+  
+  e = [[self->fileManager directoryContentsAtPath:self->path]
+       objectEnumerator];
+  
+  while ((filename = [e nextObject])) {
+    iCalPortalCalendar *cal;
+    
+    if ([self containsUnsafeChars:filename]) continue;
+    
+    if ((cal = [self calendarAtPath:filename]) == nil)
+      continue;
+    
+    if (md == nil)
+      md = [[NSMutableDictionary alloc] init];
+
+    [md setObject:cal forKey:filename];
+  }
+  return md;
+}
+
+/* logging */
+
+- (BOOL)isDebuggingEnabled {
+  return YES;
+}
+- (NSString *)loggingPrefix {
+  return [NSString stringWithFormat:@"[user:%@]", 
+                    self->login ? self->login : @"<new>"];
+}
+
+- (NSString *)description {
+  NSMutableString *s;
+  
+  s = [NSMutableString stringWithCapacity:128];
+  [s appendFormat:@"<0x%08X[%@]: ", self, NSStringFromClass([self class])];
+  [s appendFormat:@" login=%@", self->login];
+  [s appendFormat:@" path=%@",  self->path];
+  [s appendString:@">"];
+  
+  return s;
+}
+
+@end /* iCalPortalUser */
diff --git a/skyrix-sope/samples/iCalPortal/iCalView.h b/skyrix-sope/samples/iCalPortal/iCalView.h
new file mode 100644 (file)
index 0000000..4ee95c2
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalView_H__
+#define __iCalPortal_iCalView_H__
+
+#include "iCalPortalPage.h"
+
+@class NSString, NSTimeZone, NSFormatter, NSCalendarDate;
+@class EODataSource;
+@class iCalPortalDatabase, iCalPortalUser;
+
+@interface iCalView : iCalPortalPage
+{
+  NSString       *calendarName;
+  EODataSource   *dataSource;
+  NSFormatter    *dateFormatter;
+  NSCalendarDate *today;
+  
+  /* transient */
+  id item;
+}
+
+/* accessors */
+
+- (NSString *)calendarName;
+- (EODataSource *)dataSource;
+- (NSTimeZone *)viewTimeZone;
+- (NSCalendarDate *)today;
+
+@end
+
+#endif /* __iCalPortal_iCalView_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/iCalView.m b/skyrix-sope/samples/iCalPortal/iCalView.m
new file mode 100644 (file)
index 0000000..56ded59
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalView.h"
+#include "iCalPortalUser.h"
+#include <NGExtensions/EOCacheDataSource.h>
+#include "common.h"
+
+@interface iCalPortalDateFormatter : NSFormatter
+{
+  iCalView *component;
+}
+
+- (id)initWithComponent:(iCalView *)_comp;
+
+@end
+
+@implementation iCalView
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (void)dealloc {
+  [self->dateFormatter release];
+  [self->dataSource    release];
+  [self->item          release];
+  [self->calendarName  release];
+  [self->today         release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setCalendarName:(NSString *)_name {
+  ASSIGN(self->calendarName, _name);
+}
+- (NSString *)calendarName {
+  return self->calendarName;
+}
+
+- (void)setItem:(id)_item {
+  ASSIGN(self->item, _item);
+}
+- (id)item {
+  return self->item;
+}
+
+- (NSTimeZone *)viewTimeZone {
+  if ([self hasSession])
+    return [[self session] viewTimeZone];
+  
+  return [NSTimeZone timeZoneWithName:@"Europe/Berlin"];
+}
+
+/* datasource */
+
+- (NSString *)entityName {
+  return nil;
+}
+
+- (EOQualifier *)qualifier {
+  return nil;
+}
+
+- (EOFetchSpecification *)fetchSpecification {
+  EOFetchSpecification *fs;
+
+  fs = [[EOFetchSpecification alloc] init];
+  [fs setEntityName:[self entityName]];
+  [fs setQualifier:[self qualifier]];
+  return [fs autorelease];
+}
+
+- (EODataSource *)dataSource {
+  EODataSource *ds;
+  EOFetchSpecification *fspec;
+  
+  if (self->dataSource)
+    return self->dataSource;
+  
+  if ((ds = [[self user] dataSourceAtPath:self->calendarName]) == nil)
+    return nil;
+  
+  if ((fspec = [self fetchSpecification]))
+    [ds setFetchSpecification:fspec];
+  
+  if ((ds = [[EOCacheDataSource alloc] initWithDataSource:ds]) == nil)
+    return nil;
+  
+  self->dataSource = ds;
+  
+  return ds;
+}
+
+- (NSFormatter *)dateFormatter {
+  if (self->dateFormatter == nil) {
+    self->dateFormatter =
+      [[iCalPortalDateFormatter alloc] initWithComponent:self];
+  }
+  return self->dateFormatter;
+}
+
+- (NSCalendarDate *)today {
+  if (self->today == nil) {
+    self->today = [[NSCalendarDate alloc] init];
+    [self->today setTimeZone:[self viewTimeZone]];
+  }
+  return self->today;
+}
+
+/* notifications */
+
+- (void)sleep {
+  [super sleep];
+  [self setItem:nil];
+  [self->dataSource    release]; self->dataSource    = nil;
+  [self->dateFormatter release]; self->dateFormatter = nil;
+}
+
+/* labels */
+
+- (NSString *)localizedTitle {
+  NSString *s, *calType;
+  NSString *pe;
+  
+  s  = [self calendarName];
+  pe = [s pathExtension];
+  s  = [s stringByDeletingPathExtension];
+
+  if ([pe isEqualToString:@"ics"] || [pe length] == 0)
+    calType = @"iCalTypeName";
+  else if ([pe isEqualToString:@"vfb"] || [pe isEqualToString:@"ifb"])
+    calType = @"freeBusyTypeName";
+  else
+    calType = @"unknownTypeName";
+  
+  calType = [self stringForKey:calType];
+  
+  s = [NSString stringWithFormat:@"%@ on %@: %@", 
+                 [super localizedTitle], calType, s];
+  return s;
+}
+
+/* actions */
+
+- (id)run {
+  if ([self hasSession]) {
+    WORequest *rq;
+    id tmp;
+  
+    rq = [[self context] request];
+    
+    if ((tmp = [rq formValueForKey:@"calendarName"])) {
+      [self setCalendarName:tmp];
+    }
+    else {
+      /* choose default cal ... */
+    }
+  }  
+  return [super run];
+}
+
+@end /* iCalView */
+
+@implementation iCalPortalDateFormatter
+
+- (id)initWithComponent:(iCalView *)_comp {
+  self->component = _comp;
+  return self;
+}
+
+- (NSString *)stringForObjectValue:(id)_object {
+  static Class NSCalendarDateClass = Nil;
+
+  if (_object == nil) return nil;
+  
+  if (NSCalendarDateClass == Nil) 
+    NSCalendarDateClass = [NSCalendarDateClass class];
+
+  NSLog(@"string for object: %@", _object);
+  
+  if (![_object isKindOfClass:NSCalendarDateClass])
+    return [_object stringValue];
+  
+  [_object setTimeZone:[self->component viewTimeZone]];
+  return [_object descriptionWithCalendarFormat:@"%H:%M"];
+}
+
+@end /* iCalPortalDateFormatter */
diff --git a/skyrix-sope/samples/iCalPortal/iCalWeekView.h b/skyrix-sope/samples/iCalPortal/iCalWeekView.h
new file mode 100644 (file)
index 0000000..dc5ccca
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __iCalPortal_iCalWeekView_H__
+#define __iCalPortal_iCalWeekView_H__
+
+#include "iCalView.h"
+
+@interface iCalWeekView : iCalView
+{
+}
+
+@end
+
+#endif /* __iCalPortal_iCalWeekView_H__ */
diff --git a/skyrix-sope/samples/iCalPortal/iCalWeekView.m b/skyrix-sope/samples/iCalPortal/iCalWeekView.m
new file mode 100644 (file)
index 0000000..bedd462
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "iCalWeekView.h"
+#include "common.h"
+
+@implementation iCalWeekView
+
++ (int)version {
+  return [super version] + 0 /* v2 */;
+}
++ (void)initialize {
+  NSAssert2([super version] == 2,
+            @"invalid superclass (%@) version %i !",
+            NSStringFromClass([self superclass]), [super version]);
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* week start */
+
+- (NSCalendarDate *)weekStart {
+  return [[NSCalendarDate calendarDate] mondayOfWeek];
+}
+
+/* datasource */
+
+- (NSString *)entityName {
+  return @"vevent";
+}
+
+@end /* iCalWeekView */
diff --git a/skyrix-sope/samples/iCalPortal/icons.make b/skyrix-sope/samples/iCalPortal/icons.make
new file mode 100644 (file)
index 0000000..77044bb
--- /dev/null
@@ -0,0 +1,29 @@
+# $Id: icons.make,v 1.1 2004/01/23 17:47:52 helge Exp $
+
+iCalPortal_LOCALIZED_WEBSERVER_RESOURCE_FILES += \
+       favicon.ico     \
+       site.css        \
+       pixel.gif       \
+       back_menu.gif   \
+       feedback.gif    \
+       line.gif        \
+       sidesmiley.gif  \
+       submit.gif      \
+       banner_a.gif \
+       banner_b.gif \
+       banner_c.gif \
+       banner_d.gif \
+       banner_e.gif \
+       \
+       back.gif        \
+       small.gif       \
+       wp_config.gif   \
+       wp_create.gif   \
+       wp_faq.gif      \
+       wp_feedback.gif \
+       wp_info.gif     \
+       free_hosting.gif\
+       \
+       tab_.gif        \
+       tab_left.gif    \
+       tab_selected.gif
diff --git a/skyrix-sope/samples/iCalPortal/mkpage.sh b/skyrix-sope/samples/iCalPortal/mkpage.sh
new file mode 100755 (executable)
index 0000000..8cdccfb
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+pgname="$1"
+actname=`echo "$pgname"|sed "s|Page|Action|g"`
+
+mfile="$pgname.m"
+woxfile="$pgname.wox"
+
+echo "// \$Id\$
+
+#include <NGObjWeb/WOComponent.h>
+#include <NGObjWeb/WODirectAction.h>
+
+@interface $pgname : WOComponent
+{
+}
+
+@end
+
+@interface $actname : WODirectAction
+@end
+
+#include \"common.h\"
+
+@implementation $pgname
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+/* accessors */
+
+/* actions */
+
+@end /* $pgname */
+
+@implementation $actname
+@end /* $actname */
+" >$mfile
+
+echo "<?xml version='1.0' standalone='yes'?>
+
+<var:component className='iCalPortalFrame' title='localizedTitle'
+               xmlns='http://www.w3.org/1999/xhtml'
+               xmlns:var='http://www.skyrix.com/od/binding'
+               xmlns:const='http://www.skyrix.com/od/constant'>
+
+  Page: $pgname
+
+</var:component>
+" >$woxfile
diff --git a/skyrix-sope/samples/parsedav/DAVParserTest.h b/skyrix-sope/samples/parsedav/DAVParserTest.h
new file mode 100644 (file)
index 0000000..706311d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __parsedav_DAVParserTest_H__
+#define __parsedav_DAVParserTest_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSArray, NSMutableDictionary;
+
+/*
+  Useful defaults:
+    DAVParserDebugProp
+    DAVParserHeavyLog
+*/
+
+@interface DAVParserTest : NSObject
+{
+  NSMutableDictionary *propQueue;
+}
+
+- (void)runWithArguments:(NSArray *)_args;
+
+@end
+
+#endif /* __parsedav_DAVParserTest_H__ */
diff --git a/skyrix-sope/samples/parsedav/DAVParserTest.m b/skyrix-sope/samples/parsedav/DAVParserTest.m
new file mode 100644 (file)
index 0000000..dc1366b
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DAVParserTest.h"
+#include "common.h"
+#include <NGObjWeb/SaxDAVHandler.h>
+#include <SaxObjC/SaxObjC.h>
+
+@implementation DAVParserTest
+
+static id<NSObject,SaxXMLReader> xmlParser = nil;
+static SaxDAVHandler             *davsax   = nil;
+
+- (id)init {
+  if ((self = [super init])) {
+    if (xmlParser == nil) {
+      xmlParser =
+        [[[SaxXMLReaderFactory standardXMLReaderFactory] 
+                               createXMLReaderForMimeType:@"text/xml"]
+                               retain];
+      if (xmlParser == nil) {
+        [self logWithFormat:@"found no XML-parser !"];
+        return nil;
+      }
+    }
+    if (davsax == nil) {
+      if ((davsax = [[SaxDAVHandler alloc] init]) == nil) {
+        [self logWithFormat:@"found no DAV SAX handler ..."];
+        return nil;
+      }
+      [davsax setDelegate:self];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->propQueue release];
+  [super dealloc];
+}
+
+/* parser */
+
+- (void)lockParser:(id)_sax {
+  [_sax reset];
+  [xmlParser setContentHandler:_sax];
+  [xmlParser setErrorHandler:_sax];
+}
+- (void)unlockParser:(id)_sax {
+  [xmlParser setContentHandler:nil];
+  [xmlParser setErrorHandler:nil];
+  [_sax reset];
+}
+
+/* the DAV parser reports properties using the prop-queue */
+
+- (void)startPropQueue {
+  if (self->propQueue)
+    [self->propQueue removeAllObjects];
+  else
+    self->propQueue = [[NSMutableDictionary alloc] initWithCapacity:128];
+}
+- (void)clearPropQueue {
+  [self->propQueue release]; 
+  self->propQueue = nil;
+}
+
+- (void)davHandler:(SaxDAVHandler *)_handler
+  receivedProperties:(NSDictionary *)_record
+  forURI:(NSString *)_uri
+{
+  /* Note: _record is volatile ! */
+  NSURL        *lurl;
+  NSDictionary *r;
+  
+  [self logWithFormat:@"PROPS on %@: %@", _uri, _record];
+  
+  lurl = [NSURL URLWithString:_uri];
+  r = [_record copy];
+  [self->propQueue setObject:r forKey:(lurl ? [lurl path] : _uri)];
+  [r release];
+}
+
+- (NSDictionary *)doQueueParseDict:(id)_src {
+  id results;
+  
+  [self startPropQueue];
+  [self lockParser:davsax];
+  [xmlParser parseFromSource:_src];
+  [self unlockParser:davsax];
+  results = [self->propQueue retain];
+  [self clearPropQueue];
+  return [results autorelease];
+}
+- (NSArray *)doQueueParse:(id)_src {
+  return [[self doQueueParseDict:_src] allValues];
+}
+
+/* running */
+
+- (void)printResults {
+  EOFetchSpecification *fs;
+  id tmp;
+  
+  /* responses */
+  
+  if ([self->propQueue count] > 0) {
+    [self logWithFormat:@"collected %i property sets: %@",
+            [self->propQueue count],
+            self->propQueue];
+  }
+  
+  /* patches */
+  
+  if ((tmp = [davsax propPatchValues]))
+    [self logWithFormat:@"patch %i values: %@", [tmp count], tmp];
+  if ((tmp = [davsax propPatchPropertyNamesToRemove]))
+    [self logWithFormat:@"remove %i properties: %@", [tmp count], tmp];
+  
+  /* queries */
+
+  if ([davsax propFindAllProperties])
+    [self logWithFormat:@"find all properties !"];
+  if ([davsax propFindPropertyNames])
+    [self logWithFormat:@"deliver only property names (not their values)"];
+  
+  if ((tmp = [davsax propFindQueriedNames]))
+    [self logWithFormat:@"find %i attributes: %@", [tmp count], tmp];
+  
+  if ((tmp = [davsax bpropFindTargets]))
+    [self logWithFormat:@"bulkfind %i targets: %@", [tmp count], tmp];
+
+  if ((fs = [davsax searchFetchSpecification]))
+    [self logWithFormat:@"search: %@", fs];
+}
+
+- (void)runOnArgument:(NSString *)_arg {
+  NSURL *url;
+  
+  if (xmlParser == nil || davsax == nil)
+    [self logWithFormat:@"missing XML-parser ..."];
+  
+  if (![_arg isAbsolutePath]) {
+    _arg = [[[NSFileManager defaultManager] currentDirectoryPath] 
+                            stringByAppendingPathComponent:_arg];
+  }
+  url = [[[NSURL alloc] initFileURLWithPath:_arg] autorelease];
+  [self logWithFormat:@"process %@: %@", _arg, url];
+  
+  [self startPropQueue];
+  [self lockParser:davsax];
+  
+  [xmlParser parseFromSource:url];
+  [self printResults];
+  
+  [self unlockParser:davsax];
+  [self clearPropQueue];
+}
+
+- (void)runWithArguments:(NSArray *)_args {
+  unsigned i, count;
+  
+  if ((count = [_args count]) == 1) {
+    [self logWithFormat:@"usage: %@ <files*>", [_args objectAtIndex:0]];
+    return;
+  }
+  
+  /* foreach arg */
+  for (i = 1; i < count; i++)
+    [self runOnArgument:[_args objectAtIndex:i]];
+}
+
+@end /* DAVParserTest */
diff --git a/skyrix-sope/samples/parsedav/GNUmakefile b/skyrix-sope/samples/parsedav/GNUmakefile
new file mode 100644 (file)
index 0000000..1ad78c2
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+TOOL_NAME = parsedav
+
+parsedav_OBJC_FILES = parsedav.m DAVParserTest.m
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/tool.make
+-include GNUmakefile.postamble
diff --git a/skyrix-sope/samples/parsedav/GNUmakefile.preamble b/skyrix-sope/samples/parsedav/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..073fcdb
--- /dev/null
@@ -0,0 +1,16 @@
+# $Id$
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I. -I..        \
+       -I../NGObjWeb
+
+ADDITIONAL_LIB_DIRS += \
+       -L../NGObjWeb/$(GNUSTEP_OBJ_DIR)        \
+       -L../NGScripting/$(GNUSTEP_OBJ_DIR)     \
+       -L../NGJavaScript/$(GNUSTEP_OBJ_DIR)    \
+       -L../SxComponents/$(GNUSTEP_OBJ_DIR)    \
+
+parsedav_TOOL_LIBS += \
+       -lNGObjWeb -lNGScripting \
+       -lNGMime -lNGStreams -lNGExtensions -lEOControl \
+       -lDOM -lXmlRpc -lSaxObjC
diff --git a/skyrix-sope/samples/parsedav/README b/skyrix-sope/samples/parsedav/README
new file mode 100644 (file)
index 0000000..5881232
--- /dev/null
@@ -0,0 +1,7 @@
+# $Id$
+
+parsedav
+========
+
+This directory contains sources for a tool to test the NGObjWeb WebDAV
+parser.
diff --git a/skyrix-sope/samples/parsedav/common.h b/skyrix-sope/samples/parsedav/common.h
new file mode 100644 (file)
index 0000000..d23d9bb
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+#include <NGExtensions/NGExtensions.h>
+
diff --git a/skyrix-sope/samples/parsedav/data/propupt1.xml b/skyrix-sope/samples/parsedav/data/propupt1.xml
new file mode 100644 (file)
index 0000000..4317a90
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:propertyupdate xmlns:D="DAV:"><D:set><D:prop><x001A001E xmlns="http://schemas.microsoft.com/mapi/proptag/">IPM.Task</x001A001E></D:prop></D:set>
+<D:set><D:prop><x85520003 xmlns="http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-c000-000000000046}/">92814</x85520003></D:prop></D:set>
+<D:set><D:prop><x850E000B xmlns="http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-c000-000000000046}/">0</x850E000B></D:prop></D:set>
+<D:set><D:prop><x1000001E xmlns="http://schemas.microsoft.com/mapi/proptag/"></x1000001E></D:prop></D:set>
+<D:set><D:prop><x300B0102 xmlns="http://schemas.microsoft.com/mapi/proptag/">NzM3MjVBMUQtNDIwNDZBNDMtQkI2NERGNzEtMDM0RjU5QTM=</x300B0102></D:prop></D:set>
+<D:set><D:prop><x81010003 xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">0</x81010003></D:prop></D:set>
+<D:set><D:prop><x8554001E xmlns="http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-c000-000000000046}/">9.0</x8554001E></D:prop></D:set>
+<D:set><D:prop><x85110003 xmlns="http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-c000-000000000046}/">0</x85110003></D:prop></D:set>
+<D:set><D:prop><x0042001E xmlns="http://schemas.microsoft.com/mapi/proptag/"></x0042001E></D:prop></D:set>
+<D:set><D:prop><x0FF40003 xmlns="http://schemas.microsoft.com/mapi/proptag/">7</x0FF40003></D:prop></D:set>
+<D:set><D:prop><x81120003 xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">2</x81120003></D:prop></D:set>
+<D:set><D:prop><x81130003 xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">1</x81130003></D:prop></D:set>
+<D:set><D:prop><x8506000B xmlns="http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-c000-000000000046}/">0</x8506000B></D:prop></D:set>
+<D:set><D:prop><x00360003 xmlns="http://schemas.microsoft.com/mapi/proptag/">0</x00360003></D:prop></D:set>
+<D:set><D:prop><x0E060040 xmlns="http://schemas.microsoft.com/mapi/proptag/">2003-03-03T12:54:04ZUTC</x0E060040></D:prop></D:set>
+<D:set><D:prop><x0002000B xmlns="http://schemas.microsoft.com/mapi/proptag/">1</x0002000B></D:prop></D:set>
+<D:set><D:prop><x0029000B xmlns="http://schemas.microsoft.com/mapi/proptag/">0</x0029000B></D:prop></D:set>
+<D:set><D:prop><x0E070003 xmlns="http://schemas.microsoft.com/mapi/proptag/">3</x0E070003></D:prop></D:set>
+<D:set><D:prop><x360B0003 xmlns="http://schemas.microsoft.com/mapi/proptag/">0</x360B0003></D:prop></D:set>
+<D:set><D:prop><x0037001E xmlns="http://schemas.microsoft.com/mapi/proptag/">test5</x0037001E></D:prop></D:set>
+<D:set><D:prop><x85010003 xmlns="http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-c000-000000000046}/">0</x85010003></D:prop></D:set>
+<D:set><D:prop><x3001001E xmlns="http://schemas.microsoft.com/mapi/proptag/">73725A1D-42046A43-BB64DF71-034F59A3</x3001001E></D:prop></D:set>
+<D:set><D:prop><x0E080003 xmlns="http://schemas.microsoft.com/mapi/proptag/">1616</x0E080003></D:prop></D:set>
+<D:set><D:prop><x8124000B xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">0</x8124000B></D:prop></D:set>
+<D:set><D:prop><x85180003 xmlns="http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-c000-000000000046}/">0</x85180003></D:prop></D:set>
+<D:set><D:prop><x0C1A001E xmlns="http://schemas.microsoft.com/mapi/proptag/"></x0C1A001E></D:prop></D:set>
+<D:set><D:prop><x0FF70003 xmlns="http://schemas.microsoft.com/mapi/proptag/">1</x0FF70003></D:prop></D:set>
+<D:set><D:prop><x811C000B xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">0</x811C000B></D:prop></D:set>
+<D:set><D:prop><x812C000B xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">1</x812C000B></D:prop></D:set>
+<D:set><D:prop><x85600040 xmlns="http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-c000-000000000046}/">8907-12-05T17:42:00ZUTC</x85600040></D:prop></D:set>
+<D:set><D:prop><x00390040 xmlns="http://schemas.microsoft.com/mapi/proptag/">2003-03-03T12:54:06ZUTC</x00390040></D:prop></D:set>
+<D:set><D:prop><x0E170003 xmlns="http://schemas.microsoft.com/mapi/proptag/">0</x0E170003></D:prop></D:set>
+<D:set><D:prop><x81290003 xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">0</x81290003></D:prop></D:set>
+<D:set><D:prop><x8121001E xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/"></x8121001E></D:prop></D:set>
+<D:set><D:prop><x81230003 xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">-2000</x81230003></D:prop></D:set>
+<D:set><D:prop><x81020005 xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">0.000000</x81020005></D:prop></D:set>
+<D:set><D:prop><x812A0003 xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">0</x812A0003></D:prop></D:set>
+<D:set><D:prop><x811F001E xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">Ich</x811F001E></D:prop></D:set>
+<D:set><D:prop><x30050003 xmlns="http://schemas.microsoft.com/mapi/proptag/">0</x30050003></D:prop></D:set>
+<D:set><D:prop><x8503000B xmlns="http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-c000-000000000046}/">0</x8503000B></D:prop></D:set>
+<D:set><D:prop><x85100003 xmlns="http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-c000-000000000046}/">272</x85100003></D:prop></D:set>
+<D:set><D:prop><x0070001E xmlns="http://schemas.microsoft.com/mapi/proptag/">test5</x0070001E></D:prop></D:set>
+<D:set><D:prop><x0C1E001E xmlns="http://schemas.microsoft.com/mapi/proptag/"></x0C1E001E></D:prop></D:set>
+<D:set><D:prop><x003D001E xmlns="http://schemas.microsoft.com/mapi/proptag/"></x003D001E></D:prop></D:set>
+<D:set><D:prop><x81100003 xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">0</x81100003></D:prop></D:set>
+<D:set><D:prop><x8103000B xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">0</x8103000B></D:prop></D:set>
+<D:set><D:prop><x00710102 xmlns="http://schemas.microsoft.com/mapi/proptag/">AcLhg/ld+VdUbUxoRXe+19hki5cPFg==</x00710102></D:prop></D:set>
+<D:set><D:prop><x0C1F001E xmlns="http://schemas.microsoft.com/mapi/proptag/"></x0C1F001E></D:prop></D:set>
+<D:set><D:prop><x0064001E xmlns="http://schemas.microsoft.com/mapi/proptag/"></x0064001E></D:prop></D:set>
+<D:set><D:prop><x0023000B xmlns="http://schemas.microsoft.com/mapi/proptag/">0</x0023000B></D:prop></D:set>
+<D:set><D:prop><x30070040 xmlns="http://schemas.microsoft.com/mapi/proptag/">2003-03-03T12:37:05ZUTC</x30070040></D:prop></D:set>
+<D:set><D:prop><x81110003 xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">0</x81110003></D:prop></D:set>
+<D:set><D:prop><x8126000B xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/">0</x8126000B></D:prop></D:set>
+<D:set><D:prop><x00170003 xmlns="http://schemas.microsoft.com/mapi/proptag/">1</x00170003></D:prop></D:set>
+<D:set><D:prop><x0065001E xmlns="http://schemas.microsoft.com/mapi/proptag/"></x0065001E></D:prop></D:set>
+<D:set><D:prop><x0E01000B xmlns="http://schemas.microsoft.com/mapi/proptag/">0</x0E01000B></D:prop></D:set>
+<D:set><D:prop><x10800003 xmlns="http://schemas.microsoft.com/mapi/proptag/">1280</x10800003></D:prop></D:set>
+<D:set><D:prop><x8127001E xmlns="http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-c000-000000000046}/"></x8127001E></D:prop></D:set>
+<D:set><D:prop><x00260003 xmlns="http://schemas.microsoft.com/mapi/proptag/">0</x00260003></D:prop></D:set>
+<D:set><D:prop><x0E1D001E xmlns="http://schemas.microsoft.com/mapi/proptag/">test5</x0E1D001E></D:prop></D:set>
+</D:propertyupdate>
diff --git a/skyrix-sope/samples/parsedav/parsedav.m b/skyrix-sope/samples/parsedav/parsedav.m
new file mode 100644 (file)
index 0000000..a43a7a6
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DAVParserTest.h"
+#include "common.h"
+
+/* main */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+  DAVParserTest *test;
+
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY  
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  test = [[DAVParserTest alloc] init];
+  [test runWithArguments:
+          [[NSProcessInfo processInfo] argumentsWithoutDefaults]];
+  [test release];
+  
+  [pool release];
+  exit(0);
+  /* static linking */
+  [NGExtensions class];
+  return 0;
+}
diff --git a/skyrix-xml/CFXMLSaxDriver/CFXMLSaxDriver-Info.plist b/skyrix-xml/CFXMLSaxDriver/CFXMLSaxDriver-Info.plist
new file mode 100644 (file)
index 0000000..3d46e76
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>CFXMLSaxDriver</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>org.opengroupware.xml.CFXMLSaxDriver</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+       <key>NSPrincipalClass</key>
+       <string>CFXMLSaxDriver</string>
+</dict>
+</plist>
diff --git a/skyrix-xml/CFXMLSaxDriver/CFXMLSaxDriver.h b/skyrix-xml/CFXMLSaxDriver/CFXMLSaxDriver.h
new file mode 100644 (file)
index 0000000..ceb41a0
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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/NSObject.h>
+#include <SaxObjC/SaxObjC.h>
+
+@class NSString, NSMutableDictionary;
+
+@interface CFXMLSaxDriver : NSObject < SaxXMLReader >
+{
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+  id<NSObject,SaxLexicalHandler> lexicalHandler;
+  id<NSObject,SaxEntityResolver> entityResolver;
+  NSMutableDictionary *pubIdToValue;
+
+  int            depth;
+  NSMutableArray *nsStack;
+  BOOL           fNamespaces;
+  BOOL           fNamespacePrefixes;
+  
+  unichar  *buffer;
+  unsigned bufSize;
+
+  SaxAttributes *attrs;
+}
+
+/* handlers */
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler;
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler;
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler;
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler;
+- (id<NSObject,SaxContentHandler>)contentHandler;
+- (id<NSObject,SaxDTDHandler>)dtdHandler;
+- (id<NSObject,SaxErrorHandler>)errorHandler;
+- (id<NSObject,SaxEntityResolver>)entityResolver;
+
+/* parsing */
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId;
+
+@end
diff --git a/skyrix-xml/CFXMLSaxDriver/CFXMLSaxDriver.m b/skyrix-xml/CFXMLSaxDriver/CFXMLSaxDriver.m
new file mode 100644 (file)
index 0000000..e1adc8a
--- /dev/null
@@ -0,0 +1,881 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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 "CFXMLSaxDriver.h"
+#import <Foundation/Foundation.h>
+
+@interface CFXMLTagHolder : NSObject
+{
+@public
+  NSString *localName;
+  NSString *uri;
+  NSString *prefix;
+  NSString *rawName;
+}
+@end
+
+static NSString *SaxDeclHandlerProperty =
+  @"http://xml.org/sax/properties/declaration-handler";
+static NSString *SaxLexicalHandlerProperty =
+  @"http://xml.org/sax/properties/lexical-handler";
+
+@interface CFXMLSaxDriver(Privates)
+- (NSString *)nsUriForPrefix:(NSString *)_prefix;
+- (NSString *)defaultNamespace;
+- (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri;
+@end
+
+@implementation CFXMLSaxDriver
+
+static BOOL debugNS = NO;
+
+- (id)init {
+  if ((self = [super init])) {
+    self->pubIdToValue = [[NSMutableDictionary alloc] init];
+    [self->pubIdToValue setObject:@"<"  forKey:@"lt"];
+    [self->pubIdToValue setObject:@">"  forKey:@"gt"];
+    [self->pubIdToValue setObject:@"\"" forKey:@"quot"];
+    [self->pubIdToValue setObject:@"&"  forKey:@"amp"];
+
+    self->nsStack = [[NSMutableArray alloc] init];
+  
+    /* feature defaults */
+    self->fNamespaces        = YES;
+    self->fNamespacePrefixes = NO;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->attrs   release];
+  [self->nsStack release];
+
+  if (self->buffer) free(self->buffer);
+
+  [self->pubIdToValue   release];
+  [self->lexicalHandler release];
+  [self->contentHandler release];
+  [self->errorHandler   release];
+  [self->entityResolver release];
+  [super dealloc];
+}
+
+/* properties */
+
+- (void)setProperty:(NSString *)_name to:(id)_value {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
+    [self->lexicalHandler autorelease];
+    self->lexicalHandler = [_value retain];
+    return;
+  }
+  if ([_name isEqualToString:SaxDeclHandlerProperty]) {
+    return;
+  }
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+}
+- (id)property:(NSString *)_name {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty])
+    return self->lexicalHandler;
+  if ([_name isEqualToString:SaxDeclHandlerProperty])
+    return nil;
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+  return nil;
+}
+
+/* features */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value {
+  if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
+    self->fNamespaces = _value;
+    return;
+  }
+  
+  if ([_name isEqualToString:
+               @"http://xml.org/sax/features/namespace-prefixes"]) {
+    self->fNamespacePrefixes = _value;
+    return;
+  }
+
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+}
+- (BOOL)feature:(NSString *)_name {
+  if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
+    return self->fNamespaces;
+  
+  if ([_name isEqualToString:
+               @"http://xml.org/sax/features/namespace-prefixes"])
+    return self->fNamespacePrefixes;
+  
+  if ([_name isEqualToString:
+               @"http://www.skyrix.com/sax/features/predefined-namespaces"])
+    return YES;
+  
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+  return NO;
+}
+
+/* handlers */
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  [self->contentHandler autorelease];
+  self->contentHandler = [_handler retain];
+}
+- (id<NSObject,SaxContentHandler>)contentHandler {
+  return self->contentHandler;
+}
+
+- (void)setLexicalHandler:(id<NSObject,SaxLexicalHandler>)_handler {
+  [self->lexicalHandler autorelease];
+  self->lexicalHandler = [_handler retain];
+}
+- (id<NSObject,SaxLexicalHandler>)lexicalHandler {
+  return self->lexicalHandler;
+}
+
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
+}
+- (id<NSObject,SaxDTDHandler>)dtdHandler {
+  return nil;
+}
+
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  [self->errorHandler autorelease];
+  self->errorHandler = [_handler retain];
+}
+- (id<NSObject,SaxErrorHandler>)errorHandler {
+  return self->errorHandler;
+}
+
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
+  [self->entityResolver autorelease];
+  self->entityResolver = [_handler retain];
+}
+- (id<NSObject,SaxEntityResolver>)entityResolver {
+  return self->entityResolver;
+}
+
+/* method callbacks */
+
+- (void)beginDocument:(CFXMLNodeRef)_node {
+  const CFXMLDocumentInfo *docInfoPtr;
+  
+  docInfoPtr = CFXMLNodeGetInfoPtr(_node);
+  //NSLog(@"begin-doc: url=%@", docInfoPtr->sourceURL);
+}
+- (void)endDocument:(id)_node {
+  //NSLog(@"end-doc.");
+}
+
+- (id<SaxAttributes>)handleAttributesOfNode:(CFXMLNodeRef)_node 
+  nsdecls:(NSDictionary **)_ns
+  defaultPrefix:(NSString *)_defAttrNS
+{
+  const CFXMLElementInfo *elemInfo;
+  unsigned count, i, nsCount;
+  NSMutableDictionary *ns = nil;
+  
+  if ((elemInfo = CFXMLNodeGetInfoPtr(_node)) == NULL)
+    return nil;
+  
+  if ((count = [(NSArray *)elemInfo->attributeOrder count]) == 0)
+    return nil;
+  
+  /* pass one: collect all namespace declarations */
+  
+  for (i = 0, nsCount = 0; i < count; i++) {
+    NSString *attrName, *prefix, *uri;
+    NSRange r;
+    
+    attrName = [(NSArray *)elemInfo->attributeOrder objectAtIndex:i];
+    if (![attrName hasPrefix:@"xmlns"]) continue;
+
+    /* ok, found ns decl */
+    if (ns == nil) ns = [[[NSMutableDictionary alloc] init] autorelease];
+    
+    nsCount++;
+    r = [attrName rangeOfString:@"xmlns:"];
+    prefix = r.length == 0
+      ? nil
+      : [attrName substringFromIndex:(r.location + r.length)];
+    uri = [(NSDictionary *)elemInfo->attributes objectForKey:attrName];
+    
+    if (prefix) {
+      /* eg <x xmlns:nl="http://www.w3.org"/> */
+      [ns setObject:uri forKey:prefix];
+        
+      if (self->fNamespaces)
+        [self->contentHandler startPrefixMapping:prefix uri:uri];
+    }
+    else {
+      /* eg <x xmlns="http://www.w3.org"/> */
+      [ns setObject:uri forKey:@":"];
+    }
+  }
+  *_ns = (ns != nil) ? [[ns copy] autorelease] : nil;
+  
+  if (nsCount == count) /* all attrs were namespace declarations */
+    return nil;
+    
+  /* pass two: user attributes */
+  
+  for (i = 0; i < count; i++) {
+    NSString *attrName, *prefix, *localName, *uri;
+    NSString *value;
+    NSRange  r;
+    
+    attrName = [(NSArray *)elemInfo->attributeOrder objectAtIndex:i];
+    if (nsCount > 0) { /* do not consider namespace decls */
+      if ([attrName hasPrefix:@"xmlns"])  {
+        nsCount--;
+        continue;
+      }
+    }
+    
+    r = [attrName rangeOfString:@":"];
+    if (r.length == 0) { /* no prefix, use element namespace */
+      prefix    = nil;
+      localName = attrName;
+      
+      /* def-namespace for attributes is 1. element, 2. context */
+      if (_defAttrNS) {
+        if ((uri = [ns objectForKey:_defAttrNS]) == nil) {
+          if ((uri = [self nsUriForPrefix:_defAttrNS]) == nil) {
+            NSLog(@"ERROR: did not find namespace for element prefix '%@' !",
+                  _defAttrNS);
+            uri = [self defaultNamespace];
+          }
+        }
+      }
+      else
+        uri = [self defaultNamespace];
+    }
+    else { /*  has prefix, lookup namespace */
+      prefix    = [attrName substringToIndex:r.location];
+      localName = [attrName substringFromIndex:(r.location + r.length)];
+      if ((uri = [ns objectForKey:prefix]) == nil)
+        uri = [self nsUriForPrefix:prefix];
+    }
+    
+    value = [(NSDictionary *)elemInfo->attributes objectForKey:attrName];
+    
+    [self->attrs addAttribute:localName uri:uri rawName:attrName
+                 type:@"CDATA" value:value];
+  }
+  return self->attrs;
+}
+
+- (CFXMLTagHolder *)beginElementNode:(CFXMLNodeRef)_node {
+  CFXMLTagHolder    *info;
+  id<SaxAttributes> lattrs;
+  NSDictionary      *nsDict = nil;
+  NSRange r;
+  
+  info = [[CFXMLTagHolder alloc] init];
+  info->rawName = [(NSString *)CFXMLNodeGetString(_node) copy];
+  
+  /* prepare tagname processing */
+  
+  r = [info->rawName rangeOfString:@":"];
+  if (r.length == 0) { /* no namespace prefix */
+    info->prefix    = nil;
+    info->localName = [info->rawName copy];
+  }
+  else { /* has a namespace prefix */
+    info->prefix    =
+      [[info->rawName substringToIndex:r.location] copy];
+    info->localName = 
+      [[info->rawName substringFromIndex:(r.location + r.length)] copy];
+  }
+  
+  /* process attribute information (first for ns declarations) */
+  
+  if (self->attrs == nil)
+    self->attrs = [[SaxAttributes alloc] init];
+  else
+    [self->attrs clear];
+  
+  if (debugNS) NSLog(@"PROCESS attributes ...");
+  lattrs = [self handleAttributesOfNode:_node 
+                 nsdecls:&nsDict
+                 defaultPrefix:info->prefix];
+  if (nsDict == nil)
+    nsDict = [NSDictionary dictionary];
+  
+  NSCAssert(self->nsStack, @"missing namespace stack");
+  [self->nsStack addObject:nsDict];
+  
+  /* do namespace processing */
+  
+  info->uri = (info->prefix == nil)
+    ? nil /* no namespace prefix */
+    : [[self nsUriForPrefix:info->prefix] copy];
+  if (info->uri == nil) info->uri = [[self defaultNamespace] copy];
+  if (debugNS)
+    NSLog(@"TAG PREFIX: %@ URI: %@", info->prefix, info->uri);
+  
+  /* pass on */
+  
+  self->depth++;
+  [self->contentHandler startElement:info->localName
+                        namespace:info->uri
+                        rawName:info->rawName
+                        attributes:lattrs /* id<SaxAttributes> */];
+  return info; /* pass back an object */
+}
+- (void)endElementNode:(CFXMLTagHolder *)_info {
+  [self->contentHandler endElement:_info->localName
+                        namespace:_info->uri
+                        rawName:_info->rawName];
+  self->depth--;
+  [_info release];
+
+  /* process namespace stack */
+
+  if (self->fNamespaces) {
+    NSDictionary *ns;
+    NSEnumerator *keys;
+    NSString     *key;
+    
+    ns = [self->nsStack lastObject];
+    keys = [ns keyEnumerator];
+    while ((key = [keys nextObject])) {
+      if ([key isEqualToString:@":"])
+        continue;
+      [self->contentHandler endPrefixMapping:key];
+    }
+  }
+  [self->nsStack removeLastObject];
+}
+
+- (void)piNode:(CFXMLNodeRef)_node {
+  [self->contentHandler processingInstruction:(id)CFXMLNodeGetString(_node)
+                        data:nil];
+}
+
+- (void)commentNode:(CFXMLNodeRef)_node {
+  NSString *s;
+  unichar  *buf;
+  unsigned len;
+  
+  s   = (NSString *)CFXMLNodeGetString(_node);
+  len = [s length];
+  buf = calloc(len + 4, sizeof(unichar));
+  [s getCharacters:buf];
+  
+  [self->lexicalHandler comment:buf length:len];
+  if (buf) free(buf);
+}
+
+- (void)_unicharNode:(CFXMLNodeRef)_node selector:(SEL)_sel {
+  NSString *s;
+  unsigned len;
+  unichar *ownBuf = NULL, *useBuf;
+  void (*cb)(id, SEL, unichar *, int);
+  
+  if (self->contentHandler == nil)
+    return;
+  if ((s = (NSString *)CFXMLNodeGetString(_node)) == nil)
+    return;
+  if ((len = [s length]) == 0)
+    return;
+  
+  if ((cb = (void *)[(id)self->contentHandler methodForSelector:_sel])==NULL) {
+    /* content-handler does not respond to the selector */
+    NSLog(@"ERROR(%s): content handler does not implement %@: %@",
+          __PRETTY_FUNCTION__,
+          NSStringFromSelector(_sel), self->contentHandler);
+    return;
+  }
+  
+  if (self->buffer == NULL) {
+    self->buffer  = calloc(256, sizeof(unichar));
+    self->bufSize = 250;
+  }
+  if (len > 250) { /* use an own buffer for larger bodies */
+    ownBuf = calloc(len + 10, sizeof(unichar));
+    useBuf = ownBuf;
+  }
+  else
+    useBuf = self->buffer;
+  
+  [s getCharacters:useBuf];
+  cb(self->contentHandler, _sel, useBuf, len);
+  
+  if (ownBuf) free(ownBuf);
+}
+
+- (void)textNode:(CFXMLNodeRef)_node {
+  if (self->contentHandler == nil) return;
+  [self _unicharNode:_node selector:@selector(characters:length:)];
+}
+- (void)cdataNode:(CFXMLNodeRef)_node {
+  if (self->contentHandler == nil) return;
+  [self _unicharNode:_node selector:@selector(characters:length:)];
+}
+- (void)whiteSpaceNode:(CFXMLNodeRef)_node {
+  if (self->contentHandler == nil) return;
+  [self _unicharNode:_node selector:@selector(ignorableWhitespace:length:)];
+}
+
+- (void)dtdNode:(CFXMLNodeRef)_node {
+  NSLog(@"DTD: %@", CFXMLNodeGetString(_node));
+}
+
+- (void)entityReference:(NSString *)_rid {
+  NSString *value;
+  
+  if (self->contentHandler == nil)
+    return;
+  
+  if ((value = [self->pubIdToValue objectForKey:_rid]) == nil) {
+    NSLog(@"ERROR(%s): found no value for entity reference %@", 
+          __PRETTY_FUNCTION__, _rid);
+  }
+  
+  if ([value isKindOfClass:[NSString class]]) {
+    unsigned len;
+    unichar  *ownBuf;
+    
+    len = [value length];
+    ownBuf = calloc(len + 4, sizeof(unichar));
+    [value getCharacters:ownBuf];
+    [self->contentHandler characters:ownBuf length:len];
+    if (ownBuf) free(ownBuf);
+  }
+  else
+    NSLog(@"unknown value class for entity reference %@", _rid);
+}
+
+- (NSData *)resolveEntityWithPublicId:(NSString *)_pubId
+  systemId:(NSURL *)_sysId
+{
+  NSLog(@"found to value for entity %@/%@", _pubId, _sysId);
+  return nil;
+}
+
+- (BOOL)handleErrorCode:(unsigned int)_code
+  description:(NSString *)_info 
+  line:(int)_line position:(int)_pos
+{
+  NSLog(@"Parse error (%d) %@ on line %d, character %d\n",
+        (int)_code, _info, _line, _pos);
+  return NO;
+}
+
+/* callbacks */
+
+typedef struct {
+  id  info;
+  int typeCode;
+} ResInfo;
+
+void *createStructure(CFXMLParserRef parser, 
+                      CFXMLNodeRef node, void *info) 
+{
+  CFXMLSaxDriver *self = info;
+  CFStringRef myTypeStr = NULL;
+  CFStringRef myDataStr = NULL;
+  ResInfo *result = NULL;
+  
+  result = malloc(sizeof(ResInfo));
+  result->info = nil;
+  result->typeCode = CFXMLNodeGetTypeCode(node);
+  
+  // Use the dataTypeID to determine what to print.
+  switch (CFXMLNodeGetTypeCode(node)) {
+    case kCFXMLNodeTypeDocument:
+      [self beginDocument:node];
+      break;
+    
+    case kCFXMLNodeTypeElement:
+      result->info = [self beginElementNode:node];
+      break;
+    
+    case kCFXMLNodeTypeProcessingInstruction:
+      [self piNode:node];
+      break;
+      
+    case kCFXMLNodeTypeComment:
+      [self commentNode:node];
+      break;
+      
+    case kCFXMLNodeTypeText:
+      [self textNode:node];
+      break;
+      
+    case kCFXMLNodeTypeCDATASection:
+      [self cdataNode:node];
+      break;
+      
+    case kCFXMLNodeTypeEntityReference:
+      [self entityReference:(NSString *)CFXMLNodeGetString(node)];
+      break;
+        
+    case kCFXMLNodeTypeDocumentType:
+      [self dtdNode:node];
+      break;
+    
+    case kCFXMLNodeTypeWhitespace:
+      [self whiteSpaceNode:node];
+      break;
+      
+    default:
+      NSLog(@"%s: unknown node ID %i", result->typeCode);
+      break;
+  }
+
+  // Print the contents.
+  if (myTypeStr) {
+    printf("---Create Structure Called--- \n");
+    NSLog(@"type: %@", myTypeStr);
+    NSLog(@"data: %@", myDataStr);
+  }
+  
+  // Release the strings.
+  if (myTypeStr) CFRelease(myTypeStr);
+  
+  // Return the data string for use by the addChild and 
+  // endStructure callbacks.
+  return result;
+}
+
+void addChild(CFXMLParserRef parser, void *p, void *child, void *info) {
+#if 0 /* a noop */
+  NSLog(@"add child %@ to %@ ...", (id)child, (id)p);
+#endif
+}
+
+void endStructure(CFXMLParserRef parser, void *xmlType, void *info) {
+  CFXMLSaxDriver *self = info;
+  ResInfo *result = xmlType;
+  NSCAssert(self, @"missing self");
+  
+  switch (result->typeCode) {
+    case kCFXMLNodeTypeDocument: /* never called ? */
+      [self endDocument:result->info];
+      break;
+    
+    case kCFXMLNodeTypeElement:
+      [self endElementNode:result->info];
+      break;
+    
+    /* most nodes do not have an "end" event */
+    case kCFXMLNodeTypeProcessingInstruction:
+    case kCFXMLNodeTypeComment:
+    case kCFXMLNodeTypeText:
+    case kCFXMLNodeTypeCDATASection:
+    case kCFXMLNodeTypeEntityReference:
+    case kCFXMLNodeTypeDocumentType:
+    case kCFXMLNodeTypeWhitespace:
+      break;
+    
+    default:
+      NSLog(@"%s: unknown node: %i: %@", __PRETTY_FUNCTION__,
+            result->typeCode, result->info);
+      break;
+  }
+  if (result) free(result);
+}
+
+CFDataRef resolveEntity(CFXMLParserRef parser, CFXMLExternalID *extID, 
+                        void *info)
+{
+  CFXMLSaxDriver *self = info;
+  return (CFDataRef)[self resolveEntityWithPublicId:(NSString *)extID->publicID
+                          systemId:(NSURL *)extID->systemID];
+}
+
+Boolean handleError(CFXMLParserRef parser, CFXMLParserStatusCode error, void *info) {
+  CFXMLSaxDriver *self = info;
+  NSString *s;
+  BOOL     cont;
+  
+  s = [(id)CFXMLParserCopyErrorDescription(parser) autorelease];
+  cont = [self handleErrorCode:error description:s
+               line:(int)CFXMLParserGetLineNumber(parser)
+               position:(int)CFXMLParserGetLocation(parser)];
+  return cont ? TRUE : FALSE;
+}
+
+/* parsing */
+
+- (NSStringEncoding)encodingForXMLEncodingString:(NSString *)_enc {
+  if ([_enc isEqualToString:@"utf-8"])
+    return NSUTF8StringEncoding;
+  else if ([_enc isEqualToString:@"iso-8859-1"])
+    return NSISOLatin1StringEncoding;
+  else if ([_enc isEqualToString:@"ascii"])
+    return NSASCIIStringEncoding;
+  else {
+    NSLog(@"%s: UNKNOWN XML ENCODING '%@'",
+          __PRETTY_FUNCTION__, _enc);
+  }
+  return 0;
+}
+
+- (NSData *)dataForXMLString:(NSString *)_string {
+  NSData  *data;
+  NSRange r;
+
+  data = nil;
+  
+  r = [_string rangeOfString:@"?>"];
+  if ([_string hasPrefix:@"<?xml "] && (r.length != 0)) {
+    NSString *xmlDecl;
+    
+    xmlDecl = [_string substringToIndex:r.location];
+    
+    r = [xmlDecl rangeOfString:@"encoding='"];
+    if (r.length > 0) {
+      xmlDecl = [_string substringFromIndex:(r.location + 10)];
+      r = [xmlDecl rangeOfString:@"'"];
+      xmlDecl = (r.length > 0)
+        ? [xmlDecl substringToIndex:r.location]
+        : nil;
+    }
+    else {
+      r = [xmlDecl rangeOfString:@"encoding=\""];
+      if (r.length > 0) {
+        xmlDecl = [_string substringFromIndex:(r.location + 10)];
+        r = [xmlDecl rangeOfString:@"'"];
+        xmlDecl = r.length > 0
+          ? [xmlDecl substringToIndex:r.location]
+          : nil;
+      }
+      else
+      xmlDecl = nil;
+    }
+    
+    if ([xmlDecl length] > 0) {
+      NSStringEncoding enc;
+        
+      if ((enc = [self encodingForXMLEncodingString:xmlDecl]) != 0) {
+        data = [_string dataUsingEncoding:enc];
+        if (data == nil) {
+          NSLog(@"WARNING(%s): couldn't get data for string '%@', "
+                @"encoding %i !", __PRETTY_FUNCTION__, _string, enc);
+          return nil;
+        }
+      }
+    }
+  }
+  
+  if (data == nil)
+    data = [_string dataUsingEncoding:NSUTF8StringEncoding];
+
+  return data;
+}
+
+static const void *retainParser(const void *info) {
+  return [(id)info retain];
+}
+static void releaseParser(const void *info) {
+  [(id)info release];
+}
+static CFStringRef parserDescription(const void *info) {
+  return (CFStringRef)[(id)info description];
+}
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
+  CFXMLParserCallBacks callbacks = {
+    0,
+    createStructure,
+    addChild,
+    endStructure, 
+    resolveEntity,
+    handleError
+  };
+  CFXMLParserContext ctx = {
+    0    /* version */,
+    self /* info */,
+    retainParser,
+    releaseParser,
+    parserDescription /* copyDescription */
+  };
+  CFXMLParserRef parser;
+  NSData *content;
+  NSURL  *url = nil;
+  
+  if (_source == nil) {
+    /* no source ??? */
+    return;
+  }
+  
+  if ([_source isKindOfClass:[NSString class]]) {
+    /* convert strings to UTF8 data */
+    if (_sysId == nil) _sysId = @"<string>";
+    _source = [self dataForXMLString:_source];
+  }
+  else if ([_source isKindOfClass:[NSURL class]]) {
+    if (_sysId == nil) _sysId = [_source absoluteString];
+    _source = [_source resourceDataUsingCache:NO];
+  }
+  else if ([_source isKindOfClass:[NSData class]]) {
+    if (_sysId == nil) _sysId = @"<data>";
+  }
+  else {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _source ? _source : @"<nil>", @"source",
+                         self,                         @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"can't handle data-source"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+    return;
+  }
+  
+  /* get data from source */
+  
+  content = _source;
+  
+  if (url == nil) {
+    url = _sysId 
+      ? [NSURL URLWithString:_sysId] 
+      : [NSURL URLWithString:@"object://unknown"];
+  }
+  
+  /* create parser */
+  
+  parser = CFXMLParserCreate(kCFAllocatorDefault, 
+                             (CFDataRef)content, 
+                             (CFURLRef)url,
+                             kCFXMLParserSkipWhitespace,
+                             kCFXMLNodeCurrentVersion, 
+                             &callbacks,
+                             &ctx);
+  if (parser == nil) {
+    NSLog(@"got no parser ...");
+    exit(1);
+  }
+  
+  /* invoke the parser */
+  
+  [self->contentHandler startDocument];
+  
+  if (!CFXMLParserParse(parser))
+    printf("parse failed\n");
+
+  [self->contentHandler endDocument];
+  
+  /* cleanup */
+  if (parser) CFRelease(parser);
+}
+
+- (void)parseFromSource:(id)_source {
+  [self parseFromSource:_source systemId:nil];
+}
+- (void)parseFromSystemId:(NSString *)_sysId {
+  NSURL *url;
+  
+  if ([_sysId rangeOfString:@"://"].length == 0) {
+    /* not a URL */
+    if (![_sysId isAbsolutePath])
+      _sysId = [[NSFileManager defaultManager] currentDirectoryPath];
+    url = [NSURL fileURLWithPath:_sysId];
+  }
+  else
+    url = [NSURL URLWithString:_sysId];
+  
+  [self parseFromSource:url systemId:_sysId];
+}
+
+/* namespace support */
+
+- (NSString *)nsUriForPrefix:(NSString *)_prefix {
+  NSEnumerator *e;
+  NSDictionary *ns;
+  
+  if (debugNS)
+    NSLog(@"lookup prefix: '%@'", _prefix);
+  
+  e = [self->nsStack reverseObjectEnumerator];
+  while ((ns = [e nextObject])) {
+    NSString *uri;
+    
+    if ((uri = [ns objectForKey:_prefix])) {
+      if (debugNS)
+        NSLog(@"prefix %@ -> uri '%@'", _prefix, uri);
+      return uri;
+    }
+  }
+  if (debugNS)
+    NSLog(@"prefix %@ -> NO uri", _prefix);
+  //return nil;
+  return @"";
+}
+
+- (NSString *)defaultNamespace {
+  return [self nsUriForPrefix:@":"];
+}
+
+- (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri {
+  NSMutableDictionary *ns = nil;
+  NSDictionary *newns;
+  unsigned count;
+  
+  NSCAssert(self->nsStack, @"missing namespace stack");
+  
+  if ((count = [self->nsStack count]) == 0)
+    ns = [[NSMutableDictionary alloc] initWithCapacity:2];
+  else
+    ns = [[self->nsStack lastObject] mutableCopy];
+  
+  if ([_prefix length] == 0)
+    _prefix = @":";
+  
+  [ns setObject:_uri forKey:_prefix];
+
+  newns = [ns copy];
+  [ns release];
+
+  if (count == 0)
+    [self->nsStack addObject:newns];
+  else
+    [self->nsStack replaceObjectAtIndex:(count - 1) withObject:newns];
+  
+  [newns release];
+}
+
+@end /* CFXMLSaxDriver */
+
+@implementation CFXMLTagHolder
+
+- (void)dealloc {
+  [self->localName release];
+  [self->uri       release];
+  [self->prefix    release];
+  [self->rawName   release];
+  [super dealloc];
+}
+
+@end /* CFXMLTagHolder */
diff --git a/skyrix-xml/CFXMLSaxDriver/COPYING b/skyrix-xml/CFXMLSaxDriver/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-xml/CFXMLSaxDriver/ChangeLog b/skyrix-xml/CFXMLSaxDriver/ChangeLog
new file mode 100644 (file)
index 0000000..58fab43
--- /dev/null
@@ -0,0 +1,24 @@
+2004-04-13  Helge Hess  <helge.hess@opengroupware.org>
+
+       * CFXMLSaxDriver.m: do not dump core if the contentHandler callback
+          doesn't implement a proper character selector or if no contentHandler
+          is set
+
+2004-02-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * CFXMLSaxDriver.m: major fix to namespace processing (was not able to
+         properly parse .wox templates before)
+
+2003-09-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * CFXMLSaxDriver.m: fixed warnings on invalid prototypes for error
+          reporting and entity resolution CFXML callbacks (at least the entity
+          callback was completely wrong)
+        
+2003-05-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * CFXMLSaxDriver.m (-handleAttributesOfNode:nsdecls:defaultPrefix:): 
+         fixed a namespace processing bug, attributes did not inherit the 
+         namespace of their element as their default namespace
+
+       * created ChangeLog
diff --git a/skyrix-xml/CFXMLSaxDriver/README b/skyrix-xml/CFXMLSaxDriver/README
new file mode 100644 (file)
index 0000000..8dc41d9
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id$
+
+CFXMLSaxDriver
+==============
+
+This directory contains the sources for a SAX driver bundle which is based
+on the MacOSX CoreFoundation XML parser.
+
+Requirements:
+- MacOSX
diff --git a/skyrix-xml/CFXMLSaxDriver/bundle-info.plist b/skyrix-xml/CFXMLSaxDriver/bundle-info.plist
new file mode 100644 (file)
index 0000000..81a48f1
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "__cvs__" = "$Id: bundle-info.plist,v 1.1.1.1 2003/07/09 22:57:27 cvs Exp $";
+
+  requires = {
+    bundleManagerVersion = 1;
+    classes = (
+      { name = NSObject;    }
+    );
+  };
+  
+  provides = {
+    SAXDrivers = ( 
+        { 
+          name        = CFXMLSaxDriver;
+          sourceTypes = ( "text/xml" ); 
+        }
+    );
+    classes = ( { name = CFXMLSaxDriver;  } );
+  };
+}
diff --git a/skyrix-xml/COPYING b/skyrix-xml/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-xml/COPYRIGHT b/skyrix-xml/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-xml/ChangeLog b/skyrix-xml/ChangeLog
new file mode 100644 (file)
index 0000000..aa02064
--- /dev/null
@@ -0,0 +1,52 @@
+2004-08-03  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SxXML.xcode: fixed missing SaxObjC build dependency. libxmlSAXDriver is
+         now built before SaxObjC, so copying it in the framework's wrapper will
+         succeed.
+
+2004-07-21  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * README-OSX.txt: Major overhaul for build description, especially the
+         Xcode section.
+
+2004-07-16  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SxXML.xcode: added 'Wrapper' build style and 'Wrapper Contents'
+         target.  Use these to build the frameworks in an appropriate form to
+         have them embedded in an applications app wrapper's 'Frameworks'
+         folder.
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * ExpatSaxDriver/GNUmakefile, PlistSaxDriver/GNUmakefile:
+         added support for building with GNUSTEP_BUILD_DIR environment
+         variable set for recent gnustep-make package.
+
+2004-03-24  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SxXML.xcode: added -headerpad_max_install_names to linker flags
+         where appropriate.
+
+2004-03-08  Helge Hess  <helge@mac.in.skyrix.com>
+
+       * SxXML.xcode: added a README file
+
+       * README-OSX.txt: added some build notes
+
+2004-02-29  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile: compile STXSaxDriver per default
+
+       * SxXML.xcode: added new STXSaxDriver for parsing structured
+         text files
+
+2004-02-10  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SxXML.xcode: Updated prebinding information according to
+         README-OSX.txt. Also, added Foundation.framework explicitly
+         to all subprojects.
+
+       * README-OSX.txt: New README currently describing prebinding
+         information for Mac OS X.
+
+       * ChangeLog: created.
diff --git a/skyrix-xml/DOM/.cvsignore b/skyrix-xml/DOM/.cvsignore
new file mode 100644 (file)
index 0000000..ff977db
--- /dev/null
@@ -0,0 +1,4 @@
+shared_debug_obj
+shared_obj
+*.framework
+derived_src
diff --git a/skyrix-xml/DOM/COPYING b/skyrix-xml/DOM/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-xml/DOM/COPYRIGHT b/skyrix-xml/DOM/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-xml/DOM/ChangeLog b/skyrix-xml/DOM/ChangeLog
new file mode 100644 (file)
index 0000000..7d105eb
--- /dev/null
@@ -0,0 +1,132 @@
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.10
+
+       * GNUmakefile.preamble: added prebinding info
+
+       * GNUmakefile: moved preamble stuff to GNUmakefile.preamble, also 
+         build DOM.framework on non-libFoundation systems
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.9)
+
+2004-02-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * DOMElement.m: added -description method to 
+         _DOMElementAttrNamedNodeMap class (v4.2.8)
+
+2003-11-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: removed autodoc target
+
+2003-10-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * DOMDocument.m, DOMElement.m DOMQueryPathExpression.m: fixed some
+         Xcode warnings (v4.2.7)
+
+2003-07-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * DOMNode.m, DOMXMLOutputter.m: removed a warning on gstep-base, patch
+         provided by Filip Van Raemdonck (v4.2.6)
+
+2003-01-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * common.h: removed dependency on FoundationExt on MacOSX (v4.2.5)
+
+Thu Jan  2 10:49:31 2003  Helge Hess  <helge.hess@skyrix.com>
+       
+       * changes for MacOSX, does not use RETAIN macros anymore (methods are
+         used), -doesNotRecognizeSelector: instead of -notImplemented 
+         (v4.2.4)
+
+2002-09-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed some compilation warnings (v4.2.3)
+
+2002-06-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * track positional information in elements
+
+Sun May  5 18:40:10 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added DOMBuilderFactory to create DOMBuilder instances
+
+Thu May  2 12:43:12 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * DOMXMLOutputter.m: added protocols to output methods
+
+       * changed to use -rangeOfString: instead of -indexOfString:
+
+Thu Apr  4 18:12:17 2002  Martin Spindler  <spindler@mdlink.de>
+
+       * DOMSaxHandler.m: added SubHandler category
+
+Tue Feb 12 20:48:41 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * made independend from EOControl/NGExtensions
+
+Tue Nov 13 16:16:26 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * DOMSaxBuilder.m: added SAX errors to DOM document
+
+       * DOMDocument.m: ivars for storing errors/warnings
+
+       * DOMSaxHandler.m: track error messages
+
+Mon Oct 22 09:54:03 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed special namespace variants of DOMAttribute/DOMElement
+
+Mon Oct  1 15:59:16 2001  Helge Hess  <helge.hess@skyrix.com>
+       
+       * DOMSaxBuilder.h: create DOM builder by MIME-type
+       
+Fri Sep 28 16:17:17 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * DOMElement.m: added -getElementsByTagName:
+
+       * DOM+JS.m: added JS bindings for DOM objects
+
+       * DOMElement.m: added JS bindings to (private) AttrNamedNodeMap class
+
+       * DOMProtocols.h: added ObjC protocols for DOM types
+       
+Thu Aug 23 12:03:41 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * DOMSaxBuilder.m: clear sax handler after parsing
+
+       * DOMSaxHandler.m added method to clear handler
+
+Sat Aug 11 13:56:47 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * DOMSaxHandler.m: changed to use less -autorelease calls
+
+Tue Jul  3 16:26:26 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * DOMElement.m: allow * pattern in -hasAttribute:namespaceURI:
+
+Thu Jun  7 19:48:41 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * DOMNode+QueryPath.m: improved query-path parsing (namespaces made
+         possible), fixed deep child element search
+
+Thu Mar  8 12:33:27 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * DOMDocument.m: fixed bug
+
+Fri Mar  2 20:10:27 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * DOMElement.m: added ms patch
+
+Fri Feb 23 13:26:39 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * DOMElement.m: added ms bugfix
+
+       * DOMAttribute.m: improved -description
+
+Fri Feb  2 10:08:32 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * DOMNode+QueryPath.m: added partial support for NS in paths
diff --git a/skyrix-xml/DOM/DOM+JS.m b/skyrix-xml/DOM/DOM+JS.m
new file mode 100644 (file)
index 0000000..3f904ef
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <DOM/DOMDocument.h>
+#include <DOM/DOMImplementation.h>
+#include <DOM/DOMCharacterData.h>
+#include <DOM/DOMAttribute.h>
+#include <DOM/DOMElement.h>
+#include <DOM/DOMDocumentType.h>
+#include <DOM/DOMProcessingInstruction.h>
+#include "NSObject+StringValue.h"
+#include "common.h"
+
+/*
+  Differences to DOM JavaScript
+
+    Differences are due to JavaScript bridge retain-cycle issues with parent
+    properties (properties are cached by the JS engine, while function return
+    values are not) ...
+    
+    Node:
+      original property | SKYRiX function
+      parentNode        | getParentNode()
+      childNodes        | getChildNodes()
+      firstChild        | getFirstChild()
+      lastChild         | getLastChild()
+      previousSibling   | getPreviousSibling()
+      nextSibling       | getNextSibling()
+      attributes        | getAttributes()
+      ownerDocument     | getOwnerDocument()
+
+    Attr:
+      ownerElement      | getOwnerElement()
+      
+    Document:
+      original property | SKYRiX function
+      documentElement   | getDocumentElement()
+*/
+
+@implementation DOMImplementation(JSSupport)
+
+- (id)_jsfunc_createDocument:(NSArray *)_args {
+  NSString *nsuri = nil, *qname = nil, *doctype = nil;
+  unsigned count;
+
+  count = [_args count];
+  if (count > 0) nsuri   = [[_args objectAtIndex:0] stringValue];
+  if (count > 1) qname   = [[_args objectAtIndex:1] stringValue];
+  if (count > 2) doctype = [[_args objectAtIndex:2] stringValue];
+
+  return [self createDocumentWithName:qname
+               namespaceURI:nsuri
+               documentType:doctype];
+}
+
+- (id)_jsfunc_createDocumentType:(NSArray *)_args {
+  NSString *qname = nil, *pubId = nil, *sysId = nil;
+  unsigned count;
+
+  count = [_args count];
+  if (count > 0) qname = [[_args objectAtIndex:0] stringValue];
+  if (count > 1) pubId = [[_args objectAtIndex:1] stringValue];
+  if (count > 2) sysId = [[_args objectAtIndex:2] stringValue];
+  
+  return [self createDocumentType:qname publicId:pubId systemId:sysId];
+}
+
+@end /* DOMImplementation(JSSupport) */
+
+@implementation DOMDocument(JSSupport)
+
+- (id)_jsprop_doctype {
+  return [self doctype];
+}
+- (id)_jsprop_implementation {
+  return [self implementation];
+}
+
+- (id)_jsfunc_getDocumentElement:(NSArray *)_args {
+  return [self documentElement];
+}
+
+/* lookup */
+
+- (id)_jsfunc_getElementsByTagName:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) == 0) return nil;
+
+  if (count == 1)
+    return [self getElementsByTagName:[[_args objectAtIndex:0] stringValue]];
+  else {
+    return [self getElementsByTagName:[[_args objectAtIndex:1] stringValue]
+                 namespaceURI:[[_args objectAtIndex:0] stringValue]];
+  }
+}
+- (id)_jsfunc_getElementsByTagNameNS:(NSArray *)_args {
+  return [self _jsfunc_getElementsByTagName:_args];
+}
+
+- (id)_jsfunc_getElementById:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) == 0) return nil;
+
+  return [self getElementById:[[_args objectAtIndex:0] stringValue]];
+}
+
+/* factory */
+
+- (id)_jsfunc_createElement:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) == 0) return nil;
+  if (count == 1)
+    return [self createElement:[[_args objectAtIndex:0] stringValue]];
+  else {
+    return [self createElement:[[_args objectAtIndex:1] stringValue]
+                 namespaceURI:[[_args objectAtIndex:0] stringValue]];
+  }
+}
+- (id)_jsfunc_createElementNS:(NSArray *)_args {
+  return [self _jsfunc_createElement:_args];
+}
+
+- (id)_jsfunc_createDocumentFragment:(NSArray *)_args {
+  return [self createDocumentFragment];
+}
+- (id)_jsfunc_createTextNode:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) == 0) return nil;
+  return [self createTextNode:[[_args objectAtIndex:0] stringValue]];
+}
+- (id)_jsfunc_createComment:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) == 0) return nil;
+  return [self createComment:[[_args objectAtIndex:0] stringValue]];
+}
+- (id)_jsfunc_createCDATASection:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) == 0) return nil;
+  return [self createCDATASection:[[_args objectAtIndex:0] stringValue]];
+}
+
+- (id)_jsfunc_createProcessingInstruction:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) < 2) return nil;
+
+  return [self createProcessingInstruction:
+                 [[_args objectAtIndex:0] stringValue]
+               data:[[_args objectAtIndex:1] stringValue]];
+}
+- (id)_jsfunc_createAttribute:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) == 0) return nil;
+  if (count == 1)
+    return [self createAttribute:[[_args objectAtIndex:0] stringValue]];
+  else {
+    return [self createAttribute:[[_args objectAtIndex:1] stringValue]
+                 namespaceURI:[[_args objectAtIndex:0] stringValue]];
+  }
+}
+- (id)_jsfunc_createAttributeNS:(NSArray *)_args {
+  return [self _jsfunc_createAttribute:_args];
+}
+
+- (id)_jsfunc_createEntityReference:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) == 0) return nil;
+  return [self createEntityReference:[[_args objectAtIndex:0] stringValue]];
+}
+
+@end /* DOMDocument(JSSupport) */
+
+@implementation DOMNode(JSSupport)
+
+- (NSString *)_jsprop_nodeName {
+  return [self nodeName];
+}
+- (NSString *)_jsprop_nodeValue {
+  return [self nodeValue];
+}
+- (NSNumber *)_jsprop_nodeType {
+  return [NSNumber numberWithShort:[self nodeType]];
+}
+
+- (NSString *)_jsprop_namespaceURI {
+  return [self namespaceURI];
+}
+- (NSString *)_jsprop_prefix {
+  return [self prefix];
+}
+- (NSString *)_jsprop_localName {
+  return [self localName];
+}
+
+- (id)_jsfunc_getParentNode:(NSArray *)_args {
+  return [self parentNode];
+}
+- (id)_jsfunc_getChildNodes:(NSArray *)_args {
+  return [self childNodes];
+}
+- (id)_jsfunc_getFirstChild:(NSArray *)_args {
+  return [self firstChild];
+}
+- (id)_jsfunc_getLastChild:(NSArray *)_args {
+  return [self lastChild];
+}
+- (id)_jsfunc_getPreviousSibling:(NSArray *)_args {
+  return [self previousSibling];
+}
+- (id)_jsfunc_getNextSibling:(NSArray *)_args {
+  return [self nextSibling];
+}
+- (id)_jsfunc_getAttributes:(NSArray *)_args {
+  return [self attributes];
+}
+- (id)_jsfunc_getOwnerDocument:(NSArray *)_args {
+  return [self ownerDocument];
+}
+
+- (NSNumber *)_jsfunc_hasChildNodes:(NSArray *)_args {
+  return [NSNumber numberWithBool:[self hasChildNodes]];
+}
+
+- (id)_jsfunc_normalize:(NSArray *)_args {
+  return nil;
+}
+
+- (id)_jsfunc_appendChild:(NSArray *)_args {
+  unsigned i, count;
+  id last = nil;
+  for (i = 0, count = [_args count]; i < count; i++)
+    last = [self appendChild:[_args objectAtIndex:i]];
+  return last;
+}
+- (id)_jsfunc_removeChild:(NSArray *)_args {
+  unsigned i, count;
+  id last = nil;
+  for (i = 0, count = [_args count]; i < count; i++)
+    last = [self removeChild:[_args objectAtIndex:i]];
+  return last;
+}
+
+// #warning some JS DOMNode API missing
+
+@end /* DOMNode(JSSupport) */
+
+@implementation DOMCharacterData(JSSupport)
+
+- (void)_jsprop_data:(NSString *)_data {
+  _data = [_data stringValue];
+  [self setData:_data];
+}
+- (NSString *)_jsprop_data {
+  return [self data];
+}
+
+- (NSNumber *)_jsprop_length {
+  return [NSNumber numberWithInt:[self length]];
+}
+
+- (NSString *)_jsfunc_substringData:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) < 2) return nil;
+  return [self substringData:[[_args objectAtIndex:0] intValue]
+               count:[[_args objectAtIndex:1] intValue]];
+}
+- (id)_jsfunc_appendData:(NSArray *)_args {
+  unsigned i, count;
+  for (i = 0, count = [_args count]; i < count; i++)
+    [self appendData:[[_args objectAtIndex:i] stringValue]];
+  return self;
+}
+- (id)_jsfunc_insertData:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) == 0) return nil;
+  if (count == 1)
+    [self insertData:[[_args objectAtIndex:0] stringValue] offset:0];
+  else {
+    [self insertData:[[_args objectAtIndex:0] stringValue]
+          offset:[[_args objectAtIndex:1] intValue]];
+  }
+  return self;
+}
+- (id)_jsfunc_deleteData:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) < 2) return nil;
+  [self deleteData:[[_args objectAtIndex:0] intValue]
+        count:[[_args objectAtIndex:1] intValue]];
+  return self;
+}
+- (id)_jsfunc_replaceData:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) < 3) return nil;
+  [self replaceData:[[_args objectAtIndex:0] intValue]
+        count:[[_args objectAtIndex:1] intValue]
+        with:[[_args objectAtIndex:2] stringValue]];
+  return self;
+}
+
+@end /* DOMCharacterData(JSSupport) */
+
+@implementation DOMAttribute(JSSupport)
+
+- (NSString *)_jsprop_name {
+  return [self name];
+}
+- (NSNumber *)_jsprop_specified {
+  return [NSNumber numberWithBool:[self specified]];
+}
+
+- (void)_jsprop_value:(NSString *)_value {
+  [self setValue:[_value stringValue]];
+}
+- (NSString *)_jsprop_value {
+  return [self value];
+}
+
+- (id)_jsfunc_getOwnerElement:(NSArray *)_args {
+  return [self ownerElement];
+}
+
+@end /* DOMAttribute(JSSupport) */
+
+@implementation DOMElement(JSSupport)
+
+- (NSString *)_jsprop_tagName {
+  return [self tagName];
+}
+
+/* attributes */
+
+- (NSString *)_jsfunc_getAttribute:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) return nil;
+  return [self attribute:[[_args objectAtIndex:0] stringValue]];
+}
+- (NSString *)_jsfunc_getAttributeNS:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) return nil;
+  return [self attribute:[[_args objectAtIndex:1] stringValue]
+               namespaceURI:[[_args objectAtIndex:0] stringValue]];
+}
+
+- (id)_jsfunc_setAttribute:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) < 2) return nil;
+  [self setAttribute:[[_args objectAtIndex:0] stringValue]
+        value:[[_args objectAtIndex:1] stringValue]];
+  return self;
+}
+- (id)_jsfunc_setAttributeNS:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) < 3) return nil;
+  [self setAttribute:[[_args objectAtIndex:1] stringValue]
+        namespaceURI:[[_args objectAtIndex:0] stringValue]
+        value:[[_args objectAtIndex:2] stringValue]];
+  return self;
+}
+
+- (id)_jsfunc_removeAttribute:(NSArray *)_args {
+  unsigned i, count;
+  for (i = 0, count = [_args count]; i < count; i++)
+    [self removeAttribute:[[_args objectAtIndex:i] stringValue]];
+  return self;
+}
+- (id)_jsfunc_removeAttributeNS:(NSArray *)_args {
+  unsigned count;
+  if ((count = [_args count]) < 2) return nil;
+  [self removeAttribute:[[_args objectAtIndex:1] stringValue]
+        namespaceURI:[[_args objectAtIndex:0] stringValue]];
+  return self;
+}
+
+- (id)_jsfunc_getAttributeNode:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) return nil;
+  return [[self attributes] namedItem:[[_args objectAtIndex:0] stringValue]];
+}
+- (id)_jsfunc_setAttributeNode:(NSArray *)_args {
+  unsigned i, count;
+  id last = nil;
+
+  for (i = 0, count = [_args count]; i < count; i++)
+    last = [self setAttributeNode:[_args objectAtIndex:i]];
+  return last;
+}
+- (id)_jsfunc_removeAttributeNode:(NSArray *)_args {
+  unsigned i, count;
+  id last = nil;
+
+  for (i = 0, count = [_args count]; i < count; i++)
+    last = [self removeAttributeNode:[_args objectAtIndex:i]];
+  return last;
+}
+
+/* lookup */
+
+- (id)_jsfunc_getElementsByTagName:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) < 1) return nil;
+  
+  if (count == 1)
+    return [self getElementsByTagName:[[_args objectAtIndex:0] stringValue]];
+  else {
+    return [self getElementsByTagName:[[_args objectAtIndex:1] stringValue]
+                 namespaceURI:[[_args objectAtIndex:0] stringValue]];
+  }
+}
+- (id)_jsfunc_getElementsByTagNameNS:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) < 2) return nil;
+  return [self getElementsByTagName:[[_args objectAtIndex:1] stringValue]
+               namespaceURI:[[_args objectAtIndex:0] stringValue]];
+}
+
+@end /* DOMElement(JSSupport) */
+
+@implementation DOMDocumentType(JSSupport)
+
+- (NSString *)_jsprop_name {
+  return [self name];
+}
+- (NSString *)_jsprop_publicId {
+  return [self publicId];
+}
+- (NSString *)_jsprop_systemId {
+  return [self systemId];
+}
+- (NSString *)_jsprop_internalSubset {
+  return [self internalSubset];
+}
+
+@end /* DOMDocumentType(JSSupport) */
+
+@implementation DOMProcessingInstruction(JSSupport)
+
+- (NSString *)_jsprop_target {
+  return [self target];
+}
+
+- (void)_jsprop_data:(NSString *)_data {
+  [self setData:[_data stringValue]];
+}
+- (NSString *)_jsprop_data {
+  return [self data];
+}
+
+@end /* DOMProcessingInstruction(JSSupport) */
diff --git a/skyrix-xml/DOM/DOM-Info.plist b/skyrix-xml/DOM/DOM-Info.plist
new file mode 100644 (file)
index 0000000..2662257
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>DOM</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.xml.DOM</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-xml/DOM/DOM.h b/skyrix-xml/DOM/DOM.h
new file mode 100644 (file)
index 0000000..744463b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOM_H__
+#define __DOM_H__
+
+/*
+  Standard DOM stuff
+*/
+
+#include <DOM/DOMAttribute.h>
+#include <DOM/DOMCDATASection.h>
+#include <DOM/DOMCharacterData.h>
+#include <DOM/DOMComment.h>
+#include <DOM/DOMDocument.h>
+#include <DOM/DOMDocumentFragment.h>
+#include <DOM/DOMDocumentType.h>
+#include <DOM/DOMElement.h>
+#include <DOM/DOMEntity.h>
+#include <DOM/DOMEntityReference.h>
+#include <DOM/DOMImplementation.h>
+#include <DOM/DOMNode.h>
+#include <DOM/DOMNotation.h>
+#include <DOM/DOMProcessingInstruction.h>
+#include <DOM/DOMSaxBuilder.h>
+#include <DOM/DOMText.h>
+#include <DOM/DOMXMLOutputter.h>
+#include <DOM/DOMNamedNodeMap.h>
+
+#endif /* __DOM_H__ */
diff --git a/skyrix-xml/DOM/DOMAttribute.h b/skyrix-xml/DOM/DOMAttribute.h
new file mode 100644 (file)
index 0000000..ea51eb4
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOMAttribute_H__
+#define __DOMAttribute_H__
+
+#include <DOM/DOMNode.h>
+
+/*
+  Why is Attr a Node? Can it have children? Can it be a child?
+  
+  Attr is a Node because its value is actually carried by its children,
+  which may be a mixture of Text and EntityReference nodes, and because
+  making it a Node allows us to store it in a NamedNodeMap for easy retrieval. 
+
+  The getAttribute method hides this detail by returning a string representing
+  the concatenation of all these children, and similarly setAttribute replaces
+  the Attr's contents with a single Text node holding the new string. To create
+  or manipulate other children of an Attr, you have to access the Attr node
+  directly via the getAttributeNode and setAttributeNode methods, or by
+  retrieving it from the element's "attributes" NamedNodeMap. 
+
+  Section 1.1.1 of the Level 1 DOM Recommendation gives a list of which nodes
+  can be parents and children of which other nodes. Attr is not a legal child
+  of any node, so attempts to insert it as one will throw a DOMException
+  (HIERARCHY_REQUEST_ERR).
+
+  Note that:
+    parentNode, nextSibling, previousSibling always return nil !!!
+*/
+
+@interface DOMAttribute : DOMNodeWithChildren < DOMAttr >
+{
+  id       element;
+  NSString *name;
+  NSString *namespaceURI;
+  NSString *prefix;
+  BOOL     isSpecified;
+  NSString *value;
+}
+
+@end
+
+@interface DOMAttribute(PrivateCtors)
+/* use DOMDocument for constructing DOMAttributes ! */
+
+- (id)initWithName:(NSString *)_name;
+- (id)initWithName:(NSString *)_name namespaceURI:(NSString *)_uri;
+
+@end
+
+@interface DOMAttribute(ObjCValues)
+
+- (NSString *)stringValue;
+- (int)intValue;
+- (double)doubleValue;
+
+@end /* DOMAttribute(Values) */
+
+#endif /* __DOMAttribute_H__ */
diff --git a/skyrix-xml/DOM/DOMAttribute.m b/skyrix-xml/DOM/DOMAttribute.m
new file mode 100644 (file)
index 0000000..7a7e96b
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "DOMAttribute.h"
+#include "DOMDocument.h"
+#include "common.h"
+
+@implementation DOMAttribute
+
+- (id)initWithName:(NSString *)_name namespaceURI:(NSString *)_uri {
+  if ((self = [super init])) {
+    self->name         = [_name copy];
+    self->namespaceURI = [_uri  copy];
+  }
+  return self;
+}
+
+- (id)initWithName:(NSString *)_name {
+  return [self initWithName:_name namespaceURI:nil];
+}
+
+- (void)dealloc {
+  [self->prefix release];
+  [self->name   release];
+  [self->namespaceURI release];
+  [super dealloc];
+}
+
+/* element tracking */
+
+- (void)_domNodeRegisterParentNode:(id)_element {
+  self->element = _element;
+}
+- (void)_domNodeForgetParentNode:(id)_element {
+  if (_element == self->element)
+    self->element = nil;
+}
+
+/* attributes */
+
+- (id)ownerElement {
+  return self->element;
+}
+- (id)ownerDocument {
+  return [[self ownerElement] ownerDocument];
+}
+
+- (BOOL)specified {
+  return self->isSpecified;
+}
+
+- (NSString *)name {
+  return self->name;
+}
+
+- (NSString *)namespaceURI {
+  return self->namespaceURI;
+}
+
+- (void)setPrefix:(NSString *)_prefix {
+  id old = self->prefix;
+  self->prefix = [_prefix copy];
+  [old release];
+}
+- (NSString *)prefix {
+  return self->prefix;
+}
+
+- (void)setValue:(NSString *)_value {
+  id child;
+  
+  self->isSpecified = YES;
+
+  /* remove all existing children */
+  while ((child = [self lastChild]))
+    [self removeChild:child];
+  
+  child = [[self ownerDocument] createTextNode:_value];
+  NSAssert1(child, @"couldn't create text-node child for value '%@' !", _value);
+  
+  [self appendChild:child];
+}
+
+- (NSString *)_stringValueOfChildNode:(id)_node {
+  return [_node nodeValue];
+}
+- (NSString *)value {
+  id       children;
+  unsigned count;
+  
+  if (![self hasChildNodes])
+    return nil;
+  
+  children = [self childNodes];
+  if ((count = [children count]) == 0)
+    return nil;
+  
+  if (count == 1) {
+    return [self _stringValueOfChildNode:[children objectAtIndex:0]];
+  }
+  else {
+    unsigned i;
+    NSMutableString *s;
+
+    s = [NSMutableString stringWithCapacity:256];
+    for (i = 0; i < count; i++) {
+      [s appendString:
+          [self _stringValueOfChildNode:[children objectAtIndex:i]]];
+    }
+    return [[s copy] autorelease];
+  }
+}
+
+/* node */
+
+- (BOOL)_isValidChildNode:(id)_node {
+  switch ([_node nodeType]) {
+    case DOM_TEXT_NODE:
+    case DOM_ENTITY_REFERENCE_NODE:
+      return YES;
+      
+    default:
+      return NO;
+  }
+}
+
+- (DOMNodeType)nodeType {
+  return DOM_ATTRIBUTE_NODE;
+}
+
+- (id)attributes {
+  return nil;
+}
+
+- (id)parentNode {
+  return nil;
+}
+- (id)nextSibling {
+  return nil;
+}
+- (id)previousSibling {
+  return nil;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X[%@]: {%@}%@%s '%@'>",
+                     self, NSStringFromClass([self class]),
+                     self->namespaceURI,
+                     [self name],
+                     [self specified] ? " specified" : "",
+                     [self stringValue]];
+}
+
+@end /* DOMAttribute */
+
+@implementation DOMAttribute(ObjCValues)
+
+- (NSString *)stringValue {
+  return [self value];
+}
+- (int)intValue {
+  return [[self stringValue] intValue];
+}
+- (double)doubleValue {
+  return [[self stringValue] doubleValue];
+}
+
+@end /* DOMAttribute(Values) */
+
+@implementation DOMAttribute(QPValues)
+
+- (NSException *)setQueryPathValue:(id)_value {
+  [self setValue:[_value stringValue]];
+  return nil;
+}
+- (id)queryPathValue {
+  return [self value];
+}
+
+@end /* DOMAttribute(QPValues) */
diff --git a/skyrix-xml/DOM/DOMBuilder.h b/skyrix-xml/DOM/DOMBuilder.h
new file mode 100644 (file)
index 0000000..eb60450
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOMBuilder_H__
+#define __DOMBuilder_H__
+
+#import <Foundation/NSObject.h>
+#include <DOM/DOMDocument.h>
+
+/*
+  A protocol which defines the behaviour of DOM builders (classes
+  which build DOM trees from some kind of resource).
+*/
+
+@protocol DOMBuilder
+
+/* parsing */
+
+- (id<NSObject,DOMDocument>)buildFromSource:(id)_source;
+- (id<NSObject,DOMDocument>)buildFromSource:(id)_source
+  systemId:(NSString *)_sysId;
+- (id<NSObject,DOMDocument>)buildFromSystemId:(NSString *)_sysId;
+
+@end
+
+#endif /* __DOMBuilder_H__ */
diff --git a/skyrix-xml/DOM/DOMBuilderFactory.h b/skyrix-xml/DOM/DOMBuilderFactory.h
new file mode 100644 (file)
index 0000000..79e3ffa
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMBuilderFactory_H__
+#define __DOMBuilderFactory_H__
+
+#import <Foundation/NSObject.h>
+#include <DOM/DOMBuilder.h>
+
+/*
+  To get a reader for HTML files:
+    reader = [factory createDOMBuilderForMimeType:@"text/html"];
+
+  for XML files:
+    reader = [factory createDOMBuilderForMimeType:@"text/xml"];
+    
+  a specific reader:
+    reader = [factory createDOMBuilderWithName:@"libxmlSAXDriver"];
+*/
+
+@class NSDictionary;
+    
+@interface DOMBuilderFactory : NSObject
+{
+}
+
++ (id)standardDOMBuilderFactory;
+
+- (id<NSObject,DOMBuilder>)createDOMBuilder;
+- (id<NSObject,DOMBuilder>)createDOMBuilderWithName:(NSString *)_name;
+- (id<NSObject,DOMBuilder>)createDOMBuilderForMimeType:(NSString *)_mtype;
+
+- (NSArray *)availableDOMBuilders;
+
+@end
+
+#endif /* __DOMBuilderFactory_H__ */
diff --git a/skyrix-xml/DOM/DOMBuilderFactory.m b/skyrix-xml/DOM/DOMBuilderFactory.m
new file mode 100644 (file)
index 0000000..68771c3
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "DOMBuilderFactory.h"
+#include <DOM/DOMSaxBuilder.h>
+#include <SaxObjC/SaxXMLReader.h>
+#include <SaxObjC/SaxXMLReaderFactory.h>
+#include "common.h"
+
+@implementation DOMBuilderFactory
+
+static id factory = nil;
+
++ (id)standardDOMBuilderFactory {
+  if (factory == nil)
+    factory = [[self alloc] init];
+  return factory;
+}
+
+/* primary method */
+
+- (id<NSObject,DOMBuilder>)createDOMBuilderWithXmlReader:(id<SaxXMLReader>)_r {
+  DOMSaxBuilder *builder;
+
+  if (_r == nil)
+    return nil;
+  
+  builder = [[DOMSaxBuilder alloc] initWithXMLReader:_r];
+  return [builder autorelease];
+}
+
+/* reader constructors */
+
+- (SaxXMLReaderFactory *)readerFactory {
+  return [SaxXMLReaderFactory standardXMLReaderFactory];
+}
+
+- (id<NSObject,DOMBuilder>)createDOMBuilder {
+  id<SaxXMLReader> reader;
+  
+  if ((reader = [[self readerFactory] createXMLReader]) == nil) {
+    NSLog(@"%s:%i: could not create default DOM builder "
+          @"because no SAX default reader could be constructed.",
+          __PRETTY_FUNCTION__, __LINE__);
+    return nil;
+  }
+  
+  return [self createDOMBuilderWithXmlReader:reader];
+}
+- (id<NSObject,DOMBuilder>)createDOMBuilderWithName:(NSString *)_name {
+  id<SaxXMLReader> reader;
+
+  if ((reader = [[self readerFactory] createXMLReaderWithName:_name]) == nil) {
+    NSLog(@"%s:%i: could not create DOM builder '%@' "
+          @"because no SAX reader named '%@' could be constructed.",
+          __PRETTY_FUNCTION__, __LINE__,
+          _name, _name);
+    return nil;
+  }
+  
+  return [self createDOMBuilderWithXmlReader:reader];
+}
+- (id<NSObject,DOMBuilder>)createDOMBuilderForMimeType:(NSString *)_mtype {
+  id<SaxXMLReader> reader;
+
+  reader = [[self readerFactory] createXMLReaderForMimeType:_mtype];
+  if (reader == nil) {
+    NSLog(@"%s:%i: could not create DOM builder for MIME type '%@' "
+          @"because no SAX proper reader could be constructed.",
+          __PRETTY_FUNCTION__, __LINE__, _mtype);
+    return nil;
+  }
+  
+  return [self createDOMBuilderWithXmlReader:reader];
+}
+
+- (NSArray *)availableDOMBuilders {
+  return [NSArray arrayWithObject:@"DOMSaxBuilder"];
+}
+
+@end /* DOMBuilderFactory */
diff --git a/skyrix-xml/DOM/DOMCDATASection.h b/skyrix-xml/DOM/DOMCDATASection.h
new file mode 100644 (file)
index 0000000..449b317
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMCDATASection_H__
+#define __DOMCDATASection_H__
+
+#include <DOM/DOMText.h>
+
+@interface DOMCDATASection : DOMText < DOMCDATASection >
+{
+}
+
+@end
+
+@interface DOMCDATASection(PrivateCtors)
+/* use DOMDocument for constructing DOMCDATASection's ! */
+
+@end
+
+#endif /* __DOMCDATASection_H__ */
diff --git a/skyrix-xml/DOM/DOMCDATASection.m b/skyrix-xml/DOM/DOMCDATASection.m
new file mode 100644 (file)
index 0000000..737a97b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMCDATASection.h"
+
+@implementation DOMCDATASection
+
+/* node */
+
+- (DOMNodeType)nodeType {
+  return DOM_CDATA_SECTION_NODE;
+}
+
+- (BOOL)_isValidChildNode:(id)_node {
+  return NO;
+}
+- (BOOL)hasChildNodes {
+  return NO;
+}
+- (id)childNodes {
+  return nil;
+}
+- (id)appendChild:(id)_node {
+  return nil;
+}
+
+- (id)attributes {
+  return nil;
+}
+
+@end /* DOMCDATASection */
diff --git a/skyrix-xml/DOM/DOMCharacterData.h b/skyrix-xml/DOM/DOMCharacterData.h
new file mode 100644 (file)
index 0000000..4861ed1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOMCharacterData_H__
+#define __DOMCharacterData_H__
+
+#include <DOM/DOMNode.h>
+
+@class NSString;
+
+@interface DOMCharacterData : DOMNode < DOMCharacterData >
+{
+  id       parent;
+  NSString *data;
+}
+
+@end
+
+#endif /* __DOMCharacterData_H__ */
diff --git a/skyrix-xml/DOM/DOMCharacterData.m b/skyrix-xml/DOM/DOMCharacterData.m
new file mode 100644 (file)
index 0000000..914e5ff
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "DOMCharacterData.h"
+#include "common.h"
+
+@implementation DOMCharacterData
+
+- (id)initWithString:(NSString *)_s {
+  if ((self = [super init])) {
+    self->data = [_s copy];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->data release];
+  [super dealloc];
+}
+
+/* attributes */
+
+- (void)setData:(NSString *)_data {
+  id old = self->data;
+  self->data = [_data copy];
+  [old release];
+}
+- (NSString *)data {
+  return self->data;
+}
+
+- (unsigned)length {
+  return [self->data length];
+}
+
+/* operations */
+
+- (NSString *)substringData:(unsigned)_offset count:(unsigned)_count {
+  NSRange r;
+
+  r.location = _offset;
+  r.length   = _count;
+  
+  return [[self data] substringWithRange:r];
+}
+
+- (void)appendData:(NSString *)_data {
+  id old;
+  old = self->data;
+  self->data = old ? [old stringByAppendingString:_data] : _data;
+  [old release];
+}
+
+- (void)insertData:(NSString *)_data offset:(unsigned)_offset {
+  [self doesNotRecognizeSelector:_cmd];
+}
+
+- (void)deleteData:(unsigned)_offset count:(unsigned)_count {
+  NSRange r;
+  id new, old;
+  
+  r.location = _offset;
+  r.length   = _count;
+
+  new = [self->data substringWithRange:r];
+  old = self->data;
+  self->data = [new copy];
+  [old release];
+}
+
+- (void)replaceData:(unsigned)_offset count:(unsigned)_c with:(NSString *)_s {
+  [self doesNotRecognizeSelector:_cmd];
+}
+
+/* parent node */
+
+- (void)_domNodeRegisterParentNode:(id)_parent {
+  self->parent = _parent;
+}
+- (void)_domNodeForgetParentNode:(id)_parent {
+  if (_parent == self->parent)
+    /* the node's parent was deallocated */
+    self->parent = nil;
+}
+- (id)parentNode {
+  return self->parent;
+}
+
+@end /* DOMCharacterData */
+
+@implementation DOMCharacterData(QPValues)
+
+- (NSException *)setQueryPathValue:(id)_value {
+  [self setData:[_value stringValue]];
+  return nil;
+}
+- (id)queryPathValue {
+  return [self data];
+}
+
+@end /* DOMCharacterData(QPValues) */
diff --git a/skyrix-xml/DOM/DOMComment.h b/skyrix-xml/DOM/DOMComment.h
new file mode 100644 (file)
index 0000000..37f2d9a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMComment_H__
+#define __DOMComment_H__
+
+#include <DOM/DOMCharacterData.h>
+
+@class NSString;
+
+@interface DOMComment : DOMCharacterData < DOMComment >
+{
+}
+
+@end
+
+#endif /* __DOMComment_H__ */
diff --git a/skyrix-xml/DOM/DOMComment.m b/skyrix-xml/DOM/DOMComment.m
new file mode 100644 (file)
index 0000000..94134a2
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMComment.h"
+
+@implementation DOMComment
+
+/* node */
+
+- (DOMNodeType)nodeType {
+  return DOM_COMMENT_NODE;
+}
+
+- (BOOL)_isValidChildNode:(id)_node {
+  return NO;
+}
+- (BOOL)hasChildNodes {
+  return NO;
+}
+- (id)childNodes {
+  return nil;
+}
+- (id)appendChild:(id)_node {
+  return nil;
+}
+
+- (id)attributes {
+  return nil;
+}
+
+@end /* DOMComment */
diff --git a/skyrix-xml/DOM/DOMDocument+factory.m b/skyrix-xml/DOM/DOMDocument+factory.m
new file mode 100644 (file)
index 0000000..e5b44d8
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <DOM/DOMDocument.h>
+#include <DOM/DOMProcessingInstruction.h>
+#include <DOM/DOMElement.h>
+#include <DOM/DOMAttribute.h>
+#include <DOM/DOMEntityReference.h>
+#include <DOM/DOMImplementation.h>
+#include "common.h"
+
+#include <DOM/DOMTreeWalker.h>
+
+@implementation DOMDocument(DocumentTraversal)
+
+- (Class)domTreeWalkerClass {
+  return NSClassFromString(@"DOMTreeWalker");
+}
+
+- (id)createNodeIterator:(id)_node
+  whatToShow:(unsigned long)_whatToShow
+  filter:(id)_filter
+{
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (id)createTreeWalker:(id)_rootNode
+  whatToShow:(unsigned long)_whatToShow
+  filter:(id)_filter
+  expandEntityReferences:(BOOL)_expandEntityReferences
+{
+  id walker;
+
+  // should throw DOMException with NOT_SUPPORTED_ERR
+  NSAssert(_rootNode, @"invalid root node !");
+
+  walker = [[[self domTreeWalkerClass] alloc]
+                   initWithRootNode:_rootNode
+                   whatToShow:_whatToShow
+                   filter:_filter
+                   expandEntityReferences:_expandEntityReferences];
+  return [walker autorelease];
+}
+
+@end /* DOMDocument(DocumentTraversal) */
diff --git a/skyrix-xml/DOM/DOMDocument.h b/skyrix-xml/DOM/DOMDocument.h
new file mode 100644 (file)
index 0000000..73272d4
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMDocument_H__
+#define __DOMDocument_H__
+
+#include <DOM/DOMNode.h>
+
+@class NSString, NSArray;
+@class DOMImplementation;
+
+@interface DOMDocument : DOMNodeWithChildren < DOMDocument >
+{
+  NSString          *qname;
+  NSString          *uri;
+  id                doctype;
+  DOMImplementation *dom;
+  
+  NSArray           *errors;
+  NSArray           *warnings;
+}
+
++ (id)documentFromData:(NSData *)_data;
++ (id)documentFromString:(NSString *)_string;
++ (id)documentFromURI:(NSString *)_uri;
+
+/* errors/warnings */
+
+- (void)addErrors:(NSArray *)_errors;
+- (void)addWarnings:(NSArray *)_errors;
+
+@end
+
+@interface DOMDocument(DocumentTraversal)
+
+- (id)createNodeIterator:(id)_node
+  whatToShow:(unsigned long)_whatToShow
+  filter:(id)_filter;
+
+- (id)createTreeWalker:(id)_node
+  whatToShow:(unsigned long)_whatToShow
+  filter:(id)_filter
+  expandEntityReferences:(BOOL)_expandEntityReferences;
+
+@end
+
+@interface DOMDocument(PrivateCtors)
+
+/* use DOMImplementation for constructing DOMDocument ! */
+
+- (id)initWithName:(NSString *)_qname
+  namespaceURI:(NSString *)_uri
+  documentType:(id)_doctype
+  dom:(DOMImplementation *)_dom;
+
+@end
+
+#endif /* __DOMDocument_H__ */
diff --git a/skyrix-xml/DOM/DOMDocument.m b/skyrix-xml/DOM/DOMDocument.m
new file mode 100644 (file)
index 0000000..6adb587
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <DOM/DOMDocument.h>
+#include <DOM/DOMImplementation.h>
+#include <DOM/DOMElement.h>
+#include <DOM/DOMNodeWalker.h>
+#include <DOM/DOMProcessingInstruction.h>
+#include <DOM/DOMElement.h>
+#include <DOM/DOMAttribute.h>
+#include <DOM/DOMEntityReference.h>
+#include "DOMSaxBuilder.h"
+#include "common.h"
+
+//#define PROF_DEALLOC 1
+
+@implementation DOMDocument
+
++ (id)documentFromData:(NSData *)_data {
+  id builder;
+  
+  builder = [[[DOMSaxBuilder alloc] init] autorelease];
+  return [builder buildFromData:_data];
+}
++ (id)documentFromString:(NSString *)_string {
+  return [self documentFromData:
+                 [_string dataUsingEncoding:NSISOLatin1StringEncoding]];
+}
++ (id)documentFromURI:(NSString *)_uri {
+  id builder;
+  
+  builder = [[[DOMSaxBuilder alloc] init] autorelease];
+  return [builder buildFromContentsOfFile:_uri];
+}
+
+- (id)initWithName:(NSString *)_qname
+  namespaceURI:(NSString *)_uri
+  documentType:(id)_doctype
+  dom:(DOMImplementation *)_dom
+{
+  self->dom     = [_dom   retain];
+  self->qname   = [_qname copy];
+  self->uri     = [_uri   copy];
+  self->doctype = [_doctype retain];
+  return self;
+}
+
+- (void)dealloc {
+#if PROF_DEALLOC
+  NSDate *start = [NSDate date];
+#endif
+
+  [self->errors   release];
+  [self->warnings release];
+  [self->dom      release];
+  [self->qname    release];
+  [self->uri      release];
+  [self->doctype  release];
+  [super dealloc];
+
+#if PROF_DEALLOC
+  printf("%s: %.3fs\n", __PRETTY_FUNCTION__,
+         [NSDate timeIntervalSinceDate:start]);
+#endif
+}
+
+/* errors/warnings */
+
+- (void)addErrors:(NSArray *)_errors {
+  if (self->errors == nil)
+    self->errors = [_errors copy];
+  else {
+    NSArray *tmp;
+
+    tmp = self->errors;
+    self->errors = [[tmp arrayByAddingObjectsFromArray:_errors] copy];
+    [tmp release];
+  }
+}
+- (void)addWarnings:(NSArray *)_errors {
+  if (self->warnings == nil)
+    self->warnings = [_errors copy];
+  else {
+    NSArray *tmp;
+
+    tmp = self->warnings;
+    self->warnings = [[tmp arrayByAddingObjectsFromArray:_errors] copy];
+    [tmp release];
+  }
+}
+
+/* attributes */
+
+- (id)doctype {
+  return self->doctype;
+}
+- (DOMImplementation *)implementation {
+  return self->dom;
+}
+
+- (id)documentElement {
+  id children;
+  unsigned i, count;
+  
+  if ((children = [self childNodes]) == nil)
+    return nil;
+  
+  for (i = 0, count = [children count]; i < count; i++) {
+    id node;
+
+    node = [children objectAtIndex:i];
+    if ([node nodeType] == DOM_ELEMENT_NODE)
+      return node;
+  }
+  return nil;
+}
+
+/* node */
+
+- (BOOL)_isValidChildNode:(id)_node {
+  switch ([_node nodeType]) {
+    case DOM_ELEMENT_NODE:
+    case DOM_PROCESSING_INSTRUCTION_NODE:
+    case DOM_COMMENT_NODE:
+    case DOM_DOCUMENT_TYPE_NODE:
+      return YES;
+      
+    default:
+      return NO;
+  }
+}
+
+- (DOMNodeType)nodeType {
+  return DOM_DOCUMENT_NODE;
+}
+
+- (id)attributes {
+  return nil;
+}
+
+- (DOMDocument *)ownerDocument {
+  return nil;
+}
+
+- (id)parentNode {
+  /* document cannot be nested */
+  return nil;
+}
+- (id)nextSibling {
+  /* document cannot be nested */
+  return nil;
+}
+- (id)previousSibling {
+  /* document cannot be nested */
+  return nil;
+}
+
+- (void)_walk_getElementsByTagName:(id)_walker {
+  id node;
+  
+  node = [_walker currentNode];
+  if ([node nodeType] != DOM_ELEMENT_NODE)
+    return;
+
+  if (![[node tagName] isEqualToString:
+          [(NSArray *)[_walker context] objectAtIndex:0]])
+    /* tagname doesn't match */
+    return;
+  
+  [[(NSArray *)[_walker context] objectAtIndex:1] addObject:node];
+}
+- (void)_walk_getElementsByTagNameAddAll:(id)_walker {
+  id node;
+  
+  node = [_walker currentNode];
+  if ([node nodeType] != DOM_ELEMENT_NODE)
+    return;
+  
+  [(NSMutableArray *)[_walker context] addObject:node];
+}
+- (id)getElementsByTagName:(NSString *)_tagName {
+  /* introduced in DOM2, should return a *live* list ! */
+  NSMutableArray        *array;
+  DOMNodePreorderWalker *walker;
+  SEL sel;
+  id  ctx;
+  
+  if (![self hasChildNodes])
+    return nil;
+
+  if (_tagName == nil)
+    return nil;
+
+  array = [NSMutableArray array];
+  
+  if ([_tagName isEqualToString:@"*"]) {
+    _tagName = nil;
+    ctx = array;
+    sel = @selector(_walk_getElementsByTagNameAddAll:);
+  }
+  else {
+    ctx = [NSArray arrayWithObjects:_tagName, array, nil];
+    sel = @selector(_walk_getElementsByTagName:);
+  }
+  
+  walker = [[DOMNodePreorderWalker alloc]
+                                   initWithTarget:self
+                                   selector:sel
+                                   context:ctx];
+  
+  [walker walkNode:self];
+
+  [walker release]; walker = nil;
+  
+  return [[array copy] autorelease];
+}
+- (id)getElementsByTagName:(NSString *)_tagName namespaceURI:(NSString *)_uri {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (id)getElementById:(NSString *)_eid {
+  /*
+    Introduced in DOM2
+    
+    Note: The DOM implementation must have information that says which
+    attributes are of type ID. Attributes with the name "ID" are not of
+    type ID unless so defined.
+    Implementations that do not know whether attributes are of type ID
+    or not are expected to return null.
+  */
+  return nil;
+}
+
+/* factory */
+
+- (Class)domElementClass {
+  return [self->dom domElementClass];
+}
+- (Class)domElementNSClass {
+  return [self->dom domElementNSClass];
+}
+- (Class)domDocumentFragmentClass {
+  return [self->dom domDocumentFragmentClass];
+}
+- (Class)domTextNodeClass {
+  return [self->dom domTextNodeClass];
+}
+- (Class)domCommentClass {
+  return [self->dom domCommentClass];
+}
+- (Class)domCDATAClass {
+  return [self->dom domCDATAClass];
+}
+- (Class)domProcessingInstructionClass {
+  return [self->dom domProcessingInstructionClass];
+}
+- (Class)domAttributeClass {
+  return [self->dom domAttributeClass];
+}
+- (Class)domAttributeNSClass {
+  return [self->dom domAttributeNSClass];
+}
+- (Class)domEntityReferenceClass {
+  return [self->dom domEntityReferenceClass];
+}
+
+- (id)createElement:(NSString *)_tagName {
+  id elem;
+  elem = [[[self domElementClass] 
+                alloc] 
+                initWithTagName:_tagName];
+  return [elem autorelease];
+}
+- (id)createElement:(NSString *)_tagName namespaceURI:(NSString *)_uri {
+  id elem;
+  elem = [[[self domElementNSClass] 
+                alloc] 
+                initWithTagName:_tagName namespaceURI:_uri];
+  return [elem autorelease];
+}
+
+- (id)createDocumentFragment {
+  id elem;
+  elem = [[[self domDocumentFragmentClass] alloc] init];
+  return [elem autorelease];
+}
+
+- (id)createTextNode:(NSString *)_data {
+  id elem;
+  elem = [[[self domTextNodeClass] alloc] initWithString:_data];
+  return [elem autorelease];
+}
+- (id)createComment:(NSString *)_data {
+  id elem;
+  elem = [[[self domCommentClass] alloc] initWithString:_data];
+  return [elem autorelease];
+}
+- (id)createCDATASection:(NSString *)_data {
+  id elem;
+  elem = [[[self domCDATAClass] alloc] initWithString:_data];
+  return [elem autorelease];
+}
+
+- (id)createProcessingInstruction:(NSString *)_target data:(NSString *)_data {
+  id elem;
+  elem = [[[self domProcessingInstructionClass] 
+                alloc] 
+                initWithTarget:_target data:_data];
+  return [elem autorelease];
+}
+
+- (id)createAttribute:(NSString *)_name {
+  id elem;
+  elem = [[[self domAttributeClass] 
+                alloc]
+                initWithName:_name];
+  return [elem autorelease];
+}
+- (id)createAttribute:(NSString *)_name namespaceURI:(NSString *)_uri {
+  id elem;
+  elem = [[[self domAttributeNSClass] 
+                alloc]
+                initWithName:_name namespaceURI:_uri];
+  return [elem autorelease];
+}
+
+- (id)createEntityReference:(NSString *)_name {
+  id elem;
+  elem = [[[self domEntityReferenceClass] alloc] initWithName:_name];
+  return [elem autorelease];
+}
+
+@end /* DOMDocument */
+
+@implementation DOMDocument(QPValues)
+
+- (NSException *)setQueryPathValue:(id)_value {
+  return [NSException exceptionWithName:@"QueryPathEvalException"
+                      reason:@"cannot set query-path value on DOMDocument !"
+                      userInfo:nil];
+}
+- (id)queryPathValue {
+  return [self documentElement];
+}
+
+@end /* DOMDocument(QPValues) */
diff --git a/skyrix-xml/DOM/DOMDocumentBuilder.h b/skyrix-xml/DOM/DOMDocumentBuilder.h
new file mode 100644 (file)
index 0000000..b587b90
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMDocumentBuilder_H__
+#define __DOMDocumentBuilder_H__
+
+#include <DOM/DOMImplementation.h>
+
+@protocol DOMDocumentBuilder
+
+
+@end
+
+#endif /* __DOMDocumentBuilder_H__ */
diff --git a/skyrix-xml/DOM/DOMDocumentFragment.h b/skyrix-xml/DOM/DOMDocumentFragment.h
new file mode 100644 (file)
index 0000000..4b42c20
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMDocumentFragment_H__
+#define __DOMDocumentFragment_H__
+
+#include <DOM/DOMNode.h>
+
+@class NSString;
+@class DOMImplementation;
+
+@interface DOMDocumentFragment : DOMNodeWithChildren < DOMDocumentFragment >
+{
+}
+
+@end
+
+@interface DOMDocumentFragment(PrivateCtors)
+
+/* use DOMImplementation for constructing DOMDocumentFragment's ! */
+- (id)initWithName:(NSString *)_name
+  publicId:(NSString *)_p systemId:(NSString *)_s
+  dom:(DOMImplementation *)_dom;
+
+@end
+
+#endif /* __DOMDocumentFragment_H__ */
diff --git a/skyrix-xml/DOM/DOMDocumentFragment.m b/skyrix-xml/DOM/DOMDocumentFragment.m
new file mode 100644 (file)
index 0000000..6d2c050
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMDocumentFragment.h"
+#include "common.h"
+
+@implementation DOMDocumentFragment
+
+/* node */
+
+- (BOOL)_isValidChildNode:(id)_node {
+  switch ([_node nodeType]) {
+    case DOM_ELEMENT_NODE:
+    case DOM_PROCESSING_INSTRUCTION_NODE:
+    case DOM_COMMENT_NODE:
+    case DOM_TEXT_NODE:
+    case DOM_CDATA_SECTION_NODE:
+    case DOM_ENTITY_REFERENCE_NODE:
+      return YES;
+      
+    default:
+      return NO;
+  }
+}
+
+- (DOMNodeType)nodeType {
+  return DOM_DOCUMENT_FRAGMENT_NODE;
+}
+
+- (id)attributes {
+  return nil;
+}
+
+/* parent node */
+
+- (id)parentNode {
+  return nil;
+}
+- (id)nextSibling {
+  return nil;
+}
+- (id)previousSibling {
+  return nil;
+}
+
+@end /* DOMDocumentFragment */
diff --git a/skyrix-xml/DOM/DOMDocumentType.h b/skyrix-xml/DOM/DOMDocumentType.h
new file mode 100644 (file)
index 0000000..a08dd4d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMDocumentType_H__
+#define __DOMDocumentType_H__
+
+#include <DOM/DOMNode.h>
+
+@interface DOMDocumentType : DOMNode
+{
+  id parent;
+}
+
+/* attributes */
+
+- (NSString *)name;
+- (id)entities;
+- (id)notations;
+- (NSString *)publicId;
+- (NSString *)systemId;
+- (NSString *)internalSubset;
+
+/* node */
+
+@end
+
+@interface DOMDocumentType(PrivateCtors)
+/* use DOMDocument for constructing DOMDocumentType's ! */
+
+- (id)initWithName:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId;
+
+@end
+
+#endif /* __DOMDocumentType_H__ */
diff --git a/skyrix-xml/DOM/DOMDocumentType.m b/skyrix-xml/DOM/DOMDocumentType.m
new file mode 100644 (file)
index 0000000..2f8d304
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMDocumentType.h"
+#include "common.h"
+
+@implementation DOMDocumentType
+
+- (id)initWithName:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+  dom:(id)_dom
+{
+  [self release];
+  return nil;
+}
+
+/* attributes */
+
+- (NSString *)name {
+  return nil;
+}
+- (id)entities {
+  return nil;
+}
+- (id)notations {
+  return nil;
+}
+- (NSString *)publicId {
+  return nil;
+}
+- (NSString *)systemId {
+  return nil;
+}
+- (NSString *)internalSubset {
+  return nil;
+}
+
+/* node */
+
+- (DOMNodeType)nodeType {
+  return DOM_DOCUMENT_TYPE_NODE;
+}
+
+- (BOOL)_isValidChildNode:(id)_node {
+  return NO;
+}
+- (BOOL)hasChildNodes {
+  return NO;
+}
+- (id)childNodes {
+  return nil;
+}
+
+- (id)attributes {
+  return nil;
+}
+
+/* parent node */
+
+- (void)_domNodeRegisterParentNode:(id)_parent {
+  self->parent = _parent;
+}
+- (void)_domNodeForgetParentNode:(id)_parent {
+  if (_parent == self->parent)
+    /* the node's parent was deallocated */
+    self->parent = nil;
+}
+- (id)parentNode {
+  return self->parent;
+}
+
+@end /* DOMDocumentType */
diff --git a/skyrix-xml/DOM/DOMElement.h b/skyrix-xml/DOM/DOMElement.h
new file mode 100644 (file)
index 0000000..0da3e53
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOMElement_H__
+#define __DOMElement_H__
+
+#include <DOM/DOMNode.h>
+
+/*
+  Why is there no removeAttributeNodeNS method?
+  
+  There is, but it's called removeAttributeNode. 
+
+  We needed both setAttributeNode and setAttributeNodeNS, because those
+  functions use different rules to select which (if any) existing Attr the
+  new one will replace. setAttributeNode bases this decision on the nodeName,
+  while setAttributeNodeNS looks at the combination of namespaceURI and
+  localname. However, when you remove a specific Attr Node, its nodeName,
+  localname, and namespaceURI are ignored, and there's no need for a second
+  method to support this. 
+*/
+
+@class NSString, NSMutableDictionary, NSMutableArray;
+
+@interface DOMElement : DOMNodeWithChildren < DOMElement >
+{
+  id                  parent;
+  NSString            *tagName;
+  NSMutableDictionary *keyToAttribute;
+  NSMutableArray      *attributes;
+  
+  NSString *namespaceURI;
+  NSString *prefix;
+
+  /* positional info */
+  unsigned line;
+  
+  /* caches */
+  id attrNodeMap;
+}
+
+@end
+
+@interface DOMElement(PrivateCtors)
+/* use DOMDocument for constructing DOMElements ! */
+
+- (id)initWithTagName:(NSString *)_tagName;
+- (id)initWithTagName:(NSString *)_tagName namespaceURI:(NSString *)_uri;
+
+@end
+
+#endif /* __DOMElement_H__ */
diff --git a/skyrix-xml/DOM/DOMElement.m b/skyrix-xml/DOM/DOMElement.m
new file mode 100644 (file)
index 0000000..cbd0691
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <DOM/DOMElement.h>
+#include <DOM/DOMNamedNodeMap.h>
+#include <DOM/DOMAttribute.h>
+#include <DOM/DOMDocument.h>
+#include <DOM/DOMNodeWalker.h>
+#include "common.h"
+
+@interface _DOMElementAttrNamedNodeMap : NSObject < DOMNamedNodeMap >
+{
+  DOMElement *element; /* non-retained */
+}
+
+- (id)initWithElement:(id)_element;
+
+- (id)objectEnumerator;
+
+- (void)invalidate;
+
+@end /* _DOMElementAttrNamedNodeMap */
+
+@interface DOMElement(Privates)
+- (unsigned)_numberOfAttributes;
+- (id)_attributeNodeAtIndex:(unsigned)_idx;
+- (id)attributeNode:(NSString *)_localName;
+- (id)attributeNode:(NSString *)_localName namespaceURI:(NSString *)_ns;
+@end
+
+static NSNull *null = nil;
+
+@implementation DOMElement
+
+- (id)initWithTagName:(NSString *)_tagName namespaceURI:(NSString *)_uri {
+  if (null == nil)
+    null = [[NSNull null] retain];
+  
+  if ((self = [super init])) {
+    self->tagName      = [_tagName copy];
+    self->namespaceURI = [_uri     copy];
+  }
+  return self;
+}
+- (id)initWithTagName:(NSString *)_tagName {
+  return [self initWithTagName:_tagName namespaceURI:nil];
+}
+
+- (void)dealloc {
+  [self->attributes makeObjectsPerformSelector:
+                      @selector(_domNodeForgetParentNode:)
+                    withObject:self];
+
+  [self->attrNodeMap invalidate];
+  [self->attrNodeMap    release];
+  [self->keyToAttribute release];
+  [self->attributes     release];
+  [self->tagName        release];
+  [self->namespaceURI   release];
+  [self->prefix         release];
+  [super dealloc];
+}
+
+/* attributes */
+
+- (NSString *)tagName {
+  return self->tagName;
+}
+
+- (void)setPrefix:(NSString *)_prefix {
+  id old = self->prefix;
+  self->prefix = [_prefix copy];
+  [old release];
+}
+- (NSString *)prefix {
+  return self->prefix;
+}
+
+- (NSString *)namespaceURI {
+  return self->namespaceURI;
+}
+
+- (void)setLine:(unsigned)_line {
+  self->line = _line;
+}
+- (unsigned)line {
+  return self->line;
+}
+
+/* lookup */
+
+- (void)_walk_getElementsByTagName:(id)_walker {
+  id node;
+  
+  node = [_walker currentNode];
+  if ([node nodeType] != DOM_ELEMENT_NODE)
+    return;
+
+  if (![[node tagName] isEqualToString:
+          [(NSArray *)[_walker context] objectAtIndex:0]])
+    /* tagname doesn't match */
+    return;
+  
+  [[(NSArray *)[_walker context] objectAtIndex:1] addObject:node];
+}
+- (void)_walk_getElementsByTagNameAddAll:(id)_walker {
+  id node;
+  
+  node = [_walker currentNode];
+  if ([node nodeType] != DOM_ELEMENT_NODE)
+    return;
+  
+  [(NSMutableArray *)[_walker context] addObject:node];
+}
+- (id)getElementsByTagName:(NSString *)_tagName {
+  /* introduced in DOM2, should return a *live* list ! */
+  NSMutableArray        *array;
+  DOMNodePreorderWalker *walker;
+  SEL sel;
+  id  ctx;
+  
+  if (![self hasChildNodes])
+    return nil;
+
+  if (_tagName == nil)
+    return nil;
+
+  array = [NSMutableArray array];
+  
+  if ([_tagName isEqualToString:@"*"]) {
+    _tagName = nil;
+    ctx = array;
+    sel = @selector(_walk_getElementsByTagNameAddAll:);
+  }
+  else {
+    ctx = [NSArray arrayWithObjects:_tagName, array, nil];
+    sel = @selector(_walk_getElementsByTagName:);
+  }
+  
+  walker = [[DOMNodePreorderWalker alloc]
+                                   initWithTarget:self
+                                   selector:sel
+                                   context:ctx];
+  
+  [walker walkNode:self];
+
+  [walker release]; walker = nil;
+  return [[array copy] autorelease];
+}
+- (id)getElementsByTagName:(NSString *)_tagName namespaceURI:(NSString *)_uri {
+  // TODO: implement
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+/* element attributes */
+
+- (void)_ensureAttrs {
+  if (self->attributes == nil)
+    self->attributes = [[NSMutableArray alloc] init];
+  if (self->keyToAttribute == nil)
+    self->keyToAttribute = [[NSMutableDictionary alloc] init];
+}
+
+- (void)_attributeSetChanged {
+}
+
+- (unsigned)_numberOfAttributes {
+  return [self->attributes count];
+}
+- (id)_attributeNodeAtIndex:(unsigned)_idx {
+  if (_idx >= [self->attributes count])
+    return nil;
+  return [self->attributes objectAtIndex:_idx];
+}
+
+- (id)_keyForAttribute:(id<DOMAttr>)_attrNode {
+  return [_attrNode name];
+}
+- (id)_nskeyForLocalName:(NSString *)attrName namespaceURI:(NSString *)nsURI {
+  id key;
+  
+  if (attrName == nil)
+    return nil;
+  
+  if (nsURI) {
+    id objs[2];
+
+    objs[0] = attrName;
+    objs[1] = nsURI;
+    key = [NSArray arrayWithObjects:objs count:2];
+  }
+  else
+    key = attrName;
+  
+  return key;
+}
+- (id)_nskeyForAttribute:(id<DOMAttr>)_attrNode {
+  NSString *attrName;
+  
+  if ((attrName = [_attrNode name]) == nil) {
+    NSLog(@"WARNING: attribute %@ has no valid attribute name !", _attrNode);
+    return nil;
+  }
+  
+  return [self _nskeyForLocalName:attrName
+               namespaceURI:[_attrNode namespaceURI]];
+}
+
+- (BOOL)hasAttribute:(NSString *)_attrName {
+  return [self hasAttribute:_attrName namespaceURI:[self namespaceURI]];
+}
+
+- (void)setAttribute:(NSString *)_attrName value:(NSString *)_value {
+  [self setAttribute:_attrName namespaceURI:[self namespaceURI] value:_value];
+
+#if 0 // ms: ??
+  id node;
+  
+  NSAssert1(_attrName, @"invalid attribute name '%@'", _attrName);
+
+  if ((node = [self->keyToAttribute objectForKey:_attrName]) == nil) {
+    /* create new node */
+    node = [[self ownerDocument] createAttribute:_attrName];
+  }
+  NSAssert(node, @"couldn't find/create node for attribute");
+
+  node = [self setAttributeNode:node];
+  
+  [node setValue:_value];
+#endif
+}
+- (id)attributeNode:(NSString *)_attrName {
+  return [self attributeNode:_attrName namespaceURI:[self namespaceURI]];
+}
+- (NSString *)attribute:(NSString *)_attrName {
+  return [[self attributeNode:_attrName] value];
+}
+
+- (BOOL)hasAttribute:(NSString *)_localName namespaceURI:(NSString *)_ns {
+  id objs[2];
+  id key;
+
+  if ([_ns isEqualToString:@"*"]) {
+    /* match any namespace */
+    NSEnumerator *e;
+    id attr;
+    
+    if ((attr = [self->keyToAttribute objectForKey:_localName]))
+      return YES;
+    
+    e = [self->keyToAttribute keyEnumerator];
+    while ((key = [e nextObject])) {
+      if ([key isKindOfClass:[NSArray class]]) {
+        if ([[key objectAtIndex:0] isEqualToString:_localName])
+          return YES;
+      }
+    }
+    return NO;
+  }
+  
+  objs[0] = _localName;
+  objs[1] = _ns ? _ns : (id)null;
+  key = [NSArray arrayWithObjects:objs count:2];
+  
+  return [self->keyToAttribute objectForKey:key] ? YES : NO;
+}
+
+- (void)setAttribute:(NSString *)_localName namespaceURI:(NSString *)_ns
+  value:(NSString *)_value
+{
+  id key;
+  id node;
+  
+  key = [self _nskeyForLocalName:_localName namespaceURI:_ns];
+  NSAssert2(key, @"invalid (ns-)attribute name localName='%@', uri='%@'",
+            _localName, _ns);
+  
+  if ((node = [self->keyToAttribute objectForKey:key]) == nil) {
+    /* create new node */
+    node = [[self ownerDocument] createAttribute:_localName namespaceURI:_ns];
+  }
+  NSAssert(node, @"couldn't find/create node for attribute");
+
+  node = [self setAttributeNodeNS:node];
+  
+  [node setValue:_value];
+}
+- (id)attributeNode:(NSString *)_localName namespaceURI:(NSString *)_ns {
+  id objs[2];
+  id key;
+  
+  if ([_ns isEqualToString:@"*"]) {
+    /* match any namespace */
+    NSEnumerator *e;
+    id attr;
+    
+    if ((attr = [self->keyToAttribute objectForKey:_localName]))
+      return attr;
+    
+    e = [self->keyToAttribute keyEnumerator];
+    while ((key = [e nextObject])) {
+      if ([key isKindOfClass:[NSArray class]]) {
+        if ([[key objectAtIndex:0] isEqualToString:_localName])
+          return [self->keyToAttribute objectForKey:key];
+      }
+    }
+    return nil;
+  }
+  
+  objs[0] = _localName;
+  objs[1] = _ns ? _ns : (id)null;
+  key = [NSArray arrayWithObjects:objs count:2];
+
+  return [self->keyToAttribute objectForKey:key];
+}
+- (NSString *)attribute:(NSString *)_localName namespaceURI:(NSString *)_ns {
+  return [[self attributeNode:_localName namespaceURI:_ns] value];
+}
+
+- (id)setAttributeNodeNS:(id)_attrNode {
+  id key, oldNode;
+  
+  if (_attrNode == nil)
+    /* invalid node parameters */
+    return nil;
+  
+  if ((key = [self _nskeyForAttribute:_attrNode]) == nil)
+    /* couldn't get key */
+    return nil;
+  
+  [self _ensureAttrs];
+  
+  /* check if the key is already added */
+  
+  if ((oldNode = [self->keyToAttribute objectForKey:key])) {
+    if (oldNode == _attrNode) {
+      /* already contained */
+      // NSLog(@"node is already set !");
+      return _attrNode;
+    }
+    
+    /* replace existing node */
+    [self->attributes replaceObjectAtIndex:
+                        [self->attributes indexOfObject:oldNode]
+                      withObject:_attrNode];
+    [self->keyToAttribute setObject:_attrNode forKey:key];
+    
+    [_attrNode _domNodeRegisterParentNode:self];
+    [self _attributeSetChanged];
+
+    return _attrNode;
+  }
+  else {
+    /* add node */
+
+    NSAssert(self->keyToAttribute, @"missing keyToAttribute");
+    NSAssert(self->attributes,     @"missing attrs");
+    
+    [self->keyToAttribute setObject:_attrNode forKey:key];
+    [self->attributes     addObject:_attrNode];
+    
+    [_attrNode _domNodeRegisterParentNode:self];
+    [self _attributeSetChanged];
+
+    // NSLog(@"added attr %@, elem %@", _attrNode, self);
+    
+    return _attrNode;
+  }
+}
+
+- (void)removeAttribute:(NSString *)_attr namespaceURI:(NSString *)_uri {
+  id node;
+  id key;
+  
+  key = [self _nskeyForLocalName:_attr namespaceURI:_uri];
+  NSAssert2(key, @"invalid (ns-)attribute name '%@', '%@'", _attr, _uri);
+
+  node = [self->keyToAttribute objectForKey:key];
+  
+  [self removeAttributeNodeNS:node];
+}
+- (id)removeAttributeNodeNS:(id)_attrNode {
+  id key, oldNode;
+  
+  if (_attrNode == nil)
+    /* invalid node parameters */
+    return nil;
+  
+  if (self->attributes == nil)
+    /* no attributes are set up */
+    return nil;
+  
+  if ((key = [self _nskeyForAttribute:_attrNode]) == nil)
+    /* couldn't get key for node */
+    return nil;
+
+  if ((oldNode = [self->keyToAttribute objectForKey:key])) {
+    /* the node's key exists */
+    if (oldNode != _attrNode) {
+      /* the node has the same key, but isn't the same */
+      return nil;
+    }
+
+    /* ok, found the node, let's remove ! */
+    [[_attrNode retain] autorelease];
+    [self->keyToAttribute removeObjectForKey:key];
+    [self->attributes removeObjectIdenticalTo:_attrNode];
+    
+    [_attrNode _domNodeForgetParentNode:self];
+    [self _attributeSetChanged];
+    
+    return _attrNode;
+  }
+  else
+    /* no such attribute is stored */
+    return nil;
+}
+
+- (id)setAttributeNode:(id)_attrNode {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+- (id)removeAttributeNode:(id)_attrNode {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+- (void)removeAttribute:(NSString *)_attr {
+  id node;
+  
+  NSAssert1(_attr, @"invalid attribute name '%@'", _attr);
+
+  node = [self->keyToAttribute objectForKey:_attr];
+  
+  [self removeAttributeNode:node];
+}
+
+/* node */
+
+- (BOOL)_isValidChildNode:(id)_node {
+  switch ([_node nodeType]) {
+    case DOM_ELEMENT_NODE:
+    case DOM_TEXT_NODE:
+    case DOM_COMMENT_NODE:
+    case DOM_PROCESSING_INSTRUCTION_NODE:
+    case DOM_CDATA_SECTION_NODE:
+    case DOM_ENTITY_REFERENCE_NODE:
+      return YES;
+      
+    default:
+      return NO;
+  }
+}
+
+- (DOMNodeType)nodeType {
+  return DOM_ELEMENT_NODE;
+}
+
+- (id)attributes {
+  /* returns a named-node-map */
+  if (self->attrNodeMap == nil) {
+    self->attrNodeMap =
+      [[_DOMElementAttrNamedNodeMap alloc] initWithElement:self];
+  }
+  return self->attrNodeMap;
+}
+
+/* parent node */
+
+- (void)_domNodeRegisterParentNode:(id)_parent {
+  self->parent = _parent;
+}
+- (void)_domNodeForgetParentNode:(id)_parent {
+  if (_parent == self->parent)
+    /* the node's parent was deallocated */
+    self->parent = nil;
+}
+- (id)parentNode {
+  return self->parent;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<0x%08X[%@]: name=%@ parent=%@ #attrs=%i #children=%i>",
+                     self, NSStringFromClass([self class]),
+                     [self nodeName],
+                     [[self parentNode] nodeName],
+                     [self _numberOfAttributes],
+                     [self hasChildNodes] ? [[self childNodes] length] : 0];
+}
+
+@end /* DOMElement */
+
+@implementation DOMElement(QPValues)
+
+- (NSException *)setQueryPathValue:(id)_value {
+  return [NSException exceptionWithName:@"QueryPathEvalException"
+                      reason:@"cannot set query-path value on DOMElement !"
+                      userInfo:nil];
+}
+- (id)queryPathValue {
+  return [self childNodes];
+}
+
+@end /* DOMElement(QPValues) */
+
+@implementation _DOMElementAttrNamedNodeMap
+
+- (id)initWithElement:(id)_element {
+  self->element = _element;
+  return self;
+}
+
+- (void)invalidate {
+  self->element = nil;
+}
+
+static inline void _checkValid(_DOMElementAttrNamedNodeMap *self) {
+  if (self->element == nil) {
+    NSCAssert(self->element,
+              @"named node map is invalid (element was deallocated) !");
+  }
+}
+
+/* access */
+
+static NSString *_XNSUri(NSString *_name) {
+  NSRange r1;
+
+  if (![_name hasPrefix:@"{"])
+    return nil;
+  
+  r1 = [_name rangeOfString:@"}"];
+  if (r1.length == 0)
+    return nil;
+  
+  r1.length   = (r1.location - 2);
+  r1.location = 1;
+  return [_name substringWithRange:r1];
+}
+static NSString *_XNSLocalName(NSString *_name) {
+  NSRange r;
+  
+  r = [_name rangeOfString:@"}"];
+  return r.length == 0
+    ? _name
+    : [_name substringFromIndex:(r.location + r.length)];
+}
+
+- (unsigned)length {
+  _checkValid(self);
+  return [self->element _numberOfAttributes];
+}
+- (id)objectAtIndex:(unsigned)_idx {
+  _checkValid(self);
+  return [self->element _attributeNodeAtIndex:_idx];
+}
+
+- (id)namedItem:(NSString *)_name {
+  NSString *nsuri;
+  _checkValid(self);
+  
+  if ((nsuri = _XNSUri(_name)))
+    return [self namedItem:_XNSLocalName(_name) namespaceURI:nsuri];
+  
+  return [self->element attributeNode:_name];
+}
+- (id)setNamedItem:(id)_node {
+  _checkValid(self);
+  return [self->element setAttributeNode:_node];
+}
+- (id)removeNamedItem:(NSString *)_name {
+  NSString *nsuri;
+  id node;
+  
+  _checkValid(self);
+  if ((nsuri = _XNSUri(_name)))
+    return [self removeNamedItem:_XNSLocalName(_name) namespaceURI:nsuri];
+  
+  if ((node = [self->element attributeNode:_name])) {
+    node = [node retain];
+    [self->element removeAttribute:_name];
+    return [node autorelease];
+  }
+  else
+    return nil;
+}
+
+/* DOM2 access */
+
+- (id)namedItem:(NSString *)_name namespaceURI:(NSString *)_uri {
+  return [self->element attributeNode:_name namespaceURI:_uri];
+}
+- (id)setNamedItemNS:(id)_node {
+  _checkValid(self);
+  return [self->element setAttributeNodeNS:_node];
+}
+- (id)removeNamedItem:(NSString *)_name namespaceURI:(NSString *)_uri {
+  id node;
+
+  _checkValid(self);
+  if ((node = [self->element attributeNode:_name namespaceURI:_uri])) {
+    node = [node retain];
+    [self->element removeAttribute:_name namespaceURI:_uri];
+    return [node autorelease];
+  }
+  else
+    return nil;
+}
+
+/* mimic NSArray */
+
+- (unsigned)count {
+  _checkValid(self);
+  return [self->element _numberOfAttributes];
+}
+
+- (id)objectEnumerator {
+  NSMutableArray *ma;
+  unsigned i, count;
+
+  _checkValid(self);
+  if ((count = [self->element _numberOfAttributes]) == 0)
+    return nil;
+
+  ma = [NSMutableArray arrayWithCapacity:count];
+  
+  for (i = 0; i < count; i++)
+    [ma addObject:[self->element _attributeNodeAtIndex:i]];
+  
+  return [ma objectEnumerator];
+}
+
+/* mimic NSDictionary */
+
+- (void)setObject:(id)_value forKey:(id)_key {
+  _checkValid(self);
+  [self takeValue:_value forKey:[_key stringValue]];
+}
+- (id)objectForKey:(id)_key {
+  _checkValid(self);
+  return [self valueForKey:[_key stringValue]];
+}
+
+/* KVC */
+
+- (void)takeValue:(id)_value forKey:(NSString *)_key {
+  id node;
+  _checkValid(self);
+  
+  if ((node = [self->element attributeNode:_key namespaceURI:@"*"])) {
+    [node setValue:[_value stringValue]];
+  }
+  else {
+    [self->element setAttribute:_key namespaceURI:@"xhtml"
+                   value:[_value stringValue]];
+  }
+}
+- (id)valueForKey:(NSString *)_key {
+  id v;
+  _checkValid(self);
+  
+  if ((v = [self namedItem:_key]))
+    return [v value];
+  if ((v = [self namedItem:_key namespaceURI:@"*"]))
+    return [v value];
+  
+  return nil;
+}
+
+/* JSSupport */
+
+- (id)_jsprop_length {
+  return [NSNumber numberWithInt:[self length]];
+}
+
+- (id)_jsfunc_item:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) return nil;
+  return [self objectAtIndex:[[_args objectAtIndex:0] intValue]];
+}
+
+- (id)_jsfunc_getNamedItem:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) return nil;
+  return [self namedItem:[[_args objectAtIndex:0] stringValue]];
+}
+- (id)_jsfunc_getNamedItemNS:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) return nil;
+  if (count == 1)
+    return [self namedItem:[[_args objectAtIndex:0] stringValue]];
+  else {
+    return [self namedItem:[[_args objectAtIndex:1] stringValue]
+                 namespaceURI:[[_args objectAtIndex:0] stringValue]];
+  }
+}
+
+- (id)_jsfunc_setNamedItem:(NSArray *)_args {
+  unsigned i, count;
+  id last = nil;
+
+  for (i = 0, count = [_args count]; i < count; i++)
+    last = [self setNamedItem:[_args objectAtIndex:i]];
+  return last;
+}
+- (id)_jsfunc_setNamedItemNS:(NSArray *)_args {
+  unsigned i, count;
+  id last = nil;
+
+  for (i = 0, count = [_args count]; i < count; i++)
+    last = [self setNamedItemNS:[_args objectAtIndex:i]];
+  return last;
+}
+
+- (id)_jsfunc_removeNamedItem:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) return nil;
+  return [self namedItem:[[_args objectAtIndex:0] stringValue]];
+}
+- (id)_jsfunc_removeNamedItemNS:(NSArray *)_args {
+  unsigned count;
+  
+  if ((count = [_args count]) == 0) return nil;
+  if (count == 1)
+    return [self removeNamedItem:[[_args objectAtIndex:0] stringValue]];
+  else {
+    return [self removeNamedItem:[[_args objectAtIndex:1] stringValue]
+                 namespaceURI:[[_args objectAtIndex:0] stringValue]];
+  }
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  NSEnumerator *e;
+  id attr;
+  
+  ms = [NSMutableString stringWithCapacity:1024];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  [ms appendFormat:@" element=%@", self->element];
+  
+  [ms appendString:@" attributes:\n"];
+  e = [self objectEnumerator];
+  while ((attr = [e nextObject])) {
+    [ms appendString:[attr description]];
+    [ms appendString:@"\n"];
+  }
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* _DOMElementAttrNamedNodeMap */
diff --git a/skyrix-xml/DOM/DOMEntity.h b/skyrix-xml/DOM/DOMEntity.h
new file mode 100644 (file)
index 0000000..83c5ef4
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMEntity_H__
+#define __DOMEntity_H__
+
+#include <DOM/DOMNode.h>
+
+@class NSString;
+
+@interface DOMEntity : DOMNodeWithChildren
+{
+}
+
+/* attributes */
+
+- (NSString *)publicId;
+- (NSString *)systemId;
+- (NSString *)notationName;
+
+/* node */
+
+@end
+
+@interface DOMEntity(PrivateCtors)
+/* use DOMDocument for constructing DOMEntity's ! */
+
+@end
+
+#endif /* __DOMEntity_H__ */
diff --git a/skyrix-xml/DOM/DOMEntity.m b/skyrix-xml/DOM/DOMEntity.m
new file mode 100644 (file)
index 0000000..e6dce1d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMEntity.h"
+#include "common.h"
+
+@implementation DOMEntity
+
+/* attributes */
+
+- (NSString *)publicId {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+- (NSString *)systemId {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+- (NSString *)notationName {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+/* node */
+
+- (DOMNodeType)nodeType {
+  return DOM_ENTITY_NODE;
+}
+
+- (BOOL)_isValidChildNode:(id)_node {
+  switch ([_node nodeType]) {
+    case DOM_ELEMENT_NODE:
+    case DOM_PROCESSING_INSTRUCTION_NODE:
+    case DOM_COMMENT_NODE:
+    case DOM_TEXT_NODE:
+    case DOM_CDATA_SECTION_NODE:
+    case DOM_ENTITY_REFERENCE_NODE:
+      return YES;
+        
+    default:
+      return NO;
+  }
+}
+
+- (id)attributes {
+  return nil;
+}
+
+/* parent node */
+
+- (id)parentNode {
+  return nil;
+}
+- (id)nextSibling {
+  return nil;
+}
+- (id)previousSibling {
+  return nil;
+}
+
+@end /* DOMEntity */
diff --git a/skyrix-xml/DOM/DOMEntityReference.h b/skyrix-xml/DOM/DOMEntityReference.h
new file mode 100644 (file)
index 0000000..bb22b51
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMEntityReference_H__
+#define __DOMEntityReference_H__
+
+#include <DOM/DOMNode.h>
+
+@class NSString;
+
+@interface DOMEntityReference : DOMNodeWithChildren
+{
+  id parent;
+  NSString *name;
+}
+
+/* attributes */
+
+/* node */
+
+@end
+
+@interface DOMEntityReference(PrivateCtors)
+/* use DOMDocument for constructing DOMEntityReference's ! */
+
+- (id)initWithName:(NSString *)_name;
+
+@end
+
+#endif /* __DOMEntityReference_H__ */
diff --git a/skyrix-xml/DOM/DOMEntityReference.m b/skyrix-xml/DOM/DOMEntityReference.m
new file mode 100644 (file)
index 0000000..e2576d3
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMEntityReference.h"
+#include "common.h"
+
+@implementation DOMEntityReference
+
+- (id)initWithName:(NSString *)_name {
+  self->name = [_name copy];
+  return self;
+}
+- (void)dealloc {
+  [self->name release];
+  [super dealloc];
+}
+
+- (DOMNodeType)nodeType {
+  return DOM_ENTITY_REFERENCE_NODE;
+}
+
+- (id)attributes {
+  return nil;
+}
+
+/* parent node */
+
+- (void)_domNodeRegisterParentNode:(id)_parent {
+  self->parent = _parent;
+}
+- (void)_domNodeForgetParentNode:(id)_parent {
+  if (_parent == self->parent)
+    /* the node's parent was deallocated */
+    self->parent = nil;
+}
+- (id)parentNode {
+  return self->parent;
+}
+
+@end /* DOMEntityReference */
diff --git a/skyrix-xml/DOM/DOMImplementation.h b/skyrix-xml/DOM/DOMImplementation.h
new file mode 100644 (file)
index 0000000..5d561b6
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMImplementation_H__
+#define __DOMImplementation_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+
+@interface DOMImplementation : NSObject
+{
+  Class elementClass;
+  Class textNodeClass;
+  Class attrClass;
+}
+
+- (id)createDocumentWithName:(NSString *)_qname
+  namespaceURI:(NSString *)_uri
+  documentType:(id)_doctype;
+
+- (id)createDocumentType:(NSString *)_qname
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId;
+
+@end
+
+@interface DOMImplementation(PrivateClassRegistry)
+- (Class)domElementClass;
+- (Class)domElementNSClass;
+- (Class)domDocumentFragmentClass;
+- (Class)domTextNodeClass;
+- (Class)domCommentClass;
+- (Class)domCDATAClass;
+- (Class)domProcessingInstructionClass;
+- (Class)domAttributeClass;
+- (Class)domAttributeNSClass;
+- (Class)domEntityReferenceClass;
+@end
+
+#endif /* __DOMImplementation_H__ */
diff --git a/skyrix-xml/DOM/DOMImplementation.m b/skyrix-xml/DOM/DOMImplementation.m
new file mode 100644 (file)
index 0000000..cf05a7a
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMImplementation.h"
+#include "DOMDocument.h"
+#include "DOMDocumentFragment.h"
+#include "common.h"
+
+@implementation DOMImplementation
+
+- (id)init {
+  self->elementClass  = NSClassFromString(@"DOMElement");
+  self->textNodeClass = NSClassFromString(@"DOMText");
+  self->attrClass     = NSClassFromString(@"DOMAttribute");
+  return self;
+}
+
+- (Class)domDocumentClass {
+  return [DOMDocument class];
+}
+- (Class)domDocumentTypeClass {
+  return NSClassFromString(@"DOMDocumentType");
+}
+
+- (Class)domElementClass {
+  return self->elementClass;
+}
+- (Class)domElementNSClass {
+  return self->elementClass;
+}
+- (Class)domDocumentFragmentClass {
+  return NSClassFromString(@"DOMDocumentFragment");
+}
+- (Class)domTextNodeClass {
+  return self->textNodeClass;
+}
+- (Class)domCommentClass {
+  return NSClassFromString(@"DOMComment");
+}
+- (Class)domCDATAClass {
+  return NSClassFromString(@"DOMCDATA");
+}
+- (Class)domProcessingInstructionClass {
+  return NSClassFromString(@"DOMProcessingInstruction");
+}
+- (Class)domAttributeClass {
+  return self->attrClass;
+}
+- (Class)domAttributeNSClass {
+  return self->attrClass;
+}
+- (Class)domEntityReferenceClass {
+  return NSClassFromString(@"DOMEntityReference");
+}
+
+- (id)createDocumentWithName:(NSString *)_qname
+  namespaceURI:(NSString *)_uri
+  documentType:(id)_doctype
+{
+  id doc;
+  
+  doc = [[[self domDocumentClass]
+                alloc]
+                initWithName:_qname
+                namespaceURI:_uri
+                documentType:_doctype
+               dom:self];
+  
+  return [doc autorelease];
+}
+
+- (id)createDocumentType:(NSString *)_qname
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+{
+  id doc;
+  
+  doc = [[[self domDocumentTypeClass]
+                alloc]
+                initWithName:_qname
+                publicId:_pubId
+                systemId:_sysId
+               dom:self];
+  
+  return [doc autorelease];
+}
+
+@end /* DOMImplementation */
diff --git a/skyrix-xml/DOM/DOMNamedNodeMap.h b/skyrix-xml/DOM/DOMNamedNodeMap.h
new file mode 100644 (file)
index 0000000..fa4fa4d
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMNamedNodeMap_H__
+#define __DOMNamedNodeMap_H__
+
+#endif /* __DOMNamedNodeMap_H__ */
diff --git a/skyrix-xml/DOM/DOMNode+Enum.h b/skyrix-xml/DOM/DOMNode+Enum.h
new file mode 100644 (file)
index 0000000..1a1209b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOM_DOMNodeEnum_H__
+#define __DOM_DOMNodeEnum_H__
+
+#include <DOM/DOMNode.h>
+
+@class NSEnumerator;
+
+@interface NSObject(DOMNodeEnum)
+
+- (NSEnumerator *)domParentNodeEnumerator;
+
+@end /* DOMNode(Enum) */
+
+@interface DOMNode(Enum)
+
+- (NSEnumerator *)parentNodeEnumerator;
+
+@end /* DOMNode(Enum) */
+
+#endif /* __DOM_DOMNodeEnum_H__ */
diff --git a/skyrix-xml/DOM/DOMNode+Enum.m b/skyrix-xml/DOM/DOMNode+Enum.m
new file mode 100644 (file)
index 0000000..fd45786
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "DOMNode+Enum.h"
+#include "common.h"
+
+@interface _DOMNodeParentNodeEnumerator : NSEnumerator
+{
+  id currentNode;
+}
++ (id)enumeratorWithDOMNode:(id)_node;
+@end
+
+@implementation NSObject(DOMNodeEnum)
+
+- (NSEnumerator *)domParentNodeEnumerator {
+  return [_DOMNodeParentNodeEnumerator enumeratorWithDOMNode:
+                                         [(DOMNode *)self parentNode]];
+}
+
+@end /* DOMNode(Enum) */
+
+@implementation DOMNode(Enum)
+
+- (NSEnumerator *)parentNodeEnumerator {
+  return [self domParentNodeEnumerator];
+}
+
+@end /* DOMNode(Enum) */
+
+@implementation _DOMNodeParentNodeEnumerator
+
++ (id)enumeratorWithDOMNode:(id)_node {
+  _DOMNodeParentNodeEnumerator *e;
+  e = [self alloc];
+  e->currentNode = [_node retain];
+  return [e autorelease];
+}
+
+- (void)dealloc {
+  [self->currentNode release];
+  [super dealloc];
+}
+
+- (id)nextObject {
+  id old;
+
+  old = self->currentNode;
+  self->currentNode = [[old parentNode] retain];
+  return [old autorelease];
+}
+
+@end /* _DOMNodeParentNodeEnumerator */
diff --git a/skyrix-xml/DOM/DOMNode+QPEval.m b/skyrix-xml/DOM/DOMNode+QPEval.m
new file mode 100644 (file)
index 0000000..f89795d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSObject+QPEval.h"
+#include "DOMNode.h"
+#include "DOMDocument.h"
+#include "common.h"
+
+@implementation DOMNode(QPEval)
+
+- (id)queryPathRootObjectInContext:(id)_ctx {
+  return [self ownerDocument];
+}
+
+@end /* DOMNode(QPEval) */
+
+@implementation DOMDocument(QPEval)
+
+- (id)queryPathRootObjectInContext:(id)_ctx {
+  return self;
+}
+
+@end /* DOMNode(QPEval) */
diff --git a/skyrix-xml/DOM/DOMNode+QueryPath.h b/skyrix-xml/DOM/DOMNode+QueryPath.h
new file mode 100644 (file)
index 0000000..fa7f983
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOM_DOMNodeQueryPath_H__
+#define __DOM_DOMNodeQueryPath_H__
+
+#include <DOM/DOMNode.h>
+#include <DOM/DOMQueryPathExpression.h>
+
+/*
+  Perform query path lookups on a DOM node. Look into DOMQueryPathExpression
+  for the actual path syntax.
+*/
+
+@class NSString, NSArray;
+
+@interface DOMNode(QueryPath)
+
+/* Evaluate a stack of path specifiers. */
+- (id)lookupPathComponents:(NSArray *)_path;
+
+/* Same like above using a string */
+- (id)lookupQueryPath:(NSString *)_path;
+
+@end
+
+#endif /* __DOM_DOMNodeQueryPath_H__ */
diff --git a/skyrix-xml/DOM/DOMNode+QueryPath.m b/skyrix-xml/DOM/DOMNode+QueryPath.m
new file mode 100644 (file)
index 0000000..7c37506
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "DOMNode+QueryPath.h"
+#include "DOMQueryPathExpression.h"
+#include "common.h"
+
+@implementation DOMNode(QueryPath)
+
+- (id)lookupPathComponents:(NSArray *)_path {
+  DOMQueryPathExpression *expr;
+  
+  if (_path == nil)
+    return nil;
+  
+  expr = [DOMQueryPathExpression queryPathWithComponents:_path];
+  
+  return [expr evaluateWithNode:self];
+}
+
+- (id)lookupQueryPath:(NSString *)_path {
+  DOMQueryPathExpression *expr;
+  
+  if (_path == nil)
+    return nil;
+  
+  expr = [DOMQueryPathExpression queryPathWithString:_path];
+  
+  return [expr evaluateWithNode:self];
+}
+
+@end /* DOMNode(QueryPath) */
diff --git a/skyrix-xml/DOM/DOMNode.h b/skyrix-xml/DOM/DOMNode.h
new file mode 100644 (file)
index 0000000..4d1c072
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOMNode_H__
+#define __DOMNode_H__
+
+#import <Foundation/NSObject.h>
+#include <DOM/DOMProtocols.h>
+
+@class NSMutableArray, NSData;
+@class DOMDocument;
+
+@interface DOMNode : NSObject < DOMNode >
+{
+}
+
+@end
+
+@interface DOMNode(Additions)
+
+- (NSString *)nodeTypeString;
+- (NSString *)xmlStringValue;
+- (NSData *)xmlDataValue;
+- (NSString *)textValue;
+
+@end
+
+@interface DOMNodeWithChildren : DOMNode
+{
+@private
+  NSMutableArray *childNodes;
+}
+@end
+
+@interface NSObject(DOMNodePrivate)
+
+- (id)_domNodeBeforeNode:(id)_node;
+- (id)_domNodeAfterNode:(id)_node;
+
+- (void)_domNodeRegisterParentNode:(id)_parentNode;
+- (void)_domNodeForgetParentNode:(id)_parentNode;
+
+@end
+
+NSString *DOMNodeName(id _node);
+NSString *DOMNodeValue(id _node);
+
+#endif /* __DOMNode_H__ */
diff --git a/skyrix-xml/DOM/DOMNode.m b/skyrix-xml/DOM/DOMNode.m
new file mode 100644 (file)
index 0000000..bf84f61
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <DOM/DOMNode.h>
+#include <DOM/DOMDocument.h>
+#include <DOM/DOMProcessingInstruction.h>
+#include <DOM/DOMCharacterData.h>
+#include <DOM/DOMElement.h>
+#include <DOM/DOMAttribute.h>
+#include "common.h"
+
+NSString *DOMNodeName(id<DOMNode> _node) {
+  switch ([_node nodeType]) {
+    case DOM_ATTRIBUTE_NODE:
+      return [(id<DOMAttr>)_node name];
+    case DOM_CDATA_SECTION_NODE:
+      return @"#cdata-section";
+    case DOM_COMMENT_NODE:
+      return @"#comment";
+    case DOM_DOCUMENT_NODE:
+      return @"#document";
+    case DOM_DOCUMENT_FRAGMENT_NODE:
+      return @"#document-fragment";
+    case DOM_ELEMENT_NODE:
+      return [(id<DOMElement>)_node tagName];
+    case DOM_PROCESSING_INSTRUCTION_NODE:
+      return [(id<DOMProcessingInstruction>)_node target];
+    case DOM_TEXT_NODE:
+      return @"#text";
+      
+    case DOM_DOCUMENT_TYPE_NODE:
+    case DOM_ENTITY_NODE:
+    case DOM_ENTITY_REFERENCE_NODE:
+    case DOM_NOTATION_NODE:
+    default:
+      NSLog(@"ERROR: unknown node type %i !", [_node nodeType]);
+      return nil;
+  }
+}
+
+NSString *DOMNodeValue(id _node) {
+  switch ([_node nodeType]) {
+    case DOM_ATTRIBUTE_NODE:
+      return [_node value];
+      
+    case DOM_CDATA_SECTION_NODE:
+    case DOM_COMMENT_NODE:
+    case DOM_TEXT_NODE:
+      return [(DOMCharacterData *)_node data];
+
+    case DOM_DOCUMENT_NODE:
+    case DOM_DOCUMENT_FRAGMENT_NODE:
+    case DOM_ELEMENT_NODE:
+      return nil;
+      
+    case DOM_PROCESSING_INSTRUCTION_NODE:
+      return [(DOMProcessingInstruction *)_node data];
+      
+    case DOM_DOCUMENT_TYPE_NODE:
+    case DOM_ENTITY_NODE:
+    case DOM_ENTITY_REFERENCE_NODE:
+    case DOM_NOTATION_NODE:
+    default:
+      NSLog(@"ERROR: unknown node type %i !", [_node nodeType]);
+      return nil;
+  }
+}
+
+@implementation DOMNode
+
+- (void)_domNodeRegisterParentNode:(id)_parent {
+}
+- (void)_domNodeForgetParentNode:(id)_parent {
+}
+
+/* owner */
+
+- (DOMDocument *)ownerDocument {
+  id node;
+
+  for (node = [self parentNode]; node; node = [node parentNode]) {
+    if ([node nodeType] == DOM_DOCUMENT_NODE)
+      return node;
+    if ([node nodeType] == DOM_DOCUMENT_FRAGMENT_NODE)
+      return node;
+  }
+  
+  return nil;
+}
+
+/* attributes */
+
+- (DOMNodeType)nodeType {
+  return DOM_UNKNOWN_NODE;
+}
+
+- (NSString *)nodeName {
+  return DOMNodeName(self);
+}
+- (NSString *)nodeValue {
+  return DOMNodeValue(self);
+}
+
+- (id)subclassResponsibility:(SEL)_sel {
+  [self doesNotRecognizeSelector:_sel];
+  return nil;
+}
+
+- (NSString *)localName {
+  /* introduced in DOM level 2 */
+  return [self subclassResponsibility:_cmd];
+}
+- (NSString *)namespaceURI {
+  /* introduced in DOM level 2 */
+  return [self subclassResponsibility:_cmd];
+}
+
+- (void)setPrefix:(NSString *)_prefix {
+  /* introduced in DOM level 2 */
+  [self subclassResponsibility:_cmd];
+}
+- (NSString *)prefix {
+  /* introduced in DOM level 2 */
+  return [self subclassResponsibility:_cmd];
+}
+
+/* element attributes */
+
+- (id)attributes {
+  /* returns a NamedNodeList */
+  return [self subclassResponsibility:_cmd];
+}
+
+/* modification */
+
+- (BOOL)_isValidChildNode:(id)_node {
+  return NO;
+}
+
+- (id)removeChild:(id)_node {
+  return nil;
+}
+- (id)appendChild:(id)_node {
+  return nil;
+}
+
+/* navigation */
+
+- (id)parentNode {
+  return [self subclassResponsibility:_cmd];
+}
+
+- (id)previousSibling {
+  DOMNode *parent;
+  
+  if ((parent = (DOMNode *)[self parentNode]) == nil) return nil;
+  if (parent == nil) return nil;
+  if (![parent respondsToSelector:@selector(_domNodeBeforeNode:)]) return nil;
+  return [parent _domNodeBeforeNode:self];
+}
+- (id)nextSibling {
+  DOMNode *parent;
+  
+  if ((parent = (DOMNode *)[self parentNode]) == nil) return nil;
+  if (parent == nil) return nil;
+  if (![parent respondsToSelector:@selector(_domNodeBeforeNode:)]) return nil;
+  return [parent _domNodeAfterNode:self];
+}
+
+- (id)childNodes {
+  return nil;
+}
+- (BOOL)hasChildNodes {
+  return NO;
+}
+- (id)firstChild {
+  return nil;
+}
+- (id)lastChild {
+  return nil;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:
+                     @"<0x%08X[%@]: name=%@ parent=%@ type=%i #children=%i>",
+                     self, NSStringFromClass([self class]),
+                     [self nodeName],
+                     [[self parentNode] nodeName],
+                     [self nodeType],
+                     [self hasChildNodes] ? [[self childNodes] length] : 0];
+}
+
+@end /* DOMNode */
+
+#include "DOMXMLOutputter.h"
+#include "DOMCharacterData.h"
+
+@implementation DOMNode(Additions)
+
+- (NSString *)nodeTypeString {
+  switch ([self nodeType]) {
+    case DOM_ATTRIBUTE_NODE:              return @"attribute";
+    case DOM_CDATA_SECTION_NODE:          return @"cdata-section";
+    case DOM_COMMENT_NODE:                return @"comment";
+    case DOM_DOCUMENT_NODE:               return @"document";
+    case DOM_DOCUMENT_FRAGMENT_NODE:      return @"document-fragment";
+    case DOM_ELEMENT_NODE:                return @"element";
+    case DOM_PROCESSING_INSTRUCTION_NODE: return @"processing-instruction";
+    case DOM_TEXT_NODE:                   return @"text";
+    case DOM_DOCUMENT_TYPE_NODE:          return @"document-type";
+    case DOM_ENTITY_NODE:                 return @"entity";
+    case DOM_ENTITY_REFERENCE_NODE:       return @"entity-reference";
+    case DOM_NOTATION_NODE:               return @"notation";
+    default:
+      return @"unknown";
+  }
+}
+
+- (NSString *)xmlStringValue {
+  DOMXMLOutputter *out;
+  NSMutableString *s;
+  NSString *r;
+
+  s   = [[NSMutableString alloc] initWithCapacity:1024];
+  out = [[DOMXMLOutputter alloc] init];
+
+  [out outputNode:self to:s];
+  [out release];
+  
+  r = [s copy];
+  [s release];
+  return [r autorelease];
+}
+
+- (NSData *)xmlDataValue {
+  return [[self xmlStringValue] dataUsingEncoding:NSUTF8StringEncoding];
+}
+
+- (NSString *)textValue {
+  NSMutableString *s;
+  
+  s = [NSMutableString stringWithCapacity:256];
+
+  switch ([self nodeType]) {
+    case DOM_ELEMENT_NODE:
+    case DOM_DOCUMENT_NODE:
+    case DOM_ATTRIBUTE_NODE:
+      if ([self hasChildNodes]) {
+        id children;
+        unsigned i, count;
+        
+        children = [self childNodes];
+        for (i = 0, count = [children count]; i < count; i++) {
+          NSString *cs;
+
+          cs = [[children objectAtIndex:i] textValue];
+          if (cs) [s appendString:cs];
+        }
+      }
+      break;
+      
+    case DOM_TEXT_NODE:
+    case DOM_COMMENT_NODE:
+    case DOM_CDATA_SECTION_NODE:
+      [s appendString:[(DOMCharacterData *)self data]];
+      break;
+      
+    default:
+      return nil;
+  }
+  
+  return [[s copy] autorelease];
+}
+
+@end /* DOMNode(Additions) */
+
+@implementation NSArray(DOMNodeList)
+
+- (unsigned)length {
+  return [self count];
+}
+
+@end /* NSObject(DOMNodeList) */
diff --git a/skyrix-xml/DOM/DOMNodeFilter.h b/skyrix-xml/DOM/DOMNodeFilter.h
new file mode 100644 (file)
index 0000000..bb708f7
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMNodeFilter_H__
+#define __DOMNodeFilter_H__
+
+#import <Foundation/NSObject.h>
+
+typedef enum {
+  DOM_FILTER_ACCEPT = 1,
+  DOM_FILTER_REJECT = 2,
+  DOM_FILTER_SKIP   = 3
+} DOMNodeFilterType;
+
+/* constants for whatToShow */
+
+#define DOM_SHOW_ALL                    0xFFFFFFFF
+#define DOM_SHOW_ELEMENT                0x00000001
+#define DOM_SHOW_ATTRIBUTE              0x00000002
+#define DOM_SHOW_TEXT                   0x00000004
+#define DOM_SHOW_CDATA_SECTION          0x00000008
+#define DOM_SHOW_ENTITY_REFERENCE       0x00000010
+#define DOM_SHOW_ENTITY                 0x00000020
+#define DOM_SHOW_PROCESSING_INSTRUCTION 0x00000040
+#define DOM_SHOW_COMMENT                0x00000080
+#define DOM_SHOW_DOCUMENT               0x00000100
+#define DOM_SHOW_DOCUMENT_TYPE          0x00000200
+#define DOM_SHOW_DOCUMENT_FRAGMENT      0x00000400
+#define DOM_SHOW_NOTATION               0x00000800
+
+@interface DOMNodeFilter : NSObject
+
+- (DOMNodeFilterType)acceptNode:(id)_node;
+
+@end
+
+#endif /* __DOMNodeFilter_H__ */
diff --git a/skyrix-xml/DOM/DOMNodeFilter.m b/skyrix-xml/DOM/DOMNodeFilter.m
new file mode 100644 (file)
index 0000000..6f5fcef
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMNodeFilter.h"
+
+@implementation DOMNodeFilter
+
+- (DOMNodeFilterType)acceptNode:(id)_node {
+  return DOM_FILTER_ACCEPT;
+}
+
+@end /* DOMNodeFilter */
diff --git a/skyrix-xml/DOM/DOMNodeIterator.h b/skyrix-xml/DOM/DOMNodeIterator.h
new file mode 100644 (file)
index 0000000..31d4b9f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMNodeIterator_H__
+#define __DOMNodeIterator_H__
+
+#import <Foundation/NSObject.h>
+
+@interface DOMNodeIterator : NSObject
+{
+  id            root;
+  unsigned long whatToShow;
+  id            filter;
+  BOOL          expandEntityReferences;
+  
+  /* position */
+  id            lastNode;
+  BOOL          beforeFirst;
+  BOOL          afterLast;
+}
+
+/* attributes */
+
+- (id)root;
+- (unsigned long)whatToShow;
+- (id)filter;
+- (BOOL)expandEntityReferences;
+
+/* operators */
+
+- (id)nextNode;
+- (id)previousNode;
+- (void)detach;
+
+@end
+
+#endif /* __DOMNodeIterator_H__ */
diff --git a/skyrix-xml/DOM/DOMNodeIterator.m b/skyrix-xml/DOM/DOMNodeIterator.m
new file mode 100644 (file)
index 0000000..8614134
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <DOM/DOMNodeIterator.h>
+#include <DOM/DOMNodeFilter.h>
+#include <DOM/DOMNode.h>
+#include "common.h"
+
+@implementation DOMNodeIterator
+
+- (id)initWithRootNode:(id)_rootNode
+  whatToShow:(unsigned long)_whatToShow
+  filter:(id)_filter
+  expandEntityReferences:(BOOL)_flag
+{
+  NSAssert(_rootNode, @"missing root-node !");
+
+  if ((self = [super init])) {
+    self->root       = [_rootNode retain];
+    self->whatToShow = _whatToShow;
+    self->filter     = [_filter retain];
+    self->expandEntityReferences = _flag;
+
+    self->lastNode    = nil;
+    self->beforeFirst = YES;
+    self->afterLast   = NO;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->lastNode release];
+  [self->root     release];
+  [self->filter   release];
+  [super dealloc];
+}
+                 
+/* attributes */
+
+- (id)root {
+  return self->root;
+}
+- (unsigned long)whatToShow {
+  return self->whatToShow;
+}
+- (id)filter {
+  return self->filter;
+}
+- (BOOL)expandEntityReferences {
+  return self->expandEntityReferences;
+}
+
+/* operations */
+
+- (id)nextNode {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+- (id)previousNode {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (void)detach {
+}
+
+@end /* DOMNodeIterator */
diff --git a/skyrix-xml/DOM/DOMNodeWalker.h b/skyrix-xml/DOM/DOMNodeWalker.h
new file mode 100644 (file)
index 0000000..2140d37
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMNodeWalker_H__
+#define __DOMNodeWalker_H__
+
+#import <Foundation/NSObject.h>
+
+@interface DOMNodeWalker : NSObject
+{
+  id   target;
+  SEL  selector;
+  id   ctx;
+  
+  BOOL isStopped;
+  id   rootNode;
+  id   currentParentNode;
+  id   currentNode;
+}
+
+- (id)initWithTarget:(id)_target selector:(SEL)_selector context:(id)_ctx;
+
+/* context */
+
+- (id)context;
+- (id)rootNode;
+- (id)currentParentNode;
+- (id)currentNode;
+
+/* walking */
+
+- (void)walkNode:(id)_node;
+- (void)stopWalking;
+
+@end
+
+@interface DOMNodePreorderWalker : DOMNodeWalker
+@end
+@interface DOMNodePostorderWalker : DOMNodeWalker
+@end
+
+#endif /* __DOMNodeWalker_H__ */
diff --git a/skyrix-xml/DOM/DOMNodeWalker.m b/skyrix-xml/DOM/DOMNodeWalker.m
new file mode 100644 (file)
index 0000000..4a4e0f8
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMNodeWalker.h"
+#include "DOMNode.h"
+#include "common.h"
+
+@interface DOMNodeWalker(Privates)
+- (void)_processCurrentNode;
+@end
+
+@implementation DOMNodeWalker
+
+- (id)initWithTarget:(id)_target selector:(SEL)_selector context:(id)_ctx {
+  self->target   = [_target retain];
+  self->selector = _selector;
+  self->ctx      = [_ctx retain];
+
+  if (self->target == nil) {
+    [self release];
+    return nil;
+  }
+  if (self->selector == NULL) {
+    [self release];
+    return nil;
+  }
+  
+  return self;
+}
+- (void)dealloc {
+  [self->ctx      release];
+  [self->rootNode release];
+  [self->target   release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (id)context {
+  return self->ctx;
+}
+
+- (id)rootNode {
+  return self->rootNode;
+}
+- (id)currentParentNode {
+  return self->currentParentNode;
+}
+- (id)currentNode {
+  return self->currentNode;
+}
+
+/* private */
+
+- (void)_processCurrentNode {
+  [self->target performSelector:self->selector withObject:self];
+}
+
+- (void)_beforeChildren {
+}
+- (void)_afterChildren {
+}
+
+- (void)_walkNodeUsingChildNodes:(id)_node {
+  if (self->isStopped) return;
+  
+  self->currentNode = _node;
+  
+  [self _beforeChildren];
+  if (self->isStopped) return;
+
+  if ([_node hasChildNodes]) {
+    id       children;
+    unsigned i, count;
+    id oldParent;
+
+    oldParent = self->currentParentNode;
+    self->currentParentNode = self->currentNode;
+    
+    children = [_node childNodes];
+    
+    for (i = 0, count = [children count]; i < count; i++) {
+      [self _walkNodeUsingChildNodes:[children objectAtIndex:i]];
+      if (self->isStopped) return;
+    }
+    
+    self->currentParentNode = oldParent;
+  }
+
+  [self _afterChildren];
+  if (self->isStopped) return;
+}
+
+/* public */
+
+- (void)walkNode:(id)_node {
+  self->rootNode  = [_node retain];
+  self->isStopped = NO;
+  self->currentParentNode = nil;
+  
+  [self _walkNodeUsingChildNodes:_node];
+
+  [self->rootNode release]; self->rootNode = nil;
+}
+
+- (void)stopWalking {
+  self->isStopped = YES;
+}
+
+@end /* DOMNodeWalker */
+
+@implementation DOMNodePreorderWalker
+
+- (void)_beforeChildren {
+  [self _processCurrentNode];
+}
+- (void)_afterChildren {
+}
+
+@end /* DOMNodePreorderWalker */
+
+@implementation DOMNodePostorderWalker
+
+- (void)_beforeChildren {
+}
+- (void)_afterChildren {
+  [self _processCurrentNode];
+}
+
+@end /* DOMNodePreorderWalker */
diff --git a/skyrix-xml/DOM/DOMNodeWithChildren.m b/skyrix-xml/DOM/DOMNodeWithChildren.m
new file mode 100644 (file)
index 0000000..392b2c1
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <DOM/DOMNode.h>
+#include "common.h"
+
+@implementation DOMNodeWithChildren
+
+- (void)dealloc {
+  [self->childNodes makeObjectsPerformSelector:
+                     @selector(_domNodeForgetParentNode:)
+                    withObject:nil];
+  
+  [self->childNodes release];
+  [super dealloc];
+}
+
+- (void)_ensureChildNodes {
+  if (self->childNodes == nil)
+    self->childNodes = [[NSMutableArray alloc] init];
+}
+
+- (BOOL)_isValidChildNode:(id)_node {
+  return YES;
+}
+
+/* navigation */
+
+- (id)childNodes {
+  [self _ensureChildNodes];
+  return self->childNodes;
+}
+- (BOOL)hasChildNodes {
+  return [self->childNodes count] > 0 ? YES : NO;
+}
+- (id)firstChild {
+  return [self->childNodes count] > 0 
+    ? [self->childNodes objectAtIndex:0]
+    : nil;
+}
+- (id)lastChild {
+  unsigned count;
+
+  return (count = [self->childNodes count]) > 0 
+    ? [self->childNodes objectAtIndex:(count - 1)]
+    : nil;
+}
+
+/* modification */
+
+- (id)removeChild:(id)_node {
+  unsigned idx;
+
+  if (self->childNodes == nil)
+    /* this node has no childnodes ! */
+    return nil;
+  
+  if ((idx = [self->childNodes indexOfObject:_node]) == NSNotFound)
+    /* given node is not a child of this node ! */
+    return nil;
+  
+  [[_node retain] autorelease];
+  [self->childNodes removeObjectAtIndex:idx];
+  [_node _domNodeForgetParentNode:self];
+  
+  return _node;
+}
+
+- (id)appendChild:(id)_node {
+  if (_node == nil)
+    /* adding a 'nil' node ?? */
+    return nil;
+  
+  if ([_node nodeType] == DOM_DOCUMENT_FRAGMENT_NODE) {
+    id             fragNodes;
+    unsigned       i, count;
+    NSMutableArray *cache;
+    
+    fragNodes = [_node childNodes];
+    
+    if ((count = [fragNodes count]) == 0)
+      /* no nodes to add */
+      return nil;
+
+    /* 
+       copy to cache, since 'childNodes' result is 'live' and 
+       appendChild modifies the tree 
+    */
+    cache = [NSMutableArray arrayWithCapacity:count];
+    for (i = 0; i < count; i++)
+      [cache addObject:[fragNodes objectAtIndex:i]];
+    
+    /* append nodes (in reverse order [array implemention is assumed]) .. */
+    for (i = count = [cache count]; i > 0; i--)
+      [self appendChild:[cache objectAtIndex:(i - 1)]];
+  }
+  else {
+    id oldParent;
+    
+    if ((oldParent = [_node parentNode]))
+      [oldParent removeChild:_node];
+    
+    [self _ensureChildNodes];
+    
+    [self->childNodes addObject:_node];
+    [_node _domNodeRegisterParentNode:self];
+  }
+  
+  /* return the node 'added' */
+  return _node;
+}
+
+/* sibling navigation */
+
+- (id)_domNodeBeforeNode:(id)_node {
+  unsigned idx;
+  
+  if ((idx = [self->childNodes indexOfObject:_node]) == NSNotFound)
+    /* given node isn't a child of this node */
+    return nil;
+  if (idx == 0)
+    /* given node is the first child */
+    return nil;
+  
+  return [self->childNodes objectAtIndex:(idx - 1)];
+}
+- (id)_domNodeAfterNode:(id)_node {
+  unsigned idx, count;
+
+  if ((count = [self->childNodes count]) == 0)
+    /* this node has no children at all .. */
+    return nil;
+  
+  if ((idx = [self->childNodes indexOfObject:_node]) == NSNotFound)
+    /* given node isn't a child of this node */
+    return nil;
+  if (idx == (count - 1))
+    /* given node is the last child */
+    return nil;
+  
+  return [self->childNodes objectAtIndex:(idx + 1)];
+}
+
+@end /* DOMNodeWithChildren */
diff --git a/skyrix-xml/DOM/DOMNotation.h b/skyrix-xml/DOM/DOMNotation.h
new file mode 100644 (file)
index 0000000..780d43a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMNotation_H__
+#define __DOMNotation_H__
+
+#include <DOM/DOMNode.h>
+
+@interface DOMNotation : DOMNode
+{
+}
+
+/* attributes */
+
+/* node */
+
+@end
+
+@interface DOMNotation(PrivateCtors)
+/* use DOMDocument for constructing DOMNotation's ! */
+
+@end
+
+#endif /* __DOMNotation_H__ */
diff --git a/skyrix-xml/DOM/DOMNotation.m b/skyrix-xml/DOM/DOMNotation.m
new file mode 100644 (file)
index 0000000..49c92fd
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMNotation.h"
+
+@implementation DOMNotation
+
+- (DOMNodeType)nodeType {
+  return DOM_NOTATION_NODE;
+}
+
+- (BOOL)_isValidChildNode:(id)_node {
+  return NO;
+}
+- (BOOL)hasChildNodes {
+  return NO;
+}
+- (id)childNodes {
+  return nil;
+}
+- (id)appendChild:(id)_node {
+  return nil;
+}
+
+- (id)attributes {
+  return nil;
+}
+
+/* parent node */
+
+- (id)parentNode {
+  return nil;
+}
+- (id)nextSibling {
+  return nil;
+}
+- (id)previousSibling {
+  return nil;
+}
+
+@end /* DOMNotation */
diff --git a/skyrix-xml/DOM/DOMPYXOutputter.h b/skyrix-xml/DOM/DOMPYXOutputter.h
new file mode 100644 (file)
index 0000000..8ebbac7
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMPYXOutputter_H__
+#define __DOMPYXOutputter_H__
+
+#import <Foundation/NSObject.h>
+
+@interface DOMPYXOutputter : NSObject
+{
+}
+
+- (void)outputDocument:(id)_document to:(id)_target;
+
+@end
+
+#endif /* __DOMPYXOutputter_H__ */
diff --git a/skyrix-xml/DOM/DOMPYXOutputter.m b/skyrix-xml/DOM/DOMPYXOutputter.m
new file mode 100644 (file)
index 0000000..cbd11d7
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMPYXOutputter.h"
+#include "DOMDocument.h"
+#include "DOMElement.h"
+#include "common.h"
+
+@interface DOMPYXOutputter(Privates)
+- (void)outputNode:(id)_node to:(id)_target;
+- (void)outputNodeList:(id)_nodeList to:(id)_target;
+@end
+
+@implementation DOMPYXOutputter
+
+- (void)write:(NSString *)s to:(id)_target {
+  printf("%s", [s cString]);
+}
+- (BOOL)currentElementPreservesWhitespace {
+  return NO;
+}
+
+- (void)outputAttributeNode:(id<DOMAttr>)_attrNode
+  ofNode:(id<DOMNode>)_node
+  to:(id)_target
+{
+  [self write:@"A"                  to:_target];
+  [self write:[_attrNode name]      to:_target];
+  [self write:@" "                  to:_target];
+  [self write:[_attrNode nodeValue] to:_target];
+  [self write:@"\n"                 to:_target];
+}
+
+- (void)outputAttributeNodes:(id<DOMNamedNodeMap>)_nodes
+  ofNode:(id<DOMNode>)_node
+  to:(id)_target
+{
+  unsigned i, count;
+  
+  if ((count = [_nodes length]) == 0)
+    return;
+  
+  for (i = 0; i < count; i++) {
+    [self outputAttributeNode:[_nodes objectAtIndex:i]
+          ofNode:_node
+          to:_target];
+  }
+}
+
+- (void)outputTextNode:(id<DOMText>)_node to:(id)_target {
+  NSString *s;
+  unsigned len;
+  
+  s = [_node data];
+  if ((len = [s length]) == 0)
+    return;
+  
+  if ([s rangeOfString:@"\n"].length != 0) {
+    s = [[s componentsSeparatedByString:@"\n"]
+            componentsJoinedByString:@"\\n"];
+  }
+  
+  [self write:@"-"  to:_target];
+  [self write:s     to:_target];
+  [self write:@"\n" to:_target];
+}
+- (void)outputCommentNode:(id<DOMComment>)_node to:(id)_target {
+  [self write:@"<!-- "     to:_target];
+  [self write:[_node data] to:_target];
+  [self write:@" -->"      to:_target];
+  
+  if (![self currentElementPreservesWhitespace])
+    [self write:@"\n" to:_target];
+}
+
+- (void)outputElementNode:(id<DOMElement>)_node to:(id)_target {
+  NSString *tagName;
+  NSString *ns;
+  
+  /* needs to declare namespaces !!! */
+  tagName = [_node tagName];
+  if ([[_node prefix] length] > 0) {
+    NSString *p = [_node prefix];
+    
+    p       = [p stringByAppendingString:@":"];
+    tagName = [p stringByAppendingString:tagName];
+
+    ns = [NSString stringWithFormat:@" xmlns:%@=\"%@\"",
+                     [_node prefix],
+                     [_node namespaceURI]];
+  }
+  else if ([[_node namespaceURI] length] > 0) {
+    ns = [NSString stringWithFormat:@" xmlns=\"%@\"", [_node namespaceURI]];
+  }
+  else
+    ns = nil;
+
+  [self write:@"("    to:_target];
+  [self write:tagName to:_target];
+  [self write:@"\n"   to:_target];
+    
+  [self outputAttributeNodes:[_node attributes] ofNode:_node to:_target];
+  
+  if ([_node hasChildNodes])
+    [self outputNodeList:[_node childNodes] to:_target];
+    
+  [self write:@")"    to:_target];
+  [self write:tagName to:_target];
+  [self write:@"\n"   to:_target];
+}
+
+- (void)outputCDATA:(id<DOMCharacterData>)_node to:(id)_target {
+  NSString *s;
+
+  s = [_node data];
+  
+  if ([s rangeOfString:@"\n"].length != 0) {
+    /* escape newlines */
+    s = [[s componentsSeparatedByString:@"\n"]
+            componentsJoinedByString:@"\\n"];
+  }
+  
+  [self write:@"-"  to:_target];
+  [self write:s     to:_target];
+  [self write:@"\n" to:_target];
+}
+
+- (void)outputPI:(id<DOMProcessingInstruction>)_node to:(id)_target {
+  [self write:@"?"           to:_target];
+  [self write:[_node target] to:_target];
+  [self write:@" "           to:_target];
+  [self write:[_node data]   to:_target];
+  [self write:@"\n"          to:_target];
+}
+
+- (void)outputNode:(id)_node to:(id)_target {
+  switch ([_node nodeType]) {
+    case DOM_ELEMENT_NODE:
+      [self outputElementNode:_node to:_target];
+      break;
+    case DOM_CDATA_SECTION_NODE:
+      [self outputCDATA:_node to:_target];
+      break;
+    case DOM_PROCESSING_INSTRUCTION_NODE:
+      [self outputPI:_node to:_target];
+      break;
+    case DOM_TEXT_NODE:
+      [self outputTextNode:_node to:_target];
+      break;
+    case DOM_COMMENT_NODE:
+      [self outputCommentNode:_node to:_target];
+      break;
+      
+    default:
+      NSLog(@"cannot output node %@", _node);
+      break;
+  }
+}
+- (void)outputNodeList:(id)_nodeList to:(id)_target {
+  id       children;
+  unsigned i, count;
+  
+  children = _nodeList;
+  
+  for (i = 0, count = [children count]; i < count; i++)
+    [self outputNode:[children objectAtIndex:i] to:_target];
+}
+
+- (void)outputDocument:(id)_document to:(id)_target {
+  if (![_document hasChildNodes])
+    return;
+
+  NS_DURING
+    [self outputNodeList:[_document childNodes] to:_target];
+  NS_HANDLER
+    fprintf(stderr, "%s\n", [[localException description] cString]);
+    abort();
+  NS_ENDHANDLER;
+}
+
+@end /* DOMPYXOutputter */
diff --git a/skyrix-xml/DOM/DOMProcessingInstruction.h b/skyrix-xml/DOM/DOMProcessingInstruction.h
new file mode 100644 (file)
index 0000000..c9dc1e3
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMProcessingInstruction_H__
+#define __DOMProcessingInstruction_H__
+
+#include <DOM/DOMNode.h>
+
+@class NSString;
+
+@interface DOMProcessingInstruction : DOMNode
+{
+  id       parent;
+  NSString *target;
+  NSString *data;
+}
+
+/* attributes */
+
+- (NSString *)target;
+- (void)setData:(NSString *)_data;
+- (NSString *)data;
+
+/* node */
+
+@end
+
+@interface DOMProcessingInstruction(PrivateCtors)
+/* use DOMDocument for constructing DOMProcessingInstructions ! */
+
+- (id)initWithTarget:(NSString *)_target data:(NSString *)_data;
+
+@end
+
+#endif /* __DOMProcessingInstruction_H__ */
diff --git a/skyrix-xml/DOM/DOMProcessingInstruction.m b/skyrix-xml/DOM/DOMProcessingInstruction.m
new file mode 100644 (file)
index 0000000..f56f3b9
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMProcessingInstruction.h"
+#include "common.h"
+
+@implementation DOMProcessingInstruction
+
+- (id)initWithTarget:(NSString *)_target data:(NSString *)_data {
+  if ((self = [super init])) {
+    self->target = [_target copy];
+    self->data   = [_data   copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->target release];
+  [self->data   release];
+  [super dealloc];
+}
+
+/* attributes */
+
+- (NSString *)target {
+  return self->target;
+}
+
+- (void)setData:(NSString *)_data {
+  id old = self->data;
+  self->data = [_data copy];
+  [old release];
+}
+- (NSString *)data {
+  return self->data;
+}
+
+/* node */
+
+- (DOMNodeType)nodeType {
+  return DOM_PROCESSING_INSTRUCTION_NODE;
+}
+
+- (id)attributes {
+  return nil;
+}
+
+- (BOOL)_isValidChildNode:(id)_node {
+  return NO;
+}
+- (BOOL)hasChildNodes {
+  /* PI's have no children ! */
+  return NO;
+}
+- (id)childNodes {
+  /* PI's have no children ! */
+  return nil;
+}
+- (id)appendChild:(id)_node {
+  /* PI's have no children ! */
+  return nil;
+}
+
+/* parent node */
+
+- (void)_domNodeRegisterParentNode:(id)_parent {
+  self->parent = _parent;
+}
+- (void)_domNodeForgetParentNode:(id)_parent {
+  if (_parent == self->parent)
+    /* the node's parent was deallocated */
+    self->parent = nil;
+}
+- (id)parentNode {
+  return self->parent;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X[%@]: target=%@ data='%@'>",
+                     self, NSStringFromClass([self class]),
+                     [self target], [self data]];
+}
+
+@end /* DOMProcessingInstruction */
diff --git a/skyrix-xml/DOM/DOMProtocols.h b/skyrix-xml/DOM/DOMProtocols.h
new file mode 100644 (file)
index 0000000..eab5cb9
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOM_DOMProtocols_H__
+#define __DOM_DOMProtocols_H__
+
+/*
+  Protocols for DOM objects ...
+  
+  IDL taken from
+    http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010913/DOM3-Core.html
+*/
+
+typedef enum {
+  DOM_UNKNOWN_NODE                = 0,
+  DOM_ATTRIBUTE_NODE              = 1,
+  DOM_CDATA_SECTION_NODE          = 2,
+  DOM_COMMENT_NODE                = 3,
+  DOM_DOCUMENT_FRAGMENT_NODE      = 4,
+  DOM_DOCUMENT_NODE               = 5,
+  DOM_DOCUMENT_TYPE_NODE          = 6,
+  DOM_ELEMENT_NODE                = 7,
+  DOM_ENTITY_NODE                 = 8,
+  DOM_ENTITY_REFERENCE_NODE       = 9,
+  DOM_NOTATION_NODE               = 10,
+  DOM_PROCESSING_INSTRUCTION_NODE = 11,
+  DOM_TEXT_NODE                   = 12
+} DOMNodeType;
+
+#if HAVE_FORWARD_PROTOCOLS
+@protocol DOMNode;
+@protocol DOMAttr, DOMCDATASection, DOMComment, DOMDocumentFragment;
+@protocol DOMDocument, DOMDocumentType, DOMElement, DOMEntity;
+@protocol DOMEntityReference, DOMNotation, DOMProcessingInstruction;
+@protocol DOMText;
+#endif
+
+@protocol DOMNodeList
+
+- (unsigned)length;
+- (id)objectAtIndex:(unsigned)_idx; // returns the proper attribute node
+
+@end /* DOMNodeList */
+
+@protocol DOMNamedNodeMap
+
+- (unsigned)length;
+- (id)objectAtIndex:(unsigned)_idx; // returns the proper attribute node
+
+#if HAVE_FORWARD_PROTOCOLS
+- (id<NSObject,DOMNode>)namedItem:(NSString *)_name;
+- (id<NSObject,DOMNode>)setNamedItem:(id<NSObject,DOMNode>)_node;
+- (id<NSObject,DOMNode>)removeNamedItem:(NSString *)_name;
+
+/* DOM2 access */
+
+- (id<NSObject,DOMNode>)namedItem:(NSString *)_name
+  namespaceURI:(NSString *)_uri;
+- (id<NSObject,DOMNode>)setNamedItemNS:(id<NSObject,DOMNode>)_node;
+- (id<NSObject,DOMNode>)removeNamedItem:(NSString *)_name
+  namespaceURI:(NSString *)_uri;
+#else
+- (id)namedItem:(NSString *)_name;
+- (id)setNamedItem:(id)_node;
+- (id)removeNamedItem:(NSString *)_name;
+
+/* DOM2 access */
+
+- (id)namedItem:(NSString *)_name namespaceURI:(NSString *)_uri;
+- (id)setNamedItemNS:(id)_node;
+- (id)removeNamedItem:(NSString *)_name namespaceURI:(NSString *)_uri;
+#endif
+
+@end /* DOMNamedNodeMap */
+
+@protocol DOMNode
+
+- (DOMNodeType)nodeType;
+- (NSString *)nodeName;
+- (NSString *)nodeValue;
+
+- (NSString *)localName;
+- (NSString *)namespaceURI;
+- (void)setPrefix:(NSString *)_prefix;
+- (NSString *)prefix;
+
+/* element attributes */
+
+- (id<NSObject,DOMNamedNodeMap>)attributes;
+
+/* navigation */
+
+- (id<NSObject,DOMNode>)parentNode;
+- (id<NSObject,DOMNode>)previousSibling;
+- (id<NSObject,DOMNode>)nextSibling;
+
+- (id<NSObject,DOMNodeList>)childNodes;
+- (BOOL)hasChildNodes;
+- (id<NSObject,DOMNode>)firstChild;
+- (id<NSObject,DOMNode>)lastChild;
+
+/* modification */
+
+- (id<NSObject,DOMNode>)appendChild:(id<NSObject,DOMNode>)_node;
+- (id<NSObject,DOMNode>)removeChild:(id<NSObject,DOMNode>)_node;
+
+/* owner */
+
+#if HAVE_FORWARD_PROTOCOLS
+- (id<NSObject,DOMDocument>)ownerDocument;
+#else
+- (id)ownerDocument;
+#endif
+
+@end /* DOMNode */
+
+@protocol DOMDocumentFragment < DOMNode >
+@end
+
+@protocol DOMAttr < DOMNode >
+
+- (NSString *)name;
+- (BOOL)specified;
+- (void)setValue:(NSString *)_value;
+- (NSString *)value;
+
+/* owner */
+
+#if HAVE_FORWARD_PROTOCOLS
+- (id<NSObject,DOMElement>)ownerElement;
+#else
+- (id)ownerElement;
+#endif
+
+@end /* DOMAttr */
+
+@protocol DOMCharacterData < DOMNode >
+
+- (void)setData:(NSString *)_data;
+- (NSString *)data;
+- (unsigned)length;
+
+- (NSString *)substringData:(unsigned)_offset count:(unsigned)_count;
+- (void)appendData:(NSString *)_data;
+- (void)insertData:(NSString *)_data offset:(unsigned)_offset;
+- (void)deleteData:(unsigned)_offset count:(unsigned)_count;
+- (void)replaceData:(unsigned)_offset count:(unsigned)_count with:(NSString *)_s;
+
+@end /* DOMCharacterData */
+
+@protocol DOMComment < DOMCharacterData >
+@end /* DOMComment */
+
+@protocol DOMText < DOMCharacterData >
+
+- (id<NSObject,DOMText>)splitText:(unsigned)_offset;
+
+/* DOM Level 3 */
+
+- (BOOL)isWhitespaceInElementContent;
+- (NSString *)wholeText;
+- (id<NSObject,DOMText>)replaceWholeText:(NSString *)_content;
+
+@end
+
+@protocol DOMCDATASection < DOMText >
+@end
+
+@protocol DOMElement < DOMNode >
+
+/* attributes */
+
+- (NSString *)tagName;
+
+/* lookup */
+
+- (id<NSObject,DOMNodeList>)getElementsByTagName:(NSString *)_tagName;
+- (id<NSObject,DOMNodeList>)getElementsByTagName:(NSString *)_tagName
+  namespaceURI:(NSString *)_uri;
+
+/* element attributes */
+
+- (BOOL)hasAttribute:(NSString *)_attrName;
+- (BOOL)hasAttribute:(NSString *)_localName namespaceURI:(NSString *)_ns;
+
+- (void)setAttribute:(NSString *)_attrName value:(NSString *)_value;
+- (void)setAttribute:(NSString *)_localName namespaceURI:(NSString *)_ns
+  value:(NSString *)_value;
+
+- (NSString *)attribute:(NSString *)_attrName;
+- (NSString *)attribute:(NSString *)_localName namespaceURI:(NSString *)_ns;
+- (void)removeAttribute:(NSString *)_attrName;
+- (void)removeAttribute:(NSString *)_attrName namespaceURI:(NSString *)_ns;
+
+- (id<NSObject,DOMAttr>)setAttributeNode:(id<NSObject,DOMAttr>)_attrNode;
+- (id<NSObject,DOMAttr>)removeAttributeNode:(id<NSObject,DOMAttr>)_attrNode;
+- (id<NSObject,DOMAttr>)setAttributeNodeNS:(id<NSObject,DOMAttr>)_attrNode;
+- (id<NSObject,DOMAttr>)removeAttributeNodeNS:(id<NSObject,DOMAttr>)_attrNode;
+
+@end /* DOMElement */
+
+@protocol DOMDocumentType < DOMNode >
+@end /* DOMDocumentType */
+
+@protocol DOMProcessingInstruction < DOMNode >
+
+- (NSString *)target;
+- (NSString *)data;
+
+@end /* DOMProcessingInstruction */
+
+@protocol DOMEntityReference < DOMNode >
+@end
+
+@class DOMImplementation;
+
+@protocol DOMDocument < DOMNode >
+
+- (id<NSObject,DOMDocumentType>)doctype;
+- (DOMImplementation *)implementation;
+- (id<NSObject,DOMElement>)documentElement;
+
+- (id<NSObject,DOMNodeList>)getElementsByTagName:(NSString *)_tagName;
+- (id<NSObject,DOMNodeList>)getElementsByTagName:(NSString *)_tagName
+  namespaceURI:(NSString *)_uri;
+- (id<NSObject,DOMElement>)getElementById:(NSString *)_eid;
+
+/* creation */
+
+- (id<NSObject,DOMElement>)createElement:(NSString *)_tagName;
+- (id<NSObject,DOMElement>)createElement:(NSString *)_tagName
+  namespaceURI:(NSString *)_uri;
+
+- (id<NSObject,DOMDocumentFragment>)createDocumentFragment;
+- (id<NSObject,DOMText>)createTextNode:(NSString *)_data;
+- (id<NSObject,DOMComment>)createComment:(NSString *)_data;
+- (id<NSObject,DOMCDATASection>)createCDATASection:(NSString *)_data;
+
+- (id<NSObject,DOMProcessingInstruction>)
+  createProcessingInstruction:(NSString *)_target data:(NSString *)_data;
+
+- (id<NSObject,DOMAttr>)createAttribute:(NSString *)_name;
+- (id<NSObject,DOMAttr>)createAttribute:(NSString *)_name
+  namespaceURI:(NSString *)_uri;
+
+- (id<NSObject,DOMEntityReference>)createEntityReference:(NSString *)_name;
+
+@end /* DOMDocument */
+
+#endif /* __DOM_DOMProtocols_H__ */
diff --git a/skyrix-xml/DOM/DOMQueryPathExpression.h b/skyrix-xml/DOM/DOMQueryPathExpression.h
new file mode 100644 (file)
index 0000000..5f9d21a
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOMQueryPathExpression_H__
+#define __DOMQueryPathExpression_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSArray;
+
+@interface DOMQueryPathExpression : NSObject
+
+/*
+  Syntax:
+    
+    First the QueryPath is separated into path components, then the path
+    components are evaluated:
+    
+    '-'   - placed in front of the path component, makes the search flat
+    '/'   - select DOM root node (usually the document-element)
+    '.'   - select current node
+    '..'  - select DOM parent node
+    '*'   - select all child elements (either deep or non-deep)
+    '!x'  - evaluate keypath 'x' on node
+    '?x'  - lookup processing instruction 'x' (either deep or non-deep)
+    '@x'  - lookup attribute 'x',
+              if x is '*', select all attributes (the map)
+              x may contain a ':' for namespace queries
+    
+    any other string: select a child-node with the string as the name.
+
+  Samples:
+
+    "./head/title" - lookup the 'title' node contained in the 'head' child node
+    "./@name"      - lookup the 'name' attribute of the current node
+    "./?blah"      - lookup the PI 'blah' starting with the current node
+    "./!values"    - call 'valueForKey:@"values"' on the current node
+    "/-title"      - flat search for 'title' element
+*/
+
++ (id)queryPathWithString:(NSString *)_string;
++ (id)queryPathWithComponents:(NSArray *)_string;
++ (NSArray *)queryPathComponentsOfString:(NSString *)_path;
+
+- (id)evaluateWithNode:(id)_node; // DEPRECATED !!!
+- (id)evaluateWithNodeList:(id)_nodeList;
+
+@end
+
+#endif /* __DOMQueryPathExpression_H__ */
diff --git a/skyrix-xml/DOM/DOMQueryPathExpression.m b/skyrix-xml/DOM/DOMQueryPathExpression.m
new file mode 100644 (file)
index 0000000..4b7ecf3
--- /dev/null
@@ -0,0 +1,881 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <DOM/DOMQueryPathExpression.h>
+#include "DOMDocument.h"
+#include "DOMAttribute.h"
+#include "DOMNamedNodeMap.h"
+#include "common.h"
+
+@interface NSString(QP)
+- (NSArray *)queryPathComponents;
+@end
+
+#define QUERY_CURRENT 1
+#define QUERY_PARENT  2
+#define QUERY_ROOT    3
+
+/*
+  QueryPathExpression classes:
+    NSObject
+      _DOMQPPredicateExpression
+      _DOMQPPredicateQPExpression
+      DOMQueryPathExpression
+        _DOMQueryPathSequence
+        _DOMQueryPathPredicates
+        _DOMQueryPathAttribute
+        _DOMQueryPathNodeQuery
+        _DOMQueryPathChildNodes
+        _DOMQueryPathKeyPath
+*/
+
+@interface DOMQueryPathExpression(Privates)
+
++ (id)makeQueryPathExpression:(NSString *)_expr;
+
+- (id)_deepChildNodesWithName:(id)_name type:(int)_type node:(id)_domNode;
+- (id)_flatChildNodesWithName:(id)_name type:(int)_type node:(id)_domNode;
+- (id)_rootSearchNodeForNode:(id)_domNode;
+
+- (id)evaluateWithNode:(id)_node      inContext:(id)_ctx;
+- (id)evaluateWithNodeList:(id)_nodes inContext:(id)_ctx;
+
+@end
+
+@interface _DOMQPPredicateExpression : NSObject
+- (BOOL)matchesNode:(id)_node inContext:(id)_ctx;
+@end
+
+@interface _DOMQPPredicateQPExpression : NSObject
+{
+  DOMQueryPathExpression *qpexpr;
+}
+- (id)initWithQueryPathExpression:(DOMQueryPathExpression *)_expr;
+@end
+
+@interface _DOMQueryPathSequence : DOMQueryPathExpression
+{
+  NSArray *queryPaths;
+}
++ (id)sequenceWithArray:(NSArray *)_array;
+@end
+
+@interface _DOMQueryPathPredicates : DOMQueryPathExpression
+{
+  DOMQueryPathExpression *expr;
+  NSArray *predicates;
+}
+- (id)initWithQueryPathExpression:(DOMQueryPathExpression *)_expr
+  predicates:(NSArray *)_predicates;
+@end
+
+@interface _DOMQueryPathAttribute : DOMQueryPathExpression
+{
+  NSString *attrSpec;
+  NSString *uri;
+  struct {
+    int getAll:1;
+    int hasColon:1;
+  } aflags;
+}
+- (id)initWithString:(NSString *)_spec;
+@end
+
+@interface _DOMQueryPathNodeQuery : DOMQueryPathExpression
+{
+  int  queryOp;
+}
+- (id)initWithQueryOp:(int)_op;
+@end
+
+@interface _DOMQueryPathChildNodes : DOMQueryPathExpression
+{
+  NSString *elementName;
+  BOOL     deep;
+  int      nodeType;
+}
+- (id)initWithName:(NSString *)_name deep:(BOOL)_flag type:(int)_type;
+@end
+
+@interface _DOMQueryPathKeyPath : DOMQueryPathExpression
+{
+  NSString *keyPath;
+}
+- (id)initWithKeyPath:(NSString *)_path;
+@end
+
+@implementation DOMQueryPathExpression
+
+- (id)_deepChildNodesWithName:(id)_name type:(int)_type node:(id)_domNode {
+  NSMutableArray *array;
+  id       children;
+  unsigned i, count;
+  NSString *fname, *furi;
+  
+  if (![_domNode hasChildNodes])
+    return [NSArray array];
+  
+  children = [_domNode childNodes];
+  if ((count = [children count]) == 0)
+    return [NSArray array];
+
+  if (_name) {
+    NSRange r;
+
+    r = [_name rangeOfString:@"}"];
+    if (r.length != 0) {
+      fname = [_name substringFromIndex:(r.location + r.length)];
+      furi  = [[_name substringToIndex:r.location] substringFromIndex:1];
+    }
+    else {
+      fname = _name;
+      furi  = nil;
+    }
+  }
+  else {
+    fname = nil;
+    furi  = nil;
+  }
+  
+  array = [NSMutableArray arrayWithCapacity:count];
+  for (i = 0; i < count; i++) {
+    id child;
+    
+    if ((child = [children objectAtIndex:i]) == nil)
+      continue;
+    
+    if (([child nodeType] == _type) || (_type == -1)) {
+
+      if (_name == nil) {
+        /* wildcard query */
+        [array addObject:child];
+      }
+      else {
+        NSString *nname;
+        NSString *qname;
+        
+        qname = _name;
+        nname = [child nodeName];
+
+        if ([nname isEqualToString:_name]) {
+          /* FQ name matches */
+          [array addObject:child];
+        }
+        else if ([nname isEqualToString:fname]) {
+          /* name matches */
+          if (furi) {
+            /* check URI */
+            if ([[child namespaceURI] isEqualToString:furi])
+              [array addObject:child];
+          }
+          else {
+            [array addObject:child];
+          }
+        }
+      }
+    }
+    
+    [array addObjectsFromArray:
+             [self _deepChildNodesWithName:_name type:_type node:child]];
+  }
+  return array;
+}
+
+- (id)_flatChildNodesWithName:(id)_name type:(int)_type node:(id)_domNode {
+  NSMutableArray *array;
+  id       children;
+  unsigned i, count;
+  
+  if (![_domNode hasChildNodes])
+    return [NSArray array];
+  
+  children = [_domNode childNodes];
+  if ((count = [children count]) == 0)
+    return [NSArray array];
+  
+  array = [NSMutableArray arrayWithCapacity:count];
+  for (i = 0; i < count; i++) {
+    id child;
+    
+    child = [children objectAtIndex:i];
+
+    if (([child nodeType] != _type) && (_type != -1))
+      continue;
+    
+    if (_name) {
+      if (![[child nodeName] isEqualToString:_name])
+        continue;
+    }
+    
+    if (child)
+      [array addObject:child];
+  }
+  return [[array copy] autorelease];
+}
+
+- (id)_rootSearchNodeForNode:(id)_domNode {
+  id root;
+  
+  switch ([_domNode nodeType]) {
+    case DOM_DOCUMENT_NODE:
+    case DOM_DOCUMENT_FRAGMENT_NODE:
+      root = [(DOMDocument *)_domNode documentElement];
+      if (root == nil) {
+        NSLog(@"WARNING(%s): document node %@ has no root element !",
+              __PRETTY_FUNCTION__, _domNode);
+      }
+      break;
+      
+    case DOM_COMMENT_NODE:
+    case DOM_PROCESSING_INSTRUCTION_NODE:
+    case DOM_ELEMENT_NODE:
+      root = [_domNode ownerDocument];
+      if (root == nil) {
+        NSLog(@"WARNING(%s): node %@ has no owner document !",
+              __PRETTY_FUNCTION__, _domNode);
+      }
+      root = [self _rootSearchNodeForNode:root];
+      break;
+      
+    case DOM_ATTRIBUTE_NODE:
+      root = [(DOMAttribute *)_domNode ownerElement];
+      if (root == nil) {
+        NSLog(@"WARNING(%s): attribute node %@ has no owner element !",
+              __PRETTY_FUNCTION__, _domNode);
+      }
+      root = [self _rootSearchNodeForNode:root];
+      break;
+
+    default:
+      root = [self _rootSearchNodeForNode:[_domNode parentNode]];
+      break;
+  }
+  return root;
+}
+
++ (id)queryPathWithComponents:(NSArray *)_array {
+  NSMutableArray *a;
+  unsigned i, count;
+  
+  if ((count = [_array count]) == 0)
+    return nil;
+  
+  if (count == 1)
+    return [[self makeQueryPathExpression:[_array objectAtIndex:0]]
+                  autorelease];
+  
+  a = [NSMutableArray arrayWithCapacity:count];
+  for (i = 0; i < count; i++) {
+    DOMQueryPathExpression *c;
+    
+    if ((c = [self makeQueryPathExpression:[_array objectAtIndex:i]])) {
+      [a addObject:c];
+      [c release]; c = nil;
+    }
+    else {
+      NSLog(@"%s: couldn't make query-path expression ..", 
+           __PRETTY_FUNCTION__);
+    }
+  }
+  
+  return [_DOMQueryPathSequence sequenceWithArray:a];
+}
+
++ (NSArray *)queryPathComponentsOfString:(NSString *)_path {
+  return [_path queryPathComponents];
+}
+
++ (id)queryPathWithString:(NSString *)_string {
+  return [self queryPathWithComponents:[_string queryPathComponents]];
+}
+
++ (_DOMQPPredicateExpression *)parsePredicateExpression:(NSString *)_expr {
+  DOMQueryPathExpression    *qpexpr;
+  _DOMQPPredicateExpression *pred;
+#if 0
+  NSLog(@"%s: can't parse predicates yet '%@'",
+        __PRETTY_FUNCTION__, _expr);
+#endif
+
+  _expr = [@"-" stringByAppendingString:_expr];
+  
+  qpexpr = [DOMQueryPathExpression queryPathWithString:_expr];
+  //NSLog(@"Expr: %@", qpexpr);
+  
+  pred =
+    [[_DOMQPPredicateQPExpression alloc] initWithQueryPathExpression:qpexpr];
+  
+  return [pred autorelease];
+}
+
++ (NSArray *)parseNodeQueryDetailExpressions:(NSString *)_path {
+  unsigned       i, len, s;
+  NSMutableArray *predicates;
+  
+  if ([_path length] == 0) return nil;
+  
+  predicates = nil;
+  for (i = 0, s = 0, len = [_path length]; i < len; i++) {
+    unichar c;
+    
+    c = [_path characterAtIndex:i];
+    
+    if ((c == ']') && (s != 0)) {
+      /* finished a predicate */
+      NSString *ps;
+      id predicate;
+      
+      ps = ((i - s) > 0)
+        ? [_path substringWithRange:NSMakeRange(s, (i - s))]
+        : @"";
+      
+      if ((predicate = [self parsePredicateExpression:ps])) {
+        if (predicates == nil)
+          predicates = [NSMutableArray arrayWithCapacity:4];
+        [predicates addObject:predicate];
+      }
+      
+      s = 0;
+    }
+    else if (c == '[') {
+      /* start a predicate */
+
+      if (s != 0) {
+        NSLog(@"%s: syntax error, predicate not properly closed ('%@') !",
+              __PRETTY_FUNCTION__, _path);
+      }
+      
+      s = (i + 1);
+    }
+  }
+  return predicates;
+}
+
++ (id)makeQueryPathExpression:(NSString *)_path {
+  DOMQueryPathExpression *result;
+  BOOL     isDeep = NO;
+  NSString *predicateString;
+  NSRange  r;
+  
+  if (([_path rangeOfString:@")"].length) != 0) {
+    //[self doesNotRecognizeSelector:_cmd];
+    NSLog(@"%s: unsupported querypath '%@'", __PRETTY_FUNCTION__, _path);
+  }
+
+  if ([_path hasPrefix:@"-"]) {
+    isDeep = NO;
+    _path = [_path substringFromIndex:1];
+  }
+  else
+    isDeep = YES;
+
+  r = [_path rangeOfString:@"["];
+  if (r.length != 0) {
+    predicateString = [_path substringFromIndex:r.location];
+    _path           = [_path substringToIndex:r.location];
+  }
+  else
+    predicateString = nil;
+  
+  if ([_path length] == 0) {
+    /* empty path, returns current node */
+    result = [[_DOMQueryPathNodeQuery alloc] initWithQueryOp:QUERY_CURRENT];
+  }
+  else if ([_path isEqualToString:@"/"]) {
+    /* lookup root element */
+    result = [[_DOMQueryPathNodeQuery alloc] initWithQueryOp:QUERY_ROOT];
+  }
+  else if ([_path isEqualToString:@"."]) {
+    /* lookup current element */
+    result = [[_DOMQueryPathNodeQuery alloc] initWithQueryOp:QUERY_CURRENT];
+  }
+  else if ([_path isEqualToString:@".."]) {
+    /* lookup parent element */
+    result = [[_DOMQueryPathNodeQuery alloc] initWithQueryOp:QUERY_PARENT];
+  }
+  else if ([_path isEqualToString:@"*"]) {
+    result =
+      [[_DOMQueryPathChildNodes alloc] initWithName:nil
+                                      deep:isDeep
+                                      type:DOM_ELEMENT_NODE];
+  }
+  else if ([_path isEqualToString:@"#"]) {
+    result =
+      [[_DOMQueryPathChildNodes alloc] initWithName:nil
+                                      deep:isDeep
+                                      type:-1];
+  }
+  else if ([_path hasPrefix:@"!"]) {
+    /* perform key-value call */
+    _path  = [_path substringFromIndex:1];
+    result = [[_DOMQueryPathKeyPath alloc] initWithKeyPath:_path];
+  }
+  else if ([_path hasPrefix:@"?"]) {
+    /* lookup processing instruction */
+    _path = [_path substringFromIndex:1]; // target of PI
+    result = [[_DOMQueryPathChildNodes alloc] 
+              initWithName:_path
+              deep:isDeep
+              type:DOM_PROCESSING_INSTRUCTION_NODE];
+  }
+  else if ([_path hasPrefix:@"@"]) {
+    /* lookup attribute */
+    _path  = [_path substringFromIndex:1];
+    result = [[_DOMQueryPathAttribute alloc] initWithString:_path];
+  }
+  else {
+    /* deep lookup child element */
+    result =
+      [[_DOMQueryPathChildNodes alloc] 
+                                initWithName:_path deep:isDeep
+                                type:DOM_ELEMENT_NODE];
+  }
+  
+  /* attach predicates ... */
+  
+  if (([predicateString length] > 0) && (result != nil)) {
+    NSArray *predicates;
+    
+    if ((predicates = [self parseNodeQueryDetailExpressions:predicateString])){
+#if 0
+      NSLog(@"%s: can't yet handle predicates %@",
+            __PRETTY_FUNCTION__, predicates);
+#endif
+      
+      result = [result autorelease];
+      result = [[_DOMQueryPathPredicates alloc]
+                                         initWithQueryPathExpression:result
+                                         predicates:predicates];
+    }
+  }
+  
+  return result;
+}
+
+- (id)evaluateWithNode:(id)_node inContext:(id)_ctx {
+  /* override in subclasses ! */
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (id)evaluateWithNodeList:(id)_nodes inContext:(id)_ctx {
+  unsigned       i, count;
+  NSMutableArray *ma;
+  NSArray        *results;
+  
+  if ((count = [_nodes count]) == 0)
+    return _nodes;
+  
+  ma = [[NSMutableArray alloc] init];
+  for (i = 0; i < count; i++) {
+    id node;
+    
+    node = [_nodes objectAtIndex:i];
+    node = [self evaluateWithNode:node inContext:_ctx];
+    
+    if (node)
+      [ma addObject:node];
+  }
+  results = [ma copy];
+  [ma release];
+  return [results autorelease];
+}
+
+- (id)evaluateWithNode:(id)_node {
+  return [self evaluateWithNode:_node inContext:nil];
+}
+- (id)evaluateWithNodeList:(id)_nodes {
+  return [self evaluateWithNodeList:_nodes inContext:nil];
+}
+
+@end /* DOMQueryPathExpression */
+
+@implementation _DOMQueryPathChildNodes
+
+- (id)initWithName:(NSString *)_name deep:(BOOL)_flag type:(int)_type {
+  self->elementName = [_name copy];
+  self->deep        = _flag;
+  self->nodeType    = _type;
+  return self;
+}
+
+- (void)dealloc {
+  [self->elementName release];
+  [super dealloc];
+}
+
+- (id)evaluateWithNode:(id)_node inContext:(id)_ctx {
+  id   result;
+  BOOL _forceList = NO;
+  
+  result = self->deep
+    ? [self _deepChildNodesWithName:self->elementName
+            type:self->nodeType node:_node]
+    : [self _flatChildNodesWithName:self->elementName
+            type:self->nodeType node:_node];
+  
+  if (!_forceList) {
+    if ([result count] == 0)
+      result = nil;
+    else if ([result count] == 1)
+      result = [result objectAtIndex:0];
+  }
+  
+  return result;
+}
+
+- (id)evaluateWithNodeList:(id)_nodes inContext:(id)_ctx {
+  unsigned       i, count;
+  NSMutableArray *ma;
+  NSArray        *results;
+  
+  if ((count = [_nodes count]) == 0)
+    return _nodes;
+  
+  ma = [[NSMutableArray alloc] init];
+  for (i = 0; i < count; i++) {
+    id node;
+
+    node = [_nodes objectAtIndex:i];
+    
+    node = self->deep
+      ? [self _deepChildNodesWithName:self->elementName
+              type:self->nodeType node:node]
+      : [self _flatChildNodesWithName:self->elementName
+              type:self->nodeType node:node];
+    
+    [ma addObjectsFromArray:node];
+  }
+  results = [ma copy];
+  [ma release];
+  return [results autorelease];
+}
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
+  [ms appendFormat:@" element='%@'", self->elementName];
+  [ms appendString:self->deep ? @" deep" : @" shallow"];
+  [ms appendFormat:@" nodeType=%i", self->nodeType];
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* _DOMQueryPathChildNodes */
+
+@implementation _DOMQueryPathKeyPath
+
+- (id)initWithKeyPath:(NSString *)_path {
+  self->keyPath = [_path copy];
+  return self;
+}
+- (void)dealloc {
+  [self->keyPath release];
+  [super dealloc];
+}
+
+- (id)evaluateWithNode:(id)_node inContext:(id)_ctx {
+  return [_node valueForKeyPath:self->keyPath];
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X[%@]: keypath='%@'>",
+                     self, NSStringFromClass([self class]), self->keyPath];
+}
+
+@end /* _DOMQueryPathKeyPath */
+
+@implementation _DOMQueryPathNodeQuery
+
+- (id)initWithQueryOp:(int)_op {
+  self->queryOp = _op;
+  return self;
+}
+
+- (id)evaluateWithNode:(id)_node inContext:(id)_ctx {
+  switch (self->queryOp) {
+    case QUERY_ROOT:
+      return [self _rootSearchNodeForNode:_node];
+    case QUERY_PARENT:
+      return [_node parentNode];
+    case QUERY_CURRENT:
+      return _node;
+      
+    default:
+      [NSException raise:@"DOMQueryPathException"
+                   format:@"unknown node operation %i on node %@",
+                     self->queryOp, _node];
+      return nil;
+  }
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X[%@]: op=%i>",
+                     self, NSStringFromClass([self class]), self->queryOp];
+}
+
+@end /* _DOMQueryPathNodeQuery */
+
+@implementation _DOMQueryPathPredicates
+
+- (id)initWithQueryPathExpression:(DOMQueryPathExpression *)_expr
+  predicates:(NSArray *)_predicates
+{
+  self->expr       = [_expr retain];
+  self->predicates = [_predicates copy];
+  return self;
+}
+
+- (void)dealloc {
+  [self->expr       release];
+  [self->predicates release];
+  [super dealloc];
+}
+
+- (id)evaluateWithNodeList:(id)_nodes inContext:(id)_ctx {
+  NSArray *list;
+  
+  if ((list = [self->expr evaluateWithNodeList:_nodes inContext:_ctx]) &&
+      [self->predicates count] > 0) {
+    NSMutableArray *result;
+    unsigned i, count;
+
+    result = [NSMutableArray arrayWithCapacity:16];
+    
+    for (i = 0, count = [list count]; i < count; i++) {
+      NSEnumerator *e;
+      _DOMQPPredicateExpression *pred;
+      id node;
+      
+      if ((node = [list objectAtIndex:i]) == nil)
+        continue;
+      
+      e = [self->predicates objectEnumerator];
+      while ((pred = [e nextObject])) {
+        if (![pred matchesNode:node inContext:nil]) {
+          node = nil;
+          break;
+        }
+      }
+
+      if (node) [result addObject:node];
+    }
+    
+    list = [[result copy] autorelease];
+  }
+  return list;
+}
+- (id)evaluateWithNode:(id)_node inContext:(id)_ctx {
+  NSLog(@"WARNING(%s): called -evaluateWithNode: ...", __PRETTY_FUNCTION__);
+  return [self evaluateWithNodeList:[NSArray arrayWithObject:_node]
+               inContext:_ctx];
+}
+
+@end /* _DOMQueryPathPredicates */
+
+@implementation _DOMQueryPathSequence
+
+- (id)initWithArray:(NSArray *)_array {
+  self->queryPaths = [_array retain];
+  return self;
+}
++ (id)sequenceWithArray:(NSArray *)_array {
+  return [[[self alloc] initWithArray:_array] autorelease];
+}
+
+- (void)dealloc {
+  [self->queryPaths release];
+  [super dealloc];
+}
+
+- (id)evaluateWithNode:(id)_node inContext:(id)_ctx {
+  NSEnumerator          *e;
+  DOMQueryPathExpression *queryPathComponent;
+  id                    activeNode;
+
+  activeNode = _node;
+  e = [self->queryPaths objectEnumerator];
+  while ((queryPathComponent = [e nextObject]) && (activeNode != nil)) {
+    activeNode =
+      [queryPathComponent evaluateWithNode:activeNode inContext:_ctx];
+  }
+  
+  return activeNode;
+}
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<%@[0x%08X]: ", NSStringFromClass([self class]), self];
+  [ms appendString:@"sequence="];
+  [ms appendString:[self->queryPaths description]];
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* _DOMQueryPathSequence */
+
+@implementation _DOMQueryPathAttribute
+
+- (id)initWithString:(NSString *)_spec {
+  if ([_spec isEqualToString:@"*"]) {
+    /* select all attributes */
+    self->aflags.getAll = 1;
+  }
+  else if ([_spec hasPrefix:@"{"]) {
+    /* fully qualified name */
+    NSRange r;
+
+    r = [_spec rangeOfString:@"}"];
+    if (r.length == 0) {
+      /* syntax error, missing closing '}' */
+      self->attrSpec = [_spec copy];
+    }
+    else {
+      self->attrSpec =
+        [[_spec substringFromIndex:(r.location + r.length)] copy];
+      self->uri =
+        [[[_spec substringToIndex:r.location] substringFromIndex:1] copy];
+    }
+  }
+  else {
+    NSRange r;
+
+    r = [_spec rangeOfString:@":"];
+    if (r.length != 0) {
+      /* found colon (namespaces), eg 'html:blah' */
+      self->aflags.hasColon = 1;
+      self->attrSpec =
+        [[_spec substringFromIndex:(r.location + r.length)] copy];
+      
+      self->uri = [_spec substringToIndex:r.location];
+      self->uri = ([self->uri length] > 1)
+        ? [self->uri copy]
+        : @"*";
+    }
+    else {
+      /* usual 'blah' */
+      self->attrSpec = [_spec copy];
+    }
+  }  
+  return self;
+}
+
+- (void)dealloc {
+  [self->uri      release];
+  [self->attrSpec release];
+  [super dealloc];
+}
+
+- (id)evaluateWithNode:(id)_node inContext:(id)_ctx {
+  /* lookup attribute element */
+  id   attributes;
+  id   result;
+  BOOL _forceList = NO;
+  
+  attributes = [(id<DOMNode>)_node attributes];
+
+#if DEBUG
+  if (attributes == nil)
+    NSLog(@"%s: node %@ has no attributes ..", __PRETTY_FUNCTION__, _node);
+#endif
+  
+  if (self->aflags.getAll) {
+    /* all attribute elements */
+    result = attributes;
+    _forceList = NO; // attributes behave already like a list  ..
+  }
+  else if (self->uri) {
+    result = [attributes namedItem:self->attrSpec namespaceURI:self->uri];
+  }
+  else if (self->aflags.hasColon) {
+    result = [attributes namedItem:self->attrSpec namespaceURI:self->uri];
+    //result = [result value];
+  }
+  else {
+    result = [attributes namedItem:self->attrSpec];
+  }
+  
+  if (_forceList)
+    result = [NSArray arrayWithObject:result];
+  
+  return result;
+}
+
+- (NSString *)description {
+  NSMutableString *ms;
+
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
+  [ms appendFormat:@" attrSpec='%@'", self->attrSpec];
+  if (self->uri)
+    [ms appendFormat:@" uri='%@'", self->uri];
+  if (self->aflags.getAll)
+    [ms appendString:@" getall"];
+  if (self->aflags.hasColon)
+    [ms appendString:@" colon"];
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* _DOMQueryPathAttribute */
+
+@implementation _DOMQPPredicateExpression
+
+- (BOOL)matchesNode:(id)_node inContext:(id)_ctx {
+  /* override in subclasses ! */
+  [self doesNotRecognizeSelector:_cmd];
+  return NO;
+}
+
+@end /* _DOMQPPredicateExpression */
+
+@implementation _DOMQPPredicateQPExpression
+
+- (id)initWithQueryPathExpression:(DOMQueryPathExpression *)_expr {
+  self->qpexpr = [_expr retain];
+  return self;
+}
+- (id)init {
+  return [self initWithQueryPathExpression:nil];
+}
+
+- (void)dealloc {
+  [self->qpexpr release];
+  [super dealloc];
+}
+
+- (BOOL)matchesNode:(id)_node inContext:(id)_ctx {
+  id nodeList;
+  
+  //NSLog(@"check match of node %@, qpexpr %@ ...", _node, qpexpr);
+  
+  nodeList = [NSArray arrayWithObject:_node];
+  nodeList = [self->qpexpr evaluateWithNodeList:nodeList inContext:_ctx];
+  
+  return ([nodeList count] > 0) ? YES : NO;
+}
+
+@end /* _DOMQPPredicateQPExpression */
diff --git a/skyrix-xml/DOM/DOMSaxBuilder.h b/skyrix-xml/DOM/DOMSaxBuilder.h
new file mode 100644 (file)
index 0000000..a46554c
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMSaxBuilder_H__
+#define __DOMSaxBuilder_H__
+
+#import <Foundation/NSObject.h>
+#include <DOM/DOMBuilder.h>
+
+@class NSString, NSData;
+
+@interface DOMSaxBuilder : NSObject < DOMBuilder >
+{
+  id parser;
+  id sax;
+}
+
+- (id)initWithXMLReader:(id)_saxParser;
+- (id)initWithXMLReaderForMimeType:(id)_mimeType;
+
+- (id)buildFromContentsOfFile:(NSString *)_path;
+- (id)buildFromData:(NSData *)_data;
+
+@end
+
+#endif /* __DOMSaxBuilder_H__ */
diff --git a/skyrix-xml/DOM/DOMSaxBuilder.m b/skyrix-xml/DOM/DOMSaxBuilder.m
new file mode 100644 (file)
index 0000000..3b238e6
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMSaxBuilder.h"
+#include "DOMSaxHandler.h"
+#include "DOMAttribute.h"
+#include "DOMDocument.h"
+#include "common.h"
+#include <SaxObjC/SaxObjC.h>
+
+@implementation DOMSaxBuilder
+
+- (id)initWithXMLReader:(id)_saxParser {
+  if (_saxParser == nil) {
+    [self release];
+    return nil;
+  }
+  
+  ASSIGN(self->parser, _saxParser);
+  
+  self->sax = [[DOMSaxHandler alloc] init];
+  
+  [self->parser setContentHandler:self->sax];
+  [self->parser setDTDHandler:self->sax];
+  [self->parser setErrorHandler:self->sax];
+  
+  [self->parser setProperty:@"http://xml.org/sax/properties/declaration-handler"
+                to:self->sax];
+  [self->parser setProperty:@"http://xml.org/sax/properties/lexical-handler"
+                to:self->sax];
+
+  return self;
+}
+- (id)initWithXMLReaderForMimeType:(id)_mimeType {
+  id reader;
+
+  reader = [[SaxXMLReaderFactory standardXMLReaderFactory]
+                                 createXMLReaderForMimeType:_mimeType];
+  if (reader == nil) {
+    NSLog(@"%s: could not find a SAX driver bundle for type '%@' !\n",
+          __PRETTY_FUNCTION__, _mimeType);
+    [self release];
+    return nil;
+  }
+  
+  return [self initWithXMLReader:reader];
+}
+
+- (id)init {
+  id reader;
+
+  reader = [[SaxXMLReaderFactory standardXMLReaderFactory] createXMLReader];
+
+  if (reader == nil) {
+    NSLog(@"%s: could not load a SAX driver bundle !\n",
+          __PRETTY_FUNCTION__);
+    [self release];
+    return nil;
+  }
+  
+  return [self initWithXMLReader:reader];
+}
+- (void)dealloc {
+  [self->parser release];
+  [self->sax    release];
+  [super dealloc];
+}
+
+/* DOM building */
+
+- (id<NSObject,DOMDocument>)_docAfterParsing {
+  id<NSObject,DOMDocument> doc;
+
+  doc = [[self->sax document] retain];
+
+  [(id)doc addErrors:[self->sax errors]];
+  [(id)doc addWarnings:[self->sax warnings]];
+  
+  [self->sax clear];
+  return [doc autorelease];
+}
+
+- (id)buildFromData:(NSData *)_data {
+  NSAutoreleasePool *pool;
+  id doc;
+  
+  if (_data == nil) {
+    NSLog(@"missing data ..");
+    return nil;
+  }
+  NSAssert(self->sax,    @"missing sax handler ..");
+  NSAssert(self->parser, @"missing XML parser ..");
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    [self->parser parseFromSource:_data];
+    doc = [[self _docAfterParsing] retain];
+  }
+  [pool release];
+
+#if DEBUG
+  NSAssert(self->sax,    @"missing sax handler ..");
+  NSAssert(self->parser, @"missing XML parser ..");
+#endif
+  
+  return [doc autorelease];
+}
+
+- (id)buildFromContentsOfFile:(NSString *)_path {
+  NSAutoreleasePool *pool;
+  id doc;
+  
+  if ([_path length] == 0)
+    return nil;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    NSDate *date;
+    NSTimeInterval duration;
+
+    date = [NSDate date];
+    _path = [@"file://" stringByAppendingString:_path];
+    
+    [self->parser parseFromSystemId:_path];
+    doc = [[self _docAfterParsing] retain];
+    
+    duration = [[NSDate date] timeIntervalSinceDate:date];
+  }
+  [pool release];
+  
+  return [doc autorelease];
+}
+
+- (id<NSObject,DOMDocument>)buildFromSource:(id)_source
+  systemId:(NSString *)_sysId
+{
+  NSAutoreleasePool *pool;
+  id doc;
+  
+  if (_source == nil)
+    return nil;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    NSDate *date;
+    NSTimeInterval duration;
+
+    date = [NSDate date];
+    
+    [self->parser parseFromSource:_source systemId:_sysId];
+    doc = [[self _docAfterParsing] retain];
+    
+    duration = [[NSDate date] timeIntervalSinceDate:date];
+  }
+  [pool release];
+  
+  return [doc autorelease];
+}
+- (id<NSObject,DOMDocument>)buildFromSource:(id)_source {
+  return [self buildFromSource:_source systemId:nil];
+}
+
+- (id<NSObject,DOMDocument>)buildFromSystemId:(NSString *)_sysId {
+  NSAutoreleasePool *pool;
+  id doc;
+  
+  if ([_sysId length] == 0)
+    return nil;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    NSDate *date;
+    NSTimeInterval duration;
+
+    date = [NSDate date];
+    
+    [self->parser parseFromSystemId:_sysId];
+    doc = [[self _docAfterParsing] retain];
+    
+    duration = [[NSDate date] timeIntervalSinceDate:date];
+  }
+  [pool release];
+  
+  return [doc autorelease];
+}
+
+@end /* DOMSaxBuilder */
diff --git a/skyrix-xml/DOM/DOMSaxHandler.h b/skyrix-xml/DOM/DOMSaxHandler.h
new file mode 100644 (file)
index 0000000..db8b16d
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMSaxHandler_H__
+#define __DOMSaxHandler_H__
+
+#include <SaxObjC/SaxDefaultHandler.h>
+
+@class NSMutableArray;
+
+@interface DOMSaxHandler : SaxDefaultHandler
+{
+  id   locator;
+  BOOL inDTD;
+  BOOL inCDATA;
+  int  maxErrorCount;
+  NSMutableArray *errors;
+  NSMutableArray *warnings;
+  NSMutableArray *fatals;
+  
+  /* dom */
+  id  dom;
+  id  document;
+  int errorCount;
+  
+  /* dom building */
+  id currentElement;
+
+  /* */
+  unsigned tagDepth;
+}
+
+- (id)initWithDOMImplementation:(id)_domImpl;
+
+/* access result */
+
+- (id)document;
+- (void)clear;
+- (int)maxErrorCount;
+
+- (int)errorCount;
+- (int)fatalErrorCount;
+- (int)warningCount;
+- (NSArray *)warnings;
+- (NSArray *)errors;
+- (NSArray *)fatalErrors;
+
+@end
+
+#endif /* __DOMSaxHandler_H__ */
diff --git a/skyrix-xml/DOM/DOMSaxHandler.m b/skyrix-xml/DOM/DOMSaxHandler.m
new file mode 100644 (file)
index 0000000..86ce5ee
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMSaxHandler.h"
+#include "DOMImplementation.h"
+#include "DOMDocument.h"
+#include "DOMElement.h"
+#include "common.h"
+#include <SaxObjC/SaxObjC.h>
+
+@interface NSObject(LineInfoProtocol)
+- (void)setLine:(int)_line;
+@end
+
+@implementation DOMSaxHandler
+
+- (id)initWithDOMImplementation:(id)_domImpl {
+  if ((self = [super init])) {
+    self->dom = [_domImpl retain];
+    self->maxErrorCount = 100; // this also includes NPSOBJ in HTML !
+  }
+  return self;
+}
+- (id)init {
+  static id idom = nil;
+  
+  if (idom == nil)
+    idom = [[DOMImplementation alloc] init];
+  
+  return [self initWithDOMImplementation:idom];
+}
+
+- (void)dealloc {
+  [self->document release];
+  [self->dom      release];
+  [self->locator  release];
+  [self->fatals   release];
+  [self->errors   release];
+  [self->warnings release];
+  [super dealloc];
+}
+
+- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_loc {
+  ASSIGN(self->locator, _loc);
+}
+
+- (id)document {
+  return self->document;
+}
+
+- (void)clear {
+  ASSIGN(self->document, (id)nil);
+  [self->fatals   removeAllObjects];
+  [self->errors   removeAllObjects];
+  [self->warnings removeAllObjects];
+  self->errorCount = 0;
+}
+
+- (int)errorCount {
+  return self->errorCount;
+}
+- (int)fatalErrorCount {
+  return [self->fatals count];
+}
+- (int)warningCount {
+  return [self->warnings count];
+}
+- (int)maxErrorCount {
+  return self->maxErrorCount;
+}
+
+- (NSArray *)warnings {
+  return [[self->warnings copy] autorelease];
+}
+- (NSArray *)errors {
+  return [[self->errors copy] autorelease];
+}
+- (NSArray *)fatalErrors {
+  return [[self->fatals copy] autorelease];
+}
+
+/* attributes */
+
+- (id)_nodeForSaxAttrWithName:(NSString *)_name
+  namespace:(NSString *)_uri
+  rawName:(NSString *)_rawName
+  type:(NSString *)_saxType value:(NSString *)_saxValue
+{
+  id attr;
+  NSString *nsPrefix;
+  
+  attr = [self->document createAttribute:_name namespaceURI:_uri];
+  if (attr == nil) 
+    return nil;
+  
+  nsPrefix = nil;
+  if (_uri) {
+    NSRange r;
+    
+    r = [_rawName rangeOfString:@":"];
+    if (r.length > 0)
+      nsPrefix = [_rawName substringToIndex:r.location];
+  }
+  
+  if (nsPrefix)
+    [attr setPrefix:nsPrefix];
+  
+  /* add content to attribute */
+  
+  if ([_saxType isEqualToString:@"CDATA"] || (_saxType == nil)) {
+    id content;
+
+    NSAssert(self->document, @"missing document object");
+    
+    if ((content = [self->document createTextNode:_saxValue]))
+      [attr appendChild:content];
+    else
+      NSLog(@"couldn't create text node !");
+  }
+  else
+    NSLog(@"unsupported sax attr type '%@' !", _saxType);
+  
+  return attr;
+}
+
+/* document */
+
+- (void)startDocument {
+  id docType;
+  
+  [self->document release]; self->document = nil;
+  self->errorCount = 0;
+  self->tagDepth   = 0;
+  
+  docType = [self->dom createDocumentType:nil
+                       publicId:[self->locator publicId]
+                       systemId:[self->locator systemId]];
+  
+  self->document = [self->dom createDocumentWithName:nil
+                             namespaceURI:nil
+                             documentType:docType];
+  self->document = [self->document retain];
+  
+  //NSLog(@"started doc: %@", self->document);
+  
+  self->currentElement = self->document;
+}
+- (void)endDocument {
+  self->currentElement = nil;
+}
+
+- (void)startPrefixMapping:(NSString *)_prefix uri:(NSString *)_uri {
+  //printf("ns-map: %s=%s\n", [_prefix cString], [_uri cString]);
+}
+- (void)endPrefixMapping:(NSString *)_prefix {
+  //printf("ns-unmap: %s\n", [_prefix cString]);
+}
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attrs
+{
+  id       elem;
+  NSString *nsPrefix;
+
+  self->tagDepth++;
+  elem = [self->document createElement:_localName namespaceURI:_ns];
+  if (elem == nil) {
+    NSLog(@"%s: couldn't create element for tag '%@'", __PRETTY_FUNCTION__,
+          _rawName);
+    return;
+  }
+  if ([elem respondsToSelector:@selector(setLine:)])
+    [elem setLine:[self->locator lineNumber]];
+  
+  if (_ns) {
+    NSRange r;
+    
+    r = [_rawName rangeOfString:@":"];
+    nsPrefix = (r.length > 0)
+      ? [_rawName substringToIndex:r.location]
+      : nil;
+  }
+  else
+    nsPrefix = nil;
+
+  if (nsPrefix)
+    [elem setPrefix:nsPrefix];
+  
+  NSAssert(self->currentElement, @"no current element !");
+  
+  [self->currentElement appendChild:elem];
+  self->currentElement = elem;
+
+  /* process attributes */
+  {
+    unsigned i, count;
+    
+    for (i = 0, count = [_attrs count]; i < count; i++) {
+      id attr;
+      
+      // NSLog(@"attr %@", [_attrs nameAtIndex:i]);
+      
+      attr = [self _nodeForSaxAttrWithName:[_attrs nameAtIndex:i]
+                  namespace:[_attrs uriAtIndex:i]
+                   rawName:[_attrs rawNameAtIndex:i]
+                  type:[_attrs typeAtIndex:i]
+                  value:[_attrs valueAtIndex:i]];
+      if (attr == nil) {
+       NSLog(@"couldn't create attribute for SAX attr %@, element %@",
+             attr, elem);
+       continue;
+      }
+      
+      /* add node to element */
+      
+      if ([elem setAttributeNodeNS:attr] == nil)
+       NSLog(@"couldn't add attribute %@ to element %@", attr, elem);
+    }
+  }
+}
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  id parent;
+
+  parent = [self->currentElement parentNode];
+#if DEBUG
+  NSAssert1(parent, @"no parent for current element %@ !",
+            self->currentElement);
+#endif
+  self->currentElement = parent;
+  self->tagDepth--;
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  id       charNode;
+  NSString *data;
+  
+  data     = [[NSString alloc] initWithCharacters:_chars length:_len];
+  charNode = [self->document createTextNode:data];
+  [data release]; data = nil;
+  
+  [self->currentElement appendChild:charNode];
+}
+- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
+}
+
+- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data {
+  id piNode;
+
+  piNode = [self->document createProcessingInstruction:_pi data:_data];
+
+  [self->currentElement appendChild:piNode];
+}
+
+#if 0
+- (xmlEntityPtr)getEntity:(NSString *)_name {
+  NSLog(@"get entity %@", _name);
+  return NULL;
+}
+- (xmlEntityPtr)getParameterEntity:(NSString *)_name {
+  NSLog(@"get para entity %@", _name);
+  return NULL;
+}
+#endif
+
+/* lexical handler */
+
+- (void)comment:(unichar *)_chars length:(int)_len {
+  id       commentNode;
+  NSString *data;
+  
+  if (_len == 0)
+    return;
+  
+  data = [[NSString alloc] initWithCharacters:_chars length:_len];
+  commentNode = [self->document createComment:data];
+  [data release]; data = nil;
+  
+  [self->currentElement appendChild:commentNode];
+}
+
+- (void)startDTD:(NSString *)_name
+  publicId:(NSString *)_pub
+  systemId:(NSString *)_sys
+{
+  self->inDTD = YES;
+}
+- (void)endDTD {
+  self->inDTD = NO;
+}
+
+- (void)startCDATA {
+  self->inCDATA = YES;
+}
+- (void)endCDATA {
+  self->inCDATA = NO;
+}
+
+/* entities */
+
+- (id)resolveEntityWithPublicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+{
+  NSLog(@"shall resolve entity with '%@' '%@'", _pubId, _sysId);
+  return nil;
+}
+
+/* errors */
+
+- (void)warning:(SaxParseException *)_exception {
+  NSString *sysId;
+  int line;
+  
+  sysId = [[_exception userInfo] objectForKey:@"systemId"];
+  line  = [[[_exception userInfo] objectForKey:@"line"] intValue];
+  
+  NSLog(@"DOM XML WARNING(%@:%i): %@", sysId, line, [_exception reason]);
+
+  if (self->warnings == nil)
+    self->warnings = [[NSMutableArray alloc] initWithCapacity:32];
+  
+  if (_exception)
+    [self->warnings addObject:_exception];
+}
+
+- (void)error:(SaxParseException *)_exception {
+  NSString *sysId;
+  int line;
+  
+  self->errorCount++;
+  
+  sysId = [[_exception userInfo] objectForKey:@"systemId"];
+  line  = [[[_exception userInfo] objectForKey:@"line"] intValue];
+  
+  NSLog(@"DOM XML ERROR(%@:%i[%@]): %@ (errcount=%i,max=%i)", sysId, line,
+        [[_exception userInfo] objectForKey:@"parser"],
+        [_exception reason],
+        self->errorCount, self->maxErrorCount);
+
+  if (self->errors == nil)
+    self->errors = [[NSMutableArray alloc] initWithCapacity:32];
+  
+  if (_exception)
+    [self->errors addObject:_exception];
+}
+
+- (void)fatalError:(SaxParseException *)_exception {
+  NSString *sysId;
+  int line;
+  
+  sysId = [[_exception userInfo] objectForKey:@"systemId"];
+  line  = [[[_exception userInfo] objectForKey:@"line"] intValue];
+  
+  NSLog(@"DOM XML FATAL(%@:%i[%@]): %@", sysId, line,
+        [[_exception userInfo] objectForKey:@"parser"],
+        [_exception reason]);
+  
+  if (self->fatals == nil)
+    self->fatals = [[NSMutableArray alloc] initWithCapacity:32];
+  
+  if (_exception)
+    [self->fatals addObject:_exception];
+  
+  [_exception raise];
+}
+
+/* DTD */
+
+- (void)notationDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+{
+  NSLog(@"decl: notation %@ pub=%@ sys=%@", _name, _pubId, _sysId);
+}
+
+- (void)unparsedEntityDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+  notationName:(NSString *)_notName
+{
+  NSLog(@"decl: unparsed entity %@ pub=%@ sys=%@ not=%@",
+        _name, _pubId, _sysId, _notName);
+}
+
+/* decl */
+
+- (void)attributeDeclaration:(NSString *)_attributeName
+  elementName:(NSString *)_elementName
+  type:(NSString *)_type
+  defaultType:(NSString *)_defType
+  defaultValue:(NSString *)_defValue
+{
+  NSLog(@"decl: attr %@[%@] type '%@' default '%@'[%@]",
+        _attributeName, _elementName, _type, _defValue, _defType);
+}
+
+- (void)elementDeclaration:(NSString *)_name contentModel:(NSString *)_model {
+  NSLog(@"decl: element %@ model %@", _name, _model);
+}
+
+- (void)externalEntityDeclaration:(NSString *)_name
+  publicId:(NSString *)_pub
+  systemId:(NSString *)_sys
+{
+  NSLog(@"decl: e-entity %@ pub %@ sys %@", _name, _pub, _sys);
+}
+
+- (void)internalEntityDeclaration:(NSString *)_name value:(NSString *)_value {
+  NSLog(@"decl: i-entity %@ value %@", _name, _value);
+}
+
+@end /* DOMSaxHandler */
+
+
+@implementation DOMSaxHandler(SubHandler)
+
+- (unsigned)tagDepth {
+  return self->tagDepth;
+}
+
+- (id)object {
+  return [self document];
+}
+
+- (void)setNamespaces:(NSString *)_namespaces {
+  // not yet implemented
+}
+
+@end /* DOMSaxHandler(SubHandler) */
diff --git a/skyrix-xml/DOM/DOMText.h b/skyrix-xml/DOM/DOMText.h
new file mode 100644 (file)
index 0000000..ded3157
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOMText_H__
+#define __DOMText_H__
+
+#include <DOM/DOMCharacterData.h>
+
+/*
+  Why do I get adjacent Text nodes?
+  
+    The DOM structure model that is created by whatever it is that creates it
+    has one Text node per block of text when it starts. The only way you can
+    have adjacent Text nodes is as a result of user operations; it is not an
+    option for the DOM implementation when it first presents its structure
+    model to the user. The normalize method (on the Element interface in
+    level 1, but moved to Node for Level 2) will merge all the adjacent Text
+    nodes into one again, so they will have the same form as if you wrote out
+    the XML or HTML and then read it in again. Note that this will have no
+    effect on CDATA Sections.
+  
+    A filtered view of a document, such as that obtained through use of
+    TreeWalker, may have adjacent Text nodes because the intervening Nodes are
+    not seen in that view.
+*/
+
+@interface DOMText : DOMCharacterData < DOMText >
+{
+}
+
+@end
+
+#endif /* __DOMTextNode_H__ */
diff --git a/skyrix-xml/DOM/DOMText.m b/skyrix-xml/DOM/DOMText.m
new file mode 100644 (file)
index 0000000..c3d0fbb
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "DOMText.h"
+
+@interface NSObject(UsedFdExt)
+- (id)doesNotRecognizeSelector:(SEL)_sel;
+@end
+
+@implementation DOMText
+
+/* node */
+
+- (DOMNodeType)nodeType {
+  return DOM_TEXT_NODE;
+}
+
+- (BOOL)_isValidChildNode:(id)_node {
+  return NO;
+}
+- (BOOL)hasChildNodes {
+  return NO;
+}
+- (id)childNodes {
+  return nil;
+}
+- (id)appendChild:(id)_node {
+  return nil;
+}
+
+- (id)attributes {
+  return nil;
+}
+
+- (id<NSObject,DOMText>)splitText:(unsigned)_offset {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+/* Level 3 Methods */
+
+- (BOOL)isWhitespaceInElementContent {
+  return NO;
+}
+
+- (NSString *)wholeText {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (id<NSObject,DOMText>)replaceWholeText:(NSString *)_content {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+@end /* DOMText */
diff --git a/skyrix-xml/DOM/DOMTreeWalker.h b/skyrix-xml/DOM/DOMTreeWalker.h
new file mode 100644 (file)
index 0000000..708cbf5
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMTreeWalker_H__
+#define __DOMTreeWalker_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSArray;
+
+@interface DOMTreeWalker : NSObject
+{
+  id            root;
+  unsigned long whatToShow;
+  id            filter;
+  BOOL          expandEntityReferences;
+  id            currentNode;
+
+  /* cache state */
+  NSArray       *visibleChildren;
+}
+
+/* attributes */
+
+- (id)root;
+- (unsigned long)whatToShow;
+- (id)filter;
+- (BOOL)expandEntityReferences;
+
+- (void)setCurrentNode:(id)_node;
+- (id)currentNode;
+
+/* operations */
+
+- (id)parentNode;
+- (id)firstChild;
+- (id)lastChild;
+- (id)previousSibling;
+- (id)nextSibling;
+
+- (id)previousNode;
+- (id)nextNode;
+
+@end
+
+@interface DOMTreeWalker(PrivateCtors)
+/* use DOMDocument(DocumentTraversal) for constructing DOMTreeWalker's ! */
+
+- (id)initWithRootNode:(id)_rootNode
+  whatToShow:(unsigned long)_whatToShow
+  filter:(id)_filter
+  expandEntityReferences:(BOOL)_flag;
+
+@end
+
+#endif /* __DOMTreeWalker_H__ */
diff --git a/skyrix-xml/DOM/DOMTreeWalker.m b/skyrix-xml/DOM/DOMTreeWalker.m
new file mode 100644 (file)
index 0000000..fc77c92
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <DOM/DOMTreeWalker.h>
+#include <DOM/DOMNodeFilter.h>
+#include <DOM/DOMNode.h>
+#include "common.h"
+
+@implementation DOMTreeWalker
+
+- (id)initWithRootNode:(id)_rootNode
+  whatToShow:(unsigned long)_whatToShow
+  filter:(id)_filter
+  expandEntityReferences:(BOOL)_flag
+{
+  NSAssert(_rootNode, @"missing root-node !");
+
+  if ((self = [super init])) {
+    self->root       = [_rootNode retain];
+    self->whatToShow = _whatToShow;
+    self->filter     = [_filter retain];
+    self->expandEntityReferences = _flag;
+    
+    [self setCurrentNode:_rootNode];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->visibleChildren release];
+  [self->currentNode release];
+  [self->root        release];
+  [self->filter      release];
+  [super dealloc];
+}
+                 
+/* attributes */
+
+- (id)root {
+  return self->root;
+}
+- (unsigned long)whatToShow {
+  return self->whatToShow;
+}
+- (id)filter {
+  return self->filter;
+}
+- (BOOL)expandEntityReferences {
+  return self->expandEntityReferences;
+}
+
+- (void)setCurrentNode:(id)_node {
+  if (_node == self->currentNode)
+    /* same node */
+    return;
+  
+  ASSIGN(self->currentNode, _node);
+
+  /* clear state caches */
+  [self->visibleChildren release]; self->visibleChildren = nil;
+}
+- (id)currentNode {
+  return self->currentNode;
+}
+
+/* internals */
+
+- (BOOL)_shouldShowNode:(id)_node {
+  if (self->whatToShow == DOM_SHOW_ALL)
+    return YES;
+  
+  switch([_node nodeType]) {
+    case DOM_ATTRIBUTE_NODE:
+      return (self->whatToShow & DOM_SHOW_ATTRIBUTE) != 0 ? YES : NO;
+    case DOM_CDATA_SECTION_NODE:
+      return (self->whatToShow & DOM_SHOW_CDATA_SECTION) != 0 ? YES : NO;
+    case DOM_COMMENT_NODE:
+      return (self->whatToShow & DOM_SHOW_COMMENT) != 0 ? YES : NO;
+    case DOM_DOCUMENT_NODE:
+      return (self->whatToShow & DOM_SHOW_DOCUMENT) != 0 ? YES : NO;
+    case DOM_DOCUMENT_FRAGMENT_NODE:
+      return (self->whatToShow & DOM_SHOW_DOCUMENT_FRAGMENT) != 0 ? YES : NO;
+    case DOM_ELEMENT_NODE:
+      return (self->whatToShow & DOM_SHOW_ELEMENT) != 0 ? YES : NO;
+    case DOM_PROCESSING_INSTRUCTION_NODE:
+      return (self->whatToShow & DOM_SHOW_PROCESSING_INSTRUCTION) != 0 ? YES:NO;
+    case DOM_TEXT_NODE:
+      return (self->whatToShow & DOM_SHOW_TEXT) != 0 ? YES : NO;
+    case DOM_DOCUMENT_TYPE_NODE:
+      return (self->whatToShow & DOM_SHOW_DOCUMENT_TYPE) != 0 ? YES : NO;
+    case DOM_ENTITY_NODE:
+      return (self->whatToShow & DOM_SHOW_ENTITY) != 0 ? YES : NO;
+    case DOM_ENTITY_REFERENCE_NODE:
+      return (self->whatToShow & DOM_SHOW_ENTITY_REFERENCE) != 0 ? YES : NO;
+    case DOM_NOTATION_NODE:
+      return (self->whatToShow & DOM_SHOW_NOTATION) != 0 ? YES : NO;
+    default:
+      return YES;
+  }
+}
+
+- (BOOL)_isVisibleNode:(id)_node {
+  if (![self _shouldShowNode:_node])
+    return NO;
+  if (self->filter)
+    return [self->filter acceptNode:_node] == DOM_FILTER_ACCEPT ? YES : NO;
+  return YES;
+}
+- (unsigned short)_navTypeOfNode:(id)_node {
+  if (![self _shouldShowNode:_node])
+    return DOM_FILTER_SKIP;
+  if (self->filter)
+    return [self->filter acceptNode:_node] == DOM_FILTER_ACCEPT ? YES : NO;
+  return DOM_FILTER_ACCEPT;
+}
+
+- (NSArray *)_ensureVisibleChildren {
+  static NSArray *emptyArray = nil;
+  id children;
+  unsigned count;
+
+  if (self->visibleChildren)
+    return self->visibleChildren;
+  
+  children = [[self currentNode] childNodes];
+
+  if ((count = [children count]) > 0) {
+    unsigned i;
+    NSMutableArray *ma;
+    
+    ma = [[NSMutableArray alloc] initWithCapacity:(count + 1)];
+    
+    for (i = 0; i < count; i++) {
+      id childNode;
+      
+      childNode = [children objectAtIndex:i];
+      
+      if ([self _isVisibleNode:childNode])
+        [ma addObject:childNode];
+    }
+    
+    self->visibleChildren = [ma copy];
+    [ma release]; ma = nil;
+  }
+  else {
+    if (emptyArray == nil) emptyArray = [[NSArray alloc] init];
+    self->visibleChildren = [emptyArray retain];
+  }
+  return self->visibleChildren;
+}
+
+- (BOOL)_hasVisibleChildren {
+  return [[self _ensureVisibleChildren] count] > 0 ? YES : NO;
+}
+- (id)_visibleChildren {
+  return [self _ensureVisibleChildren];
+}
+- (id)_firstVisibleChild {
+  NSArray *a = [self _ensureVisibleChildren];
+  if ([a count] == 0)
+    return nil;
+  return [a objectAtIndex:0];
+}
+- (id)_lastVisibleChild {
+  NSArray *a = [self _ensureVisibleChildren];
+  unsigned count;
+  
+  if ((count = [a count]) == 0)
+    return nil;
+  return [a objectAtIndex:(count - 1)];
+}
+
+- (id)_visibleParentNode {
+  id node;
+
+  for (node = [[self currentNode] parentNode]; node; node = [node parentNode]) {
+    if ([self _isVisibleNode:node])
+      return node;
+    
+    if (node == [self root])
+      /* do not step above root */
+      break;
+  }
+  return nil;
+}
+
+- (id)_nextVisibleSibling {
+  id node;
+
+  for (node = [[self currentNode] nextSibling];
+       node;
+       node = [node nextSibling]) {
+    if ([self _isVisibleNode:node])
+      return node;
+  }
+  return nil;
+}
+- (id)_previousVisibleSibling {
+  id node;
+
+  for (node = [[self currentNode] previousSibling];
+       node;
+       node = [node previousSibling]) {
+    if ([self _isVisibleNode:node])
+      return node;
+  }
+  return nil;
+}
+
+/* operations */
+
+- (id)parentNode {
+  id parent;
+
+  if ((parent = [self _visibleParentNode])) {
+    [self setCurrentNode:parent];
+    return parent;
+  }
+  else
+    return nil;
+}
+
+- (id)firstChild {
+  if ([self _hasVisibleChildren]) {
+    id child;
+
+    child = [self _firstVisibleChild];
+    [self setCurrentNode:child];
+    return child;
+  }
+  else
+    return nil;
+}
+
+- (id)lastChild {
+  if ([self _hasVisibleChildren]) {
+    id child;
+
+    child = [self _lastVisibleChild];
+    [self setCurrentNode:child];
+    return child;
+  }
+  else
+    return nil;
+}
+
+- (id)previousSibling {
+  id node;
+
+  if ((node = [self _previousVisibleSibling])) {
+    [self setCurrentNode:node];
+    return node;
+  }
+  else
+    return nil;
+}
+
+- (id)nextSibling {
+  id node;
+
+  if ((node = [self _nextVisibleSibling])) {
+    [self setCurrentNode:node];
+    return node;
+  }
+  else
+    return nil;
+}
+
+- (id)previousNode {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+- (id)nextNode {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+@end /* DOMTreeWalker */
diff --git a/skyrix-xml/DOM/DOMXMLOutputter.h b/skyrix-xml/DOM/DOMXMLOutputter.h
new file mode 100644 (file)
index 0000000..2e47bab
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOMXMLOutputter_H__
+#define __DOMXMLOutputter_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSMutableArray;
+
+@interface DOMXMLOutputter : NSObject
+{
+  NSMutableArray *stack;
+  unsigned indent;
+}
+
+- (void)outputNode:(id)_node to:(id)_target;
+- (void)outputDocument:(id)_document to:(id)_target;
+
+@end
+
+#endif /* __DOMXMLOutputter_H__ */
diff --git a/skyrix-xml/DOM/DOMXMLOutputter.m b/skyrix-xml/DOM/DOMXMLOutputter.m
new file mode 100644 (file)
index 0000000..42a3e18
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "DOMXMLOutputter.h"
+#include "DOMDocument.h"
+#include "DOMElement.h"
+#include "common.h"
+
+@interface DOMXMLOutputter(Privates)
+- (void)outputNode:(id<DOMNode>)_node to:(id)_target;
+- (void)outputNodeList:(id<DOMNodeList>)_nodeList to:(id)_target;
+@end
+
+@interface DOMXMLOutputter(PrefixStack)
+- (NSString *)topPrefix;
+- (NSString *)topNamespace;
+- (void)pushPrefix:(NSString *)_prefix namespace:(NSString *)_namespace;
+- (void)popPrefixAndNamespace;
+- (BOOL)isTagValidInStack:(id)_node;
+- (NSArray *)newAttributePrefixesAndNamespaces:(NSArray *)_attrs;
+@end /* DOMXMLOutputter(PrefixStack) */
+
+
+@implementation DOMXMLOutputter
+
+- (id)init {
+  if ((self = [super init])) {
+    self->stack = [[NSMutableArray alloc] initWithCapacity:32];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->stack release];
+  [super dealloc];
+}
+
+- (void)indentOn:(id)_target {
+  int i;
+  
+  for (i = 0; i < (self->indent * 4); i++) {
+    if (_target)
+      [_target appendString:@" "];
+    else
+      fputc(' ', stdout);
+  }
+}
+
+- (void)write:(NSString *)s to:(id)_target {
+  if (_target)
+    [_target appendString:s];
+  else
+    printf("%s", [s cString]);
+}
+- (BOOL)currentElementPreservesWhitespace {
+  return NO;
+}
+
+- (void)outputAttributeNode:(id<DOMAttr>)_attrNode
+  ofNode:(id<DOMNode>)_node
+  to:(id)_target
+{
+  if ([[_attrNode prefix] length] > 0) {
+    [self write:[_attrNode prefix] to:_target];
+    [self write:@":"               to:_target];
+  }
+  [self write:[_attrNode name] to:_target];
+  
+  if ([_attrNode hasChildNodes]) {
+    id children;
+    unsigned i, count;
+
+    [self write:@"=\"" to:_target];
+
+    children = [_attrNode childNodes];
+    for (i = 0, count = [children count]; i < count; i++) {
+      id child;
+      
+      child = [children objectAtIndex:i];
+      
+      if ([child nodeType] == DOM_TEXT_NODE)
+        [self write:[(id<DOMText>)child data] to:_target];
+      else
+        NSLog(@"WARNING: unsupported attribute value node %@", child);
+    }
+    
+    [self write:@"\"" to:_target];
+  }
+  else
+    NSLog(@"WARNING: attribute %@ has no content !", _attrNode);
+}
+
+- (void)outputAttributeNodes:(id<DOMNamedNodeMap>)_nodes
+  list:(NSArray *)_list to:(id)_target
+{
+  unsigned i, count, count2;
+  
+  if ((count = [_nodes length]) == 0)
+    return;
+
+  // append required prefix and namespaces
+  for (i = 0, count2 = [_list count]; i < count2; i = i + 2) {
+    [self write:@" xmlns:" to:_target];
+    [self write:[_list objectAtIndex:i]   to:_target];
+    [self write:@"=\""     to:_target];
+    [self write:[_list objectAtIndex:i+1] to:_target];
+    [self write:@"\""      to:_target];
+  }
+  
+  for (i = 0; i < count; i++) {
+    id<DOMAttr> attrNode;
+    
+    attrNode = [_nodes objectAtIndex:i];
+    
+    [self write:@" " to:_target];
+    [self outputAttributeNode:attrNode ofNode:nil to:_target];
+  }
+}
+
+- (void)outputTextNode:(id<DOMText>)_node to:(id)_target {
+  NSString *s;
+  unsigned len;
+
+  s = [_node data];
+  if ((len = [s length]) == 0)
+    return;
+  
+  if (![self currentElementPreservesWhitespace]) {
+    unsigned i;
+    
+    for (i = 0; i < len; i++) {
+      if (!isspace([s characterAtIndex:i]))
+        break;
+    }
+    if (i == len)
+      /* only whitespace */
+      return;
+    
+    [self indentOn:_target];
+  }
+  
+  [self write:[_node data] to:_target];
+  
+  if (![self currentElementPreservesWhitespace])
+    [self write:@"\n" to:_target];
+}
+- (void)outputCommentNode:(id<DOMComment>)_node to:(id)_target {
+  [self write:@"<!-- "     to:_target];
+  [self write:[_node data] to:_target];
+  [self write:@" -->"      to:_target];
+  
+  if (![self currentElementPreservesWhitespace])
+    [self write:@"\n" to:_target];
+}
+
+- (void)outputElementNode:(id<DOMElement>)_node to:(id)_target {
+  NSArray  *list;  // new attribute prefixes and namespaces
+  NSString *tagName;
+  NSString *ns = nil;
+  NSString *tagURI;
+  NSString *tagPrefix;
+  BOOL     isNodeValid;
+  unsigned i, count;
+  
+  // getting new attributes prefixes and namespaces
+  list = (NSArray *)[_node attributes];
+  list = [self newAttributePrefixesAndNamespaces:list];
+
+  // push new attribute prefixes and namespaces to stack
+  for (i = 0, count = [list count]; i < count; i = i + 2) {
+    [self pushPrefix:[list objectAtIndex:i]
+          namespace:[list objectAtIndex:i+1]];
+  }
+  
+  tagURI       = [_node namespaceURI];
+  tagPrefix    = [_node prefix];
+  isNodeValid  = [self isTagValidInStack:_node];
+  if (!isNodeValid) [self pushPrefix:tagPrefix namespace:tagURI];
+
+  /* needs to declare namespaces !!! */
+  tagName = [_node tagName];
+  if ([[_node prefix] length] > 0) {
+    NSString *p;
+
+    if (!isNodeValid) {
+      ns = [NSString stringWithFormat:@" xmlns:%@=\"%@\"",
+                     tagPrefix,
+                     tagURI];
+    }
+    p       = [_node prefix];
+    p       = [p stringByAppendingString:@":"];
+    tagName = [p stringByAppendingString:tagName];
+  }
+  else if ([tagURI length] > 0) {
+    id   parent;
+    BOOL addNS;
+
+    addNS = YES;
+    if ((parent = [_node parentNode])) {
+      if ([parent nodeType] == DOM_ELEMENT_NODE) {
+        if ([[parent namespaceURI] isEqualToString:tagURI]) {
+          if ([[parent prefix] length] == 0)
+            addNS = NO;
+        }
+      }
+    }
+    else
+      addNS = YES;
+    
+    if (addNS)
+      ns = [NSString stringWithFormat:@" xmlns=\"%@\"", [_node namespaceURI]];
+    else
+      ns = nil;
+  }
+  else
+    ns = nil;
+  
+  if ([_node hasChildNodes]) {
+    [self indentOn:_target];
+    [self write:@"<"    to:_target];
+    [self write:tagName to:_target];
+    if (ns) [self write:ns to:_target];
+    
+    [self outputAttributeNodes:[_node attributes] list:list to:_target];
+    [self write:@">\n"  to:_target];
+
+    self->indent++;
+    [self outputNodeList:[_node childNodes] to:_target];
+    self->indent--;
+
+    [self indentOn:_target];
+    [self write:@"</"   to:_target];
+    [self write:tagName to:_target];
+    [self write:@">\n"  to:_target];
+  }
+  else {
+    [self indentOn:_target];
+    [self write:@"<"    to:_target];
+    [self write:tagName to:_target];
+    [self outputAttributeNodes:[_node attributes] list:list to:_target];
+    [self write:@"/>\n" to:_target];
+  }
+  // pop attributes prefixes and namespaces from stack
+  for (i = 0; i < count; i = i + 2) {
+    [self popPrefixAndNamespace];
+  }
+  if (!isNodeValid) [self popPrefixAndNamespace];
+}
+
+- (void)outputCDATA:(id<DOMCharacterData>)_node to:(id)_target {
+  [self write:@"<![CDATA[" to:_target];
+  [self outputNodeList:[_node childNodes] to:_target];
+  [self write:@"]]>" to:_target];
+}
+
+- (void)outputPI:(id<DOMProcessingInstruction>)_node to:(id)_target {
+  [self indentOn:_target];
+  [self write:@"<?"          to:_target];
+  [self write:[_node target] to:_target];
+  [self write:@" "           to:_target];
+  [self write:[_node data]   to:_target];
+  [self write:@"?>\n"        to:_target];
+}
+
+- (void)outputNode:(id<DOMNode>)_node to:(id)_target {
+  switch ([_node nodeType]) {
+    case DOM_ELEMENT_NODE:
+      [self outputElementNode:(id)_node to:_target];
+      break;
+    case DOM_CDATA_SECTION_NODE:
+      [self outputCDATA:(id)_node to:_target];
+      break;
+    case DOM_PROCESSING_INSTRUCTION_NODE:
+      [self outputPI:(id)_node to:_target];
+      break;
+    case DOM_TEXT_NODE:
+      [self outputTextNode:(id)_node to:_target];
+      break;
+    case DOM_COMMENT_NODE:
+      [self outputCommentNode:(id)_node to:_target];
+      break;
+      
+    default:
+      NSLog(@"cannot output node '%@'", _node);
+      break;
+  }
+}
+- (void)outputNodeList:(id)_nodeList to:(id)_target {
+  id       children;
+  unsigned i, count;
+  
+  children = _nodeList;
+  
+  for (i = 0, count = [children count]; i < count; i++)
+    [self outputNode:[children objectAtIndex:i] to:_target];
+}
+
+- (void)outputDocument:(id)_document to:(id)_target {
+  if (![_document hasChildNodes]) {
+    NSLog(@"ERROR: document has no childnodes !");
+    return;
+  }
+  
+  [self write:@"<?xml version=\"1.0\"?>\n" to:_target];
+  
+  [self->stack removeAllObjects];
+  [self outputNodeList:[_document childNodes] to:_target];
+  
+#if 0
+  NS_DURING {
+  }
+  NS_HANDLER
+    abort();
+  NS_ENDHANDLER;
+#endif
+}
+
+@end /* DOMXMLOutputter */
+
+
+@implementation DOMXMLOutputter(PrefixStack)
+
+- (void)_checkPrefixStack {
+  NSAssert2(([self->stack count] % 2 == 0),
+            @"%s: prefixStack is not valid (%@)!!!",
+            __PRETTY_FUNCTION__,
+            self->stack);
+}
+
+- (NSString *)topPrefix {
+  [self _checkPrefixStack];
+  if ([self->stack count] == 0) return nil;
+  return [self->stack objectAtIndex:[self->stack count] -2];
+}
+
+- (NSString *)topNamespace {
+  [self _checkPrefixStack];
+  if ([self->stack count] == 0) return nil;
+  return [self->stack lastObject];
+}
+
+- (void)pushPrefix:(NSString *)_prefix namespace:(NSString *)_namespace {
+  [self _checkPrefixStack];
+  [self->stack addObject:(_prefix)    ? _prefix    : @""];
+  [self->stack addObject:(_namespace) ? _namespace : @""];
+}
+
+- (void)popPrefixAndNamespace {
+  [self _checkPrefixStack];
+  NSAssert1(([self->stack count] > 0), @"%s: prefixStack.count == 0",
+            __PRETTY_FUNCTION__);
+  [self->stack removeLastObject]; // namespace
+  [self->stack removeLastObject]; // prefix
+}
+
+- (BOOL)isTagValidInStack:(id)_node {
+  NSString *nodeNamespace;
+  NSString *nodePrefix;
+  int      i;
+
+  nodePrefix    = [_node prefix];
+  nodeNamespace = [_node namespaceURI];
+  
+  for (i = [self->stack count]; i >= 2; i = i - 2) {
+    NSString *namespace;
+    NSString *prefix;
+
+    prefix    = [self->stack objectAtIndex:i-2];
+    namespace = [self->stack objectAtIndex:i-1];
+    if ([nodePrefix isEqualToString:prefix] &&
+        [nodeNamespace isEqualToString:namespace])
+      return YES;
+  }
+  return NO;
+}
+
+- (NSArray *)newAttributePrefixesAndNamespaces:(NSArray *)_attrs {
+  NSMutableArray *result;
+  int            i, j, count;
+
+  count = [_attrs count];
+  
+  if (count == 0) return [NSArray array];
+
+  result = [[NSMutableArray alloc] initWithCapacity:count];
+  for (j = 0; j < count; j++) {
+    id       attr;
+    NSString *attrNamespace;
+    NSString *attrPrefix;
+    BOOL     didMatch = NO;
+
+    attr          = [_attrs objectAtIndex:j];
+    attrNamespace = [attr namespaceURI];
+    attrPrefix    = [attr prefix];
+    attrNamespace = (attrNamespace) ? attrNamespace : @"";
+    attrPrefix    = (attrPrefix)    ? attrPrefix    : @"";
+
+    if (([attrNamespace length] == 0 && [attrPrefix length] == 0)) continue;
+    
+    for (i = [self->stack count]; i >= 2; i = i - 2) {
+      NSString *namespace;
+      NSString *prefix;
+
+      prefix    = [self->stack objectAtIndex:i-2];
+      namespace = [self->stack objectAtIndex:i-1];
+      if ([attrPrefix isEqualToString:prefix] &&
+          [attrNamespace isEqualToString:namespace]) {
+        didMatch = YES;
+        break;
+      }
+    }
+    if (didMatch == NO) {
+      [result addObject:attrPrefix];
+      [result addObject:attrNamespace];
+    }
+  }
+  return [result autorelease];
+}
+
+@end /* DOMXMLOutputter(PrefixStack) */
diff --git a/skyrix-xml/DOM/EDOM.h b/skyrix-xml/DOM/EDOM.h
new file mode 100644 (file)
index 0000000..5566b04
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOM_EDOM_H__
+#define __DOM_EDOM_H__
+
+/*
+  Extended Objective-C specific DOM stuff
+*/
+
+#include <DOM/DOM.h>
+#include <DOM/DOMNode+Enum.h>
+#include <DOM/DOMNode+QueryPath.h>
+
+#endif /* __DOM_EDOM_H__ */
+
diff --git a/skyrix-xml/DOM/GNUmakefile b/skyrix-xml/DOM/GNUmakefile
new file mode 100644 (file)
index 0000000..2ae78ba
--- /dev/null
@@ -0,0 +1,103 @@
+# $Id$
+
+include ../common.make
+
+LIBRARY_NAME   = libDOM
+FRAMEWORK_NAME = DOM
+
+libDOM_HEADER_FILES_DIR         = .
+libDOM_HEADER_FILES_INSTALL_DIR = /DOM
+libDOM_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+LDOM_HEADER_FILES += \
+       DOM.h                           \
+       DOMProtocols.h                  \
+       DOMAttribute.h                  \
+       DOMCDATASection.h               \
+       DOMCharacterData.h              \
+       DOMComment.h                    \
+       DOMDocument.h                   \
+       DOMDocumentFragment.h           \
+       DOMDocumentType.h               \
+       DOMElement.h                    \
+       DOMEntity.h                     \
+       DOMEntityReference.h            \
+       DOMImplementation.h             \
+       DOMNode.h                       \
+       DOMNotation.h                   \
+       DOMProcessingInstruction.h      \
+       DOMBuilder.h                    \
+       DOMBuilderFactory.h             \
+
+EDOM_HEADER_FILES += \
+       EDOM.h                          \
+       DOMNode+Enum.h                  \
+       DOMNode+QueryPath.h             \
+       DOMQueryPathExpression.h        \
+
+libDOM_HEADER_FILES = \
+       $(LDOM_HEADER_FILES)            \
+       $(EDOM_HEADER_FILES)            \
+       EDOM.h                          \
+       DOMSaxBuilder.h                 \
+       DOMSaxHandler.h                 \
+       DOMText.h                       \
+       DOMXMLOutputter.h               \
+       DOMPYXOutputter.h               \
+       DOMNodeWalker.h                 \
+       DOMNamedNodeMap.h               \
+
+DOM_CORE_OBJC_FILES = \
+       NSObject+StringValue.m          \
+       DOMAttribute.m                  \
+       DOMCDATASection.m               \
+       DOMCharacterData.m              \
+       DOMComment.m                    \
+       DOMDocument.m                   \
+       DOMElement.m                    \
+       DOMEntity.m                     \
+       DOMEntityReference.m            \
+       DOMImplementation.m             \
+       DOMNode.m                       \
+       DOMNodeWithChildren.m           \
+       DOMNotation.m                   \
+       DOMProcessingInstruction.m      \
+       DOMText.m                       \
+       DOMDocument+factory.m           \
+       DOMDocumentType.m               \
+       DOM+JS.m                        \
+       DOMBuilderFactory.m             \
+
+EDOM_OBJC_FILES = \
+       DOMNode+Enum.m                  \
+       DOMNode+QueryPath.m             \
+       DOMQueryPathExpression.m        \
+       NSObject+QPEval.m               \
+       DOMNode+QPEval.m                \
+
+DOM_TRAVERSAL_OBJC_FILES = \
+       DOMTreeWalker.m                 \
+       DOMNodeFilter.m                 \
+       DOMNodeIterator.m               \
+
+libDOM_OBJC_FILES = \
+       DOMSaxBuilder.m                 \
+       DOMSaxHandler.m                 \
+       DOMXMLOutputter.m               \
+       DOMPYXOutputter.m               \
+       DOMNodeWalker.m                 \
+       NSObject+DOM.m                  \
+       $(EDOM_OBJC_FILES)              \
+       $(DOM_CORE_OBJC_FILES)          \
+       $(DOM_TRAVERSAL_OBJC_FILES)     \
+
+DOM_HEADER_FILES = $(libDOM_HEADER_FILES)
+DOM_OBJC_FILES   = $(libDOM_OBJC_FILES)
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+
+ifeq ($(FOUNDATION_LIB),apple)
+include $(GNUSTEP_MAKEFILES)/framework.make
+endif
+-include GNUmakefile.postamble
diff --git a/skyrix-xml/DOM/GNUmakefile.preamble b/skyrix-xml/DOM/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..e96a26b
--- /dev/null
@@ -0,0 +1,34 @@
+# $Id$
+
+ADDITIONAL_INCLUDE_DIRS += -I.. -I../..
+
+libDOM_LIBRARIES_DEPEND_UPON += -lSaxObjC
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+libDOM_LIB_DIRS += -L$(GNUSTEP_BUILD_DIR)/../SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+libDOM_LIB_DIRS += -L../SaxObjC/$(GNUSTEP_OBJ_DIR)
+endif
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libDOM_PREBIND_ADDR="0xC0200000"
+libDOM_LDFLAGS += -seg1addr $(libDOM_PREBIND_ADDR)
+
+#ADDITIONAL_INCLUDE_DIRS   += -framework SaxObjC
+DOM_FRAMEWORK_LIBS       += -framework SaxObjC
+DOM_LIBRARIES_DEPEND_UPON += -framework SaxObjC
+
+endif
+
+ifeq ($(FOUNDATION_LIB),nx)
+domxml_LDFLAGS += -framework Foundation
+testqp_LDFLAGS += -framework Foundation
+endif
+
+# Windows
+
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+libDOM_LIBRARIES_DEPEND_UPON += -lFoundation -lobjc
+endif
diff --git a/skyrix-xml/DOM/NSObject+DOM.m b/skyrix-xml/DOM/NSObject+DOM.m
new file mode 100644 (file)
index 0000000..889a260
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "common.h"
+
+@implementation NSObject(DOMNode)
+
+- (id)_domNodeBeforeNode:(id)_node {
+  return nil;
+}
+- (id)_domNodeAfterNode:(id)_node {
+  return nil;
+}
+
+- (void)_domNodeForgetParentNode:(id)_parent {
+}
+- (void)_domNodeRegisterParentNode:(id)_parent {
+}
+
+@end /* NSObject(DOMNode) */
diff --git a/skyrix-xml/DOM/NSObject+QPEval.h b/skyrix-xml/DOM/NSObject+QPEval.h
new file mode 100644 (file)
index 0000000..79e9150
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __NSObject_QPEval_H__
+#define __NSObject_QPEval_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+
+@class NSArray;
+
+@interface NSObject(QPEval)
+
+- (NSArray *)evaluateQueryPath:(NSString *)_pc;
+
+@end
+
+@interface NSString(QP)
+
+- (NSArray *)queryPathComponents;
+
+@end
+
+#endif /* __NSObject_QPEval_H__ */
diff --git a/skyrix-xml/DOM/NSObject+QPEval.m b/skyrix-xml/DOM/NSObject+QPEval.m
new file mode 100644 (file)
index 0000000..fd2a2c5
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "NSObject+QPEval.h"
+#include "common.h"
+
+@interface NSObject(QPEvalPrivates)
+
+- (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx;
+- (NSArray *)evaluateQueryPathComponents:(NSArray *)_pcs;
+
+- (void)takeValue:(id)_value forQueryPath:(NSString *)_qp;
+- (id)valueForQueryPath:(NSString *)_qp;
+- (NSException *)setQueryPathValue:(id)_value;
+- (id)queryPathValue;
+
+@end /* NSObject(QPEval) */
+
+
+@implementation NSString(QP)
+
+- (NSArray *)queryPathComponents {
+  NSMutableArray *pc;
+  unsigned i, len, s;
+  
+  if ([self rangeOfString:@"/"].length == 0)
+    return [NSArray arrayWithObject:self];
+  if ([self isEqualToString:@"/"])
+    return [NSArray arrayWithObject:self];
+  
+  pc  = [NSMutableArray arrayWithCapacity:8];
+  len = [self length];
+  i   = 0;
+
+  /* add root, if absolute path */
+  if ([self characterAtIndex:0] == '/') {
+    i++;
+    [pc addObject:@"/"];
+  }
+  
+  for (s = i; i < len; i++) {
+    if ([self characterAtIndex:i] == '/') {
+      unsigned plen;
+      NSString *p;
+      
+      plen = (i - s);
+      p = [self substringWithRange:NSMakeRange(s, plen)];
+      [pc addObject:p];
+      s = (i + 1); /* next component begins at idx right after '/' .. */
+    }
+    else if ([self characterAtIndex:i] == '{') {
+      unsigned j;
+      
+      for (j = (i + 1); j < len; j++) {
+        if ([self characterAtIndex:j] == '}') {
+          /* continue after closing brace .. */
+          i = j;
+          break;
+        }
+      }
+    }
+  }
+  if (s < i) {
+    NSString *p;
+    
+    p = [self substringWithRange:NSMakeRange(s, (i - s))];
+    [pc addObject:p];
+  }
+  
+  return pc;
+}
+
+@end /* NSString(QP) */
+
+@implementation NSObject(QPEval)
+
+/* special expressions */
+
+- (id)queryPathRootObjectInContext:(id)_ctx {
+  return self;
+}
+
+/* query path evaluation */
+
+- (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx {
+  unsigned len;
+  NSArray  *result;
+  
+  result = nil;
+
+  if ((len = [_pc length]) == 0)
+    return nil;
+  else if (len == 1) {
+    unichar c;
+    
+    c = [_pc characterAtIndex:0];
+    if (c == '/') {
+      id root = [self queryPathRootObjectInContext:_ctx];
+      result = root ? [NSArray arrayWithObject:root] : nil;
+    }
+    else if (c == '.')
+      result = [NSArray arrayWithObject:self];
+  }
+  else {
+  }
+  
+  NSLog(@"0x%08X<%@> eval QP '%@': %@", self, NSStringFromClass([self class]),
+        _pc, result);
+  
+  return result;
+}
+
+- (NSArray *)queryPathCursorArray {
+  return [NSArray arrayWithObject:self];
+}
+- (NSArray *)evaluateQueryPathComponents:(NSArray *)_pcs {
+  NSEnumerator      *pcs;
+  NSString          *pc;
+  NSAutoreleasePool *pool;
+  NSArray           *array;
+  NSMutableDictionary *ctx;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  ctx = [NSMutableDictionary dictionaryWithCapacity:16];
+
+  NSLog(@"eval PCs: %@", _pcs);
+  
+  array = [self queryPathCursorArray];
+  
+  pcs = [_pcs objectEnumerator];
+  while ((array != nil) && (pc = [pcs nextObject])) {
+    if ((array = [array evaluateQueryPathComponent:pc inContext:ctx]) == nil)
+      break;
+  }
+  
+  array = [array retain];
+  [pool release];
+  
+  return [array autorelease];
+}
+
+- (NSArray *)evaluateQueryPath:(NSString *)_path {
+  if ([_path rangeOfString:@"/"].length == 0)
+    return [self evaluateQueryPathComponents:[NSArray arrayWithObject:_path]];
+  
+  if ([_path isEqualToString:@"/"]) {
+    static NSArray *rootElem = nil;
+    if (rootElem == nil)
+      rootElem = [NSArray arrayWithObject:@"/"];
+    return [self evaluateQueryPathComponents:rootElem];
+  }
+  
+  return [self evaluateQueryPathComponents:[_path queryPathComponents]];
+}
+
+/* query KVC */
+
+- (NSException *)setQueryPathValue:(id)_value {
+  if (_value == self)
+    return nil;
+  
+  return [NSException exceptionWithName:@"QueryPathEvalException"
+                      reason:@"cannot set query-path value on object"
+                      userInfo:nil];
+}
+- (id)queryPathValue {
+  return self;
+}
+
+- (void)takeValue:(id)_value forQueryPath:(NSString *)_qp {
+  [[[self evaluateQueryPath:_qp] setQueryPathValue:_value] raise];
+}
+- (id)valueForQueryPath:(NSString *)_qp {
+  return [[self evaluateQueryPath:_qp] queryPathValue];
+}
+
+@end /* NSObject(QPEval) */
+
+@implementation NSArray(QPEval)
+
+- (NSArray *)queryPathCursorArray {
+  return self;
+}
+- (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx {
+  unsigned i, j, count;
+  NSArray  *array;
+  id       *objs;
+  
+  if ((count = [self count]) == 0)
+    return [NSArray array];
+  
+  objs = calloc(count + 1, sizeof(id));
+  for (i = 0, j = 0; i < count; i++) {
+    id obj;
+    
+    obj = [self objectAtIndex:i];
+    obj = [obj evaluateQueryPathComponent:_pc inContext:_ctx];
+
+    if (obj) {
+      objs[j] = obj;
+      j++;
+    }
+  }
+  array = [NSArray arrayWithObjects:objs count:j];
+  if (objs) free(objs);
+  return array;
+}
+
+@end /* NSArray(QPEval) */
+
+@implementation NSSet(QPEval)
+
+- (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx {
+  return [[self allObjects] evaluateQueryPathComponent:_pc inContext:(id)_ctx];
+}
+- (NSArray *)evaluateQueryPathComponents:(NSArray *)_pcs {
+  return [[self allObjects] evaluateQueryPathComponents:_pcs];
+}
+
+@end /* NSSet(QPEval) */
diff --git a/skyrix-xml/DOM/NSObject+StringValue.h b/skyrix-xml/DOM/NSObject+StringValue.h
new file mode 100644 (file)
index 0000000..b03c2e3
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __DOM_NSObject_StringValue_H__
+#define __DOM_NSObject_StringValue_H__
+
+#import <Foundation/NSString.h>
+
+@interface NSObject(StringValue)
+- (NSString *)stringValue;
+@end
+
+#endif /* __DOM_NSObject_StringValue_H__ */
diff --git a/skyrix-xml/DOM/NSObject+StringValue.m b/skyrix-xml/DOM/NSObject+StringValue.m
new file mode 100644 (file)
index 0000000..545927a
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "common.h"
+
+@implementation NSObject(StringValue)
+
+- (NSString *)stringValue {
+  return [self description];
+}
+
+@end /* NSObject(StringValue) */
+
+@implementation NSString(StringValue)
+
+- (NSString *)stringValue {
+  return self;
+}
+
+@end /* NSObject(StringValue) */
+
+@implementation NSMutableString(StringValue)
+
+- (NSString *)stringValue {
+  return [[self copy] autorelease];
+}
+
+@end /* NSObject(StringValue) */
diff --git a/skyrix-xml/DOM/README b/skyrix-xml/DOM/README
new file mode 100644 (file)
index 0000000..b4eb458
--- /dev/null
@@ -0,0 +1,58 @@
+# $Id$
+
+How to build a DOM tree ?
+=========================
+
+1. get a factory
+
+  DOMBuilderFactory *factory
+    = [DOMBuilderFactory standardDOMBuilderFactory];
+
+2. get a builder for your resource type
+
+  id<DOMBuilder> builder
+    = [factory createDOMBuilderForMimeType:@"text/xml"];
+
+3. parse what you have:
+
+  id<DOMDocument> document
+    = [builder buildFromSource:@"myfile.xml"];
+
+Some info on classes ...
+========================
+
+Nodes with children
+
+  Document
+  DocumentFragment
+  EntityReference
+  Element
+  Attr
+  Entity
+
+Nodes without children
+
+  DocumentType
+  ProcessingInstruction
+  Comment
+  Text
+  CDATASection
+  Notation
+
+Nodes with parent
+
+  DocumentType
+  EntityReference
+  Element
+  ProcessingInstruction
+  Comment
+  Text
+  CDATASection
+
+Nodes without parent
+
+  Document
+  DocumentFragment
+  Attr
+  Entity
+  Notation
diff --git a/skyrix-xml/DOM/SxXML-DOM.graffle b/skyrix-xml/DOM/SxXML-DOM.graffle
new file mode 100644 (file)
index 0000000..0980bea
--- /dev/null
@@ -0,0 +1,2324 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+       <key>CanvasColor</key>
+       <dict>
+               <key>w</key>
+               <real>1.000000e+00</real>
+       </dict>
+       <key>ColumnAlign</key>
+       <integer>0</integer>
+       <key>ColumnSpacing</key>
+       <real>5.400000e+01</real>
+       <key>GraphDocumentVersion</key>
+       <integer>2</integer>
+       <key>GraphicsList</key>
+       <array>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{14, 14}, {67, 36}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>1404</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\b\fs48 \cf0 DOM}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{18, 549}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1403</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMQueryPathExpression.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMQueryPathExpression}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{18, 342}, {126, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1386</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 DOMCharacterData}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>Group</string>
+                                       <key>Graphics</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{216, 378}, {99, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1388</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMProtocols.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>Rectangle</string>
+                                                       <key>Style</key>
+                                                       <dict>
+                                                               <key>stroke</key>
+                                                               <dict>
+                                                                       <key>Color</key>
+                                                                       <dict>
+                                                                               <key>b</key>
+                                                                               <real>0.000000e+00</real>
+                                                                               <key>g</key>
+                                                                               <real>0.000000e+00</real>
+                                                                               <key>r</key>
+                                                                               <real>1.000000e+00</real>
+                                                                       </dict>
+                                                               </dict>
+                                                       </dict>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 DOMComment}</string>
+                                                       </dict>
+                                               </dict>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{105, 378}, {95, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1389</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMComment.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>Rectangle</string>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMComment}</string>
+                                                       </dict>
+                                               </dict>
+                                               <dict>
+                                                       <key>Class</key>
+                                                       <string>LineGraphic</string>
+                                                       <key>Head</key>
+                                                       <dict>
+                                                               <key>ID</key>
+                                                               <integer>1389</integer>
+                                                       </dict>
+                                                       <key>ID</key>
+                                                       <integer>1390</integer>
+                                                       <key>Points</key>
+                                                       <array>
+                                                               <string>{216, 387}</string>
+                                                               <string>{200, 387}</string>
+                                                       </array>
+                                                       <key>Style</key>
+                                                       <dict>
+                                                               <key>stroke</key>
+                                                               <dict>
+                                                                       <key>Color</key>
+                                                                       <dict>
+                                                                               <key>b</key>
+                                                                               <real>0.000000e+00</real>
+                                                                               <key>g</key>
+                                                                               <real>0.000000e+00</real>
+                                                                               <key>r</key>
+                                                                               <real>1.000000e+00</real>
+                                                                       </dict>
+                                                                       <key>HeadArrow</key>
+                                                                       <string>0</string>
+                                                                       <key>TailArrow</key>
+                                                                       <string>FilledBall</string>
+                                                               </dict>
+                                                       </dict>
+                                                       <key>Tail</key>
+                                                       <dict>
+                                                               <key>ID</key>
+                                                               <integer>1388</integer>
+                                                       </dict>
+                                               </dict>
+                                       </array>
+                                       <key>ID</key>
+                                       <integer>1387</integer>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>Group</string>
+                                       <key>Graphics</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{261, 342}, {126, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1392</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMProtocols.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>Rectangle</string>
+                                                       <key>Style</key>
+                                                       <dict>
+                                                               <key>stroke</key>
+                                                               <dict>
+                                                                       <key>Color</key>
+                                                                       <dict>
+                                                                               <key>b</key>
+                                                                               <real>0.000000e+00</real>
+                                                                               <key>g</key>
+                                                                               <real>0.000000e+00</real>
+                                                                               <key>r</key>
+                                                                               <real>1.000000e+00</real>
+                                                                       </dict>
+                                                               </dict>
+                                                       </dict>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 DOMCDATASection}</string>
+                                                       </dict>
+                                               </dict>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{261, 306}, {124, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1393</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMCDATASection.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>Rectangle</string>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMCDATASection}</string>
+                                                       </dict>
+                                               </dict>
+                                       </array>
+                                       <key>ID</key>
+                                       <integer>1391</integer>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>Group</string>
+                                       <key>Graphics</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{171, 342}, {63, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1395</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMProtocols.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>Rectangle</string>
+                                                       <key>Style</key>
+                                                       <dict>
+                                                               <key>stroke</key>
+                                                               <dict>
+                                                                       <key>Color</key>
+                                                                       <dict>
+                                                                               <key>b</key>
+                                                                               <real>0.000000e+00</real>
+                                                                               <key>g</key>
+                                                                               <real>0.000000e+00</real>
+                                                                               <key>r</key>
+                                                                               <real>1.000000e+00</real>
+                                                                       </dict>
+                                                               </dict>
+                                                       </dict>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 DOMText}</string>
+                                                       </dict>
+                                               </dict>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{171, 306}, {63, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1396</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMText.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>Rectangle</string>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMText}</string>
+                                                       </dict>
+                                               </dict>
+                                       </array>
+                                       <key>ID</key>
+                                       <integer>1394</integer>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{19, 306}, {125, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1397</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMCharacterData.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMCharacterData}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1389</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1398</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{90.375, 324}</string>
+                                               <string>{143.625, 378}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1397</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1393</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1399</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{323.75, 342}</string>
+                                               <string>{323.25, 324}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1392</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1393</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1400</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{234, 315}</string>
+                                               <string>{261, 315}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1396</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1396</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1401</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{202.5, 342}</string>
+                                               <string>{202.5, 324}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1395</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1396</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1402</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{144, 315}</string>
+                                               <string>{171, 315}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1397</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1385</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{22, 108}, {122, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1382</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMDocumentType.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMDocumentType}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{22, 81}, {158, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1383</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMProcessingInstruction.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMProcessingInstruction}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{22, 135}, {122, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1384</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMNotation.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMNotation}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1381</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{252, 36}, {72, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1379</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 DOMNode}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{162, 36}, {72, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1380</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMNode.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMNode}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1378</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{189, 243}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1377</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMEntity.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMEntity}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{18, 522}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1376</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMTreeWalker.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMTreeWalker}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{275, 423}, {81, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1373</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMBuilder.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 DOMBuilder}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{153, 423}, {104, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1374</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMSaxBuilder.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMSaxBuilder}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1374</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1375</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{275, 432}</string>
+                                               <string>{257, 432}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1373</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1372</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{18, 459}, {117, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1370</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMSaxHandler.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMSaxHandler}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{18, 423}, {117, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1371</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxDefaultHandler.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxDefaultHandler}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1369</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{364, 459}, {122, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1367</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMPYXOutputter.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMPYXOutputter}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{364, 486}, {122, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1368</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMXMLOutputter.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMXMLOutputter}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1366</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{365, 639}, {121, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1365</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMImplementation.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMImplementation}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{364, 585}, {122, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1364</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMNodeFilter.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMNodeFilter}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{365, 558}, {121, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1363</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMNodeIterator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMNodeIterator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{372, 189}, {99, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1361</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 DOMElement}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{189, 189}, {167, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1362</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMElement.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMElement}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1360</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{189, 216}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1359</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMEntityReference.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMEntityReference}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{364, 612}, {122, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1358</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMBuilderFactory.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMBuilderFactory}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{372, 270}, {99, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1356</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 DOMDocument}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{189, 270}, {167, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1357</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMDocument.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMDocument}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1355</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{372, 135}, {99, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1353</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 DOMAttr}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{189, 135}, {167, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1354</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMAttribute.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMAttribute}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1352</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{372, 162}, {153, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1350</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMProtocols.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 DOMDocumentFragment}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{189, 162}, {167, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1351</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMDocumentFragment.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMDocumentFragment}</string>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1349</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{288, 90}, {140, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1348</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMNode.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMNodeWithChildren}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{135, 630}, {162, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1343</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMNodeWalker.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMNodePostorderWalker}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{85, 603}, {113, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1344</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMNodeWalker.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMNodeWalker}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{27, 657}, {162, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1345</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/DOM/DOMNodeWalker.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 DOMNodePreorderWalker}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1343</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1346</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{166.333, 621}</string>
+                                               <string>{191.167, 630}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1344</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1345</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1347</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{135.917, 621}</string>
+                                               <string>{113.583, 657}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1344</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1342</integer>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1348</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1341</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{224.667, 54}</string>
+                               <string>{331.333, 90}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1380</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1397</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1340</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{81.125, 342}</string>
+                               <string>{81.375, 324}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1386</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1397</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1339</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{194.117, 54}</string>
+                               <string>{85.3833, 306}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1380</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1382</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1338</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{183.625, 54}</string>
+                               <string>{97.375, 108}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1380</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1380</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1337</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{252, 45}</string>
+                               <string>{234, 45}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1379</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1383</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1336</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{178.6, 54}</string>
+                               <string>{120.4, 81}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1380</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1377</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1335</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{352.971, 108}</string>
+                               <string>{277.529, 243}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1348</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1370</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1334</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{76.5, 441}</string>
+                               <string>{76.5, 459}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1371</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1384</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1333</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{187.545, 54}</string>
+                               <string>{93.4545, 135}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1380</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1362</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1332</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{372, 198}</string>
+                               <string>{356, 198}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1361</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1362</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1331</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{350.227, 108}</string>
+                               <string>{280.273, 189}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1348</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1359</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1330</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{351.893, 108}</string>
+                               <string>{278.607, 216}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1348</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1357</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1329</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{372, 279}</string>
+                               <string>{356, 279}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1356</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1357</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1328</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{353.725, 108}</string>
+                               <string>{276.775, 270}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1348</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1354</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1327</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{372, 144}</string>
+                               <string>{356, 144}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1353</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1354</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1326</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{340.9, 108}</string>
+                               <string>{289.6, 135}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1348</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1351</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1325</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{372, 171}</string>
+                               <string>{356, 171}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1350</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1351</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1324</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{347.312, 108}</string>
+                               <string>{283.188, 162}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1348</integer>
+                       </dict>
+               </dict>
+       </array>
+       <key>GridInfo</key>
+       <dict/>
+       <key>HPages</key>
+       <integer>1</integer>
+       <key>ImageCounter</key>
+       <integer>1</integer>
+       <key>IsPalette</key>
+       <string>NO</string>
+       <key>Layers</key>
+       <array>
+               <dict>
+                       <key>Lock</key>
+                       <string>NO</string>
+                       <key>Name</key>
+                       <string>Layer 1</string>
+                       <key>Print</key>
+                       <string>YES</string>
+                       <key>View</key>
+                       <string>YES</string>
+               </dict>
+       </array>
+       <key>LayoutInfo</key>
+       <dict>
+               <key>AutoAdjust</key>
+               <string>YES</string>
+               <key>HierarchicalOrientation</key>
+               <integer>0</integer>
+               <key>MagneticFieldCenter</key>
+               <string>{0, 0}</string>
+       </dict>
+       <key>MagnetsEnabled</key>
+       <string>YES</string>
+       <key>PageBreakColor</key>
+       <dict>
+               <key>w</key>
+               <real>3.333333e-01</real>
+       </dict>
+       <key>PageBreaks</key>
+       <string>YES</string>
+       <key>PageSetup</key>
+       <data>
+       BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE
+       hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpEpKEhIQITlNT
+       dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE
+       mZkOTlNCb3R0b21NYXJnaW6GkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVlAJSEASqEhAFm
+       nSSGkoSZmQtOU1BhcGVyTmFtZYaShJmZBkxldHRlcoaShJmZD05TUHJpbnRBbGxQYWdl
+       c4aShJ2chIQBc54AhpKEmZkNTlNSaWdodE1hcmdpboaShJ2cn50khpKEmZkITlNDb3Bp
+       ZXOGkoSdnISEAVOfAYaShJmZD05TU2NhbGluZ0ZhY3RvcoaShJ2chIQBZKABhpKEmZkL
+       TlNGaXJzdFBhZ2WGkoSdnKmfAYaShJmZFE5TVmVydGljYWxQYWdpbmF0aW9uhpKEnZyk
+       ngCGkoSZmRVOU0hvcml6b25hbFBhZ2luYXRpb26GkoSdnKSeAIaShJmZFk5TSG9yaXpv
+       bnRhbGx5Q2VudGVyZWSGkoSdnKSeAYaShJmZDE5TTGVmdE1hcmdpboaShJ2cn50khpKE
+       mZkNTlNPcmllbnRhdGlvboaShJ2cpJ4AhpKEmZkZTlNQcmludFJldmVyc2VPcmllbnRh
+       dGlvboaSo5KEmZkKTlNMYXN0UGFnZYaShJ2chJeXgn////+GkoSZmQtOU1RvcE1hcmdp
+       boaShJ2cn50khpKEmZkUTlNWZXJ0aWNhbGx5Q2VudGVyZWSGkrSShJmZC05TUGFwZXJT
+       aXplhpKEnpyEhAx7X05TU2l6ZT1mZn2hgQJkgQMYhoaG
+       </data>
+       <key>RowAlign</key>
+       <integer>0</integer>
+       <key>RowSpacing</key>
+       <real>9.000000e+00</real>
+       <key>VPages</key>
+       <integer>1</integer>
+       <key>WindowInfo</key>
+       <dict>
+               <key>Frame</key>
+               <string>{{137, 41}, {731, 892}}</string>
+               <key>VisibleRegion</key>
+               <string>{{-88, -46.5}, {716, 814.75}}</string>
+               <key>Zoom</key>
+               <string>1</string>
+       </dict>
+</dict>
+</plist>
diff --git a/skyrix-xml/DOM/TODO b/skyrix-xml/DOM/TODO
new file mode 100644 (file)
index 0000000..a617df7
--- /dev/null
@@ -0,0 +1,6 @@
+# $Id: TODO,v 1.1 2003/10/29 12:55:34 helge Exp $
+
+TODOs for DOM
+=============
+
+- add a DOM builder which uses NSXMLParser API
diff --git a/skyrix-xml/DOM/Version b/skyrix-xml/DOM/Version
new file mode 100644 (file)
index 0000000..317960a
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=10
diff --git a/skyrix-xml/DOM/common.h b/skyrix-xml/DOM/common.h
new file mode 100644 (file)
index 0000000..d949a5b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __DOM_common_H__
+#define __DOM_common_H__
+
+#import <Foundation/Foundation.h>
+
+#ifndef ASSIGN
+#  define ASSIGN(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) [__value retain]; \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+
+#endif /* __DOM_common_H__ */
diff --git a/skyrix-xml/ExpatSaxDriver/COPYING b/skyrix-xml/ExpatSaxDriver/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-xml/ExpatSaxDriver/ExpatSaxDriver.m b/skyrix-xml/ExpatSaxDriver/ExpatSaxDriver.m
new file mode 100644 (file)
index 0000000..938f378
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxXMLReader.h>
+#include <SaxObjC/SaxContentHandler.h>
+#include <SaxObjC/SaxDTDHandler.h>
+#include <SaxObjC/SaxErrorHandler.h>
+#include <SaxObjC/SaxEntityResolver.h>
+#include <SaxObjC/SaxLexicalHandler.h>
+#include <SaxObjC/SaxLocator.h>
+#include <SaxObjC/SaxDeclHandler.h>
+#include <expat.h>
+
+@class NSMutableArray, NSMutableDictionary;
+@class SaxAttributes;
+
+@interface ExpatSaxDriver : NSObject < SaxXMLReader >
+{
+@private
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxDTDHandler>     dtdHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+  id<NSObject,SaxEntityResolver> entityResolver;
+  
+  id<NSObject,SaxLexicalHandler> lexicalHandler;
+  id<NSObject,SaxDeclHandler>    declHandler;
+
+  /* expat */
+  XML_Parser expat;
+  
+  /* features */
+  BOOL           fNamespaces;
+  BOOL           fNamespacePrefixes;
+  NSMutableDictionary *declNS;
+
+  /* cached buffers */
+  char     *nameBuf;
+  unsigned nameBufLen;
+  SaxAttributes *attrs;
+}
+
+@end
+
+#include <SaxObjC/SaxException.h>
+#include <SaxObjC/SaxDocumentHandlerAdaptor.h>
+#include "common.h"
+
+static NSString *SaxDeclHandlerProperty =
+  @"http://xml.org/sax/properties/declaration-handler";
+static NSString *SaxLexicalHandlerProperty =
+  @"http://xml.org/sax/properties/lexical-handler";
+#if 0
+static NSString *SaxDOMNodeProperty =
+  @"http://xml.org/sax/properties/dom-node";
+static NSString *SaxXMLStringProperty =
+  @"http://xml.org/sax/properties/xml-string";
+#endif
+
+@interface ExpatSaxDriver(Privates)
+- (BOOL)_setupParser;
+- (void)_tearDownParser;
+@end
+
+static int _UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
+                        unichar **targetStart, const unichar *targetEnd);
+
+typedef struct {
+  NSString *raw;
+  NSString *tag;
+  NSString *uri;
+} TagTriple;
+
+@implementation ExpatSaxDriver
+
+static NSMapTable *uniqueStrings = NULL; // THREAD
+static Class NSStringClass = Nil;
+
+static inline NSString *uniqueStringUTF8(const char *utf8) {
+  NSString *s;
+  char *newkey;
+  
+  if (utf8 == NULL) return nil;
+  
+  if (uniqueStrings == NULL) {
+    uniqueStrings = NSCreateMapTable(NSNonOwnedCStringMapKeyCallBacks,
+                                     NSObjectMapValueCallBacks,
+                                     128);
+  }
+  else if ((s = NSMapGet(uniqueStrings, utf8))) {
+    /* found a string in cache ... */
+    return RETAIN(s);
+  }
+  
+  newkey = malloc(strlen(utf8) + 1);
+  strcpy(newkey, utf8);
+
+  if (NSStringClass == Nil)
+    NSStringClass = [NSString class];
+  
+  s = [[NSStringClass alloc] initWithUTF8String:newkey];
+  NSMapInsert(uniqueStrings, newkey, s);
+  
+  return s;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    /* feature defaults */
+    self->fNamespaces        = YES;
+    self->fNamespacePrefixes = NO;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self _tearDownParser];
+  RELEASE(self->attrs);
+  RELEASE(self->declNS);
+  RELEASE(self->declHandler);
+  RELEASE(self->lexicalHandler);
+  RELEASE(self->contentHandler);
+  RELEASE(self->dtdHandler);
+  RELEASE(self->errorHandler);
+  RELEASE(self->entityResolver);
+  [super dealloc];
+}
+
+/* properties */
+
+- (void)setProperty:(NSString *)_name to:(id)_value {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
+    ASSIGN(self->lexicalHandler, _value);
+    return;
+  }
+  if ([_name isEqualToString:SaxDeclHandlerProperty]) {
+    ASSIGN(self->declHandler, _value);
+    return;
+  }
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+}
+- (id)property:(NSString *)_name {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty])
+    return self->lexicalHandler;
+  if ([_name isEqualToString:SaxDeclHandlerProperty])
+    return self->declHandler;
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+  return nil;
+}
+
+/* features */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value {
+  if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
+    self->fNamespaces = _value;
+    return;
+  }
+  
+  if ([_name isEqualToString:
+               @"http://xml.org/sax/features/namespace-prefixes"]) {
+    self->fNamespacePrefixes = _value;
+    return;
+  }
+
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+}
+- (BOOL)feature:(NSString *)_name {
+  if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
+    return self->fNamespaces;
+  
+  if ([_name isEqualToString:
+               @"http://xml.org/sax/features/namespace-prefixes"])
+    return self->fNamespacePrefixes;
+  
+  if ([_name isEqualToString:
+               @"http://www.skyrix.com/sax/features/predefined-namespaces"])
+    return YES;
+  
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+  return NO;
+}
+
+/* pre-defining namespaces */
+
+- (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri {
+  NSAssert(_prefix, @"invalid prefix ...");
+  NSAssert(_uri,    @"invalid uri ...");
+  
+  if (self->declNS == nil) {
+    self->declNS = [[NSMutableDictionary alloc] initWithCapacity:8];
+    
+    [self->declNS
+         setObject:@"http://www.w3.org/XML/1998/namespace"
+         forKey:@"xml"];
+    [self->declNS setObject:@"" forKey:@":"];
+  }
+  
+  [self->declNS setObject:_uri forKey:_prefix];
+}
+
+/* handlers */
+
+- (void)setDocumentHandler:(id<NSObject,SaxDocumentHandler>)_handler {
+  SaxDocumentHandlerAdaptor *a;
+
+  a = [[SaxDocumentHandlerAdaptor alloc] initWithDocumentHandler:_handler];
+  [self setContentHandler:a];
+  RELEASE(a);
+}
+
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
+  ASSIGN(self->dtdHandler, _handler);
+}
+- (id<NSObject,SaxDTDHandler>)dtdHandler {
+  return self->dtdHandler;
+}
+
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  ASSIGN(self->errorHandler, _handler);
+}
+- (id<NSObject,SaxErrorHandler>)errorHandler {
+  return self->errorHandler;
+}
+
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
+  ASSIGN(self->entityResolver, _handler);
+}
+- (id<NSObject,SaxEntityResolver>)entityResolver {
+  return self->entityResolver;
+}
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  ASSIGN(self->contentHandler, _handler);
+}
+- (id<NSObject,SaxContentHandler>)contentHandler {
+  return self->contentHandler;
+}
+
+/* parsing */
+
+- (void)_reportParseError:(enum XML_Error)_error systemId:(NSString *)_sysId {
+  NSMutableDictionary *ui;
+  NSException *e;
+  NSString    *ename;
+  NSString    *ereason;
+  SEL         sel;
+
+  ename   = @"SaxException";
+  ereason = @"XML parse error";
+  sel     = @selector(fatalError:);
+
+  switch (_error) {
+    case XML_ERROR_NONE: /* no error ... */
+      return;
+    case XML_ERROR_SYNTAX:
+      sel     = @selector(error:);
+      ereason = @"XML syntax error";
+      break;
+    case XML_ERROR_NO_MEMORY:
+      sel     = @selector(fatalError:);
+      ereason = @"out of memory";
+      break;
+    case XML_ERROR_NO_ELEMENTS:
+      sel     = @selector(error:);
+      ereason = @"no elements";
+      break;
+    case XML_ERROR_INVALID_TOKEN:
+      sel     = @selector(error:);
+      ereason = @"invalid token";
+      break;
+    case XML_ERROR_UNCLOSED_TOKEN:
+      sel     = @selector(error:);
+      ereason = @"unclosed token";
+      break;
+    case XML_ERROR_PARTIAL_CHAR:
+      sel     = @selector(error:);
+      ereason = @"partial character";
+      break;
+    case XML_ERROR_TAG_MISMATCH:
+      sel     = @selector(error:);
+      ereason = @"tag mismatch";
+      break;
+    case XML_ERROR_DUPLICATE_ATTRIBUTE:
+      sel     = @selector(error:);
+      ereason = @"duplicate attribute";
+      break;
+    case XML_ERROR_JUNK_AFTER_DOC_ELEMENT:
+      sel     = @selector(warning:);
+      ereason = @"junk after document element";
+      break;
+    case XML_ERROR_PARAM_ENTITY_REF:
+      sel     = @selector(error:);
+      ereason = @"parameter entity reference";
+      break;
+    case XML_ERROR_UNDEFINED_ENTITY:
+      sel     = @selector(error:);
+      ereason = @"undefined entity";
+      break;
+    case XML_ERROR_RECURSIVE_ENTITY_REF:
+      sel     = @selector(error:);
+      ereason = @"recursive entity reference";
+      break;
+    case XML_ERROR_ASYNC_ENTITY:
+      sel     = @selector(error:);
+      ereason = @"async entity";
+      break;
+    case XML_ERROR_BAD_CHAR_REF:
+      sel     = @selector(error:);
+      ereason = @"bad character reference";
+      break;
+    case XML_ERROR_BINARY_ENTITY_REF:
+      sel     = @selector(error:);
+      ereason = @"binary entity reference";
+      break;
+    case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF:
+      sel     = @selector(error:);
+      ereason = @"attibute external entity reference";
+      break;
+    case XML_ERROR_MISPLACED_XML_PI:
+      sel     = @selector(error:);
+      ereason = @"misplaced processing instruction";
+      break;
+    case XML_ERROR_UNKNOWN_ENCODING:
+      sel     = @selector(error:);
+      ereason = @"unknown encoding";
+      break;
+    case XML_ERROR_INCORRECT_ENCODING:
+      sel     = @selector(error:);
+      ereason = @"incorrect encoding";
+      break;
+    case XML_ERROR_UNCLOSED_CDATA_SECTION:
+      sel     = @selector(error:);
+      ereason = @"unclosed CDATA section";
+      break;
+    case XML_ERROR_EXTERNAL_ENTITY_HANDLING:
+      sel     = @selector(error:);
+      ereason = @"external entity handling";
+      break;
+    case XML_ERROR_NOT_STANDALONE:
+      sel     = @selector(error:);
+      ereason = @"XML is not standalone";
+      break;
+    case XML_ERROR_UNEXPECTED_STATE:
+      sel     = @selector(fatalError:);
+      ereason = @"unexpected status";
+      break;
+  }
+  
+  ui = [NSMutableDictionary dictionaryWithCapacity:4];
+  
+  if (_sysId) [ui setObject:_sysId forKey:@"systemId"];
+  [ui setObject:self forKey:@"parser"];
+  if (self->expat) {
+    int line;
+    
+    if ((line = XML_GetCurrentLineNumber(self->expat)) > 0)
+      [ui setObject:[NSNumber numberWithInt:line] forKey:@"line"];
+  }
+  [ui setObject:[NSNumber numberWithUnsignedInt:_error]
+      forKey:@"expatErrorCode"];
+  
+  e = (id)[SaxParseException exceptionWithName:ename
+                             reason:ereason
+                             userInfo:ui];
+  
+  [self->errorHandler performSelector:sel withObject:e];
+}
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
+  if (_source == nil) {
+    /* no source ??? */
+    return;
+  }
+
+  if ([_source isKindOfClass:[NSData class]]) {
+    if ([self _setupParser]) {
+      NSAutoreleasePool *pool;
+      
+      pool = [[NSAutoreleasePool alloc] init];
+      {
+        int res;
+
+        [self->contentHandler startDocument];
+        res = XML_Parse(self->expat, [_source bytes], [_source length], 1);
+        
+        if (res == 0) {
+          [self _reportParseError:XML_GetErrorCode(self->expat)
+                systemId:_sysId];
+        }
+        [self->contentHandler endDocument];
+      }
+      RELEASE(pool);
+      [self _tearDownParser];
+    }
+  }
+  else if ([_source isKindOfClass:[NSString class]]) {
+    [self parseFromSource:
+            [_source dataUsingEncoding:NSUTF8StringEncoding]
+          systemId:_sysId];
+  }
+  else if ([_source isKindOfClass:[NSURL class]]) {
+    if (_sysId == nil)
+      _sysId = [_source absoluteString];
+    
+    [self parseFromSource:[_source resourceDataUsingCache:NO]
+          systemId:_sysId];
+  }
+  else
+    [self parseFromSource:[_source stringValue] systemId:_sysId];
+}
+
+- (void)parseFromSource:(id)_source {
+  [self parseFromSource:_source systemId:nil];
+}
+
+- (void)parseFromSystemId:(NSString *)_sysId {
+  if (![_sysId hasPrefix:@"file:"]) {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    NSURL *url;
+    
+    if ((url = [NSURL URLWithString:_sysId]))
+      return [self parseFromSource:url systemId:_sysId];
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _sysId ? _sysId : @"<nil>", @"systemID",
+                         self,                       @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"can't handle system-id"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+    return;
+  }
+  else {
+    NSData *data;
+    
+    _sysId = [_sysId substringFromIndex:7];
+    
+    if ((data = [NSData dataWithContentsOfMappedFile:_sysId]) == nil) {
+      NSLog(@"couldn't load file '%@'", _sysId);
+      return;
+    }
+    
+    return [self parseFromSource:data systemId:_sysId];
+  }
+}
+
+/* expat */
+
+static TagTriple splitName(ExpatSaxDriver *self, const char *el) {
+  TagTriple t;
+  char      *el_tag;
+  char      *buf;
+  unsigned  len;
+  
+  if ((len = strlen(el)) == 0) {
+    t.raw = @"";
+    t.tag = @"";
+    t.uri = nil;
+    return t;
+  }
+  
+  if (len >= self->nameBufLen) {
+    if (self->nameBuf) free(self->nameBuf);
+    self->nameBuf    = malloc(len + 8);
+    self->nameBufLen = len + 6;
+  }
+  buf = self->nameBuf;
+  
+  strcpy(buf, el);
+  buf[len] = '\0';
+  
+  t.raw = uniqueStringUTF8(el);
+  
+  if ((el_tag = index(buf, '\t'))) {
+    unsigned idx;
+    
+    t.tag = uniqueStringUTF8(el_tag + 1);
+    
+    idx   = [t.raw rangeOfString:@"\t"].location;
+    t.uri = [[t.raw substringToIndex:idx] copy];
+  }
+  else if ((self->declNS != nil) && ((el_tag = index(buf, ':')) != NULL)) {
+    /* check predefined namespaces ... */
+    NSString *prefix;
+    
+    *el_tag = '\0';
+    prefix = uniqueStringUTF8(buf);
+    
+    if ((t.uri = [self->declNS objectForKey:prefix])) {
+      t.tag = uniqueStringUTF8(el_tag + 1);
+      t.uri = [t.uri copy];
+    }
+    else {
+      t.uri = nil;
+      t.tag = [t.raw copy];
+    }
+
+    RELEASE(prefix);
+  }
+  else {
+    t.uri = nil;
+    t.tag = [t.raw copy];
+  }
+  
+  return t;
+}
+static void releaseTag(TagTriple t) {
+  RELEASE(t.raw);
+  RELEASE(t.tag);
+  RELEASE(t.uri);
+}
+
+static void _startElem(void *data, const char *el, const char **attr) {
+  ExpatSaxDriver *self = (ExpatSaxDriver *)data;
+  TagTriple     t;
+  unsigned      i;
+  
+  t     = splitName(self, el);
+  
+  /* process attributes */
+  
+  if (self->attrs == nil)
+    self->attrs = [[SaxAttributes alloc] init];
+  else
+    [self->attrs clear];
+  if (NSStringClass == Nil) NSStringClass = [NSString class];
+  
+  for (i = 0; attr[i] != NULL; i += 2) {
+    TagTriple at;
+    NSString *value;
+    
+    at    = splitName(self, attr[i]);
+    value = [[NSStringClass alloc] initWithUTF8String:attr[i + 1]];
+    
+    [self->attrs
+         addAttribute:at.tag
+         uri:at.uri ? at.uri : t.uri
+         rawName:at.raw
+         type:@"CDATA" value:value];
+
+    releaseTag(at);
+    RELEASE(value);
+  }
+  
+  /* notify handler ... */
+  
+  [self->contentHandler
+       startElement:t.tag namespace:t.uri rawName:t.raw
+       attributes:self->attrs];
+  
+  releaseTag(t);
+  [self->attrs clear];
+}
+static void _endElem(void *data, const char *el) {
+  ExpatSaxDriver *self = (ExpatSaxDriver *)data;
+  TagTriple  t;
+  
+  t = splitName(self, el);
+  
+  [self->contentHandler endElement:t.tag namespace:t.uri rawName:t.raw];
+  
+  releaseTag(t);
+}
+
+static void _startNS(void *data, const char *_prefix, const char *_uri) {
+  ExpatSaxDriver *self = (ExpatSaxDriver *)data;
+  NSString *spre, *suri;
+  
+  spre = _prefix ? uniqueStringUTF8(_prefix) : @"";
+  suri = _uri    ? uniqueStringUTF8(_uri)    : @"";
+  [self->contentHandler startPrefixMapping:spre uri:suri];
+  RELEASE(suri);
+  RELEASE(spre);
+}
+static void _endNS(void *data, const char *_prefix) {
+  ExpatSaxDriver *self = (ExpatSaxDriver *)data;
+  NSString *spre;
+  
+  spre = _prefix ? uniqueStringUTF8(_prefix) : @"";
+  [self->contentHandler endPrefixMapping:spre];
+  RELEASE(spre);
+}
+
+static void _characters(void *_data, const char *chars, int len) {
+  ExpatSaxDriver *self = (ExpatSaxDriver *)_data;
+  void *data, *ts;
+  
+  if (len == 0) {
+    unichar c = 0;
+    data = &c;
+    [self->contentHandler characters:data length:len];
+    return;
+  }
+  if (chars == NULL) {
+    [self->contentHandler characters:NULL length:0];
+    return;
+  }
+  
+  data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
+  
+  if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
+                   (void *)&ts, ts + (len * sizeof(unichar)))) {
+    free(data);
+    NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
+          __PRETTY_FUNCTION__, __LINE__);
+  }
+  else {
+    [self->contentHandler characters:data length:(unsigned)(ts - data)];
+    free(data);
+  }
+}
+
+static void _pi(void *_udata, const char *_target, const char *_data) {
+  ExpatSaxDriver *self = (ExpatSaxDriver *)_udata;
+  NSString *target, *data;
+  
+  target = uniqueStringUTF8(_target);
+  data   = uniqueStringUTF8(_data);
+  [self->contentHandler processingInstruction:target data:data];
+  RELEASE(target);
+  RELEASE(data);
+}
+
+static void _comment(void *_data, const char *chars) {
+  ExpatSaxDriver *self = (ExpatSaxDriver *)_data;
+  void *data, *ts;
+  unsigned len;
+  
+  len = strlen(chars);
+  
+  if (len == 0) {
+    unichar c = 0;
+    data = &c;
+    [self->lexicalHandler comment:data length:0];
+    return;
+  }
+  if (chars == NULL) {
+    [self->lexicalHandler comment:NULL length:0];
+    return;
+  }
+  
+  data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
+  
+  if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
+                   (void *)&ts, ts + (len * sizeof(unichar)))) {
+    free(data);
+    NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
+          __PRETTY_FUNCTION__, __LINE__);
+  }
+  else {
+    [self->lexicalHandler comment:data length:(ts - data)];
+    free(data);
+  }
+}
+
+static void _startCDATA(void *data) {
+}
+static void _endCDATA(void *data) {
+}
+
+- (BOOL)_setupParser {
+  [self _tearDownParser];
+  
+  if ((self->expat = XML_ParserCreateNS(NULL, '\t')) == NULL) {
+#if DEBUG
+    NSLog(@"%s: couldn't create expat parser ..", __PRETTY_FUNCTION__);
+#endif
+    return NO;
+  }
+  
+  XML_SetUserData(self->expat, self);
+  XML_SetReturnNSTriplet(self->expat, 1); /* also return NS prefix */
+  
+  if (self->contentHandler) {
+    XML_SetElementHandler(self->expat, _startElem, _endElem);
+    XML_SetNamespaceDeclHandler(self->expat, _startNS, _endNS);
+    
+    XML_SetCharacterDataHandler(self->expat, _characters);
+    XML_SetProcessingInstructionHandler(self->expat, _pi);
+    
+    XML_SetCdataSectionHandler(self->expat, _startCDATA, _endCDATA);
+  }
+  
+  if (self->lexicalHandler) {
+    XML_SetCommentHandler(self->expat, _comment);
+  }
+
+  return YES;
+}
+
+- (void)_tearDownParser {
+  if (self->expat) {
+    XML_ParserFree(self->expat);
+    self->expat = NULL;
+  }
+  if (self->nameBuf) {
+    free(self->nameBuf);
+    self->nameBuf    = NULL;
+    self->nameBufLen = 0;
+  }
+}
+
+@end /* ExpatSaxDriver */
+
+#include "unicode.h"
diff --git a/skyrix-xml/ExpatSaxDriver/GNUmakefile b/skyrix-xml/ExpatSaxDriver/GNUmakefile
new file mode 100644 (file)
index 0000000..70b8831
--- /dev/null
@@ -0,0 +1,37 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+BUNDLE_NAME        = ExpatSaxDriver
+BUNDLE_EXTENSION   = .sax
+BUNDLE_INSTALL_DIR = $(GNUSTEP_USER_ROOT)/Library/Bundles
+
+ExpatSaxDriver_OBJC_FILES = \
+       ExpatSaxDriver.m        \
+
+ExpatSaxDriver_BUNDLE_LIBS += -lSaxObjC -lexpat
+
+ExpatSaxDriver_RESOURCE_FILES = bundle-info.plist
+
+ADDITIONAL_INCLUDE_DIRS += -I../.. -I..
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_BUILD_DIR)/../SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += -L../SaxObjC/$(GNUSTEP_OBJ_DIR)
+endif
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
diff --git a/skyrix-xml/ExpatSaxDriver/README b/skyrix-xml/ExpatSaxDriver/README
new file mode 100644 (file)
index 0000000..c5fc27c
--- /dev/null
@@ -0,0 +1,7 @@
+# $Id$
+
+ExpatSaxDriver
+==============
+
+This directory contains the sources for a SAX driver bundle which works on top
+of the Expat XML processing library.
diff --git a/skyrix-xml/ExpatSaxDriver/bundle-info.plist b/skyrix-xml/ExpatSaxDriver/bundle-info.plist
new file mode 100644 (file)
index 0000000..cec64e1
--- /dev/null
@@ -0,0 +1,23 @@
+{
+  CVS = "$Id: bundle-info.plist,v 1.1.1.1 2003/07/09 22:57:27 cvs Exp $";
+  //bundleHandler = NSObject;
+
+  requires = {
+    bundleManagerVersion = 1;
+    classes = (
+      { name = NSObject;    }
+    );
+  };
+
+  provides = {
+    SAXDrivers = ( 
+        { 
+          name        = ExpatSaxDriver;
+          sourceTypes = ( "text/xml" ); 
+        },
+    );
+    classes    = ( 
+        { name = ExpatSaxDriver;     },
+    );
+  };
+}
diff --git a/skyrix-xml/ExpatSaxDriver/common.h b/skyrix-xml/ExpatSaxDriver/common.h
new file mode 100644 (file)
index 0000000..0016e58
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+
diff --git a/skyrix-xml/ExpatSaxDriver/unicode.h b/skyrix-xml/ExpatSaxDriver/unicode.h
new file mode 100644 (file)
index 0000000..73350ca
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+/* Unicode support */
+
+typedef unsigned long  UCS4;
+typedef unsigned short UCS2;
+typedef unsigned short UTF16;
+typedef unsigned char  UTF8;
+#define unichar UTF16
+
+static const int halfShift             = 10;
+static const UCS4 halfBase             = 0x0010000UL;
+static const UCS4 halfMask             = 0x3FFUL;
+static const UCS4 kSurrogateHighStart  = 0xD800UL;
+static const UCS4 kSurrogateHighEnd    = 0xDBFFUL;
+static const UCS4 kSurrogateLowStart   = 0xDC00UL;
+static const UCS4 kSurrogateLowEnd     = 0xDFFFUL;
+
+static const UCS4 kReplacementCharacter = 0x0000FFFDUL;
+static const UCS4 kMaximumUCS2          = 0x0000FFFFUL;
+static const UCS4 kMaximumUTF16         = 0x0010FFFFUL;
+static const UCS4 kMaximumUCS4          = 0x7FFFFFFFUL;
+
+static UCS4 offsetsFromUTF8[6] = {
+  0x00000000UL, 0x00003080UL, 0x000E2080UL, 
+  0x03C82080UL, 0xFA082080UL, 0x82082080UL
+};
+static char bytesFromUTF8[256] = {
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+static int
+_UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
+             unichar **targetStart, const unichar *targetEnd)
+{
+  int            result = 0;
+  register UTF8  *source = *sourceStart;
+  register UTF16 *target = *targetStart;
+  
+  while (source < sourceEnd) {
+    register UCS4 ch = 0;
+    register unsigned short extraBytesToWrite = bytesFromUTF8[*source];
+    
+    if (source + extraBytesToWrite > sourceEnd) {
+      result = 1; break;
+    };
+    switch(extraBytesToWrite) { /* note: code falls through cases! */
+      case 5:   ch += *source++; ch <<= 6;
+      case 4:   ch += *source++; ch <<= 6;
+      case 3:   ch += *source++; ch <<= 6;
+      case 2:   ch += *source++; ch <<= 6;
+      case 1:   ch += *source++; ch <<= 6;
+      case 0:   ch += *source++;
+    };
+    ch -= offsetsFromUTF8[extraBytesToWrite];
+
+    if (target >= targetEnd) {
+      result = 2; break;
+    };
+    if (ch <= kMaximumUCS2) {
+      *target++ = ch;
+    } else if (ch > kMaximumUTF16) {
+      *target++ = kReplacementCharacter;
+    } else {
+      if (target + 1 >= targetEnd) {
+        result = 2; break;
+      };
+      ch -= halfBase;
+      *target++ = (ch >> halfShift) + kSurrogateHighStart;
+      *target++ = (ch & halfMask) + kSurrogateLowStart;
+    };
+  };
+  *sourceStart = source;
+  *targetStart = target;
+  return result;
+}
diff --git a/skyrix-xml/GNUmakefile b/skyrix-xml/GNUmakefile
new file mode 100644 (file)
index 0000000..b17f4e2
--- /dev/null
@@ -0,0 +1,20 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+PACKAGE_NAME=skyrix-xml
+VERSION=4.2.0
+
+SUBPROJECTS = \
+       SaxObjC         \
+       DOM             \
+       libxmlSAXDriver \
+       STXSaxDriver    \
+       XmlRpc          \
+       samples         \
+
+ifeq ($(FOUNDATION_LIB), apple)
+# no makefile yet: SUBPROJECTS += CFXMLSaxDriver
+endif
+
+include $(GNUSTEP_MAKEFILES)/aggregate.make
diff --git a/skyrix-xml/PROJECTLEAD b/skyrix-xml/PROJECTLEAD
new file mode 100644 (file)
index 0000000..ab0c70a
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+PROJECTLEAD=helge.hess@opengroupware.org
diff --git a/skyrix-xml/PlistSaxDriver/GNUmakefile b/skyrix-xml/PlistSaxDriver/GNUmakefile
new file mode 100644 (file)
index 0000000..c4a22e9
--- /dev/null
@@ -0,0 +1,37 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+BUNDLE_NAME        = PlistSaxDriver
+BUNDLE_EXTENSION   = .sax
+BUNDLE_INSTALL_DIR = $(GNUSTEP_USER_ROOT)/Library/Bundles
+
+PlistSaxDriver_OBJC_FILES = \
+       PlistSaxDriver.m        \
+
+PlistSaxDriver_BUNDLE_LIBS += -lSaxObjC
+
+PlistSaxDriver_RESOURCE_FILES = bundle-info.plist
+
+ADDITIONAL_INCLUDE_DIRS += -I../.. -I..
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_BUILD_DIR)/../SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += -L../SaxObjC/$(GNUSTEP_OBJ_DIR)
+endif
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
diff --git a/skyrix-xml/PlistSaxDriver/PlistSaxDriver.m b/skyrix-xml/PlistSaxDriver/PlistSaxDriver.m
new file mode 100644 (file)
index 0000000..98706c1
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxXMLReader.h>
+#include <SaxObjC/SaxContentHandler.h>
+#include <SaxObjC/SaxDTDHandler.h>
+#include <SaxObjC/SaxErrorHandler.h>
+#include <SaxObjC/SaxEntityResolver.h>
+#include <SaxObjC/SaxLexicalHandler.h>
+#include <SaxObjC/SaxLocator.h>
+#include <SaxObjC/SaxDeclHandler.h>
+#include <expat.h>
+
+@class NSMutableArray, NSMutableDictionary;
+@class SaxAttributes;
+
+@interface PlistSaxDriver : NSObject < SaxXMLReader >
+{
+@private
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+
+  /* features */
+  BOOL     fNamespaces;
+  BOOL     fNamespacePrefixes;
+  NSString *plistNamespace;
+}
+
+@end
+
+#include <SaxObjC/SaxException.h>
+#include <SaxObjC/SaxDocumentHandlerAdaptor.h>
+#include <NGExtensions/NGExtensions.h>
+#include "common.h"
+
+@interface NSObject(Walking)
+- (void)_walkWithPlistSaxDriver:(PlistSaxDriver *)_driver;
+@end
+
+@interface PlistSaxDriver(Privates)
+- (void)_walkDictionary:(NSDictionary *)_dict;
+- (void)_walkArray:(NSArray *)_dict;
+- (void)_walkData:(NSData *)_dict;
+- (void)_walkString:(NSString *)_dict;
+@end
+
+@implementation PlistSaxDriver
+
+- (void)dealloc {
+  RELEASE(self->contentHandler);
+  RELEASE(self->errorHandler);
+  [super dealloc];
+}
+
+/* properties */
+
+- (void)setProperty:(NSString *)_name to:(id)_value {
+  return;
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+}
+- (id)property:(NSString *)_name {
+  return nil;
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+  return nil;
+}
+
+/* features */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value {
+  if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
+    self->fNamespaces = _value;
+    return;
+  }
+  
+  if ([_name isEqualToString:
+               @"http://xml.org/sax/features/namespace-prefixes"]) {
+    self->fNamespacePrefixes = _value;
+    return;
+  }
+
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+}
+- (BOOL)feature:(NSString *)_name {
+  if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
+    return self->fNamespaces;
+  
+  if ([_name isEqualToString:
+               @"http://xml.org/sax/features/namespace-prefixes"])
+    return self->fNamespacePrefixes;
+  
+  if ([_name isEqualToString:
+               @"http://www.skyrix.com/sax/features/predefined-namespaces"])
+    return NO;
+  
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+  return NO;
+}
+
+/* handlers */
+
+- (void)setDocumentHandler:(id<NSObject,SaxDocumentHandler>)_handler {
+  SaxDocumentHandlerAdaptor *a;
+  
+  a = [[SaxDocumentHandlerAdaptor alloc] initWithDocumentHandler:_handler];
+  [self setContentHandler:a];
+  RELEASE(a);
+}
+
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
+}
+- (id<NSObject,SaxDTDHandler>)dtdHandler {
+  return nil;
+}
+
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  ASSIGN(self->errorHandler, _handler);
+}
+- (id<NSObject,SaxErrorHandler>)errorHandler {
+  return self->errorHandler;
+}
+
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
+}
+- (id<NSObject,SaxEntityResolver>)entityResolver {
+  return nil;
+}
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  ASSIGN(self->contentHandler, _handler);
+}
+- (id<NSObject,SaxContentHandler>)contentHandler {
+  return self->contentHandler;
+}
+
+/* walking the list */
+
+- (NSString *)plistNamespace {
+  return nil;
+}
+
+- (void)_writeString:(id)_s {
+  unsigned len;
+  
+  _s = [_s stringValue];
+  if ((len = [_s length]) == 0) return;
+  
+  if (len == 1) {
+    unichar c[2];
+    [_s getCharacters:&(c[0])];
+    c[1] = '\0';
+    [self->contentHandler characters:&(c[0]) length:1];
+  }
+  else {
+    unichar *ca;
+
+    ca = calloc(len + 1, sizeof(unichar));
+    [_s getCharacters:ca];
+    ca[len] = 0;
+    [self->contentHandler characters:ca length:len];
+    if (ca) free(ca);
+  }
+}
+
+- (void)_walkDictionary:(NSDictionary *)_dict {
+  NSEnumerator *keys;
+  id key;
+
+  if (_dict == nil) return;
+  
+  [self->contentHandler
+       startElement:@"dict" namespace:self->plistNamespace
+       rawName:@"dict"
+       attributes:nil];
+  
+  keys = [_dict keyEnumerator];
+  while ((key = [keys nextObject])) {
+    id value;
+    
+    value = [_dict objectForKey:key];
+    
+    [self->contentHandler
+         startElement:@"key" namespace:self->plistNamespace
+         rawName:@"key"
+         attributes:nil];
+
+    [self _writeString:key];
+    
+    [self->contentHandler
+         endElement:@"key" namespace:self->plistNamespace
+         rawName:@"key"];
+    
+    [value _walkWithPlistSaxDriver:self];
+  }
+  
+  [self->contentHandler
+       endElement:@"dict" namespace:self->plistNamespace
+       rawName:@"dict"];
+}
+
+- (void)_walkArray:(NSArray *)_array {
+  unsigned i, count;
+
+  if (_array == nil) return;
+  
+  [self->contentHandler
+       startElement:@"array" namespace:self->plistNamespace
+       rawName:@"array"
+       attributes:nil];
+  
+  for (i = 0, count = [_array count]; i < count; i++)
+    [[_array objectAtIndex:i] _walkWithPlistSaxDriver:self];
+  
+  [self->contentHandler
+       endElement:@"array" namespace:self->plistNamespace
+       rawName:@"array"];
+}
+
+- (void)_walkData:(NSData *)_data {
+  NSString *s;
+  if (_data == nil) return;
+  
+  s = [[NSString alloc] initWithData:[_data dataByEncodingBase64]
+                        encoding:NSUTF8StringEncoding];
+  AUTORELEASE(s);
+  
+  [self->contentHandler
+       startElement:@"data" namespace:self->plistNamespace
+       rawName:@"data"
+       attributes:nil];
+  
+  [self _writeString:s];
+  
+  [self->contentHandler
+       endElement:@"data" namespace:self->plistNamespace
+       rawName:@"data"];
+}
+
+- (void)_walkString:(NSString *)_s {
+  if (_s == nil) return;
+  
+  [self->contentHandler
+       startElement:@"string" namespace:self->plistNamespace
+       rawName:@"string"
+       attributes:nil];
+
+  [self _writeString:_s];
+
+  [self->contentHandler
+       endElement:@"string" namespace:self->plistNamespace
+       rawName:@"string"];
+}
+
+- (void)_walkRoot:(id)_plist {
+  static SaxAttributes *versionAttr = nil;
+
+  if (versionAttr == nil) {
+    versionAttr = [[SaxAttributes alloc] init];
+    [versionAttr addAttribute:@"version" uri:self->plistNamespace
+                 rawName:@"version"
+                 type:@"CDATA"
+                 value:@"0.9"];
+  }
+  
+  [self->contentHandler startDocument];
+  
+  [self->contentHandler
+       startElement:@"plist" namespace:self->plistNamespace
+       rawName:@"plist"
+       attributes:versionAttr];
+  
+  [_plist _walkWithPlistSaxDriver:self];
+  
+  [self->contentHandler
+       endElement:@"plist" namespace:self->plistNamespace
+       rawName:@"plist"];
+  
+  [self->contentHandler endDocument];
+}
+
+/* parsing ... */
+
+- (void)_parseFromString:(NSString *)_str systemId:(NSString *)_sysId {
+  id plist;
+  
+  if ((plist = [_str propertyList])) {
+    [self _walkRoot:plist];
+  }
+  else if (self->errorHandler) {
+    /* log parse error */
+    SaxParseException *e;
+    NSDictionary *ui;
+
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _sysId, @"systemId",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SAXError"
+                               reason:@"couldn't parse property list"
+                               userInfo:ui];
+    
+    [self->errorHandler error:e];
+  }
+}
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
+  NSAutoreleasePool *pool;
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  if ([_source isKindOfClass:[NSData class]]) {
+    NSString *s;
+
+    s = [[NSString alloc] initWithData:_source
+                          encoding:[NSString defaultCStringEncoding]];
+    AUTORELEASE(s);
+    
+    [self _parseFromString:s systemId:_sysId];
+  }
+  else if ([_source isKindOfClass:[NSURL class]]) {
+    [self parseFromSystemId:_source];
+  }
+  else if ([_source isKindOfClass:[NSString class]]) {
+    if (_sysId == nil) _sysId = @"<string>";
+    [self _parseFromString:_source systemId:_sysId];
+  }
+  else if ([_source isKindOfClass:[NSDictionary class]]) {
+    if (_sysId == nil) _sysId = @"<dictionary>";
+    [_source _walkRoot:self];
+  }
+  else if ([_source isKindOfClass:[NSArray class]]) {
+    if (_sysId == nil) _sysId = @"<array>";
+    [_source _walkRoot:self];
+  }
+  else {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _source ? _source : @"<nil>", @"source",
+                         self,                         @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"can't handle data-source"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+  }
+  
+  RELEASE(pool);
+}
+- (void)parseFromSource:(id)_source {
+  [self parseFromSource:_source systemId:@"<memory>"];
+}
+
+- (void)parseFromSystemId:(NSString *)_sysId {
+  NSAutoreleasePool *pool;
+  NSString *str;
+  NSURL    *url;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  url = [NSURL URLWithString:_sysId];
+  str = [NSString stringWithContentsOfURL:url];
+  
+  [self _parseFromString:str systemId:_sysId];
+  
+  RELEASE(pool);
+}
+
+@end /* PlistSaxDriver */
+
+@implementation NSDictionary(Walking)
+- (void)_walkWithPlistSaxDriver:(PlistSaxDriver *)_driver {
+  [_driver _walkDictionary:self];
+}
+@end
+
+@implementation NSArray(Walking)
+- (void)_walkWithPlistSaxDriver:(PlistSaxDriver *)_driver {
+  [_driver _walkArray:self];
+}
+@end
+
+@implementation NSSet(Walking)
+- (void)_walkWithPlistSaxDriver:(PlistSaxDriver *)_driver {
+  [_driver _walkArray:[self allObjects]];
+}
+@end
+
+@implementation NSData(Walking)
+- (void)_walkWithPlistSaxDriver:(PlistSaxDriver *)_driver {
+  [_driver _walkData:self];
+}
+@end
+
+@implementation NSString(Walking)
+- (void)_walkWithPlistSaxDriver:(PlistSaxDriver *)_driver {
+  [_driver _walkString:self];
+}
+@end
+
+@implementation NSObject(Walking)
+- (void)_walkWithPlistSaxDriver:(PlistSaxDriver *)_driver {
+  [_driver _walkString:[self stringValue]];
+}
+@end
diff --git a/skyrix-xml/PlistSaxDriver/README b/skyrix-xml/PlistSaxDriver/README
new file mode 100644 (file)
index 0000000..176f766
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+PlistSaxDriver
+==============
+
+This directory contains the sources for a SAX driver bundle which can read
+"old-style" property list files. It reports the parsing events in the XML
+format of "new-style" XML property-list.
+
+This one is experimental and more a technology demo than a practical 
+application ! Feel free to extend it and submit changes ;-)
diff --git a/skyrix-xml/PlistSaxDriver/bundle-info.plist b/skyrix-xml/PlistSaxDriver/bundle-info.plist
new file mode 100644 (file)
index 0000000..ec74507
--- /dev/null
@@ -0,0 +1,23 @@
+{
+  CVS = "$Id: bundle-info.plist,v 1.1.1.1 2003/07/09 22:57:27 cvs Exp $";
+  //bundleHandler = NSObject;
+
+  requires = {
+    bundleManagerVersion = 1;
+    classes = (
+      { name = NSObject;    }
+    );
+  };
+
+  provides = {
+    SAXDrivers = ( 
+        { 
+          name        = PlistSaxDriver;
+          sourceTypes = ( "application/x-plist" ); 
+        },
+    );
+    classes    = ( 
+        { name = PlistSaxDriver;     },
+    );
+  };
+}
diff --git a/skyrix-xml/README b/skyrix-xml/README
new file mode 100644 (file)
index 0000000..a991618
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id$
+
+SKYRiX Libraries for XML Processing
+===================================
+
+This directory contains libraries for processing XML files and other tagged
+file formats like HTML, iCalendar, PYX or STX using Objective-C.
+
+For more information, please follow up on the webpage:
+  http://www.opengroupware.org/en/devs/sope/skyrix_xml/
diff --git a/skyrix-xml/README-OSX.txt b/skyrix-xml/README-OSX.txt
new file mode 100644 (file)
index 0000000..aa6a19f
--- /dev/null
@@ -0,0 +1,124 @@
+# $Id$
+
+Building Notes
+==============
+
+Prerequisites:
+- Apple Developer Tools
+
+There are two ways to build SOPE on MacOSX, either using the gnustep-make
+package or as native Xcode projects. The first option is usually used when
+you build SOPE for use with OGo, while the latter is more appropriate for
+SOPE:X applications.
+
+Building using gstep-make:
+==========================
+
+First install gnustep-make (eg v1.8), then ensure that GNUstep.sh is properly
+sources. For the build just enter:
+  make -s install
+or
+  make -s debug=yes install
+if you build with debug informations.
+
+Building using Xcode:
+=====================
+
+The Xcode build comes in two variants, one for development and the other for
+deployment.
+
+
+Development
+-----------
+Development usually means you're happily hacking away at your pet
+projects and sometimes want to update the SOPE frameworks. For this purpose
+use the "all" target and the accompanied "Development" build style. Later,
+you can narrow the target down to something more specific. For development we
+assume the destination for frameworks to be /Library/Frameworks. Once you are
+done building all the frameworks the loader commands of the frameworks will
+have that destination path built in. In order to use the frameworks you either
+have to install them (by copying them manually to their destination) or to
+prepare symlinks from /Library/Frameworks to the place where the built products
+are. I usually build everything in a central place (i.e. /Local/BuildArea) and
+have symlinks from /Library/Frameworks to /Local/BuildArea for each of the
+products.
+
+Also the following products are expected to be in the following locations:
+*.sax -> /Library/SaxDrivers
+*.sxp -> /Library/SoProducts
+
+Either copy them to the appropriate places or symlink them (my suggestion).
+
+
+Deployment
+----------
+Deployment in our terms means you want to copy all required SOPE products into
+an application's app wrapper. For this step all frameworks need to be built in
+a special fashion, as the "install_name" of the frameworks needs to be prepared
+to point to a relative path in the app wrapper. The situation is even more
+complicated as all frameworks during linking store the "install names" of other
+frameworks in their mach loader commands. In order for this step not to break
+we need to set up an environment which is clearly separated from the
+Development environment. I chose to use $(USER_LIBRARY_DIR)/EmbeddedFrameworks
+as the default destination for these builds. In order for your application to
+easily pick up the built products and copy them into its app wrapper this
+location needs to be fixed and easily accessible. Note that on my system
+~/Library/EmbeddedFrameworks is a symlink to /Library/EmbeddedFrameworks so
+even if you don't like the location at all it's very easy to point it to 
+somewhere else. As soon as you have set this up you can use the
+"Wrapper Contents" target with the accompanied "Wrapper" build style to build
+all wrapper contents in the appropriate fashion. When you're done you can copy
+all the wrapper products into your application's wrapper. The expected
+destination is the "Frameworks" directory in the wrappers "Contents" directory.
+For a complete list of what you need to copy into your application's wrapper
+see the "Direct Dependencies" of all "Wrapper Contents" targets in all SOPE
+related projects. At the time of this writing the complete list for SxXML
+consisted of the following:
+
+SxXML
+  SaxObjC.framework
+  DOM.framework
+  XmlRpc.framework
+
+Note: "A word on umbrellas"
+      The general idea of umbrellas is to make life easier by providing a cover
+      for linking. In an ideal world we would provide a SOPE umbrella (we 
+      actually do that) and you just link against that and forget about the
+      complete list. However, with the "Wrapper" style things do not work that
+      way. Because the "install name"s of all frameworks are relative paths,
+      during linking the mach dyld cannot find the dependend frameworks
+      (because the path isn't absolute) and thus symbol checking fails. This
+      directly leads to prebinding to fail which we really don't want since we
+      have such a huge dependency tree and prebinding escpecially in our case
+      speeds up loading significantly. So, umbrellas do not really help with
+      "Wrapper" products - in fact they just add to the overall dependency
+      graph without providing any benefit. With the notable exception of the
+      "Development" build style umbrellas are totally useless. If you're
+      not planning to do a "Wrapper" deployment you might be happy to have
+      the umbrellas, however, that's why they are still here.
+
+Note: You cannot use the -buildAllTargets commandline argument for Xcode,
+      because the Xcode projects also contain a target to build in the
+      gstep-make environment (called GSM:all)
+
+
+Prebinding Notes
+================
+
+General technical information about prebinding is available from Apple at
+http://developer.apple.com/documentation/Performance/Conceptual/LaunchTime/Tasks/Prebinding.html#//apple_ref/doc/uid/20001858.
+
+OGo frameworks currently use the range from 0xC0000000 to 0xCFFFFFFF.
+
+Any questions and feedback regarding our use of this range should go to
+Marcus Müller <znek@mulle-kybernetik.com>.
+
+
+SxXML: 0xC0000000 - 0xC0FFFFFF
+==============================
+
+0xC0000000 SaxObjC
+0xC0200000 DOM
+0xC0400000 XmlRpc
+0xC0FF0000 SxXML
+                   
\ No newline at end of file
diff --git a/skyrix-xml/STXSaxDriver/.cvsignore b/skyrix-xml/STXSaxDriver/.cvsignore
new file mode 100644 (file)
index 0000000..2ab00d4
--- /dev/null
@@ -0,0 +1,2 @@
+shared_debug_obj
+STXSaxDriver.sax
diff --git a/skyrix-xml/STXSaxDriver/COPYING.LIB b/skyrix-xml/STXSaxDriver/COPYING.LIB
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-xml/STXSaxDriver/COPYRIGHT b/skyrix-xml/STXSaxDriver/COPYRIGHT
new file mode 100644 (file)
index 0000000..ef4e3fe
--- /dev/null
@@ -0,0 +1,33 @@
+# $Id$
+
+Structured Text Code
+Copyright (C) 2004 eXtrapola Srl
+Contact: marco.barulli@extrapola.com
+
+SAX Driver Classes
+Copyright (C) 2004 Helge Hess
+Contact: helge.hess@opengroupware.org
+
+
+Statement by Extrapola SRL (Marco Barulli)
+==========================================
+
+I'm glad to confirm that eXtrapola Srl, as the copyright holder on the 
+StructuredText code sent to the OpenGroupware.org project and initially 
+written by Mirko Viviani and Giulio Cesare Solaroli, hereby states that the 
+code is licensed and can be used under the terms of the Lesser General Public 
+License.
+
+Statement by Mirko Viviani
+==========================
+
+Mirko Viviani, as the original author of the StructuredText framework sent to 
+the OpenGroupware.org project, hereby states that the code is licensed and can
+be used under the terms of the Lesser General Public License.
+
+Statement by Giulio Cesare Solaroli
+===================================
+
+I, as one of the original author on the StructuredText code sent to the 
+OpenGroupware.org project, hereby states that the code is licensed and can be 
+used under the terms of the Lesser General Public License.
diff --git a/skyrix-xml/STXSaxDriver/ChangeLog b/skyrix-xml/STXSaxDriver/ChangeLog
new file mode 100644 (file)
index 0000000..8fc2a36
--- /dev/null
@@ -0,0 +1,204 @@
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile.preamble, GNUmakefile.postamble: added support for
+         building with GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v1.0.6)
+
+2004-03-16  Helge Hess  <helge.hess@opengroupware.org>
+
+       * bundle-info.plist: fixed a type in the bundle-info.plist (v1.0.5)
+
+2004-03-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * STXSaxDriver.m: fixed a bug with header generation (header 
+         subelements did not properly generate) (v1.0.4)
+
+       * STXSaxDriver.m: added proper error handling for missing files 
+         (v1.0.3)
+
+2004-03-04  Helge Hess  <helge.hess@opengroupware.org>
+
+       * ExtraSTX/StructuredText.m: applied a bugfix on the header processing
+         by Mirko (v1.0.2)
+
+2004-02-29  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v1.0.1
+
+       * initial import of the SAX driver into OpenGroupware.org - many thanks
+         go to extrapola for contributing the STX framework to OGo
+       
+       * removed things unnecessary for the SAX driver
+       
+       * replace some -rangeOfString: NSNotFound checks which do not work with
+         libFoundation (need to check for range.length==0 instead!)
+       
+       * added the STXSaxDriver, an application of the StructuredText code
+       
+       * reformatted code according to OGo styleguides
+       
+2004-02-15  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredTextBodyElement.m: implementato link image ed escaping 
+         stile C.
+       
+       * NSString_StructuredText_Extra.m: implementato escaping di stringhe.
+
+2004-02-10  Giulio Cesare Solaroli  <gc.solaroli@extrapola.com>
+
+       * Aggiunti alcuni test per la verifica della gestione dei link
+         attorno alle immagini.
+
+2004-01-16  Giulio Cesare Solaroli  <gc.solaroli@extrapola.com>
+
+       * Aggiunto un test (test__characterEscaping) che fallisce, mostrando
+         un problema nella gestione nell'escape dei caratteri.
+
+2004-01-13  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredText.m ([-separateIntoBlocks]): ignora linee contenente
+         solo spazi o tab.
+
+2004-01-12  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredText.m ([-separateIntoBlocks]): rimuove \r dal testo.
+
+2004-01-08  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredText.subproj/StructuredTextBodyElement.m: fix del link 
+         target.
+
+2003-12-19  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredText.subproj/StructuredTextBodyElement.m: aggiunto
+         riconoscimento chiavi dinamiche.
+
+       * StructuredTextRenderingDelegate.h: aggiunto metodo chiamato per 
+         chiavi dinamiche.
+
+2003-12-18  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredTextRenderingDelegate.m ([-insertPreprocessedTextForKey:
+         inContext:]): metodo chiamato dal preprocessore per sostituire le
+         chiavi.
+
+       * StructuredText.subproj/StructuredTextBodyElement.m: implementato
+         preprocessore.
+
+2003-12-16  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * Test.subproj/Test_StructuredText.m: aggiunto test per link Extrapola.
+
+       * StructuredTextRenderingDelegate.h: corretto metodo per link Extrapola
+         e aggiunto parametro target al link.
+
+       * StructuredText.subproj/StructuredTextBodyElement.m: implementato link
+         Extrapola.
+
+2003-12-11  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredText.subproj/StructuredTextHeader.m: implementato rendering
+         con delegate.
+
+       * StructuredText.subproj/StructuredTextListItem.m: come sopra.
+
+       * StructuredText.subproj/StructuredTextBodyElement.m: Spostato il 
+         parser da StructuredTextParagraph.
+
+2003-12-08  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredText.subproj/StructuredTextParagraph.m: implementati link.
+
+       * Test.subproj/StructuredText_TEST.m ([StructuredTextListItem
+         -toTestInContext:]): fix per liste nidificate.
+       
+       * StructuredText_XHTML.m ([StructuredTextListItem -toXhtmlInContext:]):
+         come sopra.
+
+       * Test.subproj/Test_StructuredText.m: corretti vari tests.
+
+       * StructuredLine.m ([-setText:]): setta correttamente il numero di 
+         spazi iniziali.
+
+       * StructuredText.m ([-buildList], [-checkForListItem:]): implementata
+         lista numerata.
+         ([-adjustLineLevels]): setta i livelli correttamente anche per liste.
+         ([-lineType]): fix per liste.
+         ([-checkForListItem]): spostato codice in listItemTypology:
+         ([-buildList]): fix per liste nidificate.
+
+       * StructuredStack.m ([-pop]): posiziona correttamente il cursore.
+
+
+2003-12-08  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredText.subproj/StructuredTextParagraph.m
+       ([-parseText:inContext:]): modificato in metodo ricorsivo. Implementato
+       bold, underline e italico.
+       ([-findBoldSubstring:]: Ricerca terminatore stringa in grassetto.
+       ([-findItalicsSubstring:]: Ricerca terminatore stringa in italico.
+       ([-findUnderlineSubstring:]:  Ricerca terminatore stringa in
+       sottolineato.
+       ([-boldText:inContext]): formatta il testo con il delegato.
+       ([-italicsText:inContext]): come sopra.
+       ([-underlineText:inContext]): come sopra.
+
+2003-12-05  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredText_XHTML.m ([StructuredTextListItem -toXhtmlInContext]):
+         fix per list item.
+
+       * StructuredText.m ([-buildLiteralBlock]): aggiunto newline a fine
+         riga.
+
+2003-12-04  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredText.subproj/StructuredTextHeader.m: modificato
+         inizializzatore per settare il livello dell'header. Vari fix.
+
+       * StructuredText.m: implementate le liste di tipo DEFINITION, i blocchi
+         preformattati e gli header.
+
+       * StructuredLine.m ([-setText:]: setta il testo originale.
+         ([-text]): ritorna il testo privo di spazi iniziali/finali e newline.
+         ([-originalText]): ritorna il testo originale.
+
+       * StructuredText.subproj/StructuredTextLiteralBlock.m
+         ([-initWithString:]: inizializza il blocco.
+
+       * StructuredText.subproj/StructuredTextListItem.m: aggiunto testo del
+         list item per i tipi DEFINITION.
+
+       * StructuredStack.m ([-objectRelativeToCursorAtIndex:]: ritorna
+         l'oggetto con un indice relativo alla posizione corrente del cursore.
+
+2003-12-01  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredText.subproj/StructuredTextBodyElement.m: metodi per la
+         gestione degli elementi figli.
+
+       * StructuredText.m: fix delle strutture di stack, una (paragraphs) per
+         la gestione delle linee di testo da processare, l'altra (stack) per 
+         la posizione nell'albero del documento.
+
+       * StructuredStack.m ([StructuredStack -currentObject], [StructuredStack
+         -nextObject]): fix per fine array.
+
+       * StructuredText.subproj/StructuredTextList.h: fix typo.
+
+       * StructuredText.subproj/StructuredTextListItem.m.|.h: inizializzazione
+         e settaggio lista di appartenenza. _list non deve essere rilasciato.
+
+2003-11-27  Mirko Viviani  <mirko.viviani@e-cremona.it>
+
+       * StructuredTextRenderingDelegate.m ([StructuredTextRenderingDelegate
+         -insertExtrapolaLink:withAction:parameters:inContext:]): uso di
+         NSStringFromClass() per ottenere nome di classe.
+
+       * StructuredText.subproj/StructuredTextParagraph.m: inizializzazione e
+         minimo uso del delegate per il test.
+
+       * StructuredText.subproj/StructuredTextDocument.m|.h
+         ([-addBodyElement]): aggiunge un elemento al documento.
+
+       * PB.project, GSmakefile, Makefile: Aggiunto framework IBNExtensions
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/.cvsignore b/skyrix-xml/STXSaxDriver/ExtraSTX/.cvsignore
new file mode 100644 (file)
index 0000000..52c916d
--- /dev/null
@@ -0,0 +1 @@
+Resources
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/COPYRIGHT b/skyrix-xml/STXSaxDriver/ExtraSTX/COPYRIGHT
new file mode 100644 (file)
index 0000000..cee7d8e
--- /dev/null
@@ -0,0 +1,29 @@
+# $Id$
+
+Structured Text Code
+Copyright (C) 2004 eXtrapola Srl
+Contact: marco.barulli@extrapola.com
+
+
+Statement by Extrapola SRL (Marco Barulli)
+==========================================
+
+I'm glad to confirm that eXtrapola Srl, as the copyright holder on the 
+StructuredText code sent to the OpenGroupware.org project and initially 
+written by Mirko Viviani and Giulio Cesare Solaroli, hereby states that the 
+code is licensed and can be used under the terms of the Lesser General Public 
+License.
+
+Statement by Mirko Viviani
+==========================
+
+Mirko Viviani, as the original author of the StructuredText framework sent to 
+the OpenGroupware.org project, hereby states that the code is licensed and can
+be used under the terms of the Lesser General Public License.
+
+Statement by Giulio Cesare Solaroli
+===================================
+
+I, as one of the original author on the StructuredText code sent to the 
+OpenGroupware.org project, hereby states that the code is licensed and can be 
+used under the terms of the Lesser General Public License.
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/GNUmakefile b/skyrix-xml/STXSaxDriver/ExtraSTX/GNUmakefile
new file mode 100644 (file)
index 0000000..c6db857
--- /dev/null
@@ -0,0 +1,17 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = ExtraSTX
+
+ExtraSTX_OBJC_FILES = \
+       NSString+STX.m          \
+       StructuredLine.m        \
+       StructuredStack.m       \
+       StructuredText.m        \
+
+ADDITIONAL_INCLUDE_DIRS += -I. -I../Model -I..
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/NSString+STX.h b/skyrix-xml/STXSaxDriver/ExtraSTX/NSString+STX.h
new file mode 100644 (file)
index 0000000..21732ac
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#ifndef __NSString_STX_H__
+#define __NSString_STX_H__
+
+#import <Foundation/Foundation.h>
+#import "StructuredText.h"
+
+@interface NSString(STX)
+
+- (StructuredText *)structuredText;
+- (NSString *)unescapedString;
+
+@end
+
+#endif /* __NSString_STX_H__ */
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/NSString+STX.m b/skyrix-xml/STXSaxDriver/ExtraSTX/NSString+STX.m
new file mode 100644 (file)
index 0000000..ed7fecd
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "NSString+STX.h"
+#include "common.h"
+
+@implementation NSString(STX)
+
+- (StructuredText *)structuredText {
+  return [[[StructuredText alloc] initWithString:self] autorelease];
+}
+
+- (NSString *)unescapedString {
+  NSMutableString *result;
+  NSString        *text;
+  int             i, start, length;
+  NSRange         range;
+  
+  result = [NSMutableString stringWithCapacity:[self length]];
+
+  text = self;
+  length = [text length];
+
+  for (i = start = 0; i < length; i++) {
+    unichar c;
+
+    c = [text characterAtIndex:i];
+
+    if (c == '\\') {
+      if (i - start > 0) {
+       range.location = start;
+       range.length = i - start;
+
+       [result appendString:[text substringWithRange:range]];
+      }
+
+      if (i + 1 < length) {
+       c = [text characterAtIndex:i + 1];
+
+       if (c == '\\') {
+         start = ++i;
+       }
+      }
+    }
+  }
+
+  if (i - start > 0) {
+    range.location = start;
+    range.length = i - start;
+
+    [result appendString:[text substringWithRange:range]];
+  }
+
+  return result;
+}
+
+@end /* NSString(STX) */
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/README b/skyrix-xml/STXSaxDriver/ExtraSTX/README
new file mode 100644 (file)
index 0000000..96438cd
--- /dev/null
@@ -0,0 +1,47 @@
+# $Id$
+
+How to use
+==========
+
+1. get a string in structured text format:
+   NSString *s = "a\nb\nc"
+
+2. parse it into "StructuredText" object:
+     StructuredText *stx = [s structuredText];
+   or:
+     StructuredText *stx = [[StructuredText alloc] initWithString:s];
+
+3. render the object, eg using -toXhtmlInContext:
+
+Defaults
+========
+
+STXDebugEnabled YES|NO
+
+Links
+=====
+
+http://www.zope.org/Members/millejoh/structuredText
+http://plone.org/documentation/howto/FrontPage/UsingStructuredText
+
+Classes
+=======
+
+  NSObject
+    StructuredLine
+    StructuredStack
+    StructuredText
+    StructuredTextRenderingDelegate
+      StructuredTextRenderingDelegate_XHTML
+
+  NSString(NSString_StructuredText_Extra)
+
+  NSArray(StructuredText_XHTML)
+  StructuredText(StructuredText_XHTML)
+  StructuredTextDocument(StructuredText_XHTML)
+  StructuredTextBodyElement(StructuredText_XHTML)
+  StructuredTextHeader(StructuredText_XHTML)
+  StructuredTextParagraph(StructuredText_XHTML)
+  StructuredTextList(StructuredText_XHTML)
+  StructuredTextListItem(StructuredText_XHTML)
+  StructuredTextLiteralBlock(StructuredText_XHTML)
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredLine.h b/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredLine.h
new file mode 100644 (file)
index 0000000..bd4b7ce
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+
+@interface StructuredLine : NSObject
+{
+  NSString *_text;
+  NSString *_originalText;
+  int      numberOfSpaces;
+  int      level;
+}
+
+- (id)initWithString:(NSString *)aString level:(int)level;
+
+/* accessors */
+
+- (NSString *)text;
+- (NSString *)originalText;
+- (void)setText:(NSString *)aString;
+
+- (int)level;
+- (void)setLevel:(int)aLevel;
+
+- (int)numberOfSpacesAtBeginning;
+
+@end
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredLine.m b/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredLine.m
new file mode 100644 (file)
index 0000000..7de7a33
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#import "StructuredLine.h"
+#include "common.h"
+
+@implementation StructuredLine
+
+- (id)initWithString:(NSString *)aString level:(int)aLevel {
+  if ((self = [super init])) {
+    [self setText:aString];
+    level = aLevel;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->_text         release];
+  [self->_originalText release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)text {
+  NSMutableString *result;
+  NSArray *components;
+  int i, count;
+  
+  if (self->_text)
+    return self->_text;
+
+  result     = [NSMutableString stringWithCapacity:16];
+  components = [_originalText componentsSeparatedByString:@"\n"];
+  count      = [components count];
+
+  for (i = 0; i < count; i++) {
+    NSString *s;
+    
+    if (i > 0)
+      [result appendString:@" "];
+    
+    s = [components objectAtIndex:i];
+    s = [s stringByTrimmingCharactersInSet:
+            [NSCharacterSet whitespaceCharacterSet]];
+    [result appendString:s];
+  }
+  
+  self->_text = [result copy];
+  return self->_text;
+}
+
+- (NSString *)originalText {
+  return self->_originalText;
+}
+
+- (void)setText:(NSString *)aString {
+  BOOL     running = YES;
+  int      i, length;
+  NSString *ptr;
+  
+  numberOfSpaces = 0;
+  length = [aString length];
+  
+  for (i = 0; i < length; i++) {
+    switch (([aString characterAtIndex:i])) {
+    case ' ':
+    case 0x09:
+      break;
+
+    default:
+      running = NO;
+      break;
+    }
+    
+    if (!running)
+      break;
+  }
+
+  if (running)
+    return;
+  
+  numberOfSpaces = i;
+
+  ptr = _originalText;
+  self->_originalText = [aString retain];
+
+  [ptr release];
+  [self->_text release]; self->_text = nil;
+}
+
+- (void)setLevel:(int)aLevel {
+  level = aLevel;
+}
+- (int)level {
+  return level;
+}
+
+- (int)numberOfSpacesAtBeginning {
+  return numberOfSpaces;
+}
+
+@end /* StructuredLine */
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredStack.h b/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredStack.h
new file mode 100644 (file)
index 0000000..92f6b63
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#import <Foundation/Foundation.h>
+
+@interface StructuredStack : NSObject
+{
+  NSMutableArray *_stack;
+
+  int           start;
+  int           pos;
+
+  BOOL          cursorFIFO;
+}
+
+- (NSMutableArray *)stack;
+
+- (void)removeAllObjects;
+
+- (void)push:(id)anObject;
+- (id)pop;
+
+- (void)first;
+- (void)last;
+
+- (id)nextObject;
+- (id)currentObject;
+- (id)prevObject;
+
+- (BOOL)cursorFollowsFIFO;
+- (void)setCursorFollowsFIFO:(BOOL)aValue;
+
+- (id)objectRelativeToCursorAtIndex:(int)anIndex;
+
+@end
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredStack.m b/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredStack.m
new file mode 100644 (file)
index 0000000..23fefff
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#import "StructuredStack.h"
+#include "common.h"
+
+@implementation StructuredStack
+
+- (void)dealloc {
+  [self->_stack release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSMutableArray *)stack {
+  if (self->_stack == nil)
+    // TODO: find a proper capacity
+    self->_stack = [[NSMutableArray alloc] initWithCapacity:16];
+
+  return _stack;
+}
+
+/* operations */
+
+- (void)removeAllObjects {
+  [[self stack] removeAllObjects];
+  [self first];
+}
+
+- (void)push:(id)anObject {
+  NSMutableArray *stack;
+  
+  if (anObject == nil)
+    return;
+  
+  stack = [self stack];
+  [stack addObject:anObject];
+  
+  if (![self cursorFollowsFIFO])
+    return;
+
+  self->start = NO;
+  self->pos   = ([stack count] - 1);
+}
+
+- (id)pop {
+  NSMutableArray *stack;
+  int count;
+  id object;
+
+  object = nil;
+
+  stack = [self stack];
+  count = [stack count];
+  
+  if (count > 0) {
+    object = [stack objectAtIndex:--count];
+
+    [stack removeLastObject];
+  }
+
+  if ([self cursorFollowsFIFO]) {
+    start = NO;
+    pos = count - 1;
+  }
+
+  return object;
+}
+
+- (void)first {
+  pos = 0;
+  start = YES;
+}
+- (void)last {
+  pos = [[self stack] count];
+  start = NO;
+}
+
+/* enumerator */
+
+- (id)nextObject {
+  NSMutableArray *stack;
+  int count;
+
+  stack = [self stack];
+  count = [stack count];
+
+  if (count == 0 || pos >= count) {
+    return nil;
+  }
+
+  if (self->start) {
+    self->start = NO;
+  } 
+  else {
+    pos++;
+
+    if (pos >= count)
+      return nil;
+  }
+
+  return [stack objectAtIndex:pos];
+}
+
+- (id)currentObject {
+  NSMutableArray *stack;
+  int count;
+
+  stack = [self stack];
+  count = [stack count];
+
+  if (count == 0 || pos >= count)
+    return nil;
+  
+  self->start = NO;
+
+  return [[self stack] objectAtIndex:pos];
+}
+
+- (id)prevObject {
+  NSMutableArray *stack;
+  id result;
+
+  stack = [self stack];
+  
+  result = ((start || pos == 0) && [stack count])
+    ? nil
+    : [stack objectAtIndex:--pos];
+  return result;
+}
+
+- (void)setCursorFollowsFIFO:(BOOL)aValue {
+  self->cursorFIFO = aValue;
+}
+- (BOOL)cursorFollowsFIFO {
+  return self->cursorFIFO;
+}
+
+- (id)objectRelativeToCursorAtIndex:(int)anIndex {
+  NSMutableArray *stack;
+  int i, count;
+
+  stack = [self stack];
+  count = [stack count];
+
+  i = pos + anIndex;
+
+  if (count == 0 || i < 0 || i >= count)
+    return nil;
+  
+  return [[self stack] objectAtIndex:i];
+}
+
+@end /* StructuredStack */
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText.h b/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText.h
new file mode 100644 (file)
index 0000000..bc997be
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#ifndef __StructuredText_H__
+#define __StructuredText_H__
+
+#import <Foundation/NSObject.h>
+#include "StructuredTextDocument.h"
+
+@class NSString, NSMutableString;
+@class StructuredLine, StructuredStack;
+@class StructuredTextHeader, StructuredTextParagraph, StructuredTextList;
+@class StructuredTextListItem, StructuredTextLiteralBlock;
+
+#define StructuredTextParserLine_Header       0
+#define StructuredTextParserLine_Paragraph    1
+#define StructuredTextParserLine_List         2
+#define StructuredTextParserLine_LiteralBlock 3
+
+@interface StructuredText : NSObject
+{
+  NSString              *_text;
+  StructuredTextDocument *_document;
+  StructuredStack       *_stack;
+
+  StructuredStack       *_paragraphs;
+
+#if DISABLE_BUG_FIX
+  int                   currentHeaderLevel;
+#endif
+}
+
++ (StructuredTextDocument *)parseText:(NSString *)_txt;
+- (id)initWithString:(NSString *)_str;
+
+/* accessors */
+
+- (NSString *)text;
+- (StructuredTextDocument *)document;
+- (StructuredStack *)stack;
+- (StructuredStack *)paragraphs;
+
+/* parsing */
+
+- (void)parse;
+
+- (int)lineType:(StructuredLine *)_line;
+
+- (void)separateIntoBlocks;
+- (void)adjustLineLevels;
+- (void)buildDocument;
+
+- (BOOL)checkForHeader:(StructuredLine *)_line;
+- (BOOL)checkForListItem:(StructuredLine *)_line;
+- (BOOL)checkForPreformattedStatement:(StructuredLine *)_line;
+- (BOOL)checkForPreformattedBlock:(StructuredLine *)_line;
+
+- (StructuredTextHeader *)buildHeader;
+- (StructuredTextParagraph *)buildParagraph;
+- (StructuredTextLiteralBlock *)buildLiteralBlock;
+- (StructuredTextList *)buildList;
+
+- (int)listItemTypology:(StructuredLine *)_line;
+
+@end
+
+#endif /* __StructuredText_H__ */
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText.m b/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText.m
new file mode 100644 (file)
index 0000000..3b91299
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "StructuredText.h"
+#include "StructuredLine.h"
+#include "StructuredStack.h"
+
+#include "StructuredTextHeader.h"
+#include "StructuredTextParagraph.h"
+#include "StructuredTextList.h"
+#include "StructuredTextListItem.h"
+#include "StructuredTextLiteralBlock.h"
+
+#include "common.h"
+#include <ctype.h>
+
+@implementation StructuredText
+
+- (id)initWithString:(NSString *)_str {
+  if ((self = [super init])) {
+    self->_text = [_str copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->_text       release];
+  [self->_document   release];
+  [self->_stack      release];
+  [self->_paragraphs release];
+  [super dealloc];
+}
+
+/* factory */
+
++ (StructuredTextDocument *)parseText:(NSString *)aText {
+  StructuredText *text;
+  
+  // TODO: shouldn't we release the object?
+  text = [[StructuredText alloc] initWithString:aText];
+  
+  return [text document];
+}
+
+/* accessors */
+
+- (NSString *)text {
+  return _text;
+}
+
+- (StructuredTextDocument *)document {
+  if (self->_document)
+    return self->_document;
+
+  self->_document = [[StructuredTextDocument alloc] init];
+  [self parse];
+  return _document;
+}
+
+- (StructuredStack *)stack {
+  if (self->_stack == nil)
+    self->_stack = [[StructuredStack alloc] init];
+  
+  return self->_stack;
+}
+
+- (StructuredStack *)paragraphs {
+  if (self->_paragraphs == nil)
+    self->_paragraphs = [[StructuredStack alloc] init];
+  
+  return self->_paragraphs;
+}
+
+- (void)parse {
+#if DISABLE_BUG_FIX
+  currentHeaderLevel = 1;
+#endif
+  
+  [self separateIntoBlocks];
+  [self adjustLineLevels];
+  [self buildDocument];
+}
+
+- (void)separateIntoBlocks {
+  NSArray        *lines;
+  StructuredStack *pars;
+  NSString       *text, *currentLine, *trimmedLine;
+  NSMutableString *buf;
+  NSCharacterSet  *set;
+  int i, count;
+  
+  set   = [NSCharacterSet characterSetWithCharactersInString:@"\r"];
+  buf   = [NSMutableString stringWithCapacity:256];
+  text  = [self text];
+  pars  = [self paragraphs];
+
+  lines = [text componentsSeparatedByString:@"\n"];
+  count = [lines count];
+  
+  for (i = 0; i < count; i++) {
+    currentLine = [lines objectAtIndex:i];
+    currentLine = [currentLine stringByTrimmingCharactersInSet:set];
+    trimmedLine = [currentLine stringByTrimmingCharactersInSet:
+                                [NSCharacterSet whitespaceCharacterSet]];
+    
+    if ([trimmedLine length] > 0) {
+      if ([buf length] > 0)
+        [buf appendString:@"\n"];
+      
+      [buf appendString:currentLine];
+    }
+    else {
+      if ([buf length] > 0) {
+       StructuredLine *sl;
+
+       sl = [[StructuredLine alloc]
+              initWithString:[NSString stringWithString:buf]
+              level:0];;
+        [pars push:sl];
+       // TODO: shouldn't we release the object?
+      }
+
+      [buf setString:@""];
+    }
+  }
+
+  if ([buf length] > 0) {
+    StructuredLine *sl;
+    
+    sl = [[StructuredLine alloc]
+          initWithString:[NSString stringWithString:buf] level:0];
+    [pars push:sl];
+    // TODO: shouldn't we release the object?
+  }
+}
+
+- (void)adjustLineLevels {
+  StructuredStack      *paragraphs;
+  StructuredStack      *stack;
+  StructuredLine       *line;
+  StructuredLine       *lastParagraph = nil;
+  int level = 0;
+
+  stack = [self stack];
+  [stack setCursorFollowsFIFO:YES];
+
+  paragraphs = [self paragraphs];
+  [paragraphs first];
+
+  while ((line = [paragraphs nextObject])) {
+    StructuredLine *tmpLine;
+    
+    while ((tmpLine = [stack currentObject])) {
+      if ([line numberOfSpacesAtBeginning]>[tmpLine numberOfSpacesAtBeginning])
+        break;
+      
+      [stack pop];
+      level--;
+    }
+
+    if (!tmpLine)
+      level = 0;
+    
+    switch ([self lineType:line]) {
+    case StructuredTextParserLine_Header:
+      [line setLevel:level++];
+      [stack push:line];
+      break;
+    case StructuredTextParserLine_Paragraph:
+      lastParagraph = line;
+    case StructuredTextParserLine_LiteralBlock:
+      [line setLevel:level];
+      break;
+    case StructuredTextParserLine_List: {
+      [line setLevel:level++];
+      [stack push:line];
+      break;
+    }
+    }
+  }
+
+  [stack removeAllObjects];
+}
+
+- (void)buildDocument {
+  StructuredTextDocument *document;
+  StructuredStack       *paragraphs;
+  StructuredStack       *stack, *objectStack;
+  StructuredLine        *line;
+  
+  document = [self document];
+
+  stack = [self stack];
+  [stack setCursorFollowsFIFO:YES];
+
+  paragraphs = [self paragraphs];
+  [paragraphs first];
+
+  objectStack = [[StructuredStack alloc] init];
+  [objectStack setCursorFollowsFIFO:YES];
+
+  while ((line = [paragraphs currentObject])) {
+    StructuredLine *tmpLine;
+    id object = nil;
+
+    switch ([self lineType:line]) {
+    case StructuredTextParserLine_Header:
+      object = [self buildHeader];
+#if DISABLE_BUG_FIX
+      currentHeaderLevel++;
+#endif
+      break;
+    case StructuredTextParserLine_Paragraph:
+      object = [self buildParagraph];
+      //NSLog(@"par %@", [object text]);
+      break;
+    case StructuredTextParserLine_LiteralBlock:
+      object = [self buildLiteralBlock];
+      break;
+    case StructuredTextParserLine_List:
+      object = [self buildList];
+      break;
+    }
+
+    if (object != nil) {
+      StructuredTextBodyElement *body;
+
+      body = [objectStack currentObject];
+
+      if (body && [body respondsToSelector:@selector(addElement:)])
+        [body addElement:object];
+      else
+        [document addBodyElement:object];
+      
+      if ([object isKindOfClass:[StructuredTextHeader class]]
+          /* || [object isKindOfClass:[StructuredTextList class]] */) {
+        while ((tmpLine = [stack currentObject])) {
+          id currentObject;
+
+          if ([line level] > [tmpLine level])
+            break;
+         
+          [stack pop];
+          currentObject = [objectStack pop];
+
+#if DISABLE_BUG_FIX
+          if ([currentObject isKindOfClass:[StructuredTextHeader class]])
+            currentHeaderLevel--;
+#endif
+        }
+
+        [objectStack push:object];
+        [stack push:line];
+      }
+    }
+    
+    [paragraphs nextObject];
+  }
+
+  [objectStack release];
+}
+
+- (int)lineType:(StructuredLine *)aLine {
+  if ([self checkForListItem:aLine])
+    return StructuredTextParserLine_List;
+  
+  if ([self checkForHeader:aLine]) {
+    return [self checkForPreformattedStatement:aLine]
+      ? StructuredTextParserLine_Paragraph
+      : StructuredTextParserLine_Header;
+  } 
+  
+  if ([self checkForPreformattedBlock:aLine])
+    return StructuredTextParserLine_LiteralBlock;
+
+  return StructuredTextParserLine_Paragraph;
+}
+
+- (BOOL)checkForHeader:(StructuredLine *)aLine {
+  StructuredLine *nextLine;
+
+  nextLine = [[self paragraphs] objectRelativeToCursorAtIndex:1];
+  
+  if (nextLine == nil)
+    return NO;
+  
+  if ([nextLine numberOfSpacesAtBeginning]>[aLine numberOfSpacesAtBeginning])
+    return YES;
+  
+  return NO;
+}
+
+- (BOOL)checkForListItem:(StructuredLine *)aLine {
+  return ([self listItemTypology:aLine] == NSNotFound) ? NO : YES;
+}
+
+- (BOOL)checkForPreformattedStatement:(StructuredLine *)aLine {
+  NSString *s;
+  
+  if (aLine == nil)
+    return NO;
+  
+  s = [aLine text];
+  s = [s stringByTrimmingCharactersInSet:
+          [NSCharacterSet whitespaceCharacterSet]];
+  return [s hasSuffix:@"::"];
+}
+
+- (BOOL)checkForPreformattedBlock:(StructuredLine *)aLine {
+  id stmt;
+  
+  stmt = [[self paragraphs] objectRelativeToCursorAtIndex:-1];
+  return [self checkForPreformattedStatement:stmt] ? YES : NO;
+}
+
+- (StructuredTextHeader *)buildHeader {
+  StructuredTextHeader *result;
+  StructuredLine       *line;
+  
+  line = [[self paragraphs] currentObject];
+  
+#if DISABLE_BUG_FIX
+  result = [[StructuredTextHeader alloc] initWithString:[line text] 
+                                        level:currentHeaderLevel];
+#else
+  result = [[StructuredTextHeader alloc] initWithString:[line text] 
+                                         level:([line level] + 1)];
+#endif
+  return [result autorelease];
+}
+
+- (StructuredTextParagraph *)buildParagraph {
+  StructuredTextParagraph      *result;
+  StructuredLine                       *line;
+  NSString                             *text;
+
+  line = [[self paragraphs] currentObject];
+  text = [line text];
+  
+  if ([[text stringByTrimmingCharactersInSet:
+              [NSCharacterSet whitespaceCharacterSet]] hasSuffix:@"::"]) {
+    int length;
+
+    length = [text length];
+    text   = [text substringToIndex:length - 2];
+  }
+  
+  result = [[StructuredTextParagraph alloc] initWithString:text];
+  return [result autorelease];
+}
+
+- (StructuredTextLiteralBlock *)buildLiteralBlock {
+  StructuredTextLiteralBlock *result;
+  StructuredLine             *line;
+  NSString *s;
+  
+  line = [[self paragraphs] currentObject];
+  
+  s = [[line originalText] stringByAppendingString:@"\n"];
+  result = [[StructuredTextLiteralBlock alloc] initWithString:s];
+  return [result autorelease];
+}
+
+- (StructuredTextList *)buildList {
+  StructuredTextList    *result;
+  StructuredLine        *line, *prevLine = nil;
+  StructuredTextListItem *item = nil;
+  StructuredStack       *paragraphs;
+  int type;
+  
+  result     = nil;
+  paragraphs = [self paragraphs];
+  line       = [paragraphs currentObject];
+  
+  while (line != nil) {
+    NSString   *text, *title;
+
+    text = [line text];
+    title = nil;
+
+    type = [self listItemTypology:line];
+
+    if (type == NSNotFound) {
+      [paragraphs prevObject];
+      break;
+    }
+
+    if (!result)
+      result = [[StructuredTextList alloc] initWithTypology:type];
+    else if ([result typology] != type)
+      break;
+
+    if (prevLine) {
+      if ([line level] > [prevLine level]) {
+        if (item) {
+          [item addElement:[self buildList]];
+
+          line = [paragraphs currentObject];
+
+          continue;
+        }
+      } else if ([line level] < [prevLine level]) {
+        return result;
+      }
+    }
+
+    switch (type) {
+    case StructuredTextList_BULLET:
+      text = [text substringFromIndex:2];
+      break;
+    case StructuredTextList_DEFINITION: {
+      NSArray *components;
+      int i, count;
+
+      components = [text componentsSeparatedByString:@" -- "];
+      count = [components count];
+
+      title = [components objectAtIndex:0];
+
+      if (count > 2) {
+        NSMutableString *buffer;
+       
+        buffer = [NSMutableString stringWithCapacity:(count * 8)];
+       
+        for (i = 1; i < count; i++) {
+          if (i > 1) {
+            [buffer appendString:@" -- "];
+          }
+
+          [buffer appendString:[components objectAtIndex:i]];
+        }
+
+        text = buffer;
+      } 
+      else
+        text = [components objectAtIndex:1];
+      
+      break;
+    }
+    case StructuredTextList_ENUMERATED: {
+      NSRange range;
+
+      range = [text rangeOfString:@" "];
+      if (range.length > 0)
+        text = [text substringFromIndex:range.location + 1];
+      
+      break;
+    }
+    }
+
+    item = [[StructuredTextListItem alloc] initWithTitle:title text:text];
+    [result addElement:item];
+    [item release];
+
+    prevLine = line;
+    line = [paragraphs nextObject];
+  }
+
+  return [result autorelease];
+}
+
+- (int)listItemTypology:(StructuredLine *)aLine {
+  NSString *text;
+  int      type = NSNotFound;
+  int      i, h, length;
+  NSRange  range;
+
+  text = [aLine text];
+
+  if ([text hasPrefix:@"* "])
+    return StructuredTextList_BULLET;
+  
+  range = [text rangeOfString:@" -- "];
+  if (range.length > 0 && range.length == 4)
+    return StructuredTextList_DEFINITION;
+  
+  for (i = h = 0, length = [text length]; i < length; i++) {
+    if (!isdigit([text characterAtIndex:i]))
+      break;
+    
+    h++;
+  }
+  
+  if (h > 0)
+    type = StructuredTextList_ENUMERATED;
+  
+  return type;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->_text) [ms appendFormat:@" text-len=%d", [self->_text length]];
+  if (self->_document)
+    [ms appendFormat:@" document=%@", self->_document];
+
+#if DISABLE_BUG_FIX
+  [ms appendFormat:@" headerlevel=%i", self->currentHeaderLevel];
+#endif
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* StructuredText */
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredTextRenderingDelegate.h b/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredTextRenderingDelegate.h
new file mode 100644 (file)
index 0000000..ba07547
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#ifndef __StructuredTextRenderingDelegate_H__
+#define __StructuredTextRenderingDelegate_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSDictionary;
+
+@protocol StructuredTextRenderingDelegate
+
+- (NSString *)insertText:(NSString *)_txt      inContext:(NSDictionary *)_ctx;
+- (NSString *)insertItalics:(NSString *)_txt   inContext:(NSDictionary *)_ctx;
+- (NSString *)insertUnderline:(NSString *)_txt inContext:(NSDictionary *)_ctx;
+- (NSString *)insertBold:(NSString *)_txt      inContext:(NSDictionary *)_ctx;
+- (NSString *)insertPreformatted:(NSString *)_txt 
+  inContext:(NSDictionary *)_ctx;
+
+- (NSString *)insertLink:(NSString *)_txt 
+  withUrl:(NSString *)anUrl target:(NSString *)aTarget 
+  inContext:(NSDictionary *)_ctx;
+
+- (NSString *)insertEmail:(NSString *)_txt 
+  withAddress:(NSString *)anAddress 
+  inContext:(NSDictionary *)_ctx;
+- (NSString *)insertImage:(NSString *)_txt 
+  withUrl:(NSString *)anUrl 
+  inContext:(NSDictionary *)_ctx;
+
+- (NSString *)insertExtrapolaLink:(NSString *)_txt
+  parameters:(NSDictionary *)someParameters
+  withTarget:(NSString *)aTarget
+  inContext:(NSDictionary *)_ctx;
+
+- (NSString *)insertDynamicKey:(NSString *)_txt 
+  inContext:(NSDictionary *)_ctx;
+- (NSString *)insertPreprocessedTextForKey:(NSString *)aKey 
+  inContext:(NSDictionary *)_ctx;
+
+@end
+
+#endif /* __StructuredTextRenderingDelegate_H__ */
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText_XHTML.h b/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText_XHTML.h
new file mode 100644 (file)
index 0000000..f973b9a
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#error does not compile, just for reference!
+
+@interface StructuredTextRenderingDelegate_XHTML : StructuredTextRenderingDelegate
+@end
+
+@interface NSArray (StructuredText_XHTML)
+- (NSString *)toXhtmlInContext:(NSDictionary *)aContext;
+@end
+
+@interface StructuredText (StructuredText_XHTML)
+- (NSString *)toXhtmlInContext:(NSDictionary *)aContext;
+@end
+
+@interface StructuredTextDocument (StructuredText_XHTML)
+- (NSString *)toXhtmlInContext:(NSDictionary *)aContext;
+@end
+
+@interface StructuredTextBodyElement (StructuredText_XHTML)
+- (NSString *)toXhtmlInContext:(NSDictionary *)aContext;
+@end
+
+@interface StructuredTextHeader (StructuredText_XHTML)
+- (NSString *)toXhtmlInContext:(NSDictionary *)aContext;
+@end
+
+@interface StructuredTextParagraph (StructuredText_XHTML)
+- (NSString *)toXhtmlInContext:(NSDictionary *)aContext;
+@end
+
+@interface StructuredTextList (StructuredText_XHTML)
+- (NSString *)toXhtmlInContext:(NSDictionary *)aContext;
+@end
+
+@interface StructuredTextListItem (StructuredText_XHTML)
+- (NSString *)toXhtmlInContext:(NSDictionary *)aContext;
+@end
+
+@interface StructuredTextLiteralBlock (StructuredText_XHTML)
+- (NSString *)toXhtmlInContext:(NSDictionary *)aContext;
+@end
diff --git a/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText_XHTML.m b/skyrix-xml/STXSaxDriver/ExtraSTX/StructuredText_XHTML.m
new file mode 100644 (file)
index 0000000..f29aef1
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#error does not compile, just for reference!
+
+#include "StructuredText_XHTML.h"
+#include "common.h"
+
+@implementation StructuredTextRenderingDelegate_XHTML
+
+- (NSString *)insertText:(NSString *)_txt inContext:(NSDictionary *)_ctx {
+  return [NSString stringWithFormat:@"<p>%@</p>", _txt];
+}
+
+- (NSString *)insertItalics:(NSString *)_txt inContext:(NSDictionary *)_ctx {
+  return [NSString stringWithFormat:
+                     @"<span class=\"italics\">%@</span>", _txt];
+}
+
+- (NSString *)insertUnderline:(NSString *)_txt inContext:(NSDictionary *)_ctx {
+  return [NSString stringWithFormat:
+                     @"<span class=\"underline\">%@</span>", _txt];
+}
+
+- (NSString *)insertBold:(NSString *)_txt inContext:(NSDictionary *)_ctx {
+  return [NSString stringWithFormat:@"<span class=\"bold\">%@</span>", _txt];
+}
+
+- (NSString *)insertPreformatted:(NSString *)_txt 
+  inContext:(NSDictionary *)_ctx 
+{
+  return [NSString stringWithFormat:
+                     @"<span class=\"preformatted\">%@</span>", _txt];
+}
+
+- (NSString *)insertLink:(NSString *)_txt 
+  withUrl:(NSString *)anUrl target:(NSString *)aTarget 
+  inContext:(NSDictionary *)_ctx 
+{
+  NSString *result;
+
+  if ([aTarget length] > 0) {
+    result = [NSString stringWithFormat:
+                         @"<a href=\"%@\" target=\"%@\">%@</a>", 
+                         anUrl, aTarget, _txt];
+  } 
+  else {
+    result = [NSString stringWithFormat:@"<a href=\"%@\">%@</a>", anUrl, _txt];
+  }
+  
+  return result;
+}
+
+- (NSString *)insertEmail:(NSString *)_txt withAddress:(NSString *)anAddress 
+  inContext:(NSDictionary *)_ctx 
+{
+  return [NSString stringWithFormat:@"<a href=\"%@\">%@</a>", anAddress, _txt];
+}
+
+- (NSString *)insertImage:(NSString *)_txt withUrl:(NSString *)anUrl 
+  inContext:(NSDictionary *)_ctx 
+{
+  return [NSString stringWithFormat:@"<img src=\"%@\" title=\"%@\" />", 
+                     anUrl, _txt];
+}
+
+- (NSString *)insertExtrapolaLink:(NSString *)_txt 
+  parameters:(NSDictionary *)someParameters withTarget:(NSString *)aTarget 
+  inContext:(NSDictionary *)_ctx 
+{
+  NSString     *result;
+  NSString     *targetString;
+
+       
+  if ([aTarget length] > 0)
+    targetString = [NSString stringWithFormat:@" target = \"%@\"", aTarget];
+  else
+    targetString = @"";
+  
+  result = [NSString stringWithFormat:
+                       @"<a href=\"/cgi-bin/WebObjects/NewsX.woa/wa/%@\" %@>%@</a>", 
+                     [someParameters objectForKey:@"page"], 
+                     targetString, _txt];
+
+  return result;
+}
+
+- (NSString *)insertPreprocessedTextForKey:(NSString *)aKey 
+  inContext:(NSDictionary *)_ctx 
+{
+  return [_ctx objectForKey:aKey];
+}
+
+@end /* StructuredTextRenderingDelegate_XHTML */
+
+@implementation NSArray (StructuredText_XHTML)
+
+- (NSString *)toXhtmlInContext:(NSDictionary *)_ctx {
+  NSMutableString      *result;
+  int  i,c;
+
+  c = [self count];
+  result = [NSMutableString stringWithCapacity:(c * 16)];
+  for (i = 0; i < c; i++) {
+    id currentObject;
+
+    currentObject = [self objectAtIndex:i];
+    [result appendString:[currentObject toXhtmlInContext:_ctx]];
+  }
+
+  return result;
+}
+
+@end
+
+@implementation StructuredText(StructuredText_XHTML)
+
+- (NSString *)toXhtmlInContext:(NSDictionary *)_ctx {
+  return [[self document] toXhtmlInContext:_ctx];
+}
+
+@end /* StructuredText(StructuredText_XHTML) */
+
+@implementation StructuredTextDocument(StructuredText_XHTML)
+
+- (NSString *)toXhtmlInContext:(NSDictionary *)_ctx {
+  return [[self bodyElements] toXhtmlInContext:_ctx];
+}
+
+@end /* StructuredTextDocument(StructuredText_XHTML) */
+
+@implementation StructuredTextBodyElement(StructuredText_XHTML)
+
+- (NSString *)toXhtmlInContext:(NSDictionary *)_ctx {
+  return [[self elements] toXhtmlInContext:_ctx];
+}
+
+@end /* StructuredTextBodyElement(StructuredText_XHTML) */
+
+@implementation StructuredTextHeader(StructuredText_XHTML)
+
+- (NSString *)toXhtmlInContext:(NSDictionary *)_ctx {
+  NSMutableString *ms;
+  id delegate;
+  
+  delegate = [StructuredTextRenderingDelegate_XHTML delegate] ;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<h%d>", [self level]];
+  [ms appendString:[self textParsedWithDelegate:delegate inContext:_ctx]];
+  [ms appendFormat:@"</h%d>", [self level]];
+  
+  [ms appendString:[super toXhtmlInContext:_ctx]];
+  return ms;
+}
+
+@end /* StructuredTextHeader(StructuredText_XHTML) */
+
+@implementation StructuredTextParagraph(StructuredText_XHTML)
+
+- (NSString *)toXhtmlInContext:(NSDictionary *)_ctx {
+  id delegate;
+
+  delegate = [StructuredTextRenderingDelegate_XHTML delegate];
+  return [self textParsedWithDelegate:delegate inContext:_ctx];
+}
+
+@end /* StructuredTextParagraph (StructuredText_XHTML) */
+
+@implementation StructuredTextList(StructuredText_XHTML)
+
+- (NSString *)toXhtmlInContext:(NSDictionary *)_ctx {
+  NSString *result;
+  NSString *elemText;
+  
+  elemText = [[self elements] toXhtmlInContext:_ctx];
+  
+  switch ([self typology]) {
+    case StructuredTextList_BULLET: {
+      result = [NSString stringWithFormat:@"<ul>%@</ul>", elemText];
+      break;
+    }
+    case StructuredTextList_ENUMERATED: {
+      result = [NSString stringWithFormat:@"<ol>%@</ol>", elemText];
+      break;
+    }
+    case StructuredTextList_DEFINITION: {
+      result = [NSString stringWithFormat:@"<dl>%@</dl>", elemText];
+      break;
+    }
+    default: {
+      result = @"";
+      break;
+    }
+  }
+  return result;
+}
+
+@end /* StructuredTextList(StructuredText_XHTML) */
+
+@implementation StructuredTextListItem(StructuredText_XHTML)
+
+- (NSString *)toXhtmlInContext:(NSDictionary *)_ctx {
+  NSString *result;
+  NSString *textParsed;
+  NSString *elemText;
+  
+  elemText   = [[self elements] toXhtmlInContext:_ctx];
+  textParsed = [self textParsedWithDelegate:
+                      [StructuredTextRenderingDelegate_XHTML delegate] 
+                    inContext:_ctx];
+
+  switch ([[self list] typology]) {
+  case StructuredTextList_BULLET: {
+    result = [NSString stringWithFormat:@"<li>%@%@</li>", 
+                       textParsed, elemText];
+    break;
+  }
+  case StructuredTextList_ENUMERATED: {
+    result = [NSString stringWithFormat:@"<li>%@%@</li>", 
+                      textParsed, elemText];
+    break;
+  }
+  case StructuredTextList_DEFINITION: {
+    result = [NSString stringWithFormat:@"<dt>%@</dt><dd>%@</dd>", 
+                       [self titleParsedWithDelegate:
+                               [StructuredTextRenderingDelegate_XHTML delegate] 
+                            inContext:_ctx], 
+                      textParsed];
+    break;
+  }
+  default: {
+    result = @"";
+    break;
+  }
+  }
+
+  return result;
+}
+
+@end /* StructuredTextListItem(StructuredText_XHTML) */
+
+@implementation StructuredTextLiteralBlock(StructuredText_XHTML)
+
+- (NSString *)toXhtmlInContext:(NSDictionary *)_ctx {
+  return [NSString stringWithFormat:
+                     @"<div class=\"preformatted\">%@</div>", [self text]];
+}
+
+@end /* StructuredTextLiteralBlock(StructuredText_XHTML) */
diff --git a/skyrix-xml/STXSaxDriver/GNUmakefile b/skyrix-xml/STXSaxDriver/GNUmakefile
new file mode 100644 (file)
index 0000000..ec3b553
--- /dev/null
@@ -0,0 +1,21 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+BUNDLE_NAME        = STXSaxDriver
+BUNDLE_EXTENSION   = .sax
+BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SaxDrivers
+
+STXSaxDriver_OBJC_FILES += \
+       STXSaxDriver.m  \
+       StructuredTextBodyElement+SAX.m
+
+STXSaxDriver_SUBPROJECTS += \
+       ExtraSTX \
+       Model
+
+STXSaxDriver_RESOURCE_FILES += Version
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
diff --git a/skyrix-xml/STXSaxDriver/GNUmakefile.postamble b/skyrix-xml/STXSaxDriver/GNUmakefile.postamble
new file mode 100644 (file)
index 0000000..9741795
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
diff --git a/skyrix-xml/STXSaxDriver/GNUmakefile.preamble b/skyrix-xml/STXSaxDriver/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..c0fa86c
--- /dev/null
@@ -0,0 +1,17 @@
+# $Id$
+
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_BUILD_DIR)/../SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += -L../SaxObjC/$(GNUSTEP_OBJ_DIR)
+endif
+
+STXSaxDriver_INCLUDE_DIRS += \
+       -I.             \
+       -I./Model/      \
+       -I./ExtraSTX/   \
+       -I..
+
+STXSaxDriver_BUNDLE_LIBS += -lSaxObjC
diff --git a/skyrix-xml/STXSaxDriver/Model/.cvsignore b/skyrix-xml/STXSaxDriver/Model/.cvsignore
new file mode 100644 (file)
index 0000000..6a53797
--- /dev/null
@@ -0,0 +1,2 @@
+Resources
+shared_debug_obj
diff --git a/skyrix-xml/STXSaxDriver/Model/COPYRIGHT b/skyrix-xml/STXSaxDriver/Model/COPYRIGHT
new file mode 100644 (file)
index 0000000..cee7d8e
--- /dev/null
@@ -0,0 +1,29 @@
+# $Id$
+
+Structured Text Code
+Copyright (C) 2004 eXtrapola Srl
+Contact: marco.barulli@extrapola.com
+
+
+Statement by Extrapola SRL (Marco Barulli)
+==========================================
+
+I'm glad to confirm that eXtrapola Srl, as the copyright holder on the 
+StructuredText code sent to the OpenGroupware.org project and initially 
+written by Mirko Viviani and Giulio Cesare Solaroli, hereby states that the 
+code is licensed and can be used under the terms of the Lesser General Public 
+License.
+
+Statement by Mirko Viviani
+==========================
+
+Mirko Viviani, as the original author of the StructuredText framework sent to 
+the OpenGroupware.org project, hereby states that the code is licensed and can
+be used under the terms of the Lesser General Public License.
+
+Statement by Giulio Cesare Solaroli
+===================================
+
+I, as one of the original author on the StructuredText code sent to the 
+OpenGroupware.org project, hereby states that the code is licensed and can be 
+used under the terms of the Lesser General Public License.
diff --git a/skyrix-xml/STXSaxDriver/Model/GNUmakefile b/skyrix-xml/STXSaxDriver/Model/GNUmakefile
new file mode 100644 (file)
index 0000000..0ba6f47
--- /dev/null
@@ -0,0 +1,27 @@
+#
+#  StructuredText.subproj makefile for StructuredText.
+#  
+#  Author: Mirko Viviani <mirko@objectlab.org>
+#
+#  Date: 24 November 2003
+#
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+SUBPROJECT_NAME = Model
+
+Model_OBJC_FILES = \
+       StructuredTextDocument.m        \
+       StructuredTextBodyElement.m     \
+       StructuredTextParagraph.m       \
+       StructuredTextListItem.m        \
+       StructuredTextList.m            \
+       StructuredTextLiteralBlock.m    \
+       StructuredTextHeader.m
+
+ADDITIONAL_INCLUDE_DIRS += \
+       -I. -I.. -I../ExtraSTX
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/subproject.make
+-include GNUmakefile.postamble
diff --git a/skyrix-xml/STXSaxDriver/Model/README b/skyrix-xml/STXSaxDriver/Model/README
new file mode 100644 (file)
index 0000000..a97aaf5
--- /dev/null
@@ -0,0 +1,20 @@
+# $Id$
+
+Notes
+=====
+
+The central class containing the parsing code seems to be:
+
+  StructuredTextBodyElement
+
+Classes
+=======
+
+  NSObject
+    StructuredTextBodyElement
+      StructuredTextHeader
+      StructuredTextList
+      StructuredTextListItem
+      StructuredTextParagraph
+    StructuredTextDocument
+    StructuredTextLiteralBlock
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextBodyElement.h b/skyrix-xml/STXSaxDriver/Model/StructuredTextBodyElement.h
new file mode 100644 (file)
index 0000000..7c73113
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#ifndef __StructuredTextBodyElement_H__
+#define __StructuredTextBodyElement_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSRange.h>
+#include "StructuredTextRenderingDelegate.h"
+
+@class NSMutableArray;
+
+@interface StructuredTextBodyElement : NSObject
+{
+  NSMutableArray                     *_elements;
+  id<StructuredTextRenderingDelegate> _delegate; /* non-retained */
+  BOOL                               runPreprocessor;
+}
+
+- (NSMutableArray *)elements;
+- (void)addElement:(StructuredTextBodyElement *)_element;
+
+- (NSString *)parseText:(NSString *)_str inContext:(NSDictionary *)_ctx;
+
+- (NSRange)findBoldSubstring:(NSString *)_str;
+- (NSRange)findItalicsSubstring:(NSString *)_str;
+- (NSRange)findUnderlineSubstring:(NSString *)_str;
+- (NSRange)findLinkImageSubstring:(NSString *)_str;
+- (NSRange)findLinkSubstring:(NSString *)_str;
+- (NSRange)findLinkTargetFromString:(NSString *)_str;
+- (NSRange)findDynamicKeySubstring:(NSString *)_str;
+
+- (NSString *)preformattedText:(NSString *)_s inContext:(NSDictionary *)_ctx;
+- (NSString *)boldText:(NSString *)_str       inContext:(NSDictionary *)_ctx;
+- (NSString *)italicsText:(NSString *)_str    inContext:(NSDictionary *)_ctx;
+- (NSString *)underlineText:(NSString *)_str  inContext:(NSDictionary *)_ctx;
+- (NSString *)linkImage:(NSString *)_str      inContext:(NSDictionary *)_ctx;
+- (NSString *)linkText:(NSString *)_str       inContext:(NSDictionary *)_ctx;
+- (NSString *)linkTargetFromString:(NSString *)_str;
+- (NSString *)dynamicKeyText:(NSString *)aKey inContext:(NSDictionary *)_ctx;
+- (NSString *)preprocessText:(NSString *)_str inContext:(NSDictionary *)_ctx;
+
+@end
+
+#endif /* __StructuredTextBodyElement_H__ */
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextBodyElement.m b/skyrix-xml/STXSaxDriver/Model/StructuredTextBodyElement.m
new file mode 100644 (file)
index 0000000..d60edbe
--- /dev/null
@@ -0,0 +1,977 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "StructuredTextBodyElement.h"
+#include "NSString+STX.h"
+#include "common.h"
+
+#define ST_ESCAPE_CHAR         '\\'
+#define ST_UNDERLINE_CHAR      '_'
+#define ST_DYNAMICKEY_CHAR     '@'
+#define ST_ITALICS_CHAR                '*'
+#define ST_LINK_CHAR           '"'
+#define ST_LINKIMAGE_CHAR      '['
+
+static NSString *preprocessorTag = @"##";
+
+@implementation StructuredTextBodyElement
+
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  debugOn = [ud boolForKey:@"STXDebugEnabled"];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->runPreprocessor = YES;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->_elements release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSMutableArray *)elements {
+  if (_elements == nil)
+    _elements = [[NSMutableArray alloc] init];
+
+  return _elements;
+}
+
+- (void)addElement:(NSObject *)anElement {
+  if (anElement == nil)
+    return;
+
+  [[self elements] addObject:anElement];
+}
+
+/* operations */
+
+- (NSString *)parseText:(NSString *)_str inContext:(NSDictionary *)_ctx {
+  // TODO: too big a method
+  NSMutableString *result;
+  NSString       *text;
+  NSRange        range, rangeOut;
+  int            i, length, start;
+
+  if (debugOn) 
+    NSLog(@"PARSE TEXT: '%@' (delegate=0x%08X)", _str, self->_delegate);
+  _str = [self preprocessText:_str inContext:_ctx];
+  if (debugOn) NSLog(@"  preprocessed: '%@'", _str);
+  
+  result = [NSMutableString stringWithCapacity:[_str length]];
+  text   = _str;
+  
+  for (i = start = 0, length = [text length]; i < length; i++) {
+    unichar c;
+    
+    c = [text characterAtIndex:i];
+
+    switch (c) {
+    case ST_ESCAPE_CHAR:
+      if (i - start > 0) {
+        range.location = start;
+        range.length   = (i - start);
+       
+        [result appendString:[text substringWithRange:range]];
+      }
+
+      start = ++i;
+      break;
+
+    case '\'':
+      if (i - start > 0) {
+        range.location = start;
+        range.length = i - start;
+
+        [result appendString:[text substringWithRange:range]];
+      }
+
+      if (i + 1 < length) {
+        c = [_str characterAtIndex:i + 1];
+
+        if (c == '\'') {
+          start = ++i;
+          break;
+        }
+      }
+
+      range.location = i + 1;
+      range.length = length - range.location;
+
+      rangeOut = [text rangeOfString:@"'" options:0 range:range];
+
+      if (rangeOut.length > 0) {
+       NSString *s;
+       
+        range.location = i + 1;
+        range.length = rangeOut.location - range.location;
+       
+       s = [[text substringWithRange:range] unescapedString];
+       s = [self preformattedText:s inContext:_ctx];
+        [result appendString:s];
+
+        start = i = rangeOut.location + 1;
+      } 
+      else {
+        start = i;
+      }
+      break;
+
+    case ST_UNDERLINE_CHAR: // underline
+      if (i - start > 0) {
+        range.location = start;
+        range.length = i - start;
+
+        [result appendString:[text substringWithRange:range]];
+
+        start = i;
+      }
+
+      range = [self findUnderlineSubstring:[text substringFromIndex:i + 1]];
+      
+      if (range.length > 0) {
+       NSString *s;
+       
+        range.location = i + 1;
+       
+       s = [[text substringWithRange:range] unescapedString];
+       s = [self parseText:s inContext:_ctx];
+       s = [self underlineText:s inContext:_ctx];
+        if (s) [result appendString:s];
+
+        i += range.length + 1;
+        start = i + 1;
+      }
+      break;
+
+    case ST_DYNAMICKEY_CHAR: // dynamicKey
+      if (i - start > 0) {
+        range.location = start;
+        range.length = i - start;
+
+        [result appendString:[text substringWithRange:range]];
+
+        start = i;
+      }
+
+      range = [self findDynamicKeySubstring:[text substringFromIndex:i + 1]];
+      if (range.length > 0) {
+       NSString *s;
+       
+        range.location = i + 1;
+
+       s = [self parseText:[text substringWithRange:range] inContext:_ctx];
+        [result appendString:[self dynamicKeyText:s inContext:_ctx]];
+        
+        i += range.length + 1;
+        start = i + 1;
+      }
+      break;
+
+    case ST_ITALICS_CHAR: { // italics e bold
+      if (i - start > 0) {
+        range.location = start;
+        range.length = i - start;
+
+        [result appendString:[text substringWithRange:range]];
+
+        start = i;
+      }
+
+      if (i + 1 < length) {
+        c = [text characterAtIndex:i + 1];
+
+        if (c == ST_ITALICS_CHAR) {
+          range = [self findBoldSubstring:[text substringFromIndex:i + 2]];
+
+          if (range.length > 0) {
+           NSString *s;
+           
+            range.location = i + 2;
+            
+           s = [[text substringWithRange:range] unescapedString];
+           s = [self parseText:s inContext:_ctx];
+           s = [self boldText:s inContext:_ctx];
+            if (s) [result appendString:s];
+           
+            i += range.length + 3;
+            start = i + 1;
+          }
+        } 
+        else {
+          range = [self findItalicsSubstring:[text substringFromIndex:i + 1]];
+         
+          if (range.length > 0) {
+           NSString *s;
+           
+            range.location = i + 1;
+
+           s = [[text substringWithRange:range] unescapedString];
+           s = [self parseText:s inContext:_ctx];
+            s = [self italicsText:s inContext:_ctx];
+            if (s) [result appendString:s];
+            
+            i += range.length + 1;
+            start = i + 1;
+          }
+        }
+      }
+      break;
+    }
+
+    case ST_LINKIMAGE_CHAR: // links
+      if (i - start > 0) {
+        range.location = start;
+        range.length = i - start;
+
+        [result appendString:[text substringWithRange:range]];
+
+        start = i;
+      }
+
+      range = [self findLinkImageSubstring:[text substringFromIndex:i + 1]];
+
+      if (range.length > 0) {
+       NSString *s;
+       
+        range.location = i + 1;
+       
+       s = [self linkImage:[text substringWithRange:range] inContext:_ctx];
+        [result appendString:s];
+       
+        i += range.length;
+        start = i + 1;
+      }
+
+      break;
+
+    case ST_LINK_CHAR: // links
+      if (i - start > 0) {
+        range.location = start;
+        range.length   = i - start;
+       
+        [result appendString:[text substringWithRange:range]];
+
+        start = i;
+      }
+      
+      range = [self findLinkSubstring:[text substringFromIndex:(i + 1)]];
+      if (range.length > 0) {
+       NSString *s;
+       
+        range.location = i + 1;
+       
+       s = [self linkText:[text substringWithRange:range] inContext:_ctx];
+       [result appendString:s];
+       
+       if (debugOn) NSLog(@"found link substring: '%@'", s);
+       
+        i += range.length;
+        start = i + 1;
+      }
+
+      break;
+    }
+  }
+
+  if (i - start > 0) {
+    range.location = start;
+    range.length = i - start;
+
+    [result appendString:[text substringWithRange:range]];
+  }
+  
+  if (debugOn) NSLog(@"  result: '%@'", result);
+  return result;
+}
+
+- (NSRange)findMarkerSubstring:(NSString *)_str 
+  withMarker:(unichar)aMarker markerLength:(int)markLength 
+{
+  NSRange range;
+  int    i, h, length;
+  
+  length = [_str length];
+  markLength--;
+
+  for (i = 0; i < length; i++) {
+    unichar c;
+
+    c = [_str characterAtIndex:i];
+
+    if (c == aMarker && i + markLength < length) {
+      BOOL foundMarker = YES;
+
+      for (h = i + 1; h <= i + markLength; h++) {
+        c = [_str characterAtIndex:h];
+
+        if (c != aMarker) {
+          foundMarker = NO;
+          break;
+        }
+      }
+
+      if (foundMarker) {
+        range.location = 0;
+        range.length = i;
+
+        return range;
+      }
+    } 
+    else if (c == ST_ESCAPE_CHAR) {
+      i++;
+    }
+  }
+
+  range.location = NSNotFound;
+  range.length = 0;
+
+  return range;
+}
+
+/* find markers */
+
+- (NSRange)findBoldSubstring:(NSString *)_str {
+  return [self findMarkerSubstring:_str 
+               withMarker:ST_ITALICS_CHAR markerLength:2];
+}
+
+- (NSRange)findItalicsSubstring:(NSString *)_str {
+  return [self findMarkerSubstring:_str 
+               withMarker:ST_ITALICS_CHAR markerLength:1];
+}
+
+- (NSRange)findUnderlineSubstring:(NSString *)_str {
+  return [self findMarkerSubstring:_str 
+               withMarker:ST_UNDERLINE_CHAR markerLength:1];
+}
+
+/* operations */
+
+- (NSString *)preformattedText:(NSString *)_s inContext:(NSDictionary *)_ctx {
+  return [self->_delegate insertPreformatted:_s inContext:_ctx];
+}
+
+- (NSRange)_findLinkBlockTargetSubstring:(NSString *)_str {
+  NSRange range, rangeTarget;
+  int    length;
+  unichar c;
+  
+  length = [_str length];
+  if (debugOn) NSLog(@"  find link block target: '%s'", _str);
+
+  c = [_str characterAtIndex:0];
+  
+  if (c == ':' && 1 < length) {
+    c = [_str characterAtIndex:1];
+
+    range.location = 2;
+    range.length = length - range.location;
+
+    if (c == '\'') {
+      range = [_str rangeOfString:@"'" options:0 range:range];
+
+      if (range.length == 0)
+        return range;
+      
+      range.length = range.location + 1;
+
+      if (range.length < length) {
+        rangeTarget = [self findLinkTargetFromString:
+                              [_str substringFromIndex:range.length]];
+
+        if (rangeTarget.length > 0)
+          range.length += rangeTarget.length;
+      }
+    } 
+    else if (c == '{') {
+      range = [_str rangeOfString:@"}" options:0 range:range];
+
+      if (range.length == 0)
+        return range;
+      
+      range.length = range.location + 1;
+
+      if (range.length < length) {
+        rangeTarget = [self findLinkTargetFromString:
+                              [_str substringFromIndex:range.length]];
+
+        if (rangeTarget.length > 0)
+          range.length += rangeTarget.length;
+      }
+    } 
+    else {
+      range = [_str rangeOfString:@" " options:0 range:range];
+      
+      range.length = (range.length == 0) ? length : range.location;
+    }
+    
+    range.location = 0;
+
+    if (debugOn) NSLog(@"    range(0,%d)", range.length);
+    return range;
+  }
+  
+  range.location = NSNotFound;
+  range.length   = 0;
+  
+  if (debugOn) NSLog(@"    not found.");
+  return range;
+}
+
+- (NSRange)findLinkImageSubstring:(NSString *)_str {
+  NSRange range;
+  int     i, length;
+  
+  for (i = 0, length = [_str length]; i < length; i++) {
+    unichar c;
+
+    c = [_str characterAtIndex:i];
+
+    if (!(c == ']' && i + 1 < length))
+      continue;
+
+    range = [self _findLinkBlockTargetSubstring:
+                   [_str substringFromIndex:i + 1]];
+      
+    if (range.length > 0) {
+        range.length   += (range.location + i + 1);
+        range.location = 0;
+    }
+    
+    return range;
+  }
+
+  range.location = NSNotFound;
+  range.length = 0;
+
+  return range;
+}
+
+- (NSRange)findLinkSubstring:(NSString *)_str {
+  NSRange range;
+  int     i, length;
+
+  length = [_str length];
+  if (debugOn) NSLog(@"find link substring: '%@'(%d)", _str, length);
+
+  for (i = 0; i < length; i++) {
+    unichar c;
+
+    c = [_str characterAtIndex:i];
+
+    if (!(c == ST_LINK_CHAR && ((i + 1) < length)))
+      continue;
+
+    range = [self _findLinkBlockTargetSubstring:
+                   [_str substringFromIndex:i + 1]];
+      
+    if (range.length > 0) {
+      range.length   += (range.location + i + 1);
+      range.location = 0;
+    }
+    
+    return range;
+  }
+  
+  range.location = NSNotFound;
+  range.length = 0;
+
+  return range;
+}
+
+- (NSRange)findLinkTargetFromString:(NSString *)_str {
+  int     i, length;
+  BOOL   tag = NO;
+  NSRange range;
+  
+  for (i = 0, length = [_str length]; i < length; i++) {
+    unichar c;
+
+    c = [_str characterAtIndex:i];
+
+    if (!tag && c == ':' && i + 1 < length) {
+      c = [_str characterAtIndex:i + 1];
+
+      if (c == ':') {
+        i++;
+        tag = YES;
+      }
+    } 
+    else if (tag) {
+      if (c == '\'') {
+        range.location = i + 1;
+        range.length = length - range.location;
+
+        range = [_str rangeOfString:@"'" options:0 range:range];
+        if (range.length == 0)
+          return range;
+       
+        length = range.location + 1;
+
+        break;
+      } 
+      else {
+        range.location = i;
+        range.length   = length - i;
+       
+        range = [_str rangeOfString:@" " options:0 range:range];
+        if (range.length == 0)
+          break;
+       
+        length = range.location;
+        break;
+      }
+    } 
+    else {
+      range.location = NSNotFound;
+      range.length   = 0;
+      
+      return range;
+    }
+  }
+
+  range.location = 0;
+  range.length = length;
+
+  return range;
+}
+
+- (NSRange)findDynamicKeySubstring:(NSString *)_str {
+  NSRange range;
+  int     i, length;
+  
+  for (i = 0, length = [_str length]; i < length; i++) {
+    unichar c;
+
+    c = [_str characterAtIndex:i];
+
+    if (c == ST_DYNAMICKEY_CHAR) {
+      range.location = 0;
+      range.length = i;
+
+      return range;
+    }
+  }
+
+  range.location = NSNotFound;
+  range.length   = 0;
+  return range;
+}
+
+/* processing */
+
+- (NSString *)boldText:(NSString *)_str inContext:(NSDictionary *)_ctx {
+  return (_delegate)
+    ? [_delegate insertBold:_str inContext:_ctx]
+    : _str;
+}
+
+- (NSString *)italicsText:(NSString *)_str inContext:(NSDictionary *)_ctx {
+  return (_delegate)
+    ? [_delegate insertItalics:_str inContext:_ctx]
+    : _str;
+}
+
+- (NSString *)underlineText:(NSString *)_str inContext:(NSDictionary *)_ctx {
+  return (_delegate)
+    ? [_delegate insertUnderline:_str inContext:_ctx]
+    : _str;
+}
+
+/* links */
+
+- (NSString *)_linkBlockTarget:(NSString *)_str withName:(NSString *)aName 
+  isImage:(BOOL)isImage inContext:(NSDictionary *)_ctx 
+{
+  NSString *linkName = aName;
+  NSRange  range;
+  int     length;
+  unichar  c;
+  NSArray  *components;
+  NSString *link, *linkType = nil, *target = nil;
+  NSRange  rangeOut;
+
+  if (_delegate == nil)
+    return _str;
+  
+  length = [_str length];
+  if (length < 2)
+    return nil;
+
+  c = [_str characterAtIndex:0];
+  if (c != ':') {
+    if (debugOn) NSLog(@"no link in: '%@'", _str);
+    return nil;
+  }
+  
+  c = [_str characterAtIndex:1];
+
+  range.location = 2;
+  range.length = length - range.location;
+
+  if (c == '\'') {
+    rangeOut = [_str rangeOfString:@"'" options:0 range:range];
+
+    if (rangeOut.length == 0)
+      return nil;
+      
+    range.length = rangeOut.location - range.location;
+
+    target = [self linkTargetFromString:
+                    [_str substringFromIndex:rangeOut.location + 1]];
+  }
+  else if (c == '{') {
+    rangeOut = [_str rangeOfString:@"}" options:0 range:range];
+
+    if (rangeOut.length == 0)
+      return nil;
+      
+    range.location--;
+    range.length = rangeOut.location - range.location + 1;
+      
+    linkType = @"ibn";
+      
+    target = [self linkTargetFromString:
+                    [_str substringFromIndex:rangeOut.location + 1]];
+  }
+  else {
+    rangeOut = [_str rangeOfString:@"::" options:0 range:range];
+      
+    range.location--;
+      
+    if (rangeOut.length == 0) {
+      rangeOut = [_str rangeOfString:@" " options:0 range:range];
+
+      range.length = (rangeOut.length == 0)
+       ? length - range.location
+       : rangeOut.location - range.location;
+    } 
+    else {
+      range.length = rangeOut.location - range.location;
+       
+      target = [self linkTargetFromString:
+                      [_str substringFromIndex:rangeOut.location]];
+    }
+  }
+
+  link       = [_str substringWithRange:range];
+  components = [link componentsSeparatedByString:@":"];
+
+  if (!linkType)
+    linkType = [components objectAtIndex:0];
+    
+  if (!isImage) {
+    if ([linkType isEqualToString:@"mailto"]) {
+      return [_delegate insertEmail:linkName withAddress:link 
+                       inContext:_ctx];
+    } 
+      
+    if ([linkType isEqualToString:@"img"]) {
+      NSString *url;
+
+      url = [link substringFromIndex:[linkType length] + 1];
+
+      return [_delegate insertImage:linkName withUrl:url inContext:_ctx];
+    } 
+      
+    if ([linkType isEqualToString:@"ibn"]) {
+      if (debugOn) NSLog(@"IBN link %@", linkName);
+      return [_delegate insertExtrapolaLink:linkName 
+                       parameters:[link propertyList] 
+                       withTarget:target inContext:_ctx];
+    }
+      
+    if (debugOn) NSLog(@"link %@: %@", linkName, link);
+    return [_delegate insertLink:linkName withUrl:link target:target
+                     inContext:_ctx];
+  } 
+  
+  if (debugOn) NSLog(@"img %@: %@", linkName, link);
+  return [_delegate insertImage:linkName withUrl:link inContext:_ctx];
+}
+
+- (NSString *)linkImage:(NSString *)_str inContext:(NSDictionary *)_ctx {
+  NSString *linkName = nil;
+  NSRange  range;
+  int     i, length, startOfTarget;
+
+  if (_delegate == nil)
+    return _str;
+
+  length = [_str length];
+  
+  if (length > 1) {
+    unichar c;
+
+    range.location = 0;
+    range.length = length;
+
+    range = [_str rangeOfString:@"]" options:0 range:range];
+
+    if (range.length == 0)
+      return _str;
+    
+    startOfTarget = range.location + 1;
+
+    for (i = 1; i < range.location; i++) {
+      c = [_str characterAtIndex:i];
+
+      if (c == ST_LINK_CHAR && i + 1 < length) {
+        range.location = 1;
+        range.length = i - 1;
+
+        linkName = [_str substringWithRange:range];
+
+        range.length = startOfTarget - (i + 2);
+        range.location = i + 1;
+
+        linkName = [self _linkBlockTarget:[_str substringWithRange:range]
+                         withName:linkName isImage:YES inContext:_ctx];
+
+        break;
+      }
+    }
+
+    if (linkName) {
+      NSString *result;
+
+      result = [self _linkBlockTarget:
+                       [_str substringFromIndex:startOfTarget] 
+                     withName:linkName isImage:NO inContext:_ctx];
+      
+      if (result == nil)
+        result = _str;
+      
+      return result;
+    }
+  }
+
+  return _str;
+}
+
+- (NSString *)linkText:(NSString *)_str inContext:(NSDictionary *)_ctx {
+  NSString *linkName;
+  int     i, length;
+  
+  if (_delegate == nil)
+    return _str;
+  
+  for (i = 0, length = [_str length]; i < length; i++) {
+    NSString *result;
+    unichar c;
+
+    c = [_str characterAtIndex:i];
+    
+    if (!(c == ST_LINK_CHAR && (i + 1 < length)))
+      continue;
+    
+    linkName = [_str substringToIndex:i];
+    
+    result = [self _linkBlockTarget:[_str substringFromIndex:i + 1] 
+                   withName:linkName isImage:NO inContext:_ctx];
+    return result ? result : _str;
+  }
+  
+  return _str;
+}
+
+- (NSString *)linkTargetFromString:(NSString *)_str {
+  int    i, length, start;
+  BOOL   tag = NO;
+  NSRange range;
+
+  length = [_str length];
+
+  for (start = i = 0; i < length; i++) {
+    unichar c;
+
+    c = [_str characterAtIndex:i];
+
+    if (!tag && c == ':' && i + 1 < length) {
+      c = [_str characterAtIndex:i + 1];
+
+      if (c == ':') {
+        start = i + 2;
+        i++;
+        tag = YES;
+      }
+    } 
+    else if (c == '\'') {
+      range.location = i + 1;
+      range.length = length - range.location;
+
+      range = [_str rangeOfString:@"'" options:0 range:range];
+
+      if (range.length == 0)
+        break;
+      
+      length = range.location;
+      start++;
+
+      break;
+    }
+    else {
+      break;
+    }
+  }
+
+  range.location = start;
+  range.length = length - range.location;
+
+  if (range.length <= 0) {
+    return nil;
+  }
+
+  return [_str substringWithRange:range];
+}
+
+- (NSString *)dynamicKeyText:(NSString *)_str inContext:(NSDictionary *)_ctx {
+  if (_delegate)
+    return [_delegate insertDynamicKey:_str inContext:_ctx];
+
+  return _str;
+}
+
+- (NSString *)preprocessText:(NSString *)_str inContext:(NSDictionary *)_ctx {
+  // TODO: breaks on libFoundation
+  // TODO: need to find out what this is exactly supposed to do
+  NSMutableString *result;
+  NSRange rangeToCopy, range, rangeEnd;
+  int     length;
+  
+  if (debugOn) NSLog(@"preprocess: '%@'", _str);
+  
+  if (!self->runPreprocessor)
+    return _str;
+  
+  self->runPreprocessor = NO;
+  
+  length = [_str length];
+  result = [NSMutableString stringWithCapacity:length];
+
+  range.location = 0;
+  range.length   = length;
+
+  rangeEnd.location = 0;
+  rangeEnd.length   = length;
+
+  rangeToCopy.location = 0;
+  rangeToCopy.length   = length;
+  
+  // TODO: the NSNotFound check might make trouble on libFoundation
+  for (; range.location != NSNotFound && range.location < length;) {
+    range = [_str rangeOfString:preprocessorTag options:0 range:range];
+    
+    if (range.length == 0) {
+      if (rangeEnd.location == 0)
+        return _str;
+      
+      rangeToCopy.location = rangeEnd.location + 2;
+      rangeToCopy.length   = (length - rangeToCopy.location);
+      
+      [result appendString:[_str substringWithRange:rangeToCopy]];
+      
+      continue;
+    }
+    
+    rangeToCopy.location = rangeEnd.location;
+
+    if (rangeEnd.location > 0)
+      rangeToCopy.location += 2;
+      
+    rangeEnd.location = range.location + 2;
+    rangeEnd.length = length - rangeEnd.location;
+
+    rangeEnd = [_str rangeOfString:preprocessorTag options:0 range:rangeEnd];
+      
+    if (rangeEnd.length > 0) {
+      NSRange  keyRange;
+      NSString *text;
+       
+      rangeToCopy.length = (range.location - rangeToCopy.location);
+       
+      if (rangeToCopy.length > 0) {
+       NSString *s;
+         
+       s = [_str substringWithRange:rangeToCopy];
+       [result appendString:s];
+      }
+
+      keyRange.location = range.location + 2;
+      keyRange.length = rangeEnd.location - keyRange.location;
+        
+      text = [_delegate insertPreprocessedTextForKey:
+                         [_str substringWithRange:keyRange] 
+                       inContext:_ctx];
+      if (text)
+       [result appendString:text];
+        
+      range.location = rangeEnd.location + 2;
+      range.length = length - range.location;
+
+      self->runPreprocessor = YES;
+    } 
+    else {
+      range.location = NSNotFound;
+
+      rangeToCopy.length = length - rangeToCopy.location;
+      
+      [result appendString:[_str substringWithRange:rangeToCopy]];
+    }
+  }
+
+  return result;
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  if (self->_elements) 
+    [ms appendFormat:@" #elements=%d", [self->_elements count]];
+
+  if (self->_delegate) {
+    [ms appendFormat:@" delegate=0x%08X<%@>", 
+         self->_delegate, NSStringFromClass([(id)self->_delegate class])];
+  }
+  
+  if (self->runPreprocessor)
+    [ms appendFormat:@" run-preprocessor"];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* StructuredTextBodyElement */
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextDocument.h b/skyrix-xml/STXSaxDriver/Model/StructuredTextDocument.h
new file mode 100644 (file)
index 0000000..0e76b88
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#import <Foundation/NSObject.h>
+
+@class NSMutableArray;
+@class StructuredTextBodyElement;
+
+@interface StructuredTextDocument : NSObject
+{
+  NSMutableArray *_bodyElements;
+}
+
+- (NSMutableArray *)bodyElements;
+- (void)addBodyElement:(StructuredTextBodyElement *)aBody;
+
+@end
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextDocument.m b/skyrix-xml/STXSaxDriver/Model/StructuredTextDocument.m
new file mode 100644 (file)
index 0000000..31a2f3e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "StructuredTextDocument.h"
+#include "StructuredTextBodyElement.h"
+#include "common.h"
+
+@implementation StructuredTextDocument
+
+- (void)dealloc {
+  [self->_bodyElements release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSMutableArray *)bodyElements {
+  if (self->_bodyElements == nil)
+    self->_bodyElements = [[NSMutableArray alloc] init];
+  
+  return self->_bodyElements;
+}
+
+/* operations */
+
+- (void)addBodyElement:(StructuredTextBodyElement *)_body {
+  if (_body == nil)
+    return;
+
+  [[self bodyElements] addObject:_body];
+}
+
+@end /* StructuredTextDocument */
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextHeader.h b/skyrix-xml/STXSaxDriver/Model/StructuredTextHeader.h
new file mode 100644 (file)
index 0000000..5142597
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "StructuredTextBodyElement.h"
+
+@class NSString, NSDictionary;
+
+@interface StructuredTextHeader : StructuredTextBodyElement
+{
+  NSString *_text;
+  int     level;
+}
+
+- (id)initWithString:(NSString *)aString level:(int)aLevel;
+
+/* accessors */
+
+- (NSString *)text;
+- (int)level;
+
+/* operations */
+
+- (NSString *)textParsedWithDelegate:(id<StructuredTextRenderingDelegate>)_dele
+  inContext:(NSDictionary *)aContext;
+
+@end
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextHeader.m b/skyrix-xml/STXSaxDriver/Model/StructuredTextHeader.m
new file mode 100644 (file)
index 0000000..159179b
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "StructuredTextHeader.h"
+#include "common.h"
+
+@implementation StructuredTextHeader
+
+- (id)initWithString:(NSString *)_str level:(int)_level {
+  if ((self = [super init])) {
+    self->_text = [_str copy];
+    self->level = _level;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->_text release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)text {
+  return self->_text;
+}
+
+- (int)level {
+  return self->level;
+}
+
+/* operations */
+
+- (NSString *)textParsedWithDelegate:(id<StructuredTextRenderingDelegate>)_del
+  inContext:(NSDictionary *)_ctx 
+{
+  self->_delegate = _del;
+  return [self parseText:[self text] inContext:_ctx];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:128];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  /* header specific */
+
+  if (self->_text) [ms appendFormat:@" text-len=%d", [self->_text length]];
+  if (self->level) [ms appendFormat:@" level=%i",    self->level];
+  
+  /* common stuff */
+  
+  if (self->_elements) 
+    [ms appendFormat:@" #elements=%d", [self->_elements count]];
+
+  if (self->_delegate) {
+    [ms appendFormat:@" delegate=0x%08X<%@>", 
+         self->_delegate, NSStringFromClass([(id)self->_delegate class])];
+  }
+  
+  if (self->runPreprocessor)
+    [ms appendFormat:@" run-preprocessor"];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* StructuredTextHeader */
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextList.h b/skyrix-xml/STXSaxDriver/Model/StructuredTextList.h
new file mode 100644 (file)
index 0000000..ce2587c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#ifndef __StructuredTextList_H__
+#define __StructuredTextList_H__
+
+#include "StructuredTextBodyElement.h"
+
+#define StructuredTextList_BULLET      0
+#define StructuredTextList_ENUMERATED  1
+#define StructuredTextList_DEFINITION  2
+
+@class StructuredTextListItem;
+
+@interface StructuredTextList : StructuredTextBodyElement
+{
+  int typology;
+}
+
+- (id)initWithTypology:(int)aValue;
+
+/* accessors */
+
+- (int)typology;
+
+/* operations */
+
+- (void)addElement:(StructuredTextListItem *)anItem;
+
+@end
+
+#endif /* __StructuredTextList_H__ */
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextList.m b/skyrix-xml/STXSaxDriver/Model/StructuredTextList.m
new file mode 100644 (file)
index 0000000..7eb0577
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "StructuredTextList.h"
+#include "StructuredTextListItem.h"
+#include "common.h"
+
+@implementation StructuredTextList
+
+- (id)initWithTypology:(int)aValue {
+  if ((self = [super init])) {
+    self->typology = aValue;
+  }
+  return self;
+}
+
+/* accessors */
+
+- (int)typology {
+  return self->typology;
+}
+
+/* operations */
+
+- (void)addElement:(StructuredTextListItem *)_item {
+  if (_item == nil)
+    return;
+
+  [super addElement:_item];
+  [_item setList:self];
+}
+
+@end /* StructuredTextList */
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextListItem.h b/skyrix-xml/STXSaxDriver/Model/StructuredTextListItem.h
new file mode 100644 (file)
index 0000000..dc89085
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#ifndef __StructuredTextListItem_H__
+#define __StructuredTextListItem_H__
+
+#include "StructuredTextBodyElement.h"
+
+@class NSString, NSDictionary;
+@class StructuredTextList;
+
+@interface StructuredTextListItem : StructuredTextBodyElement
+{
+  StructuredTextList *_list;  // not retained
+  NSString          *_title;
+  NSString          *_text;
+}
+
+- (id)initWithTitle:(NSString *)aTitle text:(NSString *)aString;
+
+/* accessors */
+
+- (NSString *)title;
+- (NSString *)text;
+
+- (void)setList:(StructuredTextList *)aList;
+- (StructuredTextList *)list;
+
+/* parsing */
+
+- (NSString *)titleParsedWithDelegate:(id<StructuredTextRenderingDelegate>)_del
+  inContext:(NSDictionary *)_ctx;
+- (NSString *)textParsedWithDelegate:(id<StructuredTextRenderingDelegate>)_del
+  inContext:(NSDictionary *)_ctx;
+
+@end
+
+#endif /* __StructuredTextListItem_H__ */
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextListItem.m b/skyrix-xml/STXSaxDriver/Model/StructuredTextListItem.m
new file mode 100644 (file)
index 0000000..6300332
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "StructuredTextListItem.h"
+#include "StructuredTextList.h"
+#include "common.h"
+
+@interface NSObject(SetListPrivate)
+- (void)setList:(id)_list;
+@end
+
+@implementation StructuredTextListItem
+
+- (id)initWithTitle:(NSString *)_aTitle text:(NSString *)_aString {
+  if ((self = [super init])) {
+    self->_title = [_aTitle  copy];
+    self->_text  = [_aString copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->_title release];
+  [self->_text  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)title {
+  return self->_title;
+}
+
+- (NSString *)text {
+  return self->_text;
+}
+
+- (void)setList:(StructuredTextList *)aList {
+  self->_list = aList;
+}
+- (StructuredTextList *)list {
+  return self->_list;
+}
+
+/* operations */
+
+- (void)addElement:(StructuredTextBodyElement *)_item {
+  if (_item == nil)
+    return;
+  
+  [super addElement:_item];
+  
+  if ([_item respondsToSelector:@selector(setList:)])
+    [_item setList:_list];
+}
+
+/* parsing parts */
+
+- (NSString *)titleParsedWithDelegate:(id<StructuredTextRenderingDelegate>)_d
+  inContext:(NSDictionary *)_ctx 
+{
+  self->_delegate = _d;
+  return [self parseText:[self title] inContext:_ctx];
+}
+
+- (NSString *)textParsedWithDelegate:(id<StructuredTextRenderingDelegate>)_del
+  inContext:(NSDictionary *)_ctx 
+{
+  self->_delegate = _del;
+  return [self parseText:[self text] inContext:_ctx];
+}
+
+@end /* StructuredTextListItem */
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextLiteralBlock.h b/skyrix-xml/STXSaxDriver/Model/StructuredTextLiteralBlock.h
new file mode 100644 (file)
index 0000000..422894e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+
+@interface StructuredTextLiteralBlock : NSObject
+{
+  NSString *_text;
+}
+
+- (id)initWithString:(NSString *)aString;
+
+/* accessors */
+
+- (NSString *)text;
+
+@end
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextLiteralBlock.m b/skyrix-xml/STXSaxDriver/Model/StructuredTextLiteralBlock.m
new file mode 100644 (file)
index 0000000..155c9d6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "StructuredTextLiteralBlock.h"
+#include "common.h"
+
+@implementation StructuredTextLiteralBlock
+
+- (id)initWithString:(NSString *)_str {
+  if ((self = [super init])) {
+    self->_text = [_str copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->_text release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)text {
+  return self->_text;
+}
+
+@end /* StructuredTextLiteralBlock */
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextParagraph.h b/skyrix-xml/STXSaxDriver/Model/StructuredTextParagraph.h
new file mode 100644 (file)
index 0000000..10da8d5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "StructuredTextBodyElement.h"
+
+@interface StructuredTextParagraph : StructuredTextBodyElement
+{
+  NSString *_text;
+}
+
+- (id)initWithString:(NSString *)aString;
+
+/* accessors */
+
+- (NSString *)text;
+
+/* parsing */
+
+- (NSString *)textParsedWithDelegate:(id<StructuredTextRenderingDelegate>)_del
+  inContext:(NSDictionary *)aContext;
+
+@end
diff --git a/skyrix-xml/STXSaxDriver/Model/StructuredTextParagraph.m b/skyrix-xml/STXSaxDriver/Model/StructuredTextParagraph.m
new file mode 100644 (file)
index 0000000..7356fdf
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2004 eXtrapola Srl
+
+  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$
+
+#include "StructuredTextParagraph.h"
+#include "common.h"
+
+@implementation StructuredTextParagraph
+
+- (id)initWithString:(NSString *)aString {
+  if ((self = [super init])) {
+    _text = [aString retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [_text release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)text {
+  return _text;
+}
+
+/* processing */
+
+- (NSString *)textParsedWithDelegate:(id<StructuredTextRenderingDelegate>)_del
+  inContext:(NSDictionary *)_ctx 
+{
+  NSString *text;
+
+  self->_delegate = _del;
+  text = [self parseText:[self text] inContext:_ctx];
+  
+  return (_del)
+    ? [_del insertText:text inContext:_ctx]
+    : text;
+}
+
+@end /* StructuredTextParagraph */
diff --git a/skyrix-xml/STXSaxDriver/README b/skyrix-xml/STXSaxDriver/README
new file mode 100644 (file)
index 0000000..e2fa201
--- /dev/null
@@ -0,0 +1,105 @@
+# $Id$
+
+Note: this is the initial release, it should contain some bugs ;-)
+
+STXSaxDriver
+============
+
+This project contains a skyrix-xml/SaxObjC SAX driver bundle which can process
+so called "structured text" files, or in short "STX". The parsing events are
+reported as XHTML tags.
+
+Example:
+---snip---
+* item A
+
+* item B
+---snap---
+will be reported as SAX events similiar to such an HTML file:
+---snip---
+<ul>
+  <li>item A</li>
+  <li>item B</li>
+</ul>
+---snap---
+
+The basis for this driver bundle, the StructuredText framework, was initially
+written by Mirko Viviani and Giulio Cesare Solaroli and sponsored by eXtrapola
+Srl.
+Note that the "original" StructuredText framework is much more capable and 
+generic than what this SAX driver provides. On the pro side, your applications
+do not need to care about the actual tag format if you use SaxObjC. Your
+applications can use either, XHTML, HTML, PYX or STX files using the available
+SaxObjC drivers without any additional work.
+
+Supported MIME Types
+====================
+
+Not sure what the correct MIME type for structured text is supposed to be, for
+now we register this driver for the
+
+  "text/structured"
+
+MIME type.
+
+How to try
+==========
+
+Just use the saxxml or domxml tools which are part of skyrix-xml, eg:
+  
+  saxxml -XMLReader STXSaxDriver data/hhtest1.stx
+  
+This will print the XHTML representation of the STX file on stdout.
+
+STX Functionality which is implemented
+======================================
+
+Guilio writes:
+---snip---
+Anyway, we used this document as "reference":
+
+  http://plone.org/documentation/howto/FrontPage/UsingStructuredText
+
+of the construct defined there, we have skipped just the table construct.
+
+But we have added a few thinks:
+- it is possible to use quotes in link url (es: if you have 
+  "Link":http://www.url.com, the comma will end up into the link; to avoid 
+  this, we can parse a string like that: "Link":'http://www.url.com', and the 
+  comma will be left out of the link).
+- link target: they are not a first class citizen (specially in XHTML), but 
+  sometime they are very usefull. To define a target, you can add it after a 
+  link: "Link":'http://www.url.com'::'target'. Also the target can be quoted 
+  in order to avoid problems with punctuation.
+- Image link: in order to create a link around an image, we have defined the 
+  following sintax: 
+    ["Alt text":http://www.url.com/image.gif]:'http://www.url.com'. 
+  Here too, quoting and target are supported.
+---snap---
+
+Defaults
+========
+
+STXDebugEnabled          YES|NO
+STXSaxDriverDebugEnabled YES|NO
+
+Structured Text Links
+=====================
+
+http://www.zope.org/Members/millejoh/structuredText
+http://plone.org/documentation/howto/FrontPage/UsingStructuredText
+
+Classes
+=======
+  
+  NSObject
+    STXSaxDriver < SaxXMLReader >
+
+  NSObject
+    StructuredLine
+    StructuredStack
+    StructuredText
+    StructuredTextRenderingDelegate
+      StructuredTextRenderingDelegate_XHTML
+
+  NSString(STX)
diff --git a/skyrix-xml/STXSaxDriver/STXSaxDriver-Info.plist b/skyrix-xml/STXSaxDriver/STXSaxDriver-Info.plist
new file mode 100644 (file)
index 0000000..1bd903b
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>STXSaxDriver</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.STXSaxDriver</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
diff --git a/skyrix-xml/STXSaxDriver/STXSaxDriver.h b/skyrix-xml/STXSaxDriver/STXSaxDriver.h
new file mode 100644 (file)
index 0000000..0f90487
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __ExtraSTX_STXSaxDriver_H__
+#define __ExtraSTX_STXSaxDriver_H__
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxObjC.h>
+
+@class NSArray, NSDictionary;
+@class SaxAttributes;
+@class StructuredTextParagraph, StructuredTextList, StructuredTextListItem;
+@class StructuredTextLiteralBlock, StructuredTextHeader;
+
+@interface STXSaxDriver : NSObject < SaxXMLReader >
+{
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+  id<NSObject,SaxLexicalHandler> lexicalHandler;
+  id<NSObject,SaxEntityResolver> entityResolver;
+
+  NSDictionary  *context;
+  SaxAttributes *attrs;
+}
+
+/* handlers */
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler;
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler;
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler;
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler;
+- (id<NSObject,SaxContentHandler>)contentHandler;
+- (id<NSObject,SaxDTDHandler>)dtdHandler;
+- (id<NSObject,SaxErrorHandler>)errorHandler;
+- (id<NSObject,SaxEntityResolver>)entityResolver;
+
+/* parsing */
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId;
+
+/* generating events */
+
+- (void)produceSaxEventsForParagraph:(StructuredTextParagraph *)_p;
+- (void)produceSaxEventsForList:(StructuredTextList *)_list;
+- (void)produceSaxEventsForListItem:(StructuredTextListItem *)_item;
+- (void)produceSaxEventsForLiteralBlock:(StructuredTextLiteralBlock *)_block;
+- (void)produceSaxEventsForHeader:(StructuredTextHeader *)_header;
+
+- (void)produceSaxEventsForElement:(id)_element;
+- (void)produceSaxEventsForElements:(NSArray *)_elems;
+
+@end
+
+#endif /* __ExtraSTX_STXSaxDriver_H__ */
diff --git a/skyrix-xml/STXSaxDriver/STXSaxDriver.m b/skyrix-xml/STXSaxDriver/STXSaxDriver.m
new file mode 100644 (file)
index 0000000..b40638d
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "STXSaxDriver.h"
+#include "StructuredText.h"
+#include "StructuredTextList.h"
+#include "StructuredTextListItem.h"
+#include "StructuredTextLiteralBlock.h"
+#include "StructuredTextHeader.h"
+#include "StructuredTextParagraph.h"
+#include <SaxObjC/XMLNamespaces.h>
+#include "common.h"
+
+static NSString *SaxDeclHandlerProperty =
+  @"http://xml.org/sax/properties/declaration-handler";
+static NSString *SaxLexicalHandlerProperty =
+  @"http://xml.org/sax/properties/lexical-handler";
+
+@interface NSObject(SAX)
+- (void)produceSaxEventsOnSTXSaxDriver:(STXSaxDriver *)_sax;
+@end
+
+@implementation STXSaxDriver
+
+static BOOL debugOn = NO;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  debugOn = [ud boolForKey:@"STXSaxDriverDebugEnabled"];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->attrs = [[SaxAttributes alloc] init];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->context        release];
+  [self->attrs          release];
+  
+  [self->lexicalHandler release];
+  [self->contentHandler release];
+  [self->errorHandler   release];
+  [self->entityResolver release];
+  [super dealloc];
+}
+
+/* properties */
+
+- (void)setProperty:(NSString *)_name to:(id)_value {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
+    [self->lexicalHandler autorelease];
+    self->lexicalHandler = [_value retain];
+    return;
+  }
+  if ([_name isEqualToString:SaxDeclHandlerProperty]) {
+    return;
+  }
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+}
+- (id)property:(NSString *)_name {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty])
+    return self->lexicalHandler;
+  if ([_name isEqualToString:SaxDeclHandlerProperty])
+    return nil;
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+  return nil;
+}
+
+/* features */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value {
+  return;
+#if 0 // be tolerant
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+#endif
+}
+- (BOOL)feature:(NSString *)_name {
+  return NO;
+}
+
+/* handlers */
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  [self->contentHandler autorelease];
+  self->contentHandler = [_handler retain];
+}
+- (id<NSObject,SaxContentHandler>)contentHandler {
+  return self->contentHandler;
+}
+
+- (void)setLexicalHandler:(id<NSObject,SaxLexicalHandler>)_handler {
+  [self->lexicalHandler autorelease];
+  self->lexicalHandler = [_handler retain];
+}
+- (id<NSObject,SaxLexicalHandler>)lexicalHandler {
+  return self->lexicalHandler;
+}
+
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
+}
+- (id<NSObject,SaxDTDHandler>)dtdHandler {
+  return nil;
+}
+
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  [self->errorHandler autorelease];
+  self->errorHandler = [_handler retain];
+}
+- (id<NSObject,SaxErrorHandler>)errorHandler {
+  return self->errorHandler;
+}
+
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
+  [self->entityResolver autorelease];
+  self->entityResolver = [_handler retain];
+}
+- (id<NSObject,SaxEntityResolver>)entityResolver {
+  return self->entityResolver;
+}
+
+/* support */
+
+- (void)_beginTag:(NSString *)_tag {
+  [self->contentHandler startElement:_tag namespace:XMLNS_XHTML rawName:_tag
+                        attributes:nil /* id<SaxAttributes> */];
+}
+- (void)_endTag:(NSString *)_tag {
+  [self->contentHandler endElement:_tag namespace:XMLNS_XHTML rawName:_tag];
+}
+- (void)_characters:(NSString *)_chars {
+  unichar      *buf;
+  unsigned int len;
+  
+  if ((len = [_chars length]) == 0) // TODO: may or may not be correct
+    return;
+  
+  buf = calloc(len + 4, sizeof(unichar)); // TODO: cache/reuse buffer
+  [_chars getCharacters:buf];
+  
+  [self->contentHandler characters:buf length:len];
+  if (buf) free(buf);
+}
+
+/* STX delegate */
+
+- (NSString *)insertText:(NSString *)_txt inContext:(NSDictionary *)_ctx {
+  if (debugOn) NSLog(@"        insert text: (len=%d)", [_txt length]);
+  [self _beginTag:@"p"];
+  [self _characters:_txt];
+  [self _endTag:@"p"];
+  return nil;
+}
+
+- (NSString *)insertItalics:(NSString *)_txt inContext:(NSDictionary *)_ctx {
+  if (debugOn) NSLog(@"        insert italics: (len=%d)", [_txt length]);
+  [self _beginTag:@"em"];
+  [self _characters:_txt];
+  [self _endTag:@"em"];
+  return nil;
+}
+
+- (NSString *)insertUnderline:(NSString *)_txt inContext:(NSDictionary *)_ctx {
+  if (debugOn) NSLog(@"        insert underline: (len=%d)", [_txt length]);
+  [self _beginTag:@"u"];
+  [self _characters:_txt];
+  [self _endTag:@"u"];
+  return nil;
+}
+
+- (NSString *)insertBold:(NSString *)_txt inContext:(NSDictionary *)_ctx {
+  if (debugOn) NSLog(@"        insert bold: (len=%d)", [_txt length]);
+  [self _beginTag:@"strong"];
+  [self _characters:_txt];
+  [self _endTag:@"strong"];
+  return nil;
+}
+
+- (NSString *)insertPreformatted:(NSString *)_txt
+  inContext:(NSDictionary *)_ctx 
+{
+  [self _beginTag:@"pre"];
+  [self _characters:_txt];
+  [self _endTag:@"pre"];
+  return nil;
+}
+
+- (NSString *)insertLink:(NSString *)_txt 
+  withUrl:(NSString *)_url target:(NSString *)_target 
+  inContext:(NSDictionary *)_ctx 
+{
+  // TODO: need to generate SaxAttributes here
+  
+  [self->attrs clear];
+  [self->attrs 
+       addAttribute:@"href" uri:XMLNS_XHTML rawName:@"href"
+       type:@"CDATA" value:_url];
+  if ([_target length] > 0) {
+    [self->attrs
+        addAttribute:@"target" uri:XMLNS_XHTML rawName:@"target"
+        type:@"CDATA" value:_target];
+  }
+
+  [self->contentHandler startElement:@"a" namespace:XMLNS_XHTML rawName:@"a"
+                        attributes:self->attrs];
+  [self _characters:_txt];
+  [self _endTag:@"a"];
+
+  // if we return nil, the content will be generated as if it didn't match
+  // if we return an empty string, a zero-length string is reported
+  return @""; 
+}
+
+- (NSString *)insertEmail:(NSString *)_txt withAddress:(NSString *)_link 
+  inContext:(NSDictionary *)_ctx 
+{
+  // TODO: check&implement
+#if 0
+  [NSString stringWithFormat:@"<a href=\"%@\">%@</a>", anAddress, _txt];
+#endif
+  return _txt;
+}
+
+- (NSString *)insertImage:(NSString *)_title withUrl:(NSString *)_src
+  inContext:(NSDictionary *)_ctx 
+{
+  // TODO: check&implement
+#if 0
+  [NSString stringWithFormat:@"<img src=\"%@\" title=\"%@\" />", anUrl, _txt];
+#endif
+  return _title;
+}
+
+- (NSString *)insertExtrapolaLink:(NSString *)_txt
+  parameters:(NSDictionary *)_paras
+  withTarget:(NSString *)_target
+  inContext:(NSDictionary *)_ctx 
+{
+  // TODO: do we want to support that?
+  if (debugOn) NSLog(@"insert extrapola link: %@", _txt);
+  [self _characters:_txt];
+  return nil;
+}
+
+- (NSString *)insertDynamicKey:(NSString *)_k inContext:(NSDictionary *)_ctx {
+  // TODO: what to do here?
+  return [_ctx objectForKey:_k];
+}
+
+- (NSString *)insertPreprocessedTextForKey:(NSString *)_k 
+  inContext:(NSDictionary *)_ctx 
+{
+  // TODO: what to do here?
+  return [_ctx objectForKey:_k];
+}
+
+/* generating element events */
+
+- (void)produceSaxEventsForParagraph:(StructuredTextParagraph *)_p {
+  NSString *s;
+  
+  if (debugOn) NSLog(@"      produce SAX events for paragraph: %@", _p);
+  
+  s = [_p textParsedWithDelegate:(id)self inContext:self->context];
+  if ([s length] > 0) [self _characters:s];
+}
+
+- (void)produceSaxEventsForHeader:(StructuredTextHeader *)_h {
+  NSString *tagName, *s;
+  
+  if (debugOn) NSLog(@"      produce SAX events for header: %@", _h);
+  
+  switch ([_h level]) {
+  case 1: tagName = @"h1"; break;
+  case 2: tagName = @"h2"; break;
+  case 3: tagName = @"h3"; break;
+  case 4: tagName = @"h4"; break;
+  case 5: tagName = @"h5"; break;
+  case 6: tagName = @"h6"; break;
+  default:
+    tagName = [@"h" stringByAppendingFormat:@"%d", [_h level]];
+    break;
+  }
+  
+  [self _beginTag:tagName];
+  if ((s = [_h textParsedWithDelegate:(id)self inContext:self->context]))
+    [self _characters:s];
+  [self _endTag:tagName];
+  
+  [self produceSaxEventsForElements:[_h elements]];
+}
+
+- (void)produceSaxEventsForList:(StructuredTextList *)_list {
+  NSString *tagName;
+  
+  if (debugOn) NSLog(@"      produce SAX events for list: %@", _list);
+  switch ([_list typology]) {
+    case StructuredTextList_BULLET:     tagName = @"ul"; break;
+    case StructuredTextList_ENUMERATED: tagName = @"ol"; break;
+    case StructuredTextList_DEFINITION: tagName = @"dl"; break;
+    default: tagName = nil;
+  }
+  
+  [self _beginTag:tagName];
+  [self produceSaxEventsForElements:[_list elements]];
+  [self _endTag:tagName];
+}
+
+- (void)produceSaxEventsForListItem:(StructuredTextListItem *)_item {
+  NSString *s;
+  int typology;
+  
+  if (debugOn) NSLog(@"        produce SAX events for item: %@", _item);
+  
+  typology = [[_item list] typology];
+
+  if (typology == StructuredTextList_DEFINITION) {
+    [self _beginTag:@"dt"];
+    if ((s = [_item titleParsedWithDelegate:(id)self inContext:self->context]))
+      [self _characters:s];
+    [self _endTag:@"dt"];
+  }
+  
+  switch (typology) {
+    case StructuredTextList_BULLET:     [self _beginTag:@"li"]; break;
+    case StructuredTextList_ENUMERATED: [self _beginTag:@"li"]; break;
+    case StructuredTextList_DEFINITION: [self _beginTag:@"dd"]; break;
+  }
+  
+  if ((s = [_item textParsedWithDelegate:(id)self inContext:self->context])) {
+    if (debugOn) NSLog(@"          chars: %d", [s length]);
+    [self _characters:s];
+  }
+  
+    if (debugOn) NSLog(@"          elems: %d", [[_item elements] count]);
+  [self produceSaxEventsForElements:[_item elements]];
+  
+  switch (typology) {
+    case StructuredTextList_BULLET:     [self _endTag:@"li"]; break;
+    case StructuredTextList_ENUMERATED: [self _endTag:@"li"]; break;
+    case StructuredTextList_DEFINITION: [self _endTag:@"dd"]; break;
+  }
+}
+
+- (void)produceSaxEventsForLiteralBlock:(StructuredTextLiteralBlock *)_block {
+  [self _beginTag:@"pre"];
+  [self _characters:[_block text]];
+  [self _endTag:@"pre"];
+}
+
+/* generating events */
+
+- (void)produceSaxEventsForElement:(id)_element {
+  if (debugOn) NSLog(@"    produce SAX events for element: %@", _element);
+
+  if (_element == nil)
+    return;
+  
+  if ([_element respondsToSelector:@selector(produceSaxEventsOnSTXSaxDriver:)])
+    [_element produceSaxEventsOnSTXSaxDriver:self];
+  else {
+    NSLog(@"Note: cannot handle STX element: %@", _element);
+  }
+}
+
+- (void)produceSaxEventsForElements:(NSArray *)_elems {
+  unsigned int i, c;
+  
+  if (debugOn)
+    NSLog(@"  produce SAX events for elements: %d", [_elems count]);
+  for (i = 0, c = [_elems count]; i < c; i++) {
+    id currentObject;
+    
+    currentObject = [_elems objectAtIndex:i];
+    if (debugOn) NSLog(@"   element[%d]/%d: %@", i, c, currentObject);
+    [self produceSaxEventsForElement:currentObject];
+  }
+}
+
+- (void)produceSaxEventsForStructuredTextDocument:(StructuredTextDocument *)_d{
+  if (debugOn) NSLog(@"  produce SAX events for document: %@", _d);
+  [self produceSaxEventsForElements:[_d bodyElements]];
+}
+
+- (void)produceSaxEventsForStructuredText:(StructuredText *)_stx 
+  systemId:(NSString *)_sysId
+{
+  if (debugOn) NSLog(@"produce SAX events for: %@", _stx);
+  
+  [self->contentHandler startDocument];
+  
+  [self produceSaxEventsForStructuredTextDocument:[_stx document]];
+
+  [self->contentHandler endDocument];
+}
+
+/* parsing */
+
+- (void)parseFromString:(NSString *)_str systemId:(NSString *)_sysId {
+  StructuredText *stx;
+  
+  if (_sysId == nil) _sysId = @"<string>";
+  stx = [[[StructuredText alloc] initWithString:_str] autorelease];
+  
+  if (debugOn) NSLog(@"%s: %@: %@", __PRETTY_FUNCTION__, _sysId, stx);
+  [self produceSaxEventsForStructuredText:stx systemId:_sysId];
+}
+
+- (void)parseFromData:(NSData *)_data systemId:(NSString *)_sysId {
+  NSString *s;
+  
+  if (_sysId == nil) _sysId = @"<data>";
+  s = [[NSString alloc] initWithData:_data encoding:NSISOLatin1StringEncoding];
+  s = [s autorelease];
+  
+  [self parseFromString:s systemId:_sysId];
+}
+
+- (void)parseFromNSURL:(NSURL *)_url systemId:(NSString *)_sysId {
+  NSData *data;
+  
+  if (_sysId == nil) 
+    _sysId = [_url absoluteString];
+  
+  if ((data = [_url resourceDataUsingCache:NO]) == nil) {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _url   ? _url   : (id)@"<nil>", @"url",
+                         _sysId ? _sysId : (id)@"<nil>", @"publicId",
+                         self,                           @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"could not retrieve URL content"
+                               userInfo:ui];
+    [self->errorHandler fatalError:e];
+    return;
+  }
+  
+  [self parseFromData:data systemId:_sysId];
+}
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
+  if (_source == nil) {
+    /* no source ??? */
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _sysId ? _sysId : (id)@"<nil>", @"publicId",
+                         self,                           @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"missing source for parsing!"
+                               userInfo:ui];
+    [self->errorHandler fatalError:e];
+    return;
+  }
+  
+  if ([_source isKindOfClass:[NSString class]]) {
+    [self parseFromString:_source systemId:_sysId];
+    return;
+  }
+
+  if ([_source isKindOfClass:[NSURL class]]) {
+    [self parseFromNSURL:_source systemId:_sysId];
+    return;
+  }
+  
+  if ([_source isKindOfClass:[NSData class]]) {
+    [self parseFromData:_source systemId:_sysId];
+    return;
+  }
+  
+  {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _source ? _source : @"<nil>", @"source",
+                         _sysId  ? _sysId  : @"<nil>", @"publicId",
+                         self,                         @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"can not handle data-source"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+    return;
+  }
+}
+
+- (void)parseFromSource:(id)_source {
+  [self parseFromSource:_source systemId:nil];
+}
+- (void)parseFromSystemId:(NSString *)_sysId {
+  NSURL *url;
+
+  if ([_sysId length] == 0) {
+    SaxParseException *e;
+    NSDictionary *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:self, @"parser", nil];
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"missing system-id for parsing!"
+                               userInfo:ui];
+    [self->errorHandler fatalError:e];
+    return;
+  }
+  
+  if ([_sysId rangeOfString:@"://"].length == 0) {
+    /* not a URL */
+    if (![_sysId isAbsolutePath])
+      _sysId = [[NSFileManager defaultManager] currentDirectoryPath];
+    url = [[[NSURL alloc] initFileURLWithPath:_sysId] autorelease];
+  }
+  else
+    url = [NSURL URLWithString:_sysId];
+  
+  [self parseFromSource:url systemId:_sysId];
+}
+
+@end /* STXSaxDriver */
diff --git a/skyrix-xml/STXSaxDriver/StructuredTextBodyElement+SAX.m b/skyrix-xml/STXSaxDriver/StructuredTextBodyElement+SAX.m
new file mode 100644 (file)
index 0000000..11409f2
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "StructuredTextBodyElement.h"
+#include "StructuredTextParagraph.h"
+#include "StructuredTextList.h"
+#include "StructuredTextListItem.h"
+#include "StructuredTextLiteralBlock.h"
+#include "StructuredTextHeader.h"
+#include "STXSaxDriver.h"
+#include "common.h"
+
+@implementation StructuredTextBodyElement(SAX)
+
+@end /* StructuredTextBodyElement(SAX) */
+
+@implementation StructuredTextParagraph(SAX)
+
+- (void)produceSaxEventsOnSTXSaxDriver:(STXSaxDriver *)_sax {
+  [_sax produceSaxEventsForParagraph:self];
+}
+
+@end /* StructuredTextParagraph(SAX) */
+
+@implementation StructuredTextList(SAX)
+
+- (void)produceSaxEventsOnSTXSaxDriver:(STXSaxDriver *)_sax {
+  [_sax produceSaxEventsForList:self];
+}
+
+@end /* StructuredTextList(SAX) */
+
+@implementation StructuredTextListItem(SAX)
+
+- (void)produceSaxEventsOnSTXSaxDriver:(STXSaxDriver *)_sax {
+  [_sax produceSaxEventsForListItem:self];
+}
+
+@end /* StructuredTextListItem(SAX) */
+
+@implementation StructuredTextLiteralBlock(SAX)
+
+- (void)produceSaxEventsOnSTXSaxDriver:(STXSaxDriver *)_sax {
+  [_sax produceSaxEventsForLiteralBlock:self];
+}
+
+@end /* StructuredTextLiteralBlock(SAX) */
+
+@implementation StructuredTextHeader(SAX)
+
+- (void)produceSaxEventsOnSTXSaxDriver:(STXSaxDriver *)_sax {
+  [_sax produceSaxEventsForHeader:self];
+}
+
+@end /* StructuredTextHeader(SAX) */
diff --git a/skyrix-xml/STXSaxDriver/TODO b/skyrix-xml/STXSaxDriver/TODO
new file mode 100644 (file)
index 0000000..7737c3c
--- /dev/null
@@ -0,0 +1,15 @@
+# $Id: TODO,v 1.1 2004/02/28 23:49:14 helge Exp $
+
+- find out proper MIME types for STX
+
+- check why data/hhtest2.stx fails
+
+- further cleanup of the sources to OGo styleguides
+
+- remove unused classes
+
+- complete support for missing STX model classes in the SAX driver?
+
+- document the exact set of STX grammar which is supported
+
+- check for memory leaks (see TODO comments in sources)
diff --git a/skyrix-xml/STXSaxDriver/Version b/skyrix-xml/STXSaxDriver/Version
new file mode 100644 (file)
index 0000000..95c761e
--- /dev/null
@@ -0,0 +1,5 @@
+# $Id$
+
+MAJOR_VERSION=1
+MINOR_VERSION=0
+SUBMINOR_VERSION:=6
diff --git a/skyrix-xml/STXSaxDriver/bundle-info.plist b/skyrix-xml/STXSaxDriver/bundle-info.plist
new file mode 100644 (file)
index 0000000..e94e3f7
--- /dev/null
@@ -0,0 +1,24 @@
+{
+  "__cvs__" = "$Id: bundle-info.plist,v 1.3 2004/03/16 17:44:27 helge Exp $";
+
+  requires = {
+    bundleManagerVersion = 1;
+    classes = (
+      { name = NSObject;    }
+    );
+  };
+  
+  provides = {
+    SAXDrivers = ( 
+        { 
+          name        = STXSaxDriver;
+          sourceTypes = ( "text/structured" ); 
+        },
+        { 
+          name        = STXSaxDriver;
+          sourceTypes = ( "text/restructured" ); 
+        }
+    );
+    classes = ( { name = STXSaxDriver;  } );
+  };
+}
diff --git a/skyrix-xml/STXSaxDriver/common.h b/skyrix-xml/STXSaxDriver/common.h
new file mode 100644 (file)
index 0000000..f771957
--- /dev/null
@@ -0,0 +1,3 @@
+// $Id$
+
+#import <Foundation/Foundation.h>
diff --git a/skyrix-xml/STXSaxDriver/data/extra_test1-expect.pyx b/skyrix-xml/STXSaxDriver/data/extra_test1-expect.pyx
new file mode 100644 (file)
index 0000000..ebdbf50
--- /dev/null
@@ -0,0 +1,8 @@
+(ul
+(li
+- a
+)li
+(li
+- b
+)li
+)ul
diff --git a/skyrix-xml/STXSaxDriver/data/extra_test1.stx b/skyrix-xml/STXSaxDriver/data/extra_test1.stx
new file mode 100644 (file)
index 0000000..872c70d
--- /dev/null
@@ -0,0 +1,3 @@
+*  a\r
+\r
+*  b
\ No newline at end of file
diff --git a/skyrix-xml/STXSaxDriver/data/extra_test2-expect.pyx b/skyrix-xml/STXSaxDriver/data/extra_test2-expect.pyx
new file mode 100644 (file)
index 0000000..0c46094
--- /dev/null
@@ -0,0 +1,68 @@
+(p
+-Municipia aggrega 12099 lettori in diverse comunita che accedono alla versione completa del magazine e ad utili servizi di personalizzazione.
+)p
+-Leggi le Faq!
+(p
+-Vuoi saperne di piu? Leggi le Faq!":{url = article; action= ciao;}
+)p
+(p
+-Richiedi l'accesso a una comunita di Municipia
+)p
+(ul
+(li
+-COM-P.A.
+-COM-P.A.":{url = article; action= ciao;}
+)li
+(li
+-Comune di Senigallia
+-Comune di Senigallia":{url = article; action= ciao;}
+)li
+(li
+-Comuneinlinea
+-Comuneinlinea":{url = article; action= ciao;}
+)li
+(li
+-Comunicatori Pubblici
+-Comunicatori Pubblici":{url = article; action= ciao;}
+)li
+(li
+-Findonline
+-Findonline":{url = article; action= ciao;}
+)li
+(li
+-Provincia Regionale di Messina
+-Provincia Regionale di Messina":{url = article; action= ciao;}
+)li
+(li
+-Provincia di Brescia
+-Provincia di Brescia":{url = article; action= ciao;}
+)li
+(li
+-Provincia di Milano
+-Provincia di Milano":{url = article; action= ciao;}
+)li
+(li
+-Provincia di Modena
+-Provincia di Modena":{url = article; action= ciao;}
+)li
+(li
+-Provincia di Napoli
+-Provincia di Napoli":{url = article; action= ciao;}
+)li
+(li
+-Provincia di Padova
+-Provincia di Padova":{url = article; action= ciao;}
+)li
+(li
+-Provincia di Pesaro-Urbino
+-Provincia di Pesaro-Urbino":{url = article; action= ciao;}
+)li
+(li
+-Provincia Autonoma di Trento
+-Provincia Autonoma di Trento":{url = article; action= ciao;}
+)li
+)ul
+-segnala una nuova comunita!
+(p
+-Oppure segnala una nuova comunita!":{url = article; action= ciao;}
+)p
diff --git a/skyrix-xml/STXSaxDriver/data/extra_test2.stx b/skyrix-xml/STXSaxDriver/data/extra_test2.stx
new file mode 100644 (file)
index 0000000..b697155
--- /dev/null
@@ -0,0 +1,34 @@
+Municipia aggrega 12099 lettori in diverse comunita che accedono alla versione completa del magazine e ad utili servizi di personalizzazione.\r
+\r
+Vuoi saperne di piu? "Leggi le Faq!":{url = article; action= ciao;}\r
+\r
+Richiedi l'accesso a una comunita di Municipia\r
+\r
+* "COM-P.A.":{url = article; action= ciao;}\r
\r
+* "Comune di Senigallia":{url = article; action= ciao;}\r
+       \r
+* "Comuneinlinea":{url = article; action= ciao;}\r
+  \r
+* "Comunicatori Pubblici":{url = article; action= ciao;}\r
+\r
+* "Findonline":{url = article; action= ciao;}\r
+
+* "Provincia Regionale di Messina":{url = article; action= ciao;}\r
+\r
+* "Provincia di Brescia":{url = article; action= ciao;}\r
+\r
+* "Provincia di Milano":{url = article; action= ciao;}\r
+\r
+* "Provincia di Modena":{url = article; action= ciao;}\r
+\r
+* "Provincia di Napoli":{url = article; action= ciao;}\r
+\r
+* "Provincia di Padova":{url = article; action= ciao;}\r
+\r
+* "Provincia di Pesaro-Urbino":{url = article; action= ciao;}\r
+\r
+* "Provincia Autonoma di Trento":{url = article; action= ciao;}\r
+\r
+\r
+Oppure "segnala una nuova comunita!":{url = article; action= ciao;}
\ No newline at end of file
diff --git a/skyrix-xml/STXSaxDriver/data/hhtest1-expect.pyx b/skyrix-xml/STXSaxDriver/data/hhtest1-expect.pyx
new file mode 100644 (file)
index 0000000..77a8d8c
--- /dev/null
@@ -0,0 +1,29 @@
+(p
+-jasdhf sdajfh asdfh asdfh ajasdhfj hasdjkfh jkasdf asdf jasd fhjasdhf jkasdhf
+)p
+(em
+-asdklf
+)em
+(strong
+-klasdf
+)strong
+(u
+-asf
+)u
+(p
+-asdkfj kl;asdfk asdjfjasdhf asdfkj daskjf asdkj flkasdf asdfkj   
+)p
+(ul
+(li
+(a
+Ahref http://www.skyrix.de/
+-SKYRiX
+)a
+)li
+(li
+(a
+Ahref http://www.opengroupware.org/
+-OGo
+)a
+)li
+)ul
diff --git a/skyrix-xml/STXSaxDriver/data/hhtest1.stx b/skyrix-xml/STXSaxDriver/data/hhtest1.stx
new file mode 100644 (file)
index 0000000..fd080e2
--- /dev/null
@@ -0,0 +1,11 @@
+jasdhf sdajfh asdfh 
+asdfh ajasdhfj hasdjkfh jkasdf
+asdf jasd fhjasdhf jkasdhf
+
+asdkfj kl;asdfk asdjfjasdhf 
+asdfkj daskjf asdkj flkasdf
+asdfkj *asdklf* **klasdf** _asf_
+
+* "SKYRiX":http://www.skyrix.de/
+
+* "OGo":http://www.opengroupware.org/
diff --git a/skyrix-xml/STXSaxDriver/data/hhtest2.stx b/skyrix-xml/STXSaxDriver/data/hhtest2.stx
new file mode 100644 (file)
index 0000000..687eee4
--- /dev/null
@@ -0,0 +1,14 @@
+jasdhf sdajfh asdfh 
+asdfh ajasdhfj hasdjkfh jkasdf
+asdf jasd fhjasdhf jkasdhf
+
+  asdkfj 
+  asdf asdf
+
+asdkfj kl;asdfk asdjfjasdhf 
+asdfkj daskjf asdkj flkasdf
+asdfkj *asdklf* **klasdf** _asf_
+
+* "SKYRiX":http://www.skyrix.de/
+
+* "OGo":http://www.opengroupware.org/
diff --git a/skyrix-xml/STXSaxDriver/data/hhtest3-expect.pyx b/skyrix-xml/STXSaxDriver/data/hhtest3-expect.pyx
new file mode 100644 (file)
index 0000000..a8527cd
--- /dev/null
@@ -0,0 +1,11 @@
+(ol
+(li
+-sdkfj
+)li
+(li
+-ksdafj
+)li
+(li
+-asldfk
+)li
+)ol
diff --git a/skyrix-xml/STXSaxDriver/data/hhtest3.stx b/skyrix-xml/STXSaxDriver/data/hhtest3.stx
new file mode 100644 (file)
index 0000000..f0567ba
--- /dev/null
@@ -0,0 +1,5 @@
+1 sdkfj
+
+2 ksdafj
+
+3 asldfk
diff --git a/skyrix-xml/SaxObjC/.cvsignore b/skyrix-xml/SaxObjC/.cvsignore
new file mode 100644 (file)
index 0000000..ff977db
--- /dev/null
@@ -0,0 +1,4 @@
+shared_debug_obj
+shared_obj
+*.framework
+derived_src
diff --git a/skyrix-xml/SaxObjC/COPYING b/skyrix-xml/SaxObjC/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-xml/SaxObjC/COPYRIGHT b/skyrix-xml/SaxObjC/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-xml/SaxObjC/ChangeLog b/skyrix-xml/SaxObjC/ChangeLog
new file mode 100644 (file)
index 0000000..1c090c6
--- /dev/null
@@ -0,0 +1,243 @@
+2004-08-03  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * SaxXMLReaderFactory.m: fixed multiple registration of sax drivers in the
+         search path. Also, when built as a framework, the frameworks's
+         SaxDriver directory is added to the search path (with least
+         significance, so it doesn't interfere with development and custom
+         deployments). (v4.2.37)
+
+2004-07-17  Helge Hess  <helge.hess@opengroupware.org>
+
+       * XMLNamespaces.h: added OOo WebDAV namespace (v4.2.36)
+
+2004-07-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * XMLNamespaces.h: added namespace declaration for Kupu and XInclude 
+         (v4.2.35)
+
+2004-07-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * XMLNamespaces.h: added relaxng structure namespace as used by Kupu
+         (v4.2.34)
+
+2004-07-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * XMLNamespaces.h: added namespace declarations for SOAP, XMLSchema and
+         some Novell namespaces (v4.2.33)
+
+2004-06-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * XMLNamespaces.h: added namespace declaration for OOo meta (v4.2.32)
+
+2004-06-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxObjectModel.m: fixed a warning with gcc 3.4 (v4.2.31)
+
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.30
+
+       * GNUmakefile: also build SaxObjC.framework on non-libFoundation 
+         systems
+       
+       * GNUmakefile.preamble: added prebinding segaddr
+       
+2004-03-16  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SaxXMLReaderFactory.m: added SaxDebugReaderFactory default to enable
+         debug logs, added more debug logging (v4.2.29)
+
+       * XMLNamespaces.h: added namespace declaration for Zope METAL (v4.2.28)
+
+2004-03-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * XMLNamespaces.h: added namespace declaration for Zope TAL (v4.2.27)
+
+2004-02-27  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SaxXMLReaderFactory.m: subminbor improvement to warn-log in case
+         multiple XML parsers are found for a single type (v4.2.26)
+
+2004-02-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxXMLReaderFactory.m: subminor code cleanup and fixes to log 
+         messages (v4.2.25)
+
+2003-12-26  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SaxXMLReaderFactory.m: cleaned up logging for missing parsers 
+         (v4.2.24)
+
+2003-11-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * XMLNamespaces.h: added namespace declaration for some proprietary
+         groupware server (v4.2.23)
+
+2003-11-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: removed autodoc target
+
+2003-11-09  Helge Hess  <helge.hess@opengroupware.org>
+        
+        * v4.2.22
+        
+        * SaxAttributes.m: added -initWithDictionary method necessary for the
+          NSXMLParser support (Note: Panther NSXMLParser currently doesn't seem
+          to be able to do proper namespace processing for attributes?)
+
+       * added the SaxDefaultHandler+NSXML category which allows any SAX 
+          handler inheriting from SaxDefaultHandler to be used as a delegate 
+          for the new NSXMLParser in Panther
+
+2003-10-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SaxAttributes.m: fixed an Xcode warning (v4.2.21)
+
+2003-10-15  Helge Hess  <helge.hess@opengroupware.org>
+
+       * XMLNamespaces.h: added MS WordML namespace, added Dublin Core
+         namespace (v4.2.20)
+
+2003-10-12  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SaxObjectModel.m, SaxXMLReaderFactory.m: added support for 
+         GNUSTEP_PATHLIST (apparently replaces GNUSTEP_PATHPREFIX_LIST in 
+         newer gstep-make versions (v4.2.19)
+
+2003-08-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxObjectDecoder.m: fixed OGo bug 133, decoder did not properly 
+         check value classes on Cocoa (v4.2.18)
+
+2003-07-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxXMLReaderFactory.m: added a missing @end for gstep-base, patch
+         provided by Filip Van Raemdonck (v4.2.17)
+
+2003-07-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * XMLNamespaces.h: added defines for the various XML namespaces used
+         in OpenOffice.org emitted XML files (v4.2.16)
+
+2003-06-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.15
+       
+       * SaxXMLReaderFactory.m: added SaxCoreOnMissingParser default to 
+         trigger a coredump for debugging purposes
+
+       * fixed some signed/unsigned warnings
+
+2003-02-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved saxxml and xmln tools to ../samples/
+
+2003-01-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxMethodCallHandler.m, SaxObjectDecoder.m: reduced logging if
+         debugOn is off (v4.2.14)
+
+Thu Jan  2 10:40:19 2003  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.13
+       
+       * saxxml.m: replaced RELEASE macros with method calls
+
+       * common.h: define ASSIGN macro if missing, do not include headers from
+         FoundationExt
+       
+       * SaxNamespaceSupport.m: replaced -notImplemented: with 
+         -doesNotRecognizeSelector: since -notImplemented: is not available
+         on MacOSX
+       
+2002-11-27  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxObjectModel.m: fixed a bug with parsing toMany keys (addToRel:
+         was not properly called) (v4.2.12)
+
+2002-11-05  Helge Hess  <helge.hess@skyrix.com>
+
+       * XMLNamespaces.h: added Nautilus namespace (v4.2.11)
+
+2002-11-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * XMLNamespaces.h: added the cadaver namespaces (v4.2.10)
+
+2002-10-24  Helge Hess  <helge.hess@skyrix.com>
+
+       * XMLNamespaces.h: added various namespace declarations (v4.2.9)
+
+2002-10-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxObjectModel.m, SaxObjectDecoder.m: added a namespaceKey to the
+         model (allows you to track the namespace in your parsed objects)
+
+       * XMLNamespaces.h: added the hotmail and httpmail namespaces (v4.2.8)
+
+Thu Oct 17 20:24:53 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxObjectDecoder.m ([_SaxObjTagInfo -unableToSetValue:forKey:withTag:toParent:exception:]):
+         now logs, why it was unable to set the key (exception) (v4.2.7)
+
+2002-10-17  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxObjectModel.m: when searching for a model the mainbundle resources
+         are checked before traversing the Library/SaxMappings pathes (v4.2.6)
+
+2002-10-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxObjectDecoder.m: added support for contentKey (v4.2.5)
+
+2002-10-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * added SaxObjectDecoder, a SAX handler which constructs object trees
+         by consulting a XML<->object mapping model (v4.2.4)
+
+2002-10-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * XMLNamespaces.h: added namespace declaration for xcal 01 (v4.2.3)
+
+2002-08-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxXMLReaderFactory.m: small fix for OSX, renamed COCOA_FRAMEWORK
+         define to COCOA_Foundation_LIBRARY
+
+2002-05-31  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxXMLReaderFactory.m: added NSBundle -copyWithZone: when compiling
+         for gstep-base compatibility
+
+Sun May  5 18:01:32 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed SAX1<->SAX2 adaptor classes, SAX1 stuff in general
+
+Tue Feb 12 20:24:59 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxXMLReaderFactory.m: modified to be usable without NGBundleManager
+         (but uses same bundle-info.plist ...)
+
+Sat Feb  9 11:35:27 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved XML test files to Examples/xmlsamples
+
+Wed Jan  9 13:24:40 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxXMLReaderFactory.m: ensure that a text/xml reader is created ...
+
+Mon Dec 17 17:02:15 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * added namespaces-declaration header
+
+Wed Oct 24 18:45:05 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * ExpatSaxDriver/ExpatSaxDriver.m: fixed UTF8->UTF16 conversion bug
+         (incorrect string length was passed to Sax callbacks)
+
+Mon Oct  1 15:47:31 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxXMLReaderFactory.m: added capability to create SAX parsers based
+         on MIME-type
+
+Thu Aug 16 13:48:01 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * SaxAttributes.m: added NSCopying
diff --git a/skyrix-xml/SaxObjC/GNUmakefile b/skyrix-xml/SaxObjC/GNUmakefile
new file mode 100644 (file)
index 0000000..b9e7542
--- /dev/null
@@ -0,0 +1,64 @@
+# $Id$
+
+include ../common.make
+
+LIBRARY_NAME   = libSaxObjC
+FRAMEWORK_NAME = SaxObjC
+
+libSaxObjC_DLL_DEF      = libSaxObjC.def
+libSaxObjC_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libSaxObjC_HEADER_FILES_DIR         = .
+libSaxObjC_HEADER_FILES_INSTALL_DIR = /SaxObjC
+
+libSaxObjC_OBJC_FILES = \
+       SaxAttributeList.m              \
+       SaxAttributes.m                 \
+       SaxDefaultHandler.m             \
+       SaxException.m                  \
+       SaxHandlerBase.m                \
+       SaxLocator.m                    \
+       SaxMethodCallHandler.m          \
+       SaxNamespaceSupport.m           \
+       SaxObjectDecoder.m              \
+       SaxObjectModel.m                \
+       SaxXMLFilter.m                  \
+       SaxXMLReaderFactory.m           \
+
+libSaxObjC_HEADER_FILES = \
+       SaxObjC.h                       \
+       SaxAttributeList.h              \
+       SaxAttributes.h                 \
+       SaxContentHandler.h             \
+       SaxDTDHandler.h                 \
+       SaxDeclHandler.h                \
+       SaxDefaultHandler.h             \
+       SaxDocumentHandler.h            \
+       SaxEntityResolver.h             \
+       SaxErrorHandler.h               \
+       SaxException.h                  \
+       SaxHandlerBase.h                \
+       SaxLexicalHandler.h             \
+       SaxLocator.h                    \
+       SaxNamespaceSupport.h           \
+       SaxObjectDecoder.h              \
+       SaxObjectModel.h                \
+       SaxXMLFilter.h                  \
+       SaxXMLReader.h                  \
+       SaxXMLReaderFactory.h           \
+       SaxMethodCallHandler.h          \
+       XMLNamespaces.h                 \
+
+SaxObjC_HEADER_FILES = $(libSaxObjC_HEADER_FILES)
+SaxObjC_OBJC_FILES   = $(libSaxObjC_OBJC_FILES)
+
+# flags
+
+-include GNUmakefile.preamble
+
+include $(GNUSTEP_MAKEFILES)/library.make
+
+ifeq ($(FOUNDATION_LIB),apple)
+include $(GNUSTEP_MAKEFILES)/framework.make
+endif
+-include GNUmakefile.postamble
diff --git a/skyrix-xml/SaxObjC/GNUmakefile.preamble b/skyrix-xml/SaxObjC/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..c62bd74
--- /dev/null
@@ -0,0 +1,33 @@
+# $Id$
+
+ADDITIONAL_CPPFLAGS += -Wno-protocol
+
+saxxml_INCLUDE_DIRS += -I..
+saxxml_LIB_DIRS     += -L./$(GNUSTEP_OBJ_DIR)
+saxxml_TOOL_LIBS    += -lSaxObjC
+
+xmln_INCLUDE_DIRS += -I..
+xmln_LIB_DIRS     += -L./$(GNUSTEP_OBJ_DIR)
+xmln_TOOL_LIBS    += -lSaxObjC
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libSaxObjC_PREBIND_ADDR="0xC0000000"
+libSaxObjC_LDFLAGS += -seg1addr $(libSaxObjC_PREBIND_ADDR)
+endif
+
+ifeq ($(FOUNDATION_LIB),nx)
+saxxml_LDFLAGS += -framework Foundation
+xmln_LDFLAGS   += -framework Foundation
+endif
+
+# Windows
+
+ifeq ($(GNUSTEP_TARGET_OS),mingw32)
+libSaxObjC_LIBRARIES_DEPEND_UPON += -lobjc
+endif
+
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+libSaxObjC_LIBRARIES_DEPEND_UPON += -lobjc
+endif
diff --git a/skyrix-xml/SaxObjC/README b/skyrix-xml/SaxObjC/README
new file mode 100644 (file)
index 0000000..7e75816
--- /dev/null
@@ -0,0 +1,21 @@
+# $Id$
+
+This directory contains a SAX (Simple API for XML) for Objective-C.
+
+SaxObjDecoder
+=============
+
+Take a look at SaxObjDecoder for simple mapping from XML to ObjC objects.
+
+SaxMethodCallHandler
+====================
+
+Take a look at SaxMethodCallHandler for mapping SAX events to ObjC method
+calls. Write a method per tag and SaxMethodCallHandler will call that for
+you ;-)
+
+Defaults
+========
+
+SaxCoreOnMissingParser - YES|NO - abort if a SAX driver could not be found
+SaxDebugReaderFactory  - YES|NO - debug SAX reader lookup/loading
diff --git a/skyrix-xml/SaxObjC/SaxAttributeList.h b/skyrix-xml/SaxObjC/SaxAttributeList.h
new file mode 100644 (file)
index 0000000..ef63785
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxAttributeList_H__
+#define __SaxAttributeList_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSMutableArray;
+
+/* deprecated in SAX 2.0beta */
+
+@protocol SaxAttributeList
+
+- (NSString *)nameAtIndex:(unsigned int)_idx;
+- (NSString *)typeAtIndex:(unsigned int)_idx;
+- (NSString *)valueAtIndex:(unsigned int)_idx;
+- (NSString *)typeForName:(NSString *)_name;
+- (NSString *)valueForName:(NSString *)_name;
+
+- (unsigned int)count;
+
+@end
+
+@interface SaxAttributeList : NSObject < SaxAttributeList, NSCopying >
+{
+@private
+  NSMutableArray *names;
+  NSMutableArray *types;
+  NSMutableArray *values;
+}
+
+- (id)init;
+- (id)initWithAttributeList:(id<SaxAttributeList>)_attrList;
+
+- (void)setAttributeList:(id<SaxAttributeList>)_attrList;
+- (void)clear;
+
+- (void)addAttribute:(NSString *)_name
+  type:(NSString *)_type
+  value:(NSString *)_value;
+- (void)removeAttribute:(NSString *)_attr;
+
+@end
+
+#include <SaxObjC/SaxAttributes.h>
+
+@interface SaxAttributeList(Compatibility)
+- (id)initWithAttributes:(id<SaxAttributes>)_attrs;
+@end
+
+#endif /* __SaxAttributeList_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxAttributeList.m b/skyrix-xml/SaxObjC/SaxAttributeList.m
new file mode 100644 (file)
index 0000000..d336908
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SaxAttributeList.h"
+#include "SaxAttributes.h"
+#include "common.h"
+
+@implementation SaxAttributeList
+
+- (id)init {
+  self->names  = [[NSMutableArray alloc] init];
+  self->types  = [[NSMutableArray alloc] init];
+  self->values = [[NSMutableArray alloc] init];
+  return self;
+}
+- (id)initWithAttributeList:(id<SaxAttributeList>)_attrList {
+  if ((self = [self init])) {
+    unsigned i;
+
+    for (i = 0; i < [_attrList count]; i++) {
+      [self->names  addObject:[_attrList nameAtIndex:i]];
+      [self->types  addObject:[_attrList typeAtIndex:i]];
+      [self->values addObject:[_attrList valueAtIndex:i]];
+    }
+  }
+  return self;
+}
+
+- (id)initWithAttributes:(id<SaxAttributes>)_attrList {
+  if ((self = [self init])) {
+    int i, c;
+
+    for (i = 0, c = [_attrList count]; i < c; i++) {
+      [self->names  addObject:[_attrList rawNameAtIndex:i]];
+      [self->types  addObject:[_attrList typeAtIndex:i]];
+      [self->values addObject:[_attrList valueAtIndex:i]];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->names  release];
+  [self->types  release];
+  [self->values release];
+  [super dealloc];
+}
+
+/* modify operations */
+
+- (void)setAttributeList:(id<SaxAttributeList>)_attrList {
+  unsigned i;
+
+  [self clear];
+  
+  for (i = 0; i < [_attrList count]; i++) {
+    [self->names  addObject:[_attrList nameAtIndex:i]];
+    [self->types  addObject:[_attrList typeAtIndex:i]];
+    [self->values addObject:[_attrList valueAtIndex:i]];
+  }
+}
+- (void)clear {
+  [self->names  removeAllObjects];
+  [self->types  removeAllObjects];
+  [self->values removeAllObjects];
+}
+
+- (void)addAttribute:(NSString *)_name
+  type:(NSString *)_type
+  value:(NSString *)_value
+{
+  if (_type  == nil) _type  = @"CDATA";
+  if (_value == nil) _value = @"";
+  [self->names  addObject:_name];
+  [self->types  addObject:_type];
+  [self->values addObject:_value];
+}
+
+- (void)removeAttribute:(NSString *)_name {
+  int idx;
+
+  if ((idx = [self->names indexOfObject:_name]) == NSNotFound)
+    return;
+
+  [self->names  removeObjectAtIndex:idx];
+  [self->types  removeObjectAtIndex:idx];
+  [self->values removeObjectAtIndex:idx];
+}
+
+/* protocol implementation */
+
+- (NSString *)nameAtIndex:(unsigned int)_idx {
+  return [self->names objectAtIndex:_idx];
+}
+- (NSString *)typeAtIndex:(unsigned int)_idx {
+  return [self->types objectAtIndex:_idx];
+}
+- (NSString *)valueAtIndex:(unsigned int)_idx {
+  return [self->values objectAtIndex:_idx];
+}
+
+- (NSString *)typeForName:(NSString *)_name {
+  int i;
+
+  if ((i = [self->names indexOfObject:_name]) == NSNotFound)
+    return nil;
+
+  return [self typeAtIndex:i];
+}
+- (NSString *)valueForName:(NSString *)_name {
+  int i;
+
+  if ((i = [self->names indexOfObject:_name]) == NSNotFound)
+    return nil;
+
+  return [self valueAtIndex:i];
+}
+
+- (unsigned int)count {
+  return [self->names count];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[[self class] allocWithZone:_zone] initWithAttributeList:self];
+}
+
+/* description */
+
+- (id)propertyList {
+  id objs[3], keys[3];
+  objs[0] = self->names;  keys[0] = @"names";
+  objs[1] = self->types;  keys[1] = @"types";
+  objs[2] = self->values; keys[2] = @"values";
+  return [NSDictionary dictionaryWithObjects:objs forKeys:keys count:3];
+}
+
+- (NSString *)description {
+  NSMutableString *s;
+  NSString        *is;
+  int i, c;
+  
+  s = [[NSMutableString alloc] init];
+  [s appendFormat:@"<%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  for (i = 0, c = [self count]; i < c; i++) {
+    NSString *type;
+
+    [s appendString:@" "];
+    [s appendString:[self nameAtIndex:i]];
+    [s appendString:@"='"];
+    [s appendString:[self valueAtIndex:i]];
+    [s appendString:@"'"];
+
+    type = [self typeAtIndex:i];
+    if (![type isEqualToString:@"CDATA"]) {
+      [s appendString:@"["];
+      [s appendString:type];
+      [s appendString:@"]"];
+    }
+  }
+  [s appendString:@">"];
+  
+  is = [s copy];
+  [s release];
+  return [is autorelease];
+}
+
+@end /* SaxAttributeList */
diff --git a/skyrix-xml/SaxObjC/SaxAttributes.h b/skyrix-xml/SaxObjC/SaxAttributes.h
new file mode 100644 (file)
index 0000000..5b54f01
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxAttributes_H__
+#define __SaxAttributes_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSArray, NSMutableArray, NSDictionary;
+
+/*
+  new in SAX 2.0beta, replaces the SaxAttributeList
+*/
+
+@protocol SaxAttributes
+
+/* lookup indices */
+
+- (unsigned int)indexOfRawName:(NSString *)_rawName;
+- (unsigned int)indexOfName:(NSString *)_localPart uri:(NSString *)_uri;
+
+/* lookup data by index */
+
+- (NSString *)nameAtIndex:(unsigned int)_idx;
+- (NSString *)rawNameAtIndex:(unsigned int)_idx;
+- (NSString *)typeAtIndex:(unsigned int)_idx;
+- (NSString *)uriAtIndex:(unsigned int)_idx;
+- (NSString *)valueAtIndex:(unsigned int)_idx;
+
+/* lookup data by name */
+
+- (NSString *)typeForRawName:(NSString *)_rawName;
+- (NSString *)typeForName:(NSString *)_localName uri:(NSString *)_uri;
+- (NSString *)valueForRawName:(NSString *)_rawName;
+- (NSString *)valueForName:(NSString *)_localName uri:(NSString *)_uri;
+
+/* list size */
+
+- (unsigned int)count;
+
+@end
+
+/* simple attributes implementation, should be improved */
+
+@interface SaxAttributes : NSObject < SaxAttributes, NSCopying >
+{
+@private
+  NSMutableArray *names;
+  NSMutableArray *uris;
+  NSMutableArray *rawNames;
+  NSMutableArray *types;
+  NSMutableArray *values;
+}
+
+- (id)initWithAttributes:(id<SaxAttributes>)_attrs;
+- (id)initWithDictionary:(NSDictionary *)_dict;
+
+- (void)addAttribute:(NSString *)_localName uri:(NSString  *)_uri
+  rawName:(NSString *)_rawName
+  type:(NSString *)_type
+  value:(NSString *)_value;
+
+- (void)clear;
+
+@end
+
+#include <SaxObjC/SaxAttributeList.h>
+
+@interface SaxAttributes(Compatibility)
+- (id)initWithAttributeList:(id<SaxAttributeList>)_attrList;
+@end
+
+#endif /* __SaxAttributes_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxAttributes.m b/skyrix-xml/SaxObjC/SaxAttributes.m
new file mode 100644 (file)
index 0000000..0b77879
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SaxAttributes.h"
+#include "common.h"
+
+@implementation SaxAttributes
+
+- (id)init {
+  Class c = [NSMutableArray class];
+  
+  self->names    = [[c alloc] init];
+  self->uris     = [[c alloc] init];
+  self->rawNames = [[c alloc] init];
+  self->types    = [[c alloc] init];
+  self->values   = [[c alloc] init];
+  return self;
+}
+- (id)initWithAttributes:(id<SaxAttributes>)_attrs {
+  if ((self = [self init])) {
+    int i, c;
+    
+    for (i = 0, c = [_attrs count]; i < c; i++) {
+      [self addAttribute:[_attrs nameAtIndex:i]
+            uri:[_attrs uriAtIndex:i]
+            rawName:[_attrs rawNameAtIndex:i]
+            type:[_attrs typeAtIndex:i]
+            value:[_attrs valueAtIndex:i]];
+    }
+  }
+  return self;
+}
+
+- (id)initWithAttributeList:(id<SaxAttributeList>)_attrList {
+  if ((self = [self init])) {
+    unsigned i;
+    
+    for (i = 0; i < [_attrList count]; i++) {
+      [self addAttribute:[_attrList nameAtIndex:i] uri:@""
+            rawName:[_attrList nameAtIndex:i]
+            type:[_attrList typeAtIndex:i]
+            value:[_attrList valueAtIndex:i]];
+    }
+  }
+  return self;
+}
+- (id)initWithDictionary:(NSDictionary *)_dict {
+  if ((self = [self init])) {
+    NSEnumerator *keys;
+    NSString     *key;
+    
+    keys = [_dict keyEnumerator];
+    while ((key = [keys nextObject])) {
+      [self addAttribute:key uri:nil rawName:key
+            type:nil 
+            value:[_dict objectForKey:key]];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->names    release];
+  [self->uris     release];
+  [self->rawNames release];
+  [self->types    release];
+  [self->values   release];
+  [super dealloc];
+}
+
+/* modifications */
+
+- (void)addAttribute:(NSString *)_localName uri:(NSString  *)_uri
+  rawName:(NSString *)_rawName
+  type:(NSString *)_type
+  value:(NSString *)_value
+{
+  [self->names    addObject:_localName ? _localName : _rawName];
+  [self->uris     addObject:_uri       ? _uri       : @""];
+  [self->rawNames addObject:_rawName   ? _rawName   : @""];
+  [self->types    addObject:_type      ? _type      : @"CDATA"];
+  [self->values   addObject:_value];
+}
+
+- (void)clear {
+  [self->names    removeAllObjects];
+  [self->uris     removeAllObjects];
+  [self->rawNames removeAllObjects];
+  [self->types    removeAllObjects];
+  [self->values   removeAllObjects];
+}
+
+/* lookup indices */
+
+- (unsigned int)indexOfRawName:(NSString *)_rawName {
+  return [self->rawNames indexOfObject:_rawName];
+}
+- (unsigned int)indexOfName:(NSString *)_localPart uri:(NSString *)_uri
+{
+  unsigned int i, c;
+  
+  for (i = 0, c = [self count]; i < c; i++) {
+    NSString *name;
+    
+    name = [self nameAtIndex:i];
+    
+    if ([name isEqualToString:_localPart]) {
+      NSString *auri;
+      
+      auri = [self uriAtIndex:i];
+
+      //NSLog(@"found name %@", name);
+      
+      if (([auri length] == 0) && ([_uri length] == 0))
+        return i;
+      
+      if ([_uri isEqualToString:auri])
+        return i;
+    }
+  }
+  return NSNotFound;
+}
+
+/* lookup data by index */
+
+- (NSString *)nameAtIndex:(unsigned int)_idx {
+  return [self->names objectAtIndex:_idx];
+}
+- (NSString *)rawNameAtIndex:(unsigned int)_idx {
+  return [self->rawNames objectAtIndex:_idx];
+}
+- (NSString *)typeAtIndex:(unsigned int)_idx {
+  return [self->types objectAtIndex:_idx];
+}
+- (NSString *)uriAtIndex:(unsigned int)_idx {
+  return [self->uris objectAtIndex:_idx];
+}
+- (NSString *)valueAtIndex:(unsigned int)_idx {
+  return [self->values objectAtIndex:_idx];
+}
+
+/* lookup data by name */
+
+- (NSString *)typeForRawName:(NSString *)_rawName {
+  unsigned int i;
+
+  if ((i = [self indexOfRawName:_rawName]) == NSNotFound)
+    return nil;
+
+  return [self typeAtIndex:i];
+}
+- (NSString *)typeForName:(NSString *)_localName uri:(NSString *)_uri {
+  unsigned int i;
+  
+  if ((i = [self indexOfName:_localName uri:_uri]) == NSNotFound)
+    return nil;
+
+  return [self typeAtIndex:i];
+}
+
+- (NSString *)valueForRawName:(NSString *)_rawName {
+  unsigned int i;
+
+  if ((i = [self indexOfRawName:_rawName]) == NSNotFound)
+    return nil;
+
+  return [self valueAtIndex:i];
+}
+- (NSString *)valueForName:(NSString *)_localName uri:(NSString *)_uri {
+  unsigned int i;
+  
+  if ((i = [self indexOfName:_localName uri:_uri]) == NSNotFound)
+    return nil;
+
+  return [self valueAtIndex:i];
+}
+
+/* list size */
+
+- (unsigned int)count {
+  return [self->names count];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [(SaxAttributes *)[[self class] alloc] initWithAttributes:self];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+  NSString        *is;
+  int i, c;
+  
+  s = [[NSMutableString alloc] init];
+  [s appendFormat:@"<%08X[%@]:", self, NSStringFromClass([self class])];
+  
+  for (i = 0, c = [self count]; i < c; i++) {
+    NSString *type;
+
+    [s appendString:@" "];
+    [s appendString:[self nameAtIndex:i]];
+    [s appendString:@"='"];
+    [s appendString:[self valueAtIndex:i]];
+    [s appendString:@"'"];
+
+    type = [self typeAtIndex:i];
+    if (![type isEqualToString:@"CDATA"]) {
+      [s appendString:@"["];
+      [s appendString:type];
+      [s appendString:@"]"];
+    }
+  }
+  [s appendString:@">"];
+  
+  is = [s copy];
+  [s release];
+  return [is autorelease];
+}
+
+@end /* SaxAttributes */
diff --git a/skyrix-xml/SaxObjC/SaxContentHandler.h b/skyrix-xml/SaxObjC/SaxContentHandler.h
new file mode 100644 (file)
index 0000000..1c11bf5
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxContentHandler_H__
+#define __SaxContentHandler_H__
+
+#import <Foundation/NSString.h>
+#include <SaxObjC/SaxAttributes.h>
+#include <SaxObjC/SaxLocator.h>
+
+@class NSString;
+
+/*
+  new in SAX 2.0beta, replaces SaxDocumentHandler
+*/
+  
+@protocol SaxContentHandler
+
+- (void)startDocument;
+- (void)endDocument;
+
+- (void)startPrefixMapping:(NSString *)_prefix uri:(NSString *)_uri;
+- (void)endPrefixMapping:(NSString *)_prefix;
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attributes;
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName;
+
+/* CDATA */
+
+- (void)characters:(unichar *)_chars          length:(int)_len;
+- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len;
+
+/* PIs */
+
+- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data;
+
+/* positioning info */
+
+- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator;
+
+/* entities */
+
+- (void)skippedEntity:(NSString *)_entityName;
+
+@end
+
+#endif /* __SaxContentHandler_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxDTDHandler.h b/skyrix-xml/SaxObjC/SaxDTDHandler.h
new file mode 100644 (file)
index 0000000..0815092
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxDTDHandler_H__
+#define __SaxDTDHandler_H__
+
+@class NSString;
+
+@protocol SaxDTDHandler
+
+- (void)notationDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId;
+
+- (void)unparsedEntityDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+  notationName:(NSString *)_notName;
+
+@end /* SaxDTDHandler */
+
+#endif /* __SaxDTDHandler_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxDeclHandler.h b/skyrix-xml/SaxObjC/SaxDeclHandler.h
new file mode 100644 (file)
index 0000000..5f4ae1a
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxDeclHandler_H__
+#define __SaxDeclHandler_H__
+
+@class NSString;
+
+/*
+  new in SAX 2.0beta
+
+  In Java this class is in the ext-package, that is,
+  implementation is optional.
+
+  SAX2 extension handler for DTD declaration events. 
+
+  This is an optional extension handler for SAX2 to provide information
+  about DTD declarations in an XML document. XML readers are not required
+  to support this handler.
+
+  Note that data-related DTD declarations (unparsed entities and notations)
+  are already reported through the DTDHandler interface.
+
+  If you are using the declaration handler together with a lexical handler,
+  all of the events will occur between the startDTD and the endDTD events.
+
+  To set the DeclHandler for an XML reader, use the setProperty method with
+  the propertyId "http://xml.org/sax/handlers/DeclHandler". If the reader
+  does not support declaration events, it will throw a
+  SAXNotRecognizedException or a SAXNotSupportedException when you attempt
+  to register the handler.
+*/
+
+@protocol SaxDeclHandler
+
+/*
+  Report an attribute type declaration.
+  
+  Only the effective (first) declaration for an attribute will be
+  reported. The type will be one of the strings "CDATA", "ID", "IDREF",
+  "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", or "NOTATION",
+  or a parenthesized token group with the separator "|" and all whitespace
+  removed.
+
+  valueDefault - A string representing the attribute default ("#IMPLIED",
+  "#REQUIRED", or "#FIXED") or nil if none of these applies
+*/
+- (void)attributeDeclaration:(NSString *)_attributeName
+  elementName:(NSString *)_elementName
+  type:(NSString *)_type
+  defaultType:(NSString *)_defType
+  defaultValue:(NSString *)_defValue;
+
+/*
+  Report an attribute type declaration.
+  
+  Only the effective (first) declaration for an attribute will be
+  reported. The type will be one of the strings "CDATA", "ID", "IDREF",
+  "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", or "NOTATION",
+  or a parenthesized token group with the separator "|" and all whitespace
+  removed.
+
+  If it is a parameter entity, the name will begin with '%'.
+*/
+- (void)elementDeclaration:(NSString *)_name contentModel:(NSString *)_model;
+
+/*
+  Report a parsed external entity declaration.
+  
+  Only the effective (first) declaration for each entity will be reported.
+
+  If it is a parameter entity, the name will begin with '%'.
+*/
+- (void)externalEntityDeclaration:(NSString *)_name
+  publicId:(NSString *)_pub
+  systemId:(NSString *)_sys;
+
+/*
+  Report an internal entity declaration.
+  
+  Only the effective (first) declaration for each entity will be reported.
+
+  If it is a parameter entity, the name will begin with '%'.
+*/
+- (void)internalEntityDeclaration:(NSString *)_name value:(NSString *)_value;
+
+@end
+
+#endif /* __SaxDeclHandler_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxDefaultHandler+NSXML.m b/skyrix-xml/SaxObjC/SaxDefaultHandler+NSXML.m
new file mode 100644 (file)
index 0000000..2c9ed6e
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SaxDefaultHandler.h"
+#include "SaxException.h"
+
+@implementation SaxDefaultHandler(NSXML)
+
+static BOOL doDebug = NO;
+
+- (void)parserDidStartDocument:(id)_parser {
+  if (doDebug) NSLog(@"parser: startdoc %@", _parser);
+  [self startDocument];
+}
+- (void)parserDidEndDocument:(id)_parser {
+  if (doDebug) NSLog(@"parser: endoc    %@", _parser);
+  [self endDocument];
+}
+
+- (id<NSObject,SaxAttributes>)_wrapAttributes:(NSDictionary *)_attrs {
+  // TODO: implement ..
+  return [[SaxAttributes alloc] initWithDictionary:_attrs];
+}
+
+- (void)parser:(id)_parser 
+  didStartElement:(NSString *)_tag 
+  namespaceURI:(NSString *)_nsuri 
+  qualifiedName:(NSString *)_rawName 
+  attributes:(NSDictionary *)_attrs
+{
+  id<NSObject,SaxAttributes> attrs;
+
+  if ([_rawName length] == 0) _rawName = _tag;
+  if (doDebug) 
+    NSLog(@"parser: start %@ raw %@ uri %@", _tag, _rawName, _nsuri);
+  
+  attrs = [self _wrapAttributes:_attrs];
+  [self startElement:_tag namespace:_nsuri rawName:_rawName
+        attributes:attrs];
+  [attrs release];
+}
+
+- (void)parser:(id)_parser 
+  didEndElement:(NSString *)_tag 
+  namespaceURI:(NSString *)_nsuri
+  qualifiedName:(NSString *)_rawName
+{
+  if ([_rawName length] == 0) _rawName = _tag;
+  if (doDebug) 
+    NSLog(@"parser: end %@ raw %@ uri %@", _tag, _rawName, _nsuri);
+  [self endElement:_tag namespace:_nsuri rawName:_rawName];
+}
+
+- (void)parser:(id)_parser 
+  didStartMappingPrefix:(NSString *)_prefix 
+  toURI:(NSString *)_uri
+{
+  [self startPrefixMapping:_prefix uri:_uri];
+}
+- (void)parser:(id)_parser didEndMappingPrefix:(NSString *)_prefix {
+  [self endPrefixMapping:_prefix];
+}
+
+- (void)parser:(id)_parser foundCharacters:(NSString *)_string {
+  /* Note: expensive ..., decompose string into chars */
+  int     len;
+  unichar *buf = NULL;
+  
+  if ((len = [_string length]) > 0) {
+    buf = calloc(len + 2, sizeof(unichar));
+    [_string getCharacters:buf];
+  }
+  [self characters:buf length:len];
+  if (buf) free(buf);
+}
+- (void)parser:(id)_parser foundIgnorableWhitespace:(NSString *)_ws {
+  /* Note: expensive ..., decompose string into chars */
+  int     len;
+  unichar *buf = NULL;
+  
+  if ((len = [_ws length]) > 0) {
+    buf = calloc(len + 2, sizeof(unichar));
+    [_ws getCharacters:buf];
+  }
+  [self ignorableWhitespace:buf length:len];
+  if (buf) free(buf);
+}
+
+- (void)parser:(id)_parser foundCDATA:(NSData *)_data {
+  /* TODO: what about that? */
+  NSLog(@"ERROR(%s): CDATA section ignored!", __PRETTY_FUNCTION__);
+}
+
+#if 0 /* TODO: implement */
+- (void)parser:(id)_parser foundComment:(NSString *)comment {
+}
+#endif
+
+- (void)parser:(id)_parser 
+  foundProcessingInstructionWithTarget:(NSString *)_target 
+  data:(NSString *)_data
+{
+  [self processingInstruction:_target data:_data];
+}
+
+/* entity resolver */
+
+- (NSData *)parser:(id)_parser 
+  resolveExternalEntityName:(NSString *)_name 
+  systemID:(NSString *)_sysId
+{
+  return [self resolveEntityWithPublicId:_name systemId:_sysId];
+}
+
+/* handle errors */
+
+- (SaxParseException *)_wrapErrorIntoException:(NSError *)_error {
+  // TODO: perform proper wrapping or conversion
+  return (id)_error;
+}
+
+- (void)parser:(id)_parser parseErrorOccurred:(NSError *)_error {
+  if (doDebug) NSLog(@"parser: error %@", _error);
+  [self error:[self _wrapErrorIntoException:_error]];
+}
+- (void)parser:(id)_parser validationErrorOccurred:(NSError *)_error {
+  if (doDebug) NSLog(@"parser: validation error %@", _error);
+  [self error:[self _wrapErrorIntoException:_error]];
+}
+
+/* DTD processing */
+
+- (void)parser:(id)_parser 
+  foundNotationDeclarationWithName:(NSString *)_name 
+  publicID:(NSString *)_pubId systemID:(NSString *)_sysId
+{
+  [self notationDeclaration:_name publicId:_pubId systemId:_sysId];
+}
+
+- (void)parser:(id)_parser 
+  foundUnparsedEntityDeclarationWithName:(NSString *)_name 
+  publicID:(NSString *)_pubId systemID:(NSString *)_sysId
+  notationName:(NSString *)_notName
+{
+  [self unparsedEntityDeclaration:_name
+        publicId:_pubId systemId:_sysId
+        notationName:_notName];
+}
+
+#if 0 /* TODO: DTD processing ... */
+
+- (void)parser:(id)_parser 
+  foundAttributeDeclarationWithName:(NSString *)attributeName 
+  forElement:(NSString *)_tag type:(NSString *)type 
+  defaultValue:(NSString *)defaultValue;
+
+- (void)parser:(id)_parser 
+  foundElementDeclarationWithName:(NSString *)_tag model:(NSString *)model;
+
+- (void)parser:(id)_parser 
+  foundInternalEntityDeclarationWithName:(NSString *)name 
+  value:(NSString *)value;
+
+- (void)parser:(id)_parser 
+  foundExternalEntityDeclarationWithName:(NSString *)name 
+  publicID:(NSString *)publicID systemID:(NSString *)systemID;
+
+#endif
+
+@end /* SaxDefaultHandler(NSXML) */
diff --git a/skyrix-xml/SaxObjC/SaxDefaultHandler.h b/skyrix-xml/SaxObjC/SaxDefaultHandler.h
new file mode 100644 (file)
index 0000000..946218c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxDefaultHandler_H__
+#define __SaxDefaultHandler_H__
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxEntityResolver.h>
+#include <SaxObjC/SaxDTDHandler.h>
+#include <SaxObjC/SaxContentHandler.h>
+#include <SaxObjC/SaxErrorHandler.h>
+
+@interface SaxDefaultHandler : NSObject
+  < SaxEntityResolver, SaxDTDHandler, SaxContentHandler, SaxErrorHandler >
+@end
+
+#endif /* __SaxDefaultHandler_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxDefaultHandler.m b/skyrix-xml/SaxObjC/SaxDefaultHandler.m
new file mode 100644 (file)
index 0000000..bc7ac2b
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SaxDefaultHandler.h"
+#include "SaxException.h"
+
+@implementation SaxDefaultHandler
+
+/* SaxContentHandler */
+
+- (void)startDocument {
+}
+- (void)endDocument {
+}
+
+- (void)startPrefixMapping:(NSString *)_prefix uri:(NSString *)_uri {
+}
+- (void)endPrefixMapping:(NSString *)_prefix {
+}
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attributes
+{
+}
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+}
+- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
+}
+
+- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data {
+}
+- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator {
+}
+- (void)skippedEntity:(NSString *)_entityName {
+}
+
+/* SaxDTDHandler */
+
+- (void)notationDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+{
+}
+
+- (void)unparsedEntityDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+  notationName:(NSString *)_notName
+{
+}
+
+/* SaxEntityResolver */
+
+- (id)resolveEntityWithPublicId:(NSString *)_pubId systemId:(NSString *)_sysId {
+  return nil;
+}
+
+/* SaxErrorHandler */
+
+- (void)warning:(SaxParseException *)_exception {
+}
+- (void)error:(SaxParseException *)_exception {
+}
+
+- (void)fatalError:(SaxParseException *)_exception {
+  [_exception raise];
+}
+
+@end /* SaxDefaultHandler */
diff --git a/skyrix-xml/SaxObjC/SaxDocumentHandler.h b/skyrix-xml/SaxObjC/SaxDocumentHandler.h
new file mode 100644 (file)
index 0000000..8fd5774
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxDocumentHandler_H__
+#define __SaxDocumentHandler_H__
+
+#import <Foundation/NSString.h>
+#include <SaxObjC/SaxAttributeList.h>
+#include <SaxObjC/SaxLocator.h>
+
+/* deprecated in SAX 2.0beta (replaced by SaxXMLContentHandler) */
+
+@protocol SaxDocumentHandler
+
+- (void)startDocument;
+- (void)endDocument;
+
+- (void)startElement:(NSString *)_tagName
+  attributes:(id<SaxAttributeList>)_attrs;
+- (void)endElement:(NSString *)_tagName;
+
+/* CDATA */
+
+- (void)characters:(unichar *)_chars          length:(int)_len;
+- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len;
+
+/* PIs */
+
+- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data;
+
+/* positioning info */
+
+- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator;
+
+@end
+
+#endif /* __SaxDocumentHandler_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxEntityResolver.h b/skyrix-xml/SaxObjC/SaxEntityResolver.h
new file mode 100644 (file)
index 0000000..9aeaf41
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxEntityResolver_H__
+#define __SaxEntityResolver_H__
+
+@class NSString;
+
+@protocol SaxEntityResolver
+
+- (id)resolveEntityWithPublicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId;
+
+@end /* SaxEntityResolver */
+
+#endif /* __SaxEntityResolver_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxErrorHandler.h b/skyrix-xml/SaxObjC/SaxErrorHandler.h
new file mode 100644 (file)
index 0000000..31b8829
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxErrorHandler_H__
+#define __SaxErrorHandler_H__
+
+@class SaxParseException;
+
+@protocol SaxErrorHandler
+
+- (void)warning:(SaxParseException *)_exception;
+- (void)error:(SaxParseException *)_exception;
+- (void)fatalError:(SaxParseException *)_exception;
+
+@end
+
+#endif /* __SaxErrorHandler_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxException.h b/skyrix-xml/SaxObjC/SaxException.h
new file mode 100644 (file)
index 0000000..8d059d0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxException_H__
+#define __SaxException_H__
+
+#import <Foundation/NSException.h>
+
+@interface SaxException : NSException
+@end
+
+@interface SaxParseException : SaxException
+@end
+
+/* new in SAX 2.0beta */
+
+@interface SaxNotSupportedException : SaxException
+@end
+
+@interface SaxNotRecognizedException : SaxException
+@end
+
+#endif /* __SaxException_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxException.m b/skyrix-xml/SaxObjC/SaxException.m
new file mode 100644 (file)
index 0000000..d976df2
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SaxException.h"
+
+@implementation SaxException
+@end
+
+@implementation SaxParseException
+@end
+
+@implementation SaxNotSupportedException
+@end
+
+@implementation SaxNotRecognizedException
+@end
diff --git a/skyrix-xml/SaxObjC/SaxHandlerBase.h b/skyrix-xml/SaxObjC/SaxHandlerBase.h
new file mode 100644 (file)
index 0000000..e0cb2d5
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxHandlerBase_H__
+#define __SaxHandlerBase_H__
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxEntityResolver.h>
+#include <SaxObjC/SaxDTDHandler.h>
+#include <SaxObjC/SaxDocumentHandler.h>
+#include <SaxObjC/SaxErrorHandler.h>
+
+/* deprecated in SAX 2.0beta */
+
+@interface SaxHandlerBase : NSObject
+  < SaxEntityResolver, SaxDTDHandler, SaxDocumentHandler, SaxErrorHandler >
+
+@end /* SaxHandlerBase */
+
+#endif /* __SaxHandlerBase_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxHandlerBase.m b/skyrix-xml/SaxObjC/SaxHandlerBase.m
new file mode 100644 (file)
index 0000000..da9d159
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SaxHandlerBase.h"
+#include "SaxException.h"
+
+@implementation SaxHandlerBase
+
+/* SaxDocumentHandler */
+
+- (void)startDocument {
+}
+- (void)endDocument {
+}
+
+- (void)startElement:(NSString *)_tagName
+  attributes:(id<SaxAttributeList>)_attrs
+{
+}
+- (void)endElement:(NSString *)_tagName {
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+}
+- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
+}
+
+- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data {
+}
+
+- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator {
+}
+
+/* SaxDTDHandler */
+
+- (void)notationDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+{
+}
+
+- (void)unparsedEntityDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+  notationName:(NSString *)_notName
+{
+}
+
+/* SaxEntityResolver */
+
+- (id)resolveEntityWithPublicId:(NSString *)_pubId systemId:(NSString *)_sysId {
+  return nil;
+}
+
+/* SaxErrorHandler */
+
+- (void)warning:(SaxParseException *)_exception {
+}
+- (void)error:(SaxParseException *)_exception {
+}
+
+- (void)fatalError:(SaxParseException *)_exception {
+  [_exception raise];
+}
+
+@end /* SaxHandlerBase */
diff --git a/skyrix-xml/SaxObjC/SaxLexicalHandler.h b/skyrix-xml/SaxObjC/SaxLexicalHandler.h
new file mode 100644 (file)
index 0000000..eee4059
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxLexicalHandler_H__
+#define __SaxLexicalHandler_H__
+
+#import <Foundation/NSString.h>
+
+/*
+  new in SAX 2.0beta
+
+  SAX2 extension handler for lexical events. 
+
+  This is an optional extension handler for SAX2 to provide lexical
+  information about an XML document, such as comments and CDATA section
+  boundaries; XML readers are not required to support this handler.
+
+  The events in the lexical handler apply to the entire document, not
+  just to the document element, and all lexical handler events must
+  appear between the content handler's startDocument and endDocument
+  events.
+
+  To set the LexicalHandler for an XML reader, use the setProperty method
+  with the propertyId "http://xml.org/sax/handlers/LexicalHandler". If
+  the reader does not support lexical events, it will throw a
+  SAXNotRecognizedException or a SAXNotSupportedException when you attempt
+  to register the handler.
+*/
+
+@protocol SaxLexicalHandler
+
+/*
+  Report an XML comment anywhere in the document.
+  
+  This callback will be used for comments inside or outside the document
+  element, including comments in the external DTD subset (if read).
+*/
+- (void)comment:(unichar *)_chars length:(int)_len;
+
+/*
+  Report the start of DTD declarations, if any.
+  
+  Any declarations are assumed to be in the internal subset unless
+  otherwise indicated by a startEntity event.
+
+  Note that the start/endDTD events will appear within the
+  start/endDocument events from ContentHandler and before the first
+  startElement event.
+*/
+- (void)startDTD:(NSString *)_name
+  publicId:(NSString *)_pub
+  systemId:(NSString *)_sys;
+
+/* Report the end of DTD declarations. */
+- (void)endDTD;
+
+/*
+  Report the beginning of an entity in content.
+  
+  NOTE: entity references in attribute values -- and the start and end
+  of the document entity -- are never reported.
+
+  The start and end of the external DTD subset are reported using the
+  pseudo-name "[dtd]". All other events must be properly nested within
+  start/end entity events.
+
+  Note that skipped entities will be reported through the skippedEntity
+  event, which is part of the ContentHandler interface.
+
+  If it is a parameter entity, the name will begin with '%'.
+*/
+- (void)startEntity:(NSString *)_name;
+
+/* report the end of an entity */
+- (void)endEntity:(NSString *)_name;
+
+/*
+  Report the start of a CDATA section.
+  
+  The contents of the CDATA section will be reported through the regular
+  characters event.
+*/
+- (void)startCDATA;
+
+/* Report the end of a CDATA section */
+- (void)endCDATA;
+
+@end
+
+#endif /* __SaxLexicalHandler_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxLocator.h b/skyrix-xml/SaxObjC/SaxLocator.h
new file mode 100644 (file)
index 0000000..fca8ae0
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __SaxLocator_H__
+#define __SaxLocator_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString;
+
+@protocol SaxLocator
+
+- (int)columnNumber;
+- (int)lineNumber;
+- (NSString *)publicId;
+- (NSString *)systemId;
+
+@end
+
+/* sample locator */
+
+@interface SaxLocator : NSObject < SaxLocator, NSCopying >
+{
+@private
+  int      column;
+  int      line;
+  NSString *pubId;
+  NSString *sysId;
+}
+
+- (id)init;
+- (id)initWithLocator:(id<SaxLocator>)_locator;
+
+- (void)setColumnNumber:(int)_col;
+- (int)columnNumber;
+- (void)setLineNumber:(int)_line;
+- (int)lineNumber;
+- (void)setPublicId:(NSString *)_pubId;
+- (NSString *)publicId;
+- (void)setSystemId:(NSString *)_sysId;
+- (NSString *)systemId;
+
+@end
+
+#endif /* __SaxLocator_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxLocator.m b/skyrix-xml/SaxObjC/SaxLocator.m
new file mode 100644 (file)
index 0000000..49350b4
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "SaxLocator.h"
+#include "common.h"
+
+@implementation SaxLocator
+
+- (id)init {
+  return self;
+}
+- (id)initWithLocator:(id<SaxLocator>)_locator {
+  if ((self = [self init])) {
+    self->column = [_locator columnNumber];
+    self->line   = [_locator lineNumber];
+    self->pubId  = [[_locator publicId] copy];
+    self->sysId  = [[_locator systemId] copy];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->pubId release];
+  [self->sysId release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setColumnNumber:(int)_col {
+  self->column = _col;
+}
+- (int)columnNumber {
+  return self->column;
+}
+
+- (void)setLineNumber:(int)_line {
+  self->line = _line;
+}
+- (int)lineNumber {
+  return self->line;
+}
+
+- (void)setPublicId:(NSString *)_pubId {
+  id o = self->pubId;
+  self->pubId = [_pubId copy];
+  [o release];
+}
+- (NSString *)publicId {
+  return self->pubId;
+}
+
+- (void)setSystemId:(NSString *)_sysId {
+  id o = self->sysId;
+  self->sysId = [_sysId copy];
+  [o release];
+}
+- (NSString *)systemId {
+  return self->sysId;
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+  return [[[self class] allocWithZone:_zone] initWithLocator:self];
+}
+
+@end /* SaxLocator */
diff --git a/skyrix-xml/SaxObjC/SaxMethodCallHandler.h b/skyrix-xml/SaxObjC/SaxMethodCallHandler.h
new file mode 100644 (file)
index 0000000..ea56ae6
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxMethodCallHandler_H__
+#define __SaxMethodCallHandler_H__
+
+#include <SaxObjC/SaxDefaultHandler.h>
+#import <Foundation/NSMapTable.h>
+
+@class NSString, NSMutableArray, NSMutableDictionary;
+
+/*
+  [also take a look at SaxObjectDecoder]
+  
+  This handler calls a method on a delegate for each tag. The selector is
+  constructed this way:
+  
+    [start|end] + nskey + tagname + ':'
+
+  If no method could be found for the tag, it is first checked whether the
+  delegate responds to
+
+    [start|end] + nskey + 'unknownTag:attributes:'
+
+  and it this couldn't be found, it is checked for
+
+    [start|end] + 'tag:_tagName namespace:_ns attributes:'
+
+  If no key could be found for a namespace, it is first checked whether the
+  delegate responds to
+
+    [start|end] + 'any_' + tagname + ':'
+
+  if this fails it is checked for this selector
+
+    [start|end] + 'tag:_tagName namespace:_ns attributes:'
+
+  if neither exists, the tag is ignored.
+  
+  Eg:
+
+    nskey='xhtml' startKey='start_' endKey='end_'
+    - (void)start_xhtml_br:(id<SaxAttributes>)_attrs;
+    - (void)end_xhtml_br;
+*/
+
+@interface SaxMethodCallHandler : SaxDefaultHandler
+{
+  id                  delegate; // non-retained: default=self (for subclasses)
+  NSMutableDictionary *namespaceToKey;
+  NSMutableArray      *tagStack;
+  NSString            *startKey;            // default: 'start_'
+  NSString            *endKey;              // default: 'end_'
+  NSString            *unknownNamespaceKey; // default: 'any_'
+  int                 ignoreLevel;
+  
+  /* processing */
+  NSMapTable      *fqNameToStartSel;
+  NSMutableString *selName; /* reused for each construction */
+}
+
+/* namespaces */
+
+- (void)registerNamespace:(NSString *)_namespace withKey:(NSString *)_key;
+
+/* keys */
+
+- (void)setStartKey:(NSString *)_s;
+- (NSString *)startKey;
+- (void)setEndKey:(NSString *)_s;
+- (NSString *)endKey;
+- (void)setUnknownNamespaceKey:(NSString *)_s;
+- (NSString *)unknownNamespaceKey;
+
+/* tag stack */
+
+- (NSArray *)tagStack;
+- (unsigned)depth;
+
+- (void)ignoreChildren;
+- (BOOL)doesIgnoreChildren;
+
+/* delegate */
+
+- (void)setDelegate:(id)_delegate;
+- (id)delegate;
+
+@end
+
+#endif /* __SaxMethodCallHandler_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxMethodCallHandler.m b/skyrix-xml/SaxObjC/SaxMethodCallHandler.m
new file mode 100644 (file)
index 0000000..a6bf1ee
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SaxMethodCallHandler.h"
+#include "common.h"
+
+@interface NSObject(ToBeFixed)
+
+- (id)performSelector:(SEL)_sel
+  withObject:(id)_arg1
+  withObject:(id)_arg2
+  withObject:(id)_arg3;
+
+@end
+
+@implementation SaxMethodCallHandler
+
+static BOOL debugOn = NO;
+
+- (id)init {
+  if ((self = [super init])) {
+    self->delegate = self;
+    
+    self->fqNameToStartSel = NSCreateMapTable(NSObjectMapKeyCallBacks,
+                                              NSNonOwnedPointerMapValueCallBacks,
+                                              64);
+    self->selName     = [[NSMutableString alloc] initWithCapacity:64];
+    self->tagStack    = [[NSMutableArray alloc] initWithCapacity:16];
+    
+    self->startKey            = @"start_";
+    self->endKey              = @"end_";
+    self->unknownNamespaceKey = @"any_";
+
+    self->ignoreLevel = -1;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  NSFreeMapTable(self->fqNameToStartSel);
+  [self->tagStack       release];
+  [self->unknownNamespaceKey release];
+  [self->startKey       release];
+  [self->endKey         release];
+  [self->selName        release];
+  [self->namespaceToKey release];
+  [super dealloc];
+}
+
+- (void)registerNamespace:(NSString *)_namespace withKey:(NSString *)_key {
+  if (self->namespaceToKey == nil)
+    self->namespaceToKey = [[NSMutableDictionary alloc] initWithCapacity:16];
+  
+  [self->namespaceToKey setObject:_key forKey:_namespace];
+}
+
+- (void)setDelegate:(id)_delegate {
+  NSResetMapTable(self->fqNameToStartSel);
+  
+  self->delegate = _delegate;
+}
+- (id)delegate {
+  return self->delegate;
+}
+
+- (void)setStartKey:(NSString *)_s {
+  id o = self->startKey;
+  self->startKey = [_s copy];
+  [o release];
+}
+- (NSString *)startKey {
+  return self->startKey;
+}
+
+- (void)setEndKey:(NSString *)_s {
+  id o = self->endKey;
+  self->endKey = [_s copy];
+  [o release];
+}
+- (NSString *)endKey {
+  return self->endKey;
+}
+
+- (void)setUnknownNamespaceKey:(NSString *)_s {
+  id o = self->unknownNamespaceKey;
+  self->unknownNamespaceKey = [_s copy];
+  [o release];
+}
+- (NSString *)unknownNamespaceKey {
+  return self->unknownNamespaceKey;
+}
+
+- (NSArray *)tagStack {
+  return self->tagStack;
+}
+- (unsigned)depth {
+  return [self->tagStack count];
+}
+
+- (void)ignoreChildren {
+  if (self->ignoreLevel == -1)
+    self->ignoreLevel = [self depth];
+}
+- (BOOL)doesIgnoreChildren {
+  if (self->ignoreLevel == -1)
+    return NO;
+  
+  return (int)[self depth] >= self->ignoreLevel ? YES : NO;
+}
+
+/* standard Sax callbacks */
+
+- (void)endDocument {
+  [super endDocument];
+  [selName setString:@""];
+}
+
+static inline void _selAdd(SaxMethodCallHandler *self, NSString *_s) {
+  [self->selName appendString:_s];
+}
+static inline void _selAddEscaped(SaxMethodCallHandler *self, NSString *_s) {
+  const unsigned char *cstr;
+  register unsigned i, len;
+  BOOL needsEscape = NO;
+  
+  if ((len = [_s cStringLength]) == 0)
+    return;
+  
+  cstr = [_s cString];
+  for (i = 0; i < len; i++) {
+    register unsigned char c = cstr[i];
+
+    if (!(isalnum((int)c) || (c == '_'))) {
+      needsEscape = YES;
+      break;
+    }
+  }
+  
+  if (needsEscape) {
+    unsigned char *buf;
+    unsigned j;
+    NSString *s;
+    
+    buf = malloc(len + 1);
+    for (i = 0, j = 0; i < len; i++) {
+      register unsigned char c = cstr[i];
+      
+      if (isalnum((int)c) || (c == '_')) {
+        if (i > 0) {
+          if (cstr[i - 1] == '-')
+            c = toupper(c);
+        }
+        buf[j] = c;
+        j++;
+      }
+      else {
+        /* do nothing, leave out char */
+      }
+    }
+    buf[j] = '\0';
+    
+    s = [[NSString alloc] initWithCString:buf length:j];
+    [self->selName appendString:s];
+    [s release];
+  }
+  else
+    [self->selName appendString:_s];
+}
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attrs
+{
+  NSString *fqName;
+  NSString *nskey;
+  SEL      sel;
+  
+  fqName = [[NSString alloc] initWithFormat:@"{%@}%@", _ns, _localName];
+  [self->tagStack addObject:fqName];
+  [fqName release]; // still retained by tagStack
+  
+  if ((int)[self depth] > self->ignoreLevel)
+    return;
+  
+  if ((nskey = [self->namespaceToKey objectForKey:_ns]) == nil) {
+    /* unknown namespace */
+    if (debugOn)
+      NSLog(@"unknown namespace key %@ (tag=%@)", _ns, _rawName);
+
+    [self->selName setString:@""];
+    _selAdd(self, self->startKey);
+  }
+  else if ((sel = NSMapGet(self->fqNameToStartSel, fqName))) {
+    /* cached a selector .. */
+    [self->delegate performSelector:sel withObject:_attrs];
+    goto found;
+  }
+  else {
+    [self->selName setString:self->startKey];
+    _selAdd(self, nskey);
+    _selAddEscaped(self, _localName);
+    _selAdd(self, @":");
+    
+    sel = NSSelectorFromString(self->selName);
+    if ([self->delegate respondsToSelector:sel]) {
+      /* ok, found correct selector */
+      [self->delegate performSelector:sel withObject:_attrs];
+      NSMapInsert(self->fqNameToStartSel, fqName, sel);
+      goto found;
+    }
+    
+    /* check for 'start_nskey_unknownTag:attributes:' */
+    [self->selName setString:self->startKey];
+    _selAdd(self, nskey);
+    _selAdd(self, @"unknownTag:attributes:");
+    sel = NSSelectorFromString(self->selName);
+    if ([self->delegate respondsToSelector:sel]) {
+      /* ok, found selector */
+      [self->delegate performSelector:sel
+                      withObject:_localName
+                      withObject:_attrs];
+      goto found;
+    }
+    
+    /* check for 'start_tag:namespace:attributes:' */
+    [self->selName setString:self->startKey];
+    _selAdd(self, @"tag:namespace:attributes:");
+    sel = NSSelectorFromString(self->selName);
+    if ([self->delegate respondsToSelector:sel]) {
+      /* ok, found selector */
+      [self->delegate performSelector:sel
+                      withObject:_localName withObject:_ns
+                      withObject:_attrs];
+      goto found;
+    }
+    
+    /* ignore tag */
+  }
+  
+  if (debugOn) {
+    NSLog(@"%s: ignore tag: %@, sel %@", __PRETTY_FUNCTION__,
+         fqName, self->selName);
+  }
+  return;
+
+ found:
+  ; // required for MacOSX gcc
+}
+
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  NSString *nskey;
+  SEL      sel;
+  
+  if ((int)[self depth] > self->ignoreLevel) {
+    [self->tagStack removeLastObject];
+    return;
+  }
+  self->ignoreLevel = -1;
+  
+  if ((nskey = [self->namespaceToKey objectForKey:_ns]) == nil) {
+    /* unknown namespace */
+    if (debugOn)
+      NSLog(@"unknown namespace key %@ (tag=%@)", _ns, _rawName);
+    [selName setString:self->endKey];
+  }
+  else {
+    [selName setString:self->endKey];
+    _selAdd(self, nskey);
+    _selAdd(self, _localName);
+    
+    sel = NSSelectorFromString(self->selName);
+    if ([self->delegate respondsToSelector:sel]) {
+      /* ok, found correct selector */
+      [self->delegate performSelector:sel];
+      goto found;
+    }
+    
+    /* check for 'end_nskey_unknownTag:' */
+    [self->selName setString:self->endKey];
+    _selAdd(self, nskey);
+    _selAdd(self, @"unknownTag:");
+    sel = NSSelectorFromString(self->selName);
+    if ([self->delegate respondsToSelector:sel]) {
+      /* ok, found selector */
+      [self->delegate performSelector:sel withObject:_localName];
+      goto found;
+    }
+    
+    /* check for 'end_tag:namespace:attributes:' */
+    [self->selName setString:self->endKey];
+    _selAdd(self, @"tag:namespace:");
+    sel = NSSelectorFromString(self->selName);
+    if ([self->delegate respondsToSelector:sel]) {
+      /* ok, found selector */
+      [self->delegate performSelector:sel withObject:_localName withObject:_ns];
+      goto found;
+    }
+
+    /* didn't find end tag .. */
+  }
+  
+  [self->tagStack removeLastObject];
+  return;
+  
+ found:
+  [self->tagStack removeLastObject];
+}
+
+@end /* SaxMethodCallHandler */
diff --git a/skyrix-xml/SaxObjC/SaxNamespaceSupport.h b/skyrix-xml/SaxObjC/SaxNamespaceSupport.h
new file mode 100644 (file)
index 0000000..2a1457b
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxNamespaceSupport_H__
+#define __SaxNamespaceSupport_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSEnumerator, NSArray;
+
+/*
+  New in SAX2, defined in helpers/NamespaceSupport
+
+  Encapsulate Namespace logic for use by SAX drivers. 
+
+  This class encapsulates the logic of Namespace processing: it tracks
+  the declarations currently in force for each context and automatically
+  processing raw XML 1.0 names into their Namespace parts.
+
+  Namespace support objects are reusable, but the reset method must be
+  invoked between each session.
+
+  Here is a simple session:
+  
+      String parts[] = new String[3];
+      SaxNamespaceSupport support;
+
+      support = [[SaxNamespaceSupport alloc] init];
+      
+      [support pushContext];
+      [support declarePrefix:@""   uri:@"http://www.w3.org/1999/xhtml"];
+      [support declarePrefix:@"dc" uri:@"http://www.purl.org/dc#"];
+      
+      String parts[] = support.processName("p", parts, false);
+      System.out.println("Namespace URI: " + parts[0]);
+      System.out.println("Local name: " + parts[1]);
+      System.out.println("Raw name: " + parts[2]);
+     
+      String parts[] = support.processName("dc:title", parts, false);
+      System.out.println("Namespace URI: " + parts[0]);
+      System.out.println("Local name: " + parts[1]);
+      System.out.println("Raw name: " + parts[2]);
+     
+      [support popContext];
+  Note that this class is optimized for the use case where most elements
+  do not contain Namespace declarations: if the same prefix/URI mapping
+  is repeated for each context (for example), this class will be somewhat
+  less efficient.
+*/
+
+extern NSString *SaxXMLNS;
+
+@interface SaxNamespaceSupport : NSObject
+{
+@private
+}
+
+/* start a new ns context */
+- (void)pushContext;
+
+/* revert to previous ns context */
+- (void)popContext;
+
+/* Declare a Namespace prefix. */
+- (BOOL)declarePrefix:(NSString *)_prefix uri:(NSString *)_uri;
+
+/* Return an enumeration of all prefixes declared in this context. */
+- (NSEnumerator *)prefixEnumerator;
+
+/* Look up a prefix and get the currently-mapped Namespace URI. */
+- (NSString *)getUriForPrefix:(NSString *)_prefix;
+
+/* Reset this Namespace support object for reuse. */
+- (void)reset;
+
+/*
+  Process a raw XML 1.0 name.
+  
+  This method processes a raw XML 1.0 name in the current context by
+  removing the prefix and looking it up among the prefixes currently
+  declared. The return value will be the array supplied by the caller,
+  filled in as follows:
+
+    parts[0] The Namespace URI, or an empty string if none is in use. 
+    parts[1] The local name (without prefix). 
+    parts[2] The original raw name.
+    
+  All of the strings in the array will be internalized. If the raw name
+  has a prefix that has not been declared, then the return value will be
+  null.
+
+  Note that attribute names are processed differently than element names:
+  an unprefixed element name will received the default Namespace (if any),
+  while an unprefixed element name will not.
+*/
+- (NSArray *)processName:(NSString *)_rawName
+  parts:(NSArray *)_parts
+  isAttribute:(BOOL)_isAttribute;
+
+@end
+
+#endif /* __SaxNamespaceSupport_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxNamespaceSupport.m b/skyrix-xml/SaxObjC/SaxNamespaceSupport.m
new file mode 100644 (file)
index 0000000..a001a48
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SaxNamespaceSupport.h"
+#include "common.h"
+
+@implementation SaxNamespaceSupport
+
+- (void)pushContext {
+  [self doesNotRecognizeSelector:_cmd];
+}
+
+- (void)popContext {
+  [self doesNotRecognizeSelector:_cmd];
+}
+
+- (BOOL)declarePrefix:(NSString *)_prefix uri:(NSString *)_uri {
+  [self doesNotRecognizeSelector:_cmd];
+  return NO;
+}
+
+- (NSEnumerator *)prefixEnumerator {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (NSString *)getUriForPrefix:(NSString *)_prefix {
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+- (void)reset {
+}
+
+- (NSArray *)processName:(NSString *)_rawName
+  parts:(NSArray *)_parts
+  isAttribute:(BOOL)_isAttribute
+{
+  [self doesNotRecognizeSelector:_cmd];
+  return nil;
+}
+
+@end /* SaxNamespaceSupport */
diff --git a/skyrix-xml/SaxObjC/SaxObjC-Info.plist b/skyrix-xml/SaxObjC/SaxObjC-Info.plist
new file mode 100644 (file)
index 0000000..012c171
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SaxObjC</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.xml.SaxObjC</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-xml/SaxObjC/SaxObjC.h b/skyrix-xml/SaxObjC/SaxObjC.h
new file mode 100644 (file)
index 0000000..7662240
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxObjC_H__
+#define __SaxObjC_H__
+
+#include <SaxObjC/SaxAttributeList.h>
+#include <SaxObjC/SaxAttributes.h>
+#include <SaxObjC/SaxContentHandler.h>
+#include <SaxObjC/SaxDTDHandler.h>
+#include <SaxObjC/SaxDeclHandler.h>
+#include <SaxObjC/SaxDefaultHandler.h>
+#include <SaxObjC/SaxDocumentHandler.h>
+#include <SaxObjC/SaxEntityResolver.h>
+#include <SaxObjC/SaxErrorHandler.h>
+#include <SaxObjC/SaxException.h>
+#include <SaxObjC/SaxHandlerBase.h>
+#include <SaxObjC/SaxLexicalHandler.h>
+#include <SaxObjC/SaxLocator.h>
+#include <SaxObjC/SaxNamespaceSupport.h>
+#include <SaxObjC/SaxXMLFilter.h>
+#include <SaxObjC/SaxXMLReader.h>
+#include <SaxObjC/SaxXMLReaderFactory.h>
+#include <SaxObjC/SaxObjectDecoder.h>
+
+#endif /* __SaxObjC_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxObjectDecoder.h b/skyrix-xml/SaxObjC/SaxObjectDecoder.h
new file mode 100644 (file)
index 0000000..de3c1a4
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __SaxObjC_SaxObjectDecoder_H__
+#define __SaxObjC_SaxObjectDecoder_H__
+
+#include <SaxObjC/SaxDefaultHandler.h>
+
+/*
+  This SAX handler takes a model dictionary and maps the SAX events
+  to object construction commands.
+  
+  [to be done: further description of format and function]
+*/
+
+@class SaxObjectModel;
+
+@interface SaxObjectDecoder : SaxDefaultHandler
+{
+  id<NSObject,SaxLocator> locator;
+  id rootObject;
+  id mapping;
+
+  NSMutableArray *infoStack;
+  NSMutableArray *mappingStack;
+  NSMutableArray *objectStack;
+}
+
+- (id)initWithMappingModel:(SaxObjectModel *)_model;
+- (id)initWithMappingAtPath:(NSString *)_path;
+- (id)initWithMappingNamed:(NSString *)_name;
+
+/* parse results */
+
+- (id)rootObject;
+
+/* cleanup */
+
+- (void)reset;
+
+@end
+
+@interface NSObject(SaxObjectCoding)
+
+- (id)initWithSaxDecoder:(SaxObjectDecoder *)_decoder;
+- (id)awakeAfterUsingSaxDecoder:(SaxObjectDecoder *)_decoder;
+
+@end
+
+#endif /* __SaxObjC_SaxObjectDecoder_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxObjectDecoder.m b/skyrix-xml/SaxObjC/SaxObjectDecoder.m
new file mode 100644 (file)
index 0000000..b1f3145
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "SaxObjectDecoder.h"
+#include "SaxObjectModel.h"
+#include "common.h"
+
+static BOOL debugOn = NO;
+
+@interface _SaxObjTagInfo : NSObject
+{
+@public
+  SaxObjectDecoder *decoder;    /* non-retained */
+  _SaxObjTagInfo   *parentInfo; /* non-retained */
+  SaxTagModel *mapping;
+  NSString    *tagName;
+  NSString    *namespace;
+  NSException *error;
+  id          object;
+  struct {
+    int isRoot:1;
+    int isMutableDict:1;
+    int isString:1;
+    int isMutableString:1;
+    int hasContentKey:1;
+  } flags;
+  NSMutableString *collectedCharData;
+}
+
+/* accessors */
+
+- (SaxTagModel *)mapping;
+- (id)object;
+
+/* tag handling */
+
+- (void)start;
+- (void)stop;
+
+- (void)characters:(unichar *)_chars length:(int)_len;
+
+@end
+
+@implementation SaxObjectDecoder
+
+static NSNull *null = nil;
+
++ (void)initialize {
+  if (null == nil) null = [[NSNull null] retain];
+}
+
+- (id)initWithMappingModel:(SaxObjectModel *)_model {
+  if ((self = [super init])) {
+    self->mapping = [_model retain];
+  }
+  return self;
+}
+
+- (id)initWithMappingAtPath:(NSString *)_path {
+  SaxObjectModel *model;
+
+  model = [SaxObjectModel modelWithContentsOfFile:_path];
+  return [self initWithMappingModel:model];
+}
+- (id)initWithMappingNamed:(NSString *)_name {
+  SaxObjectModel *model;
+  
+  model = [SaxObjectModel modelWithName:_name];
+  return [self initWithMappingModel:model];
+}
+
+- (id)init {
+  return [self initWithMappingModel:nil];
+}
+
+- (void)dealloc {
+  [self reset];
+  [self->objectStack  release];
+  [self->mappingStack release];
+  [self->infoStack    release];
+  [self->locator      release];
+  [super dealloc];
+}
+
+/* parse results */
+
+- (id)rootObject {
+  return self->rootObject;
+}
+
+/* cleanup */
+
+- (void)parseReset {
+  NSAutoreleasePool *pool;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  [self->infoStack    removeAllObjects];
+  [self->mappingStack removeAllObjects];
+  [self->objectStack  removeAllObjects];
+  [pool release];
+}
+- (void)reset {
+  [self parseReset];
+  
+  [self->rootObject release]; 
+  self->rootObject = nil;
+}
+
+/* parsing */
+
+- (void)startDocument {
+  [self reset];
+  
+  if (self->infoStack == nil)
+    self->infoStack = [[NSMutableArray alloc] initWithCapacity:16];
+}
+
+- (void)endDocument {
+  [self parseReset];
+}
+
+/* positioning info */
+
+- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator {
+  ASSIGN(self->locator, _locator);
+}
+
+/* stacks */
+
+- (void)pushInfo:(_SaxObjTagInfo *)_info {
+  [self->infoStack addObject:_info];
+}
+- (void)popInfo {
+  [self->infoStack removeObjectAtIndex:([self->infoStack count] - 1)];
+}
+- (id)currentInfo {
+  return [self->infoStack lastObject];
+}
+
+/* elements */
+
+- (NSException *)missingNamespaceMapping:(NSString *)_ns {
+  return [NSException exceptionWithName:@"MissingNamespaceMapping"
+                     reason:_ns
+                     userInfo:nil];
+}
+- (NSException *)missingElementMapping:(NSString *)_ns:(NSString *)_tag {
+  return [NSException exceptionWithName:@"MissingElementMapping"
+                     reason:_tag
+                     userInfo:nil];
+}
+- (NSException *)missingMappedClass:(NSString *)_className {
+  return [NSException exceptionWithName:@"MissingMappedClass"
+                     reason:_className
+                     userInfo:nil];
+}
+
+- (SaxTagModel *)mappingForTag:(NSString *)_tag namespace:(NSString *)_ns {
+  return [self->mapping modelForTag:_tag namespace:_ns];
+}
+
+- (void)couldNotApplyAttribute:(NSString *)_attr asKey:(NSString *)_key
+  onObject:(id)_object
+{
+  NSLog(@"SaxObjectDecoder: could not apply attribute '%@' (key=%@) "
+       @"on object %@",
+       _attr, _key, _object);
+}
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attributes
+{
+  _SaxObjTagInfo *info;
+  
+  info = [_SaxObjTagInfo alloc];
+  info->decoder      = self;
+  info->flags.isRoot = [self->infoStack count] == 0 ? 1 : 0;
+  info->parentInfo   = info->flags.isRoot ? nil : [self->infoStack lastObject];
+  info->tagName      = [_localName copy];
+  info->namespace    = [_ns        copy];
+  
+  [self->infoStack addObject:info];
+  
+  /* determine mapping dictionary */
+  
+  if ((info->mapping = [self mappingForTag:_localName namespace:_ns]) == nil) {
+    if (debugOn) {
+      NSLog(@"found no mapping for element '%@' (namespace %@)", 
+           _localName, _ns);
+    }
+    info->error = [[self missingElementMapping:_ns:_localName] retain];
+    return;
+  }
+  
+  /* start object */
+  [info start];
+  
+  /* add attribute values */
+  {
+    NSEnumerator *e;
+    NSString     *a;
+    
+    e = [[info->mapping attributeKeys] objectEnumerator];
+    while ((a = [e nextObject])) {
+      NSString *v, *key;
+      
+      if ((v = [_attributes valueForName:a uri:_ns])) {
+       key = [info->mapping propertyKeyForAttribute:a];
+       
+       NS_DURING
+         [info->object takeValue:v forKey:key];
+       NS_HANDLER
+         [self couldNotApplyAttribute:a asKey:key onObject:info->object];
+       NS_ENDHANDLER;
+      }
+    }
+  }
+}
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  _SaxObjTagInfo *info;
+  unsigned idx;
+
+  idx = [self->infoStack count] - 1;
+  info = [self->infoStack objectAtIndex:idx];
+  [info stop];
+  
+  if (idx == 0)
+    ASSIGN(self->rootObject, [info object]);
+  
+  [self->infoStack removeObjectAtIndex:idx];
+}
+
+/* CDATA */
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  _SaxObjTagInfo *info;
+  
+  if (_len == 0) return;
+  info = [self->infoStack objectAtIndex:([self->infoStack count] - 1)];
+  [info characters:_chars length:_len];
+}
+
+- (BOOL)processIgnorableWhitespace {
+  return NO;
+}
+
+- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
+  if ([self processIgnorableWhitespace])
+    [self characters:_chars length:_len];
+}
+
+@end /* SaxObjectDecoder */
+
+@implementation NSObject(SaxObjectCoding)
+
+- (id)initWithSaxDecoder:(SaxObjectDecoder *)_decoder {
+  return [self init];
+}
+
+- (id)awakeAfterUsingSaxDecoder:(SaxObjectDecoder *)_decoder {
+  return self;
+}
+
+@end /* SaxCoding */
+
+@implementation _SaxObjTagInfo
+
+static Class  MutableDictClass   = Nil;
+static Class  MutableStringClass = Nil;
+static Class  StringClass        = Nil;
+
++ (void)initialize {
+  MutableDictClass   = [NSMutableDictionary class];
+  MutableStringClass = [NSMutableString     class];
+  StringClass        = [NSString            class];
+}
+
+- (void)dealloc {
+  [self->tagName   release];
+  [self->namespace release];
+  [self->error     release];
+  [self->object    release];
+  [self->collectedCharData release];
+  [super dealloc];
+}
+
+/* errors */
+
+- (NSException *)missingMappedClass:(NSString *)_className {
+  return [NSException exceptionWithName:@"MissingMappedClass"
+                     reason:_className
+                     userInfo:nil];
+}
+
+/* accessors */
+
+- (SaxTagModel *)mapping {
+  return self->mapping;
+}
+- (id)object {
+  return (self->object == null) ? nil : self->object;
+}
+
+- (SaxTagModel *)parentMapping {
+  return [self->parentInfo mapping];
+}
+- (id)parentObject {
+  return [self->parentInfo object];
+}
+
+/* run */
+
+- (Class)defaultElementClass {
+  return [NSMutableDictionary class];
+}
+
+- (void)unableToSetValue:(id)_object forKey:(NSString *)_key
+  withTag:(NSString *)_tag toParent:(id)_parent
+  exception:(NSException *)_exc
+{
+  NSLog(@"couldn't apply value %@ for key %@ with parent %@<%@>: %@",
+       _object, _key, _parent, NSStringFromClass([_parent class]), _exc);
+}
+
+- (void)addObject:(id)_object fromTag:(NSString *)_tag
+  withMapping:(SaxTagModel *)_elementMap
+  toParent:(id)_parent withMapping:(SaxTagModel *)_parentMap
+{
+  NSString *key;
+
+  if (_object     == nil || _object     == null) return;
+  if (_parent     == nil || _parent     == null) return;
+  if (_elementMap == nil || _elementMap == (id)null) return;
+  if (_parentMap  == nil || _parentMap  == (id)null) return;
+  
+  if ((key = [_parentMap propertyKeyForChildTag:_tag]) == nil) {
+    if ((key = [_elementMap key]) == nil)
+      key = _tag;
+  }
+  
+  NS_DURING {
+    if ([_parentMap isToManyKey:key]) {
+      [_parentMap addValue:_object toPropertyWithKey:key ofObject:_parent];
+    }
+    else {
+      [_parent takeValue:_object forKey:key];
+    }
+  }
+  NS_HANDLER {
+    [self unableToSetValue:_object forKey:key withTag:_tag toParent:_parent
+          exception:localException];
+  }
+  NS_ENDHANDLER;
+}
+
+- (void)start {
+  NSString *s;
+  Class    mappedClazz;
+  
+  /* determine class */
+  
+  if ((s = [self->mapping className])) {
+    mappedClazz = NSClassFromString(s);
+    if (mappedClazz == Nil) {
+      self->error = [[self missingMappedClass:s] retain];
+      return;
+    }
+  }
+  else
+    mappedClazz = [self defaultElementClass];
+  
+  /* do we need to check for subclasses? I guess not. */
+  self->flags.isMutableDict   = (mappedClazz == MutableDictClass)   ? 1 : 0;
+  self->flags.isMutableString = (mappedClazz == MutableStringClass) ? 1 : 0;
+  self->flags.isString        = (mappedClazz == StringClass)        ? 1 : 0;
+  self->flags.hasContentKey   = [[self->mapping contentKey] length] > 0 ?1:0;
+  
+  /* create an object for the element .. */
+  
+  if ((self->object = [[mappedClazz alloc] initWithSaxDecoder:self->decoder])) {
+    NSDictionary *defaultValues;
+    id tmp;
+    
+    if ((defaultValues = [self->mapping defaultValues]))
+      [self->object takeValuesFromDictionary:defaultValues];
+    
+    if ((tmp = [self->mapping tagKey]))
+      [self->object takeValue:self->tagName forKey:tmp];
+    if ((tmp = [self->mapping namespaceKey]))
+      [self->object takeValue:self->namespace forKey:tmp];
+  }
+}
+
+- (void)stop {
+  id tmp;
+
+  /* awake from decoding (the decoded object can replace itself :-) */
+  
+  if (self->flags.isString) {
+  }
+  else {
+    if (self->flags.hasContentKey) {
+      NSString *s;
+
+      s = [self->collectedCharData copy];
+      ASSIGN(self->collectedCharData, (id)nil);
+      
+      [self->object takeValue:s forKey:[self->mapping contentKey]];
+      [s release];
+    }
+    
+    tmp = self->object;
+    self->object =
+      [[self->object awakeAfterUsingSaxDecoder:self->decoder] retain];
+    [tmp release];
+  }
+  if (!self->flags.isRoot) {
+    NSString *t;
+    id parent;
+
+    parent = [self parentObject];
+    
+    /* add to parent */
+
+    if ((t = [self->mapping parentKey]))
+      [self->object takeValue:parent forKey:t];
+    
+    [self addObject:self->object 
+         fromTag:self->tagName
+         withMapping:self->mapping
+         toParent:parent
+         withMapping:[self parentMapping]];
+  }
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  if (self->flags.isMutableString) {
+    NSString *tmp;
+    
+    tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
+    [self->object appendString:tmp];
+    [tmp release];
+  }
+  else if (self->flags.isString) {
+    NSString *tmp, *old;
+
+    old = self->object;
+    
+    tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
+    self->object = [self->object stringByAppendingString:tmp];
+    [tmp release];
+    [old release];
+  }
+  else if (self->flags.hasContentKey) {
+    if (self->collectedCharData == nil) {
+      self->collectedCharData = 
+       [[NSMutableString alloc] initWithCharacters:_chars length:_len];
+    }
+    else {
+      NSString *tmp;
+      
+      tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
+      [self->collectedCharData appendString:tmp];
+      [tmp release];
+    }
+  }
+}
+
+@end /* _SaxObjTagInfo */
diff --git a/skyrix-xml/SaxObjC/SaxObjectModel.h b/skyrix-xml/SaxObjC/SaxObjectModel.h
new file mode 100644 (file)
index 0000000..9613565
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxObjC_SaxObjectModel_H__
+#define __SaxObjC_SaxObjectModel_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSDictionary, NSString, NSArray;
+@class SaxTagModel;
+
+@interface SaxObjectModel : NSObject
+{
+  NSDictionary *nsToModel;
+}
+
++ (id)modelWithName:(NSString *)_name;
++ (id)modelWithContentsOfFile:(NSString *)_path;
+
+- (id)initWithDictionary:(NSDictionary *)_dict;
+
+/* queries */
+
+- (SaxTagModel *)modelForTag:(NSString *)_localName namespace:(NSString *)_ns;
+
+@end
+
+@interface SaxNamespaceModel : NSObject
+{
+  NSDictionary *tagToModel;
+}
+
+/* queries */
+
+- (SaxTagModel *)modelForTag:(NSString *)_localName;
+
+@end
+
+@interface SaxTagModel : NSObject
+{
+  NSString     *className;
+  NSString     *key;
+  NSString     *tagKey;       /* the key to store the tag name under */
+  NSString     *namespaceKey; /* the key to store the namespace uri under */
+  NSString     *parentKey;    /* the key to store the parent object under */
+  NSString     *contentKey;   /* the key to store the cdata content under */
+  NSArray      *toManyRelationshipKeys;
+  NSDictionary *defaultValues;
+  NSDictionary *tagToKey;
+  NSDictionary *attrToKey;
+}
+
+/* accessors */
+
+- (NSString *)className;
+- (NSString *)key;
+- (NSString *)tagKey;
+- (NSString *)namespaceKey;
+- (NSString *)parentKey;
+- (NSString *)contentKey;
+- (NSDictionary *)defaultValues;
+
+- (NSString *)propertyKeyForChildTag:(NSString *)_tag;
+
+- (BOOL)isToManyKey:(NSString *)_key;
+- (NSArray *)toManyRelationshipKeys;
+
+- (NSArray *)attributeKeys;
+- (NSString *)propertyKeyForAttribute:(NSString *)_attr;
+
+/* object operations */
+
+- (void)addValue:(id)_val toPropertyWithKey:(NSString *)_key ofObject:(id)_obj;
+
+@end
+
+#endif /* __SaxObjC_SaxObjectModel_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxObjectModel.m b/skyrix-xml/SaxObjC/SaxObjectModel.m
new file mode 100644 (file)
index 0000000..df3a58a
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "SaxObjectModel.h"
+#include "common.h"
+
+static NSDictionary *mapDictsToObjects(NSDictionary *_dict, Class clazz) {
+  NSMutableDictionary *md;
+  NSEnumerator *e;
+  NSString     *key;
+  
+  md = [NSMutableDictionary dictionaryWithCapacity:16];
+  
+  e = [_dict keyEnumerator];
+  while ((key = [e nextObject])) {
+    id obj;
+
+    obj = [[clazz alloc] initWithDictionary:[_dict objectForKey:key]];
+    [md setObject:obj forKey:key];
+    [obj release];
+  }
+  return md;
+}
+
+@implementation SaxObjectModel
+
+static BOOL    doDebug = NO;
+static NSArray *searchPathes = nil;
+
++ (NSArray *)saxMappingSearchPathes {
+  if (searchPathes == nil) {
+    NSMutableArray *ma;
+    NSDictionary   *env;
+    id tmp;
+    
+    env = [[NSProcessInfo processInfo] environment];
+    ma  = [NSMutableArray arrayWithCapacity:6];
+
+#if COCOA_Foundation_LIBRARY
+    tmp = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory,
+                                              NSAllDomainsMask,
+                                              YES);
+    if ([tmp count] > 0) {
+      NSEnumerator *e;
+      
+      e = [tmp objectEnumerator];
+      while ((tmp = [e nextObject])) {
+        tmp = [tmp stringByAppendingPathComponent:@"SaxMappings"];
+        if (![ma containsObject:tmp])
+          [ma addObject:tmp];
+      }
+    }
+#else
+    if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil)
+      tmp = [env objectForKey:@"GNUSTEP_PATHLIST"];
+    tmp = [tmp componentsSeparatedByString:@":"];
+    if ([tmp count] > 0) {
+      NSEnumerator *e;
+      
+      e = [tmp objectEnumerator];
+      while ((tmp = [e nextObject])) {
+        tmp = [tmp stringByAppendingPathComponent:@"Library/SaxMappings"];
+        if (![ma containsObject:tmp])
+          [ma addObject:tmp];
+      }
+    }
+    else {
+      NSLog(@"%s: empty library search path !", __PRETTY_FUNCTION__);
+    }
+#endif
+    
+    searchPathes = [ma copy];
+    
+    if ([searchPathes count] == 0)
+      NSLog(@"%s: no search pathes were found !", __PRETTY_FUNCTION__);
+  }
+  return searchPathes;
+}
+
++ (id)modelWithName:(NSString *)_name {
+  NSFileManager *fileManager;
+  NSEnumerator  *pathes;
+  NSString      *path;
+
+  /* first look in main bundle */
+  
+  if ((path = [[NSBundle mainBundle] pathForResource:_name ofType:@"xmap"]))
+    return [self modelWithContentsOfFile:path];
+
+  /* then in Library */
+  
+  fileManager = [NSFileManager defaultManager];
+  pathes      = [[[self class] saxMappingSearchPathes] objectEnumerator];
+  _name       = [_name stringByAppendingPathExtension:@"xmap"];
+  
+  while ((path = [pathes nextObject])) {
+    BOOL isDir;
+    
+    path = [path stringByAppendingPathComponent:_name];
+    
+    if (![fileManager fileExistsAtPath:path isDirectory:&isDir])
+      continue;
+    if (isDir)
+      continue;
+    
+    break;
+  }
+  
+  return [self modelWithContentsOfFile:path];
+}
+
++ (id)modelWithContentsOfFile:(NSString *)_path {
+  NSDictionary *dict;
+  
+  if ((dict = [NSDictionary dictionaryWithContentsOfFile:_path]) == nil)
+    return nil;
+  
+  return [[[self alloc] initWithDictionary:dict] autorelease];
+}
+
+- (id)initWithDictionary:(NSDictionary *)_dict {
+  self->nsToModel =
+    [mapDictsToObjects(_dict, [SaxNamespaceModel class]) retain];
+  return self;
+}
+
+- (void)dealloc {
+  [self->nsToModel release];
+  [super dealloc];
+}
+
+/* queries */
+
+- (SaxTagModel *)modelForTag:(NSString *)_localName namespace:(NSString *)_ns {
+  SaxNamespaceModel *nsmap;
+  
+  if ((nsmap = [self->nsToModel objectForKey:_ns]) == nil) {
+    if ((nsmap = [self->nsToModel objectForKey:@"*"]) == nil)
+      return nil;
+  }
+  return [nsmap modelForTag:_localName];
+}
+
+/* faking dictionary */
+
+- (id)objectForKey:(id)_key {
+  return [self->nsToModel objectForKey:_key];
+}
+
+@end /* SaxMappingModel */
+
+@implementation SaxNamespaceModel
+
+- (id)initWithDictionary:(NSDictionary *)_dict {
+  self->tagToModel = [mapDictsToObjects(_dict, [SaxTagModel class]) retain];
+  return self;
+}
+
+- (void)dealloc {
+  [self->tagToModel release];
+  [super dealloc];
+}
+
+/* queries */
+
+- (SaxTagModel *)modelForTag:(NSString *)_localName {
+  SaxTagModel *map;
+  
+  if ((map = [self->tagToModel objectForKey:_localName]))
+    return map;
+  if ((map = [self->tagToModel objectForKey:@"*"]))
+    return map;
+  return nil;
+}
+
+/* faking dictionary */
+
+- (id)objectForKey:(id)_key {
+  return [self->tagToModel objectForKey:_key];
+}
+
+@end /* SaxNamespaceModel */
+
+@implementation SaxTagModel
+
+- (NSDictionary *)_extractAttributeMapping:(NSDictionary *)as {
+  NSMutableDictionary *md;
+  NSEnumerator *keys;
+  NSString     *k;
+  NSDictionary *result;
+      
+  md = [[NSMutableDictionary alloc] initWithCapacity:16];
+      
+  keys = [as keyEnumerator];
+  while ((k = [keys nextObject])) {
+    id val;
+       
+    val = [as objectForKey:k];
+       
+    if ([val isKindOfClass:[NSString class]])
+      [md setObject:val forKey:k];
+    else if ([val count] == 0)
+      [md setObject:k forKey:k];
+    else 
+      [md setObject:[(NSDictionary *)val objectForKey:@"key"] forKey:k];
+  }
+  
+  result = [md copy];
+  [md release];
+  return result;
+}
+
+- (id)initWithDictionary:(NSDictionary *)_dict {
+  if ((self = [super init])) {
+    NSDictionary *rels;
+    NSDictionary *as;
+    
+    self->className     = [[_dict objectForKey:@"class"]  copy];
+    self->key           = [[_dict objectForKey:@"key"]    copy];
+    self->tagKey        = [[_dict objectForKey:@"tagKey"] copy];
+    self->namespaceKey  = [[_dict objectForKey:@"namespaceKey"] copy];
+    self->parentKey     = [[_dict objectForKey:@"parentKey"] copy];
+    self->contentKey    = [[_dict objectForKey:@"contentKey"] copy];
+    self->defaultValues = [[_dict objectForKey:@"defaultValues"] copy];
+    
+    if ((as = [_dict objectForKey:@"attributes"]))
+      self->attrToKey = [self _extractAttributeMapping:as];
+    
+    if ((rels = [_dict objectForKey:@"ToManyRelationships"])) {
+      NSMutableDictionary *md;
+      NSEnumerator *keys;
+      NSString *k;
+      
+      self->toManyRelationshipKeys = [[rels allKeys] copy];
+    
+      md = [[NSMutableDictionary alloc] initWithCapacity:16];
+      
+      keys = [self->toManyRelationshipKeys objectEnumerator];
+      while ((k = [keys nextObject])) {
+       id       tags;
+       NSString *tag;
+       
+       tags = [rels objectForKey:k];
+       if ([tags isKindOfClass:[NSString class]])
+         tags = [NSArray arrayWithObject:tags];
+       tags = [tags objectEnumerator];
+       
+       while ((tag = [tags nextObject])) {
+         NSString *t;
+         
+         if ((t = [md objectForKey:tag])) {
+           NSLog(@"SaxObjectModel: cannot map tag '%@' to key '%@', "
+                 @"it is already mapped to key '%@'.",
+                 tag, k, t);
+         }
+         else {
+           [md setObject:k forKey:tag];
+         }
+       }
+      }
+      self->tagToKey = [md copy];
+      [md release];
+    }
+    
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->defaultValues          release];
+  [self->toManyRelationshipKeys release];
+  [self->tagToKey     release];
+  [self->className    release];
+  [self->tagKey       release];
+  [self->namespaceKey release];
+  [self->parentKey  release];
+  [self->contentKey release];
+  [self->key        release];
+  [self->attrToKey  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (NSString *)className {
+  return self->className;
+}
+- (NSString *)key {
+  return self->key;
+}
+- (NSString *)tagKey {
+  return self->tagKey;
+}
+- (NSString *)namespaceKey {
+  return self->namespaceKey;
+}
+- (NSString *)parentKey {
+  return self->parentKey;
+}
+- (NSString *)contentKey {
+  return self->contentKey;
+}
+
+- (NSDictionary *)defaultValues {
+  return self->defaultValues;
+}
+
+- (BOOL)isToManyKey:(NSString *)_key {
+  return [self->toManyRelationshipKeys containsObject:_key];
+}
+- (NSArray *)toManyRelationshipKeys {
+  return self->toManyRelationshipKeys;
+}
+
+- (BOOL)isToManyTag:(NSString *)_tag {
+  return ([self->tagToKey objectForKey:_tag] != nil) ? YES : NO;
+}
+
+- (NSString *)propertyKeyForChildTag:(NSString *)_tag {
+  return [self->tagToKey objectForKey:_tag];
+}
+
+- (NSArray *)attributeKeys {
+  return [self->attrToKey allKeys];
+}
+- (NSString *)propertyKeyForAttribute:(NSString *)_attr {
+  return [self->attrToKey objectForKey:_attr];
+}
+
+/* object operations */
+
+- (void)addValue:(id)_value toPropertyWithKey:(NSString *)_key 
+  ofObject:(id)_object
+{
+  NSString *selname;
+  SEL      sel;
+  
+  selname = [[NSString alloc] initWithFormat:@"addTo%@:", 
+                             [_key capitalizedString]];
+  if ((sel = NSSelectorFromString(selname)) == NULL) {
+    if (doDebug) {
+      NSLog(@"got no selector for key '%@', selname '%@' !",
+           _key, selname);
+    }
+  }
+  [selname release]; selname = nil;
+  
+  if (doDebug) {
+    NSLog(@"%s: adding value %@ to %@ of %@", __PRETTY_FUNCTION__,
+         _value, _key, _object);
+    NSLog(@"  selector: %@", NSStringFromSelector(sel));
+  }
+  
+  if ((sel != NULL) && [_object respondsToSelector:sel]) {
+    [_object performSelector:sel withObject:_value];
+  }
+  else {
+    id v;
+    
+    v = [_object valueForKey:_key];
+    
+    if ([self isToManyKey:_key]) {
+      /* to-many relationship */
+
+      if (v == nil) {
+        [_object takeValue:[NSArray arrayWithObject:_value] forKey:_key];
+      }
+      else {
+        if ([v respondsToSelector:@selector(addObject:)])
+         /* the value is mutable */
+          [v addObject:_value];
+        else {
+         /* the value is immutable */
+          v = [v arrayByAddingObject:_value];
+          [_object takeValue:v forKey:_key];
+        }
+      }
+    }
+    else {
+      NSLog(@" APPLIED ON TO-ONE (%@) !", _key);
+      /* to-one relationship */
+      if (v != _value)
+        [_object takeValue:v forKey:_key];
+    }
+  }
+}
+
+@end /* SaxTagModel */
diff --git a/skyrix-xml/SaxObjC/SaxXMLFilter.h b/skyrix-xml/SaxObjC/SaxXMLFilter.h
new file mode 100644 (file)
index 0000000..7c63bbb
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxXMLFilter_H__
+#define __SaxXMLFilter_H__
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxXMLReader.h>
+
+/* new in SAX 2.0beta */
+
+@protocol SaxXMLFilter < SaxXMLReader >
+
+- (void)setParent:(id<NSObject,SaxXMLReader>)_parent;
+- (id<NSObject,SaxXMLReader>)parent;
+
+@end
+
+#include "SaxEntityResolver.h"
+#include "SaxDTDHandler.h"
+#include "SaxContentHandler.h"
+#include "SaxErrorHandler.h"
+
+@interface SaxXMLFilter : NSObject
+  < SaxXMLFilter,
+    SaxEntityResolver, SaxDTDHandler, SaxContentHandler, SaxErrorHandler >
+{
+@private
+  id<NSObject,SaxXMLReader>      parent;
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxDTDHandler>     dtdHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+  id<NSObject,SaxEntityResolver> entityResolver;
+}
+
+- (id)initWithParent:(id<NSObject,SaxXMLReader>)_parent;
+
+@end
+
+#endif /* __SaxXMLFilter_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxXMLFilter.m b/skyrix-xml/SaxObjC/SaxXMLFilter.m
new file mode 100644 (file)
index 0000000..d42b392
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "SaxXMLFilter.h"
+#include "common.h"
+
+@implementation SaxXMLFilter
+
+- (id)initWithParent:(id<NSObject,SaxXMLReader>)_parent {
+  if ((self = [self init])) {
+    [self setParent:_parent];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->parent release];
+  [super dealloc];
+}
+
+- (void)setParent:(id<NSObject,SaxXMLReader>)_parent {
+  if (self->parent == _parent)
+    return;
+  
+  [self->parent setContentHandler:nil];
+  [self->parent setDTDHandler:nil];
+  [self->parent setErrorHandler:nil];
+  [self->parent setEntityResolver:nil];
+
+  ASSIGN(self->parent, _parent);
+  
+  [self->parent setContentHandler:self];
+  [self->parent setDTDHandler:self];
+  [self->parent setErrorHandler:self];
+  [self->parent setEntityResolver:self];
+}
+
+- (id<NSObject,SaxXMLReader>)parent {
+  return self->parent;
+}
+
+/* features & properties */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value {
+  [self->parent setFeature:_name to:_value];
+}
+- (BOOL)feature:(NSString *)_name {
+  return [self->parent feature:_name];
+}
+
+- (void)setProperty:(NSString *)_name to:(id)_value {
+  [self->parent setProperty:_name to:_value];
+}
+- (id)property:(NSString *)_name {
+  return [self->parent property:_name];
+}
+
+/* handlers */
+
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
+  ASSIGN(self->dtdHandler, _handler);
+}
+- (id<NSObject,SaxDTDHandler>)dtdHandler {
+  return self->dtdHandler;
+}
+
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  ASSIGN(self->errorHandler, _handler);
+}
+- (id<NSObject,SaxErrorHandler>)errorHandler {
+  return self->errorHandler;
+}
+
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
+  ASSIGN(self->entityResolver, _handler);
+}
+- (id<NSObject,SaxEntityResolver>)entityResolver {
+  return self->entityResolver;
+}
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  ASSIGN(self->contentHandler, _handler);
+}
+- (id<NSObject,SaxContentHandler>)contentHandler {
+  return self->contentHandler;
+}
+
+/* parsing */
+
+- (void)parseFromSource:(id)_source {
+  [self->parent parseFromSource:_source];
+}
+- (void)parseFromSystemId:(NSString *)_sysId {
+  [self->parent parseFromSystemId:_sysId];
+}
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
+  [self->parent parseFromSource:_source systemId:_sysId];
+}
+
+/* SaxEntityResolver */
+
+- (id)resolveEntityWithPublicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+{
+  return [self->entityResolver resolveEntityWithPublicId:_pubId systemId:_sysId];
+}
+
+/* SaxContentHandler */
+
+- (void)startDocument {
+  [self->contentHandler startDocument];
+}
+- (void)endDocument {
+  [self->contentHandler endDocument];
+}
+
+- (void)startPrefixMapping:(NSString *)_prefix uri:(NSString *)_uri {
+  [self->contentHandler startPrefixMapping:_prefix uri:_uri];
+}
+- (void)endPrefixMapping:(NSString *)_prefix {
+  [self->contentHandler endPrefixMapping:_prefix];
+}
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attributes
+{
+  [self->contentHandler startElement:_localName namespace:_ns
+                        rawName:_rawName attributes:_attributes];
+}
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  [self->contentHandler endElement:_localName namespace:_ns rawName:_rawName];
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  [self->contentHandler characters:_chars length:_len];
+}
+- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
+  [self->contentHandler ignorableWhitespace:_chars length:_len];
+}
+- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data {
+  [self->contentHandler processingInstruction:_pi data:_data];
+}
+- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator {
+  [self->contentHandler setDocumentLocator:_locator];
+}
+- (void)skippedEntity:(NSString *)_entityName {
+  [self->contentHandler skippedEntity:_entityName];
+}
+
+/* error-handler */
+
+- (void)warning:(SaxParseException *)_exception {
+  [self->errorHandler warning:_exception];
+}
+- (void)error:(SaxParseException *)_exception {
+  [self->errorHandler error:_exception];
+}
+- (void)fatalError:(SaxParseException *)_exception {
+  [self->errorHandler fatalError:_exception];
+}
+
+/* dtd-handler */
+
+- (void)notationDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+{
+  [self->dtdHandler notationDeclaration:_name publicId:_pubId systemId:_sysId];
+}
+
+- (void)unparsedEntityDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+  notationName:(NSString *)_notName
+{
+  [self->dtdHandler unparsedEntityDeclaration:_name
+                    publicId:_pubId systemId:_sysId
+                    notationName:_notName];
+}
+
+@end /* SaxXMLFilter */
diff --git a/skyrix-xml/SaxObjC/SaxXMLReader.h b/skyrix-xml/SaxObjC/SaxXMLReader.h
new file mode 100644 (file)
index 0000000..57cae7a
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __SaxXMLReader_H__
+#define __SaxXMLReader_H__
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxContentHandler.h>
+#include <SaxObjC/SaxDTDHandler.h>
+#include <SaxObjC/SaxErrorHandler.h>
+#include <SaxObjC/SaxEntityResolver.h>
+
+/*
+  new in SAX 2.0beta, replaces SaxParser
+
+  Interface for reading an XML document using callbacks. 
+
+  This is a common interface that can be shared by many XML parsers. This
+  interface allows an application to set and query features and properties
+  in the parser, to register event handlers for document processing, and to
+  initiate a document parse.
+
+  This interface replaces the (now deprecated) SAX 1.0 Parser interface; it
+  currently extends Parser to aid in the transition to SAX2, but it will
+  likely not do so in any future versions of SAX.
+
+  The Reader interface contains two important enhancements over the old
+  Parser interface:
+
+    1. it adds a standard way to query and set features and properties; and 
+    2. it adds Namespace support, which is required for many higher-level XML
+       standards. 
+
+  There are adapters available to convert a SAX1 Parser to a SAX2 XMLReader
+  and vice-versa.
+*/
+
+@protocol SaxXMLReader
+
+/* features & properties */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value;
+- (BOOL)feature:(NSString *)_name;
+- (void)setProperty:(NSString *)_name to:(id)_value;
+- (id)property:(NSString *)_name;
+
+/* handlers */
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler;
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler;
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler;
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler;
+- (id<NSObject,SaxContentHandler>)contentHandler;
+- (id<NSObject,SaxDTDHandler>)dtdHandler;
+- (id<NSObject,SaxErrorHandler>)errorHandler;
+- (id<NSObject,SaxEntityResolver>)entityResolver;
+
+/* parsing */
+
+- (void)parseFromSource:(id)_source;
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId;
+- (void)parseFromSystemId:(NSString *)_sysId;
+
+@end
+
+#endif /* __SaxXMLReader_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxXMLReaderFactory.h b/skyrix-xml/SaxObjC/SaxXMLReaderFactory.h
new file mode 100644 (file)
index 0000000..beda338
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __SaxXMLReaderFactory_H__
+#define __SaxXMLReaderFactory_H__
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxXMLReader.h>
+
+/*
+  To get a reader for HTML files:
+    reader = [factory createXMLReaderForMimeType:@"text/html"];
+
+  for XML files:
+    reader = [factory createXMLReaderForMimeType:@"text/xml"];
+    
+  a specific reader:
+    reader = [factory createXMLReaderWithName:@"libxmlSAXDriver"];
+*/
+
+@class NSDictionary;
+    
+@interface SaxXMLReaderFactory : NSObject
+{
+  NSDictionary *nameToBundle;
+  NSDictionary *mimeTypeToName;
+}
+
++ (id)standardXMLReaderFactory;
+
+- (id<NSObject,SaxXMLReader>)createXMLReader;
+- (id<NSObject,SaxXMLReader>)createXMLReaderWithName:(NSString *)_name;
+- (id<NSObject,SaxXMLReader>)createXMLReaderForMimeType:(NSString *)_mtype;
+
+- (NSArray *)availableXMLReaders;
+
+@end
+
+#endif /* __SaxXMLReaderFactory_H__ */
diff --git a/skyrix-xml/SaxObjC/SaxXMLReaderFactory.m b/skyrix-xml/SaxObjC/SaxXMLReaderFactory.m
new file mode 100644 (file)
index 0000000..90dd7b6
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "SaxXMLReaderFactory.h"
+#include "common.h"
+
+#if GNUSTEP_BASE_LIBRARY
+@implementation NSBundle(Copying)
+- (id)copyWithZone:(NSZone *)_zone {
+  return [self retain];
+}
+@end
+#endif
+
+@implementation SaxXMLReaderFactory
+
+static BOOL    coreOnMissingParser = NO;
+static BOOL    debugOn       = NO;
+static NSArray *searchPathes = nil;
+static NSNull  *null         = nil;
+static id      factory       = nil;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  coreOnMissingParser = [ud boolForKey:@"SaxCoreOnMissingParser"];
+  debugOn             = [ud boolForKey:@"SaxDebugReaderFactory"];
+}
+
++ (id)standardXMLReaderFactory {
+  if (factory == nil)
+    factory = [[self alloc] init];
+  return factory;
+}
+
+- (void)dealloc {
+  [self->nameToBundle   release];
+  [self->mimeTypeToName release];
+  [super dealloc];
+}
+
+/* operations */
+
+- (void)flush {
+  [self->nameToBundle   release]; self->nameToBundle   = nil;
+  [self->mimeTypeToName release]; self->mimeTypeToName = nil;
+}
+
+- (NSArray *)saxReaderSearchPathes {
+  NSMutableArray *ma;
+  id tmp;
+#if !COCOA_Foundation_LIBRARY
+  NSDictionary   *env;
+#endif
+
+  if (searchPathes)
+    return searchPathes;
+    
+  ma  = [NSMutableArray arrayWithCapacity:8];
+
+#if COCOA_Foundation_LIBRARY
+  tmp = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory,
+                                              NSAllDomainsMask,
+                                              YES);
+  if ([tmp count] > 0) {
+      NSEnumerator *e;
+      
+      e = [tmp objectEnumerator];
+      while ((tmp = [e nextObject])) {
+        tmp = [tmp stringByAppendingPathComponent:@"SaxDrivers"];
+        if (![ma containsObject:tmp])
+          [ma addObject:tmp];
+      }
+  }
+#if COMPILE_AS_FRAMEWORK
+  {
+      NSBundle *fwBundle;
+      
+      fwBundle = [NSBundle bundleForClass:[self class]];
+      [ma addObject:[[fwBundle resourcePath]
+                               stringByAppendingPathComponent:@"SaxDrivers"]];
+  }
+#endif
+#else
+  env = [[NSProcessInfo processInfo] environment];
+
+  if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil)
+    tmp = [env objectForKey:@"GNUSTEP_PATHLIST"];
+  tmp = [tmp componentsSeparatedByString:@":"];
+  if ([tmp count] > 0) {
+      NSEnumerator *e;
+      
+      e = [tmp objectEnumerator];
+      while ((tmp = [e nextObject])) {
+        tmp = [tmp stringByAppendingPathComponent:@"Library/SaxDrivers"];
+        if (![ma containsObject:tmp])
+          [ma addObject:tmp];
+      }
+  }
+  else {
+    NSLog(@"%s: empty library search path !", __PRETTY_FUNCTION__);
+  }
+#endif
+    
+  searchPathes = [ma copy];
+    
+  if ([searchPathes count] == 0)
+    NSLog(@"%s: no search pathes were found !", __PRETTY_FUNCTION__);
+  
+  return searchPathes;
+}
+
+- (void)_loadBundlePath:(NSString *)_bundlePath
+  infoDictionary:(NSDictionary *)_info
+  nameMap:(NSMutableDictionary *)_nameMap
+  typeMap:(NSMutableDictionary *)_typeMap
+{
+  NSArray      *drivers;
+  NSEnumerator *e;
+  NSDictionary *driverInfo;
+  NSBundle     *bundle;
+
+  _info = [_info objectForKey:@"provides"];
+  if ((drivers = [_info objectForKey:@"SAXDrivers"]) == nil) {
+    NSLog(@"%s: .sax bundle '%@' does not provide any SAX drivers ...",
+          __PRETTY_FUNCTION__, _bundlePath);
+    return;
+  }
+  
+  if ((bundle = [NSBundle bundleWithPath:_bundlePath]) == nil) {
+    NSLog(@"%s: could not create bundle from path '%@'",
+          __PRETTY_FUNCTION__, _bundlePath);
+    return;
+  }
+  
+  /* found a driver with valid info dict, process it ... */
+  
+  e = [drivers objectEnumerator];
+  while ((driverInfo = [e nextObject])) {
+    NSString     *name, *tname;
+    NSEnumerator *te;
+    
+    name = [driverInfo objectForKey:@"name"];
+    if ([name length] == 0) {
+      NSLog(@"%s: missing name in sax driver section of bundle %@ ...",
+            __PRETTY_FUNCTION__, _bundlePath);
+      continue;
+    }
+
+    /* check if name is already registered */
+    if ([_nameMap objectForKey:name]) {
+      if (debugOn)
+        NSLog(@"%s: already have sax driver named '%@' ...",
+              __PRETTY_FUNCTION__, name);
+      continue;
+    }
+
+    /* register bundle for name */
+    [_nameMap setObject:bundle forKey:name];
+
+    /* register MIME-types */
+    te = [[driverInfo objectForKey:@"sourceTypes"] objectEnumerator];
+    while ((tname = [te nextObject])) {
+      NSString *tmp;
+      
+      if ((tmp = [_typeMap objectForKey:tname])) {
+        NSLog(@"WARNING(%s): multiple parsers available for MIME type '%@', "
+              @"using '%@' as default for type %@.", 
+              __PRETTY_FUNCTION__, tname, tmp, tname);
+        continue;
+      }
+      
+      [_typeMap setObject:name forKey:tname];
+    }
+  }
+}
+
+- (void)_loadLibraryPath:(NSString *)_libraryPath
+  nameMap:(NSMutableDictionary *)_nameMap
+  typeMap:(NSMutableDictionary *)_typeMap
+{
+  NSFileManager *fm = [NSFileManager defaultManager];
+  NSEnumerator  *e;
+  NSString      *p;
+  
+  e = [[fm directoryContentsAtPath:_libraryPath] objectEnumerator];
+  while ((p = [e nextObject])) {
+    NSDictionary *info;
+    NSString     *infoPath;
+    BOOL         isDir;
+    
+    if (![p hasSuffix:@".sax"]) continue;
+    
+    p = [_libraryPath stringByAppendingPathComponent:p];
+    if (![fm fileExistsAtPath:p isDirectory:&isDir])
+      continue;
+    if (!isDir) { /* info file is a directory ??? */
+      NSLog(@"%s: .sax is not a dir: '%@' ???", __PRETTY_FUNCTION__, p);
+      continue;
+    }
+    
+#if COCOA_Foundation_LIBRARY
+    {
+      NSBundle *b;
+      
+      b = [NSBundle bundleWithPath:p];
+      infoPath = [b pathForResource:@"bundle-info" ofType:@"plist"];
+    }
+#else
+    infoPath = [p stringByAppendingPathComponent:@"bundle-info.plist"];
+#endif
+    
+    info = [NSDictionary dictionaryWithContentsOfFile:infoPath];
+    if (info == nil) {
+      NSLog(@"%s: could not parse bundle-info dictionary: '%@'",
+            __PRETTY_FUNCTION__, infoPath);
+      continue;
+    }
+    
+    [self _loadBundlePath:p infoDictionary:info
+          nameMap:_nameMap typeMap:_typeMap];
+  }
+}
+
+- (void)_loadAvailableBundles {
+  NSAutoreleasePool *pool;
+  
+  /* setup globals */
+  if (null == nil)
+    null = [[NSNull null] retain];
+
+#if DEBUG
+  NSAssert(self->nameToBundle   == nil, @"already set up !");
+  NSAssert(self->mimeTypeToName == nil, @"partially set up !");
+#else
+  if (self->nameToBundle) return;
+#endif
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  {
+    /* lookup bundle in Libary/SaxDrivers pathes */
+    NSEnumerator        *pathes;
+    NSString            *path;
+    NSMutableDictionary *nameMap, *typeMap;
+
+    nameMap = [NSMutableDictionary dictionaryWithCapacity:16];
+    typeMap = [NSMutableDictionary dictionaryWithCapacity:16];
+    
+    pathes = [[self saxReaderSearchPathes] objectEnumerator];
+    while ((path = [pathes nextObject]))
+      [self _loadLibraryPath:path nameMap:nameMap typeMap:typeMap];
+    
+    self->nameToBundle   = [nameMap copy];
+    self->mimeTypeToName = [typeMap copy];
+
+#if DEBUG
+    if ([self->nameToBundle count] == 0) {
+      NSLog(@"%s: no XML parser could be found ...", __PRETTY_FUNCTION__);
+    }
+    else if ([self->mimeTypeToName count] == 0) {
+      NSLog(@"%s: no XML parser declared a MIME type ...",__PRETTY_FUNCTION__);
+    }
+#endif
+  }
+  [pool release];
+}
+
+- (id<NSObject,SaxXMLReader>)createXMLReader {
+  NSString *defReader;
+  id       reader;
+
+  if (debugOn) NSLog(@"%s: lookup default XML reader ...",__PRETTY_FUNCTION__);
+  
+  defReader = 
+    [[NSUserDefaults standardUserDefaults] stringForKey:@"XMLReader"];
+
+  if (debugOn) NSLog(@"%s:   default name ...",__PRETTY_FUNCTION__, defReader);
+  
+  if (defReader) {
+    if ((reader = [self createXMLReaderWithName:defReader]))
+      return reader;
+
+    NSLog(@"%s: could not create default XMLReader '%@' !",
+          __PRETTY_FUNCTION__, defReader);
+  }
+  
+  return [self createXMLReaderForMimeType:@"text/xml"];
+}
+
+- (id<NSObject,SaxXMLReader>)createXMLReaderWithName:(NSString *)_name {
+  NSBundle *bundle;
+  Class    readerClass;
+  
+  if (debugOn)
+    NSLog(@"%s: lookup XML reader with name: '%@'",__PRETTY_FUNCTION__,_name);
+  
+  if ([_name length] == 0)
+    return [self createXMLReader];
+  
+  if (self->nameToBundle == nil)
+    [self _loadAvailableBundles];
+  
+  if ((bundle = [self->nameToBundle objectForKey:_name]) == nil)
+    return nil;
+  
+  /* load bundle executable code */
+  if (![bundle load]) {
+    NSLog(@"%s: could not load SaxDriver bundle %@ !", __PRETTY_FUNCTION__,
+          bundle);
+    return nil;
+  }
+  
+  NSAssert(bundle, @"should have a loaded bundle at this stage ...");
+  
+  /* lookup class */
+  if ((readerClass = NSClassFromString(_name)) == Nil) {
+    NSLog(@"WARNING(%s): could not find SAX reader class %@ (SAX bundle=%@)",
+          __PRETTY_FUNCTION__, _name, bundle);
+    return nil;
+  }
+  
+  /* create instance */
+  return [[[readerClass alloc] init] autorelease];
+}
+
+- (id<NSObject,SaxXMLReader>)createXMLReaderForMimeType:(NSString *)_mtype {
+  id<NSObject,SaxXMLReader> reader;
+  NSString *name;
+
+  if (self->mimeTypeToName == nil)
+    [self _loadAvailableBundles];
+  
+  if (debugOn)
+    NSLog(@"%s: lookup XML reader for type: '%@'",__PRETTY_FUNCTION__, _mtype);
+  
+  if ([_mtype respondsToSelector:@selector(stringValue)])
+    _mtype = [(id)_mtype stringValue];
+  if ([_mtype length] == 0)
+    _mtype = @"text/xml";
+  
+  if ((name = [self->mimeTypeToName objectForKey:_mtype]) == nil) {
+    if (debugOn) {
+      NSLog(@"%s: did not find SAX parser for MIME type %@ map: \n%@",
+           __PRETTY_FUNCTION__, _mtype, self->mimeTypeToName);
+      NSLog(@"%s: parsers: %@", __PRETTY_FUNCTION__, 
+           [self->nameToBundle allKeys]);
+    }
+    if (coreOnMissingParser) {
+      NSLog(@"%s: aborting, because 'SaxCoreOnMissingParser' "
+           @"default is enabled!", __PRETTY_FUNCTION__);
+      abort();
+    }
+    return nil;
+  }
+  if (debugOn) 
+    NSLog(@"%s:  found XML reader named: '%@'", __PRETTY_FUNCTION__, name);
+  
+  reader = [self createXMLReaderWithName:name];
+
+  if (debugOn)
+    NSLog(@"%s:  created XML reader: %@", __PRETTY_FUNCTION__, reader);
+  return reader;
+}
+
+- (NSArray *)availableXMLReaders {
+  return [self->nameToBundle allKeys];
+}
+
+@end /* SaxXMLReaderFactory */
diff --git a/skyrix-xml/SaxObjC/SxXML-SaxObjC.graffle b/skyrix-xml/SaxObjC/SxXML-SaxObjC.graffle
new file mode 100644 (file)
index 0000000..d838075
--- /dev/null
@@ -0,0 +1,2050 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+       <key>CanvasColor</key>
+       <dict>
+               <key>w</key>
+               <real>1.000000e+00</real>
+       </dict>
+       <key>ColumnAlign</key>
+       <integer>0</integer>
+       <key>ColumnSpacing</key>
+       <real>5.400000e+01</real>
+       <key>GraphDocumentVersion</key>
+       <integer>2</integer>
+       <key>GraphicsList</key>
+       <array>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{12, 477}, {98, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>1101</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 libxmlSAXDriver}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{9, 10}, {112, 36}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>1100</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\b\fs48 \cf0 SaxObjC}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{9, 459}, {702, 1}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1099</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{27, 81}, {131, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1073</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxDocumentHandler.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 SaxDocumentHandler}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{202, 81}, {104, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1074</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxHandlerBase.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxHandlerBase}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>Group</string>
+                                       <key>Graphics</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{189, 306}, {135, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1076</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxMethodCallHandler.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>Rectangle</string>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxMethodCallHandler}</string>
+                                                       </dict>
+                                               </dict>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{202, 270}, {113, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1077</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxDefaultHandler.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>Rectangle</string>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxDefaultHandler}</string>
+                                                       </dict>
+                                               </dict>
+                                       </array>
+                                       <key>ID</key>
+                                       <integer>1075</integer>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>Group</string>
+                                       <key>Graphics</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{315, 180}, {90, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1079</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxXMLFilter.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>Rectangle</string>
+                                                       <key>Style</key>
+                                                       <dict>
+                                                               <key>stroke</key>
+                                                               <dict>
+                                                                       <key>Color</key>
+                                                                       <dict>
+                                                                               <key>b</key>
+                                                                               <real>0.000000e+00</real>
+                                                                               <key>g</key>
+                                                                               <real>0.000000e+00</real>
+                                                                               <key>r</key>
+                                                                               <real>1.000000e+00</real>
+                                                                       </dict>
+                                                               </dict>
+                                                       </dict>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 SaxXMLFilter}</string>
+                                                       </dict>
+                                               </dict>
+                                               <dict>
+                                                       <key>Bounds</key>
+                                                       <string>{{207, 180}, {90, 18}}</string>
+                                                       <key>Class</key>
+                                                       <string>ShapedGraphic</string>
+                                                       <key>ID</key>
+                                                       <integer>1080</integer>
+                                                       <key>Link</key>
+                                                       <dict>
+                                                               <key>url</key>
+                                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxXMLFilter.h</string>
+                                                       </dict>
+                                                       <key>Shape</key>
+                                                       <string>Rectangle</string>
+                                                       <key>Text</key>
+                                                       <dict>
+                                                               <key>Text</key>
+                                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxXMLFilter}</string>
+                                                       </dict>
+                                               </dict>
+                                       </array>
+                                       <key>ID</key>
+                                       <integer>1078</integer>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{27, 180}, {131, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1081</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxEntityResolver.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 SaxEntityResolver}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{27, 135}, {131, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1082</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxDTDHandler.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 SaxDTDHandler}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{27, 270}, {131, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1083</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxContentHandler.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 SaxContentHandler}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{27, 225}, {131, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1084</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxErrorHandler.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 SaxErrorHandler}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1074</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1085</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{107.182, 180}</string>
+                                               <string>{239.318, 99}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1081</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1074</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1086</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{119.417, 135}</string>
+                                               <string>{227.083, 99}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1082</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1074</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1087</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{158, 90}</string>
+                                               <string>{202, 90}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1073</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1074</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1088</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{102.594, 225}</string>
+                                               <string>{243.906, 99}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1084</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1076</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1089</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{258, 288}</string>
+                                               <string>{257, 306}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1077</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1077</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1090</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{109.1, 198}</string>
+                                               <string>{241.9, 270}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1081</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1077</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1091</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{103.567, 153}</string>
+                                               <string>{247.433, 270}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1082</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1077</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1092</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{158, 279}</string>
+                                               <string>{202, 279}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1083</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1077</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1093</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{125.7, 243}</string>
+                                               <string>{225.3, 270}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1084</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1080</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1094</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{315, 189}</string>
+                                               <string>{297, 189}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1079</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1080</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1095</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{158, 189}</string>
+                                               <string>{207, 189}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1081</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1080</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1096</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{124.4, 153}</string>
+                                               <string>{220.1, 180}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1082</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1080</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1097</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{108.45, 270}</string>
+                                               <string>{236.05, 198}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1083</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1080</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1098</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{124.4, 225}</string>
+                                               <string>{220.1, 198}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1084</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1072</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{333, 504}, {130, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1071</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/libxmlSAXDriver/libxmlSAXDriver.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 libxmlSAXDriver}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{603, 81}, {90, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1068</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxAttributes.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 SaxAttributes}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{495, 81}, {90, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1069</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxAttributes.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxAttributes}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1069</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1070</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{603, 90}</string>
+                                               <string>{585, 90}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1068</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1067</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{495, 504}, {108, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1066</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/libxmlSAXDriver/libxmlSAXLocator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 libxmlSAXLocator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{193, 504}, {131, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1065</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/libxmlSAXDriver/libxmlDocSAXDriver.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 libxmlDocSAXDriver}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{490, 207}, {86, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1058</integer>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>fill</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>5.000000e-01</real>
+                                                               <key>g</key>
+                                                               <real>1.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{508, 333}, {167, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1059</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxException.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxNotSupportedException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{508, 279}, {167, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1060</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxException.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxParseException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{486, 243}, {91, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1061</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxException.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{418, 306}, {167, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1062</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxException.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxNotRecognizedException}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1059</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1063</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{537.5, 261}</string>
+                                               <string>{585.5, 333}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1061</integer>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1060</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1064</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{546.5, 261}</string>
+                                               <string>{576.5, 279}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>FilledArrow</string>
+                                                       <key>TailArrow</key>
+                                                       <string>0</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1061</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1057</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{207, 423}, {99, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1056</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxXMLReader.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 SaxXMLReader}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{54, 504}, {130, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1055</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/libxmlSAXDriver/libxmlHTMLSAXDriver.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 libxmlHTMLSAXDriver}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{527, 153}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1054</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxXMLReaderFactory.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxXMLReaderFactory}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>Group</string>
+                       <key>Graphics</key>
+                       <array>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{265, 360}, {95, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1051</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxAttributeList.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                               </dict>
+                                       </dict>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 SaxAttributeList}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Bounds</key>
+                                       <string>{{144, 360}, {103, 18}}</string>
+                                       <key>Class</key>
+                                       <string>ShapedGraphic</string>
+                                       <key>ID</key>
+                                       <integer>1052</integer>
+                                       <key>Link</key>
+                                       <dict>
+                                               <key>url</key>
+                                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxAttributeList.h</string>
+                                       </dict>
+                                       <key>Shape</key>
+                                       <string>Rectangle</string>
+                                       <key>Text</key>
+                                       <dict>
+                                               <key>Text</key>
+                                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxAttributeList}</string>
+                                       </dict>
+                               </dict>
+                               <dict>
+                                       <key>Class</key>
+                                       <string>LineGraphic</string>
+                                       <key>Head</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1052</integer>
+                                       </dict>
+                                       <key>ID</key>
+                                       <integer>1053</integer>
+                                       <key>Points</key>
+                                       <array>
+                                               <string>{265, 369}</string>
+                                               <string>{247, 369}</string>
+                                       </array>
+                                       <key>Style</key>
+                                       <dict>
+                                               <key>stroke</key>
+                                               <dict>
+                                                       <key>Color</key>
+                                                       <dict>
+                                                               <key>b</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>g</key>
+                                                               <real>0.000000e+00</real>
+                                                               <key>r</key>
+                                                               <real>1.000000e+00</real>
+                                                       </dict>
+                                                       <key>HeadArrow</key>
+                                                       <string>0</string>
+                                                       <key>TailArrow</key>
+                                                       <string>FilledBall</string>
+                                               </dict>
+                                       </dict>
+                                       <key>Tail</key>
+                                       <dict>
+                                               <key>ID</key>
+                                               <integer>1051</integer>
+                                       </dict>
+                               </dict>
+                       </array>
+                       <key>ID</key>
+                       <integer>1050</integer>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{527, 126}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1049</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxNamespaceSupport.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxNamespaceSupport}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{495, 423}, {108, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1048</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxLocator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Oblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\fs24 \cf0 SaxLocator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{396, 423}, {81, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1047</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxLocator.h</string>
+                       </dict>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxLocator}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1071</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1046</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{272.222, 441}</string>
+                               <string>{382.278, 504}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1056</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1066</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1045</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{549, 441}</string>
+                               <string>{549, 504}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1048</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1065</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1044</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{256.722, 441}</string>
+                               <string>{258.278, 504}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1056</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1061</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1043</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{532.625, 225}</string>
+                               <string>{531.875, 243}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1058</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1055</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1042</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{241.222, 441}</string>
+                               <string>{134.278, 504}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1056</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1062</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1041</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{527.214, 261}</string>
+                               <string>{505.786, 306}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>FilledArrow</string>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1061</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1047</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1040</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{495, 432}</string>
+                               <string>{477, 432}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>0.000000e+00</real>
+                                               <key>g</key>
+                                               <real>0.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>TailArrow</key>
+                                       <string>FilledBall</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1048</integer>
+                       </dict>
+               </dict>
+       </array>
+       <key>GridInfo</key>
+       <dict/>
+       <key>HPages</key>
+       <integer>1</integer>
+       <key>ImageCounter</key>
+       <integer>1</integer>
+       <key>IsPalette</key>
+       <string>NO</string>
+       <key>Layers</key>
+       <array>
+               <dict>
+                       <key>Lock</key>
+                       <string>NO</string>
+                       <key>Name</key>
+                       <string>Layer 1</string>
+                       <key>Print</key>
+                       <string>YES</string>
+                       <key>View</key>
+                       <string>YES</string>
+               </dict>
+       </array>
+       <key>LayoutInfo</key>
+       <dict>
+               <key>AutoAdjust</key>
+               <string>YES</string>
+               <key>HierarchicalOrientation</key>
+               <integer>0</integer>
+               <key>MagneticFieldCenter</key>
+               <string>{0, 0}</string>
+       </dict>
+       <key>MagnetsEnabled</key>
+       <string>YES</string>
+       <key>PageBreakColor</key>
+       <dict>
+               <key>w</key>
+               <real>3.333333e-01</real>
+       </dict>
+       <key>PageBreaks</key>
+       <string>YES</string>
+       <key>PageSetup</key>
+       <data>
+       BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE
+       hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpEpKEhIQITlNT
+       dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE
+       mZkOTlNCb3R0b21NYXJnaW6GkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVlAJSEASqEhAFm
+       nSSGkoSZmQtOU1BhcGVyTmFtZYaShJmZBkxldHRlcoaShJmZD05TUHJpbnRBbGxQYWdl
+       c4aShJ2chIQBc54AhpKEmZkNTlNSaWdodE1hcmdpboaShJ2cn50khpKEmZkITlNDb3Bp
+       ZXOGkoSdnISEAVOfAYaShJmZD05TU2NhbGluZ0ZhY3RvcoaShJ2chIQBZKABhpKEmZkL
+       TlNGaXJzdFBhZ2WGkoSdnKmfAYaShJmZFE5TVmVydGljYWxQYWdpbmF0aW9uhpKEnZyk
+       ngCGkoSZmRVOU0hvcml6b25hbFBhZ2luYXRpb26GkoSdnKSeAIaShJmZFk5TSG9yaXpv
+       bnRhbGx5Q2VudGVyZWSGkoSdnKSeAYaShJmZDE5TTGVmdE1hcmdpboaShJ2cn50khpKE
+       mZkNTlNPcmllbnRhdGlvboaShJ2cpJ4BhpKEmZkZTlNQcmludFJldmVyc2VPcmllbnRh
+       dGlvboaSo5KEmZkKTlNMYXN0UGFnZYaShJ2chJeXgn////+GkoSZmQtOU1RvcE1hcmdp
+       boaShJ2cn50khpKEmZkUTlNWZXJ0aWNhbGx5Q2VudGVyZWSGkrSShJmZC05TUGFwZXJT
+       aXplhpKEnpyEhAx7X05TU2l6ZT1mZn2hgQMYgQJkhoaG
+       </data>
+       <key>RowAlign</key>
+       <integer>0</integer>
+       <key>RowSpacing</key>
+       <real>9.000000e+00</real>
+       <key>VPages</key>
+       <integer>1</integer>
+       <key>WindowInfo</key>
+       <dict>
+               <key>Frame</key>
+               <string>{{109, 134}, {783, 743}}</string>
+               <key>VisibleRegion</key>
+               <string>{{-24, -63}, {768, 666}}</string>
+               <key>Zoom</key>
+               <string>1</string>
+       </dict>
+</dict>
+</plist>
diff --git a/skyrix-xml/SaxObjC/TODO b/skyrix-xml/SaxObjC/TODO
new file mode 100644 (file)
index 0000000..9d302ff
--- /dev/null
@@ -0,0 +1,7 @@
+# $Id: TODO,v 1.1 2003/10/29 12:55:34 helge Exp $
+
+TODOs for SaxObjC
+=================
+
+- find out whether SaxObjC is deprecated due to NSXMLParser
+  (probably not ;-)
diff --git a/skyrix-xml/SaxObjC/Version b/skyrix-xml/SaxObjC/Version
new file mode 100644 (file)
index 0000000..62c8c2f
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=37
diff --git a/skyrix-xml/SaxObjC/XMLNamespaces.h b/skyrix-xml/SaxObjC/XMLNamespaces.h
new file mode 100644 (file)
index 0000000..e556bb7
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __SaxObjC_XML_Namespaces_H__
+#define __SaxObjC_XML_Namespaces_H__
+
+#ifndef XMLNS_OD_BIND
+#  define XMLNS_OD_BIND             @"http://www.skyrix.com/od/binding"
+#endif
+#ifndef XMLNS_OD_CONST
+#  define XMLNS_OD_CONST            @"http://www.skyrix.com/od/constant"
+#endif
+#ifndef XMLNS_OD_ACTION
+#  define XMLNS_OD_ACTION           @"http://www.skyrix.com/od/action"
+#endif
+#ifndef XMLNS_OD_EVALJS
+#  define XMLNS_OD_EVALJS           @"http://www.skyrix.com/od/javascript"
+#endif
+#ifndef XMLNS_XHTML
+#  define XMLNS_XHTML               @"http://www.w3.org/1999/xhtml"
+#endif
+#ifndef XMLNS_HTML40
+#  define XMLNS_HTML40              @"http://www.w3.org/TR/REC-html40"
+#endif
+
+#ifndef XMLNS_XLINK
+#  define XMLNS_XLINK               @"http://www.w3.org/1999/xlink"
+#endif
+
+#ifndef XMLNS_XSLT
+#  define XMLNS_XSLT                @"http://www.w3.org/1999/XSL/Transform"
+#endif
+#ifndef XMLNS_XSL_FO
+#  define XMLNS_XSL_FO              @"http://www.w3.org/1999/XSL/Format"
+#endif
+
+#ifndef XMLNS_RDF
+#  define XMLNS_RDF \
+     @"http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+#endif
+
+#ifndef XMLNS_XUL
+#  define XMLNS_XUL \
+     @"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+#endif
+
+#ifndef XMLNS_XFORMS
+#  define XMLNS_XFORMS @"http://www.w3.org/2001/06/xforms"
+#endif
+
+#ifndef XMLNS_SVG
+#  define XMLNS_SVG    @"http://www.w3.org/2000/svg"
+#endif
+#ifndef XMLNS_MATHML
+#  define XMLNS_MATHML @"http://www.w3.org/1998/Math/MathML"
+#endif
+
+#ifndef XMLNS_WML12
+#  define XMLNS_WML12               @"http://www.wapforum.org/DTD/wml_1.2.xml"
+#endif
+
+#ifndef XMLNS_XUPDATE
+#  define XMLNS_XUPDATE             @"http://www.xmldb.org/xupdate"
+#endif
+
+#ifndef XMLNS_WEBDAV
+#  define XMLNS_WEBDAV @"DAV:"
+#endif
+
+#ifndef XMLNS_XCAL_01
+#  define XMLNS_XCAL_01 \
+     @"http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt"
+#endif
+
+#ifndef XMLNS_RELAXNG_STRUCTURE
+#  define XMLNS_RELAXNG_STRUCTURE @"http://relaxng.org/ns/structure/1.0"
+#endif
+
+#ifndef XMLNS_XINCLUDE
+#  define XMLNS_XINCLUDE @"http://www.w3.org/2001/XInclude"
+#endif
+
+#ifndef XMLNS_KUPU
+#  define XMLNS_KUPU @"http://kupu.oscom.org/namespaces/dist"
+#endif
+
+/* Microsoft related namespaces */
+
+#ifndef XMLNS_MS_OFFICE_WORDML
+#  define XMLNS_MS_OFFICE_WORDML \
+     @"http://schemas.microsoft.com/office/word/2003/wordml"
+#endif
+
+#ifndef XMLNS_MS_OFFICE_OFFICE
+#  define XMLNS_MS_OFFICE_OFFICE @"urn:schemas-microsoft-com:office:office"
+#endif
+
+#ifndef XMLNS_MS_OFFICE_WORD
+#  define XMLNS_MS_OFFICE_WORD @"urn:schemas-microsoft-com:office:word"
+#endif
+
+#ifndef XMLNS_MS_HOTMAIL
+#  define XMLNS_MS_HOTMAIL  @"http://schemas.microsoft.com/hotmail/"
+#endif
+
+#ifndef XMLNS_MS_HTTPMAIL
+#  define XMLNS_MS_HTTPMAIL @"urn:schemas:httpmail:"
+#endif
+
+#ifndef XMLNS_MS_EXCHANGE
+#  define XMLNS_MS_EXCHANGE @"http://schemas.microsoft.com/exchange/"
+#endif
+#ifndef XMLNS_MS_EX_CALENDAR
+#  define XMLNS_MS_EX_CALENDAR @"urn:schemas:calendar:"
+#endif
+#ifndef XMLNS_MS_EX_CONTACTS
+#  define XMLNS_MS_EX_CONTACTS @"urn:schemas:contacts:"
+#endif
+
+/* WebDAV related namespaces */
+
+#ifndef XMLNS_WEBDAV_APACHE
+#  define XMLNS_WEBDAV_APACHE @"http://apache.org/dav/props/"
+#endif
+#ifndef XMLNS_CADAVER_PROPS
+#  define XMLNS_CADAVER_PROPS @"http://webdav.org/cadaver/custom-properties/"
+#endif
+#ifndef XMLNS_NAUTILUS_PROPS
+#  define XMLNS_NAUTILUS_PROPS @"http://services.eazel.com/namespaces"
+#endif
+
+/* OpenOffice.org namespaces */
+
+#ifndef XMLNS_OOo_UCB_WEBDAV
+#  define XMLNS_OOo_UCB_WEBDAV   @"http://ucb.openoffice.org/dav/props/"
+#endif
+
+#ifndef XMLNS_OOo_MANIFEST
+#  define XMLNS_OOo_MANIFEST     @"http://openoffice.org/2001/manifest"
+#endif
+
+#ifndef XMLNS_OOo_OFFICE
+#  define XMLNS_OOo_OFFICE       @"http://openoffice.org/2000/office"
+#endif
+#ifndef XMLNS_OOo_TEXT
+#  define XMLNS_OOo_TEXT         @"http://openoffice.org/2000/text"
+#endif
+#ifndef XMLNS_OOo_META
+#  define XMLNS_OOo_META         @"http://openoffice.org/2000/meta"
+#endif
+#ifndef XMLNS_OOo_STYLE
+#  define XMLNS_OOo_STYLE        @"http://openoffice.org/2000/style"
+#endif
+#ifndef XMLNS_OOo_TABLE
+#  define XMLNS_OOo_TABLE        @"http://openoffice.org/2000/table"
+#endif
+#ifndef XMLNS_OOo_DRAWING
+#  define XMLNS_OOo_DRAWING      @"http://openoffice.org/2000/drawing"
+#endif
+#ifndef XMLNS_OOo_DATASTYLE
+#  define XMLNS_OOo_DATASTYLE    @"http://openoffice.org/2000/datastyle"
+#endif
+#ifndef XMLNS_OOo_PRESENTATION
+#  define XMLNS_OOo_PRESENTATION @"http://openoffice.org/2000/presentation"
+#endif
+#ifndef XMLNS_OOo_CHART
+#  define XMLNS_OOo_CHART        @"http://openoffice.org/2000/chart"
+#endif
+#ifndef XMLNS_OOo_DRAW3D
+#  define XMLNS_OOo_DRAW3D       @"http://openoffice.org/2000/dr3d"
+#endif
+#ifndef XMLNS_OOo_FORM
+#  define XMLNS_OOo_FORM         @"http://openoffice.org/2000/form"
+#endif
+#ifndef XMLNS_OOo_SCRIPT
+#  define XMLNS_OOo_SCRIPT       @"http://openoffice.org/2000/script"
+#endif
+
+#ifndef XMLNS_DublinCore
+#  define XMLNS_DublinCore @"http://purl.org/dc/elements/1.1/"
+#endif
+
+#ifndef XMLNS_PROPRIETARY_SLOX
+#  define XMLNS_PROPRIETARY_SLOX @"SLOX:"
+#endif
+
+/* Zope */
+
+#ifndef XMLNS_Zope_TAL
+#  define XMLNS_Zope_TAL @"http://xml.zope.org/namespaces/tal"
+#endif
+#ifndef XMLNS_Zope_METAL
+#  define XMLNS_Zope_METAL @"http://xml.zope.org/namespaces/metal"
+#endif
+
+/* SOAP */
+
+#ifndef XMLNS_SOAP_ENVELOPE
+#  define XMLNS_SOAP_ENVELOPE @"http://schemas.xmlsoap.org/soap/envelope/"
+#endif
+#ifndef XMLNS_SOAP_ENCODING
+#  define XMLNS_SOAP_ENCODING @"http://schemas.xmlsoap.org/soap/encoding/"
+#endif
+
+#ifndef XMLNS_XMLSchema
+#  define XMLNS_XMLSchema @"http://www.w3.org/1999/XMLSchema"
+#endif
+#ifndef XMLNS_XMLSchemaInstance1999
+#  define XMLNS_XMLSchemaInstance1999 \
+            @"http://www.w3.org/1999/XMLSchema-instance"
+#endif
+#ifndef XMLNS_XMLSchemaInstance2001
+#  define XMLNS_XMLSchemaInstance2001 \
+            @"http://www.w3.org/2001/XMLSchema-instance"
+#endif
+
+/* Novell */
+
+#ifndef XMLNS_Novell_NCSP_Types
+#  define XMLNS_Novell_NCSP_Types \
+            @"http://schemas.novell.com/2003/10/NCSP/types.xsd"
+#endif
+#ifndef XMLNS_Novell_NCSP_Methods
+#  define XMLNS_Novell_NCSP_Methods \
+            @"http://schemas.novell.com/2003/10/NCSP/methods.xsd"
+#endif
+
+#endif /* __SaxObjC_XML_Namespaces_H__ */
diff --git a/skyrix-xml/SaxObjC/common.h b/skyrix-xml/SaxObjC/common.h
new file mode 100644 (file)
index 0000000..0b200c6
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __common_H__
+#define __common_H__
+
+#import <Foundation/Foundation.h>
+
+#ifndef ASSIGN
+#  define ASSIGN(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) [__value retain]; \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+
+#endif /* __common_H__ */
diff --git a/skyrix-xml/SaxObjC/libSAXObjC.def b/skyrix-xml/SaxObjC/libSAXObjC.def
new file mode 100644 (file)
index 0000000..db9495c
--- /dev/null
@@ -0,0 +1,13 @@
+EXPORTS
+       __objc_class_name_SaxAttributeList;
+       __objc_class_name_SaxAttributes;
+       __objc_class_name_SaxDefaultHandler;
+       __objc_class_name_SaxException;
+       __objc_class_name_SaxHandlerBase;
+       __objc_class_name_SaxLocator;
+       __objc_class_name_SaxNamespaceSupport;
+       __objc_class_name_SaxNotRecognizedException;
+       __objc_class_name_SaxNotSupportedException;
+       __objc_class_name_SaxParseException;
+       __objc_class_name_SaxXMLFilter;
+       __objc_class_name_SaxXMLReaderFactory;
diff --git a/skyrix-xml/SxXML-Info.plist b/skyrix-xml/SxXML-Info.plist
new file mode 100644 (file)
index 0000000..1f16abf
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SxXML</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>org.OpenGroupware.SOPE.SxXML</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-xml/SxXML.xcode/.cvsignore b/skyrix-xml/SxXML.xcode/.cvsignore
new file mode 100644 (file)
index 0000000..f062c09
--- /dev/null
@@ -0,0 +1 @@
+helge.pbxuser
diff --git a/skyrix-xml/SxXML.xcode/project.pbxproj b/skyrix-xml/SxXML.xcode/project.pbxproj
new file mode 100644 (file)
index 0000000..efdfc29
--- /dev/null
@@ -0,0 +1,6380 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 39;
+       objects = {
+               AD0CDFF405D950A8004D9B87 = {
+                       fileEncoding = 5;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       tabWidth = 4;
+                       usesTabs = 1;
+               };
+               AD1626DE05D9127900A7368D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1626DF05D9127900A7368D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1626E005D9127900A7368D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = PROJECTLEAD;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1626E105D9127900A7368D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = TODO;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1626E205D9127900A7368D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD16270D05D91EDF00A7368D = {
+                       fileEncoding = 5;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = "README-OSX.txt";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD16279F05D9358800A7368D = {
+                       children = (
+                               AD1627A005D935BE00A7368D,
+                       );
+                       isa = PBXGroup;
+                       name = "Linked Frameworks";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               AD1627A005D935BE00A7368D = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       name = Foundation.framework;
+                       path = /System/Library/Frameworks/Foundation.framework;
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               AD1627A105D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627A205D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627A305D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627A405D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627A505D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627A605D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627A705D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627A805D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627A905D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627AA05D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD1627AB05D935BE00A7368D = {
+                       fileRef = AD1627A005D935BE00A7368D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD52209506A7D5C500B24132 = {
+                       buildActionMask = 2147483647;
+                       dstPath = SaxDrivers;
+                       dstSubfolderSpec = 7;
+                       files = (
+                               AD52209606A7D5DD00B24132,
+                       );
+                       isa = PBXCopyFilesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               AD52209606A7D5DD00B24132 = {
+                       fileRef = E8DD6663055EC8BB00166B93;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               AD52237E06A7EB7600B24132 = {
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               DEPLOYMENT_LOCATION = NO;
+                               DEPLOYMENT_POSTPROCESSING = YES;
+                               DSTROOT = /;
+                               DYLIB_INSTALL_NAME_BASE = "@executable_path/../Frameworks";
+                               FRAMEWORK_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_OPTIMIZATION_LEVEL = 3;
+                               GCC_PREPROCESSOR_DEFINITIONS = "APPLE_RUNTIME=1 NeXT_Foundation_LIBRARY=1 COCOA_Foundation_LIBRARY=1 NeXT_RUNTIME=1 COMPILE_AS_FRAMEWORK=1";
+                               SKIP_INSTALL = YES;
+                               SYMROOT = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+                               TEMP_DIR = "$(SYMROOT)/$(PROJECT_NAME).build";
+                               UNSTRIPPED_PRODUCT = NO;
+                               ZERO_LINK = NO;
+                       };
+                       isa = PBXBuildStyle;
+                       name = Wrapper;
+               };
+               AD52238106A7EBDA00B24132 = {
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "SxXML Umbrella Framework Contents";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       dependencies = (
+                               AD52238306A7EC0B00B24132,
+                               AD52238506A7EC0B00B24132,
+                               AD52238706A7EC0B00B24132,
+                               AD52238906A7EC0B00B24132,
+                       );
+                       isa = PBXAggregateTarget;
+                       name = "Wrapper Contents";
+                       productName = "SxXML Umbrella Framework Contents";
+               };
+               AD52238206A7EC0B00B24132 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8FEA8C7055170B60031BF98;
+                       remoteInfo = SaxObjC;
+               };
+               AD52238306A7EC0B00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E8FEA8C7055170B60031BF98;
+                       targetProxy = AD52238206A7EC0B00B24132;
+               };
+               AD52238406A7EC0B00B24132 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8FEA8D0055170C50031BF98;
+                       remoteInfo = DOM;
+               };
+               AD52238506A7EC0B00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E8FEA8D0055170C50031BF98;
+                       targetProxy = AD52238406A7EC0B00B24132;
+               };
+               AD52238606A7EC0B00B24132 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8FEA8D8055170D40031BF98;
+                       remoteInfo = XmlRpc;
+               };
+               AD52238706A7EC0B00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E8FEA8D8055170D40031BF98;
+                       targetProxy = AD52238606A7EC0B00B24132;
+               };
+               AD52238806A7EC0B00B24132 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8DD6662055EC8BB00166B93;
+                       remoteInfo = libxmlSAXDriver;
+               };
+               AD52238906A7EC0B00B24132 = {
+                       isa = PBXTargetDependency;
+                       target = E8DD6662055EC8BB00166B93;
+                       targetProxy = AD52238806A7EC0B00B24132;
+               };
+               ADDB70E505C06107009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB70E605C06107009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E857FDF805FC9D8A0026154C,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB70E705C06107009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADDB714005C066FD009DBFB4,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB70E805C06107009DBFB4 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               ADDB713605C0666D009DBFB4,
+                               ADDB713705C0666D009DBFB4,
+                               ADDB713805C0666D009DBFB4,
+                               AD1627A405D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               ADDB70E905C06107009DBFB4 = {
+                       buildPhases = (
+                               ADDB70E505C06107009DBFB4,
+                               ADDB70E605C06107009DBFB4,
+                               ADDB70E705C06107009DBFB4,
+                               ADDB70E805C06107009DBFB4,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "SxXML-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC0FF0000 -sub_umbrella SaxObjC -sub_umbrella DOM -sub_umbrella XmlRpc -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = SxXML;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                               ADDB70EF05C0612D009DBFB4,
+                               ADDB70F105C0612D009DBFB4,
+                               ADDB70F305C0612D009DBFB4,
+                       );
+                       isa = PBXNativeTarget;
+                       name = "SxXML (Umbrella)";
+                       productName = SxXML;
+                       productReference = ADDB70EA05C06107009DBFB4;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SxXML</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.SxXML</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               ADDB70EA05C06107009DBFB4 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = SxXML.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               ADDB70EB05C06108009DBFB4 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       path = "SxXML-Info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADDB70EC05C0611E009DBFB4 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = ADDB70E905C06107009DBFB4;
+                       remoteInfo = SxXML;
+               };
+               ADDB70ED05C0611E009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = ADDB70E905C06107009DBFB4;
+                       targetProxy = ADDB70EC05C0611E009DBFB4;
+               };
+               ADDB70EE05C0612D009DBFB4 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8FEA8C7055170B60031BF98;
+                       remoteInfo = SaxObjC;
+               };
+               ADDB70EF05C0612D009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E8FEA8C7055170B60031BF98;
+                       targetProxy = ADDB70EE05C0612D009DBFB4;
+               };
+               ADDB70F005C0612D009DBFB4 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8FEA8D0055170C50031BF98;
+                       remoteInfo = DOM;
+               };
+               ADDB70F105C0612D009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E8FEA8D0055170C50031BF98;
+                       targetProxy = ADDB70F005C0612D009DBFB4;
+               };
+               ADDB70F205C0612D009DBFB4 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8FEA8D8055170D40031BF98;
+                       remoteInfo = XmlRpc;
+               };
+               ADDB70F305C0612D009DBFB4 = {
+                       isa = PBXTargetDependency;
+                       target = E8FEA8D8055170D40031BF98;
+                       targetProxy = ADDB70F205C0612D009DBFB4;
+               };
+               ADDB713605C0666D009DBFB4 = {
+                       fileRef = E8FEA8C8055170B60031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB713705C0666D009DBFB4 = {
+                       fileRef = E8FEA8D1055170C50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB713805C0666D009DBFB4 = {
+                       fileRef = E8FEA8D9055170D40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               ADDB713E05C066CF009DBFB4 = {
+                       children = (
+                               ADDB70EB05C06108009DBFB4,
+                               ADDB713F05C066FD009DBFB4,
+                       );
+                       isa = PBXGroup;
+                       name = SxXML;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADDB713F05C066FD009DBFB4 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.c;
+                       path = dummy.c;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADDB714005C066FD009DBFB4 = {
+                       fileRef = ADDB713F05C066FD009DBFB4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+//AD0
+//AD1
+//AD2
+//AD3
+//AD4
+//E80
+//E81
+//E82
+//E83
+//E84
+               E80DE02F05769AF00022D5D9 = {
+                       children = (
+                               E80DE03205769B140022D5D9,
+                               E80DE03505769B140022D5D9,
+                               E80DE03305769B140022D5D9,
+                               E80DE03405769B140022D5D9,
+                               E80DE03605769B140022D5D9,
+                               E80DE03705769B140022D5D9,
+                               E80DE03805769B140022D5D9,
+                               E80DE03905769B140022D5D9,
+                               E80DE03A05769B140022D5D9,
+                               E80DE03B05769B140022D5D9,
+                               E80DE03C05769B140022D5D9,
+                       );
+                       isa = PBXGroup;
+                       name = Samples;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03205769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = samples/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03305769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = samples/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03405769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = domxml.m;
+                       path = samples/domxml.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03505769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = samples/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03605769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = rss2plist1.m;
+                       path = samples/rss2plist1.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03705769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = rss2plist2.m;
+                       path = samples/rss2plist2.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03805769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = rssparse.m;
+                       path = samples/rssparse.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03905769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       name = rssparse.xmap;
+                       path = samples/rssparse.xmap;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03A05769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = saxxml.m;
+                       path = samples/saxxml.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03B05769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = testqp.m;
+                       path = samples/testqp.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE03C05769B140022D5D9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = xmln.m;
+                       path = samples/xmln.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E80DE04105769B360022D5D9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E80DE04205769B360022D5D9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E80DE05905769B5F0022D5D9,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E80DE04305769B360022D5D9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E80DE07105769B760022D5D9,
+                               AD1627A905D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E80DE04405769B360022D5D9 = {
+                       buildPhases = (
+                               E80DE04105769B360022D5D9,
+                               E80DE04205769B360022D5D9,
+                               E80DE04305769B360022D5D9,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = saxxml;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = saxxml;
+                       productName = saxxml;
+                       productReference = E80DE04505769B360022D5D9;
+                       productType = "com.apple.product-type.tool";
+               };
+               E80DE04505769B360022D5D9 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = saxxml;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E80DE04B05769B420022D5D9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E80DE04C05769B420022D5D9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E80DE07505769B8E0022D5D9,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E80DE04D05769B420022D5D9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E80DE07205769B800022D5D9,
+                               E80DE07305769B810022D5D9,
+                               AD1627AA05D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E80DE04E05769B420022D5D9 = {
+                       buildPhases = (
+                               E80DE04B05769B420022D5D9,
+                               E80DE04C05769B420022D5D9,
+                               E80DE04D05769B420022D5D9,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = domxml;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = domxml;
+                       productName = domxml;
+                       productReference = E80DE04F05769B420022D5D9;
+                       productType = "com.apple.product-type.tool";
+               };
+               E80DE04F05769B420022D5D9 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = domxml;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E80DE05305769B4C0022D5D9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E80DE05405769B4C0022D5D9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E80DE07605769B910022D5D9,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E80DE05505769B4C0022D5D9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E80DE07405769B860022D5D9,
+                               AD1627AB05D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E80DE05605769B4C0022D5D9 = {
+                       buildPhases = (
+                               E80DE05305769B4C0022D5D9,
+                               E80DE05405769B4C0022D5D9,
+                               E80DE05505769B4C0022D5D9,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INSTALL_PATH = /usr/local/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = xmln;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = xmln;
+                       productName = xmln;
+                       productReference = E80DE05705769B4C0022D5D9;
+                       productType = "com.apple.product-type.tool";
+               };
+               E80DE05705769B4C0022D5D9 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = xmln;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E80DE05905769B5F0022D5D9 = {
+                       fileRef = E80DE03A05769B140022D5D9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80DE07105769B760022D5D9 = {
+                       fileRef = E8FEA8C8055170B60031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80DE07205769B800022D5D9 = {
+                       fileRef = E8FEA8C8055170B60031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80DE07305769B810022D5D9 = {
+                       fileRef = E8FEA8D1055170C50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80DE07405769B860022D5D9 = {
+                       fileRef = E8FEA8C8055170B60031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80DE07505769B8E0022D5D9 = {
+                       fileRef = E80DE03405769B140022D5D9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80DE07605769B910022D5D9 = {
+                       fileRef = E80DE03C05769B140022D5D9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E80DE07905769BC50022D5D9 = {
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = Samples;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       dependencies = (
+                               E80DE07B05769BD20022D5D9,
+                               E80DE07D05769BD20022D5D9,
+                               E80DE07F05769BD20022D5D9,
+                       );
+                       isa = PBXAggregateTarget;
+                       name = Samples;
+                       productName = Samples;
+               };
+               E80DE07A05769BD20022D5D9 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E80DE04405769B360022D5D9;
+                       remoteInfo = saxxml;
+               };
+               E80DE07B05769BD20022D5D9 = {
+                       isa = PBXTargetDependency;
+                       target = E80DE04405769B360022D5D9;
+                       targetProxy = E80DE07A05769BD20022D5D9;
+               };
+               E80DE07C05769BD20022D5D9 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E80DE04E05769B420022D5D9;
+                       remoteInfo = domxml;
+               };
+               E80DE07D05769BD20022D5D9 = {
+                       isa = PBXTargetDependency;
+                       target = E80DE04E05769B420022D5D9;
+                       targetProxy = E80DE07C05769BD20022D5D9;
+               };
+               E80DE07E05769BD20022D5D9 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E80DE05605769B4C0022D5D9;
+                       remoteInfo = xmln;
+               };
+               E80DE07F05769BD20022D5D9 = {
+                       isa = PBXTargetDependency;
+                       target = E80DE05605769B4C0022D5D9;
+                       targetProxy = E80DE07E05769BD20022D5D9;
+               };
+               E80DE08005769BDB0022D5D9 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E80DE07905769BC50022D5D9;
+                       remoteInfo = Samples;
+               };
+               E80DE08105769BDB0022D5D9 = {
+                       isa = PBXTargetDependency;
+                       target = E80DE07905769BC50022D5D9;
+                       targetProxy = E80DE08005769BDB0022D5D9;
+               };
+               E816B379055171A900058059 = {
+                       children = (
+                               E8FEA90A055170F40031BF98,
+                               E8FEA90C055170F40031BF98,
+                               E8FEA90E055170F40031BF98,
+                               E8FEA90F055170F40031BF98,
+                               E8FEA910055170F40031BF98,
+                               E8FEA912055170F40031BF98,
+                               E8FEA913055170F40031BF98,
+                               E8FEA914055170F40031BF98,
+                               E8FEA915055170F40031BF98,
+                               E8FEA916055170F40031BF98,
+                               E8FEA918055170F40031BF98,
+                               E8FEA91A055170F40031BF98,
+                               E8FEA91B055170F50031BF98,
+                               E8FEA91D055170F50031BF98,
+                               E8FEA91F055170F50031BF98,
+                               E8FEA921055170F50031BF98,
+                               E8FEA922055170F50031BF98,
+                               E8FEA924055170F50031BF98,
+                               E8FEA926055170F50031BF98,
+                               E8FEA928055170F50031BF98,
+                               E8FEA929055170F50031BF98,
+                               E8FEA968055170F50031BF98,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B37C055171B300058059 = {
+                       children = (
+                               E8FEA8E5055170F40031BF98,
+                               E8FEA90B055170F40031BF98,
+                               E8FEA90D055170F40031BF98,
+                               E8FEA911055170F40031BF98,
+                               E885C6D3055EE27F00A13E26,
+                               E8FEA917055170F40031BF98,
+                               E8FEA919055170F40031BF98,
+                               E8FEA91C055170F50031BF98,
+                               E8FEA91E055170F50031BF98,
+                               E8FEA920055170F50031BF98,
+                               E8FEA923055170F50031BF98,
+                               E8FEA925055170F50031BF98,
+                               E8FEA927055170F50031BF98,
+                               E8FEA92A055170F50031BF98,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B383055171E500058059 = {
+                       children = (
+                               E8FEA965055170F50031BF98,
+                       );
+                       isa = PBXGroup;
+                       name = Documentation;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3890551734B00058059 = {
+                       children = (
+                               E816B4520551742F00058059,
+                               E816B3990551738C00058059,
+                               E816B4530551742F00058059,
+                               E816B4540551742F00058059,
+                               E816B4550551742F00058059,
+                               E816B4570551742F00058059,
+                               E816B4630551745500058059,
+                               E816B3950551736A00058059,
+                               E816B38F0551735D00058059,
+                               E816B3920551736400058059,
+                       );
+                       isa = PBXGroup;
+                       name = DOM;
+                       path = "";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B38C0551735300058059 = {
+                       children = (
+                               E816B4FF055177A000058059,
+                               E816B504055177A000058059,
+                               E816B501055177A000058059,
+                               E816B502055177A000058059,
+                               E816B49F055175C500058059,
+                               E816B49C055175BE00058059,
+                               E816B499055175B000058059,
+                               E816B496055175A700058059,
+                               E816B50D055177C900058059,
+                       );
+                       isa = PBXGroup;
+                       name = XmlRpc;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B38F0551735D00058059 = {
+                       children = (
+                               E816B3B5055173B000058059,
+                               E816B3B7055173B000058059,
+                               E816B3B9055173B000058059,
+                               E816B3BA055173B000058059,
+                               E816B3BC055173B000058059,
+                               E816B3BE055173B000058059,
+                               E816B3C0055173B000058059,
+                               E816B3C2055173B000058059,
+                               E816B3C5055173B000058059,
+                               E816B3C6055173B000058059,
+                               E816B3C8055173B000058059,
+                               E816B3CA055173B000058059,
+                               E816B3CC055173B000058059,
+                               E816B3CE055173B000058059,
+                               E816B3D0055173B000058059,
+                               E816B3D2055173B000058059,
+                               E816B3D3055173B000058059,
+                               E816B3D5055173B000058059,
+                               E816B3D8055173B000058059,
+                               E816B3DA055173B000058059,
+                               E816B3DC055173B000058059,
+                               E816B3DE055173B000058059,
+                               E816B3E1055173B100058059,
+                               E816B3E3055173B100058059,
+                               E816B3E5055173B100058059,
+                               E816B3E6055173B100058059,
+                               E816B3E8055173B100058059,
+                               E816B3EA055173B100058059,
+                               E816B3EC055173B100058059,
+                               E816B3EE055173B100058059,
+                               E816B3F0055173B100058059,
+                               E816B3F2055173B100058059,
+                               E816B3F4055173B100058059,
+                               E816B3F6055173B100058059,
+                               E816B3F8055173B100058059,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3920551736400058059 = {
+                       children = (
+                               E816B3B4055173B000058059,
+                               E816B3B6055173B000058059,
+                               E816B3B8055173B000058059,
+                               E816B3BB055173B000058059,
+                               E816B3BD055173B000058059,
+                               E816B3BF055173B000058059,
+                               E816B3C1055173B000058059,
+                               E816B3C3055173B000058059,
+                               E816B3C4055173B000058059,
+                               E816B3C7055173B000058059,
+                               E816B3C9055173B000058059,
+                               E816B3CB055173B000058059,
+                               E816B3CD055173B000058059,
+                               E816B3CF055173B000058059,
+                               E816B3D1055173B000058059,
+                               E816B3D4055173B000058059,
+                               E816B3D6055173B000058059,
+                               E816B3D7055173B000058059,
+                               E816B3D9055173B000058059,
+                               E816B3DB055173B000058059,
+                               E816B3DD055173B000058059,
+                               E816B3DF055173B100058059,
+                               E816B3E0055173B100058059,
+                               E816B3E2055173B100058059,
+                               E816B3E4055173B100058059,
+                               E816B3E7055173B100058059,
+                               E816B3E9055173B100058059,
+                               E816B3EB055173B100058059,
+                               E816B3ED055173B100058059,
+                               E816B3EF055173B100058059,
+                               E816B3F1055173B100058059,
+                               E816B3F3055173B100058059,
+                               E816B3F5055173B100058059,
+                               E816B3F7055173B100058059,
+                               E816B3F9055173B100058059,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3950551736A00058059 = {
+                       children = (
+                               E816B3980551738C00058059,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3980551738C00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = DOM/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3990551738C00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = DOM/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B39A0551738C00058059 = {
+                       fileRef = E816B3980551738C00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B39B0551738C00058059 = {
+                       fileRef = E816B3990551738C00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B3B4055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = DOM/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3B5055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOM.h;
+                       path = DOM/DOM.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3B6055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "DOM+JS.m";
+                       path = "DOM/DOM+JS.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3B7055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMAttribute.h;
+                       path = DOM/DOMAttribute.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3B8055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMAttribute.m;
+                       path = DOM/DOMAttribute.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3B9055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMBuilder.h;
+                       path = DOM/DOMBuilder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3BA055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMBuilderFactory.h;
+                       path = DOM/DOMBuilderFactory.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3BB055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMBuilderFactory.m;
+                       path = DOM/DOMBuilderFactory.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3BC055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMCDATASection.h;
+                       path = DOM/DOMCDATASection.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3BD055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMCDATASection.m;
+                       path = DOM/DOMCDATASection.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3BE055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMCharacterData.h;
+                       path = DOM/DOMCharacterData.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3BF055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMCharacterData.m;
+                       path = DOM/DOMCharacterData.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3C0055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMComment.h;
+                       path = DOM/DOMComment.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3C1055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMComment.m;
+                       path = DOM/DOMComment.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3C2055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMDocument.h;
+                       path = DOM/DOMDocument.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3C3055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMDocument.m;
+                       path = DOM/DOMDocument.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3C4055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "DOMDocument+factory.m";
+                       path = "DOM/DOMDocument+factory.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3C5055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMDocumentBuilder.h;
+                       path = DOM/DOMDocumentBuilder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3C6055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMDocumentFragment.h;
+                       path = DOM/DOMDocumentFragment.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3C7055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMDocumentFragment.m;
+                       path = DOM/DOMDocumentFragment.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3C8055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMDocumentType.h;
+                       path = DOM/DOMDocumentType.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3C9055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMDocumentType.m;
+                       path = DOM/DOMDocumentType.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3CA055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMElement.h;
+                       path = DOM/DOMElement.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3CB055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMElement.m;
+                       path = DOM/DOMElement.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3CC055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMEntity.h;
+                       path = DOM/DOMEntity.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3CD055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMEntity.m;
+                       path = DOM/DOMEntity.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3CE055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMEntityReference.h;
+                       path = DOM/DOMEntityReference.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3CF055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMEntityReference.m;
+                       path = DOM/DOMEntityReference.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3D0055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMImplementation.h;
+                       path = DOM/DOMImplementation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3D1055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMImplementation.m;
+                       path = DOM/DOMImplementation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3D2055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMNamedNodeMap.h;
+                       path = DOM/DOMNamedNodeMap.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3D3055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMNode.h;
+                       path = DOM/DOMNode.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3D4055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMNode.m;
+                       path = DOM/DOMNode.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3D5055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "DOMNode+Enum.h";
+                       path = "DOM/DOMNode+Enum.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3D6055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "DOMNode+Enum.m";
+                       path = "DOM/DOMNode+Enum.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3D7055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "DOMNode+QPEval.m";
+                       path = "DOM/DOMNode+QPEval.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3D8055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "DOMNode+QueryPath.h";
+                       path = "DOM/DOMNode+QueryPath.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3D9055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "DOMNode+QueryPath.m";
+                       path = "DOM/DOMNode+QueryPath.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3DA055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMNodeFilter.h;
+                       path = DOM/DOMNodeFilter.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3DB055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMNodeFilter.m;
+                       path = DOM/DOMNodeFilter.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3DC055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMNodeIterator.h;
+                       path = DOM/DOMNodeIterator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3DD055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMNodeIterator.m;
+                       path = DOM/DOMNodeIterator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3DE055173B000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMNodeWalker.h;
+                       path = DOM/DOMNodeWalker.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3DF055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMNodeWalker.m;
+                       path = DOM/DOMNodeWalker.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3E0055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMNodeWithChildren.m;
+                       path = DOM/DOMNodeWithChildren.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3E1055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMNotation.h;
+                       path = DOM/DOMNotation.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3E2055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMNotation.m;
+                       path = DOM/DOMNotation.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3E3055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMProcessingInstruction.h;
+                       path = DOM/DOMProcessingInstruction.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3E4055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMProcessingInstruction.m;
+                       path = DOM/DOMProcessingInstruction.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3E5055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMProtocols.h;
+                       path = DOM/DOMProtocols.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3E6055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMPYXOutputter.h;
+                       path = DOM/DOMPYXOutputter.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3E7055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMPYXOutputter.m;
+                       path = DOM/DOMPYXOutputter.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3E8055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMQueryPathExpression.h;
+                       path = DOM/DOMQueryPathExpression.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3E9055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMQueryPathExpression.m;
+                       path = DOM/DOMQueryPathExpression.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3EA055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMSaxBuilder.h;
+                       path = DOM/DOMSaxBuilder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3EB055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMSaxBuilder.m;
+                       path = DOM/DOMSaxBuilder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3EC055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMSaxHandler.h;
+                       path = DOM/DOMSaxHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3ED055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMSaxHandler.m;
+                       path = DOM/DOMSaxHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3EE055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMText.h;
+                       path = DOM/DOMText.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3EF055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMText.m;
+                       path = DOM/DOMText.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3F0055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMTreeWalker.h;
+                       path = DOM/DOMTreeWalker.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3F1055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMTreeWalker.m;
+                       path = DOM/DOMTreeWalker.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3F2055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = DOMXMLOutputter.h;
+                       path = DOM/DOMXMLOutputter.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3F3055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = DOMXMLOutputter.m;
+                       path = DOM/DOMXMLOutputter.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3F4055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = EDOM.h;
+                       path = DOM/EDOM.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3F5055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSObject+DOM.m";
+                       path = "DOM/NSObject+DOM.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3F6055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NSObject+QPEval.h";
+                       path = "DOM/NSObject+QPEval.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3F7055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSObject+QPEval.m";
+                       path = "DOM/NSObject+QPEval.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3F8055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NSObject+StringValue.h";
+                       path = "DOM/NSObject+StringValue.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3F9055173B100058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSObject+StringValue.m";
+                       path = "DOM/NSObject+StringValue.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B3FA055173B100058059 = {
+                       fileRef = E816B3B4055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B3FB055173B100058059 = {
+                       fileRef = E816B3B5055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B3FC055173B100058059 = {
+                       fileRef = E816B3B6055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B3FD055173B100058059 = {
+                       fileRef = E816B3B7055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B3FE055173B100058059 = {
+                       fileRef = E816B3B8055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B3FF055173B100058059 = {
+                       fileRef = E816B3B9055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B400055173B100058059 = {
+                       fileRef = E816B3BA055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B401055173B100058059 = {
+                       fileRef = E816B3BB055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B402055173B100058059 = {
+                       fileRef = E816B3BC055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B403055173B100058059 = {
+                       fileRef = E816B3BD055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B404055173B100058059 = {
+                       fileRef = E816B3BE055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B405055173B100058059 = {
+                       fileRef = E816B3BF055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B406055173B100058059 = {
+                       fileRef = E816B3C0055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B407055173B100058059 = {
+                       fileRef = E816B3C1055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B408055173B100058059 = {
+                       fileRef = E816B3C2055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B409055173B100058059 = {
+                       fileRef = E816B3C3055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B40A055173B100058059 = {
+                       fileRef = E816B3C4055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B40B055173B100058059 = {
+                       fileRef = E816B3C5055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B40C055173B100058059 = {
+                       fileRef = E816B3C6055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B40D055173B100058059 = {
+                       fileRef = E816B3C7055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B40E055173B100058059 = {
+                       fileRef = E816B3C8055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B40F055173B100058059 = {
+                       fileRef = E816B3C9055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B410055173B100058059 = {
+                       fileRef = E816B3CA055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B411055173B100058059 = {
+                       fileRef = E816B3CB055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B412055173B100058059 = {
+                       fileRef = E816B3CC055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B413055173B100058059 = {
+                       fileRef = E816B3CD055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B414055173B100058059 = {
+                       fileRef = E816B3CE055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B415055173B100058059 = {
+                       fileRef = E816B3CF055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B416055173B100058059 = {
+                       fileRef = E816B3D0055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B417055173B100058059 = {
+                       fileRef = E816B3D1055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B418055173B100058059 = {
+                       fileRef = E816B3D2055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B419055173B100058059 = {
+                       fileRef = E816B3D3055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B41A055173B100058059 = {
+                       fileRef = E816B3D4055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B41B055173B100058059 = {
+                       fileRef = E816B3D5055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B41C055173B100058059 = {
+                       fileRef = E816B3D6055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B41D055173B100058059 = {
+                       fileRef = E816B3D7055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B41E055173B100058059 = {
+                       fileRef = E816B3D8055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B41F055173B100058059 = {
+                       fileRef = E816B3D9055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B420055173B100058059 = {
+                       fileRef = E816B3DA055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B421055173B100058059 = {
+                       fileRef = E816B3DB055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B422055173B100058059 = {
+                       fileRef = E816B3DC055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B423055173B100058059 = {
+                       fileRef = E816B3DD055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B424055173B100058059 = {
+                       fileRef = E816B3DE055173B000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B425055173B100058059 = {
+                       fileRef = E816B3DF055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B426055173B100058059 = {
+                       fileRef = E816B3E0055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B427055173B100058059 = {
+                       fileRef = E816B3E1055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B428055173B100058059 = {
+                       fileRef = E816B3E2055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B429055173B100058059 = {
+                       fileRef = E816B3E3055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B42A055173B100058059 = {
+                       fileRef = E816B3E4055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B42B055173B100058059 = {
+                       fileRef = E816B3E5055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B42C055173B100058059 = {
+                       fileRef = E816B3E6055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B42D055173B100058059 = {
+                       fileRef = E816B3E7055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B42E055173B100058059 = {
+                       fileRef = E816B3E8055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B42F055173B100058059 = {
+                       fileRef = E816B3E9055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B430055173B100058059 = {
+                       fileRef = E816B3EA055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B431055173B100058059 = {
+                       fileRef = E816B3EB055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B432055173B100058059 = {
+                       fileRef = E816B3EC055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B433055173B100058059 = {
+                       fileRef = E816B3ED055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B434055173B100058059 = {
+                       fileRef = E816B3EE055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B435055173B100058059 = {
+                       fileRef = E816B3EF055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B436055173B100058059 = {
+                       fileRef = E816B3F0055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B437055173B100058059 = {
+                       fileRef = E816B3F1055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B438055173B100058059 = {
+                       fileRef = E816B3F2055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B439055173B100058059 = {
+                       fileRef = E816B3F3055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B43A055173B100058059 = {
+                       fileRef = E816B3F4055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B43B055173B100058059 = {
+                       fileRef = E816B3F5055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B43C055173B100058059 = {
+                       fileRef = E816B3F6055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B43D055173B100058059 = {
+                       fileRef = E816B3F7055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B43E055173B100058059 = {
+                       fileRef = E816B3F8055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B43F055173B100058059 = {
+                       fileRef = E816B3F9055173B100058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4520551742F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = DOM/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4530551742F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = DOM/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4540551742F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = DOM/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4550551742F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = DOM/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4560551742F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       name = "SxXML-DOM.graffle";
+                       path = "DOM/SxXML-DOM.graffle";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4570551742F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = TODO;
+                       path = DOM/TODO;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4580551742F00058059 = {
+                       fileRef = E816B4520551742F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4590551742F00058059 = {
+                       fileRef = E816B4530551742F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B45A0551742F00058059 = {
+                       fileRef = E816B4540551742F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B45B0551742F00058059 = {
+                       fileRef = E816B4550551742F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B45C0551742F00058059 = {
+                       fileRef = E816B4560551742F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B45D0551742F00058059 = {
+                       fileRef = E816B4570551742F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4630551745500058059 = {
+                       children = (
+                               E816B4560551742F00058059,
+                       );
+                       isa = PBXGroup;
+                       name = Documentation;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B48C055174C700058059 = {
+                       fileRef = E8FEA8C8055170B60031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B496055175A700058059 = {
+                       children = (
+                               E816B500055177A000058059,
+                               E816B4CA0551775F00058059,
+                               E816B4CB0551775F00058059,
+                               E816B4CC0551775F00058059,
+                               E816B4CD0551775F00058059,
+                               E816B4CE0551775F00058059,
+                               E816B4CF0551775F00058059,
+                               E816B4D00551775F00058059,
+                               E816B4D10551775F00058059,
+                               E816B4D20551775F00058059,
+                               E816B4D30551775F00058059,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B499055175B000058059 = {
+                       children = (
+                               E816B4EC0551777700058059,
+                               E816B4ED0551777700058059,
+                               E816B4EE0551777700058059,
+                               E816B4EF0551777700058059,
+                               E816B4F00551777700058059,
+                               E816B4F10551777700058059,
+                               E816B4F20551777700058059,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B49C055175BE00058059 = {
+                       children = (
+                               E816B503055177A000058059,
+                       );
+                       isa = PBXGroup;
+                       name = Documentation;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B49F055175C500058059 = {
+                       children = (
+                               E816B4B80551773900058059,
+                               E816B4B90551773900058059,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4B80551773900058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = XmlRpc/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4B90551773900058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = XmlRpc/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4BA0551773900058059 = {
+                       fileRef = E816B4B80551773900058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4BB0551773900058059 = {
+                       fileRef = E816B4B90551773900058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4BE0551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSArray+XmlRpcCoding.m";
+                       path = "XmlRpc/NSArray+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4BF0551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSData+XmlRpcCoding.m";
+                       path = "XmlRpc/NSData+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4C00551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSDate+XmlRpcCoding.m";
+                       path = "XmlRpc/NSDate+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4C10551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSDictionary+XmlRpcCoding.m";
+                       path = "XmlRpc/NSDictionary+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4C20551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSException+XmlRpcCoding.m";
+                       path = "XmlRpc/NSException+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4C30551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSHost+XmlRpcCoding.m";
+                       path = "XmlRpc/NSHost+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4C40551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSMutableString+XmlRpcDecoder.m";
+                       path = "XmlRpc/NSMutableString+XmlRpcDecoder.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4C50551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSNotification+XmlRpcCoding.m";
+                       path = "XmlRpc/NSNotification+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4C60551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSNumber+XmlRpcCoding.m";
+                       path = "XmlRpc/NSNumber+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4C70551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSObject+XmlRpc.m";
+                       path = "XmlRpc/NSObject+XmlRpc.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4C80551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSString+XmlRpcCoding.m";
+                       path = "XmlRpc/NSString+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4C90551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "NSURL+XmlRpcCoding.m";
+                       path = "XmlRpc/NSURL+XmlRpcCoding.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4CA0551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = XmlRpcDecoder.m;
+                       path = XmlRpc/XmlRpcDecoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4CB0551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = XmlRpcEncoder.m;
+                       path = XmlRpc/XmlRpcEncoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4CC0551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = XmlRpcMethodCall.m;
+                       path = XmlRpc/XmlRpcMethodCall.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4CD0551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = XmlRpcMethodResponse.m;
+                       path = XmlRpc/XmlRpcMethodResponse.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4CE0551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = XmlRpcRequestDecoder.m;
+                       path = XmlRpc/XmlRpcRequestDecoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4CF0551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = XmlRpcRequestEncoder.m;
+                       path = XmlRpc/XmlRpcRequestEncoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4D00551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = XmlRpcResponseDecoder.m;
+                       path = XmlRpc/XmlRpcResponseDecoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4D10551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = XmlRpcResponseEncoder.m;
+                       path = XmlRpc/XmlRpcResponseEncoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4D20551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = XmlRpcSaxHandler.m;
+                       path = XmlRpc/XmlRpcSaxHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4D30551775F00058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = XmlRpcValue.m;
+                       path = XmlRpc/XmlRpcValue.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4D40551775F00058059 = {
+                       fileRef = E816B4BE0551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4D50551775F00058059 = {
+                       fileRef = E816B4BF0551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4D60551775F00058059 = {
+                       fileRef = E816B4C00551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4D70551775F00058059 = {
+                       fileRef = E816B4C10551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4D80551775F00058059 = {
+                       fileRef = E816B4C20551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4D90551775F00058059 = {
+                       fileRef = E816B4C30551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4DA0551775F00058059 = {
+                       fileRef = E816B4C40551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4DB0551775F00058059 = {
+                       fileRef = E816B4C50551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4DC0551775F00058059 = {
+                       fileRef = E816B4C60551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4DD0551775F00058059 = {
+                       fileRef = E816B4C70551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4DE0551775F00058059 = {
+                       fileRef = E816B4C80551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4DF0551775F00058059 = {
+                       fileRef = E816B4C90551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4E00551775F00058059 = {
+                       fileRef = E816B4CA0551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4E10551775F00058059 = {
+                       fileRef = E816B4CB0551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4E20551775F00058059 = {
+                       fileRef = E816B4CC0551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4E30551775F00058059 = {
+                       fileRef = E816B4CD0551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4E80551775F00058059 = {
+                       fileRef = E816B4D20551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4E90551775F00058059 = {
+                       fileRef = E816B4D30551775F00058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4EC0551777700058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = "NSObject+XmlRpc.h";
+                       path = "XmlRpc/NSObject+XmlRpc.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4ED0551777700058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = XmlRpc.h;
+                       path = XmlRpc/XmlRpc.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4EE0551777700058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = XmlRpcCoder.h;
+                       path = XmlRpc/XmlRpcCoder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4EF0551777700058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = XmlRpcMethodCall.h;
+                       path = XmlRpc/XmlRpcMethodCall.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4F00551777700058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = XmlRpcMethodResponse.h;
+                       path = XmlRpc/XmlRpcMethodResponse.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4F10551777700058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = XmlRpcSaxHandler.h;
+                       path = XmlRpc/XmlRpcSaxHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4F20551777700058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = XmlRpcValue.h;
+                       path = XmlRpc/XmlRpcValue.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B4F30551777700058059 = {
+                       fileRef = E816B4EC0551777700058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B4F40551777700058059 = {
+                       fileRef = E816B4ED0551777700058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B4F50551777700058059 = {
+                       fileRef = E816B4EE0551777700058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B4F60551777700058059 = {
+                       fileRef = E816B4EF0551777700058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B4F70551777700058059 = {
+                       fileRef = E816B4F00551777700058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B4F80551777700058059 = {
+                       fileRef = E816B4F10551777700058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B4F90551777700058059 = {
+                       fileRef = E816B4F20551777700058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E816B4FA0551778000058059 = {
+                       fileRef = E8FEA8C8055170B60031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B4FF055177A000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = XmlRpc/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B500055177A000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = XmlRpc/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B501055177A000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = XmlRpc/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B502055177A000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = XmlRpc/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B503055177A000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       name = "SxXML-XmlRpc.graffle";
+                       path = "XmlRpc/SxXML-XmlRpc.graffle";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B504055177A000058059 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = XmlRpc/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B505055177A100058059 = {
+                       fileRef = E816B4FF055177A000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B506055177A100058059 = {
+                       fileRef = E816B500055177A000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B507055177A100058059 = {
+                       fileRef = E816B501055177A000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B508055177A100058059 = {
+                       fileRef = E816B502055177A000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B509055177A100058059 = {
+                       fileRef = E816B503055177A000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B50A055177A100058059 = {
+                       fileRef = E816B504055177A000058059;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E816B50D055177C900058059 = {
+                       children = (
+                               E816B4BE0551775F00058059,
+                               E816B4BF0551775F00058059,
+                               E816B4C00551775F00058059,
+                               E816B4C10551775F00058059,
+                               E816B4C20551775F00058059,
+                               E816B4C30551775F00058059,
+                               E816B4C40551775F00058059,
+                               E816B4C50551775F00058059,
+                               E816B4C60551775F00058059,
+                               E816B4C70551775F00058059,
+                               E816B4C80551775F00058059,
+                               E816B4C90551775F00058059,
+                       );
+                       isa = PBXGroup;
+                       name = "Foundation Mappings";
+                       path = "";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E816B51F055178BC00058059 = {
+                       buildArgumentsString = "all $(ACTION)";
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "GSM: all";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                               debug = yes;
+                       };
+                       buildToolPath = /usr/bin/make;
+                       buildWorkingDirectory = "$(PROJECT_DIRECTORY)";
+                       dependencies = (
+                       );
+                       isa = PBXLegacyTarget;
+                       name = "GSM: all";
+                       passBuildSettingsInEnvironment = 1;
+                       productName = "GSM: all";
+               };
+               E816B60B05517A8C00058059 = {
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = all;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       dependencies = (
+                               E8DD6646055EC85D00166B93,
+                               E8DD6648055EC86000166B93,
+                               E8DD664A055EC86300166B93,
+                               ADDB70ED05C0611E009DBFB4,
+                               E8DD664C055EC86600166B93,
+                               E8B3E599055ED970000B00C4,
+                               E8BB9C2105F16F6900D767A8,
+                               E80DE08105769BDB0022D5D9,
+                       );
+                       isa = PBXAggregateTarget;
+                       name = all;
+                       productName = all;
+               };
+               E857FDF705FC9D8A0026154C = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E857FDF805FC9D8A0026154C = {
+                       fileRef = E857FDF705FC9D8A0026154C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E885C6D3055EE27F00A13E26 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "SaxDefaultHandler+NSXML.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E885C6D4055EE27F00A13E26 = {
+                       fileRef = E885C6D3055EE27F00A13E26;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897275505F1661400B5B1A9 = {
+                       children = (
+                               E897279005F1670C00B5B1A9,
+                               E897276005F1670B00B5B1A9,
+                               E897279505F1670D00B5B1A9,
+                               E897279405F1670C00B5B1A9,
+                               E897276205F1670B00B5B1A9,
+                               E897276305F1670B00B5B1A9,
+                               E897275F05F1670B00B5B1A9,
+                               E897275E05F1664A00B5B1A9,
+                               E89727CC05F1673E00B5B1A9,
+                               E89727D005F1677000B5B1A9,
+                               E897276A05F1670B00B5B1A9,
+                               E897277D05F1670C00B5B1A9,
+                               E897276405F1670B00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = STXSaxDriver;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897275805F1664A00B5B1A9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E897279805F1670D00B5B1A9,
+                               E89727A305F1670D00B5B1A9,
+                               E89727A605F1670D00B5B1A9,
+                               E89727A805F1670D00B5B1A9,
+                               E89727AA05F1670D00B5B1A9,
+                               E89727AE05F1670D00B5B1A9,
+                               E89727B605F1670D00B5B1A9,
+                               E89727B805F1670D00B5B1A9,
+                               E89727BA05F1670D00B5B1A9,
+                               E89727BC05F1670D00B5B1A9,
+                               E89727BE05F1670D00B5B1A9,
+                               E89727C005F1670D00B5B1A9,
+                               E89727C205F1670D00B5B1A9,
+                               E89727C605F1670D00B5B1A9,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E897275905F1664A00B5B1A9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E897279605F1670D00B5B1A9,
+                               E897279705F1670D00B5B1A9,
+                               E897279905F1670D00B5B1A9,
+                               E897279A05F1670D00B5B1A9,
+                               E897279B05F1670D00B5B1A9,
+                               E897279C05F1670D00B5B1A9,
+                               E897279D05F1670D00B5B1A9,
+                               E897279E05F1670D00B5B1A9,
+                               E897279F05F1670D00B5B1A9,
+                               E89727A005F1670D00B5B1A9,
+                               E89727A105F1670D00B5B1A9,
+                               E89727A205F1670D00B5B1A9,
+                               E89727A505F1670D00B5B1A9,
+                               E89727AF05F1670D00B5B1A9,
+                               E89727B005F1670D00B5B1A9,
+                               E89727B105F1670D00B5B1A9,
+                               E89727B205F1670D00B5B1A9,
+                               E89727B305F1670D00B5B1A9,
+                               E89727B405F1670D00B5B1A9,
+                               E89727B505F1670D00B5B1A9,
+                               E89727C405F1670D00B5B1A9,
+                               E89727C805F1670D00B5B1A9,
+                               E89727C905F1670D00B5B1A9,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E897275A05F1664A00B5B1A9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E89727A405F1670D00B5B1A9,
+                               E89727A705F1670D00B5B1A9,
+                               E89727A905F1670D00B5B1A9,
+                               E89727AB05F1670D00B5B1A9,
+                               E89727B705F1670D00B5B1A9,
+                               E89727B905F1670D00B5B1A9,
+                               E89727BB05F1670D00B5B1A9,
+                               E89727BD05F1670D00B5B1A9,
+                               E89727BF05F1670D00B5B1A9,
+                               E89727C105F1670D00B5B1A9,
+                               E89727C305F1670D00B5B1A9,
+                               E89727C505F1670D00B5B1A9,
+                               E89727C705F1670D00B5B1A9,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E897275B05F1664A00B5B1A9 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E897275C05F1664A00B5B1A9 = {
+                       buildPhases = (
+                               E897275805F1664A00B5B1A9,
+                               E897275905F1664A00B5B1A9,
+                               E897275A05F1664A00B5B1A9,
+                               E897275B05F1664A00B5B1A9,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "STXSaxDriver/STXSaxDriver-Info.plist";
+                               INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers";
+                               OTHER_CFLAGS = "-DAPPLE_RUNTIME=1 -DNeXT_RUNTIME=1 -DNeXT_Foundation_LIBRARY=1 -DCOCOA_Foundation_LIBRARY=1";
+                               OTHER_LDFLAGS = "-framework Foundation -framework SaxObjC";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = STXSaxDriver;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                               WRAPPER_EXTENSION = sax;
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = STXSaxDriver;
+                       productName = STXSaxDriver;
+                       productReference = E897275D05F1664A00B5B1A9;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>STXSaxDriver</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.STXSaxDriver</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.bundle";
+               };
+               E897275D05F1664A00B5B1A9 = {
+                       explicitFileType = wrapper.cfbundle;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = STXSaxDriver.sax;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E897275E05F1664A00B5B1A9 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       name = "STXSaxDriver-Info.plist";
+                       path = "STXSaxDriver/STXSaxDriver-Info.plist";
+                       refType = 2;
+                       sourceTree = SOURCE_ROOT;
+               };
+               E897275F05F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = "bundle-info.plist";
+                       path = "STXSaxDriver/bundle-info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276005F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = STXSaxDriver/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276105F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = STXSaxDriver/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276205F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING.LIB;
+                       path = STXSaxDriver/COPYING.LIB;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276305F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = STXSaxDriver/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276405F1670B00B5B1A9 = {
+                       children = (
+                               E897276505F1670B00B5B1A9,
+                               E897276605F1670B00B5B1A9,
+                               E897276705F1670B00B5B1A9,
+                               E897276805F1670B00B5B1A9,
+                               E897276905F1670B00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = data;
+                       path = STXSaxDriver/data;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276505F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = extra_test1.stx;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276605F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = extra_test2.stx;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276705F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = hhtest1.stx;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276805F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = hhtest2.stx;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276905F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = hhtest3.stx;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276A05F1670B00B5B1A9 = {
+                       children = (
+                               E897277005F1670B00B5B1A9,
+                               E897276C05F1670B00B5B1A9,
+                               E89727CA05F1672000B5B1A9,
+                               E89727CB05F1673100B5B1A9,
+                               E897276F05F1670B00B5B1A9,
+                               E897277205F1670B00B5B1A9,
+                               E897277405F1670B00B5B1A9,
+                               E897277605F1670B00B5B1A9,
+                               E897277805F1670C00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = ExtraSTX;
+                       path = STXSaxDriver/ExtraSTX;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276B05F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276C05F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276D05F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276E05F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSString+STX.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897276F05F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+STX.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277005F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277105F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredLine.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277205F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredLine.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277305F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredStack.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277405F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredStack.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277505F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredText.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277605F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredText.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277705F1670B00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredText_XHTML.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277805F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredText_XHTML.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277905F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredTextRenderingDelegate.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277A05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = STXSaxDriver/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277B05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.postamble;
+                       path = STXSaxDriver/GNUmakefile.postamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277C05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = STXSaxDriver/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277D05F1670C00B5B1A9 = {
+                       children = (
+                               E897277F05F1670C00B5B1A9,
+                               E897278105F1670C00B5B1A9,
+                               E89727CE05F1675D00B5B1A9,
+                               E89727CD05F1675600B5B1A9,
+                               E897278305F1670C00B5B1A9,
+                               E897278505F1670C00B5B1A9,
+                               E897278705F1670C00B5B1A9,
+                               E897278905F1670C00B5B1A9,
+                               E897278B05F1670C00B5B1A9,
+                               E897278D05F1670C00B5B1A9,
+                               E897278F05F1670C00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = Model;
+                       path = STXSaxDriver/Model;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277E05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = .cvsignore;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897277F05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278005F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278105F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278205F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredTextBodyElement.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278305F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredTextBodyElement.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278405F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredTextDocument.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278505F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredTextDocument.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278605F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredTextHeader.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278705F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredTextHeader.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278805F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredTextList.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278905F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredTextList.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278A05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredTextListItem.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278B05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredTextListItem.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278C05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredTextLiteralBlock.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278D05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredTextLiteralBlock.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278E05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = StructuredTextParagraph.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897278F05F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = StructuredTextParagraph.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897279005F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = STXSaxDriver/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897279105F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = "StructuredTextBodyElement+SAX.m";
+                       path = "STXSaxDriver/StructuredTextBodyElement+SAX.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897279205F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = STXSaxDriver.h;
+                       path = STXSaxDriver/STXSaxDriver.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897279305F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = STXSaxDriver.m;
+                       path = STXSaxDriver/STXSaxDriver.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897279405F1670C00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = TODO;
+                       path = STXSaxDriver/TODO;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897279505F1670D00B5B1A9 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = STXSaxDriver/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E897279605F1670D00B5B1A9 = {
+                       fileRef = E897275F05F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897279705F1670D00B5B1A9 = {
+                       fileRef = E897276005F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897279805F1670D00B5B1A9 = {
+                       fileRef = E897276105F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897279905F1670D00B5B1A9 = {
+                       fileRef = E897276205F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897279A05F1670D00B5B1A9 = {
+                       fileRef = E897276305F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897279B05F1670D00B5B1A9 = {
+                       fileRef = E897276505F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897279C05F1670D00B5B1A9 = {
+                       fileRef = E897276605F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897279D05F1670D00B5B1A9 = {
+                       fileRef = E897276705F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897279E05F1670D00B5B1A9 = {
+                       fileRef = E897276805F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E897279F05F1670D00B5B1A9 = {
+                       fileRef = E897276905F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727A005F1670D00B5B1A9 = {
+                       fileRef = E897276B05F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727A105F1670D00B5B1A9 = {
+                       fileRef = E897276C05F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727A205F1670D00B5B1A9 = {
+                       fileRef = E897276D05F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727A305F1670D00B5B1A9 = {
+                       fileRef = E897276E05F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727A405F1670D00B5B1A9 = {
+                       fileRef = E897276F05F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727A505F1670D00B5B1A9 = {
+                       fileRef = E897277005F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727A605F1670D00B5B1A9 = {
+                       fileRef = E897277105F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727A705F1670D00B5B1A9 = {
+                       fileRef = E897277205F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727A805F1670D00B5B1A9 = {
+                       fileRef = E897277305F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727A905F1670D00B5B1A9 = {
+                       fileRef = E897277405F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727AA05F1670D00B5B1A9 = {
+                       fileRef = E897277505F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727AB05F1670D00B5B1A9 = {
+                       fileRef = E897277605F1670B00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727AE05F1670D00B5B1A9 = {
+                       fileRef = E897277905F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727AF05F1670D00B5B1A9 = {
+                       fileRef = E897277A05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727B005F1670D00B5B1A9 = {
+                       fileRef = E897277B05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727B105F1670D00B5B1A9 = {
+                       fileRef = E897277C05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727B205F1670D00B5B1A9 = {
+                       fileRef = E897277E05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727B305F1670D00B5B1A9 = {
+                       fileRef = E897277F05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727B405F1670D00B5B1A9 = {
+                       fileRef = E897278005F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727B505F1670D00B5B1A9 = {
+                       fileRef = E897278105F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727B605F1670D00B5B1A9 = {
+                       fileRef = E897278205F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727B705F1670D00B5B1A9 = {
+                       fileRef = E897278305F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727B805F1670D00B5B1A9 = {
+                       fileRef = E897278405F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727B905F1670D00B5B1A9 = {
+                       fileRef = E897278505F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727BA05F1670D00B5B1A9 = {
+                       fileRef = E897278605F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727BB05F1670D00B5B1A9 = {
+                       fileRef = E897278705F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727BC05F1670D00B5B1A9 = {
+                       fileRef = E897278805F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727BD05F1670D00B5B1A9 = {
+                       fileRef = E897278905F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727BE05F1670D00B5B1A9 = {
+                       fileRef = E897278A05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727BF05F1670D00B5B1A9 = {
+                       fileRef = E897278B05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727C005F1670D00B5B1A9 = {
+                       fileRef = E897278C05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727C105F1670D00B5B1A9 = {
+                       fileRef = E897278D05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727C205F1670D00B5B1A9 = {
+                       fileRef = E897278E05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727C305F1670D00B5B1A9 = {
+                       fileRef = E897278F05F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727C405F1670D00B5B1A9 = {
+                       fileRef = E897279005F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727C505F1670D00B5B1A9 = {
+                       fileRef = E897279105F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727C605F1670D00B5B1A9 = {
+                       fileRef = E897279205F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727C705F1670D00B5B1A9 = {
+                       fileRef = E897279305F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727C805F1670D00B5B1A9 = {
+                       fileRef = E897279405F1670C00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727C905F1670D00B5B1A9 = {
+                       fileRef = E897279505F1670D00B5B1A9;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E89727CA05F1672000B5B1A9 = {
+                       children = (
+                               E897276B05F1670B00B5B1A9,
+                               E897276D05F1670B00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E89727CB05F1673100B5B1A9 = {
+                       children = (
+                               E897276E05F1670B00B5B1A9,
+                               E897277105F1670B00B5B1A9,
+                               E897277305F1670B00B5B1A9,
+                               E897277505F1670B00B5B1A9,
+                               E897277705F1670B00B5B1A9,
+                               E897277905F1670C00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E89727CC05F1673E00B5B1A9 = {
+                       children = (
+                               E897277A05F1670C00B5B1A9,
+                               E897277B05F1670C00B5B1A9,
+                               E897277C05F1670C00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E89727CD05F1675600B5B1A9 = {
+                       children = (
+                               E897278205F1670C00B5B1A9,
+                               E897278405F1670C00B5B1A9,
+                               E897278605F1670C00B5B1A9,
+                               E897278805F1670C00B5B1A9,
+                               E897278A05F1670C00B5B1A9,
+                               E897278C05F1670C00B5B1A9,
+                               E897278E05F1670C00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E89727CE05F1675D00B5B1A9 = {
+                       children = (
+                               E897277E05F1670C00B5B1A9,
+                               E897278005F1670C00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E89727D005F1677000B5B1A9 = {
+                       children = (
+                               E897276105F1670B00B5B1A9,
+                               E897279105F1670C00B5B1A9,
+                               E897279205F1670C00B5B1A9,
+                               E897279305F1670C00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E559055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = "bundle-info.plist";
+                       path = "libxmlSAXDriver/bundle-info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E55A055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = libxmlSAXDriver/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E55B055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = common.h;
+                       path = libxmlSAXDriver/common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E55C055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = libxmlSAXDriver/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E55D055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYRIGHT;
+                       path = libxmlSAXDriver/COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E55E055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile;
+                       path = libxmlSAXDriver/GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E55F055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = GNUmakefile.preamble;
+                       path = libxmlSAXDriver/GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E561055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = libxmlDocSAXDriver.h;
+                       path = libxmlSAXDriver/libxmlDocSAXDriver.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E562055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = libxmlDocSAXDriver.m;
+                       path = libxmlSAXDriver/libxmlDocSAXDriver.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E563055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = libxmlHTMLSAXDriver.h;
+                       path = libxmlSAXDriver/libxmlHTMLSAXDriver.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E564055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = libxmlHTMLSAXDriver.m;
+                       path = libxmlSAXDriver/libxmlHTMLSAXDriver.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E565055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = "libxmlSAXDriver-Info.plist";
+                       path = "libxmlSAXDriver/libxmlSAXDriver-Info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E566055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = libxmlSAXDriver.h;
+                       path = libxmlSAXDriver/libxmlSAXDriver.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E567055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = libxmlSAXDriver.m;
+                       path = libxmlSAXDriver/libxmlSAXDriver.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E568055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = libxmlSAXLocator.h;
+                       path = libxmlSAXDriver/libxmlSAXLocator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E569055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = libxmlSAXLocator.m;
+                       path = libxmlSAXDriver/libxmlSAXLocator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E56A055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = libxmlSAXDriver/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E56B055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = TableCallbacks.h;
+                       path = libxmlSAXDriver/TableCallbacks.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E56C055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = TableCallbacks.m;
+                       path = libxmlSAXDriver/TableCallbacks.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E56D055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = unicode.h;
+                       path = libxmlSAXDriver/unicode.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E56E055ED8A7000B00C4 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = Version;
+                       path = libxmlSAXDriver/Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E56F055ED8A7000B00C4 = {
+                       fileRef = E8B3E559055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E570055ED8A7000B00C4 = {
+                       fileRef = E8B3E55A055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E571055ED8A7000B00C4 = {
+                       fileRef = E8B3E55B055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E572055ED8A7000B00C4 = {
+                       fileRef = E8B3E55C055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E573055ED8A7000B00C4 = {
+                       fileRef = E8B3E55D055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E577055ED8A7000B00C4 = {
+                       fileRef = E8B3E561055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E578055ED8A7000B00C4 = {
+                       fileRef = E8B3E562055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E579055ED8A7000B00C4 = {
+                       fileRef = E8B3E563055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E57A055ED8A7000B00C4 = {
+                       fileRef = E8B3E564055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E57B055ED8A7000B00C4 = {
+                       fileRef = E8B3E565055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E57C055ED8A7000B00C4 = {
+                       fileRef = E8B3E566055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E57D055ED8A7000B00C4 = {
+                       fileRef = E8B3E567055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E57E055ED8A7000B00C4 = {
+                       fileRef = E8B3E568055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E57F055ED8A7000B00C4 = {
+                       fileRef = E8B3E569055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E580055ED8A7000B00C4 = {
+                       fileRef = E8B3E56A055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E581055ED8A7000B00C4 = {
+                       fileRef = E8B3E56B055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E582055ED8A7000B00C4 = {
+                       fileRef = E8B3E56C055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E583055ED8A7000B00C4 = {
+                       fileRef = E8B3E56D055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E584055ED8A7000B00C4 = {
+                       fileRef = E8B3E56E055ED8A7000B00C4;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8B3E587055ED8AF000B00C4 = {
+                       children = (
+                               E8B3E55E055ED8A7000B00C4,
+                               E8B3E55F055ED8A7000B00C4,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E58A055ED8D4000B00C4 = {
+                       children = (
+                               E8B3E55B055ED8A7000B00C4,
+                               E8B3E56D055ED8A7000B00C4,
+                               E8B3E562055ED8A7000B00C4,
+                               E8B3E564055ED8A7000B00C4,
+                               E8B3E567055ED8A7000B00C4,
+                               E8B3E569055ED8A7000B00C4,
+                               E8B3E56C055ED8A7000B00C4,
+                       );
+                       isa = PBXGroup;
+                       name = Classes;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E58D055ED8E5000B00C4 = {
+                       children = (
+                               E8B3E561055ED8A7000B00C4,
+                               E8B3E563055ED8A7000B00C4,
+                               E8B3E566055ED8A7000B00C4,
+                               E8B3E568055ED8A7000B00C4,
+                               E8B3E56B055ED8A7000B00C4,
+                       );
+                       isa = PBXGroup;
+                       name = Headers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8B3E598055ED970000B00C4 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8DD6662055EC8BB00166B93;
+                       remoteInfo = libxmlSAXDriver;
+               };
+               E8B3E599055ED970000B00C4 = {
+                       isa = PBXTargetDependency;
+                       target = E8DD6662055EC8BB00166B93;
+                       targetProxy = E8B3E598055ED970000B00C4;
+               };
+               E8BA20E1055F003F00AD687B = {
+                       children = (
+                               E8B3E559055ED8A7000B00C4,
+                               E8B3E565055ED8A7000B00C4,
+                       );
+                       isa = PBXGroup;
+                       name = Resources;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8BB9C2005F16F6900D767A8 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E897275C05F1664A00B5B1A9;
+                       remoteInfo = STXSaxDriver;
+               };
+               E8BB9C2105F16F6900D767A8 = {
+                       isa = PBXTargetDependency;
+                       target = E897275C05F1664A00B5B1A9;
+                       targetProxy = E8BB9C2005F16F6900D767A8;
+               };
+               E8DD6638055EC7AD00166B93 = {
+                       children = (
+                               E8DD6653055EC89800166B93,
+                               E8DD6654055EC89800166B93,
+                               E8DD6655055EC89800166B93,
+                               E8DD6650055EC89700166B93,
+                               E8DD6651055EC89800166B93,
+                               E8DD6652055EC89800166B93,
+                       );
+                       isa = PBXGroup;
+                       name = CFXMLSaxDriver;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8DD663B055EC7D100166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8DD6657055EC89800166B93,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD663C055EC7D100166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8DD6656055EC89800166B93,
+                               E8DD6659055EC89800166B93,
+                               E8DD665A055EC89800166B93,
+                               E8DD665B055EC89800166B93,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD663D055EC7D100166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8DD6658055EC89800166B93,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD663E055EC7D100166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8DD6697055EC9EF00166B93,
+                               AD1627A505D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD663F055EC7D100166B93 = {
+                       buildPhases = (
+                               E8DD663B055EC7D100166B93,
+                               E8DD663C055EC7D100166B93,
+                               E8DD663D055EC7D100166B93,
+                               E8DD663E055EC7D100166B93,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 4.2;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "CFXMLSaxDriver/CFXMLSaxDriver-Info.plist";
+                               INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = CFXMLSaxDriver;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                               WRAPPER_EXTENSION = sax;
+                       };
+                       dependencies = (
+                               E8DD667D055EC94800166B93,
+                       );
+                       isa = PBXNativeTarget;
+                       name = CFXMLSaxDriver;
+                       productName = CFXMLSaxDriver;
+                       productReference = E8DD6640055EC7D100166B93;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>CFXMLSaxDriver</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.CFXMLSaxDriver</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.bundle";
+               };
+               E8DD6640055EC7D100166B93 = {
+                       explicitFileType = wrapper.cfbundle;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = CFXMLSaxDriver.sax;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8DD6645055EC85D00166B93 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8FEA8C7055170B60031BF98;
+                       remoteInfo = SaxObjC;
+               };
+               E8DD6646055EC85D00166B93 = {
+                       isa = PBXTargetDependency;
+                       target = E8FEA8C7055170B60031BF98;
+                       targetProxy = E8DD6645055EC85D00166B93;
+               };
+               E8DD6647055EC86000166B93 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8FEA8D0055170C50031BF98;
+                       remoteInfo = DOM;
+               };
+               E8DD6648055EC86000166B93 = {
+                       isa = PBXTargetDependency;
+                       target = E8FEA8D0055170C50031BF98;
+                       targetProxy = E8DD6647055EC86000166B93;
+               };
+               E8DD6649055EC86300166B93 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8FEA8D8055170D40031BF98;
+                       remoteInfo = XmlRpc;
+               };
+               E8DD664A055EC86300166B93 = {
+                       isa = PBXTargetDependency;
+                       target = E8FEA8D8055170D40031BF98;
+                       targetProxy = E8DD6649055EC86300166B93;
+               };
+               E8DD664B055EC86600166B93 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8DD663F055EC7D100166B93;
+                       remoteInfo = CFXMLSaxDriver;
+               };
+               E8DD664C055EC86600166B93 = {
+                       isa = PBXTargetDependency;
+                       target = E8DD663F055EC7D100166B93;
+                       targetProxy = E8DD664B055EC86600166B93;
+               };
+               E8DD6650055EC89700166B93 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist;
+                       name = "bundle-info.plist";
+                       path = "CFXMLSaxDriver/bundle-info.plist";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8DD6651055EC89800166B93 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = CFXMLSaxDriver.h;
+                       path = CFXMLSaxDriver/CFXMLSaxDriver.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8DD6652055EC89800166B93 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       name = CFXMLSaxDriver.m;
+                       path = CFXMLSaxDriver/CFXMLSaxDriver.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8DD6653055EC89800166B93 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = ChangeLog;
+                       path = CFXMLSaxDriver/ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8DD6654055EC89800166B93 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = COPYING;
+                       path = CFXMLSaxDriver/COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8DD6655055EC89800166B93 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       name = README;
+                       path = CFXMLSaxDriver/README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8DD6656055EC89800166B93 = {
+                       fileRef = E8DD6650055EC89700166B93;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8DD6657055EC89800166B93 = {
+                       fileRef = E8DD6651055EC89800166B93;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8DD6658055EC89800166B93 = {
+                       fileRef = E8DD6652055EC89800166B93;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8DD6659055EC89800166B93 = {
+                       fileRef = E8DD6653055EC89800166B93;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8DD665A055EC89800166B93 = {
+                       fileRef = E8DD6654055EC89800166B93;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8DD665B055EC89800166B93 = {
+                       fileRef = E8DD6655055EC89800166B93;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8DD665E055EC8BB00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8B3E571055ED8A7000B00C4,
+                               E8B3E577055ED8A7000B00C4,
+                               E8B3E579055ED8A7000B00C4,
+                               E8B3E57C055ED8A7000B00C4,
+                               E8B3E57E055ED8A7000B00C4,
+                               E8B3E581055ED8A7000B00C4,
+                               E8B3E583055ED8A7000B00C4,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD665F055EC8BB00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8B3E56F055ED8A7000B00C4,
+                               E8B3E570055ED8A7000B00C4,
+                               E8B3E572055ED8A7000B00C4,
+                               E8B3E573055ED8A7000B00C4,
+                               E8B3E57B055ED8A7000B00C4,
+                               E8B3E580055ED8A7000B00C4,
+                               E8B3E584055ED8A7000B00C4,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD6660055EC8BB00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8B3E578055ED8A7000B00C4,
+                               E8B3E57A055ED8A7000B00C4,
+                               E8B3E57D055ED8A7000B00C4,
+                               E8B3E57F055ED8A7000B00C4,
+                               E8B3E582055ED8A7000B00C4,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD6661055EC8BB00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8DD6698055EC9F900166B93,
+                               AD1627A605D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD6662055EC8BB00166B93 = {
+                       buildPhases = (
+                               E8DD665E055EC8BB00166B93,
+                               E8DD665F055EC8BB00166B93,
+                               E8DD6660055EC8BB00166B93,
+                               E8DD6661055EC8BB00166B93,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "libxmlSAXDriver/libxmlSAXDriver-Info.plist";
+                               INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers";
+                               OTHER_CFLAGS = "-I/usr/include/libxml2";
+                               OTHER_LDFLAGS = "-lxml2";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = libxmlSAXDriver;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                               WRAPPER_EXTENSION = sax;
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = libxmlSAXDriver;
+                       productName = libxmlSAXDriver;
+                       productReference = E8DD6663055EC8BB00166B93;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>libxmlSAXDriver</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.libxmlSAXDriver</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.bundle";
+               };
+               E8DD6663055EC8BB00166B93 = {
+                       explicitFileType = wrapper.cfbundle;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = libxmlSAXDriver.sax;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8DD6666055EC8C200166B93 = {
+                       children = (
+                               E8B3E56A055ED8A7000B00C4,
+                               E8B3E55A055ED8A7000B00C4,
+                               E8B3E55C055ED8A7000B00C4,
+                               E8B3E55D055ED8A7000B00C4,
+                               E8B3E56E055ED8A7000B00C4,
+                               E8BA20E1055F003F00AD687B,
+                               E8B3E587055ED8AF000B00C4,
+                               E8B3E58D055ED8E5000B00C4,
+                               E8B3E58A055ED8D4000B00C4,
+                       );
+                       isa = PBXGroup;
+                       name = libxmlSAXDriver;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8DD6667055EC8C900166B93 = {
+                       children = (
+                       );
+                       isa = PBXGroup;
+                       name = iCalSaxDriver;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8DD6668055EC8CE00166B93 = {
+                       children = (
+                       );
+                       isa = PBXGroup;
+                       name = pyxSAXDriver;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8DD666B055EC8ED00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD666C055EC8ED00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD666D055EC8ED00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD666E055EC8ED00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8DD6699055EC9FC00166B93,
+                               AD1627A705D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD666F055EC8ED00166B93 = {
+                       buildPhases = (
+                               E8DD666B055EC8ED00166B93,
+                               E8DD666C055EC8ED00166B93,
+                               E8DD666D055EC8ED00166B93,
+                               E8DD666E055EC8ED00166B93,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "iCalSaxDriver/iCalSaxDriver-Info.plist";
+                               INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-lical";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = iCalSaxDriver;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                               WRAPPER_EXTENSION = sax;
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = iCalSaxDriver;
+                       productName = iCalSaxDriver;
+                       productReference = E8DD6670055EC8ED00166B93;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>iCalSaxDriver</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.iCalSaxDriver</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.bundle";
+               };
+               E8DD6670055EC8ED00166B93 = {
+                       explicitFileType = wrapper.cfbundle;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = iCalSaxDriver.sax;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8DD6673055EC8FD00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD6674055EC8FD00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD6675055EC8FD00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD6676055EC8FD00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXRezBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD6677055EC8FD00166B93 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8DD669A055EC9FF00166B93,
+                               AD1627A805D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8DD6678055EC8FD00166B93 = {
+                       buildPhases = (
+                               E8DD6673055EC8FD00166B93,
+                               E8DD6674055EC8FD00166B93,
+                               E8DD6675055EC8FD00166B93,
+                               E8DD6676055EC8FD00166B93,
+                               E8DD6677055EC8FD00166B93,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "pyxSAXDriver/pyxSAXDriver-Info.plist";
+                               INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = pyxSAXDriver;
+                               REZ_EXECUTABLE = NO;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                               WRAPPER_EXTENSION = sax;
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = pyxSAXDriver;
+                       productName = pyxSAXDriver;
+                       productReference = E8DD6679055EC8FD00166B93;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>pyxSAXDriver</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.pyxSAXDriver</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+       <key>CSResourcesFileMapped</key>
+       <string>yes</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.bundle";
+               };
+               E8DD6679055EC8FD00166B93 = {
+                       explicitFileType = wrapper.cfbundle;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = pyxSAXDriver.sax;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8DD667C055EC94800166B93 = {
+                       containerPortal = E8FEA8B7055170790031BF98;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = E8FEA8C7055170B60031BF98;
+                       remoteInfo = SaxObjC;
+               };
+               E8DD667D055EC94800166B93 = {
+                       isa = PBXTargetDependency;
+                       target = E8FEA8C7055170B60031BF98;
+                       targetProxy = E8DD667C055EC94800166B93;
+               };
+               E8DD6697055EC9EF00166B93 = {
+                       fileRef = E8FEA8C8055170B60031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8DD6698055EC9F900166B93 = {
+                       fileRef = E8FEA8C8055170B60031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8DD6699055EC9FC00166B93 = {
+                       fileRef = E8FEA8C8055170B60031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8DD669A055EC9FF00166B93 = {
+                       fileRef = E8FEA8C8055170B60031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA8B3055170790031BF98 = {
+                       children = (
+                               E857FDF705FC9D8A0026154C,
+                               AD16270D05D91EDF00A7368D,
+                               AD1626DE05D9127900A7368D,
+                               AD1626DF05D9127900A7368D,
+                               AD1626E005D9127900A7368D,
+                               AD1626E105D9127900A7368D,
+                               AD0CDFF405D950A8004D9B87,
+                               AD1626E205D9127900A7368D,
+                               E8FEA8E2055170F40031BF98,
+                               E816B3890551734B00058059,
+                               E816B38C0551735300058059,
+                               E8DD6638055EC7AD00166B93,
+                               E8DD6666055EC8C200166B93,
+                               E897275505F1661400B5B1A9,
+                               E8DD6667055EC8C900166B93,
+                               E8DD6668055EC8CE00166B93,
+                               ADDB713E05C066CF009DBFB4,
+                               E80DE02F05769AF00022D5D9,
+                               E8FEA8C9055170B60031BF98,
+                               AD16279F05D9358800A7368D,
+                       );
+                       isa = PBXGroup;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA8B5055170790031BF98 = {
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = "APPLE_RUNTIME=1 NeXT_Foundation_LIBRARY=1 COCOA_Foundation_LIBRARY=1 NeXT_RUNTIME=1 COMPILE_AS_FRAMEWORK=1 DEBUG=1";
+                       };
+                       isa = PBXBuildStyle;
+                       name = Development;
+               };
+               E8FEA8B7055170790031BF98 = {
+                       buildSettings = {
+                       };
+                       buildStyles = (
+                               E8FEA8B5055170790031BF98,
+                               AD52237E06A7EB7600B24132,
+                       );
+                       hasScannedForEncodings = 1;
+                       isa = PBXProject;
+                       mainGroup = E8FEA8B3055170790031BF98;
+                       productRefGroup = E8FEA8C9055170B60031BF98;
+                       projectDirPath = "";
+                       targets = (
+                               E8FEA8C7055170B60031BF98,
+                               E8FEA8D0055170C50031BF98,
+                               E8FEA8D8055170D40031BF98,
+                               ADDB70E905C06107009DBFB4,
+                               AD52238106A7EBDA00B24132,
+                               E8DD663F055EC7D100166B93,
+                               E8DD6662055EC8BB00166B93,
+                               E897275C05F1664A00B5B1A9,
+                               E8DD666F055EC8ED00166B93,
+                               E8DD6678055EC8FD00166B93,
+                               E80DE04405769B360022D5D9,
+                               E80DE04E05769B420022D5D9,
+                               E80DE05605769B4C0022D5D9,
+                               E816B60B05517A8C00058059,
+                               E816B51F055178BC00058059,
+                               E80DE07905769BC50022D5D9,
+                       );
+               };
+               E8FEA8C3055170B60031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8FEA96B055170F50031BF98,
+                               E8FEA98F055170F50031BF98,
+                               E8FEA991055170F50031BF98,
+                               E8FEA993055170F50031BF98,
+                               E8FEA994055170F50031BF98,
+                               E8FEA995055170F50031BF98,
+                               E8FEA997055170F50031BF98,
+                               E8FEA998055170F50031BF98,
+                               E8FEA999055170F50031BF98,
+                               E8FEA99A055170F50031BF98,
+                               E8FEA99B055170F50031BF98,
+                               E8FEA99D055170F50031BF98,
+                               E8FEA99F055170F50031BF98,
+                               E8FEA9A0055170F50031BF98,
+                               E8FEA9A2055170F50031BF98,
+                               E8FEA9A4055170F50031BF98,
+                               E8FEA9A6055170F50031BF98,
+                               E8FEA9A7055170F50031BF98,
+                               E8FEA9A9055170F50031BF98,
+                               E8FEA9AB055170F50031BF98,
+                               E8FEA9AD055170F50031BF98,
+                               E8FEA9AE055170F50031BF98,
+                               E8FEA9EB055170F60031BF98,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8C4055170B60031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8FEA96A055170F50031BF98,
+                               E8FEA96C055170F50031BF98,
+                               E8FEA96D055170F50031BF98,
+                               E8FEA96E055170F50031BF98,
+                               E8FEA96F055170F50031BF98,
+                               E8FEA970055170F50031BF98,
+                               E8FEA98E055170F50031BF98,
+                               E8FEA9E8055170F60031BF98,
+                               E8FEA9E9055170F60031BF98,
+                               E8FEA9EA055170F60031BF98,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8C5055170B60031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E8FEA990055170F50031BF98,
+                               E8FEA992055170F50031BF98,
+                               E8FEA996055170F50031BF98,
+                               E8FEA99C055170F50031BF98,
+                               E8FEA99E055170F50031BF98,
+                               E8FEA9A1055170F50031BF98,
+                               E8FEA9A3055170F50031BF98,
+                               E8FEA9A5055170F50031BF98,
+                               E8FEA9A8055170F50031BF98,
+                               E8FEA9AA055170F50031BF98,
+                               E8FEA9AC055170F50031BF98,
+                               E8FEA9AF055170F50031BF98,
+                               E885C6D4055EE27F00A13E26,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8C6055170B60031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               AD1627A105D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8C7055170B60031BF98 = {
+                       buildPhases = (
+                               E8FEA8C3055170B60031BF98,
+                               E8FEA8C4055170B60031BF98,
+                               E8FEA8C5055170B60031BF98,
+                               E8FEA8C6055170B60031BF98,
+                               AD52209506A7D5C500B24132,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = SaxObjC/common.h;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "SaxObjC/SaxObjC-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_LDFLAGS = "-seg1addr 0xC0000000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = SaxObjC;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = SaxObjC;
+                       productName = SaxObjC;
+                       productReference = E8FEA8C8055170B60031BF98;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SaxObjC</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.SaxObjC</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E8FEA8C8055170B60031BF98 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = SaxObjC.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8FEA8C9055170B60031BF98 = {
+                       children = (
+                               E8FEA8C8055170B60031BF98,
+                               E8FEA8D1055170C50031BF98,
+                               E8FEA8D9055170D40031BF98,
+                               E8DD6640055EC7D100166B93,
+                               E8DD6663055EC8BB00166B93,
+                               E8DD6670055EC8ED00166B93,
+                               E8DD6679055EC8FD00166B93,
+                               E80DE04505769B360022D5D9,
+                               E80DE04F05769B420022D5D9,
+                               E80DE05705769B4C0022D5D9,
+                               ADDB70EA05C06107009DBFB4,
+                               E897275D05F1664A00B5B1A9,
+                       );
+                       isa = PBXGroup;
+                       name = Products;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA8CC055170C50031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E816B3FA055173B100058059,
+                               E816B3FB055173B100058059,
+                               E816B3FD055173B100058059,
+                               E816B3FF055173B100058059,
+                               E816B400055173B100058059,
+                               E816B402055173B100058059,
+                               E816B404055173B100058059,
+                               E816B406055173B100058059,
+                               E816B408055173B100058059,
+                               E816B40B055173B100058059,
+                               E816B40C055173B100058059,
+                               E816B40E055173B100058059,
+                               E816B410055173B100058059,
+                               E816B412055173B100058059,
+                               E816B414055173B100058059,
+                               E816B416055173B100058059,
+                               E816B418055173B100058059,
+                               E816B419055173B100058059,
+                               E816B41B055173B100058059,
+                               E816B41E055173B100058059,
+                               E816B420055173B100058059,
+                               E816B422055173B100058059,
+                               E816B424055173B100058059,
+                               E816B427055173B100058059,
+                               E816B429055173B100058059,
+                               E816B42B055173B100058059,
+                               E816B42C055173B100058059,
+                               E816B42E055173B100058059,
+                               E816B430055173B100058059,
+                               E816B432055173B100058059,
+                               E816B434055173B100058059,
+                               E816B436055173B100058059,
+                               E816B438055173B100058059,
+                               E816B43A055173B100058059,
+                               E816B43C055173B100058059,
+                               E816B43E055173B100058059,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8CD055170C50031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E816B39A0551738C00058059,
+                               E816B39B0551738C00058059,
+                               E816B4580551742F00058059,
+                               E816B4590551742F00058059,
+                               E816B45A0551742F00058059,
+                               E816B45B0551742F00058059,
+                               E816B45C0551742F00058059,
+                               E816B45D0551742F00058059,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8CE055170C50031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E816B3FC055173B100058059,
+                               E816B3FE055173B100058059,
+                               E816B401055173B100058059,
+                               E816B403055173B100058059,
+                               E816B405055173B100058059,
+                               E816B407055173B100058059,
+                               E816B409055173B100058059,
+                               E816B40A055173B100058059,
+                               E816B40D055173B100058059,
+                               E816B40F055173B100058059,
+                               E816B411055173B100058059,
+                               E816B413055173B100058059,
+                               E816B415055173B100058059,
+                               E816B417055173B100058059,
+                               E816B41A055173B100058059,
+                               E816B41C055173B100058059,
+                               E816B41D055173B100058059,
+                               E816B41F055173B100058059,
+                               E816B421055173B100058059,
+                               E816B423055173B100058059,
+                               E816B425055173B100058059,
+                               E816B426055173B100058059,
+                               E816B428055173B100058059,
+                               E816B42A055173B100058059,
+                               E816B42D055173B100058059,
+                               E816B42F055173B100058059,
+                               E816B431055173B100058059,
+                               E816B433055173B100058059,
+                               E816B435055173B100058059,
+                               E816B437055173B100058059,
+                               E816B439055173B100058059,
+                               E816B43B055173B100058059,
+                               E816B43D055173B100058059,
+                               E816B43F055173B100058059,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8CF055170C50031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E816B48C055174C700058059,
+                               AD1627A205D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8D0055170C50031BF98 = {
+                       buildPhases = (
+                               E8FEA8CC055170C50031BF98,
+                               E8FEA8CD055170C50031BF98,
+                               E8FEA8CE055170C50031BF98,
+                               E8FEA8CF055170C50031BF98,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "DOM/DOM-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-seg1addr 0xC0200000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = DOM;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = DOM;
+                       productName = DOM;
+                       productReference = E8FEA8D1055170C50031BF98;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>DOM</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.DOM</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E8FEA8D1055170C50031BF98 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = DOM.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8FEA8D4055170D40031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E816B4F30551777700058059,
+                               E816B4F40551777700058059,
+                               E816B4F50551777700058059,
+                               E816B4F60551777700058059,
+                               E816B4F70551777700058059,
+                               E816B4F80551777700058059,
+                               E816B4F90551777700058059,
+                               E816B506055177A100058059,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8D5055170D40031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E816B4BA0551773900058059,
+                               E816B4BB0551773900058059,
+                               E816B505055177A100058059,
+                               E816B507055177A100058059,
+                               E816B508055177A100058059,
+                               E816B509055177A100058059,
+                               E816B50A055177A100058059,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8D6055170D40031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E816B4D40551775F00058059,
+                               E816B4D50551775F00058059,
+                               E816B4D60551775F00058059,
+                               E816B4D70551775F00058059,
+                               E816B4D80551775F00058059,
+                               E816B4D90551775F00058059,
+                               E816B4DA0551775F00058059,
+                               E816B4DB0551775F00058059,
+                               E816B4DC0551775F00058059,
+                               E816B4DD0551775F00058059,
+                               E816B4DE0551775F00058059,
+                               E816B4DF0551775F00058059,
+                               E816B4E00551775F00058059,
+                               E816B4E10551775F00058059,
+                               E816B4E20551775F00058059,
+                               E816B4E30551775F00058059,
+                               E816B4E80551775F00058059,
+                               E816B4E90551775F00058059,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8D7055170D40031BF98 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               E816B4FA0551778000058059,
+                               AD1627A305D935BE00A7368D,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               E8FEA8D8055170D40031BF98 = {
+                       buildPhases = (
+                               E8FEA8D4055170D40031BF98,
+                               E8FEA8D5055170D40031BF98,
+                               E8FEA8D6055170D40031BF98,
+                               E8FEA8D7055170D40031BF98,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               FRAMEWORK_VERSION = A;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Foundation.framework/Headers/Foundation.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "XmlRpc/XmlRpc-Info.plist";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               OTHER_CFLAGS = "-DHAVE_NSXMLPARSER=1";
+                               OTHER_LDFLAGS = "-seg1addr 0xC0400000 -headerpad_max_install_names";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = XmlRpc;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = XmlRpc;
+                       productName = XmlRpc;
+                       productReference = E8FEA8D9055170D40031BF98;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>XmlRpc</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.MySoftwareCompany.XmlRpc</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.framework";
+               };
+               E8FEA8D9055170D40031BF98 = {
+                       explicitFileType = wrapper.framework;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = XmlRpc.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               E8FEA8E2055170F40031BF98 = {
+                       children = (
+                               E8FEA8E4055170F40031BF98,
+                               E8FEA8E6055170F40031BF98,
+                               E8FEA909055170F40031BF98,
+                               E8FEA8E7055170F40031BF98,
+                               E8FEA966055170F50031BF98,
+                               E8FEA967055170F50031BF98,
+                               E816B383055171E500058059,
+                               E8FEA9F4055171170031BF98,
+                               E816B379055171A900058059,
+                               E816B37C055171B300058059,
+                       );
+                       isa = PBXGroup;
+                       path = SaxObjC;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA8E4055170F40031BF98 = {
+                       explicitFileType = text;
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       path = ChangeLog;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       tabWidth = 4;
+                       usesTabs = 1;
+               };
+               E8FEA8E5055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = common.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA8E6055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYING;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA8E7055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = COPYRIGHT;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA8E8055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA8E9055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = GNUmakefile.preamble;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA8EA055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = libSAXObjC.def;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA909055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = README;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA90A055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxAttributeList.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA90B055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxAttributeList.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA90C055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxAttributes.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA90D055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxAttributes.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA90E055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxContentHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA90F055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxDeclHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA910055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxDefaultHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA911055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxDefaultHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA912055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxDocumentHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA913055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxDTDHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA914055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxEntityResolver.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA915055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxErrorHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA916055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxException.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA917055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxException.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA918055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxHandlerBase.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA919055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxHandlerBase.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA91A055170F40031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxLexicalHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA91B055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxLocator.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA91C055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxLocator.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA91D055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxMethodCallHandler.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA91E055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxMethodCallHandler.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA91F055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxNamespaceSupport.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA920055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxNamespaceSupport.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA921055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxObjC.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA922055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxObjectDecoder.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA923055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxObjectDecoder.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA924055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxObjectModel.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA925055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxObjectModel.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA926055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxXMLFilter.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA927055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxXMLFilter.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA928055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxXMLReader.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA929055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = SaxXMLReaderFactory.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA92A055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = SaxXMLReaderFactory.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA965055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.xml;
+                       path = "SxXML-SaxObjC.graffle";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA966055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = TODO;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA967055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text;
+                       path = Version;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA968055170F50031BF98 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = XMLNamespaces.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               E8FEA96A055170F50031BF98 = {
+                       fileRef = E8FEA8E4055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA96B055170F50031BF98 = {
+                       fileRef = E8FEA8E5055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA96C055170F50031BF98 = {
+                       fileRef = E8FEA8E6055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA96D055170F50031BF98 = {
+                       fileRef = E8FEA8E7055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA96E055170F50031BF98 = {
+                       fileRef = E8FEA8E8055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA96F055170F50031BF98 = {
+                       fileRef = E8FEA8E9055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA970055170F50031BF98 = {
+                       fileRef = E8FEA8EA055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA98E055170F50031BF98 = {
+                       fileRef = E8FEA909055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA98F055170F50031BF98 = {
+                       fileRef = E8FEA90A055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA990055170F50031BF98 = {
+                       fileRef = E8FEA90B055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA991055170F50031BF98 = {
+                       fileRef = E8FEA90C055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA992055170F50031BF98 = {
+                       fileRef = E8FEA90D055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA993055170F50031BF98 = {
+                       fileRef = E8FEA90E055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA994055170F50031BF98 = {
+                       fileRef = E8FEA90F055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA995055170F50031BF98 = {
+                       fileRef = E8FEA910055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA996055170F50031BF98 = {
+                       fileRef = E8FEA911055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA997055170F50031BF98 = {
+                       fileRef = E8FEA912055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA998055170F50031BF98 = {
+                       fileRef = E8FEA913055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA999055170F50031BF98 = {
+                       fileRef = E8FEA914055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA99A055170F50031BF98 = {
+                       fileRef = E8FEA915055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA99B055170F50031BF98 = {
+                       fileRef = E8FEA916055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA99C055170F50031BF98 = {
+                       fileRef = E8FEA917055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA99D055170F50031BF98 = {
+                       fileRef = E8FEA918055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA99E055170F50031BF98 = {
+                       fileRef = E8FEA919055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA99F055170F50031BF98 = {
+                       fileRef = E8FEA91A055170F40031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9A0055170F50031BF98 = {
+                       fileRef = E8FEA91B055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9A1055170F50031BF98 = {
+                       fileRef = E8FEA91C055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA9A2055170F50031BF98 = {
+                       fileRef = E8FEA91D055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9A3055170F50031BF98 = {
+                       fileRef = E8FEA91E055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA9A4055170F50031BF98 = {
+                       fileRef = E8FEA91F055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9A5055170F50031BF98 = {
+                       fileRef = E8FEA920055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA9A6055170F50031BF98 = {
+                       fileRef = E8FEA921055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9A7055170F50031BF98 = {
+                       fileRef = E8FEA922055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9A8055170F50031BF98 = {
+                       fileRef = E8FEA923055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA9A9055170F50031BF98 = {
+                       fileRef = E8FEA924055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9AA055170F50031BF98 = {
+                       fileRef = E8FEA925055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA9AB055170F50031BF98 = {
+                       fileRef = E8FEA926055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9AC055170F50031BF98 = {
+                       fileRef = E8FEA927055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA9AD055170F50031BF98 = {
+                       fileRef = E8FEA928055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9AE055170F50031BF98 = {
+                       fileRef = E8FEA929055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9AF055170F50031BF98 = {
+                       fileRef = E8FEA92A055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA9E8055170F60031BF98 = {
+                       fileRef = E8FEA965055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA9E9055170F60031BF98 = {
+                       fileRef = E8FEA966055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA9EA055170F60031BF98 = {
+                       fileRef = E8FEA967055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               E8FEA9EB055170F60031BF98 = {
+                       fileRef = E8FEA968055170F50031BF98;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                                       Public,
+                               );
+                       };
+               };
+               E8FEA9F4055171170031BF98 = {
+                       children = (
+                               E8FEA8E8055170F40031BF98,
+                               E8FEA8E9055170F40031BF98,
+                               E8FEA8EA055170F40031BF98,
+                       );
+                       isa = PBXGroup;
+                       name = Makefiles;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+       };
+       rootObject = E8FEA8B7055170790031BF98;
+}
diff --git a/skyrix-xml/TODO b/skyrix-xml/TODO
new file mode 100644 (file)
index 0000000..6257cc3
--- /dev/null
@@ -0,0 +1,12 @@
+# $Id: TODO,v 1.3 2003/11/09 22:28:35 helge Exp $
+
+- add SAX wrapper for Parsifal ?
+  http://www.saunalahti.fi/~samiuus/toni/xmlproc/
+
+- add a DOM builder which can create a DOM from a libxml2 or
+  CoreFoundation DOM tree instead of using SAX
+  (should be much more efficient)
+
+- write a SAX driver based on NSXMLParser (should be an almost trivial 1:1
+  mapping)
+
diff --git a/skyrix-xml/Version b/skyrix-xml/Version
new file mode 100644 (file)
index 0000000..8393deb
--- /dev/null
@@ -0,0 +1,7 @@
+# $Id$
+#
+# This file is included by library makefiles to set the version information 
+# of the executable.
+
+MAJOR_VERSION=4
+MINOR_VERSION=2
diff --git a/skyrix-xml/XmlRpc/.cvsignore b/skyrix-xml/XmlRpc/.cvsignore
new file mode 100644 (file)
index 0000000..ff977db
--- /dev/null
@@ -0,0 +1,4 @@
+shared_debug_obj
+shared_obj
+*.framework
+derived_src
diff --git a/skyrix-xml/XmlRpc/COPYING b/skyrix-xml/XmlRpc/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-xml/XmlRpc/COPYRIGHT b/skyrix-xml/XmlRpc/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-xml/XmlRpc/ChangeLog b/skyrix-xml/XmlRpc/ChangeLog
new file mode 100644 (file)
index 0000000..cb390a7
--- /dev/null
@@ -0,0 +1,283 @@
+2004-06-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.21
+
+       * GNUmakefile.preamble: added prebinding info
+
+       * GNUmakefile: moved preamble stuff to GNUmakefile.preamble, also 
+         build XmlRpc.framework on non-libFoundation systems
+
+2004-05-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * XmlRpcDecoder.m: do not print a compile warning if NSXMLParser is 
+         used (on MacOSX) (v4.2.20)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.19)
+
+2003-11-19  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile: removed autodoc target
+
+2003-11-09  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.18
+
+       * XmlRpcDecoder.m: can use NSXMLParser for parsing, if available
+
+       * XmlRpcMethodResponse: now accepts an NSData object for parsing, this
+         avoids costly conversions between NSString and NSData for parsing
+         ...
+
+       * XmlRpcRequestDecoder.m, XmlRpcSaxHandler.m: added debug logging 
+         facilities
+
+2003-10-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * XmlRpcDecoder.m: fixed some Xcode warnings (v4.2.17)
+
+2003-08-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * fixed an MacOSX warning in XmlRpcEncoder (v4.2.16)
+
+2003-08-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.15
+       
+       * NSObject+XmlRpc.m: catch year-values bigger than 2033 or smaller than
+         1900 and transform them into something usable by libFoundation 
+         (problem exposed by JOGI)
+
+       * XmlRpcEncoder.m: moved string category to separate file
+       
+       * XmlRpcDecoder.m: smaller cleanups
+
+2003-08-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.14
+
+       * NSObject+XmlRpc.m: map XML-RPC "value" type to "NSString". This 
+         happens if the XML-RPC client does not send the "string" tag
+         (<value>abc</value> instead of <value><string>abc</string></value>)
+
+2003-07-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSNotification+XmlRpcCoding.m: use -name instead of -notificationName
+         to get the name of the notification for encoding (required for
+         gstep-base, Cocoa, also works on lF) (v4.2.13)
+
+2003-04-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcEncoder.m: fixed a bug in encode-datetime (wrong timezone was
+         used due to a bug in libFoundation), smaller speed optimizations
+         (v4.2.12)
+
+2003-02-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.11
+
+       * XmlRpcSaxHandler.m: if an incorrect fault object is returned, try to
+         transform it to a exception
+
+       * XmlRpcEncoder.m: renamed -appendHTMLString: to -appendXmlRpcString:,
+         added specialized methods for adding int and double members (since
+         performSelector:withObject: doesn't coerce arguments on Cocoa)
+
+2003-01-30  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcMethodCall.m: removed dependency on -shallowCopy (dependency
+         to EOControl being linked in ...) (v4.2.10)
+
+2003-01-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.9
+
+       * NSDate+XmlRpcCoding.m: fixed a warning on MacOSX
+
+       * common.h: removed dependency on FoundationExt on MacOSX
+
+Thu Jan  2 10:52:41 2003  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.8
+       
+       * common.h: defined ASSIGN macro if missing
+
+       * XmlRpcValue.m, XmlRpcDecoder.m: do not use AUTORELEASE macros
+
+Fri Dec 27 10:56:51 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcEncoder.m: added a new escaping function which works with
+         unicode strings (v4.2.7)
+
+2002-09-28  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed some compilation warnings (v4.2.6)
+
+2002-09-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * made docs AutoDoc compliant
+
+2002-08-08  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcDecoder.m: fixed major bugs in the XML-RPC decoding code,
+         when contained in structures, base types like int,bool resulted 
+         in a core dump (basetypes were handled like objects)
+
+2002-07-03  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSException+XmlRpcCoding.m: improved mapping of NSException's to
+         XML-RPC faults
+
+       * XmlRpcMethodResponse.m: added better -description
+
+Tue Jul  2 16:09:45 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * fixed a bug with exception encoding/decoding
+
+2002-07-01  Helge Hess  <helge.hess@skyrix.com>
+
+       * replaced -initWithXmlRpcDecoder: with -decodeObjectWithXmlRpcCoder:
+         due to a problem with releasing newly allocated objects in MacOSX
+
+Fri May 17 11:03:12 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcValue.m: added some stuff for the fix below
+
+       * XmlRpcSaxHandler.m: added a fixup to end_fault that turns 
+         NSDictionary XmlRpcValues into NSExceptions
+
+       * XmlRpcResponseDecoder.m: pass string directly to the parser, not an
+         NSData generated using NSASCIIStringEncoding ...
+
+Thu May  2 12:58:59 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * changed to use -rangeOfString: instead of -indexOfString:
+
+Thu Feb 28 15:16:21 2002  Jan41 Reichmann  <jan@skyrix.com>
+
+       * NSException+XmlRpcCoding.m: fixed encode bug
+
+Wed Feb 27 11:51:17 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added -xmlRpcType method to determine the "default" type which
+         will result in encoding the object as XML-RPC
+
+Tue Feb 26 10:18:50 2002  Bjoern Stierand  <bjoern@skyrix.com>
+
+       * XmlRpcEncoder.m: removed newlines created during en-/decoding
+
+Mon Feb 25 17:41:03 2002  Martin Spindler  <spindler@mdlink.de>
+
+       * XmlRpcSaxHandler.m: decode <value>test</value> as string
+
+Wed Feb 13 13:52:09 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved generic stuff to XML/XmlRpc
+
+Sat Feb  9 13:00:11 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcSaxHandler.m: added warning and error handlers ...
+
+       * XmlRpcDecoder.m: improved error output
+
+Fri Feb  8 17:35:05 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcDecoder.m: fixed charset problems
+
+Fri Feb  8 12:29:28 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpcIntrospection.m: changed to return "string"
+         signature for object types
+
+Thu Feb  7 20:19:55 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpc.m: autogenerate SandStorm component name
+
+Wed Jan 30 18:16:31 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpcIntrospection.m: fixed bug with method names
+
+       * NGXmlRpcInvocation.m: convert types prior to call, if signature
+         is available
+
+Tue Jan 29 18:30:56 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added NGXmlRpcInvocation, NGXmlRpcMethodSignature
+
+Mon Jan 28 18:46:34 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpc.m: improved reflection capabilities
+
+       * WODirectAction+XmlRpc.m: support a GET action for dynamic reflection
+
+       * WODirectAction+XmlRpc.m: added method to define component prefix
+
+Fri Jan 25 18:36:58 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * WODirectAction+XmlRpc.m: use RPC2 as action name ...
+
+       * added NGXmlRpcClient class
+
+Thu Jan 17 17:23:09 2002  Martin Spindler  <spindler@mdlink.de>
+
+       * NSObject+XmlRpc.m: raise exception if coding methods arn't supported
+
+Tue Nov 13 09:34:54 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * EOKeyGlobalID+XmlRpcCoding.m: removed unnecessary retain/autorelease
+
+Tue Nov 13 01:06:50 2001  Jan41 Reichmann  <jan@skyrix.com>
+
+       * EOKeyGlobalID+XmlRpcCoding.m: fixed decoding bug
+
+Wed Oct 24 13:23:54 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * XmlRpcSaxHandler.m: fixed multiple call of -characters:length:
+
+Mon Oct 22 20:53:33 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcEncoder.m: normalize NSString subclasses
+
+Mon Oct 22 18:20:54 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcMethodResponse+WO.m: enabled UTF-8 for result encoding
+
+Wed Oct 10 19:42:17 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * XmlRpcEncoder.m: use -classForCoder instead of -class
+
+Tue Aug 28 15:38:05 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * changed 'timeZone' - tag into 'timeZone' - attribute
+
+Tue Aug 28 14:21:54 2001  Martin Spindler  <spindler@mdlink.de>
+
+       * support of 'timeZone' - tag (not xmlprc compatible!)
+
+       * XmlRpcCoder: added accessors for defaultTimeZone
+
+Mon Aug 27 10:47:03 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved SKYRiX Logic categories back to skyxmlrpcd
+
+Wed Aug 22 15:41:39 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * XmlRpcDecoder.m: decode dates as calendar-dates
+
+Wed Aug 22 14:56:22 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * use ObjC base-types for decoding/encoding numbers
+
+Wed Aug 22 11:36:02 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * NSDate+XmlRpcCoding.m: fixed NSTimeZone decoding
+
+       * NSArray+XmlRpcCoding.m: fixed NSEnumerator coding, fixed RC bugs
+
+Mon Aug 20 21:55:41 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * created ChangeLog
+
diff --git a/skyrix-xml/XmlRpc/GNUmakefile b/skyrix-xml/XmlRpc/GNUmakefile
new file mode 100644 (file)
index 0000000..927f5e0
--- /dev/null
@@ -0,0 +1,49 @@
+# $Id$
+
+include ../common.make
+
+LIBRARY_NAME   = libXmlRpc
+FRAMEWORK_NAME = XmlRpc
+
+libXmlRpc_HEADER_FILES_DIR         = .
+libXmlRpc_HEADER_FILES_INSTALL_DIR = /XmlRpc
+libXmlRpc_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+
+libXmlRpc_HEADER_FILES = \
+       XmlRpc.h                        \
+       NSObject+XmlRpc.h               \
+       XmlRpcCoder.h                   \
+       XmlRpcMethodCall.h              \
+       XmlRpcMethodResponse.h          \
+
+libXmlRpc_OBJC_FILES = \
+       XmlRpcEncoder.m                 \
+       XmlRpcDecoder.m                 \
+       XmlRpcMethodCall.m              \
+       XmlRpcMethodResponse.m          \
+       XmlRpcSaxHandler.m              \
+       XmlRpcValue.m                   \
+       NSMutableString+XmlRpcDecoder.m \
+       \
+       NSArray+XmlRpcCoding.m          \
+       NSData+XmlRpcCoding.m           \
+       NSDate+XmlRpcCoding.m           \
+       NSDictionary+XmlRpcCoding.m     \
+       NSException+XmlRpcCoding.m      \
+       NSHost+XmlRpcCoding.m           \
+       NSNotification+XmlRpcCoding.m   \
+       NSNumber+XmlRpcCoding.m         \
+       NSObject+XmlRpc.m               \
+       NSString+XmlRpcCoding.m         \
+       NSURL+XmlRpcCoding.m            \
+
+XmlRpc_HEADER_FILES = $(libXmlRpc_HEADER_FILES)
+XmlRpc_OBJC_FILES   = $(libXmlRpc_OBJC_FILES)
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+
+ifeq ($(FOUNDATION_LIB),apple)
+include $(GNUSTEP_MAKEFILES)/framework.make
+endif
+-include GNUmakefile.postamble
diff --git a/skyrix-xml/XmlRpc/GNUmakefile.preamble b/skyrix-xml/XmlRpc/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..be24a68
--- /dev/null
@@ -0,0 +1,26 @@
+# $Id$
+
+libXmlRpc_LIBRARIES_DEPEND_UPON += -lSaxObjC -lDOM
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+libXmlRpc_LIB_DIRS += \
+       -L$(GNUSTEP_BUILD_DIR)/../SaxObjC/$(GNUSTEP_OBJ_DIR_NAME) \
+       -L$(GNUSTEP_BUILD_DIR)/../DOM/$(GNUSTEP_OBJ_DIR_NAME)
+else
+libXmlRpc_LIB_DIRS += \
+       -L../SaxObjC/$(GNUSTEP_OBJ_DIR) \
+       -L../DOM/$(GNUSTEP_OBJ_DIR)
+endif
+
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libXmlRpc_PREBIND_ADDR="0xC0400000"
+libXmlRpc_LDFLAGS += -seg1addr $(libXmlRpc_PREBIND_ADDR)
+
+#ADDITIONAL_INCLUDE_DIRS     += -framework SaxObjC
+XmlRpc_FRAMEWORK_LIBS        += -framework SaxObjC
+XmlRpc_LIBRARIES_DEPEND_UPON += -framework SaxObjC
+
+endif
diff --git a/skyrix-xml/XmlRpc/NSArray+XmlRpcCoding.m b/skyrix-xml/XmlRpc/NSArray+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..e0df43c
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "XmlRpcMethodResponse.h"
+#include "XmlRpcCoder.h"
+#include "NSObject+XmlRpc.h"
+#include "common.h"
+
+@implementation NSEnumerator(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"array";
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  NSMutableArray *objs;
+  id obj;
+  
+  /* make a copy to keep the enum state */
+  self = [self copy];
+  
+  objs = [[NSMutableArray alloc] initWithCapacity:16];
+  
+  while ((obj = [self nextObject]))
+    [objs addObject:obj];
+  
+  [_coder encodeArray:objs];
+  [objs release];
+  [self release];
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [[_coder decodeArray] objectEnumerator];
+}
+
+@end /* NSEnumerator(XmlRpc) */
+
+@implementation NSArray(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"array";
+}
+- (NSArray *)xmlRpcElementSignature {
+  unsigned i, count;
+  NSMutableArray *ma;
+  
+  if ((count = [self count]) == 0)
+    return [NSArray array];
+  
+  ma = [NSMutableArray arrayWithCapacity:count];
+  for (i = 0; i < count; i++)
+    [ma addObject:[[self objectAtIndex:i] xmlRpcType]];
+  return ma;
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeArray:self];
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [_coder decodeArray];
+}
+
+@end /* NSArray(XmlRpc) */
+
+@implementation NSSet(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"array";
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeArray:[self allObjects]];
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [NSSet setWithArray:[_coder decodeArray]];
+}
+
+@end /* NSSet(XmlRpcCoding) */
diff --git a/skyrix-xml/XmlRpc/NSData+XmlRpcCoding.m b/skyrix-xml/XmlRpc/NSData+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..8e12c96
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcMethodResponse.h"
+#include "common.h"
+#include "XmlRpcCoder.h"
+
+@implementation NSData(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"base64";
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeBase64:self];
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [_coder decodeBase64];
+}
+
+@end /* NSData(XmlRpcCoding) */
diff --git a/skyrix-xml/XmlRpc/NSDate+XmlRpcCoding.m b/skyrix-xml/XmlRpc/NSDate+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..9f4b9c8
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcMethodResponse.h"
+#include "NSObject+XmlRpc.h"
+#include "XmlRpcCoder.h"
+#import <Foundation/NSCalendarDate.h>
+#include "common.h"
+
+@implementation NSDate(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"dateTime.iso8601";
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeDateTime:self];
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [_coder decodeDateTime];
+}
+
+@end /* NSDate(XmlRpcCoding) */
+
+@implementation NSTimeZone(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"string";
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY
+  [_coder encodeString:[self name]];
+#else
+  [_coder encodeString:[self timeZoneName]];
+#endif
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [NSTimeZone timeZoneWithName:[_coder decodeString]];
+}
+
+@end /* NSTimeZone(XmlRpcCoding) */
diff --git a/skyrix-xml/XmlRpc/NSDictionary+XmlRpcCoding.m b/skyrix-xml/XmlRpc/NSDictionary+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..9ac094f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcMethodResponse.h"
+#include "NSObject+XmlRpc.h"
+#include "common.h"
+#include "XmlRpcCoder.h"
+
+@implementation NSDictionary(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"struct";
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeStruct:self];
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [_coder decodeStruct];
+}
+
+@end /* NSDictionary(XmlRpcCoding) */
diff --git a/skyrix-xml/XmlRpc/NSException+XmlRpcCoding.m b/skyrix-xml/XmlRpc/NSException+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..fc39358
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcMethodResponse.h"
+#include "common.h"
+#include "XmlRpcCoder.h"
+
+@implementation NSException(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"struct";
+}
+
+- (NSNumber *)xmlRpcFaultCode {
+  NSDictionary *ui;
+  id code;
+
+  ui = [self userInfo];
+  
+  if ((code = [ui objectForKey:@"XmlRpcFaultCode"]))
+    /* code is set */;
+  else if ((code = [ui objectForKey:@"faultCode"]))
+    /* code is set */;
+  else
+    code = [self name];
+  
+  return [NSNumber numberWithInt:[code intValue]];
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  int      code;
+  NSString *str, *n, *r;
+  NSDictionary *ui;
+  
+  code = [[self xmlRpcFaultCode] intValue];
+  
+  n = [self name];
+  r = [self reason];
+  
+  if ([n length] == 0)
+    str = r;
+  else if ([r length] == 0)
+    str = n;
+  else
+    str = [NSString stringWithFormat:@"%@: %@", n, r];
+  
+  if ((ui = [self userInfo]))
+    str = [NSString stringWithFormat:@"%@ %@", str, ui];
+  
+  [_coder encodeInt:code   forKey:@"faultCode"];
+  [_coder encodeString:str forKey:@"faultString"];
+}
+
++ (NSString *)exceptionNameForXmlRpcFaultCode:(int)_code {
+  return [NSString stringWithFormat:@"XmlRpcFault<%i>", _code];
+}
+- (NSString *)exceptionNameForXmlRpcFaultCode:(int)_code {
+  return [[self class] exceptionNameForXmlRpcFaultCode:_code];
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  int          code;
+  NSString     *r;
+  NSDictionary *ui;
+  
+  code = [_coder decodeIntForKey:@"faultCode"];
+  r    = [_coder decodeStringForKey:@"faultString"];
+  ui   = [NSDictionary dictionaryWithObjectsAndKeys:
+                         [NSNumber numberWithInt:code], @"faultCode",
+                         r, @"faultString",
+                         nil];
+  
+  return [self exceptionWithName:
+                 [self exceptionNameForXmlRpcFaultCode:code]
+               reason:r
+               userInfo:ui];
+}
+
+@end /* NSException(XmlRpcCoding) */
diff --git a/skyrix-xml/XmlRpc/NSHost+XmlRpcCoding.m b/skyrix-xml/XmlRpc/NSHost+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..874f245
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcMethodResponse.h"
+#include "NSObject+XmlRpc.h"
+#include "common.h"
+#include "XmlRpcCoder.h"
+
+@implementation NSHost(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"string";
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeString:[self name]];
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [NSHost hostWithName:[_coder decodeString]];
+}
+
+@end /* NSHost(XmlRpcCoding) */
diff --git a/skyrix-xml/XmlRpc/NSMutableString+XmlRpcDecoder.m b/skyrix-xml/XmlRpc/NSMutableString+XmlRpcDecoder.m
new file mode 100644 (file)
index 0000000..eb7a450
--- /dev/null
@@ -0,0 +1,138 @@
+// $Id$
+
+#include "common.h"
+
+@implementation NSMutableString(XmlRpcDecoder)
+
+- (void)appendXmlRpcString:(NSString *)_value {
+#if 1 // TODO: to be tested !
+  unsigned i, j, len;
+  BOOL     didEscape = NO;
+  unichar  *buf, *escbuf = NULL;
+  
+  if ((len = [_value length]) == 0)
+    /* nothing to add ... */
+    return;
+    
+  if (len == 1) {
+    /* a single char */
+    unichar c;
+    
+    switch ((c = [_value characterAtIndex:0])) {
+      case '&': [self appendString:@"&amp;"];  break;
+      case '<': [self appendString:@"&lt;"];   break;
+      case '>': [self appendString:@"&gt;"];   break;
+      case '"': [self appendString:@"&quot;"]; break;
+      default:  [self appendString:_value];    break;
+    }
+    return;
+  }
+  
+  buf = calloc(len + 2, sizeof(unichar));
+  [_value getCharacters:buf];
+  
+  for (i = 0, j = 0; i < len; i++) {
+    switch (buf[i]) {
+      case '&':
+      case '<':
+      case '>':
+      case '"': {
+        didEscape = YES;
+        if (escbuf == NULL) {
+          /* worst case: string consists of quotes */
+          escbuf = calloc(len * 6 + 2, sizeof(unichar));
+          memcpy(escbuf, buf, i * sizeof(unichar));
+          j = i;
+        }
+        escbuf[j++] = '&';
+        switch (buf[i]) {
+          case '&':
+            escbuf[j++] = 'a'; escbuf[j++] = 'm'; escbuf[j++] = 'p';
+            break;
+          case '<':
+            escbuf[j++] = 'l'; escbuf[j++] = 't';
+            break;
+          case '>':
+            escbuf[j++] = 'g'; escbuf[j++] = 't';
+            break;
+          case '"':
+            escbuf[j++] = 'q'; escbuf[j++] = 'u';
+            escbuf[j++] = 'o'; escbuf[j++] = 't';
+            break;
+        }
+        escbuf[j++] = ';';
+        break;
+      }
+      default:
+        if (escbuf)
+          escbuf[j++] = buf[i];
+        break;
+    }
+  }
+  
+  if (escbuf) {
+    NSString *s;
+    
+    s = [[NSString alloc] initWithCharacters:escbuf length:j];
+    [self appendString:s];
+    [s release];
+    free(escbuf);
+  }
+  else
+    [self appendString:_value];
+  
+  if (buf) free(buf);
+#else
+#warning UNICODE !!!
+  void (*addBytes)(id,SEL,const char *,unsigned);
+  id            dummy = nil;
+  unsigned      clen;
+  unsigned char *cbuf;
+  unsigned char *cstr;
+
+  if ([_value length] == 0) return;
+
+  clen = [_value cStringLength];
+  if (clen == 0) return; /* nothing to add .. */
+  
+  cbuf = cstr = malloc(clen + 1);
+  [_value getCString:cbuf]; cbuf[clen] = '\0';
+  dummy = [[NSMutableData alloc] initWithCapacity:2*clen];
+
+  addBytes = (void*)[dummy methodForSelector:@selector(appendBytes:length:)];
+  NSAssert(addBytes != NULL, @"could not get appendBytes:length: ..");
+  
+  while (*cstr) {
+    switch (*cstr) {
+      case '&':
+        addBytes(dummy, @selector(appendBytes:length:), "&amp;", 5);
+        break;
+      case '<':
+        addBytes(dummy, @selector(appendBytes:length:), "&lt;", 4);
+        break;
+      case '>':
+        addBytes(dummy, @selector(appendBytes:length:), "&gt;", 4);
+        break;
+      case '"':
+        addBytes(dummy, @selector(appendBytes:length:), "&quot;", 6);
+        break;
+      
+      default:
+        addBytes(dummy, @selector(appendBytes:length:), cstr, 1);
+        break;
+    }
+    cstr++;
+  }
+  free(cbuf);
+  {
+    NSString *tmp = nil;
+    
+    tmp = [[NSString alloc] initWithData:dummy
+                            encoding:[NSString defaultCStringEncoding]];
+    [self appendString:tmp];
+    [tmp release];
+  }
+#endif
+}
+
+@end /* NSMutableString(XmlRpcDecoder) */
diff --git a/skyrix-xml/XmlRpc/NSNotification+XmlRpcCoding.m b/skyrix-xml/XmlRpc/NSNotification+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..e3c0eae
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcMethodResponse.h"
+#include "common.h"
+#include "XmlRpcCoder.h"
+
+@implementation NSNotification(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"struct";
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  self = [NSNotification notificationWithName:
+                           [_coder decodeStringForKey:@"name"]
+                         object:[_coder decodeObjectForKey:@"object"]
+                         userInfo:[_coder decodeStructForKey:@"userInfo"]];
+  return self;
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  NSString *n;
+  
+  n = [self name];
+  [_coder encodeString:n               forKey:@"name"];
+  [_coder encodeObject:[self object]   forKey:@"object"];
+  [_coder encodeStruct:[self userInfo] forKey:@"userInfo"];
+}
+
+@end /* NSNotification(XmlRpcCoding) */
diff --git a/skyrix-xml/XmlRpc/NSNumber+XmlRpcCoding.m b/skyrix-xml/XmlRpc/NSNumber+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..2ddbeca
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcMethodResponse.h"
+#include "NSObject+XmlRpc.h"
+#include "XmlRpcCoder.h"
+#include "common.h"
+
+#if LIB_FOUNDATION_LIBRARY
+#  include <Foundation/NSConcreteNumber.h>
+#endif
+
+#define BOOLEAN_TYPE 0
+#define INTEGER_TYPE 1
+#define DOUBLE_TYPE  2
+
+@implementation NSNumber(XmlRpcCoding)
+
+- (unsigned int)_xmlRpcNumberType {
+  static Class BoolClass = Nil;
+
+  if (BoolClass == Nil)
+    BoolClass = NSClassFromString(@"NSBoolNumber");
+
+  if ([self isKindOfClass:BoolClass])
+    return BOOLEAN_TYPE;
+  
+  switch (*[self objCType]) {
+    case 'i':
+    case 'I':
+    case 'c':
+    case 'C':
+    case 's':
+    case 'S':
+    case 'l':
+    case 'L':
+      return INTEGER_TYPE;
+      
+    case 'f':
+    case 'd':
+    default:
+      return DOUBLE_TYPE;
+  }
+}
+
+- (NSString *)xmlRpcType {
+  switch ([self _xmlRpcNumberType]) {
+    case BOOLEAN_TYPE:
+      return @"boolean";
+    case DOUBLE_TYPE:
+      return @"double";
+    default: /* INTEGER_TYPE */
+      return @"i4";
+  }
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  switch ([self _xmlRpcNumberType]) {
+    case BOOLEAN_TYPE:
+      [_coder encodeBoolean:[self boolValue]];
+      break;
+    case DOUBLE_TYPE:
+      [_coder encodeDouble:[self doubleValue]];
+      break;
+    default: /* INTEGER_TYPE */
+      [_coder encodeInt:[self intValue]];
+  }
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [NSNumber numberWithInt:[_coder decodeInt]];
+}
+
+@end /* NSNumber(XmlRpcCoding) */
+
+#if LIB_FOUNDATION_LIBRARY
+
+@implementation NSBoolNumber(XmlRpcCoding)
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [[[NSNumber alloc] initWithBool:[_coder decodeBoolean]] autorelease];
+}
+
+- (NSString *)xmlRpcType {
+  return @"boolean";
+}
+
+@end /* NSBoolNumber(XmlRpcCoding) */
+
+// nicht notwendig, nur BOOL muss speziell abgefangen werden ??? :
+@implementation NSFloatNumber(XmlRpcCoding)
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [[[NSNumber alloc] initWithDouble:[_coder decodeDouble]] autorelease];
+}
+
+- (NSString *)xmlRpcType {
+  return @"double";
+}
+
+@end /* NSFloatNumber(XmlRpcCoding) */
+
+@implementation NSDoubleNumber(XmlRpcCoding)
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [[[NSNumber alloc] initWithDouble:[_coder decodeDouble]] autorelease];
+}
+
+- (NSString *)xmlRpcType {
+  return @"double";
+}
+
+@end /* NSDoubleNumber(XmlRpcCoding) */
+
+#endif
diff --git a/skyrix-xml/XmlRpc/NSObject+XmlRpc.h b/skyrix-xml/XmlRpc/NSObject+XmlRpc.h
new file mode 100644 (file)
index 0000000..68d5c36
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __NSObject_XMLRPC_H__
+#define __NSObject_XMLRPC_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSArray.h>
+
+@interface NSObject(XmlRpcValues)
+
++ (id)objectWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars length:(int)_len;
+
+@end
+
+@interface NSObject(XmlRpcSignatures)
+- (NSString *)xmlRpcType;
+@end
+
+@interface NSArray(XmlRpcSignatures)
+- (NSArray *)xmlRpcElementSignature;
+@end
+
+#endif /* __NSObject_XMLRPC_H__ */
diff --git a/skyrix-xml/XmlRpc/NSObject+XmlRpc.m b/skyrix-xml/XmlRpc/NSObject+XmlRpc.m
new file mode 100644 (file)
index 0000000..99c4779
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <XmlRpc/XmlRpcMethodResponse.h>
+#include <XmlRpc/XmlRpcCoder.h>
+#include <XmlRpc/NSObject+XmlRpc.h>
+#include "common.h"
+
+@interface NSObject(Misc)
+- (id)initWithString:(NSString *)_s;
+@end
+
+@interface NSString(XmlRpcParsing)
+- (id)initWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars
+  length:(int)_len;
+@end
+
+@interface NSDate(XmlRpcParsing)
+- (id)initWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars
+  length:(int)_len;
+@end
+
+@interface NSNumber(XmlRpcParsing)
+- (id)initWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars
+  length:(int)_len;
+@end
+
+@interface NSData(XmlRpcParsing)
+- (id)initWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars
+  length:(int)_len;
+@end
+
+@interface NSData(UsedNGExtensions)
+- (NSData *)dataByDecodingBase64;
+@end
+
+@implementation NSObject(XmlRpcParsing)
+
+- (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  NSClassDescription *cd;
+  
+  if ((cd = [self classDescription])) {
+    NSEnumerator *e;
+    NSString     *k;
+
+    if ((self = [self init])) {
+      e = [[cd attributeKeys] objectEnumerator];
+      while ((k = [e nextObject]))
+        [self takeValue:[_coder decodeObjectForKey:k] forKey:k];
+    
+      e = [[cd toOneRelationshipKeys] objectEnumerator];
+      while ((k = [e nextObject]))
+        [self takeValue:[_coder decodeObjectForKey:k] forKey:k];
+    
+      e = [[cd toManyRelationshipKeys] objectEnumerator];
+      while ((k = [e nextObject]))
+        [self takeValue:[_coder decodeArrayForKey:k] forKey:k];
+    }
+  }
+  else if ([self respondsToSelector:@selector(initWithString:)]) {
+    self = [(id)self initWithString:[_coder decodeString]];
+  }
+  else {
+    [NSException raise:@"XmlRpcCodingException"
+                 format:
+                 @"in initWithXmlRpcCoder: cannot decode class '%@'",
+                 NSStringFromClass([self class])];
+    [self release];
+    return nil;
+  }
+  return self;
+}
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_decoder {
+  return [[[self alloc] initWithXmlRpcCoder:_decoder] autorelease];
+}
+
+- (NSString *)xmlRpcType {
+  return @"struct";
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  NSClassDescription *cd;
+  
+  if ((cd = [self classDescription])) {
+    NSEnumerator *e;
+    NSString     *k;
+    
+    e = [[cd attributeKeys] objectEnumerator];
+    while ((k = [e nextObject]))
+      [_coder encodeObject:[self valueForKey:k] forKey:k];
+    
+    e = [[cd toOneRelationshipKeys] objectEnumerator];
+    while ((k = [e nextObject]))
+      [_coder encodeObject:[self valueForKey:k] forKey:k];
+    
+    e = [[cd toManyRelationshipKeys] objectEnumerator];
+    while ((k = [e nextObject]))
+      [_coder encodeArray:[self valueForKey:k] forKey:k];
+  }
+  else if ([self respondsToSelector:@selector(initWithString:)]) {
+    [_coder encodeString:[self description]];
+  }
+  else {
+    [NSException raise:@"XmlRpcCodingException"
+                 format:
+                   @"in encodeWithXmlRpcCoder: "
+                   @"cannot encode class '%@', object=%@B",
+                 NSStringFromClass([self class]), self];
+  }
+}
+
++ (id)objectWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars length:(int)_len
+{
+  static NSDictionary *typeToClass = nil;
+  Class ObjClass = Nil;
+  id obj;
+  
+  if (typeToClass == nil) {
+    typeToClass = [[NSDictionary alloc] initWithObjectsAndKeys:
+                                          [NSNumber class], @"i4",
+                                          [NSNumber class], @"int",
+                                          [NSNumber class], @"double",
+                                          [NSNumber class], @"boolean",
+                                          [NSString class], @"string",
+                                          [NSString class], @"value",
+                                          [NSData   class], @"base64",
+                                          [NSCalendarDate class],
+                                          @"dateTime.iso8601",
+                                          nil];
+  }
+  
+  /* determine basetype class */
+  
+  if ((ObjClass = [typeToClass objectForKey:_type]) == Nil) {
+    NSLog(@"WARNING(%s): unknown XML-RPC type '%@', using String ...",
+          __PRETTY_FUNCTION__, _type);
+    ObjClass = [NSString class];
+  }
+  
+  /* construct object */
+  
+  obj =
+    [[ObjClass alloc] initWithXmlRpcType:_type characters:_chars length:_len];
+  return [obj autorelease];
+}
+
+- (id)initWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars length:(int)_len
+{
+  if ([self respondsToSelector:@selector(initWithString:)]) {
+    NSString *s;
+
+    s = [[NSString alloc] initWithCharacters:_chars length:_len];
+    self = [self initWithString:s];
+    [s release];
+    return self;
+  }
+  
+  /* don't know how to init with given type ... */
+  [self release];
+  return nil;
+}
+
+@end /* NSObject(XmlRpc) */
+
+@implementation NSData(XmlRpcParsing)
+
+/* NSData represents the xml-rpc base type 'base64' */
+
+- (id)initWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars length:(int)_len
+{
+  NSString *v;
+
+  [self release]; self = nil;
+  
+  v    = [NSString stringWithCharacters:_chars length:_len];
+  self = [v dataUsingEncoding:NSUTF8StringEncoding];
+  
+  if ([_type isEqualToString:@"base64"])
+    self = [self dataByDecodingBase64];
+  
+  return [self copy];
+}
+
+@end /* NSData(XmlRpcParsing) */
+
+@implementation NSDate(XmlRpcParsing)
+
+/* NSDate represents the xml-rpc type dateTime.iso8601: */
+- (id)initWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars length:(int)_len
+{
+  /* eg 19980717T14:08:55 */
+  if (_len < 17) {
+    [self release];
+    return nil;
+  }
+  
+  {
+    unsigned char buf[8];
+    int year, month, day, hour, min, sec;
+        
+    buf[0] = _chars[0]; buf[1] = _chars[1];
+    buf[2] = _chars[2]; buf[3] = _chars[3];
+    buf[4] = '\0';
+    year = atoi(buf);
+    buf[0] = _chars[4]; buf[1] = _chars[5]; buf[2] = '\0';
+    month = atoi(buf);
+    buf[0] = _chars[6]; buf[1] = _chars[7]; buf[2] = '\0';
+    day = atoi(buf);
+
+    buf[0] = _chars[9]; buf[1] = _chars[10]; buf[2] = '\0';
+    hour = atoi(buf);
+    buf[0] = _chars[12]; buf[1] = _chars[13]; buf[2] = '\0';
+    min = atoi(buf);
+    buf[0] = _chars[15]; buf[1] = _chars[16]; buf[2] = '\0';
+    sec = atoi(buf);
+    
+    if (year > 2033) {
+      NSString *s;
+
+      s = [[NSString alloc] initWithCharacters:_chars length:_len];
+      NSLog(@"WARNING: got a date value '%@' with year >2033, "
+            @"which cannot be represented, silently using 2033  ...",
+            s);
+      [s release];
+      year = 2033;
+    }
+    else if (year < 1900) {
+      NSString *s;
+
+      s = [[NSString alloc] initWithCharacters:_chars length:_len];
+      NSLog(@"WARNING: got a date value '%@' with year < 1900, "
+            @"which cannot be represented, silently using 1900  ...",
+            s);
+      [s release];
+      year = 1900;
+    }
+    
+    if (![self isKindOfClass:[NSCalendarDate class]]) {
+      [self release];
+      self = [NSCalendarDate alloc];
+    }
+    
+    return [(NSCalendarDate *)self
+                              initWithYear:year month:month day:day
+                              hour:hour minute:min second:sec
+                              timeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
+  }
+}
+
+@end /* NSDate(XmlRpcParsing) */
+
+@implementation NSNumber(XmlRpcParsing)
+
+/* NSNumber represents the xml-rpc base types: 'int', 'double', 'boolean': */
+
+- (id)initWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars length:(int)_len
+{
+  if ([_type isEqualToString:@"boolean"]) {
+    BOOL v;
+      
+    v = (_len > 0)
+      ? ((_chars[0] == '1') ? YES : NO)
+      : NO;
+    return [self initWithBool:v];
+  }
+  else {
+    NSString *v;
+    BOOL isInt = NO;
+    
+    v = [NSString stringWithCharacters:_chars length:_len];
+    
+    if ([_type isEqualToString:@"i4"] || [_type isEqualToString:@"int"])
+      isInt = YES;
+    else if ([_type isEqualToString:@"double"])
+      isInt = NO;
+    else
+      isInt = ([v rangeOfString:@"."].length == 0) ? YES : NO;
+    
+    return isInt
+      ? [self initWithInt:[v intValue]]
+      : [self initWithDouble:[v doubleValue]];
+  }
+}
+
+@end /* NSNumber(XmlRpcParsing */
+
+
+@implementation NSString(XmlRpcParsing)
+
+- (id)initWithXmlRpcType:(NSString *)_type
+  characters:(unichar *)_chars length:(int)_len
+{
+  /* this is *never* called, since NSString+alloc returns a NSTemporaryString*/
+  return [self initWithCharacters:_chars length:_len];
+}
+
+@end /* NSString(XmlRpcParsing) */
diff --git a/skyrix-xml/XmlRpc/NSString+XmlRpcCoding.m b/skyrix-xml/XmlRpc/NSString+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..5d41a04
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcMethodResponse.h"
+#include "NSObject+XmlRpc.h"
+#include "XmlRpcCoder.h"
+#include "common.h"
+
+@implementation NSString(XmlRpcCoding)
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [_coder decodeString];
+}
+
+- (NSString *)xmlRpcType {
+  return @"string";
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeString:self];
+}
+
+@end /* NSString(XmlRpcCoding) */
diff --git a/skyrix-xml/XmlRpc/NSURL+XmlRpcCoding.m b/skyrix-xml/XmlRpc/NSURL+XmlRpcCoding.m
new file mode 100644 (file)
index 0000000..fc5f161
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcMethodResponse.h"
+#include "NSObject+XmlRpc.h"
+#include "XmlRpcCoder.h"
+#include "common.h"
+
+@implementation NSURL(XmlRpcCoding)
+
+- (NSString *)xmlRpcType {
+  return @"string";
+}
+
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
+  [_coder encodeString:[self absoluteString]];
+}
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
+  return [self URLWithString:[_coder decodeString]];
+}
+
+@end /* NSURL(XmlRpcCoding) */
diff --git a/skyrix-xml/XmlRpc/SxXML-XmlRpc.graffle b/skyrix-xml/XmlRpc/SxXML-XmlRpc.graffle
new file mode 100644 (file)
index 0000000..d6d5758
--- /dev/null
@@ -0,0 +1,627 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+       <key>CanvasColor</key>
+       <dict>
+               <key>w</key>
+               <real>1.000000e+00</real>
+       </dict>
+       <key>ColumnAlign</key>
+       <integer>0</integer>
+       <key>ColumnSpacing</key>
+       <real>5.400000e+01</real>
+       <key>GraphDocumentVersion</key>
+       <integer>2</integer>
+       <key>GraphicsList</key>
+       <array>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{15, 13}, {101, 36}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>FitText</key>
+                       <string>YES</string>
+                       <key>ID</key>
+                       <integer>1012</integer>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>shadow</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>Draws</key>
+                                       <string>NO</string>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\i\b\fs48 \cf0 XmlRpc}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{284, 207}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1011</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/XmlRpc/XmlRpcMethodResponse.h</string>
+                       </dict>
+                       <key>Magnets</key>
+                       <array>
+                               <string>{0.5, 0}</string>
+                               <string>{-0.5, 0}</string>
+                       </array>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 XmlRpcMethodResponse}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{284, 180}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1010</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/XmlRpc/XmlRpcValue.h</string>
+                       </dict>
+                       <key>Magnets</key>
+                       <array>
+                               <string>{0.5, 0}</string>
+                               <string>{-0.5, 0}</string>
+                       </array>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 XmlRpcValue}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{284, 261}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1009</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/SaxObjC/SaxDefaultHandler.h</string>
+                       </dict>
+                       <key>Magnets</key>
+                       <array>
+                               <string>{0.5, 0}</string>
+                               <string>{-0.5, 0}</string>
+                       </array>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>5.000000e-01</real>
+                                               <key>g</key>
+                                               <real>1.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 SaxDefaultHandler}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{477, 261}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1008</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/XmlRpc/XmlRpcSaxHandler.h</string>
+                       </dict>
+                       <key>Magnets</key>
+                       <array>
+                               <string>{0.5, 0}</string>
+                               <string>{-0.5, 0}</string>
+                       </array>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 XmlRpcSaxHandler}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{284, 153}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1007</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/XmlRpc/XmlRpcMethodCall.h</string>
+                       </dict>
+                       <key>Magnets</key>
+                       <array>
+                               <string>{0.5, 0}</string>
+                               <string>{-0.5, 0}</string>
+                       </array>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 XmlRpcMethodCall}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{284, 126}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1006</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/XmlRpc/XmlRpcCoder.h</string>
+                       </dict>
+                       <key>Magnets</key>
+                       <array>
+                               <string>{0.5, 0}</string>
+                               <string>{-0.5, 0}</string>
+                       </array>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 XmlRpcEncoder}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{284, 99}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1005</integer>
+                       <key>Link</key>
+                       <dict>
+                               <key>url</key>
+                               <string>file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-xml-42/XmlRpc/XmlRpcCoder.h</string>
+                       </dict>
+                       <key>Magnets</key>
+                       <array>
+                               <string>{0.5, 0}</string>
+                               <string>{-0.5, 0}</string>
+                       </array>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 XmlRpcDecoder}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Bounds</key>
+                       <string>{{63, 153}, {167, 18}}</string>
+                       <key>Class</key>
+                       <string>ShapedGraphic</string>
+                       <key>ID</key>
+                       <integer>1004</integer>
+                       <key>Magnets</key>
+                       <array>
+                               <string>{0.5, 0}</string>
+                               <string>{-0.5, 0}</string>
+                       </array>
+                       <key>Shape</key>
+                       <string>Rectangle</string>
+                       <key>Style</key>
+                       <dict>
+                               <key>fill</key>
+                               <dict>
+                                       <key>Color</key>
+                                       <dict>
+                                               <key>b</key>
+                                               <real>5.000000e-01</real>
+                                               <key>g</key>
+                                               <real>1.000000e+00</real>
+                                               <key>r</key>
+                                               <real>1.000000e+00</real>
+                                       </dict>
+                               </dict>
+                       </dict>
+                       <key>Text</key>
+                       <dict>
+                               <key>Text</key>
+                               <string>{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 NSObject}</string>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1011</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1003</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{230, 162}</string>
+                               <string>{284, 216}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>LineType</key>
+                                       <integer>2</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1004</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1010</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1002</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{230, 162}</string>
+                               <string>{284, 189}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>LineType</key>
+                                       <integer>2</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1004</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1009</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1001</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{230, 162}</string>
+                               <string>{284, 270}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>LineType</key>
+                                       <integer>2</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1004</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1008</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>1000</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{451, 270}</string>
+                               <string>{477, 270}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>LineType</key>
+                                       <integer>2</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1009</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1007</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>999</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{230, 162}</string>
+                               <string>{284, 162}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>LineType</key>
+                                       <integer>2</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1004</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1006</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>998</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{230, 162}</string>
+                               <string>{284, 135}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>LineType</key>
+                                       <integer>2</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1004</integer>
+                       </dict>
+               </dict>
+               <dict>
+                       <key>Class</key>
+                       <string>LineGraphic</string>
+                       <key>Head</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1005</integer>
+                       </dict>
+                       <key>ID</key>
+                       <integer>997</integer>
+                       <key>Points</key>
+                       <array>
+                               <string>{230, 162}</string>
+                               <string>{284, 108}</string>
+                       </array>
+                       <key>Style</key>
+                       <dict>
+                               <key>stroke</key>
+                               <dict>
+                                       <key>HeadArrow</key>
+                                       <string>0</string>
+                                       <key>LineType</key>
+                                       <integer>2</integer>
+                                       <key>TailArrow</key>
+                                       <string>0</string>
+                               </dict>
+                       </dict>
+                       <key>Tail</key>
+                       <dict>
+                               <key>ID</key>
+                               <integer>1004</integer>
+                       </dict>
+               </dict>
+       </array>
+       <key>GridInfo</key>
+       <dict/>
+       <key>HPages</key>
+       <integer>1</integer>
+       <key>ImageCounter</key>
+       <integer>1</integer>
+       <key>IsPalette</key>
+       <string>NO</string>
+       <key>Layers</key>
+       <array>
+               <dict>
+                       <key>Lock</key>
+                       <string>NO</string>
+                       <key>Name</key>
+                       <string>Layer 1</string>
+                       <key>Print</key>
+                       <string>YES</string>
+                       <key>View</key>
+                       <string>YES</string>
+               </dict>
+       </array>
+       <key>LayoutInfo</key>
+       <dict>
+               <key>AutoAdjust</key>
+               <string>YES</string>
+               <key>HierarchicalOrientation</key>
+               <integer>0</integer>
+               <key>MagneticFieldCenter</key>
+               <string>{0, 0}</string>
+       </dict>
+       <key>MagnetsEnabled</key>
+       <string>YES</string>
+       <key>PageBreakColor</key>
+       <dict>
+               <key>w</key>
+               <real>3.333333e-01</real>
+       </dict>
+       <key>PageBreaks</key>
+       <string>YES</string>
+       <key>PageSetup</key>
+       <data>
+       BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE
+       hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpEpKEhIQITlNT
+       dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE
+       mZkOTlNCb3R0b21NYXJnaW6GkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVlAJSEASqEhAFm
+       nSSGkoSZmQtOU1BhcGVyTmFtZYaShJmZBkxldHRlcoaShJmZD05TUHJpbnRBbGxQYWdl
+       c4aShJ2chIQBY54AhpKEmZkNTlNSaWdodE1hcmdpboaShJ2cn50khpKEmZkITlNDb3Bp
+       ZXOGkoSdnISEAVOfAYaShJmZD05TU2NhbGluZ0ZhY3RvcoaShJ2chIQBZKABhpKEmZkL
+       TlNGaXJzdFBhZ2WGkoSdnKmfAYaShJmZFE5TVmVydGljYWxQYWdpbmF0aW9uhpKEnZyE
+       hAFzoQCGkoSZmRVOU0hvcml6b25hbFBhZ2luYXRpb26GkoSdnLGhAIaShJmZFk5TSG9y
+       aXpvbnRhbGx5Q2VudGVyZWSGkoSdnKSeAYaShJmZDE5TTGVmdE1hcmdpboaShJ2cn50k
+       hpKEmZkNTlNPcmllbnRhdGlvboaShJ2csaEBhpKEmZkZTlNQcmludFJldmVyc2VPcmll
+       bnRhdGlvboaSo5KEmZkKTlNMYXN0UGFnZYaShJ2chJeXgn////+GkoSZmQtOU1RvcE1h
+       cmdpboaShJ2cn50khpKEmZkUTlNWZXJ0aWNhbGx5Q2VudGVyZWSGkrWShJmZC05TUGFw
+       ZXJTaXplhpKEnpyEhAx7X05TU2l6ZT1mZn2igQMYgQJkhoaG
+       </data>
+       <key>RowAlign</key>
+       <integer>0</integer>
+       <key>RowSpacing</key>
+       <real>9.000000e+00</real>
+       <key>VPages</key>
+       <integer>1</integer>
+       <key>WindowInfo</key>
+       <dict>
+               <key>Frame</key>
+               <string>{{67, 90}, {826, 833}}</string>
+               <key>VisibleRegion</key>
+               <string>{{-44.5, -108}, {811, 756}}</string>
+               <key>Zoom</key>
+               <string>1</string>
+       </dict>
+</dict>
+</plist>
diff --git a/skyrix-xml/XmlRpc/Version b/skyrix-xml/XmlRpc/Version
new file mode 100644 (file)
index 0000000..49f242e
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=21
diff --git a/skyrix-xml/XmlRpc/XmlRpc-Info.plist b/skyrix-xml/XmlRpc/XmlRpc-Info.plist
new file mode 100644 (file)
index 0000000..3ca3f2e
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>XmlRpc</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.skyrix.xml.XmlRpc</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+</dict>
+</plist>
diff --git a/skyrix-xml/XmlRpc/XmlRpc.h b/skyrix-xml/XmlRpc/XmlRpc.h
new file mode 100644 (file)
index 0000000..a344c0f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __XmlRpc_XmlRpc_H__
+#define __XmlRpc_XmlRpc_H__
+
+#include <XmlRpc/NSObject+XmlRpc.h>
+#include <XmlRpc/XmlRpcCoder.h>
+#include <XmlRpc/XmlRpcMethodCall.h>
+#include <XmlRpc/XmlRpcMethodResponse.h>
+
+#endif /* __XmlRpc_XmlRpc_H__ */
diff --git a/skyrix-xml/XmlRpc/XmlRpcCoder.h b/skyrix-xml/XmlRpc/XmlRpcCoder.h
new file mode 100644 (file)
index 0000000..92ae18b
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __XmlRpc_XmlRpcCoder_H__
+#define __XmlRpc_XmlRpcCoder_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSDictionary, NSArray, NSNumber, NSString, NSCalendarDate, NSData;
+@class NSMutableArray, NSMutableString, NSTimeZone, NSDate;
+@class XmlRpcValue, XmlRpcMethodCall, XmlRpcMethodResponse;
+
+/*"
+  The XmlRpcEncoder is used to encode XML-RPC objects. It's pretty much like
+  NSArchiver, only for XML-RPC.
+  
+  Encoder example: 
+
+   NSMutableString *str;                 // asume that exists
+   XmlRpcMethodResponse *methodResponse; // asume that exists
+   XmlRpcMethodCall     *methodCall;     // asume that exists
+   coder = [[XmlRpcEncoder alloc] initForWritingWithMutableString:str];
+   
+   [coder encodeMethodCall:methodCall];
+
+   // or
+
+   [coder encodeMethodResponse:methodResponse];
+"*/
+@interface XmlRpcEncoder : NSObject
+{
+  NSMutableString *string;
+  
+  NSMutableArray  *objectStack;
+  NSMutableArray  *objectHasStructStack;
+  NSTimeZone      *timeZone;
+}
+
+- (id)initForWritingWithMutableString:(NSMutableString *)_string;
+
+- (void)encodeMethodCall:(XmlRpcMethodCall *)_methodCall;
+- (void)encodeMethodResponse:(XmlRpcMethodResponse *)_methodResponse;
+
+- (void)encodeStruct:(NSDictionary *)_struct;
+- (void)encodeArray:(NSArray *)_array;
+- (void)encodeBase64:(NSData *)_data;
+- (void)encodeBoolean:(BOOL)_number;
+- (void)encodeInt:(int)_number;
+- (void)encodeDouble:(double)_number;
+- (void)encodeString:(NSString *)_string;
+- (void)encodeDateTime:(NSDate *)_date;
+- (void)encodeObject:(id)_object;
+
+- (void)encodeStruct:(NSDictionary *)_struct   forKey:(NSString *)_key;
+- (void)encodeArray:(NSArray *)_array          forKey:(NSString *)_key;
+- (void)encodeBase64:(NSData *)_data           forKey:(NSString *)_key;
+- (void)encodeBoolean:(BOOL)_number            forKey:(NSString *)_key;
+- (void)encodeInt:(int)_number                 forKey:(NSString *)_key;
+- (void)encodeDouble:(double)_number           forKey:(NSString *)_key;
+- (void)encodeString:(NSString *)_string       forKey:(NSString *)_key;
+- (void)encodeDateTime:(NSDate *)_date         forKey:(NSString *)_key;
+- (void)encodeObject:(id)_object               forKey:(NSString *)_key;
+
+- (void)setDefaultTimeZone:(NSTimeZone *)_timeZone;
+
+- (NSTimeZone *)defaultTimeZone;
+
+@end
+
+@class NSMutableSet;
+
+/*"
+  The XmlRpcDecoder is used to decode XML-RPC objects. It's pretty much like
+  NSUnarchiver, only for XML-RPC.
+  
+  Decoder example:
+
+   NSString             *xmlRpcString; // asume that exists
+   XmlRpcMethodCall     *methodCall     = nil;
+   XmlRpcMethodResponse *methodResponse = nil;
+
+   coder = [[XmlRpcDecoder alloc] initForReadingWithString:xmlRpcString];
+
+   methodCall = [coder decodeMethodCall];
+   
+   // or
+   
+   methodResponse = [coder decodeMethodResponse];
+"*/
+@interface XmlRpcDecoder : NSObject
+{
+  NSData         *data;
+  NSMutableArray *valueStack;
+   unsigned       nesting;
+  NSMutableArray *unarchivedObjects;
+  NSMutableSet   *awakeObjects;
+  NSTimeZone     *timeZone;
+}
+
+- (id)initForReadingWithString:(NSString *)_string;
+- (id)initForReadingWithData:(NSData *)_data;
+
+- (XmlRpcMethodCall *)decodeMethodCall;
+- (XmlRpcMethodResponse *)decodeMethodResponse;
+
+/* decoding */
+- (NSDictionary *)decodeStruct;
+- (NSArray *)decodeArray;
+- (NSData *)decodeBase64;
+- (BOOL)decodeBoolean;
+- (int)decodeInt;
+- (double)decodeDouble;
+- (NSString *)decodeString;
+- (NSCalendarDate *)decodeDateTime;
+- (id)decodeObject;
+
+- (NSDictionary *)decodeStructForKey:(NSString *)_key;
+- (NSArray *)decodeArrayForKey:(NSString *)_key;
+- (NSData *)decodeBase64ForKey:(NSString *)_key;
+- (BOOL)decodeBooleanForKey:(NSString *)_key;
+- (int)decodeIntForKey:(NSString *)_key;
+- (double)decodeDoubleForKey:(NSString *)_key;
+- (NSString *)decodeStringForKey:(NSString *)_key;
+- (NSCalendarDate *)decodeDateTimeForKey:(NSString *)_key;
+- (id)decodeObjectForKey:(NSString *)_key;
+
+- (void)setDefaultTimeZone:(NSTimeZone *)_timeZone;
+- (NSTimeZone *)defaultTimeZone;
+
+/* operations */
+- (void)ensureObjectAwake:(id)_object;
+- (void)finishInitializationOfObjects;
+- (void)awakeObjects;
+
+@end
+
+@interface NSObject(XmlRpcCoder)
+
++ (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_decoder;
+- (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder;
+
+@end
+
+@interface NSObject(XmlRpcDecoderAwakeMethods)
+
+- (void)finishInitializationWithXmlRpcDecoder:(XmlRpcDecoder *)_decoder;
+- (void)awakeFromXmlRpcDecoder:(XmlRpcDecoder *)_decoder;
+
+@end
+
+
+#endif /* __XmlRpc_XmlRpcCoder_H__ */
diff --git a/skyrix-xml/XmlRpc/XmlRpcDecoder.m b/skyrix-xml/XmlRpc/XmlRpcDecoder.m
new file mode 100644 (file)
index 0000000..0e8ae17
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcCoder.h"
+#include "XmlRpcValue.h"
+#include "XmlRpcSaxHandler.h"
+#include <SaxObjC/SaxXMLReaderFactory.h>
+#include "XmlRpcMethodCall.h"
+#include "XmlRpcMethodResponse.h"
+#include "common.h"
+
+/* self->unarchivedObjects does *not* store objects with xmlrpc base type! */
+
+@interface XmlRpcDecoder(PrivateMethodes)
+- (id)_decodeObject:(XmlRpcValue *)_value;
+@end
+
+@interface NSData(NGExtensions)
+- (NSData *)dataByDecodingBase64;
+@end
+
+@implementation XmlRpcDecoder
+
+- (BOOL)profileXmlRpcCoding {
+  return [[NSUserDefaults standardUserDefaults]
+                          boolForKey:@"ProfileXmlRpcCoding"];
+}
+
+#if HAVE_NSXMLPARSER && 0
+#warning using NSXMLParser!
+static BOOL useNSXMLParser = YES;
+#else
+static BOOL useNSXMLParser = NO;
+#endif
+static id saxHandler   = nil;
+static id xmlRpcParser = nil;
+
+static Class ArrayClass      = Nil;
+static Class DictionaryClass = Nil;
+static Class DataClass       = Nil;
+static Class NumberClass     = Nil;
+static Class StringClass     = Nil;
+static Class DateClass       = Nil;
+static BOOL  doDebug         = NO;
+
++ (void)initialize {
+  if (ArrayClass      == Nil) ArrayClass      = [NSArray        class];
+  if (DictionaryClass == Nil) DictionaryClass = [NSDictionary   class];
+  if (DataClass       == Nil) DataClass       = [NSData         class];
+  if (NumberClass     == Nil) NumberClass     = [NSNumber       class];
+  if (StringClass     == Nil) StringClass     = [NSString       class];
+  if (DateClass       == Nil) DateClass       = [NSCalendarDate class];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->unarchivedObjects = [[NSMutableArray alloc] init];
+    self->awakeObjects      = [[NSMutableSet alloc] init];
+    self->valueStack        = [[NSMutableArray alloc] initWithCapacity:4];
+    self->timeZone = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+  }
+  return self;
+}
+
+- (NSStringEncoding)encodingForXMLEncodingString:(NSString *)_enc {
+  _enc = [_enc lowercaseString];
+  if ([_enc isEqualToString:@"utf-8"])
+    return NSUTF8StringEncoding;
+  else if ([_enc isEqualToString:@"iso-8859-1"])
+    return NSISOLatin1StringEncoding;
+#if !(NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY)
+  else if ([_enc isEqualToString:@"iso-8859-9"])
+    return NSISOLatin9StringEncoding;
+#endif
+  else if ([_enc isEqualToString:@"ascii"])
+    return NSASCIIStringEncoding;
+  else
+    NSLog(@"%s: UNKNOWN XML ENCODING '%@'", __PRETTY_FUNCTION__, _enc);
+  return 0;
+}
+
+- (id)initForReadingWithString:(NSString *)_string {
+  if ((self = [self init])) {
+    NSRange r;
+    
+    r = [_string rangeOfString:@"?>"];
+    if ([_string hasPrefix:@"<?xml "] && r.length != 0) {
+      NSString *xmlDecl;
+      
+      xmlDecl = [_string substringToIndex:r.location];
+
+      r = [xmlDecl rangeOfString:@"encoding='"];
+      if (r.length != 0) {
+        xmlDecl = [_string substringFromIndex:(r.location + 10)];
+        r = [xmlDecl rangeOfString:@"'"];
+        xmlDecl = r.length == 0
+          ? nil
+          : [xmlDecl substringToIndex:r.location];
+      }
+      else {
+        r = [xmlDecl rangeOfString:@"encoding=\""];
+        if (r.length != 0) {
+          xmlDecl = [_string substringFromIndex:(r.location + 10)];
+          r = [xmlDecl rangeOfString:@"\""];
+          xmlDecl = r.length == 0
+            ? nil
+            : [xmlDecl substringToIndex:r.location];
+        }
+        else
+          xmlDecl = nil;
+      }
+      
+      if ([xmlDecl length] > 0) {
+        NSStringEncoding enc;
+        
+        if ((enc = [self encodingForXMLEncodingString:xmlDecl]) != 0) {
+          self->data = [[_string dataUsingEncoding:enc] retain];
+          if (self->data == nil) {
+            NSLog(@"WARNING(%s): couldn't get data for string '%@', "
+                  @"encoding %i !", __PRETTY_FUNCTION__, _string, enc);
+            [self release];
+            return nil;
+          }
+        }
+      }
+    }
+    
+    if (self->data == nil)
+      self->data = [[_string dataUsingEncoding:NSUTF8StringEncoding] retain];
+  }
+  return self;
+}
+- (id)initForReadingWithData:(NSData *)_data {
+  if ((self = [self init])) {
+    self->data = [_data retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->data         release];
+  [self->valueStack   release];
+  [self->unarchivedObjects release];
+  [self->awakeObjects release];
+  
+  [self->timeZone release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setDefaultTimeZone:(NSTimeZone *)_timeZone {
+  [self->timeZone autorelease];
+  self->timeZone = [_timeZone retain];
+}
+
+- (NSTimeZone *)defaultTimeZone {
+  return self->timeZone;
+}
+
+/* *** */
+
+- (void)_ensureSaxAndParser {
+  if (saxHandler == nil) {
+    if ((saxHandler = [[XmlRpcSaxHandler alloc] init]) == nil) {
+      NSLog(@"%s: did not find sax handler ...", __PRETTY_FUNCTION__);
+      return;
+    }
+  }
+
+  if (useNSXMLParser)      return;
+  if (xmlRpcParser != nil) return;
+  
+  xmlRpcParser =
+    [[SaxXMLReaderFactory standardXMLReaderFactory] 
+                          createXMLReaderForMimeType:@"text/xml"];
+  if (xmlRpcParser == nil) {
+    NSLog(@"%s: did not find an XML parser ...", __PRETTY_FUNCTION__);
+    return;
+  }
+
+  [xmlRpcParser setContentHandler:saxHandler];
+  [xmlRpcParser setDTDHandler:saxHandler];
+  [xmlRpcParser setErrorHandler:saxHandler];
+  [xmlRpcParser retain];
+}
+
+- (id)_decodeValueOfClass:(Class)_class {
+  id obj;
+  
+  obj = [[self->valueStack lastObject] value];
+
+  if ([obj isKindOfClass:_class])
+    return obj;
+  
+  NSLog(@"WARNING(%s): obj (%@) is not of proper class ('%@'<-->'%@'",
+        __PRETTY_FUNCTION__,
+        obj,
+        NSStringFromClass(_class),
+        NSStringFromClass([obj class]),
+        nil);
+  return nil;
+}
+
+- (XmlRpcMethodCall *)_decodeMethodCall:(XmlRpcMethodCall *)_baseCall {
+  NSArray          *params;
+  NSEnumerator     *paramEnum;
+  XmlRpcMethodCall *result    = nil;
+  XmlRpcValue    *param       = nil;
+  NSMutableArray *decParams   = nil;  // decoded parameters
+
+  params    = [_baseCall parameters]; // XmlRpcValues!!
+  decParams = [[NSMutableArray alloc] initWithCapacity:[params count]];
+  
+  paramEnum = [params objectEnumerator];
+  while ((param = [paramEnum nextObject])) {
+    id obj;
+
+    if ((obj = [self _decodeObject:param]) != nil)
+      [decParams addObject:obj];
+  }
+
+  result = [[XmlRpcMethodCall alloc] initWithMethodName:[_baseCall methodName]
+                                     parameters:decParams];
+
+  [decParams release];
+
+  return [result autorelease];
+}
+
+- (XmlRpcMethodResponse *)_decodeMethodResponse:(XmlRpcMethodResponse *)_resp {
+  static Class ExceptionClass = Nil;
+  XmlRpcMethodResponse *response = nil;
+  id                   result    = [_resp result];
+  
+  if (ExceptionClass == Nil)
+    ExceptionClass = [NSException class];
+
+  if (![result isKindOfClass:ExceptionClass]) {
+
+    result = [self _decodeObject:result]; // => XmlRpcValue
+  }
+  response = [[XmlRpcMethodResponse alloc] initWithResult:result];
+  
+  return [response autorelease];
+}
+
+- (NSStringEncoding)logEncoding {
+  return NSUTF8StringEncoding;
+}
+- (id)decodeRootObject {
+  id tmp = nil;
+  
+  if (doDebug) {
+    NSLog(@"%s: begin (data: %i bytes, nesting: %i)", __PRETTY_FUNCTION__, 
+          [self->data length], self->nesting);
+  }
+  if ([self->data length] == 0) return nil;
+  
+  self->nesting++;
+  
+  [self _ensureSaxAndParser];
+  NSAssert(saxHandler,   @"missing sax handler ...");
+  NSAssert(xmlRpcParser || useNSXMLParser, @"missing parser handler ...");
+  
+  [saxHandler reset];
+  if (doDebug) NSLog(@"%s:  SAX handler: %@", __PRETTY_FUNCTION__, saxHandler);
+#if HAVE_NSXMLPARSER
+  if (useNSXMLParser) {
+    NSXMLParser *parser;
+    
+    parser = [[NSXMLParser alloc] initWithData:self->data];
+    if (doDebug) 
+      NSLog(@"%s:  using NSXMLParser: %@", __PRETTY_FUNCTION__, parser);
+    [parser setDelegate:saxHandler];
+    [parser setShouldProcessNamespaces:NO];
+    [parser setShouldReportNamespacePrefixes:NO];
+    [parser setShouldResolveExternalEntities:NO];
+    [parser parse];
+    [parser release];
+  }
+  else
+#endif
+    [xmlRpcParser parseFromSource:self->data systemId:@"<xmlrpc-data>"];
+  
+  if ((tmp = [saxHandler methodCall]) != nil) {
+    tmp = [self _decodeMethodCall:tmp];
+  }
+  else if ((tmp = [saxHandler methodResponse]) != nil) {
+    tmp = [self _decodeMethodResponse:tmp];
+  }
+  else if (tmp == nil) {
+    NSString *s;
+    
+    s = [[NSString alloc] initWithData:self->data encoding:[self logEncoding]];
+    NSLog(@"%s: couldn't parse source\n"
+          @"  parser:  %@\n"
+          @"  handler: %@\n"
+          @"  data:    %@"
+          @"  string:  '%@'",
+          __PRETTY_FUNCTION__, xmlRpcParser, saxHandler, self->data, s);
+    [s release];
+  }
+  else {
+    NSLog(@"%s: neither call nor response (handler=%@): %@ ..",
+          __PRETTY_FUNCTION__,
+          saxHandler, tmp);
+  }
+  
+  self->nesting--;
+
+  // [saxHandler reset]; // hh asks: why is that commented out?
+  if (doDebug) NSLog(@"%s: end: %@", __PRETTY_FUNCTION__, tmp);
+  return tmp;  
+}
+
+- (XmlRpcMethodCall *)decodeMethodCall {
+  XmlRpcMethodCall *result;
+  NSTimeInterval st     = 0.0;
+    
+  if ([self profileXmlRpcCoding])
+    st = [[NSDate date] timeIntervalSince1970];  
+
+  result = [self decodeRootObject];
+
+  if ([self profileXmlRpcCoding]) {
+    NSTimeInterval diff;
+    diff = [[NSDate date] timeIntervalSince1970] - st;
+    
+    printf("+++     decodeMethodCall: %0.5fs\n", diff);
+  }
+  
+  return ([result isKindOfClass:[XmlRpcMethodCall class]])
+    ? result
+    : nil;
+}
+
+- (XmlRpcMethodResponse *)decodeMethodResponse {
+  XmlRpcMethodResponse *result;
+  NSTimeInterval st    = 0.0;
+
+  if ([self profileXmlRpcCoding])
+    st = [[NSDate date] timeIntervalSince1970];
+
+  result = [self decodeRootObject];
+
+  if ([self profileXmlRpcCoding]) {
+    NSTimeInterval diff;
+    diff = [[NSDate date] timeIntervalSince1970] - st;
+    
+    printf("+++ decodeMethodResponse: %0.5fs\n", diff);
+  }
+  
+  return [result isKindOfClass:[XmlRpcMethodResponse class]]
+    ? result
+    : nil;
+}
+
+- (id)_decodeObject:(XmlRpcValue *)_value {
+  id result;
+  
+  if (_value == nil) return nil;
+  
+  [self->valueStack addObject:_value];
+  result = [self decodeObject];
+  [self->valueStack removeLastObject];
+  return result;
+}
+
+- (id)decodeObject {
+  Class objClass = Nil;
+  id    object   = nil;
+  
+  self->nesting++;
+
+  if ((self->nesting == 1) && ([self->valueStack count] == 0)) {
+    object = [self decodeRootObject];
+  }
+  else {
+    NSString *className;
+    id value = [self->valueStack lastObject];
+    
+    className = [value className];
+
+    if ([className length] == 0) {
+      object = [value value];
+    }
+    else if ((objClass = NSClassFromString(className)) != Nil) {
+      object = [objClass decodeObjectWithXmlRpcCoder:self];
+    }
+    else {
+      NSLog(@"%s: class (%@) specified by value (%@) wasn't found.",
+            __PRETTY_FUNCTION__, className, value);
+      object = [value value];
+    }
+
+    if (object) [self->unarchivedObjects addObject:object];
+  }
+  self->nesting--;
+  
+  return object;
+}
+
+- (NSDictionary *)decodeStruct {
+  NSDictionary *dict;
+  id           result = nil;
+  NSMutableDictionary *tmp;
+  NSEnumerator        *keyEnum;
+  NSString            *key;
+  
+  dict  = (NSDictionary *)[[self->valueStack lastObject] value];
+  
+  if (!([dict respondsToSelector:@selector(keyEnumerator)] &&
+        [dict respondsToSelector:@selector(objectForKey:)]))
+    return nil;
+  
+  keyEnum  = [dict keyEnumerator];
+  tmp = [[NSMutableDictionary alloc] initWithCapacity:8];
+    
+  while ((key = [keyEnum nextObject])) {
+    XmlRpcValue *v;
+    id          obj;
+
+    v = [dict objectForKey:key];
+    if ((obj = [self _decodeObject:v]) != nil)
+        [tmp setObject:obj forKey:key];
+  }
+  result = [NSDictionary dictionaryWithDictionary:tmp];
+  [tmp release];
+  return result;
+}
+
+- (NSArray *)decodeArray {
+  NSArray        *array;
+  id             result = nil;
+  NSMutableArray *tmp      = nil;
+  NSEnumerator   *valEnum;
+  XmlRpcValue    *val      = nil;
+  
+  array = (NSArray *)[[self->valueStack lastObject] value];
+  if (![array respondsToSelector:@selector(objectEnumerator)])
+    return nil;
+
+  valEnum = [array objectEnumerator];
+  tmp = [[NSMutableArray alloc] initWithCapacity:8];
+    
+  while ((val = [valEnum nextObject])) {
+    id obj;
+
+    if ((obj = [self _decodeObject:val]) != nil)
+        [tmp addObject:obj];
+  }
+  result = [NSArray arrayWithArray:tmp];
+  [tmp release];
+  return result;
+}
+
+- (NSData *)decodeBase64 {
+  return [[self _decodeValueOfClass:DataClass]
+                dataByDecodingBase64];
+}
+
+- (BOOL)decodeBoolean {
+  return [[self _decodeValueOfClass:NumberClass] boolValue];
+}
+
+- (int)decodeInt {
+  return [[self _decodeValueOfClass:NumberClass] intValue];
+}
+
+- (double)decodeDouble {
+  return [[self _decodeValueOfClass:NumberClass] doubleValue];
+}
+
+- (NSString *)decodeString {
+  return [self _decodeValueOfClass:StringClass];
+}
+
+- (NSCalendarDate *)decodeDateTime {
+  NSCalendarDate *date;
+  NSTimeZone     *tz;
+  int            secFromGMT;
+  
+  if ((date = [self _decodeValueOfClass:DateClass]) == nil)
+    return nil;
+  
+  if ((tz = [date timeZone]))
+    return date;
+  
+  if (![date respondsToSelector:@selector(setTimeZone:)]) {
+    /* a plain date ... */
+    NSLog(@"cannot set timezone on date: %@", date);
+    return date;
+  }
+  
+  /* apply timezone correction */
+  secFromGMT = [self->timeZone secondsFromGMT];
+  [date setTimeZone:self->timeZone];
+  date = [date dateByAddingYears:0 months:0 days:0
+               hours:0 minutes:0 seconds:-secFromGMT];
+  return date;
+}
+
+- (XmlRpcValue *)beginDecodingKey:(NSString *)_key {
+  XmlRpcValue  *newValue;
+  NSDictionary *obj;
+  
+  obj = (NSDictionary *)[[self->valueStack lastObject] value];
+  NSAssert(_key != nil, @"_key is not allowed to be nil");
+  
+  if (![obj isKindOfClass:DictionaryClass]) {
+    NSLog(@"WARNING(%s): obj (%@) is not kind of class NSDictionary !!",
+          __PRETTY_FUNCTION__, obj, nil);
+    return nil;
+  }
+  
+  if ((newValue = [obj objectForKey:_key]) == nil)
+    /* got no value for key ... */
+    return nil;
+  
+  [self->valueStack addObject:newValue];
+  return newValue;
+}
+- (void)finishedDecodingKey {
+  [self->valueStack removeLastObject];
+}
+
+- (id)_decodeValueForKey:(NSString *)_key selector:(SEL)_selector {
+  XmlRpcValue *newValue;
+  id result;
+  
+  if ((newValue = [self beginDecodingKey:_key]) == nil)
+    return nil;
+  
+  result = [[self performSelector:_selector] retain];
+  [self finishedDecodingKey];
+  return [result autorelease];
+}
+
+- (NSDictionary *)decodeStructForKey:(NSString *)_key {
+  return [self _decodeValueForKey:_key selector:@selector(decodeStruct)];
+}
+
+- (NSArray *)decodeArrayForKey:(NSString *)_key {
+  return [self _decodeValueForKey:_key selector:@selector(decodeArray)];
+}
+
+- (NSData *)decodeBase64ForKey:(NSString *)_key {
+  return [self _decodeValueForKey:_key selector:@selector(decodeBase64)];
+}
+
+- (BOOL)decodeBooleanForKey:(NSString *)_key {
+  XmlRpcValue *newValue;
+  BOOL result;
+  
+  if ((newValue = [self beginDecodingKey:_key]) == nil)
+    /* any useful alternatives ? */
+    return NO;
+  
+  result = [self decodeBoolean];
+  [self finishedDecodingKey];
+  return result;
+}
+
+- (int)decodeIntForKey:(NSString *)_key {
+  XmlRpcValue *newValue;
+  int result;
+  
+  if ((newValue = [self beginDecodingKey:_key]) == nil)
+    /* any useful alternatives ? */
+    return NSNotFound;
+  
+  result = [self decodeInt];
+  [self finishedDecodingKey];
+  return result;
+}
+
+- (double)decodeDoubleForKey:(NSString *)_key {
+  XmlRpcValue *newValue;
+  double result;
+  
+  if ((newValue = [self beginDecodingKey:_key]) == nil)
+    /* any useful alternatives ? */
+    return 0.0;
+  
+  result = [self decodeDouble];
+  [self finishedDecodingKey];
+  return result;
+}
+
+- (NSString *)decodeStringForKey:(NSString *)_key {
+  return [self _decodeValueForKey:_key selector:@selector(decodeString)];
+}
+
+- (NSCalendarDate *)decodeDateTimeForKey:(NSString *)_key {
+  return [self _decodeValueForKey:_key selector:@selector(decodeDateTime)];
+}
+
+- (id)decodeObjectForKey:(NSString *)_key {
+ return [self _decodeValueForKey:_key selector:@selector(decodeObject)];
+}
+
+/* operations */
+
+- (void)ensureObjectAwake:(id)_object {
+  if ([self->awakeObjects containsObject:_object])
+    return;
+  
+  if ([_object respondsToSelector:@selector(awakeFromXmlRpcDecoder:)])
+    [_object awakeFromXmlRpcDecoder:self];
+  [self->awakeObjects addObject:_object];
+}
+- (void)awakeObjects {
+  NSEnumerator *e;
+  id obj;
+
+  e = [self->unarchivedObjects objectEnumerator];
+  while ((obj = [e nextObject]))
+    [self ensureObjectAwake:obj];
+}
+
+- (void)finishInitializationOfObjects {
+  NSEnumerator *e;
+  id obj;
+
+  e = [self->unarchivedObjects objectEnumerator];
+  while ((obj = [e nextObject])) {
+    if ([obj respondsToSelector:
+               @selector(finishInitializationWithXmlRpcDecoder:)])
+      [obj finishInitializationWithXmlRpcDecoder:self];
+  }
+}
+
+@end /* XmlRpcDecoder */
diff --git a/skyrix-xml/XmlRpc/XmlRpcEncoder.m b/skyrix-xml/XmlRpc/XmlRpcEncoder.m
new file mode 100644 (file)
index 0000000..4b0e8e1
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcCoder.h"
+#include "XmlRpcMethodCall.h"
+#include "XmlRpcMethodResponse.h"
+#include "common.h"
+
+@interface NSMutableString(XmlRpcDecoder)
+- (void)appendXmlRpcString:(NSString *)_value;
+@end
+
+@interface NSData(UsedNGExtensions)
+- (NSData *)dataByEncodingBase64;
+@end
+
+@implementation XmlRpcEncoder
+
+static NSTimeZone *gmt     = nil;
+static BOOL profileOn      = NO;
+static Class NSNumberClass = Nil;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  profileOn = [ud boolForKey:@"ProfileXmlRpcCoding"];
+  gmt       = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+  NSNumberClass = [NSNumber class];
+}
+
+- (id)initForWritingWithMutableString:(NSMutableString *)_string {
+  if ((self = [super init])) {
+    self->string = [_string retain];
+    self->timeZone = [gmt retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->string release];
+  
+  [self->objectStack release];
+  [self->objectHasStructStack release];
+
+  [self->timeZone release];
+  [super dealloc];
+}
+
+- (BOOL)profileXmlRpcCoding {
+  return profileOn;
+}
+
+/* accessors */
+
+- (void)setDefaultTimeZone:(NSTimeZone *)_timeZone {
+  [self->timeZone autorelease];
+  self->timeZone = [_timeZone retain];
+}
+
+/*"
+  This returns the timezone which will be associated with XML-RPC
+  datetime objects. Note: XML-RPC datetime values have no! associated timezone,
+  it's recommended that you always use UTC though.
+"*/
+- (NSTimeZone *)defaultTimeZone {
+  return self->timeZone;
+}
+
+/* *** */
+
+- (void)encodeMethodCall:(XmlRpcMethodCall *)_methodCall {
+  NSEnumerator *paramEnum = [[_methodCall parameters] objectEnumerator];
+  id           param;
+  NSTimeInterval st     = 0.0;
+
+  if ([self profileXmlRpcCoding])
+    st = [[NSDate date] timeIntervalSince1970];
+  
+  [self->string appendString:@"<?xml version='1.0'?>"];
+  [self->string appendString:@"<methodCall>"];
+  
+  [self->string appendString:@"<methodName>"];
+  [self->string appendString:[_methodCall methodName]];
+  [self->string appendString:@"</methodName>"];
+  
+  [self->string appendString:@"<params>"];
+  
+  while ((param = [paramEnum nextObject])) {
+    [self->string appendString:@"<param>"];
+    [self->string appendString:@"<value>"];
+
+    [self encodeObject:param];
+    
+    [self->string appendString:@"</value>"];
+    [self->string appendString:@"</param>"];
+  }
+
+  [self->string appendString:@"</params>"];
+  [self->string appendString:@"</methodCall>"];
+
+  if ([self profileXmlRpcCoding]) {
+    NSTimeInterval diff;
+    diff = [[NSDate date] timeIntervalSince1970] - st;
+    
+    printf("+++     encodeMethodCall: %0.5fs\n", diff);
+  }
+}
+
+- (void)encodeMethodResponse:(XmlRpcMethodResponse *)_methodResponse {
+  id result = [_methodResponse result];
+  static Class ExceptionClass = Nil;
+  NSTimeInterval st           = 0.0;
+
+  if ([self profileXmlRpcCoding])
+    st = [[NSDate date] timeIntervalSince1970];
+
+  if (ExceptionClass == Nil)
+    ExceptionClass = [NSException class];
+
+  [self->string appendString:@"<?xml version='1.0'?>"];
+  [self->string appendString:@"<methodResponse>"];
+
+  if ([result isKindOfClass:ExceptionClass]) {
+    [self->string appendString:@"<fault>"];
+    [self->string appendString:@"<value>"];
+
+    [self encodeObject:result];
+    
+    [self->string appendString:@"</value>"];
+    [self->string appendString:@"</fault>"];
+  }
+  else {
+    [self->string appendString:@"<params>"];
+    [self->string appendString:@"<param>"];
+    [self->string appendString:@"<value>"];
+
+    [self encodeObject:result];
+    
+    [self->string appendString:@"</value>"];
+    [self->string appendString:@"</param>"];
+    [self->string appendString:@"</params>"];
+  }
+
+  [self->string appendString:@"</methodResponse>"];
+
+  if ([self profileXmlRpcCoding]) {
+    NSTimeInterval diff;
+    diff = [[NSDate date] timeIntervalSince1970] - st;
+    
+    printf("+++ enocdeMethodResponse: %0.5fs\n", diff);
+  }
+}
+
+
+- (void)_reset {
+  [self->objectStack release];          self->objectStack          = nil;
+  [self->objectHasStructStack release]; self->objectHasStructStack = nil;
+}
+
+- (void)_ensureStacks {
+  if (self->objectStack == nil)
+    self->objectStack = [[NSMutableArray alloc] initWithCapacity:8];
+  if (self->objectHasStructStack == nil)
+    self->objectHasStructStack = [[NSMutableArray alloc] initWithCapacity:8];
+}
+
+- (void)_encodeObject:(id)_object {
+  if (_object) {
+    [self _ensureStacks];
+    [self->objectStack addObject:_object];
+    [self->objectHasStructStack addObject:@"NO"];
+
+    [_object encodeWithXmlRpcCoder:self];
+
+    if ([[self->objectHasStructStack lastObject] boolValue]) {
+      [self->string appendString:@"</struct>"];
+    }
+    [self->objectHasStructStack removeLastObject];
+    [self->objectStack removeLastObject];
+  }
+}
+
+- (NSString *)_className {
+  id obj;
+  
+  if ((obj = [self->objectStack lastObject]) == nil)
+    return nil;
+
+  if ([obj isKindOfClass:[NSString class]])
+    return @"NSString";
+  
+  return NSStringFromClass([obj classForCoder]);
+}
+
+- (void)encodeObject:(id)_obj {
+  [self _encodeObject:_obj];
+}
+
+- (BOOL)isObjectClassAttributeEnabled {
+  // adding of NSObjectClass removed due to compatibility issues !
+  return NO;
+}
+
+- (void)_appendTagName:(NSString *)_tagName attributes:(NSDictionary *)_attrs {
+  NSEnumerator *keyEnum   = [_attrs keyEnumerator];
+  NSString     *key       = nil;
+  
+  [self->string appendString:@"<"];
+  [self->string appendString:_tagName];
+  
+  if ([self isObjectClassAttributeEnabled]) {
+    NSString *className = [self _className];
+    
+    if ([className length] > 0) {
+      [self->string appendString:@" NSObjectClass=\""];
+      [self->string appendXmlRpcString:className];
+      [self->string appendString:@"\""];
+    }
+  }
+  
+  while ((key = [keyEnum nextObject])) {
+    [self->string appendString:@" "];
+    [self->string appendString:key];
+    [self->string appendString:@"=\""];
+    [self->string appendXmlRpcString:[_attrs objectForKey:key]];
+    [self->string appendString:@"\""];
+  }
+  [self->string appendString:@">"];  
+}
+
+- (void)_appendTagName:(NSString *)_tagName {
+  [self _appendTagName:_tagName attributes:nil];
+}
+
+- (void)_encodeNumber:(NSNumber *)_number tagName:(NSString *)_tagName {
+  [self _appendTagName:_tagName];
+  
+  if ([_tagName isEqualToString:@"boolean"])
+    [self->string appendString:[_number boolValue] ? @"1" : @"0"];
+  else if ([_tagName isEqualToString:@"int"])
+    [self->string appendFormat:@"%i", [_number intValue]];
+  else
+    [self->string appendXmlRpcString:[_number stringValue]];
+  
+  [self->string appendString:@"</"];
+  [self->string appendString:_tagName];
+  [self->string appendString:@">"];
+  
+}
+
+- (void)encodeStruct:(NSDictionary *)_struct {
+  NSEnumerator *keys = nil;
+  id           key   = nil;
+  
+  [self _appendTagName:@"struct"];
+  
+  keys = [_struct keyEnumerator];
+  while ((key = [keys nextObject])) {
+    [self->string appendString:@"<member>"];
+    
+    [self->string appendString:@"<name>"];
+    [self->string appendXmlRpcString:key];
+    [self->string appendString:@"</name>"];
+
+    [self->string appendString:@"<value>"];
+
+    [self _encodeObject:[_struct objectForKey:key]];
+    
+    [self->string appendString:@"</value>"];
+    
+    [self->string appendString:@"</member>"];
+  }
+  
+  [self->string appendString:@"</struct>"];
+}
+
+- (void)encodeArray:(NSArray *)_array {
+  NSEnumerator    *valueEnum = [_array objectEnumerator];
+  id value;
+
+  [self _appendTagName:@"array"];
+
+  [self->string appendString:@"<data>"];
+  
+  while ((value = [valueEnum nextObject])) {
+    [self->string appendString:@"<value>"];
+
+    [self _encodeObject:value];
+    
+    [self->string appendString:@"</value>"];
+  }
+  
+  [self->string appendString:@"</data>"];
+  [self->string appendString:@"</array>"];
+}
+
+- (void)encodeBase64:(NSData *)_data {
+  NSString *base64;
+  
+  base64 = [[NSString alloc] initWithData:[_data dataByEncodingBase64]
+                             encoding:NSASCIIStringEncoding];
+
+  [self _appendTagName:@"base64"];
+  [self->string appendString:base64];
+  [self->string appendString:@"</base64>"];
+
+  [base64 release]; base64 = nil;
+}
+
+- (void)encodeBoolean:(BOOL)_number {
+  [self _encodeNumber:[NSNumberClass numberWithBool:_number] tagName:@"boolean"];
+}
+- (void)encodeInt:(int)_number {
+  [self _encodeNumber:[NSNumberClass numberWithInt:_number] tagName:@"int"];
+}
+- (void)encodeDouble:(double)_number {
+  [self _encodeNumber:[NSNumberClass numberWithDouble:_number] tagName:@"double"];
+}
+
+- (void)encodeString:(NSString *)_string {
+  [self _appendTagName:@"string"];
+  [self->string appendXmlRpcString:_string];
+  [self->string appendString:@"</string>"];
+}
+
+- (void)encodeDateTime:(NSDate *)_date {
+  static NSDictionary *attrs = nil;
+  NSCalendarDate *date;
+  NSString *s;
+  
+  if (attrs == nil) {
+    attrs = [[NSDictionary alloc] 
+              initWithObjectsAndKeys:@"GMT",@"timeZone",nil];
+  }
+  
+  /* convert parameter to GMT */
+  
+#if LIB_FOUNDATION_LIBRARY
+  /* TODO: not sure whether lF handles reference-date correctly ... */
+  date = [[NSCalendarDate alloc] initWithTimeIntervalSince1970:
+                                   [_date timeIntervalSince1970]];
+#else
+  date = [[NSCalendarDate alloc] initWithTimeIntervalSinceReferenceDate:
+                                   [_date timeIntervalSinceReferenceDate]];
+#endif
+  [date setTimeZone:gmt];
+
+  /* format in XML-RPC date format */
+  
+  s = [[NSString alloc] initWithFormat:@"%04i%02i%02iT%02i:%02i:%02i",
+                 [date yearOfCommonEra], [date monthOfYear], [date dayOfMonth],
+                 [date hourOfDay], [date minuteOfHour], [date secondOfMinute]];
+  
+  [date release]; date = nil;
+  
+  [self _appendTagName:@"dateTime.iso8601" attributes:attrs];
+  [self->string appendString:s];
+  [self->string appendString:@"</dateTime.iso8601>"];
+  
+  [s release];
+}
+
+- (void)_appendMember:(id)_obj forKey:(NSString *)_key selector:(SEL)_sel {
+  [self _ensureStacks];
+  
+  if (![[self->objectHasStructStack lastObject] boolValue]) {
+    [self->objectHasStructStack removeLastObject];
+    [self->objectHasStructStack addObject:@"YES"];
+    [self _appendTagName:@"struct"];
+  }  
+  if (_obj != nil) {
+    [self->objectStack addObject:_obj];
+    [self->string appendString:@"<member><name>"];
+    [self->string appendString:_key];
+    [self->string appendString:@"</name><value>"];
+    
+    /* 
+      this does not work for int/double on OSX, since OSX doesn't coerce the
+      argument to the receivers parameter type
+    */
+    [self performSelector:_sel withObject:_obj];
+    
+    [self->string appendString:@"</value></member>"];
+    [self->objectStack removeLastObject];
+  }
+}
+- (void)_appendInt:(int)_i forKey:(NSString *)_key selector:(SEL)_sel {
+  /* special methods required for OSX */
+  void (*m)(id,SEL,int);
+  [self _ensureStacks];
+  
+  if (![[self->objectHasStructStack lastObject] boolValue]) {
+    [self->objectHasStructStack removeLastObject];
+    [self->objectHasStructStack addObject:@"YES"];
+    [self _appendTagName:@"struct"];
+  }  
+  
+  [self->objectStack addObject:[NSNumberClass numberWithInt:_i]];
+  [self->string appendString:@"<member><name>"];
+  [self->string appendString:_key];
+  [self->string appendString:@"</name><value>"];
+  
+  m = (void *)[self methodForSelector:_sel];
+  m(self, _sel, _i);
+  
+  [self->string appendString:@"</value></member>"];
+  [self->objectStack removeLastObject];
+}
+- (void)_appendDouble:(double)_d forKey:(NSString *)_key selector:(SEL)_sel {
+  /* special methods required for OSX */
+  void (*m)(id,SEL,double);
+  [self _ensureStacks];
+  
+  if (![[self->objectHasStructStack lastObject] boolValue]) {
+    [self->objectHasStructStack removeLastObject];
+    [self->objectHasStructStack addObject:@"YES"];
+    [self _appendTagName:@"struct"];
+  }  
+  
+  [self->objectStack addObject:[NSNumberClass numberWithDouble:_d]];
+  [self->string appendString:@"<member><name>"];
+  [self->string appendString:_key];
+  [self->string appendString:@"</name><value>"];
+  
+  m = (void *)[self methodForSelector:_sel];
+  m(self, _sel, _d);
+  
+  [self->string appendString:@"</value></member>"];
+  [self->objectStack removeLastObject];
+}
+
+- (void)encodeStruct:(NSDictionary *)_struct forKey:(NSString *)_key {
+  [self _appendMember:_struct forKey:_key selector:@selector(encodeStruct:)];
+}
+- (void)encodeArray:(NSArray *)_array  forKey:(NSString *)_key {
+  [self _appendMember:_array forKey:_key selector:@selector(encodeArray:)];
+}
+- (void)encodeBase64:(NSData *)_data forKey:(NSString *)_key {
+  [self _appendMember:_data forKey:_key selector:@selector(encodeBase64:)];
+}
+- (void)encodeBoolean:(BOOL)_number forKey:(NSString *)_key {
+  [self _appendInt:(int)_number forKey:_key selector:@selector(encodeBoolean:)];
+}
+- (void)encodeInt:(int)_number forKey:(NSString *)_key {
+  [self _appendInt:_number forKey:_key selector:@selector(encodeInt:)];
+}
+- (void)encodeDouble:(double)_number forKey:(NSString *)_key {
+  [self _appendDouble:_number forKey:_key selector:@selector(encodeDouble:)];
+}
+- (void)encodeString:(NSString *)_string forKey:(NSString *)_key {
+  [self _appendMember:_string forKey:_key selector:@selector(encodeString:)];
+}
+- (void)encodeDateTime:(NSDate *)_date forKey:(NSString *)_key {
+  [self _appendMember:_date forKey:_key selector:@selector(encodeDateTime:)];
+}
+- (void)encodeObject:(id)_object forKey:(NSString *)_key {
+  [self _appendMember:_object forKey:_key selector:@selector(encodeObject:)];
+}
+
+@end /* XmlRpcEncoder */
diff --git a/skyrix-xml/XmlRpc/XmlRpcMethodCall.h b/skyrix-xml/XmlRpc/XmlRpcMethodCall.h
new file mode 100644 (file)
index 0000000..c04d5ff
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __XmlRpcMethodCall_H__
+#define __XmlRpcMethodCall_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSArray, NSData;
+
+@interface XmlRpcMethodCall : NSObject
+{
+  NSString *methodName;
+  NSArray  *parameters;
+}
+
+- (id)initWithXmlRpcString:(NSString *)_xmlRpcString;
+- (id)initWithXmlRpcData:(NSData *)_xmlRpcData;
+- (id)initWithMethodName:(NSString *)_name parameters:(NSArray *)_params;
+
+/* accessors */
+
+- (void)setMethodName:(NSString *)_name;
+- (NSString *)methodName;
+
+- (void)setParameters:(NSArray *)_params;
+- (NSArray *)parameters;
+
+- (NSString *)xmlRpcString;
+
+@end
+
+#endif /* __XmlRpcMethodCall_H__ */
diff --git a/skyrix-xml/XmlRpc/XmlRpcMethodCall.m b/skyrix-xml/XmlRpc/XmlRpcMethodCall.m
new file mode 100644 (file)
index 0000000..6ff0290
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <XmlRpc/XmlRpcMethodCall.h>
+#include <XmlRpc/XmlRpcCoder.h>
+#include "common.h"
+
+@interface XmlRpcMethodCall(PrivateMethodes)
+- (NSString *)_encodeXmlRpcMethodCall;
+@end
+
+@implementation XmlRpcMethodCall
+
+- (id)initWithXmlRpcString:(NSString *)_string {
+  XmlRpcDecoder    *coder;
+  XmlRpcMethodCall *baseCall;
+  
+  if ([_string length] == 0) {
+    [self release];
+    return nil;
+  }
+  
+  coder = [[XmlRpcDecoder alloc] initForReadingWithString:_string];
+  baseCall = [coder decodeMethodCall];
+  [coder release];
+
+  if (baseCall == nil) {
+    [self release];
+    return nil;
+  }
+  
+  self = [self initWithMethodName:[baseCall methodName]
+               parameters:[baseCall parameters]];
+  
+  return self;
+}
+- (id)initWithXmlRpcData:(NSData *)_xmlRpcData {
+  XmlRpcDecoder    *coder;
+  XmlRpcMethodCall *baseCall;
+  
+  if ([_xmlRpcData length] == 0) {
+    [self release];
+    return nil;
+  }
+  
+  coder = [[XmlRpcDecoder alloc] initForReadingWithData:_xmlRpcData];
+  baseCall = [coder decodeMethodCall];
+  [coder release];
+  
+  if (baseCall == nil) {
+    [self release];
+    return nil;
+  }
+  
+  self = [self initWithMethodName:[baseCall methodName]
+               parameters:[baseCall parameters]];
+  
+  return self;
+}
+
+- (id)initWithMethodName:(NSString *)_name parameters:(NSArray *)_params {
+  if ((self = [super init])) {
+    self->methodName = [_name copy];
+    [self setParameters:_params];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->methodName release];
+  [self->parameters release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setMethodName:(NSString *)_name {
+  [self->methodName autorelease];
+  self->methodName = [_name copy];
+}
+- (NSString *)methodName {
+  return self->methodName;
+}
+
+- (void)setParameters:(NSArray *)_params {
+  if (self->parameters != _params) {
+    unsigned i, cc;
+    id *objects;
+    
+    [self->parameters autorelease];
+    
+    /* 
+       shallow copy parameters, it is implemented here 'by-hand', since 
+       skyrix-xml is not dependend on EOControl
+    */
+    cc = [_params count];
+    objects = calloc(cc + 1, sizeof(id));
+    
+    for (i = 0; i < cc; i++)
+      objects[i] = [_params objectAtIndex:i];
+    self->parameters = [[NSArray alloc] initWithObjects:objects count:cc];
+    if (objects) free(objects);
+  }
+}
+- (NSArray *)parameters {
+  return self->parameters;
+}
+
+- (NSString *)xmlRpcString {
+  return [self _encodeXmlRpcMethodCall];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s;
+  
+  s = [NSMutableString stringWithFormat:@"<0x%08X[%@]: ",
+                         self, NSStringFromClass([self class])];
+  [s appendFormat:@"method=%@", [self methodName]];
+  [s appendFormat:@" #paras=%d", [self->parameters count]];
+  [s appendString:@">"];
+  return s;
+}
+
+@end /* XmlRpcMethodCall */
+
+
+@implementation XmlRpcMethodCall(PrivateMethodes)
+
+- (NSString *)_encodeXmlRpcMethodCall {
+  NSMutableString *str;
+  XmlRpcEncoder   *coder;
+
+#if DEBUG
+  NSAssert1(self->methodName, @"%s, methodName is not allowed to be nil!",
+            __PRETTY_FUNCTION__);
+#endif
+  
+  str   = [NSMutableString stringWithCapacity:512];
+  coder = [[XmlRpcEncoder alloc] initForWritingWithMutableString:str];
+  [coder encodeMethodCall:self];
+
+  [coder release]; coder = nil;
+  
+  return str;
+}
+
+@end /* XmlRpcMethodCall(PrivateMethodes) */
diff --git a/skyrix-xml/XmlRpc/XmlRpcMethodResponse.h b/skyrix-xml/XmlRpc/XmlRpcMethodResponse.h
new file mode 100644 (file)
index 0000000..02b63d5
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __XmlRpcMethodResponse_H__
+#define __XmlRpcMethodResponse_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSData;
+
+@interface XmlRpcMethodResponse : NSObject
+{
+  id result;
+}
+
+- (id)initWithXmlRpcString:(NSString *)_xmlRpcString;
+- (id)initWithXmlRpcData:(NSData *)_data;
+- (id)initWithResult:(id)_result;
+
+/* accessors */
+
+- (void)setResult:(id)_result;
+- (id)result;
+
+- (NSString *)xmlRpcString;
+
+@end
+
+#endif /* __XmlRpcMethodResponse_H__ */
diff --git a/skyrix-xml/XmlRpc/XmlRpcMethodResponse.m b/skyrix-xml/XmlRpc/XmlRpcMethodResponse.m
new file mode 100644 (file)
index 0000000..f296c6b
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcMethodResponse.h"
+#include "XmlRpcCoder.h"
+#include "common.h"
+
+@interface XmlRpcMethodResponse(PrivateMethodes)
+- (NSString *)_encodeXmlRpcMethodResponse;
+@end
+
+@implementation XmlRpcMethodResponse
+
+- (id)initWithXmlRpcString:(NSString *)_string {
+  XmlRpcDecoder        *coder;
+  XmlRpcMethodResponse *baseResponse;
+  
+  if ([_string length] == 0) {
+    [self release];
+    return nil;
+  }
+
+  coder        = [[XmlRpcDecoder alloc] initForReadingWithString:_string];
+  baseResponse = [coder decodeMethodResponse];
+  [coder release];
+
+  if (baseResponse == nil) {
+    [self release];
+    return nil;
+  }
+  
+  self = [self initWithResult:[baseResponse result]];
+  
+  return self;
+}
+- (id)initWithXmlRpcData:(NSData *)_data {
+  XmlRpcDecoder        *coder;
+  XmlRpcMethodResponse *baseResponse;
+  
+  if ([_data length] == 0) {
+    [self release];
+    return nil;
+  }
+
+  coder        = [[XmlRpcDecoder alloc] initForReadingWithData:_data];
+  baseResponse = [coder decodeMethodResponse];
+  [coder release];
+
+  if (baseResponse == nil) {
+    [self release];
+    return nil;
+  }
+  
+  self = [self initWithResult:[baseResponse result]];
+  
+  return self;
+}
+
+- (id)initWithResult:(id)_result {
+  if ((self = [super init])) {
+    self->result = [_result retain];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->result release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setResult:(id)_result {
+  [self->result autorelease];
+  self->result = [_result retain];
+}
+- (id)result {
+  return self->result;
+}
+
+- (NSString *)xmlRpcString {
+  return [self _encodeXmlRpcMethodResponse];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *ms;
+  
+  ms = [NSMutableString stringWithCapacity:64];
+  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+
+  if (result)
+    [ms appendFormat:@" %@", self->result];
+  else
+    [ms appendString:@" no result"];
+  
+  [ms appendString:@">"];
+  return ms;
+}
+
+@end /* XmlRpcMethodResponse */
+
+@implementation XmlRpcMethodResponse(PrivateMethodes)
+
+- (NSString *)_encodeXmlRpcMethodResponse {
+  XmlRpcEncoder   *encoder = nil;
+  NSMutableString *str     = nil;
+
+  str = [NSMutableString stringWithCapacity:512];
+
+  encoder = [[XmlRpcEncoder alloc] initForWritingWithMutableString:str];
+  [encoder encodeMethodResponse:self];
+  [encoder release];
+
+  return str;
+}
+
+@end /* XmlRpcMethodResponse(PrivateMethodes) */
diff --git a/skyrix-xml/XmlRpc/XmlRpcRequestDecoder.m b/skyrix-xml/XmlRpc/XmlRpcRequestDecoder.m
new file mode 100644 (file)
index 0000000..f798398
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <XmlRpc/XmlRpcCoder.h>
+#include <XmlRpc/XmlRpcSaxHandler.h>
+#include <XmlRpc/XmlRpcMethodCall.h>
+#include <XmlRpc/XmlRpcValue.h>
+#include <SaxObjC/SaxXMLReaderFactory.h>
+#include "common.h"
+
+@implementation XmlRpcRequestDecoder
+
+static id   saxRequestHandler = nil;
+static id   requestParser     = nil;
+static BOOL doDebug           = NO;
+
+- (void)_ensureSaxAndParser {
+  if (saxRequestHandler == nil) {
+    static Class clazz = Nil;
+    
+    if (clazz == Nil)
+      clazz = NSClassFromString(@"XmlRpcSaxRequestHandler");
+    
+    if ((saxRequestHandler = [[clazz alloc] init]) == nil) {
+      NSLog(@"%s: did not find sax handler ...", __PRETTY_FUNCTION__);
+      return;
+    }
+  }
+  
+  if (requestParser != nil) return;
+  
+  requestParser =
+    [[SaxXMLReaderFactory standardXMLReaderFactory] createXMLReader];
+  
+  if (requestParser == nil) {
+    NSLog(@"%s: did not find an XML parser ...", __PRETTY_FUNCTION__);
+    return;
+  }
+  
+  [requestParser setContentHandler:saxRequestHandler];
+  [requestParser setDTDHandler:saxRequestHandler];
+  [requestParser setErrorHandler:saxRequestHandler];
+
+  [requestParser retain];
+}
+
+- (XmlRpcMethodCall *)decodeRootObject {
+  XmlRpcMethodCall *methodCall;
+  NSEnumerator     *paramEnum;
+  NSMutableArray   *params;
+  XmlRpcValue      *param;
+  
+  if (doDebug) NSLog(@"%s: begin", __PRETTY_FUNCTION__);
+  [self _ensureSaxAndParser];
+  
+  [saxRequestHandler reset];
+  
+  [requestParser parseFromSource:self->string systemId:nil];
+  
+  methodCall = [saxRequestHandler methodCall];
+  
+  // the methodCall's parameters is an array of XmlRpcValues!!!
+  
+  paramEnum = [[methodCall parameters] objectEnumerator];
+  params    = [[NSMutableArray alloc] initWithCapacity:
+                                      [[methodCall parameters] count]];
+
+  while ((param = [paramEnum nextObject])) {
+    Class objClass = Nil;
+    id    obj;
+    
+    [self->value autorelease];
+    self->value = [param retain];
+    
+    if ((objClass = NSClassFromString([param className])) != Nil) {
+      if ((obj = [objClass decodeObjectWithXmlRpcCoder:self])) {
+        [params addObject:obj];
+      }
+      else {
+        NSLog(@"%s: Warning: try to add 'nil' object to params (class='%@')",
+              __PRETTY_FUNCTION__,
+              [param className]);
+      }
+    }
+  }
+  [methodCall setParameters:params];
+  
+  [params release];
+
+  if (doDebug) NSLog(@"%s: done: %@", __PRETTY_FUNCTION__, methodCall);
+  return methodCall;
+}
+
+@end /* XmlRpcRequestDecoder */
diff --git a/skyrix-xml/XmlRpc/XmlRpcRequestEncoder.m b/skyrix-xml/XmlRpc/XmlRpcRequestEncoder.m
new file mode 100644 (file)
index 0000000..b9c4323
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcCoder.h"
+#include "XmlRpcMethodCall.h"
+#include "common.h"
+
+@interface XmlRpcEncoder(PrivateMethodes)
+- (void)_encodeObject:(id)_object;
+- (void)_reset;
+@end
+
+@implementation XmlRpcRequestEncoder
+
+- (void)encodeRootObject:(XmlRpcMethodCall *)_methodCall {
+  NSEnumerator *paramEnum;
+  id           param;
+
+  if (_methodCall == nil) return;
+
+  if (![_methodCall isKindOfClass:[XmlRpcMethodCall class]]) {
+    NSLog(@"%s: Warning: rootObject MUST be a XmlRpcMethodCall\n "
+          @"(rootObject=%@)",
+          __PRETTY_FUNCTION__,
+          _methodCall);
+    return;
+  }
+  
+  [self _reset];
+  
+  paramEnum = [[_methodCall parameters] objectEnumerator];
+  
+  [self->string appendString:@"<?xml version='1.0'?>\n"];
+  [self->string appendString:@"<methodCall>\n"];
+
+  [self->string appendString:@"<methodName>"];
+  [self->string appendString:[_methodCall methodName]];
+  [self->string appendString:@"</methodName>\n"];
+  
+  [self->string appendString:@"<params>\n"];
+  
+  while ((param = [paramEnum nextObject])) {
+    [self->string appendString:@"<param>\n"];
+    [self->string appendString:@"<value>\n"];
+
+    [self _encodeObject:param];
+    
+    [self->string appendString:@"</value>\n"];
+    [self->string appendString:@"</param>\n"];
+  }
+
+  [self->string appendString:@"</params>\n"];
+  
+  [self->string appendString:@"</methodCall>\n"];
+}
+
+@end /* XmlRpcRequestEncoder */
diff --git a/skyrix-xml/XmlRpc/XmlRpcResponseDecoder.m b/skyrix-xml/XmlRpc/XmlRpcResponseDecoder.m
new file mode 100644 (file)
index 0000000..9558b8d
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcCoder.h"
+#include "XmlRpcSaxHandler.h"
+#include <SaxObjC/SaxXMLReaderFactory.h>
+#include "common.h"
+
+@implementation XmlRpcResponseDecoder
+
+static id saxResponseHandler = nil;
+static id responseParser     = nil;
+
+- (void)_ensureSaxAndParser {
+  if (saxResponseHandler == nil) {
+    if ((saxResponseHandler = [[XmlRpcSaxResponseHandler alloc] init])==nil) {
+      NSLog(@"%s: did not find sax handler ...", __PRETTY_FUNCTION__);
+      return;
+    }
+  }
+
+  if (responseParser != nil) return;
+  
+  responseParser =
+    [[SaxXMLReaderFactory standardXMLReaderFactory]
+                          createXMLReaderForMimeType:@"text/xml"];
+  
+  if (responseParser == nil) {
+    NSLog(@"%s: did not find an XML parser ...", __PRETTY_FUNCTION__);
+    return;
+  }
+  
+  responseParser = [responseParser retain];
+  [responseParser setContentHandler:saxResponseHandler];
+  [responseParser setDTDHandler:saxResponseHandler];
+  [responseParser setErrorHandler:saxResponseHandler];
+}
+
+- (id)decodeRootObject {
+  static Class ExceptionClass = Nil;
+  id     result;
+  
+  [self _ensureSaxAndParser];
+
+  if (ExceptionClass == Nil)
+    ExceptionClass = [NSException class];
+  
+  [saxResponseHandler reset];
+
+  [responseParser parseFromSource:self->string systemId:nil];
+  
+  result = [saxResponseHandler result];
+
+  if ([result isKindOfClass:ExceptionClass]) {
+    return result;
+  }
+  else { // => XmlRpcValue
+    XmlRpcValue *val     = result;
+    Class       objClass = Nil;
+    id          obj;
+
+    [self->value autorelease];
+    self->value = [val retain];
+
+    if ((objClass = NSClassFromString([val className])) != Nil) {
+      obj = [objClass decodeObjectWithXmlRpcCoder:self];
+      return obj;
+    }
+  }
+  
+  return nil;
+}
+
+@end /* XmlRpcResponseDecoder */
diff --git a/skyrix-xml/XmlRpc/XmlRpcResponseEncoder.m b/skyrix-xml/XmlRpc/XmlRpcResponseEncoder.m
new file mode 100644 (file)
index 0000000..da06ccd
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcCoder.h"
+#include "common.h"
+
+@interface XmlRpcEncoder(PrivateMethodes)
+- (void)_encodeObject:(id)_object;
+- (void)_reset;
+@end
+
+@implementation XmlRpcResponseEncoder
+
+- (void)encodeRootObject:(id)_object {
+  static Class ExceptionClass = Nil;
+
+  if (ExceptionClass == Nil)
+    ExceptionClass = [NSException class];
+
+  [self _reset];
+  
+  [self->string appendString:@"<?xml version='1.0'?>\n"];
+  [self->string appendString:@"<methodResponse>\n"];
+
+  if ([_object isKindOfClass:ExceptionClass]) {
+    [self->string appendString:@"<fault>\n"];
+    [self->string appendString:@"<value>\n"];
+
+    [self _encodeObject:_object];
+    
+    [self->string appendString:@"</value>\n"];
+    [self->string appendString:@"</fault>\n"];
+  }
+  else {
+    [self->string appendString:@"<params>\n"];
+    [self->string appendString:@"<param>\n"];
+    [self->string appendString:@"<value>\n"];
+
+    [self _encodeObject:_object];
+    
+    [self->string appendString:@"</value>\n"];
+    [self->string appendString:@"</param>\n"];
+    [self->string appendString:@"</params>\n"];
+  }
+
+  [self->string appendString:@"</methodResponse>\n"];
+}
+
+@end /* XmlRpcResponseEncoder */
diff --git a/skyrix-xml/XmlRpc/XmlRpcSaxHandler.h b/skyrix-xml/XmlRpc/XmlRpcSaxHandler.h
new file mode 100644 (file)
index 0000000..80ebd20
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __XmlRpcSaxHandler_H__
+#define __XmlRpcSaxHandler_H__
+
+#include <SaxObjC/SaxDefaultHandler.h>
+
+/*
+  Mappings:
+  
+    <i4> or <int>      -> NSNumber
+    <boolean>          -> NSNumber
+    <double>           -> NSNumber
+    <base64>           -> NSData
+    <string>           -> NSString
+    <dateTime.iso8601> -> NSCalendarDate
+    <struct>           -> NSDictionary
+    <array>            -> NSArray
+*/
+
+@class NSMutableArray, NSTimeZone, NSCalendarDate;
+@class XmlRpcMethodCall, XmlRpcMethodResponse;
+
+@interface XmlRpcSaxHandler : SaxDefaultHandler
+{
+  XmlRpcMethodCall     *call;
+  XmlRpcMethodResponse *response;
+  
+  NSMutableArray *params;
+  NSString       *methodName;
+  
+  BOOL           invalidCall;
+  NSMutableArray *tagStack;
+  
+  NSMutableArray *valueStack;
+  NSString       *className;
+  
+  NSMutableArray *memberNameStack;
+  NSMutableArray *memberValueStack;
+
+  NSTimeZone     *timeZone;
+  NSCalendarDate *dateTime;
+  NSMutableString *characters;
+  
+  unsigned valueNestingLevel;
+  SEL      nextCharactersProcessor;
+}
+
+/* reusing sax handler */
+
+- (void)reset;
+
+/* result accessors */
+
+- (XmlRpcMethodCall *)methodCall;
+- (XmlRpcMethodResponse *)methodResponse;
+
+@end
+
+#endif /* __XmlRpcSaxHandler_H__ */
diff --git a/skyrix-xml/XmlRpc/XmlRpcSaxHandler.m b/skyrix-xml/XmlRpc/XmlRpcSaxHandler.m
new file mode 100644 (file)
index 0000000..e214f4d
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcSaxHandler.h"
+#include "XmlRpcMethodCall.h"
+#include "XmlRpcMethodResponse.h"
+#include "NSObject+XmlRpc.h"
+#include "XmlRpcValue.h"
+#include "common.h"
+
+@implementation XmlRpcSaxHandler
+/*"
+  The SAX handler used to decode XML-RPC responses and requests. If the
+  parsing finishes successfully, either -methodCall or -methodResponse will
+  return an properly initialized object representing the XML-RPC response.
+  
+  The SAX handler is used by the XmlRpcDecoder class internally, in most
+  cases you shouldn't need to access it directly.
+"*/
+
+static Class ArrayClass      = Nil;
+static Class DictionaryClass = Nil;
+static BOOL  doDebug         = NO;
+
++ (void)initialize {
+  if (ArrayClass      == Nil) ArrayClass      = [NSMutableArray      class];
+  if (DictionaryClass == Nil) DictionaryClass = [NSMutableDictionary class];
+}
+
+- (void)reset {
+  if (doDebug) NSLog(@"%s: begin ...", __PRETTY_FUNCTION__);
+  [self->response   release]; self->response   = nil;
+  [self->call       release]; self->call       = nil;
+  [self->methodName release]; self->methodName = nil;
+  [self->params     release]; self->params     = nil;
+  
+  // for recursive structures (struct, array)
+  [self->valueStack removeAllObjects];
+
+  [self->className release]; self->className = nil;
+  
+  [self->memberNameStack  removeAllObjects];
+  [self->memberValueStack removeAllObjects];
+  [self->timeZone release]; self->timeZone = nil;
+  [self->dateTime release]; self->dateTime = nil;
+  
+  [self->characters setString:@""];
+  
+  self->valueNestingLevel = 0;
+  self->nextCharactersProcessor = NULL;
+  self->invalidCall = NO;
+  [self->tagStack removeAllObjects];
+}
+- (void)dealloc {
+  [self reset];
+  
+  [self->characters release];
+  [self->tagStack   release];
+  [self->valueStack release];
+  
+  [self->memberNameStack  release];
+  [self->memberValueStack release];
+  
+  [super dealloc];
+}
+
+/* accessors */
+
+- (XmlRpcMethodCall *)methodCall {
+  return self->call;
+}
+
+- (XmlRpcMethodResponse *)methodResponse {
+  return self->response;
+}
+
+- (id)result {
+  return [self->params lastObject]; // => NSException || XmlRpcValue
+}
+
+/* *** */
+
+- (void)_addValueToParas:(id)_value {
+  id topValue = [[self->valueStack lastObject] value];
+
+  if ([topValue isKindOfClass:ArrayClass])
+    [topValue addObject:_value];
+  else if ([topValue isKindOfClass:DictionaryClass])
+    [self->memberValueStack addObject:_value];
+  else
+    [self->params addObject:_value];
+}
+
+/* document */
+
+- (void)startDocument {
+  if (doDebug) NSLog(@"%s: begin ...", __PRETTY_FUNCTION__);
+  [self reset];
+  
+  if (self->tagStack == nil)
+    self->tagStack = [[NSMutableArray alloc] initWithCapacity:8];
+  if (self->valueStack == nil)
+    self->valueStack = [[NSMutableArray alloc] initWithCapacity:8];
+  if (self->characters == nil)
+    self->characters = [[NSMutableString alloc] initWithCapacity:128];
+  
+  if (doDebug) NSLog(@"%s: done ...", __PRETTY_FUNCTION__);
+}
+- (void)endDocument {
+  if (doDebug) NSLog(@"%s: begin ...", __PRETTY_FUNCTION__);
+  
+  if ([self->tagStack count] > 0) {
+    self->invalidCall = YES;
+    NSLog(@"Warning(%s): tagStack is not empty (%@)",
+          __PRETTY_FUNCTION__,
+          self->tagStack);
+  }
+
+  if (self->call != nil && self->response != nil) {
+    self->invalidCall = YES;
+    NSLog(@"Warning(%s): got methodCall *AND* methodResponse!!! (%@<->%@)",
+          __PRETTY_FUNCTION__,
+          self->call,
+          self->response);
+  }
+
+  if (self->invalidCall) {
+    if (doDebug) NSLog(@"%s:   marked as invalid call!", __PRETTY_FUNCTION__);
+    [self->call     release]; self->call     = nil;
+    [self->response release]; self->response = nil;
+  }
+  if (doDebug) NSLog(@"%s: done ...", __PRETTY_FUNCTION__);
+}
+
+/* elements */
+
+- (void)start_name:(id<SaxAttributes>)_attrs {
+  self->nextCharactersProcessor = @selector(_name:length:);
+}
+- (void)end_name {
+  self->nextCharactersProcessor = NULL;
+}
+- (void)_name:(unichar *)_chars length:(int)_len {
+  NSString *name;
+  name = [NSString stringWithCharacters:_chars length:_len];
+  [self->memberNameStack addObject:name];
+}
+
+- (void)start_params:(id<SaxAttributes>)_attrs {
+  if (self->params) {
+    self->invalidCall = YES;
+    return;
+  }
+  self->params = [[NSMutableArray alloc] initWithCapacity:8];
+}
+- (void)end_params {
+  if (self->params == nil)
+    self->invalidCall =YES;
+}
+
+- (void)start_value:(id<SaxAttributes>)_attrs {
+  self->valueNestingLevel++;
+  self->nextCharactersProcessor = @selector(_baseValue:length:);
+}
+- (void)end_value {
+  self->valueNestingLevel--;
+}
+
+- (void)_dateValue:(unichar *)_chars length:(int)_len {
+  if (self->dateTime)
+    return;
+  
+  self->dateTime = [[NSObject objectWithXmlRpcType:@"dateTime.iso8601"
+                              characters:_chars length:_len]
+                              retain];
+}
+
+- (void)_baseValue:(unichar *)_chars length:(int)_len {
+  id value;
+
+  if (self->valueNestingLevel == 0) {
+    NSLog(@"%s: invalidCall......... self->valueNestingLevel = 0",
+          __PRETTY_FUNCTION__);
+    return;
+  }
+  
+  value = [NSObject objectWithXmlRpcType:[self->tagStack lastObject]
+                    characters:_chars length:_len];
+  
+  if (value == nil)
+    value = [NSNull null];
+
+  value = [[XmlRpcValue alloc] initWithValue:value className:self->className];
+    
+  if (self->params == nil) {
+    NSLog(@"%s: invalidCall......... self->params = nil",
+          __PRETTY_FUNCTION__);
+    return;
+  }
+  [self _addValueToParas:value];
+  
+  [value release];
+}
+
+- (void)start_i4:(id<SaxAttributes>)_attrs {
+  self->nextCharactersProcessor = @selector(_baseValue:length:);
+}
+- (void)start_int:(id<SaxAttributes>)_attrs {
+  self->nextCharactersProcessor = @selector(_baseValue:length:);
+}
+- (void)start_double:(id<SaxAttributes>)_attrs {
+  self->nextCharactersProcessor = @selector(_baseValue:length:);
+}
+- (void)start_base64:(id<SaxAttributes>)_attrs {
+  self->nextCharactersProcessor = @selector(_baseValue:length:);
+}
+- (void)start_boolean:(id<SaxAttributes>)_attrs {
+  self->nextCharactersProcessor = @selector(_baseValue:length:);
+}
+- (void)start_string:(id<SaxAttributes>)_attrs {
+  self->nextCharactersProcessor = @selector(_baseValue:length:);
+}
+- (void)start_dateTime:(id<SaxAttributes>)_attrs {
+  NSString *tz;
+  int      idx;
+  
+  [self->timeZone release]; self->timeZone = nil;
+  [self->dateTime release]; self->dateTime = nil;
+  
+  tz = ((idx = [_attrs indexOfRawName:@"timeZone"]) != NSNotFound)
+      ? [_attrs valueAtIndex:idx]
+      : nil;
+  
+  if (tz) {
+    self->timeZone = [[NSTimeZone timeZoneWithAbbreviation:tz] retain];
+  }
+  self->nextCharactersProcessor = @selector(_dateValue:length:);
+}
+
+- (void)end_dateTime {
+  if (self->dateTime) {
+    NSCalendarDate *date;
+    XmlRpcValue    *value;
+    int            secFromGMT;
+    
+    if ([self->dateTime respondsToSelector:@selector(setTimeZone:)]) {
+      secFromGMT = [self->timeZone secondsFromGMT];
+      [self->dateTime setTimeZone:self->timeZone];
+      date = [self->dateTime dateByAddingYears:0 months:0 days:0
+                             hours:0 minutes:0 seconds:-secFromGMT];
+    }
+    else {
+      NSLog(@"WARNING(%s): cannot set timezone on date: %@", 
+            __PRETTY_FUNCTION__, self->dateTime);
+      date = self->dateTime;
+    }
+    
+    value = [[XmlRpcValue alloc] initWithValue:date
+                                 className:@"NSCalendarDate"];
+    [value autorelease];
+    [self _addValueToParas:value];
+  }
+  
+  [self->timeZone release]; self->timeZone = nil;
+  [self->dateTime release]; self->dateTime = nil;
+  self->nextCharactersProcessor = NULL;
+}
+
+
+- (void)start_array:(id<SaxAttributes>)_attrs {
+  id value = [NSMutableArray arrayWithCapacity:8];
+
+  value = [[XmlRpcValue alloc] initWithValue:value className:self->className];
+  
+  [self _addValueToParas:value];
+  [self->valueStack addObject:value];
+  
+  self->nextCharactersProcessor = NULL;
+  [value release];
+}
+
+- (void)end_array {
+  if ([self->valueStack count] > 0)
+    [self->valueStack removeLastObject];
+  else {
+    NSLog(@"%s: valueStack should be empty: %@",
+          __PRETTY_FUNCTION__,
+          self->valueStack);
+  }
+}
+
+- (void)start_struct:(id<SaxAttributes>)_attrs {
+  id value = [NSMutableDictionary dictionaryWithCapacity:8];
+
+  value = [[XmlRpcValue alloc] initWithValue:value className:self->className];
+  
+  [self _addValueToParas:value];
+  [self->valueStack addObject:value];
+
+  self->nextCharactersProcessor = NULL;
+  [value release];
+}
+
+- (void)end_struct {
+  if ([self->valueStack count] > 0)
+    [self->valueStack removeLastObject];
+  else {
+    NSLog(@"%s: valueStack should be empty: %@",
+          __PRETTY_FUNCTION__,
+          self->valueStack);
+  }
+}
+
+- (void)start_member:(id<SaxAttributes>)_attrs {
+  if (![[[self->valueStack lastObject] value] isKindOfClass:DictionaryClass]) {
+    self->invalidCall = YES;
+  }
+  else {
+    if (self->memberNameStack == nil)
+      self->memberNameStack = [[NSMutableArray alloc] initWithCapacity:8];
+    if (self->memberValueStack == nil)
+      self->memberValueStack = [[NSMutableArray alloc] initWithCapacity:8];
+  }
+  self->nextCharactersProcessor = NULL;
+}
+
+- (void)end_member {
+  id tmp = [[self->valueStack lastObject] value];
+
+  if ([self->memberNameStack count] != [self->memberValueStack count]) {
+    NSLog(@"Warning(%s): memberNameStack.count != memberValueStack.count"
+          @" (%@ <--> %@)",
+          __PRETTY_FUNCTION__,
+          self->memberNameStack,
+          self->memberValueStack,
+          nil);
+    [self->memberValueStack release]; self->memberValueStack = nil;
+    [self->memberNameStack  release]; self->memberNameStack  = nil;
+    self->invalidCall = YES;
+  }
+  else if ([self->memberNameStack count] == 0) {
+    NSLog(@"Warning(%s): memberNameStack and memberValueStack are empty!",
+          __PRETTY_FUNCTION__,
+          nil);
+    [self->memberValueStack release]; self->memberValueStack = nil;
+    [self->memberNameStack  release]; self->memberNameStack  = nil;
+    self->invalidCall = YES;
+  }
+  else if (![tmp isKindOfClass:DictionaryClass])
+    self->invalidCall = YES;
+  else {
+    [tmp setObject:[self->memberValueStack lastObject]
+            forKey:[self->memberNameStack lastObject]];
+    
+    [self->memberNameStack  removeLastObject];
+    [self->memberValueStack removeLastObject];
+  }
+}
+
+- (void)start_methodCall:(id<SaxAttributes>)_attrs {
+  /* can't create call here, args unknown !!! */
+  if (self->call != nil) {
+    if (doDebug) 
+      NSLog(@"%s: method-call already setup!", __PRETTY_FUNCTION__);
+    self->invalidCall = YES;
+    return;
+  }
+  if (doDebug) NSLog(@"%s: ...", __PRETTY_FUNCTION__);
+}
+- (void)end_methodCall {
+  if (self->call != nil) {
+    if (doDebug) 
+      NSLog(@"%s: method-call already setup!", __PRETTY_FUNCTION__);
+    self->invalidCall = YES;
+    return;
+  }
+  
+  self->call = [[XmlRpcMethodCall alloc] initWithMethodName:self->methodName
+                                         parameters:self->params];
+  
+  /* reset args */
+  [self->methodName release]; self->methodName = nil;
+  [self->params     release]; self->params     = nil;
+}
+
+- (void)start_methodResponse:(id<SaxAttributes>)_attrs {
+  if (self->response != nil) {
+    if (doDebug) 
+      NSLog(@"%s: method-response already setup!", __PRETTY_FUNCTION__);
+    self->invalidCall = YES;
+    return;
+  }
+}
+
+- (void)end_methodResponse {
+  if (doDebug) NSLog(@"%s: begin ...", __PRETTY_FUNCTION__);
+  
+  if (self->response != nil) {
+    if (doDebug) 
+      NSLog(@"%s:   method-response already setup!", __PRETTY_FUNCTION__);
+    self->invalidCall = YES;
+    return;
+  }
+
+  if ([self->params count] > 1) {
+    if (doDebug) {
+      NSLog(@"%s:   has more than one params (%i)!", __PRETTY_FUNCTION__, 
+      [self->params count]);
+    }
+    self->invalidCall = YES;
+  }
+  
+  if (self->invalidCall) {
+    NSException *error;
+
+    if (doDebug)
+      NSLog(@"%s:   response marked as invalid!", __PRETTY_FUNCTION__);
+    
+    error = [NSException exceptionWithName:@"error while parsing response"
+                         reason:@"error while parsing response"
+                         userInfo:nil];
+    
+    [self->params release];
+    self->params = [[NSMutableArray arrayWithObject:error] retain];
+  }
+
+  self->response =
+    [[XmlRpcMethodResponse alloc] initWithResult:[self->params lastObject]];
+  if (doDebug)
+    NSLog(@"%s:   response: %@", __PRETTY_FUNCTION__, self->response);
+
+  /* reset args */
+  [self->params release]; self->params = nil;
+  if (doDebug) NSLog(@"%s: done.", __PRETTY_FUNCTION__);
+}
+
+- (void)start_methodName:(id<SaxAttributes>)_attrs {
+  if (self->call != nil) {
+    self->invalidCall = YES;
+    return;
+  }
+  self->nextCharactersProcessor = @selector(_methodName:length:);
+}
+
+- (void)end_methodName {
+  self->nextCharactersProcessor = NULL;
+}
+- (void)_methodName:(unichar *)_chars length:(int)_len {
+  [self->methodName release];
+  self->methodName = [[NSString alloc] initWithCharacters:_chars length:_len];
+}
+
+- (void)start_fault:(id<SaxAttributes>)_attrs {
+  if (self->params) {
+    self->invalidCall = YES;
+    return;
+  }
+  else
+    self->params = [[NSMutableArray alloc] initWithCapacity:2];
+  
+  self->nextCharactersProcessor = NULL;
+}
+- (void)end_fault {
+  if (self->params == nil)
+    self->invalidCall = YES;
+
+  self->nextCharactersProcessor = NULL;
+
+  /* fixup result class */
+  if ([self->params count] != 1) {
+    NSLog(@"XML-RPC: incorrect params count (should be 1 for faults) ?: %@",
+          self->params);
+  }
+  else {
+    XmlRpcValue *fault;
+    
+    fault = [self->params objectAtIndex:0];
+    if (![fault isException]) {
+      if ([fault isDictionary]) {
+        [fault setClassName:@"NSException"];
+      }
+      else {
+        NSException *e;
+        NSString *name;
+        NSString *reason;
+        
+        NSLog(@"XML-RPC: got incorrect fault object (class=%@) ?: %@",
+              [fault className], fault);
+        name = [NSString stringWithFormat:@"XmlRpcFault<%@>", 
+                           [fault valueForKey:@"faultCode"]];
+        if (name == nil) name = @"GenericXmlRpcFault";
+        reason = [fault valueForKey:@"faultString"];
+        if (reason == nil) reason = name;
+        
+        e = [NSException exceptionWithName:name reason:reason userInfo:nil];
+        [self->params replaceObjectAtIndex:0 withObject:e];
+      }
+    }
+  }
+}
+
+/* generic dispatcher */
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attrs
+{
+  NSString *tmp = nil;
+  SEL      sel;
+  int      idx;
+  
+  [self->tagStack addObject:_rawName];
+
+  tmp = ((idx = [_attrs indexOfRawName:@"NSObjectClass"]) != NSNotFound)
+      ? [_attrs valueAtIndex:idx]
+      : nil;
+    
+  [self->className autorelease];
+  self->className = [tmp retain];
+
+  if (self->invalidCall) return;
+
+  if ([_rawName isEqualToString:@"dateTime.iso8601"])
+    _rawName = @"dateTime";
+
+  [self->characters setString:@""];
+
+  tmp = [NSString stringWithFormat:@"start_%@:",_rawName];
+  if ((sel = NSSelectorFromString(tmp))) {
+    if ([self respondsToSelector:sel])
+      [self performSelector:sel withObject:_attrs];
+  }
+}
+
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  unsigned stackDepth, lastIdx;
+  NSString *tmp;
+  SEL sel;
+
+  if (self->nextCharactersProcessor != NULL) {
+    void (*m)(id, SEL, unichar *, int);
+    unichar *chars;
+    unsigned len;
+
+    len   = [self->characters length];
+    chars = malloc(sizeof(unichar)*len);
+    [self->characters getCharacters:chars];
+    
+    if ((m = (void*)[self methodForSelector:self->nextCharactersProcessor]))
+      m(self, self->nextCharactersProcessor, chars, len);
+    
+    free(chars);
+  }
+  
+  self->nextCharactersProcessor = NULL;
+  
+  if ((stackDepth = [self->tagStack count]) == 0) {
+    self->invalidCall = YES;
+    return;
+  }
+  lastIdx = stackDepth - 1;
+  if (![[self->tagStack objectAtIndex:lastIdx] isEqualToString:_rawName]) {
+    self->invalidCall = YES;
+    return;
+  }
+  [self->tagStack removeObjectAtIndex:lastIdx];
+  stackDepth--;
+
+  if (self->invalidCall) {
+    return;
+  }
+  
+  if ([_rawName isEqualToString:@"dateTime.iso8601"])
+    _rawName = @"dateTime";
+  
+  tmp = [NSString stringWithFormat:@"end_%@", _rawName];
+  if ((sel = NSSelectorFromString(tmp))) {
+    if ([self respondsToSelector:sel])
+      [self performSelector:sel];
+  }
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  if (_len > 0) {
+    [self->characters appendString:
+         [NSString stringWithCharacters:_chars length:_len]];
+  }
+}
+
+/* errors */
+
+- (void)warning:(SaxParseException *)_exception {
+  NSLog(@"XML-RPC warning: %@", _exception);
+}
+- (void)error:(SaxParseException *)_exception {
+  NSLog(@"XML-RPC error: %@", _exception);
+}
+
+@end /* XmlRpcSaxHandler */
diff --git a/skyrix-xml/XmlRpc/XmlRpcValue.h b/skyrix-xml/XmlRpc/XmlRpcValue.h
new file mode 100644 (file)
index 0000000..96e9f06
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __XML_RPC_XmlRpcValue_H__
+#define __XML_RPC_XmlRpcValue_H__
+
+#import <Foundation/NSObject.h>
+
+@interface XmlRpcValue : NSObject
+{
+  NSString *className;
+  id       value;
+}
+
+- (id)initWithValue:(id)_value className:(NSString *)_className;
+
+/* accessors */
+
+- (void)setClassName:(NSString *)_className;
+- (NSString *)className;
+- (id)value;
+
+- (Class)class;
+- (BOOL)isException;
+- (BOOL)isDictionary;
+
+@end
+
+#endif /* __XML_RPC_XmlRpcValue_H__ */
diff --git a/skyrix-xml/XmlRpc/XmlRpcValue.m b/skyrix-xml/XmlRpc/XmlRpcValue.m
new file mode 100644 (file)
index 0000000..483bdfc
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "XmlRpcValue.h"
+#include "common.h"
+
+@implementation XmlRpcValue
+/*"
+  The XmlRpcValue class is used internally by the XML-RPC decoder to
+  represent any valid XML-RPC value. You should never need to use this class.
+"*/
+
+- (id)initWithValue:(id)_value className:(NSString *)_className {
+  if ((self = [super init])) {
+    NSString *cName;
+    
+    ASSIGN(self->value, _value);
+    cName = (_className != nil)
+      ? _className
+      : NSStringFromClass([_value class]);
+
+    ASSIGN(self->className, cName);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->className release];
+  [self->value     release];
+  [super dealloc];
+}
+
+- (id)value {
+  return self->value;
+}
+
+- (void)setClassName:(NSString *)_className {
+  if (_className != self->className) {
+    [self->className autorelease];
+    self->className = [_className copy];
+  }
+}
+- (NSString *)className {
+  return self->className;
+}
+
+- (Class)class {
+  return NSClassFromString([self className]);
+}
+
+- (BOOL)isException {
+  return [(id<NSObject>)[self class] isKindOfClass:[NSException class]];
+}
+- (BOOL)isDictionary {
+  return [(id<NSObject>)[self class] isKindOfClass:[NSDictionary class]];
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"XmlRpcValue: %@->%@",
+                   self->className,
+                   self->value];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)zone {
+  return [[[self class] alloc]
+                 initWithValue:self->value className:self->className];
+}
+
+@end /* XmlRpcValue */
diff --git a/skyrix-xml/XmlRpc/common.h b/skyrix-xml/XmlRpc/common.h
new file mode 100644 (file)
index 0000000..b04aadb
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __XmlRpc_common_h__
+#define __XmlRpc_common_h__
+
+#import <Foundation/Foundation.h>
+
+#ifndef ASSIGN
+#  define ASSIGN(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) [__value retain]; \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+
+#endif /* __XmlRpc_common_h__ */
diff --git a/skyrix-xml/common.make b/skyrix-xml/common.make
new file mode 100644 (file)
index 0000000..22c0e70
--- /dev/null
@@ -0,0 +1,36 @@
+# $Id: common.make,v 1.1.1.1 2003/07/09 22:57:27 cvs Exp $
+
+SKYROOT=..
+
+include $(GNUSTEP_MAKEFILES)/common.make
+include $(SKYROOT)/Version
+-include ./Version
+
+GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT)
+
+ADDITIONAL_CPPFLAGS += -pipe -Wall -Wno-protocol
+
+ADDITIONAL_INCLUDE_DIRS += -I..
+
+ADDITIONAL_LIB_DIRS += \
+        -L./$(GNUSTEP_OBJ_DIR)                 \
+       -L../SaxObjC/$(GNUSTEP_OBJ_DIR)         \
+       -L../DOM/$(GNUSTEP_OBJ_DIR)             \
+
+AUTODOC_COPYRIGHT = "SKYRIX Software AG"
+AUTODOC_SxVERSION = "4.2"
+AUTODOC_TEMPLATE  = "../Documentation/AutoDocTemplate.html"
+
+AUTODOC_FLAGS     = \
+       -copyright $(AUTODOC_COPYRIGHT) \
+       -format html                    \
+       -typedirs                       \
+       -copydocs                       \
+       -tree                           \
+       -allclasses                     \
+       -define-SxVersion $(AUTODOC_SxVERSION) \
+       -template $(AUTODOC_TEMPLATE)
+
+ifeq ($(FOUNDATION_LIB),nx)
+ADDITIONAL_LDFLAGS += -framework Foundation
+endif
diff --git a/skyrix-xml/dummy.c b/skyrix-xml/dummy.c
new file mode 100644 (file)
index 0000000..800929a
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+// required for compilation of empty MacOSX frameworks ...
diff --git a/skyrix-xml/iCalSaxDriver/COPYING b/skyrix-xml/iCalSaxDriver/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-xml/iCalSaxDriver/COPYRIGHT b/skyrix-xml/iCalSaxDriver/COPYRIGHT
new file mode 100644 (file)
index 0000000..c928419
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2003 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-xml/iCalSaxDriver/ChangeLog b/skyrix-xml/iCalSaxDriver/ChangeLog
new file mode 100644 (file)
index 0000000..b936876
--- /dev/null
@@ -0,0 +1,50 @@
+2004-07-02  Helge Hess  <helge.hess@opengroupware.org>
+
+       * ICalSaxParser.m: added default 'iCalSaxDriverDebugEnabled' to enable
+         debug logs, subminor fixed to exception reason strings (v4.2.8)
+
+2004-06-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * ICalSaxParser.m: cache NSString class, added ability to parse DIR
+         parameters (v4.2.7)
+
+2004-06-28  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.2.6
+       
+       * ICalSaxParser.m: fixed a wrong return
+       
+       * common.h: fixed for non-lF Foundation libraries
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile.preamble, GNUmakefile.postamble: added support for
+         building with GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package. (v4.2.5)
+
+2004-02-25  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile.preamble: fixed for OGo gstep-make (v4.2.4)
+
+2003-12-11  Helge Hess  <helge.hess@opengroupware.org>
+
+       * install into GNUSTEP_INSTALLATION_DIR instead of GNUSTEP_USER_ROOT,
+         split up makefiles (v4.2.3)
+
+2003-08-26  Helge Hess  <helge.hess@skyrix.com>
+
+       * ICalSaxParser.m: added debug logs (v4.2.2)
+
+2002-10-16  Helge Hess  <helge.hess@skyrix.com>
+
+       * ICalSaxParser.m: added support for percent-complete property and
+         several new parameter types
+
+2002-10-14  Helge Hess  <helge.hess@skyrix.com>
+       
+       * ICalSaxParser.m: added some error handling (x-lic-error props)
+       
+2002-10-10  Helge Hess  <helge.hess@skyrix.com>
+
+       * create ChangeLog
+
diff --git a/skyrix-xml/iCalSaxDriver/GNUmakefile b/skyrix-xml/iCalSaxDriver/GNUmakefile
new file mode 100644 (file)
index 0000000..09454d7
--- /dev/null
@@ -0,0 +1,18 @@
+# $Id$
+
+include ../common.make
+
+BUNDLE_NAME        = iCalSaxDriver
+BUNDLE_EXTENSION   = .sax
+BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SaxDrivers
+
+iCalSaxDriver_OBJC_FILES = \
+       ICalSaxParser.m         \
+       NSCalendarDate+ICal.m   \
+       NSString+ICal.m         \
+
+iCalSaxDriver_RESOURCE_FILES = bundle-info.plist
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
diff --git a/skyrix-xml/iCalSaxDriver/GNUmakefile.postamble b/skyrix-xml/iCalSaxDriver/GNUmakefile.postamble
new file mode 100644 (file)
index 0000000..9741795
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
diff --git a/skyrix-xml/iCalSaxDriver/GNUmakefile.preamble b/skyrix-xml/iCalSaxDriver/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..02ba40b
--- /dev/null
@@ -0,0 +1,12 @@
+# $Id$
+
+BUNDLE_LIBS += -lSaxObjC -lical
+
+ADDITIONAL_BUNDLE_LIBS += $(BUNDLE_LIBS)
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_BUILD_DIR)/../SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += -L../SaxObjC/$(GNUSTEP_OBJ_DIR)
+endif
diff --git a/skyrix-xml/iCalSaxDriver/ICalSaxParser.h b/skyrix-xml/iCalSaxDriver/ICalSaxParser.h
new file mode 100644 (file)
index 0000000..f56163f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ICal2_ICalSaxParser_H__
+#define __ICal2_ICalSaxParser_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+
+#include <SaxObjC/SaxXMLReader.h>
+#include <SaxObjC/SaxContentHandler.h>
+#include <SaxObjC/SaxErrorHandler.h>
+#include <SaxObjC/SaxLexicalHandler.h>
+#include <SaxObjC/SaxLocator.h>
+
+@class SaxAttributes;
+
+@interface ICalSaxParser : NSObject < SaxXMLReader >
+{
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+  
+  /* transient */
+  NSStringEncoding encoding;
+  SaxAttributes    *attrs;
+}
+
+@end
+
+#endif /* __ICal2_ICalSaxParser_H__ */
diff --git a/skyrix-xml/iCalSaxDriver/ICalSaxParser.m b/skyrix-xml/iCalSaxDriver/ICalSaxParser.m
new file mode 100644 (file)
index 0000000..6e24134
--- /dev/null
@@ -0,0 +1,1059 @@
+/*
+  Copyright (C) 2000-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$
+
+#include "ICalSaxParser.h"
+#include "NSString+ICal.h"
+#include <SaxObjC/XMLNamespaces.h>
+#include <SaxObjC/SaxAttributes.h>
+#include "common.h"
+#include <ical.h>
+
+/*
+  OPEN: apply default attributes in conformance to xcal !
+*/
+
+@interface ICalSaxParser(Privates)
+
+/* walking */
+
+- (void)logUnknownComponentKind:(icalcomponent *)_comp;
+- (void)walkSubComponents:(icalcomponent *)_comp;
+- (void)walkComponent:(icalcomponent *)_comp;
+
+@end
+
+static BOOL debugOn = NO;
+
+static int _UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
+                        unichar **targetStart, const unichar *targetEnd);
+
+@implementation ICalSaxParser 
+
+static Class StrClass = Nil;
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  StrClass = [NSString class];
+
+  debugOn = [ud boolForKey:@"iCalSaxDriverDebugEnabled"];
+}
+
+- (void)dealloc {
+  [self->contentHandler release];
+  [self->errorHandler   release];
+  [self->attrs          release];
+  [super dealloc];
+}
+
+/* logging of unknown elements etc */
+
+- (void)logUnknownComponentKind:(icalcomponent *)_comp {
+  NSLog(@"%s: cannot process component kind %s",
+        __PRETTY_FUNCTION__,
+        icalenum_component_kind_to_string(icalcomponent_isa(_comp)));
+}
+
+- (void)logUnknownPropertyKind:(icalproperty *)_p {
+  NSLog(@"%s: cannot process property kind %s",
+        __PRETTY_FUNCTION__,
+        icalenum_property_kind_to_string(icalproperty_isa(_p)));
+}
+
+- (void)logUnknownParameterKind:(icalparameter *)_pa {
+  NSLog(@"%s: cannot process parameter kind %s",
+        __PRETTY_FUNCTION__,
+        icalparameter_kind_to_string(icalparameter_isa(_pa)));
+}
+
+/* walking */
+
+- (NSString *)stringForValue:(icalvalue *)_val 
+  ofProperty:(icalproperty *)_p 
+  inComponent:(icalcomponent *)_comp 
+{
+  const unsigned char *s;
+  int len;
+
+  if (_val == NULL) return nil;
+  
+  if ((s = icalvalue_as_ical_string(_val)) == NULL) {
+    /* error ? */
+    NSLog(@"%s: couldn't process an iCal value (component=%s,property=%s).",
+         __PRETTY_FUNCTION__,
+         icalenum_component_kind_to_string(icalcomponent_isa(_comp)),
+         icalenum_property_kind_to_string(icalproperty_isa(_p)));
+    return nil;
+  }
+  
+  if ((len = strlen(s)) == 0) 
+    return @"";
+
+  /* SHOULD USE UTF-8 ?? */
+  return [StrClass stringWithCString:s];
+}
+
+- (void)walkValue:(icalvalue *)_val 
+  ofProperty:(icalproperty *)_p 
+  inComponent:(icalcomponent *)_comp 
+{
+  const unsigned char *s;
+  unichar  *data, *ts;
+  unsigned len;
+  
+  if (_val == NULL) return;
+  
+  /* generic handling for value: pass them as SAX characters ... */
+  
+  if ((s = icalvalue_as_ical_string(_val)) == NULL) {
+    /* error ? */
+    NSLog(@"%s: couldn't process an iCal value (component=%s,property=%s).",
+         __PRETTY_FUNCTION__,
+         icalenum_component_kind_to_string(icalcomponent_isa(_comp)),
+         icalenum_property_kind_to_string(icalproperty_isa(_p)));
+    return;
+  }
+  
+  if ((len = strlen(s)) == 0) {
+    unichar c = 0;
+    data = &c;
+    [self->contentHandler characters:data length:0];
+    return;
+  }
+
+  data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
+  
+  if (_UTF8ToUTF16((void *)&s, (void *)(s + len),
+                   (void *)&ts, ts + (len * sizeof(unichar)))) {
+    free(data);
+    NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
+          __PRETTY_FUNCTION__, __LINE__);
+  }
+  else {
+    [self->contentHandler characters:data length:((unsigned)(ts - data))];
+    free(data);
+  }
+}
+
+- (NSString *)stringForValueParameter:(icalparameter *)_pa {
+  switch (icalparameter_get_value(_pa)) {
+  case ICAL_VALUE_BINARY:     return @"binary";
+  case ICAL_VALUE_BOOLEAN:    return @"boolean";
+  case ICAL_VALUE_DATE:       return @"date";
+  case ICAL_VALUE_DURATION:   return @"duration";
+  case ICAL_VALUE_FLOAT:      return @"float";
+  case ICAL_VALUE_INTEGER:    return @"integer";
+  case ICAL_VALUE_PERIOD:     return @"period";
+  case ICAL_VALUE_RECUR:      return @"recur";
+  case ICAL_VALUE_TEXT:       return @"text";
+  case ICAL_VALUE_TIME:       return @"time";
+  case ICAL_VALUE_URI:        return @"uri";
+  case ICAL_VALUE_ERROR:      return @"error";
+  case ICAL_VALUE_DATETIME:   return @"datetime";
+  case ICAL_VALUE_UTCOFFSET:  return @"utcoffset";
+  case ICAL_VALUE_CALADDRESS: return @"caladdress";
+  default:
+    return nil;
+  }
+}
+- (NSString *)stringForTzIdParameter:(icalparameter *)_pa {
+  const char *s;
+
+  if ((s = icalparameter_get_tzid(_pa)))
+    return [StrClass stringWithCString:s];
+  return nil;
+}
+- (NSString *)stringForXParameter:(icalparameter *)_pa {
+  const char *s;
+
+  if ((s = icalparameter_get_x(_pa)))
+    return [StrClass stringWithCString:s];
+  return nil;
+}
+- (NSString *)stringForCnParameter:(icalparameter *)_pa {
+  const char *s;
+
+  if ((s = icalparameter_get_cn(_pa)))
+    return [StrClass stringWithCString:s];
+  return nil;
+}
+- (NSString *)stringForDirParameter:(icalparameter *)_pa {
+  const char *s;
+  
+  if ((s = icalparameter_get_dir(_pa)))
+    return [StrClass stringWithCString:s];
+  return nil;
+}
+- (NSString *)stringForRoleParameter:(icalparameter *)_pa {
+  switch (icalparameter_get_role(_pa)) {
+  case ICAL_ROLE_CHAIR:
+    return @"CHAIR";
+  case ICAL_ROLE_REQPARTICIPANT:
+    return @"REQ-PART";
+  case ICAL_ROLE_OPTPARTICIPANT:
+    return @"OPT-PART";
+  case ICAL_ROLE_NONPARTICIPANT:
+    return @"NON-PART";
+    
+  case ICAL_ROLE_NONE:
+  case ICAL_ROLE_X:
+  default:
+    return nil;
+  }
+}
+
+- (NSString *)stringForPartStatParameter:(icalparameter *)_pa {
+  switch (icalparameter_get_partstat(_pa)) {
+  case ICAL_PARTSTAT_NEEDSACTION: return @"NEEDSACTION";
+  case ICAL_PARTSTAT_ACCEPTED:    return @"ACCEPTED";
+  case ICAL_PARTSTAT_DECLINED:    return @"DECLINED";
+  case ICAL_PARTSTAT_TENTATIVE:   return @"TENTATIVE";
+  case ICAL_PARTSTAT_DELEGATED:   return @"DELEGATED";
+  case ICAL_PARTSTAT_COMPLETED:   return @"COMPLETED";
+  case ICAL_PARTSTAT_INPROCESS:   return @"INPROCESS";
+    
+  case ICAL_PARTSTAT_X:
+  case ICAL_PARTSTAT_NONE:
+  default:
+    return nil;
+  }
+}
+
+- (NSString *)stringForRsvpParameter:(icalparameter *)_pa {
+  switch (icalparameter_get_rsvp(_pa)) {
+  case ICAL_RSVP_TRUE:  return @"true";
+  case ICAL_RSVP_FALSE: return @"false";
+    
+  case ICAL_RSVP_X:
+  case ICAL_RSVP_NONE:
+  default:
+    return nil;
+  }
+}
+
+- (id<SaxAttributes>)attrsForPropertyParameters:(icalproperty *)_p {
+  /*
+   2.7 Mapping Property Parameters to XML
+
+   The property parameters defined in the standard iCalendar format are
+   represented in the XML representation as an attribute on element
+   types.  The following table specifies the attribute name
+   corresponding to each property parameter.
+
+      +----------------+----------------+-----------+-----------------+
+      | Property       | Attribute      | Attribute | Default         |
+      | Parameter Name | Name           | Type      | Value           |
+      +----------------+----------------+-----------+-----------------+
+      | ALTREP         | altrep         | ENTITY    | IMPLIED         |
+      | CN             | cn             | CDATA     | Null String     |
+      | CUTYPE         | cutype         | NMTOKEN   | INDIVIDUAL      |
+      | DELEGATED-FROM | delegated-from | CDATA     | IMPLIED         |
+      | DELEGATED-TO   | delegated-to   | CDATA     | IMPLIED         |
+      | DIR            | dir            | ENTITY    | IMPLIED         |
+      | ENCODING       | Not Used       | n/a       | n/a             |
+      | FMTTYPE        | fmttype        | CDATA     | REQUIRED        |
+      | FBTYPE         | fbtype         | NMTOKEN   | BUSY            |
+      | LANGUAGE       | language       | CDATA     | IMPLIED         |
+      | MEMBER         | member         | CDATA     | IMPLIED         |
+      | PARTSTAT       | partstat       | NMTOKEN   | NEEDS-ACTION    |
+      | RANGE          | range          | NMTOKEN   | THISONLY        |
+      | RELATED        | related        | NMTOKEN   | START           |
+      | RELTYPE        | reltype        | NMTOKEN   | PARENT          |
+      | ROLE           | role           | NMTOKEN   | REQ-PARTICIPANT |
+      | RSVP           | rsvp           | NMTOKEN   | FALSE           |
+      | SENT-BY        | sent-by        | CDATA     | IMPLIED         |
+      | TZID           | tzid           | CDATA     | IMPLIED         |
+      | VALUE          | value          | NOTATION  | See elements    |
+      +----------------+----------------+-----------+-----------------+
+
+   The inline "ENCODING" property parameter is not needed in the XML
+   representation.  Inline binary information is always included as
+   parsable character data, after first being encoded using the BASE64
+   encoding of [RFC 2045].
+   */
+  icalparameter *pa;
+  int s = 0;
+  
+  for (pa = icalproperty_get_first_parameter(_p, ICAL_ANY_PARAMETER);
+       pa != NULL;
+       pa = icalproperty_get_next_parameter(_p, ICAL_ANY_PARAMETER)) {
+    NSString   *v = nil;
+    NSString   *attrName = nil;
+    
+    switch (icalparameter_isa(pa)) {
+    case ICAL_VALUE_PARAMETER:
+      attrName = @"value";
+      v = [self stringForValueParameter:pa];
+      break;
+      
+    case ICAL_TZID_PARAMETER:
+      attrName = @"tzid";
+      v = [self stringForTzIdParameter:pa];
+      break;
+      
+    case ICAL_X_PARAMETER:
+      attrName = [StrClass stringWithFormat:@"x-unknown-%i", s++];
+      v = [self stringForXParameter:pa];
+      break;
+    case ICAL_CN_PARAMETER:
+      attrName = @"cn";
+      v = [self stringForCnParameter:pa];
+      break;
+    case ICAL_DIR_PARAMETER:
+      attrName = @"dir";
+      v = [self stringForDirParameter:pa];
+      break;
+    case ICAL_RSVP_PARAMETER:
+      attrName = @"rsvp";
+      v = [self stringForRsvpParameter:pa];
+      break;
+    case ICAL_PARTSTAT_PARAMETER:
+      attrName = @"partstat";
+      v = [self stringForPartStatParameter:pa];
+      break;
+    case ICAL_ROLE_PARAMETER:
+      attrName = @"role";
+      v = [self stringForRoleParameter:pa];
+      break;
+      
+    default:
+      [self logUnknownParameterKind:pa];
+      break;
+    }
+    
+    if (attrName == nil) continue;
+    if (v        == nil) continue;
+    
+    if (self->attrs == nil)
+      self->attrs = [[SaxAttributes alloc] init];
+
+    [self->attrs
+        addAttribute:attrName uri:XMLNS_XCAL_01 rawName:attrName 
+        type:@"CDATA"
+        value:v];
+  }
+  
+  return attrs;
+}
+
+- (void)handleErrorProperty:(icalproperty *)_p
+  ofComponent:(icalcomponent *)_comp 
+{
+  switch (icalproperty_isa(_p)) {
+  case ICAL_XLICERROR_PROPERTY:
+    NSLog(@"iCalSaxDriver: found an error property: %s",
+         icalproperty_get_xlicerror(_p));
+    break;
+    
+  default:
+    NSLog(@"iCalSaxDriver: found an unknown error property !");
+    break;
+  }
+}
+
+- (void)walkProperty:(icalproperty *)_p ofComponent:(icalcomponent *)_comp {
+  /*
+2.9 Mapping Component Properties to XML
+
+   Component properties in the standard iCalendar format provide
+   calendar information about the calendar component.  The component
+   properties defined in the standard iCalendar format are represented
+   in the XML representation as element types.  The following tables
+   specify the element types corresponding to each of the properties in
+   the specified property category.
+
+      Descriptive Component Properties
+      +----------------+-------------+-----------------------------+
+      | Component      | Element     | Element Content Model       |
+      | Property Name  | Name        |                             |
+      +----------------+-------------+-----------------------------+
+      | ATTACH         | attach      | extref or b64bin            |
+      |                | extref      | EMPTY                       |
+      |                | b64bin      | PCDATA                      |
+      | CATEGORIES     | categories  | Any number of item elements |
+      |                | item        | PCDATA                      |
+      | CLASS          | class       | PCDATA                      |
+      | COMMENT        | comment     | PCDATA                      |
+      | DESCRIPTION    | description | PCDATA                      |
+      | GEO            | geo         | lat followed by lon element |
+      |                | lat         | PCDATA                      |
+      |                | lon         | PCDATA                      |
+      | LOCATION       | location    | PCDATA                      |
+      | PERCENT        | percent     | PCDATA                      |
+      | PRIORITY       | priority    | PCDATA                      |
+      | RESOURCES      | resources   | Any number of item elements |
+      | STATUS         | status      | PCDATA                      |
+      | SUMMARY        | summary     | PCDATA                      |
+      +----------------+-------------+-----------------------------+
+      Date and Time Component Properties
+      +----------------+------------+-----------------------------+
+      | Component      | Element    | Element Content Model       |
+      | Property Name  | Name       |                             |
+      +----------------+------------+-----------------------------+
+      | COMPLETED      | completed  | PCDATA                      |
+      | DTEND          | dtend      | PCDATA                      |
+      | DUE            | due        | PCDATA                      |
+      | DTSTART        | dtstart    | PCDATA                      |
+      | DURATION       | duration   | PCDATA                      |
+      | FREEBUSY       | freebusy   | PCDATA                      |
+      | TRANSP         | transp     | PCDATA                      |
+      +----------------+------------+-----------------------------+
+
+
+      Time Zone Component Properties
+      +----------------+-------------+-----------------------------+
+      | Component      | Element     | Element Content Model       |
+      | Property Name  | Name        |                             |
+      +----------------+-------------+-----------------------------+
+      | TZID           | tzid        | PCDATA                      |
+      | TZNAME         | tzname      | PCDATA                      |
+      | TZOFFSETFROM   | tzoffsetfrom| PCDATA                      |
+      | TZOFFSETTO     | tzoffsetto  | PCDATA                      |
+      | TZURL          | tzurl       | EMPTY                       |
+      +----------------+-------------+-----------------------------+
+
+
+      Relationship Component Properties
+      +----------------+---------------+--------------------------+
+      | Component      | Element       | Element Content Model    |
+      | Property Name  | Name          |                          |
+      +----------------+---------------+--------------------------+
+      | ATTENDEE       | attendee      | PCDATA                   |
+      | CONTACT        | contact       | PCDATA                   |
+      | ORGANIZER      | organizer     | PCDATA                   |
+      | RECURRENCE-ID  | recurrence-id | PCDATA                   |
+      | RELATED-TO     | related-to    | PCDATA                   |
+      | URL            | url           | EMPTY                    |
+      | UID            | uid           | PCDATA                   |
+      +----------------+---------------+--------------------------+
+
+
+      Recurrence Component Properties
+      +----------------+------------+-----------------------------+
+      | Component      | Element    | Element Content Model       |
+      | Property Name  | Name       |                             |
+      +----------------+------------+-----------------------------+
+      | EXDATE         | exdate     | PCDATA                      |
+      | EXRULE         | exrule     | PCDATA                      |
+      | RDATE          | rdate      | PCDATA                      |
+      | RRULE          | rrule      | PCDATA                      |
+      +----------------+------------+-----------------------------+
+
+
+      Alarm Component Properties
+      +----------------+------------+-----------------------------+
+      | Component      | Element    | Element Content Model       |
+      | Property Name  | Name       |                             |
+      +----------------+------------+-----------------------------+
+      | ACTION         | action     | PCDATA                      |
+      | REPEAT         | repeat     | PCDATA                      |
+      | TRIGGER        | trigger    | PCDATA                      |
+      +----------------+------------+-----------------------------+
+
+
+      Change Management Component Properties
+      +----------------+---------------+--------------------------+
+      | Component      | Element       | Element Content Model    |
+      | Property Name  | Name          |                          |
+      +----------------+---------------+--------------------------+
+      | CREATED        | created       | PCDATA                   |
+      | DTSTAMP        | dtstamp       | PCDATA                   |
+      | LAST-MODIFIED  | last-modified | PCDATA                   |
+      | SEQUENCE       | sequence      | PCDATA                   |
+      +----------------+---------------+--------------------------+
+
+
+      Miscellaneous Component Properties
+      +----------------+----------------+-------------------------+
+      | Component      | Element        | Element Content Model   |
+      | Property Name  | Name           |                         |
+      +----------------+----------------+-------------------------+
+      | REQUEST-STATUS | request-status | PCDATA                  |
+      +----------------+----------------+-------------------------+
+  */
+  NSString *tagName = nil;
+  
+  if (_p == NULL) return;
+  
+  switch (icalproperty_isa(_p)) {
+  case ICAL_ACTION_PROPERTY:        tagName = @"action";         break;
+  case ICAL_ATTENDEE_PROPERTY:      tagName = @"attendee";       break;
+  case ICAL_CLASS_PROPERTY:         tagName = @"class";          break;
+  case ICAL_COMMENT_PROPERTY:       tagName = @"comment";        break;
+  case ICAL_COMPLETED_PROPERTY:     tagName = @"completed";      break;
+  case ICAL_CONTACT_PROPERTY:       tagName = @"contact";        break;
+  case ICAL_CREATED_PROPERTY:       tagName = @"created";        break;
+  case ICAL_DESCRIPTION_PROPERTY:   tagName = @"description";    break;
+  case ICAL_DTEND_PROPERTY:         tagName = @"dtend";          break;
+  case ICAL_DTSTAMP_PROPERTY:       tagName = @"dtstamp";        break;
+  case ICAL_DTSTART_PROPERTY:       tagName = @"dtstart";        break;
+  case ICAL_DUE_PROPERTY:           tagName = @"due";            break;
+  case ICAL_DURATION_PROPERTY:      tagName = @"duration";       break;
+  case ICAL_FREEBUSY_PROPERTY:      tagName = @"freebusy";       break;
+  case ICAL_EXDATE_PROPERTY:        tagName = @"exdate";         break;
+  case ICAL_EXRULE_PROPERTY:        tagName = @"exrule";         break;
+  case ICAL_RDATE_PROPERTY:         tagName = @"rdate";          break;
+  case ICAL_RRULE_PROPERTY:         tagName = @"rrule";          break;
+  case ICAL_LASTMODIFIED_PROPERTY:  tagName = @"last-modified";  break;
+  case ICAL_LOCATION_PROPERTY:      tagName = @"location";       break;
+  case ICAL_ORGANIZER_PROPERTY:     tagName = @"organizer";      break;
+  case ICAL_PRIORITY_PROPERTY:      tagName = @"priority";       break;
+  case ICAL_REPEAT_PROPERTY:        tagName = @"repeat";         break;
+  case ICAL_RELATEDTO_PROPERTY:     tagName = @"related-to";     break;
+  case ICAL_RECURRENCEID_PROPERTY:  tagName = @"recurrence-id";  break;
+  case ICAL_REQUESTSTATUS_PROPERTY: tagName = @"request-status"; break;
+  case ICAL_SEQUENCE_PROPERTY:      tagName = @"sequence";       break;
+  case ICAL_STATUS_PROPERTY:        tagName = @"status";         break;
+  case ICAL_SUMMARY_PROPERTY:       tagName = @"summary";        break;
+  case ICAL_TRANSP_PROPERTY:        tagName = @"transp";         break;
+  case ICAL_TRIGGER_PROPERTY:       tagName = @"trigger";        break;
+  case ICAL_TZID_PROPERTY:          tagName = @"tzid";           break;
+  case ICAL_TZNAME_PROPERTY:        tagName = @"tzname";         break;
+  case ICAL_TZOFFSETFROM_PROPERTY:  tagName = @"tzoffsetfrom";   break;
+  case ICAL_TZOFFSETTO_PROPERTY:    tagName = @"tzoffsetto";     break;
+  case ICAL_TZURL_PROPERTY:         tagName = @"tzurl";          break;
+  case ICAL_UID_PROPERTY:           tagName = @"uid";            break;
+  case ICAL_URL_PROPERTY:           tagName = @"url";            break;
+  case ICAL_PERCENTCOMPLETE_PROPERTY:  
+    tagName = @"percent-complete";        
+    break;
+    
+    /* special handling in xcal !! check ! */
+
+  case ICAL_GEO_PROPERTY:
+    tagName = @"geo";   /* lat followed by lon element */
+    //tagName = @"lat";
+    //tagName = @"lon";
+    break;
+    
+  case ICAL_RESOURCES_PROPERTY:    
+    /* content model: Any number of item elements */
+    tagName = @"resources";        
+    break;
+  case ICAL_CATEGORIES_PROPERTY:    
+    /* content model: Any number of item elements */
+    tagName = @"categories";        
+    break;
+
+  case ICAL_ATTACH_PROPERTY: 
+    tagName = @"attach";    /* content model: extref || b64bin */
+    // tagName = @"extref"; /* content model: empty  */
+    // tagName = @"b64bin"; /* content model: pcdata */
+    break;
+    
+    /* attribute properties */
+  case ICAL_PRODID_PROPERTY:
+  case ICAL_METHOD_PROPERTY:
+  case ICAL_VERSION_PROPERTY:
+  case ICAL_CALSCALE_PROPERTY:
+    return;
+    
+    /* extension properties */
+  case ICAL_XLICERROR_PROPERTY:
+    [self handleErrorProperty:_p ofComponent:_comp];
+    return;
+    
+  case ICAL_X_PROPERTY:
+    tagName = [StrClass stringWithCString:icalproperty_get_x_name(_p)];
+    break;
+    
+  default:
+    [self logUnknownPropertyKind:_p];
+    return;
+  }
+  
+  [self->attrs clear];
+  [self->contentHandler
+       startElement:tagName
+       namespace:XMLNS_XCAL_01
+       rawName:tagName
+       attributes:[self attrsForPropertyParameters:_p]];
+  [self->attrs clear];
+  
+  switch (icalproperty_isa(_p)) {
+    case ICAL_RRULE_PROPERTY: {
+      /* this should unparse the rrule parameters as-is */
+      NSLog(@"iCalSaxDriver: recurrence rules are not properly handled yet");
+      break;
+    }
+    
+    default:
+      /* generic handling for value: pass them as SAX characters ... */
+      [self walkValue:icalproperty_get_value(_p) 
+           ofProperty:_p inComponent:_comp];
+  }
+  
+  [self->contentHandler
+       endElement:tagName
+       namespace:XMLNS_XCAL_01
+       rawName:tagName];
+}
+
+- (id<SaxAttributes>)attrPropertiesOfComponent:(icalcomponent *)_comp {
+  icalproperty *p;
+  
+  for (p = icalcomponent_get_first_property(_comp,ICAL_ANY_PROPERTY);
+       p != nil;
+       p = icalcomponent_get_next_property(_comp,ICAL_ANY_PROPERTY)) {
+    NSString   *v = nil;
+    NSString   *attrName = nil;
+    
+    switch (icalproperty_isa(p)) {
+    case ICAL_PRODID_PROPERTY:    attrName = @"prodid";   break;
+    case ICAL_METHOD_PROPERTY:    attrName = @"method";   break;
+    case ICAL_VERSION_PROPERTY:   attrName = @"version";  break;
+    case ICAL_CALSCALE_PROPERTY:  attrName = @"calscale"; break;
+    default:
+      continue;
+    }
+    
+    if (attrName == nil) continue;
+    
+    v = [self stringForValue:icalproperty_get_value(p)
+             ofProperty:p
+             inComponent:_comp];
+    
+    if (v == nil) continue;
+    
+    if (self->attrs == nil)
+      self->attrs = [[SaxAttributes alloc] init];
+    
+    [self->attrs
+        addAttribute:attrName uri:XMLNS_XCAL_01 rawName:attrName 
+        type:@"CDATA"
+        value:v];
+  }
+  return self->attrs;
+}
+
+- (void)walkPropertiesOfComponent:(icalcomponent *)_comp {
+  icalproperty *p;
+  
+  for (p = icalcomponent_get_first_property(_comp,ICAL_ANY_PROPERTY);
+       p != nil;
+       p = icalcomponent_get_next_property(_comp,ICAL_ANY_PROPERTY)) {
+    [self walkProperty:p ofComponent:_comp];
+  }
+}
+
+- (void)walkSubComponents:(icalcomponent *)_comp {
+  icalcomponent *c;
+  
+  for(c = icalcomponent_get_first_component(_comp, ICAL_ANY_COMPONENT);
+      c != NULL;
+      c = icalcomponent_get_next_component(_comp, ICAL_ANY_COMPONENT)) {
+    [self walkComponent:c];
+  }
+}
+
+- (void)walkComponent:(icalcomponent *)_comp {
+  /*
+      Component Structuring Properties
+      +----------------+------------+-------------------------------+
+      | Component      | Element    | Element Content Model         |
+      | Property Name  | Name       |                               |
+      +----------------+------------+-------------------------------+
+      | Multiple iCal- | iCalendar  | One or more iCal elements     |
+      | endar objects  |            |                               |
+      | VCALENDAR      | vcalendar  | calcomp parameter entity      |
+      | VEVENT         | vevent     | vevent.opt1 and vevent.optm   |
+      |                |            | parameter entity and valarm   |
+      |                |            | element                       |
+      | VTODO          | vtodo      | vtodo.opt1 and vtodo.optm     |
+      |                |            | parameter entity and valarm   |
+      |                |            | element                       |
+      | VJOURNAL       | vjournal   | vjournal.opt1 and             |
+      |                |            | vjournal.optm parameter       |
+      |                |            | entity                        |
+      | VFREEBUSY      | vfreebusy  | vfreebusy.opt1 and            |
+      |                |            | vfreebusy.optm parameter      |
+      |                |            | entity                        |
+      | VTIMEZONE      | vtimezone  | vtimezone.man,                |
+      |                |            | vtimezone.opt1,               |
+      |                |            | vtimezone.mann parameter      |
+      |                |            | entity                        |
+      | STANDARD       | standard   | standard.man or standard.optm |
+      |                |            | entity                        |
+      | DAYLIGHT       | daylight   | daylight.man or daylight.optm |
+      |                |            | entity                        |
+      | VALARM         | valarm     | valarm.audio, valarm.display, |
+      |                |            | valarm.email and              |
+      |                |            | valarm.procedure entity       |
+      +----------------+------------+-------------------------------+
+  */
+  NSString *tagName = nil;
+  
+  switch (icalcomponent_isa(_comp)) {
+    case ICAL_VCALENDAR_COMPONENT:
+      tagName = @"vcalendar";
+      break;
+    case ICAL_VFREEBUSY_COMPONENT:
+      tagName = @"vfreebusy";
+      break;
+    case ICAL_VEVENT_COMPONENT:
+      tagName = @"vevent";
+      break;
+    case ICAL_VTODO_COMPONENT:
+      tagName = @"vtodo";
+      break;
+    case ICAL_VJOURNAL_COMPONENT:
+      tagName = @"vjournal";
+      break;
+    case ICAL_VTIMEZONE_COMPONENT:
+      tagName = @"vtimezone";
+      break;
+    case ICAL_VALARM_COMPONENT:
+      tagName = @"valarm";
+      break;
+
+    case ICAL_XSTANDARD_COMPONENT:
+      tagName = @"standard"; // in xcal as "standard" component ?
+      break;
+    case ICAL_XDAYLIGHT_COMPONENT:
+      tagName = @"daylight"; // in xcal as "daylight" component ?
+      break;
+      
+    case ICAL_XROOT_COMPONENT:
+      /* root component for a file with multiple components */
+      tagName = @"iCalendar";
+      break;
+      
+    default:
+      [self logUnknownComponentKind:_comp];
+      return;
+  }
+  
+  /*
+    attributes:
+      calscale - cdata   - implied
+      method   - nmtoken - publish
+      version  - cdata   - required
+      prodid   - cdata   - implied
+
+    vcalendar: language - cdata - implied
+  */
+  
+  [self->attrs clear];
+  [self->contentHandler
+       startElement:tagName
+       namespace:XMLNS_XCAL_01
+       rawName:tagName
+       attributes:[self attrPropertiesOfComponent:_comp]];
+  [self->attrs clear];
+
+  [self walkPropertiesOfComponent:_comp];
+  
+  [self walkSubComponents:_comp];
+  
+  [self->contentHandler
+       endElement:tagName
+       namespace:XMLNS_XCAL_01
+       rawName:tagName];
+}
+
+- (void)walkRootComponent:(icalcomponent *)_comp {
+  [self->contentHandler startDocument];
+  [self->contentHandler startPrefixMapping:@"" uri:XMLNS_XCAL_01];
+  
+  [self walkComponent:_comp];
+  
+  [self->contentHandler endPrefixMapping:@""];
+  [self->contentHandler endDocument];
+}
+
+/* parsing */
+
+- (void)_reportICalErrno:(icalerrorenum)_errcode {
+  switch (_errcode) {
+  case ICAL_NO_ERROR:
+    /* well, no error ... */
+    break;
+    
+  case ICAL_BADARG_ERROR:
+  case ICAL_NEWFAILED_ERROR:
+  case ICAL_ALLOCATION_ERROR:
+  case ICAL_MALFORMEDDATA_ERROR:
+  case ICAL_PARSE_ERROR:
+  case ICAL_INTERNAL_ERROR:
+    /* Like assert --internal consist. prob */
+  case ICAL_FILE_ERROR:
+  case ICAL_USAGE_ERROR:
+  case ICAL_UNIMPLEMENTED_ERROR:
+  case ICAL_UNKNOWN_ERROR:
+    /* Used for problems in input to icalerror_strerror()*/
+    
+  default: {
+    SaxParseException *e;
+    const char *errstr;
+    NSString   *s;
+    
+    errstr = icalerror_strerror(_errcode);
+    if (debugOn) {
+      NSLog(@"%s: generic ical parsing error(code=%i): %s",
+           __PRETTY_FUNCTION__, _errcode, errstr);
+    }
+    s = [[StrClass alloc] initWithFormat:@"generic libical error %i: %s",
+                           _errcode, errstr];
+    e = (id)[SaxParseException exceptionWithName:@"SaxParseException"
+                               reason:s
+                               userInfo:nil];
+    [s release];
+    [self->errorHandler fatalError:e];
+    break;
+  }
+  }
+}
+
+- (BOOL)parseString:(NSString *)_string {
+  icalcomponent *c;
+  const char    *str;
+
+  if (debugOn) {
+    NSLog(@"%s: parse string (len=%i)", __PRETTY_FUNCTION__, 
+         [_string length]);
+  }
+  if (_string == nil) {
+    if (debugOn) NSLog(@"%s:   got no string ...", __PRETTY_FUNCTION__);
+    return NO;
+  }
+  if ((str = [_string icalCString]) == NULL) {
+    if (debugOn) NSLog(@"%s:   got no icalCString ...", __PRETTY_FUNCTION__);
+    return NO;
+  }
+
+  // printf("STR: '%s'(%i)\n", str, strlen(str));
+  
+  if ((c = icalparser_parse_string(str)) == NULL) {
+    /* parsing failed ... */
+    if (debugOn)
+      NSLog(@"%s:   libical parsing failed ...", __PRETTY_FUNCTION__);
+    [self _reportICalErrno:icalerrno];
+    return NO;
+  }
+  
+  [self walkRootComponent:c];
+  
+  return YES;
+}
+- (BOOL)parseData:(NSData *)_data {
+  icalcomponent *c;
+  unsigned char *str;
+  unsigned len;
+  
+  if (_data == nil) return NO;
+
+  len = [_data length];
+  str = malloc(len + 10);
+  [_data getBytes:str length:len];
+  str[len] = '\0';
+  
+  if ((c = icalparser_parse_string(str)) == NULL)
+    /* parsing failed ... */
+    return NO;
+  
+  [self walkRootComponent:c];
+  
+  return YES;
+}
+
+- (void)parseFileAtPath:(NSString *)_path encoding:(NSStringEncoding)_enc {
+  NSAutoreleasePool *pool;
+  NSData   *data;
+  NSString *s;
+
+  if (debugOn)
+    NSLog(@"%s: parse file: %@", __PRETTY_FUNCTION__, _path);
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  data = [[NSData alloc] initWithContentsOfMappedFile:_path];
+  if (data == nil) {
+    /* throw Sax Exception ! */
+    if (debugOn)
+      NSLog(@"%s:   could not map data: %@", __PRETTY_FUNCTION__, _path);
+    return;
+  }
+  
+  s = [[[StrClass alloc] initWithData:data encoding:_enc] autorelease];
+  [data release];
+  
+  [self parseString:s];
+  
+  [pool release];
+}
+- (void)parseFileAtPath:(NSString *)_path {
+  [self parseFileAtPath:_path encoding:NSUTF8StringEncoding];
+}
+
+/* SaxXMLReader */
+
+/* features & properties */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value {
+}
+- (BOOL)feature:(NSString *)_name {
+  return NO;
+}
+- (void)setProperty:(NSString *)_name to:(id)_value {
+}
+- (id)property:(NSString *)_name {
+  return nil;
+}
+
+/* handlers */
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  ASSIGN(self->contentHandler, _handler);
+}
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
+}
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  ASSIGN(self->errorHandler, _handler);
+}
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
+}
+- (id<NSObject,SaxContentHandler>)contentHandler {
+  return self->contentHandler;
+}
+- (id<NSObject,SaxDTDHandler>)dtdHandler {
+  return nil;
+}
+- (id<NSObject,SaxErrorHandler>)errorHandler {
+  return self->errorHandler;
+}
+- (id<NSObject,SaxEntityResolver>)entityResolver {
+  return nil;
+}
+
+/* parsing */
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
+  if (debugOn)
+    NSLog(@"%s: parse(%@): %@", __PRETTY_FUNCTION__, _sysId, _source);
+  
+  if (_source == nil) {
+    /* no source ??? */
+    if (debugOn) NSLog(@"%s: not source: %@)", __PRETTY_FUNCTION__, _sysId);
+    return;
+  }
+
+  if ([_source isKindOfClass:StrClass]) {
+    /* convert strings to UTF8 data */
+    if (_sysId == nil) _sysId = @"<string>";
+    if (debugOn) {
+      NSLog(@"%s:   parse string (len=%i))", __PRETTY_FUNCTION__, 
+           [_source length]);
+    }
+    [self parseString:_source];
+    return;
+  }
+  
+  if ([_source isKindOfClass:[NSURL class]]) {
+    if (_sysId == nil) _sysId = [_source absoluteString];
+    if (debugOn) NSLog(@"%s:  load URL: %@", __PRETTY_FUNCTION__, _source);
+    _source = [_source resourceDataUsingCache:NO];
+  }
+  else if ([_source isKindOfClass:[NSData class]]) {
+    if (_sysId == nil) _sysId = @"<data>";
+  }
+  else {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    if (debugOn) {
+      NSLog(@"%s:  unknown source class: %@", __PRETTY_FUNCTION__, 
+           NSStringFromClass([_source class]));
+    }
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _source ? _source : @"<nil>", @"source",
+                         self,                         @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"cannot handle datasource"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+    return;
+  }
+  
+  if (debugOn) {
+    NSLog(@"%s:   parse data (len=%i))", __PRETTY_FUNCTION__, 
+         [_source length]);
+  }
+  [self parseData:_source];
+}
+
+- (void)parseFromSource:(id)_source {
+  [self parseFromSource:_source systemId:nil];
+}
+
+- (void)parseFromSystemId:(NSString *)_sysId {
+  if (debugOn)
+    NSLog(@"%s: parse ID: %@", __PRETTY_FUNCTION__, _sysId);
+  
+  if (![_sysId hasPrefix:@"file:"]) {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    NSURL *url;
+    
+    if ((url = [NSURL URLWithString:_sysId])) {
+      [self parseFromSource:url systemId:_sysId];
+      return;
+    }
+
+    if (debugOn)
+      NSLog(@"%s:   could not parse ID: %@", __PRETTY_FUNCTION__, _sysId);
+  
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _sysId ? _sysId : @"<nil>", @"systemID",
+                         self,                       @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"cannot handle system-id"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+    return;
+  }
+
+  /* cut off file:// */
+  if ([_sysId hasPrefix:@"file://"])
+    _sysId = [_sysId substringFromIndex:7];
+  else
+    _sysId = [_sysId substringFromIndex:5];
+  
+  if (debugOn)
+    NSLog(@"%s:   parse file: %@", __PRETTY_FUNCTION__, _sysId);
+  [self parseFileAtPath:_sysId];
+}
+
+@end /* ICalSaxParser */
+
+@interface iCalSaxDriver : ICalSaxParser
+@end
+
+@implementation iCalSaxDriver
+@end
+
+#include "unicode.h"
diff --git a/skyrix-xml/iCalSaxDriver/NSCalendarDate+ICal.h b/skyrix-xml/iCalSaxDriver/NSCalendarDate+ICal.h
new file mode 100644 (file)
index 0000000..c2056f2
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ICal2_NSCalendarDate_ICal_H__
+#define __ICal2_NSCalendarDate_ICal_H__
+
+#import <Foundation/NSCalendarDate.h>
+#include <ical.h>
+
+@class NSTimeZone;
+
+@interface NSCalendarDate(ICalValue)
+
+- (id)initWithICalTime:(struct icaltimetype)_dt timeZone:(NSTimeZone *)_tz;
+- (id)initWithICalTime:(struct icaltimetype)_dt;
+
+- (id)initWithICalDate:(struct icaltimetype)_dt timeZone:(NSTimeZone *)_tz;
+- (id)initWithICalDate:(struct icaltimetype)_dt;
+
+- (NSTimeZone *)timeZoneFromICalTime:(struct icaltimetype *)_dt
+  defaultTimeZone:(NSTimeZone *)_tz;
+
+/* libical values */
+
+- (id)initWithICalValueHandle:(icalvalue *)_handle;
+- (id)initWithICalValueOfProperty:(icalproperty *)_prop;
+
+/* durations */
+
+- (NSCalendarDate *)dateByApplyingICalDuration:(struct icaldurationtype)_dur;
+
+/* represention */
+
+- (NSString *)icalStringWithTimeZone:(NSTimeZone *)_tz;
+- (NSString *)icalString;
+
+@end
+
+#endif /* __ICal2_NSCalendarDate_ICal_H__ */
diff --git a/skyrix-xml/iCalSaxDriver/NSCalendarDate+ICal.m b/skyrix-xml/iCalSaxDriver/NSCalendarDate+ICal.m
new file mode 100644 (file)
index 0000000..fb7ef4c
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+#include <ical.h>
+
+static NSTimeZone *gmt = nil;
+static inline void _setupGMT(void) {
+  if (gmt == nil)
+    gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+}
+
+@implementation NSCalendarDate(ICalValue)
+
+- (NSTimeZone *)timeZoneFromICalTime:(struct icaltimetype *)_dt
+  defaultTimeZone:(NSTimeZone *)_tz
+{
+  _setupGMT();
+
+  if (_dt->is_utc)
+    return gmt;
+
+  if (_tz)
+    return _tz;
+  
+  NSLog(@"WARNING(%s): using localtimezone !", __PRETTY_FUNCTION__);
+  return [NSTimeZone localTimeZone];
+}
+
+- (id)initWithICalDate:(struct icaltimetype)_dt timeZone:(NSTimeZone *)_tz {
+  NSTimeZone *tz;
+  
+  tz = [self timeZoneFromICalTime:&_dt defaultTimeZone:_tz];
+  
+  self = [self initWithYear:_dt.year month:_dt.month day:_dt.day
+               hour:12 minute:0 second:0
+               timeZone:_tz];
+  return self;
+}
+
+- (id)initWithICalTime:(struct icaltimetype)_dt timeZone:(NSTimeZone *)_tz {
+  NSTimeZone *tz;
+  
+  if (_dt.is_date)
+    return [self initWithICalDate:_dt timeZone:_tz];
+  
+  tz = [self timeZoneFromICalTime:&_dt defaultTimeZone:_tz];
+  
+  
+  self = [self initWithYear:_dt.year month:_dt.month day:_dt.day
+               hour:_dt.hour minute:_dt.minute second:_dt.second
+               timeZone:tz];
+  return self;
+}
+
+- (id)initWithICalDate:(struct icaltimetype)_dt {
+  _setupGMT();
+  return [self initWithICalDate:_dt timeZone:gmt];
+}
+- (id)initWithICalTime:(struct icaltimetype)_dt {
+  _setupGMT();
+  return [self initWithICalTime:_dt timeZone:gmt];
+}
+
+- (id)initWithICalValueHandle:(icalvalue *)_handle {
+  if (_handle == NULL) {
+    RELEASE(self);
+    return nil;
+  }
+  return [self initWithICalTime:icalvalue_get_datetime(_handle)];
+}
+- (id)initWithICalValueOfProperty:(icalproperty *)_prop {
+  icalvalue *val;
+  
+  if (_prop == NULL) {
+    RELEASE(self);
+    return nil;
+  }
+
+  if ((val = icalproperty_get_value(_prop)) == NULL) {
+    NSLog(@"%s: ical property has no value ??", __PRETTY_FUNCTION__);
+    RELEASE(self);
+    return nil;
+  }
+  
+  return [self initWithICalValueHandle:val];
+}
+
+/* durations */
+
+- (NSCalendarDate *)dateByApplyingICalDuration:(struct icaldurationtype)_dur {
+  if (_dur.is_neg) {
+    return [self dateByAddingYears:0 months:0
+                 days:-(_dur.days + (_dur.weeks * 7))
+                 hours:-(_dur.hours)
+                 minutes:-(_dur.minutes)
+                 seconds:-(_dur.seconds)];
+  }
+  else {
+    return [self dateByAddingYears:0 months:0
+                 days:(_dur.days + (_dur.weeks * 7))
+                 hours:_dur.hours minutes:_dur.minutes seconds:_dur.seconds];
+  }
+}
+
+/* represention */
+
+static NSString *gmtcalfmt = @"%Y%m%dT%H%M00Z";
+
+- (NSString *)icalStringInGMT {
+  NSTimeZone *oldtz;
+  NSString   *s;
+  _setupGMT();
+  
+  /* set GMT as timezone */
+  oldtz = [[self timeZone] retain];
+  if (oldtz == gmt) {
+    [oldtz release];
+    oldtz = nil;
+  }
+  else {
+    [self setTimeZone:gmt];
+  }
+  
+  /* calc string */
+  s = [self descriptionWithCalendarFormat:gmtcalfmt];
+  
+  /* restore old timezone */
+  if (oldtz) {
+    [self setTimeZone:oldtz];
+    [oldtz release];
+  }
+  
+  return s;
+}
+
+- (NSString *)icalStringWithTimeZone:(NSTimeZone *)_tz {
+  _setupGMT();
+  
+  if (_tz == gmt || _tz == nil)
+    return [self icalStringInGMT];
+  else if ([_tz isEqual:gmt])
+    return [self icalStringInGMT];
+  else {
+    /* not in GMT */
+    NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
+          __PRETTY_FUNCTION__, _tz);
+    return [self icalStringInGMT];
+  }
+}
+
+- (NSString *)icalString {
+  _setupGMT();
+  return [self icalStringWithTimeZone:gmt];
+}
+
+@end /* NSDate(ICalValue) */
diff --git a/skyrix-xml/iCalSaxDriver/NSString+ICal.h b/skyrix-xml/iCalSaxDriver/NSString+ICal.h
new file mode 100644 (file)
index 0000000..96bc29c
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __ICal2_NSString_ICal_H__
+#define __ICal2_NSString_ICal_H__
+
+#import <Foundation/NSString.h>
+#include <ical.h>
+
+@interface NSString(ICalValue)
+
+/* libical internal C-strings */
+
++ (NSStringEncoding)libicalStringEncoding;
+- (id)initWithICalCString:(const char *)_cstr;
+- (const char *)icalCString;
+- (NSString *)icalString;
+
+/* libical values */
+
+- (id)initWithICalValueHandle:(icalvalue *)_handle;
+- (id)initWithICalValueOfProperty:(icalproperty *)_prop;
+
+@end /* NSString(ICalValue) */
+
+#endif /* __ICal2_NSString_ICal_H__ */
diff --git a/skyrix-xml/iCalSaxDriver/NSString+ICal.m b/skyrix-xml/iCalSaxDriver/NSString+ICal.m
new file mode 100644 (file)
index 0000000..b56593d
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "NSString+ICal.h"
+#include "common.h"
+#include <ical.h>
+
+@implementation NSString(ICalCString)
+
+- (const char *)icalCString {
+  NSStringEncoding enc;
+  
+  enc = [[self class] libicalStringEncoding];
+  
+  if (enc == NSUTF8StringEncoding)
+    return [self UTF8String];
+  else if (enc == [NSString defaultCStringEncoding])
+    return [self cString];
+  else
+    return [[self dataUsingEncoding:enc] bytes];
+}
+
+- (NSString *)icalString {
+  return self;
+}
+
+@end /* NSString(ICalCString) */
+
+@implementation NSObject(TemporaryStringInit)
+
++ (NSStringEncoding)libicalStringEncoding {
+  return NSUTF8StringEncoding;
+}
+
+- (id)initWithICalCString:(const char *)_cstr {
+  NSStringEncoding enc;
+
+  if (_cstr == NULL) {
+    RELEASE(self);
+    return nil;
+  }
+  
+  enc = [[self class] libicalStringEncoding];
+  
+  if (enc == NSUTF8StringEncoding)
+    return [(NSString *)self initWithUTF8String:_cstr];
+  else if (enc == [[self class] defaultCStringEncoding])
+    return [(NSString *)self initWithCString:_cstr];
+  else {
+    NSData *d;
+    
+    d = [[NSData alloc] initWithBytes:_cstr length:strlen(_cstr)];
+    self = [(NSString *)self initWithData:d encoding:enc];
+    RELEASE(d);
+    
+    return self;
+  }
+  
+  return nil;
+}
+
+- (id)initWithICalValueHandle:(icalvalue *)_handle {
+  const char *s;
+  
+  if (_handle == NULL) {
+    RELEASE(self);
+    return nil;
+  }
+  if ((s = icalvalue_as_ical_string(_handle)) == NULL) {
+    RELEASE(self);
+    return nil;
+  }
+  return [self initWithICalCString:s];
+}
+
+- (id)initWithICalValueOfProperty:(icalproperty *)_prop {
+  icalvalue *val;
+
+  if (_prop == nil) {
+    RELEASE(self);
+    return nil;
+  }
+  
+  if ((val = icalproperty_get_value(_prop)) == NULL) {
+    NSLog(@"%s: ical property has no value ??", __PRETTY_FUNCTION__);
+    RELEASE(self);
+    return nil;
+  }
+  
+  return [self initWithICalValueHandle:val];
+}
+
+@end /* NSObject(TemporaryStringInit) */
+
diff --git a/skyrix-xml/iCalSaxDriver/README b/skyrix-xml/iCalSaxDriver/README
new file mode 100644 (file)
index 0000000..872cfb9
--- /dev/null
@@ -0,0 +1,37 @@
+# $Id$
+
+Overview
+========
+
+An SaxObjC driver for iCalendar files. It basically maps iCal 2.0
+components, properties and paraemters 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).
+
+ToDo
+====
+
+The driver is by no means complete or 100% compliant to xCal (which
+isn't final anyway ...). So:
+- improve error handling (SaxExceptions !)
+- make the driver fully xCal compliant
+- recurrence rules !!!
+- implement all components supported by libical
+- make it as fast as possible ;-) (probably most gains can be made by
+  improving DOM, not iCalSaxDriver ...)
+
+Examples
+========
+
+To "convert" an iCalendar to xCal (the test programs print out some XML):
+
+  saxxml -XMLReader iCalSaxDriver test1.ics
+  domxml -XMLReader iCalSaxDriver -xml  test1.ics
+
+To "convert" an iCalendar to PYX:
+
+  domxml -XMLReader iCalSaxDriver -pyx  test1.ics
diff --git a/skyrix-xml/iCalSaxDriver/TODO b/skyrix-xml/iCalSaxDriver/TODO
new file mode 100644 (file)
index 0000000..fb5e99a
--- /dev/null
@@ -0,0 +1,22 @@
+# $Id: TODO,v 1.2 2004/02/25 12:24:36 helge Exp $
+
+iCalSaxDriver Todos ...
+=======================
+
+report errors as SAX exceptions ...
+- _reportICalErrno:
+
+handle iCal entities which do not properly close vtimezone
+components (for example Entourage ...)
+
+
+With iCal 1.5.2:
+---snip---
+-[ICalSaxParser logUnknownParameterKind:]: cannot process parameter kind CUTYPE
+-[ICalSaxParser logUnknownParameterKind:]: cannot process parameter kind CUTYPE
+-[ICalSaxParser logUnknownParameterKind:]: cannot process parameter kind CUTYPE
+---snap---
+---snip---
+ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;ROLE=OPT-PARTICIPANT;RS
+ VP=TRUE:MAILTO:helge.hess@skyrix.com
+---snap---
diff --git a/skyrix-xml/iCalSaxDriver/Version b/skyrix-xml/iCalSaxDriver/Version
new file mode 100644 (file)
index 0000000..28292b5
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=8
diff --git a/skyrix-xml/iCalSaxDriver/bundle-info.plist b/skyrix-xml/iCalSaxDriver/bundle-info.plist
new file mode 100644 (file)
index 0000000..1a8f300
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  requires = {
+    bundleManagerVersion = 1;
+    classes = ( { name = NSObject; } );
+  };
+  
+  provides = {
+    SAXDrivers = ( 
+      { 
+        name        = "iCalSaxDriver";
+        sourceTypes = ( "text/calendar" ); 
+      }
+    );
+    classes = ( 
+      { name = "ICalSaxParser"; },
+      { name = "iCalSaxDriver"; } 
+    );
+  };
+}
diff --git a/skyrix-xml/iCalSaxDriver/common.h b/skyrix-xml/iCalSaxDriver/common.h
new file mode 100644 (file)
index 0000000..93a3a7a
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2000-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$
+
+#ifndef __ICal_common_H__
+#define __ICal_common_H__
+
+#import <Foundation/Foundation.h>
+
+#if !LIB_FOUNDATION_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#  include <NGExtensions/NSString+Ext.h>
+#endif
+
+#endif /* __ICal_common_H__ */
diff --git a/skyrix-xml/iCalSaxDriver/iCalSaxDriver-Info.plist b/skyrix-xml/iCalSaxDriver/iCalSaxDriver-Info.plist
new file mode 100644 (file)
index 0000000..100cf0d
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>iCalSaxDriver</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>org.opengroupware.xml.iCalSaxDriver</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+       <key>NSPrincipalClass</key>
+       <string>iCalSaxDriver</string>
+</dict>
+</plist>
diff --git a/skyrix-xml/iCalSaxDriver/test1.ics b/skyrix-xml/iCalSaxDriver/test1.ics
new file mode 100644 (file)
index 0000000..86aad3b
--- /dev/null
@@ -0,0 +1,56 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+X-WR-TIMEZONE;VALUE=TEXT:Europe/Berlin
+PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
+X-WR-CALNAME;VALUE=TEXT:shire-cal1
+X-WR-RELCALID;VALUE=TEXT:C3CBA0E4-DBCC-11D6-A381-00039340AF4A
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20021008T155243Z
+SUMMARY:work
+UID:C3CB87C0-DBCC-11D6-A381-00039340AF4A
+DTSTART;TZID=Europe/Berlin:20021009T120000
+DURATION:PT3H45M
+END:VEVENT
+BEGIN:VEVENT
+ATTENDEE;CN=Anja Berlin:mailto:anja.berlin@regiocom.net
+ATTENDEE;CN=Marcus Müller:mailto:mm@codeon.de
+DTSTAMP:20021009T211904Z
+SUMMARY:trink
+UID:C3CB8E9A-DBCC-11D6-A381-00039340AF4A
+ORGANIZER;CN=Helge Heß:mailto:helge.hess@skyrix.com
+DTSTART;TZID=Europe/Berlin:20021010T190000
+DURATION:PT45M
+BEGIN:VALARM
+TRIGGER;VALUE=DURATION:-PT15M
+ACTION:DISPLAY
+DESCRIPTION:Event reminder
+END:VALARM
+BEGIN:VALARM
+ATTACH;VALUE=URI:Ping
+TRIGGER;VALUE=DURATION:-PT15M
+ACTION:AUDIO
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20021008T155256Z
+SUMMARY:Zahnarzt
+DTEND;TZID=Europe/Berlin:20021009T110000
+UID:C3CB92B0-DBCC-11D6-A381-00039340AF4A
+DTSTART;TZID=Europe/Berlin:20021009T094500
+END:VEVENT
+BEGIN:VTODO
+DTSTAMP:20021009T154221Z
+SUMMARY:testjob
+UID:C3CB96C7-DBCC-11D6-A381-00039340AF4A
+DUE;TZID=Europe/Berlin:20021011T175228
+PRIORITY:5
+DTSTART;TZID=Europe/Berlin:20021008T175228
+END:VTODO
+BEGIN:VTODO
+UID:C3CB9A9F-DBCC-11D6-A381-00039340AF4A
+DTSTART;TZID=Europe/Berlin:20021010T000000
+DTSTAMP:20021009T154205Z
+SUMMARY:testjob2
+END:VTODO
+END:VCALENDAR
diff --git a/skyrix-xml/iCalSaxDriver/test2.vfb b/skyrix-xml/iCalSaxDriver/test2.vfb
new file mode 100644 (file)
index 0000000..30a5e67
--- /dev/null
@@ -0,0 +1,14 @@
+BEGIN:VCALENDAR
+PRODID:-//Microsoft Corporation//Outlook 9.0 MIMEDIR//EN
+VERSION:2.0
+METHOD:PUBLISH
+BEGIN:VFREEBUSY
+ORGANIZER:Unknown
+DTSTAMP:20020212T110727Z
+DTSTART:20020131T230000Z
+DTEND:20020430T220000Z
+FREEBUSY:20020206T113000Z/20020206T120000Z
+FREEBUSY:20020219T143000Z/20020219T150000Z
+FREEBUSY:20020210T143000Z/20020220T140000Z
+END:VFREEBUSY
+END:VCALENDAR
diff --git a/skyrix-xml/iCalSaxDriver/test3.ics b/skyrix-xml/iCalSaxDriver/test3.ics
new file mode 100644 (file)
index 0000000..3208214
--- /dev/null
@@ -0,0 +1,26 @@
+BEGIN:VCALENDAR\r
+VERSION:2.0\r
+PRODID:-//Microsoft Corporation//Entourage Mac 10.0 MIMEDIR//EN\r
+METHOD:REQUEST\r
+BEGIN:VTIMEZONE\r
+UID:B9C2613D.A077F%x@x.x\r
+TZID:/softwarestudio.org/Olson_20011030_5/America/New_York\r
+BEGIN:VEVENT\r
+CATEGORIES:Status\r
+CLASS:PUBLIC\r
+DTEND;TZID="/softwarestudio.\r
+  org/Olson_20011030_5/America/New_York":20021003T210000\r
+DTSTART;TZID="/softwarestudio.\r
+  org/Olson_20011030_5/America/New_York":20021003T090000\r
+LAST-MODIFIED:20021002T172148\r
+SEQUENCE:2\r
+SUMMARY:Evolution bug day\r
+TRANSP:OPAQUE\r
+UID:20021002T152046Z-12054-1000-1-0@azkoyen\r
+DTSTAMP:20021003T210900\r
+ATTENDEE;ROLE=OPT-PARTICIPANT;RSVP=TRUE;PARTSTAT=ACCEPTED;X-ATDPARAM=1:MAI\r
+ LTO:helge\r
+X-MICROSOFT-CDO-INSTTYPE:0\r
+X-MICROSOFT-CDO-BUSYSTATUS:BUSY\r
+END:VEVENT\r
+END:VCALENDAR\r
diff --git a/skyrix-xml/iCalSaxDriver/test4.ics b/skyrix-xml/iCalSaxDriver/test4.ics
new file mode 100644 (file)
index 0000000..c45e31f
--- /dev/null
@@ -0,0 +1,26 @@
+BEGIN:VCALENDAR\r
+VERSION:2.0\r
+PRODID:-//Microsoft Corporation//Entourage Mac 10.0 MIMEDIR//EN\r
+METHOD:REQUEST\r
+BEGIN:VTIMEZONE\r
+UID:B9C2613D.A077F%x@x.x\r
+TZID:/softwarestudio.org/Olson_20011030_5/America/New_York\r
+BEGIN:VEVENT\r
+CATEGORIES:Status\r
+CLASS:PUBLIC\r
+DTEND;TZID="/softwarestudio.\r
+  org/Olson_20011030_5/America/New_York":20021003T210000\r
+DTSTART;TZID="/softwarestudio.\r
+  org/Olson_20011030_5/America/New_York":20021003T090000\r
+LAST-MODIFIED:20021002T172148\r
+SEQUENCE:2\r
+SUMMARY:Evolution bug day\r
+TRANSP:OPAQUE\r
+UID:20021002T152046Z-12054-1000-1-0@azkoyen\r
+DTSTAMP:20021003T210900\r
+ATTENDEE;ROLE=OPT-PARTICIPANT;RSVP=TRUE;PARTSTAT=ACCEPTED;X-ATDPARAM=1:MAI\r
+ LTO:donald\r
+X-MICROSOFT-CDO-INSTTYPE:0\r
+X-MICROSOFT-CDO-BUSYSTATUS:BUSY\r
+END:VEVENT\r
+END:VCALENDAR\r
diff --git a/skyrix-xml/iCalSaxDriver/test5-entourage.ics b/skyrix-xml/iCalSaxDriver/test5-entourage.ics
new file mode 100644 (file)
index 0000000..3d6d102
--- /dev/null
@@ -0,0 +1,49 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Microsoft Corporation//Entourage Mac 10.0 MIMEDIR//EN
+METHOD:REQUEST
+BEGIN:VTIMEZONE
+UID:B9C624B1.6AE7C6%x@x.x
+X-ENTOURAGE-TZID:9
+TZID:Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
+BEGIN:STANDARD
+DTSTART:20001029T030000
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10
+UID:B9C624B1.6AE7C6%x@x.x
+TZNAME:Standard Time
+TZOFFSETTO:+0100
+TZOFFSETFROM:+0200
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20010325T020000
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3
+UID:B9C624B1.6AE7C6%x@x.x
+TZNAME:Daylight Savings Time
+TZOFFSETTO:+0200
+TZOFFSETFROM:+0100
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+ATTENDEE;ROLE=REQ-PARTICIPANT;RSVP=TRUE;CN="Donald Duck
+  (E-Mail)":MAILTO:donald@entenhausen.com
+CLASS:PUBLIC
+DESCRIPTION:Zeit: Freitag\, 22. Februar 2002 15:00-18:00 (GMT+01:00)
+  Amsterdam\, Berlin\, Bern\, Rom\, Stockholm\, Wien.\nOrt:
+  dort\n\n*~*~*~*~*~*~*~*~*~*\n\n
+DTEND:20020222T190000
+DTSTART:20020222T160000
+LOCATION:dort
+PRIORITY:5
+SEQUENCE:0
+SUMMARY:nexte Woche
+TRANSP:OPAQUE
+UID:040000008200E00074C5B7101A82E0080000000040028583B1B3C10100000000000000
+ 00100000002A630344F69E4D4592BEDDF473DD5B34
+DTSTAMP:20021006T173400
+ORGANIZER:MAILTO:donald@entenhausen.com
+ATTENDEE;ROLE=OPT-PARTICIPANT;RSVP=TRUE;PARTSTAT=ACCEPTED;X-ATDPARAM=1:MAI
+ LTO:donald
+X-MICROSOFT-CDO-INSTTYPE:0
+X-MICROSOFT-CDO-BUSYSTATUS:BUSY
+END:VEVENT
+END:VCALENDAR
diff --git a/skyrix-xml/iCalSaxDriver/test6-appleical.ics b/skyrix-xml/iCalSaxDriver/test6-appleical.ics
new file mode 100644 (file)
index 0000000..ea4f18c
--- /dev/null
@@ -0,0 +1,50 @@
+VERSION:2.0
+X-WR-CALNAME:Home
+PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
+X-WR-RELCALID:5AE4874A-C2C7-11D7-94E9-00039340AF4A-CALP
+X-WR-TIMEZONE;VALUE=TEXT:Europe/Berlin
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:Europe/Berlin
+LAST-MODIFIED:20031217T103412Z
+BEGIN:DAYLIGHT
+DTSTART:20030330T010000
+TZOFFSETTO:+0200
+TZOFFSETFROM:+0000
+TZNAME:CEST
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20031026T030000
+TZOFFSETTO:+0100
+TZOFFSETFROM:+0200
+TZNAME:CET
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20040328T030000
+TZOFFSETTO:+0200
+TZOFFSETFROM:+0100
+TZNAME:CEST
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20030913
+DTEND;VALUE=DATE:20031004
+SUMMARY:Urlaub
+UID:64B213D2-C2C7-11D7-94E9-00039340AF4A-RID
+DTSTAMP:20030730T195305Z
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;TZID=Europe/Berlin:20030807T000000
+SUMMARY:dsfsdjjjf
+UID:C02440DC-D1C2-11D7-B4D3-00039340AF4A-RID
+DTSTAMP:20030818T212734Z
+DURATION:PT1H
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;TZID=Europe/Berlin:20031217T160000
+SUMMARY:kjhjhjk
+UID:6DC63BEA-2FEA-11D8-A355-00039340AF4A-RID
+DTSTAMP:20031217T103243Z
+DURATION:PT1H
+END:VEVENT
+END:VCALENDAR
diff --git a/skyrix-xml/iCalSaxDriver/unicode.h b/skyrix-xml/iCalSaxDriver/unicode.h
new file mode 100644 (file)
index 0000000..73350ca
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+/* Unicode support */
+
+typedef unsigned long  UCS4;
+typedef unsigned short UCS2;
+typedef unsigned short UTF16;
+typedef unsigned char  UTF8;
+#define unichar UTF16
+
+static const int halfShift             = 10;
+static const UCS4 halfBase             = 0x0010000UL;
+static const UCS4 halfMask             = 0x3FFUL;
+static const UCS4 kSurrogateHighStart  = 0xD800UL;
+static const UCS4 kSurrogateHighEnd    = 0xDBFFUL;
+static const UCS4 kSurrogateLowStart   = 0xDC00UL;
+static const UCS4 kSurrogateLowEnd     = 0xDFFFUL;
+
+static const UCS4 kReplacementCharacter = 0x0000FFFDUL;
+static const UCS4 kMaximumUCS2          = 0x0000FFFFUL;
+static const UCS4 kMaximumUTF16         = 0x0010FFFFUL;
+static const UCS4 kMaximumUCS4          = 0x7FFFFFFFUL;
+
+static UCS4 offsetsFromUTF8[6] = {
+  0x00000000UL, 0x00003080UL, 0x000E2080UL, 
+  0x03C82080UL, 0xFA082080UL, 0x82082080UL
+};
+static char bytesFromUTF8[256] = {
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+static int
+_UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
+             unichar **targetStart, const unichar *targetEnd)
+{
+  int            result = 0;
+  register UTF8  *source = *sourceStart;
+  register UTF16 *target = *targetStart;
+  
+  while (source < sourceEnd) {
+    register UCS4 ch = 0;
+    register unsigned short extraBytesToWrite = bytesFromUTF8[*source];
+    
+    if (source + extraBytesToWrite > sourceEnd) {
+      result = 1; break;
+    };
+    switch(extraBytesToWrite) { /* note: code falls through cases! */
+      case 5:   ch += *source++; ch <<= 6;
+      case 4:   ch += *source++; ch <<= 6;
+      case 3:   ch += *source++; ch <<= 6;
+      case 2:   ch += *source++; ch <<= 6;
+      case 1:   ch += *source++; ch <<= 6;
+      case 0:   ch += *source++;
+    };
+    ch -= offsetsFromUTF8[extraBytesToWrite];
+
+    if (target >= targetEnd) {
+      result = 2; break;
+    };
+    if (ch <= kMaximumUCS2) {
+      *target++ = ch;
+    } else if (ch > kMaximumUTF16) {
+      *target++ = kReplacementCharacter;
+    } else {
+      if (target + 1 >= targetEnd) {
+        result = 2; break;
+      };
+      ch -= halfBase;
+      *target++ = (ch >> halfShift) + kSurrogateHighStart;
+      *target++ = (ch & halfMask) + kSurrogateLowStart;
+    };
+  };
+  *sourceStart = source;
+  *targetStart = target;
+  return result;
+}
diff --git a/skyrix-xml/libxmlSAXDriver/.cvsignore b/skyrix-xml/libxmlSAXDriver/.cvsignore
new file mode 100644 (file)
index 0000000..32eb5ce
--- /dev/null
@@ -0,0 +1,3 @@
+shared_debug_obj
+shared_obj
+libxmlSAXDriver.sax
diff --git a/skyrix-xml/libxmlSAXDriver/COPYING b/skyrix-xml/libxmlSAXDriver/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-xml/libxmlSAXDriver/COPYRIGHT b/skyrix-xml/libxmlSAXDriver/COPYRIGHT
new file mode 100644 (file)
index 0000000..8e76449
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (C) 2000-2004 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
diff --git a/skyrix-xml/libxmlSAXDriver/ChangeLog b/skyrix-xml/libxmlSAXDriver/ChangeLog
new file mode 100644 (file)
index 0000000..c5871ad
--- /dev/null
@@ -0,0 +1,195 @@
+2004-05-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlHTMLSAXDriver.m: do not report unclosed entity references
+         (as they often appear as query parameters in URLs) per default, can
+         be enabled using the libxmlHTMLSAXDriverReportUnclosedEntityRefs
+         default (v4.2.13)
+
+       * libxmlHTMLSAXDriver.m: invalid tags are now reported to the SAX
+         error handler if you enable the libxmlHTMLSAXDriverReportInvalidTags
+         default (v4.2.12)
+
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * v4.2.11
+
+       * GNUmakefile, GNUmakefile.preamble: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package.
+
+       * GNUmakefile.preamble: get libxml_INCLUDE_DIR and libxml_LIBS via
+         xml2-config instead of hardcoding. This plays nicely on
+         systems that use their own libxml as well as on GNUstep
+         installations that install an own copy of libxml2 in GNUSTEP_ROOT,
+         because xml2-config will be found in PATH prior to the system one.
+
+2003-12-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile: install driver in GNUSTEP_INSTALLATION_DIR instead
+         of GNUSTEP_USER_DIR, as "demanded" by Nicola ;-) (v4.2.10)
+
+2003-12-03  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile: include common.make from GNUSTEP_MAKEFILES (v4.2.9)
+
+2003-10-15  Helge Hess  <helge@groove.local.>
+
+       * created GNUmakefile.preamble, look for libxml2 in Fink (/sw/lib)
+         if we are building on darwin6 (v4.2.8)
+
+2003-10-13  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlSAXDriver.m: fixed a void-return issue (v4.2.7)
+
+2003-08-29  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlSAXDriver.m: fixed compilation on Cocoa (v4.2.6)
+
+2003-07-21  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlSAXDriver.m: improved XML charset detection (v4.2.5)
+
+2003-07-02  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlHTMLSAXDriver.m: proper handling of system-id (v4.2.4)
+
+       * libxmlHTMLSAXDriver.m: changed not to report "invalid tag" errors,
+         used for allowing SKYOBJ tags in .html files (v4.2.3)
+
+       * unicode.h: removed some unused statics
+
+2003-06-23  Helge Hess  <helge.hess@skyrix.com>
+
+       * v4.2.2
+
+       * added Version file to bundle
+
+       * libxmlHTMLSAXDriver.m: do not log unsupported features
+
+2003-01-14  Helge Hess  <helge.hess@skyrix.com>
+
+       * GNUmakefile (ADDITIONAL_INCLUDE_DIRS): added /usr/include/libxml2 for
+         cases were we compile without sxsys-libxml2
+
+2003-01-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed dependency on FoundationExt on MacOSX
+
+Thu Jan  2 10:53:25 2003  Helge Hess  <helge.hess@skyrix.com>
+       
+       * replaced usage of RETAIN macros with method calls
+       
+Thu Oct 17 20:27:14 2002  Helge Hess  <helge.hess@skyrix.com>
+       
+       * libxmlSAXDriver.m: fixed a rare problem where an element was popped
+         from the namespace stack in endDocument, but the stack was empty
+       
+2002-06-04  Helge Hess  <helge.hess@skyrix.com>
+       
+       * GNUmakefile: fixed linking of libSaxObjC if SaxObjC isn't installed
+         yet
+       
+Sun May  5 18:57:02 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * removed SAX1 document handler
+
+Thu May  2 12:21:48 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * added own NSMapTable callbacks since NSNonOwnedCStringMapKeyCallBacks
+         aren't available on MacOSX and gstep-base
+
+       * changed bundle to use -rangeOfString: instead of -indexOfString:
+
+Mon Feb 11 17:33:52 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlSAXDriver.m: fixed bug in XML charset detection
+
+Sat Feb  9 13:39:55 2002  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlSAXDriver.m: made less sensible regarding whitespace before
+         XML declaration
+
+       * libxmlSAXDriver.m: added charset detection for NSString's containing
+         XML
+
+Wed Nov 14 13:02:13 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlHTMLSAXDriver.m: fixed bug: unicode length was incorrectly
+         calculated
+       
+       * libxmlHTMLSAXDriver.m: check for empty text nodes
+
+Tue Nov 13 16:22:13 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlHTMLSAXDriver.m: don't throw exception on unrecognized features
+
+Mon Nov  5 14:13:45 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlSAXDriver.m: fixed bug (_cdataBlock called libxml characters())
+
+Fri Nov  2 12:56:54 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlSAXDriver.m: prefix all libxml SAX callbacks with underscore
+         (libxml 2.4.7 compatibility)
+
+Wed Oct 24 18:31:52 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * all drivers: fixed bug in UTF8-UTF16 conversion (incorrect length
+         was passed to -characters:length: SAX callback !!!)
+
+Mon Aug 27 19:39:07 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlHTMLSAXDriver.m: use UTF8 for parsing
+
+Mon Aug 27 18:25:41 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * again: more stable in error conditions ;-)
+
+Fri Aug 24 19:50:44 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlHTMLSAXDriver.m: more stable in error conditions
+
+Fri Aug 17 18:35:56 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlHTMLSAXDriver.m: place autorelease pool around parsing
+
+Fri Aug 17 18:18:35 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlHTMLSAXDriver.m: added string uniquing table
+
+       * libxmlSAXDriver.m: added string uniquing table
+
+Thu Aug 16 13:46:06 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlSAXDriver.m: cache SaxAttributes for efficiency, SAX callbacks
+         may not reuse SaxAttributes objects but must copy them ...
+
+Thu Aug  9 20:11:01 2001  Helge Hess  <helge.hess@skyrix.com>
+
+       * libxmlSAXDriver.m: reduced use of autorelease
+
+Fri Mar  9 10:40:53 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * libxmlSAXDriver.m: fixed bug with declaration of default-namespace
+
+Wed Feb  7 10:33:39 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * libxmlSAXDriver.m: add support for NSURL
+
+Fri Jan 12 16:36:42 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * libxmlSAXDriver.m: changed locator handling, lost reentrancy
+
+Wed Jan  3 14:50:07 2001  Helge Hess  <helge.hess@mdlink.de>
+
+       * libxmlSAXDriver.m: removed caching of SaxAttrs
+
+Tue Dec 12 20:20:02 2000  Helge Hess  <helge.hess@mdlink.de>
+
+       * added a driver for the libxml's HTML parser
+
+2000-10-09    <hh@skyrix.com>
+
+       * libxmlSAXDriver.m: fixed bug with NSData parsing
+
+
diff --git a/skyrix-xml/libxmlSAXDriver/GNUmakefile b/skyrix-xml/libxmlSAXDriver/GNUmakefile
new file mode 100644 (file)
index 0000000..a910163
--- /dev/null
@@ -0,0 +1,32 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+BUNDLE_NAME        = libxmlSAXDriver
+BUNDLE_EXTENSION   = .sax
+BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SaxDrivers
+
+libxmlSAXDriver_OBJC_FILES = \
+       libxmlSAXDriver.m       \
+       libxmlHTMLSAXDriver.m   \
+       libxmlDocSAXDriver.m    \
+       libxmlSAXLocator.m      \
+       TableCallbacks.m        \
+
+libxmlSAXDriver_RESOURCE_FILES = bundle-info.plist Version
+libxmlSAXDriver_LOCALIZED_RESOURCE_FILES =
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
+
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
diff --git a/skyrix-xml/libxmlSAXDriver/GNUmakefile.preamble b/skyrix-xml/libxmlSAXDriver/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..7b34819
--- /dev/null
@@ -0,0 +1,33 @@
+# $Id$
+
+
+ADDITIONAL_INCLUDE_DIRS += -I../.. -I..
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_BUILD_DIR)/../SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += -L../SaxObjC/$(GNUSTEP_OBJ_DIR)
+endif
+
+libxml_INCLUDE_DIR := $(shell xml2-config --cflags)
+libxml_LIBS := $(shell xml2-config --libs)
+
+ADDITIONAL_INCLUDE_DIRS += $(libxml_INCLUDE_DIR)
+
+
+libxmlSAXDriver_BUNDLE_LIBS += -lSaxObjC $(libxml_LIBS)
+
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+libxmlSAXDriver_BUNDLE_LIBS += \
+       -lz \
+       -lFoundation -lobjc
+endif
+
+ifeq ($(GNUSTEP_TARGET_OS),darwin6)
+ADDITIONAL_LIB_DIRS += -L/sw/lib
+endif
+
+ifeq ($(FOUNDATION_LIB),nx)
+libxmlSAXDriver_LDFLAGS += -framework Foundation
+endif
diff --git a/skyrix-xml/libxmlSAXDriver/README b/skyrix-xml/libxmlSAXDriver/README
new file mode 100644 (file)
index 0000000..c2f7c2f
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+libxmlSAXDriver
+===============
+
+This directory contains the sources for a SAX driver bundle that works on
+top of the libxml2 library. It can be used for processing XML, but also
+for parsing HTML.
+
+Requirements:
+- libxml2
diff --git a/skyrix-xml/libxmlSAXDriver/TableCallbacks.h b/skyrix-xml/libxmlSAXDriver/TableCallbacks.h
new file mode 100644 (file)
index 0000000..21e8771
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __libxml_TableCallbacks_H__
+#define __libxml_TableCallbacks_H__
+
+#import <Foundation/NSMapTable.h>
+
+extern const NSMapTableKeyCallBacks libxmlNonOwnedCStringMapKeyCallBacks; 
+
+#endif /* __libxml_TableCallbacks_H__ */
diff --git a/skyrix-xml/libxmlSAXDriver/TableCallbacks.m b/skyrix-xml/libxmlSAXDriver/TableCallbacks.m
new file mode 100644 (file)
index 0000000..82484af
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "TableCallbacks.h"
+#include "common.h"
+
+//#define NSNonOwnedCStringMapKeyCallBacks NSNonOwnedPointerMapKeyCallBacks
+
+/* From Aho, Sethi & Ullman: Principles of compiler design. */
+static unsigned __hashCString(void *table, const void *aString) {
+  register const char* p = (char*)aString;
+  register unsigned hash = 0, hash2;
+  register int i, n;
+  
+  n = aString ? strlen(aString) : 0;
+  for(i=0; i < n; i++) {
+    hash <<= 4;
+    hash += *p++;
+    if((hash2 = hash & 0xf0000000))
+      hash ^= (hash2 >> 24) ^ hash2;
+  }
+  return hash;
+}
+
+static BOOL __compareCString(void *table, 
+                               const void *anObject1,
+                               const void *anObject2)
+{
+  if (anObject1 == NULL && anObject2 == NULL) return YES;
+  if (anObject1 == NULL || anObject2 == NULL) return NO;
+  return strcmp((char*)anObject1, (char*)anObject2) == 0;
+}
+
+static void __retain(void *table, const void *anObject) {}
+static void __release(void *table, void *anObject) {}
+
+static NSString *__describe(void *table, const void *anObject) {
+    return [NSString stringWithFormat:@"%p", anObject];
+}
+
+const NSMapTableKeyCallBacks libxmlNonOwnedCStringMapKeyCallBacks =  {
+    (unsigned(*)(NSMapTable *, const void *))__hashCString,
+    (BOOL(*)(NSMapTable *, const void *, const void *))__compareCString,
+    (void (*)(NSMapTable *, const void *anObject))__retain,
+    (void (*)(NSMapTable *, void *anObject))__release,
+    (NSString *(*)(NSMapTable *, const void *))__describe,
+    (const void *)NULL
+};
diff --git a/skyrix-xml/libxmlSAXDriver/Version b/skyrix-xml/libxmlSAXDriver/Version
new file mode 100644 (file)
index 0000000..92c8fa0
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id$
+
+SUBMINOR_VERSION:=13
diff --git a/skyrix-xml/libxmlSAXDriver/bundle-info.plist b/skyrix-xml/libxmlSAXDriver/bundle-info.plist
new file mode 100644 (file)
index 0000000..f0182af
--- /dev/null
@@ -0,0 +1,28 @@
+{
+  "__cvs__" = "$Id: bundle-info.plist,v 1.1.1.1 2003/07/09 22:57:27 cvs Exp $";
+
+  requires = {
+    bundleManagerVersion = 1;
+    classes = (
+      { name = NSObject;    }
+    );
+  };
+
+  provides = {
+    SAXDrivers = ( 
+        { 
+          name        = libxmlSAXDriver;
+          sourceTypes = ( "text/xml" ); 
+        },
+        {
+          name        = libxmlHTMLSAXDriver; 
+          sourceTypes = ( "text/html" );
+        },
+    );
+    classes    = ( 
+        { name = libxmlSAXDriver;     },
+        { name = libxmlDocSAXDriver;  },
+        { name = libxmlHTMLSAXDriver; },
+    );
+  };
+}
diff --git a/skyrix-xml/libxmlSAXDriver/common.h b/skyrix-xml/libxmlSAXDriver/common.h
new file mode 100644 (file)
index 0000000..abb8f64
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __libxmlSAXDriver_common_H__
+#define __libxmlSAXDriver_common_H__
+
+#import <Foundation/Foundation.h>
+
+#ifndef ASSIGN
+#  define ASSIGN(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) [__value retain]; \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
+
+#endif /* __libxmlSAXDriver_common_H__ */
diff --git a/skyrix-xml/libxmlSAXDriver/libxmlDocSAXDriver.h b/skyrix-xml/libxmlSAXDriver/libxmlDocSAXDriver.h
new file mode 100644 (file)
index 0000000..c947788
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <SaxObjC/SaxXMLReader.h>
+#include <SaxObjC/SaxLexicalHandler.h>
+#include <SaxObjC/SaxDeclHandler.h>
+
+/*
+  recognized properties:
+    http://xml.org/sax/properties/declaration-handler
+    http://xml.org/sax/properties/lexical-handler
+    http://www.skyrix.com/sax/properties/html-namespace
+*/
+
+@class libxmlSAXLocator;
+
+@interface libxmlDocSAXDriver : NSObject < SaxXMLReader >
+{
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxDTDHandler>     dtdHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+  id<NSObject,SaxEntityResolver> entityResolver;
+  
+  id<NSObject,SaxLexicalHandler> lexicalHandler;
+  id<NSObject,SaxDeclHandler>    declHandler;
+  
+  unsigned depth;
+  BOOL     encodeEntities;
+  libxmlSAXLocator *locator;
+  
+  /* libxml */
+  void *doc;
+  void *ctxt;
+}
+
+@end
diff --git a/skyrix-xml/libxmlSAXDriver/libxmlDocSAXDriver.m b/skyrix-xml/libxmlSAXDriver/libxmlDocSAXDriver.m
new file mode 100644 (file)
index 0000000..6df4edb
--- /dev/null
@@ -0,0 +1,712 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "libxmlDocSAXDriver.h"
+#import "libxmlSAXLocator.h"
+#include <SaxObjC/SaxObjC.h>
+#include <SaxObjC/SaxException.h>
+#include "common.h"
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+@interface libxmlDocSAXDriver(PrivateMethods)
+
+- (void)tearDownParser;
+
+- (BOOL)walkDocumentTree:(xmlDocPtr)_doc;
+- (BOOL)processNode:(xmlNodePtr)_node;
+- (BOOL)processTextNode:(xmlNodePtr)_node;
+- (BOOL)processChildren:(xmlNodePtr)children;
+
+@end
+
+static int _UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
+                        unichar **targetStart, const unichar *targetEnd);
+
+static inline NSString *xmlCharsToString(const xmlChar *_s) {
+  static Class NSStringClass = Nil;
+  if (NSStringClass == Nil)
+    NSStringClass = [NSString class];
+  return _s ? [[NSStringClass alloc] initWithUTF8String:_s] : nil;
+}
+
+static NSString *SaxDeclHandlerProperty =
+  @"http://xml.org/sax/properties/declaration-handler";
+static NSString *SaxLexicalHandlerProperty =
+  @"http://xml.org/sax/properties/lexical-handler";
+
+@implementation libxmlDocSAXDriver
+
+static libxmlDocSAXDriver *activeDriver = nil;
+static void warning(void *udata, const char *msg, ...);
+static void error(void *udata, const char *msg, ...);
+static void fatalError(void *udata, const char *msg, ...);
+static void setLocator(void *udata, xmlSAXLocatorPtr _locator);
+
+- (id)init {
+  if ((self = [super init])) {
+    self->encodeEntities = NO;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self tearDownParser];
+  [self->lexicalHandler release];
+  [self->declHandler    release];
+  [self->contentHandler release];
+  [self->dtdHandler     release];
+  [self->errorHandler   release];
+  [self->entityResolver release];
+  [super dealloc];
+}
+
+/* features & properties */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value {
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+}
+- (BOOL)feature:(NSString *)_name {
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+  return NO;
+}
+
+- (void)setProperty:(NSString *)_name to:(id)_value {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
+    ASSIGN(self->lexicalHandler, _value);
+    return;
+  }
+  if ([_name isEqualToString:SaxDeclHandlerProperty]) {
+    ASSIGN(self->declHandler, _value);
+    return;
+  }
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+}
+- (id)property:(NSString *)_name {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty])
+    return self->lexicalHandler;
+  if ([_name isEqualToString:SaxDeclHandlerProperty])
+    return self->declHandler;
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+  return nil;
+}
+
+/* handlers */
+
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
+  ASSIGN(self->dtdHandler, _handler);
+}
+- (id<NSObject,SaxDTDHandler>)dtdHandler {
+  return self->dtdHandler;
+}
+
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  ASSIGN(self->errorHandler, _handler);
+}
+- (id<NSObject,SaxErrorHandler>)errorHandler {
+  return self->errorHandler;
+}
+
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
+  ASSIGN(self->entityResolver, _handler);
+}
+- (id<NSObject,SaxEntityResolver>)entityResolver {
+  return self->entityResolver;
+}
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  ASSIGN(self->contentHandler, _handler);
+}
+- (id<NSObject,SaxContentHandler>)contentHandler {
+  return self->contentHandler;
+}
+
+/* libxml */
+
+- (void)setupParserWithDocumentPath:(NSString *)_path {
+  static xmlSAXHandler sax;
+  
+  NSAssert(self->ctxt == NULL, @"DocSAX parser context already setup !");
+  
+  memcpy(&sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
+  sax.error              = error;
+  sax.warning            = warning;
+  sax.fatalError         = fatalError;
+  sax.setDocumentLocator = setLocator;
+  
+  NSAssert(activeDriver == nil, @"a parser is already running !");
+  activeDriver = self;
+  
+  self->ctxt = xmlCreatePushParserCtxt(&sax             /* sax      */,
+                                       NULL /*self*/    /* userdata */,
+                                       NULL             /* chunk    */,
+                                       0                /* chunklen */,
+                                       [_path cString]  /* filename */);
+  self->doc = NULL;
+}
+- (void)tearDownParser {
+  if (activeDriver == self)
+    activeDriver = nil;
+  
+  if (self->doc) {
+    xmlFreeDoc(self->doc);
+    self->doc = NULL;
+  }
+  if (self->ctxt) {
+    xmlFreeParserCtxt(self->ctxt);
+    self->ctxt = NULL;
+  }
+}
+
+/* IO */
+
+- (void)pushBytes:(const char *)_bytes count:(unsigned)_len {
+  if (_len == 0) return;
+  NSAssert(self->ctxt, @"missing DocSAX parser context");
+  xmlParseChunk(self->ctxt, _bytes, _len, 0);
+}
+- (void)pushEOF {
+  char dummyByte;
+  xmlParseChunk(self->ctxt, &dummyByte, 0, 1 /* terminate */);
+  self->doc = ((xmlParserCtxtPtr)ctxt)->myDoc;
+}
+
+/* parsing */
+
+- (void)_parseFromData:(NSData *)_data systemId:(NSString *)_sysId {
+  NSAutoreleasePool *pool;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  /* parse into structure */
+  [self setupParserWithDocumentPath:_sysId];
+  [self pushBytes:[_data bytes] count:[_data length]];
+  [self pushEOF];
+  
+  if (self->doc == NULL) {
+    NSLog(@"Couldn't parse file: %@", _sysId);
+    [self tearDownParser];
+  }
+  else {
+    //NSLog(@"parsed file: %@", _sysId);
+    
+    [self walkDocumentTree:self->doc];
+    [self tearDownParser];
+  }
+  
+  [pool release];
+}
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
+  if ([_source isKindOfClass:[NSData class]]) {
+    [self _parseFromData:_source systemId:nil];
+  }
+  else if ([_source isKindOfClass:[NSString class]]) {
+    [self _parseFromData:[_source dataUsingEncoding:NSISOLatin1StringEncoding]
+          systemId:nil];
+  }
+  else {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _source ? _source : @"<nil>", @"source",
+                         self,                         @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"can't handle data-source"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+  }
+}
+- (void)parseFromSource:(id)_source {
+  [self parseFromSource:_source systemId:@"<memory>"];
+}
+
+- (void)parseFromSystemId:(NSString *)_sysId {
+  NSAutoreleasePool *pool;
+  NSData *data;
+  
+  if (![_sysId hasPrefix:@"file://"]) {
+    /* exception */
+    return;
+  }
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  /* cut off file:// */
+  _sysId = [_sysId substringFromIndex:7];
+  
+  /* load data */
+  data = [NSData dataWithContentsOfFile:_sysId];
+
+  [self _parseFromData:data systemId:_sysId];
+  
+  [pool release];
+}
+
+/* process attribute nodes */
+
+- (SaxAttributes *)processAttributes:(xmlAttrPtr)_attributes {
+  xmlAttrPtr    attribute;
+  SaxAttributes *attributes;
+  
+  if (_attributes == NULL)
+    /* nothing to process */
+    return nil;
+
+  /* setup or clear attribute cache */
+  
+  attributes = [[SaxAttributes alloc] init];
+  
+  /* add attributes */
+  
+  for (attribute = _attributes; attribute; attribute = attribute->next) {
+    NSString *name;
+    NSString *value;
+    NSString *nsuri;
+#if 0
+    printf("attr name '%s' has NS '%s'\n",
+           attribute->name, attribute->ns ? "yes" : "no");
+#endif
+    
+    name      = xmlCharsToString(attribute->name);
+    value     = @"";
+    
+    if (attribute->children) {
+      xmlChar  *t;
+      
+      if ((t = xmlNodeListGetString(doc, attribute->children, 0))) {
+        value = xmlCharsToString(t);
+       free(t); /* should be xmlFree ?? */
+      }
+    }
+
+    nsuri = (attribute->ns != NULL)
+      ? xmlCharsToString(attribute->ns->href)
+      : nil;
+    
+    [attributes addAttribute:name
+                uri:nsuri
+                rawName:name
+                type:@"CDATA" value:value];
+    
+    [nsuri release]; nsuri = nil;
+    [name  release]; name  = nil;
+    [value release]; value = nil;
+  }
+  
+  return attributes;
+}
+
+/* walking the tree, generating SAX events */
+
+- (BOOL)_resolveEntityReferences {
+  return YES;
+}
+
+- (BOOL)processEntityRefNode:(xmlNodePtr)_node {
+  if ([self _resolveEntityReferences])
+    return [self processTextNode:_node];
+  else {
+    NSString *refName;
+    NSString *entityValue;
+
+    refName     = xmlCharsToString(_node->name);
+    entityValue = xmlCharsToString(_node->content);
+
+#if 0
+    NSLog(@"%s:%i: Ignoring entity ref: '%@' %s\n",
+          __PRETTY_FUNCTION__, __LINE__, refName, _node->content);
+#endif
+  
+    [entityValue release];
+    [refName     release];
+    return YES;
+  }
+}
+
+- (BOOL)processDocumentNode:(xmlNodePtr)node {
+  BOOL result;
+  
+  [self->contentHandler startDocument];
+  [self->contentHandler
+       startPrefixMapping:@""
+       uri:@"http://www.w3.org/XML/1998/namespace"];
+  result = [self processChildren:node->children];
+  [self->contentHandler endPrefixMapping:@""];
+  [self->contentHandler endDocument];
+  
+  return result;
+}
+
+- (BOOL)processTextNode:(xmlNodePtr)_node {
+  static unichar c = '\0';
+  
+  if (self->contentHandler == nil)
+    return YES;
+  
+  if (_node->content) {
+    xmlChar *chars;
+    
+    if (self->encodeEntities) {
+      /* should use the DocSAX encoding routine (htmlEncodeEntities) ??? */
+      
+      chars = xmlEncodeEntitiesReentrant(self->doc, _node->content);
+    }
+    else
+      chars = _node->content;
+    
+    if (chars == NULL) {
+      [self->contentHandler characters:&c length:0];
+    }
+    else {
+      void     *data, *ts;
+      unsigned len;
+      
+      len = strlen(chars);
+      
+      data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
+      
+      if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
+                       (void *)&ts, ts + (len * sizeof(unichar)))) {
+        free(data);
+        NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
+              __PRETTY_FUNCTION__, __LINE__);
+        return NO;
+      }
+      
+      [self->contentHandler characters:data length:(unsigned)(ts - data)];
+      
+      free(data);
+    }
+  }
+  else
+    [self->contentHandler characters:&c length:0];
+  
+  return YES;
+}
+
+- (BOOL)processCommentNode:(xmlNodePtr)_node {
+  unichar c = '\0';
+  
+  if (self->lexicalHandler == nil)
+    return YES;
+  
+  if (_node->content) {
+    xmlChar  *chars;
+    
+    /* uses the DocSAX encoding routine !!!!!!!!!! */
+    chars = xmlEncodeEntitiesReentrant(self->doc, _node->content);
+    
+    if (chars == NULL) {
+      [self->lexicalHandler comment:&c length:0];
+    }
+    else {
+      void     *data, *ts;
+      unsigned len;
+    
+      len = strlen(chars);
+
+      data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
+  
+      if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
+                       (void *)&ts, ts + (len * sizeof(unichar)))) {
+        free(data);
+        NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
+              __PRETTY_FUNCTION__, __LINE__);
+        return NO;
+      }
+      
+      [self->lexicalHandler comment:data length:(ts - data)];
+      
+      free(data);
+    }
+  }
+  else
+    [self->lexicalHandler comment:&c length:0];
+  
+  return YES;
+}
+
+- (BOOL)processDTDNode:(xmlNodePtr)node {
+  /* do nothing with DTD nodes .. */
+  return YES;
+}
+
+- (BOOL)processEntityNode:(xmlNodePtr)node {
+  /* do nothing with entity nodes .. */
+  NSLog(@"%s:%i: ignoring entity node (name='%s') ...",
+        __PRETTY_FUNCTION__, __LINE__, node->name);
+  return YES;
+}
+
+- (BOOL)processPINode:(xmlNodePtr)node {
+  NSString *piName;
+  NSString *piValue;
+  
+  piName  = xmlCharsToString(node->name);
+  piValue = xmlCharsToString(node->content);
+  
+  [self->contentHandler processingInstruction:piName data:piValue];
+
+  [piName  release];
+  [piValue release];
+  return YES;
+}
+
+- (BOOL)processElementNode:(xmlNodePtr)node {
+  id<NSObject,SaxAttributes> attrs;
+  NSString *tagName;
+  NSString *nsuri;
+  BOOL     result;
+  
+  self->depth++;
+  
+  tagName = xmlCharsToString(node->name);
+  nsuri = (node->ns != NULL)
+    ? xmlCharsToString(node->ns->href)
+    : nil;
+  
+  attrs = [self processAttributes:node->properties];
+  
+  [self->contentHandler
+       startElement:tagName
+       namespace:nsuri
+       rawName:tagName
+       attributes:attrs];
+  
+  [attrs release]; attrs = nil;
+  
+  result = [self processChildren:node->children];
+  
+  [self->contentHandler
+       endElement:tagName
+       namespace:nsuri
+       rawName:tagName];
+  
+  self->depth--;
+
+  [nsuri   release]; nsuri   = nil;
+  [tagName release]; tagName = nil;
+  [attrs   release]; attrs   = nil;
+  return result;
+}
+
+- (BOOL)processChildren:(xmlNodePtr)children {
+  xmlNodePtr node;
+  
+  if (children == NULL)
+    return YES;
+  
+  for (node = children; node; node = node->next) {
+    [self processNode:node];
+  }
+  
+  return YES;
+}
+
+- (BOOL)processNode:(xmlNodePtr)_node {
+  switch(_node->type) {
+    case XML_ELEMENT_NODE:
+      return [self processElementNode:_node];
+
+    case XML_ATTRIBUTE_NODE:
+      NSLog(@"invalid place for attribute-node !");
+      return NO;
+      
+    case XML_TEXT_NODE:
+      return [self processTextNode:_node];
+
+    case XML_CDATA_SECTION_NODE:
+      return [self processTextNode:_node];
+      
+    case XML_ENTITY_REF_NODE:
+      return [self processEntityRefNode:_node];
+
+    case XML_ENTITY_NODE:
+      return [self processEntityNode:_node];
+      
+    case XML_PI_NODE:
+      return [self processPINode:_node];
+      
+    case XML_COMMENT_NODE:
+      return [self processCommentNode:_node];
+      
+    case XML_DOCUMENT_NODE:
+      return [self processDocumentNode:_node];
+      
+    case XML_DTD_NODE:
+      return [self processDTDNode:_node];
+    
+    default:
+      NSLog(@"WARNING: UNKNOWN node type %i\n", _node->type);
+      break;
+  }
+  return NO;
+}
+
+- (BOOL)walkDocumentTree:(xmlDocPtr)_doc {
+  int  type;
+  BOOL result;
+  
+  type = ((xmlDocPtr)self->doc)->type;
+  ((xmlDocPtr)self->doc)->type = XML_DOCUMENT_NODE;
+  
+  result = [self processNode:(xmlNodePtr)self->doc];
+  
+  ((xmlDocPtr)self->doc)->type = type;
+  
+  return result;
+}
+
+/* callbacks */
+
+static SaxParseException *
+mkException(libxmlDocSAXDriver *self, NSString *key,
+            const char *msg, va_list va)
+{
+  NSString          *s, *reason;
+  NSDictionary      *ui;
+  SaxParseException *e;
+  int count = 0, i;
+  id  keys[7], values[7];
+  id  tmp;
+  NSRange r;
+  
+  s = [NSString stringWithCString:msg];
+  s = [[[NSString alloc]
+                  initWithFormat:s arguments:va]
+                  autorelease];
+  
+  r = [s rangeOfString:@"\n"];
+  reason = (r.length > 0)
+    ? [s substringToIndex:r.location]
+    : s;
+  
+  if ([reason length] == 0)
+    reason = @"unknown reason";
+  
+  keys[0] = @"parser"; values[0] = self; count++;
+  keys[1] = @"depth";  values[1] = [NSNumber numberWithInt:self->depth]; count++;
+  
+  if ([s length] > 0) {
+    keys[count]   = @"errorMessage";
+    values[count] = s;
+    count++;
+  }
+
+  // NSLog(@"locator: %@", self->locator);
+  
+  if ((i = [self->locator lineNumber]) >= 0) {
+    keys[count] = @"line";
+    values[count] = [NSNumber numberWithInt:i];
+    count++;
+  }
+  if ((i = [self->locator columnNumber]) >= 0) {
+    keys[count] = @"column";
+    values[count] = [NSNumber numberWithInt:i];
+    count++;
+  }
+  if ((tmp = [self->locator publicId])) {
+    keys[count]   = @"publicId";
+    values[count] = tmp;
+    count++;
+  }
+  if ((tmp = [self->locator systemId])) {
+    keys[count]   = @"systemId";
+    values[count] = tmp;
+    count++;
+  }
+  
+  ui = [NSDictionary dictionaryWithObjects:values forKeys:keys count:count];
+  
+  e = (id)[SaxParseException exceptionWithName:key
+                             reason:reason
+                             userInfo:ui];
+  return e;
+}
+
+static void warning(void *udata, const char *msg, ...) {
+  va_list           args;
+  SaxParseException *e;
+  
+  NSCAssert(activeDriver, @"no driver is active !");
+  
+  va_start(args, msg);
+  e = mkException(activeDriver, @"SAXWarning", msg, args);
+  va_end(args);
+  
+  [activeDriver->errorHandler warning:e];
+}
+
+static void error(void *udata, const char *msg, ...) {
+  va_list           args;
+  SaxParseException *e;
+
+  NSCAssert(activeDriver, @"no driver is active !");
+  
+  va_start(args, msg);
+  e = mkException(activeDriver, @"SAXError", msg, args);
+  va_end(args);
+  
+  [activeDriver->errorHandler error:e];
+}
+
+static void fatalError(void *udata, const char *msg, ...) {
+  va_list           args;
+  SaxParseException *e;
+
+  NSCAssert(activeDriver, @"no driver is active !");
+  
+  va_start(args, msg);
+  e = mkException(activeDriver, @"SAXFatalError", msg, args);
+  va_end(args);
+  
+  [activeDriver->errorHandler fatalError:e];
+}
+
+static void setLocator(void *udata, xmlSAXLocatorPtr _locator) {
+  NSCAssert(activeDriver, @"no driver is active !");
+  
+  [activeDriver->locator release];
+  
+  activeDriver->locator = [[libxmlSAXLocator alloc]
+                                             initWithSaxLocator:_locator
+                                             parser:activeDriver];
+  activeDriver->locator->ctx = activeDriver->ctxt;
+  
+  [activeDriver->contentHandler setDocumentLocator:activeDriver->locator];
+}
+
+@end /* libxmlDocSAXDriver */
+
+#include "unicode.h"
diff --git a/skyrix-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h b/skyrix-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h
new file mode 100644 (file)
index 0000000..9d88d40
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <SaxObjC/SaxXMLReader.h>
+#include <SaxObjC/SaxLexicalHandler.h>
+#include <SaxObjC/SaxDeclHandler.h>
+
+/*
+  recognized properties:
+    http://xml.org/sax/properties/declaration-handler
+    http://xml.org/sax/properties/lexical-handler
+    http://www.skyrix.com/sax/properties/html-namespace
+*/
+
+@class libxmlSAXLocator;
+
+@interface libxmlHTMLSAXDriver : NSObject < SaxXMLReader >
+{
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxDTDHandler>     dtdHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+  id<NSObject,SaxEntityResolver> entityResolver;
+  
+  id<NSObject,SaxLexicalHandler> lexicalHandler;
+  id<NSObject,SaxDeclHandler>    declHandler;
+  
+  NSString *namespaceURI;
+  unsigned depth;
+  BOOL     encodeEntities;
+  libxmlSAXLocator *locator;
+  
+  /* libxml */
+  void *doc;
+  void *ctxt;
+  SaxAttributes *attributes;
+}
+
+@end
diff --git a/skyrix-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m b/skyrix-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m
new file mode 100644 (file)
index 0000000..c4799b4
--- /dev/null
@@ -0,0 +1,772 @@
+/*
+  Copyright (C) 2000-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$
+
+#import "libxmlHTMLSAXDriver.h"
+#import "libxmlSAXLocator.h"
+#include "TableCallbacks.h"
+#include <SaxObjC/SaxObjC.h>
+#include <SaxObjC/SaxException.h>
+#include "common.h"
+
+#include <libxml/HTMLparser.h>
+#include <libxml/HTMLtree.h>
+
+@interface libxmlHTMLSAXDriver(PrivateMethods)
+
+- (void)tearDownParser;
+
+- (BOOL)walkDocumentTree:(xmlDocPtr)_doc;
+- (BOOL)processNode:(xmlNodePtr)_node;
+- (BOOL)processChildren:(xmlNodePtr)children;
+
+@end
+
+static int _UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
+                        unichar **targetStart, const unichar *targetEnd);
+
+static BOOL       logUnsupportedFeatures = NO;
+static BOOL       reportInvalidTags      = NO;
+static BOOL       reportUnclosedEntities = NO;
+static NSMapTable *uniqueStrings = NULL; // THREAD
+static Class      NSStringClass = Nil;
+
+/* error string detection */
+/*
+  TODO: obviously this may change between libxml versions or even
+        localisations ... why doesn't libxml support error codes ?
+        (or does it ?)
+*/
+static const unsigned char *tagInvalidMsg = "tag %s invalid";
+static const unsigned char *unclosedEntityInvalidMsg = 
+  "htmlParseEntityRef: expecting ';'";
+
+static inline NSString *xmlCharsToString(const xmlChar *_s) {
+  NSString *s;
+  char *newkey;
+  
+  if (_s == NULL) return nil;
+  
+  if (uniqueStrings == NULL) {
+    uniqueStrings = NSCreateMapTable(libxmlNonOwnedCStringMapKeyCallBacks,
+                                     NSObjectMapValueCallBacks,
+                                     128);
+  }
+  else if ((s = NSMapGet(uniqueStrings, _s))) {
+    /* found a string in cache ... */
+    return [s retain];
+  }
+  
+  newkey = malloc(strlen(_s) + 1);
+  strcpy(newkey, _s);
+  
+  if (NSStringClass == Nil)
+    NSStringClass = [NSString class];
+  
+  s = [[NSStringClass alloc] initWithUTF8String:_s];
+  NSMapInsert(uniqueStrings, newkey, s);
+  return s;
+}
+
+static NSString *SaxDeclHandlerProperty =
+  @"http://xml.org/sax/properties/declaration-handler";
+static NSString *SaxLexicalHandlerProperty =
+  @"http://xml.org/sax/properties/lexical-handler";
+
+static NSString *XMLNS_XHTML = @"http://www.w3.org/1999/xhtml";
+
+@implementation libxmlHTMLSAXDriver
+
+static libxmlHTMLSAXDriver *activeDriver = nil;
+static void warning(void *udata, const char *msg, ...);
+static void error(void *udata, const char *msg, ...);
+static void fatalError(void *udata, const char *msg, ...);
+static void setLocator(void *udata, xmlSAXLocatorPtr _locator);
+
++ (void)initialize {
+  NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+  
+  reportInvalidTags  = [ud boolForKey:@"libxmlHTMLSAXDriverReportInvalidTags"];
+  reportUnclosedEntities = 
+    [ud boolForKey:@"libxmlHTMLSAXDriverReportUnclosedEntityRefs"];
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    self->namespaceURI   = [XMLNS_XHTML copy];
+    self->encodeEntities = NO;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self tearDownParser];
+  
+  [self->attributes     release];
+  [self->namespaceURI   release];
+  [self->lexicalHandler release];
+  [self->declHandler    release];
+  [self->contentHandler release];
+  [self->dtdHandler     release];
+  [self->errorHandler   release];
+  [self->entityResolver release];
+  [super dealloc];
+}
+
+/* features & properties */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value {
+  if (logUnsupportedFeatures)
+    NSLog(@"%s: don't know feature %@", __PRETTY_FUNCTION__, _name);
+}
+- (BOOL)feature:(NSString *)_name {
+  if (logUnsupportedFeatures)
+    NSLog(@"%s: don't know feature %@", __PRETTY_FUNCTION__, _name);
+  return NO;
+}
+
+- (void)setProperty:(NSString *)_name to:(id)_value {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
+    ASSIGN(self->lexicalHandler, _value);
+    return;
+  }
+  if ([_name isEqualToString:SaxDeclHandlerProperty]) {
+    ASSIGN(self->declHandler, _value);
+    return;
+  }
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+}
+- (id)property:(NSString *)_name {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty])
+    return self->lexicalHandler;
+  if ([_name isEqualToString:SaxDeclHandlerProperty])
+    return self->declHandler;
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+  return nil;
+}
+
+/* handlers */
+
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
+  ASSIGN(self->dtdHandler, _handler);
+}
+- (id<NSObject,SaxDTDHandler>)dtdHandler {
+  return self->dtdHandler;
+}
+
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  ASSIGN(self->errorHandler, _handler);
+}
+- (id<NSObject,SaxErrorHandler>)errorHandler {
+  return self->errorHandler;
+}
+
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
+  ASSIGN(self->entityResolver, _handler);
+}
+- (id<NSObject,SaxEntityResolver>)entityResolver {
+  return self->entityResolver;
+}
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  ASSIGN(self->contentHandler, _handler);
+}
+- (id<NSObject,SaxContentHandler>)contentHandler {
+  return self->contentHandler;
+}
+
+/* libxml */
+
+- (void)setupParserWithDocumentPath:(NSString *)_path {
+  xmlSAXHandler sax;
+  
+  if (self->ctxt != NULL) {
+    NSLog(@"WARNING(%s): HTML parser context already setup !",
+          __PRETTY_FUNCTION__);
+    [self tearDownParser];
+  }
+  
+  memcpy(&sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandler));
+  sax.error              = error;
+  sax.warning            = warning;
+  sax.fatalError         = fatalError;
+  sax.setDocumentLocator = setLocator;
+  
+  if (activeDriver != nil) {
+    NSLog(@"WARNING(%s): %@ there is an active driver set (%@), override !",
+          __PRETTY_FUNCTION__, self, activeDriver);
+  }
+  activeDriver = self;
+  
+  self->ctxt = htmlCreatePushParserCtxt(&sax             /* sax      */,
+                                        NULL /*self*/    /* userdata */,
+                                        NULL             /* chunk    */,
+                                        0                /* chunklen */,
+                                        [_path cString]  /* filename */,
+                                        XML_CHAR_ENCODING_8859_1
+                                        /* encoding */);
+  self->doc = NULL;
+}
+- (void)tearDownParser {
+  if (activeDriver == self)
+    activeDriver = nil;
+  
+  if (self->doc) {
+    xmlFreeDoc(self->doc);
+    self->doc = NULL;
+  }
+  if (self->ctxt) {
+    htmlFreeParserCtxt(self->ctxt);
+    self->ctxt = NULL;
+  }
+}
+
+/* IO */
+
+- (void)pushBytes:(const char *)_bytes count:(unsigned)_len {
+  if (_len == 0) return;
+  NSAssert(self->ctxt, @"missing HTML parser context");
+  htmlParseChunk(self->ctxt, _bytes, _len, 0);
+}
+- (void)pushEOF {
+  char dummyByte;
+  htmlParseChunk(self->ctxt, &dummyByte, 0, 1 /* terminate */);
+  self->doc = ((xmlParserCtxtPtr)ctxt)->myDoc;
+}
+
+/* parsing */
+
+- (void)_parseFromData:(NSData *)_data systemId:(NSString *)_sysId {
+  NSAutoreleasePool *pool;
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  /* parse into structure */
+  [self setupParserWithDocumentPath:_sysId];
+  [self pushBytes:[_data bytes] count:[_data length]];
+  [self pushEOF];
+  
+  if (self->doc == NULL) {
+    NSLog(@"Could not parse HTML file: %@", _sysId);
+    [self tearDownParser];
+  }
+  else {
+    [self walkDocumentTree:self->doc];
+    [self tearDownParser];
+  }
+  
+  [pool release];
+}
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
+  NSAutoreleasePool *pool;
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  if ([_source isKindOfClass:[NSData class]]) {
+    [self _parseFromData:_source systemId:_sysId];
+  }
+  else if ([_source isKindOfClass:[NSString class]]) {
+    [self _parseFromData:[_source dataUsingEncoding:NSISOLatin1StringEncoding]
+          systemId:_sysId];
+  }
+  else {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _source ? _source : @"<nil>", @"source",
+                         self,                         @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"can't handle data-source"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+  }
+
+  [self tearDownParser];
+  
+  [pool release];
+}
+- (void)parseFromSource:(id)_source {
+  [self parseFromSource:_source systemId:@"<memory>"];
+}
+
+- (void)parseFromSystemId:(NSString *)_sysId {
+  NSAutoreleasePool *pool;
+  NSData *data;
+  
+  if (![_sysId hasPrefix:@"file://"]) {
+    /* exception */
+    return;
+  }
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  /* cut off file:// */
+  _sysId = [_sysId substringFromIndex:7];
+  
+  /* load data */
+  data = [NSData dataWithContentsOfFile:_sysId];
+
+  [self _parseFromData:data systemId:_sysId];
+  
+  [pool release];
+}
+
+/* process attribute nodes */
+
+- (void)processAttributes:(xmlAttrPtr)_attributes {
+  xmlAttrPtr  attribute;
+  
+  /* setup or clear attribute cache */
+  if (self->attributes == nil)
+    attributes = [[SaxAttributes alloc] init];
+  else
+    [attributes clear];
+  
+  if (_attributes == NULL)
+    /* nothing to process */
+    return;
+
+  /* add attributes */
+  
+  for (attribute = _attributes; attribute; attribute = attribute->next) {
+    NSString *name, *xhtmlName;
+    NSString *value;
+#if 0
+    printf("attr name '%s' has NS '%s'\n",
+           attribute->name, attribute->ns ? "yes" : "no");
+#endif
+    
+    name      = xmlCharsToString(attribute->name);
+    xhtmlName = [name lowercaseString];
+    value     = @"";
+    
+    if (attribute->children) {
+      xmlChar  *t;
+      
+      if ((t = xmlNodeListGetString(doc, attribute->children, 0))) {
+        value = xmlCharsToString(t);
+       free(t); /* should be xmlFree ?? */
+      }
+    }
+    
+    [attributes addAttribute:xhtmlName
+                uri:self->namespaceURI
+                rawName:name
+                type:@"CDATA" value:value];
+
+    [name  release]; name  = nil;
+    [value release]; value = nil;
+  }
+  
+  return;
+}
+
+/* walking the tree, generating SAX events */
+
+- (BOOL)processEntityRefNode:(xmlNodePtr)node {
+  NSLog(@"Ignoring entity ref: '%s'\n", node->name);
+  return YES;
+}
+
+- (BOOL)processDocumentNode:(xmlNodePtr)node {
+  BOOL result;
+  
+  [self->contentHandler startDocument];
+  [self->contentHandler startPrefixMapping:@"" uri:self->namespaceURI];
+  result = [self processChildren:node->children];
+  [self->contentHandler endPrefixMapping:@""];
+  [self->contentHandler endDocument];
+  
+  return result;
+}
+
+- (BOOL)processTextNode:(xmlNodePtr)_node {
+  static unichar c = '\0';
+  xmlChar  *chars;
+  unsigned len;
+  
+  if (self->contentHandler == nil)
+    return YES;
+
+  if (_node->content == NULL) {
+    [self->contentHandler characters:&c length:0];
+    return YES;
+  }
+  
+  if (self->encodeEntities) {
+    /* should use the HTML encoding routine (htmlEncodeEntities) ??? */
+      
+    chars = xmlEncodeEntitiesReentrant(self->doc, _node->content);
+  }
+  else
+    chars = _node->content;
+  
+  if (chars == NULL) {
+    [self->contentHandler characters:&c length:0];
+    return YES;
+  }
+  if ((len = strlen(chars)) == 0) {
+    unichar c = '\0';
+    [self->contentHandler characters:&c length:0];
+    return YES;
+  }
+  
+  {
+    void *data, *ts;
+    
+    data = ts = calloc(len + 2, sizeof(unichar)); /* GC ?! */
+  
+    if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
+                     (void *)&ts, ts + (len * sizeof(unichar)))) {
+      NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
+            __PRETTY_FUNCTION__, __LINE__);
+      if (data) free(data);
+      return NO;
+    }
+
+    len = (ts - data) / 2;
+    [self->contentHandler characters:data length:len];
+    
+    if (data) free(data);
+  }
+  
+  return YES;
+}
+
+- (BOOL)processCommentNode:(xmlNodePtr)_node {
+  unichar c = '\0';
+  
+  if (self->lexicalHandler == nil)
+    return YES;
+  
+  if (_node->content) {
+    xmlChar  *chars;
+    
+    /* uses the HTML encoding routine !!!!!!!!!! */
+    chars = xmlEncodeEntitiesReentrant(self->doc, _node->content);
+    
+    if (chars == NULL) {
+      [self->lexicalHandler comment:&c length:0];
+    }
+    else {
+      unsigned len;
+      
+      if ((len = strlen(chars)) > 0) {
+        void *data, *ts;
+        
+        data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
+  
+        if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
+                         (void *)&ts, ts + (len * sizeof(unichar)))) {
+          free(data);
+          NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
+                __PRETTY_FUNCTION__, __LINE__);
+          return NO;
+        }
+        
+        len = (ts - data) / 2;
+        [self->lexicalHandler comment:data length:len];
+        
+        free(data);
+      }
+      else {
+        unichar c = '\0';
+        [self->lexicalHandler comment:&c length:0];
+      }
+    }
+  }
+  else
+    [self->lexicalHandler comment:&c length:0];
+  
+  return YES;
+}
+
+- (BOOL)processDTDNode:(xmlNodePtr)node {
+  /* do nothing with DTD nodes .. */
+  return YES;
+}
+- (BOOL)processEntityNode:(xmlNodePtr)node {
+  /* do nothing with entity nodes .. */
+  NSLog(@"%s:%i: ignoring entity node ..", __PRETTY_FUNCTION__, __LINE__);
+  return YES;
+}
+- (BOOL)processPINode:(xmlNodePtr)node {
+  /* do nothing with PI nodes .. */
+  return YES;
+}
+
+- (BOOL)processElementNode:(xmlNodePtr)node {
+  const htmlElemDesc *tagInfo;
+  NSString *tagName, *xhtmlName;
+  BOOL     result;
+  
+  self->depth++;
+  
+  tagInfo   = htmlTagLookup(node->name);
+  tagName   = xmlCharsToString(node->name);
+  xhtmlName = [tagName lowercaseString];
+  
+  [self processAttributes:node->properties];
+  
+  [self->contentHandler
+       startElement:xhtmlName
+       namespace:self->namespaceURI
+       rawName:tagName
+       attributes:self->attributes];
+  
+  [self->attributes clear];
+  
+  result = [self processChildren:node->children];
+  
+  [self->contentHandler
+       endElement:xhtmlName
+       namespace:self->namespaceURI
+       rawName:tagName];
+  
+  self->depth--;
+  
+  [tagName release];
+  return result;
+}
+
+- (BOOL)processChildren:(xmlNodePtr)children {
+  xmlNodePtr node;
+  
+  if (children == NULL)
+    return YES;
+  
+  for (node = children; node; node = node->next) {
+    [self processNode:node];
+  }
+  
+  return YES;
+}
+
+- (BOOL)processNode:(xmlNodePtr)_node {
+  switch(_node->type) {
+    case XML_ELEMENT_NODE:
+      return [self processElementNode:_node];
+
+    case XML_ATTRIBUTE_NODE:
+      NSLog(@"invalid place for attribute-node !");
+      return NO;
+      
+    case HTML_TEXT_NODE:
+      return [self processTextNode:_node];
+
+    case XML_CDATA_SECTION_NODE:
+      return [self processTextNode:_node];
+      
+    case HTML_ENTITY_REF_NODE:
+      return [self processEntityRefNode:_node];
+
+    case XML_ENTITY_NODE:
+      return [self processEntityNode:_node];
+      
+    case XML_PI_NODE:
+      return [self processPINode:_node];
+      
+    case HTML_COMMENT_NODE:
+      return [self processCommentNode:_node];
+      
+    case XML_HTML_DOCUMENT_NODE:
+      return [self processDocumentNode:_node];
+      
+    case XML_DTD_NODE:
+      return [self processDTDNode:_node];
+    
+    default:
+      NSLog(@"WARNING: UNKNOWN node type %i\n", _node->type);
+      break;
+  }
+  return NO;
+}
+
+- (BOOL)walkDocumentTree:(xmlDocPtr)_doc {
+  int  type;
+  BOOL result;
+  
+  type = ((xmlDocPtr)self->doc)->type;
+  ((xmlDocPtr)self->doc)->type = XML_HTML_DOCUMENT_NODE;
+  
+  result = [self processNode:(xmlNodePtr)self->doc];
+  
+  ((xmlDocPtr)self->doc)->type = type;
+  
+  return result;
+}
+
+/* callbacks */
+
+static SaxParseException *
+mkException(libxmlHTMLSAXDriver *self, NSString *key,
+            const char *msg, va_list va)
+{
+  NSString          *s, *reason;
+  NSDictionary      *ui;
+  SaxParseException *e;
+  int count = 0, i;
+  id  keys[7], values[7];
+  id  tmp;
+  NSRange r;
+
+  s = [NSString stringWithCString:msg];
+  s = [[[NSString alloc]
+                  initWithFormat:s arguments:va]
+                  autorelease];
+
+  r = [s rangeOfString:@"\n"];
+  reason = (r.length > 0)
+    ? [s substringToIndex:r.location]
+    : s;
+  
+  if ([reason length] == 0)
+    reason = @"unknown reason";
+  
+  keys[0] = @"parser"; values[0] = self; count++;
+  keys[1] = @"depth";
+  values[1] = [NSNumber numberWithInt:self->depth]; count++;
+  
+  if ([s length] > 0) {
+    keys[count]   = @"errorMessage";
+    values[count] = s;
+    count++;
+  }
+
+  // NSLog(@"locator: %@", self->locator);
+  
+  if ((i = [self->locator lineNumber]) >= 0) {
+    keys[count] = @"line";
+    values[count] = [NSNumber numberWithInt:i];
+    count++;
+  }
+  if ((i = [self->locator columnNumber]) >= 0) {
+    keys[count] = @"column";
+    values[count] = [NSNumber numberWithInt:i];
+    count++;
+  }
+  if ((tmp = [self->locator publicId])) {
+    keys[count]   = @"publicId";
+    values[count] = tmp;
+    count++;
+  }
+  if ((tmp = [self->locator systemId])) {
+    keys[count]   = @"systemId";
+    values[count] = tmp;
+    count++;
+  }
+  
+  ui = [NSDictionary dictionaryWithObjects:values forKeys:keys count:count];
+  
+  e = (id)[SaxParseException exceptionWithName:key
+                             reason:reason
+                             userInfo:ui];
+  return e;
+}
+
+static void warning(void *udata, const char *msg, ...) {
+  va_list           args;
+  SaxParseException *e;
+  
+  if (activeDriver == nil) {
+    NSLog(@"ERROR(%s): no driver is active !", __PRETTY_FUNCTION__);
+    return;
+  }
+  
+  va_start(args, msg);
+  e = mkException(activeDriver, @"SAXWarning", msg, args);
+  va_end(args);
+  
+  [activeDriver->errorHandler warning:e];
+}
+
+static void error(void *udata, const char *msg, ...) {
+  va_list           args;
+  SaxParseException *e;
+  
+  if (!reportInvalidTags && msg != NULL && toupper(msg[0]) == 'T') {
+    if (strncasecmp(tagInvalidMsg, msg, strlen(tagInvalidMsg)) == 0)
+      return;
+  }
+  if (!reportUnclosedEntities && msg != NULL && toupper(msg[0]) == 'H') {
+    if (strncasecmp(unclosedEntityInvalidMsg, msg, 
+                    strlen(unclosedEntityInvalidMsg)) == 0)
+      return;
+  }
+  
+  if (activeDriver == nil) {
+    NSLog(@"ERROR(%s): no driver is active !", __PRETTY_FUNCTION__);
+    return;
+  }
+  
+  /* msg is a format, eg 'tag %s is invalid' */
+  
+  va_start(args, msg);
+  e = mkException(activeDriver, @"SAXError", msg, args);
+  va_end(args);
+  
+  [activeDriver->errorHandler error:e];
+}
+
+static void fatalError(void *udata, const char *msg, ...) {
+  va_list           args;
+  SaxParseException *e;
+  
+  if (activeDriver == nil) {
+    NSLog(@"ERROR(%s): no driver is active !", __PRETTY_FUNCTION__);
+    return;
+  }
+  
+  va_start(args, msg);
+  e = mkException(activeDriver, @"SAXFatalError", msg, args);
+  va_end(args);
+  
+  [activeDriver->errorHandler fatalError:e];
+}
+
+static void setLocator(void *udata, xmlSAXLocatorPtr _locator) {
+  if (activeDriver == nil) {
+    NSLog(@"ERROR(%s): no driver is active !", __PRETTY_FUNCTION__);
+    return;
+  }
+  
+  [activeDriver->locator release];
+  
+  activeDriver->locator = [[libxmlSAXLocator alloc]
+                                             initWithSaxLocator:_locator
+                                             parser:activeDriver];
+  activeDriver->locator->ctx = activeDriver->ctxt;
+  
+  [activeDriver->contentHandler setDocumentLocator:activeDriver->locator];
+}
+
+@end /* libxmlHTMLSAXDriver */
+
+#include "unicode.h"
diff --git a/skyrix-xml/libxmlSAXDriver/libxmlSAXDriver-Info.plist b/skyrix-xml/libxmlSAXDriver/libxmlSAXDriver-Info.plist
new file mode 100644 (file)
index 0000000..e204732
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>libxmlSAXDriver</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>org.opengroupware.xml.libxmlSAXDriver</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+</dict>
+</plist>
diff --git a/skyrix-xml/libxmlSAXDriver/libxmlSAXDriver.h b/skyrix-xml/libxmlSAXDriver/libxmlSAXDriver.h
new file mode 100644 (file)
index 0000000..a29c6d3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __libxmlSAXDriver_H__
+#define __libxmlSAXDriver_H__
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxXMLReader.h>
+#include <SaxObjC/SaxContentHandler.h>
+#include <SaxObjC/SaxDTDHandler.h>
+#include <SaxObjC/SaxErrorHandler.h>
+#include <SaxObjC/SaxEntityResolver.h>
+#include <SaxObjC/SaxLexicalHandler.h>
+#include <SaxObjC/SaxLocator.h>
+#include <SaxObjC/SaxDeclHandler.h>
+
+@class NSMutableArray;
+@class SaxAttributes;
+
+@class libxmlSAXLocator;
+
+@interface libxmlSAXDriver : NSObject < SaxXMLReader >
+{
+@private
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxDTDHandler>     dtdHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+  id<NSObject,SaxEntityResolver> entityResolver;
+  
+  id<NSObject,SaxLexicalHandler> lexicalHandler;
+  id<NSObject,SaxDeclHandler>    declHandler;
+  
+  void           *sax;    /* ptr to libxml sax structure */
+  void           *ctxt;   /* libxml parser context */
+  void           *entity; /* used during entity lookup */
+  
+  int            depth;
+  NSMutableArray *nsStack;
+  BOOL           fNamespaces;
+  BOOL           fNamespacePrefixes;
+  
+  /* cache */
+  libxmlSAXLocator *locator;
+  SaxAttributes    *attrs;
+}
+
+@end
+
+#endif /* __libxmlSAXDriver_H__ */
diff --git a/skyrix-xml/libxmlSAXDriver/libxmlSAXDriver.m b/skyrix-xml/libxmlSAXDriver/libxmlSAXDriver.m
new file mode 100644 (file)
index 0000000..3296af7
--- /dev/null
@@ -0,0 +1,1413 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "libxmlSAXDriver.h"
+#include "libxmlSAXLocator.h"
+#include "TableCallbacks.h"
+#include <SaxObjC/SaxException.h>
+#include <SaxObjC/SaxAttributes.h>
+#include "common.h"
+
+#include <libxml/parser.h>
+
+/*
+  TODO: xmlChar is really UTF-8, not cString !!!
+*/
+
+static NSString *SaxDeclHandlerProperty =
+  @"http://xml.org/sax/properties/declaration-handler";
+static NSString *SaxLexicalHandlerProperty =
+  @"http://xml.org/sax/properties/lexical-handler";
+#if 0
+static NSString *SaxDOMNodeProperty =
+  @"http://xml.org/sax/properties/dom-node";
+static NSString *SaxXMLStringProperty =
+  @"http://xml.org/sax/properties/xml-string";
+#endif
+
+static int _UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
+                        unichar **targetStart, const unichar *targetEnd);
+
+static NSMapTable *uniqueStrings = NULL; // THREAD
+static Class NSStringClass = Nil;
+
+static inline NSString *xmlCharsToString(const xmlChar *_s) {
+  NSString *s;
+  char *newkey;
+  
+  if (_s == NULL) return nil;
+  
+  if (uniqueStrings == NULL) {
+    uniqueStrings = NSCreateMapTable(libxmlNonOwnedCStringMapKeyCallBacks,
+                                     NSObjectMapValueCallBacks,
+                                     128);
+  }
+  else if ((s = NSMapGet(uniqueStrings, _s))) {
+    /* found a string in cache ... */
+    return [s retain];
+  }
+
+  newkey = malloc(strlen(_s) + 1);
+  strcpy(newkey, _s);
+  
+  if (NSStringClass == Nil)
+    NSStringClass = [NSString class];
+  
+  s = [[NSStringClass alloc] initWithUTF8String:_s];
+  NSMapInsert(uniqueStrings, newkey, s);
+  return s;
+}
+
+extern xmlParserCtxtPtr xmlCreateMemoryParserCtxt(char *buffer, int size);
+
+@implementation libxmlSAXDriver
+
+static libxmlSAXDriver *activeDriver = nil;
+
+static void
+_startElement(libxmlSAXDriver *self, const xmlChar *name, const xmlChar **atts);
+static void _endElement(libxmlSAXDriver *self, const xmlChar *name);
+static void _startDocument(libxmlSAXDriver *self);
+static void _endDocument(libxmlSAXDriver *self);
+static void _characters(libxmlSAXDriver *self, const xmlChar *chars, int len);
+static void
+_ignorableWhiteSpace(libxmlSAXDriver *self, const xmlChar *chars, int len);
+static void __pi(libxmlSAXDriver *self, const xmlChar *target, const xmlChar *data);
+static void _comment(libxmlSAXDriver *self, const xmlChar *value);
+static xmlParserInputPtr
+_resolveEntity(libxmlSAXDriver *self, const xmlChar *pub, const xmlChar *sys)
+     __attribute__((unused));
+static xmlEntityPtr _getEntity(libxmlSAXDriver *self, const xmlChar *name)
+     __attribute__((unused));
+static void _warning(libxmlSAXDriver *self, const char *msg, ...);
+static void _error(libxmlSAXDriver *self, const char *msg, ...);
+static void _fatalError(libxmlSAXDriver *self, const char *msg, ...);
+static void _setLocator(void *udata, xmlSAXLocatorPtr _locator);
+static void _cdataBlock(libxmlSAXDriver *self, const xmlChar *value, int len);
+static void _entityDecl(libxmlSAXDriver *self, const xmlChar *name, int type,
+                       const xmlChar *publicId, const xmlChar *systemId,
+                       xmlChar *content)
+     __attribute__((unused));
+static void _notationDecl(libxmlSAXDriver *self, const xmlChar *name,
+                         const xmlChar *publicId, const xmlChar *systemId)
+     __attribute__((unused));
+static void
+_unparsedEntityDecl(libxmlSAXDriver *self, const xmlChar *name,
+                   const xmlChar *publicId, const xmlChar *systemId,
+                   const xmlChar *notationName)
+     __attribute__((unused));
+static void _elementDecl(libxmlSAXDriver *self, const xmlChar *name, int type,
+                        xmlElementContentPtr content)
+     __attribute__((unused));
+static void _attrDecl(libxmlSAXDriver *self, const xmlChar *elem,
+                     const xmlChar *name, int type, int def,
+                     const xmlChar *defaultValue, xmlEnumerationPtr tree)
+     __attribute__((unused));
+static void _internalSubset(libxmlSAXDriver *ctx, const xmlChar *name,
+                           const xmlChar *ExternalID, const xmlChar *SystemID);
+static void _externalSubset(libxmlSAXDriver *ctx, const xmlChar *name,
+                           const xmlChar *ExternalID, const xmlChar *SystemID);
+static void _reference(libxmlSAXDriver *ctx, const xmlChar *name);
+#if 0
+static int _isStandalone(libxmlSAXDriver *self);
+static int _hasInternalSubset(libxmlSAXDriver *self);
+static int _hasExternalSubset(libxmlSAXDriver *self);
+#endif
+
+static xmlSAXHandler saxHandler = {
+  (void*)_internalSubset,      /* internalSubset */
+#if 1
+  NULL,NULL,NULL,
+#else
+  (void*)_isStandalone,        /* isStandalone */
+  (void*)_hasInternalSubset,   /* hasInternalSubset */
+  (void*)_hasExternalSubset,   /* hasExternalSubset */
+#endif
+#if HANDLE_XML_ENTITIES
+  (void*)_resolveEntity,       /* resolveEntity */
+  (void*)_getEntity,           /* getEntity */
+#else
+  NULL, NULL,
+#endif
+#if HANDLE_XML_DELCS
+  (void*)_entityDecl,          /* entityDecl */
+  (void*)_notationDecl,        /* notationDecl */
+  (void*)_attrDecl,            /* attributeDecl */
+  (void*)_elementDecl,         /* elementDecl */
+  (void*)_unparsedEntityDecl,  /* unparsedEntityDecl */
+#else
+  NULL, NULL, NULL, NULL, NULL,
+#endif
+  (void*)_setLocator,          /* setDocumentLocator */
+  (void*)_startDocument,       /* startDocument */
+  (void*)_endDocument,         /* endDocument */
+  (void*)_startElement,        /* startElement */
+  (void*)_endElement,          /* endElement */
+  (void*)_reference,           /* reference */
+  (void*)_characters,          /* characters */
+  (void*)_ignorableWhiteSpace, /* ignorableWhitespace */
+  (void*)__pi,                  /* processingInstruction */
+  (void*)_comment,             /* comment */
+  (void*)_warning,             /* warning */
+  (void*)_error,               /* error */
+  (void*)_fatalError,          /* fatalError */
+  NULL,       /* getParameterEntity */
+  (void*)_cdataBlock,          /* cdataBlock */
+  (void*)_externalSubset       /* externalSubset */
+};
+
+- (id)init {
+  self->sax     = &saxHandler;
+  self->nsStack = [[NSMutableArray alloc] init];
+  
+  /* feature defaults */
+  self->fNamespaces        = YES;
+  self->fNamespacePrefixes = NO;
+  
+  return self;
+}
+
+- (void)dealloc {
+  [self->attrs   release];
+  [self->nsStack release];
+  
+  [self->declHandler    release];
+  [self->lexicalHandler release];
+  [self->contentHandler release];
+  [self->dtdHandler     release];
+  [self->errorHandler   release];
+  [self->entityResolver release];
+  
+  [self->locator clear];
+  [self->locator release];
+
+  if (self->entity) free(self->entity);
+  [super dealloc];
+}
+
+/* properties */
+
+- (void)setProperty:(NSString *)_name to:(id)_value {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
+    ASSIGN(self->lexicalHandler, _value);
+    return;
+  }
+  if ([_name isEqualToString:SaxDeclHandlerProperty]) {
+    ASSIGN(self->declHandler, _value);
+    return;
+  }
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+}
+- (id)property:(NSString *)_name {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty])
+    return self->lexicalHandler;
+  if ([_name isEqualToString:SaxDeclHandlerProperty])
+    return self->declHandler;
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+  return nil;
+}
+
+/* features */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value {
+  if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
+    self->fNamespaces = _value;
+    return;
+  }
+  
+  if ([_name isEqualToString:
+               @"http://xml.org/sax/features/namespace-prefixes"]) {
+    self->fNamespacePrefixes = _value;
+    return;
+  }
+
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+}
+- (BOOL)feature:(NSString *)_name {
+  if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
+    return self->fNamespaces;
+  
+  if ([_name isEqualToString:
+               @"http://xml.org/sax/features/namespace-prefixes"])
+    return self->fNamespacePrefixes;
+  
+  if ([_name isEqualToString:
+               @"http://www.skyrix.com/sax/features/predefined-namespaces"])
+    return YES;
+  
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+  return NO;
+}
+
+/* handlers */
+
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
+  ASSIGN(self->dtdHandler, _handler);
+}
+- (id<NSObject,SaxDTDHandler>)dtdHandler {
+  return self->dtdHandler;
+}
+
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  ASSIGN(self->errorHandler, _handler);
+}
+- (id<NSObject,SaxErrorHandler>)errorHandler {
+  return self->errorHandler;
+}
+
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
+  ASSIGN(self->entityResolver, _handler);
+}
+- (id<NSObject,SaxEntityResolver>)entityResolver {
+  return self->entityResolver;
+}
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  ASSIGN(self->contentHandler, _handler);
+}
+- (id<NSObject,SaxContentHandler>)contentHandler {
+  return self->contentHandler;
+}
+
+/* parsing */
+
+- (NSStringEncoding)encodingForXMLEncodingString:(NSString *)_enc {
+  // TODO: use the string-charset functions in NGExtensions
+  _enc = [_enc lowercaseString];
+
+  if ([_enc isEqualToString:@"utf-8"])
+    return NSUTF8StringEncoding;
+  if ([_enc isEqualToString:@"iso-8859-1"])
+    return NSISOLatin1StringEncoding;
+  
+#ifndef NeXT_Foundation_LIBRARY
+  if ([_enc isEqualToString:@"iso-8859-9"])
+    return NSISOLatin9StringEncoding;
+#endif
+
+  if ([_enc isEqualToString:@"iso-8859-2"])
+    return NSISOLatin2StringEncoding;
+
+  if ([_enc isEqualToString:@"ascii"])
+    return NSASCIIStringEncoding;
+
+  NSLog(@"%s: UNKNOWN XML ENCODING '%@'",
+        __PRETTY_FUNCTION__, _enc);
+  return 0;
+}
+- (NSData *)dataForXMLString:(NSString *)_string {
+  NSData  *data;
+  NSRange r;
+
+  data = nil;
+  
+  r = [_string rangeOfString:@"?>"];
+  if ([_string hasPrefix:@"<?xml "] && (r.length != 0)) {
+    NSString *xmlDecl;
+    
+    xmlDecl = [_string substringToIndex:r.location];
+    
+    r = [xmlDecl rangeOfString:@"encoding='"];
+    if (r.length > 0) {
+      xmlDecl = [_string substringFromIndex:(r.location + 10)];
+      r = [xmlDecl rangeOfString:@"'"];
+      xmlDecl = (r.length > 0)
+        ? [xmlDecl substringToIndex:r.location]
+        : nil;
+    }
+    else {
+      r = [xmlDecl rangeOfString:@"encoding=\""];
+      if (r.length > 0) {
+        xmlDecl = [_string substringFromIndex:(r.location + r.length)];
+        r = [xmlDecl rangeOfString:@"\""];
+        xmlDecl = r.length > 0
+          ? [xmlDecl substringToIndex:r.location]
+          : nil;
+      }
+      else
+        xmlDecl = nil;
+    }
+    
+    if ([xmlDecl length] > 0) {
+      NSStringEncoding enc;
+        
+      if ((enc = [self encodingForXMLEncodingString:xmlDecl]) != 0) {
+        data = [_string dataUsingEncoding:enc];
+        if (data == nil) {
+          NSLog(@"WARNING(%s): couldn't get data for string '%@', "
+                @"encoding %i !", __PRETTY_FUNCTION__, _string, enc);
+          return nil;
+        }
+      }
+    }
+  }
+  
+  if (data == nil)
+    data = [_string dataUsingEncoding:NSUTF8StringEncoding];
+
+  return data;
+}
+
+- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
+  NSAutoreleasePool *pool;
+  
+  if (_source == nil) {
+    /* no source ??? */
+    return;
+  }
+  
+  if ([_source isKindOfClass:[NSString class]]) {
+    /* convert strings to UTF8 data */
+    if (_sysId == nil) _sysId = @"<string>";
+    _source = [self dataForXMLString:_source];
+  }
+  else if ([_source isKindOfClass:[NSURL class]]) {
+    if (_sysId == nil) _sysId = [_source absoluteString];
+    _source = [_source resourceDataUsingCache:NO];
+  }
+  else if ([_source isKindOfClass:[NSData class]]) {
+    if (_sysId == nil) _sysId = @"<data>";
+  }
+  else {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _source ? _source : @"<nil>", @"source",
+                         self,                         @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"can't handle data-source"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+    return;
+  }
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  /* start parsing */
+  {
+    unsigned char *src, *start;
+    unsigned len;
+    void     *oldsax;
+    
+    if ((len = [_source length]) == 0) {
+      /* no content ... */
+      return;
+    }
+    
+    /* zero-terminate the data !!! */
+    src = malloc(len + 1);
+    [_source getBytes:src length:len];
+    src[len] = '\0';
+    start = src;
+    
+    if (len > 5) {
+      unsigned char *tmp;
+      
+      if ((tmp = strstr(src, "<?xml"))) {
+        if (tmp != src) {
+          /* skip leading spaces till <?xml ...*/
+          while (*start != '\0' && isspace(*start)) {
+            start++;
+            len--;
+          }
+        }
+      }
+    }
+    
+    if (activeDriver != nil) {
+      NSLog(@"ERROR(%s): %@ there is an active driver set (%@), override !",
+            __PRETTY_FUNCTION__, self, activeDriver);
+    }
+    activeDriver = self;
+    
+    self->ctxt =
+      xmlCreateMemoryParserCtxt(start, len);
+    
+    if (self->ctxt == nil) {
+      SaxParseException *e;
+      NSDictionary *ui;
+      
+      NSLog(@"%s: couldn't create memory parser ctx (src=0x%08X, len=%d) !",
+            __PRETTY_FUNCTION__, src, len);
+      
+      if (activeDriver == self)
+        activeDriver = nil;
+      
+      ui = nil;
+      e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                                 reason:@"couldn't create memory parser context"
+                                 userInfo:ui];
+      
+      [self->errorHandler fatalError:e];
+      return;
+    }
+    
+    if (((xmlParserCtxtPtr)self->ctxt)->input != NULL && [_sysId length] > 0) {
+      ((xmlParserInputPtr)((xmlParserCtxtPtr)self->ctxt)->input)->filename =
+        [_sysId cString];
+    }
+    
+    oldsax = ((xmlParserCtxtPtr)self->ctxt)->sax;
+    ((xmlParserCtxtPtr)self->ctxt)->sax = self->sax;
+    ((xmlParserCtxtPtr)self->ctxt)->userData = self;
+    
+    xmlParseDocument(ctxt);
+    
+    if (!(((xmlParserCtxtPtr)self->ctxt)->wellFormed))
+      NSLog(@"%@: not well formed", _sysId);
+    
+    if (((xmlParserCtxtPtr)self->ctxt)->input != NULL && [_sysId length] > 0)
+      ((xmlParserInputPtr)((xmlParserCtxtPtr)self->ctxt)->input)->filename =NULL;
+    
+    ((xmlParserCtxtPtr)self->ctxt)->sax = oldsax;
+    ((xmlParserCtxtPtr)self->ctxt)->userData = NULL;
+    xmlFreeParserCtxt(ctxt);
+    
+    if (activeDriver == self)
+      activeDriver = nil;
+    
+    if (src) { 
+      free(src); 
+      src = NULL;
+    }
+  }
+  
+  [pool release];
+}
+- (void)parseFromSource:(id)_source {
+  [self parseFromSource:_source systemId:nil];
+}
+
+static int mfread(void *f, char *buf, int len) {
+  int l;
+  l = fread(buf, 1, len, f);
+  //printf("read %i bytes\n", l);
+  return l;
+}
+static int mfclose(void *f) {
+  return fclose(f);
+}
+
+- (void)parseFromSystemId:(NSString *)_sysId {
+  /* _sysId is a URI */
+  NSAutoreleasePool *pool;
+  
+  if (![_sysId hasPrefix:@"file:"]) {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    NSURL *url;
+    
+    if ((url = [NSURL URLWithString:_sysId])) {
+      [self parseFromSource:url systemId:_sysId];
+      return;
+    }
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _sysId ? _sysId : @"<nil>", @"systemID",
+                         self,                       @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"can't handle system-id"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+    return;
+  }
+  
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  /* cut off file:// */
+  if ([_sysId hasPrefix:@"file://"])
+    _sysId = [_sysId substringFromIndex:7];
+  else
+    _sysId = [_sysId substringFromIndex:5];
+  
+  /* start parsing .. */
+#if 0
+  ret = xmlSAXUserParseFile(self->sax, (void *)self, [_sysId cString]);
+#else
+  {
+    FILE *f;
+    f = fopen([_sysId cString], "r");
+
+    if (f == NULL) {
+      SaxParseException *e;
+      NSDictionary *ui;
+#if DEBUG
+      NSLog(@"%s: missing file '%@'", __PRETTY_FUNCTION__, _sysId);
+#endif
+      ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                           _sysId ? _sysId : @"<nil>", @"path",
+                           self,                       @"parser",
+                           nil];
+      e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                                 reason:@"can't find file"
+                                 userInfo:ui];
+      
+      [self->errorHandler fatalError:e];
+      [pool release];
+      return;
+    }
+    
+    self->ctxt =
+      xmlCreateIOParserCtxt(self->sax, self /* userdata */,
+                           mfread,  /* ioread  */
+                           mfclose, /* ioclose */
+                           f,       /* ioctx   */
+                           XML_CHAR_ENCODING_UTF8 /* encoding */);
+    
+    if (((xmlParserCtxtPtr)self->ctxt)->input != NULL && [_sysId length] > 0) {
+      ((xmlParserInputPtr)((xmlParserCtxtPtr)self->ctxt)->input)->filename =
+        [_sysId cString];
+    }
+    
+    if (activeDriver != nil) {
+      NSLog(@"WARNING(%s): %@ there is an active driver set (%@), override !",
+            __PRETTY_FUNCTION__, self, activeDriver);
+    }
+    activeDriver = self;
+    
+    xmlParseDocument(self->ctxt);
+    
+    if (activeDriver == self)
+      activeDriver = nil;
+    
+    if (((xmlParserCtxtPtr)self->ctxt)->input != NULL && [_sysId length] > 0)
+      ((xmlParserInputPtr)((xmlParserCtxtPtr)self->ctxt)->input)->filename =NULL;
+    
+    if (!(((xmlParserCtxtPtr)self->ctxt)->wellFormed))
+      NSLog(@"%@: not well formed", _sysId);
+    
+    ((xmlParserCtxtPtr)self->ctxt)->sax = NULL;
+    xmlFreeParserCtxt(self->ctxt);
+  }
+#endif
+
+  [pool release];
+}
+
+/* entities */
+
+- (NSString *)replacementStringForEntityNamed:(NSString *)_entityName {
+  // TODO: check, how this is used, could explain some problems
+  //NSLog(@"get entity: %@", _entityName);
+  return [[@"&amp;" stringByAppendingString:_entityName]
+                    stringByAppendingString:@";"];
+}
+
+/* namespace support */
+
+- (NSString *)nsUriForPrefix:(NSString *)_prefix {
+  NSEnumerator *e;
+  NSDictionary *ns;
+  
+  e = [self->nsStack reverseObjectEnumerator];
+  while ((ns = [e nextObject])) {
+    NSString *uri;
+    
+    if ((uri = [ns objectForKey:_prefix])) {
+      //NSLog(@"prefix %@ -> uri %@", _prefix, uri);
+      return uri;
+    }
+  }
+  //NSLog(@"prefix %@ -> uri %@", _prefix, nil);
+  return nil;
+}
+
+- (NSString *)defaultNamespace {
+  return [self nsUriForPrefix:@":"];
+}
+
+- (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri {
+  NSMutableDictionary *ns = nil;
+  NSDictionary *newns;
+  unsigned count;
+  
+  NSCAssert(self->nsStack, @"missing namespace stack");
+
+  if ((count = [self->nsStack count]) == 0)
+    ns = [[NSMutableDictionary alloc] initWithCapacity:2];
+  else
+    ns = [[self->nsStack lastObject] mutableCopy];
+  
+  if ([_prefix length] == 0)
+    _prefix = @":";
+  
+  [ns setObject:_uri forKey:_prefix];
+
+  newns = [ns copy];
+  [ns release];
+
+  if (count == 0)
+    [self->nsStack addObject:newns];
+  else
+    [self->nsStack replaceObjectAtIndex:(count - 1) withObject:newns];
+  
+  [newns release];
+}
+
+/* ---------- libxml sax connection ---------- */
+
+static void
+_startElement(libxmlSAXDriver *self, const xmlChar *name, const xmlChar **atts)
+{
+  NSString *ename, *rawName, *euri;
+  NSDictionary *nsDict = nil;
+  NSRange r;
+  
+  /* first scan for namespace declaration */
+  
+  if (atts) {
+    NSMutableDictionary *ns = nil;
+    int i;
+    
+    for (i = 0; atts[i]; i += 2) {
+      const xmlChar *an = atts[i];
+      
+      /* check for attr-names beginning with 'xmlns' */
+      if (an[0] != 'x') continue;
+      if (an[1] != 'm') continue;
+      if (an[2] != 'l') continue;
+      if (an[3] != 'n') continue;
+      if (an[4] != 's') continue;
+      
+      /* ok, found ns decl */
+      
+      if (ns == nil) ns = [[NSMutableDictionary alloc] init];
+      
+      if (an[5] == ':') {
+        /* eg <x xmlns:nl="http://www.w3.org"/> */
+        NSString *prefix, *uri;
+        
+        if (an[6] == '\0') {
+          /* invalid, namespace name may not be empty ! */
+          NSLog(@"WARNING(%s): empty namespace prefix !", __PRETTY_FUNCTION__);
+        }
+        
+        prefix = xmlCharsToString(&(an[6]));
+        uri    = xmlCharsToString(atts[i + 1]);
+        
+        //NSLog(@"prefix %@ uri %@", prefix, uri);
+        
+        NSCAssert(ns, @"missing namespace dictionary");
+        [ns setObject:uri forKey:prefix];
+        
+        if (self->fNamespaces)
+          [self->contentHandler startPrefixMapping:prefix uri:uri];
+
+        [prefix release]; prefix = nil;
+        [uri release];    uri    = nil;
+      }
+      else {
+        /* eg <x xmlns="http://www.w3.org"/> */
+        NSString *uri;
+        
+        uri = xmlCharsToString(atts[i + 1]);
+        [ns setObject:uri forKey:@":"];
+
+        //NSLog(@"prefix default uri %@", uri);
+        [uri release]; uri = nil;
+      }
+    }
+    
+    nsDict = [ns copy];
+    [ns release];
+  }
+  
+  /* manage namespace stack */
+  
+  if (nsDict == nil)
+    nsDict = [NSDictionary dictionary];
+  
+  NSCAssert(self->nsStack, @"missing namespace stack");
+  [self->nsStack addObject:nsDict];
+  
+  /* process element name */
+  
+  rawName = xmlCharsToString(name);
+  r = [rawName rangeOfString:@":"];
+  if (r.length > 0) {
+    /* eg: <edi:bill/> */
+    NSString *prefix;
+    
+    prefix = [rawName substringToIndex:r.location];
+    ename  = [rawName substringFromIndex:(r.location + r.length)];
+    euri   = [self nsUriForPrefix:prefix];
+  }
+  else {
+    ename = rawName;
+    euri  = [self defaultNamespace];
+  }
+  
+  /* create sax attrs */
+
+  if (self->attrs == nil)
+    self->attrs = [[SaxAttributes alloc] init];
+  else
+    [self->attrs clear];
+  
+  if (atts) {
+    int i;
+    
+    for (i = 0; atts[i]; i += 2) {
+      NSString *name, *rawName, *uri;
+      NSString *type, *value;
+      NSRange  r;
+
+      if (!self->fNamespacePrefixes) {
+        if (atts[i][0] == 'x') {
+          const char *an = atts[i];
+        
+          if (strstr(an, "xmlns") == an)
+            continue;
+        }
+      }
+      
+      rawName = xmlCharsToString(atts[i]);
+      r = [rawName rangeOfString:@":"];
+      
+      if (r.length > 0) {
+        /* explicit attribute namespace, eg '<d edi:bill="100"/>' */
+        NSString *prefix;
+        
+        prefix = [rawName substringToIndex:r.location];
+        name   = [rawName substringFromIndex:(r.location + r.length)];
+        uri    = [self nsUriForPrefix:prefix];
+      }
+      else {
+        /* plain attribute, eg '<d bill="100"/>' */
+        name   = rawName;
+        uri    = euri; /* attr inherits namespace from element-name */
+      }
+      
+      type  = @"CDATA";
+      value = xmlCharsToString(atts[i + 1]);
+      
+      [self->attrs
+           addAttribute:name uri:uri rawName:rawName
+           type:type value:value];
+
+      [value   release]; value   = nil;
+      [rawName release]; rawName = nil;
+    }
+  }
+  
+  self->depth++;
+  
+  /* send notification */
+  
+  [self->contentHandler startElement:ename namespace:euri
+                        rawName:rawName
+                        attributes:self->attrs];
+
+  [rawName release]; rawName = nil;
+  
+  [self->attrs clear];
+}
+
+static void _endElement(libxmlSAXDriver *self, const xmlChar *name) {
+  NSString *ename, *rawName, *uri;
+  NSRange  r;
+  
+  rawName = xmlCharsToString(name);
+  r = [rawName rangeOfString:@":"];
+  
+  if (r.length > 0) {
+    /* eg: <edi:bill/> */
+    NSString *prefix;
+    
+    prefix = [rawName substringToIndex:r.location];
+    ename  = [rawName substringFromIndex:(r.location + r.length)];
+    uri    = [self nsUriForPrefix:prefix];
+  }
+  else {
+    ename = rawName;
+    uri   = [self defaultNamespace];
+  }
+  
+  [self->contentHandler endElement:ename namespace:uri rawName:rawName];
+  self->depth--;
+  [rawName release]; rawName = nil;
+
+  /* process namespace stack */
+
+  if (self->fNamespaces) {
+    NSDictionary *ns;
+    NSEnumerator *keys;
+    NSString     *key;
+    
+    ns = [self->nsStack lastObject];
+    keys = [ns keyEnumerator];
+    while ((key = [keys nextObject])) {
+      if ([key isEqualToString:@":"])
+        continue;
+      [self->contentHandler endPrefixMapping:key];
+    }
+  }
+  [self->nsStack removeLastObject];
+}
+
+static void _startDocument(libxmlSAXDriver *self) {
+  static NSDictionary *defNS = nil;
+  id keys[2], values[2];
+
+  //NSLog(@"start doc 0x%08X", self);
+
+  if (defNS == nil) {
+    keys[0] = @"xml"; values[0] = @"http://www.w3.org/XML/1998/namespace";
+    keys[1] = @":";   values[1] = @"";
+    defNS = [[NSDictionary alloc] initWithObjects:values forKeys:keys count:2];
+  }
+  if ([self->nsStack count] == 0)
+    [self->nsStack addObject:defNS];
+  else
+    [self->nsStack insertObject:defNS atIndex:0];
+  
+  [self->contentHandler startDocument];
+}
+static void _endDocument(libxmlSAXDriver *self) {
+  [self->contentHandler endDocument];
+  
+  if ([self->nsStack count] > 0)
+    [self->nsStack removeObjectAtIndex:0];
+  else {
+    NSLog(@"libxmlSAXDriver: inconsistent state, "
+          @"nothing on NS stack in endDocument !");
+  }
+}
+
+static void _characters(libxmlSAXDriver *self, const xmlChar *chars, int len) {
+  /* need to transform UTF8 to UTF16 */
+  unichar *data, *ts;
+  
+  if (len == 0) {
+    unichar c = 0;
+    data = &c;
+    [self->contentHandler characters:data length:0];
+    return;
+  }
+  if (chars == NULL) {
+    [self->contentHandler characters:NULL length:0];
+    return;
+  }
+  
+  data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
+  
+  if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
+                   (void *)&ts, ts + (len * sizeof(unichar)))) {
+    free(data);
+    NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
+          __PRETTY_FUNCTION__, __LINE__);
+  }
+  else {
+    [self->contentHandler characters:data length:((unsigned)(ts - data))];
+    free(data);
+  }
+}
+
+static void
+_ignorableWhiteSpace(libxmlSAXDriver *self, const xmlChar *chars, int len)
+{
+  /* need to transform UTF8 to UTF16 */
+  unichar *data, *ts;
+  
+  if (len == 0) {
+    unichar c = 0;
+    data = &c;
+    [self->contentHandler ignorableWhitespace:data length:len];
+    return;
+  }
+  if (chars == NULL) {
+    [self->contentHandler ignorableWhitespace:NULL length:0];
+    return;
+  }
+  
+  data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
+  
+  if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
+                   (void *)&ts, ts + (len * sizeof(unichar)))) {
+    free(data);
+    NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
+          __PRETTY_FUNCTION__, __LINE__);
+  }
+  else {
+    [self->contentHandler ignorableWhitespace:data length:(ts - data)];
+    free(data);
+  }
+}
+
+static void __pi(libxmlSAXDriver *self, const xmlChar *pi, const xmlChar *data) {
+  NSString *epi, *edata;
+  
+  epi   = xmlCharsToString(pi);
+  edata = xmlCharsToString(data);
+  
+  [self->contentHandler processingInstruction:epi data:edata];
+
+  [epi   release]; epi   = nil;
+  [edata release]; edata = nil;
+}
+
+static void _comment(libxmlSAXDriver *self, const xmlChar *value) {
+  if (self->lexicalHandler) {
+    /* need to transform UTF8 to UTF16 */
+    unichar *data;
+    register int i, len;
+    
+    len = strlen(value);
+    
+    data = calloc(len +1 ,sizeof(unichar)); /* GC ?! */
+
+    for (i = 0; i < len; i++)
+      data[i] = value[i];
+
+    [self->lexicalHandler comment:data length:len];
+    
+    if (data) { free(data); data = NULL; }
+  }
+}
+
+static void _setLocator(void *udata, xmlSAXLocatorPtr _locator) {
+  if (activeDriver == nil) { 
+    NSLog(@"ERROR(%s): no driver is active !", __PRETTY_FUNCTION__);
+    return;
+  }
+  
+  [activeDriver->locator release];
+  
+  activeDriver->locator = [[libxmlSAXLocator alloc]
+                                             initWithSaxLocator:_locator
+                                             parser:activeDriver];
+  activeDriver->locator->ctx = activeDriver->ctxt;
+  
+  [activeDriver->contentHandler setDocumentLocator:activeDriver->locator];
+}
+
+static xmlParserInputPtr
+_resolveEntity(libxmlSAXDriver *self, const xmlChar *pub, const xmlChar *sys)
+{
+  NSString *pubId, *sysId;
+  id src;
+
+  pubId = xmlCharsToString(pub);
+  sysId = xmlCharsToString(sys);
+  
+  src = [self->entityResolver resolveEntityWithPublicId:pubId systemId:sysId];
+  if (src == nil) {
+    //return xmlLoadExternalEntity(sys, pub, self);
+    return NULL;
+  }
+  
+  NSLog(@"ignored entity src %@", src);
+  
+  [pubId release]; pubId = nil;
+  [sysId release]; sysId = nil;
+  return NULL;
+}
+
+static xmlEntityPtr _getEntity(libxmlSAXDriver *self, const xmlChar *name) {
+  xmlEntityPtr p;
+  NSString *ename, *s;
+  
+  if ((p = xmlGetPredefinedEntity(name)))
+    return p;
+  
+  if (self->entity == NULL)
+    /* setup shared entity structure */
+    self->entity = calloc(1, sizeof(xmlEntity));
+  
+  ename = xmlCharsToString(name);
+  s     = [self replacementStringForEntityNamed:ename];
+
+  /* need to convert to unicode ! */
+  
+  /* fill entity structure */
+  p = self->entity;
+  p->name    = [ename cString];
+  p->etype   = XML_INTERNAL_GENERAL_ENTITY;
+  p->orig    = (void *)[ename cString];
+  p->content = (void *)[s cString];
+  p->length  = [s cStringLength];
+  
+  [ename release]; ename = nil;
+  
+  return p;
+}
+
+static void _cdataBlock(libxmlSAXDriver *self, const xmlChar *value, int len) {
+  [self->lexicalHandler startCDATA];
+  _characters(self, value, len);
+  [self->lexicalHandler endCDATA];
+}
+
+static SaxParseException *
+mkException(libxmlSAXDriver *self, NSString *key, const char *msg, va_list va)
+{
+  NSString          *s, *reason;
+  NSDictionary      *ui;
+  SaxParseException *e;
+  NSRange r;
+  int count = 0, i;
+  id  keys[7], values[7];
+  id  tmp;
+  
+  s = [NSString stringWithCString:msg];
+  s = [[[NSString alloc]
+                  initWithFormat:s arguments:va]
+                  autorelease];
+  r = [s rangeOfString:@"\n"];
+  reason = r.length > 0
+    ? [s substringToIndex:r.location]
+    : s;
+  
+  if ([reason length] == 0)
+    reason = @"unknown reason";
+  
+  keys[0] = @"parser"; values[0] = self; count++;
+  keys[1] = @"depth";  values[1] = [NSNumber numberWithInt:self->depth]; count++;
+  
+  if ([s length] > 0) {
+    keys[count]   = @"errorMessage";
+    values[count] = s;
+    count++;
+  }
+  
+  if ((i = [self->locator lineNumber]) >= 0) {
+    keys[count] = @"line";
+    values[count] = [NSNumber numberWithInt:i];
+    count++;
+  }
+  if ((i = [self->locator columnNumber]) >= 0) {
+    keys[count] = @"column";
+    values[count] = [NSNumber numberWithInt:i];
+    count++;
+  }
+  if ((tmp = [self->locator publicId])) {
+    keys[count]   = @"publicId";
+    values[count] = tmp;
+    count++;
+  }
+  if ((tmp = [self->locator systemId])) {
+    keys[count]   = @"systemId";
+    values[count] = tmp;
+    count++;
+  }
+  
+  ui = [NSDictionary dictionaryWithObjects:values forKeys:keys count:count];
+  
+  e = (id)[SaxParseException exceptionWithName:key
+                             reason:reason
+                             userInfo:ui];
+  return e;
+}
+
+static void _warning(libxmlSAXDriver *self, const char *msg, ...) {
+  va_list           args;
+  SaxParseException *e;
+
+  va_start(args, msg);
+  e = mkException(self, @"SAXWarning", msg, args);
+  va_end(args);
+  
+  [self->errorHandler warning:e];
+}
+static void _error(libxmlSAXDriver *self, const char *msg, ...) {
+  va_list           args;
+  SaxParseException *e;
+
+  va_start(args, msg);
+  e = mkException(self, @"SAXError", msg, args);
+  va_end(args);
+  
+  [self->errorHandler error:e];
+}
+static void _fatalError(libxmlSAXDriver *self, const char *msg, ...) {
+  va_list           args;
+  SaxParseException *e;
+
+  va_start(args, msg);
+  e = mkException(self, @"SAXFatalError", msg, args);
+  va_end(args);
+  
+  [self->errorHandler fatalError:e];
+}
+
+static void _entityDecl(libxmlSAXDriver *self, const xmlChar *name, int type,
+                       const xmlChar *publicId, const xmlChar *systemId,
+                       xmlChar *content)
+{
+  NSString *ename, *pubId, *sysId;
+  NSString *value;
+  
+  ename = xmlCharsToString(name);
+  pubId = xmlCharsToString(publicId);
+  sysId = xmlCharsToString(systemId);
+  value = xmlCharsToString(content);
+  
+  switch (type) {
+    case XML_INTERNAL_GENERAL_ENTITY:
+    case XML_INTERNAL_PARAMETER_ENTITY:
+    case XML_INTERNAL_PREDEFINED_ENTITY:
+      [self->declHandler internalEntityDeclaration:ename value:value];
+      break;
+    
+    case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
+    case XML_EXTERNAL_PARAMETER_ENTITY:
+      [self->declHandler externalEntityDeclaration:ename
+                         publicId:pubId systemId:sysId];
+      break;
+      
+    case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
+      /* is content really =notationName ??? */
+      NSLog(@"unparsed ext entity ..");
+      [self->dtdHandler unparsedEntityDeclaration:ename
+                        publicId:pubId systemId:sysId
+                        notationName:value];
+      break;
+      
+    default:
+      [NSException raise:@"InvalidEntityType"
+                   format:@"don't know entity type with code %i", type];
+  }
+
+  [ename release];
+  [pubId release];
+  [sysId release];
+  [value release];
+}
+
+static void
+_unparsedEntityDecl(libxmlSAXDriver *self,const xmlChar *name,
+                    const xmlChar *publicId, const xmlChar *systemId,
+                    const xmlChar *notationName)
+{
+  if (self->dtdHandler) {
+    NSString *ename, *nname, *pubId, *sysId;
+    
+    ename = xmlCharsToString(name);
+    nname = xmlCharsToString(notationName);
+    pubId = xmlCharsToString(publicId);
+    sysId = xmlCharsToString(systemId);
+    
+    [self->dtdHandler unparsedEntityDeclaration:ename
+                      publicId:pubId systemId:sysId
+                      notationName:nname];
+
+    [ename release];
+    [nname release];
+    [pubId release];
+    [sysId release];
+  }
+}
+
+static void _notationDecl(libxmlSAXDriver *self, const xmlChar *name,
+                         const xmlChar *publicId, const xmlChar *systemId)
+{
+  if (self->dtdHandler) {
+    NSString *nname, *pubId, *sysId;
+    
+    nname = xmlCharsToString(name);
+    pubId = xmlCharsToString(publicId);
+    sysId = xmlCharsToString(systemId);
+    
+    [self->dtdHandler notationDeclaration:nname publicId:pubId systemId:sysId];
+
+    [nname release];
+    [pubId release];
+    [sysId release];
+  }
+}
+
+static NSString *_occurString(xmlElementContentOccur _occurType)
+     __attribute__((unused));
+static NSString *_occurString(xmlElementContentOccur _occurType) {
+  switch (_occurType) {
+    case XML_ELEMENT_CONTENT_ONCE: return @"";
+    case XML_ELEMENT_CONTENT_OPT:  return @"?";
+    case XML_ELEMENT_CONTENT_MULT: return @"*";
+    case XML_ELEMENT_CONTENT_PLUS: return @"+";
+  }
+  return @"";
+}
+
+static void _addElemModel(xmlElementContentPtr p, NSMutableString *s, int pt) {
+  if (p == NULL) return;
+
+  switch (p->type) {
+    case XML_ELEMENT_CONTENT_PCDATA:
+      if (pt == -1) [s appendString:@"("];
+      [s appendString:@"#PCDATA"];
+      if (pt == -1) [s appendString:@")"];
+      break;
+      
+    case XML_ELEMENT_CONTENT_ELEMENT: {
+      NSString *ename;
+      
+      ename = xmlCharsToString(p->name);
+      
+      if (pt == -1) [s appendString:@"("];
+      [s appendString:ename];
+      if (pt == -1) [s appendString:@")"];
+
+      [ename release]; ename = nil;
+      break;
+    }
+    
+    case XML_ELEMENT_CONTENT_SEQ:
+      if (pt != XML_ELEMENT_CONTENT_SEQ) [s appendString:@"("];
+      _addElemModel(p->c1, s, XML_ELEMENT_CONTENT_SEQ);
+      [s appendString:@","];
+      _addElemModel(p->c2, s, XML_ELEMENT_CONTENT_SEQ);
+      if (pt != XML_ELEMENT_CONTENT_SEQ) [s appendString:@")"];
+      break;
+      
+    case XML_ELEMENT_CONTENT_OR:
+      if (pt != XML_ELEMENT_CONTENT_OR) [s appendString:@"("];
+      _addElemModel(p->c1, s, XML_ELEMENT_CONTENT_OR);
+      [s appendString:@"|"];
+      _addElemModel(p->c2, s, XML_ELEMENT_CONTENT_OR);
+      if (pt != XML_ELEMENT_CONTENT_OR) [s appendString:@")"];
+      break;
+  }
+  switch (p->ocur) {
+    case XML_ELEMENT_CONTENT_ONCE: break;
+    case XML_ELEMENT_CONTENT_OPT:  [s appendString:@"?"]; break;
+    case XML_ELEMENT_CONTENT_MULT: [s appendString:@"*"]; break;
+    case XML_ELEMENT_CONTENT_PLUS: [s appendString:@"+"]; break;
+  }
+}
+
+static void _elementDecl(libxmlSAXDriver *self, const xmlChar *name, int type,
+                        xmlElementContentPtr content)
+{
+  if (self->declHandler) {
+    NSString *ename, *model;
+    
+    ename = xmlCharsToString(name);
+    
+    if (content) {
+      NSMutableString *emodel;
+      
+      emodel = [[NSMutableString alloc] init];
+      _addElemModel(content, emodel, -1);
+      model = [[emodel copy] autorelease];
+      [emodel release];
+    }
+    else
+      model = nil;
+    
+    [self->declHandler elementDeclaration:ename contentModel:model];
+    [ename release]; ename = nil;
+  }
+}
+
+static void _attrDecl(libxmlSAXDriver *self, const xmlChar *elem,
+                     const xmlChar *name, int type, int def,
+                     const xmlChar *defaultValue, xmlEnumerationPtr tree)
+{
+  if (self->declHandler) {
+    NSString *ename, *aname, *defValue, *atype, *defType;
+    
+    ename    = xmlCharsToString(elem);
+    aname    = xmlCharsToString(name);
+    defValue = xmlCharsToString(defaultValue);
+    atype    = nil;
+    defType  = nil;
+
+    switch (type) {
+      case XML_ATTRIBUTE_CDATA:       atype = @"CDATA";       break;
+      case XML_ATTRIBUTE_ID:          atype = @"ID";          break;
+      case XML_ATTRIBUTE_IDREF:       atype = @"IDREF";       break;
+      case XML_ATTRIBUTE_IDREFS:      atype = @"IDREFS";      break;
+      case XML_ATTRIBUTE_ENTITY:      atype = @"ENTITY";      break;
+      case XML_ATTRIBUTE_ENTITIES:    atype = @"ENTITIES";    break;
+      case XML_ATTRIBUTE_NMTOKEN:     atype = @"NMTOKEN";     break;
+      case XML_ATTRIBUTE_NMTOKENS:    atype = @"NMTOKENS";    break;
+      case XML_ATTRIBUTE_ENUMERATION: atype = @"ENUMERATION"; break;
+      case XML_ATTRIBUTE_NOTATION:    atype = @"NOTATION";    break;
+      
+      default:
+        [NSException raise:@"InvalidAttributeType"
+                     format:@"don't know attr type with code %i", type];
+    }
+    switch (def) {
+      case XML_ATTRIBUTE_NONE:     defType = nil;          break;
+      case XML_ATTRIBUTE_REQUIRED: defType = @"#REQUIRED"; break;
+      case XML_ATTRIBUTE_IMPLIED:  defType = @"#IMPLIED";  break;
+      case XML_ATTRIBUTE_FIXED:    defType = @"#FIXED";    break;
+        
+      default:
+        [NSException raise:@"InvalidAttributeDefaultType"
+                     format:@"don't know attr default type with code %i", def];
+    }
+    
+    [self->declHandler attributeDeclaration:aname elementName:ename
+                       type:atype
+                       defaultType:defType defaultValue:defValue];
+    [ename release];
+    [aname release];
+    [defValue release];
+  }
+}
+
+#if 0
+static int isStandalone(libxmlSAXDriver *self) {
+}
+static int hasInternalSubset(libxmlSAXDriver *self) {
+}
+static int hasExternalSubset(libxmlSAXDriver *self) {
+}
+#endif
+
+static void _externalSubset(libxmlSAXDriver *ctx, const xmlChar *name,
+                           const xmlChar *ExternalID, const xmlChar *SystemID)
+{
+}
+static void _internalSubset(libxmlSAXDriver *ctx, const xmlChar *name,
+                           const xmlChar *ExternalID, const xmlChar *SystemID)
+{
+}
+
+static void _reference(libxmlSAXDriver *ctx, const xmlChar *name) {
+#if 0
+  NSString *refName;
+
+  refName = xmlCharsToString(name);
+  NSLog(@"reference: '%@'", refName);
+  [refName release];
+#endif
+}
+
+@end /* libxmlSAXDriver */
+
+#include "unicode.h"
diff --git a/skyrix-xml/libxmlSAXDriver/libxmlSAXLocator.h b/skyrix-xml/libxmlSAXDriver/libxmlSAXLocator.h
new file mode 100644 (file)
index 0000000..b84b403
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __libxmlSAXLocator_H__
+#define __libxmlSAXLocator_H__
+
+#import <Foundation/NSObject.h>
+#import <SaxObjC/SaxLocator.h>
+
+#include <libxml/parser.h>
+
+@interface libxmlSAXLocator : NSObject < SaxLocator >
+{
+@public
+  id            parser;
+  void          *ctx;
+  const xmlChar *(*getPublicId)(void *ctx);
+  const xmlChar *(*getSystemId)(void *ctx);
+  int           (*getLineNumber)(void *ctx);
+  int           (*getColumnNumber)(void *ctx);
+}
+
+- (id)initWithSaxLocator:(xmlSAXLocatorPtr)_loc parser:(id)_parser;
+- (void)clear;
+
+/* accessors */
+
+- (int)columnNumber;
+- (int)lineNumber;
+- (NSString *)publicId;
+- (NSString *)systemId;
+
+@end
+
+#endif /* __libxmlSAXLocator_H__ */
diff --git a/skyrix-xml/libxmlSAXDriver/libxmlSAXLocator.m b/skyrix-xml/libxmlSAXDriver/libxmlSAXLocator.m
new file mode 100644 (file)
index 0000000..c98a329
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import "libxmlSAXLocator.h"
+#include "common.h"
+
+@implementation libxmlSAXLocator
+
+- (id)initWithSaxLocator:(xmlSAXLocatorPtr)_loc parser:(id)_parser {
+  if (_loc == NULL) {
+    [self release];
+    return nil;
+  }
+  self->parser = _parser;
+  self->getPublicId     = _loc->getPublicId;
+  self->getSystemId     = _loc->getSystemId;
+  self->getLineNumber   = _loc->getLineNumber;
+  self->getColumnNumber = _loc->getColumnNumber;
+  return self;
+}
+
+- (void)clear {
+  self->parser = nil;
+}
+
+/* accessors */
+
+- (int)columnNumber {
+  //return -1;
+  NSAssert(self->ctx, @"missing locator ctx ..");
+  return self->getColumnNumber ? self->getColumnNumber(self->ctx) : -1;
+}
+- (int)lineNumber {
+  //return -1;
+  NSAssert(self->ctx, @"missing locator ctx ..");
+  return self->getLineNumber ? self->getLineNumber(self->ctx) : -1;
+}
+
+- (NSString *)publicId {
+  const xmlChar *s;
+  //return nil;
+  s = self->getPublicId ? self->getPublicId(self->ctx) : NULL;
+  return s ? [NSString stringWithCString:s] : nil;
+}
+
+- (NSString *)systemId {
+  const xmlChar *s;
+  //return nil;
+  s = self->getSystemId ? self->getSystemId(self->ctx) : NULL;
+  return s ? [NSString stringWithCString:s] : nil;
+}
+
+/* description */
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<0x%08X[%@]: pub=%@ sys=%@ L%i C%i>",
+                     self, NSStringFromClass([self class]),
+                     [self publicId], [self systemId],
+                     [self lineNumber], [self columnNumber]];
+}
+
+@end /* libxmlSaxLocator */
diff --git a/skyrix-xml/libxmlSAXDriver/unicode.h b/skyrix-xml/libxmlSAXDriver/unicode.h
new file mode 100644 (file)
index 0000000..48c8769
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+/* Unicode support */
+
+typedef unsigned long  UCS4;
+typedef unsigned short UCS2;
+typedef unsigned short UTF16;
+typedef unsigned char  UTF8;
+#define unichar UTF16
+
+static const int halfShift             = 10;
+static const UCS4 halfBase             = 0x0010000UL;
+static const UCS4 halfMask             = 0x3FFUL;
+static const UCS4 kSurrogateHighStart  = 0xD800UL;
+static const UCS4 kSurrogateLowStart   = 0xDC00UL;
+
+static const UCS4 kReplacementCharacter = 0x0000FFFDUL;
+static const UCS4 kMaximumUCS2          = 0x0000FFFFUL;
+static const UCS4 kMaximumUTF16         = 0x0010FFFFUL;
+
+static UCS4 offsetsFromUTF8[6] = {
+  0x00000000UL, 0x00003080UL, 0x000E2080UL, 
+  0x03C82080UL, 0xFA082080UL, 0x82082080UL
+};
+static char bytesFromUTF8[256] = {
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+static int
+_UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
+             unichar **targetStart, const unichar *targetEnd)
+{
+  int            result = 0;
+  register UTF8  *source = *sourceStart;
+  register UTF16 *target = *targetStart;
+  
+  while (source < sourceEnd) {
+    register UCS4 ch = 0;
+    register unsigned short extraBytesToWrite = bytesFromUTF8[*source];
+    
+    if (source + extraBytesToWrite > sourceEnd) {
+      result = 1; break;
+    };
+    switch(extraBytesToWrite) { /* note: code falls through cases! */
+      case 5:   ch += *source++; ch <<= 6;
+      case 4:   ch += *source++; ch <<= 6;
+      case 3:   ch += *source++; ch <<= 6;
+      case 2:   ch += *source++; ch <<= 6;
+      case 1:   ch += *source++; ch <<= 6;
+      case 0:   ch += *source++;
+    };
+    ch -= offsetsFromUTF8[extraBytesToWrite];
+
+    if (target >= targetEnd) {
+      result = 2; break;
+    };
+    if (ch <= kMaximumUCS2) {
+      *target++ = ch;
+    } else if (ch > kMaximumUTF16) {
+      *target++ = kReplacementCharacter;
+    } else {
+      if (target + 1 >= targetEnd) {
+        result = 2; break;
+      };
+      ch -= halfBase;
+      *target++ = (ch >> halfShift) + kSurrogateHighStart;
+      *target++ = (ch & halfMask) + kSurrogateLowStart;
+    };
+  };
+  *sourceStart = source;
+  *targetStart = target;
+  return result;
+}
diff --git a/skyrix-xml/pyxSAXDriver/COPYING b/skyrix-xml/pyxSAXDriver/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/skyrix-xml/pyxSAXDriver/ChangeLog b/skyrix-xml/pyxSAXDriver/ChangeLog
new file mode 100644 (file)
index 0000000..79dc115
--- /dev/null
@@ -0,0 +1,18 @@
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package.
+
+2003-12-03  Helge Hess  <helge.hess@opengroupware.org>
+
+       * GNUmakefile: include common.make from GNUSTEP_MAKEFILES
+
+2003-01-07  Helge Hess  <helge.hess@skyrix.com>
+
+       * fixed a compilation bug, maybe the driver needs to be updated to
+         the current SAX API
+
+       * created ChangeLog
+
+
diff --git a/skyrix-xml/pyxSAXDriver/GNUmakefile b/skyrix-xml/pyxSAXDriver/GNUmakefile
new file mode 100644 (file)
index 0000000..856c240
--- /dev/null
@@ -0,0 +1,34 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+BUNDLE_NAME        = pyxSAXDriver
+BUNDLE_EXTENSION   = .sax
+BUNDLE_INSTALL_DIR = $(GNUSTEP_USER_ROOT)/Library/Bundles
+
+pyxSAXDriver_OBJC_FILES = pyxSAXDriver.m
+
+pyxSAXDriver_BUNDLE_LIBS += -lSaxObjC
+
+ifeq ($(GNUSTEP_TARGET_OS),cygwin32)
+pyxSAXDriver_BUNDLE_LIBS += \
+       -lFoundation -lobjc
+endif
+
+pyxSAXDriver_RESOURCE_FILES = bundle-info.plist
+pyxSAXDriver_LOCALIZED_RESOURCE_FILES =
+
+ADDITIONAL_INCLUDE_DIRS += -I.. -I../..
+ADDITIONAL_LIB_DIRS     += -L../SaxObjC/$(GNUSTEP_OBJ_DIR)
+
+include $(GNUSTEP_MAKEFILES)/bundle.make
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
diff --git a/skyrix-xml/pyxSAXDriver/README b/skyrix-xml/pyxSAXDriver/README
new file mode 100644 (file)
index 0000000..c4a3100
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+pyxSAXDriver
+============
+
+This directory contains the sources for a SAX driver bundle which can read
+so called "pyx" files. PYX is a line based representation for XML useful for
+processing XML files using Unix cmdline tools (like grep or awk).
+
+The parser itself is written in Objective-C (and probably pretty slow for
+large files ;-)
diff --git a/skyrix-xml/pyxSAXDriver/bundle-info.plist b/skyrix-xml/pyxSAXDriver/bundle-info.plist
new file mode 100644 (file)
index 0000000..bb99410
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  CVS = "$Id: bundle-info.plist,v 1.1.1.1 2003/07/09 22:57:27 cvs Exp $";
+  //bundleHandler = NSObject;
+
+  requires = {
+    bundleManagerVersion = 1;
+    classes = (
+      { name = NSObject;    }
+    );
+  };
+  
+  provides = {
+    SAXDrivers = ( 
+      { 
+        name        = pyxSAXDriver; 
+        sourceTypes = ( "text/pyx" );
+      }
+    );
+    classes    = ( { name = pyxSAXDriver; } );
+  };
+}
diff --git a/skyrix-xml/pyxSAXDriver/pyxSAXDriver-Info.plist b/skyrix-xml/pyxSAXDriver/pyxSAXDriver-Info.plist
new file mode 100644 (file)
index 0000000..2e908df
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>pyxSAXDriver</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>org.opengroupware.xml.pyxSAXDriver</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>4.2</string>
+       <key>CSResourcesFileMapped</key>
+       <string>yes</string>
+</dict>
+</plist>
diff --git a/skyrix-xml/pyxSAXDriver/pyxSAXDriver.h b/skyrix-xml/pyxSAXDriver/pyxSAXDriver.h
new file mode 100644 (file)
index 0000000..af76c6b
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#ifndef __pyxSAXDriver_H__
+#define __pyxSAXDriver_H__
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxXMLReader.h>
+#include <SaxObjC/SaxContentHandler.h>
+#include <SaxObjC/SaxDTDHandler.h>
+#include <SaxObjC/SaxErrorHandler.h>
+#include <SaxObjC/SaxEntityResolver.h>
+#include <SaxObjC/SaxLexicalHandler.h>
+#include <SaxObjC/SaxLocator.h>
+#include <SaxObjC/SaxDeclHandler.h>
+
+@class NSMutableArray;
+@class SaxAttributes;
+
+@interface pyxSAXDriver : NSObject < SaxXMLReader >
+{
+@private
+  id<NSObject,SaxContentHandler> contentHandler;
+  id<NSObject,SaxDTDHandler>     dtdHandler;
+  id<NSObject,SaxErrorHandler>   errorHandler;
+  id<NSObject,SaxEntityResolver> entityResolver;
+  
+  id<NSObject,SaxLexicalHandler> lexicalHandler;
+  id<NSObject,SaxDeclHandler>    declHandler;
+  
+  int            depth;
+  NSMutableArray *nsStack;
+  BOOL           fNamespaces;
+  BOOL           fNamespacePrefixes;
+  
+  /* cache */
+  id            locator;
+  SaxAttributes *attrs;
+}
+
+@end
+
+#endif /* __pyxSAXDriver_H__ */
diff --git a/skyrix-xml/pyxSAXDriver/pyxSAXDriver.m b/skyrix-xml/pyxSAXDriver/pyxSAXDriver.m
new file mode 100644 (file)
index 0000000..3becc95
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include "pyxSAXDriver.h"
+#include <SaxObjC/SaxException.h>
+#include <SaxObjC/SaxAttributes.h>
+#include <SaxObjC/SaxDocumentHandler.h>
+#import <Foundation/Foundation.h>
+
+#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY
+#  include <FoundationExt/NSObjectMacros.h>
+#  include <FoundationExt/MissingMethods.h>
+#endif
+
+static NSString *SaxDeclHandlerProperty =
+  @"http://xml.org/sax/properties/declaration-handler";
+static NSString *SaxLexicalHandlerProperty =
+  @"http://xml.org/sax/properties/lexical-handler";
+#if 0
+static NSString *SaxDOMNodeProperty =
+  @"http://xml.org/sax/properties/dom-node";
+static NSString *SaxXMLStringProperty =
+  @"http://xml.org/sax/properties/xml-string";
+#endif
+
+@implementation pyxSAXDriver
+
+- (id)init {
+  self->nsStack = [[NSMutableArray alloc] init];
+  
+  /* feature defaults */
+  self->fNamespaces        = YES;
+  self->fNamespacePrefixes = NO;
+  
+  return self;
+}
+
+- (void)dealloc {
+  RELEASE(self->nsStack);
+  RELEASE(self->attrs);
+
+  RELEASE(self->declHandler);
+  RELEASE(self->lexicalHandler);
+  RELEASE(self->contentHandler);
+  RELEASE(self->dtdHandler);
+  RELEASE(self->errorHandler);
+  RELEASE(self->entityResolver);
+  [super dealloc];
+}
+
+/* properties */
+
+- (void)setProperty:(NSString *)_name to:(id)_value {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
+    ASSIGN(self->lexicalHandler, _value);
+    return;
+  }
+  if ([_name isEqualToString:SaxDeclHandlerProperty]) {
+    ASSIGN(self->declHandler, _value);
+    return;
+  }
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+}
+- (id)property:(NSString *)_name {
+  if ([_name isEqualToString:SaxLexicalHandlerProperty])
+    return self->lexicalHandler;
+  if ([_name isEqualToString:SaxDeclHandlerProperty])
+    return self->declHandler;
+  
+  [SaxNotRecognizedException raise:@"PropertyException"
+                             format:@"don't know property %@", _name];
+  return nil;
+}
+
+/* features */
+
+- (void)setFeature:(NSString *)_name to:(BOOL)_value {
+  if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
+    self->fNamespaces = _value;
+    return;
+  }
+  
+  if ([_name isEqualToString:
+               @"http://xml.org/sax/features/namespace-prefixes"]) {
+    self->fNamespacePrefixes = _value;
+    return;
+  }
+
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+}
+- (BOOL)feature:(NSString *)_name {
+  if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
+    return self->fNamespaces;
+  
+  if ([_name isEqualToString:
+               @"http://xml.org/sax/features/namespace-prefixes"])
+    return self->fNamespacePrefixes;
+  
+  [SaxNotRecognizedException raise:@"FeatureException"
+                             format:@"don't know feature %@", _name];
+  return NO;
+}
+
+/* handlers */
+
+#if 0
+- (void)setDocumentHandler:(id<NSObject,SaxDocumentHandler>)_handler {
+  SaxDocumentHandlerAdaptor *a;
+
+  a = [[SaxDocumentHandlerAdaptor alloc] initWithDocumentHandler:_handler];
+  [self setContentHandler:a];
+  RELEASE(a);
+}
+#endif
+
+- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
+  ASSIGN(self->dtdHandler, _handler);
+}
+- (id<NSObject,SaxDTDHandler>)dtdHandler {
+  return self->dtdHandler;
+}
+
+- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
+  ASSIGN(self->errorHandler, _handler);
+}
+- (id<NSObject,SaxErrorHandler>)errorHandler {
+  return self->errorHandler;
+}
+
+- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
+  ASSIGN(self->entityResolver, _handler);
+}
+- (id<NSObject,SaxEntityResolver>)entityResolver {
+  return self->entityResolver;
+}
+
+- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
+  ASSIGN(self->contentHandler, _handler);
+}
+- (id<NSObject,SaxContentHandler>)contentHandler {
+  return self->contentHandler;
+}
+
+/* parsing */
+
+- (void)parseFromSource:(id)_source {
+  NSAutoreleasePool *pool;
+  NSArray *lines;
+  
+  if ([_source isKindOfClass:[NSString class]]) {
+    lines = [_source componentsSeparatedByString:@"\n"];
+  }
+  else if ([_source isKindOfClass:[NSData class]]) {
+    _source = [[NSString alloc] 
+               initWithData:_source
+               encoding:[NSString defaultCStringEncoding]];
+    lines = [_source componentsSeparatedByString:@"\n"];
+    RELEASE(_source);
+  }
+  else {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _source ? _source : @"<nil>", @"source",
+                         self,                         @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"can't handle data-source"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+    return;
+  }
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  /* start parsing lines */
+  {
+    NSEnumerator *e;
+    NSString *line;
+    
+    e = [lines objectEnumerator];
+    while ((line = [e nextObject])) {
+    recheck:
+      if ([line hasPrefix:@"("]) {
+       NSMutableDictionary *ns = nil;
+       NSString *startTag;
+        NSDictionary *nsDict = nil;
+
+       /* not yet finished ! */
+       
+       startTag = [line substringFromIndex:1];
+       line = [e nextObject];
+       while ([line hasPrefix:@"A"]) {
+         /* attribute */
+         NSString *rawName, *value;
+         unsigned idx;
+         
+         line = [line substringFromIndex:1];
+         
+         if ((idx = [line indexOfString:@" "]) == NSNotFound) {
+           value   = @"";
+           rawName = line;
+         }
+         else {
+           rawName = [line substringToIndex:idx];
+           value   = [line substringFromIndex:(idx + 1)];
+         }
+         
+         if ([rawName hasPrefix:@"xmlns"]) {
+           /* a namespace declaration */
+           if (ns == nil) ns = [[NSMutableDictionary alloc] init];
+           
+           if ([rawName hasPrefix:@"xmlns:"]) {
+             /* eg <x xmlns:nl="http://www.w3.org"/> */
+             NSString *prefix, *uri;
+             
+             prefix = [rawName substringFromIndex:6];
+             uri    = value;
+             
+             [ns setObject:uri forKey:prefix];
+
+             if (self->fNamespaces)
+               [self->contentHandler startPrefixMapping:prefix uri:uri];
+           }
+           else {
+             /* eg <x xmlns="http://www.w3.org"/> */
+             [ns setObject:value forKey:@":"];
+           }
+         }
+       }
+       /* start tag finished */
+       nsDict = [ns copy];
+       RELEASE(ns); ns = nil;
+       
+       /* manage namespace stack */
+  
+       if (nsDict == nil)
+         nsDict = [NSDictionary dictionary];
+        
+       [self->nsStack addObject:nsDict];
+
+       /* to be completed ! */
+       
+       if (line != nil)
+         goto recheck;
+      }
+    }
+  }
+  
+  RELEASE(pool);
+}
+
+- (void)parseFromSystemId:(NSString *)_sysId {
+  NSString *s;
+
+  /* _sysId is a URI */
+  if (![_sysId hasPrefix:@"file://"]) {
+    SaxParseException *e;
+    NSDictionary      *ui;
+    
+    ui = [NSDictionary dictionaryWithObjectsAndKeys:
+                         _sysId ? _sysId : @"<nil>", @"systemID",
+                         self,                       @"parser",
+                         nil];
+    
+    e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
+                               reason:@"can't handle system-id"
+                               userInfo:ui];
+    
+    [self->errorHandler fatalError:e];
+    return;
+  }
+
+  /* cut off file:// */
+  _sysId = [_sysId substringFromIndex:7];
+  
+  /* start parsing .. */
+  if ((s = [NSString stringWithContentsOfFile:_sysId]))
+    [self parseFromSource:s];
+}
+
+/* entities */
+
+- (NSString *)replacementStringForEntityNamed:(NSString *)_entityName {
+  //NSLog(@"get entity: %@", _entityName);
+  return [[@"&amp;" stringByAppendingString:_entityName]
+                    stringByAppendingString:@";"];
+}
+
+/* namespace support */
+
+- (NSString *)nsUriForPrefix:(NSString *)_prefix {
+  NSEnumerator *e;
+  NSDictionary *ns;
+  
+  e = [self->nsStack reverseObjectEnumerator];
+  while ((ns = [e nextObject])) {
+    NSString *uri;
+    
+    if ((uri = [ns objectForKey:_prefix]))
+      return uri;
+  }
+  return nil;
+}
+
+- (NSString *)defaultNamespace {
+  return [self nsUriForPrefix:@":"];
+}
+
+@end /* pyxSAXDriver */
diff --git a/skyrix-xml/pyxSAXDriver/slashdot.pyx b/skyrix-xml/pyxSAXDriver/slashdot.pyx
new file mode 100644 (file)
index 0000000..28f7387
--- /dev/null
@@ -0,0 +1,403 @@
+(ultramode
+-\n 
+(story
+-\n    
+(title
+-100 Mbit/s on Fibre to the home
+)title
+-\n    
+(url
+-http://slashdot.org/articles/99/06/06/1440211.shtml
+)url
+-\n    
+(time
+-1999-06-06 14:39:59
+)time
+-\n    
+(author
+-CmdrTaco
+)author
+-\n    
+(department
+-wouldn't-it-be-nice
+)department
+-\n    
+(topic
+-internet
+)topic
+-\n    
+(comments
+-20
+)comments
+-\n    
+(section
+-articles
+)section
+-\n    
+(image
+-topicinternet.jpg
+)image
+-\n  
+)story
+-\n 
+(story
+-\n    
+(title
+-Gimp 1.2 Preview
+)title
+-\n    
+(url
+-http://slashdot.org/articles/99/06/06/1438246.shtml
+)url
+-\n    
+(time
+-1999-06-06 14:38:40
+)time
+-\n    
+(author
+-CmdrTaco
+)author
+-\n    
+(department
+-stuff-to-read
+)department
+-\n    
+(topic
+-gimp
+)topic
+-\n    
+(comments
+-12
+)comments
+-\n    
+(section
+-articles
+)section
+-\n    
+(image
+-topicgimp.gif
+)image
+-\n  
+)story
+-\n 
+(story
+-\n    
+(title
+-Sony's AIBO robot Sold Out
+)title
+-\n    
+(url
+-http://slashdot.org/articles/99/06/06/1432256.shtml
+)url
+-\n    
+(time
+-1999-06-06 14:32:51
+)time
+-\n    
+(author
+-CmdrTaco
+)author
+-\n    
+(department
+-stuff-to-see
+)department
+-\n    
+(topic
+-tech
+)topic
+-\n    
+(comments
+-10
+)comments
+-\n    
+(section
+-articles
+)section
+-\n    
+(image
+-topictech2.jpg
+)image
+-\n  
+)story
+-\n 
+(story
+-\n    
+(title
+-Ask Slashdot: Another Word for "Hacker"?
+)title
+-\n    
+(url
+-http://slashdot.org/askslashdot/99/06/05/1815225.shtml
+)url
+-\n    
+(time
+-1999-06-05 20:00:00
+)time
+-\n    
+(author
+-Cliff
+)author
+-\n    
+(department
+-hacker-vs-cracker
+)department
+-\n    
+(topic
+-news
+)topic
+-\n    
+(comments
+-385
+)comments
+-\n    
+(section
+-askslashdot
+)section
+-\n    
+(image
+-topicnews.gif
+)image
+-\n  
+)story
+-\n 
+(story
+-\n    
+(title
+-Corel Linux FAQ
+)title
+-\n    
+(url
+-http://slashdot.org/articles/99/06/05/1842218.shtml
+)url
+-\n    
+(time
+-1999-06-05 18:42:06
+)time
+-\n    
+(author
+-CmdrTaco
+)author
+-\n    
+(department
+-stuff-to-read
+)department
+-\n    
+(topic
+-corel
+)topic
+-\n    
+(comments
+-164
+)comments
+-\n    
+(section
+-articles
+)section
+-\n    
+(image
+-topiccorel.gif
+)image
+-\n  
+)story
+-\n 
+(story
+-\n    
+(title
+-Upside downsides MP3.COM.
+)title
+-\n    
+(url
+-http://slashdot.org/articles/99/06/05/1558210.shtml
+)url
+-\n    
+(time
+-1999-06-05 15:56:45
+)time
+-\n    
+(author
+-CmdrTaco
+)author
+-\n    
+(department
+-stuff-to-think-about
+)department
+-\n    
+(topic
+-music
+)topic
+-\n    
+(comments
+-48
+)comments
+-\n    
+(section
+-articles
+)section
+-\n    
+(image
+-topicmusic.gif
+)image
+-\n  
+)story
+-\n 
+(story
+-\n    
+(title
+-2 Terabits of Bandwidth
+)title
+-\n    
+(url
+-http://slashdot.org/articles/99/06/05/1554258.shtml
+)url
+-\n    
+(time
+-1999-06-05 15:53:43
+)time
+-\n    
+(author
+-CmdrTaco
+)author
+-\n    
+(department
+-faster-porn
+)department
+-\n    
+(topic
+-internet
+)topic
+-\n    
+(comments
+-66
+)comments
+-\n    
+(section
+-articles
+)section
+-\n    
+(image
+-topicinternet.jpg
+)image
+-\n  
+)story
+-\n 
+(story
+-\n    
+(title
+-Suppression of cold fusion research?
+)title
+-\n    
+(url
+-http://slashdot.org/articles/99/06/04/2313200.shtml
+)url
+-\n    
+(time
+-1999-06-04 23:12:29
+)time
+-\n    
+(author
+-Hemos
+)author
+-\n    
+(department
+-possibly-probably
+)department
+-\n    
+(topic
+-science
+)topic
+-\n    
+(comments
+-217
+)comments
+-\n    
+(section
+-articles
+)section
+-\n    
+(image
+-topicscience.gif
+)image
+-\n  
+)story
+-\n 
+(story
+-\n    
+(title
+-California Gov. Halts Wage Info Sale
+)title
+-\n    
+(url
+-http://slashdot.org/articles/99/06/04/235256.shtml
+)url
+-\n    
+(time
+-1999-06-04 23:05:34
+)time
+-\n    
+(author
+-Hemos
+)author
+-\n    
+(department
+-woo-hoo!
+)department
+-\n    
+(topic
+-usa
+)topic
+-\n    
+(comments
+-16
+)comments
+-\n    
+(section
+-articles
+)section
+-\n    
+(image
+-topicus.gif
+)image
+-\n  
+)story
+-\n 
+(story
+-\n    
+(title
+-Red Hat Announces IPO
+)title
+-\n    
+(url
+-http://slashdot.org/articles/99/06/04/0849207.shtml
+)url
+-\n    
+(time
+-1999-06-04 19:30:18
+)time
+-\n    
+(author
+-Justin
+)author
+-\n    
+(department
+-details-sketchy
+)department
+-\n    
+(topic
+-redhat
+)topic
+-\n    
+(comments
+-155
+)comments
+-\n    
+(section
+-articles
+)section
+-\n    
+(image
+-topicredhat.gif
+)image
+-\n  
+)story
+-\n
+)ultramode
diff --git a/skyrix-xml/samples/.cvsignore b/skyrix-xml/samples/.cvsignore
new file mode 100644 (file)
index 0000000..49a10b1
--- /dev/null
@@ -0,0 +1,2 @@
+shared_debug_obj
+shared_obj
diff --git a/skyrix-xml/samples/ChangeLog b/skyrix-xml/samples/ChangeLog
new file mode 100644 (file)
index 0000000..2369d24
--- /dev/null
@@ -0,0 +1,29 @@
+2004-05-05  Marcus Mueller  <znek@mulle-kybernetik.com>  
+
+       * GNUmakefile: added support for building with
+         GNUSTEP_BUILD_DIR environment variable set for recent
+         gnustep-make package.
+
+2004-03-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * saxxml.m: minor improvements in error processing
+
+2003-11-30  Helge Hess  <helge.hess@opengroupware.org>
+
+       * domxml.m: minor fix to result logging
+
+2003-07-04  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved in domxml and testqp from DOM
+
+2003-02-18  Helge Hess  <helge.hess@skyrix.com>
+
+       * saxxml.m: makes pathes absolute, before constructing a URL from
+         them
+
+2003-02-11  Helge Hess  <helge.hess@skyrix.com>
+
+       * moved in xmln and saxxml tools
+
+       * created ChangeLog for tools
+
diff --git a/skyrix-xml/samples/GNUmakefile b/skyrix-xml/samples/GNUmakefile
new file mode 100644 (file)
index 0000000..4732305
--- /dev/null
@@ -0,0 +1,49 @@
+# $Id$
+
+include $(GNUSTEP_MAKEFILES)/common.make
+
+TOOL_NAME = \
+       saxxml          \
+       xmln            \
+       rss2plist1      \
+       rss2plist2      \
+       rssparse        \
+       domxml          \
+       testqp          \
+
+rss2plist1_OBJC_FILES = rss2plist1.m
+rss2plist2_OBJC_FILES = rss2plist2.m
+rssparse_OBJC_FILES   = rssparse.m
+saxxml_OBJC_FILES     = saxxml.m
+xmln_OBJC_FILES       = xmln.m
+domxml_OBJC_FILES     = domxml.m
+testqp_OBJC_FILES     = testqp.m
+
+domxml_TOOL_LIBS  += -lDOM -lSaxObjC
+
+testqp_TOOL_LIBS  += -lDOM -lSaxObjC
+
+ADDITIONAL_CPPFLAGS  += -Wno-protocol
+ADDITIONAL_TOOL_LIBS += -lSaxObjC
+
+# only with libFoundation
+#ADDITIONAL_TOOL_LIBS += -lEOControl
+
+ADDITIONAL_INCLUDE_DIRS += -I..
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_BUILD_DIR)/../DOM/$(GNUSTEP_OBJ_DIR_NAME)           \
+       -L$(GNUSTEP_BUILD_DIR)/../SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)       \
+       -L$(GNUSTEP_BUILD_DIR)/../XmlRpc/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += \
+       -L../DOM/$(GNUSTEP_OBJ_DIR)     \
+       -L../SaxObjC/$(GNUSTEP_OBJ_DIR) \
+       -L../XmlRpc/$(GNUSTEP_OBJ_DIR)
+endif
+
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/tool.make
+-include GNUmakefile.postamble
diff --git a/skyrix-xml/samples/README b/skyrix-xml/samples/README
new file mode 100644 (file)
index 0000000..d45ce21
--- /dev/null
@@ -0,0 +1,18 @@
+# $Id$
+
+Examples for using skyrix-xml
+=============================
+
+saxxml         - parse a file using SAX and print out the XML
+
+xmln           - convert a give file to PYX using a SAX handler
+
+rss2plist1     - a sample for writing a "raw" SaxObjC handler
+
+rss2plist2     - a sample for writing a method-callback SaxObjC handler
+
+rssparse       - a sample for using the SaxObjectDecoder
+
+domxml         - parse a file into a DOM and print out the XML
+
+testqp         - a sample for testing DOM query pathes
diff --git a/skyrix-xml/samples/common.h b/skyrix-xml/samples/common.h
new file mode 100644 (file)
index 0000000..983a30e
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#import <Foundation/Foundation.h>
+
+#ifndef ASSIGN
+#  define ASSIGN(object, value) \
+       ({id __object = (id)object;    \
+         id __value = (id)value;      \
+         if (__value != __object) { if (__value) [__value retain]; \
+          if (__object) [__object release]; \
+          object = __value;}})
+#endif
diff --git a/skyrix-xml/samples/data/Main.xtmpl b/skyrix-xml/samples/data/Main.xtmpl
new file mode 100644 (file)
index 0000000..d1cdb52
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:var="http://www.skyrix.com/od/binding">
+  <head>
+    <title><var:string value="context.page.title"/></title>
+    
+    <meta name="lastChanged" var:content="clientObject.davLastModified"/>
+    <meta name="author"      content="SKYRIX Software AG"/>
+    <meta name="generator"   content="SKYRiX Object Publishing Environment"/>
+    <meta name="robots"      content="index, follow, all" />
+    
+    <link rel="shortcut icon" href="/favicon.ico" />
+    <link rel="stylesheet"    href="stylesheet.css" type="text/css" />
+    <link rev="made"          href="mailto:info@developer.skyrix.com" /> 
+  </head>
+  
+  <body bgcolor="white">
+    <table width="100%" cellpadding="0" cellspacing="0" border="0">
+      <tr>
+        <td width="462"><a target="_top" href="/index.html"
+         ><img border="0" src="images/banner_left.gif"/></a></td>
+        <td width="100%" 
+            background="images/banner_back.gif"><entity name="nbsp"/></td>
+        <td align="right" width="14"
+         ><img border="0" src="images/banner_right.gif"/></td>
+      </tr>
+    </table>
+    
+    <var:component value="context.page"/>
+
+    <hr />
+    <var:foreach list="clientObject.container.toOneRelationshipKeys"
+                 item="sibling">
+      <var:string value="sibling" />
+    </var:foreach>
+  </body>
+</html>
diff --git a/skyrix-xml/samples/data/skyrix-xml.xml b/skyrix-xml/samples/data/skyrix-xml.xml
new file mode 100644 (file)
index 0000000..a4b1426
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE project-listing SYSTEM "http://freshmeat.net/backend/fm-projects-0.1.dtd">
+<project-listing>
+  <project>
+    <project_id>34265</project_id>
+    <date_added>2003-01-17 05:08:06</date_added>
+    <date_updated>2003-01-17 05:57:18</date_updated>
+    <projectname_short>skyrix-xml</projectname_short>
+    <projectname_full>SKYRiX XML Processing Libraries</projectname_full>
+    <desc_short>A SAX, DOM, and XML-RPC Implementation for Objective-C.</desc_short>
+    <desc_full>The SKYRiX XML library package is a set of\r
+Objective-C libraries for processing XML and\r
+XML-like data. It includes a SAX2, DOM, and\r
+XML-RPC implementation for Objective-C. SAX\r
+drivers are provided for accessing HTML and XML\r
+files using libxml2, XML using expat, iCal/vCard\r
+using libical, pyx and plist files. The package\r
+works with GNUstep and with the Apple Cocoa\r
+Foundation. </desc_full>
+    <vitality_score>0.00</vitality_score>
+    <vitality_percent>0.00</vitality_percent>
+    <popularity_score>5.01</popularity_score>
+    <popularity_percent>0.01</popularity_percent>
+    <rating>0.00</rating>
+    <rating_count>0</rating_count>
+    <subscriptions>0</subscriptions>
+    <branch_name>Default</branch_name>
+    <url_project_page>http://freshmeat.net/projects/skyrix-xml/</url_project_page>
+    <url_homepage>http://freshmeat.net/redir/skyrix-xml/36366/url_homepage/</url_homepage>
+    <url_tgz>http://freshmeat.net/redir/skyrix-xml/36366/url_tgz/</url_tgz>
+    <url_changelog></url_changelog>
+    <url_rpm></url_rpm>
+    <url_deb></url_deb>
+    <url_bz2></url_bz2>
+    <url_cvs></url_cvs>
+    <url_list></url_list>
+    <url_zip></url_zip>
+    <license>GNU Lesser General Public License (LGPL)</license>
+    <latest_version></latest_version>
+    <screenshot_thumb></screenshot_thumb>
+  </project>
+</project-listing>
diff --git a/skyrix-xml/samples/data/slashdot.rss b/skyrix-xml/samples/data/slashdot.rss
new file mode 100644 (file)
index 0000000..8017596
--- /dev/null
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<rdf:RDF
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns="http://purl.org/rss/1.0/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
+ xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
+ xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
+>
+
+<channel rdf:about="http://slashdot.org/">
+<title>Slashdot</title>
+<link>http://slashdot.org/</link>
+<description>News for nerds, stuff that matters</description>
+<dc:language>en-us</dc:language>
+<dc:rights>Copyright &amp;copy; 1997-2001, OSDN</dc:rights>
+<dc:date>2003-01-23T09:44:04+00:00</dc:date>
+<dc:publisher>OSDN</dc:publisher>
+<dc:creator>pater@slashdot.org</dc:creator>
+<dc:subject>Technology</dc:subject>
+<syn:updatePeriod>hourly</syn:updatePeriod>
+<syn:updateFrequency>1</syn:updateFrequency>
+<syn:updateBase>1970-01-01T00:00+00:00</syn:updateBase>
+<items>
+ <rdf:Seq>
+  <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/01/23/0247248" />
+  <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/01/23/0221242" />
+  <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/01/22/2324241" />
+  <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/01/22/2233227" />
+  <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/01/22/1413238" />
+  <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/01/22/2041211" />
+  <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/01/22/1514201" />
+  <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/01/22/1932238" />
+  <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/01/22/196249" />
+  <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/01/22/188234" />
+ </rdf:Seq>
+</items>
+<image rdf:resource="http://images.slashdot.org/topics/topicslashdot.gif" />
+<textinput rdf:resource="http://slashdot.org/search.pl" />
+</channel>
+
+<image rdf:about="http://images.slashdot.org/topics/topicslashdot.gif">
+<title>Slashdot</title>
+<url>http://images.slashdot.org/topics/topicslashdot.gif</url>
+<link>http://slashdot.org/</link>
+</image>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/01/23/0247248">
+<title>XBox Chip With Legal BIOS</title>
+<link>http://slashdot.org/article.pl?sid=03/01/23/0247248</link>
+<description>Lours writes "(OzChip, an Australian company, has a new Xbox chip which comes preinstalled with the new (Cromwell Linux BIOS. Previous chips came without (or ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>hardware</dc:subject>
+<dc:date>2003-01-23T07:47:14+00:00</dc:date>
+<slash:department>keeping-legal</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>92</slash:comments>
+<slash:hitparade>92,83,61,38,20,11,5</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/01/23/0221242">
+<title>Using Redundancies to Find Errors</title>
+<link>http://slashdot.org/article.pl?sid=03/01/23/0221242</link>
+<description>gsbarnes writes "Two Stanford researchers (Dawson Engler and Yichen Xie) have written a paper (pdf) showing that seemingly harmless redundant code is ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>programming</dc:subject>
+<dc:date>2003-01-23T04:20:58+00:00</dc:date>
+<slash:department>the-error-is-right-around-here</slash:department>
+<slash:section>developers</slash:section>
+<slash:comments>148</slash:comments>
+<slash:hitparade>148,138,102,65,20,11,6</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/01/22/2324241">
+<title>Hilary Rosen Will Step Down As RIAA Head</title>
+<link>http://slashdot.org/article.pl?sid=03/01/22/2324241</link>
+<description>Phoenix666 writes "NYT Business reports Hilary Rosen is leaving. Question is, what head will spring from the Hydra next? Could this signal a shift in the ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>music</dc:subject>
+<dc:date>2003-01-23T01:24:05+00:00</dc:date>
+<slash:department>yawn</slash:department>
+<slash:section>yro</slash:section>
+<slash:comments>399</slash:comments>
+<slash:hitparade>399,387,288,170,55,35,27</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/01/22/2233227">
+<title>Microsoft to Buy Vivendi Games Division?</title>
+<link>http://slashdot.org/article.pl?sid=03/01/22/2233227</link>
+<description>Unknown Relic writes "While far from confirmed, it is reported that Microsoft is seriously looking into buying, or may have already bought, Vivendi's Games ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>games</dc:subject>
+<dc:date>2003-01-22T23:59:51+00:00</dc:date>
+<slash:department>passive-voice</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>353</slash:comments>
+<slash:hitparade>353,332,235,136,48,21,15</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/01/22/1413238">
+<title>Elect Steve Jobs President of the United States</title>
+<link>http://slashdot.org/article.pl?sid=03/01/22/1413238</link>
+<description>Will Foster writes "There is a groundswell of support for electing Steve Jobs President of the United States." I'll vote for him if I can write in my vote -- ...</description>
+<dc:creator>pudge</dc:creator>
+<dc:subject>humor</dc:subject>
+<dc:date>2003-01-22T23:12:48+00:00</dc:date>
+<slash:department>we-need-a-megalomaniacal-leader-for-a-change</slash:department>
+<slash:section>apple</slash:section>
+<slash:comments>606</slash:comments>
+<slash:hitparade>606,593,430,255,71,49,39</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/01/22/2041211">
+<title>Building a Multi-Channel PVR System?</title>
+<link>http://slashdot.org/article.pl?sid=03/01/22/2041211</link>
+<description>Dr.Ruud asks: "What would be good ways to build a multichannel VCR? Think of a cluster of 4 PCs, each having 4 TV-cards (with MPEG-hardware on each) and (if ...</description>
+<dc:creator>Cliff</dc:creator>
+<dc:subject>tech</dc:subject>
+<dc:date>2003-01-22T22:35:58+00:00</dc:date>
+<slash:department>it-doesn't-HAVE-to-be-a-single-box</slash:department>
+<slash:section>askslashdot</slash:section>
+<slash:comments>301</slash:comments>
+<slash:hitparade>301,295,216,125,49,31,20</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/01/22/1514201">
+<title>Lucas Digital Releases OpenEXR Format</title>
+<link>http://slashdot.org/article.pl?sid=03/01/22/1514201</link>
+<description>frankie writes "Although George Lucas may have gone over to the dark side, at least some of his staff prefer Freedom and light. ILM has released OpenEXR, a ...</description>
+<dc:creator>chrisd</dc:creator>
+<dc:subject>movies</dc:subject>
+<dc:date>2003-01-22T21:08:08+00:00</dc:date>
+<slash:department>no-oscars-till-2005</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>144</slash:comments>
+<slash:hitparade>144,133,107,77,36,17,9</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/01/22/1932238">
+<title>Bitstream To Donate 10 Fonts To Free Software World</title>
+<link>http://slashdot.org/article.pl?sid=03/01/22/1932238</link>
+<description>21mhz writes "Posted on FootNotes: The GNOME Foundation and Bitstream Inc. announce long-term agreement to bring high quality fonts to Free Software. Ten fonts ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>graphics</dc:subject>
+<dc:date>2003-01-22T20:38:56+00:00</dc:date>
+<slash:department>some-gnus-is-good-gnus</slash:department>
+<slash:section>developers</slash:section>
+<slash:comments>352</slash:comments>
+<slash:hitparade>352,345,260,165,66,37,22</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/01/22/196249">
+<title>Congress To Consider Age Limits On Violent Games</title>
+<link>http://slashdot.org/article.pl?sid=03/01/22/196249</link>
+<description>labrat1123 writes "It looks like Congress is getting ready to revisit the 'Protect Children from Video Game Sex and Violence Act.' Cliff Notes version: It ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>censorship</dc:subject>
+<dc:date>2003-01-22T19:46:10+00:00</dc:date>
+<slash:department>on-this-date-in-1984</slash:department>
+<slash:section>yro</slash:section>
+<slash:comments>538</slash:comments>
+<slash:hitparade>538,531,422,258,80,54,44</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/01/22/188234">
+<title>SCO Group Hires Boies After All</title>
+<link>http://slashdot.org/article.pl?sid=03/01/22/188234</link>
+<description>pitr256 writes "So it seems the SCO Group has decided to hire infamous Anti-Microsoft lawyer David Boies after all. This comes upon reversal of the SCO Group ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>patents</dc:subject>
+<dc:date>2003-01-22T18:57:04+00:00</dc:date>
+<slash:department>mendacity-mendacity-mendacity</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>441</slash:comments>
+<slash:hitparade>441,426,313,203,66,42,24</slash:hitparade>
+</item>
+
+<textinput rdf:about="http://slashdot.org/search.pl">
+<title>Search Slashdot</title>
+<description>Search Slashdot stories</description>
+<name>query</name>
+<link>http://slashdot.org/search.pl</link>
+</textinput>
+
+</rdf:RDF>
\ No newline at end of file
diff --git a/skyrix-xml/samples/domxml.m b/skyrix-xml/samples/domxml.m
new file mode 100644 (file)
index 0000000..fe61bb7
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <SaxObjC/SaxObjC.h>
+#include "common.h"
+#include <DOM/DOMBuilderFactory.h>
+#include <DOM/DOMXMLOutputter.h>
+#include <DOM/DOMPYXOutputter.h>
+#include <DOM/DOMSaxBuilder.h>
+
+/*
+  Usage
+  
+    domxml [options] files
+      -repeat <n-times>
+      -xml|-pyx         - output in XML or PYX format ...
+*/
+
+int main(int argc, char **argv, char **env) {
+  NSEnumerator      *paths;
+  NSString          *path;
+  NSAutoreleasePool *pool;
+  id<DOMBuilder>    builder;
+  id                out;
+  unsigned          repeat;
+  
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  out    = nil;
+  repeat = 1;
+
+  builder = [[DOMBuilderFactory standardDOMBuilderFactory]
+                                createDOMBuilder];
+  if (builder == nil) {
+    fprintf(stderr, "could not create DOM builder !\n");
+    exit(2);
+  }
+  
+  /* parse */
+
+  paths = [[[NSProcessInfo processInfo] arguments] objectEnumerator];
+  [paths nextObject]; // skip toolname
+  while ((path = [paths nextObject])) {
+    NSAutoreleasePool *pool;
+    NSDate            *date;
+    NSTimeInterval    duration;
+    unsigned          i;
+    id doc;
+    
+    if ([path hasPrefix:@"-"]) {
+      if ([path isEqualToString:@"-pyx"]) {
+        out = [[[DOMPYXOutputter alloc] init] autorelease];
+      }
+      else if ([path isEqualToString:@"-xml"]) {
+        out = [[[DOMXMLOutputter alloc] init] autorelease];
+      }
+      else if ([path isEqualToString:@"-repeat"]) {
+        repeat = [[paths nextObject] intValue];
+      }
+      else {
+        // a default ? skip the value
+        [paths nextObject];
+      }
+      
+      continue;
+    }
+    
+    pool = [[NSAutoreleasePool alloc] init];
+
+    if (repeat > 1)
+      NSLog(@"repeat %i times ...", repeat);
+
+    doc = nil;
+    for (i = 0; i < repeat; i++) {
+      NSAutoreleasePool *pool2;
+      
+      pool2 = [[NSAutoreleasePool alloc] init];
+      [doc release]; doc = nil;
+      
+      date = [NSDate date];
+      doc = [(id)builder buildFromContentsOfFile:path];
+      duration = [[NSDate date] timeIntervalSinceDate:date];
+      if (doc)
+       NSLog(@"doc(%i) is %@, parsed in %.3fs", i, doc, duration);
+      else if (doc == nil) {
+        NSLog(@"couldn't build DOM from path '%@' (%.3fs)", path, duration);
+        [pool release]; pool = nil;
+        break;
+      }
+      
+      doc = [doc retain];
+      [pool2 release];
+    }
+    
+    //NSLog(@"doc is %@, parsed in %.3fs", doc, duration);
+    
+    if (doc == nil)
+      continue;
+    
+    [out outputDocument:doc to:nil];
+    
+    [pool release];
+  }
+  
+  [pool release];
+
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-xml/samples/rss2plist1.m b/skyrix-xml/samples/rss2plist1.m
new file mode 100644 (file)
index 0000000..ce5fc41
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+  Copyright (C) 2000-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$
+
+/*
+  A small demonstration program to show how to write a SAX handler
+  using SaxObjC. It goes over a RSS channel file and collects the
+  item information in a dictionary.
+  
+  As you will see it's quite a bit of work dealing with SAX ;-)
+*/
+
+#import <Foundation/Foundation.h>
+#include <SaxObjC/SaxObjC.h>
+
+/* ******************** the SAX handler ****************** */
+
+@interface RSSSaxHandler : SaxDefaultHandler
+{
+  NSMutableArray      *entries;
+  NSMutableDictionary *entry;
+
+  /* parsing state */
+  BOOL     isInItem; /* are we inside an 'item' tag ? */
+  NSString *value;   /* the (PCDATA) content of a tag */
+}
+
+- (NSArray *)rssEntries;
+
+@end
+
+@implementation RSSSaxHandler
+
+- (id)init {
+  if ((self = [super init])) {
+    self->entries = [[NSMutableArray alloc] initWithCapacity:16];
+    self->entry   = [[NSMutableDictionary alloc] initWithCapacity:8];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->entry   release];
+  [self->entries release];
+  [super dealloc];
+}
+
+/* accessing results */
+
+- (NSArray *)rssEntries {
+  return [[self->entries copy] autorelease];
+}
+
+/* setup/teardown */
+
+- (void)startDocument {
+  /* ensure consistent state */
+  [self->entries removeAllObjects];
+  self->isInItem = NO;
+}
+
+/* parsing */
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attributes
+{
+  if ([_localName isEqualToString:@"item"]) {
+    [self->entry removeAllObjects];
+    self->isInItem = YES;
+  }
+  
+  /* always reset content when entering a new tag */
+  [self->value release]; self->value = nil;
+}
+
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  if ([_localName isEqualToString:@"item"]) {
+    /* found end of item */
+    self->isInItem = NO;
+    [self->entries addObject:[[self->entry copy] autorelease]];
+  }
+  else if (self->isInItem) {
+    /* any tag inside of an item is a key for the entry dict */
+    if (self->value) {
+      /* if we collected a PCDATA value, add it */
+      [self->entry setObject:self->value forKey:_localName];
+      [self->value release]; self->value = nil;
+    }
+  }
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  NSString *s;
+  
+  if (!self->isInItem)
+    /* only track content if we are inside an item ... */
+    return;
+    
+  /* 
+     Note: The characters callback is allowed to be called multiple times
+           by the parser (makes writing parsers easier, but complicates the
+           handler ...).
+  */
+  s = [[NSString alloc] initWithCharacters:_chars length:_len];
+  if (self->value) {
+    self->value = [[self->value stringByAppendingString:s] copy];
+    [s release];
+  }
+  else
+    self->value = s;
+}
+
+@end /* RSSSaxHandler */
+
+/* ******************** C main section ******************** */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  if ([[[NSProcessInfo processInfo] arguments] count] < 2) {
+    fprintf(stderr, "usage: %s <rssfile>\n",
+           [[[[NSProcessInfo processInfo] arguments] lastObject] cString]);
+    return 1;
+  }
+  
+  /* the interesting section */
+  {
+    NSEnumerator     *args;
+    NSString         *arg;
+    id<SaxXMLReader> parser;
+    RSSSaxHandler    *sax;
+    
+    /* step a, get a parser for XML */
+    parser = [[SaxXMLReaderFactory standardXMLReaderFactory]
+                                  createXMLReaderForMimeType:@"text/xml"];
+    
+    /* step b, create a SAX handler and attach it to the parser */
+    sax = [[[RSSSaxHandler alloc] init] autorelease];
+    [parser setContentHandler:sax];
+    [parser setErrorHandler:sax];
+    
+    /* step c, parse :-) */
+    
+    args = [[[NSProcessInfo processInfo] arguments] objectEnumerator];
+    [args nextObject]; /* skip tool name */
+    
+    while ((arg = [args nextObject])) {
+      NSArray *entries;
+      
+      /* the parser takes URLs, NSData's, NSString's */
+      arg = [[[NSURL alloc] initFileURLWithPath:arg] autorelease];
+      
+      /* let the parser parse (it will report SAX events to the handler) */
+      [parser parseFromSource:arg];
+      
+      /* now query the handler for the result */
+      entries = [sax rssEntries];
+      
+      /* TODO: use NSPropertyListSerialization on OSX */
+      printf("%s\n", [[entries description] cString]);
+    }
+    
+    return 0;
+  }
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-xml/samples/rss2plist2.m b/skyrix-xml/samples/rss2plist2.m
new file mode 100644 (file)
index 0000000..5bff621
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  A small demonstration program to show how to write a SAX handler
+  using SaxObjC. It goes over a RSS channel file and collects the
+  item information in a dictionary.
+  
+  This example is almost the same like rss2plist1.m, but uses the
+  SaxMethodCallHandler which calls a method for each tag, so you
+  don't need to do manual tagname checks.
+  Note that we only process known content, all other tags are ignored.
+  
+  As you will see it's quite a bit of work dealing with SAX ;-)
+*/
+
+#import <Foundation/Foundation.h>
+#include <SaxObjC/SaxObjC.h>
+#include <SaxObjC/SaxMethodCallHandler.h>
+
+/* ******************** the SAX handler ****************** */
+
+@interface RSSSaxHandler : SaxMethodCallHandler
+{
+  NSMutableArray      *entries;
+  NSMutableDictionary *entry;
+
+  /* parsing state */
+  NSString *value;   /* the (PCDATA) content of a tag */
+}
+
+- (NSArray *)rssEntries;
+
+@end
+
+@implementation RSSSaxHandler
+
+- (id)init {
+  if ((self = [super init])) {
+    self->entries = [[NSMutableArray alloc] initWithCapacity:16];
+    self->entry   = [[NSMutableDictionary alloc] initWithCapacity:8];
+    
+    /* those are required for mapping the names */
+    [self registerNamespace:@"http://purl.org/rss/1.0/" withKey:@"rss"];
+    [self registerNamespace:@"http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+         withKey:@"rdf"];
+    [self registerNamespace:@"http://purl.org/rss/1.0/modules/slash/"
+         withKey:@"slash"];
+    [self registerNamespace:@"http://purl.org/rss/1.0/modules/syndication/"
+         withKey:@"syn"];
+  }
+  return self;
+}
+- (void)dealloc {
+  [self->entry   release];
+  [self->entries release];
+  [super dealloc];
+}
+
+/* accessing results */
+
+- (NSArray *)rssEntries {
+  return [[self->entries copy] autorelease];
+}
+
+/* setup/teardown */
+
+- (void)startDocument {
+  /* ensure consistent state */
+  [self->entries removeAllObjects];
+}
+
+/* parsing */
+
+- (void)start_rssitem:(id<SaxAttributes>)_attributes {
+  [self->entry removeAllObjects];
+}
+- (void)end_rssitem {
+  [self->entries addObject:[[self->entry copy] autorelease]];
+}
+
+/* the subtags of item ... */
+
+- (void)start_rsstitle:(id<SaxAttributes>)_attributes {
+  [self->value release]; self->value = nil;
+}
+- (void)end_rsstitle {
+  if (self->value)
+    [self->entry setObject:self->value forKey:@"title"];
+}
+
+- (void)start_rsslink:(id<SaxAttributes>)_attributes {
+  [self->value release]; self->value = nil;
+}
+- (void)end_rsslink {
+  if (self->value)
+    [self->entry setObject:self->value forKey:@"link"];
+}
+
+- (void)start_rssdescription:(id<SaxAttributes>)_attributes {
+  [self->value release]; self->value = nil;
+}
+- (void)end_rssdescription {
+  if (self->value)
+    [self->entry setObject:self->value forKey:@"info"];
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  NSString *s;
+  
+  /* 
+     Note: The characters callback is allowed to be called multiple times
+           by the parser (makes writing parsers easier, but complicates the
+           handler ...).
+  */
+  s = [[NSString alloc] initWithCharacters:_chars length:_len];
+  if (self->value) {
+    self->value = [[self->value stringByAppendingString:s] copy];
+    [s release];
+  }
+  else
+    self->value = s;
+}
+
+@end /* RSSSaxHandler */
+
+/* ******************** C main section ******************** */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  if ([[[NSProcessInfo processInfo] arguments] count] < 2) {
+    fprintf(stderr, "usage: %s <rssfile>\n",
+           [[[[NSProcessInfo processInfo] arguments] lastObject] cString]);
+    return 1;
+  }
+  
+  /* the interesting section */
+  {
+    NSEnumerator     *args;
+    NSString         *arg;
+    id<SaxXMLReader> parser;
+    RSSSaxHandler    *sax;
+    
+    /* step a, get a parser for XML */
+    parser = [[SaxXMLReaderFactory standardXMLReaderFactory]
+                                createXMLReaderForMimeType:@"text/xml"];
+    
+    /* step b, create a SAX handler and attach it to the parser */
+    sax = [[[RSSSaxHandler alloc] init] autorelease];
+    [parser setContentHandler:sax];
+    [parser setErrorHandler:sax];
+    
+    /* step c, parse :-) */
+    
+    args = [[[NSProcessInfo processInfo] arguments] objectEnumerator];
+    [args nextObject]; /* skip tool name */
+    
+    while ((arg = [args nextObject])) {
+      NSArray *entries;
+      
+      /* the parser takes URLs, NSData's, NSString's */
+      arg = [[[NSURL alloc] initFileURLWithPath:arg] autorelease];
+      
+      /* let the parser parse (it will report SAX events to the handler) */
+      [parser parseFromSource:arg];
+      
+      /* now query the handler for the result */
+      entries = [sax rssEntries];
+      
+      /* TODO: use NSPropertyListSerialization on OSX */
+      printf("%s\n", [[entries description] cString]);
+    }
+    
+    return 0;
+  }
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-xml/samples/rssparse.m b/skyrix-xml/samples/rssparse.m
new file mode 100644 (file)
index 0000000..9ac89ff
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+/*
+  A small demonstration program to show how to use SaxObjectDecoder
+  to parse XML files. This one parses a RSS channel file and collects
+  the information in a dictionary.
+  
+  This one is much easier and more high-level than rss2plist1 and rss2plist2.
+  Instead of writing a low level SAX event handler, you just define a mapping
+  model and the "enterprise" classes.
+*/
+
+#import <Foundation/Foundation.h>
+#include <SaxObjC/SaxObjC.h>
+#include <SaxObjC/SaxMethodCallHandler.h>
+
+/* ******************** the "business" objects ************ */
+
+@interface RSSObject : NSObject
+{
+  NSString *title;
+  NSString *link;
+  NSString *info;
+}
+
+@end
+
+@interface RSSChannel : RSSObject
+@end
+
+@interface RSSItem : RSSObject
+@end
+
+@implementation RSSObject
+
+- (void)dealloc {
+  [self->title release];
+  [self->link  release];
+  [self->info  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setTitle:(NSString *)_value {
+  [self->title autorelease];
+  self->title = [_value copy];
+}
+- (void)setLink:(NSString *)_value {
+  [self->link autorelease];
+  self->link = [_value copy];
+}
+- (void)setInfo:(NSString *)_value {
+  [self->info autorelease];
+  self->info = [_value copy];
+}
+
+/* description */
+
+- (NSString *)description {
+  NSMutableString *s = [NSMutableString stringWithCapacity:64];
+  [s appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+  if (self->title) [s appendFormat:@" title='%@'", self->title];
+  if (self->link)  [s appendFormat:@" link='%@'",  self->link];
+  //[s appendFormat:@" info='%@'", self->info];
+  [s appendString:@">"];
+  return s;
+}
+
+@end /* RSSObject */
+
+@implementation RSSChannel
+@end /* RSSChannel */
+
+@implementation RSSItem
+@end /* RSSItem */
+
+/* ******************** C main section ******************** */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  pool = [[NSAutoreleasePool alloc] init];
+
+  if ([[[NSProcessInfo processInfo] arguments] count] < 2) {
+    fprintf(stderr, "usage: %s <rssfile>\n",
+           [[[[NSProcessInfo processInfo] arguments] lastObject] cString]);
+    return 1;
+  }
+  
+  /* the interesting section */
+  {
+    NSEnumerator     *args;
+    NSString         *arg;
+    id<SaxXMLReader> parser;
+    SaxObjectDecoder *sax;
+    
+    /* step a, get a parser for XML */
+    parser = [[SaxXMLReaderFactory standardXMLReaderFactory]
+                                  createXMLReaderForMimeType:@"text/xml"];
+    
+    /* step b, create a SAX handler and attach it to the parser */
+    sax = [[SaxObjectDecoder alloc] initWithMappingAtPath:@"./rssparse.xmap"];
+    [parser setContentHandler:sax];
+    [parser setErrorHandler:sax];
+    [sax autorelease];
+    
+    /* step c, parse :-) */
+    
+    args = [[[NSProcessInfo processInfo] arguments] objectEnumerator];
+    [args nextObject]; /* skip tool name */
+    
+    while ((arg = [args nextObject])) {
+      id channel;
+      
+      /* the parser takes URLs, NSData's, NSString's */
+      arg = [[[NSURL alloc] initFileURLWithPath:arg] autorelease];
+      
+      /* let the parser parse (it will report SAX events to the handler) */
+      [parser parseFromSource:arg];
+      
+      /* now query the handler for the result */
+      channel = [sax rootObject];
+      
+      /* TODO: use NSPropertyListSerialization on OSX */
+      NSLog(@"parsed channel: %@", channel);
+    }
+    
+    return 0;
+  }
+  [pool release];
+  return 0;
+}
diff --git a/skyrix-xml/samples/rssparse.xmap b/skyrix-xml/samples/rssparse.xmap
new file mode 100644 (file)
index 0000000..89df54a
--- /dev/null
@@ -0,0 +1,38 @@
+{
+  "http://purl.org/rss/1.0/" = {
+
+    channel = {
+      class  = RSSChannel;
+      
+      attributes = {
+        title       = title;
+        link        = link;
+        description = info;
+      };
+    };
+    
+    item = {
+      class  = RSSItem;
+      
+      attributes = {
+        title       = title;
+        link        = link;
+        description = info;
+      };
+    };
+    
+    title       = { class = NSString; };
+    link        = { class = NSString; };
+    description = { class = NSString; key = "info"; };
+  };
+  
+  "http://www.w3.org/1999/02/22-rdf-syntax-ns#" = {
+    RDF = {
+      class = NSMutableDictionary;
+      ToManyRelationships = {
+       channels = ( channel );
+        items    = ( item );
+      };
+    };
+  };
+}
diff --git a/skyrix-xml/samples/saxxml.m b/skyrix-xml/samples/saxxml.m
new file mode 100644 (file)
index 0000000..17eb8d5
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <SaxObjC/SaxObjC.h>
+#import <Foundation/Foundation.h>
+
+/*
+  Usage:
+
+    saxxml -XMLReader libxmlHTMLSAXDriver test.html
+*/
+
+@interface MySAXHandler : SaxDefaultHandler
+{
+  id  locator;
+  int indent;
+}
+
+- (void)indent;
+
+@end
+
+int main(int argc, char **argv, char **env) {
+  id<NSObject,SaxXMLReader> parser;
+  id           sax;
+  NSEnumerator *paths;
+  NSString     *path;
+  NSAutoreleasePool *pool;
+  NSString          *cwd;
+  
+  pool   = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  parser = [[SaxXMLReaderFactory standardXMLReaderFactory] createXMLReader];
+  cwd    = [[NSFileManager defaultManager] currentDirectoryPath];
+  
+  if (parser == nil) {
+    fprintf(stderr, "could not load a SAX driver bundle !\n");
+    exit(2);
+  }
+  
+  sax = [[MySAXHandler alloc] init];
+  [parser setContentHandler:sax];
+  [parser setDTDHandler:sax];
+  [parser setErrorHandler:sax];
+  
+  [parser setProperty:@"http://xml.org/sax/properties/declaration-handler"
+          to:sax];
+#if 0
+  [parser setProperty:@"http://xml.org/sax/properties/lexical-handler"
+          to:sax];
+#endif
+  
+  /* parse */
+
+  paths = [[[NSProcessInfo processInfo] arguments] objectEnumerator];
+  [paths nextObject];
+  while ((path = [paths nextObject])) {
+    NSAutoreleasePool *pool;
+
+    if ([path hasPrefix:@"-"]) { /* consume defaults */
+      [paths nextObject];
+      continue;
+    }
+    
+    pool = [[NSAutoreleasePool alloc] init];
+    
+    if (![path isAbsolutePath])
+      path = [cwd stringByAppendingPathComponent:path];
+    
+    path = [@"file://" stringByAppendingString:path];
+    
+    NS_DURING
+      [parser parseFromSystemId:path];
+    NS_HANDLER
+      abort();
+    NS_ENDHANDLER;
+    
+    [pool release];
+  }
+  
+  /* cleanup */
+  
+  [sax release];
+  //[parser release];
+
+  [pool release];
+
+  exit(0);
+  return 0;
+}
+
+@implementation MySAXHandler
+
+- (void)indent {
+  int i;
+  
+  for (i = 0; i < (self->indent * 4); i++)
+    fputc(' ', stdout);
+}
+
+@end /* MySAXHandler */
+
+@implementation MySAXHandler(Documents)
+
+- (void)dealloc {
+  [self->locator release];
+  [super dealloc];
+}
+
+- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_loc {
+  [self->locator autorelease];
+  self->locator = [_loc retain];
+}
+
+- (void)startDocument {
+  puts("start document ..");
+  self->indent++;
+}
+- (void)endDocument {
+  self->indent--;
+  puts("end document.");
+}
+
+- (void)startPrefixMapping:(NSString *)_prefix uri:(NSString *)_uri {
+  [self indent];
+  printf("ns-map: %s=%s\n", [_prefix cString], [_uri cString]);
+}
+- (void)endPrefixMapping:(NSString *)_prefix {
+  [self indent];
+  printf("ns-unmap: %s\n", [_prefix cString]);
+}
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attrs
+{
+  int i, c;
+  [self indent];
+  printf("<%s", [_localName cString]);
+  
+  if ([_ns length] > 0)
+    printf(" (ns=%s)", [_ns cString]);
+  
+  for (i = 0, c = [_attrs count]; i < c; i++) {
+    NSString *type;
+    
+    printf(" %s=\"%s\"",
+           [[_attrs nameAtIndex:i] cString],
+           [[_attrs valueAtIndex:i] cString]);
+
+    if (![_ns isEqualToString:[_attrs uriAtIndex:i]])
+      printf("(ns=%s)", [[_attrs uriAtIndex:i] cString]);
+    
+    type = [_attrs typeAtIndex:i];
+    if (![type isEqualToString:@"CDATA"] && (type != nil))
+      printf("[%s]", [type cString]);
+  }
+  puts(">");
+  self->indent++;
+}
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  self->indent--;
+  [self indent];
+  printf("</%s>\n", [_localName cString]);
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  NSString *str;
+  id tmp;
+  unsigned i, len;
+
+  if (_len == 0) {
+    [self indent];
+    printf("\"\"\n");
+    return;
+  }
+  
+  for (i = 0; i < (unsigned)_len; i++) {
+    if (_chars[i] > 255) {
+      NSLog(@"detected large char: o%04o d%03i h%04X",
+            _chars[i], _chars[i], _chars[i]);
+    }
+  }
+  
+  str = [NSString stringWithCharacters:_chars length:_len];
+  len = [str length];
+  
+  tmp = [str componentsSeparatedByString:@"\n"];
+  str = [tmp componentsJoinedByString:@"\\n"];
+  tmp = [str componentsSeparatedByString:@"\r"];
+  str = [tmp componentsJoinedByString:@"\\r"];
+  
+  [self indent];
+  printf("\"%s\"\n", [str cString]);
+}
+- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
+  NSString *data;
+  id tmp;
+
+  data = [NSString stringWithCharacters:_chars length:_len];
+  tmp  = [data componentsSeparatedByString:@"\n"];
+  data = [tmp componentsJoinedByString:@"\\n"];
+  tmp  = [data componentsSeparatedByString:@"\r"];
+  data = [tmp componentsJoinedByString:@"\\r"];
+  
+  [self indent];
+  printf("whitespace: \"%s\"\n", [data cString]);
+}
+
+- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data {
+  [self indent];
+  printf("PI: '%s' '%s'\n", [_pi cString], [_data cString]);
+}
+
+#if 0
+- (xmlEntityPtr)getEntity:(NSString *)_name {
+  NSLog(@"get entity %@", _name);
+  return NULL;
+}
+- (xmlEntityPtr)getParameterEntity:(NSString *)_name {
+  NSLog(@"get para entity %@", _name);
+  return NULL;
+}
+#endif
+
+@end /* MySAXHandler(Documents) */
+
+@implementation MySAXHandler(EntityResolver)
+
+- (id)resolveEntityWithPublicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+{
+  [self indent];
+  printf("shall resolve entity with '%s' '%s'",
+         [_pubId cString], [_sysId cString]);
+  return nil;
+}
+
+@end /* MySAXHandler(EntityResolver) */
+
+@implementation MySAXHandler(Errors)
+
+- (void)warning:(SaxParseException *)_exception {
+  NSLog(@"warning(%@:%i): %@",
+        [[_exception userInfo] objectForKey:@"publicId"],
+        [[[_exception userInfo] objectForKey:@"line"] intValue],
+        [_exception reason]);
+}
+
+- (void)error:(SaxParseException *)_exception {
+  NSLog(@"error(%@:%i): %@",
+        [[_exception userInfo] objectForKey:@"publicId"],
+        [[[_exception userInfo] objectForKey:@"line"] intValue],
+        [_exception reason]);
+}
+
+- (void)fatalError:(SaxParseException *)_exception {
+  NSLog(@"fatal error(%@:%i): %@",
+        [[_exception userInfo] objectForKey:@"publicId"],
+        [[[_exception userInfo] objectForKey:@"line"] intValue],
+        [_exception reason]);
+  [_exception raise];
+}
+
+@end /* MySAXHandler(Errors) */
+
+@implementation MySAXHandler(DTD)
+
+- (void)notationDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+{
+  NSLog(@"decl: notation %@ pub=%@ sys=%@", _name, _pubId, _sysId);
+}
+
+- (void)unparsedEntityDeclaration:(NSString *)_name
+  publicId:(NSString *)_pubId
+  systemId:(NSString *)_sysId
+  notationName:(NSString *)_notName
+{
+  NSLog(@"decl: unparsed entity %@ pub=%@ sys=%@ not=%@",
+        _name, _pubId, _sysId, _notName);
+}
+
+@end /* MySAXHandler(DTD) */
+
+@implementation MySAXHandler(Decl)
+
+- (void)attributeDeclaration:(NSString *)_attributeName
+  elementName:(NSString *)_elementName
+  type:(NSString *)_type
+  defaultType:(NSString *)_defType
+  defaultValue:(NSString *)_defValue
+{
+  NSLog(@"decl: attr %@[%@] type '%@' default '%@'[%@]",
+        _attributeName, _elementName, _type, _defValue, _defType);
+}
+
+- (void)elementDeclaration:(NSString *)_name contentModel:(NSString *)_model {
+  NSLog(@"decl: element %@ model %@", _name, _model);
+}
+
+- (void)externalEntityDeclaration:(NSString *)_name
+  publicId:(NSString *)_pub
+  systemId:(NSString *)_sys
+{
+  NSLog(@"decl: e-entity %@ pub %@ sys %@", _name, _pub, _sys);
+}
+
+- (void)internalEntityDeclaration:(NSString *)_name value:(NSString *)_value {
+  NSLog(@"decl: i-entity %@ value %@", _name, _value);
+}
+
+@end /* MySAXHandler(Decl) */
diff --git a/skyrix-xml/samples/testqp.m b/skyrix-xml/samples/testqp.m
new file mode 100644 (file)
index 0000000..1d41597
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+  Copyright (C) 2000-2003 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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$
+
+#include <SaxObjC/SaxObjC.h>
+#include "common.h"
+#include <DOM/DOMSaxBuilder.h>
+#include <DOM/DOMXMLOutputter.h>
+#include <DOM/DOMPYXOutputter.h>
+#include <DOM/NSObject+QPEval.h>
+
+/*
+  Usage
+  
+    testqp [options] files
+      -xml|-pyx         - output in XML or PYX format ...
+*/
+
+int main(int argc, char **argv, char **env) {
+  NSEnumerator      *paths;
+  NSString          *path;
+  NSAutoreleasePool *pool;
+  Class             builderClass;
+  DOMSaxBuilder     *builder;
+  id                out;
+  
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  out = nil;
+  
+  builderClass = Nil;
+  if ((builder = [[DOMSaxBuilder alloc] init]) == nil) {
+    fprintf(stderr, "could not load a SAX driver bundle !\n");
+    exit(2);
+  }
+  [builder autorelease];
+  
+  /* parse */
+
+  paths = [[[NSProcessInfo processInfo] arguments] objectEnumerator];
+  [paths nextObject]; // skip toolname
+  while ((path = [paths nextObject])) {
+    NSAutoreleasePool *pool;
+    NSDate            *date;
+    NSTimeInterval    duration;
+    id doc;
+    
+    if ([path hasPrefix:@"-"]) {
+      if ([path isEqualToString:@"-pyx"]) {
+        out = [[[DOMPYXOutputter alloc] init] autorelease];
+      }
+      else if ([path isEqualToString:@"-xml"]) {
+        out = [[[DOMXMLOutputter alloc] init] autorelease];
+      }
+      else {
+        // a default ? skip the value
+        [paths nextObject];
+      }
+      
+      continue;
+    }
+    
+    pool = [[NSAutoreleasePool alloc] init];
+
+    date = [NSDate date];
+    doc = [builder buildFromContentsOfFile:path];
+    duration = [[NSDate date] timeIntervalSinceDate:date];
+    
+    if (doc == nil) {
+      NSLog(@"couldn't build DOM from path '%@'", path);
+      [pool release]; pool = nil;
+    }
+    else {
+      [out outputDocument:doc to:nil];
+      NSLog(@"doc is %@, parsed in %.3fs", doc, duration);
+      
+      while (1) {
+        NSAutoreleasePool *pool;
+        char buf[4096];
+        
+        pool = [[NSAutoreleasePool alloc] init];
+        printf("enter query path: ");
+        fflush(stdout);
+        
+        fgets(buf, 4000, stdin);
+        
+        if (buf[0] == '\n' || buf[0] == 0) {
+          printf("... exit\n");
+          break;
+        }
+        else {
+          NSString *s;
+          volatile id res;
+
+          buf[strlen(buf) - 1] = '\0';
+          s = [NSString stringWithCString:buf];
+          NSLog(@"eval: '%@'", s);
+
+          NS_DURING
+            if ((res = [doc evaluateQueryPath:s])) 
+              NSLog(@"result: %@", res);
+            else
+              NSLog(@"no rresult ...");
+          NS_HANDLER {
+            fprintf(stderr, "%s\n", [[localException description] cString]);
+            abort();
+          }
+          NS_ENDHANDLER;
+        }
+        
+        [pool release];
+      }
+    }
+    
+    [pool release];
+  }
+  
+  [pool release];
+
+  exit(0);
+  return 0;
+}
diff --git a/skyrix-xml/samples/xmln.m b/skyrix-xml/samples/xmln.m
new file mode 100644 (file)
index 0000000..41dd634
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+  Copyright (C) 2000-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$
+
+#include <SaxObjC/SaxObjC.h>
+#import <Foundation/Foundation.h>
+
+/*
+  This tool uses a SAX parser to generate a PYX representation
+  of an XML file. PYX is a simplified XML syntax for line oriented
+  processing of XML files.
+  See 'XML Processing with Python' for an explanation of PYX.
+*/
+
+@interface PYXSaxHandler : SaxDefaultHandler
+{
+  FILE *out;
+}
+
+- (void)write:(NSString *)_s;
+
+@end
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool         *pool;
+  id<NSObject,SaxXMLReader> parser;
+  id                        sax;
+  NSEnumerator              *paths;
+  NSString                  *path;
+
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+  pool = [[NSAutoreleasePool alloc] init];
+  
+  parser = [[SaxXMLReaderFactory standardXMLReaderFactory]
+                                 createXMLReader];
+  if (parser == nil) {
+    fprintf(stderr, "could not load a SAX driver bundle !\n");
+    exit(2);
+  }
+  
+  sax = [[[PYXSaxHandler alloc] init] autorelease];
+  [parser setContentHandler:sax];
+  [parser setDTDHandler:sax];
+  [parser setErrorHandler:sax];
+  
+  /* parse */
+
+  paths = [[[NSProcessInfo processInfo] arguments] objectEnumerator];
+  [paths nextObject];
+  while ((path = [paths nextObject])) {
+    NSAutoreleasePool *pool;
+
+    if ([path hasPrefix:@"-"]) {
+      /* skip defaults */
+      [paths nextObject];
+      continue;
+    }
+    
+    pool = [[NSAutoreleasePool alloc] init];
+
+    path = [@"file://" stringByAppendingString:path];
+    
+    NS_DURING
+      [parser parseFromSystemId:path];
+    NS_HANDLER
+      fprintf(stderr, "xmln: catched: %s\n", 
+             [[localException description] cString]);
+    NS_ENDHANDLER;
+    
+    [pool release]; pool = nil;
+  }
+  
+  /* cleanup */
+  [pool release];
+
+  exit(0);
+  return 0;
+}
+
+#include <stdio.h>
+
+@implementation PYXSaxHandler
+
+- (id)init {
+  self->out = stdout;
+  return self;
+}
+
+- (void)write:(NSString *)_s {
+  unsigned len;
+  char *buf;
+  if ((len = [_s cStringLength]) == 0)
+    return;
+  buf = malloc(len + 1);
+  [_s getCString:buf];
+  fprintf(self->out, "%s", buf);
+  free(buf); buf = NULL;
+}
+- (void)tag:(unsigned char)_t key:(NSString *)_s value:(NSString *)_value {
+  unsigned len, vlen;
+  char *buf;
+  
+  fputc(_t, self->out);
+  
+  len  = [_s cStringLength];
+  vlen = [_value cStringLength];
+  
+  buf = malloc((len>vlen ? len : vlen) + 1);
+  [_s getCString:buf];
+  if (_value) {
+    fprintf(self->out, "%s", buf);
+    [_value getCString:buf];
+    fprintf(self->out, " %s\n", buf);
+  }
+  else
+    fprintf(self->out, "%s\n", buf);
+  free(buf); buf = NULL;
+}
+- (void)tag:(unsigned char)_t key:(NSString *)_s {
+  [self tag:_t key:_s value:nil];
+}
+
+- (void)startElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+  attributes:(id<SaxAttributes>)_attrs
+{
+  int i, c;
+  
+  [self tag:'(' key:_rawName];
+  
+  for (i = 0, c = [_attrs count]; i < c; i++) {
+    NSString *aname, *avalue;
+    
+    aname  = [_attrs rawNameAtIndex:i];
+    avalue = [_attrs valueAtIndex:i];
+    
+    [self tag:'A' key:aname value:avalue];
+  }
+}
+
+- (void)endElement:(NSString *)_localName
+  namespace:(NSString *)_ns
+  rawName:(NSString *)_rawName
+{
+  [self tag:')' key:_rawName];
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+  int i;
+  
+  if (_len == 0) return;
+  
+  fputc('-', self->out);
+  
+  for (i = 0; i < _len; i++) {
+    if (_chars[i] > 255) {
+      fprintf(stderr, "found unichar, code 0x%04X\n", _chars[i]);
+    }
+    else {
+      register unsigned char c = _chars[i];
+
+      switch (c) {
+      case '\n':
+       fputc('\\', self->out);
+       fputc('n', self->out);
+       break;
+      default:
+       fputc(c, self->out);
+       break;
+      }
+    }
+  }
+  fputc('\n', self->out);
+}
+
+- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data {
+  [self tag:'?' key:_pi value:_data];
+}
+
+- (void)warning:(SaxParseException *)_exception {
+  NSLog(@"WARNING: %@", [_exception reason]);
+}
+- (void)error:(SaxParseException *)_exception {
+  NSLog(@"ERROR: %@:%@: %@",
+        [[_exception userInfo] objectForKey:@"systemId"],
+        [[_exception userInfo] objectForKey:@"line"],
+        [_exception reason]);
+}
+- (void)fatalError:(SaxParseException *)_exception {
+  [_exception raise];
+}
+
+@end /* PYXSaxHandler */
diff --git a/svn-commit.tmp b/svn-commit.tmp
new file mode 100644 (file)
index 0000000..c9f6549
--- /dev/null
@@ -0,0 +1,4 @@
+foo
+--This line, and those below, will be ignored--
+
+A    .